summaryrefslogtreecommitdiff
path: root/gst/rtp
diff options
context:
space:
mode:
Diffstat (limited to 'gst/rtp')
-rwxr-xr-xgst/rtp/Makefile.am182
-rwxr-xr-xgst/rtp/Makefile.in1743
-rwxr-xr-xgst/rtp/README398
-rwxr-xr-xgst/rtp/TODO15
-rwxr-xr-xgst/rtp/dboolhuff.LICENSE29
-rwxr-xr-xgst/rtp/dboolhuff.c68
-rwxr-xr-xgst/rtp/dboolhuff.h151
-rwxr-xr-xgst/rtp/fnv1hash.c63
-rwxr-xr-xgst/rtp/fnv1hash.h36
-rwxr-xr-xgst/rtp/gstasteriskh263.c230
-rwxr-xr-xgst/rtp/gstasteriskh263.h65
-rwxr-xr-xgst/rtp/gstrtp.c343
-rwxr-xr-xgst/rtp/gstrtpL16depay.c288
-rwxr-xr-xgst/rtp/gstrtpL16depay.h67
-rwxr-xr-xgst/rtp/gstrtpL16pay.c263
-rwxr-xr-xgst/rtp/gstrtpL16pay.h63
-rwxr-xr-xgst/rtp/gstrtpL24depay.c266
-rwxr-xr-xgst/rtp/gstrtpL24depay.h67
-rwxr-xr-xgst/rtp/gstrtpL24pay.c244
-rwxr-xr-xgst/rtp/gstrtpL24pay.h63
-rwxr-xr-xgst/rtp/gstrtpac3depay.c182
-rwxr-xr-xgst/rtp/gstrtpac3depay.h58
-rwxr-xr-xgst/rtp/gstrtpac3pay.c469
-rwxr-xr-xgst/rtp/gstrtpac3pay.h64
-rwxr-xr-xgst/rtp/gstrtpamrdepay.c479
-rwxr-xr-xgst/rtp/gstrtpamrdepay.h77
-rwxr-xr-xgst/rtp/gstrtpamrpay.c459
-rwxr-xr-xgst/rtp/gstrtpamrpay.h70
-rwxr-xr-xgst/rtp/gstrtpbvdepay.c188
-rwxr-xr-xgst/rtp/gstrtpbvdepay.h60
-rwxr-xr-xgst/rtp/gstrtpbvpay.c228
-rwxr-xr-xgst/rtp/gstrtpbvpay.h60
-rwxr-xr-xgst/rtp/gstrtpceltdepay.c276
-rwxr-xr-xgst/rtp/gstrtpceltdepay.h54
-rwxr-xr-xgst/rtp/gstrtpceltpay.c488
-rwxr-xr-xgst/rtp/gstrtpceltpay.h62
-rwxr-xr-xgst/rtp/gstrtpchannels.c164
-rwxr-xr-xgst/rtp/gstrtpchannels.h190
-rwxr-xr-xgst/rtp/gstrtpdvdepay.c415
-rwxr-xr-xgst/rtp/gstrtpdvdepay.h66
-rwxr-xr-xgst/rtp/gstrtpdvpay.c395
-rwxr-xr-xgst/rtp/gstrtpdvpay.h69
-rwxr-xr-xgst/rtp/gstrtpg722depay.c262
-rwxr-xr-xgst/rtp/gstrtpg722depay.h64
-rwxr-xr-xgst/rtp/gstrtpg722pay.c217
-rwxr-xr-xgst/rtp/gstrtpg722pay.h61
-rwxr-xr-xgst/rtp/gstrtpg723depay.c228
-rwxr-xr-xgst/rtp/gstrtpg723depay.h59
-rwxr-xr-xgst/rtp/gstrtpg723pay.c317
-rwxr-xr-xgst/rtp/gstrtpg723pay.h64
-rwxr-xr-xgst/rtp/gstrtpg726depay.c395
-rwxr-xr-xgst/rtp/gstrtpg726depay.h58
-rwxr-xr-xgst/rtp/gstrtpg726pay.c422
-rwxr-xr-xgst/rtp/gstrtpg726pay.h55
-rwxr-xr-xgst/rtp/gstrtpg729depay.c226
-rwxr-xr-xgst/rtp/gstrtpg729depay.h61
-rwxr-xr-xgst/rtp/gstrtpg729pay.c418
-rwxr-xr-xgst/rtp/gstrtpg729pay.h66
-rwxr-xr-xgst/rtp/gstrtpgsmdepay.c151
-rwxr-xr-xgst/rtp/gstrtpgsmdepay.h58
-rwxr-xr-xgst/rtp/gstrtpgsmpay.c191
-rwxr-xr-xgst/rtp/gstrtpgsmpay.h59
-rwxr-xr-xgst/rtp/gstrtpgstdepay.c625
-rwxr-xr-xgst/rtp/gstrtpgstdepay.h66
-rwxr-xr-xgst/rtp/gstrtpgstpay.c661
-rwxr-xr-xgst/rtp/gstrtpgstpay.h72
-rwxr-xr-xgst/rtp/gstrtph263depay.c430
-rwxr-xr-xgst/rtp/gstrtph263depay.h66
-rwxr-xr-xgst/rtp/gstrtph263pay.c1838
-rwxr-xr-xgst/rtp/gstrtph263pay.h414
-rwxr-xr-xgst/rtp/gstrtph263pdepay.c395
-rwxr-xr-xgst/rtp/gstrtph263pdepay.h62
-rwxr-xr-xgst/rtp/gstrtph263ppay.c777
-rwxr-xr-xgst/rtp/gstrtph263ppay.h70
-rwxr-xr-xgst/rtp/gstrtph264depay.c1174
-rwxr-xr-xgst/rtp/gstrtph264depay.h85
-rwxr-xr-xgst/rtp/gstrtph264pay.c1405
-rwxr-xr-xgst/rtp/gstrtph264pay.h95
-rwxr-xr-xgst/rtp/gstrtpilbcdepay.c237
-rwxr-xr-xgst/rtp/gstrtpilbcdepay.h65
-rwxr-xr-xgst/rtp/gstrtpilbcpay.c217
-rwxr-xr-xgst/rtp/gstrtpilbcpay.h60
-rwxr-xr-xgst/rtp/gstrtpj2kdepay.c646
-rwxr-xr-xgst/rtp/gstrtpj2kdepay.h75
-rwxr-xr-xgst/rtp/gstrtpj2kpay.c536
-rwxr-xr-xgst/rtp/gstrtpj2kpay.h61
-rwxr-xr-xgst/rtp/gstrtpjpegdepay.c790
-rwxr-xr-xgst/rtp/gstrtpjpegdepay.h70
-rwxr-xr-xgst/rtp/gstrtpjpegpay.c996
-rwxr-xr-xgst/rtp/gstrtpjpegpay.h63
-rwxr-xr-xgst/rtp/gstrtpmp1sdepay.c142
-rwxr-xr-xgst/rtp/gstrtpmp1sdepay.h58
-rwxr-xr-xgst/rtp/gstrtpmp2tdepay.c243
-rwxr-xr-xgst/rtp/gstrtpmp2tdepay.h60
-rwxr-xr-xgst/rtp/gstrtpmp2tpay.c234
-rwxr-xr-xgst/rtp/gstrtpmp2tpay.h64
-rwxr-xr-xgst/rtp/gstrtpmp4adepay.c445
-rwxr-xr-xgst/rtp/gstrtpmp4adepay.h62
-rwxr-xr-xgst/rtp/gstrtpmp4apay.c452
-rwxr-xr-xgst/rtp/gstrtpmp4apay.h65
-rwxr-xr-xgst/rtp/gstrtpmp4gdepay.c774
-rwxr-xr-xgst/rtp/gstrtpmp4gdepay.h86
-rwxr-xr-xgst/rtp/gstrtpmp4gpay.c641
-rwxr-xr-xgst/rtp/gstrtpmp4gpay.h74
-rwxr-xr-xgst/rtp/gstrtpmp4vdepay.c226
-rwxr-xr-xgst/rtp/gstrtpmp4vdepay.h61
-rwxr-xr-xgst/rtp/gstrtpmp4vpay.c617
-rwxr-xr-xgst/rtp/gstrtpmp4vpay.h74
-rwxr-xr-xgst/rtp/gstrtpmpadepay.c181
-rwxr-xr-xgst/rtp/gstrtpmpadepay.h58
-rwxr-xr-xgst/rtp/gstrtpmpapay.c329
-rwxr-xr-xgst/rtp/gstrtpmpapay.h63
-rwxr-xr-xgst/rtp/gstrtpmparobustdepay.c814
-rwxr-xr-xgst/rtp/gstrtpmparobustdepay.h78
-rwxr-xr-xgst/rtp/gstrtpmpvdepay.c198
-rwxr-xr-xgst/rtp/gstrtpmpvdepay.h58
-rwxr-xr-xgst/rtp/gstrtpmpvpay.c313
-rwxr-xr-xgst/rtp/gstrtpmpvpay.h64
-rwxr-xr-xgst/rtp/gstrtppcmadepay.c165
-rwxr-xr-xgst/rtp/gstrtppcmadepay.h53
-rwxr-xr-xgst/rtp/gstrtppcmapay.c116
-rwxr-xr-xgst/rtp/gstrtppcmapay.h54
-rwxr-xr-xgst/rtp/gstrtppcmudepay.c165
-rwxr-xr-xgst/rtp/gstrtppcmudepay.h53
-rwxr-xr-xgst/rtp/gstrtppcmupay.c116
-rwxr-xr-xgst/rtp/gstrtppcmupay.h54
-rwxr-xr-xgst/rtp/gstrtpqcelpdepay.c435
-rwxr-xr-xgst/rtp/gstrtpqcelpdepay.h62
-rwxr-xr-xgst/rtp/gstrtpqdmdepay.c416
-rwxr-xr-xgst/rtp/gstrtpqdmdepay.h85
-rwxr-xr-xgst/rtp/gstrtpsbcdepay.c287
-rwxr-xr-xgst/rtp/gstrtpsbcdepay.h65
-rwxr-xr-xgst/rtp/gstrtpsbcpay.c350
-rwxr-xr-xgst/rtp/gstrtpsbcpay.h64
-rwxr-xr-xgst/rtp/gstrtpsirendepay.c123
-rwxr-xr-xgst/rtp/gstrtpsirendepay.h59
-rwxr-xr-xgst/rtp/gstrtpsirenpay.c147
-rwxr-xr-xgst/rtp/gstrtpsirenpay.h57
-rwxr-xr-xgst/rtp/gstrtpspeexdepay.c225
-rwxr-xr-xgst/rtp/gstrtpspeexdepay.h53
-rwxr-xr-xgst/rtp/gstrtpspeexpay.c352
-rwxr-xr-xgst/rtp/gstrtpspeexpay.h56
-rwxr-xr-xgst/rtp/gstrtpstreamdepay.c219
-rwxr-xr-xgst/rtp/gstrtpstreamdepay.h57
-rwxr-xr-xgst/rtp/gstrtpstreampay.c287
-rwxr-xr-xgst/rtp/gstrtpstreampay.h54
-rwxr-xr-xgst/rtp/gstrtpsv3vdepay.c323
-rwxr-xr-xgst/rtp/gstrtpsv3vdepay.h67
-rwxr-xr-xgst/rtp/gstrtptheoradepay.c656
-rwxr-xr-xgst/rtp/gstrtptheoradepay.h72
-rwxr-xr-xgst/rtp/gstrtptheorapay.c947
-rwxr-xr-xgst/rtp/gstrtptheorapay.h84
-rwxr-xr-xgst/rtp/gstrtpvorbisdepay.c706
-rwxr-xr-xgst/rtp/gstrtpvorbisdepay.h70
-rwxr-xr-xgst/rtp/gstrtpvorbispay.c943
-rwxr-xr-xgst/rtp/gstrtpvorbispay.h84
-rwxr-xr-xgst/rtp/gstrtpvp8depay.c296
-rwxr-xr-xgst/rtp/gstrtpvp8depay.h69
-rwxr-xr-xgst/rtp/gstrtpvp8pay.c539
-rwxr-xr-xgst/rtp/gstrtpvp8pay.h74
-rwxr-xr-xgst/rtp/gstrtpvrawdepay.c668
-rwxr-xr-xgst/rtp/gstrtpvrawdepay.h71
-rwxr-xr-xgst/rtp/gstrtpvrawpay.c647
-rwxr-xr-xgst/rtp/gstrtpvrawpay.h67
164 files changed, 41846 insertions, 0 deletions
diff --git a/gst/rtp/Makefile.am b/gst/rtp/Makefile.am
new file mode 100755
index 0000000..441c52f
--- /dev/null
+++ b/gst/rtp/Makefile.am
@@ -0,0 +1,182 @@
+plugin_LTLIBRARIES = libgstrtp.la
+
+libgstrtp_la_SOURCES = \
+ dboolhuff.c \
+ fnv1hash.c \
+ gstrtp.c \
+ gstrtpchannels.c \
+ gstrtpac3depay.c \
+ gstrtpac3pay.c \
+ gstrtpbvdepay.c \
+ gstrtpbvpay.c \
+ gstrtpceltdepay.c \
+ gstrtpceltpay.c \
+ gstrtpdvdepay.c \
+ gstrtpdvpay.c \
+ gstrtpgstdepay.c \
+ gstrtpgstpay.c \
+ gstrtpilbcdepay.c \
+ gstrtpilbcpay.c \
+ gstrtpmpadepay.c \
+ gstrtpmpapay.c \
+ gstrtpmparobustdepay.c \
+ gstrtpmpvdepay.c \
+ gstrtpmpvpay.c \
+ gstrtppcmadepay.c \
+ gstrtppcmudepay.c \
+ gstrtppcmupay.c \
+ gstrtppcmapay.c \
+ gstrtpg722depay.c \
+ gstrtpg722pay.c \
+ gstrtpg723depay.c \
+ gstrtpg723pay.c \
+ gstrtpg726pay.c \
+ gstrtpg726depay.c \
+ gstrtpg729pay.c \
+ gstrtpg729depay.c \
+ gstrtpgsmdepay.c \
+ gstrtpgsmpay.c \
+ gstrtpamrdepay.c \
+ gstrtpamrpay.c \
+ gstrtph263pdepay.c \
+ gstrtph263ppay.c \
+ gstrtph263depay.c \
+ gstrtph263pay.c \
+ gstrtph264depay.c \
+ gstrtph264pay.c \
+ gstrtpj2kdepay.c \
+ gstrtpj2kpay.c \
+ gstrtpjpegdepay.c \
+ gstrtpjpegpay.c \
+ gstrtpL16depay.c \
+ gstrtpL16pay.c \
+ gstrtpL24depay.c \
+ gstrtpL24pay.c \
+ gstasteriskh263.c \
+ gstrtpmp1sdepay.c \
+ gstrtpmp2tdepay.c \
+ gstrtpmp2tpay.c \
+ gstrtpmp4vdepay.c \
+ gstrtpmp4vpay.c \
+ gstrtpmp4gdepay.c \
+ gstrtpmp4gpay.c \
+ gstrtpmp4adepay.c \
+ gstrtpmp4apay.c \
+ gstrtpqcelpdepay.c \
+ gstrtpqdmdepay.c \
+ gstrtpsbcdepay.c \
+ gstrtpsbcpay.c \
+ gstrtpsirenpay.c \
+ gstrtpsirendepay.c \
+ gstrtpspeexdepay.c \
+ gstrtpspeexpay.c \
+ gstrtpsv3vdepay.c \
+ gstrtptheoradepay.c \
+ gstrtptheorapay.c \
+ gstrtpvorbisdepay.c \
+ gstrtpvorbispay.c \
+ gstrtpvp8depay.c \
+ gstrtpvp8pay.c \
+ gstrtpvrawdepay.c \
+ gstrtpvrawpay.c \
+ gstrtpstreampay.c \
+ gstrtpstreamdepay.c
+
+libgstrtp_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) \
+ $(GST_CFLAGS) -Dvp8_norm=gst_rtpvp8_vp8_norm \
+ -Dvp8dx_start_decode=gst_rtpvp8_vp8dx_start_decode \
+ -Dvp8dx_bool_decoder_fill=gst_rtpvp8_vp8dx_bool_decoder_fill
+
+libgstrtp_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
+ -lgstaudio-@GST_API_VERSION@ \
+ -lgstvideo-@GST_API_VERSION@ \
+ -lgsttag-@GST_API_VERSION@ \
+ -lgstrtp-@GST_API_VERSION@ \
+ -lgstpbutils-@GST_API_VERSION@ \
+ $(GST_BASE_LIBS) $(GST_LIBS) \
+ $(LIBM)
+libgstrtp_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstrtp_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
+
+noinst_HEADERS = \
+ dboolhuff.h \
+ fnv1hash.h \
+ gstrtpchannels.h \
+ gstrtpL16depay.h \
+ gstrtpL16pay.h \
+ gstrtpL24depay.h \
+ gstrtpL24pay.h \
+ gstrtpac3depay.h \
+ gstrtpac3pay.h \
+ gstrtpbvdepay.h \
+ gstrtpbvpay.h \
+ gstrtpceltpay.h \
+ gstrtpceltdepay.h \
+ gstrtpdvdepay.h \
+ gstrtpdvpay.h \
+ gstrtpamrdepay.h \
+ gstrtpamrpay.h \
+ gstrtpgstdepay.h \
+ gstrtpgstpay.h \
+ gstrtpilbcdepay.h \
+ gstrtpilbcpay.h \
+ gstrtppcmadepay.h \
+ gstrtppcmudepay.h \
+ gstrtppcmupay.h \
+ gstrtppcmapay.h \
+ gstrtpg722depay.h \
+ gstrtpg722pay.h \
+ gstrtpg723depay.h\
+ gstrtpg723pay.h \
+ gstrtpg726depay.h \
+ gstrtpg726pay.h \
+ gstrtpg729depay.h \
+ gstrtpg729pay.h \
+ gstrtpgsmdepay.h \
+ gstrtpgsmpay.h \
+ gstrtpmpadepay.h \
+ gstrtpmparobustdepay.h \
+ gstrtpmpapay.h \
+ gstrtpmpvdepay.h \
+ gstrtpmpvpay.h \
+ gstrtph263pdepay.h \
+ gstrtph263ppay.h \
+ gstrtph263depay.h \
+ gstrtph263pay.h \
+ gstrtph264depay.h \
+ gstrtph264pay.h \
+ gstrtpj2kdepay.h \
+ gstrtpj2kpay.h \
+ gstrtpjpegdepay.h \
+ gstrtpjpegpay.h \
+ gstrtpmp1sdepay.h \
+ gstrtpmp2tdepay.h \
+ gstrtpmp2tpay.h \
+ gstrtpmp4vdepay.h \
+ gstrtpmp4vpay.h \
+ gstrtpmp4gdepay.h \
+ gstrtpmp4gpay.h \
+ gstrtpmp4adepay.h \
+ gstrtpmp4apay.h \
+ gstasteriskh263.h \
+ gstrtpqcelpdepay.h \
+ gstrtpqdmdepay.h \
+ gstrtpsbcdepay.h \
+ gstrtpsbcpay.h \
+ gstrtpsirenpay.h \
+ gstrtpsirendepay.h \
+ gstrtpspeexdepay.h \
+ gstrtpspeexpay.h \
+ gstrtpsv3vdepay.h \
+ gstrtptheoradepay.h \
+ gstrtptheorapay.h \
+ gstrtpvorbisdepay.h \
+ gstrtpvorbispay.h \
+ gstrtpvp8depay.h \
+ gstrtpvp8pay.h \
+ gstrtpvrawdepay.h \
+ gstrtpvrawpay.h \
+ gstrtpstreampay.h \
+ gstrtpstreamdepay.h
+
+EXTRA_DIST = dboolhuff.LICENSE
diff --git a/gst/rtp/Makefile.in b/gst/rtp/Makefile.in
new file mode 100755
index 0000000..a1ae6ff
--- /dev/null
+++ b/gst/rtp/Makefile.in
@@ -0,0 +1,1743 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = gst/rtp
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/depcomp $(noinst_HEADERS) README TODO
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \
+ $(top_srcdir)/common/m4/as-auto-alt.m4 \
+ $(top_srcdir)/common/m4/as-compiler-flag.m4 \
+ $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \
+ $(top_srcdir)/common/m4/as-libtool.m4 \
+ $(top_srcdir)/common/m4/as-version.m4 \
+ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \
+ $(top_srcdir)/common/m4/gst-arch.m4 \
+ $(top_srcdir)/common/m4/gst-args.m4 \
+ $(top_srcdir)/common/m4/gst-check.m4 \
+ $(top_srcdir)/common/m4/gst-default.m4 \
+ $(top_srcdir)/common/m4/gst-dowhile.m4 \
+ $(top_srcdir)/common/m4/gst-error.m4 \
+ $(top_srcdir)/common/m4/gst-feature.m4 \
+ $(top_srcdir)/common/m4/gst-gettext.m4 \
+ $(top_srcdir)/common/m4/gst-glib2.m4 \
+ $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \
+ $(top_srcdir)/common/m4/gst-platform.m4 \
+ $(top_srcdir)/common/m4/gst-plugin-docs.m4 \
+ $(top_srcdir)/common/m4/gst-plugindir.m4 \
+ $(top_srcdir)/common/m4/gst-x11.m4 \
+ $(top_srcdir)/common/m4/gst.m4 \
+ $(top_srcdir)/common/m4/gtk-doc.m4 \
+ $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \
+ $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgstrtp_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_libgstrtp_la_OBJECTS = libgstrtp_la-dboolhuff.lo \
+ libgstrtp_la-fnv1hash.lo libgstrtp_la-gstrtp.lo \
+ libgstrtp_la-gstrtpchannels.lo libgstrtp_la-gstrtpac3depay.lo \
+ libgstrtp_la-gstrtpac3pay.lo libgstrtp_la-gstrtpbvdepay.lo \
+ libgstrtp_la-gstrtpbvpay.lo libgstrtp_la-gstrtpceltdepay.lo \
+ libgstrtp_la-gstrtpceltpay.lo libgstrtp_la-gstrtpdvdepay.lo \
+ libgstrtp_la-gstrtpdvpay.lo libgstrtp_la-gstrtpgstdepay.lo \
+ libgstrtp_la-gstrtpgstpay.lo libgstrtp_la-gstrtpilbcdepay.lo \
+ libgstrtp_la-gstrtpilbcpay.lo libgstrtp_la-gstrtpmpadepay.lo \
+ libgstrtp_la-gstrtpmpapay.lo \
+ libgstrtp_la-gstrtpmparobustdepay.lo \
+ libgstrtp_la-gstrtpmpvdepay.lo libgstrtp_la-gstrtpmpvpay.lo \
+ libgstrtp_la-gstrtppcmadepay.lo \
+ libgstrtp_la-gstrtppcmudepay.lo libgstrtp_la-gstrtppcmupay.lo \
+ libgstrtp_la-gstrtppcmapay.lo libgstrtp_la-gstrtpg722depay.lo \
+ libgstrtp_la-gstrtpg722pay.lo libgstrtp_la-gstrtpg723depay.lo \
+ libgstrtp_la-gstrtpg723pay.lo libgstrtp_la-gstrtpg726pay.lo \
+ libgstrtp_la-gstrtpg726depay.lo libgstrtp_la-gstrtpg729pay.lo \
+ libgstrtp_la-gstrtpg729depay.lo libgstrtp_la-gstrtpgsmdepay.lo \
+ libgstrtp_la-gstrtpgsmpay.lo libgstrtp_la-gstrtpamrdepay.lo \
+ libgstrtp_la-gstrtpamrpay.lo libgstrtp_la-gstrtph263pdepay.lo \
+ libgstrtp_la-gstrtph263ppay.lo libgstrtp_la-gstrtph263depay.lo \
+ libgstrtp_la-gstrtph263pay.lo libgstrtp_la-gstrtph264depay.lo \
+ libgstrtp_la-gstrtph264pay.lo libgstrtp_la-gstrtpj2kdepay.lo \
+ libgstrtp_la-gstrtpj2kpay.lo libgstrtp_la-gstrtpjpegdepay.lo \
+ libgstrtp_la-gstrtpjpegpay.lo libgstrtp_la-gstrtpL16depay.lo \
+ libgstrtp_la-gstrtpL16pay.lo libgstrtp_la-gstrtpL24depay.lo \
+ libgstrtp_la-gstrtpL24pay.lo libgstrtp_la-gstasteriskh263.lo \
+ libgstrtp_la-gstrtpmp1sdepay.lo \
+ libgstrtp_la-gstrtpmp2tdepay.lo libgstrtp_la-gstrtpmp2tpay.lo \
+ libgstrtp_la-gstrtpmp4vdepay.lo libgstrtp_la-gstrtpmp4vpay.lo \
+ libgstrtp_la-gstrtpmp4gdepay.lo libgstrtp_la-gstrtpmp4gpay.lo \
+ libgstrtp_la-gstrtpmp4adepay.lo libgstrtp_la-gstrtpmp4apay.lo \
+ libgstrtp_la-gstrtpqcelpdepay.lo \
+ libgstrtp_la-gstrtpqdmdepay.lo libgstrtp_la-gstrtpsbcdepay.lo \
+ libgstrtp_la-gstrtpsbcpay.lo libgstrtp_la-gstrtpsirenpay.lo \
+ libgstrtp_la-gstrtpsirendepay.lo \
+ libgstrtp_la-gstrtpspeexdepay.lo \
+ libgstrtp_la-gstrtpspeexpay.lo libgstrtp_la-gstrtpsv3vdepay.lo \
+ libgstrtp_la-gstrtptheoradepay.lo \
+ libgstrtp_la-gstrtptheorapay.lo \
+ libgstrtp_la-gstrtpvorbisdepay.lo \
+ libgstrtp_la-gstrtpvorbispay.lo libgstrtp_la-gstrtpvp8depay.lo \
+ libgstrtp_la-gstrtpvp8pay.lo libgstrtp_la-gstrtpvrawdepay.lo \
+ libgstrtp_la-gstrtpvrawpay.lo libgstrtp_la-gstrtpstreampay.lo \
+ libgstrtp_la-gstrtpstreamdepay.lo
+libgstrtp_la_OBJECTS = $(am_libgstrtp_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libgstrtp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgstrtp_la_CFLAGS) $(CFLAGS) \
+ $(libgstrtp_la_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libgstrtp_la_SOURCES)
+DIST_SOURCES = $(libgstrtp_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AALIB_CFLAGS = @AALIB_CFLAGS@
+AALIB_CONFIG = @AALIB_CONFIG@
+AALIB_LIBS = @AALIB_LIBS@
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BZ2_LIBS = @BZ2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@
+DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@
+DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@
+DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@
+DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@
+DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@
+DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@
+DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DV1394_CFLAGS = @DV1394_CFLAGS@
+DV1394_LIBS = @DV1394_LIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ERROR_CFLAGS = @ERROR_CFLAGS@
+ERROR_CXXFLAGS = @ERROR_CXXFLAGS@
+ERROR_OBJCFLAGS = @ERROR_OBJCFLAGS@
+EXEEXT = @EXEEXT@
+FFLAGS = @FFLAGS@
+FGREP = @FGREP@
+FLAC_CFLAGS = @FLAC_CFLAGS@
+FLAC_LIBS = @FLAC_LIBS@
+GCOV = @GCOV@
+GCOV_CFLAGS = @GCOV_CFLAGS@
+GCOV_LIBS = @GCOV_LIBS@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LDFLAGS = @GIO_LDFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GLIB_PREFIX = @GLIB_PREFIX@
+GLIB_REQ = @GLIB_REQ@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@
+GSTPB_PREFIX = @GSTPB_PREFIX@
+GST_AGE = @GST_AGE@
+GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@
+GST_API_VERSION = @GST_API_VERSION@
+GST_BASE_CFLAGS = @GST_BASE_CFLAGS@
+GST_BASE_LIBS = @GST_BASE_LIBS@
+GST_CFLAGS = @GST_CFLAGS@
+GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@
+GST_CHECK_LIBS = @GST_CHECK_LIBS@
+GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@
+GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@
+GST_CURRENT = @GST_CURRENT@
+GST_CXXFLAGS = @GST_CXXFLAGS@
+GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@
+GST_LIBS = @GST_LIBS@
+GST_LIBVERSION = @GST_LIBVERSION@
+GST_LICENSE = @GST_LICENSE@
+GST_LT_LDFLAGS = @GST_LT_LDFLAGS@
+GST_NET_CFLAGS = @GST_NET_CFLAGS@
+GST_NET_LIBS = @GST_NET_LIBS@
+GST_OBJCFLAGS = @GST_OBJCFLAGS@
+GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@
+GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@
+GST_OPTION_OBJCFLAGS = @GST_OPTION_OBJCFLAGS@
+GST_PACKAGE_NAME = @GST_PACKAGE_NAME@
+GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@
+GST_PLUGINS_ALL = @GST_PLUGINS_ALL@
+GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@
+GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@
+GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@
+GST_PLUGINS_DIR = @GST_PLUGINS_DIR@
+GST_PLUGINS_NONPORTED = @GST_PLUGINS_NONPORTED@
+GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@
+GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@
+GST_PLUGIN_LIBTOOLFLAGS = @GST_PLUGIN_LIBTOOLFLAGS@
+GST_PREFIX = @GST_PREFIX@
+GST_REVISION = @GST_REVISION@
+GST_TOOLS_DIR = @GST_TOOLS_DIR@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_X11_CFLAGS = @GTK_X11_CFLAGS@
+GTK_X11_LIBS = @GTK_X11_LIBS@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HAVE_AVC1394 = @HAVE_AVC1394@
+HAVE_CXX = @HAVE_CXX@
+HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@
+HAVE_ROM1394 = @HAVE_ROM1394@
+HAVE_SPEEX = @HAVE_SPEEX@
+HAVE_X = @HAVE_X@
+HAVE_XSHM = @HAVE_XSHM@
+HAVE_ZLIB = @HAVE_ZLIB@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@
+JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@
+JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@
+JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@
+JACK_CFLAGS = @JACK_CFLAGS@
+JACK_LIBS = @JACK_LIBS@
+JPEG_LIBS = @JPEG_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCACA_CFLAGS = @LIBCACA_CFLAGS@
+LIBCACA_LIBS = @LIBCACA_LIBS@
+LIBDV_CFLAGS = @LIBDV_CFLAGS@
+LIBDV_LIBS = @LIBDV_LIBS@
+LIBICONV = @LIBICONV@
+LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@
+LIBIEC61883_LIBS = @LIBIEC61883_LIBS@
+LIBINTL = @LIBINTL@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPNG_CFLAGS = @LIBPNG_CFLAGS@
+LIBPNG_LIBS = @LIBPNG_LIBS@
+LIBRT = @LIBRT@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@
+LIBV4L2_LIBS = @LIBV4L2_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJCFLAGS = @OBJCFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCC = @ORCC@
+ORCC_FLAGS = @ORCC_FLAGS@
+ORC_CFLAGS = @ORC_CFLAGS@
+ORC_LIBS = @ORC_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
+PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@
+PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
+PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@
+PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLUGINDIR = @PLUGINDIR@
+POSUB = @POSUB@
+PROFILE_CFLAGS = @PROFILE_CFLAGS@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RAW1394_CFLAGS = @RAW1394_CFLAGS@
+RAW1394_LIBS = @RAW1394_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHOUT2_CFLAGS = @SHOUT2_CFLAGS@
+SHOUT2_LIBS = @SHOUT2_LIBS@
+SOUP_CFLAGS = @SOUP_CFLAGS@
+SOUP_LIBS = @SOUP_LIBS@
+SPEEX_CFLAGS = @SPEEX_CFLAGS@
+SPEEX_LIBS = @SPEEX_LIBS@
+STRIP = @STRIP@
+TAGLIB_CFLAGS = @TAGLIB_CFLAGS@
+TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@
+TAGLIB_LIBS = @TAGLIB_LIBS@
+USE_NLS = @USE_NLS@
+VALGRIND_CFLAGS = @VALGRIND_CFLAGS@
+VALGRIND_LIBS = @VALGRIND_LIBS@
+VALGRIND_PATH = @VALGRIND_PATH@
+VERSION = @VERSION@
+VPX_130_CFLAGS = @VPX_130_CFLAGS@
+VPX_130_LIBS = @VPX_130_LIBS@
+VPX_CFLAGS = @VPX_CFLAGS@
+VPX_LIBS = @VPX_LIBS@
+WARNING_CFLAGS = @WARNING_CFLAGS@
+WARNING_CXXFLAGS = @WARNING_CXXFLAGS@
+WARNING_OBJCFLAGS = @WARNING_OBJCFLAGS@
+WAVPACK_CFLAGS = @WAVPACK_CFLAGS@
+WAVPACK_LIBS = @WAVPACK_LIBS@
+XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@
+XDAMAGE_LIBS = @XDAMAGE_LIBS@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+XMKMF = @XMKMF@
+XSHM_LIBS = @XSHM_LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugin_LTLIBRARIES = libgstrtp.la
+libgstrtp_la_SOURCES = \
+ dboolhuff.c \
+ fnv1hash.c \
+ gstrtp.c \
+ gstrtpchannels.c \
+ gstrtpac3depay.c \
+ gstrtpac3pay.c \
+ gstrtpbvdepay.c \
+ gstrtpbvpay.c \
+ gstrtpceltdepay.c \
+ gstrtpceltpay.c \
+ gstrtpdvdepay.c \
+ gstrtpdvpay.c \
+ gstrtpgstdepay.c \
+ gstrtpgstpay.c \
+ gstrtpilbcdepay.c \
+ gstrtpilbcpay.c \
+ gstrtpmpadepay.c \
+ gstrtpmpapay.c \
+ gstrtpmparobustdepay.c \
+ gstrtpmpvdepay.c \
+ gstrtpmpvpay.c \
+ gstrtppcmadepay.c \
+ gstrtppcmudepay.c \
+ gstrtppcmupay.c \
+ gstrtppcmapay.c \
+ gstrtpg722depay.c \
+ gstrtpg722pay.c \
+ gstrtpg723depay.c \
+ gstrtpg723pay.c \
+ gstrtpg726pay.c \
+ gstrtpg726depay.c \
+ gstrtpg729pay.c \
+ gstrtpg729depay.c \
+ gstrtpgsmdepay.c \
+ gstrtpgsmpay.c \
+ gstrtpamrdepay.c \
+ gstrtpamrpay.c \
+ gstrtph263pdepay.c \
+ gstrtph263ppay.c \
+ gstrtph263depay.c \
+ gstrtph263pay.c \
+ gstrtph264depay.c \
+ gstrtph264pay.c \
+ gstrtpj2kdepay.c \
+ gstrtpj2kpay.c \
+ gstrtpjpegdepay.c \
+ gstrtpjpegpay.c \
+ gstrtpL16depay.c \
+ gstrtpL16pay.c \
+ gstrtpL24depay.c \
+ gstrtpL24pay.c \
+ gstasteriskh263.c \
+ gstrtpmp1sdepay.c \
+ gstrtpmp2tdepay.c \
+ gstrtpmp2tpay.c \
+ gstrtpmp4vdepay.c \
+ gstrtpmp4vpay.c \
+ gstrtpmp4gdepay.c \
+ gstrtpmp4gpay.c \
+ gstrtpmp4adepay.c \
+ gstrtpmp4apay.c \
+ gstrtpqcelpdepay.c \
+ gstrtpqdmdepay.c \
+ gstrtpsbcdepay.c \
+ gstrtpsbcpay.c \
+ gstrtpsirenpay.c \
+ gstrtpsirendepay.c \
+ gstrtpspeexdepay.c \
+ gstrtpspeexpay.c \
+ gstrtpsv3vdepay.c \
+ gstrtptheoradepay.c \
+ gstrtptheorapay.c \
+ gstrtpvorbisdepay.c \
+ gstrtpvorbispay.c \
+ gstrtpvp8depay.c \
+ gstrtpvp8pay.c \
+ gstrtpvrawdepay.c \
+ gstrtpvrawpay.c \
+ gstrtpstreampay.c \
+ gstrtpstreamdepay.c
+
+libgstrtp_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) \
+ $(GST_CFLAGS) -Dvp8_norm=gst_rtpvp8_vp8_norm \
+ -Dvp8dx_start_decode=gst_rtpvp8_vp8dx_start_decode \
+ -Dvp8dx_bool_decoder_fill=gst_rtpvp8_vp8dx_bool_decoder_fill
+
+libgstrtp_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
+ -lgstaudio-@GST_API_VERSION@ \
+ -lgstvideo-@GST_API_VERSION@ \
+ -lgsttag-@GST_API_VERSION@ \
+ -lgstrtp-@GST_API_VERSION@ \
+ -lgstpbutils-@GST_API_VERSION@ \
+ $(GST_BASE_LIBS) $(GST_LIBS) \
+ $(LIBM)
+
+libgstrtp_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstrtp_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
+noinst_HEADERS = \
+ dboolhuff.h \
+ fnv1hash.h \
+ gstrtpchannels.h \
+ gstrtpL16depay.h \
+ gstrtpL16pay.h \
+ gstrtpL24depay.h \
+ gstrtpL24pay.h \
+ gstrtpac3depay.h \
+ gstrtpac3pay.h \
+ gstrtpbvdepay.h \
+ gstrtpbvpay.h \
+ gstrtpceltpay.h \
+ gstrtpceltdepay.h \
+ gstrtpdvdepay.h \
+ gstrtpdvpay.h \
+ gstrtpamrdepay.h \
+ gstrtpamrpay.h \
+ gstrtpgstdepay.h \
+ gstrtpgstpay.h \
+ gstrtpilbcdepay.h \
+ gstrtpilbcpay.h \
+ gstrtppcmadepay.h \
+ gstrtppcmudepay.h \
+ gstrtppcmupay.h \
+ gstrtppcmapay.h \
+ gstrtpg722depay.h \
+ gstrtpg722pay.h \
+ gstrtpg723depay.h\
+ gstrtpg723pay.h \
+ gstrtpg726depay.h \
+ gstrtpg726pay.h \
+ gstrtpg729depay.h \
+ gstrtpg729pay.h \
+ gstrtpgsmdepay.h \
+ gstrtpgsmpay.h \
+ gstrtpmpadepay.h \
+ gstrtpmparobustdepay.h \
+ gstrtpmpapay.h \
+ gstrtpmpvdepay.h \
+ gstrtpmpvpay.h \
+ gstrtph263pdepay.h \
+ gstrtph263ppay.h \
+ gstrtph263depay.h \
+ gstrtph263pay.h \
+ gstrtph264depay.h \
+ gstrtph264pay.h \
+ gstrtpj2kdepay.h \
+ gstrtpj2kpay.h \
+ gstrtpjpegdepay.h \
+ gstrtpjpegpay.h \
+ gstrtpmp1sdepay.h \
+ gstrtpmp2tdepay.h \
+ gstrtpmp2tpay.h \
+ gstrtpmp4vdepay.h \
+ gstrtpmp4vpay.h \
+ gstrtpmp4gdepay.h \
+ gstrtpmp4gpay.h \
+ gstrtpmp4adepay.h \
+ gstrtpmp4apay.h \
+ gstasteriskh263.h \
+ gstrtpqcelpdepay.h \
+ gstrtpqdmdepay.h \
+ gstrtpsbcdepay.h \
+ gstrtpsbcpay.h \
+ gstrtpsirenpay.h \
+ gstrtpsirendepay.h \
+ gstrtpspeexdepay.h \
+ gstrtpspeexpay.h \
+ gstrtpsv3vdepay.h \
+ gstrtptheoradepay.h \
+ gstrtptheorapay.h \
+ gstrtpvorbisdepay.h \
+ gstrtpvorbispay.h \
+ gstrtpvp8depay.h \
+ gstrtpvp8pay.h \
+ gstrtpvrawdepay.h \
+ gstrtpvrawpay.h \
+ gstrtpstreampay.h \
+ gstrtpstreamdepay.h
+
+EXTRA_DIST = dboolhuff.LICENSE
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu gst/rtp/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu gst/rtp/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(plugindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(plugindir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libgstrtp.la: $(libgstrtp_la_OBJECTS) $(libgstrtp_la_DEPENDENCIES) $(EXTRA_libgstrtp_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgstrtp_la_LINK) -rpath $(plugindir) $(libgstrtp_la_OBJECTS) $(libgstrtp_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-dboolhuff.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-fnv1hash.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstasteriskh263.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpL16depay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpL16pay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpL24depay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpL24pay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpac3depay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpac3pay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpamrdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpamrpay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpbvdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpbvpay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpceltdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpceltpay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpchannels.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpdvdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpdvpay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpg722depay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpg722pay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpg723depay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpg723pay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpg726depay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpg726pay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpg729depay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpg729pay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpgsmdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpgsmpay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpgstdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpgstpay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtph263depay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtph263pay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtph263pdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtph263ppay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtph264depay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtph264pay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpilbcdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpilbcpay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpj2kdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpj2kpay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpjpegdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpjpegpay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpmp1sdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpmp2tdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpmp2tpay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpmp4adepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpmp4apay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpmp4gdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpmp4gpay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpmp4vdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpmp4vpay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpmpadepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpmpapay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpmparobustdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpmpvdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpmpvpay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtppcmadepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtppcmapay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtppcmudepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtppcmupay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpqcelpdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpqdmdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpsbcdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpsbcpay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpsirendepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpsirenpay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpspeexdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpspeexpay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpstreamdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpstreampay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpsv3vdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtptheoradepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtptheorapay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpvorbisdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpvorbispay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpvp8depay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpvp8pay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpvrawdepay.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstrtp_la-gstrtpvrawpay.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgstrtp_la-dboolhuff.lo: dboolhuff.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-dboolhuff.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-dboolhuff.Tpo -c -o libgstrtp_la-dboolhuff.lo `test -f 'dboolhuff.c' || echo '$(srcdir)/'`dboolhuff.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-dboolhuff.Tpo $(DEPDIR)/libgstrtp_la-dboolhuff.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dboolhuff.c' object='libgstrtp_la-dboolhuff.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-dboolhuff.lo `test -f 'dboolhuff.c' || echo '$(srcdir)/'`dboolhuff.c
+
+libgstrtp_la-fnv1hash.lo: fnv1hash.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-fnv1hash.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-fnv1hash.Tpo -c -o libgstrtp_la-fnv1hash.lo `test -f 'fnv1hash.c' || echo '$(srcdir)/'`fnv1hash.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-fnv1hash.Tpo $(DEPDIR)/libgstrtp_la-fnv1hash.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fnv1hash.c' object='libgstrtp_la-fnv1hash.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-fnv1hash.lo `test -f 'fnv1hash.c' || echo '$(srcdir)/'`fnv1hash.c
+
+libgstrtp_la-gstrtp.lo: gstrtp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtp.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtp.Tpo -c -o libgstrtp_la-gstrtp.lo `test -f 'gstrtp.c' || echo '$(srcdir)/'`gstrtp.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtp.Tpo $(DEPDIR)/libgstrtp_la-gstrtp.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtp.c' object='libgstrtp_la-gstrtp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtp.lo `test -f 'gstrtp.c' || echo '$(srcdir)/'`gstrtp.c
+
+libgstrtp_la-gstrtpchannels.lo: gstrtpchannels.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpchannels.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpchannels.Tpo -c -o libgstrtp_la-gstrtpchannels.lo `test -f 'gstrtpchannels.c' || echo '$(srcdir)/'`gstrtpchannels.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpchannels.Tpo $(DEPDIR)/libgstrtp_la-gstrtpchannels.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpchannels.c' object='libgstrtp_la-gstrtpchannels.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpchannels.lo `test -f 'gstrtpchannels.c' || echo '$(srcdir)/'`gstrtpchannels.c
+
+libgstrtp_la-gstrtpac3depay.lo: gstrtpac3depay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpac3depay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpac3depay.Tpo -c -o libgstrtp_la-gstrtpac3depay.lo `test -f 'gstrtpac3depay.c' || echo '$(srcdir)/'`gstrtpac3depay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpac3depay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpac3depay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpac3depay.c' object='libgstrtp_la-gstrtpac3depay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpac3depay.lo `test -f 'gstrtpac3depay.c' || echo '$(srcdir)/'`gstrtpac3depay.c
+
+libgstrtp_la-gstrtpac3pay.lo: gstrtpac3pay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpac3pay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpac3pay.Tpo -c -o libgstrtp_la-gstrtpac3pay.lo `test -f 'gstrtpac3pay.c' || echo '$(srcdir)/'`gstrtpac3pay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpac3pay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpac3pay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpac3pay.c' object='libgstrtp_la-gstrtpac3pay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpac3pay.lo `test -f 'gstrtpac3pay.c' || echo '$(srcdir)/'`gstrtpac3pay.c
+
+libgstrtp_la-gstrtpbvdepay.lo: gstrtpbvdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpbvdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpbvdepay.Tpo -c -o libgstrtp_la-gstrtpbvdepay.lo `test -f 'gstrtpbvdepay.c' || echo '$(srcdir)/'`gstrtpbvdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpbvdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpbvdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpbvdepay.c' object='libgstrtp_la-gstrtpbvdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpbvdepay.lo `test -f 'gstrtpbvdepay.c' || echo '$(srcdir)/'`gstrtpbvdepay.c
+
+libgstrtp_la-gstrtpbvpay.lo: gstrtpbvpay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpbvpay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpbvpay.Tpo -c -o libgstrtp_la-gstrtpbvpay.lo `test -f 'gstrtpbvpay.c' || echo '$(srcdir)/'`gstrtpbvpay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpbvpay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpbvpay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpbvpay.c' object='libgstrtp_la-gstrtpbvpay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpbvpay.lo `test -f 'gstrtpbvpay.c' || echo '$(srcdir)/'`gstrtpbvpay.c
+
+libgstrtp_la-gstrtpceltdepay.lo: gstrtpceltdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpceltdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpceltdepay.Tpo -c -o libgstrtp_la-gstrtpceltdepay.lo `test -f 'gstrtpceltdepay.c' || echo '$(srcdir)/'`gstrtpceltdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpceltdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpceltdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpceltdepay.c' object='libgstrtp_la-gstrtpceltdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpceltdepay.lo `test -f 'gstrtpceltdepay.c' || echo '$(srcdir)/'`gstrtpceltdepay.c
+
+libgstrtp_la-gstrtpceltpay.lo: gstrtpceltpay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpceltpay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpceltpay.Tpo -c -o libgstrtp_la-gstrtpceltpay.lo `test -f 'gstrtpceltpay.c' || echo '$(srcdir)/'`gstrtpceltpay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpceltpay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpceltpay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpceltpay.c' object='libgstrtp_la-gstrtpceltpay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpceltpay.lo `test -f 'gstrtpceltpay.c' || echo '$(srcdir)/'`gstrtpceltpay.c
+
+libgstrtp_la-gstrtpdvdepay.lo: gstrtpdvdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpdvdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpdvdepay.Tpo -c -o libgstrtp_la-gstrtpdvdepay.lo `test -f 'gstrtpdvdepay.c' || echo '$(srcdir)/'`gstrtpdvdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpdvdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpdvdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpdvdepay.c' object='libgstrtp_la-gstrtpdvdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpdvdepay.lo `test -f 'gstrtpdvdepay.c' || echo '$(srcdir)/'`gstrtpdvdepay.c
+
+libgstrtp_la-gstrtpdvpay.lo: gstrtpdvpay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpdvpay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpdvpay.Tpo -c -o libgstrtp_la-gstrtpdvpay.lo `test -f 'gstrtpdvpay.c' || echo '$(srcdir)/'`gstrtpdvpay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpdvpay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpdvpay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpdvpay.c' object='libgstrtp_la-gstrtpdvpay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpdvpay.lo `test -f 'gstrtpdvpay.c' || echo '$(srcdir)/'`gstrtpdvpay.c
+
+libgstrtp_la-gstrtpgstdepay.lo: gstrtpgstdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpgstdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpgstdepay.Tpo -c -o libgstrtp_la-gstrtpgstdepay.lo `test -f 'gstrtpgstdepay.c' || echo '$(srcdir)/'`gstrtpgstdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpgstdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpgstdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpgstdepay.c' object='libgstrtp_la-gstrtpgstdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpgstdepay.lo `test -f 'gstrtpgstdepay.c' || echo '$(srcdir)/'`gstrtpgstdepay.c
+
+libgstrtp_la-gstrtpgstpay.lo: gstrtpgstpay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpgstpay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpgstpay.Tpo -c -o libgstrtp_la-gstrtpgstpay.lo `test -f 'gstrtpgstpay.c' || echo '$(srcdir)/'`gstrtpgstpay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpgstpay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpgstpay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpgstpay.c' object='libgstrtp_la-gstrtpgstpay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpgstpay.lo `test -f 'gstrtpgstpay.c' || echo '$(srcdir)/'`gstrtpgstpay.c
+
+libgstrtp_la-gstrtpilbcdepay.lo: gstrtpilbcdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpilbcdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpilbcdepay.Tpo -c -o libgstrtp_la-gstrtpilbcdepay.lo `test -f 'gstrtpilbcdepay.c' || echo '$(srcdir)/'`gstrtpilbcdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpilbcdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpilbcdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpilbcdepay.c' object='libgstrtp_la-gstrtpilbcdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpilbcdepay.lo `test -f 'gstrtpilbcdepay.c' || echo '$(srcdir)/'`gstrtpilbcdepay.c
+
+libgstrtp_la-gstrtpilbcpay.lo: gstrtpilbcpay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpilbcpay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpilbcpay.Tpo -c -o libgstrtp_la-gstrtpilbcpay.lo `test -f 'gstrtpilbcpay.c' || echo '$(srcdir)/'`gstrtpilbcpay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpilbcpay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpilbcpay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpilbcpay.c' object='libgstrtp_la-gstrtpilbcpay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpilbcpay.lo `test -f 'gstrtpilbcpay.c' || echo '$(srcdir)/'`gstrtpilbcpay.c
+
+libgstrtp_la-gstrtpmpadepay.lo: gstrtpmpadepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpmpadepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpmpadepay.Tpo -c -o libgstrtp_la-gstrtpmpadepay.lo `test -f 'gstrtpmpadepay.c' || echo '$(srcdir)/'`gstrtpmpadepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpmpadepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpmpadepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpmpadepay.c' object='libgstrtp_la-gstrtpmpadepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpmpadepay.lo `test -f 'gstrtpmpadepay.c' || echo '$(srcdir)/'`gstrtpmpadepay.c
+
+libgstrtp_la-gstrtpmpapay.lo: gstrtpmpapay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpmpapay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpmpapay.Tpo -c -o libgstrtp_la-gstrtpmpapay.lo `test -f 'gstrtpmpapay.c' || echo '$(srcdir)/'`gstrtpmpapay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpmpapay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpmpapay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpmpapay.c' object='libgstrtp_la-gstrtpmpapay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpmpapay.lo `test -f 'gstrtpmpapay.c' || echo '$(srcdir)/'`gstrtpmpapay.c
+
+libgstrtp_la-gstrtpmparobustdepay.lo: gstrtpmparobustdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpmparobustdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpmparobustdepay.Tpo -c -o libgstrtp_la-gstrtpmparobustdepay.lo `test -f 'gstrtpmparobustdepay.c' || echo '$(srcdir)/'`gstrtpmparobustdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpmparobustdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpmparobustdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpmparobustdepay.c' object='libgstrtp_la-gstrtpmparobustdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpmparobustdepay.lo `test -f 'gstrtpmparobustdepay.c' || echo '$(srcdir)/'`gstrtpmparobustdepay.c
+
+libgstrtp_la-gstrtpmpvdepay.lo: gstrtpmpvdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpmpvdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpmpvdepay.Tpo -c -o libgstrtp_la-gstrtpmpvdepay.lo `test -f 'gstrtpmpvdepay.c' || echo '$(srcdir)/'`gstrtpmpvdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpmpvdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpmpvdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpmpvdepay.c' object='libgstrtp_la-gstrtpmpvdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpmpvdepay.lo `test -f 'gstrtpmpvdepay.c' || echo '$(srcdir)/'`gstrtpmpvdepay.c
+
+libgstrtp_la-gstrtpmpvpay.lo: gstrtpmpvpay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpmpvpay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpmpvpay.Tpo -c -o libgstrtp_la-gstrtpmpvpay.lo `test -f 'gstrtpmpvpay.c' || echo '$(srcdir)/'`gstrtpmpvpay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpmpvpay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpmpvpay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpmpvpay.c' object='libgstrtp_la-gstrtpmpvpay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpmpvpay.lo `test -f 'gstrtpmpvpay.c' || echo '$(srcdir)/'`gstrtpmpvpay.c
+
+libgstrtp_la-gstrtppcmadepay.lo: gstrtppcmadepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtppcmadepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtppcmadepay.Tpo -c -o libgstrtp_la-gstrtppcmadepay.lo `test -f 'gstrtppcmadepay.c' || echo '$(srcdir)/'`gstrtppcmadepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtppcmadepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtppcmadepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtppcmadepay.c' object='libgstrtp_la-gstrtppcmadepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtppcmadepay.lo `test -f 'gstrtppcmadepay.c' || echo '$(srcdir)/'`gstrtppcmadepay.c
+
+libgstrtp_la-gstrtppcmudepay.lo: gstrtppcmudepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtppcmudepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtppcmudepay.Tpo -c -o libgstrtp_la-gstrtppcmudepay.lo `test -f 'gstrtppcmudepay.c' || echo '$(srcdir)/'`gstrtppcmudepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtppcmudepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtppcmudepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtppcmudepay.c' object='libgstrtp_la-gstrtppcmudepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtppcmudepay.lo `test -f 'gstrtppcmudepay.c' || echo '$(srcdir)/'`gstrtppcmudepay.c
+
+libgstrtp_la-gstrtppcmupay.lo: gstrtppcmupay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtppcmupay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtppcmupay.Tpo -c -o libgstrtp_la-gstrtppcmupay.lo `test -f 'gstrtppcmupay.c' || echo '$(srcdir)/'`gstrtppcmupay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtppcmupay.Tpo $(DEPDIR)/libgstrtp_la-gstrtppcmupay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtppcmupay.c' object='libgstrtp_la-gstrtppcmupay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtppcmupay.lo `test -f 'gstrtppcmupay.c' || echo '$(srcdir)/'`gstrtppcmupay.c
+
+libgstrtp_la-gstrtppcmapay.lo: gstrtppcmapay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtppcmapay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtppcmapay.Tpo -c -o libgstrtp_la-gstrtppcmapay.lo `test -f 'gstrtppcmapay.c' || echo '$(srcdir)/'`gstrtppcmapay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtppcmapay.Tpo $(DEPDIR)/libgstrtp_la-gstrtppcmapay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtppcmapay.c' object='libgstrtp_la-gstrtppcmapay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtppcmapay.lo `test -f 'gstrtppcmapay.c' || echo '$(srcdir)/'`gstrtppcmapay.c
+
+libgstrtp_la-gstrtpg722depay.lo: gstrtpg722depay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpg722depay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpg722depay.Tpo -c -o libgstrtp_la-gstrtpg722depay.lo `test -f 'gstrtpg722depay.c' || echo '$(srcdir)/'`gstrtpg722depay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpg722depay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpg722depay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpg722depay.c' object='libgstrtp_la-gstrtpg722depay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpg722depay.lo `test -f 'gstrtpg722depay.c' || echo '$(srcdir)/'`gstrtpg722depay.c
+
+libgstrtp_la-gstrtpg722pay.lo: gstrtpg722pay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpg722pay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpg722pay.Tpo -c -o libgstrtp_la-gstrtpg722pay.lo `test -f 'gstrtpg722pay.c' || echo '$(srcdir)/'`gstrtpg722pay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpg722pay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpg722pay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpg722pay.c' object='libgstrtp_la-gstrtpg722pay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpg722pay.lo `test -f 'gstrtpg722pay.c' || echo '$(srcdir)/'`gstrtpg722pay.c
+
+libgstrtp_la-gstrtpg723depay.lo: gstrtpg723depay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpg723depay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpg723depay.Tpo -c -o libgstrtp_la-gstrtpg723depay.lo `test -f 'gstrtpg723depay.c' || echo '$(srcdir)/'`gstrtpg723depay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpg723depay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpg723depay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpg723depay.c' object='libgstrtp_la-gstrtpg723depay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpg723depay.lo `test -f 'gstrtpg723depay.c' || echo '$(srcdir)/'`gstrtpg723depay.c
+
+libgstrtp_la-gstrtpg723pay.lo: gstrtpg723pay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpg723pay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpg723pay.Tpo -c -o libgstrtp_la-gstrtpg723pay.lo `test -f 'gstrtpg723pay.c' || echo '$(srcdir)/'`gstrtpg723pay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpg723pay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpg723pay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpg723pay.c' object='libgstrtp_la-gstrtpg723pay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpg723pay.lo `test -f 'gstrtpg723pay.c' || echo '$(srcdir)/'`gstrtpg723pay.c
+
+libgstrtp_la-gstrtpg726pay.lo: gstrtpg726pay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpg726pay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpg726pay.Tpo -c -o libgstrtp_la-gstrtpg726pay.lo `test -f 'gstrtpg726pay.c' || echo '$(srcdir)/'`gstrtpg726pay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpg726pay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpg726pay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpg726pay.c' object='libgstrtp_la-gstrtpg726pay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpg726pay.lo `test -f 'gstrtpg726pay.c' || echo '$(srcdir)/'`gstrtpg726pay.c
+
+libgstrtp_la-gstrtpg726depay.lo: gstrtpg726depay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpg726depay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpg726depay.Tpo -c -o libgstrtp_la-gstrtpg726depay.lo `test -f 'gstrtpg726depay.c' || echo '$(srcdir)/'`gstrtpg726depay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpg726depay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpg726depay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpg726depay.c' object='libgstrtp_la-gstrtpg726depay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpg726depay.lo `test -f 'gstrtpg726depay.c' || echo '$(srcdir)/'`gstrtpg726depay.c
+
+libgstrtp_la-gstrtpg729pay.lo: gstrtpg729pay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpg729pay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpg729pay.Tpo -c -o libgstrtp_la-gstrtpg729pay.lo `test -f 'gstrtpg729pay.c' || echo '$(srcdir)/'`gstrtpg729pay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpg729pay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpg729pay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpg729pay.c' object='libgstrtp_la-gstrtpg729pay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpg729pay.lo `test -f 'gstrtpg729pay.c' || echo '$(srcdir)/'`gstrtpg729pay.c
+
+libgstrtp_la-gstrtpg729depay.lo: gstrtpg729depay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpg729depay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpg729depay.Tpo -c -o libgstrtp_la-gstrtpg729depay.lo `test -f 'gstrtpg729depay.c' || echo '$(srcdir)/'`gstrtpg729depay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpg729depay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpg729depay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpg729depay.c' object='libgstrtp_la-gstrtpg729depay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpg729depay.lo `test -f 'gstrtpg729depay.c' || echo '$(srcdir)/'`gstrtpg729depay.c
+
+libgstrtp_la-gstrtpgsmdepay.lo: gstrtpgsmdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpgsmdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpgsmdepay.Tpo -c -o libgstrtp_la-gstrtpgsmdepay.lo `test -f 'gstrtpgsmdepay.c' || echo '$(srcdir)/'`gstrtpgsmdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpgsmdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpgsmdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpgsmdepay.c' object='libgstrtp_la-gstrtpgsmdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpgsmdepay.lo `test -f 'gstrtpgsmdepay.c' || echo '$(srcdir)/'`gstrtpgsmdepay.c
+
+libgstrtp_la-gstrtpgsmpay.lo: gstrtpgsmpay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpgsmpay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpgsmpay.Tpo -c -o libgstrtp_la-gstrtpgsmpay.lo `test -f 'gstrtpgsmpay.c' || echo '$(srcdir)/'`gstrtpgsmpay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpgsmpay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpgsmpay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpgsmpay.c' object='libgstrtp_la-gstrtpgsmpay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpgsmpay.lo `test -f 'gstrtpgsmpay.c' || echo '$(srcdir)/'`gstrtpgsmpay.c
+
+libgstrtp_la-gstrtpamrdepay.lo: gstrtpamrdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpamrdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpamrdepay.Tpo -c -o libgstrtp_la-gstrtpamrdepay.lo `test -f 'gstrtpamrdepay.c' || echo '$(srcdir)/'`gstrtpamrdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpamrdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpamrdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpamrdepay.c' object='libgstrtp_la-gstrtpamrdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpamrdepay.lo `test -f 'gstrtpamrdepay.c' || echo '$(srcdir)/'`gstrtpamrdepay.c
+
+libgstrtp_la-gstrtpamrpay.lo: gstrtpamrpay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpamrpay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpamrpay.Tpo -c -o libgstrtp_la-gstrtpamrpay.lo `test -f 'gstrtpamrpay.c' || echo '$(srcdir)/'`gstrtpamrpay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpamrpay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpamrpay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpamrpay.c' object='libgstrtp_la-gstrtpamrpay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpamrpay.lo `test -f 'gstrtpamrpay.c' || echo '$(srcdir)/'`gstrtpamrpay.c
+
+libgstrtp_la-gstrtph263pdepay.lo: gstrtph263pdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtph263pdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtph263pdepay.Tpo -c -o libgstrtp_la-gstrtph263pdepay.lo `test -f 'gstrtph263pdepay.c' || echo '$(srcdir)/'`gstrtph263pdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtph263pdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtph263pdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtph263pdepay.c' object='libgstrtp_la-gstrtph263pdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtph263pdepay.lo `test -f 'gstrtph263pdepay.c' || echo '$(srcdir)/'`gstrtph263pdepay.c
+
+libgstrtp_la-gstrtph263ppay.lo: gstrtph263ppay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtph263ppay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtph263ppay.Tpo -c -o libgstrtp_la-gstrtph263ppay.lo `test -f 'gstrtph263ppay.c' || echo '$(srcdir)/'`gstrtph263ppay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtph263ppay.Tpo $(DEPDIR)/libgstrtp_la-gstrtph263ppay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtph263ppay.c' object='libgstrtp_la-gstrtph263ppay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtph263ppay.lo `test -f 'gstrtph263ppay.c' || echo '$(srcdir)/'`gstrtph263ppay.c
+
+libgstrtp_la-gstrtph263depay.lo: gstrtph263depay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtph263depay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtph263depay.Tpo -c -o libgstrtp_la-gstrtph263depay.lo `test -f 'gstrtph263depay.c' || echo '$(srcdir)/'`gstrtph263depay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtph263depay.Tpo $(DEPDIR)/libgstrtp_la-gstrtph263depay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtph263depay.c' object='libgstrtp_la-gstrtph263depay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtph263depay.lo `test -f 'gstrtph263depay.c' || echo '$(srcdir)/'`gstrtph263depay.c
+
+libgstrtp_la-gstrtph263pay.lo: gstrtph263pay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtph263pay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtph263pay.Tpo -c -o libgstrtp_la-gstrtph263pay.lo `test -f 'gstrtph263pay.c' || echo '$(srcdir)/'`gstrtph263pay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtph263pay.Tpo $(DEPDIR)/libgstrtp_la-gstrtph263pay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtph263pay.c' object='libgstrtp_la-gstrtph263pay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtph263pay.lo `test -f 'gstrtph263pay.c' || echo '$(srcdir)/'`gstrtph263pay.c
+
+libgstrtp_la-gstrtph264depay.lo: gstrtph264depay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtph264depay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtph264depay.Tpo -c -o libgstrtp_la-gstrtph264depay.lo `test -f 'gstrtph264depay.c' || echo '$(srcdir)/'`gstrtph264depay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtph264depay.Tpo $(DEPDIR)/libgstrtp_la-gstrtph264depay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtph264depay.c' object='libgstrtp_la-gstrtph264depay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtph264depay.lo `test -f 'gstrtph264depay.c' || echo '$(srcdir)/'`gstrtph264depay.c
+
+libgstrtp_la-gstrtph264pay.lo: gstrtph264pay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtph264pay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtph264pay.Tpo -c -o libgstrtp_la-gstrtph264pay.lo `test -f 'gstrtph264pay.c' || echo '$(srcdir)/'`gstrtph264pay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtph264pay.Tpo $(DEPDIR)/libgstrtp_la-gstrtph264pay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtph264pay.c' object='libgstrtp_la-gstrtph264pay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtph264pay.lo `test -f 'gstrtph264pay.c' || echo '$(srcdir)/'`gstrtph264pay.c
+
+libgstrtp_la-gstrtpj2kdepay.lo: gstrtpj2kdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpj2kdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpj2kdepay.Tpo -c -o libgstrtp_la-gstrtpj2kdepay.lo `test -f 'gstrtpj2kdepay.c' || echo '$(srcdir)/'`gstrtpj2kdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpj2kdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpj2kdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpj2kdepay.c' object='libgstrtp_la-gstrtpj2kdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpj2kdepay.lo `test -f 'gstrtpj2kdepay.c' || echo '$(srcdir)/'`gstrtpj2kdepay.c
+
+libgstrtp_la-gstrtpj2kpay.lo: gstrtpj2kpay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpj2kpay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpj2kpay.Tpo -c -o libgstrtp_la-gstrtpj2kpay.lo `test -f 'gstrtpj2kpay.c' || echo '$(srcdir)/'`gstrtpj2kpay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpj2kpay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpj2kpay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpj2kpay.c' object='libgstrtp_la-gstrtpj2kpay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpj2kpay.lo `test -f 'gstrtpj2kpay.c' || echo '$(srcdir)/'`gstrtpj2kpay.c
+
+libgstrtp_la-gstrtpjpegdepay.lo: gstrtpjpegdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpjpegdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpjpegdepay.Tpo -c -o libgstrtp_la-gstrtpjpegdepay.lo `test -f 'gstrtpjpegdepay.c' || echo '$(srcdir)/'`gstrtpjpegdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpjpegdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpjpegdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpjpegdepay.c' object='libgstrtp_la-gstrtpjpegdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpjpegdepay.lo `test -f 'gstrtpjpegdepay.c' || echo '$(srcdir)/'`gstrtpjpegdepay.c
+
+libgstrtp_la-gstrtpjpegpay.lo: gstrtpjpegpay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpjpegpay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpjpegpay.Tpo -c -o libgstrtp_la-gstrtpjpegpay.lo `test -f 'gstrtpjpegpay.c' || echo '$(srcdir)/'`gstrtpjpegpay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpjpegpay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpjpegpay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpjpegpay.c' object='libgstrtp_la-gstrtpjpegpay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpjpegpay.lo `test -f 'gstrtpjpegpay.c' || echo '$(srcdir)/'`gstrtpjpegpay.c
+
+libgstrtp_la-gstrtpL16depay.lo: gstrtpL16depay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpL16depay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpL16depay.Tpo -c -o libgstrtp_la-gstrtpL16depay.lo `test -f 'gstrtpL16depay.c' || echo '$(srcdir)/'`gstrtpL16depay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpL16depay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpL16depay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpL16depay.c' object='libgstrtp_la-gstrtpL16depay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpL16depay.lo `test -f 'gstrtpL16depay.c' || echo '$(srcdir)/'`gstrtpL16depay.c
+
+libgstrtp_la-gstrtpL16pay.lo: gstrtpL16pay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpL16pay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpL16pay.Tpo -c -o libgstrtp_la-gstrtpL16pay.lo `test -f 'gstrtpL16pay.c' || echo '$(srcdir)/'`gstrtpL16pay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpL16pay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpL16pay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpL16pay.c' object='libgstrtp_la-gstrtpL16pay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpL16pay.lo `test -f 'gstrtpL16pay.c' || echo '$(srcdir)/'`gstrtpL16pay.c
+
+libgstrtp_la-gstrtpL24depay.lo: gstrtpL24depay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpL24depay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpL24depay.Tpo -c -o libgstrtp_la-gstrtpL24depay.lo `test -f 'gstrtpL24depay.c' || echo '$(srcdir)/'`gstrtpL24depay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpL24depay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpL24depay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpL24depay.c' object='libgstrtp_la-gstrtpL24depay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpL24depay.lo `test -f 'gstrtpL24depay.c' || echo '$(srcdir)/'`gstrtpL24depay.c
+
+libgstrtp_la-gstrtpL24pay.lo: gstrtpL24pay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpL24pay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpL24pay.Tpo -c -o libgstrtp_la-gstrtpL24pay.lo `test -f 'gstrtpL24pay.c' || echo '$(srcdir)/'`gstrtpL24pay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpL24pay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpL24pay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpL24pay.c' object='libgstrtp_la-gstrtpL24pay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpL24pay.lo `test -f 'gstrtpL24pay.c' || echo '$(srcdir)/'`gstrtpL24pay.c
+
+libgstrtp_la-gstasteriskh263.lo: gstasteriskh263.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstasteriskh263.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstasteriskh263.Tpo -c -o libgstrtp_la-gstasteriskh263.lo `test -f 'gstasteriskh263.c' || echo '$(srcdir)/'`gstasteriskh263.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstasteriskh263.Tpo $(DEPDIR)/libgstrtp_la-gstasteriskh263.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstasteriskh263.c' object='libgstrtp_la-gstasteriskh263.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstasteriskh263.lo `test -f 'gstasteriskh263.c' || echo '$(srcdir)/'`gstasteriskh263.c
+
+libgstrtp_la-gstrtpmp1sdepay.lo: gstrtpmp1sdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpmp1sdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpmp1sdepay.Tpo -c -o libgstrtp_la-gstrtpmp1sdepay.lo `test -f 'gstrtpmp1sdepay.c' || echo '$(srcdir)/'`gstrtpmp1sdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpmp1sdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpmp1sdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpmp1sdepay.c' object='libgstrtp_la-gstrtpmp1sdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpmp1sdepay.lo `test -f 'gstrtpmp1sdepay.c' || echo '$(srcdir)/'`gstrtpmp1sdepay.c
+
+libgstrtp_la-gstrtpmp2tdepay.lo: gstrtpmp2tdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpmp2tdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpmp2tdepay.Tpo -c -o libgstrtp_la-gstrtpmp2tdepay.lo `test -f 'gstrtpmp2tdepay.c' || echo '$(srcdir)/'`gstrtpmp2tdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpmp2tdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpmp2tdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpmp2tdepay.c' object='libgstrtp_la-gstrtpmp2tdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpmp2tdepay.lo `test -f 'gstrtpmp2tdepay.c' || echo '$(srcdir)/'`gstrtpmp2tdepay.c
+
+libgstrtp_la-gstrtpmp2tpay.lo: gstrtpmp2tpay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpmp2tpay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpmp2tpay.Tpo -c -o libgstrtp_la-gstrtpmp2tpay.lo `test -f 'gstrtpmp2tpay.c' || echo '$(srcdir)/'`gstrtpmp2tpay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpmp2tpay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpmp2tpay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpmp2tpay.c' object='libgstrtp_la-gstrtpmp2tpay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpmp2tpay.lo `test -f 'gstrtpmp2tpay.c' || echo '$(srcdir)/'`gstrtpmp2tpay.c
+
+libgstrtp_la-gstrtpmp4vdepay.lo: gstrtpmp4vdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpmp4vdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpmp4vdepay.Tpo -c -o libgstrtp_la-gstrtpmp4vdepay.lo `test -f 'gstrtpmp4vdepay.c' || echo '$(srcdir)/'`gstrtpmp4vdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpmp4vdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpmp4vdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpmp4vdepay.c' object='libgstrtp_la-gstrtpmp4vdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpmp4vdepay.lo `test -f 'gstrtpmp4vdepay.c' || echo '$(srcdir)/'`gstrtpmp4vdepay.c
+
+libgstrtp_la-gstrtpmp4vpay.lo: gstrtpmp4vpay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpmp4vpay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpmp4vpay.Tpo -c -o libgstrtp_la-gstrtpmp4vpay.lo `test -f 'gstrtpmp4vpay.c' || echo '$(srcdir)/'`gstrtpmp4vpay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpmp4vpay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpmp4vpay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpmp4vpay.c' object='libgstrtp_la-gstrtpmp4vpay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpmp4vpay.lo `test -f 'gstrtpmp4vpay.c' || echo '$(srcdir)/'`gstrtpmp4vpay.c
+
+libgstrtp_la-gstrtpmp4gdepay.lo: gstrtpmp4gdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpmp4gdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpmp4gdepay.Tpo -c -o libgstrtp_la-gstrtpmp4gdepay.lo `test -f 'gstrtpmp4gdepay.c' || echo '$(srcdir)/'`gstrtpmp4gdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpmp4gdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpmp4gdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpmp4gdepay.c' object='libgstrtp_la-gstrtpmp4gdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpmp4gdepay.lo `test -f 'gstrtpmp4gdepay.c' || echo '$(srcdir)/'`gstrtpmp4gdepay.c
+
+libgstrtp_la-gstrtpmp4gpay.lo: gstrtpmp4gpay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpmp4gpay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpmp4gpay.Tpo -c -o libgstrtp_la-gstrtpmp4gpay.lo `test -f 'gstrtpmp4gpay.c' || echo '$(srcdir)/'`gstrtpmp4gpay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpmp4gpay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpmp4gpay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpmp4gpay.c' object='libgstrtp_la-gstrtpmp4gpay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpmp4gpay.lo `test -f 'gstrtpmp4gpay.c' || echo '$(srcdir)/'`gstrtpmp4gpay.c
+
+libgstrtp_la-gstrtpmp4adepay.lo: gstrtpmp4adepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpmp4adepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpmp4adepay.Tpo -c -o libgstrtp_la-gstrtpmp4adepay.lo `test -f 'gstrtpmp4adepay.c' || echo '$(srcdir)/'`gstrtpmp4adepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpmp4adepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpmp4adepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpmp4adepay.c' object='libgstrtp_la-gstrtpmp4adepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpmp4adepay.lo `test -f 'gstrtpmp4adepay.c' || echo '$(srcdir)/'`gstrtpmp4adepay.c
+
+libgstrtp_la-gstrtpmp4apay.lo: gstrtpmp4apay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpmp4apay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpmp4apay.Tpo -c -o libgstrtp_la-gstrtpmp4apay.lo `test -f 'gstrtpmp4apay.c' || echo '$(srcdir)/'`gstrtpmp4apay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpmp4apay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpmp4apay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpmp4apay.c' object='libgstrtp_la-gstrtpmp4apay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpmp4apay.lo `test -f 'gstrtpmp4apay.c' || echo '$(srcdir)/'`gstrtpmp4apay.c
+
+libgstrtp_la-gstrtpqcelpdepay.lo: gstrtpqcelpdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpqcelpdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpqcelpdepay.Tpo -c -o libgstrtp_la-gstrtpqcelpdepay.lo `test -f 'gstrtpqcelpdepay.c' || echo '$(srcdir)/'`gstrtpqcelpdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpqcelpdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpqcelpdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpqcelpdepay.c' object='libgstrtp_la-gstrtpqcelpdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpqcelpdepay.lo `test -f 'gstrtpqcelpdepay.c' || echo '$(srcdir)/'`gstrtpqcelpdepay.c
+
+libgstrtp_la-gstrtpqdmdepay.lo: gstrtpqdmdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpqdmdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpqdmdepay.Tpo -c -o libgstrtp_la-gstrtpqdmdepay.lo `test -f 'gstrtpqdmdepay.c' || echo '$(srcdir)/'`gstrtpqdmdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpqdmdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpqdmdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpqdmdepay.c' object='libgstrtp_la-gstrtpqdmdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpqdmdepay.lo `test -f 'gstrtpqdmdepay.c' || echo '$(srcdir)/'`gstrtpqdmdepay.c
+
+libgstrtp_la-gstrtpsbcdepay.lo: gstrtpsbcdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpsbcdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpsbcdepay.Tpo -c -o libgstrtp_la-gstrtpsbcdepay.lo `test -f 'gstrtpsbcdepay.c' || echo '$(srcdir)/'`gstrtpsbcdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpsbcdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpsbcdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpsbcdepay.c' object='libgstrtp_la-gstrtpsbcdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpsbcdepay.lo `test -f 'gstrtpsbcdepay.c' || echo '$(srcdir)/'`gstrtpsbcdepay.c
+
+libgstrtp_la-gstrtpsbcpay.lo: gstrtpsbcpay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpsbcpay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpsbcpay.Tpo -c -o libgstrtp_la-gstrtpsbcpay.lo `test -f 'gstrtpsbcpay.c' || echo '$(srcdir)/'`gstrtpsbcpay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpsbcpay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpsbcpay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpsbcpay.c' object='libgstrtp_la-gstrtpsbcpay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpsbcpay.lo `test -f 'gstrtpsbcpay.c' || echo '$(srcdir)/'`gstrtpsbcpay.c
+
+libgstrtp_la-gstrtpsirenpay.lo: gstrtpsirenpay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpsirenpay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpsirenpay.Tpo -c -o libgstrtp_la-gstrtpsirenpay.lo `test -f 'gstrtpsirenpay.c' || echo '$(srcdir)/'`gstrtpsirenpay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpsirenpay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpsirenpay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpsirenpay.c' object='libgstrtp_la-gstrtpsirenpay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpsirenpay.lo `test -f 'gstrtpsirenpay.c' || echo '$(srcdir)/'`gstrtpsirenpay.c
+
+libgstrtp_la-gstrtpsirendepay.lo: gstrtpsirendepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpsirendepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpsirendepay.Tpo -c -o libgstrtp_la-gstrtpsirendepay.lo `test -f 'gstrtpsirendepay.c' || echo '$(srcdir)/'`gstrtpsirendepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpsirendepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpsirendepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpsirendepay.c' object='libgstrtp_la-gstrtpsirendepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpsirendepay.lo `test -f 'gstrtpsirendepay.c' || echo '$(srcdir)/'`gstrtpsirendepay.c
+
+libgstrtp_la-gstrtpspeexdepay.lo: gstrtpspeexdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpspeexdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpspeexdepay.Tpo -c -o libgstrtp_la-gstrtpspeexdepay.lo `test -f 'gstrtpspeexdepay.c' || echo '$(srcdir)/'`gstrtpspeexdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpspeexdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpspeexdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpspeexdepay.c' object='libgstrtp_la-gstrtpspeexdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpspeexdepay.lo `test -f 'gstrtpspeexdepay.c' || echo '$(srcdir)/'`gstrtpspeexdepay.c
+
+libgstrtp_la-gstrtpspeexpay.lo: gstrtpspeexpay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpspeexpay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpspeexpay.Tpo -c -o libgstrtp_la-gstrtpspeexpay.lo `test -f 'gstrtpspeexpay.c' || echo '$(srcdir)/'`gstrtpspeexpay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpspeexpay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpspeexpay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpspeexpay.c' object='libgstrtp_la-gstrtpspeexpay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpspeexpay.lo `test -f 'gstrtpspeexpay.c' || echo '$(srcdir)/'`gstrtpspeexpay.c
+
+libgstrtp_la-gstrtpsv3vdepay.lo: gstrtpsv3vdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpsv3vdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpsv3vdepay.Tpo -c -o libgstrtp_la-gstrtpsv3vdepay.lo `test -f 'gstrtpsv3vdepay.c' || echo '$(srcdir)/'`gstrtpsv3vdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpsv3vdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpsv3vdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpsv3vdepay.c' object='libgstrtp_la-gstrtpsv3vdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpsv3vdepay.lo `test -f 'gstrtpsv3vdepay.c' || echo '$(srcdir)/'`gstrtpsv3vdepay.c
+
+libgstrtp_la-gstrtptheoradepay.lo: gstrtptheoradepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtptheoradepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtptheoradepay.Tpo -c -o libgstrtp_la-gstrtptheoradepay.lo `test -f 'gstrtptheoradepay.c' || echo '$(srcdir)/'`gstrtptheoradepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtptheoradepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtptheoradepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtptheoradepay.c' object='libgstrtp_la-gstrtptheoradepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtptheoradepay.lo `test -f 'gstrtptheoradepay.c' || echo '$(srcdir)/'`gstrtptheoradepay.c
+
+libgstrtp_la-gstrtptheorapay.lo: gstrtptheorapay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtptheorapay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtptheorapay.Tpo -c -o libgstrtp_la-gstrtptheorapay.lo `test -f 'gstrtptheorapay.c' || echo '$(srcdir)/'`gstrtptheorapay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtptheorapay.Tpo $(DEPDIR)/libgstrtp_la-gstrtptheorapay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtptheorapay.c' object='libgstrtp_la-gstrtptheorapay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtptheorapay.lo `test -f 'gstrtptheorapay.c' || echo '$(srcdir)/'`gstrtptheorapay.c
+
+libgstrtp_la-gstrtpvorbisdepay.lo: gstrtpvorbisdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpvorbisdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpvorbisdepay.Tpo -c -o libgstrtp_la-gstrtpvorbisdepay.lo `test -f 'gstrtpvorbisdepay.c' || echo '$(srcdir)/'`gstrtpvorbisdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpvorbisdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpvorbisdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpvorbisdepay.c' object='libgstrtp_la-gstrtpvorbisdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpvorbisdepay.lo `test -f 'gstrtpvorbisdepay.c' || echo '$(srcdir)/'`gstrtpvorbisdepay.c
+
+libgstrtp_la-gstrtpvorbispay.lo: gstrtpvorbispay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpvorbispay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpvorbispay.Tpo -c -o libgstrtp_la-gstrtpvorbispay.lo `test -f 'gstrtpvorbispay.c' || echo '$(srcdir)/'`gstrtpvorbispay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpvorbispay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpvorbispay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpvorbispay.c' object='libgstrtp_la-gstrtpvorbispay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpvorbispay.lo `test -f 'gstrtpvorbispay.c' || echo '$(srcdir)/'`gstrtpvorbispay.c
+
+libgstrtp_la-gstrtpvp8depay.lo: gstrtpvp8depay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpvp8depay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpvp8depay.Tpo -c -o libgstrtp_la-gstrtpvp8depay.lo `test -f 'gstrtpvp8depay.c' || echo '$(srcdir)/'`gstrtpvp8depay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpvp8depay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpvp8depay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpvp8depay.c' object='libgstrtp_la-gstrtpvp8depay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpvp8depay.lo `test -f 'gstrtpvp8depay.c' || echo '$(srcdir)/'`gstrtpvp8depay.c
+
+libgstrtp_la-gstrtpvp8pay.lo: gstrtpvp8pay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpvp8pay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpvp8pay.Tpo -c -o libgstrtp_la-gstrtpvp8pay.lo `test -f 'gstrtpvp8pay.c' || echo '$(srcdir)/'`gstrtpvp8pay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpvp8pay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpvp8pay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpvp8pay.c' object='libgstrtp_la-gstrtpvp8pay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpvp8pay.lo `test -f 'gstrtpvp8pay.c' || echo '$(srcdir)/'`gstrtpvp8pay.c
+
+libgstrtp_la-gstrtpvrawdepay.lo: gstrtpvrawdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpvrawdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpvrawdepay.Tpo -c -o libgstrtp_la-gstrtpvrawdepay.lo `test -f 'gstrtpvrawdepay.c' || echo '$(srcdir)/'`gstrtpvrawdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpvrawdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpvrawdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpvrawdepay.c' object='libgstrtp_la-gstrtpvrawdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpvrawdepay.lo `test -f 'gstrtpvrawdepay.c' || echo '$(srcdir)/'`gstrtpvrawdepay.c
+
+libgstrtp_la-gstrtpvrawpay.lo: gstrtpvrawpay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpvrawpay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpvrawpay.Tpo -c -o libgstrtp_la-gstrtpvrawpay.lo `test -f 'gstrtpvrawpay.c' || echo '$(srcdir)/'`gstrtpvrawpay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpvrawpay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpvrawpay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpvrawpay.c' object='libgstrtp_la-gstrtpvrawpay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpvrawpay.lo `test -f 'gstrtpvrawpay.c' || echo '$(srcdir)/'`gstrtpvrawpay.c
+
+libgstrtp_la-gstrtpstreampay.lo: gstrtpstreampay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpstreampay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpstreampay.Tpo -c -o libgstrtp_la-gstrtpstreampay.lo `test -f 'gstrtpstreampay.c' || echo '$(srcdir)/'`gstrtpstreampay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpstreampay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpstreampay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpstreampay.c' object='libgstrtp_la-gstrtpstreampay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpstreampay.lo `test -f 'gstrtpstreampay.c' || echo '$(srcdir)/'`gstrtpstreampay.c
+
+libgstrtp_la-gstrtpstreamdepay.lo: gstrtpstreamdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -MT libgstrtp_la-gstrtpstreamdepay.lo -MD -MP -MF $(DEPDIR)/libgstrtp_la-gstrtpstreamdepay.Tpo -c -o libgstrtp_la-gstrtpstreamdepay.lo `test -f 'gstrtpstreamdepay.c' || echo '$(srcdir)/'`gstrtpstreamdepay.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstrtp_la-gstrtpstreamdepay.Tpo $(DEPDIR)/libgstrtp_la-gstrtpstreamdepay.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstrtpstreamdepay.c' object='libgstrtp_la-gstrtpstreamdepay.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstrtp_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstrtp_la_CFLAGS) $(CFLAGS) -c -o libgstrtp_la-gstrtpstreamdepay.lo `test -f 'gstrtpstreamdepay.c' || echo '$(srcdir)/'`gstrtpstreamdepay.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-pluginLTLIBRARIES install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-pluginLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/gst/rtp/README b/gst/rtp/README
new file mode 100755
index 0000000..5042bd5
--- /dev/null
+++ b/gst/rtp/README
@@ -0,0 +1,398 @@
+This directory contains some RTP payloaders/depayloaders for different payload
+types. Use one payloader/depayloder pair per payload. If several payloads can be
+payloaded/depayloaded by the same element, make different copies of it, one for
+each payload.
+
+The application/x-rtp mime type
+-------------------------------
+
+For valid RTP packets encapsulated in GstBuffers, we use the caps with
+mime type application/x-rtp.
+
+The following fields can or must (*) be specified in the structure:
+
+ * media: (String) [ "audio", "video", "application", "data", "control" ]
+ Defined in RFC 2327 in the SDP media announcement field.
+ Converted to lower case.
+
+ * payload: (int) [0, 127]
+ For audio and video, these will normally be a media payload type as
+ defined in the RTP Audio/Video Profile. For dynamicaly allocated
+ payload types, this value will be >= 96 and the encoding-name must be
+ set.
+
+ * clock-rate: (int) [0 - MAXINT]
+ The RTP clock rate.
+
+ encoding-name: (String) ANY
+ typically second part of the mime type. ex. MP4V-ES. only required if
+ payload type >= 96. Converted to upper case.
+
+ encoding-params: (String) ANY
+ extra encoding parameters (as in the SDP a=rtpmap: field). only required
+ if different from the default of the encoding-name.
+ Converted to lower-case.
+
+ ssrc: (uint) [0 - MAXINT]
+ The ssrc value currently in use. (default = the SSRC of the first RTP
+ packet)
+
+ timestamp-offset: (uint) [0 - MAXINT]
+ The RTP time representing time npt-start. (default = rtptime of first RTP
+ packet).
+
+ seqnum-offset: (uint) [0 - MAXINT]
+ The RTP sequence number representing the first rtp packet. When this
+ parameter is given, all sequence numbers below this seqnum should be
+ ignored. (default = seqnum of first RTP packet).
+
+ npt-start: (uint64) [0 - MAXINT]
+ The Normal Play Time for clock-base. This is the position in the stream and
+ is between 0 and the duration of the stream. This value is expressed in
+ nanoseconds GstClockTime. (default = 0)
+
+ npt-stop: (uint64) [0 - MAXINT]
+ The last position in the stream. This value is expressed in nanoseconds
+ GstClockTime. (default = -1, stop unknown)
+
+ play-speed: (gdouble) [-MIN - MAX]
+ The intended playback speed of the stream. The client is delivered data at
+ the adjusted speed. The client should adjust its playback speed with this
+ value and thus corresponds to the GStreamer rate field in the NEWSEGMENT
+ event. (default = 1.0)
+
+ play-scale: (gdouble) [-MIN - MAX]
+ The rate already applied to the stream. The client is delivered a stream
+ that is scaled by this amount. This value is used to adjust position
+ reporting and corresponds to the GStream applied-rate field in the
+ NEWSEGMENT event. (default = 1.0)
+
+ maxptime: (uint) [0, MAX]
+ The maxptime as defined in RFC 4566, this defines the maximum size of a
+ packet. It overrides the max-ptime property of payloaders.
+
+ Optional parameters as key/value pairs, media type specific. The value type
+ should be of type G_TYPE_STRING. The key is converted to lower-case. The
+ value is left in its original case.
+ A parameter with no value is converted to <param>=1.
+
+ Example:
+
+ "application/x-rtp",
+ "media", G_TYPE_STRING, "audio", -.
+ "payload", G_TYPE_INT, 96, | - required
+ "clock-rate", G_TYPE_INT, 8000, -'
+ "encoding-name", G_TYPE_STRING, "AMR", -. - required since payload >= 96
+ "encoding-params", G_TYPE_STRING, "1", -' - optional param for AMR
+ "octet-align", G_TYPE_STRING, "1", -.
+ "crc", G_TYPE_STRING, "0", |
+ "robust-sorting", G_TYPE_STRING, "0", | AMR specific params.
+ "interleaving", G_TYPE_STRING, "0", -'
+
+ Mapping of caps to and from SDP fields:
+
+ m=<media> <udp port> RTP/AVP <payload> -] media and payload from caps
+ a=rtpmap:<payload> <encoding-name>/<clock-rate>[/<encoding-params>]
+ -> when <payload> >= 96
+ a=fmtp:<payload> <param>=<value>;...
+
+ For above caps:
+
+ m=audio <udp port> RTP/AVP 96
+ a=rtpmap:96 AMR/8000/1
+ a=fmtp:96 octet-align=1;crc=0;robust-sorting=0;interleaving=0
+
+ Attributes are converted as follows:
+
+ IANA registered attribute names are prepended with 'a-' before putting them in
+ the caps. Unregistered keys (starting with 'x-') are copied directly into the
+ caps.
+
+ in RTSP, the SSRC is also sent.
+
+ The optional parameters in the SDP fields are case insensitive. In the caps we
+ always use the lowercase names so that the SDP -> caps mapping remains
+ possible.
+
+ Mapping of caps to NEWSEGMENT:
+
+ rate: <play-speed>
+ applied-rate: <play-scale>
+ format: GST_FORMAT_TIME
+ start: <clock-base> * GST_SECOND / <clock-rate>
+ stop: if <ntp-stop> != -1
+ <npt-stop> - <npt-start> + start
+ else
+ -1
+ time: <npt-start>
+
+
+Timestamping
+------------
+
+RTP in GStreamer uses a combination of the RTP timestamps and GStreamer buffer
+timestamps to ensure proper synchronisation at the sender and the receiver end.
+
+In RTP applications, the synchronisation is most complex at the receiver side.
+
+At the sender side, the RTP timestamps are generated in the payloaders based on
+GStreamer timestamps. At the receiver, GStreamer timestamps are reconstructed
+from the RTP timestamps and the GStreamer timestamps in the jitterbuffer. This
+process is explained in more detail below.
+
+= synchronisation at the sender
+
+Individual streams at the sender are synchronised using GStreamer timestamps.
+The payloader at the sender will convert the GStreamer timestamp into an RTP
+timestamp using the following formula:
+
+ RTP = ((RT - RT-base) * clock-rate / GST_SECOND) + RTP-offset
+
+ RTP: the RTP timestamp for the stream. This value is truncated to
+ 32 bits.
+ RT: the GStreamer running time corresponding to the timestamp of the
+ packet to payload
+ RT-base: the GStreamer running time of the first packet encoded
+ clock-rate: the clock-rate of the stream
+ RTP-offset: a random RTP offset
+
+The RTP timestamp corresponding to RT-base is the clock-base (see caps above).
+
+In addition to setting an RTP timestamp in the RTP packet, the payloader is also
+responsible for putting the GStreamer timestamp on the resulting output buffer.
+This timestamp is used for further synchronisation at the sender pipeline, such
+as for sending out the packet on the network.
+
+Notice that the absolute timing information is lost; if the sender is sending
+multiple streams, the RTP timestamps in the packets do not contain enough
+information to synchronize them in the receiver. The receiver can however use
+the RTP timestamps to reconstruct the timing of the stream as it was created by
+the sender according to the sender's clock.
+
+Because the payloaded packet contains both an RTP timestamp and a GStreamer
+timestamp, it is possible for an RTP session manager to derive the relation
+between the RTP and GST timestamps. This information is used by a session
+manager to create SR reports. The NTP time in the report will contain the
+running time converted to NTP time and the corresponding RTP timestamp.
+
+Note that at the sender side, the RTP and GStreamer timestamp both increment at
+the same rate, the sender rate. This rate depends on the global pipeline clock
+of the sender.
+
+Some pipelines to illustrate the process:
+
+ gst-launch-1.0 v4l2src ! videoconvert ! avenc_h263p ! rtph263ppay ! udpsink
+
+ v4l2src puts a GStreamer timestamp on the video frames base on the current
+ running_time. The encoder encodes and passed the timestamp on. The payloader
+ generates an RTP timestamp using the above formula and puts it in the RTP
+ packet. It also copies the incomming GStreamer timestamp on the output RTP
+ packet. udpsink synchronizes on the gstreamer timestamp before pushing out the
+ packet.
+
+
+= synchronisation at the receiver
+
+The receiver is responsible for timestamping the received RTP packet with the
+running_time of the clock at the time the packet was received. This GStreamer
+timestamp reflects the receiver rate and depends on the global pipeline clock of
+the receiver. The gstreamer timestamp of the received RTP packet contains a
+certain amount of jitter introduced by the network.
+
+The most simple option for the receiver is to depayload the RTP packet and play
+it back as soon as possible, this is with the timestamp when it was received
+from the network. For the above sender pipeline this would be done with the
+following pipeline:
+
+ gst-launch-1.0 udpsrc caps="application/x-rtp, media=(string)video,
+ clock-rate=(int)90000, encoding-name=(string)H263-1998" ! rtph263pdepay !
+ avdec_h263 ! autovideosink
+
+It is important that the depayloader copies the incomming GStreamer timestamp
+directly to the depayloaded output buffer. It should never attempt to perform
+any logic with the RTP timestamp, this task is for the jitterbuffer as we will
+see next.
+
+The above pipeline does not attempt to deal with reordered packets or network
+jitter, which could result in jerky playback in the case of high jitter or
+corrupted video in the case of packet loss or reordering. This functionality is
+performed by the gstrtpjitterbuffer in GStreamer.
+
+The task of the gstrtpjitterbuffer element is to:
+
+ - deal with reordered packets based on the seqnum
+ - calculate the drift between the sender and receiver clocks using the
+ GStreamer timestamps (receiver clock rate) and RTP timestamps (sender clock
+ rate).
+
+To deal with reordered packet, the jitterbuffer holds on to the received RTP
+packets in a queue for a configurable amount of time, called the latency.
+
+The jitterbuffer also eliminates network jitter and then tracks the drift
+between the local clock (as expressed in the GStreamer timestamps) and the
+remote clock (as expressed in the RTP timestamps). It will remove the jitter
+and will apply the drift correction to the GStreamer timestamp before pushing
+the buffer downstream. The result is that the depayloader receives a smoothed
+GStreamer timestamp on the RTP packet, which is copied to the depayloaded data.
+
+The following pipeline illustrates a receiver with a jitterbuffer.
+
+ gst-launch-1.0 udpsrc caps="application/x-rtp, media=(string)video,
+ clock-rate=(int)90000, encoding-name=(string)H263-1998" !
+ rtpjitterbuffer latency=100 ! rtph263pdepay ! avdec_h263 ! autovideosink
+
+The latency property on the jitterbuffer controls the amount of delay (in
+milliseconds) to apply to the outgoing packets. A higher latency will produce
+smoother playback in networks with high jitter but cause a higher latency.
+Choosing a good value for the latency is a tradeoff between the quality and
+latency. The better the network, the lower the latency can be set.
+
+
+usage with UDP
+--------------
+
+To correctly and completely use the RTP payloaders on the sender and the
+receiver you need to write an application. It is not possible to write a full
+blown RTP server with a single gst-launch-1.0 line.
+
+That said, it is possible to do something functional with a few gst-launch
+lines. The biggest problem when constructing a correct gst-launch-1.0 line lies on
+the receiver end.
+
+The receiver needs to know about the type of the RTP data along with a set of
+RTP configuration parameters. This information is usually transmitted to the
+client using some sort of session description language (SDP) over some reliable
+channel (HTTP/RTSP/...).
+
+All of the required parameters to connect and use the RTP session on the
+server can be found in the caps on the server end. The client receives this
+information in some way (caps are converted to and from SDP, as explained above,
+for example).
+
+Some gst-launch-1.0 lines:
+
+ gst-launch-1.0 -v videotestsrc ! videoconvert ! avenc_h263p ! rtph263ppay ! udpsink
+
+ Setting pipeline to PAUSED ...
+ /pipeline0/videotestsrc0.src: caps = video/x-raw, format=(string)I420,
+ width=(int)320, height=(int)240, framerate=(fraction)30/1
+ Pipeline is PREROLLING ...
+ ....
+ /pipeline0/udpsink0.sink: caps = application/x-rtp, media=(string)video,
+ payload=(int)96, clock-rate=(int)90000, encoding-name=(string)H263-1998,
+ ssrc=(guint)527842345, clock-base=(guint)1150776941, seqnum-base=(guint)30982
+ ....
+ Pipeline is PREROLLED ...
+ Setting pipeline to PLAYING ...
+ New clock: GstSystemClock
+
+ Write down the caps on the udpsink and set them as the caps of the UDP
+ receiver:
+
+ gst-launch-1.0 -v udpsrc caps="application/x-rtp, media=(string)video,
+ payload=(int)96, clock-rate=(int)90000, encoding-name=(string)H263-1998,
+ ssrc=(guint)527842345, clock-base=(guint)1150776941, seqnum-base=(guint)30982"
+ ! rtph263pdepay ! avdec_h263 ! autovideosink
+
+ The receiver now displays an h263 image. Since there is no jitterbuffer in the
+ pipeline, frames will be displayed at the time when they are received. This can
+ result in jerky playback in the case of high network jitter or currupted video
+ when packets are dropped or reordered.
+
+ Stream a quicktime file with mpeg4 video and AAC audio on port 5000 and port
+ 5002.
+
+ gst-launch-1.0 -v filesrc location=~/data/sincity.mp4 ! qtdemux name=d ! queue ! rtpmp4vpay ! udpsink port=5000
+ d. ! queue ! rtpmp4gpay ! udpsink port=5002
+ ....
+ /pipeline0/udpsink0.sink: caps = application/x-rtp, media=(string)video,
+ payload=(int)96, clock-rate=(int)90000, encoding-name=(string)MP4V-ES,
+ ssrc=(guint)1162703703, clock-base=(guint)816135835, seqnum-base=(guint)9294,
+ profile-level-id=(string)3, config=(string)000001b003000001b50900000100000001200086c5d4c307d314043c1463000001b25876694430303334
+ /pipeline0/udpsink1.sink: caps = application/x-rtp, media=(string)audio,
+ payload=(int)96, clock-rate=(int)44100, encoding-name=(string)MPEG4-GENERIC,
+ ssrc=(guint)3246149898, clock-base=(guint)4134514058, seqnum-base=(guint)57633,
+ encoding-params=(string)2, streamtype=(string)5, profile-level-id=(string)1,
+ mode=(string)aac-hbr, config=(string)1210, sizelength=(string)13,
+ indexlength=(string)3, indexdeltalength=(string)3
+ ....
+
+ Again copy the caps on both sinks to the receiver launch line
+
+ gst-launch-1.0
+ udpsrc port=5000 caps="application/x-rtp, media=(string)video, payload=(int)96,
+ clock-rate=(int)90000, encoding-name=(string)MP4V-ES, ssrc=(guint)1162703703,
+ clock-base=(guint)816135835, seqnum-base=(guint)9294, profile-level-id=(string)3,
+ config=(string)000001b003000001b50900000100000001200086c5d4c307d314043c1463000001b25876694430303334"
+ ! rtpmp4vdepay ! ffdec_mpeg4 ! autovideosink sync=false
+ udpsrc port=5002 caps="application/x-rtp, media=(string)audio, payload=(int)96,
+ clock-rate=(int)44100, encoding-name=(string)MPEG4-GENERIC, ssrc=(guint)3246149898,
+ clock-base=(guint)4134514058, seqnum-base=(guint)57633, encoding-params=(string)2,
+ streamtype=(string)5, profile-level-id=(string)1, mode=(string)aac-hbr,
+ config=(string)1210, sizelength=(string)13, indexlength=(string)3,
+ indexdeltalength=(string)3"
+ ! rtpmp4gdepay ! faad ! alsasink sync=false
+
+ The caps on the udpsinks can be retrieved when the server pipeline prerolled to
+ PAUSED.
+
+ The above pipeline sets sync=false on the audio and video sink which means that
+ no synchronisation will be performed in the sinks, they play the data when it
+ arrives. If you want to enable synchronisation in the sinks it is highly
+ recommended to use a gstrtpjitterbuffer after the udpsrc elements.
+
+ Even when sync is enabled, the two different streams will not play synchronised
+ against eachother because the receiver does not have enough information to
+ perform this task. For this you need to add the rtpbin element in both the
+ sender and receiver pipeline and use additional sources and sinks to transmit
+ RTCP packets used for inter-stream synchronisation.
+
+ The caps on the receiver side can be set on the UDP source elements when the
+ pipeline went to PAUSED. In that state no data is received from the UDP sources
+ as they are live sources and only produce data in PLAYING.
+
+
+Relevant RFCs
+-------------
+
+3550 RTP: A Transport Protocol for Real-Time Applications. ( 1889 Obsolete )
+
+2198 RTP Payload for Redundant Audio Data.
+3119 A More Loss-Tolerant RTP Payload Format for MP3 Audio.
+
+2793 RTP Payload for Text Conversation.
+
+2032 RTP Payload Format for H.261 Video Streams.
+2190 RTP Payload Format for H.263 Video Streams.
+2250 RTP Payload Format for MPEG1/MPEG2 Video.
+2343 RTP Payload Format for Bundled MPEG.
+2429 RTP Payload Format for the 1998 Version of ITU-T Rec. H.263 Video
+2431 RTP Payload Format for BT.656 Video Encoding.
+2435 RTP Payload Format for JPEG-compressed Video.
+3016 RTP Payload Format for MPEG-4 Audio/Visual Streams.
+3047 RTP Payload Format for ITU-T Recommendation G.722.1.
+3189 RTP Payload Format for DV (IEC 61834) Video.
+3190 RTP Payload Format for 12-bit DAT Audio and 20- and 24-bit Linear Sampled Audio.
+3389 Real-time Transport Protocol (RTP) Payload for Comfort Noise (CN)
+2733 An RTP Payload Format for Generic Forward Error Correction.
+2833 RTP Payload for DTMF Digits, Telephony Tones and Telephony
+ Signals.
+2862 RTP Payload Format for Real-Time Pointers.
+3351 RTP Profile for Audio and Video Conferences with Minimal Control. ( 1890 Obsolete )
+3555 MIME Type Registration of RTP Payload Formats.
+
+2508 Compressing IP/UDP/RTP Headers for Low-Speed Serial Links.
+1305 Network Time Protocol (Version 3) Specification, Implementation and Analysis.
+3339 Date and Time on the Internet: Timestamps.
+2246 The TLS Protocol Version 1.0
+3546 Transport Layer Security (TLS) Extensions. ( Updates 2246 )
+
+do we care?
+-----------
+
+2029 RTP Payload Format of Sun's CellB Video Encoding.
+
+usefull
+-------
+
+http://www.iana.org/assignments/rtp-parameters
diff --git a/gst/rtp/TODO b/gst/rtp/TODO
new file mode 100755
index 0000000..8065a9c
--- /dev/null
+++ b/gst/rtp/TODO
@@ -0,0 +1,15 @@
+* MPEG4 header
+ - ffmpeg mpeg4 decoder gives error message when sending only the config
+ string, parsing is OK, error just means no picture was found in the
+ stream.
+
+* compare H263 encoders and H263+
+
+* better RTP packetizing for h263
+
+* bitrate tuning in ffmpeg
+ - fixed the qmax values so we can quantize more.
+
+* make ffmpeg negotiate only with accepted framerates
+
+
diff --git a/gst/rtp/dboolhuff.LICENSE b/gst/rtp/dboolhuff.LICENSE
new file mode 100755
index 0000000..83e4e6f
--- /dev/null
+++ b/gst/rtp/dboolhuff.LICENSE
@@ -0,0 +1,29 @@
+Copyright (c) 2010, Google Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ * Neither the name of Google nor the names of its contributors may
+ be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/gst/rtp/dboolhuff.c b/gst/rtp/dboolhuff.c
new file mode 100755
index 0000000..0e1fd6e
--- /dev/null
+++ b/gst/rtp/dboolhuff.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the dboolhuff.LICENSE file in this directory.
+ * See the libvpx original distribution for more information,
+ * including patent information, and author information.
+ */
+
+
+#include "dboolhuff.h"
+
+const unsigned char vp8_norm[256] __attribute__ ((aligned (16))) = {
+0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+int
+vp8dx_start_decode (BOOL_DECODER * br,
+ const unsigned char *source, unsigned int source_sz)
+{
+ br->user_buffer_end = source + source_sz;
+ br->user_buffer = source;
+ br->value = 0;
+ br->count = -8;
+ br->range = 255;
+
+ if (source_sz && !source)
+ return 1;
+
+ /* Populate the buffer */
+ vp8dx_bool_decoder_fill (br);
+
+ return 0;
+}
+
+
+void
+vp8dx_bool_decoder_fill (BOOL_DECODER * br)
+{
+ const unsigned char *bufptr;
+ const unsigned char *bufend;
+ VP8_BD_VALUE value;
+ int count;
+ bufend = br->user_buffer_end;
+ bufptr = br->user_buffer;
+ value = br->value;
+ count = br->count;
+
+ VP8DX_BOOL_DECODER_FILL (count, value, bufptr, bufend);
+
+ br->user_buffer = bufptr;
+ br->value = value;
+ br->count = count;
+}
diff --git a/gst/rtp/dboolhuff.h b/gst/rtp/dboolhuff.h
new file mode 100755
index 0000000..41b0f5d
--- /dev/null
+++ b/gst/rtp/dboolhuff.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the dboolhuff.LICENSE file in this directory.
+ * See the libvpx original distribution for more information,
+ * including patent information, and author information.
+ */
+
+
+#ifndef DBOOLHUFF_H
+#define DBOOLHUFF_H
+#include <stddef.h>
+#include <limits.h>
+#include <glib.h>
+
+typedef size_t VP8_BD_VALUE;
+
+# define VP8_BD_VALUE_SIZE ((int)sizeof(VP8_BD_VALUE)*CHAR_BIT)
+/*This is meant to be a large, positive constant that can still be efficiently
+ loaded as an immediate (on platforms like ARM, for example).
+ Even relatively modest values like 100 would work fine.*/
+# define VP8_LOTS_OF_BITS (0x40000000)
+
+typedef struct
+{
+ const unsigned char *user_buffer_end;
+ const unsigned char *user_buffer;
+ VP8_BD_VALUE value;
+ int count;
+ unsigned int range;
+} BOOL_DECODER;
+
+extern const unsigned char vp8_norm[256] __attribute__((aligned(16)));
+
+int vp8dx_start_decode(BOOL_DECODER *br,
+ const unsigned char *source,
+ unsigned int source_sz);
+
+void vp8dx_bool_decoder_fill(BOOL_DECODER *br);
+
+/*The refill loop is used in several places, so define it in a macro to make
+ sure they're all consistent.
+ An inline function would be cleaner, but has a significant penalty, because
+ multiple BOOL_DECODER fields must be modified, and the compiler is not smart
+ enough to eliminate the stores to those fields and the subsequent reloads
+ from them when inlining the function.*/
+#define VP8DX_BOOL_DECODER_FILL(_count,_value,_bufptr,_bufend) \
+ do \
+ { \
+ int shift = VP8_BD_VALUE_SIZE - 8 - ((_count) + 8); \
+ int loop_end, x; \
+ size_t bits_left = ((_bufend)-(_bufptr))*CHAR_BIT; \
+ \
+ x = shift + CHAR_BIT - bits_left; \
+ loop_end = 0; \
+ if(x >= 0) \
+ { \
+ (_count) += VP8_LOTS_OF_BITS; \
+ loop_end = x; \
+ if(!bits_left) break; \
+ } \
+ while(shift >= loop_end) \
+ { \
+ (_count) += CHAR_BIT; \
+ (_value) |= (VP8_BD_VALUE)*(_bufptr)++ << shift; \
+ shift -= CHAR_BIT; \
+ } \
+ } \
+ while(0) \
+
+
+static int vp8dx_decode_bool(BOOL_DECODER *br, int probability) {
+ unsigned int bit = 0;
+ VP8_BD_VALUE value;
+ unsigned int split;
+ VP8_BD_VALUE bigsplit;
+ int count;
+ unsigned int range;
+
+ split = 1 + (((br->range - 1) * probability) >> 8);
+
+ if(br->count < 0)
+ vp8dx_bool_decoder_fill(br);
+
+ value = br->value;
+ count = br->count;
+
+ bigsplit = (VP8_BD_VALUE)split << (VP8_BD_VALUE_SIZE - 8);
+
+ range = split;
+
+ if (value >= bigsplit)
+ {
+ range = br->range - split;
+ value = value - bigsplit;
+ bit = 1;
+ }
+
+ {
+ register unsigned int shift = vp8_norm[range];
+ range <<= shift;
+ value <<= shift;
+ count -= shift;
+ }
+ br->value = value;
+ br->count = count;
+ br->range = range;
+
+ return bit;
+}
+
+static G_GNUC_UNUSED int vp8_decode_value(BOOL_DECODER *br, int bits)
+{
+ int z = 0;
+ int bit;
+
+ for (bit = bits - 1; bit >= 0; bit--)
+ {
+ z |= (vp8dx_decode_bool(br, 0x80) << bit);
+ }
+
+ return z;
+}
+
+static G_GNUC_UNUSED int vp8dx_bool_error(BOOL_DECODER *br)
+{
+ /* Check if we have reached the end of the buffer.
+ *
+ * Variable 'count' stores the number of bits in the 'value' buffer, minus
+ * 8. The top byte is part of the algorithm, and the remainder is buffered
+ * to be shifted into it. So if count == 8, the top 16 bits of 'value' are
+ * occupied, 8 for the algorithm and 8 in the buffer.
+ *
+ * When reading a byte from the user's buffer, count is filled with 8 and
+ * one byte is filled into the value buffer. When we reach the end of the
+ * data, count is additionally filled with VP8_LOTS_OF_BITS. So when
+ * count == VP8_LOTS_OF_BITS - 1, the user's data has been exhausted.
+ */
+ if ((br->count > VP8_BD_VALUE_SIZE) && (br->count < VP8_LOTS_OF_BITS))
+ {
+ /* We have tried to decode bits after the end of
+ * stream was encountered.
+ */
+ return 1;
+ }
+
+ /* No error. */
+ return 0;
+}
+#endif
diff --git a/gst/rtp/fnv1hash.c b/gst/rtp/fnv1hash.c
new file mode 100755
index 0000000..9885bb2
--- /dev/null
+++ b/gst/rtp/fnv1hash.c
@@ -0,0 +1,63 @@
+/* GStreamer
+ * Copyright (C) 2007 Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <glib.h>
+
+#include "fnv1hash.h"
+
+/* This file implements FNV-1 hashing used in the Ogg payload encoders
+ * to generate the 24-bit ident value based on the header pages.
+ * See http://isthe.com/chongo/tech/comp/fnv/
+ */
+
+#define MASK_24 (((guint32) 1 << 24) -1)
+
+#define FNV1_HASH_32_INIT ((guint32) 0x811C9DC5L)
+//2166136261L)
+#define FNV1_HASH_32_PRIME 16777619
+
+guint32
+fnv1_hash_32_new (void)
+{
+ return FNV1_HASH_32_INIT;
+}
+
+guint32
+fnv1_hash_32_update (guint32 hash, const guchar * data, guint length)
+{
+ guint i;
+ const guchar *p = data;
+
+ for (i = 0; i < length; ++i, ++p) {
+ hash *= FNV1_HASH_32_PRIME;
+ hash ^= *p;
+ }
+
+ return hash;
+}
+
+guint32
+fnv1_hash_32_to_24 (guint32 hash)
+{
+ return (hash >> 24) ^ (hash & MASK_24);
+}
diff --git a/gst/rtp/fnv1hash.h b/gst/rtp/fnv1hash.h
new file mode 100755
index 0000000..7047067
--- /dev/null
+++ b/gst/rtp/fnv1hash.h
@@ -0,0 +1,36 @@
+/* GStreamer
+ * Copyright (C) 2007 Thomas Vander Stichele <thomas at apestaart dot org>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_FNV1_HASH_H__
+#define __GST_FNV1_HASH_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+guint32 fnv1_hash_32_new (void);
+guint32 fnv1_hash_32_update (guint32 hash, const guchar *data, guint length);
+guint32 fnv1_hash_32_to_24 (guint32 hash);
+
+G_END_DECLS
+
+#endif /* __GST_FNV1_HASH_H__ */
+
diff --git a/gst/rtp/gstasteriskh263.c b/gst/rtp/gstasteriskh263.c
new file mode 100755
index 0000000..72fe656
--- /dev/null
+++ b/gst/rtp/gstasteriskh263.c
@@ -0,0 +1,230 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include "gstasteriskh263.h"
+
+#define GST_ASTERISKH263_HEADER_LEN 6
+
+typedef struct _GstAsteriskH263Header
+{
+ guint32 timestamp; /* Timestamp */
+ guint16 length; /* Length */
+} GstAsteriskH263Header;
+
+#define GST_ASTERISKH263_HEADER_TIMESTAMP(data) (((GstAsteriskH263Header *)(data))->timestamp)
+#define GST_ASTERISKH263_HEADER_LENGTH(data) (((GstAsteriskH263Header *)(data))->length)
+
+static GstStaticPadTemplate gst_asteriskh263_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-asteriskh263")
+ );
+
+static GstStaticPadTemplate gst_asteriskh263_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"video\", "
+ "payload = (int) [ 96, 127 ], "
+ "clock-rate = (int) 90000, " "encoding-name = (string) \"H263-1998\"")
+ );
+
+static void gst_asteriskh263_finalize (GObject * object);
+
+static GstFlowReturn gst_asteriskh263_chain (GstPad * pad, GstObject * parent,
+ GstBuffer * buffer);
+
+static GstStateChangeReturn gst_asteriskh263_change_state (GstElement *
+ element, GstStateChange transition);
+
+#define gst_asteriskh263_parent_class parent_class
+G_DEFINE_TYPE (GstAsteriskh263, gst_asteriskh263, GST_TYPE_ELEMENT);
+
+static void
+gst_asteriskh263_class_init (GstAsteriskh263Class * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gobject_class->finalize = gst_asteriskh263_finalize;
+
+ gstelement_class->change_state = gst_asteriskh263_change_state;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_asteriskh263_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_asteriskh263_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP Asterisk H263 depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts H263 video from RTP and encodes in Asterisk H263 format",
+ "Neil Stratford <neils@vipadia.com>");
+}
+
+static void
+gst_asteriskh263_init (GstAsteriskh263 * asteriskh263)
+{
+ asteriskh263->srcpad =
+ gst_pad_new_from_static_template (&gst_asteriskh263_src_template, "src");
+ gst_element_add_pad (GST_ELEMENT (asteriskh263), asteriskh263->srcpad);
+
+ asteriskh263->sinkpad =
+ gst_pad_new_from_static_template (&gst_asteriskh263_sink_template,
+ "sink");
+ gst_pad_set_chain_function (asteriskh263->sinkpad, gst_asteriskh263_chain);
+ gst_element_add_pad (GST_ELEMENT (asteriskh263), asteriskh263->sinkpad);
+
+ asteriskh263->adapter = gst_adapter_new ();
+}
+
+static void
+gst_asteriskh263_finalize (GObject * object)
+{
+ GstAsteriskh263 *asteriskh263;
+
+ asteriskh263 = GST_ASTERISK_H263 (object);
+
+ g_object_unref (asteriskh263->adapter);
+ asteriskh263->adapter = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstFlowReturn
+gst_asteriskh263_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+{
+ GstAsteriskh263 *asteriskh263;
+ GstBuffer *outbuf;
+ GstFlowReturn ret;
+
+ asteriskh263 = GST_ASTERISK_H263 (parent);
+
+ {
+ gint payload_len;
+ guint8 *payload;
+ gboolean M;
+ guint32 timestamp;
+ guint32 samples;
+ guint16 asterisk_len;
+ GstRTPBuffer rtp = { NULL };
+ GstMapInfo map;
+
+ if (!gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp))
+ goto bad_packet;
+
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+ payload = gst_rtp_buffer_get_payload (&rtp);
+
+ M = gst_rtp_buffer_get_marker (&rtp);
+ timestamp = gst_rtp_buffer_get_timestamp (&rtp);
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ outbuf = gst_buffer_new_and_alloc (payload_len +
+ GST_ASTERISKH263_HEADER_LEN);
+
+ /* build the asterisk header */
+ asterisk_len = payload_len;
+ if (M)
+ asterisk_len |= 0x8000;
+ if (!asteriskh263->lastts)
+ asteriskh263->lastts = timestamp;
+ samples = timestamp - asteriskh263->lastts;
+ asteriskh263->lastts = timestamp;
+
+ gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+ GST_ASTERISKH263_HEADER_TIMESTAMP (map.data) = g_htonl (samples);
+ GST_ASTERISKH263_HEADER_LENGTH (map.data) = g_htons (asterisk_len);
+
+ /* copy the data into place */
+ memcpy (map.data + GST_ASTERISKH263_HEADER_LEN, payload, payload_len);
+
+ gst_buffer_unmap (outbuf, &map);
+
+ GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
+ if (!gst_pad_has_current_caps (asteriskh263->srcpad)) {
+ GstCaps *caps;
+
+ caps = gst_pad_get_pad_template_caps (asteriskh263->srcpad);
+ gst_pad_set_caps (asteriskh263->srcpad, caps);
+ gst_caps_unref (caps);
+ }
+
+ ret = gst_pad_push (asteriskh263->srcpad, outbuf);
+
+ gst_buffer_unref (buf);
+ }
+
+ return ret;
+
+bad_packet:
+ {
+ GST_DEBUG ("Packet does not validate");
+ gst_buffer_unref (buf);
+ return GST_FLOW_ERROR;
+ }
+}
+
+static GstStateChangeReturn
+gst_asteriskh263_change_state (GstElement * element, GstStateChange transition)
+{
+ GstAsteriskh263 *asteriskh263;
+ GstStateChangeReturn ret;
+
+ asteriskh263 = GST_ASTERISK_H263 (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_adapter_clear (asteriskh263->adapter);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ /*
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+ default:
+ break;
+ }
+ */
+ return ret;
+}
+
+gboolean
+gst_asteriskh263_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "asteriskh263",
+ GST_RANK_SECONDARY-1, GST_TYPE_ASTERISK_H263);
+}
diff --git a/gst/rtp/gstasteriskh263.h b/gst/rtp/gstasteriskh263.h
new file mode 100755
index 0000000..1c9523d
--- /dev/null
+++ b/gst/rtp/gstasteriskh263.h
@@ -0,0 +1,65 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_ASTERISK_H263_H__
+#define __GST_ASTERISK_H263_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_ASTERISK_H263 \
+ (gst_asteriskh263_get_type())
+#define GST_ASTERISK_H263(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ASTERISK_H263,GstAsteriskh263))
+#define GST_ASTERISK_H263_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ASTERISK_H263,GstAsteriskh263Class))
+#define GST_IS_ASTERISK_H263(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ASTERISK_H263))
+#define GST_IS_ASTERISK_H263_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ASTERISK_H263))
+
+typedef struct _GstAsteriskh263 GstAsteriskh263;
+typedef struct _GstAsteriskh263Class GstAsteriskh263Class;
+
+struct _GstAsteriskh263
+{
+ GstElement element;
+
+ GstPad *sinkpad;
+ GstPad *srcpad;
+
+ GstAdapter *adapter;
+
+ guint32 lastts;
+};
+
+struct _GstAsteriskh263Class
+{
+ GstElementClass parent_class;
+};
+
+GType gst_asteriskh263_get_type (void);
+
+gboolean gst_asteriskh263_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_ASTERISK_H263_H__ */
diff --git a/gst/rtp/gstrtp.c b/gst/rtp/gstrtp.c
new file mode 100755
index 0000000..a3cbccd
--- /dev/null
+++ b/gst/rtp/gstrtp.c
@@ -0,0 +1,343 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/tag/tag.h>
+
+#include "gstrtpac3depay.h"
+#include "gstrtpac3pay.h"
+#include "gstrtpbvdepay.h"
+#include "gstrtpbvpay.h"
+#include "gstrtpceltdepay.h"
+#include "gstrtpceltpay.h"
+#include "gstrtpdvdepay.h"
+#include "gstrtpdvpay.h"
+#include "gstrtpgstdepay.h"
+#include "gstrtpgstpay.h"
+#include "gstrtpilbcdepay.h"
+#include "gstrtpilbcpay.h"
+#include "gstrtppcmupay.h"
+#include "gstrtppcmapay.h"
+#include "gstrtppcmadepay.h"
+#include "gstrtppcmudepay.h"
+#include "gstrtpg722depay.h"
+#include "gstrtpg722pay.h"
+#include "gstrtpg723depay.h"
+#include "gstrtpg723pay.h"
+#include "gstrtpg726depay.h"
+#include "gstrtpg726pay.h"
+#include "gstrtpg729depay.h"
+#include "gstrtpg729pay.h"
+#include "gstrtpgsmpay.h"
+#include "gstrtpgsmdepay.h"
+#include "gstrtpamrpay.h"
+#include "gstrtpamrdepay.h"
+#include "gstrtpmpapay.h"
+#include "gstrtpmpadepay.h"
+#include "gstrtpmparobustdepay.h"
+#include "gstrtpmpvdepay.h"
+#include "gstrtpmpvpay.h"
+#include "gstrtph263pdepay.h"
+#include "gstrtph263ppay.h"
+#include "gstrtph263depay.h"
+#include "gstrtph263pay.h"
+#include "gstrtph264depay.h"
+#include "gstrtph264pay.h"
+#include "gstrtpj2kdepay.h"
+#include "gstrtpj2kpay.h"
+#include "gstrtpjpegdepay.h"
+#include "gstrtpjpegpay.h"
+#include "gstrtpL16depay.h"
+#include "gstrtpL16pay.h"
+#include "gstrtpL24depay.h"
+#include "gstrtpL24pay.h"
+#include "gstasteriskh263.h"
+#include "gstrtpmp1sdepay.h"
+#include "gstrtpmp2tdepay.h"
+#include "gstrtpmp2tpay.h"
+#include "gstrtpmp4vdepay.h"
+#include "gstrtpmp4vpay.h"
+#include "gstrtpmp4adepay.h"
+#include "gstrtpmp4apay.h"
+#include "gstrtpmp4gdepay.h"
+#include "gstrtpmp4gpay.h"
+#include "gstrtpqcelpdepay.h"
+#include "gstrtpqdmdepay.h"
+#include "gstrtpsbcdepay.h"
+#include "gstrtpsbcpay.h"
+#include "gstrtpsirenpay.h"
+#include "gstrtpsirendepay.h"
+#include "gstrtpspeexpay.h"
+#include "gstrtpspeexdepay.h"
+#include "gstrtpsv3vdepay.h"
+#include "gstrtptheoradepay.h"
+#include "gstrtptheorapay.h"
+#include "gstrtpvorbisdepay.h"
+#include "gstrtpvorbispay.h"
+#include "gstrtpvp8depay.h"
+#include "gstrtpvp8pay.h"
+#include "gstrtpvrawdepay.h"
+#include "gstrtpvrawpay.h"
+#include "gstrtpstreampay.h"
+#include "gstrtpstreamdepay.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ gst_tag_image_type_get_type ();
+
+ if (!gst_rtp_ac3_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_ac3_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_bv_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_bv_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_celt_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_celt_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_dv_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_dv_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_gst_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_gst_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_ilbc_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_ilbc_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_g722_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_g722_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_g723_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_g723_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_g726_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_g726_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_g729_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_g729_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_gsm_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_gsm_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_amr_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_amr_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_pcma_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_pcmu_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_pcmu_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_pcma_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_mpa_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_mpa_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_mpa_robust_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_mpv_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_mpv_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_h263p_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_h263p_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_h263_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_h263_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_h264_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_h264_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_j2k_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_j2k_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_jpeg_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_jpeg_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_L16_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_L16_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_L24_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_L24_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_asteriskh263_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_mp1s_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_mp2t_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_mp2t_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_mp4v_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_mp4v_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_mp4a_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_mp4a_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_mp4g_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_mp4g_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_qcelp_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_qdm2_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_sbc_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_sbc_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_siren_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_siren_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_speex_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_speex_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_sv3v_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_theora_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_theora_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_vorbis_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_vorbis_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_vp8_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_vp8_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_vraw_depay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_vraw_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_stream_pay_plugin_init (plugin))
+ return FALSE;
+
+ if (!gst_rtp_stream_depay_plugin_init (plugin))
+ return FALSE;
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ rtp,
+ "Real-time protocol plugins",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/gst/rtp/gstrtpL16depay.c b/gst/rtp/gstrtpL16depay.c
new file mode 100755
index 0000000..667a64a
--- /dev/null
+++ b/gst/rtp/gstrtpL16depay.c
@@ -0,0 +1,288 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpL16depay
+ * @see_also: rtpL16pay
+ *
+ * Extract raw audio from RTP packets according to RFC 3551.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc3551.txt
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 udpsrc caps='application/x-rtp, media=(string)audio, clock-rate=(int)44100, encoding-name=(string)L16, encoding-params=(string)1, channels=(int)1, payload=(int)96' ! rtpL16depay ! pulsesink
+ * ]| This example pipeline will depayload an RTP raw audio stream. Refer to
+ * the rtpL16pay example to create the RTP stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gst/audio/audio.h>
+
+#include "gstrtpL16depay.h"
+#include "gstrtpchannels.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpL16depay_debug);
+#define GST_CAT_DEFAULT (rtpL16depay_debug)
+
+static GstStaticPadTemplate gst_rtp_L16_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-raw, "
+ "format = (string) S16BE, "
+ "layout = (string) interleaved, "
+ "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
+ );
+
+static GstStaticPadTemplate gst_rtp_L16_depay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", " "clock-rate = (int) [ 1, MAX ], "
+ /* "channels = (int) [1, MAX]" */
+ /* "emphasis = (string) ANY" */
+ /* "channel-order = (string) ANY" */
+ "encoding-name = (string) \"L16\";"
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) { " GST_RTP_PAYLOAD_L16_STEREO_STRING ", "
+ GST_RTP_PAYLOAD_L16_MONO_STRING " }," "clock-rate = (int) [ 1, MAX ]"
+ /* "channels = (int) [1, MAX]" */
+ /* "emphasis = (string) ANY" */
+ /* "channel-order = (string) ANY" */
+ )
+ );
+
+#define gst_rtp_L16_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpL16Depay, gst_rtp_L16_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_L16_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_L16_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+
+static void
+gst_rtp_L16_depay_class_init (GstRtpL16DepayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gstrtpbasedepayload_class->set_caps = gst_rtp_L16_depay_setcaps;
+ gstrtpbasedepayload_class->process = gst_rtp_L16_depay_process;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_L16_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_L16_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP audio depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts raw audio from RTP packets",
+ "Zeeshan Ali <zak147@yahoo.com>," "Wim Taymans <wim.taymans@gmail.com>");
+
+ GST_DEBUG_CATEGORY_INIT (rtpL16depay_debug, "rtpL16depay", 0,
+ "Raw Audio RTP Depayloader");
+}
+
+static void
+gst_rtp_L16_depay_init (GstRtpL16Depay * rtpL16depay)
+{
+}
+
+static gint
+gst_rtp_L16_depay_parse_int (GstStructure * structure, const gchar * field,
+ gint def)
+{
+ const gchar *str;
+ gint res;
+
+ if ((str = gst_structure_get_string (structure, field)))
+ return atoi (str);
+
+ if (gst_structure_get_int (structure, field, &res))
+ return res;
+
+ return def;
+}
+
+static gboolean
+gst_rtp_L16_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstStructure *structure;
+ GstRtpL16Depay *rtpL16depay;
+ gint clock_rate, payload;
+ gint channels;
+ GstCaps *srccaps;
+ gboolean res;
+ const gchar *channel_order;
+ const GstRTPChannelOrder *order;
+ GstAudioInfo *info;
+
+ rtpL16depay = GST_RTP_L16_DEPAY (depayload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ payload = 96;
+ gst_structure_get_int (structure, "payload", &payload);
+ switch (payload) {
+ case GST_RTP_PAYLOAD_L16_STEREO:
+ channels = 2;
+ clock_rate = 44100;
+ break;
+ case GST_RTP_PAYLOAD_L16_MONO:
+ channels = 1;
+ clock_rate = 44100;
+ break;
+ default:
+ /* no fixed mapping, we need clock-rate */
+ channels = 0;
+ clock_rate = 0;
+ break;
+ }
+
+ /* caps can overwrite defaults */
+ clock_rate =
+ gst_rtp_L16_depay_parse_int (structure, "clock-rate", clock_rate);
+ if (clock_rate == 0)
+ goto no_clockrate;
+
+ channels =
+ gst_rtp_L16_depay_parse_int (structure, "encoding-params", channels);
+ if (channels == 0) {
+ channels = gst_rtp_L16_depay_parse_int (structure, "channels", channels);
+ if (channels == 0) {
+ /* channels defaults to 1 otherwise */
+ channels = 1;
+ }
+ }
+
+ depayload->clock_rate = clock_rate;
+
+ info = &rtpL16depay->info;
+ gst_audio_info_init (info);
+ info->finfo = gst_audio_format_get_info (GST_AUDIO_FORMAT_S16BE);
+ info->rate = clock_rate;
+ info->channels = channels;
+ info->bpf = (info->finfo->width / 8) * channels;
+
+ /* add channel positions */
+ channel_order = gst_structure_get_string (structure, "channel-order");
+
+ order = gst_rtp_channels_get_by_order (channels, channel_order);
+ rtpL16depay->order = order;
+ if (order) {
+ memcpy (info->position, order->pos,
+ sizeof (GstAudioChannelPosition) * channels);
+ gst_audio_channel_positions_to_valid_order (info->position, info->channels);
+ } else {
+ GST_ELEMENT_WARNING (rtpL16depay, STREAM, DECODE,
+ (NULL), ("Unknown channel order '%s' for %d channels",
+ GST_STR_NULL (channel_order), channels));
+ /* create default NONE layout */
+ gst_rtp_channels_create_default (channels, info->position);
+ }
+
+ srccaps = gst_audio_info_to_caps (info);
+ res = gst_pad_set_caps (depayload->srcpad, srccaps);
+ gst_caps_unref (srccaps);
+
+ return res;
+
+ /* ERRORS */
+no_clockrate:
+ {
+ GST_ERROR_OBJECT (depayload, "no clock-rate specified");
+ return FALSE;
+ }
+}
+
+static GstBuffer *
+gst_rtp_L16_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpL16Depay *rtpL16depay;
+ GstBuffer *outbuf;
+ gint payload_len;
+ gboolean marker;
+ GstRTPBuffer rtp = { NULL };
+
+ rtpL16depay = GST_RTP_L16_DEPAY (depayload);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+
+ if (payload_len <= 0)
+ goto empty_packet;
+
+ GST_DEBUG_OBJECT (rtpL16depay, "got payload of %d bytes", payload_len);
+
+ outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
+ marker = gst_rtp_buffer_get_marker (&rtp);
+
+ if (marker) {
+ /* mark talk spurt with RESYNC */
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+ }
+
+ outbuf = gst_buffer_make_writable (outbuf);
+ if (rtpL16depay->order &&
+ !gst_audio_buffer_reorder_channels (outbuf,
+ rtpL16depay->info.finfo->format, rtpL16depay->info.channels,
+ rtpL16depay->info.position, rtpL16depay->order->pos)) {
+ goto reorder_failed;
+ }
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ return outbuf;
+
+ /* ERRORS */
+empty_packet:
+ {
+ GST_ELEMENT_WARNING (rtpL16depay, STREAM, DECODE,
+ ("Empty Payload."), (NULL));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+reorder_failed:
+ {
+ GST_ELEMENT_ERROR (rtpL16depay, STREAM, DECODE,
+ ("Channel reordering failed."), (NULL));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+}
+
+gboolean
+gst_rtp_L16_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpL16depay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_L16_DEPAY);
+}
diff --git a/gst/rtp/gstrtpL16depay.h b/gst/rtp/gstrtpL16depay.h
new file mode 100755
index 0000000..125d4cd
--- /dev/null
+++ b/gst/rtp/gstrtpL16depay.h
@@ -0,0 +1,67 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_L16_DEPAY_H__
+#define __GST_RTP_L16_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+#include <gst/audio/audio.h>
+
+#include "gstrtpchannels.h"
+
+G_BEGIN_DECLS
+
+/* Standard macros for defining types for this element. */
+#define GST_TYPE_RTP_L16_DEPAY \
+ (gst_rtp_L16_depay_get_type())
+#define GST_RTP_L16_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_L16_DEPAY,GstRtpL16Depay))
+#define GST_RTP_L16_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_L16_DEPAY,GstRtpL16DepayClass))
+#define GST_IS_RTP_L16_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_L16_DEPAY))
+#define GST_IS_RTP_L16_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_L16_DEPAY))
+
+typedef struct _GstRtpL16Depay GstRtpL16Depay;
+typedef struct _GstRtpL16DepayClass GstRtpL16DepayClass;
+
+/* Definition of structure storing data for this element. */
+struct _GstRtpL16Depay
+{
+ GstRTPBaseDepayload depayload;
+
+ GstAudioInfo info;
+ const GstRTPChannelOrder *order;
+};
+
+/* Standard definition defining a class for this element. */
+struct _GstRtpL16DepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_L16_depay_get_type (void);
+
+gboolean gst_rtp_L16_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_L16_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpL16pay.c b/gst/rtp/gstrtpL16pay.c
new file mode 100755
index 0000000..a8ed36f
--- /dev/null
+++ b/gst/rtp/gstrtpL16pay.c
@@ -0,0 +1,263 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpL16pay
+ * @see_also: rtpL16depay
+ *
+ * Payload raw audio into RTP packets according to RFC 3551.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc3551.txt
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 -v audiotestsrc ! audioconvert ! rtpL16pay ! udpsink
+ * ]| This example pipeline will payload raw audio. Refer to
+ * the rtpL16depay example to depayload and play the RTP stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/audio/audio.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpL16pay.h"
+#include "gstrtpchannels.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpL16pay_debug);
+#define GST_CAT_DEFAULT (rtpL16pay_debug)
+
+static GstStaticPadTemplate gst_rtp_L16_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-raw, "
+ "format = (string) S16BE, "
+ "layout = (string) interleaved, "
+ "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
+ );
+
+static GstStaticPadTemplate gst_rtp_L16_pay_src_template =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) [ 96, 127 ], "
+ "clock-rate = (int) [ 1, MAX ], "
+ "encoding-name = (string) \"L16\", "
+ "channels = (int) [ 1, MAX ];"
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "encoding-name = (string) \"L16\", "
+ "payload = (int) " GST_RTP_PAYLOAD_L16_STEREO_STRING ", "
+ "clock-rate = (int) 44100;"
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "encoding-name = (string) \"L16\", "
+ "payload = (int) " GST_RTP_PAYLOAD_L16_MONO_STRING ", "
+ "clock-rate = (int) 44100")
+ );
+
+static gboolean gst_rtp_L16_pay_setcaps (GstRTPBasePayload * basepayload,
+ GstCaps * caps);
+static GstCaps *gst_rtp_L16_pay_getcaps (GstRTPBasePayload * rtppayload,
+ GstPad * pad, GstCaps * filter);
+static GstFlowReturn
+gst_rtp_L16_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer);
+
+#define gst_rtp_L16_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpL16Pay, gst_rtp_L16_pay, GST_TYPE_RTP_BASE_AUDIO_PAYLOAD);
+
+static void
+gst_rtp_L16_pay_class_init (GstRtpL16PayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_L16_pay_setcaps;
+ gstrtpbasepayload_class->get_caps = gst_rtp_L16_pay_getcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_L16_pay_handle_buffer;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_L16_pay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_L16_pay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP audio payloader", "Codec/Payloader/Network/RTP",
+ "Payload-encode Raw audio into RTP packets (RFC 3551)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ GST_DEBUG_CATEGORY_INIT (rtpL16pay_debug, "rtpL16pay", 0,
+ "L16 RTP Payloader");
+}
+
+static void
+gst_rtp_L16_pay_init (GstRtpL16Pay * rtpL16pay)
+{
+ GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+ rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpL16pay);
+
+ /* tell rtpbaseaudiopayload that this is a sample based codec */
+ gst_rtp_base_audio_payload_set_sample_based (rtpbaseaudiopayload);
+}
+
+static gboolean
+gst_rtp_L16_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
+{
+ GstRtpL16Pay *rtpL16pay;
+ gboolean res;
+ gchar *params;
+ GstAudioInfo *info;
+ const GstRTPChannelOrder *order;
+ GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+ rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (basepayload);
+ rtpL16pay = GST_RTP_L16_PAY (basepayload);
+
+ info = &rtpL16pay->info;
+ gst_audio_info_init (info);
+ if (!gst_audio_info_from_caps (info, caps))
+ goto invalid_caps;
+
+ order = gst_rtp_channels_get_by_pos (info->channels, info->position);
+ rtpL16pay->order = order;
+
+ gst_rtp_base_payload_set_options (basepayload, "audio", TRUE, "L16",
+ info->rate);
+ params = g_strdup_printf ("%d", info->channels);
+
+ if (!order && info->channels > 2) {
+ GST_ELEMENT_WARNING (rtpL16pay, STREAM, DECODE,
+ (NULL), ("Unknown channel order for %d channels", info->channels));
+ }
+
+ if (order && order->name) {
+ res = gst_rtp_base_payload_set_outcaps (basepayload,
+ "encoding-params", G_TYPE_STRING, params, "channels", G_TYPE_INT,
+ info->channels, "channel-order", G_TYPE_STRING, order->name, NULL);
+ } else {
+ res = gst_rtp_base_payload_set_outcaps (basepayload,
+ "encoding-params", G_TYPE_STRING, params, "channels", G_TYPE_INT,
+ info->channels, NULL);
+ }
+
+ g_free (params);
+
+ /* octet-per-sample is 2 * channels for L16 */
+ gst_rtp_base_audio_payload_set_sample_options (rtpbaseaudiopayload,
+ 2 * info->channels);
+
+ return res;
+
+ /* ERRORS */
+invalid_caps:
+ {
+ GST_DEBUG_OBJECT (rtpL16pay, "invalid caps");
+ return FALSE;
+ }
+}
+
+static GstCaps *
+gst_rtp_L16_pay_getcaps (GstRTPBasePayload * rtppayload, GstPad * pad,
+ GstCaps * filter)
+{
+ GstCaps *otherpadcaps;
+ GstCaps *caps;
+
+ caps = gst_pad_get_pad_template_caps (pad);
+
+ otherpadcaps = gst_pad_get_allowed_caps (rtppayload->srcpad);
+ if (otherpadcaps) {
+ if (!gst_caps_is_empty (otherpadcaps)) {
+ GstStructure *structure;
+ gint channels;
+ gint pt;
+ gint rate;
+
+ structure = gst_caps_get_structure (otherpadcaps, 0);
+ caps = gst_caps_make_writable (caps);
+
+ if (gst_structure_get_int (structure, "channels", &channels)) {
+ gst_caps_set_simple (caps, "channels", G_TYPE_INT, channels, NULL);
+ } else if (gst_structure_get_int (structure, "payload", &pt)) {
+ if (pt == 10)
+ gst_caps_set_simple (caps, "channels", G_TYPE_INT, 2, NULL);
+ else if (pt == 11)
+ gst_caps_set_simple (caps, "channels", G_TYPE_INT, 1, NULL);
+ }
+
+ if (gst_structure_get_int (structure, "clock-rate", &rate)) {
+ gst_caps_set_simple (caps, "rate", G_TYPE_INT, rate, NULL);
+ } else if (gst_structure_get_int (structure, "payload", &pt)) {
+ if (pt == 10 || pt == 11)
+ gst_caps_set_simple (caps, "rate", G_TYPE_INT, 44100, NULL);
+ }
+
+ }
+ gst_caps_unref (otherpadcaps);
+ }
+
+ if (filter) {
+ GstCaps *tcaps = caps;
+
+ caps = gst_caps_intersect_full (filter, tcaps, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (tcaps);
+ }
+
+ return caps;
+}
+
+static GstFlowReturn
+gst_rtp_L16_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer)
+{
+ GstRtpL16Pay *rtpL16pay;
+
+ rtpL16pay = GST_RTP_L16_PAY (basepayload);
+ buffer = gst_buffer_make_writable (buffer);
+
+ if (rtpL16pay->order &&
+ !gst_audio_buffer_reorder_channels (buffer, rtpL16pay->info.finfo->format,
+ rtpL16pay->info.channels, rtpL16pay->info.position,
+ rtpL16pay->order->pos)) {
+ return GST_FLOW_ERROR;
+ }
+
+ return GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->handle_buffer (basepayload,
+ buffer);
+}
+
+gboolean
+gst_rtp_L16_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpL16pay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_L16_PAY);
+}
diff --git a/gst/rtp/gstrtpL16pay.h b/gst/rtp/gstrtpL16pay.h
new file mode 100755
index 0000000..f4f3702
--- /dev/null
+++ b/gst/rtp/gstrtpL16pay.h
@@ -0,0 +1,63 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_L16_PAY_H__
+#define __GST_RTP_L16_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+#include "gstrtpchannels.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_L16_PAY \
+ (gst_rtp_L16_pay_get_type())
+#define GST_RTP_L16_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_L16_PAY,GstRtpL16Pay))
+#define GST_RTP_L16_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_L16_PAY,GstRtpL16PayClass))
+#define GST_IS_RTP_L16_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_L16_PAY))
+#define GST_IS_RTP_L16_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_L16_PAY))
+
+typedef struct _GstRtpL16Pay GstRtpL16Pay;
+typedef struct _GstRtpL16PayClass GstRtpL16PayClass;
+
+struct _GstRtpL16Pay
+{
+ GstRTPBaseAudioPayload payload;
+
+ GstAudioInfo info;
+ const GstRTPChannelOrder *order;
+};
+
+struct _GstRtpL16PayClass
+{
+ GstRTPBaseAudioPayloadClass parent_class;
+};
+
+GType gst_rtp_L16_pay_get_type (void);
+
+gboolean gst_rtp_L16_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_L16_PAY_H__ */
diff --git a/gst/rtp/gstrtpL24depay.c b/gst/rtp/gstrtpL24depay.c
new file mode 100755
index 0000000..7b5ef0c
--- /dev/null
+++ b/gst/rtp/gstrtpL24depay.c
@@ -0,0 +1,266 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpL24depay
+ * @see_also: rtpL24pay
+ *
+ * Extract raw audio from RTP packets according to RFC 3190, section 4.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc3190.txt
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 udpsrc caps='application/x-rtp, media=(string)audio, clock-rate=(int)44100, encoding-name=(string)L24, encoding-params=(string)1, channels=(int)1, payload=(int)96' ! rtpL24depay ! pulsesink
+ * ]| This example pipeline will depayload an RTP raw audio stream. Refer to
+ * the rtpL24pay example to create the RTP stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gst/audio/audio.h>
+
+#include "gstrtpL24depay.h"
+#include "gstrtpchannels.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpL24depay_debug);
+#define GST_CAT_DEFAULT (rtpL24depay_debug)
+
+static GstStaticPadTemplate gst_rtp_L24_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-raw, "
+ "format = (string) S24BE, "
+ "layout = (string) interleaved, "
+ "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
+ );
+
+static GstStaticPadTemplate gst_rtp_L24_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", " "clock-rate = (int) [ 1, MAX ], "
+ "encoding-name = (string) \"L24\"")
+ );
+
+#define gst_rtp_L24_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpL24Depay, gst_rtp_L24_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_L24_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_L24_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+
+static void
+gst_rtp_L24_depay_class_init (GstRtpL24DepayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gstrtpbasedepayload_class->set_caps = gst_rtp_L24_depay_setcaps;
+ gstrtpbasedepayload_class->process = gst_rtp_L24_depay_process;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_L24_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_L24_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP audio depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts raw 24-bit audio from RTP packets",
+ "Zeeshan Ali <zak147@yahoo.com>," "Wim Taymans <wim.taymans@gmail.com>,"
+ "David Holroyd <dave@badgers-in-foil.co.uk>");
+
+ GST_DEBUG_CATEGORY_INIT (rtpL24depay_debug, "rtpL24depay", 0,
+ "Raw Audio RTP Depayloader");
+}
+
+static void
+gst_rtp_L24_depay_init (GstRtpL24Depay * rtpL24depay)
+{
+}
+
+static gint
+gst_rtp_L24_depay_parse_int (GstStructure * structure, const gchar * field,
+ gint def)
+{
+ const gchar *str;
+ gint res;
+
+ if ((str = gst_structure_get_string (structure, field)))
+ return atoi (str);
+
+ if (gst_structure_get_int (structure, field, &res))
+ return res;
+
+ return def;
+}
+
+static gboolean
+gst_rtp_L24_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstStructure *structure;
+ GstRtpL24Depay *rtpL24depay;
+ gint clock_rate, payload;
+ gint channels;
+ GstCaps *srccaps;
+ gboolean res;
+ const gchar *channel_order;
+ const GstRTPChannelOrder *order;
+ GstAudioInfo *info;
+
+ rtpL24depay = GST_RTP_L24_DEPAY (depayload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ payload = 96;
+ gst_structure_get_int (structure, "payload", &payload);
+ /* no fixed mapping, we need clock-rate */
+ channels = 0;
+ clock_rate = 0;
+
+ /* caps can overwrite defaults */
+ clock_rate =
+ gst_rtp_L24_depay_parse_int (structure, "clock-rate", clock_rate);
+ if (clock_rate == 0)
+ goto no_clockrate;
+
+ channels =
+ gst_rtp_L24_depay_parse_int (structure, "encoding-params", channels);
+ if (channels == 0) {
+ channels = gst_rtp_L24_depay_parse_int (structure, "channels", channels);
+ if (channels == 0) {
+ /* channels defaults to 1 otherwise */
+ channels = 1;
+ }
+ }
+
+ depayload->clock_rate = clock_rate;
+
+ info = &rtpL24depay->info;
+ gst_audio_info_init (info);
+ info->finfo = gst_audio_format_get_info (GST_AUDIO_FORMAT_S24BE);
+ info->rate = clock_rate;
+ info->channels = channels;
+ info->bpf = (info->finfo->width / 8) * channels;
+
+ /* add channel positions */
+ channel_order = gst_structure_get_string (structure, "channel-order");
+
+ order = gst_rtp_channels_get_by_order (channels, channel_order);
+ rtpL24depay->order = order;
+ if (order) {
+ memcpy (info->position, order->pos,
+ sizeof (GstAudioChannelPosition) * channels);
+ gst_audio_channel_positions_to_valid_order (info->position, info->channels);
+ } else {
+ GST_ELEMENT_WARNING (rtpL24depay, STREAM, DECODE,
+ (NULL), ("Unknown channel order '%s' for %d channels",
+ GST_STR_NULL (channel_order), channels));
+ /* create default NONE layout */
+ gst_rtp_channels_create_default (channels, info->position);
+ }
+
+ srccaps = gst_audio_info_to_caps (info);
+ res = gst_pad_set_caps (depayload->srcpad, srccaps);
+ gst_caps_unref (srccaps);
+
+ return res;
+
+ /* ERRORS */
+no_clockrate:
+ {
+ GST_ERROR_OBJECT (depayload, "no clock-rate specified");
+ return FALSE;
+ }
+}
+
+static GstBuffer *
+gst_rtp_L24_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpL24Depay *rtpL24depay;
+ GstBuffer *outbuf;
+ gint payload_len;
+ gboolean marker;
+ GstRTPBuffer rtp = { NULL };
+
+ rtpL24depay = GST_RTP_L24_DEPAY (depayload);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+
+ if (payload_len <= 0)
+ goto empty_packet;
+
+ GST_DEBUG_OBJECT (rtpL24depay, "got payload of %d bytes", payload_len);
+
+ outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
+ marker = gst_rtp_buffer_get_marker (&rtp);
+
+ if (marker) {
+ /* mark talk spurt with RESYNC */
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+ }
+
+ outbuf = gst_buffer_make_writable (outbuf);
+ if (rtpL24depay->order &&
+ !gst_audio_buffer_reorder_channels (outbuf,
+ rtpL24depay->info.finfo->format, rtpL24depay->info.channels,
+ rtpL24depay->info.position, rtpL24depay->order->pos)) {
+ goto reorder_failed;
+ }
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ return outbuf;
+
+ /* ERRORS */
+empty_packet:
+ {
+ GST_ELEMENT_WARNING (rtpL24depay, STREAM, DECODE,
+ ("Empty Payload."), (NULL));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+reorder_failed:
+ {
+ GST_ELEMENT_ERROR (rtpL24depay, STREAM, DECODE,
+ ("Channel reordering failed."), (NULL));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+}
+
+gboolean
+gst_rtp_L24_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpL24depay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_L24_DEPAY);
+}
diff --git a/gst/rtp/gstrtpL24depay.h b/gst/rtp/gstrtpL24depay.h
new file mode 100755
index 0000000..c4e00e6
--- /dev/null
+++ b/gst/rtp/gstrtpL24depay.h
@@ -0,0 +1,67 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_L24_DEPAY_H__
+#define __GST_RTP_L24_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+#include <gst/audio/audio.h>
+
+#include "gstrtpchannels.h"
+
+G_BEGIN_DECLS
+
+/* Standard macros for defining types for this element. */
+#define GST_TYPE_RTP_L24_DEPAY \
+ (gst_rtp_L24_depay_get_type())
+#define GST_RTP_L24_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_L24_DEPAY,GstRtpL24Depay))
+#define GST_RTP_L24_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_L24_DEPAY,GstRtpL24DepayClass))
+#define GST_IS_RTP_L24_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_L24_DEPAY))
+#define GST_IS_RTP_L24_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_L24_DEPAY))
+
+typedef struct _GstRtpL24Depay GstRtpL24Depay;
+typedef struct _GstRtpL24DepayClass GstRtpL24DepayClass;
+
+/* Definition of structure storing data for this element. */
+struct _GstRtpL24Depay
+{
+ GstRTPBaseDepayload depayload;
+
+ GstAudioInfo info;
+ const GstRTPChannelOrder *order;
+};
+
+/* Standard definition defining a class for this element. */
+struct _GstRtpL24DepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_L24_depay_get_type (void);
+
+gboolean gst_rtp_L24_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_L24_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpL24pay.c b/gst/rtp/gstrtpL24pay.c
new file mode 100755
index 0000000..1bb37cb
--- /dev/null
+++ b/gst/rtp/gstrtpL24pay.c
@@ -0,0 +1,244 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpL24pay
+ * @see_also: rtpL24depay
+ *
+ * Payload raw 24-bit audio into RTP packets according to RFC 3190, section 4.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc3190.txt
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 -v audiotestsrc ! audioconvert ! rtpL24pay ! udpsink
+ * ]| This example pipeline will payload raw audio. Refer to
+ * the rtpL24depay example to depayload and play the RTP stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/audio/audio.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpL24pay.h"
+#include "gstrtpchannels.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpL24pay_debug);
+#define GST_CAT_DEFAULT (rtpL24pay_debug)
+
+static GstStaticPadTemplate gst_rtp_L24_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-raw, "
+ "format = (string) S24BE, "
+ "layout = (string) interleaved, "
+ "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
+ );
+
+static GstStaticPadTemplate gst_rtp_L24_pay_src_template =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) [ 96, 127 ], "
+ "clock-rate = (int) [ 1, MAX ], "
+ "encoding-name = (string) \"L24\", " "channels = (int) [ 1, MAX ];")
+ );
+
+static gboolean gst_rtp_L24_pay_setcaps (GstRTPBasePayload * basepayload,
+ GstCaps * caps);
+static GstCaps *gst_rtp_L24_pay_getcaps (GstRTPBasePayload * rtppayload,
+ GstPad * pad, GstCaps * filter);
+static GstFlowReturn
+gst_rtp_L24_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer);
+
+#define gst_rtp_L24_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpL24Pay, gst_rtp_L24_pay, GST_TYPE_RTP_BASE_AUDIO_PAYLOAD);
+
+static void
+gst_rtp_L24_pay_class_init (GstRtpL24PayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_L24_pay_setcaps;
+ gstrtpbasepayload_class->get_caps = gst_rtp_L24_pay_getcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_L24_pay_handle_buffer;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_L24_pay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_L24_pay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP audio payloader", "Codec/Payloader/Network/RTP",
+ "Payload-encode Raw 24-bit audio into RTP packets (RFC 3190)",
+ "Wim Taymans <wim.taymans@gmail.com>,"
+ "David Holroyd <dave@badgers-in-foil.co.uk>");
+
+ GST_DEBUG_CATEGORY_INIT (rtpL24pay_debug, "rtpL24pay", 0,
+ "L24 RTP Payloader");
+}
+
+static void
+gst_rtp_L24_pay_init (GstRtpL24Pay * rtpL24pay)
+{
+ GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+ rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpL24pay);
+
+ /* tell rtpbaseaudiopayload that this is a sample based codec */
+ gst_rtp_base_audio_payload_set_sample_based (rtpbaseaudiopayload);
+}
+
+static gboolean
+gst_rtp_L24_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
+{
+ GstRtpL24Pay *rtpL24pay;
+ gboolean res;
+ gchar *params;
+ GstAudioInfo *info;
+ const GstRTPChannelOrder *order;
+ GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+ rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (basepayload);
+ rtpL24pay = GST_RTP_L24_PAY (basepayload);
+
+ info = &rtpL24pay->info;
+ gst_audio_info_init (info);
+ if (!gst_audio_info_from_caps (info, caps))
+ goto invalid_caps;
+
+ order = gst_rtp_channels_get_by_pos (info->channels, info->position);
+ rtpL24pay->order = order;
+
+ gst_rtp_base_payload_set_options (basepayload, "audio", TRUE, "L24",
+ info->rate);
+ params = g_strdup_printf ("%d", info->channels);
+
+ if (!order && info->channels > 2) {
+ GST_ELEMENT_WARNING (rtpL24pay, STREAM, DECODE,
+ (NULL), ("Unknown channel order for %d channels", info->channels));
+ }
+
+ if (order && order->name) {
+ res = gst_rtp_base_payload_set_outcaps (basepayload,
+ "encoding-params", G_TYPE_STRING, params, "channels", G_TYPE_INT,
+ info->channels, "channel-order", G_TYPE_STRING, order->name, NULL);
+ } else {
+ res = gst_rtp_base_payload_set_outcaps (basepayload,
+ "encoding-params", G_TYPE_STRING, params, "channels", G_TYPE_INT,
+ info->channels, NULL);
+ }
+
+ g_free (params);
+
+ /* octet-per-sample is 3 * channels for L24 */
+ gst_rtp_base_audio_payload_set_sample_options (rtpbaseaudiopayload,
+ 3 * info->channels);
+
+ return res;
+
+ /* ERRORS */
+invalid_caps:
+ {
+ GST_DEBUG_OBJECT (rtpL24pay, "invalid caps");
+ return FALSE;
+ }
+}
+
+static GstCaps *
+gst_rtp_L24_pay_getcaps (GstRTPBasePayload * rtppayload, GstPad * pad,
+ GstCaps * filter)
+{
+ GstCaps *otherpadcaps;
+ GstCaps *caps;
+
+ caps = gst_pad_get_pad_template_caps (pad);
+
+ otherpadcaps = gst_pad_get_allowed_caps (rtppayload->srcpad);
+ if (otherpadcaps) {
+ if (!gst_caps_is_empty (otherpadcaps)) {
+ GstStructure *structure;
+ gint channels;
+ gint rate;
+
+ structure = gst_caps_get_structure (otherpadcaps, 0);
+ caps = gst_caps_make_writable (caps);
+
+ if (gst_structure_get_int (structure, "channels", &channels)) {
+ gst_caps_set_simple (caps, "channels", G_TYPE_INT, channels, NULL);
+ }
+
+ if (gst_structure_get_int (structure, "clock-rate", &rate)) {
+ gst_caps_set_simple (caps, "rate", G_TYPE_INT, rate, NULL);
+ }
+
+ }
+ gst_caps_unref (otherpadcaps);
+ }
+
+ if (filter) {
+ GstCaps *tcaps = caps;
+
+ caps = gst_caps_intersect_full (filter, tcaps, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (tcaps);
+ }
+
+ return caps;
+}
+
+static GstFlowReturn
+gst_rtp_L24_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer)
+{
+ GstRtpL24Pay *rtpL24pay;
+
+ rtpL24pay = GST_RTP_L24_PAY (basepayload);
+ buffer = gst_buffer_make_writable (buffer);
+
+ if (rtpL24pay->order &&
+ !gst_audio_buffer_reorder_channels (buffer, rtpL24pay->info.finfo->format,
+ rtpL24pay->info.channels, rtpL24pay->info.position,
+ rtpL24pay->order->pos)) {
+ return GST_FLOW_ERROR;
+ }
+
+ return GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->handle_buffer (basepayload,
+ buffer);
+}
+
+gboolean
+gst_rtp_L24_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpL24pay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_L24_PAY);
+}
diff --git a/gst/rtp/gstrtpL24pay.h b/gst/rtp/gstrtpL24pay.h
new file mode 100755
index 0000000..47395ad
--- /dev/null
+++ b/gst/rtp/gstrtpL24pay.h
@@ -0,0 +1,63 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_L24_PAY_H__
+#define __GST_RTP_L24_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+#include "gstrtpchannels.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_L24_PAY \
+ (gst_rtp_L24_pay_get_type())
+#define GST_RTP_L24_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_L24_PAY,GstRtpL24Pay))
+#define GST_RTP_L24_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_L24_PAY,GstRtpL24PayClass))
+#define GST_IS_RTP_L24_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_L24_PAY))
+#define GST_IS_RTP_L24_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_L24_PAY))
+
+typedef struct _GstRtpL24Pay GstRtpL24Pay;
+typedef struct _GstRtpL24PayClass GstRtpL24PayClass;
+
+struct _GstRtpL24Pay
+{
+ GstRTPBaseAudioPayload payload;
+
+ GstAudioInfo info;
+ const GstRTPChannelOrder *order;
+};
+
+struct _GstRtpL24PayClass
+{
+ GstRTPBaseAudioPayloadClass parent_class;
+};
+
+GType gst_rtp_L24_pay_get_type (void);
+
+gboolean gst_rtp_L24_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_L24_PAY_H__ */
diff --git a/gst/rtp/gstrtpac3depay.c b/gst/rtp/gstrtpac3depay.c
new file mode 100755
index 0000000..e8a05c9
--- /dev/null
+++ b/gst/rtp/gstrtpac3depay.c
@@ -0,0 +1,182 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpac3depay
+ * @see_also: rtpac3pay
+ *
+ * Extract AC3 audio from RTP packets according to RFC 4184.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc4184.txt
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 udpsrc caps='application/x-rtp, media=(string)audio, clock-rate=(int)44100, encoding-name=(string)AC3, payload=(int)96' ! rtpac3depay ! a52dec ! pulsesink
+ * ]| This example pipeline will depayload and decode an RTP AC3 stream. Refer to
+ * the rtpac3pay example to create the RTP stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <string.h>
+#include "gstrtpac3depay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpac3depay_debug);
+#define GST_CAT_DEFAULT (rtpac3depay_debug)
+
+static GstStaticPadTemplate gst_rtp_ac3_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/ac3")
+ );
+
+static GstStaticPadTemplate gst_rtp_ac3_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "clock-rate = (int) { 32000, 44100, 48000 }, "
+ "encoding-name = (string) \"AC3\"")
+ );
+
+G_DEFINE_TYPE (GstRtpAC3Depay, gst_rtp_ac3_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_ac3_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_ac3_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+
+static void
+gst_rtp_ac3_depay_class_init (GstRtpAC3DepayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_ac3_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_ac3_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP AC3 depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts AC3 audio from RTP packets (RFC 4184)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ gstrtpbasedepayload_class->set_caps = gst_rtp_ac3_depay_setcaps;
+ gstrtpbasedepayload_class->process = gst_rtp_ac3_depay_process;
+
+ GST_DEBUG_CATEGORY_INIT (rtpac3depay_debug, "rtpac3depay", 0,
+ "AC3 Audio RTP Depayloader");
+}
+
+static void
+gst_rtp_ac3_depay_init (GstRtpAC3Depay * rtpac3depay)
+{
+ /* needed because of G_DEFINE_TYPE */
+}
+
+static gboolean
+gst_rtp_ac3_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstStructure *structure;
+ gint clock_rate;
+ GstCaps *srccaps;
+ gboolean res;
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 90000; /* default */
+ depayload->clock_rate = clock_rate;
+
+ srccaps = gst_caps_new_empty_simple ("audio/ac3");
+ res = gst_pad_set_caps (depayload->srcpad, srccaps);
+ gst_caps_unref (srccaps);
+
+ return res;
+}
+
+static GstBuffer *
+gst_rtp_ac3_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpAC3Depay *rtpac3depay;
+ GstBuffer *outbuf;
+ GstRTPBuffer rtp = { NULL, };
+ guint8 *payload;
+ guint16 FT, NF;
+
+ rtpac3depay = GST_RTP_AC3_DEPAY (depayload);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ if (gst_rtp_buffer_get_payload_len (&rtp) < 2)
+ goto empty_packet;
+
+ payload = gst_rtp_buffer_get_payload (&rtp);
+
+ /* strip off header
+ *
+ * 0 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | MBZ | FT| NF |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ FT = payload[0] & 0x3;
+ NF = payload[1];
+
+ GST_DEBUG_OBJECT (rtpac3depay, "FT: %d, NF: %d", FT, NF);
+
+ /* We don't bother with fragmented packets yet */
+ outbuf = gst_rtp_buffer_get_payload_subbuffer (&rtp, 2, -1);
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ if (outbuf)
+ GST_DEBUG_OBJECT (rtpac3depay, "pushing buffer of size %" G_GSIZE_FORMAT,
+ gst_buffer_get_size (outbuf));
+
+ return outbuf;
+
+ /* ERRORS */
+empty_packet:
+ {
+ GST_ELEMENT_WARNING (rtpac3depay, STREAM, DECODE,
+ ("Empty Payload."), (NULL));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+}
+
+gboolean
+gst_rtp_ac3_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpac3depay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_AC3_DEPAY);
+}
diff --git a/gst/rtp/gstrtpac3depay.h b/gst/rtp/gstrtpac3depay.h
new file mode 100755
index 0000000..294bb12
--- /dev/null
+++ b/gst/rtp/gstrtpac3depay.h
@@ -0,0 +1,58 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_AC3_DEPAY_H__
+#define __GST_RTP_AC3_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_AC3_DEPAY \
+ (gst_rtp_ac3_depay_get_type())
+#define GST_RTP_AC3_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_AC3_DEPAY,GstRtpAC3Depay))
+#define GST_RTP_AC3_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_AC3_DEPAY,GstRtpAC3DepayClass))
+#define GST_IS_RTP_AC3_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_AC3_DEPAY))
+#define GST_IS_RTP_AC3_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_AC3_DEPAY))
+
+typedef struct _GstRtpAC3Depay GstRtpAC3Depay;
+typedef struct _GstRtpAC3DepayClass GstRtpAC3DepayClass;
+
+struct _GstRtpAC3Depay
+{
+ GstRTPBaseDepayload depayload;
+};
+
+struct _GstRtpAC3DepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_ac3_depay_get_type (void);
+
+gboolean gst_rtp_ac3_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_AC3_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpac3pay.c b/gst/rtp/gstrtpac3pay.c
new file mode 100755
index 0000000..e283afd
--- /dev/null
+++ b/gst/rtp/gstrtpac3pay.c
@@ -0,0 +1,469 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpac3pay
+ * @see_also: rtpac3depay
+ *
+ * Payload AC3 audio into RTP packets according to RFC 4184.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc4184.txt
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 -v audiotestsrc ! avenc_ac3 ! rtpac3pay ! udpsink
+ * ]| This example pipeline will encode and payload AC3 stream. Refer to
+ * the rtpac3depay example to depayload and decode the RTP stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpac3pay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpac3pay_debug);
+#define GST_CAT_DEFAULT (rtpac3pay_debug)
+
+static GstStaticPadTemplate gst_rtp_ac3_pay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/ac3; " "audio/x-ac3; ")
+ );
+
+static GstStaticPadTemplate gst_rtp_ac3_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) { 32000, 44100, 48000 }, "
+ "encoding-name = (string) \"AC3\"")
+ );
+
+static void gst_rtp_ac3_pay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_ac3_pay_change_state (GstElement * element,
+ GstStateChange transition);
+
+static gboolean gst_rtp_ac3_pay_setcaps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+static gboolean gst_rtp_ac3_pay_sink_event (GstRTPBasePayload * payload,
+ GstEvent * event);
+static GstFlowReturn gst_rtp_ac3_pay_flush (GstRtpAC3Pay * rtpac3pay);
+static GstFlowReturn gst_rtp_ac3_pay_handle_buffer (GstRTPBasePayload * payload,
+ GstBuffer * buffer);
+
+#define gst_rtp_ac3_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpAC3Pay, gst_rtp_ac3_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_ac3_pay_class_init (GstRtpAC3PayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ GST_DEBUG_CATEGORY_INIT (rtpac3pay_debug, "rtpac3pay", 0,
+ "AC3 Audio RTP Depayloader");
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_ac3_pay_finalize;
+
+ gstelement_class->change_state = gst_rtp_ac3_pay_change_state;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_ac3_pay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_ac3_pay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP AC3 audio payloader", "Codec/Payloader/Network/RTP",
+ "Payload AC3 audio as RTP packets (RFC 4184)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_ac3_pay_setcaps;
+ gstrtpbasepayload_class->sink_event = gst_rtp_ac3_pay_sink_event;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_ac3_pay_handle_buffer;
+}
+
+static void
+gst_rtp_ac3_pay_init (GstRtpAC3Pay * rtpac3pay)
+{
+ rtpac3pay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_ac3_pay_finalize (GObject * object)
+{
+ GstRtpAC3Pay *rtpac3pay;
+
+ rtpac3pay = GST_RTP_AC3_PAY (object);
+
+ g_object_unref (rtpac3pay->adapter);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_rtp_ac3_pay_reset (GstRtpAC3Pay * pay)
+{
+ pay->first_ts = -1;
+ pay->duration = 0;
+ gst_adapter_clear (pay->adapter);
+ GST_DEBUG_OBJECT (pay, "reset depayloader");
+}
+
+static gboolean
+gst_rtp_ac3_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ gboolean res;
+ gint rate;
+ GstStructure *structure;
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "rate", &rate))
+ rate = 90000; /* default */
+
+ gst_rtp_base_payload_set_options (payload, "audio", TRUE, "AC3", rate);
+ res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+
+ return res;
+}
+
+static gboolean
+gst_rtp_ac3_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+ gboolean res;
+ GstRtpAC3Pay *rtpac3pay;
+
+ rtpac3pay = GST_RTP_AC3_PAY (payload);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_EOS:
+ /* make sure we push the last packets in the adapter on EOS */
+ gst_rtp_ac3_pay_flush (rtpac3pay);
+ break;
+ case GST_EVENT_FLUSH_STOP:
+ gst_rtp_ac3_pay_reset (rtpac3pay);
+ break;
+ default:
+ break;
+ }
+
+ res = GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
+
+ return res;
+}
+
+struct frmsize_s
+{
+ guint16 bit_rate;
+ guint16 frm_size[3];
+};
+
+static const struct frmsize_s frmsizecod_tbl[] = {
+ {32, {64, 69, 96}},
+ {32, {64, 70, 96}},
+ {40, {80, 87, 120}},
+ {40, {80, 88, 120}},
+ {48, {96, 104, 144}},
+ {48, {96, 105, 144}},
+ {56, {112, 121, 168}},
+ {56, {112, 122, 168}},
+ {64, {128, 139, 192}},
+ {64, {128, 140, 192}},
+ {80, {160, 174, 240}},
+ {80, {160, 175, 240}},
+ {96, {192, 208, 288}},
+ {96, {192, 209, 288}},
+ {112, {224, 243, 336}},
+ {112, {224, 244, 336}},
+ {128, {256, 278, 384}},
+ {128, {256, 279, 384}},
+ {160, {320, 348, 480}},
+ {160, {320, 349, 480}},
+ {192, {384, 417, 576}},
+ {192, {384, 418, 576}},
+ {224, {448, 487, 672}},
+ {224, {448, 488, 672}},
+ {256, {512, 557, 768}},
+ {256, {512, 558, 768}},
+ {320, {640, 696, 960}},
+ {320, {640, 697, 960}},
+ {384, {768, 835, 1152}},
+ {384, {768, 836, 1152}},
+ {448, {896, 975, 1344}},
+ {448, {896, 976, 1344}},
+ {512, {1024, 1114, 1536}},
+ {512, {1024, 1115, 1536}},
+ {576, {1152, 1253, 1728}},
+ {576, {1152, 1254, 1728}},
+ {640, {1280, 1393, 1920}},
+ {640, {1280, 1394, 1920}}
+};
+
+static GstFlowReturn
+gst_rtp_ac3_pay_flush (GstRtpAC3Pay * rtpac3pay)
+{
+ guint avail, FT, NF, mtu;
+ GstBuffer *outbuf;
+ GstFlowReturn ret;
+
+ /* the data available in the adapter is either smaller
+ * than the MTU or bigger. In the case it is smaller, the complete
+ * adapter contents can be put in one packet. In the case the
+ * adapter has more than one MTU, we need to split the AC3 data
+ * over multiple packets. */
+ avail = gst_adapter_available (rtpac3pay->adapter);
+
+ ret = GST_FLOW_OK;
+
+ FT = 0;
+ /* number of frames */
+ NF = rtpac3pay->NF;
+
+ mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpac3pay);
+
+ GST_LOG_OBJECT (rtpac3pay, "flushing %u bytes", avail);
+
+ while (avail > 0) {
+ guint towrite;
+ guint8 *payload;
+ guint payload_len;
+ guint packet_len;
+ GstRTPBuffer rtp = { NULL, };
+
+ /* this will be the total length of the packet */
+ packet_len = gst_rtp_buffer_calc_packet_len (2 + avail, 0, 0);
+
+ /* fill one MTU or all available bytes */
+ towrite = MIN (packet_len, mtu);
+
+ /* this is the payload length */
+ payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
+
+ /* create buffer to hold the payload */
+ outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
+
+ if (FT == 0) {
+ /* check if it all fits */
+ if (towrite < packet_len) {
+ guint maxlen;
+
+ GST_LOG_OBJECT (rtpac3pay, "we need to fragment");
+ /* check if we will be able to put at least 5/8th of the total
+ * frame in this first frame. */
+ if ((avail * 5) / 8 >= (payload_len - 2))
+ FT = 1;
+ else
+ FT = 2;
+ /* check how many fragments we will need */
+ maxlen = gst_rtp_buffer_calc_payload_len (mtu - 2, 0, 0);
+ NF = (avail + maxlen - 1) / maxlen;
+ }
+ } else if (FT != 3) {
+ /* remaining fragment */
+ FT = 3;
+ }
+
+ /*
+ * 0 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | MBZ | FT| NF |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * FT: 0: one or more complete frames
+ * 1: initial 5/8 fragment
+ * 2: initial fragment not 5/8
+ * 3: other fragment
+ * NF: amount of frames if FT = 0, else number of fragments.
+ */
+ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+ GST_LOG_OBJECT (rtpac3pay, "FT %u, NF %u", FT, NF);
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ payload[0] = (FT & 3);
+ payload[1] = NF;
+ payload_len -= 2;
+
+ gst_adapter_copy (rtpac3pay->adapter, &payload[2], 0, payload_len);
+ gst_adapter_flush (rtpac3pay->adapter, payload_len);
+
+ avail -= payload_len;
+ if (avail == 0)
+ gst_rtp_buffer_set_marker (&rtp, TRUE);
+ gst_rtp_buffer_unmap (&rtp);
+
+ GST_BUFFER_TIMESTAMP (outbuf) = rtpac3pay->first_ts;
+ GST_BUFFER_DURATION (outbuf) = rtpac3pay->duration;
+
+ ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpac3pay), outbuf);
+ }
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_rtp_ac3_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer)
+{
+ GstRtpAC3Pay *rtpac3pay;
+ GstFlowReturn ret;
+ gsize avail, left, NF;
+ GstMapInfo map;
+ guint8 *p;
+ guint packet_len;
+ GstClockTime duration, timestamp;
+
+ rtpac3pay = GST_RTP_AC3_PAY (basepayload);
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+ duration = GST_BUFFER_DURATION (buffer);
+ timestamp = GST_BUFFER_TIMESTAMP (buffer);
+
+ if (GST_BUFFER_IS_DISCONT (buffer)) {
+ GST_DEBUG_OBJECT (rtpac3pay, "DISCONT");
+ gst_rtp_ac3_pay_reset (rtpac3pay);
+ }
+
+ /* count the amount of incomming packets */
+ NF = 0;
+ left = map.size;
+ p = map.data;
+ while (TRUE) {
+ guint bsid, fscod, frmsizecod, frame_size;
+
+ if (left < 6)
+ break;
+
+ if (p[0] != 0x0b || p[1] != 0x77)
+ break;
+
+ bsid = p[5] >> 3;
+ if (bsid > 8)
+ break;
+
+ frmsizecod = p[4] & 0x3f;
+ fscod = p[4] >> 6;
+
+ GST_DEBUG_OBJECT (rtpac3pay, "fscod %u, %u", fscod, frmsizecod);
+
+ if (fscod >= 3 || frmsizecod >= 38)
+ break;
+
+ frame_size = frmsizecod_tbl[frmsizecod].frm_size[fscod] * 2;
+ if (frame_size > left)
+ break;
+
+ NF++;
+ GST_DEBUG_OBJECT (rtpac3pay, "found frame %" G_GSIZE_FORMAT " of size %u",
+ NF, frame_size);
+
+ p += frame_size;
+ left -= frame_size;
+ }
+ gst_buffer_unmap (buffer, &map);
+ if (NF == 0)
+ goto no_frames;
+
+ avail = gst_adapter_available (rtpac3pay->adapter);
+
+ /* get packet length of previous data and this new data,
+ * payload length includes a 4 byte header */
+ packet_len = gst_rtp_buffer_calc_packet_len (2 + avail + map.size, 0, 0);
+
+ /* if this buffer is going to overflow the packet, flush what we
+ * have. */
+ if (gst_rtp_base_payload_is_filled (basepayload,
+ packet_len, rtpac3pay->duration + duration)) {
+ ret = gst_rtp_ac3_pay_flush (rtpac3pay);
+ avail = 0;
+ } else {
+ ret = GST_FLOW_OK;
+ }
+
+ if (avail == 0) {
+ GST_DEBUG_OBJECT (rtpac3pay,
+ "first packet, save timestamp %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (timestamp));
+ rtpac3pay->first_ts = timestamp;
+ rtpac3pay->duration = 0;
+ rtpac3pay->NF = 0;
+ }
+
+ gst_adapter_push (rtpac3pay->adapter, buffer);
+ rtpac3pay->duration += duration;
+ rtpac3pay->NF += NF;
+
+ return ret;
+
+ /* ERRORS */
+no_frames:
+ {
+ GST_WARNING_OBJECT (rtpac3pay, "no valid AC3 frames found");
+ return GST_FLOW_OK;
+ }
+}
+
+static GstStateChangeReturn
+gst_rtp_ac3_pay_change_state (GstElement * element, GstStateChange transition)
+{
+ GstRtpAC3Pay *rtpac3pay;
+ GstStateChangeReturn ret;
+
+ rtpac3pay = GST_RTP_AC3_PAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_rtp_ac3_pay_reset (rtpac3pay);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_rtp_ac3_pay_reset (rtpac3pay);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+gboolean
+gst_rtp_ac3_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpac3pay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_AC3_PAY);
+}
diff --git a/gst/rtp/gstrtpac3pay.h b/gst/rtp/gstrtpac3pay.h
new file mode 100755
index 0000000..c131eac
--- /dev/null
+++ b/gst/rtp/gstrtpac3pay.h
@@ -0,0 +1,64 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_AC3_PAY_H__
+#define __GST_RTP_AC3_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_AC3_PAY \
+ (gst_rtp_ac3_pay_get_type())
+#define GST_RTP_AC3_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_AC3_PAY,GstRtpAC3Pay))
+#define GST_RTP_AC3_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_AC3_PAY,GstRtpAC3PayClass))
+#define GST_IS_RTP_AC3_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_AC3_PAY))
+#define GST_IS_RTP_AC3_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_AC3_PAY))
+
+typedef struct _GstRtpAC3Pay GstRtpAC3Pay;
+typedef struct _GstRtpAC3PayClass GstRtpAC3PayClass;
+
+struct _GstRtpAC3Pay
+{
+ GstRTPBasePayload payload;
+
+ GstAdapter *adapter;
+ GstClockTime first_ts;
+ GstClockTime duration;
+ guint NF;
+};
+
+struct _GstRtpAC3PayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_ac3_pay_get_type (void);
+
+gboolean gst_rtp_ac3_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_AC3_PAY_H__ */
diff --git a/gst/rtp/gstrtpamrdepay.c b/gst/rtp/gstrtpamrdepay.c
new file mode 100755
index 0000000..4b53843
--- /dev/null
+++ b/gst/rtp/gstrtpamrdepay.c
@@ -0,0 +1,479 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpamrdepay
+ * @see_also: rtpamrpay
+ *
+ * Extract AMR audio from RTP packets according to RFC 3267.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc3267.txt
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 udpsrc caps='application/x-rtp, media=(string)audio, clock-rate=(int)8000, encoding-name=(string)AMR, encoding-params=(string)1, octet-align=(string)1, payload=(int)96' ! rtpamrdepay ! amrnbdec ! pulsesink
+ * ]| This example pipeline will depayload and decode an RTP AMR stream. Refer to
+ * the rtpamrpay example to create the RTP stream.
+ * </refsect2>
+ */
+
+/*
+ * RFC 3267 - Real-Time Transport Protocol (RTP) Payload Format and File
+ * Storage Format for the Adaptive Multi-Rate (AMR) and Adaptive Multi-Rate
+ * Wideband (AMR-WB) Audio Codecs.
+ *
+ */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include "gstrtpamrdepay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpamrdepay_debug);
+#define GST_CAT_DEFAULT (rtpamrdepay_debug)
+
+/* RtpAMRDepay signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0
+};
+
+/* input is an RTP packet
+ *
+ * params see RFC 3267, section 8.1
+ */
+static GstStaticPadTemplate gst_rtp_amr_depay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "clock-rate = (int) 8000, " "encoding-name = (string) \"AMR\", "
+ /* This is the default, so the peer doesn't have to specify it
+ * "encoding-params = (string) \"1\", " */
+ /* NOTE that all values must be strings in orde to be able to do SDP <->
+ * GstCaps mapping. */
+ "octet-align = (string) \"1\";"
+ /* following options are not needed for a decoder
+ *
+ "crc = (string) { \"0\", \"1\" }, "
+ "robust-sorting = (string) \"0\", "
+ "interleaving = (string) \"0\";"
+ "mode-set = (int) [ 0, 7 ], "
+ "mode-change-period = (int) [ 1, MAX ], "
+ "mode-change-neighbor = (boolean) { TRUE, FALSE }, "
+ "maxptime = (int) [ 20, MAX ], "
+ "ptime = (int) [ 20, MAX ]"
+ */
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "clock-rate = (int) 16000, " "encoding-name = (string) \"AMR-WB\", "
+ /* This is the default, so the peer doesn't have to specify it
+ * "encoding-params = (string) \"1\", " */
+ /* NOTE that all values must be strings in orde to be able to do SDP <->
+ * GstCaps mapping. */
+ "octet-align = (string) \"1\";"
+ /* following options are not needed for a decoder
+ *
+ "crc = (string) { \"0\", \"1\" }, "
+ "robust-sorting = (string) \"0\", "
+ "interleaving = (string) \"0\""
+ "mode-set = (int) [ 0, 7 ], "
+ "mode-change-period = (int) [ 1, MAX ], "
+ "mode-change-neighbor = (boolean) { TRUE, FALSE }, "
+ "maxptime = (int) [ 20, MAX ], "
+ "ptime = (int) [ 20, MAX ]"
+ */
+ )
+ );
+
+static GstStaticPadTemplate gst_rtp_amr_depay_src_template =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/AMR, " "channels = (int) 1," "rate = (int) 8000;"
+ "audio/AMR-WB, " "channels = (int) 1," "rate = (int) 16000")
+ );
+
+static gboolean gst_rtp_amr_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_amr_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+
+#define gst_rtp_amr_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpAMRDepay, gst_rtp_amr_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_amr_depay_class_init (GstRtpAMRDepayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_amr_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_amr_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP AMR depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts AMR or AMR-WB audio from RTP packets (RFC 3267)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ gstrtpbasedepayload_class->process = gst_rtp_amr_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_amr_depay_setcaps;
+
+ GST_DEBUG_CATEGORY_INIT (rtpamrdepay_debug, "rtpamrdepay", 0,
+ "AMR/AMR-WB RTP Depayloader");
+}
+
+static void
+gst_rtp_amr_depay_init (GstRtpAMRDepay * rtpamrdepay)
+{
+ GstRTPBaseDepayload *depayload;
+
+ depayload = GST_RTP_BASE_DEPAYLOAD (rtpamrdepay);
+
+ gst_pad_use_fixed_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload));
+}
+
+static gboolean
+gst_rtp_amr_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstStructure *structure;
+ GstCaps *srccaps;
+ GstRtpAMRDepay *rtpamrdepay;
+ const gchar *params;
+ const gchar *str, *type;
+ gint clock_rate, need_clock_rate;
+ gboolean res;
+
+ rtpamrdepay = GST_RTP_AMR_DEPAY (depayload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ /* figure out the mode first and set the clock rates */
+ if ((str = gst_structure_get_string (structure, "encoding-name"))) {
+ if (strcmp (str, "AMR") == 0) {
+ rtpamrdepay->mode = GST_RTP_AMR_DP_MODE_NB;
+ need_clock_rate = 8000;
+ type = "audio/AMR";
+ } else if (strcmp (str, "AMR-WB") == 0) {
+ rtpamrdepay->mode = GST_RTP_AMR_DP_MODE_WB;
+ need_clock_rate = 16000;
+ type = "audio/AMR-WB";
+ } else
+ goto invalid_mode;
+ } else
+ goto invalid_mode;
+
+ if (!(str = gst_structure_get_string (structure, "octet-align")))
+ rtpamrdepay->octet_align = FALSE;
+ else
+ rtpamrdepay->octet_align = (atoi (str) == 1);
+
+ if (!(str = gst_structure_get_string (structure, "crc")))
+ rtpamrdepay->crc = FALSE;
+ else
+ rtpamrdepay->crc = (atoi (str) == 1);
+
+ if (rtpamrdepay->crc) {
+ /* crc mode implies octet aligned mode */
+ rtpamrdepay->octet_align = TRUE;
+ }
+
+ if (!(str = gst_structure_get_string (structure, "robust-sorting")))
+ rtpamrdepay->robust_sorting = FALSE;
+ else
+ rtpamrdepay->robust_sorting = (atoi (str) == 1);
+
+ if (rtpamrdepay->robust_sorting) {
+ /* robust_sorting mode implies octet aligned mode */
+ rtpamrdepay->octet_align = TRUE;
+ }
+
+ if (!(str = gst_structure_get_string (structure, "interleaving")))
+ rtpamrdepay->interleaving = FALSE;
+ else
+ rtpamrdepay->interleaving = (atoi (str) == 1);
+
+ if (rtpamrdepay->interleaving) {
+ /* interleaving mode implies octet aligned mode */
+ rtpamrdepay->octet_align = TRUE;
+ }
+
+ if (!(params = gst_structure_get_string (structure, "encoding-params")))
+ rtpamrdepay->channels = 1;
+ else {
+ rtpamrdepay->channels = atoi (params);
+ }
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = need_clock_rate;
+ depayload->clock_rate = clock_rate;
+
+ /* we require 1 channel, 8000 Hz, octet aligned, no CRC,
+ * no robust sorting, no interleaving for now */
+ if (rtpamrdepay->channels != 1)
+ return FALSE;
+ if (clock_rate != need_clock_rate)
+ return FALSE;
+ if (rtpamrdepay->octet_align != TRUE)
+ return FALSE;
+ if (rtpamrdepay->robust_sorting != FALSE)
+ return FALSE;
+ if (rtpamrdepay->interleaving != FALSE)
+ return FALSE;
+
+ srccaps = gst_caps_new_simple (type,
+ "channels", G_TYPE_INT, rtpamrdepay->channels,
+ "rate", G_TYPE_INT, clock_rate, NULL);
+ res = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+ gst_caps_unref (srccaps);
+
+ return res;
+
+ /* ERRORS */
+invalid_mode:
+ {
+ GST_ERROR_OBJECT (rtpamrdepay, "invalid encoding-name");
+ return FALSE;
+ }
+}
+
+/* -1 is invalid */
+static const gint nb_frame_size[16] = {
+ 12, 13, 15, 17, 19, 20, 26, 31,
+ 5, -1, -1, -1, -1, -1, -1, 0
+};
+
+static const gint wb_frame_size[16] = {
+ 17, 23, 32, 36, 40, 46, 50, 58,
+ 60, 5, -1, -1, -1, -1, -1, 0
+};
+
+static GstBuffer *
+gst_rtp_amr_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpAMRDepay *rtpamrdepay;
+ const gint *frame_size;
+ GstBuffer *outbuf = NULL;
+ gint payload_len;
+ GstRTPBuffer rtp = { NULL };
+ GstMapInfo map;
+
+ rtpamrdepay = GST_RTP_AMR_DEPAY (depayload);
+
+ /* setup frame size pointer */
+ if (rtpamrdepay->mode == GST_RTP_AMR_DP_MODE_NB)
+ frame_size = nb_frame_size;
+ else
+ frame_size = wb_frame_size;
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ /* when we get here, 1 channel, 8000/16000 Hz, octet aligned, no CRC,
+ * no robust sorting, no interleaving data is to be depayloaded */
+ {
+ guint8 *payload, *p, *dp;
+ gint i, num_packets, num_nonempty_packets;
+ gint amr_len;
+ gint ILL, ILP;
+
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+
+ /* need at least 2 bytes for the header */
+ if (payload_len < 2)
+ goto too_small;
+
+ payload = gst_rtp_buffer_get_payload (&rtp);
+
+ /* depay CMR. The CMR is used by the sender to request
+ * a new encoding mode.
+ *
+ * 0 1 2 3 4 5 6 7
+ * +-+-+-+-+-+-+-+-+
+ * | CMR |R|R|R|R|
+ * +-+-+-+-+-+-+-+-+
+ */
+ /* CMR = (payload[0] & 0xf0) >> 4; */
+
+ /* strip CMR header now, pack FT and the data for the decoder */
+ payload_len -= 1;
+ payload += 1;
+
+ GST_DEBUG_OBJECT (rtpamrdepay, "payload len %d", payload_len);
+
+ if (rtpamrdepay->interleaving) {
+ ILL = (payload[0] & 0xf0) >> 4;
+ ILP = (payload[0] & 0x0f);
+
+ payload_len -= 1;
+ payload += 1;
+
+ if (ILP > ILL)
+ goto wrong_interleaving;
+ }
+
+ /*
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
+ * +-+-+-+-+-+-+-+-+..
+ * |F| FT |Q|P|P| more FT..
+ * +-+-+-+-+-+-+-+-+..
+ */
+ /* count number of packets by counting the FTs. Also
+ * count number of amr data bytes and number of non-empty
+ * packets (this is also the number of CRCs if present). */
+ amr_len = 0;
+ num_nonempty_packets = 0;
+ num_packets = 0;
+ for (i = 0; i < payload_len; i++) {
+ gint fr_size;
+ guint8 FT;
+
+ FT = (payload[i] & 0x78) >> 3;
+
+ fr_size = frame_size[FT];
+ GST_DEBUG_OBJECT (rtpamrdepay, "frame size %d", fr_size);
+ if (fr_size == -1)
+ goto wrong_framesize;
+
+ if (fr_size > 0) {
+ amr_len += fr_size;
+ num_nonempty_packets++;
+ }
+ num_packets++;
+
+ if ((payload[i] & 0x80) == 0)
+ break;
+ }
+
+ if (rtpamrdepay->crc) {
+ /* data len + CRC len + header bytes should be smaller than payload_len */
+ if (num_packets + num_nonempty_packets + amr_len > payload_len)
+ goto wrong_length_1;
+ } else {
+ /* data len + header bytes should be smaller than payload_len */
+ if (num_packets + amr_len > payload_len)
+ goto wrong_length_2;
+ }
+
+ outbuf = gst_buffer_new_and_alloc (payload_len);
+
+ /* point to destination */
+ gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+
+ /* point to first data packet */
+ p = map.data;
+ dp = payload + num_packets;
+ if (rtpamrdepay->crc) {
+ /* skip CRC if present */
+ dp += num_nonempty_packets;
+ }
+
+ for (i = 0; i < num_packets; i++) {
+ gint fr_size;
+
+ /* copy FT, clear F bit */
+ *p++ = payload[i] & 0x7f;
+
+ fr_size = frame_size[(payload[i] & 0x78) >> 3];
+ if (fr_size > 0) {
+ /* copy data packet, FIXME, calc CRC here. */
+ memcpy (p, dp, fr_size);
+
+ p += fr_size;
+ dp += fr_size;
+ }
+ }
+ gst_buffer_unmap (outbuf, &map);
+
+ /* we can set the duration because each packet is 20 milliseconds */
+ GST_BUFFER_DURATION (outbuf) = num_packets * 20 * GST_MSECOND;
+
+ if (gst_rtp_buffer_get_marker (&rtp)) {
+ /* marker bit marks a buffer after a talkspurt. */
+ GST_DEBUG_OBJECT (depayload, "marker bit was set");
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+ }
+
+ GST_DEBUG_OBJECT (depayload, "pushing buffer of size %" G_GSIZE_FORMAT,
+ gst_buffer_get_size (outbuf));
+ }
+
+ gst_rtp_buffer_unmap (&rtp);
+ return outbuf;
+
+ /* ERRORS */
+too_small:
+ {
+ GST_ELEMENT_WARNING (rtpamrdepay, STREAM, DECODE,
+ (NULL), ("AMR RTP payload too small (%d)", payload_len));
+ goto bad_packet;
+ }
+wrong_interleaving:
+ {
+ GST_ELEMENT_WARNING (rtpamrdepay, STREAM, DECODE,
+ (NULL), ("AMR RTP wrong interleaving"));
+ goto bad_packet;
+ }
+wrong_framesize:
+ {
+ GST_ELEMENT_WARNING (rtpamrdepay, STREAM, DECODE,
+ (NULL), ("AMR RTP frame size == -1"));
+ goto bad_packet;
+ }
+wrong_length_1:
+ {
+ GST_ELEMENT_WARNING (rtpamrdepay, STREAM, DECODE,
+ (NULL), ("AMR RTP wrong length 1"));
+ goto bad_packet;
+ }
+wrong_length_2:
+ {
+ GST_ELEMENT_WARNING (rtpamrdepay, STREAM, DECODE,
+ (NULL), ("AMR RTP wrong length 2"));
+ goto bad_packet;
+ }
+bad_packet:
+ {
+ /* no fatal error */
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+}
+
+gboolean
+gst_rtp_amr_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpamrdepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_AMR_DEPAY);
+}
diff --git a/gst/rtp/gstrtpamrdepay.h b/gst/rtp/gstrtpamrdepay.h
new file mode 100755
index 0000000..0b80634
--- /dev/null
+++ b/gst/rtp/gstrtpamrdepay.h
@@ -0,0 +1,77 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_AMR_DEPAY_H__
+#define __GST_RTP_AMR_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_AMR_DEPAY \
+ (gst_rtp_amr_depay_get_type())
+#define GST_RTP_AMR_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_AMR_DEPAY,GstRtpAMRDepay))
+#define GST_RTP_AMR_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_AMR_DEPAY,GstRtpAMRDepayClass))
+#define GST_IS_RTP_AMR_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_AMR_DEPAY))
+#define GST_IS_RTP_AMR_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_AMR_DEPAY))
+
+typedef struct _GstRtpAMRDepay GstRtpAMRDepay;
+typedef struct _GstRtpAMRDepayClass GstRtpAMRDepayClass;
+
+typedef enum {
+ GST_RTP_AMR_DP_MODE_INVALID = 0,
+ GST_RTP_AMR_DP_MODE_NB = 1,
+ GST_RTP_AMR_DP_MODE_WB = 2
+} GstRtpAMRDepayMode;
+
+struct _GstRtpAMRDepay
+{
+ GstRTPBaseDepayload depayload;
+
+ GstRtpAMRDepayMode mode;
+
+ gboolean octet_align;
+ guint8 mode_set;
+ gint mode_change_period;
+ gboolean mode_change_neighbor;
+ gint maxptime;
+ gboolean crc;
+ gboolean robust_sorting;
+ gboolean interleaving;
+ gint ptime;
+ gint channels;
+};
+
+struct _GstRtpAMRDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_amr_depay_get_type (void);
+
+gboolean gst_rtp_amr_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_AMR_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpamrpay.c b/gst/rtp/gstrtpamrpay.c
new file mode 100755
index 0000000..ead9f94
--- /dev/null
+++ b/gst/rtp/gstrtpamrpay.c
@@ -0,0 +1,459 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpamrpay
+ * @see_also: rtpamrdepay
+ *
+ * Payload AMR audio into RTP packets according to RFC 3267.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc3267.txt
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 -v audiotestsrc ! amrnbenc ! rtpamrpay ! udpsink
+ * ]| This example pipeline will encode and payload an AMR stream. Refer to
+ * the rtpamrdepay example to depayload and decode the RTP stream.
+ * </refsect2>
+ */
+
+/* references:
+ *
+ * RFC 3267 - Real-Time Transport Protocol (RTP) Payload Format and File
+ * Storage Format for the Adaptive Multi-Rate (AMR) and Adaptive
+ * Multi-Rate Wideband (AMR-WB) Audio Codecs.
+ *
+ * ETSI TS 126 201 V6.0.0 (2004-12) - Digital cellular telecommunications system (Phase 2+);
+ * Universal Mobile Telecommunications System (UMTS);
+ * AMR speech codec, wideband;
+ * Frame structure
+ * (3GPP TS 26.201 version 6.0.0 Release 6)
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpamrpay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpamrpay_debug);
+#define GST_CAT_DEFAULT (rtpamrpay_debug)
+
+static GstStaticPadTemplate gst_rtp_amr_pay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/AMR, channels=(int)1, rate=(int)8000; "
+ "audio/AMR-WB, channels=(int)1, rate=(int)16000")
+ );
+
+static GstStaticPadTemplate gst_rtp_amr_pay_src_template =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) 8000, "
+ "encoding-name = (string) \"AMR\", "
+ "encoding-params = (string) \"1\", "
+ "octet-align = (string) \"1\", "
+ "crc = (string) \"0\", "
+ "robust-sorting = (string) \"0\", "
+ "interleaving = (string) \"0\", "
+ "mode-set = (int) [ 0, 7 ], "
+ "mode-change-period = (int) [ 1, MAX ], "
+ "mode-change-neighbor = (string) { \"0\", \"1\" }, "
+ "maxptime = (int) [ 20, MAX ], " "ptime = (int) [ 20, MAX ];"
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) 16000, "
+ "encoding-name = (string) \"AMR-WB\", "
+ "encoding-params = (string) \"1\", "
+ "octet-align = (string) \"1\", "
+ "crc = (string) \"0\", "
+ "robust-sorting = (string) \"0\", "
+ "interleaving = (string) \"0\", "
+ "mode-set = (int) [ 0, 7 ], "
+ "mode-change-period = (int) [ 1, MAX ], "
+ "mode-change-neighbor = (string) { \"0\", \"1\" }, "
+ "maxptime = (int) [ 20, MAX ], " "ptime = (int) [ 20, MAX ]")
+ );
+
+static gboolean gst_rtp_amr_pay_setcaps (GstRTPBasePayload * basepayload,
+ GstCaps * caps);
+static GstFlowReturn gst_rtp_amr_pay_handle_buffer (GstRTPBasePayload * pad,
+ GstBuffer * buffer);
+
+static GstStateChangeReturn
+gst_rtp_amr_pay_change_state (GstElement * element, GstStateChange transition);
+
+#define gst_rtp_amr_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpAMRPay, gst_rtp_amr_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_amr_pay_class_init (GstRtpAMRPayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gstelement_class->change_state = gst_rtp_amr_pay_change_state;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_amr_pay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_amr_pay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class, "RTP AMR payloader",
+ "Codec/Payloader/Network/RTP",
+ "Payload-encode AMR or AMR-WB audio into RTP packets (RFC 3267)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_amr_pay_setcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_amr_pay_handle_buffer;
+
+ GST_DEBUG_CATEGORY_INIT (rtpamrpay_debug, "rtpamrpay", 0,
+ "AMR/AMR-WB RTP Payloader");
+}
+
+static void
+gst_rtp_amr_pay_init (GstRtpAMRPay * rtpamrpay)
+{
+}
+
+static void
+gst_rtp_amr_pay_reset (GstRtpAMRPay * pay)
+{
+ pay->next_rtp_time = 0;
+ pay->first_ts = GST_CLOCK_TIME_NONE;
+ pay->first_rtp_time = 0;
+}
+
+static gboolean
+gst_rtp_amr_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
+{
+ GstRtpAMRPay *rtpamrpay;
+ gboolean res;
+ const GstStructure *s;
+ const gchar *str;
+
+ rtpamrpay = GST_RTP_AMR_PAY (basepayload);
+
+ /* figure out the mode Narrow or Wideband */
+ s = gst_caps_get_structure (caps, 0);
+ if ((str = gst_structure_get_name (s))) {
+ if (strcmp (str, "audio/AMR") == 0)
+ rtpamrpay->mode = GST_RTP_AMR_P_MODE_NB;
+ else if (strcmp (str, "audio/AMR-WB") == 0)
+ rtpamrpay->mode = GST_RTP_AMR_P_MODE_WB;
+ else
+ goto wrong_type;
+ } else
+ goto wrong_type;
+
+ if (rtpamrpay->mode == GST_RTP_AMR_P_MODE_NB)
+ gst_rtp_base_payload_set_options (basepayload, "audio", TRUE, "AMR", 8000);
+ else
+ gst_rtp_base_payload_set_options (basepayload, "audio", TRUE, "AMR-WB",
+ 16000);
+
+ res = gst_rtp_base_payload_set_outcaps (basepayload,
+ "encoding-params", G_TYPE_STRING, "1", "octet-align", G_TYPE_STRING, "1",
+ /* don't set the defaults
+ *
+ * "crc", G_TYPE_STRING, "0",
+ * "robust-sorting", G_TYPE_STRING, "0",
+ * "interleaving", G_TYPE_STRING, "0",
+ */
+ NULL);
+
+ return res;
+
+ /* ERRORS */
+wrong_type:
+ {
+ GST_ERROR_OBJECT (rtpamrpay, "unsupported media type '%s'",
+ GST_STR_NULL (str));
+ return FALSE;
+ }
+}
+
+static void
+gst_rtp_amr_pay_recalc_rtp_time (GstRtpAMRPay * rtpamrpay,
+ GstClockTime timestamp)
+{
+ /* re-sync rtp time */
+ if (GST_CLOCK_TIME_IS_VALID (rtpamrpay->first_ts) &&
+ GST_CLOCK_TIME_IS_VALID (timestamp) && timestamp >= rtpamrpay->first_ts) {
+ GstClockTime diff;
+ guint32 rtpdiff;
+
+ /* interpolate to reproduce gap from start, rather than intermediate
+ * intervals to avoid roundup accumulation errors */
+ diff = timestamp - rtpamrpay->first_ts;
+ rtpdiff = ((diff / GST_MSECOND) * 8) <<
+ (rtpamrpay->mode == GST_RTP_AMR_P_MODE_WB);
+ rtpamrpay->next_rtp_time = rtpamrpay->first_rtp_time + rtpdiff;
+ GST_DEBUG_OBJECT (rtpamrpay,
+ "elapsed time %" GST_TIME_FORMAT ", rtp %" G_GUINT32_FORMAT ", "
+ "new offset %" G_GUINT32_FORMAT, GST_TIME_ARGS (diff), rtpdiff,
+ rtpamrpay->next_rtp_time);
+ }
+}
+
+/* -1 is invalid */
+static const gint nb_frame_size[16] = {
+ 12, 13, 15, 17, 19, 20, 26, 31,
+ 5, -1, -1, -1, -1, -1, -1, 0
+};
+
+static const gint wb_frame_size[16] = {
+ 17, 23, 32, 36, 40, 46, 50, 58,
+ 60, 5, -1, -1, -1, -1, -1, 0
+};
+
+static GstFlowReturn
+gst_rtp_amr_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer)
+{
+ GstRtpAMRPay *rtpamrpay;
+ const gint *frame_size;
+ GstFlowReturn ret;
+ guint payload_len;
+ GstMapInfo map;
+ GstBuffer *outbuf;
+ guint8 *payload, *ptr, *payload_amr;
+ GstClockTime timestamp, duration;
+ guint packet_len, mtu;
+ gint i, num_packets, num_nonempty_packets;
+ gint amr_len;
+ gboolean sid = FALSE;
+ GstRTPBuffer rtp = { NULL };
+
+ rtpamrpay = GST_RTP_AMR_PAY (basepayload);
+ mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpamrpay);
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+ timestamp = GST_BUFFER_TIMESTAMP (buffer);
+ duration = GST_BUFFER_DURATION (buffer);
+
+ /* setup frame size pointer */
+ if (rtpamrpay->mode == GST_RTP_AMR_P_MODE_NB)
+ frame_size = nb_frame_size;
+ else
+ frame_size = wb_frame_size;
+
+ GST_DEBUG_OBJECT (basepayload, "got %" G_GSIZE_FORMAT " bytes", map.size);
+
+ /* FIXME, only
+ * octet aligned, no interleaving, single channel, no CRC,
+ * no robust-sorting. To fix this you need to implement the downstream
+ * negotiation function. */
+
+ /* first count number of packets and total amr frame size */
+ amr_len = num_packets = num_nonempty_packets = 0;
+ for (i = 0; i < map.size; i++) {
+ guint8 FT;
+ gint fr_size;
+
+ FT = (map.data[i] & 0x78) >> 3;
+
+ fr_size = frame_size[FT];
+ GST_DEBUG_OBJECT (basepayload, "frame type %d, frame size %d", FT, fr_size);
+ /* FIXME, we don't handle this yet.. */
+ if (fr_size <= 0)
+ goto wrong_size;
+
+ if (fr_size == 5)
+ sid = TRUE;
+
+ amr_len += fr_size;
+ num_nonempty_packets++;
+ num_packets++;
+ i += fr_size;
+ }
+ if (amr_len > map.size)
+ goto incomplete_frame;
+
+ /* we need one extra byte for the CMR, the ToC is in the input
+ * data */
+ payload_len = map.size + 1;
+
+ /* get packet len to check against MTU */
+ packet_len = gst_rtp_buffer_calc_packet_len (payload_len, 0, 0);
+ if (packet_len > mtu)
+ goto too_big;
+
+ /* now alloc output buffer */
+ outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
+
+ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+ /* copy timestamp */
+ GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
+
+ if (duration != GST_CLOCK_TIME_NONE)
+ GST_BUFFER_DURATION (outbuf) = duration;
+ else {
+ GST_BUFFER_DURATION (outbuf) = num_packets * 20 * GST_MSECOND;
+ }
+
+ if (GST_BUFFER_IS_DISCONT (buffer)) {
+ GST_DEBUG_OBJECT (basepayload, "discont, setting marker bit");
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+ gst_rtp_buffer_set_marker (&rtp, TRUE);
+ gst_rtp_amr_pay_recalc_rtp_time (rtpamrpay, timestamp);
+ }
+
+ if (G_UNLIKELY (sid)) {
+ gst_rtp_amr_pay_recalc_rtp_time (rtpamrpay, timestamp);
+ }
+
+ /* perfect rtptime */
+ if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (rtpamrpay->first_ts))) {
+ rtpamrpay->first_ts = timestamp;
+ rtpamrpay->first_rtp_time = rtpamrpay->next_rtp_time;
+ }
+ GST_BUFFER_OFFSET (outbuf) = rtpamrpay->next_rtp_time;
+ rtpamrpay->next_rtp_time +=
+ (num_packets * 160) << (rtpamrpay->mode == GST_RTP_AMR_P_MODE_WB);
+
+ /* get payload, this is now writable */
+ payload = gst_rtp_buffer_get_payload (&rtp);
+
+ /* 0 1 2 3 4 5 6 7
+ * +-+-+-+-+-+-+-+-+
+ * | CMR |R|R|R|R|
+ * +-+-+-+-+-+-+-+-+
+ */
+ payload[0] = 0xF0; /* CMR, no specific mode requested */
+
+ /* this is where we copy the AMR data, after num_packets FTs and the
+ * CMR. */
+ payload_amr = payload + num_packets + 1;
+
+ /* copy data in payload, first we copy all the FTs then all
+ * the AMR data. The last FT has to have the F flag cleared. */
+ ptr = map.data;
+ for (i = 1; i <= num_packets; i++) {
+ guint8 FT;
+ gint fr_size;
+
+ /* 0 1 2 3 4 5 6 7
+ * +-+-+-+-+-+-+-+-+
+ * |F| FT |Q|P|P| more FT...
+ * +-+-+-+-+-+-+-+-+
+ */
+ FT = (*ptr & 0x78) >> 3;
+
+ fr_size = frame_size[FT];
+
+ if (i == num_packets)
+ /* last packet, clear F flag */
+ payload[i] = *ptr & 0x7f;
+ else
+ /* set F flag */
+ payload[i] = *ptr | 0x80;
+
+ memcpy (payload_amr, &ptr[1], fr_size);
+
+ /* all sizes are > 0 since we checked for that above */
+ ptr += fr_size + 1;
+ payload_amr += fr_size;
+ }
+
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ ret = gst_rtp_base_payload_push (basepayload, outbuf);
+
+ return ret;
+
+ /* ERRORS */
+wrong_size:
+ {
+ GST_ELEMENT_ERROR (basepayload, STREAM, FORMAT,
+ (NULL), ("received AMR frame with size <= 0"));
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+
+ return GST_FLOW_ERROR;
+ }
+incomplete_frame:
+ {
+ GST_ELEMENT_ERROR (basepayload, STREAM, FORMAT,
+ (NULL), ("received incomplete AMR frames"));
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+
+ return GST_FLOW_ERROR;
+ }
+too_big:
+ {
+ GST_ELEMENT_ERROR (basepayload, STREAM, FORMAT,
+ (NULL), ("received too many AMR frames for MTU"));
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+
+ return GST_FLOW_ERROR;
+ }
+}
+
+static GstStateChangeReturn
+gst_rtp_amr_pay_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+ /* handle upwards state changes here */
+ switch (transition) {
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ /* handle downwards state changes */
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_rtp_amr_pay_reset (GST_RTP_AMR_PAY (element));
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+gboolean
+gst_rtp_amr_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpamrpay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_AMR_PAY);
+}
diff --git a/gst/rtp/gstrtpamrpay.h b/gst/rtp/gstrtpamrpay.h
new file mode 100755
index 0000000..a3df1ce
--- /dev/null
+++ b/gst/rtp/gstrtpamrpay.h
@@ -0,0 +1,70 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_AMR_PAY_H__
+#define __GST_RTP_AMR_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_AMR_PAY \
+ (gst_rtp_amr_pay_get_type())
+#define GST_RTP_AMR_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_AMR_PAY,GstRtpAMRPay))
+#define GST_RTP_AMR_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_AMR_PAY,GstRtpAMRPayClass))
+#define GST_IS_RTP_AMR_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_AMR_PAY))
+#define GST_IS_RTP_AMR_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_AMR_PAY))
+
+typedef struct _GstRtpAMRPay GstRtpAMRPay;
+typedef struct _GstRtpAMRPayClass GstRtpAMRPayClass;
+
+typedef enum {
+ GST_RTP_AMR_P_MODE_INVALID = 0,
+ GST_RTP_AMR_P_MODE_NB = 1,
+ GST_RTP_AMR_P_MODE_WB = 2
+} GstRtpAMRPayMode;
+
+struct _GstRtpAMRPay
+{
+ GstRTPBasePayload payload;
+
+ GstRtpAMRPayMode mode;
+ GstClockTime first_ts;
+ guint32 first_rtp_time;
+ guint32 next_rtp_time;
+};
+
+struct _GstRtpAMRPayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_amr_pay_get_type (void);
+
+gboolean gst_rtp_amr_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_AMR_PAY_H__ */
diff --git a/gst/rtp/gstrtpbvdepay.c b/gst/rtp/gstrtpbvdepay.c
new file mode 100755
index 0000000..13efebb
--- /dev/null
+++ b/gst/rtp/gstrtpbvdepay.c
@@ -0,0 +1,188 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpbvdepay
+ * @see_also: rtpbvpay
+ *
+ * Extract BroadcomVoice audio from RTP packets according to RFC 4298.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc4298.txt
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include "gstrtpbvdepay.h"
+
+static GstStaticPadTemplate gst_rtp_bv_depay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "clock-rate = (int) 8000, "
+ "encoding-name = (string) \"BV16\"; "
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "clock-rate = (int) 16000, " "encoding-name = (string) \"BV32\"")
+ );
+
+static GstStaticPadTemplate gst_rtp_bv_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-bv, " "mode = (int) { 16, 32 }")
+ );
+
+static GstBuffer *gst_rtp_bv_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+static gboolean gst_rtp_bv_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+
+#define gst_rtp_bv_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPBVDepay, gst_rtp_bv_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_bv_depay_class_init (GstRTPBVDepayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_bv_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_bv_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP BroadcomVoice depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts BroadcomVoice audio from RTP packets (RFC 4298)",
+ "Wim Taymans <wim.taymans@collabora.co.uk>");
+
+ gstrtpbasedepayload_class->process = gst_rtp_bv_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_bv_depay_setcaps;
+}
+
+static void
+gst_rtp_bv_depay_init (GstRTPBVDepay * rtpbvdepay)
+{
+ rtpbvdepay->mode = -1;
+}
+
+static gboolean
+gst_rtp_bv_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstRTPBVDepay *rtpbvdepay = GST_RTP_BV_DEPAY (depayload);
+ GstCaps *srccaps;
+ GstStructure *structure;
+ const gchar *mode_str = NULL;
+ gint mode, clock_rate, expected_rate;
+ gboolean ret;
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ mode_str = gst_structure_get_string (structure, "encoding-name");
+ if (!mode_str)
+ goto no_mode;
+
+ if (!strcmp (mode_str, "BV16")) {
+ mode = 16;
+ expected_rate = 8000;
+ } else if (!strcmp (mode_str, "BV32")) {
+ mode = 32;
+ expected_rate = 16000;
+ } else
+ goto invalid_mode;
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = expected_rate;
+ else if (clock_rate != expected_rate)
+ goto wrong_rate;
+
+ depayload->clock_rate = clock_rate;
+ rtpbvdepay->mode = mode;
+
+ srccaps = gst_caps_new_simple ("audio/x-bv",
+ "mode", G_TYPE_INT, rtpbvdepay->mode, NULL);
+ ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+
+ GST_DEBUG ("set caps on source: %" GST_PTR_FORMAT " (ret=%d)", srccaps, ret);
+ gst_caps_unref (srccaps);
+
+ return ret;
+
+ /* ERRORS */
+no_mode:
+ {
+ GST_ERROR_OBJECT (rtpbvdepay, "did not receive an encoding-name");
+ return FALSE;
+ }
+invalid_mode:
+ {
+ GST_ERROR_OBJECT (rtpbvdepay,
+ "invalid encoding-name, expected BV16 or BV32, got %s", mode_str);
+ return FALSE;
+ }
+wrong_rate:
+ {
+ GST_ERROR_OBJECT (rtpbvdepay, "invalid clock-rate, expected %d, got %d",
+ expected_rate, clock_rate);
+ return FALSE;
+ }
+}
+
+static GstBuffer *
+gst_rtp_bv_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstBuffer *outbuf;
+ gboolean marker;
+ GstRTPBuffer rtp = { NULL, };
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ marker = gst_rtp_buffer_get_marker (&rtp);
+
+ GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d",
+ gst_buffer_get_size (buf), marker,
+ gst_rtp_buffer_get_timestamp (&rtp), gst_rtp_buffer_get_seq (&rtp));
+
+ outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
+ gst_rtp_buffer_unmap (&rtp);
+
+ if (marker && outbuf) {
+ /* mark start of talkspurt with RESYNC */
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+ }
+
+ return outbuf;
+}
+
+gboolean
+gst_rtp_bv_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpbvdepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_BV_DEPAY);
+}
diff --git a/gst/rtp/gstrtpbvdepay.h b/gst/rtp/gstrtpbvdepay.h
new file mode 100755
index 0000000..f130682
--- /dev/null
+++ b/gst/rtp/gstrtpbvdepay.h
@@ -0,0 +1,60 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_BV_DEPAY_H__
+#define __GST_RTP_BV_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRTPBVDepay GstRTPBVDepay;
+typedef struct _GstRTPBVDepayClass GstRTPBVDepayClass;
+
+#define GST_TYPE_RTP_BV_DEPAY \
+ (gst_rtp_bv_depay_get_type())
+#define GST_RTP_BV_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_BV_DEPAY,GstRTPBVDepay))
+#define GST_RTP_BV_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_BV_DEPAY,GstRTPBVDepayClass))
+#define GST_IS_RTP_BV_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_BV_DEPAY))
+#define GST_IS_RTP_BV_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_BV_DEPAY))
+
+struct _GstRTPBVDepay
+{
+ GstRTPBaseDepayload depayload;
+
+ gint mode;
+};
+
+struct _GstRTPBVDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_bv_depay_get_type (void);
+
+gboolean gst_rtp_bv_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_BV_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpbvpay.c b/gst/rtp/gstrtpbvpay.c
new file mode 100755
index 0000000..15a7b7f
--- /dev/null
+++ b/gst/rtp/gstrtpbvpay.c
@@ -0,0 +1,228 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpbvpay
+ * @see_also: rtpbvdepay
+ *
+ * Payload BroadcomVoice audio into RTP packets according to RFC 4298.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc4298.txt
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include "gstrtpbvpay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpbvpay_debug);
+#define GST_CAT_DEFAULT (rtpbvpay_debug)
+
+static GstStaticPadTemplate gst_rtp_bv_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-bv, " "mode = (int) {16, 32}")
+ );
+
+static GstStaticPadTemplate gst_rtp_bv_pay_src_template =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) 8000, "
+ "encoding-name = (string) \"BV16\";"
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) 16000, " "encoding-name = (string) \"BV32\"")
+ );
+
+
+static GstCaps *gst_rtp_bv_pay_sink_getcaps (GstRTPBasePayload * payload,
+ GstPad * pad, GstCaps * filter);
+static gboolean gst_rtp_bv_pay_sink_setcaps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+
+#define gst_rtp_bv_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPBVPay, gst_rtp_bv_pay, GST_TYPE_RTP_BASE_AUDIO_PAYLOAD);
+
+static void
+gst_rtp_bv_pay_class_init (GstRTPBVPayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ GST_DEBUG_CATEGORY_INIT (rtpbvpay_debug, "rtpbvpay", 0,
+ "BroadcomVoice audio RTP payloader");
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_bv_pay_sink_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_bv_pay_src_template));
+
+ gst_element_class_set_static_metadata (gstelement_class, "RTP BV Payloader",
+ "Codec/Payloader/Network/RTP",
+ "Packetize BroadcomVoice audio streams into RTP packets (RFC 4298)",
+ "Wim Taymans <wim.taymans@collabora.co.uk>");
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_bv_pay_sink_setcaps;
+ gstrtpbasepayload_class->get_caps = gst_rtp_bv_pay_sink_getcaps;
+}
+
+static void
+gst_rtp_bv_pay_init (GstRTPBVPay * rtpbvpay)
+{
+ GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+ rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpbvpay);
+
+ rtpbvpay->mode = -1;
+
+ /* tell rtpbaseaudiopayload that this is a frame based codec */
+ gst_rtp_base_audio_payload_set_frame_based (rtpbaseaudiopayload);
+}
+
+static gboolean
+gst_rtp_bv_pay_sink_setcaps (GstRTPBasePayload * rtpbasepayload, GstCaps * caps)
+{
+ GstRTPBVPay *rtpbvpay;
+ GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+ gint mode;
+ GstStructure *structure;
+ const char *payload_name;
+
+ rtpbvpay = GST_RTP_BV_PAY (rtpbasepayload);
+ rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpbasepayload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ payload_name = gst_structure_get_name (structure);
+ if (g_ascii_strcasecmp ("audio/x-bv", payload_name))
+ goto wrong_caps;
+
+ if (!gst_structure_get_int (structure, "mode", &mode))
+ goto no_mode;
+
+ if (mode != 16 && mode != 32)
+ goto wrong_mode;
+
+ if (mode == 16) {
+ gst_rtp_base_payload_set_options (rtpbasepayload, "audio", TRUE, "BV16",
+ 8000);
+ rtpbasepayload->clock_rate = 8000;
+ } else {
+ gst_rtp_base_payload_set_options (rtpbasepayload, "audio", TRUE, "BV32",
+ 16000);
+ rtpbasepayload->clock_rate = 16000;
+ }
+
+ /* set options for this frame based audio codec */
+ gst_rtp_base_audio_payload_set_frame_options (rtpbaseaudiopayload,
+ mode, mode == 16 ? 10 : 20);
+
+ if (mode != rtpbvpay->mode && rtpbvpay->mode != -1)
+ goto mode_changed;
+
+ rtpbvpay->mode = mode;
+
+ return TRUE;
+
+ /* ERRORS */
+wrong_caps:
+ {
+ GST_ERROR_OBJECT (rtpbvpay, "expected audio/x-bv, received %s",
+ payload_name);
+ return FALSE;
+ }
+no_mode:
+ {
+ GST_ERROR_OBJECT (rtpbvpay, "did not receive a mode");
+ return FALSE;
+ }
+wrong_mode:
+ {
+ GST_ERROR_OBJECT (rtpbvpay, "mode must be 16 or 32, received %d", mode);
+ return FALSE;
+ }
+mode_changed:
+ {
+ GST_ERROR_OBJECT (rtpbvpay, "Mode has changed from %d to %d! "
+ "Mode cannot change while streaming", rtpbvpay->mode, mode);
+ return FALSE;
+ }
+}
+
+/* we return the padtemplate caps with the mode field fixated to a value if we
+ * can */
+static GstCaps *
+gst_rtp_bv_pay_sink_getcaps (GstRTPBasePayload * rtppayload, GstPad * pad,
+ GstCaps * filter)
+{
+ GstCaps *otherpadcaps;
+ GstCaps *caps;
+
+ caps = gst_pad_get_pad_template_caps (pad);
+
+ otherpadcaps = gst_pad_get_allowed_caps (rtppayload->srcpad);
+ if (otherpadcaps) {
+ if (!gst_caps_is_empty (otherpadcaps)) {
+ GstStructure *structure;
+ const gchar *mode_str;
+ gint mode;
+
+ structure = gst_caps_get_structure (otherpadcaps, 0);
+
+ /* construct mode, if we can */
+ mode_str = gst_structure_get_string (structure, "encoding-name");
+ if (mode_str) {
+ if (!strcmp (mode_str, "BV16"))
+ mode = 16;
+ else if (!strcmp (mode_str, "BV32"))
+ mode = 32;
+ else
+ mode = -1;
+
+ if (mode == 16 || mode == 32) {
+ caps = gst_caps_make_writable (caps);
+ structure = gst_caps_get_structure (caps, 0);
+ gst_structure_set (structure, "mode", G_TYPE_INT, mode, NULL);
+ }
+ }
+ }
+ gst_caps_unref (otherpadcaps);
+ }
+ return caps;
+}
+
+gboolean
+gst_rtp_bv_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpbvpay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_BV_PAY);
+}
diff --git a/gst/rtp/gstrtpbvpay.h b/gst/rtp/gstrtpbvpay.h
new file mode 100755
index 0000000..09766cc
--- /dev/null
+++ b/gst/rtp/gstrtpbvpay.h
@@ -0,0 +1,60 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_BV_PAY_H__
+#define __GST_RTP_BV_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_BV_PAY \
+ (gst_rtp_bv_pay_get_type())
+#define GST_RTP_BV_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_BV_PAY,GstRTPBVPay))
+#define GST_RTP_BV_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_BV_PAY,GstRTPBVPayClass))
+#define GST_IS_RTP_BV_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_BV_PAY))
+#define GST_IS_RTP_BV_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_BV_PAY))
+
+typedef struct _GstRTPBVPay GstRTPBVPay;
+typedef struct _GstRTPBVPayClass GstRTPBVPayClass;
+
+struct _GstRTPBVPay
+{
+ GstRTPBaseAudioPayload audiopayload;
+
+ gint mode;
+};
+
+struct _GstRTPBVPayClass
+{
+ GstRTPBaseAudioPayloadClass parent_class;
+};
+
+GType gst_rtp_bv_pay_get_type (void);
+
+gboolean gst_rtp_bv_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_BV_PAY_H__ */
diff --git a/gst/rtp/gstrtpceltdepay.c b/gst/rtp/gstrtpceltdepay.c
new file mode 100755
index 0000000..5e15cc6
--- /dev/null
+++ b/gst/rtp/gstrtpceltdepay.c
@@ -0,0 +1,276 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpceltdepay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpceltdepay_debug);
+#define GST_CAT_DEFAULT (rtpceltdepay_debug)
+
+/* RtpCELTDepay signals and args */
+
+#define DEFAULT_FRAMESIZE 480
+#define DEFAULT_CHANNELS 1
+#define DEFAULT_CLOCKRATE 32000
+
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0
+};
+
+static GstStaticPadTemplate gst_rtp_celt_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "clock-rate = (int) [32000, 48000], "
+ "encoding-name = (string) \"CELT\"")
+ );
+
+static GstStaticPadTemplate gst_rtp_celt_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-celt")
+ );
+
+static GstBuffer *gst_rtp_celt_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+static gboolean gst_rtp_celt_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+
+#define gst_rtp_celt_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpCELTDepay, gst_rtp_celt_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_celt_depay_class_init (GstRtpCELTDepayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ GST_DEBUG_CATEGORY_INIT (rtpceltdepay_debug, "rtpceltdepay", 0,
+ "CELT RTP Depayloader");
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_celt_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_celt_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP CELT depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts CELT audio from RTP packets",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ gstrtpbasedepayload_class->process = gst_rtp_celt_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_celt_depay_setcaps;
+}
+
+static void
+gst_rtp_celt_depay_init (GstRtpCELTDepay * rtpceltdepay)
+{
+}
+
+/* len 4 bytes LE,
+ * vendor string (len bytes),
+ * user_len 4 (0) bytes LE
+ */
+static const gchar gst_rtp_celt_comment[] =
+ "\045\0\0\0Depayloaded with GStreamer celtdepay\0\0\0\0";
+
+static gboolean
+gst_rtp_celt_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstStructure *structure;
+ GstRtpCELTDepay *rtpceltdepay;
+ gint clock_rate, nb_channels = 0, frame_size = 0;
+ GstBuffer *buf;
+ GstMapInfo map;
+ guint8 *ptr;
+ const gchar *params;
+ GstCaps *srccaps;
+ gboolean res;
+
+ rtpceltdepay = GST_RTP_CELT_DEPAY (depayload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ goto no_clockrate;
+ depayload->clock_rate = clock_rate;
+
+ if ((params = gst_structure_get_string (structure, "encoding-params")))
+ nb_channels = atoi (params);
+ if (!nb_channels)
+ nb_channels = DEFAULT_CHANNELS;
+
+ if ((params = gst_structure_get_string (structure, "frame-size")))
+ frame_size = atoi (params);
+ if (!frame_size)
+ frame_size = DEFAULT_FRAMESIZE;
+ rtpceltdepay->frame_size = frame_size;
+
+ GST_DEBUG_OBJECT (depayload, "clock-rate=%d channels=%d frame-size=%d",
+ clock_rate, nb_channels, frame_size);
+
+ /* construct minimal header and comment packet for the decoder */
+ buf = gst_buffer_new_and_alloc (60);
+ gst_buffer_map (buf, &map, GST_MAP_WRITE);
+ ptr = map.data;
+ memcpy (ptr, "CELT ", 8);
+ ptr += 8;
+ memcpy (ptr, "1.1.12", 7);
+ ptr += 20;
+ GST_WRITE_UINT32_LE (ptr, 0x80000006); /* version */
+ ptr += 4;
+ GST_WRITE_UINT32_LE (ptr, 56); /* header_size */
+ ptr += 4;
+ GST_WRITE_UINT32_LE (ptr, clock_rate); /* rate */
+ ptr += 4;
+ GST_WRITE_UINT32_LE (ptr, nb_channels); /* channels */
+ ptr += 4;
+ GST_WRITE_UINT32_LE (ptr, frame_size); /* frame-size */
+ ptr += 4;
+ GST_WRITE_UINT32_LE (ptr, -1); /* overlap */
+ ptr += 4;
+ GST_WRITE_UINT32_LE (ptr, -1); /* bytes_per_packet */
+ ptr += 4;
+ GST_WRITE_UINT32_LE (ptr, 0); /* extra headers */
+ gst_buffer_unmap (buf, &map);
+
+ srccaps = gst_caps_new_empty_simple ("audio/x-celt");
+ res = gst_pad_set_caps (depayload->srcpad, srccaps);
+ gst_caps_unref (srccaps);
+
+ gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpceltdepay), buf);
+
+ buf = gst_buffer_new_and_alloc (sizeof (gst_rtp_celt_comment));
+ gst_buffer_fill (buf, 0, gst_rtp_celt_comment, sizeof (gst_rtp_celt_comment));
+
+ gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpceltdepay), buf);
+
+ return res;
+
+ /* ERRORS */
+no_clockrate:
+ {
+ GST_ERROR_OBJECT (depayload, "no clock-rate specified");
+ return FALSE;
+ }
+}
+
+static GstBuffer *
+gst_rtp_celt_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstBuffer *outbuf = NULL;
+ guint8 *payload;
+ guint offset, pos, payload_len, total_size, size;
+ guint8 s;
+ gint clock_rate = 0, frame_size = 0;
+ GstClockTime framesize_ns = 0, timestamp;
+ guint n = 0;
+ GstRtpCELTDepay *rtpceltdepay;
+ GstRTPBuffer rtp = { NULL, };
+
+ rtpceltdepay = GST_RTP_CELT_DEPAY (depayload);
+ clock_rate = depayload->clock_rate;
+ frame_size = rtpceltdepay->frame_size;
+ framesize_ns = gst_util_uint64_scale_int (frame_size, GST_SECOND, clock_rate);
+
+ timestamp = GST_BUFFER_TIMESTAMP (buf);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ GST_LOG_OBJECT (depayload,
+ "got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d",
+ gst_buffer_get_size (buf), gst_rtp_buffer_get_marker (&rtp),
+ gst_rtp_buffer_get_timestamp (&rtp), gst_rtp_buffer_get_seq (&rtp));
+
+ GST_LOG_OBJECT (depayload, "got clock-rate=%d, frame_size=%d, "
+ "_ns=%" GST_TIME_FORMAT ", timestamp=%" GST_TIME_FORMAT, clock_rate,
+ frame_size, GST_TIME_ARGS (framesize_ns), GST_TIME_ARGS (timestamp));
+
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+
+ /* first count how many bytes are consumed by the size headers and make offset
+ * point to the first data byte */
+ total_size = 0;
+ offset = 0;
+ while (total_size < payload_len) {
+ do {
+ s = payload[offset++];
+ total_size += s + 1;
+ } while (s == 0xff);
+ }
+
+ /* offset is now pointing to the payload */
+ total_size = 0;
+ pos = 0;
+ while (total_size < payload_len) {
+ n++;
+ size = 0;
+ do {
+ s = payload[pos++];
+ size += s;
+ total_size += s + 1;
+ } while (s == 0xff);
+
+ outbuf = gst_rtp_buffer_get_payload_subbuffer (&rtp, offset, size);
+ offset += size;
+
+ if (frame_size != -1 && clock_rate != -1) {
+ GST_BUFFER_TIMESTAMP (outbuf) = timestamp + framesize_ns * n;
+ GST_BUFFER_DURATION (outbuf) = framesize_ns;
+ }
+ GST_LOG_OBJECT (depayload, "push timestamp=%"
+ GST_TIME_FORMAT ", duration=%" GST_TIME_FORMAT,
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
+ GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));
+
+ gst_rtp_base_depayload_push (depayload, outbuf);
+ }
+ gst_rtp_buffer_unmap (&rtp);
+
+ return NULL;
+}
+
+gboolean
+gst_rtp_celt_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpceltdepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_CELT_DEPAY);
+}
diff --git a/gst/rtp/gstrtpceltdepay.h b/gst/rtp/gstrtpceltdepay.h
new file mode 100755
index 0000000..0905c68
--- /dev/null
+++ b/gst/rtp/gstrtpceltdepay.h
@@ -0,0 +1,54 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@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
+ */
+
+#ifndef __GST_RTP_CELT_DEPAY_H__
+#define __GST_RTP_CELT_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRtpCELTDepay GstRtpCELTDepay;
+typedef struct _GstRtpCELTDepayClass GstRtpCELTDepayClass;
+
+#define GST_TYPE_RTP_CELT_DEPAY \
+ (gst_rtp_celt_depay_get_type())
+#define GST_RTP_CELT_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_CELT_DEPAY,GstRtpCELTDepay))
+#define GST_RTP_CELT_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_CELT_DEPAY,GstRtpCELTDepayClass))
+#define GST_IS_RTP_CELT_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_CELT_DEPAY))
+#define GST_IS_RTP_CELT_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_CELT_DEPAY))
+
+struct _GstRtpCELTDepay
+{
+ GstRTPBaseDepayload depayload;
+ gint frame_size;
+};
+
+struct _GstRtpCELTDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_celt_depay_get_type (void);
+
+gboolean gst_rtp_celt_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_CELT_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpceltpay.c b/gst/rtp/gstrtpceltpay.c
new file mode 100755
index 0000000..3aabd9f
--- /dev/null
+++ b/gst/rtp/gstrtpceltpay.c
@@ -0,0 +1,488 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpceltpay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpceltpay_debug);
+#define GST_CAT_DEFAULT (rtpceltpay_debug)
+
+static GstStaticPadTemplate gst_rtp_celt_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-celt, "
+ "rate = (int) [ 32000, 64000 ], "
+ "channels = (int) [1, 2], " "frame-size = (int) [ 64, 512 ]")
+ );
+
+static GstStaticPadTemplate gst_rtp_celt_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) [ 32000, 48000 ], "
+ "encoding-name = (string) \"CELT\"")
+ );
+
+static void gst_rtp_celt_pay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_celt_pay_change_state (GstElement *
+ element, GstStateChange transition);
+
+static gboolean gst_rtp_celt_pay_setcaps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+static GstCaps *gst_rtp_celt_pay_getcaps (GstRTPBasePayload * payload,
+ GstPad * pad, GstCaps * filter);
+static GstFlowReturn gst_rtp_celt_pay_handle_buffer (GstRTPBasePayload *
+ payload, GstBuffer * buffer);
+
+#define gst_rtp_celt_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpCELTPay, gst_rtp_celt_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_celt_pay_class_init (GstRtpCELTPayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ GST_DEBUG_CATEGORY_INIT (rtpceltpay_debug, "rtpceltpay", 0,
+ "CELT RTP Payloader");
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_celt_pay_finalize;
+
+ gstelement_class->change_state = gst_rtp_celt_pay_change_state;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_celt_pay_sink_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_celt_pay_src_template));
+
+ gst_element_class_set_static_metadata (gstelement_class, "RTP CELT payloader",
+ "Codec/Payloader/Network/RTP",
+ "Payload-encodes CELT audio into a RTP packet",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_celt_pay_setcaps;
+ gstrtpbasepayload_class->get_caps = gst_rtp_celt_pay_getcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_celt_pay_handle_buffer;
+}
+
+static void
+gst_rtp_celt_pay_init (GstRtpCELTPay * rtpceltpay)
+{
+ rtpceltpay->queue = g_queue_new ();
+}
+
+static void
+gst_rtp_celt_pay_finalize (GObject * object)
+{
+ GstRtpCELTPay *rtpceltpay;
+
+ rtpceltpay = GST_RTP_CELT_PAY (object);
+
+ g_queue_free (rtpceltpay->queue);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_rtp_celt_pay_clear_queued (GstRtpCELTPay * rtpceltpay)
+{
+ GstBuffer *buf;
+
+ while ((buf = g_queue_pop_head (rtpceltpay->queue)))
+ gst_buffer_unref (buf);
+
+ rtpceltpay->bytes = 0;
+ rtpceltpay->sbytes = 0;
+ rtpceltpay->qduration = 0;
+}
+
+static void
+gst_rtp_celt_pay_add_queued (GstRtpCELTPay * rtpceltpay, GstBuffer * buffer,
+ guint ssize, guint size, GstClockTime duration)
+{
+ g_queue_push_tail (rtpceltpay->queue, buffer);
+ rtpceltpay->sbytes += ssize;
+ rtpceltpay->bytes += size;
+ /* only add durations when we have a valid previous duration */
+ if (rtpceltpay->qduration != -1) {
+ if (duration != -1)
+ /* only add valid durations */
+ rtpceltpay->qduration += duration;
+ else
+ /* if we add a buffer without valid duration, our total queued duration
+ * becomes unknown */
+ rtpceltpay->qduration = -1;
+ }
+}
+
+static gboolean
+gst_rtp_celt_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ /* don't configure yet, we wait for the ident packet */
+ return TRUE;
+}
+
+
+static GstCaps *
+gst_rtp_celt_pay_getcaps (GstRTPBasePayload * payload, GstPad * pad,
+ GstCaps * filter)
+{
+ GstCaps *otherpadcaps;
+ GstCaps *caps;
+ const gchar *params;
+
+ caps = gst_pad_get_pad_template_caps (pad);
+
+ otherpadcaps = gst_pad_get_allowed_caps (payload->srcpad);
+ if (otherpadcaps) {
+ if (!gst_caps_is_empty (otherpadcaps)) {
+ GstStructure *ps;
+ GstStructure *s;
+ gint clock_rate = 0, frame_size = 0, channels = 1;
+
+ caps = gst_caps_make_writable (caps);
+
+ ps = gst_caps_get_structure (otherpadcaps, 0);
+ s = gst_caps_get_structure (caps, 0);
+
+ if (gst_structure_get_int (ps, "clock-rate", &clock_rate)) {
+ gst_structure_fixate_field_nearest_int (s, "rate", clock_rate);
+ }
+
+ if ((params = gst_structure_get_string (ps, "frame-size")))
+ frame_size = atoi (params);
+ if (frame_size)
+ gst_structure_set (s, "frame-size", G_TYPE_INT, frame_size, NULL);
+
+ if ((params = gst_structure_get_string (ps, "encoding-params"))) {
+ channels = atoi (params);
+ gst_structure_fixate_field_nearest_int (s, "channels", channels);
+ }
+
+ GST_DEBUG_OBJECT (payload, "clock-rate=%d frame-size=%d channels=%d",
+ clock_rate, frame_size, channels);
+ }
+ gst_caps_unref (otherpadcaps);
+ }
+
+ return caps;
+}
+
+static gboolean
+gst_rtp_celt_pay_parse_ident (GstRtpCELTPay * rtpceltpay,
+ const guint8 * data, guint size)
+{
+ guint32 version, header_size, rate, nb_channels, frame_size, overlap;
+ guint32 bytes_per_packet;
+ GstRTPBasePayload *payload;
+ gchar *cstr, *fsstr;
+ gboolean res;
+
+ /* we need the header string (8), the version string (20), the version
+ * and the header length. */
+ if (size < 36)
+ goto too_small;
+
+ if (!g_str_has_prefix ((const gchar *) data, "CELT "))
+ goto wrong_header;
+
+ /* skip header and version string */
+ data += 28;
+
+ version = GST_READ_UINT32_LE (data);
+ GST_DEBUG_OBJECT (rtpceltpay, "version %08x", version);
+#if 0
+ if (version != 1)
+ goto wrong_version;
+#endif
+
+ data += 4;
+ /* ensure sizes */
+ header_size = GST_READ_UINT32_LE (data);
+ if (header_size < 56)
+ goto header_too_small;
+
+ if (size < header_size)
+ goto payload_too_small;
+
+ data += 4;
+ rate = GST_READ_UINT32_LE (data);
+ data += 4;
+ nb_channels = GST_READ_UINT32_LE (data);
+ data += 4;
+ frame_size = GST_READ_UINT32_LE (data);
+ data += 4;
+ overlap = GST_READ_UINT32_LE (data);
+ data += 4;
+ bytes_per_packet = GST_READ_UINT32_LE (data);
+
+ GST_DEBUG_OBJECT (rtpceltpay, "rate %d, nb_channels %d, frame_size %d",
+ rate, nb_channels, frame_size);
+ GST_DEBUG_OBJECT (rtpceltpay, "overlap %d, bytes_per_packet %d",
+ overlap, bytes_per_packet);
+
+ payload = GST_RTP_BASE_PAYLOAD (rtpceltpay);
+
+ gst_rtp_base_payload_set_options (payload, "audio", FALSE, "CELT", rate);
+ cstr = g_strdup_printf ("%d", nb_channels);
+ fsstr = g_strdup_printf ("%d", frame_size);
+ res = gst_rtp_base_payload_set_outcaps (payload, "encoding-params",
+ G_TYPE_STRING, cstr, "frame-size", G_TYPE_STRING, fsstr, NULL);
+ g_free (cstr);
+ g_free (fsstr);
+
+ return res;
+
+ /* ERRORS */
+too_small:
+ {
+ GST_DEBUG_OBJECT (rtpceltpay,
+ "ident packet too small, need at least 32 bytes");
+ return FALSE;
+ }
+wrong_header:
+ {
+ GST_DEBUG_OBJECT (rtpceltpay,
+ "ident packet does not start with \"CELT \"");
+ return FALSE;
+ }
+#if 0
+wrong_version:
+ {
+ GST_DEBUG_OBJECT (rtpceltpay, "can only handle version 1, have version %d",
+ version);
+ return FALSE;
+ }
+#endif
+header_too_small:
+ {
+ GST_DEBUG_OBJECT (rtpceltpay,
+ "header size too small, need at least 80 bytes, " "got only %d",
+ header_size);
+ return FALSE;
+ }
+payload_too_small:
+ {
+ GST_DEBUG_OBJECT (rtpceltpay,
+ "payload too small, need at least %d bytes, got only %d", header_size,
+ size);
+ return FALSE;
+ }
+}
+
+static GstFlowReturn
+gst_rtp_celt_pay_flush_queued (GstRtpCELTPay * rtpceltpay)
+{
+ GstFlowReturn ret;
+ GstBuffer *buf, *outbuf;
+ guint8 *payload, *spayload;
+ guint payload_len;
+ GstClockTime duration;
+ GstRTPBuffer rtp = { NULL, };
+
+ payload_len = rtpceltpay->bytes + rtpceltpay->sbytes;
+ duration = rtpceltpay->qduration;
+
+ GST_DEBUG_OBJECT (rtpceltpay, "flushing out %u, duration %" GST_TIME_FORMAT,
+ payload_len, GST_TIME_ARGS (rtpceltpay->qduration));
+
+ /* get a big enough packet for the sizes + payloads */
+ outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
+
+ GST_BUFFER_DURATION (outbuf) = duration;
+
+ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+ /* point to the payload for size headers and data */
+ spayload = gst_rtp_buffer_get_payload (&rtp);
+ payload = spayload + rtpceltpay->sbytes;
+
+ while ((buf = g_queue_pop_head (rtpceltpay->queue))) {
+ guint size;
+
+ /* copy first timestamp to output */
+ if (GST_BUFFER_TIMESTAMP (outbuf) == -1)
+ GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
+
+ /* write the size to the header */
+ size = gst_buffer_get_size (buf);
+ while (size > 0xff) {
+ *spayload++ = 0xff;
+ size -= 0xff;
+ }
+ *spayload++ = size;
+
+ /* copy payload */
+ size = gst_buffer_get_size (buf);
+ gst_buffer_extract (buf, 0, payload, size);
+ payload += size;
+
+ gst_buffer_unref (buf);
+ }
+ gst_rtp_buffer_unmap (&rtp);
+
+ /* we consumed it all */
+ rtpceltpay->bytes = 0;
+ rtpceltpay->sbytes = 0;
+ rtpceltpay->qduration = 0;
+
+ ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpceltpay), outbuf);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_rtp_celt_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer)
+{
+ GstFlowReturn ret;
+ GstRtpCELTPay *rtpceltpay;
+ gsize payload_len;
+ GstMapInfo map;
+ GstClockTime duration, packet_dur;
+ guint i, ssize, packet_len;
+
+ rtpceltpay = GST_RTP_CELT_PAY (basepayload);
+
+ ret = GST_FLOW_OK;
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+ switch (rtpceltpay->packet) {
+ case 0:
+ /* ident packet. We need to parse the headers to construct the RTP
+ * properties. */
+ if (!gst_rtp_celt_pay_parse_ident (rtpceltpay, map.data, map.size))
+ goto parse_error;
+
+ goto cleanup;
+ case 1:
+ /* comment packet, we ignore it */
+ goto cleanup;
+ default:
+ /* other packets go in the payload */
+ break;
+ }
+ gst_buffer_unmap (buffer, &map);
+
+ duration = GST_BUFFER_DURATION (buffer);
+
+ GST_LOG_OBJECT (rtpceltpay,
+ "got buffer of duration %" GST_TIME_FORMAT ", size %" G_GSIZE_FORMAT,
+ GST_TIME_ARGS (duration), map.size);
+
+ /* calculate the size of the size field and the payload */
+ ssize = 1;
+ for (i = map.size; i > 0xff; i -= 0xff)
+ ssize++;
+
+ GST_DEBUG_OBJECT (rtpceltpay, "bytes for size %u", ssize);
+
+ /* calculate what the new size and duration would be of the packet */
+ payload_len = ssize + map.size + rtpceltpay->bytes + rtpceltpay->sbytes;
+ if (rtpceltpay->qduration != -1 && duration != -1)
+ packet_dur = rtpceltpay->qduration + duration;
+ else
+ packet_dur = 0;
+
+ packet_len = gst_rtp_buffer_calc_packet_len (payload_len, 0, 0);
+
+ if (gst_rtp_base_payload_is_filled (basepayload, packet_len, packet_dur)) {
+ /* size or duration would overflow the packet, flush the queued data */
+ ret = gst_rtp_celt_pay_flush_queued (rtpceltpay);
+ }
+
+ /* queue the packet */
+ gst_rtp_celt_pay_add_queued (rtpceltpay, buffer, ssize, map.size, duration);
+
+done:
+ rtpceltpay->packet++;
+
+ return ret;
+
+ /* ERRORS */
+cleanup:
+ {
+ gst_buffer_unmap (buffer, &map);
+ goto done;
+ }
+parse_error:
+ {
+ GST_ELEMENT_ERROR (rtpceltpay, STREAM, DECODE, (NULL),
+ ("Error parsing first identification packet."));
+ gst_buffer_unmap (buffer, &map);
+ return GST_FLOW_ERROR;
+ }
+}
+
+static GstStateChangeReturn
+gst_rtp_celt_pay_change_state (GstElement * element, GstStateChange transition)
+{
+ GstRtpCELTPay *rtpceltpay;
+ GstStateChangeReturn ret;
+
+ rtpceltpay = GST_RTP_CELT_PAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ rtpceltpay->packet = 0;
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_rtp_celt_pay_clear_queued (rtpceltpay);
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+gboolean
+gst_rtp_celt_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpceltpay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_CELT_PAY);
+}
diff --git a/gst/rtp/gstrtpceltpay.h b/gst/rtp/gstrtpceltpay.h
new file mode 100755
index 0000000..dcdd0ec
--- /dev/null
+++ b/gst/rtp/gstrtpceltpay.h
@@ -0,0 +1,62 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@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
+ */
+
+
+#ifndef __GST_RTP_CELT_PAY_H__
+#define __GST_RTP_CELT_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRtpCELTPay GstRtpCELTPay;
+typedef struct _GstRtpCELTPayClass GstRtpCELTPayClass;
+
+#define GST_TYPE_RTP_CELT_PAY \
+ (gst_rtp_celt_pay_get_type())
+#define GST_RTP_CELT_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_CELT_PAY,GstRtpCELTPay))
+#define GST_RTP_CELT_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_CELT_PAY,GstRtpCELTPayClass))
+#define GST_IS_RTP_CELT_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_CELT_PAY))
+#define GST_IS_RTP_CELT_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_CELT_PAY))
+
+struct _GstRtpCELTPay
+{
+ GstRTPBasePayload payload;
+
+ guint64 packet;
+
+ /* queue to hold packets */
+ GQueue *queue;
+ guint sbytes; /* bytes queued for sizes */
+ guint bytes; /* bytes queued for data */
+ GstClockTime qduration; /* queued duration */
+};
+
+struct _GstRtpCELTPayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_celt_pay_get_type (void);
+
+gboolean gst_rtp_celt_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_CELT_PAY_H__ */
diff --git a/gst/rtp/gstrtpchannels.c b/gst/rtp/gstrtpchannels.c
new file mode 100755
index 0000000..100aaa4
--- /dev/null
+++ b/gst/rtp/gstrtpchannels.c
@@ -0,0 +1,164 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "gstrtpchannels.h"
+
+/*
+ * RTP channel positions as discussed in RFC 3551 and also RFC 3555
+ *
+ * We can't really represent the described channel positions in GStreamer but we
+ * implement a (very rough) approximation here.
+ */
+
+static gboolean
+check_channels (const GstRTPChannelOrder * order,
+ const GstAudioChannelPosition * pos)
+{
+ gint i, j;
+ gboolean res = TRUE;
+
+ for (i = 0; i < order->channels; i++) {
+ for (j = 0; j < order->channels; j++) {
+ if (order->pos[j] == pos[i])
+ break;
+ }
+ if (j == order->channels)
+ return FALSE;
+ }
+ return res;
+}
+
+/**
+ * gst_rtp_channels_get_by_pos:
+ * @channels: the amount of channels
+ * @pos: a channel layout
+ *
+ * Return a description of the channel layout.
+ *
+ * Returns: a #GstRTPChannelOrder with the channel information or NULL when @pos
+ * is not a valid layout.
+ */
+const GstRTPChannelOrder *
+gst_rtp_channels_get_by_pos (gint channels, const GstAudioChannelPosition * pos)
+{
+ gint i;
+ const GstRTPChannelOrder *res = NULL;
+
+ g_return_val_if_fail (pos != NULL, NULL);
+
+ for (i = 0; channel_orders[i].pos; i++) {
+ if (channel_orders[i].channels != channels)
+ continue;
+
+ if (check_channels (&channel_orders[i], pos)) {
+ res = &channel_orders[i];
+ break;
+ }
+ }
+ return res;
+}
+
+/**
+ * gst_rtp_channels_create_default:
+ * @channels: the amount of channels
+ * @order: a channel order
+ *
+ * Get the channel order info the @order and @channels.
+ *
+ * Returns: a #GstRTPChannelOrder with the channel information or NULL when
+ * @order is not a know layout for @channels.
+ */
+const GstRTPChannelOrder *
+gst_rtp_channels_get_by_order (gint channels, const gchar * order)
+{
+ gint i;
+ const GstRTPChannelOrder *res = NULL;
+
+ for (i = 0; channel_orders[i].pos; i++) {
+ if (channel_orders[i].channels != channels)
+ continue;
+
+ /* no name but channels match, continue */
+ if (!channel_orders[i].name || !order) {
+ res = &channel_orders[i];
+ break;
+ }
+
+ /* compare names */
+ if (g_ascii_strcasecmp (channel_orders[i].name, order)) {
+ res = &channel_orders[i];
+ break;
+ }
+ }
+ return res;
+}
+
+/**
+ * gst_rtp_channels_get_by_index:
+ * @channels: the amount of channels
+ * @idx: the channel index to retrieve
+ *
+ * Get the allowed channel order descriptions for @channels. @idx can be used to
+ * retrieve the desired index.
+ *
+ * Returns: a #GstRTPChannelOrder at @idx, NULL when there are no valid channel
+ * orders.
+ */
+const GstRTPChannelOrder *
+gst_rtp_channels_get_by_index (gint channels, guint idx)
+{
+ gint i;
+ const GstRTPChannelOrder *res = NULL;
+
+ for (i = 0; channel_orders[i].pos; i++) {
+ if (channel_orders[i].channels != channels)
+ continue;
+
+ if (idx == 0) {
+ res = &channel_orders[i];
+ break;
+ }
+ idx--;
+ }
+ return res;
+}
+
+
+/**
+ * gst_rtp_channels_create_default:
+ * @channels: the amount of channels
+ *
+ * Create a default none channel mapping for @channels.
+ *
+ * Returns: a #GstAudioChannelPosition with all the channel position info set to
+ * #GST_AUDIO_CHANNEL_POSITION_NONE.
+ */
+void
+gst_rtp_channels_create_default (gint channels, GstAudioChannelPosition * posn)
+{
+ gint i;
+
+ g_return_if_fail (channels > 0);
+
+ for (i = 0; i < channels; i++)
+ posn[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
+}
diff --git a/gst/rtp/gstrtpchannels.h b/gst/rtp/gstrtpchannels.h
new file mode 100755
index 0000000..31727fb
--- /dev/null
+++ b/gst/rtp/gstrtpchannels.h
@@ -0,0 +1,190 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gst/audio/audio.h>
+
+#ifndef __GST_RTP_CHANNELS_H__
+#define __GST_RTP_CHANNELS_H__
+
+typedef struct
+{
+ const gchar *name;
+ gint channels;
+ const GstAudioChannelPosition *pos;
+} GstRTPChannelOrder;
+
+static const GstAudioChannelPosition pos_4_1[] = {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT
+};
+
+static const GstAudioChannelPosition pos_4_2[] = {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_LFE1
+};
+
+static const GstAudioChannelPosition pos_4_3[] = {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_LFE1
+};
+
+static const GstAudioChannelPosition pos_5_1[] = {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER
+};
+
+static const GstAudioChannelPosition pos_6_1[] = {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_LFE1
+};
+
+static const GstAudioChannelPosition pos_6_2[] = {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_LFE1,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT
+};
+
+static const GstAudioChannelPosition pos_8_1[] = {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_LFE1,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT
+};
+
+static const GstAudioChannelPosition pos_8_2[] = {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_LFE1,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT
+};
+
+static const GstAudioChannelPosition pos_8_3[] = {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_LFE1,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT
+};
+
+static const GstAudioChannelPosition pos_def_1[] = {
+ GST_AUDIO_CHANNEL_POSITION_MONO
+};
+
+static const GstAudioChannelPosition pos_def_2[] = {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT
+};
+
+static const GstAudioChannelPosition pos_def_3[] = {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER
+};
+
+static const GstAudioChannelPosition pos_def_4[] = {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_LFE1
+};
+
+static const GstAudioChannelPosition pos_def_5[] = {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT
+};
+
+static const GstAudioChannelPosition pos_def_6[] = {
+ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_LFE1
+};
+
+static const GstRTPChannelOrder channel_orders[] =
+{
+ /* 4 channels */
+ { "DV.LRLsRs", 4, pos_4_1 },
+ { "DV.LRCS", 4, pos_4_2 },
+ { "DV.LRCWo", 4, pos_4_3 },
+ /* 5 channels */
+ { "DV.LRLsRsC", 5, pos_5_1 },
+ /* 6 channels */
+ { "DV.LRLsRsCS", 6, pos_6_1 },
+ { "DV.LmixRmixTWoQ1Q2", 6, pos_6_2 },
+ /* 8 channels */
+ { "DV.LRCWoLsRsLmixRmix", 8, pos_8_1 },
+ { "DV.LRCWoLs1Rs1Ls2Rs2", 8, pos_8_2 },
+ { "DV.LRCWoLsRsLcRc", 8, pos_8_3 },
+
+ /* default layouts */
+ { NULL, 1, pos_def_1 },
+ { NULL, 2, pos_def_2 },
+ { NULL, 3, pos_def_3 },
+ { NULL, 4, pos_def_4 },
+ { NULL, 5, pos_def_5 },
+ { NULL, 6, pos_def_6 },
+
+ /* terminator, invalid entry */
+ { NULL, 0, NULL },
+};
+
+const GstRTPChannelOrder * gst_rtp_channels_get_by_pos (gint channels,
+ const GstAudioChannelPosition *pos);
+const GstRTPChannelOrder * gst_rtp_channels_get_by_order (gint channels,
+ const gchar *order);
+const GstRTPChannelOrder * gst_rtp_channels_get_by_index (gint channels, guint idx);
+
+void gst_rtp_channels_create_default (gint channels, GstAudioChannelPosition *pos);
+
+#endif /* __GST_RTP_CHANNELS_H__ */
diff --git a/gst/rtp/gstrtpdvdepay.c b/gst/rtp/gstrtpdvdepay.c
new file mode 100755
index 0000000..f13b696
--- /dev/null
+++ b/gst/rtp/gstrtpdvdepay.c
@@ -0,0 +1,415 @@
+/* Farsight
+ * Copyright (C) 2006 Marcel Moreaux <marcelm@spacelabs.nl>
+ * (C) 2008 Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * RTP DV depayloader.
+ *
+ * Important note for NTSC-users:
+ *
+ * Because the author uses PAL video, and he does not have proper DV
+ * documentation (the DV format specification is not freely available),
+ * this code may very well contain PAL-specific assumptions.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/gst.h>
+
+#include "gstrtpdvdepay.h"
+
+GST_DEBUG_CATEGORY (rtpdvdepay_debug);
+#define GST_CAT_DEFAULT (rtpdvdepay_debug)
+/* Filter signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0,
+};
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-dv")
+ );
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) { \"video\", \"audio\" },"
+ "encoding-name = (string) \"DV\", "
+ "clock-rate = (int) 90000,"
+ "encode = (string) { \"SD-VCR/525-60\", \"SD-VCR/625-50\", \"HD-VCR/1125-60\","
+ "\"HD-VCR/1250-50\", \"SDL-VCR/525-60\", \"SDL-VCR/625-50\","
+ "\"306M/525-60\", \"306M/625-50\", \"314M-25/525-60\","
+ "\"314M-25/625-50\", \"314M-50/525-60\", \"314M-50/625-50\" }"
+ /* optional parameters can't go in the template
+ * "audio = (string) { \"bundled\", \"none\" }"
+ */
+ )
+ );
+
+static GstStateChangeReturn
+gst_rtp_dv_depay_change_state (GstElement * element, GstStateChange transition);
+
+static GstBuffer *gst_rtp_dv_depay_process (GstRTPBaseDepayload * base,
+ GstBuffer * in);
+static gboolean gst_rtp_dv_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+
+#define gst_rtp_dv_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPDVDepay, gst_rtp_dv_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+
+static void
+gst_rtp_dv_depay_class_init (GstRTPDVDepayClass * klass)
+{
+ GstElementClass *gstelement_class = (GstElementClass *) klass;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class =
+ (GstRTPBaseDepayloadClass *) klass;
+
+ GST_DEBUG_CATEGORY_INIT (rtpdvdepay_debug, "rtpdvdepay", 0,
+ "DV RTP Depayloader");
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_rtp_dv_depay_change_state);
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&src_factory));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&sink_factory));
+
+ gst_element_class_set_static_metadata (gstelement_class, "RTP DV Depayloader",
+ "Codec/Depayloader/Network/RTP",
+ "Depayloads DV from RTP packets (RFC 3189)",
+ "Marcel Moreaux <marcelm@spacelabs.nl>, Wim Taymans <wim.taymans@gmail.com>");
+
+ gstrtpbasedepayload_class->process =
+ GST_DEBUG_FUNCPTR (gst_rtp_dv_depay_process);
+ gstrtpbasedepayload_class->set_caps =
+ GST_DEBUG_FUNCPTR (gst_rtp_dv_depay_setcaps);
+}
+
+/* initialize the new element
+ * instantiate pads and add them to element
+ * set functions
+ * initialize structure
+ */
+static void
+gst_rtp_dv_depay_init (GstRTPDVDepay * filter)
+{
+}
+
+static gboolean
+parse_encode (GstRTPDVDepay * rtpdvdepay, const gchar * encode)
+{
+ rtpdvdepay->width = 720;
+ if (!strcmp (encode, "314M-25/525-60")) {
+ rtpdvdepay->frame_size = 240000;
+ rtpdvdepay->height = 480;
+ rtpdvdepay->rate_num = 30000;
+ rtpdvdepay->rate_denom = 1001;
+ } else if (!strcmp (encode, "SD-VCR/525-60")) {
+ rtpdvdepay->frame_size = 120000;
+ rtpdvdepay->height = 480;
+ rtpdvdepay->rate_num = 30000;
+ rtpdvdepay->rate_denom = 1001;
+ } else if (!strcmp (encode, "314M-50/625-50")) {
+ rtpdvdepay->frame_size = 288000;
+ rtpdvdepay->height = 576;
+ rtpdvdepay->rate_num = 25;
+ rtpdvdepay->rate_denom = 1;
+ } else if (!strcmp (encode, "SD-VCR/625-50")) {
+ rtpdvdepay->frame_size = 144000;
+ rtpdvdepay->height = 576;
+ rtpdvdepay->rate_num = 25;
+ rtpdvdepay->rate_denom = 1;
+ } else if (!strcmp (encode, "314M-25/625-50")) {
+ rtpdvdepay->frame_size = 144000;
+ rtpdvdepay->height = 576;
+ rtpdvdepay->rate_num = 25;
+ rtpdvdepay->rate_denom = 1;
+ } else
+ rtpdvdepay->frame_size = -1;
+
+ return rtpdvdepay->frame_size != -1;
+}
+
+static gboolean
+gst_rtp_dv_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstStructure *structure;
+ GstRTPDVDepay *rtpdvdepay;
+ GstCaps *srccaps;
+ gint clock_rate;
+ gboolean systemstream, ret;
+ const gchar *encode, *media;
+
+ rtpdvdepay = GST_RTP_DV_DEPAY (depayload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 90000; /* default */
+ depayload->clock_rate = clock_rate;
+
+ /* we really need the encode property to figure out the frame size, it's also
+ * required by the spec */
+ if (!(encode = gst_structure_get_string (structure, "encode")))
+ goto no_encode;
+
+ /* figure out the size of one frame */
+ if (!parse_encode (rtpdvdepay, encode))
+ goto unknown_encode;
+
+ /* check the media, this tells us that the stream has video or not */
+ if (!(media = gst_structure_get_string (structure, "media")))
+ goto no_media;
+
+ systemstream = FALSE;
+
+ if (!strcmp (media, "audio")) {
+ /* we need a demuxer for audio only */
+ systemstream = TRUE;
+ } else if (!strcmp (media, "video")) {
+ const gchar *audio;
+
+ /* check the optional audio field, if it's present and set to bundled, we
+ * are dealing with a system stream. */
+ if ((audio = gst_structure_get_string (structure, "audio"))) {
+ if (!strcmp (audio, "bundled"))
+ systemstream = TRUE;
+ }
+ }
+
+ /* allocate accumulator */
+ rtpdvdepay->acc = gst_buffer_new_and_alloc (rtpdvdepay->frame_size);
+
+ /* Initialize the new accumulator frame.
+ * If the previous frame exists, copy that into the accumulator frame.
+ * This way, missing packets in the stream won't show up badly. */
+ gst_buffer_memset (rtpdvdepay->acc, 0, 0, rtpdvdepay->frame_size);
+
+ srccaps = gst_caps_new_simple ("video/x-dv",
+ "systemstream", G_TYPE_BOOLEAN, systemstream,
+ "width", G_TYPE_INT, rtpdvdepay->width,
+ "height", G_TYPE_INT, rtpdvdepay->height,
+ "framerate", GST_TYPE_FRACTION, rtpdvdepay->rate_num,
+ rtpdvdepay->rate_denom, NULL);
+ ret = gst_pad_set_caps (depayload->srcpad, srccaps);
+ gst_caps_unref (srccaps);
+
+ return ret;
+
+ /* ERRORS */
+no_encode:
+ {
+ GST_ERROR_OBJECT (rtpdvdepay, "required encode property not found in caps");
+ return FALSE;
+ }
+unknown_encode:
+ {
+ GST_ERROR_OBJECT (rtpdvdepay, "unknown encode property %s found", encode);
+ return FALSE;
+ }
+no_media:
+ {
+ GST_ERROR_OBJECT (rtpdvdepay, "required media property not found in caps");
+ return FALSE;
+ }
+}
+
+/* A DV frame consists of a bunch of 80-byte DIF blocks.
+ * Each DIF block contains a 3-byte header telling where in the DV frame the
+ * DIF block should go. We use this information to calculate its position.
+ */
+static guint
+calculate_difblock_location (guint8 * block)
+{
+ gint block_type, dif_sequence, dif_block;
+ guint location;
+
+ block_type = block[0] >> 5;
+ dif_sequence = block[1] >> 4;
+ dif_block = block[2];
+
+ location = dif_sequence * 150;
+
+ switch (block_type) {
+ case 0: /* Header block, no offset */
+ break;
+ case 1: /* Subcode block */
+ location += (1 + dif_block);
+ break;
+ case 2: /* VAUX block */
+ location += (3 + dif_block);
+ break;
+ case 3: /* Audio block */
+ location += (6 + dif_block * 16);
+ break;
+ case 4: /* Video block */
+ location += (7 + (dif_block / 15) + dif_block);
+ break;
+ default: /* Something bogus */
+ GST_DEBUG ("UNKNOWN BLOCK");
+ location = -1;
+ break;
+ }
+ return location;
+}
+
+/* Process one RTP packet. Accumulate RTP payload in the proper place in a DV
+ * frame, and return that frame if we detect a new frame, or NULL otherwise.
+ * We assume a DV frame is 144000 bytes. That should accomodate PAL as well as
+ * NTSC.
+ */
+static GstBuffer *
+gst_rtp_dv_depay_process (GstRTPBaseDepayload * base, GstBuffer * in)
+{
+ GstBuffer *out = NULL;
+ guint8 *payload;
+ guint32 rtp_ts;
+ guint payload_len, location;
+ GstRTPDVDepay *dvdepay = GST_RTP_DV_DEPAY (base);
+ gboolean marker;
+ GstRTPBuffer rtp = { NULL, };
+
+ gst_rtp_buffer_map (in, GST_MAP_READ, &rtp);
+
+ marker = gst_rtp_buffer_get_marker (&rtp);
+
+ /* Check if the received packet contains (the start of) a new frame, we do
+ * this by checking the RTP timestamp. */
+ rtp_ts = gst_rtp_buffer_get_timestamp (&rtp);
+
+ /* we cannot copy the packet yet if the marker is set, we will do that below
+ * after taking out the data */
+ if (dvdepay->prev_ts != -1 && rtp_ts != dvdepay->prev_ts && !marker) {
+ /* the timestamp changed */
+ GST_DEBUG_OBJECT (dvdepay, "new frame with ts %u, old ts %u", rtp_ts,
+ dvdepay->prev_ts);
+
+ /* return copy of accumulator. */
+ out = gst_buffer_copy (dvdepay->acc);
+ }
+
+ /* Extract the payload */
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+ payload = gst_rtp_buffer_get_payload (&rtp);
+
+ /* copy all DIF chunks in their place. */
+ while (payload_len >= 80) {
+ guint offset;
+
+ /* Calculate where in the frame the payload should go */
+ location = calculate_difblock_location (payload);
+
+ if (location < 6) {
+ /* part of a header, set the flag to mark that we have the header. */
+ dvdepay->header_mask |= (1 << location);
+ GST_LOG_OBJECT (dvdepay, "got header at location %d, now %02x", location,
+ dvdepay->header_mask);
+ } else {
+ GST_LOG_OBJECT (dvdepay, "got block at location %d", location);
+ }
+
+ if (location != -1) {
+ /* get the byte offset of the dif block */
+ offset = location * 80;
+
+ /* And copy it in, provided the location is sane. */
+ if (offset <= dvdepay->frame_size - 80)
+ gst_buffer_fill (dvdepay->acc, offset, payload, 80);
+ }
+
+ payload += 80;
+ payload_len -= 80;
+ }
+ gst_rtp_buffer_unmap (&rtp);
+
+ if (marker) {
+ GST_DEBUG_OBJECT (dvdepay, "marker bit complete frame %u", rtp_ts);
+ /* only copy the frame when we have a complete header */
+ if (dvdepay->header_mask == 0x3f) {
+ /* The marker marks the end of a frame that we need to push. The next frame
+ * will change the timestamp but we won't copy the accumulator again because
+ * we set the prev_ts to -1. */
+ out = gst_buffer_copy (dvdepay->acc);
+ } else {
+ GST_WARNING_OBJECT (dvdepay, "waiting for frame headers %02x",
+ dvdepay->header_mask);
+ }
+ dvdepay->prev_ts = -1;
+ } else {
+ /* save last timestamp */
+ dvdepay->prev_ts = rtp_ts;
+ }
+ return out;
+}
+
+static void
+gst_rtp_dv_depay_reset (GstRTPDVDepay * depay)
+{
+ if (depay->acc)
+ gst_buffer_unref (depay->acc);
+ depay->acc = NULL;
+
+ depay->prev_ts = -1;
+ depay->header_mask = 0;
+}
+
+static GstStateChangeReturn
+gst_rtp_dv_depay_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret;
+ GstRTPDVDepay *depay = GST_RTP_DV_DEPAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_rtp_dv_depay_reset (depay);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,
+ (element, transition), GST_STATE_CHANGE_FAILURE);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_rtp_dv_depay_reset (depay);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+gboolean
+gst_rtp_dv_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpdvdepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_DV_DEPAY);
+}
diff --git a/gst/rtp/gstrtpdvdepay.h b/gst/rtp/gstrtpdvdepay.h
new file mode 100755
index 0000000..1ce5b97
--- /dev/null
+++ b/gst/rtp/gstrtpdvdepay.h
@@ -0,0 +1,66 @@
+/* Farsight
+ * Copyright (C) 2006 Marcel Moreaux <marcelm@spacelabs.nl>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GSTRTPDVDEPAY_H__
+#define __GSTRTPDVDEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+/* #define's don't like whitespacey bits */
+#define GST_TYPE_RTP_DV_DEPAY (gst_rtp_dv_depay_get_type())
+#define GST_RTP_DV_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_DV_DEPAY,GstRTPDVDepay))
+#define GST_RTP_DV_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_DV_DEPAY,GstRTPDVDepay))
+#define GST_IS_RTP_DV_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_DV_DEPAY))
+#define GST_IS_RTP_DV_DEPAY_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_DV_DEPAY))
+
+typedef struct _GstRTPDVDepay GstRTPDVDepay;
+typedef struct _GstRTPDVDepayClass GstRTPDVDepayClass;
+
+struct _GstRTPDVDepay
+{
+ GstRTPBaseDepayload parent;
+
+ GstBuffer *acc;
+ guint frame_size;
+ guint32 prev_ts;
+ guint8 header_mask;
+
+ gint width, height;
+ gint rate_num, rate_denom;
+};
+
+struct _GstRTPDVDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_dv_depay_get_type (void);
+
+gboolean gst_rtp_dv_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GSTRTPDVDEPAY_H__ */
diff --git a/gst/rtp/gstrtpdvpay.c b/gst/rtp/gstrtpdvpay.c
new file mode 100755
index 0000000..db75cf6
--- /dev/null
+++ b/gst/rtp/gstrtpdvpay.c
@@ -0,0 +1,395 @@
+/* Farsight
+ * Copyright (C) 2006 Marcel Moreaux <marcelm@spacelabs.nl>
+ * (C) 2008 Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpdvpay.h"
+
+GST_DEBUG_CATEGORY (rtpdvpay_debug);
+#define GST_CAT_DEFAULT (rtpdvpay_debug)
+
+#define DEFAULT_MODE GST_DV_PAY_MODE_VIDEO
+enum
+{
+ PROP_0,
+ PROP_MODE
+};
+
+/* takes both system and non-system streams */
+static GstStaticPadTemplate gst_rtp_dv_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-dv")
+ );
+
+static GstStaticPadTemplate gst_rtp_dv_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) { \"video\", \"audio\" } ,"
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "encoding-name = (string) \"DV\", "
+ "clock-rate = (int) 90000,"
+ "encode = (string) { \"SD-VCR/525-60\", \"SD-VCR/625-50\", \"HD-VCR/1125-60\","
+ "\"HD-VCR/1250-50\", \"SDL-VCR/525-60\", \"SDL-VCR/625-50\","
+ "\"306M/525-60\", \"306M/625-50\", \"314M-25/525-60\","
+ "\"314M-25/625-50\", \"314M-50/525-60\", \"314M-50/625-50\" }"
+ /* optional parameters can't go in the template
+ * "audio = (string) { \"bundled\", \"none\" }"
+ */
+ )
+ );
+
+static gboolean gst_rtp_dv_pay_setcaps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+static GstFlowReturn gst_rtp_dv_pay_handle_buffer (GstRTPBasePayload * payload,
+ GstBuffer * buffer);
+
+#define GST_TYPE_DV_PAY_MODE (gst_dv_pay_mode_get_type())
+static GType
+gst_dv_pay_mode_get_type (void)
+{
+ static GType dv_pay_mode_type = 0;
+ static const GEnumValue dv_pay_modes[] = {
+ {GST_DV_PAY_MODE_VIDEO, "Video only", "video"},
+ {GST_DV_PAY_MODE_BUNDLED, "Video and Audio bundled", "bundled"},
+ {GST_DV_PAY_MODE_AUDIO, "Audio only", "audio"},
+ {0, NULL, NULL},
+ };
+
+ if (!dv_pay_mode_type) {
+ dv_pay_mode_type = g_enum_register_static ("GstDVPayMode", dv_pay_modes);
+ }
+ return dv_pay_mode_type;
+}
+
+
+static void gst_dv_pay_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_dv_pay_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec);
+
+#define gst_rtp_dv_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPDVPay, gst_rtp_dv_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_dv_pay_class_init (GstRTPDVPayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ GST_DEBUG_CATEGORY_INIT (rtpdvpay_debug, "rtpdvpay", 0, "DV RTP Payloader");
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gobject_class->set_property = gst_dv_pay_set_property;
+ gobject_class->get_property = gst_dv_pay_get_property;
+
+ g_object_class_install_property (gobject_class, PROP_MODE,
+ g_param_spec_enum ("mode", "Mode",
+ "The payload mode of payloading",
+ GST_TYPE_DV_PAY_MODE, DEFAULT_MODE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_dv_pay_sink_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_dv_pay_src_template));
+
+ gst_element_class_set_static_metadata (gstelement_class, "RTP DV Payloader",
+ "Codec/Payloader/Network/RTP",
+ "Payloads DV into RTP packets (RFC 3189)",
+ "Marcel Moreaux <marcelm@spacelabs.nl>, Wim Taymans <wim.taymans@gmail.com>");
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_dv_pay_setcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_dv_pay_handle_buffer;
+}
+
+static void
+gst_rtp_dv_pay_init (GstRTPDVPay * rtpdvpay)
+{
+}
+
+static void
+gst_dv_pay_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ GstRTPDVPay *rtpdvpay = GST_RTP_DV_PAY (object);
+
+ switch (prop_id) {
+ case PROP_MODE:
+ rtpdvpay->mode = g_value_get_enum (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_dv_pay_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ GstRTPDVPay *rtpdvpay = GST_RTP_DV_PAY (object);
+
+ switch (prop_id) {
+ case PROP_MODE:
+ g_value_set_enum (value, rtpdvpay->mode);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+gst_rtp_dv_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ /* We don't do anything here, but we could check if it's a system stream and if
+ * it's not, default to sending the video only. We will negotiate downstream
+ * caps when we get to see the first frame. */
+
+ return TRUE;
+}
+
+static gboolean
+gst_dv_pay_negotiate (GstRTPDVPay * rtpdvpay, guint8 * data, gsize size)
+{
+ const gchar *encode, *media;
+ gboolean audio_bundled, res;
+
+ if ((data[3] & 0x80) == 0) { /* DSF flag */
+ /* it's an NTSC format */
+ if ((data[80 * 5 + 48 + 3] & 0x4) && (data[80 * 5 + 48] == 0x60)) { /* 4:2:2 sampling */
+ /* NTSC 50Mbps */
+ encode = "314M-25/525-60";
+ } else { /* 4:1:1 sampling */
+ /* NTSC 25Mbps */
+ encode = "SD-VCR/525-60";
+ }
+ } else {
+ /* it's a PAL format */
+ if ((data[80 * 5 + 48 + 3] & 0x4) && (data[80 * 5 + 48] == 0x60)) { /* 4:2:2 sampling */
+ /* PAL 50Mbps */
+ encode = "314M-50/625-50";
+ } else if ((data[5] & 0x07) == 0) { /* APT flag */
+ /* PAL 25Mbps 4:2:0 */
+ encode = "SD-VCR/625-50";
+ } else
+ /* PAL 25Mbps 4:1:1 */
+ encode = "314M-25/625-50";
+ }
+
+ media = "video";
+ audio_bundled = FALSE;
+
+ switch (rtpdvpay->mode) {
+ case GST_DV_PAY_MODE_AUDIO:
+ media = "audio";
+ break;
+ case GST_DV_PAY_MODE_BUNDLED:
+ audio_bundled = TRUE;
+ break;
+ default:
+ break;
+ }
+ gst_rtp_base_payload_set_options (GST_RTP_BASE_PAYLOAD (rtpdvpay), media,
+ TRUE, "DV", 90000);
+
+ if (audio_bundled) {
+ res = gst_rtp_base_payload_set_outcaps (GST_RTP_BASE_PAYLOAD (rtpdvpay),
+ "encode", G_TYPE_STRING, encode,
+ "audio", G_TYPE_STRING, "bundled", NULL);
+ } else {
+ res = gst_rtp_base_payload_set_outcaps (GST_RTP_BASE_PAYLOAD (rtpdvpay),
+ "encode", G_TYPE_STRING, encode, NULL);
+ }
+ return res;
+}
+
+static gboolean
+include_dif (GstRTPDVPay * rtpdvpay, guint8 * data)
+{
+ gint block_type;
+ gboolean res;
+
+ block_type = data[0] >> 5;
+
+ switch (block_type) {
+ case 0: /* Header block */
+ case 1: /* Subcode block */
+ case 2: /* VAUX block */
+ /* always include these blocks */
+ res = TRUE;
+ break;
+ case 3: /* Audio block */
+ /* never include audio if we are doing video only */
+ if (rtpdvpay->mode == GST_DV_PAY_MODE_VIDEO)
+ res = FALSE;
+ else
+ res = TRUE;
+ break;
+ case 4: /* Video block */
+ /* never include video if we are doing audio only */
+ if (rtpdvpay->mode == GST_DV_PAY_MODE_AUDIO)
+ res = FALSE;
+ else
+ res = TRUE;
+ break;
+ default: /* Something bogus, just ignore */
+ res = FALSE;
+ break;
+ }
+ return res;
+}
+
+/* Get a DV frame, chop it up in pieces, and push the pieces to the RTP layer.
+ */
+static GstFlowReturn
+gst_rtp_dv_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer)
+{
+ GstRTPDVPay *rtpdvpay;
+ guint max_payload_size;
+ GstBuffer *outbuf;
+ GstFlowReturn ret = GST_FLOW_OK;
+ gint hdrlen;
+ gsize size;
+ GstMapInfo map;
+ guint8 *data;
+ guint8 *dest;
+ guint filled;
+ GstRTPBuffer rtp = { NULL, };
+
+ rtpdvpay = GST_RTP_DV_PAY (basepayload);
+
+ hdrlen = gst_rtp_buffer_calc_header_len (0);
+ /* DV frames are made up from a bunch of DIF blocks. DIF blocks are 80 bytes
+ * each, and we should put an integral number of them in each RTP packet.
+ * Therefore, we round the available room down to the nearest multiple of 80.
+ *
+ * The available room is just the packet MTU, minus the RTP header length. */
+ max_payload_size = ((GST_RTP_BASE_PAYLOAD_MTU (rtpdvpay) - hdrlen) / 80) * 80;
+
+ /* The length of the buffer to transmit. */
+ if (!gst_buffer_map (buffer, &map, GST_MAP_READ)) {
+ GST_ELEMENT_ERROR (rtpdvpay, CORE, FAILED,
+ (NULL), ("Failed to map buffer"));
+ gst_buffer_unref (buffer);
+ return GST_FLOW_ERROR;
+ }
+ data = map.data;
+ size = map.size;
+
+ GST_DEBUG_OBJECT (rtpdvpay,
+ "DV RTP payloader got buffer of %" G_GSIZE_FORMAT
+ " bytes, splitting in %u byte " "payload fragments, at time %"
+ GST_TIME_FORMAT, size, max_payload_size,
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
+
+ if (!rtpdvpay->negotiated) {
+ gst_dv_pay_negotiate (rtpdvpay, data, size);
+ /* if we have not yet scanned the stream for its type, do so now */
+ rtpdvpay->negotiated = TRUE;
+ }
+
+ outbuf = NULL;
+ dest = NULL;
+ filled = 0;
+
+ /* while we have a complete DIF chunks left */
+ while (size >= 80) {
+ /* Allocate a new buffer, set the timestamp */
+ if (outbuf == NULL) {
+ outbuf = gst_rtp_buffer_new_allocate (max_payload_size, 0, 0);
+ GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buffer);
+
+ if (!gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp)) {
+ gst_buffer_unref (outbuf);
+ GST_ELEMENT_ERROR (rtpdvpay, CORE, FAILED,
+ (NULL), ("Failed to map RTP buffer"));
+ ret = GST_FLOW_ERROR;
+ goto beach;
+ }
+ dest = gst_rtp_buffer_get_payload (&rtp);
+ filled = 0;
+ }
+
+ /* inspect the DIF chunk, if we don't need to include it, skip to the next one. */
+ if (include_dif (rtpdvpay, data)) {
+ /* copy data in packet */
+ memcpy (dest, data, 80);
+
+ dest += 80;
+ filled += 80;
+ }
+
+ /* go to next dif chunk */
+ size -= 80;
+ data += 80;
+
+ /* push out the buffer if the next one would exceed the max packet size or
+ * when we are pushing the last packet */
+ if (filled + 80 > max_payload_size || size < 80) {
+ if (size < 160) {
+ guint hlen;
+
+ /* set marker */
+ gst_rtp_buffer_set_marker (&rtp, TRUE);
+
+ /* shrink buffer to last packet */
+ hlen = gst_rtp_buffer_get_header_len (&rtp);
+ gst_rtp_buffer_set_packet_len (&rtp, hlen + filled);
+ }
+
+ /* Push out the created piece, and check for errors. */
+ gst_rtp_buffer_unmap (&rtp);
+ ret = gst_rtp_base_payload_push (basepayload, outbuf);
+ if (ret != GST_FLOW_OK)
+ break;
+
+ outbuf = NULL;
+ }
+ }
+
+beach:
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+
+ return ret;
+}
+
+gboolean
+gst_rtp_dv_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpdvpay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_DV_PAY);
+}
diff --git a/gst/rtp/gstrtpdvpay.h b/gst/rtp/gstrtpdvpay.h
new file mode 100755
index 0000000..4c250a8
--- /dev/null
+++ b/gst/rtp/gstrtpdvpay.h
@@ -0,0 +1,69 @@
+/* Farsight
+ * Copyright (C) 2006 Marcel Moreaux <marcelm@spacelabs.nl>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GSTRTPDVPAY_H__
+#define __GSTRTPDVPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRTPDVPay GstRTPDVPay;
+typedef struct _GstRTPDVPayClass GstRTPDVPayClass;
+
+#define GST_TYPE_RTP_DV_PAY \
+ (gst_rtp_dv_pay_get_type())
+#define GST_RTP_DV_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_DV_PAY,GstRTPDVPay))
+#define GST_RTP_DV_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_DV_PAY,GstRTPDVPay))
+#define GST_IS_RTP_DV_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_DV_PAY))
+#define GST_IS_RTP_DV_PAY_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_DV_PAY))
+
+typedef enum
+{
+ GST_DV_PAY_MODE_VIDEO,
+ GST_DV_PAY_MODE_BUNDLED,
+ GST_DV_PAY_MODE_AUDIO
+} GstDVPayMode;
+
+struct _GstRTPDVPay
+{
+ GstRTPBasePayload payload;
+
+ gboolean negotiated;
+ GstDVPayMode mode;
+};
+
+struct _GstRTPDVPayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_dv_pay_get_type (void);
+
+gboolean gst_rtp_dv_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GSTRTPDVPAY_H__ */
diff --git a/gst/rtp/gstrtpg722depay.c b/gst/rtp/gstrtpg722depay.c
new file mode 100755
index 0000000..c77fb95
--- /dev/null
+++ b/gst/rtp/gstrtpg722depay.c
@@ -0,0 +1,262 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gst/audio/audio.h>
+
+#include "gstrtpg722depay.h"
+#include "gstrtpchannels.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpg722depay_debug);
+#define GST_CAT_DEFAULT (rtpg722depay_debug)
+
+static GstStaticPadTemplate gst_rtp_g722_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/G722, "
+ "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
+ );
+
+static GstStaticPadTemplate gst_rtp_g722_depay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", " "clock-rate = (int) 8000, "
+ /* "channels = (int) [1, MAX]" */
+ /* "channel-order = (string) ANY" */
+ "encoding-name = (string) \"G722\";"
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_G722_STRING ", "
+ "clock-rate = (int) [ 1, MAX ]"
+ /* "channels = (int) [1, MAX]" */
+ /* "emphasis = (string) ANY" */
+ /* "channel-order = (string) ANY" */
+ )
+ );
+
+#define gst_rtp_g722_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpG722Depay, gst_rtp_g722_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_g722_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_g722_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+
+static void
+gst_rtp_g722_depay_class_init (GstRtpG722DepayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ GST_DEBUG_CATEGORY_INIT (rtpg722depay_debug, "rtpg722depay", 0,
+ "G722 RTP Depayloader");
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_g722_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_g722_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP audio depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts G722 audio from RTP packets",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ gstrtpbasedepayload_class->set_caps = gst_rtp_g722_depay_setcaps;
+ gstrtpbasedepayload_class->process = gst_rtp_g722_depay_process;
+}
+
+static void
+gst_rtp_g722_depay_init (GstRtpG722Depay * rtpg722depay)
+{
+}
+
+static gint
+gst_rtp_g722_depay_parse_int (GstStructure * structure, const gchar * field,
+ gint def)
+{
+ const gchar *str;
+ gint res;
+
+ if ((str = gst_structure_get_string (structure, field)))
+ return atoi (str);
+
+ if (gst_structure_get_int (structure, field, &res))
+ return res;
+
+ return def;
+}
+
+static gboolean
+gst_rtp_g722_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstStructure *structure;
+ GstRtpG722Depay *rtpg722depay;
+ gint clock_rate, payload, samplerate;
+ gint channels;
+ GstCaps *srccaps;
+ gboolean res;
+#if 0
+ const gchar *channel_order;
+ const GstRTPChannelOrder *order;
+#endif
+
+ rtpg722depay = GST_RTP_G722_DEPAY (depayload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ payload = 96;
+ gst_structure_get_int (structure, "payload", &payload);
+ switch (payload) {
+ case GST_RTP_PAYLOAD_G722:
+ channels = 1;
+ clock_rate = 8000;
+ samplerate = 16000;
+ break;
+ default:
+ /* no fixed mapping, we need clock-rate */
+ channels = 0;
+ clock_rate = 0;
+ samplerate = 0;
+ break;
+ }
+
+ /* caps can overwrite defaults */
+ clock_rate =
+ gst_rtp_g722_depay_parse_int (structure, "clock-rate", clock_rate);
+ if (clock_rate == 0)
+ goto no_clockrate;
+
+ if (clock_rate == 8000)
+ samplerate = 16000;
+
+ if (samplerate == 0)
+ samplerate = clock_rate;
+
+ channels =
+ gst_rtp_g722_depay_parse_int (structure, "encoding-params", channels);
+ if (channels == 0) {
+ channels = gst_rtp_g722_depay_parse_int (structure, "channels", channels);
+ if (channels == 0) {
+ /* channels defaults to 1 otherwise */
+ channels = 1;
+ }
+ }
+
+ depayload->clock_rate = clock_rate;
+ rtpg722depay->rate = samplerate;
+ rtpg722depay->channels = channels;
+
+ srccaps = gst_caps_new_simple ("audio/G722",
+ "rate", G_TYPE_INT, samplerate, "channels", G_TYPE_INT, channels, NULL);
+
+ /* FIXME: Do something with the channel order */
+#if 0
+ /* add channel positions */
+ channel_order = gst_structure_get_string (structure, "channel-order");
+
+ order = gst_rtp_channels_get_by_order (channels, channel_order);
+ if (order) {
+ gst_audio_set_channel_positions (gst_caps_get_structure (srccaps, 0),
+ order->pos);
+ } else {
+ GstAudioChannelPosition *pos;
+
+ GST_ELEMENT_WARNING (rtpg722depay, STREAM, DECODE,
+ (NULL), ("Unknown channel order '%s' for %d channels",
+ GST_STR_NULL (channel_order), channels));
+ /* create default NONE layout */
+ pos = gst_rtp_channels_create_default (channels);
+ gst_audio_set_channel_positions (gst_caps_get_structure (srccaps, 0), pos);
+ g_free (pos);
+ }
+#endif
+
+ res = gst_pad_set_caps (depayload->srcpad, srccaps);
+ gst_caps_unref (srccaps);
+
+ return res;
+
+ /* ERRORS */
+no_clockrate:
+ {
+ GST_ERROR_OBJECT (depayload, "no clock-rate specified");
+ return FALSE;
+ }
+}
+
+static GstBuffer *
+gst_rtp_g722_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpG722Depay *rtpg722depay;
+ GstBuffer *outbuf;
+ gint payload_len;
+ gboolean marker;
+ GstRTPBuffer rtp = { NULL };
+
+ rtpg722depay = GST_RTP_G722_DEPAY (depayload);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+
+ if (payload_len <= 0)
+ goto empty_packet;
+
+ GST_DEBUG_OBJECT (rtpg722depay, "got payload of %d bytes", payload_len);
+
+ outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
+ marker = gst_rtp_buffer_get_marker (&rtp);
+ gst_rtp_buffer_unmap (&rtp);
+
+ if (marker && outbuf) {
+ /* mark talk spurt with RESYNC */
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+ }
+
+ return outbuf;
+
+ /* ERRORS */
+empty_packet:
+ {
+ GST_ELEMENT_WARNING (rtpg722depay, STREAM, DECODE,
+ ("Empty Payload."), (NULL));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+}
+
+gboolean
+gst_rtp_g722_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpg722depay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_G722_DEPAY);
+}
diff --git a/gst/rtp/gstrtpg722depay.h b/gst/rtp/gstrtpg722depay.h
new file mode 100755
index 0000000..8b6ffa0
--- /dev/null
+++ b/gst/rtp/gstrtpg722depay.h
@@ -0,0 +1,64 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_G722_DEPAY_H__
+#define __GST_RTP_G722_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+/* Standard macros for defining types for this element. */
+#define GST_TYPE_RTP_G722_DEPAY \
+ (gst_rtp_g722_depay_get_type())
+#define GST_RTP_G722_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_G722_DEPAY,GstRtpG722Depay))
+#define GST_RTP_G722_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_G722_DEPAY,GstRtpG722DepayClass))
+#define GST_IS_RTP_G722_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_G722_DEPAY))
+#define GST_IS_RTP_G722_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_G722_DEPAY))
+
+typedef struct _GstRtpG722Depay GstRtpG722Depay;
+typedef struct _GstRtpG722DepayClass GstRtpG722DepayClass;
+
+/* Definition of structure storing data for this element. */
+struct _GstRtpG722Depay
+{
+ GstRTPBaseDepayload depayload;
+
+ guint rate;
+ guint channels;
+};
+
+/* Standard definition defining a class for this element. */
+struct _GstRtpG722DepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_g722_depay_get_type (void);
+
+gboolean gst_rtp_g722_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_G722_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpg722pay.c b/gst/rtp/gstrtpg722pay.c
new file mode 100755
index 0000000..e9e625a
--- /dev/null
+++ b/gst/rtp/gstrtpg722pay.c
@@ -0,0 +1,217 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/audio/audio.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpg722pay.h"
+#include "gstrtpchannels.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpg722pay_debug);
+#define GST_CAT_DEFAULT (rtpg722pay_debug)
+
+static GstStaticPadTemplate gst_rtp_g722_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/G722, " "rate = (int) 16000, " "channels = (int) 1")
+ );
+
+static GstStaticPadTemplate gst_rtp_g722_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "encoding-name = (string) \"G722\", "
+ "payload = (int) " GST_RTP_PAYLOAD_G722_STRING ", "
+ "clock-rate = (int) 8000")
+ );
+
+static gboolean gst_rtp_g722_pay_setcaps (GstRTPBasePayload * basepayload,
+ GstCaps * caps);
+static GstCaps *gst_rtp_g722_pay_getcaps (GstRTPBasePayload * rtppayload,
+ GstPad * pad, GstCaps * filter);
+
+#define gst_rtp_g722_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpG722Pay, gst_rtp_g722_pay,
+ GST_TYPE_RTP_BASE_AUDIO_PAYLOAD);
+
+static void
+gst_rtp_g722_pay_class_init (GstRtpG722PayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ GST_DEBUG_CATEGORY_INIT (rtpg722pay_debug, "rtpg722pay", 0,
+ "G722 RTP Payloader");
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_g722_pay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_g722_pay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP audio payloader", "Codec/Payloader/Network/RTP",
+ "Payload-encode Raw audio into RTP packets (RFC 3551)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_g722_pay_setcaps;
+ gstrtpbasepayload_class->get_caps = gst_rtp_g722_pay_getcaps;
+}
+
+static void
+gst_rtp_g722_pay_init (GstRtpG722Pay * rtpg722pay)
+{
+ GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+ rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpg722pay);
+
+ /* tell rtpbaseaudiopayload that this is a sample based codec */
+ gst_rtp_base_audio_payload_set_sample_based (rtpbaseaudiopayload);
+}
+
+static gboolean
+gst_rtp_g722_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
+{
+ GstRtpG722Pay *rtpg722pay;
+ GstStructure *structure;
+ gint rate, channels, clock_rate;
+ gboolean res;
+ gchar *params;
+#if 0
+ GstAudioChannelPosition *pos;
+ const GstRTPChannelOrder *order;
+#endif
+ GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+ rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (basepayload);
+ rtpg722pay = GST_RTP_G722_PAY (basepayload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ /* first parse input caps */
+ if (!gst_structure_get_int (structure, "rate", &rate))
+ goto no_rate;
+
+ if (!gst_structure_get_int (structure, "channels", &channels))
+ goto no_channels;
+
+ /* FIXME: Do something with the channel positions */
+#if 0
+ /* get the channel order */
+ pos = gst_audio_get_channel_positions (structure);
+ if (pos)
+ order = gst_rtp_channels_get_by_pos (channels, pos);
+ else
+ order = NULL;
+#endif
+
+ /* Clock rate is always 8000 Hz for G722 according to
+ * RFC 3551 although the sampling rate is 16000 Hz */
+ clock_rate = 8000;
+
+ gst_rtp_base_payload_set_options (basepayload, "audio", TRUE, "G722",
+ clock_rate);
+ params = g_strdup_printf ("%d", channels);
+
+#if 0
+ if (!order && channels > 2) {
+ GST_ELEMENT_WARNING (rtpg722pay, STREAM, DECODE,
+ (NULL), ("Unknown channel order for %d channels", channels));
+ }
+
+ if (order && order->name) {
+ res = gst_rtp_base_payload_set_outcaps (basepayload,
+ "encoding-params", G_TYPE_STRING, params, "channels", G_TYPE_INT,
+ channels, "channel-order", G_TYPE_STRING, order->name, NULL);
+ } else {
+#endif
+ res = gst_rtp_base_payload_set_outcaps (basepayload,
+ "encoding-params", G_TYPE_STRING, params, "channels", G_TYPE_INT,
+ channels, NULL);
+#if 0
+ }
+#endif
+
+ g_free (params);
+#if 0
+ g_free (pos);
+#endif
+
+ rtpg722pay->rate = rate;
+ rtpg722pay->channels = channels;
+
+ /* bits-per-sample is 4 * channels for G722, but as the RTP clock runs at
+ * half speed (8 instead of 16 khz), pretend it's 8 bits per sample
+ * channels. */
+ gst_rtp_base_audio_payload_set_samplebits_options (rtpbaseaudiopayload,
+ 8 * rtpg722pay->channels);
+
+ return res;
+
+ /* ERRORS */
+no_rate:
+ {
+ GST_DEBUG_OBJECT (rtpg722pay, "no rate given");
+ return FALSE;
+ }
+no_channels:
+ {
+ GST_DEBUG_OBJECT (rtpg722pay, "no channels given");
+ return FALSE;
+ }
+}
+
+static GstCaps *
+gst_rtp_g722_pay_getcaps (GstRTPBasePayload * rtppayload, GstPad * pad,
+ GstCaps * filter)
+{
+ GstCaps *otherpadcaps;
+ GstCaps *caps;
+
+ otherpadcaps = gst_pad_get_allowed_caps (rtppayload->srcpad);
+ caps = gst_pad_get_pad_template_caps (pad);
+
+ if (otherpadcaps) {
+ if (!gst_caps_is_empty (otherpadcaps)) {
+ caps = gst_caps_make_writable (caps);
+ gst_caps_set_simple (caps, "channels", G_TYPE_INT, 1, NULL);
+ gst_caps_set_simple (caps, "rate", G_TYPE_INT, 16000, NULL);
+ }
+ gst_caps_unref (otherpadcaps);
+ }
+ return caps;
+}
+
+gboolean
+gst_rtp_g722_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpg722pay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_G722_PAY);
+}
diff --git a/gst/rtp/gstrtpg722pay.h b/gst/rtp/gstrtpg722pay.h
new file mode 100755
index 0000000..f238286
--- /dev/null
+++ b/gst/rtp/gstrtpg722pay.h
@@ -0,0 +1,61 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_G722_PAY_H__
+#define __GST_RTP_G722_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_G722_PAY \
+ (gst_rtp_g722_pay_get_type())
+#define GST_RTP_G722_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_G722_PAY,GstRtpG722Pay))
+#define GST_RTP_G722_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_G722_PAY,GstRtpG722PayClass))
+#define GST_IS_RTP_G722_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_G722_PAY))
+#define GST_IS_RTP_G722_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_G722_PAY))
+
+typedef struct _GstRtpG722Pay GstRtpG722Pay;
+typedef struct _GstRtpG722PayClass GstRtpG722PayClass;
+
+struct _GstRtpG722Pay
+{
+ GstRTPBaseAudioPayload payload;
+
+ gint rate;
+ gint channels;
+};
+
+struct _GstRtpG722PayClass
+{
+ GstRTPBaseAudioPayloadClass parent_class;
+};
+
+GType gst_rtp_g722_pay_get_type (void);
+
+gboolean gst_rtp_g722_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_G722_PAY_H__ */
diff --git a/gst/rtp/gstrtpg723depay.c b/gst/rtp/gstrtpg723depay.c
new file mode 100755
index 0000000..fb726f2
--- /dev/null
+++ b/gst/rtp/gstrtpg723depay.c
@@ -0,0 +1,228 @@
+/* GStreamer
+ *
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include "gstrtpg723depay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpg723depay_debug);
+#define GST_CAT_DEFAULT (rtpg723depay_debug)
+
+
+/* references:
+ *
+ * RFC 3551 (4.5.3)
+ */
+
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0
+};
+
+/* input is an RTP packet
+ *
+ */
+static GstStaticPadTemplate gst_rtp_g723_depay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "clock-rate = (int) 8000, "
+ "encoding-name = (string) \"G723\"; "
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_G723_STRING ", "
+ "clock-rate = (int) 8000")
+ );
+
+static GstStaticPadTemplate gst_rtp_g723_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/G723, " "channels = (int) 1," "rate = (int) 8000")
+ );
+
+static gboolean gst_rtp_g723_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_g723_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+
+#define gst_rtp_g723_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpG723Depay, gst_rtp_g723_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_g723_depay_class_init (GstRtpG723DepayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ GST_DEBUG_CATEGORY_INIT (rtpg723depay_debug, "rtpg723depay", 0,
+ "G.723 RTP Depayloader");
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_g723_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_g723_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP G.723 depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts G.723 audio from RTP packets (RFC 3551)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ gstrtpbasedepayload_class->process = gst_rtp_g723_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_g723_depay_setcaps;
+}
+
+static void
+gst_rtp_g723_depay_init (GstRtpG723Depay * rtpg723depay)
+{
+ GstRTPBaseDepayload *depayload;
+
+ depayload = GST_RTP_BASE_DEPAYLOAD (rtpg723depay);
+
+ gst_pad_use_fixed_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload));
+}
+
+static gboolean
+gst_rtp_g723_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstStructure *structure;
+ GstCaps *srccaps;
+ GstRtpG723Depay *rtpg723depay;
+ const gchar *params;
+ gint clock_rate, channels;
+ gboolean ret;
+
+ rtpg723depay = GST_RTP_G723_DEPAY (depayload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!(params = gst_structure_get_string (structure, "encoding-params")))
+ channels = 1;
+ else {
+ channels = atoi (params);
+ }
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 8000;
+
+ if (channels != 1)
+ goto wrong_channels;
+
+ if (clock_rate != 8000)
+ goto wrong_clock_rate;
+
+ depayload->clock_rate = clock_rate;
+
+ srccaps = gst_caps_new_simple ("audio/G723",
+ "channels", G_TYPE_INT, channels, "rate", G_TYPE_INT, clock_rate, NULL);
+ ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+ gst_caps_unref (srccaps);
+
+ return ret;
+
+ /* ERRORS */
+wrong_channels:
+ {
+ GST_DEBUG_OBJECT (rtpg723depay, "expected 1 channel, got %d", channels);
+ return FALSE;
+ }
+wrong_clock_rate:
+ {
+ GST_DEBUG_OBJECT (rtpg723depay, "expected 8000 clock-rate, got %d",
+ clock_rate);
+ return FALSE;
+ }
+}
+
+
+static GstBuffer *
+gst_rtp_g723_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpG723Depay *rtpg723depay;
+ GstBuffer *outbuf = NULL;
+ gint payload_len;
+ gboolean marker;
+ GstRTPBuffer rtp = { NULL };
+
+ rtpg723depay = GST_RTP_G723_DEPAY (depayload);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+
+ /* At least 4 bytes */
+ if (payload_len < 4)
+ goto too_small;
+
+ GST_LOG_OBJECT (rtpg723depay, "payload len %d", payload_len);
+
+ outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
+ marker = gst_rtp_buffer_get_marker (&rtp);
+ gst_rtp_buffer_unmap (&rtp);
+
+ if (marker) {
+ /* marker bit starts talkspurt */
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+ }
+
+ GST_LOG_OBJECT (depayload, "pushing buffer of size %" G_GSIZE_FORMAT,
+ gst_buffer_get_size (outbuf));
+
+ return outbuf;
+
+ /* ERRORS */
+too_small:
+ {
+ GST_ELEMENT_WARNING (rtpg723depay, STREAM, DECODE,
+ (NULL), ("G723 RTP payload too small (%d)", payload_len));
+ goto bad_packet;
+ }
+bad_packet:
+ {
+ /* no fatal error */
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+}
+
+gboolean
+gst_rtp_g723_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpg723depay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_G723_DEPAY);
+}
diff --git a/gst/rtp/gstrtpg723depay.h b/gst/rtp/gstrtpg723depay.h
new file mode 100755
index 0000000..dd942b3
--- /dev/null
+++ b/gst/rtp/gstrtpg723depay.h
@@ -0,0 +1,59 @@
+/* GStreamer
+ *
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_G723_DEPAY_H__
+#define __GST_RTP_G723_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_G723_DEPAY \
+ (gst_rtp_g723_depay_get_type())
+#define GST_RTP_G723_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_G723_DEPAY,GstRtpG723Depay))
+#define GST_RTP_G723_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_G723_DEPAY,GstRtpG723DepayClass))
+#define GST_IS_RTP_G723_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_G723_DEPAY))
+#define GST_IS_RTP_G723_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_G723_DEPAY))
+
+typedef struct _GstRtpG723Depay GstRtpG723Depay;
+typedef struct _GstRtpG723DepayClass GstRtpG723DepayClass;
+
+struct _GstRtpG723Depay
+{
+ GstRTPBaseDepayload depayload;
+};
+
+struct _GstRtpG723DepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_g723_depay_get_type (void);
+
+gboolean gst_rtp_g723_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_G723_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpg723pay.c b/gst/rtp/gstrtpg723pay.c
new file mode 100755
index 0000000..4a10b3b
--- /dev/null
+++ b/gst/rtp/gstrtpg723pay.c
@@ -0,0 +1,317 @@
+/* GStreamer
+ * Copyright (C) <2007> Nokia Corporation
+ * Copyright (C) <2007> Collabora Ltd
+ * @author: Olivier Crete <olivier.crete@collabora.co.uk>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/base/gstadapter.h>
+
+#include "gstrtpg723pay.h"
+
+#define GST_RTP_PAYLOAD_G723 4
+#define GST_RTP_PAYLOAD_G723_STRING "4"
+
+#define G723_FRAME_DURATION (30 * GST_MSECOND)
+
+static gboolean gst_rtp_g723_pay_set_caps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+static GstFlowReturn gst_rtp_g723_pay_handle_buffer (GstRTPBasePayload *
+ payload, GstBuffer * buf);
+
+static GstStaticPadTemplate gst_rtp_g723_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/G723, " /* according to RFC 3551 */
+ "channels = (int) 1, " "rate = (int) 8000")
+ );
+
+static GstStaticPadTemplate gst_rtp_g723_pay_src_template =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_G723_STRING ", "
+ "clock-rate = (int) 8000, "
+ "encoding-name = (string) \"G723\"; "
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) 8000, " "encoding-name = (string) \"G723\"")
+ );
+
+static void gst_rtp_g723_pay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_g723_pay_change_state (GstElement * element,
+ GstStateChange transition);
+
+#define gst_rtp_g723_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPG723Pay, gst_rtp_g723_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_g723_pay_class_init (GstRTPG723PayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *payload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ payload_class = (GstRTPBasePayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_g723_pay_finalize;
+
+ gstelement_class->change_state = gst_rtp_g723_pay_change_state;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_g723_pay_sink_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_g723_pay_src_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP G.723 payloader", "Codec/Payloader/Network/RTP",
+ "Packetize G.723 audio into RTP packets",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ payload_class->set_caps = gst_rtp_g723_pay_set_caps;
+ payload_class->handle_buffer = gst_rtp_g723_pay_handle_buffer;
+}
+
+static void
+gst_rtp_g723_pay_init (GstRTPG723Pay * pay)
+{
+ GstRTPBasePayload *payload = GST_RTP_BASE_PAYLOAD (pay);
+
+ pay->adapter = gst_adapter_new ();
+
+ payload->pt = GST_RTP_PAYLOAD_G723;
+ gst_rtp_base_payload_set_options (payload, "audio", FALSE, "G723", 8000);
+}
+
+static void
+gst_rtp_g723_pay_finalize (GObject * object)
+{
+ GstRTPG723Pay *pay;
+
+ pay = GST_RTP_G723_PAY (object);
+
+ g_object_unref (pay->adapter);
+ pay->adapter = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static gboolean
+gst_rtp_g723_pay_set_caps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ gboolean res;
+ GstStructure *structure;
+ gint pt;
+
+ structure = gst_caps_get_structure (caps, 0);
+ if (!gst_structure_get_int (structure, "payload", &pt))
+ pt = GST_RTP_PAYLOAD_G723;
+
+ payload->pt = pt;
+ payload->dynamic = pt != GST_RTP_PAYLOAD_G723;
+
+ res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+
+ return res;
+}
+
+static GstFlowReturn
+gst_rtp_g723_pay_flush (GstRTPG723Pay * pay)
+{
+ GstBuffer *outbuf;
+ GstFlowReturn ret;
+ guint8 *payload;
+ guint avail;
+ GstRTPBuffer rtp = { NULL };
+
+ avail = gst_adapter_available (pay->adapter);
+
+ outbuf = gst_rtp_buffer_new_allocate (avail, 0, 0);
+
+ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+ payload = gst_rtp_buffer_get_payload (&rtp);
+
+ GST_BUFFER_TIMESTAMP (outbuf) = pay->timestamp;
+ GST_BUFFER_DURATION (outbuf) = pay->duration;
+
+ /* copy G723 data as payload */
+ gst_adapter_copy (pay->adapter, payload, 0, avail);
+
+ /* flush bytes from adapter */
+ gst_adapter_flush (pay->adapter, avail);
+ pay->timestamp = GST_CLOCK_TIME_NONE;
+ pay->duration = 0;
+
+ /* set discont and marker */
+ if (pay->discont) {
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+ gst_rtp_buffer_set_marker (&rtp, TRUE);
+ pay->discont = FALSE;
+ }
+ gst_rtp_buffer_unmap (&rtp);
+
+ ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (pay), outbuf);
+
+ return ret;
+}
+
+/* 00 high-rate speech (6.3 kb/s) 24
+ * 01 low-rate speech (5.3 kb/s) 20
+ * 10 SID frame 4
+ * 11 reserved 0 */
+static const guint size_tab[4] = {
+ 24, 20, 4, 0
+};
+
+static GstFlowReturn
+gst_rtp_g723_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buf)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstMapInfo map;
+ guint8 HDR;
+ GstRTPG723Pay *pay;
+ GstClockTime packet_dur, timestamp;
+ guint payload_len, packet_len;
+
+ pay = GST_RTP_G723_PAY (payload);
+
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+ timestamp = GST_BUFFER_TIMESTAMP (buf);
+
+ if (GST_BUFFER_IS_DISCONT (buf)) {
+ /* flush everything on discont */
+ gst_adapter_clear (pay->adapter);
+ pay->timestamp = GST_CLOCK_TIME_NONE;
+ pay->duration = 0;
+ pay->discont = TRUE;
+ }
+
+ /* should be one of these sizes */
+ if (map.size != 4 && map.size != 20 && map.size != 24)
+ goto invalid_size;
+
+ /* check size by looking at the header bits */
+ HDR = map.data[0] & 0x3;
+ if (size_tab[HDR] != map.size)
+ goto wrong_size;
+
+ /* calculate packet size and duration */
+ payload_len = gst_adapter_available (pay->adapter) + map.size;
+ packet_dur = pay->duration + G723_FRAME_DURATION;
+ packet_len = gst_rtp_buffer_calc_packet_len (payload_len, 0, 0);
+
+ if (gst_rtp_base_payload_is_filled (payload, packet_len, packet_dur)) {
+ /* size or duration would overflow the packet, flush the queued data */
+ ret = gst_rtp_g723_pay_flush (pay);
+ }
+
+ /* update timestamp, we keep the timestamp for the first packet in the adapter
+ * but are able to calculate it from next packets. */
+ if (timestamp != GST_CLOCK_TIME_NONE && pay->timestamp == GST_CLOCK_TIME_NONE) {
+ if (timestamp > pay->duration)
+ pay->timestamp = timestamp - pay->duration;
+ else
+ pay->timestamp = 0;
+ }
+ gst_buffer_unmap (buf, &map);
+
+ /* add packet to the queue */
+ gst_adapter_push (pay->adapter, buf);
+ pay->duration = packet_dur;
+
+ /* check if we can flush now */
+ if (pay->duration >= payload->min_ptime) {
+ ret = gst_rtp_g723_pay_flush (pay);
+ }
+
+ return ret;
+
+ /* WARNINGS */
+invalid_size:
+ {
+ GST_ELEMENT_WARNING (pay, STREAM, WRONG_TYPE,
+ ("Invalid input buffer size"),
+ ("Input size should be 4, 20 or 24, got %" G_GSIZE_FORMAT, map.size));
+ gst_buffer_unmap (buf, &map);
+ gst_buffer_unref (buf);
+ return GST_FLOW_OK;
+ }
+wrong_size:
+ {
+ GST_ELEMENT_WARNING (pay, STREAM, WRONG_TYPE,
+ ("Wrong input buffer size"),
+ ("Expected input buffer size %u but got %" G_GSIZE_FORMAT,
+ size_tab[HDR], map.size));
+ gst_buffer_unmap (buf, &map);
+ gst_buffer_unref (buf);
+ return GST_FLOW_OK;
+ }
+}
+
+static GstStateChangeReturn
+gst_rtp_g723_pay_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret;
+ GstRTPG723Pay *pay;
+
+ pay = GST_RTP_G723_PAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_adapter_clear (pay->adapter);
+ pay->timestamp = GST_CLOCK_TIME_NONE;
+ pay->duration = 0;
+ pay->discont = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_adapter_clear (pay->adapter);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/*Plugin init functions*/
+gboolean
+gst_rtp_g723_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpg723pay", GST_RANK_SECONDARY,
+ gst_rtp_g723_pay_get_type ());
+}
diff --git a/gst/rtp/gstrtpg723pay.h b/gst/rtp/gstrtpg723pay.h
new file mode 100755
index 0000000..3780741
--- /dev/null
+++ b/gst/rtp/gstrtpg723pay.h
@@ -0,0 +1,64 @@
+/* GStreamer
+ * Copyright (C) <2007> Nokia Corporation
+ * Copyright (C) <2007> Collabora Ltd
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_G723_PAY_H__
+#define __GST_RTP_G723_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_G723_PAY \
+ (gst_rtp_g723_pay_get_type())
+#define GST_RTP_G723_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_G723_PAY,GstRTPG723Pay))
+#define GST_RTP_G723_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_G723_PAY,GstRTPG723PayClass))
+#define GST_IS_RTP_G723_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_G723_PAY))
+#define GST_IS_RTP_G723_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_G723_PAY))
+
+typedef struct _GstRTPG723Pay GstRTPG723Pay;
+typedef struct _GstRTPG723PayClass GstRTPG723PayClass;
+
+struct _GstRTPG723Pay
+{
+ GstRTPBasePayload payload;
+
+ GstAdapter *adapter;
+ GstClockTime duration;
+ GstClockTime timestamp;
+ gboolean discont;
+};
+
+struct _GstRTPG723PayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_g723_pay_get_type (void);
+
+gboolean gst_rtp_g723_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_G723_PAY_H__ */
diff --git a/gst/rtp/gstrtpg726depay.c b/gst/rtp/gstrtpg726depay.c
new file mode 100755
index 0000000..a6175eb
--- /dev/null
+++ b/gst/rtp/gstrtpg726depay.c
@@ -0,0 +1,395 @@
+/* GStreamer
+ * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2005 Edgard Lima <edgard.lima@indt.org.br>
+ * Copyright (C) 2005 Zeeshan Ali <zeenix@gmail.com>
+ * Copyright (C) 2008 Axis Communications <dev-gstreamer@axis.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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpg726depay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpg726depay_debug);
+#define GST_CAT_DEFAULT (rtpg726depay_debug)
+
+#define DEFAULT_BIT_RATE 32000
+#define DEFAULT_BLOCK_ALIGN 4
+#define SAMPLE_RATE 8000
+#define LAYOUT_G726 "g726"
+
+/* RtpG726Depay signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+#define DEFAULT_FORCE_AAL2 TRUE
+
+enum
+{
+ PROP_0,
+ PROP_FORCE_AAL2
+};
+
+static GstStaticPadTemplate gst_rtp_g726_depay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "encoding-name = (string) { \"G726\", \"G726-16\", \"G726-24\", \"G726-32\", \"G726-40\", "
+ "\"AAL2-G726-16\", \"AAL2-G726-24\", \"AAL2-G726-32\", \"AAL2-G726-40\" }, "
+ "clock-rate = (int) 8000;")
+ );
+
+static GstStaticPadTemplate gst_rtp_g726_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-adpcm, "
+ "channels = (int) 1, "
+ "rate = (int) 8000, "
+ "bitrate = (int) { 16000, 24000, 32000, 40000 }, "
+ "block_align = (int) { 2, 3, 4, 5 }, " "layout = (string) \"g726\"")
+ );
+
+static void gst_rtp_g726_depay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_rtp_g726_depay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+
+static GstBuffer *gst_rtp_g726_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+static gboolean gst_rtp_g726_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+
+#define gst_rtp_g726_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpG726Depay, gst_rtp_g726_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_g726_depay_class_init (GstRtpG726DepayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ GST_DEBUG_CATEGORY_INIT (rtpg726depay_debug, "rtpg726depay", 0,
+ "G.726 RTP Depayloader");
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gobject_class->set_property = gst_rtp_g726_depay_set_property;
+ gobject_class->get_property = gst_rtp_g726_depay_get_property;
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FORCE_AAL2,
+ g_param_spec_boolean ("force-aal2", "Force AAL2",
+ "Force AAL2 decoding for compatibility with bad payloaders",
+ DEFAULT_FORCE_AAL2, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_g726_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_g726_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP G.726 depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts G.726 audio from RTP packets",
+ "Axis Communications <dev-gstreamer@axis.com>");
+
+ gstrtpbasedepayload_class->process = gst_rtp_g726_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_g726_depay_setcaps;
+}
+
+static void
+gst_rtp_g726_depay_init (GstRtpG726Depay * rtpG726depay)
+{
+ GstRTPBaseDepayload *depayload;
+
+ depayload = GST_RTP_BASE_DEPAYLOAD (rtpG726depay);
+
+ gst_pad_use_fixed_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload));
+
+ rtpG726depay->force_aal2 = DEFAULT_FORCE_AAL2;
+}
+
+static gboolean
+gst_rtp_g726_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstCaps *srccaps;
+ GstStructure *structure;
+ gboolean ret;
+ gint clock_rate;
+ const gchar *encoding_name;
+ GstRtpG726Depay *depay;
+
+ depay = GST_RTP_G726_DEPAY (depayload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 8000; /* default */
+ depayload->clock_rate = clock_rate;
+
+ depay->aal2 = FALSE;
+ encoding_name = gst_structure_get_string (structure, "encoding-name");
+ if (encoding_name == NULL || g_ascii_strcasecmp (encoding_name, "G726") == 0) {
+ depay->bitrate = DEFAULT_BIT_RATE;
+ depay->block_align = DEFAULT_BLOCK_ALIGN;
+ } else {
+ if (g_str_has_prefix (encoding_name, "AAL2-")) {
+ depay->aal2 = TRUE;
+ encoding_name += 5;
+ }
+ if (g_ascii_strcasecmp (encoding_name, "G726-16") == 0) {
+ depay->bitrate = 16000;
+ depay->block_align = 2;
+ } else if (g_ascii_strcasecmp (encoding_name, "G726-24") == 0) {
+ depay->bitrate = 24000;
+ depay->block_align = 3;
+ } else if (g_ascii_strcasecmp (encoding_name, "G726-32") == 0) {
+ depay->bitrate = 32000;
+ depay->block_align = 4;
+ } else if (g_ascii_strcasecmp (encoding_name, "G726-40") == 0) {
+ depay->bitrate = 40000;
+ depay->block_align = 5;
+ } else
+ goto unknown_encoding;
+ }
+
+ GST_DEBUG ("RTP G.726 depayloader, bitrate set to %d\n", depay->bitrate);
+
+ srccaps = gst_caps_new_simple ("audio/x-adpcm",
+ "channels", G_TYPE_INT, 1,
+ "rate", G_TYPE_INT, clock_rate,
+ "bitrate", G_TYPE_INT, depay->bitrate,
+ "block_align", G_TYPE_INT, depay->block_align,
+ "layout", G_TYPE_STRING, LAYOUT_G726, NULL);
+
+ ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+ gst_caps_unref (srccaps);
+
+ return ret;
+
+ /* ERRORS */
+unknown_encoding:
+ {
+ GST_WARNING ("Could not determine bitrate from encoding-name (%s)",
+ encoding_name);
+ return FALSE;
+ }
+}
+
+
+static GstBuffer *
+gst_rtp_g726_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpG726Depay *depay;
+ GstBuffer *outbuf = NULL;
+ gboolean marker;
+ GstRTPBuffer rtp = { NULL };
+
+ depay = GST_RTP_G726_DEPAY (depayload);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp);
+
+ marker = gst_rtp_buffer_get_marker (&rtp);
+
+ GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d",
+ gst_buffer_get_size (buf), marker,
+ gst_rtp_buffer_get_timestamp (&rtp), gst_rtp_buffer_get_seq (&rtp));
+
+ if (depay->aal2 || depay->force_aal2) {
+ /* AAL2, we can just copy the bytes */
+ outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
+ if (!outbuf)
+ goto bad_len;
+ } else {
+ guint8 *in, *out, tmp;
+ guint len;
+ GstMapInfo map;
+
+ in = gst_rtp_buffer_get_payload (&rtp);
+ len = gst_rtp_buffer_get_payload_len (&rtp);
+
+ outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
+ if (!outbuf)
+ goto bad_len;
+ outbuf = gst_buffer_make_writable (outbuf);
+
+ gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+ out = map.data;
+
+ /* we need to reshuffle the bytes, input is always of the form
+ * A B C D ... with the number of bits depending on the bitrate. */
+ switch (depay->bitrate) {
+ case 16000:
+ {
+ /* 0
+ * 0 1 2 3 4 5 6 7
+ * +-+-+-+-+-+-+-+-+-
+ * |D D|C C|B B|A A| ...
+ * |0 1|0 1|0 1|0 1|
+ * +-+-+-+-+-+-+-+-+-
+ */
+ while (len > 0) {
+ tmp = *in++;
+ *out++ = ((tmp & 0xc0) >> 6) |
+ ((tmp & 0x30) >> 2) | ((tmp & 0x0c) << 2) | ((tmp & 0x03) << 6);
+ len--;
+ }
+ break;
+ }
+ case 24000:
+ {
+ /* 0 1 2
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+ * |C C|B B B|A A A|F|E E E|D D D|C|H H H|G G G|F F| ...
+ * |1 2|0 1 2|0 1 2|2|0 1 2|0 1 2|0|0 1 2|0 1 2|0 1|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+ */
+ while (len > 2) {
+ tmp = *in++;
+ *out++ = ((tmp & 0xe0) >> 5) |
+ ((tmp & 0x1c) << 1) | ((tmp & 0x03) << 6);
+ tmp = *in++;
+ *out++ = ((tmp & 0x80) >> 7) |
+ ((tmp & 0x70) >> 3) | ((tmp & 0x0e) << 4) | ((tmp & 0x01) << 7);
+ tmp = *in++;
+ *out++ = ((tmp & 0xc0) >> 6) |
+ ((tmp & 0x38) >> 1) | ((tmp & 0x07) << 5);
+ len -= 3;
+ }
+ break;
+ }
+ case 32000:
+ {
+ /* 0 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+ * |B B B B|A A A A|D D D D|C C C C| ...
+ * |0 1 2 3|0 1 2 3|0 1 2 3|0 1 2 3|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+ */
+ while (len > 0) {
+ tmp = *in++;
+ *out++ = ((tmp & 0xf0) >> 4) | ((tmp & 0x0f) << 4);
+ len--;
+ }
+ break;
+ }
+ case 40000:
+ {
+ /* 0 1 2 3 4
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+ * |B B B|A A A A A|D|C C C C C|B B|E E E E|D D D D|G G|F F F F F|E|H H H H H|G G G|
+ * |2 3 4|0 1 2 3 4|4|0 1 2 3 4|0 1|1 2 3 4|0 1 2 3|3 4|0 1 2 3 4|0|0 1 2 3 4|0 1 2|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+ */
+ while (len > 4) {
+ tmp = *in++;
+ *out++ = ((tmp & 0xf8) >> 3) | ((tmp & 0x07) << 5);
+ tmp = *in++;
+ *out++ = ((tmp & 0xc0) >> 6) |
+ ((tmp & 0x3e) << 1) | ((tmp & 0x01) << 7);
+ tmp = *in++;
+ *out++ = ((tmp & 0xf0) >> 4) | ((tmp & 0x0f) << 4);
+ tmp = *in++;
+ *out++ = ((tmp & 0x80) >> 7) |
+ ((tmp & 0x7c) >> 1) | ((tmp & 0x03) << 6);
+ tmp = *in++;
+ *out++ = ((tmp & 0xe0) >> 5) | ((tmp & 0x1f) << 3);
+ len -= 5;
+ }
+ break;
+ }
+ }
+ gst_buffer_unmap (outbuf, &map);
+ }
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ if (marker) {
+ /* mark start of talkspurt with RESYNC */
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+ }
+
+ return outbuf;
+
+bad_len:
+ {
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+
+}
+
+static void
+gst_rtp_g726_depay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstRtpG726Depay *rtpg726depay;
+
+ rtpg726depay = GST_RTP_G726_DEPAY (object);
+
+ switch (prop_id) {
+ case PROP_FORCE_AAL2:
+ rtpg726depay->force_aal2 = g_value_get_boolean (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_rtp_g726_depay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstRtpG726Depay *rtpg726depay;
+
+ rtpg726depay = GST_RTP_G726_DEPAY (object);
+
+ switch (prop_id) {
+ case PROP_FORCE_AAL2:
+ g_value_set_boolean (value, rtpg726depay->force_aal2);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+gboolean
+gst_rtp_g726_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpg726depay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_G726_DEPAY);
+}
diff --git a/gst/rtp/gstrtpg726depay.h b/gst/rtp/gstrtpg726depay.h
new file mode 100755
index 0000000..c395a37
--- /dev/null
+++ b/gst/rtp/gstrtpg726depay.h
@@ -0,0 +1,58 @@
+/* GStreamer
+ * Copyright (C) 2005 Edgard Lima <edgard.lima@indt.org.br>
+ * Copyright (C) 2008 Axis Communications AB <dev-gstreamer@axis.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
+ */
+
+#ifndef __GST_RTP_G726_DEPAY_H__
+#define __GST_RTP_G726_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRtpG726Depay GstRtpG726Depay;
+typedef struct _GstRtpG726DepayClass GstRtpG726DepayClass;
+
+#define GST_TYPE_RTP_G726_DEPAY \
+ (gst_rtp_g726_depay_get_type())
+#define GST_RTP_G726_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_G726_DEPAY,GstRtpG726Depay))
+#define GST_RTP_G726_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_G726_DEPAY,GstRtpG726DepayClass))
+#define GST_IS_RTP_G726_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_G726_DEPAY))
+#define GST_IS_RTP_G726_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_G726_DEPAY))
+
+struct _GstRtpG726Depay
+{
+ GstRTPBaseDepayload depayload;
+
+ gboolean aal2;
+ gboolean force_aal2;
+ gint bitrate;
+ guint block_align;
+};
+
+struct _GstRtpG726DepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_g726_depay_get_type (void);
+
+gboolean gst_rtp_g726_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_G726_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpg726pay.c b/gst/rtp/gstrtpg726pay.c
new file mode 100755
index 0000000..7c7e9a8
--- /dev/null
+++ b/gst/rtp/gstrtpg726pay.c
@@ -0,0 +1,422 @@
+/* GStreamer
+ * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2005 Edgard Lima <edgard.lima@indt.org.br>
+ * Copyright (C) 2005 Nokia Corporation <kai.vehmanen@nokia.com>
+ * Copyright (C) 2007,2008 Axis Communications <dev-gstreamer@axis.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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpg726pay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpg726pay_debug);
+#define GST_CAT_DEFAULT (rtpg726pay_debug)
+
+#define DEFAULT_FORCE_AAL2 TRUE
+
+enum
+{
+ PROP_0,
+ PROP_FORCE_AAL2
+};
+
+static GstStaticPadTemplate gst_rtp_g726_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-adpcm, "
+ "channels = (int) 1, "
+ "rate = (int) 8000, "
+ "bitrate = (int) { 16000, 24000, 32000, 40000 }, "
+ "layout = (string) \"g726\"")
+ );
+
+static GstStaticPadTemplate gst_rtp_g726_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) 8000, "
+ "encoding-name = (string) { \"G726-16\", \"G726-24\", \"G726-32\", \"G726-40\", "
+ " \"AAL2-G726-16\", \"AAL2-G726-24\", \"AAL2-G726-32\", \"AAL2-G726-40\" } ")
+ );
+
+static void gst_rtp_g726_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_rtp_g726_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+
+static gboolean gst_rtp_g726_pay_setcaps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+static GstFlowReturn gst_rtp_g726_pay_handle_buffer (GstRTPBasePayload *
+ payload, GstBuffer * buffer);
+
+#define gst_rtp_g726_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpG726Pay, gst_rtp_g726_pay,
+ GST_TYPE_RTP_BASE_AUDIO_PAYLOAD);
+
+static void
+gst_rtp_g726_pay_class_init (GstRtpG726PayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gobject_class->set_property = gst_rtp_g726_pay_set_property;
+ gobject_class->get_property = gst_rtp_g726_pay_get_property;
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FORCE_AAL2,
+ g_param_spec_boolean ("force-aal2", "Force AAL2",
+ "Force AAL2 encoding for compatibility with bad depayloaders",
+ DEFAULT_FORCE_AAL2, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_g726_pay_sink_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_g726_pay_src_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP G.726 payloader", "Codec/Payloader/Network/RTP",
+ "Payload-encodes G.726 audio into a RTP packet",
+ "Axis Communications <dev-gstreamer@axis.com>");
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_g726_pay_setcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_g726_pay_handle_buffer;
+
+ GST_DEBUG_CATEGORY_INIT (rtpg726pay_debug, "rtpg726pay", 0,
+ "G.726 RTP Payloader");
+}
+
+static void
+gst_rtp_g726_pay_init (GstRtpG726Pay * rtpg726pay)
+{
+ GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+ rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpg726pay);
+
+ GST_RTP_BASE_PAYLOAD (rtpg726pay)->clock_rate = 8000;
+
+ rtpg726pay->force_aal2 = DEFAULT_FORCE_AAL2;
+
+ /* sample based codec */
+ gst_rtp_base_audio_payload_set_sample_based (rtpbaseaudiopayload);
+}
+
+static gboolean
+gst_rtp_g726_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ gchar *encoding_name;
+ GstStructure *structure;
+ GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+ GstRtpG726Pay *pay;
+ GstCaps *peercaps;
+ gboolean res;
+
+ rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (payload);
+ pay = GST_RTP_G726_PAY (payload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "bitrate", &pay->bitrate))
+ pay->bitrate = 32000;
+
+ GST_DEBUG_OBJECT (payload, "using bitrate %d", pay->bitrate);
+
+ pay->aal2 = FALSE;
+
+ /* first see what we can do with the bitrate */
+ switch (pay->bitrate) {
+ case 16000:
+ encoding_name = g_strdup ("G726-16");
+ gst_rtp_base_audio_payload_set_samplebits_options (rtpbaseaudiopayload,
+ 2);
+ break;
+ case 24000:
+ encoding_name = g_strdup ("G726-24");
+ gst_rtp_base_audio_payload_set_samplebits_options (rtpbaseaudiopayload,
+ 3);
+ break;
+ case 32000:
+ encoding_name = g_strdup ("G726-32");
+ gst_rtp_base_audio_payload_set_samplebits_options (rtpbaseaudiopayload,
+ 4);
+ break;
+ case 40000:
+ encoding_name = g_strdup ("G726-40");
+ gst_rtp_base_audio_payload_set_samplebits_options (rtpbaseaudiopayload,
+ 5);
+ break;
+ default:
+ goto invalid_bitrate;
+ }
+
+ GST_DEBUG_OBJECT (payload, "selected base encoding %s", encoding_name);
+
+ /* now see if we need to produce AAL2 or not */
+ peercaps = gst_pad_peer_query_caps (payload->srcpad, NULL);
+ if (peercaps) {
+ GstCaps *filter, *intersect;
+ gchar *capsstr;
+
+ GST_DEBUG_OBJECT (payload, "have peercaps %" GST_PTR_FORMAT, peercaps);
+
+ capsstr = g_strdup_printf ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "clock-rate = (int) 8000, "
+ "encoding-name = (string) %s; "
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "clock-rate = (int) 8000, "
+ "encoding-name = (string) AAL2-%s", encoding_name, encoding_name);
+ filter = gst_caps_from_string (capsstr);
+ g_free (capsstr);
+ g_free (encoding_name);
+
+ /* intersect to filter */
+ intersect = gst_caps_intersect (peercaps, filter);
+ gst_caps_unref (peercaps);
+ gst_caps_unref (filter);
+
+ GST_DEBUG_OBJECT (payload, "intersected to %" GST_PTR_FORMAT, intersect);
+
+ if (!intersect)
+ goto no_format;
+ if (gst_caps_is_empty (intersect)) {
+ gst_caps_unref (intersect);
+ goto no_format;
+ }
+
+ structure = gst_caps_get_structure (intersect, 0);
+
+ /* now see what encoding name we settled on, we need to dup because the
+ * string goes away when we unref the intersection below. */
+ encoding_name =
+ g_strdup (gst_structure_get_string (structure, "encoding-name"));
+
+ /* if we managed to negotiate to AAL2, we definatly are going to do AAL2
+ * encoding. Else we only encode AAL2 when explicitly set by the
+ * property. */
+ if (g_str_has_prefix (encoding_name, "AAL2-"))
+ pay->aal2 = TRUE;
+ else
+ pay->aal2 = pay->force_aal2;
+
+ GST_DEBUG_OBJECT (payload, "final encoding %s, AAL2 %d", encoding_name,
+ pay->aal2);
+
+ gst_caps_unref (intersect);
+ } else {
+ /* downstream can do anything but we prefer the better supported non-AAL2 */
+ pay->aal2 = pay->force_aal2;
+ GST_DEBUG_OBJECT (payload, "no peer caps, AAL2 %d", pay->aal2);
+ }
+
+ gst_rtp_base_payload_set_options (payload, "audio", TRUE, encoding_name,
+ 8000);
+ res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+
+ g_free (encoding_name);
+
+ return res;
+
+ /* ERRORS */
+invalid_bitrate:
+ {
+ GST_ERROR_OBJECT (payload, "invalid bitrate %d specified", pay->bitrate);
+ return FALSE;
+ }
+no_format:
+ {
+ GST_ERROR_OBJECT (payload, "could not negotiate format");
+ return FALSE;
+ }
+}
+
+static GstFlowReturn
+gst_rtp_g726_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
+{
+ GstFlowReturn res;
+ GstRtpG726Pay *pay;
+
+ pay = GST_RTP_G726_PAY (payload);
+
+ if (!pay->aal2) {
+ GstMapInfo map;
+ guint8 *data, tmp;
+ gsize size;
+
+ /* for non AAL2, we need to reshuffle the bytes, we can do this in-place
+ * when the buffer is writable. */
+ buffer = gst_buffer_make_writable (buffer);
+
+ gst_buffer_map (buffer, &map, GST_MAP_READWRITE);
+ data = map.data;
+ size = map.size;
+
+ GST_LOG_OBJECT (pay, "packing %" G_GSIZE_FORMAT " bytes of data", map.size);
+
+ /* we need to reshuffle the bytes, output is of the form:
+ * A B C D .. with the number of bits depending on the bitrate. */
+ switch (pay->bitrate) {
+ case 16000:
+ {
+ /* 0
+ * 0 1 2 3 4 5 6 7
+ * +-+-+-+-+-+-+-+-+-
+ * |D D|C C|B B|A A| ...
+ * |0 1|0 1|0 1|0 1|
+ * +-+-+-+-+-+-+-+-+-
+ */
+ while (size > 0) {
+ tmp = *data;
+ *data++ = ((tmp & 0xc0) >> 6) |
+ ((tmp & 0x30) >> 2) | ((tmp & 0x0c) << 2) | ((tmp & 0x03) << 6);
+ size--;
+ }
+ break;
+ }
+ case 24000:
+ {
+ /* 0 1 2
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+ * |C C|B B B|A A A|F|E E E|D D D|C|H H H|G G G|F F| ...
+ * |1 2|0 1 2|0 1 2|2|0 1 2|0 1 2|0|0 1 2|0 1 2|0 1|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+ */
+ while (size > 2) {
+ tmp = *data;
+ *data++ = ((tmp & 0xc0) >> 6) |
+ ((tmp & 0x38) >> 1) | ((tmp & 0x07) << 5);
+ tmp = *data;
+ *data++ = ((tmp & 0x80) >> 7) |
+ ((tmp & 0x70) >> 3) | ((tmp & 0x0e) << 4) | ((tmp & 0x01) << 7);
+ tmp = *data;
+ *data++ = ((tmp & 0xe0) >> 5) |
+ ((tmp & 0x1c) >> 2) | ((tmp & 0x03) << 6);
+ size -= 3;
+ }
+ break;
+ }
+ case 32000:
+ {
+ /* 0 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+ * |B B B B|A A A A|D D D D|C C C C| ...
+ * |0 1 2 3|0 1 2 3|0 1 2 3|0 1 2 3|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+ */
+ while (size > 0) {
+ tmp = *data;
+ *data++ = ((tmp & 0xf0) >> 4) | ((tmp & 0x0f) << 4);
+ size--;
+ }
+ break;
+ }
+ case 40000:
+ {
+ /* 0 1 2 3 4
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+ * |B B B|A A A A A|D|C C C C C|B B|E E E E|D D D D|G G|F F F F F|E|H H H H H|G G G|
+ * |2 3 4|0 1 2 3 4|4|0 1 2 3 4|0 1|1 2 3 4|0 1 2 3|3 4|0 1 2 3 4|0|0 1 2 3 4|0 1 2|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+ */
+ while (size > 4) {
+ tmp = *data;
+ *data++ = ((tmp & 0xe0) >> 5) | ((tmp & 0x1f) << 3);
+ tmp = *data;
+ *data++ = ((tmp & 0x80) >> 7) |
+ ((tmp & 0x7c) >> 2) | ((tmp & 0x03) << 6);
+ tmp = *data;
+ *data++ = ((tmp & 0xf0) >> 4) | ((tmp & 0x0f) << 4);
+ tmp = *data;
+ *data++ = ((tmp & 0xc0) >> 6) |
+ ((tmp & 0x3e) << 2) | ((tmp & 0x01) << 7);
+ tmp = *data;
+ *data++ = ((tmp & 0xf8) >> 3) | ((tmp & 0x07) << 5);
+ size -= 5;
+ }
+ break;
+ }
+ }
+ gst_buffer_unmap (buffer, &map);
+ }
+
+ res =
+ GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->handle_buffer (payload,
+ buffer);
+
+ return res;
+}
+
+static void
+gst_rtp_g726_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstRtpG726Pay *rtpg726pay;
+
+ rtpg726pay = GST_RTP_G726_PAY (object);
+
+ switch (prop_id) {
+ case PROP_FORCE_AAL2:
+ rtpg726pay->force_aal2 = g_value_get_boolean (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_rtp_g726_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstRtpG726Pay *rtpg726pay;
+
+ rtpg726pay = GST_RTP_G726_PAY (object);
+
+ switch (prop_id) {
+ case PROP_FORCE_AAL2:
+ g_value_set_boolean (value, rtpg726pay->force_aal2);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+gboolean
+gst_rtp_g726_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpg726pay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_G726_PAY);
+}
diff --git a/gst/rtp/gstrtpg726pay.h b/gst/rtp/gstrtpg726pay.h
new file mode 100755
index 0000000..5b16966
--- /dev/null
+++ b/gst/rtp/gstrtpg726pay.h
@@ -0,0 +1,55 @@
+/* GStreamer
+ * Copyright (C) 2005 Edgard Lima <edgard.lima@indt.org.br>
+ * Copyright (C) 2007,2008 Axis Communications <dev-gstreamer@axis.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
+ */
+
+#ifndef __GST_RTP_G726_PAY_H__
+#define __GST_RTP_G726_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+G_BEGIN_DECLS typedef struct _GstRtpG726Pay GstRtpG726Pay;
+typedef struct _GstRtpG726PayClass GstRtpG726PayClass;
+
+#define GST_TYPE_RTP_G726_PAY \
+ (gst_rtp_g726_pay_get_type())
+#define GST_RTP_G726_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_G726_PAY,GstRtpG726Pay))
+#define GST_RTP_G726_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_G726_PAY,GstRtpG726PayClass))
+#define GST_IS_RTP_G726_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_G726_PAY))
+#define GST_IS_RTP_G726_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_G726_PAY))
+
+struct _GstRtpG726Pay
+{
+ GstRTPBaseAudioPayload audiopayload;
+
+ gboolean aal2;
+ gboolean force_aal2;
+ gint bitrate;
+};
+
+struct _GstRtpG726PayClass
+{
+ GstRTPBaseAudioPayloadClass parent_class;
+};
+
+GType gst_rtp_g726_pay_get_type (void);
+
+gboolean gst_rtp_g726_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_G726_PAY_H__ */
diff --git a/gst/rtp/gstrtpg729depay.c b/gst/rtp/gstrtpg729depay.c
new file mode 100755
index 0000000..9910add
--- /dev/null
+++ b/gst/rtp/gstrtpg729depay.c
@@ -0,0 +1,226 @@
+/* GStreamer
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include "gstrtpg729depay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpg729depay_debug);
+#define GST_CAT_DEFAULT (rtpg729depay_debug)
+
+
+/* references:
+ *
+ * RFC 3551 (4.5.6)
+ */
+
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0
+};
+
+/* input is an RTP packet
+ *
+ */
+static GstStaticPadTemplate gst_rtp_g729_depay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "clock-rate = (int) 8000, "
+ "encoding-name = (string) \"G729\"; "
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_G729_STRING ", "
+ "clock-rate = (int) 8000")
+ );
+
+static GstStaticPadTemplate gst_rtp_g729_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/G729, " "channels = (int) 1," "rate = (int) 8000")
+ );
+
+static gboolean gst_rtp_g729_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_g729_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+
+#define gst_rtp_g729_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpG729Depay, gst_rtp_g729_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_g729_depay_class_init (GstRtpG729DepayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ GST_DEBUG_CATEGORY_INIT (rtpg729depay_debug, "rtpg729depay", 0,
+ "G.729 RTP Depayloader");
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_g729_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_g729_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP G.729 depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts G.729 audio from RTP packets (RFC 3551)",
+ "Laurent Glayal <spglegle@yahoo.fr>");
+
+ gstrtpbasedepayload_class->process = gst_rtp_g729_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_g729_depay_setcaps;
+}
+
+static void
+gst_rtp_g729_depay_init (GstRtpG729Depay * rtpg729depay)
+{
+ GstRTPBaseDepayload *depayload;
+
+ depayload = GST_RTP_BASE_DEPAYLOAD (rtpg729depay);
+
+ gst_pad_use_fixed_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload));
+}
+
+static gboolean
+gst_rtp_g729_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstStructure *structure;
+ GstCaps *srccaps;
+ GstRtpG729Depay *rtpg729depay;
+ const gchar *params;
+ gint clock_rate, channels;
+ gboolean ret;
+
+ rtpg729depay = GST_RTP_G729_DEPAY (depayload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!(params = gst_structure_get_string (structure, "encoding-params")))
+ channels = 1;
+ else {
+ channels = atoi (params);
+ }
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 8000;
+
+ if (channels != 1)
+ goto wrong_channels;
+
+ if (clock_rate != 8000)
+ goto wrong_clock_rate;
+
+ depayload->clock_rate = clock_rate;
+
+ srccaps = gst_caps_new_simple ("audio/G729",
+ "channels", G_TYPE_INT, channels, "rate", G_TYPE_INT, clock_rate, NULL);
+ ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+ gst_caps_unref (srccaps);
+
+ return ret;
+
+ /* ERRORS */
+wrong_channels:
+ {
+ GST_DEBUG_OBJECT (rtpg729depay, "expected 1 channel, got %d", channels);
+ return FALSE;
+ }
+wrong_clock_rate:
+ {
+ GST_DEBUG_OBJECT (rtpg729depay, "expected 8000 clock-rate, got %d",
+ clock_rate);
+ return FALSE;
+ }
+}
+
+static GstBuffer *
+gst_rtp_g729_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpG729Depay *rtpg729depay;
+ GstBuffer *outbuf = NULL;
+ gint payload_len;
+ gboolean marker;
+ GstRTPBuffer rtp = { NULL };
+
+ rtpg729depay = GST_RTP_G729_DEPAY (depayload);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+
+ /* At least 2 bytes (CNG from G729 Annex B) */
+ if (payload_len < 2) {
+ GST_ELEMENT_WARNING (rtpg729depay, STREAM, DECODE,
+ (NULL), ("G729 RTP payload too small (%d)", payload_len));
+ goto bad_packet;
+ }
+
+ GST_LOG_OBJECT (rtpg729depay, "payload len %d", payload_len);
+
+ if ((payload_len % 10) == 2) {
+ GST_LOG_OBJECT (rtpg729depay, "G729 payload contains CNG frame");
+ }
+
+ outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
+ marker = gst_rtp_buffer_get_marker (&rtp);
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ if (marker) {
+ /* marker bit starts talkspurt */
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+ }
+
+ GST_LOG_OBJECT (depayload, "pushing buffer of size %" G_GSIZE_FORMAT,
+ gst_buffer_get_size (outbuf));
+
+ return outbuf;
+
+ /* ERRORS */
+bad_packet:
+ {
+ /* no fatal error */
+ return NULL;
+ }
+}
+
+gboolean
+gst_rtp_g729_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpg729depay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_G729_DEPAY);
+}
diff --git a/gst/rtp/gstrtpg729depay.h b/gst/rtp/gstrtpg729depay.h
new file mode 100755
index 0000000..a23562e
--- /dev/null
+++ b/gst/rtp/gstrtpg729depay.h
@@ -0,0 +1,61 @@
+/* GStreamer
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_G729_DEPAY_H__
+#define __GST_RTP_G729_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_G729_DEPAY \
+ (gst_rtp_g729_depay_get_type())
+
+#define GST_RTP_G729_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_G729_DEPAY,GstRtpG729Depay))
+
+#define GST_RTP_G729_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_G729_DEPAY,GstRtpG729DepayClass))
+
+#define GST_IS_RTP_G729_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_G729_DEPAY))
+
+#define GST_IS_RTP_G729_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_G729_DEPAY))
+
+typedef struct _GstRtpG729Depay GstRtpG729Depay;
+typedef struct _GstRtpG729DepayClass GstRtpG729DepayClass;
+
+struct _GstRtpG729Depay
+{
+ GstRTPBaseDepayload depayload;
+};
+
+struct _GstRtpG729DepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_g729_depay_get_type (void);
+
+gboolean gst_rtp_g729_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_G729_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpg729pay.c b/gst/rtp/gstrtpg729pay.c
new file mode 100755
index 0000000..306e175
--- /dev/null
+++ b/gst/rtp/gstrtpg729pay.c
@@ -0,0 +1,418 @@
+/* GStreamer
+ * Copyright (C) <2007> Nokia Corporation
+ * Copyright (C) <2007> Collabora Ltd
+ * @author: Olivier Crete <olivier.crete@collabora.co.uk>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * This payloader assumes that the data will ALWAYS come as zero or more
+ * 10 bytes frame of audio followed by 0 or 1 2 byte frame of silence.
+ * Any other buffer format won't work
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/base/gstadapter.h>
+
+#include "gstrtpg729pay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpg729pay_debug);
+#define GST_CAT_DEFAULT (rtpg729pay_debug)
+
+#define G729_FRAME_SIZE 10
+#define G729B_CN_FRAME_SIZE 2
+#define G729_FRAME_DURATION (10 * GST_MSECOND)
+#define G729_FRAME_DURATION_MS (10)
+
+static gboolean
+gst_rtp_g729_pay_set_caps (GstRTPBasePayload * payload, GstCaps * caps);
+static GstFlowReturn
+gst_rtp_g729_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buf);
+
+static GstStateChangeReturn
+gst_rtp_g729_pay_change_state (GstElement * element, GstStateChange transition);
+
+static GstStaticPadTemplate gst_rtp_g729_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/G729, " /* according to RFC 3555 */
+ "channels = (int) 1, " "rate = (int) 8000")
+ );
+
+static GstStaticPadTemplate gst_rtp_g729_pay_src_template =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_G729_STRING ", "
+ "clock-rate = (int) 8000, "
+ "encoding-name = (string) \"G729\"; "
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) 8000, " "encoding-name = (string) \"G729\"")
+ );
+
+#define gst_rtp_g729_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPG729Pay, gst_rtp_g729_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_g729_pay_finalize (GObject * object)
+{
+ GstRTPG729Pay *pay = GST_RTP_G729_PAY (object);
+
+ g_object_unref (pay->adapter);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_rtp_g729_pay_class_init (GstRTPG729PayClass * klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstElementClass *gstelement_class = (GstElementClass *) klass;
+ GstRTPBasePayloadClass *payload_class = GST_RTP_BASE_PAYLOAD_CLASS (klass);
+
+ GST_DEBUG_CATEGORY_INIT (rtpg729pay_debug, "rtpg729pay", 0,
+ "G.729 RTP Payloader");
+
+ gobject_class->finalize = gst_rtp_g729_pay_finalize;
+
+ gstelement_class->change_state = gst_rtp_g729_pay_change_state;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_g729_pay_sink_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_g729_pay_src_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP G.729 payloader", "Codec/Payloader/Network/RTP",
+ "Packetize G.729 audio into RTP packets",
+ "Olivier Crete <olivier.crete@collabora.co.uk>");
+
+ payload_class->set_caps = gst_rtp_g729_pay_set_caps;
+ payload_class->handle_buffer = gst_rtp_g729_pay_handle_buffer;
+}
+
+static void
+gst_rtp_g729_pay_init (GstRTPG729Pay * pay)
+{
+ GstRTPBasePayload *payload = GST_RTP_BASE_PAYLOAD (pay);
+
+ payload->pt = GST_RTP_PAYLOAD_G729;
+ gst_rtp_base_payload_set_options (payload, "audio", FALSE, "G729", 8000);
+
+ pay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_g729_pay_reset (GstRTPG729Pay * pay)
+{
+ gst_adapter_clear (pay->adapter);
+ pay->discont = FALSE;
+ pay->next_rtp_time = 0;
+ pay->first_ts = GST_CLOCK_TIME_NONE;
+ pay->first_rtp_time = 0;
+}
+
+static gboolean
+gst_rtp_g729_pay_set_caps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ gboolean res;
+ GstStructure *structure;
+ gint pt;
+
+ structure = gst_caps_get_structure (caps, 0);
+ if (!gst_structure_get_int (structure, "payload", &pt))
+ pt = GST_RTP_PAYLOAD_G729;
+
+ payload->pt = pt;
+ payload->dynamic = pt != GST_RTP_PAYLOAD_G729;
+
+ res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+
+ return res;
+}
+
+static GstFlowReturn
+gst_rtp_g729_pay_push (GstRTPG729Pay * rtpg729pay,
+ const guint8 * data, guint payload_len)
+{
+ GstRTPBasePayload *basepayload;
+ GstClockTime duration;
+ guint frames;
+ GstBuffer *outbuf;
+ guint8 *payload;
+ GstFlowReturn ret;
+ GstRTPBuffer rtp = { NULL };
+
+ basepayload = GST_RTP_BASE_PAYLOAD (rtpg729pay);
+
+ GST_DEBUG_OBJECT (rtpg729pay, "Pushing %d bytes ts %" GST_TIME_FORMAT,
+ payload_len, GST_TIME_ARGS (rtpg729pay->next_ts));
+
+ /* create buffer to hold the payload */
+ outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
+
+ gst_rtp_buffer_map (outbuf, GST_MAP_READWRITE, &rtp);
+
+ /* copy payload */
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ memcpy (payload, data, payload_len);
+
+ /* set metadata */
+ frames =
+ (payload_len / G729_FRAME_SIZE) + ((payload_len % G729_FRAME_SIZE) >> 1);
+ duration = frames * G729_FRAME_DURATION;
+ GST_BUFFER_TIMESTAMP (outbuf) = rtpg729pay->next_ts;
+ GST_BUFFER_DURATION (outbuf) = duration;
+ GST_BUFFER_OFFSET (outbuf) = rtpg729pay->next_rtp_time;
+ rtpg729pay->next_ts += duration;
+ rtpg729pay->next_rtp_time += frames * 80;
+
+ if (G_UNLIKELY (rtpg729pay->discont)) {
+ GST_DEBUG_OBJECT (basepayload, "discont, setting marker bit");
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+ gst_rtp_buffer_set_marker (&rtp, TRUE);
+ rtpg729pay->discont = FALSE;
+ }
+ gst_rtp_buffer_unmap (&rtp);
+
+ ret = gst_rtp_base_payload_push (basepayload, outbuf);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_rtp_g729_pay_push_and_free (GstRTPG729Pay * rtpg729pay,
+ guint8 * data, guint payload_len)
+{
+ GstFlowReturn ret;
+
+ ret = gst_rtp_g729_pay_push (rtpg729pay, data, payload_len);
+ g_free (data);
+ return ret;
+}
+
+static void
+gst_rtp_g729_pay_recalc_rtp_time (GstRTPG729Pay * rtpg729pay, GstClockTime time)
+{
+ if (GST_CLOCK_TIME_IS_VALID (rtpg729pay->first_ts)
+ && GST_CLOCK_TIME_IS_VALID (time) && time >= rtpg729pay->first_ts) {
+ GstClockTime diff;
+ guint32 rtpdiff;
+
+ diff = time - rtpg729pay->first_ts;
+ rtpdiff = (diff / GST_MSECOND) * 8;
+ rtpg729pay->next_rtp_time = rtpg729pay->first_rtp_time + rtpdiff;
+ GST_DEBUG_OBJECT (rtpg729pay,
+ "elapsed time %" GST_TIME_FORMAT ", rtp %" G_GUINT32_FORMAT ", "
+ "new offset %" G_GUINT32_FORMAT, GST_TIME_ARGS (diff), rtpdiff,
+ rtpg729pay->next_rtp_time);
+ }
+}
+
+static GstFlowReturn
+gst_rtp_g729_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buf)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstRTPG729Pay *rtpg729pay = GST_RTP_G729_PAY (payload);
+ GstAdapter *adapter = NULL;
+ guint payload_len;
+ guint available;
+ guint maxptime_octets = G_MAXUINT;
+ guint minptime_octets = 0;
+ guint min_payload_len;
+ guint max_payload_len;
+ gsize size;
+ GstClockTime timestamp;
+
+ size = gst_buffer_get_size (buf);
+
+ if (size % G729_FRAME_SIZE != 0 &&
+ size % G729_FRAME_SIZE != G729B_CN_FRAME_SIZE)
+ goto invalid_size;
+
+ /* max number of bytes based on given ptime, has to be multiple of
+ * frame_duration */
+ if (payload->max_ptime != -1) {
+ guint ptime_ms = payload->max_ptime / GST_MSECOND;
+
+ maxptime_octets = G729_FRAME_SIZE *
+ (int) (ptime_ms / G729_FRAME_DURATION_MS);
+
+ if (maxptime_octets < G729_FRAME_SIZE) {
+ GST_WARNING_OBJECT (payload, "Given ptime %" G_GINT64_FORMAT
+ " is smaller than minimum %d ns, overwriting to minimum",
+ payload->max_ptime, G729_FRAME_DURATION_MS);
+ maxptime_octets = G729_FRAME_SIZE;
+ }
+ }
+
+ max_payload_len = MIN (
+ /* MTU max */
+ (int) (gst_rtp_buffer_calc_payload_len (GST_RTP_BASE_PAYLOAD_MTU
+ (payload), 0, 0) / G729_FRAME_SIZE)
+ * G729_FRAME_SIZE,
+ /* ptime max */
+ maxptime_octets);
+
+ /* min number of bytes based on a given ptime, has to be a multiple
+ of frame duration */
+ {
+ guint64 min_ptime = payload->min_ptime;
+
+ min_ptime = min_ptime / GST_MSECOND;
+ minptime_octets = G729_FRAME_SIZE *
+ (int) (min_ptime / G729_FRAME_DURATION_MS);
+ }
+
+ min_payload_len = MAX (minptime_octets, G729_FRAME_SIZE);
+
+ if (min_payload_len > max_payload_len) {
+ min_payload_len = max_payload_len;
+ }
+
+ /* If the ptime is specified in the caps, tried to adhere to it exactly */
+ if (payload->ptime) {
+ guint64 ptime = payload->ptime / GST_MSECOND;
+ guint ptime_in_bytes = G729_FRAME_SIZE *
+ (guint) (ptime / G729_FRAME_DURATION_MS);
+
+ /* clip to computed min and max lengths */
+ ptime_in_bytes = MAX (min_payload_len, ptime_in_bytes);
+ ptime_in_bytes = MIN (max_payload_len, ptime_in_bytes);
+
+ min_payload_len = max_payload_len = ptime_in_bytes;
+ }
+
+ GST_LOG_OBJECT (payload,
+ "Calculated min_payload_len %u and max_payload_len %u",
+ min_payload_len, max_payload_len);
+
+ adapter = rtpg729pay->adapter;
+ available = gst_adapter_available (adapter);
+
+ timestamp = GST_BUFFER_TIMESTAMP (buf);
+
+ /* resync rtp time on discont or a discontinuous cn packet */
+ if (GST_BUFFER_IS_DISCONT (buf)) {
+ /* flush remainder */
+ if (available > 0) {
+ gst_rtp_g729_pay_push_and_free (rtpg729pay,
+ gst_adapter_take (adapter, available), available);
+ available = 0;
+ }
+ rtpg729pay->discont = TRUE;
+ gst_rtp_g729_pay_recalc_rtp_time (rtpg729pay, timestamp);
+ }
+
+ if (size < G729_FRAME_SIZE)
+ gst_rtp_g729_pay_recalc_rtp_time (rtpg729pay, timestamp);
+
+ if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (rtpg729pay->first_ts))) {
+ rtpg729pay->first_ts = timestamp;
+ rtpg729pay->first_rtp_time = rtpg729pay->next_rtp_time;
+ }
+
+ /* let's reset the base timestamp when the adapter is empty */
+ if (available == 0)
+ rtpg729pay->next_ts = timestamp;
+
+ if (available == 0 && size >= min_payload_len && size <= max_payload_len) {
+ GstMapInfo map;
+
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+ ret = gst_rtp_g729_pay_push (rtpg729pay, map.data, map.size);
+ gst_buffer_unmap (buf, &map);
+ gst_buffer_unref (buf);
+ return ret;
+ }
+
+ gst_adapter_push (adapter, buf);
+ available = gst_adapter_available (adapter);
+
+ /* as long as we have full frames */
+ /* this loop will push all available buffers till the last frame */
+ while (available >= min_payload_len ||
+ available % G729_FRAME_SIZE == G729B_CN_FRAME_SIZE) {
+ /* We send as much as we can */
+ if (available <= max_payload_len) {
+ payload_len = available;
+ } else {
+ payload_len = MIN (max_payload_len,
+ (available / G729_FRAME_SIZE) * G729_FRAME_SIZE);
+ }
+
+ ret = gst_rtp_g729_pay_push_and_free (rtpg729pay,
+ gst_adapter_take (adapter, payload_len), payload_len);
+ available -= payload_len;
+ }
+
+ return ret;
+
+ /* ERRORS */
+invalid_size:
+ {
+ GST_ELEMENT_ERROR (payload, STREAM, WRONG_TYPE,
+ ("Invalid input buffer size"),
+ ("Invalid buffer size, should be a multiple of"
+ " G729_FRAME_SIZE(10) with an optional G729B_CN_FRAME_SIZE(2)"
+ " added to it, but it is %" G_GSIZE_FORMAT, size));
+ gst_buffer_unref (buf);
+ return GST_FLOW_ERROR;
+ }
+}
+
+static GstStateChangeReturn
+gst_rtp_g729_pay_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+ /* handle upwards state changes here */
+ switch (transition) {
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ /* handle downwards state changes */
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_rtp_g729_pay_reset (GST_RTP_G729_PAY (element));
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+gboolean
+gst_rtp_g729_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpg729pay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_G729_PAY);
+}
diff --git a/gst/rtp/gstrtpg729pay.h b/gst/rtp/gstrtpg729pay.h
new file mode 100755
index 0000000..1b92460
--- /dev/null
+++ b/gst/rtp/gstrtpg729pay.h
@@ -0,0 +1,66 @@
+/* GStreamer
+ * Copyright (C) <2007> Nokia Corporation
+ * Copyright (C) <2007> Collabora Ltd
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_G729_PAY_H__
+#define __GST_RTP_G729_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_G729_PAY \
+ (gst_rtp_g729_pay_get_type())
+#define GST_RTP_G729_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_G729_PAY,GstRTPG729Pay))
+#define GST_RTP_G729_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_G729_PAY,GstRTPG729PayClass))
+#define GST_IS_RTP_G729_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_G729_PAY))
+#define GST_IS_RTP_G729_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_G729_PAY))
+
+typedef struct _GstRTPG729Pay GstRTPG729Pay;
+typedef struct _GstRTPG729PayClass GstRTPG729PayClass;
+
+struct _GstRTPG729Pay
+{
+ GstRTPBasePayload payload;
+
+ GstAdapter *adapter;
+ GstClockTime next_ts;
+ guint32 next_rtp_time;
+ GstClockTime first_ts;
+ guint32 first_rtp_time;
+ gboolean discont;
+};
+
+struct _GstRTPG729PayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_g729_pay_get_type (void);
+
+gboolean gst_rtp_g729_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_G729_PAY_H__ */
diff --git a/gst/rtp/gstrtpgsmdepay.c b/gst/rtp/gstrtpgsmdepay.c
new file mode 100755
index 0000000..96b30cf
--- /dev/null
+++ b/gst/rtp/gstrtpgsmdepay.c
@@ -0,0 +1,151 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2005> Zeeshan Ali <zeenix@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include "gstrtpgsmdepay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpgsmdepay_debug);
+#define GST_CAT_DEFAULT (rtpgsmdepay_debug)
+
+/* RTPGSMDepay signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+static GstStaticPadTemplate gst_rtp_gsm_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-gsm, " "rate = (int) 8000, " "channels = 1")
+ );
+
+static GstStaticPadTemplate gst_rtp_gsm_depay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "clock-rate = (int) 8000, " "encoding-name = (string) \"GSM\";"
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_GSM_STRING ", "
+ "clock-rate = (int) 8000")
+ );
+
+static GstBuffer *gst_rtp_gsm_depay_process (GstRTPBaseDepayload * _depayload,
+ GstBuffer * buf);
+static gboolean gst_rtp_gsm_depay_setcaps (GstRTPBaseDepayload * _depayload,
+ GstCaps * caps);
+
+#define gst_rtp_gsm_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPGSMDepay, gst_rtp_gsm_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_gsm_depay_class_init (GstRTPGSMDepayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbase_depayload_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbase_depayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_gsm_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_gsm_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP GSM depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts GSM audio from RTP packets", "Zeeshan Ali <zeenix@gmail.com>");
+
+ gstrtpbase_depayload_class->process = gst_rtp_gsm_depay_process;
+ gstrtpbase_depayload_class->set_caps = gst_rtp_gsm_depay_setcaps;
+
+ GST_DEBUG_CATEGORY_INIT (rtpgsmdepay_debug, "rtpgsmdepay", 0,
+ "GSM Audio RTP Depayloader");
+}
+
+static void
+gst_rtp_gsm_depay_init (GstRTPGSMDepay * rtpgsmdepay)
+{
+}
+
+static gboolean
+gst_rtp_gsm_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstCaps *srccaps;
+ gboolean ret;
+ GstStructure *structure;
+ gint clock_rate;
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 8000; /* default */
+ depayload->clock_rate = clock_rate;
+
+ srccaps = gst_caps_new_simple ("audio/x-gsm",
+ "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, clock_rate, NULL);
+ ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+ gst_caps_unref (srccaps);
+
+ return ret;
+}
+
+static GstBuffer *
+gst_rtp_gsm_depay_process (GstRTPBaseDepayload * _depayload, GstBuffer * buf)
+{
+ GstBuffer *outbuf = NULL;
+ gboolean marker;
+ GstRTPBuffer rtp = { NULL };
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ marker = gst_rtp_buffer_get_marker (&rtp);
+
+ GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d",
+ gst_buffer_get_size (buf), marker,
+ gst_rtp_buffer_get_timestamp (&rtp), gst_rtp_buffer_get_seq (&rtp));
+
+ outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ if (marker && outbuf) {
+ /* mark start of talkspurt with RESYNC */
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+ }
+
+ return outbuf;
+}
+
+gboolean
+gst_rtp_gsm_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpgsmdepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_GSM_DEPAY);
+}
diff --git a/gst/rtp/gstrtpgsmdepay.h b/gst/rtp/gstrtpgsmdepay.h
new file mode 100755
index 0000000..e428aa0
--- /dev/null
+++ b/gst/rtp/gstrtpgsmdepay.h
@@ -0,0 +1,58 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_GSM_DEPAY_H__
+#define __GST_RTP_GSM_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRTPGSMDepay GstRTPGSMDepay;
+typedef struct _GstRTPGSMDepayClass GstRTPGSMDepayClass;
+
+#define GST_TYPE_RTP_GSM_DEPAY \
+ (gst_rtp_gsm_depay_get_type())
+#define GST_RTP_GSM_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_GSM_DEPAY,GstRTPGSMDepay))
+#define GST_RTP_GSM_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_GSM_DEPAY,GstRTPGSMDepayClass))
+#define GST_IS_RTP_GSM_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_GSM_DEPAY))
+#define GST_IS_RTP_GSM_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_GSM_DEPAY))
+
+struct _GstRTPGSMDepay
+{
+ GstRTPBaseDepayload _depayload;
+};
+
+struct _GstRTPGSMDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_gsm_depay_get_type (void);
+
+gboolean gst_rtp_gsm_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_GSM_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpgsmpay.c b/gst/rtp/gstrtpgsmpay.c
new file mode 100755
index 0000000..b6964c5
--- /dev/null
+++ b/gst/rtp/gstrtpgsmpay.c
@@ -0,0 +1,191 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2005> Zeeshan Ali <zeenix@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpgsmpay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpgsmpay_debug);
+#define GST_CAT_DEFAULT (rtpgsmpay_debug)
+
+static GstStaticPadTemplate gst_rtp_gsm_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-gsm, " "rate = (int) 8000, " "channels = (int) 1")
+ );
+
+static GstStaticPadTemplate gst_rtp_gsm_pay_src_template =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_GSM_STRING ", "
+ "clock-rate = (int) 8000, " "encoding-name = (string) \"GSM\"; "
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) 8000, " "encoding-name = (string) \"GSM\"")
+ );
+
+static gboolean gst_rtp_gsm_pay_setcaps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+static GstFlowReturn gst_rtp_gsm_pay_handle_buffer (GstRTPBasePayload * payload,
+ GstBuffer * buffer);
+
+#define gst_rtp_gsm_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPGSMPay, gst_rtp_gsm_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_gsm_pay_class_init (GstRTPGSMPayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ GST_DEBUG_CATEGORY_INIT (rtpgsmpay_debug, "rtpgsmpay", 0,
+ "GSM Audio RTP Payloader");
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_gsm_pay_sink_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_gsm_pay_src_template));
+
+ gst_element_class_set_static_metadata (gstelement_class, "RTP GSM payloader",
+ "Codec/Payloader/Network/RTP",
+ "Payload-encodes GSM audio into a RTP packet",
+ "Zeeshan Ali <zeenix@gmail.com>");
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_gsm_pay_setcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_gsm_pay_handle_buffer;
+}
+
+static void
+gst_rtp_gsm_pay_init (GstRTPGSMPay * rtpgsmpay)
+{
+ GST_RTP_BASE_PAYLOAD (rtpgsmpay)->clock_rate = 8000;
+ GST_RTP_BASE_PAYLOAD_PT (rtpgsmpay) = GST_RTP_PAYLOAD_GSM;
+}
+
+static gboolean
+gst_rtp_gsm_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ const char *stname;
+ GstStructure *structure;
+ gboolean res;
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ stname = gst_structure_get_name (structure);
+
+ if (strcmp ("audio/x-gsm", stname))
+ goto invalid_type;
+
+ gst_rtp_base_payload_set_options (payload, "audio", FALSE, "GSM", 8000);
+ res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+
+ return res;
+
+ /* ERRORS */
+invalid_type:
+ {
+ GST_WARNING_OBJECT (payload, "invalid media type received");
+ return FALSE;
+ }
+}
+
+static GstFlowReturn
+gst_rtp_gsm_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer)
+{
+ GstRTPGSMPay *rtpgsmpay;
+ guint payload_len;
+ GstBuffer *outbuf;
+ GstMapInfo map;
+ guint8 *payload;
+ GstClockTime timestamp, duration;
+ GstFlowReturn ret;
+ GstRTPBuffer rtp = { NULL };
+
+ rtpgsmpay = GST_RTP_GSM_PAY (basepayload);
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+ timestamp = GST_BUFFER_TIMESTAMP (buffer);
+ duration = GST_BUFFER_DURATION (buffer);
+
+ /* FIXME, only one GSM frame per RTP packet for now */
+ payload_len = map.size;
+
+ /* FIXME, just error out for now */
+ if (payload_len > GST_RTP_BASE_PAYLOAD_MTU (rtpgsmpay))
+ goto too_big;
+
+ outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
+
+ /* copy timestamp and duration */
+ GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
+ GST_BUFFER_DURATION (outbuf) = duration;
+
+ /* get payload */
+ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+ /* copy data in payload */
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ memcpy (payload, map.data, map.size);
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+
+ GST_DEBUG ("gst_rtp_gsm_pay_chain: pushing buffer of size %" G_GSIZE_FORMAT,
+ gst_buffer_get_size (outbuf));
+
+ ret = gst_rtp_base_payload_push (basepayload, outbuf);
+
+ return ret;
+
+ /* ERRORS */
+too_big:
+ {
+ GST_ELEMENT_ERROR (rtpgsmpay, STREAM, ENCODE, (NULL),
+ ("payload_len %u > mtu %u", payload_len,
+ GST_RTP_BASE_PAYLOAD_MTU (rtpgsmpay)));
+ gst_buffer_unmap (buffer, &map);
+ return GST_FLOW_ERROR;
+ }
+}
+
+gboolean
+gst_rtp_gsm_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpgsmpay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_GSM_PAY);
+}
diff --git a/gst/rtp/gstrtpgsmpay.h b/gst/rtp/gstrtpgsmpay.h
new file mode 100755
index 0000000..b6437f5
--- /dev/null
+++ b/gst/rtp/gstrtpgsmpay.h
@@ -0,0 +1,59 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_RTP_GSM_PAY_H__
+#define __GST_RTP_GSM_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRTPGSMPay GstRTPGSMPay;
+typedef struct _GstRTPGSMPayClass GstRTPGSMPayClass;
+
+#define GST_TYPE_RTP_GSM_PAY \
+ (gst_rtp_gsm_pay_get_type())
+#define GST_RTP_GSM_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_GSM_PAY,GstRTPGSMPay))
+#define GST_RTP_GSM_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_GSM_PAY,GstRTPGSMPayClass))
+#define GST_IS_RTP_GSM_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_GSM_PAY))
+#define GST_IS_RTP_GSM_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_GSM_PAY))
+
+struct _GstRTPGSMPay
+{
+ GstRTPBasePayload payload;
+};
+
+struct _GstRTPGSMPayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_gsm_pay_get_type (void);
+
+gboolean gst_rtp_gsm_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_GSM_PAY_H__ */
diff --git a/gst/rtp/gstrtpgstdepay.c b/gst/rtp/gstrtpgstdepay.c
new file mode 100755
index 0000000..621aa47
--- /dev/null
+++ b/gst/rtp/gstrtpgstdepay.c
@@ -0,0 +1,625 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "gstrtpgstdepay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpgstdepay_debug);
+#define GST_CAT_DEFAULT (rtpgstdepay_debug)
+
+static GstStaticPadTemplate gst_rtp_gst_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate gst_rtp_gst_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"application\", "
+ "clock-rate = (int) 90000, " "encoding-name = (string) \"X-GST\"")
+ );
+
+#define gst_rtp_gst_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpGSTDepay, gst_rtp_gst_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_gst_depay_finalize (GObject * object);
+
+static gboolean gst_rtp_gst_depay_handle_event (GstRTPBaseDepayload * depay,
+ GstEvent * event);
+static GstStateChangeReturn gst_rtp_gst_depay_change_state (GstElement *
+ element, GstStateChange transition);
+
+static void gst_rtp_gst_depay_reset (GstRtpGSTDepay * rtpgstdepay, gboolean
+ full);
+static gboolean gst_rtp_gst_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_gst_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+
+static void
+gst_rtp_gst_depay_class_init (GstRtpGSTDepayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ GST_DEBUG_CATEGORY_INIT (rtpgstdepay_debug, "rtpgstdepay", 0,
+ "Gstreamer RTP Depayloader");
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_gst_depay_finalize;
+
+ gstelement_class->change_state = gst_rtp_gst_depay_change_state;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_gst_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_gst_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "GStreamer depayloader", "Codec/Depayloader/Network",
+ "Extracts GStreamer buffers from RTP packets",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ gstrtpbasedepayload_class->handle_event = gst_rtp_gst_depay_handle_event;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_gst_depay_setcaps;
+ gstrtpbasedepayload_class->process = gst_rtp_gst_depay_process;
+}
+
+static void
+gst_rtp_gst_depay_init (GstRtpGSTDepay * rtpgstdepay)
+{
+ rtpgstdepay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_gst_depay_finalize (GObject * object)
+{
+ GstRtpGSTDepay *rtpgstdepay;
+
+ rtpgstdepay = GST_RTP_GST_DEPAY (object);
+
+ gst_rtp_gst_depay_reset (rtpgstdepay, TRUE);
+ g_object_unref (rtpgstdepay->adapter);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+store_cache (GstRtpGSTDepay * rtpgstdepay, guint CV, GstCaps * caps)
+{
+ if (rtpgstdepay->CV_cache[CV])
+ gst_caps_unref (rtpgstdepay->CV_cache[CV]);
+ rtpgstdepay->CV_cache[CV] = caps;
+}
+
+static void
+gst_rtp_gst_depay_reset (GstRtpGSTDepay * rtpgstdepay, gboolean full)
+{
+ guint i;
+
+ gst_adapter_clear (rtpgstdepay->adapter);
+ if (full) {
+ rtpgstdepay->current_CV = 0;
+ for (i = 0; i < 8; i++)
+ store_cache (rtpgstdepay, i, NULL);
+ g_free (rtpgstdepay->stream_id);
+ rtpgstdepay->stream_id = NULL;
+ if (rtpgstdepay->tags)
+ gst_tag_list_unref (rtpgstdepay->tags);
+ rtpgstdepay->tags = NULL;
+ }
+}
+
+static gboolean
+gst_rtp_gst_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstRtpGSTDepay *rtpgstdepay;
+ GstStructure *structure;
+ gint clock_rate;
+ gboolean res;
+ const gchar *capsenc;
+
+ rtpgstdepay = GST_RTP_GST_DEPAY (depayload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 90000;
+ depayload->clock_rate = clock_rate;
+
+ capsenc = gst_structure_get_string (structure, "caps");
+ if (capsenc) {
+ GstCaps *outcaps;
+ gsize out_len;
+ gchar *capsstr;
+ const gchar *capsver;
+ guint CV;
+
+ /* decode caps */
+ capsstr = (gchar *) g_base64_decode (capsenc, &out_len);
+ outcaps = gst_caps_from_string (capsstr);
+ g_free (capsstr);
+
+ /* parse version */
+ capsver = gst_structure_get_string (structure, "capsversion");
+ if (capsver) {
+ CV = atoi (capsver);
+ } else {
+ /* no version, assume 0 */
+ CV = 0;
+ }
+ /* store in cache */
+ rtpgstdepay->current_CV = CV;
+ gst_caps_ref (outcaps);
+ store_cache (rtpgstdepay, CV, outcaps);
+
+ res = gst_pad_set_caps (depayload->srcpad, outcaps);
+ gst_caps_unref (outcaps);
+ } else {
+ GST_WARNING_OBJECT (depayload, "no caps given");
+ rtpgstdepay->current_CV = -1;
+ res = TRUE;
+ }
+
+ return res;
+}
+
+static gboolean
+read_length (GstRtpGSTDepay * rtpgstdepay, guint8 * data, guint size,
+ guint * length, guint * skip)
+{
+ guint b, len, offset;
+
+ /* start reading the length, we need this to skip to the data later */
+ len = offset = 0;
+ do {
+ if (offset >= size)
+ return FALSE;
+ b = data[offset++];
+ len = (len << 7) | (b & 0x7f);
+ } while (b & 0x80);
+
+ /* check remaining buffer size */
+ if (size - offset < len)
+ return FALSE;
+
+ *length = len;
+ *skip = offset;
+
+ return TRUE;
+}
+
+static GstCaps *
+read_caps (GstRtpGSTDepay * rtpgstdepay, GstBuffer * buf, guint * skip)
+{
+ guint offset, length;
+ GstCaps *caps;
+ GstMapInfo map;
+
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+
+ GST_DEBUG_OBJECT (rtpgstdepay, "buffer size %" G_GSIZE_FORMAT, map.size);
+
+ if (!read_length (rtpgstdepay, map.data, map.size, &length, &offset))
+ goto too_small;
+
+ if (length == 0 || map.data[offset + length - 1] != '\0')
+ goto invalid_buffer;
+
+ GST_DEBUG_OBJECT (rtpgstdepay, "parsing caps %s", &map.data[offset]);
+
+ /* parse and store in cache */
+ caps = gst_caps_from_string ((gchar *) & map.data[offset]);
+ gst_buffer_unmap (buf, &map);
+
+ *skip = length + offset;
+
+ return caps;
+
+too_small:
+ {
+ GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE,
+ ("Buffer too small."), (NULL));
+ gst_buffer_unmap (buf, &map);
+ return NULL;
+ }
+invalid_buffer:
+ {
+ GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE,
+ ("caps string not 0-terminated."), (NULL));
+ gst_buffer_unmap (buf, &map);
+ return NULL;
+ }
+}
+
+static GstEvent *
+read_event (GstRtpGSTDepay * rtpgstdepay, guint type,
+ GstBuffer * buf, guint * skip)
+{
+ guint offset, length;
+ GstStructure *s;
+ GstEvent *event;
+ GstEventType etype;
+ gchar *end;
+ GstMapInfo map;
+
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+
+ GST_DEBUG_OBJECT (rtpgstdepay, "buffer size %" G_GSIZE_FORMAT, map.size);
+
+ if (!read_length (rtpgstdepay, map.data, map.size, &length, &offset))
+ goto too_small;
+
+ if (length == 0)
+ goto invalid_buffer;
+ if (map.data[offset + length - 1] != '\0')
+ goto invalid_buffer;
+ /* backward compat, old payloader did not put 0-byte at the end */
+ if (map.data[offset + length - 1] != ';')
+ goto invalid_buffer;
+
+ GST_DEBUG_OBJECT (rtpgstdepay, "parsing event %s", &map.data[offset]);
+
+ /* parse */
+ s = gst_structure_from_string ((gchar *) & map.data[offset], &end);
+ gst_buffer_unmap (buf, &map);
+
+ if (s == NULL)
+ goto parse_failed;
+
+ switch (type) {
+ case 1:
+ etype = GST_EVENT_TAG;
+ break;
+ case 2:
+ etype = GST_EVENT_CUSTOM_DOWNSTREAM;
+ break;
+ case 3:
+ etype = GST_EVENT_CUSTOM_BOTH;
+ break;
+ case 4:
+ etype = GST_EVENT_STREAM_START;
+ break;
+ default:
+ goto unknown_event;
+ }
+ event = gst_event_new_custom (etype, s);
+
+ *skip = length + offset;
+
+ return event;
+
+too_small:
+ {
+ GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE,
+ ("Buffer too small."), (NULL));
+ gst_buffer_unmap (buf, &map);
+ return NULL;
+ }
+invalid_buffer:
+ {
+ GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE,
+ ("event string not 0-terminated."), (NULL));
+ gst_buffer_unmap (buf, &map);
+ return NULL;
+ }
+parse_failed:
+ {
+ GST_WARNING_OBJECT (rtpgstdepay, "could not parse event");
+ return NULL;
+ }
+unknown_event:
+ {
+ GST_DEBUG_OBJECT (rtpgstdepay, "unknown event type");
+ gst_structure_free (s);
+ return NULL;
+ }
+}
+
+static void
+store_event (GstRtpGSTDepay * rtpgstdepay, GstEvent * event)
+{
+ gboolean do_push = FALSE;
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_TAG:
+ {
+ GstTagList *old, *tags;
+
+ gst_event_parse_tag (event, &tags);
+
+ old = rtpgstdepay->tags;
+ if (!old || !gst_tag_list_is_equal (old, tags)) {
+ do_push = TRUE;
+ if (old)
+ gst_tag_list_unref (old);
+ rtpgstdepay->tags = gst_tag_list_ref (tags);
+ }
+ break;
+ }
+ case GST_EVENT_CUSTOM_DOWNSTREAM:
+ case GST_EVENT_CUSTOM_BOTH:
+ /* always push custom events */
+ do_push = TRUE;
+ break;
+ case GST_EVENT_STREAM_START:
+ {
+ gchar *old;
+ const gchar *stream_id = NULL;
+
+ gst_event_parse_stream_start (event, &stream_id);
+
+ old = rtpgstdepay->stream_id;
+ if (!old || g_strcmp0 (old, stream_id)) {
+ do_push = TRUE;
+ g_free (old);
+ rtpgstdepay->stream_id = g_strdup (stream_id);
+ }
+ break;
+ }
+ default:
+ /* unknown event, don't push */
+ break;
+ }
+ if (do_push)
+ gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD (rtpgstdepay)->srcpad, event);
+ else
+ gst_event_unref (event);
+}
+
+static GstBuffer *
+gst_rtp_gst_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpGSTDepay *rtpgstdepay;
+ GstBuffer *subbuf, *outbuf = NULL;
+ gint payload_len;
+ guint8 *payload;
+ guint CV, frag_offset, avail, offset;
+ GstRTPBuffer rtp = { NULL };
+
+ rtpgstdepay = GST_RTP_GST_DEPAY (depayload);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+
+ if (payload_len <= 8)
+ goto empty_packet;
+
+ if (GST_BUFFER_IS_DISCONT (buf)) {
+ GST_WARNING_OBJECT (rtpgstdepay, "DISCONT, clear adapter");
+ gst_adapter_clear (rtpgstdepay->adapter);
+ }
+
+ payload = gst_rtp_buffer_get_payload (&rtp);
+
+ /* strip off header
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |C| CV |D|0|0|0| ETYPE | MBZ |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Frag_offset |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ frag_offset =
+ (payload[4] << 24) | (payload[5] << 16) | (payload[6] << 8) | payload[7];
+
+ avail = gst_adapter_available (rtpgstdepay->adapter);
+ if (avail != frag_offset)
+ goto wrong_frag;
+
+ /* subbuffer skipping the 8 header bytes */
+ subbuf = gst_rtp_buffer_get_payload_subbuffer (&rtp, 8, -1);
+ gst_adapter_push (rtpgstdepay->adapter, subbuf);
+
+ offset = 0;
+ if (gst_rtp_buffer_get_marker (&rtp)) {
+ guint avail;
+ GstCaps *outcaps;
+
+ /* take the buffer */
+ avail = gst_adapter_available (rtpgstdepay->adapter);
+ outbuf = gst_adapter_take_buffer (rtpgstdepay->adapter, avail);
+
+ CV = (payload[0] >> 4) & 0x7;
+
+ if (payload[0] & 0x80) {
+ guint size;
+
+ /* C bit, we have inline caps */
+ outcaps = read_caps (rtpgstdepay, outbuf, &size);
+ if (outcaps == NULL)
+ goto no_caps;
+
+ GST_DEBUG_OBJECT (rtpgstdepay,
+ "inline caps %u, length %u, %" GST_PTR_FORMAT, CV, size, outcaps);
+
+ store_cache (rtpgstdepay, CV, outcaps);
+
+ /* skip caps */
+ offset += size;
+ avail -= size;
+ }
+ if (payload[1]) {
+ guint size;
+ GstEvent *event;
+
+ /* we have an event */
+ event = read_event (rtpgstdepay, payload[1], outbuf, &size);
+ if (event == NULL)
+ goto no_event;
+
+ GST_DEBUG_OBJECT (rtpgstdepay,
+ "inline event, length %u, %" GST_PTR_FORMAT, size, event);
+
+ store_event (rtpgstdepay, event);
+
+ /* no buffer after event */
+ avail = 0;
+ }
+
+ if (avail) {
+ if (offset != 0) {
+ GstBuffer *temp;
+
+ GST_DEBUG_OBJECT (rtpgstdepay, "sub buffer: offset %u, size %u", offset,
+ avail);
+
+ temp =
+ gst_buffer_copy_region (outbuf, GST_BUFFER_COPY_ALL, offset, avail);
+
+ gst_buffer_unref (outbuf);
+ outbuf = temp;
+ }
+
+ /* see what caps we need */
+ if (CV != rtpgstdepay->current_CV) {
+ /* we need to switch caps, check if we have the caps */
+ if ((outcaps = rtpgstdepay->CV_cache[CV]) == NULL)
+ goto missing_caps;
+
+ GST_DEBUG_OBJECT (rtpgstdepay,
+ "need caps switch from %u to %u, %" GST_PTR_FORMAT,
+ rtpgstdepay->current_CV, CV, outcaps);
+
+ /* and set caps */
+ if (gst_pad_set_caps (depayload->srcpad, outcaps))
+ rtpgstdepay->current_CV = CV;
+ }
+
+ if (payload[0] & 0x8)
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+ } else {
+ gst_buffer_unref (outbuf);
+ outbuf = NULL;
+ }
+ }
+ gst_rtp_buffer_unmap (&rtp);
+
+ return outbuf;
+
+ /* ERRORS */
+empty_packet:
+ {
+ GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE,
+ ("Empty Payload."), (NULL));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+wrong_frag:
+ {
+ gst_adapter_clear (rtpgstdepay->adapter);
+ gst_rtp_buffer_unmap (&rtp);
+ GST_LOG_OBJECT (rtpgstdepay, "wrong fragment, skipping");
+ return NULL;
+ }
+no_caps:
+ {
+ GST_WARNING_OBJECT (rtpgstdepay, "failed to parse caps");
+ gst_buffer_unref (outbuf);
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+no_event:
+ {
+ GST_WARNING_OBJECT (rtpgstdepay, "failed to parse event");
+ gst_buffer_unref (outbuf);
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+missing_caps:
+ {
+ GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE,
+ ("Missing caps %u.", CV), (NULL));
+ gst_buffer_unref (outbuf);
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+}
+
+static gboolean
+gst_rtp_gst_depay_handle_event (GstRTPBaseDepayload * depay, GstEvent * event)
+{
+ GstRtpGSTDepay *rtpgstdepay;
+
+ rtpgstdepay = GST_RTP_GST_DEPAY (depay);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_STOP:
+ gst_rtp_gst_depay_reset (rtpgstdepay, FALSE);
+ break;
+ default:
+ break;
+ }
+
+ return
+ GST_RTP_BASE_DEPAYLOAD_CLASS (parent_class)->handle_event (depay, event);
+}
+
+
+static GstStateChangeReturn
+gst_rtp_gst_depay_change_state (GstElement * element, GstStateChange transition)
+{
+ GstRtpGSTDepay *rtpgstdepay;
+ GstStateChangeReturn ret;
+
+ rtpgstdepay = GST_RTP_GST_DEPAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_rtp_gst_depay_reset (rtpgstdepay, TRUE);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_rtp_gst_depay_reset (rtpgstdepay, TRUE);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+
+gboolean
+gst_rtp_gst_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpgstdepay",
+ GST_RANK_MARGINAL, GST_TYPE_RTP_GST_DEPAY);
+}
diff --git a/gst/rtp/gstrtpgstdepay.h b/gst/rtp/gstrtpgstdepay.h
new file mode 100755
index 0000000..4b8f2c6
--- /dev/null
+++ b/gst/rtp/gstrtpgstdepay.h
@@ -0,0 +1,66 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_GST_DEPAY_H__
+#define __GST_RTP_GST_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_GST_DEPAY \
+ (gst_rtp_gst_depay_get_type())
+#define GST_RTP_GST_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_GST_DEPAY,GstRtpGSTDepay))
+#define GST_RTP_GST_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_GST_DEPAY,GstRtpGSTDepayClass))
+#define GST_IS_RTP_GST_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_GST_DEPAY))
+#define GST_IS_RTP_GST_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_GST_DEPAY))
+
+typedef struct _GstRtpGSTDepay GstRtpGSTDepay;
+typedef struct _GstRtpGSTDepayClass GstRtpGSTDepayClass;
+
+struct _GstRtpGSTDepay
+{
+ GstRTPBaseDepayload depayload;
+
+ GstAdapter *adapter;
+ guint current_CV;
+ GstCaps *CV_cache[8];
+
+ GstTagList *tags;
+ gchar *stream_id;
+};
+
+struct _GstRtpGSTDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_gst_depay_get_type (void);
+
+gboolean gst_rtp_gst_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_GST_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpgstpay.c b/gst/rtp/gstrtpgstpay.c
new file mode 100755
index 0000000..6167008
--- /dev/null
+++ b/gst/rtp/gstrtpgstpay.c
@@ -0,0 +1,661 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpgstpay.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_rtp_pay_debug);
+#define GST_CAT_DEFAULT gst_rtp_pay_debug
+
+/*
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |C| CV |D|0|0|0| ETYPE | MBZ |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Frag_offset |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * C: caps inlined flag
+ * When C set, first part of payload contains caps definition. Caps definition
+ * starts with variable-length length prefix and then a string of that length.
+ * the length is encoded in big endian 7 bit chunks, the top 1 bit of a byte
+ * is the continuation marker and the 7 next bits the data. A continuation
+ * marker of 1 means that the next byte contains more data.
+ *
+ * CV: caps version, 0 = caps from SDP, 1 - 7 inlined caps
+ * D: delta unit buffer
+ * ETYPE: type of event. Payload contains the event, prefixed with a
+ * variable length field.
+ * 0 = NO event
+ * 1 = GST_EVENT_TAG
+ * 2 = GST_EVENT_CUSTOM_DOWNSTREAM
+ * 3 = GST_EVENT_CUSTOM_BOTH
+ * 4 = GST_EVENT_STREAM_START
+ */
+
+static GstStaticPadTemplate gst_rtp_gst_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate gst_rtp_gst_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"application\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) 90000, " "encoding-name = (string) \"X-GST\"")
+ );
+
+enum
+{
+ PROP_0,
+ PROP_CONFIG_INTERVAL
+};
+
+#define DEFAULT_CONFIG_INTERVAL 0
+
+static void gst_rtp_gst_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_rtp_gst_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_rtp_gst_pay_finalize (GObject * obj);
+static GstStateChangeReturn gst_rtp_gst_pay_change_state (GstElement * element,
+ GstStateChange transition);
+
+static gboolean gst_rtp_gst_pay_setcaps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+static GstFlowReturn gst_rtp_gst_pay_handle_buffer (GstRTPBasePayload * payload,
+ GstBuffer * buffer);
+static gboolean gst_rtp_gst_pay_sink_event (GstRTPBasePayload * payload,
+ GstEvent * event);
+
+#define gst_rtp_gst_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpGSTPay, gst_rtp_gst_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_gst_pay_class_init (GstRtpGSTPayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gobject_class->set_property = gst_rtp_gst_pay_set_property;
+ gobject_class->get_property = gst_rtp_gst_pay_get_property;
+ gobject_class->finalize = gst_rtp_gst_pay_finalize;
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_CONFIG_INTERVAL,
+ g_param_spec_uint ("config-interval",
+ "Caps/Tags Send Interval",
+ "Interval for sending caps and TAG events in seconds (0 = disabled)",
+ 0, 3600, DEFAULT_CONFIG_INTERVAL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+ );
+
+ gstelement_class->change_state = gst_rtp_gst_pay_change_state;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_gst_pay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_gst_pay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP GStreamer payloader", "Codec/Payloader/Network/RTP",
+ "Payload GStreamer buffers as RTP packets",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_gst_pay_setcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_gst_pay_handle_buffer;
+ gstrtpbasepayload_class->sink_event = gst_rtp_gst_pay_sink_event;
+
+ GST_DEBUG_CATEGORY_INIT (gst_rtp_pay_debug, "rtpgstpay", 0,
+ "rtpgstpay element");
+}
+
+static void
+gst_rtp_gst_pay_init (GstRtpGSTPay * rtpgstpay)
+{
+ rtpgstpay->adapter = gst_adapter_new ();
+ rtpgstpay->pending_buffers = NULL;
+ gst_rtp_base_payload_set_options (GST_RTP_BASE_PAYLOAD (rtpgstpay),
+ "application", TRUE, "X-GST", 90000);
+ rtpgstpay->last_config = GST_CLOCK_TIME_NONE;
+ rtpgstpay->taglist = NULL;
+ rtpgstpay->config_interval = DEFAULT_CONFIG_INTERVAL;
+}
+
+static void
+gst_rtp_gst_pay_reset (GstRtpGSTPay * rtpgstpay, gboolean full)
+{
+ rtpgstpay->last_config = GST_CLOCK_TIME_NONE;
+ gst_adapter_clear (rtpgstpay->adapter);
+ rtpgstpay->flags &= 0x70;
+ rtpgstpay->etype = 0;
+ if (rtpgstpay->pending_buffers)
+ g_list_free_full (rtpgstpay->pending_buffers,
+ (GDestroyNotify) gst_buffer_list_unref);
+ rtpgstpay->pending_buffers = NULL;
+ if (full) {
+ if (rtpgstpay->taglist)
+ gst_tag_list_unref (rtpgstpay->taglist);
+ rtpgstpay->taglist = NULL;
+ if (rtpgstpay->stream_id)
+ g_free (rtpgstpay->stream_id);
+ rtpgstpay->stream_id = NULL;
+ rtpgstpay->current_CV = 0;
+ rtpgstpay->next_CV = 0;
+ }
+}
+
+static void
+gst_rtp_gst_pay_finalize (GObject * obj)
+{
+ GstRtpGSTPay *rtpgstpay;
+
+ rtpgstpay = GST_RTP_GST_PAY (obj);
+
+ gst_rtp_gst_pay_reset (rtpgstpay, TRUE);
+
+ g_object_unref (rtpgstpay->adapter);
+
+ G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+gst_rtp_gst_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstRtpGSTPay *rtpgstpay;
+
+ rtpgstpay = GST_RTP_GST_PAY (object);
+
+ switch (prop_id) {
+ case PROP_CONFIG_INTERVAL:
+ rtpgstpay->config_interval = g_value_get_uint (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_rtp_gst_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstRtpGSTPay *rtpgstpay;
+
+ rtpgstpay = GST_RTP_GST_PAY (object);
+
+ switch (prop_id) {
+ case PROP_CONFIG_INTERVAL:
+ g_value_set_uint (value, rtpgstpay->config_interval);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GstStateChangeReturn
+gst_rtp_gst_pay_change_state (GstElement * element, GstStateChange transition)
+{
+ GstRtpGSTPay *rtpgstpay;
+ GstStateChangeReturn ret;
+
+ rtpgstpay = GST_RTP_GST_PAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_rtp_gst_pay_reset (rtpgstpay, TRUE);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_rtp_gst_pay_reset (rtpgstpay, TRUE);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+#define RTP_HEADER_LEN 12
+
+static gboolean
+gst_rtp_gst_pay_create_from_adapter (GstRtpGSTPay * rtpgstpay,
+ GstClockTime timestamp)
+{
+ guint avail, mtu;
+ guint frag_offset;
+ GstBufferList *list;
+
+ avail = gst_adapter_available (rtpgstpay->adapter);
+ if (avail == 0)
+ return FALSE;
+
+ mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpgstpay);
+
+ list = gst_buffer_list_new_sized ((avail / (mtu - (RTP_HEADER_LEN + 8))) + 1);
+ frag_offset = 0;
+
+ while (avail) {
+ guint towrite;
+ guint8 *payload;
+ guint payload_len;
+ guint packet_len;
+ GstBuffer *outbuf;
+ GstRTPBuffer rtp = { NULL };
+ GstBuffer *paybuf;
+
+
+ /* this will be the total lenght of the packet */
+ packet_len = gst_rtp_buffer_calc_packet_len (8 + avail, 0, 0);
+
+ /* fill one MTU or all available bytes */
+ towrite = MIN (packet_len, mtu);
+
+ /* this is the payload length */
+ payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
+
+ /* create buffer to hold the header */
+ outbuf = gst_rtp_buffer_new_allocate (8, 0, 0);
+
+ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+ payload = gst_rtp_buffer_get_payload (&rtp);
+
+ GST_DEBUG_OBJECT (rtpgstpay, "new packet len %u, frag %u", packet_len,
+ frag_offset);
+
+ /*
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |C| CV |D|0|0|0| ETYPE | MBZ |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Frag_offset |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ payload[0] = rtpgstpay->flags;
+ payload[1] = rtpgstpay->etype;
+ payload[2] = payload[3] = 0;
+ payload[4] = frag_offset >> 24;
+ payload[5] = frag_offset >> 16;
+ payload[6] = frag_offset >> 8;
+ payload[7] = frag_offset & 0xff;
+
+ payload += 8;
+ payload_len -= 8;
+
+ frag_offset += payload_len;
+ avail -= payload_len;
+
+ if (avail == 0)
+ gst_rtp_buffer_set_marker (&rtp, TRUE);
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ /* create a new buf to hold the payload */
+ GST_DEBUG_OBJECT (rtpgstpay, "take %u bytes from adapter", payload_len);
+ paybuf = gst_adapter_take_buffer_fast (rtpgstpay->adapter, payload_len);
+
+ /* create a new group to hold the rtp header and the payload */
+ gst_buffer_append (outbuf, paybuf);
+
+ GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
+
+ /* and add to list */
+ gst_buffer_list_insert (list, -1, outbuf);
+ }
+
+ rtpgstpay->flags &= 0x70;
+ rtpgstpay->etype = 0;
+ rtpgstpay->pending_buffers = g_list_append (rtpgstpay->pending_buffers, list);
+
+ return TRUE;
+}
+
+static GstFlowReturn
+gst_rtp_gst_pay_flush (GstRtpGSTPay * rtpgstpay, GstClockTime timestamp)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ GList *iter;
+
+ gst_rtp_gst_pay_create_from_adapter (rtpgstpay, timestamp);
+
+ iter = rtpgstpay->pending_buffers;
+ while (iter) {
+ GstBufferList *list = iter->data;
+
+ rtpgstpay->pending_buffers = iter =
+ g_list_delete_link (rtpgstpay->pending_buffers, iter);
+
+ /* push the whole buffer list at once */
+ ret = gst_rtp_base_payload_push_list (GST_RTP_BASE_PAYLOAD (rtpgstpay),
+ list);
+ if (ret != GST_FLOW_OK)
+ break;
+ }
+
+ return ret;
+}
+
+static GstBuffer *
+make_data_buffer (GstRtpGSTPay * rtpgstpay, gchar * data, guint size)
+{
+ guint plen;
+ guint8 *ptr;
+ GstBuffer *outbuf;
+ GstMapInfo map;
+
+ /* calculate length */
+ plen = 1;
+ while (size >> (7 * plen))
+ plen++;
+
+ outbuf = gst_buffer_new_allocate (NULL, plen + size, NULL);
+
+ gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+ ptr = map.data;
+
+ /* write length */
+ while (plen) {
+ plen--;
+ *ptr++ = ((plen > 0) ? 0x80 : 0) | ((size >> (7 * plen)) & 0x7f);
+ }
+ /* copy data */
+ memcpy (ptr, data, size);
+ gst_buffer_unmap (outbuf, &map);
+
+ return outbuf;
+}
+
+static void
+gst_rtp_gst_pay_send_caps (GstRtpGSTPay * rtpgstpay, guint8 cv, GstCaps * caps)
+{
+ gchar *capsstr;
+ guint capslen;
+ GstBuffer *outbuf;
+
+ if (rtpgstpay->flags & (1 << 7))
+ return;
+
+ capsstr = gst_caps_to_string (caps);
+ capslen = strlen (capsstr);
+ /* for 0 byte */
+ capslen++;
+
+ GST_DEBUG_OBJECT (rtpgstpay, "sending caps=%s", capsstr);
+
+ /* make a data buffer of it */
+ outbuf = make_data_buffer (rtpgstpay, capsstr, capslen);
+ g_free (capsstr);
+
+ /* store in adapter, we don't flush yet, buffer might follow */
+ rtpgstpay->flags = (1 << 7) | (cv << 4);
+ gst_adapter_push (rtpgstpay->adapter, outbuf);
+}
+
+static gboolean
+gst_rtp_gst_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ GstRtpGSTPay *rtpgstpay;
+ gboolean res;
+ gchar *capsstr, *capsenc, *capsver;
+ guint capslen;
+
+ rtpgstpay = GST_RTP_GST_PAY (payload);
+
+ capsstr = gst_caps_to_string (caps);
+ capslen = strlen (capsstr);
+
+ /* encode without 0 byte */
+ capsenc = g_base64_encode ((guchar *) capsstr, capslen);
+ GST_DEBUG_OBJECT (payload, "caps=%s, caps(base64)=%s", capsstr, capsenc);
+ g_free (capsstr);
+
+ /* Send the new caps */
+ rtpgstpay->current_CV = rtpgstpay->next_CV;
+ rtpgstpay->next_CV = (rtpgstpay->next_CV + 1) & 0x7;
+ gst_rtp_gst_pay_send_caps (rtpgstpay, rtpgstpay->current_CV, caps);
+
+ /* make caps for SDP */
+ capsver = g_strdup_printf ("%d", rtpgstpay->current_CV);
+ res =
+ gst_rtp_base_payload_set_outcaps (payload, "caps", G_TYPE_STRING, capsenc,
+ "capsversion", G_TYPE_STRING, capsver, NULL);
+ g_free (capsenc);
+ g_free (capsver);
+
+ return res;
+}
+
+static void
+gst_rtp_gst_pay_send_event (GstRtpGSTPay * rtpgstpay, guint etype,
+ GstEvent * event)
+{
+ const GstStructure *s;
+ gchar *estr;
+ guint elen;
+ GstBuffer *outbuf;
+
+ /* Create the standalone caps packet if an inlined caps was pending */
+ gst_rtp_gst_pay_create_from_adapter (rtpgstpay, GST_CLOCK_TIME_NONE);
+
+ s = gst_event_get_structure (event);
+
+ estr = gst_structure_to_string (s);
+ elen = strlen (estr);
+ /* for 0 byte */
+ elen++;
+ outbuf = make_data_buffer (rtpgstpay, estr, elen);
+ GST_DEBUG_OBJECT (rtpgstpay, "sending event=%s", estr);
+ g_free (estr);
+
+ rtpgstpay->etype = etype;
+ gst_adapter_push (rtpgstpay->adapter, outbuf);
+ /* Create the event packet now to avoid conflict with data/caps packets */
+ gst_rtp_gst_pay_create_from_adapter (rtpgstpay, GST_CLOCK_TIME_NONE);
+}
+
+static gboolean
+gst_rtp_gst_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+ gboolean ret;
+ GstRtpGSTPay *rtpgstpay;
+ guint etype = 0;
+
+ rtpgstpay = GST_RTP_GST_PAY (payload);
+
+ ret =
+ GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload,
+ gst_event_ref (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_STOP:
+ gst_rtp_gst_pay_reset (rtpgstpay, FALSE);
+ break;
+ case GST_EVENT_TAG:{
+ GstTagList *tags;
+
+ gst_event_parse_tag (event, &tags);
+
+ if (gst_tag_list_get_scope (tags) == GST_TAG_SCOPE_STREAM) {
+ GstTagList *old;
+
+ GST_DEBUG_OBJECT (rtpgstpay, "storing stream tags %" GST_PTR_FORMAT,
+ tags);
+ if ((old = rtpgstpay->taglist))
+ gst_tag_list_unref (old);
+ rtpgstpay->taglist = gst_tag_list_ref (tags);
+ }
+ etype = 1;
+ break;
+ }
+ case GST_EVENT_CUSTOM_DOWNSTREAM:
+ etype = 2;
+ break;
+ case GST_EVENT_CUSTOM_BOTH:
+ etype = 3;
+ break;
+ case GST_EVENT_STREAM_START:{
+ const gchar *stream_id = NULL;
+
+ if (rtpgstpay->taglist)
+ gst_tag_list_unref (rtpgstpay->taglist);
+ rtpgstpay->taglist = NULL;
+
+ gst_event_parse_stream_start (event, &stream_id);
+ if (stream_id) {
+ if (rtpgstpay->stream_id)
+ g_free (rtpgstpay->stream_id);
+ rtpgstpay->stream_id = g_strdup (stream_id);
+ }
+ etype = 4;
+ break;
+ }
+ default:
+ GST_LOG_OBJECT (rtpgstpay, "no event for %s",
+ GST_EVENT_TYPE_NAME (event));
+ break;
+ }
+ if (etype) {
+ GST_DEBUG_OBJECT (rtpgstpay, "make event type %d for %s",
+ etype, GST_EVENT_TYPE_NAME (event));
+ gst_rtp_gst_pay_send_event (rtpgstpay, etype, event);
+ /* Do not send stream-start right away since caps/new-segment were not yet
+ sent, so our data would be considered invalid */
+ if (etype != 4) {
+ /* flush the adapter immediately */
+ gst_rtp_gst_pay_flush (rtpgstpay, GST_CLOCK_TIME_NONE);
+ }
+ }
+
+ gst_event_unref (event);
+
+ return ret;
+}
+
+static void
+gst_rtp_gst_pay_send_config (GstRtpGSTPay * rtpgstpay, GstClockTime timestamp)
+{
+ GstPad *pad = GST_RTP_BASE_PAYLOAD_SINKPAD (rtpgstpay);
+ GstCaps *caps = NULL;
+ GstEvent *tag = NULL;
+ GstEvent *stream_start = NULL;
+
+ GST_DEBUG_OBJECT (rtpgstpay, "time to send config");
+ /* Send tags */
+ if (rtpgstpay->taglist && !gst_tag_list_is_empty (rtpgstpay->taglist))
+ tag = gst_event_new_tag (gst_tag_list_ref (rtpgstpay->taglist));
+ if (tag) {
+ /* Send start-stream to clear tags */
+ if (rtpgstpay->stream_id)
+ stream_start = gst_event_new_stream_start (rtpgstpay->stream_id);
+ if (stream_start) {
+ gst_rtp_gst_pay_send_event (rtpgstpay, 4, stream_start);
+ gst_event_unref (stream_start);
+ }
+ gst_rtp_gst_pay_send_event (rtpgstpay, 1, tag);
+ gst_event_unref (tag);
+ }
+ /* send caps */
+ caps = gst_pad_get_current_caps (pad);
+ if (caps) {
+ gst_rtp_gst_pay_send_caps (rtpgstpay, rtpgstpay->current_CV, caps);
+ gst_caps_unref (caps);
+ }
+ rtpgstpay->last_config = timestamp;
+}
+
+static GstFlowReturn
+gst_rtp_gst_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer)
+{
+ GstFlowReturn ret;
+ GstRtpGSTPay *rtpgstpay;
+ GstClockTime timestamp;
+
+ rtpgstpay = GST_RTP_GST_PAY (basepayload);
+
+ timestamp = GST_BUFFER_TIMESTAMP (buffer);
+
+ /* check if we need to send the caps and taglist now */
+ if (rtpgstpay->config_interval > 0) {
+ GST_DEBUG_OBJECT (rtpgstpay,
+ "timestamp %" GST_TIME_FORMAT ", last config %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (timestamp), GST_TIME_ARGS (rtpgstpay->last_config));
+
+ if (timestamp != GST_CLOCK_TIME_NONE &&
+ rtpgstpay->last_config != GST_CLOCK_TIME_NONE) {
+ guint64 diff;
+
+ /* calculate diff between last SPS/PPS in milliseconds */
+ if (timestamp > rtpgstpay->last_config)
+ diff = timestamp - rtpgstpay->last_config;
+ else
+ diff = 0;
+
+ GST_DEBUG_OBJECT (rtpgstpay,
+ "interval since last config %" GST_TIME_FORMAT, GST_TIME_ARGS (diff));
+
+ /* bigger than interval, queue SPS/PPS */
+ if (GST_TIME_AS_SECONDS (diff) >= rtpgstpay->config_interval)
+ gst_rtp_gst_pay_send_config (rtpgstpay, timestamp);
+ } else {
+ gst_rtp_gst_pay_send_config (rtpgstpay, timestamp);
+ }
+ }
+
+ /* caps always from SDP for now */
+ if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT))
+ rtpgstpay->flags |= (1 << 3);
+
+ gst_adapter_push (rtpgstpay->adapter, buffer);
+ ret = gst_rtp_gst_pay_flush (rtpgstpay, timestamp);
+
+ return ret;
+}
+
+gboolean
+gst_rtp_gst_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpgstpay",
+ GST_RANK_NONE, GST_TYPE_RTP_GST_PAY);
+}
diff --git a/gst/rtp/gstrtpgstpay.h b/gst/rtp/gstrtpgstpay.h
new file mode 100755
index 0000000..f3272b2
--- /dev/null
+++ b/gst/rtp/gstrtpgstpay.h
@@ -0,0 +1,72 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_GST_PAY_H__
+#define __GST_RTP_GST_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_GST_PAY \
+ (gst_rtp_gst_pay_get_type())
+#define GST_RTP_GST_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_GST_PAY,GstRtpGSTPay))
+#define GST_RTP_GST_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_GST_PAY,GstRtpGSTPayClass))
+#define GST_IS_RTP_GST_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_GST_PAY))
+#define GST_IS_RTP_GST_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_GST_PAY))
+
+typedef struct _GstRtpGSTPay GstRtpGSTPay;
+typedef struct _GstRtpGSTPayClass GstRtpGSTPayClass;
+
+struct _GstRtpGSTPay
+{
+ GstRTPBasePayload payload;
+
+ GList *pending_buffers; /* GstBufferList */
+ GstAdapter *adapter;
+ guint8 flags;
+ guint8 etype;
+
+ guint8 current_CV; /* CV field of incoming caps*/
+ guint8 next_CV;
+
+ gchar *stream_id;
+ GstTagList *taglist;
+ guint config_interval;
+ GstClockTime last_config;
+};
+
+struct _GstRtpGSTPayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_gst_pay_get_type (void);
+
+gboolean gst_rtp_gst_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_GST_PAY_H__ */
diff --git a/gst/rtp/gstrtph263depay.c b/gst/rtp/gstrtph263depay.c
new file mode 100755
index 0000000..a63b0b1
--- /dev/null
+++ b/gst/rtp/gstrtph263depay.c
@@ -0,0 +1,430 @@
+/* GStreamer
+ *
+ * Copyright 2007 Nokia Corporation
+ * Copyright 2007 Collabora Ltd,
+ * @author: Philippe Kalaf <philippe.kalaf@collabora.co.uk>
+ *
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ * <2007> Edward Hervey <bilboed@bilboed.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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include "gstrtph263depay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtph263depay_debug);
+#define GST_CAT_DEFAULT (rtph263depay_debug)
+
+#define GST_RFC2190A_HEADER_LEN 4
+#define GST_RFC2190B_HEADER_LEN 8
+#define GST_RFC2190C_HEADER_LEN 12
+
+static GstStaticPadTemplate gst_rtp_h263_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-h263, "
+ "variant = (string) \"itu\", " "h263version = (string) \"h263\"")
+ );
+
+static GstStaticPadTemplate gst_rtp_h263_depay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"video\", "
+ "payload = (int) " GST_RTP_PAYLOAD_H263_STRING ", "
+ "clock-rate = (int) 90000; "
+ /* optional SDP attribute:
+ * "a-framesize = (string) \"1234-1234\", "
+ */
+ "application/x-rtp, "
+ "media = (string) \"video\", "
+ "clock-rate = (int) 90000, " "encoding-name = (string) \"H263\""
+ /* optional SDP attribute:
+ * "a-framesize = (string) \"1234-1234\", "
+ */
+ )
+ );
+
+#define gst_rtp_h263_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpH263Depay, gst_rtp_h263_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_h263_depay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_h263_depay_change_state (GstElement *
+ element, GstStateChange transition);
+
+static GstBuffer *gst_rtp_h263_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+gboolean gst_rtp_h263_depay_setcaps (GstRTPBaseDepayload * filter,
+ GstCaps * caps);
+
+static void
+gst_rtp_h263_depay_class_init (GstRtpH263DepayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ GST_DEBUG_CATEGORY_INIT (rtph263depay_debug, "rtph263depay", 0,
+ "H263 Video RTP Depayloader");
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_h263_depay_finalize;
+
+ gstelement_class->change_state = gst_rtp_h263_depay_change_state;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_h263_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_h263_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP H263 depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts H263 video from RTP packets (RFC 2190)",
+ "Philippe Kalaf <philippe.kalaf@collabora.co.uk>, "
+ "Edward Hervey <bilboed@bilboed.com>");
+
+ gstrtpbasedepayload_class->process = gst_rtp_h263_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_h263_depay_setcaps;
+}
+
+static void
+gst_rtp_h263_depay_init (GstRtpH263Depay * rtph263depay)
+{
+ rtph263depay->adapter = gst_adapter_new ();
+
+ rtph263depay->offset = 0;
+ rtph263depay->leftover = 0;
+}
+
+static void
+gst_rtp_h263_depay_finalize (GObject * object)
+{
+ GstRtpH263Depay *rtph263depay;
+
+ rtph263depay = GST_RTP_H263_DEPAY (object);
+
+ g_object_unref (rtph263depay->adapter);
+ rtph263depay->adapter = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rtp_h263_parse_framesize (GstRTPBaseDepayload * filter,
+ const gchar * media_attr, GstCaps * srccaps)
+{
+ gchar *dimension, *endptr;
+ gint width, height;
+ GstStructure *d;
+
+ width = g_ascii_strtoull (media_attr, &endptr, 10);
+ if (width <= 0) {
+ GST_ERROR_OBJECT (filter,
+ "Framesize media attribute width out of valid range");
+ return FALSE;
+ } else if (*endptr != '-') {
+ GST_ERROR_OBJECT (filter,
+ "Framesize media attribute has invalid dimension separator");
+ return FALSE;
+ }
+
+ dimension = endptr + 1;
+ height = g_ascii_strtoull (dimension, &endptr, 10);
+ if (height <= 0) {
+ GST_ERROR_OBJECT (filter,
+ "Framesize media attribute height out of valid range");
+ return FALSE;
+ } else if (*endptr != '\0') {
+ GST_ERROR_OBJECT (filter,
+ "Framesize media attribute unexpectedly has trailing characters");
+ return FALSE;
+ }
+
+ d = gst_caps_get_structure (srccaps, 0);
+ gst_structure_set (d, "width", G_TYPE_INT, width, "height", G_TYPE_INT,
+ height, NULL);
+
+ return TRUE;
+}
+
+gboolean
+gst_rtp_h263_depay_setcaps (GstRTPBaseDepayload * filter, GstCaps * caps)
+{
+ GstCaps *srccaps;
+ GstStructure *structure = gst_caps_get_structure (caps, 0);
+ gint clock_rate;
+ const gchar *framesize;
+
+ srccaps = gst_caps_new_simple ("video/x-h263",
+ "variant", G_TYPE_STRING, "itu",
+ "h263version", G_TYPE_STRING, "h263", NULL);
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 90000; /* default */
+ filter->clock_rate = clock_rate;
+
+ framesize = gst_structure_get_string (structure, "a-framesize");
+ if (framesize != NULL) {
+ if (!gst_rtp_h263_parse_framesize (filter, framesize, srccaps)) {
+ return FALSE;
+ }
+ }
+
+ gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (filter), srccaps);
+ gst_caps_unref (srccaps);
+
+ return TRUE;
+}
+
+static GstBuffer *
+gst_rtp_h263_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpH263Depay *rtph263depay;
+ GstBuffer *outbuf;
+ gint payload_len;
+ guint8 *payload;
+ guint header_len;
+ guint SBIT, EBIT;
+ gboolean F, P, M;
+ gboolean I;
+ GstRTPBuffer rtp = { NULL };
+
+ rtph263depay = GST_RTP_H263_DEPAY (depayload);
+
+ /* flush remaining data on discont */
+ if (GST_BUFFER_IS_DISCONT (buf)) {
+ GST_LOG_OBJECT (depayload, "Discont buffer, flushing adapter");
+ gst_adapter_clear (rtph263depay->adapter);
+ rtph263depay->offset = 0;
+ rtph263depay->leftover = 0;
+ rtph263depay->start = FALSE;
+ }
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+ payload = gst_rtp_buffer_get_payload (&rtp);
+
+ M = gst_rtp_buffer_get_marker (&rtp);
+
+ /* Let's see what mode we are using */
+ F = (payload[0] & 0x80) == 0x80;
+ P = (payload[0] & 0x40) == 0x40;
+
+ /* Bit shifting */
+ SBIT = (payload[0] & 0x38) >> 3;
+ EBIT = (payload[0] & 0x07);
+
+ /* Figure out header length and I-flag */
+ if (F == 0) {
+ /* F == 0 and P == 0 or 1
+ * mode A */
+ header_len = GST_RFC2190A_HEADER_LEN;
+ GST_LOG ("Mode A");
+
+ /* 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |F|P|SBIT |EBIT | SRC |I|U|S|A|R |DBQ| TRB | TR |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ I = (payload[1] & 0x10) == 0x10;
+ } else {
+ if (P == 0) {
+ /* F == 1 and P == 0
+ * mode B */
+ header_len = GST_RFC2190B_HEADER_LEN;
+ GST_LOG ("Mode B");
+
+ /* 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |F|P|SBIT |EBIT | SRC | QUANT | GOBN | MBA |R |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |I|U|S|A| HMV1 | VMV1 | HMV2 | VMV2 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ I = (payload[4] & 0x80) == 0x80;
+ } else {
+ /* F == 1 and P == 1
+ * mode C */
+ header_len = GST_RFC2190C_HEADER_LEN;
+ GST_LOG ("Mode C");
+
+ /* 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |F|P|SBIT |EBIT | SRC | QUANT | GOBN | MBA |R |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |I|U|S|A| HMV1 | VMV1 | HMV2 | VMV2 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | RR |DBQ| TRB | TR |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ I = (payload[4] & 0x80) == 0x80;
+ }
+ }
+
+ GST_LOG ("F/P/M/I : %d/%d/%d/%d", F, P, M, I);
+ GST_LOG ("SBIT : %d , EBIT : %d", SBIT, EBIT);
+ GST_LOG ("payload_len : %d, header_len : %d , leftover : 0x%x",
+ payload_len, header_len, rtph263depay->leftover);
+
+ /* skip header */
+ payload += header_len;
+ payload_len -= header_len;
+
+ if (!rtph263depay->start) {
+ /* do not skip this fragment if it is a Mode A with picture start code */
+ if (!F && payload_len > 4 && (GST_READ_UINT32_BE (payload) >> 10 == 0x20)) {
+ GST_DEBUG ("Mode A with PSC => frame start");
+ rtph263depay->start = TRUE;
+ if ((! !(payload[4] & 0x02)) != I) {
+ GST_DEBUG ("Wrong Picture Coding Type Flag in rtp header");
+ I = !I;
+ }
+ rtph263depay->psc_I = I;
+ } else {
+ GST_DEBUG ("no frame start yet, skipping payload");
+ goto skip;
+ }
+ }
+
+ /* only trust I info from Mode A starting packet
+ * from buggy payloaders or hw */
+ I = rtph263depay->psc_I;
+
+ if (SBIT) {
+ /* take the leftover and merge it at the beginning, FIXME make the buffer
+ * data writable. */
+ GST_LOG ("payload[0] : 0x%x", payload[0]);
+ payload[0] &= 0xFF >> SBIT;
+ GST_LOG ("payload[0] : 0x%x", payload[0]);
+ payload[0] |= rtph263depay->leftover;
+ GST_LOG ("payload[0] : 0x%x", payload[0]);
+ rtph263depay->leftover = 0;
+ rtph263depay->offset = 0;
+ }
+
+ if (!EBIT) {
+ GstBuffer *tmp;
+
+ /* Take the entire buffer */
+ tmp = gst_rtp_buffer_get_payload_subbuffer (&rtp, header_len, payload_len);
+ gst_adapter_push (rtph263depay->adapter, tmp);
+ } else {
+ GstBuffer *tmp;
+
+ /* Take the entire buffer except for the last byte */
+ tmp = gst_rtp_buffer_get_payload_subbuffer (&rtp, header_len,
+ payload_len - 1);
+ gst_adapter_push (rtph263depay->adapter, tmp);
+
+ /* Put the last byte into the leftover */
+ GST_DEBUG ("payload[payload_len - 1] : 0x%x", payload[payload_len - 1]);
+ GST_DEBUG ("mask : 0x%x", 0xFF << EBIT);
+ rtph263depay->leftover = (payload[payload_len - 1] >> EBIT) << EBIT;
+ rtph263depay->offset = 1;
+ GST_DEBUG ("leftover : 0x%x", rtph263depay->leftover);
+ }
+
+skip:
+ if (M) {
+ if (rtph263depay->start) {
+ /* frame is completed */
+ guint avail;
+
+ if (rtph263depay->offset) {
+ /* push in the leftover */
+ GstBuffer *buf = gst_buffer_new_and_alloc (1);
+
+ GST_DEBUG ("Pushing leftover in adapter");
+ gst_buffer_fill (buf, 0, &rtph263depay->leftover, 1);
+ gst_adapter_push (rtph263depay->adapter, buf);
+ }
+
+ avail = gst_adapter_available (rtph263depay->adapter);
+ outbuf = gst_adapter_take_buffer (rtph263depay->adapter, avail);
+
+ if (I)
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+
+ GST_DEBUG ("Pushing out a buffer of %d bytes", avail);
+
+ gst_rtp_base_depayload_push (depayload, outbuf);
+ rtph263depay->offset = 0;
+ rtph263depay->leftover = 0;
+ rtph263depay->start = FALSE;
+ } else {
+ rtph263depay->start = TRUE;
+ }
+ }
+ gst_rtp_buffer_unmap (&rtp);
+
+ return NULL;
+}
+
+static GstStateChangeReturn
+gst_rtp_h263_depay_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstRtpH263Depay *rtph263depay;
+ GstStateChangeReturn ret;
+
+ rtph263depay = GST_RTP_H263_DEPAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_adapter_clear (rtph263depay->adapter);
+ rtph263depay->start = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+gboolean
+gst_rtp_h263_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtph263depay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_H263_DEPAY);
+}
diff --git a/gst/rtp/gstrtph263depay.h b/gst/rtp/gstrtph263depay.h
new file mode 100755
index 0000000..2d9ca55
--- /dev/null
+++ b/gst/rtp/gstrtph263depay.h
@@ -0,0 +1,66 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_H263_DEPAY_H__
+#define __GST_RTP_H263_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_H263_DEPAY \
+ (gst_rtp_h263_depay_get_type())
+#define GST_RTP_H263_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_H263_DEPAY,GstRtpH263Depay))
+#define GST_RTP_H263_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_H263_DEPAY,GstRtpH263DepayClass))
+#define GST_IS_RTP_H263_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_H263_DEPAY))
+#define GST_IS_RTP_H263_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_H263_DEPAY))
+
+typedef struct _GstRtpH263Depay GstRtpH263Depay;
+typedef struct _GstRtpH263DepayClass GstRtpH263DepayClass;
+
+struct _GstRtpH263Depay
+{
+ GstRTPBaseDepayload depayload;
+
+ guint8 offset; /* offset to apply to next payload */
+ guint8 leftover; /* leftover from previous payload (if offset != 0) */
+ gboolean psc_I; /* Picture-Coding-Type == I from Picture Start Code packet */
+ GstAdapter *adapter;
+ gboolean start;
+};
+
+struct _GstRtpH263DepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_h263_depay_get_type (void);
+
+gboolean gst_rtp_h263_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_H263_DEPAY_H__ */
+
diff --git a/gst/rtp/gstrtph263pay.c b/gst/rtp/gstrtph263pay.c
new file mode 100755
index 0000000..0b7d24e
--- /dev/null
+++ b/gst/rtp/gstrtph263pay.c
@@ -0,0 +1,1838 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C) <2008> Dejan Sakelsak <dejan.sakelsak@marand.si>
+ * Copyright (C) <2009> Janin Kolenc <janin.kolenc@marand.si>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <math.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtph263pay.h"
+
+typedef enum
+{
+ GST_H263_FRAME_TYPE_I = 0,
+ GST_H263_FRAME_TYPE_P = 1,
+ GST_H263_FRAME_TYPE_PB = 2
+} GstRtpH263PayFrameType;
+
+typedef enum
+{
+ GST_RTP_H263_PAYLOAD_PICTURE_FORMAT_RES1 = 0,
+ GST_RTP_H263_PAYLOAD_PICTURE_FORMAT_SQCIF = 1,
+ GST_RTP_H263_PAYLOAD_PICTURE_FORMAT_QCIF = 2,
+ GST_RTP_H263_PAYLOAD_PICTURE_FORMAT_CIF = 3,
+ GST_RTP_H263_PAYLOAD_PICTURE_FORMAT_4CIF = 4,
+ GST_RTP_H263_PAYLOAD_PICTURE_FORMAT_16CIF = 5,
+ GST_RTP_H263_PAYLOAD_PICTURE_FORMAT_RES2 = 6,
+ GST_H263_PAYLOAD_PICTURE_FORMAT_PLUS = 7
+} GstRtpH263PayPictureFormat;
+
+static const guint format_props[8][2] = { {254, 254},
+{6, 8},
+{9, 11},
+{18, 22},
+{18, 88},
+{18, 352},
+{254, 254},
+{255, 255}
+};
+
+/*
+ * I-frame MCBPC table: code, mask, nbits, cb, cr, mb type -> 10 = undefined (because we have guint)
+ */
+#define MCBPC_I_LEN 9
+#define MCBPC_I_WID 6
+static const guint32 mcbpc_I[9][6] = {
+ {0x8000, 0x8000, 1, 0, 0, 3},
+ {0x2000, 0xe000, 3, 0, 1, 3},
+ {0x4000, 0xe000, 3, 1, 0, 3},
+ {0x6000, 0xe000, 3, 1, 1, 3},
+ {0x1000, 0xf000, 4, 0, 0, 4},
+ {0x0400, 0xfc00, 6, 0, 1, 4},
+ {0x0800, 0xfc00, 6, 1, 0, 4},
+ {0x0c00, 0xfc00, 6, 1, 1, 4},
+ {0x0080, 0xff80, 9, 10, 10, 10}
+};
+
+/*
+ * P-frame MCBPC table: code, mask, nbits, cb, cr, mb type -> 10 = undefined (because we have guint)
+ */
+#define MCBPC_P_LEN 21
+#define MCBPC_P_WID 6
+static const guint16 mcbpc_P[21][6] = {
+ {0x8000, 0x8000, 1, 0, 0, 0},
+ {0x3000, 0xf000, 4, 0, 1, 0},
+ {0x2000, 0xf000, 4, 1, 0, 0},
+ {0x1400, 0xfc00, 6, 1, 1, 0},
+ {0x6000, 0xe000, 3, 0, 0, 1},
+ {0x0e00, 0xfe00, 7, 0, 1, 1},
+ {0x0c00, 0xfe00, 7, 1, 0, 1},
+ {0x0280, 0xff80, 9, 1, 1, 1},
+ {0x4000, 0xe000, 3, 0, 0, 2},
+ {0x0a00, 0xfe00, 7, 0, 1, 2},
+ {0x0800, 0xfe00, 7, 1, 0, 2},
+ {0x0500, 0xff00, 8, 1, 1, 2},
+ {0x1800, 0xf800, 5, 0, 0, 3},
+ {0x0400, 0xff00, 8, 0, 1, 3},
+ {0x0300, 0xff00, 8, 1, 0, 3},
+ {0x0600, 0xfe00, 7, 1, 1, 3},
+ {0x1000, 0xfc00, 6, 0, 0, 4},
+ {0x0200, 0xff80, 9, 0, 1, 4},
+ {0x0180, 0xff80, 9, 1, 0, 4},
+ {0x0100, 0xff80, 9, 1, 1, 4},
+ {0x0080, 0xff80, 9, 10, 10, 10}
+};
+
+/*
+ * I-frame CBPY (code, mask, nbits, Y0, Y1, Y2, Y3)
+ */
+#define CBPY_LEN 16
+#define CBPY_WID 7
+static const guint8 cbpy_I[16][7] = {
+ {0x30, 0xf0, 4, 0, 0, 0, 0},
+ {0x28, 0xf8, 5, 0, 0, 0, 1},
+ {0x20, 0xf8, 5, 0, 0, 1, 0},
+ {0x90, 0xf0, 4, 0, 0, 1, 1},
+ {0x18, 0xf8, 5, 0, 1, 0, 0},
+ {0x70, 0xf0, 4, 0, 1, 0, 1},
+ {0x08, 0xfc, 6, 0, 1, 1, 0},
+ {0xb0, 0xf0, 4, 0, 1, 1, 1},
+ {0x10, 0xf8, 5, 1, 0, 0, 0},
+ {0x0c, 0xfc, 6, 1, 0, 0, 1},
+ {0x50, 0xf0, 4, 1, 0, 1, 0},
+ {0xa0, 0xf0, 4, 1, 0, 1, 1},
+ {0x40, 0xf0, 4, 1, 1, 0, 0},
+ {0x80, 0xf0, 4, 1, 1, 0, 1},
+ {0x60, 0xf0, 4, 1, 1, 1, 0},
+ {0xc0, 0xc0, 2, 1, 1, 1, 1}
+};
+
+/*
+ * P-frame CBPY (code, mask, nbits, Y0, Y1, Y2, Y3)
+ */
+static const guint8 cbpy_P[16][7] = {
+ {0x30, 0xf0, 4, 1, 1, 1, 1},
+ {0x28, 0xf8, 5, 1, 1, 1, 0},
+ {0x20, 0xf8, 5, 1, 1, 0, 1},
+ {0x90, 0xf0, 4, 1, 1, 0, 0},
+ {0x18, 0xf8, 5, 1, 0, 1, 1},
+ {0x70, 0xf0, 4, 1, 0, 1, 0},
+ {0x08, 0xfc, 6, 1, 0, 0, 1},
+ {0xb0, 0xf0, 4, 1, 0, 0, 0},
+ {0x10, 0xf8, 5, 0, 1, 1, 1},
+ {0x0c, 0xfc, 6, 0, 1, 1, 0},
+ {0x50, 0xf0, 4, 0, 1, 0, 1},
+ {0xa0, 0xf0, 4, 0, 1, 0, 0},
+ {0x40, 0xf0, 4, 0, 0, 1, 1},
+ {0x80, 0xf0, 4, 0, 0, 1, 0},
+ {0x60, 0xf0, 4, 0, 0, 0, 1},
+ {0xc0, 0xc0, 2, 0, 0, 0, 0}
+};
+
+/*
+ * Block TCOEF table (code, mask, nbits, LAST, RUN, LEVEL)
+ */
+#define TCOEF_LEN 103
+#define TCOEF_WID 6
+static const guint16 tcoef[103][6] = {
+ {0x8000, 0xc000, 3, 0, 0, 1},
+ {0xf000, 0xf000, 5, 0, 0, 2},
+ {0x5400, 0xfc00, 7, 0, 0, 3},
+ {0x2e00, 0xfe00, 8, 0, 0, 4},
+ {0x1f00, 0xff00, 9, 0, 0, 5},
+ {0x1280, 0xff80, 10, 0, 0, 6},
+ {0x1200, 0xff80, 10, 0, 0, 7},
+ {0x0840, 0xffc0, 11, 0, 0, 8},
+ {0x0800, 0xffc0, 11, 0, 0, 9},
+ {0x00e0, 0xffe0, 12, 0, 0, 10}, //10
+ {0x00c0, 0xffe0, 12, 0, 0, 11},
+ {0x0400, 0xffe0, 12, 0, 0, 12},
+ {0xc000, 0xe000, 4, 0, 1, 1},
+ {0x5000, 0xfc00, 7, 0, 1, 2},
+ {0x1e00, 0xff00, 9, 0, 1, 3},
+ {0x03c0, 0xffc0, 11, 0, 1, 4},
+ {0x0420, 0xffe0, 12, 0, 1, 5},
+ {0x0500, 0xfff0, 13, 0, 1, 6},
+ {0xe000, 0xf000, 5, 0, 2, 1},
+ {0x1d00, 0xff00, 9, 0, 2, 2}, //20
+ {0x0380, 0xffc0, 11, 0, 2, 3},
+ {0x0510, 0xfff0, 13, 0, 2, 4},
+ {0x6800, 0xf800, 6, 0, 3, 1},
+ {0x1180, 0xff80, 10, 0, 3, 2},
+ {0x0340, 0xffc0, 11, 0, 3, 3},
+ {0x6000, 0xf800, 6, 0, 4, 1},
+ {0x1100, 0xff80, 10, 0, 4, 2},
+ {0x0520, 0xfff0, 13, 0, 4, 3},
+ {0x5800, 0xf800, 6, 0, 5, 1},
+ {0x0300, 0xffc0, 11, 0, 5, 2}, // 30
+ {0x0530, 0xfff0, 13, 0, 5, 3},
+ {0x4c00, 0xfc00, 7, 0, 6, 1},
+ {0x02c0, 0xffc0, 11, 0, 6, 2},
+ {0x0540, 0xfff0, 13, 0, 6, 3},
+ {0x4800, 0xfc00, 7, 0, 7, 1},
+ {0x0280, 0xffc0, 11, 0, 7, 2},
+ {0x4400, 0xfc00, 7, 0, 8, 1},
+ {0x0240, 0xffc0, 11, 0, 8, 2},
+ {0x4000, 0xfc00, 7, 0, 9, 1},
+ {0x0200, 0xffc0, 11, 0, 9, 2}, // 40
+ {0x2c00, 0xfe00, 8, 0, 10, 1},
+ {0x0550, 0xfff0, 13, 0, 10, 2},
+ {0x2a00, 0xfe00, 8, 0, 11, 1},
+ {0x2800, 0xfe00, 8, 0, 12, 1},
+ {0x1c00, 0xff00, 9, 0, 13, 1},
+ {0x1b00, 0xff00, 9, 0, 14, 1},
+ {0x1080, 0xff80, 10, 0, 15, 1},
+ {0x1000, 0xff80, 10, 0, 16, 1},
+ {0x0f80, 0xff80, 10, 0, 17, 1},
+ {0x0f00, 0xff80, 10, 0, 18, 1}, // 50
+ {0x0e80, 0xff80, 10, 0, 19, 1},
+ {0x0e00, 0xff80, 10, 0, 20, 1},
+ {0x0d80, 0xff80, 10, 0, 21, 1},
+ {0x0d00, 0xff80, 10, 0, 22, 1},
+ {0x0440, 0xffe0, 12, 0, 23, 1},
+ {0x0460, 0xffe0, 12, 0, 24, 1},
+ {0x0560, 0xfff0, 13, 0, 25, 1},
+ {0x0570, 0xfff0, 13, 0, 26, 1},
+ {0x7000, 0xf000, 5, 1, 0, 1},
+ {0x0c80, 0xff80, 10, 1, 0, 2}, // 60
+ {0x00a0, 0xffe0, 12, 1, 0, 3},
+ {0x3c00, 0xfc00, 7, 1, 1, 1},
+ {0x0080, 0xffe0, 12, 1, 1, 2},
+ {0x3800, 0xfc00, 7, 1, 2, 1},
+ {0x3400, 0xfc00, 7, 1, 3, 1},
+ {0x3000, 0xfc00, 7, 1, 4, 1},
+ {0x2600, 0xfe00, 8, 1, 5, 1},
+ {0x2400, 0xfe00, 8, 1, 6, 1},
+ {0x2200, 0xfe00, 8, 1, 7, 1},
+ {0x2000, 0xfe00, 8, 1, 8, 1}, // 70
+ {0x1a00, 0xff00, 9, 1, 9, 1},
+ {0x1900, 0xff00, 9, 1, 10, 1},
+ {0x1800, 0xff00, 9, 1, 11, 1},
+ {0x1700, 0xff00, 9, 1, 12, 1},
+ {0x1600, 0xff00, 9, 1, 13, 1},
+ {0x1500, 0xff00, 9, 1, 14, 1},
+ {0x1400, 0xff00, 9, 1, 15, 1},
+ {0x1300, 0xff00, 9, 1, 16, 1},
+ {0x0c00, 0xff80, 10, 1, 17, 1},
+ {0x0b80, 0xff80, 10, 1, 18, 1}, // 80
+ {0x0b00, 0xff80, 10, 1, 19, 1},
+ {0x0a80, 0xff80, 10, 1, 20, 1},
+ {0x0a00, 0xff80, 10, 1, 21, 1},
+ {0x0980, 0xff80, 10, 1, 22, 1},
+ {0x0900, 0xff80, 10, 1, 23, 1},
+ {0x0880, 0xff80, 10, 1, 24, 1},
+ {0x01c0, 0xffc0, 11, 1, 25, 1},
+ {0x0180, 0xffc0, 11, 1, 26, 1},
+ {0x0140, 0xffc0, 11, 1, 27, 1},
+ {0x0100, 0xffc0, 11, 1, 28, 1}, // 90
+ {0x0480, 0xffe0, 12, 1, 29, 1},
+ {0x04a0, 0xffe0, 12, 1, 30, 1},
+ {0x04c0, 0xffe0, 12, 1, 31, 1},
+ {0x04e0, 0xffe0, 12, 1, 32, 1},
+ {0x0580, 0xfff0, 13, 1, 33, 1},
+ {0x0590, 0xfff0, 13, 1, 34, 1},
+ {0x05a0, 0xfff0, 13, 1, 35, 1},
+ {0x05b0, 0xfff0, 13, 1, 36, 1},
+ {0x05c0, 0xfff0, 13, 1, 37, 1},
+ {0x05d0, 0xfff0, 13, 1, 38, 1}, // 100
+ {0x05e0, 0xfff0, 13, 1, 39, 1},
+ {0x05f0, 0xfff0, 13, 1, 40, 1},
+ {0x0600, 0xfe00, 7, 0, 0xffff, 0xffff}
+};
+
+/*
+ * Motion vector code table (Code, mask, nbits, vector (halfpixel, two's complement), diff (halfpixel, two's complement))
+ */
+#define MVD_LEN 64
+#define MVD_WID 5
+static const guint16 mvd[64][5] = {
+ {0x0028, 0xfff8, 13, 0x0060, 0x0020},
+ {0x0038, 0xfff8, 13, 0x0061, 0x0021},
+ {0x0050, 0xfff0, 12, 0x0062, 0x0022},
+ {0x0070, 0xfff0, 12, 0x0063, 0x0023},
+ {0x0090, 0xfff0, 12, 0x0064, 0x0024},
+ {0x00b0, 0xfff0, 12, 0x0065, 0x0025},
+ {0x00d0, 0xfff0, 12, 0x0066, 0x0026},
+ {0x00f0, 0xfff0, 12, 0x0067, 0x0027},
+ {0x0120, 0xffe0, 11, 0x0068, 0x0028},
+ {0x0160, 0xffe0, 11, 0x0069, 0x0029},
+ {0x01a0, 0xffe0, 11, 0x006a, 0x002a},
+ {0x01e0, 0xffe0, 11, 0x006b, 0x002b},
+ {0x0220, 0xffe0, 11, 0x006c, 0x002c},
+ {0x0260, 0xffe0, 11, 0x006d, 0x002d},
+ {0x02a0, 0xffe0, 11, 0x006e, 0x002e},
+ {0x02e0, 0xffe0, 11, 0x006f, 0x002f},
+ {0x0320, 0xffe0, 11, 0x0070, 0x0030},
+ {0x0360, 0xffe0, 11, 0x0071, 0x0031},
+ {0x03a0, 0xffe0, 11, 0x0072, 0x0032},
+ {0x03e0, 0xffe0, 11, 0x0073, 0x0033},
+ {0x0420, 0xffe0, 11, 0x0074, 0x0034},
+ {0x0460, 0xffe0, 11, 0x0075, 0x0035},
+ {0x04c0, 0xffc0, 10, 0x0076, 0x0036},
+ {0x0540, 0xffc0, 10, 0x0077, 0x0037},
+ {0x05c0, 0xffc0, 10, 0x0078, 0x0038},
+ {0x0700, 0xff00, 8, 0x0079, 0x0039},
+ {0x0900, 0xff00, 8, 0x007a, 0x003a},
+ {0x0b00, 0xff00, 8, 0x007b, 0x003b},
+ {0x0e00, 0xfe00, 7, 0x007c, 0x003c},
+ {0x1800, 0xf800, 5, 0x007d, 0x003d},
+ {0x3000, 0xf000, 4, 0x007e, 0x003e},
+ {0x6000, 0xe000, 3, 0x007f, 0x003f},
+ {0x8000, 0x8000, 1, 0x0000, 0x0000},
+ {0x4000, 0xe000, 3, 0x0001, 0x0041},
+ {0x2000, 0xf000, 4, 0x0002, 0x0042},
+ {0x1000, 0xf800, 5, 0x0003, 0x0043},
+ {0x0c00, 0xfe00, 7, 0x0004, 0x0044},
+ {0x0a00, 0xff00, 8, 0x0005, 0x0045},
+ {0x0800, 0xff00, 8, 0x0006, 0x0046},
+ {0x0600, 0xff00, 8, 0x0007, 0x0047},
+ {0x0580, 0xffc0, 10, 0x0008, 0x0048},
+ {0x0500, 0xffc0, 10, 0x0009, 0x0049},
+ {0x0480, 0xffc0, 10, 0x000a, 0x004a},
+ {0x0440, 0xffe0, 11, 0x000b, 0x004b},
+ {0x0400, 0xffe0, 11, 0x000c, 0x004c},
+ {0x03c0, 0xffe0, 11, 0x000d, 0x004d},
+ {0x0380, 0xffe0, 11, 0x000e, 0x004e},
+ {0x0340, 0xffe0, 11, 0x000f, 0x004f},
+ {0x0300, 0xffe0, 11, 0x0010, 0x0050},
+ {0x02c0, 0xffe0, 11, 0x0011, 0x0051},
+ {0x0280, 0xffe0, 11, 0x0012, 0x0052},
+ {0x0240, 0xffe0, 11, 0x0013, 0x0053},
+ {0x0200, 0xffe0, 11, 0x0014, 0x0054},
+ {0x01c0, 0xffe0, 11, 0x0015, 0x0055},
+ {0x0180, 0xffe0, 11, 0x0016, 0x0056},
+ {0x0140, 0xffe0, 11, 0x0017, 0x0057},
+ {0x0100, 0xffe0, 11, 0x0018, 0x0058},
+ {0x00e0, 0xfff0, 12, 0x0019, 0x0059},
+ {0x00c0, 0xfff0, 12, 0x001a, 0x005a},
+ {0x00a0, 0xfff0, 12, 0x001b, 0x005b},
+ {0x0080, 0xfff0, 12, 0x001c, 0x005c},
+ {0x0060, 0xfff0, 12, 0x001d, 0x005d},
+ {0x0040, 0xfff0, 12, 0x001e, 0x005e},
+ {0x0030, 0xfff8, 13, 0x001f, 0x005f}
+};
+
+GST_DEBUG_CATEGORY_STATIC (rtph263pay_debug);
+#define GST_CAT_DEFAULT (rtph263pay_debug)
+
+#define GST_RTP_HEADER_LEN 12
+
+enum
+{
+ PROP_0,
+ PROP_MODE_A_ONLY
+};
+
+static GstStaticPadTemplate gst_rtp_h263_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-h263, "
+ "variant = (string) \"itu\", " "h263version = (string) \"h263\"")
+ );
+
+static GstStaticPadTemplate gst_rtp_h263_pay_src_template =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"video\", "
+ "payload = (int) " GST_RTP_PAYLOAD_H263_STRING ", "
+ "clock-rate = (int) 90000, " "encoding-name = (string) \"H263\"; "
+ "application/x-rtp, "
+ "media = (string) \"video\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) 90000, " "encoding-name = (string) \"H263\"")
+ );
+
+static void gst_rtp_h263_pay_finalize (GObject * object);
+
+static gboolean gst_rtp_h263_pay_setcaps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+static void gst_rtp_h263_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_rtp_h263_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static GstFlowReturn gst_rtp_h263_pay_handle_buffer (GstRTPBasePayload *
+ payload, GstBuffer * buffer);
+
+static void gst_rtp_h263_pay_boundry_init (GstRtpH263PayBoundry * boundry,
+ guint8 * start, guint8 * end, guint8 sbit, guint8 ebit);
+static GstRtpH263PayGob *gst_rtp_h263_pay_gob_new (GstRtpH263PayBoundry *
+ boundry, guint gobn);
+static GstRtpH263PayMB *gst_rtp_h263_pay_mb_new (GstRtpH263PayBoundry * boundry,
+ guint mba);
+static GstRtpH263PayPackage *gst_rtp_h263_pay_package_new_empty ();
+static GstRtpH263PayPackage *gst_rtp_h263_pay_package_new (guint8 * start,
+ guint8 * end, guint length, guint8 sbit, guint8 ebit, GstBuffer * outbuf,
+ gboolean marker);
+
+static void gst_rtp_h263_pay_mb_destroy (GstRtpH263PayMB * mb);
+static void gst_rtp_h263_pay_gob_destroy (GstRtpH263PayGob * gob, guint ind);
+static void gst_rtp_h263_pay_context_destroy (GstRtpH263PayContext * context,
+ guint ind);
+static void gst_rtp_h263_pay_package_destroy (GstRtpH263PayPackage * pack);
+
+#define gst_rtp_h263_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpH263Pay, gst_rtp_h263_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_h263_pay_class_init (GstRtpH263PayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_h263_pay_finalize;
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_h263_pay_setcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_h263_pay_handle_buffer;
+ gobject_class->set_property = gst_rtp_h263_pay_set_property;
+ gobject_class->get_property = gst_rtp_h263_pay_get_property;
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_MODE_A_ONLY, g_param_spec_boolean ("modea-only",
+ "Fragment packets in mode A Only",
+ "Disable packetization modes B and C", DEFAULT_MODE_A,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_h263_pay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_h263_pay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP H263 packet payloader", "Codec/Payloader/Network/RTP",
+ "Payload-encodes H263 video in RTP packets (RFC 2190)",
+ "Neil Stratford <neils@vipadia.com>"
+ "Dejan Sakelsak <dejan.sakelsak@marand.si>");
+
+ GST_DEBUG_CATEGORY_INIT (rtph263pay_debug, "rtph263pay", 0,
+ "H263 RTP Payloader");
+}
+
+static void
+gst_rtp_h263_pay_init (GstRtpH263Pay * rtph263pay)
+{
+ rtph263pay->adapter = gst_adapter_new ();
+
+ rtph263pay->prop_payload_mode = DEFAULT_MODE_A;
+}
+
+static void
+gst_rtp_h263_pay_finalize (GObject * object)
+{
+ GstRtpH263Pay *rtph263pay;
+
+ rtph263pay = GST_RTP_H263_PAY (object);
+
+ g_object_unref (rtph263pay->adapter);
+ rtph263pay->adapter = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rtp_h263_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ GstStructure *s = gst_caps_get_structure (caps, 0);
+ gint width, height;
+ gchar *framesize = NULL;
+ gboolean res;
+
+ if (gst_structure_has_field (s, "width") &&
+ gst_structure_has_field (s, "height")) {
+ if (!gst_structure_get_int (s, "width", &width) || width <= 0) {
+ goto invalid_dimension;
+ }
+
+ if (!gst_structure_get_int (s, "height", &height) || height <= 0) {
+ goto invalid_dimension;
+ }
+
+ framesize = g_strdup_printf ("%d-%d", width, height);
+ }
+
+ payload->pt = GST_RTP_PAYLOAD_H263;
+ gst_rtp_base_payload_set_options (payload, "video", TRUE, "H263", 90000);
+
+ if (framesize != NULL) {
+ res = gst_rtp_base_payload_set_outcaps (payload,
+ "a-framesize", G_TYPE_STRING, framesize, NULL);
+ } else {
+ res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+ }
+ g_free (framesize);
+
+ return res;
+
+ /* ERRORS */
+invalid_dimension:
+ {
+ GST_ERROR_OBJECT (payload, "Invalid width/height from caps");
+ return FALSE;
+ }
+}
+
+static void
+gst_rtp_h263_pay_context_destroy (GstRtpH263PayContext * context, guint ind)
+{
+ if (!context)
+ return;
+
+ if (context->gobs) {
+ guint i;
+
+ for (i = 0; i < format_props[ind][0]; i++) {
+ if (context->gobs[i]) {
+ gst_rtp_h263_pay_gob_destroy (context->gobs[i], ind);
+ }
+ }
+
+ g_free (context->gobs);
+ }
+
+ g_free (context);
+}
+
+static void
+gst_rtp_h263_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstRtpH263Pay *rtph263pay;
+
+ rtph263pay = GST_RTP_H263_PAY (object);
+
+ switch (prop_id) {
+ case PROP_MODE_A_ONLY:
+ rtph263pay->prop_payload_mode = g_value_get_boolean (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_rtp_h263_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstRtpH263Pay *rtph263pay;
+
+ rtph263pay = GST_RTP_H263_PAY (object);
+
+ switch (prop_id) {
+ case PROP_MODE_A_ONLY:
+ g_value_set_boolean (value, rtph263pay->prop_payload_mode);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GstRtpH263PayPackage *
+gst_rtp_h263_pay_package_new_empty (void)
+{
+ return (GstRtpH263PayPackage *) g_malloc0 (sizeof (GstRtpH263PayPackage));
+}
+
+static GstRtpH263PayPackage *
+gst_rtp_h263_pay_package_new (guint8 * start, guint8 * end, guint length,
+ guint8 sbit, guint8 ebit, GstBuffer * outbuf, gboolean marker)
+{
+
+ GstRtpH263PayPackage *package;
+
+ package = gst_rtp_h263_pay_package_new_empty ();
+
+ package->payload_start = start;
+ package->payload_end = end;
+ package->payload_len = length;
+ package->sbit = sbit;
+ package->ebit = ebit;
+ package->outbuf = outbuf;
+ package->marker = marker;
+
+ return package;
+}
+
+static void
+gst_rtp_h263_pay_package_destroy (GstRtpH263PayPackage * pack)
+{
+ if (pack)
+ g_free (pack);
+}
+
+static void
+gst_rtp_h263_pay_boundry_init (GstRtpH263PayBoundry * boundry,
+ guint8 * start, guint8 * end, guint8 sbit, guint8 ebit)
+{
+ boundry->start = start;
+ boundry->end = end;
+ boundry->sbit = sbit;
+ boundry->ebit = ebit;
+}
+
+static void
+gst_rtp_h263_pay_splat_header_A (guint8 * header,
+ GstRtpH263PayPackage * package, GstRtpH263PayPic * piclayer)
+{
+
+ GstRtpH263PayAHeader *a_header;
+
+ a_header = (GstRtpH263PayAHeader *) header;
+
+ a_header->f = 0;
+ a_header->p = 0;
+ a_header->sbit = package->sbit;
+ a_header->ebit = package->ebit;
+ a_header->src = GST_H263_PICTURELAYER_PLSRC (piclayer);
+ a_header->i = GST_H263_PICTURELAYER_PLTYPE (piclayer);
+ a_header->u = GST_H263_PICTURELAYER_PLUMV (piclayer);
+ a_header->s = GST_H263_PICTURELAYER_PLSAC (piclayer);
+ a_header->a = GST_H263_PICTURELAYER_PLAP (piclayer);
+ a_header->r1 = 0;
+ a_header->r2 = 0;
+ a_header->dbq = 0;
+ a_header->trb = 0;
+ a_header->tr = 0;
+
+}
+
+static void
+gst_rtp_h263_pay_splat_header_B (guint8 * header,
+ GstRtpH263PayPackage * package, GstRtpH263PayPic * piclayer)
+{
+
+ GstRtpH263PayBHeader *b_header;
+
+ b_header = (GstRtpH263PayBHeader *) header;
+
+ b_header->f = 1;
+ b_header->p = 0;
+ b_header->sbit = package->sbit;
+ b_header->ebit = package->ebit;
+ b_header->src = GST_H263_PICTURELAYER_PLSRC (piclayer);
+ b_header->quant = package->quant;
+ b_header->gobn = package->gobn;
+ b_header->mba1 = package->mba >> 6;
+ b_header->mba2 = package->mba & 0x003f;
+ b_header->r = 0;
+ b_header->i = GST_H263_PICTURELAYER_PLTYPE (piclayer);
+ b_header->u = GST_H263_PICTURELAYER_PLUMV (piclayer);
+ b_header->s = GST_H263_PICTURELAYER_PLSAC (piclayer);
+ b_header->a = GST_H263_PICTURELAYER_PLAP (piclayer);
+
+ b_header->hmv11 = 0;
+ b_header->hmv12 = 0;
+ b_header->vmv11 = 0;
+ b_header->vmv12 = 0;
+ b_header->hmv21 = 0;
+ b_header->hmv22 = 0;
+ b_header->vmv21 = 0;
+
+ if (package->nmvd > 0) {
+ //mvd[0]
+ b_header->hmv11 = (package->mvd[0] & 0x7f) >> 3;
+ b_header->hmv12 = (package->mvd[0] & 0x07);
+ //mvd[1]
+ b_header->vmv11 = (package->mvd[1] & 0x07f) >> 2;
+ b_header->vmv12 = (package->mvd[1] & 0x03);
+
+ if (package->nmvd == 8) {
+ //mvd[4]
+ b_header->hmv21 = (package->mvd[4] & 0x7f) >> 1;
+ b_header->hmv22 = (package->mvd[4] & 0x01);
+ //mvd[5]
+ b_header->vmv21 = (package->mvd[5] & 0x7f);
+ }
+ }
+
+}
+
+static gboolean
+gst_rtp_h263_pay_gobfinder (GstRtpH263Pay * rtph263pay,
+ GstRtpH263PayBoundry * boundry)
+{
+ guint8 *current;
+ guint range;
+ guint i;
+
+ current = boundry->end + 1;
+ range = (rtph263pay->data - current) + rtph263pay->available_data;
+
+
+ GST_DEBUG ("Searching for next GOB, data:%p, len:%u, payload_len:%p,"
+ " current:%p, range:%u", rtph263pay->data, rtph263pay->available_data,
+ boundry->end + 1, current, range);
+
+ /* If we are past the end, stop */
+ if (current >= rtph263pay->data + rtph263pay->available_data)
+ return FALSE;
+
+ for (i = 3; i < range - 3; i++) {
+ if ((current[i] == 0x0) &&
+ (current[i + 1] == 0x0) && (current[i + 2] >> 7 == 0x1)) {
+ GST_LOG ("GOB end found at: %p start: %p len: %u", current + i - 1,
+ boundry->end + 1, (guint) (current + i - boundry->end + 2));
+ gst_rtp_h263_pay_boundry_init (boundry, boundry->end + 1,
+ current + i - 1, 0, 0);
+
+ return TRUE;
+ }
+ }
+
+ GST_DEBUG ("Couldn't find any new GBSC in this frame, range:%u", range);
+
+ gst_rtp_h263_pay_boundry_init (boundry, boundry->end + 1,
+ (guint8 *) (rtph263pay->data + rtph263pay->available_data - 1), 0, 0);
+
+ return TRUE;
+}
+
+static GstRtpH263PayGob *
+gst_rtp_h263_pay_gob_new (GstRtpH263PayBoundry * boundry, guint gobn)
+{
+ GstRtpH263PayGob *gob;
+
+ gob = (GstRtpH263PayGob *) g_malloc0 (sizeof (GstRtpH263PayGob));
+
+ gob->start = boundry->start;
+ gob->end = boundry->end;
+ gob->length = boundry->end - boundry->start + 1;
+ gob->ebit = boundry->ebit;
+ gob->sbit = boundry->sbit;
+ gob->gobn = gobn;
+ gob->quant = 0;
+ gob->macroblocks = NULL;
+ gob->nmacroblocs = 0;
+
+ return gob;
+}
+
+static void
+gst_rtp_h263_pay_gob_destroy (GstRtpH263PayGob * gob, guint ind)
+{
+
+ if (!gob)
+ return;
+
+ if (gob->macroblocks) {
+
+ guint i;
+
+ for (i = 0; i < gob->nmacroblocs; i++) {
+ gst_rtp_h263_pay_mb_destroy (gob->macroblocks[i]);
+ }
+
+ g_free (gob->macroblocks);
+ }
+
+ g_free (gob);
+}
+
+/*
+ * decode MCBPC for I frames and return index in table or -1 if not found
+ */
+static gint
+gst_rtp_h263_pay_decode_mcbpc_I (guint32 value)
+{
+
+ gint i;
+ guint16 code;
+
+ code = value >> 16;
+
+ GST_DEBUG ("value:0x%08x, code:0x%04x", value, code);
+
+ for (i = 0; i < MCBPC_I_LEN; i++) {
+ if ((code & mcbpc_I[i][1]) == mcbpc_I[i][0]) {
+ return i;
+ }
+ }
+
+ GST_WARNING ("Couldn't find code, returning -1");
+
+ return -1;
+}
+
+/*
+ * decode MCBPC for P frames and return index in table or -1 if not found
+ */
+static gint
+gst_rtp_h263_pay_decode_mcbpc_P (guint32 value)
+{
+
+ gint i;
+ guint16 code;
+
+ code = value >> 16;
+
+ GST_DEBUG ("value:0x%08x, code:0x%04x", value, code);
+
+ for (i = 0; i < MCBPC_P_LEN; i++) {
+ if ((code & mcbpc_P[i][1]) == mcbpc_P[i][0]) {
+ return i;
+ }
+ }
+
+ GST_WARNING ("Couldn't find code, returning -1");
+
+ return -1;
+}
+
+/*
+ * decode CBPY and return index in table or -1 if not found
+ */
+static gint
+gst_rtp_h263_pay_decode_cbpy (guint32 value, const guint8 cbpy_table[16][7])
+{
+
+ gint i;
+ guint8 code;
+
+ code = value >> 24;
+
+ GST_DEBUG ("value:0x%08x, code:0x%04x", value, code);
+
+ for (i = 0; i < CBPY_LEN; i++) {
+ if ((code & cbpy_table[i][1]) == cbpy_table[i][0]) {
+ return i;
+ }
+ }
+
+ GST_WARNING ("Couldn't find code, returning -1");
+
+ return -1;
+}
+
+/*
+ * decode MVD and return index in table or -1 if not found
+ */
+static gint
+gst_rtp_h263_pay_decode_mvd (guint32 value)
+{
+
+ gint i;
+ guint16 code;
+
+ code = value >> 16;
+
+ GST_DEBUG ("value:0x%08x, code:0x%04x", value, code);
+
+ for (i = 0; i < MVD_LEN; i++) {
+ if ((code & mvd[i][1]) == mvd[i][0]) {
+ return i;
+ }
+ }
+
+ GST_WARNING ("Couldn't find code, returning -1");
+
+ return -1;
+}
+
+/*
+ * decode TCOEF and return index in table or -1 if not found
+ */
+static gint
+gst_rtp_h263_pay_decode_tcoef (guint32 value)
+{
+
+ gint i;
+ guint16 code;
+
+ code = value >> 16;
+
+ GST_DEBUG ("value:0x%08x, code:0x%04x", value, code);
+
+ for (i = 0; i < TCOEF_LEN; i++) {
+ if ((code & tcoef[i][1]) == tcoef[i][0]) {
+ GST_LOG ("tcoef is %d", i);
+ return i;
+ }
+ }
+
+ GST_WARNING ("Couldn't find code, returning -1");
+
+ return -1;
+}
+
+/*
+ * the 32-bit register is like a window that we move right for "move_bits" to get the next v "data" h263 field
+ * "rest_bits" tells how many bits in the "data" byte address are still not used
+ */
+
+static gint
+gst_rtp_h263_pay_move_window_right (GstRtpH263PayContext * context, guint n,
+ guint rest_bits, guint8 ** orig_data, guint8 ** data_end)
+{
+
+ GST_DEBUG ("Moving window: 0x%08x from: %p for %d bits, rest_bits: %d",
+ context->window, context->win_end, n, rest_bits);
+
+ if (n == 0)
+ return rest_bits;
+
+ while (n != 0 || context->win_end == ((*data_end) + 1)) {
+ //guint8 a = *data;
+ if (rest_bits == 0) {
+ if (n > 8) {
+ context->window = (context->window << 8) | *context->win_end;
+ n -= 8;
+ } else {
+ context->window =
+ (context->window << n) | (*context->win_end >> (8 - n));
+ rest_bits = 8 - n;
+ if (rest_bits == 0)
+ context->win_end++;
+ break;
+ }
+ } else {
+ if (n > rest_bits) {
+ context->window =
+ (context->window << rest_bits) | (*context->
+ win_end & (((guint) pow (2.0, (double) rest_bits)) - 1));
+ n -= rest_bits;
+ rest_bits = 0;
+ } else {
+ context->window =
+ (context->window << n) | ((*context->win_end & (((guint) pow (2.0,
+ (double) rest_bits)) - 1)) >> (rest_bits - n));
+ rest_bits -= n;
+ if (rest_bits == 0)
+ context->win_end++;
+ break;
+ }
+ }
+
+ context->win_end++;
+ }
+
+ *orig_data = context->win_end - 4;
+
+ GST_DEBUG
+ ("Window moved to %p with value: 0x%08x and orig_data: %p rest_bits: %d",
+ context->win_end, context->window, *orig_data, rest_bits);
+ return rest_bits;
+}
+
+/*
+ * Find the start of the next MB (end of the current MB)
+ * returns the number of excess bits and stores the end of the MB in end
+ * data must be placed on first MB byte
+ */
+static GstRtpH263PayMB *
+gst_rtp_h263_pay_B_mbfinder (GstRtpH263PayContext * context,
+ GstRtpH263PayGob * gob, GstRtpH263PayMB * macroblock, guint mba)
+{
+
+ guint mb_type_index;
+ guint cbpy_type_index;
+ guint tcoef_type_index;
+ GstRtpH263PayMB *mac;
+ GstRtpH263PayBoundry boundry;
+
+
+ gst_rtp_h263_pay_boundry_init (&boundry, macroblock->end,
+ macroblock->end, 8 - macroblock->ebit, macroblock->ebit);
+ mac = gst_rtp_h263_pay_mb_new (&boundry, mba);
+
+
+ if (mac->sbit == 8) {
+ mac->start++;
+// mac->end++;
+ mac->sbit = 0;
+ }
+
+ GST_LOG ("current_pos:%p, end:%p, rest_bits:%d, window:%x",
+ mac->start, mac->end, macroblock->ebit, context->window);
+
+ GST_LOG ("Current pos after COD: %p", mac->end);
+
+ if (context->piclayer->ptype_pictype == 0) {
+ //We have an I frame
+ gint i;
+ guint last;
+ guint ind;
+
+ //Step 2 decode MCBPC I
+ mb_type_index = gst_rtp_h263_pay_decode_mcbpc_I (context->window);
+
+ GST_DEBUG ("MCBPC index: %d", mb_type_index);
+ if (mb_type_index == -1) {
+ GST_ERROR ("MB index shouldn't be -1 in window: %08x", context->window);
+ goto beach;
+ }
+
+ mac->ebit =
+ gst_rtp_h263_pay_move_window_right (context, mcbpc_I[mb_type_index][2],
+ mac->ebit, &mac->end, &gob->end);
+
+ mac->mb_type = mcbpc_I[mb_type_index][5];
+
+ if (mb_type_index == 8) {
+ GST_LOG ("Stuffing skipping rest of MB header");
+ return mac;
+ }
+ //Step 3 decode CBPY I
+ cbpy_type_index = gst_rtp_h263_pay_decode_cbpy (context->window, cbpy_I);
+
+ GST_DEBUG ("CBPY index: %d", cbpy_type_index);
+ if (cbpy_type_index == -1) {
+ GST_ERROR ("CBPY index shouldn't be -1 in window: %08x", context->window);
+ goto beach;
+ }
+
+ mac->ebit =
+ gst_rtp_h263_pay_move_window_right (context, cbpy_I[cbpy_type_index][2],
+ mac->ebit, &mac->end, &gob->end);
+
+ //Step 4 decode rest of MB
+ //MB type 1 and 4 have DQUANT - we store it for packaging purposes
+ if (mcbpc_I[mb_type_index][5] == 4) {
+ GST_DEBUG ("Shifting DQUANT");
+
+ mac->quant = (context->window >> 30);
+
+ mac->ebit =
+ gst_rtp_h263_pay_move_window_right (context, 2, mac->ebit, &mac->end,
+ &gob->end);
+ }
+ //Step 5 go trough the blocks - decode DC and TCOEF
+ last = 0;
+ for (i = 0; i < N_BLOCKS; i++) {
+
+ GST_DEBUG ("Decoding INTRADC and TCOEF, i:%d", i);
+ mac->ebit =
+ gst_rtp_h263_pay_move_window_right (context, 8, mac->ebit, &mac->end,
+ &gob->end);
+
+ if (i > 3) {
+ ind = mcbpc_I[mb_type_index][i - 1];
+ } else {
+ ind = cbpy_I[cbpy_type_index][i + 3];
+ }
+
+ if (ind == 1) {
+ while (last == 0) {
+ tcoef_type_index = gst_rtp_h263_pay_decode_tcoef (context->window);
+
+ GST_DEBUG ("TCOEF index: %d", tcoef_type_index);
+ if (tcoef_type_index == -1) {
+ GST_ERROR ("TCOEF index shouldn't be -1 in window: %08x",
+ context->window);
+ goto beach;
+ }
+ mac->ebit =
+ gst_rtp_h263_pay_move_window_right (context,
+ tcoef[tcoef_type_index][2], mac->ebit, &mac->end, &gob->end);
+
+ last = tcoef[tcoef_type_index][3];
+ if (tcoef_type_index == 102) {
+ if ((context->window & 0x80000000) == 0x80000000)
+ last = 1;
+ else
+ last = 0;
+
+ mac->ebit =
+ gst_rtp_h263_pay_move_window_right (context, 15,
+ mac->ebit, &mac->end, &gob->end);
+ }
+ }
+ last = 0;
+ }
+ }
+
+ } else {
+ //We have a P frame
+ guint i;
+ guint last;
+ guint ind;
+
+ //Step 1 check COD
+ GST_DEBUG ("Checking for COD");
+ if ((context->window & 0x80000000) == 0x80000000) {
+ //The MB is not coded
+ mac->ebit =
+ gst_rtp_h263_pay_move_window_right (context, 1, mac->ebit, &mac->end,
+ &gob->end);
+ GST_DEBUG ("COOOOOOOOOOOD = 1");
+
+ return mac;
+ } else {
+ //The MB is coded
+ mac->ebit =
+ gst_rtp_h263_pay_move_window_right (context, 1, mac->ebit, &mac->end,
+ &gob->end);
+ }
+
+ //Step 2 decode MCBPC P
+ mb_type_index = gst_rtp_h263_pay_decode_mcbpc_P (context->window);
+
+ GST_DEBUG ("MCBPC index: %d", mb_type_index);
+ if (mb_type_index == -1) {
+ GST_ERROR ("MB index shouldn't be -1 in window: %08x", context->window);
+ goto beach;
+ }
+ mac->ebit =
+ gst_rtp_h263_pay_move_window_right (context, mcbpc_P[mb_type_index][2],
+ mac->ebit, &mac->end, &gob->end);
+
+ mac->mb_type = mcbpc_P[mb_type_index][5];
+
+ if (mb_type_index == 20) {
+ GST_LOG ("Stuffing skipping rest of MB header");
+ return mac;
+ }
+ //Step 3 decode CBPY P
+ cbpy_type_index = gst_rtp_h263_pay_decode_cbpy (context->window, cbpy_P);
+
+ GST_DEBUG ("CBPY index: %d", cbpy_type_index);
+ if (cbpy_type_index == -1) {
+ GST_ERROR ("CBPY index shouldn't be -1 in window: %08x", context->window);
+ goto beach;
+ }
+ mac->ebit =
+ gst_rtp_h263_pay_move_window_right (context, cbpy_P[cbpy_type_index][2],
+ mac->ebit, &mac->end, &gob->end);
+
+ //MB type 1 and 4 have DQUANT - we add it to MB object and jump over
+ if (mcbpc_P[mb_type_index][5] == 4 || mcbpc_P[mb_type_index][5] == 1) {
+ GST_DEBUG ("Shifting DQUANT");
+
+ mac->quant = context->window >> 30;
+
+ mac->ebit =
+ gst_rtp_h263_pay_move_window_right (context, 2, mac->ebit, &mac->end,
+ &gob->end);
+ }
+ //MB types < 3 have MVD1-4
+ if (mcbpc_P[mb_type_index][5] < 3) {
+
+ guint nmvd;
+ gint j;
+
+ nmvd = 2;
+ if (mcbpc_P[mb_type_index][5] == 2)
+ nmvd = 8;
+
+ for (j = 0; j < nmvd; j++) {
+ guint mvd_type;
+
+ mvd_type = gst_rtp_h263_pay_decode_mvd (context->window);
+
+ if (mvd_type == -1) {
+ GST_ERROR ("MVD1-4 index shouldn't be -1 in window: %08x",
+ context->window);
+ goto beach;
+ }
+ //set the MB mvd values
+ mac->mvd[j] = mvd[mvd_type][3];
+
+ mac->ebit =
+ gst_rtp_h263_pay_move_window_right (context, mvd[mvd_type][2],
+ mac->ebit, &mac->end, &gob->end);
+ }
+
+
+ }
+ //Step 5 go trough the blocks - decode DC and TCOEF
+ last = 0;
+ for (i = 0; i < N_BLOCKS; i++) {
+
+ //if MB type 3 or 4 then INTRADC coef are present in blocks
+ if (mcbpc_P[mb_type_index][5] > 2) {
+ GST_DEBUG ("INTRADC coef: %d", i);
+ mac->ebit =
+ gst_rtp_h263_pay_move_window_right (context, 8, mac->ebit,
+ &mac->end, &gob->end);
+ } else {
+ GST_DEBUG ("INTRADC coef is not present");
+ }
+
+ //check if the block has TCOEF
+ if (i > 3) {
+ ind = mcbpc_P[mb_type_index][i - 1];
+ } else {
+ if (mcbpc_P[mb_type_index][5] > 2) {
+ ind = cbpy_I[cbpy_type_index][i + 3];
+ } else {
+ ind = cbpy_P[cbpy_type_index][i + 3];
+ }
+ }
+
+ if (ind == 1) {
+ while (last == 0) {
+ tcoef_type_index = gst_rtp_h263_pay_decode_tcoef (context->window);
+
+ GST_DEBUG ("TCOEF index: %d", tcoef_type_index);
+ if (tcoef_type_index == -1) {
+ GST_ERROR ("TCOEF index shouldn't be -1 in window: %08x",
+ context->window);
+ goto beach;
+ }
+
+ mac->ebit =
+ gst_rtp_h263_pay_move_window_right (context,
+ tcoef[tcoef_type_index][2], mac->ebit, &mac->end, &gob->end);
+
+ last = tcoef[tcoef_type_index][3];
+ if (tcoef_type_index == 102) {
+ if ((context->window & 0x80000000) == 0x80000000)
+ last = 1;
+ else
+ last = 0;
+
+ mac->ebit =
+ gst_rtp_h263_pay_move_window_right (context, 15,
+ mac->ebit, &mac->end, &gob->end);
+ }
+ }
+ last = 0;
+ }
+ }
+ }
+
+ mac->length = mac->end - mac->start + 1;
+
+ return mac;
+
+beach:
+ gst_rtp_h263_pay_mb_destroy (mac);
+ return NULL;
+}
+
+static GstRtpH263PayMB *
+gst_rtp_h263_pay_mb_new (GstRtpH263PayBoundry * boundry, guint mba)
+{
+ GstRtpH263PayMB *mb;
+ gint i;
+
+ mb = (GstRtpH263PayMB *) g_malloc0 (sizeof (GstRtpH263PayMB));
+
+ mb->start = boundry->start;
+ mb->end = boundry->end;
+ mb->length = boundry->end - boundry->start + 1;
+ mb->sbit = boundry->sbit;
+ mb->ebit = boundry->ebit;
+ mb->mba = mba;
+
+ for (i = 0; i < 5; i++)
+ mb->mvd[i] = 0;
+
+ return mb;
+}
+
+static void
+gst_rtp_h263_pay_mb_destroy (GstRtpH263PayMB * mb)
+{
+ if (!mb)
+ return;
+
+ g_free (mb);
+}
+
+static GstFlowReturn
+gst_rtp_h263_pay_push (GstRtpH263Pay * rtph263pay,
+ GstRtpH263PayContext * context, GstRtpH263PayPackage * package)
+{
+
+ /*
+ * Splat the payload header values
+ */
+ guint8 *header;
+ guint8 *payload;
+ GstFlowReturn ret;
+ GstRTPBuffer rtp = { NULL };
+
+ gst_rtp_buffer_map (package->outbuf, GST_MAP_WRITE, &rtp);
+
+ header = gst_rtp_buffer_get_payload (&rtp);
+ payload = header + package->mode;
+
+ switch (package->mode) {
+ case GST_RTP_H263_PAYLOAD_HEADER_MODE_A:
+ GST_LOG ("Pushing A packet");
+ gst_rtp_h263_pay_splat_header_A (header, package, context->piclayer);
+ break;
+ case GST_RTP_H263_PAYLOAD_HEADER_MODE_B:
+ GST_LOG ("Pushing B packet");
+ gst_rtp_h263_pay_splat_header_B (header, package, context->piclayer);
+ break;
+ case GST_RTP_H263_PAYLOAD_HEADER_MODE_C:
+ //gst_rtp_h263_pay_splat_header_C(header, package, context->piclayer);
+ //break;
+ default:
+ return GST_FLOW_ERROR;
+ }
+
+
+ /*
+ * Copy the payload data in the buffer
+ */
+ GST_DEBUG ("Copying memory");
+ memcpy (payload, (guint8 *) package->payload_start, package->payload_len);
+
+ /*
+ * timestamp the buffer
+ */
+ GST_BUFFER_TIMESTAMP (package->outbuf) = rtph263pay->first_ts;
+
+ gst_rtp_buffer_set_marker (&rtp, package->marker);
+ if (package->marker)
+ GST_DEBUG ("Marker set!");
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ ret =
+ gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtph263pay),
+ package->outbuf);
+ GST_DEBUG ("Package pushed, returning");
+
+ gst_rtp_h263_pay_package_destroy (package);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_rtp_h263_pay_A_fragment_push (GstRtpH263Pay * rtph263pay,
+ GstRtpH263PayContext * context, guint first, guint last)
+{
+
+ GstRtpH263PayPackage *pack;
+
+ pack = gst_rtp_h263_pay_package_new_empty ();
+
+ pack->payload_start = context->gobs[first]->start;
+ pack->sbit = context->gobs[first]->sbit;
+ pack->ebit = context->gobs[last]->ebit;
+ pack->payload_len =
+ (context->gobs[last]->end - context->gobs[first]->start) + 1;
+ pack->marker = FALSE;
+
+ if (last == context->no_gobs - 1) {
+ pack->marker = TRUE;
+ }
+
+ pack->gobn = context->gobs[first]->gobn;
+ pack->mode = GST_RTP_H263_PAYLOAD_HEADER_MODE_A;
+ pack->outbuf =
+ gst_rtp_buffer_new_allocate (pack->payload_len + pack->mode, 0, 0);
+
+ GST_DEBUG ("Sending len:%d data to push function", pack->payload_len);
+
+ return gst_rtp_h263_pay_push (rtph263pay, context, pack);
+}
+
+static GstFlowReturn
+gst_rtp_h263_pay_B_fragment_push (GstRtpH263Pay * rtph263pay,
+ GstRtpH263PayContext * context, GstRtpH263PayGob * gob, guint first,
+ guint last, GstRtpH263PayBoundry * boundry)
+{
+
+ GstRtpH263PayPackage *pack;
+ guint mv;
+
+ pack = gst_rtp_h263_pay_package_new_empty ();
+
+ pack->payload_start = gob->macroblocks[first]->start;
+ pack->sbit = gob->macroblocks[first]->sbit;
+ if (first == 0) {
+ pack->payload_start = boundry->start;
+ pack->sbit = boundry->sbit;
+ pack->quant = gob->quant;
+ } else {
+ pack->quant = gob->macroblocks[first]->quant;
+ }
+ pack->payload_end = gob->macroblocks[last]->end;
+
+ pack->ebit = gob->macroblocks[last]->ebit;
+ pack->mba = gob->macroblocks[first]->mba;
+ pack->gobn = gob->gobn;
+ pack->mode = GST_RTP_H263_PAYLOAD_HEADER_MODE_B;
+ pack->nmvd = 0;
+
+ if (gob->macroblocks[first]->mb_type < 3) {
+ if (gob->macroblocks[first]->mb_type == 2)
+ pack->nmvd = 8;
+ else if (gob->macroblocks[first]->mb_type < 2)
+ pack->nmvd = 2;
+
+ for (mv = 0; mv < pack->nmvd; mv++)
+ pack->mvd[mv] = gob->macroblocks[first]->mvd[mv];
+ }
+
+ pack->marker = FALSE;
+ if (last == gob->nmacroblocs - 1) {
+ pack->ebit = 0;
+ }
+
+ if ((format_props[context->piclayer->ptype_srcformat][0] - 1 == gob->gobn)
+ && (last == gob->nmacroblocs - 1)) {
+ pack->marker = TRUE;
+ }
+
+ pack->payload_len = pack->payload_end - pack->payload_start + 1;
+ pack->outbuf =
+ gst_rtp_buffer_new_allocate (pack->payload_len + pack->mode, 0, 0);
+
+ return gst_rtp_h263_pay_push (rtph263pay, context, pack);
+}
+
+
+static gboolean
+gst_rtp_h263_pay_mode_B_fragment (GstRtpH263Pay * rtph263pay,
+ GstRtpH263PayContext * context, GstRtpH263PayGob * gob)
+{
+
+
+ /*---------- MODE B MODE FRAGMENTATION ----------*/
+ GstRtpH263PayMB *mac = NULL;
+ guint max_payload_size;
+ GstRtpH263PayBoundry boundry;
+ guint mb;
+ guint8 ebit;
+
+ guint first = 0;
+ guint payload_len;
+
+ max_payload_size =
+ context->mtu - GST_RTP_H263_PAYLOAD_HEADER_MODE_B - GST_RTP_HEADER_LEN;
+
+ gst_rtp_h263_pay_boundry_init (&boundry, gob->start, gob->start, gob->sbit,
+ 0);
+
+ gob->macroblocks =
+ (GstRtpH263PayMB **) g_malloc0 (sizeof (GstRtpH263PayMB *) *
+ format_props[context->piclayer->ptype_srcformat][1]);
+
+ GST_LOG ("GOB isn't PB frame, applying mode B");
+
+ //initializing window
+ context->win_end = boundry.end;
+ if (gst_rtp_h263_pay_move_window_right (context, 32, boundry.ebit,
+ &boundry.end, &gob->end) != 0) {
+ GST_ERROR
+ ("The rest of the bits should be 0, exiting, because something bad happend");
+ gst_adapter_flush (rtph263pay->adapter, rtph263pay->available_data);
+ goto decode_error;
+ }
+ //The first GOB of a frame "has no" actual header - PICTURE header is his header
+ if (gob->gobn == 0) {
+ guint shift;
+ GST_LOG ("Initial GOB");
+ shift = 43;
+
+ boundry.ebit =
+ gst_rtp_h263_pay_move_window_right (context, shift, boundry.ebit,
+ &boundry.end, &gob->end);
+
+ //We need PQUANT for mode B packages - so we store it
+ gob->quant = context->window >> 27;
+
+ //if PCM == 1, then PSBI is present - header has 51 bits
+ //shift for PQUANT (5) and PCM (1) = 6 bits
+ shift = 6;
+ if (context->cpm == 1)
+ shift += 2;
+ boundry.ebit =
+ gst_rtp_h263_pay_move_window_right (context, shift, boundry.ebit,
+ &boundry.end, &gob->end);
+
+ GST_DEBUG ("window: 0x%08x", context->window);
+
+ //Shifting the PEI and PSPARE fields
+ while ((context->window & 0x80000000) == 0x80000000) {
+ boundry.ebit =
+ gst_rtp_h263_pay_move_window_right (context, 9,
+ boundry.ebit, &boundry.end, &gob->end);
+ GST_LOG ("window: 0x%x", context->window);
+ }
+
+ //shift the last PEI field
+ boundry.ebit =
+ gst_rtp_h263_pay_move_window_right (context, 1, boundry.ebit,
+ &boundry.end, &gob->end);
+
+ } else {
+ //skipping GOBs 24 header bits + 5 GQUANT
+ guint shift = 24;
+
+ GST_LOG ("INTER GOB");
+
+ //if CPM == 1, there are 2 more bits in the header - GSBI header is 31 bits long
+ if (context->cpm == 1)
+ shift += 2;
+
+ GST_LOG ("window: 0x%x", context->window);
+ boundry.ebit =
+ gst_rtp_h263_pay_move_window_right (context, shift,
+ boundry.ebit, &boundry.end, &gob->end);
+
+ //We need GQUANT for mode B packages - so we store it
+ gob->quant = context->window >> 27;
+
+ shift = 5;
+ boundry.ebit =
+ gst_rtp_h263_pay_move_window_right (context, shift,
+ boundry.ebit, &boundry.end, &gob->end);
+
+ GST_LOG ("window: 0x%x", context->window);
+ }
+
+ GST_DEBUG ("GQUANT IS: %08x", gob->quant);
+
+ // We are on MB layer
+
+ mac = gst_rtp_h263_pay_mb_new (&boundry, 0);
+ for (mb = 0; mb < format_props[context->piclayer->ptype_srcformat][1]; mb++) {
+
+ GST_DEBUG ("================ START MB %d =================", mb);
+
+ //Find next macroblock boundaries
+ ebit = mac->ebit;
+ if (!(mac = gst_rtp_h263_pay_B_mbfinder (context, gob, mac, mb))) {
+
+ GST_DEBUG ("Error decoding MB - sbit: %d", 8 - ebit);
+ GST_ERROR ("Error decoding in GOB");
+
+ goto decode_error;
+ }
+ //If mb_type == stuffing, don't increment the mb address
+ if (mac->mb_type == 10) {
+ mb--;
+ continue;
+ } else {
+ gob->nmacroblocs++;
+ }
+
+ gob->macroblocks[mb] = mac;
+
+ if (mac->end >= gob->end) {
+ GST_LOG ("No more MBs in this GOB");
+ if (!mac->ebit) {
+ mac->end--;
+ }
+ gob->end = mac->end;
+ break;
+ }
+ GST_DEBUG ("Found MB: mba: %d start: %p end: %p len: %d sbit: %d ebit: %d",
+ mac->mba, mac->start, mac->end, mac->length, mac->sbit, mac->ebit);
+ GST_DEBUG ("================ END MB %d =================", mb);
+ }
+
+ mb = 0;
+ first = 0;
+ payload_len = boundry.end - boundry.start + 1;
+ GST_DEBUG ("------------------------- NEW PACKAGE ----------------------");
+ while (mb < gob->nmacroblocs) {
+ if (payload_len + gob->macroblocks[mb]->length < max_payload_size) {
+
+ //FIXME: payload_len is not the real length -> ignoring sbit/ebit
+ payload_len += gob->macroblocks[mb]->length;
+ mb++;
+
+ } else {
+ //FIXME: we should include the last few bits of the GOB in the package - do we do that now?
+ //GST_DEBUG ("Pushing GOBS %d to %d because payload size is %d", first,
+ // first == mb - 1, payload_len);
+
+ if (gst_rtp_h263_pay_B_fragment_push (rtph263pay, context, gob, first,
+ mb - 1, &boundry)) {
+ GST_ERROR ("Oooops, there was an error sending");
+ goto decode_error;
+ }
+
+ payload_len = 0;
+ first = mb;
+ GST_DEBUG
+ ("------------------------- END PACKAGE ----------------------");
+ GST_DEBUG
+ ("------------------------- NEW PACKAGE ----------------------");
+ }
+ }
+
+ /* Push rest */
+ GST_DEBUG ("Remainder first: %d, MB: %d", first, mb);
+ if (payload_len != 0) {
+ if (gst_rtp_h263_pay_B_fragment_push (rtph263pay, context, gob, first,
+ mb - 1, &boundry)) {
+ GST_ERROR ("Oooops, there was an error sending!");
+ goto decode_error;
+ }
+ }
+
+ /*---------- END OF MODE B FRAGMENTATION ----------*/
+
+ gst_rtp_h263_pay_mb_destroy (mac);
+ return TRUE;
+
+decode_error:
+ gst_rtp_h263_pay_mb_destroy (mac);
+ return FALSE;
+}
+
+static GstFlowReturn
+gst_rtp_h263_send_entire_frame (GstRtpH263Pay * rtph263pay,
+ GstRtpH263PayContext * context)
+{
+ GstRtpH263PayPackage *pack;
+ pack =
+ gst_rtp_h263_pay_package_new (rtph263pay->data,
+ rtph263pay->data + rtph263pay->available_data,
+ rtph263pay->available_data, 0, 0, NULL, TRUE);
+ pack->mode = GST_RTP_H263_PAYLOAD_HEADER_MODE_A;
+
+ GST_DEBUG ("Available data: %d", rtph263pay->available_data);
+
+ pack->outbuf =
+ gst_rtp_buffer_new_allocate (pack->payload_len +
+ GST_RTP_H263_PAYLOAD_HEADER_MODE_A, 0, 0);
+
+ return gst_rtp_h263_pay_push (rtph263pay, context, pack);
+}
+
+static GstFlowReturn
+gst_rtp_h263_pay_flush (GstRtpH263Pay * rtph263pay)
+{
+
+ /*
+ * FIXME: GSTUF bits are ignored right now,
+ * - not using EBIT/SBIT payload header fields in mode A fragmentation - ffmpeg doesn't need them, but others?
+ */
+
+ GstFlowReturn ret;
+ GstRtpH263PayContext *context;
+ gint i;
+
+ ret = 0;
+ context = (GstRtpH263PayContext *) g_malloc0 (sizeof (GstRtpH263PayContext));
+ context->mtu =
+ rtph263pay->payload.mtu - (MTU_SECURITY_OFFSET + GST_RTP_HEADER_LEN +
+ GST_RTP_H263_PAYLOAD_HEADER_MODE_C);
+
+ GST_DEBUG ("MTU: %d", context->mtu);
+ rtph263pay->available_data = gst_adapter_available (rtph263pay->adapter);
+ if (rtph263pay->available_data == 0) {
+ ret = GST_FLOW_OK;
+ goto end;
+ }
+
+ /* Get a pointer to all the data for the frame */
+ rtph263pay->data =
+ (guint8 *) gst_adapter_map (rtph263pay->adapter,
+ rtph263pay->available_data);
+
+ /* Picture header */
+ context->piclayer = (GstRtpH263PayPic *) rtph263pay->data;
+
+ if (context->piclayer->ptype_pictype == 0)
+ GST_DEBUG ("We got an I-frame");
+ else
+ GST_DEBUG ("We got a P-frame");
+
+ context->cpm = rtph263pay->data[6] >> 7;
+
+ GST_DEBUG ("CPM: %d", context->cpm);
+
+ GST_DEBUG ("Payload length is: %d", rtph263pay->available_data);
+
+ /*
+ * - MODE A - If normal, I and P frames, -> mode A
+ * - GOB layer fragmentation
+ * - MODE B - If normal, I and P frames, but GOBs > mtu
+ * - MB layer fragmentation
+ * - MODE C - For P frames with PB option, but GOBs > mtu
+ * - MB layer fragmentation
+ */
+ if (rtph263pay->available_data + GST_RTP_H263_PAYLOAD_HEADER_MODE_A +
+ GST_RTP_HEADER_LEN < context->mtu) {
+ ret = gst_rtp_h263_send_entire_frame (rtph263pay, context);
+ } else {
+
+ /*---------- FRAGMENTING THE FRAME BECAUSE TOO LARGE TO FIT IN MTU ----------*/
+ GstRtpH263PayBoundry bound;
+ gint first;
+ guint payload_len;
+ gboolean forcea = FALSE;
+
+ GST_DEBUG ("Frame too large for MTU");
+ /*
+ * Let's go trough all the data and fragment it untill end is reached
+ */
+
+ gst_rtp_h263_pay_boundry_init (&bound, NULL, rtph263pay->data - 1, 0, 0);
+ context->gobs =
+ (GstRtpH263PayGob **) g_malloc0 (format_props[context->piclayer->
+ ptype_srcformat][0] * sizeof (GstRtpH263PayGob *));
+
+
+ for (i = 0; i < format_props[context->piclayer->ptype_srcformat][0]; i++) {
+ GST_DEBUG ("Searching for gob %d", i);
+ if (!gst_rtp_h263_pay_gobfinder (rtph263pay, &bound)) {
+ if (i <= 1) {
+ GST_WARNING
+ ("No GOB's were found in data stream! Please enable RTP mode in encoder. Forcing mode A for now.");
+ ret = gst_rtp_h263_send_entire_frame (rtph263pay, context);
+ goto end;
+ } else {
+ /* try to send fragments corresponding to found GOBs */
+ forcea = TRUE;
+ break;
+ }
+ }
+
+ context->gobs[i] = gst_rtp_h263_pay_gob_new (&bound, i);
+ //FIXME - encoders may generate an EOS gob that has to be processed
+ GST_DEBUG
+ ("Gob values are: gobn: %d, start: %p len: %d ebit: %d sbit: %d", i,
+ context->gobs[i]->start, context->gobs[i]->length,
+ context->gobs[i]->ebit, context->gobs[i]->sbit);
+ }
+ /* NOTE some places may still assume this to be the max possible */
+ context->no_gobs = i;
+ GST_DEBUG ("Found %d GOBS of maximum %d",
+ context->no_gobs, format_props[context->piclayer->ptype_srcformat][0]);
+
+ // Make packages smaller than MTU
+ // A mode
+ // - if ( GOB > MTU) -> B mode || C mode
+ // Push packages
+
+ first = 0;
+ payload_len = 0;
+ i = 0;
+ while (i < context->no_gobs) {
+
+ if (context->gobs[i]->length >= context->mtu) {
+ if (payload_len == 0) {
+
+ GST_DEBUG ("GOB len > MTU");
+ if (rtph263pay->prop_payload_mode || forcea) {
+ payload_len = context->gobs[i]->length;
+ goto force_a;
+ }
+ if (!context->piclayer->ptype_pbmode) {
+ GST_DEBUG ("MODE B on GOB %d needed", i);
+ if (!gst_rtp_h263_pay_mode_B_fragment (rtph263pay, context,
+ context->gobs[i])) {
+ GST_ERROR ("There was an error fragmenting in mode B");
+ ret = GST_FLOW_ERROR;
+ goto end;
+ }
+ } else {
+ //IMPLEMENT C mode
+ GST_ERROR ("MODE C on GOB %d needed, but not supported yet", i);
+ /*if(!gst_rtp_h263_pay_mode_C_fragment(rtph263pay, context, context->gobs[i])) {
+ ret = GST_FLOW_OK;
+ GST_ERROR("There was an error fragmenting in mode C");
+ goto decode_error;
+ } */
+ goto decode_error;
+ }
+ decode_error:
+ i++;
+ first = i;
+ continue;
+
+ } else {
+ goto payload_a_push;
+ }
+ }
+
+ if (payload_len + context->gobs[i]->length < context->mtu) {
+ GST_DEBUG ("GOB %d fills mtu", i);
+ payload_len += context->gobs[i]->length;
+ i++;
+ if (i == context->no_gobs) {
+ GST_DEBUG ("LAST GOB %d", i);
+ goto payload_a_push;
+ }
+
+ } else {
+ payload_a_push:
+ GST_DEBUG ("Pushing GOBS %d to %d because payload size is %d", first,
+ first == i ? i : i - 1, payload_len);
+ gst_rtp_h263_pay_A_fragment_push (rtph263pay, context, first,
+ first == i ? i : i - 1);
+ payload_len = 0;
+ first = i;
+ }
+ continue;
+
+ force_a:
+ GST_DEBUG ("Pushing GOBS %d to %d because payload size is %d", first, i,
+ payload_len);
+ gst_rtp_h263_pay_A_fragment_push (rtph263pay, context, first, i);
+ payload_len = 0;
+ i++;
+ first = i;
+ }
+
+
+ }/*---------- END OF FRAGMENTATION ----------*/
+
+ /* Flush the input buffer data */
+
+end:
+ gst_rtp_h263_pay_context_destroy (context,
+ context->piclayer->ptype_srcformat);
+ gst_adapter_unmap (rtph263pay->adapter);
+ gst_adapter_flush (rtph263pay->adapter, rtph263pay->available_data);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_rtp_h263_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
+{
+
+ GstRtpH263Pay *rtph263pay;
+ GstFlowReturn ret;
+
+ GST_DEBUG ("-------------------- NEW FRAME ---------------");
+ rtph263pay = GST_RTP_H263_PAY (payload);
+
+ rtph263pay->first_ts = GST_BUFFER_TIMESTAMP (buffer);
+
+ /* we always encode and flush a full picture */
+ gst_adapter_push (rtph263pay->adapter, buffer);
+ ret = gst_rtp_h263_pay_flush (rtph263pay);
+ GST_DEBUG ("-------------------- END FRAME ---------------");
+
+ return ret;
+}
+
+gboolean
+gst_rtp_h263_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtph263pay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_H263_PAY);
+}
diff --git a/gst/rtp/gstrtph263pay.h b/gst/rtp/gstrtph263pay.h
new file mode 100755
index 0000000..d41c3ed
--- /dev/null
+++ b/gst/rtp/gstrtph263pay.h
@@ -0,0 +1,414 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Author: Dejan Sakelsak sahel@kiberpipa.org
+ */
+
+#ifndef __GST_RTP_H263_PAY_H__
+#define __GST_RTP_H263_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_RTP_H263_PAY \
+ (gst_rtp_h263_pay_get_type())
+#define GST_RTP_H263_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_H263_PAY,GstRtpH263Pay))
+#define GST_RTP_H263_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_H263_PAY,GstRtpH263PayClass))
+#define GST_IS_RTP_H263_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_H263_PAY))
+#define GST_IS_RTP_H263_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_H263_PAY))
+// blocks per macroblock
+#define N_BLOCKS 6
+#define DEFAULT_MODE_A FALSE
+#define MTU_SECURITY_OFFSET 50
+ typedef enum _GstRtpH263PayHeaderMode
+{
+ GST_RTP_H263_PAYLOAD_HEADER_MODE_A = 4,
+ GST_RTP_H263_PAYLOAD_HEADER_MODE_B = 8,
+ GST_RTP_H263_PAYLOAD_HEADER_MODE_C = 12
+} GstRtpH263PayHeaderMode;
+
+typedef struct _GstRtpH263PayContext GstRtpH263PayContext;
+typedef struct _GstRtpH263PayPic GstRtpH263PayPic;
+typedef struct _GstRtpH263PayClass GstRtpH263PayClass;
+typedef struct _GstRtpH263Pay GstRtpH263Pay;
+typedef struct _GstRtpH263PayBoundry GstRtpH263PayBoundry;
+typedef struct _GstRtpH263PayMB GstRtpH263PayMB;
+typedef struct _GstRtpH263PayGob GstRtpH263PayGob;
+typedef struct _GstRtpH263PayPackage GstRtpH263PayPackage;
+
+//typedef enum _GstRtpH263PayHeaderMode GstRtpH263PayHeaderMode;
+
+struct _GstRtpH263Pay
+{
+ GstRTPBasePayload payload;
+
+ GstAdapter *adapter;
+ GstClockTime first_ts;
+ gboolean prop_payload_mode;
+ guint8 *data;
+ guint available_data;
+
+};
+
+struct _GstRtpH263PayContext
+{
+ GstRtpH263PayPic *piclayer;
+
+ guint mtu;
+ guint window;
+ guint8 *win_end;
+ guint8 cpm;
+
+ guint no_gobs;
+ GstRtpH263PayGob **gobs;
+
+};
+
+struct _GstRtpH263PayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+typedef struct _GstRtpH263PayAHeader
+{
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ unsigned int ebit:3; /* End position */
+ unsigned int sbit:3; /* Start position */
+ unsigned int p:1; /* PB-frames mode */
+ unsigned int f:1; /* flag bit */
+
+ unsigned int r1:1; /* Reserved */
+ unsigned int a:1; /* Advanced Prediction */
+ unsigned int s:1; /* syntax based arithmetic coding */
+ unsigned int u:1; /* Unrestricted motion vector */
+ unsigned int i:1; /* Picture coding type */
+ unsigned int src:3; /* Source format */
+
+ unsigned int trb:3; /* Temporal ref for B frame */
+ unsigned int dbq:2; /* Differential Quantisation parameter */
+ unsigned int r2:3; /* Reserved */
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+ unsigned int f:1; /* flag bit */
+ unsigned int p:1; /* PB-frames mode */
+ unsigned int sbit:3; /* Start position */
+ unsigned int ebit:3; /* End position */
+
+ unsigned int src:3; /* Source format */
+ unsigned int i:1; /* Picture coding type */
+ unsigned int u:1; /* Unrestricted motion vector */
+ unsigned int s:1; /* syntax based arithmetic coding */
+ unsigned int a:1; /* Advanced Prediction */
+ unsigned int r1:1; /* Reserved */
+
+ unsigned int r2:3; /* Reserved */
+ unsigned int dbq:2; /* Differential Quantisation parameter */
+ unsigned int trb:3; /* Temporal ref for B frame */
+#else
+#error "G_BYTE_ORDER should be big or little endian."
+#endif
+ unsigned int tr:8; /* Temporal ref for P frame */
+} GstRtpH263PayAHeader;
+
+typedef struct _GstRtpH263PayBHeader
+{
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ unsigned int ebit:3; /* End position */
+ unsigned int sbit:3; /* Start position */
+ unsigned int p:1; /* PB-frames mode */
+ unsigned int f:1; /* flag bit */
+
+ unsigned int quant:5; /* Quantization value for first MB */
+ unsigned int src:3; /* Source format */
+
+ unsigned int mba1:3; /* Address of first MB starting count from 0 - part1 */
+ unsigned int gobn:5; /* GOB number in effect at start of packet */
+
+ unsigned int r:2; /* Reserved */
+ unsigned int mba2:6; /* Address of first MB starting count from 0 - part2 */
+
+ unsigned int hmv11:4; /* horizontal motion vector predictor for MB 1 - part 1 */
+ unsigned int a:1; /* Advanced Prediction */
+ unsigned int s:1; /* syntax based arithmetic coding */
+ unsigned int u:1; /* Unrestricted motion vector */
+ unsigned int i:1; /* Picture coding type */
+
+ unsigned int vmv11:5; /* vertical motion vector predictor for MB 1 - part 1 */
+ unsigned int hmv12:3; /* horizontal motion vector predictor for MB 1 - part 2 */
+
+ unsigned int hmv21:6; /* horizontal motion vector predictor for MB 3 - part 1 */
+ unsigned int vmv12:2; /* vertical motion vector predictor for MB 1 - part 2 */
+
+ unsigned int vmv21:7; /* vertical motion vector predictor for MB 3 */
+ unsigned int hmv22:1; /* horizontal motion vector predictor for MB 3 - part 2 */
+
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+ unsigned int f:1; /* flag bit */
+ unsigned int p:1; /* PB-frames mode */
+ unsigned int sbit:3; /* Start position */
+ unsigned int ebit:3; /* End position */
+
+ unsigned int src:3; /* Source format */
+ unsigned int quant:5; /* Quantization value for first MB */
+
+ unsigned int gobn:5; /* GOB number in effect at start of packet */
+ unsigned int mba1:3; /* Address of first MB starting count from 0 - part1 */
+
+ unsigned int mba2:6; /* Address of first MB starting count from 0 - part2 */
+ unsigned int r:2; /* Reserved */
+
+ unsigned int i:1; /* Picture coding type */
+ unsigned int u:1; /* Unrestricted motion vector */
+ unsigned int s:1; /* syntax based arithmetic coding */
+ unsigned int a:1; /* Advanced Prediction */
+ unsigned int hmv11:4; /* horizontal motion vector predictor for MB 1 - part 1 */
+
+ unsigned int hmv12:3; /* horizontal motion vector predictor for MB 1 - part 2 */
+ unsigned int vmv11:5; /* vertical motion vector predictor for MB 1 - part 1 */
+
+ unsigned int vmv12:2; /* vertical motion vector predictor for MB 1 - part 2 */
+ unsigned int hmv21:6; /* horizontal motion vector predictor for MB 3 - part 1 */
+
+ unsigned int hmv22:1; /* horizontal motion vector predictor for MB 3 - part 2 */
+ unsigned int vmv21:7; /* vertical motion vector predictor for MB 3 */
+#else
+#error "G_BYTE_ORDER should be big or little endian."
+#endif
+} GstRtpH263PayBHeader;
+
+typedef struct _GstRtpH263PayCHeader
+{
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ unsigned int ebit:3; /* End position */
+ unsigned int sbit:3; /* Start position */
+ unsigned int p:1; /* PB-frames mode */
+ unsigned int f:1; /* flag bit */
+
+ unsigned int quant:5; /* Quantization value for first MB */
+ unsigned int src:3; /* Source format */
+
+ unsigned int mba1:3; /* Address of first MB starting count from 0 - part1 */
+ unsigned int gobn:5; /* GOB number in effect at start of packet */
+
+ unsigned int r:2; /* Reserved */
+ unsigned int mba2:6; /* Address of first MB starting count from 0 - part2 */
+
+ unsigned int hmv11:4; /* horizontal motion vector predictor for MB 1 - part 1 */
+ unsigned int a:1; /* Advanced Prediction */
+ unsigned int s:1; /* syntax based arithmetic coding */
+ unsigned int u:1; /* Unrestricted motion vector */
+ unsigned int i:1; /* Picture coding type */
+
+ unsigned int vmv11:5; /* vertical motion vector predictor for MB 1 - part 1 */
+ unsigned int hmv12:3; /* horizontal motion vector predictor for MB 1 - part 2 */
+
+ unsigned int hmv21:6; /* horizontal motion vector predictor for MB 3 - part 1 */
+ unsigned int vmv12:2; /* vertical motion vector predictor for MB 1 - part 2 */
+
+ unsigned int vmv21:7; /* vertical motion vector predictor for MB 3 */
+ unsigned int hmv22:1; /* horizontal motion vector predictor for MB 3 - part 2 */
+
+ unsigned int rr1:8; /* reserved */
+
+ unsigned int rr2:8; /* reserved */
+
+ unsigned int trb:3; /* Temporal Reference for the B */
+ unsigned int dbq:2; /* Differential quantization parameter */
+ unsigned int rr3:3; /* reserved */
+
+ unsigned int tr:8; /* Temporal Reference for the P frame */
+
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+ unsigned int f:1; /* flag bit */
+ unsigned int p:1; /* PB-frames mode */
+ unsigned int sbit:3; /* Start position */
+ unsigned int ebit:3; /* End position */
+
+ unsigned int src:3; /* Source format */
+ unsigned int quant:5; /* Quantization value for first MB */
+
+ unsigned int gobn:5; /* GOB number in effect at start of packet */
+ unsigned int mba1:3; /* Address of first MB starting count from 0 - part1 */
+
+ unsigned int mba2:6; /* Address of first MB starting count from 0 - part2 */
+ unsigned int r:2; /* Reserved */
+
+ unsigned int i:1; /* Picture coding type */
+ unsigned int u:1; /* Unrestricted motion vector */
+ unsigned int s:1; /* syntax based arithmetic coding */
+ unsigned int a:1; /* Advanced Prediction */
+ unsigned int hmv11:4; /* horizontal motion vector predictor for MB 1 - part 1 */
+
+ unsigned int hmv12:3; /* horizontal motion vector predictor for MB 1 - part 2 */
+ unsigned int vmv11:5; /* vertical motion vector predictor for MB 1 - part 1 */
+
+ unsigned int vmv12:2; /* vertical motion vector predictor for MB 1 - part 2 */
+ unsigned int hmv21:6; /* horizontal motion vector predictor for MB 3 - part 1 */
+
+ unsigned int hmv22:1; /* horizontal motion vector predictor for MB 3 - part 2 */
+ unsigned int vmv21:7; /* vertical motion vector predictor for MB 3 */
+ unsigned int rr1:8; /* reserved */
+ unsigned int rr2:8; /* reserved */
+
+ unsigned int rr3:3; /* reserved */
+ unsigned int dbq:2; /* Differential quantization parameter */
+ unsigned int trb:3; /* Temporal Reference for the B */
+
+ unsigned int tr:8; /* Temporal Reference for the P frame */
+#else
+#error "G_BYTE_ORDER should be big or little endian."
+#endif
+} GstRtpH263PayCHeader;
+
+struct _GstRtpH263PayPic
+{
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ unsigned int psc1:16;
+
+ unsigned int tr1:2;
+ unsigned int psc2:6;
+
+ unsigned int ptype_263:1;
+ unsigned int ptype_start:1;
+ unsigned int tr2:6;
+
+ unsigned int ptype_umvmode:1;
+ unsigned int ptype_pictype:1;
+ unsigned int ptype_srcformat:3;
+ unsigned int ptype_freeze:1;
+ unsigned int ptype_camera:1;
+ unsigned int ptype_split:1;
+
+ unsigned int pquant:5;
+ unsigned int ptype_pbmode:1;
+ unsigned int ptype_apmode:1;
+ unsigned int ptype_sacmode:1;
+
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+ unsigned int psc1:16;
+
+ unsigned int psc2:6;
+ unsigned int tr1:2;
+
+ unsigned int tr2:6;
+ unsigned int ptype_start:2;
+
+ unsigned int ptype_split:1;
+ unsigned int ptype_camera:1;
+ unsigned int ptype_freeze:1;
+ unsigned int ptype_srcformat:3;
+ unsigned int ptype_pictype:1;
+ unsigned int ptype_umvmode:1;
+
+ unsigned int ptype_sacmode:1;
+ unsigned int ptype_apmode:1;
+ unsigned int ptype_pbmode:1;
+ unsigned int pquant:5;
+
+#else
+#error "G_BYTE_ORDER should be big or little endian."
+#endif
+};
+
+struct _GstRtpH263PayBoundry
+{
+
+ guint8 *start;
+ guint8 *end;
+ guint8 sbit;
+ guint8 ebit;
+
+};
+
+struct _GstRtpH263PayMB
+{
+ guint8 *start;
+ guint8 *end;
+ guint8 sbit;
+ guint8 ebit;
+ guint length;
+
+ guint8 mb_type;
+ guint quant;
+
+ guint mba;
+ guint8 mvd[10];
+};
+
+struct _GstRtpH263PayGob
+{
+ guint8 *start;
+ guint8 *end;
+ guint length;
+ guint8 sbit;
+ guint8 ebit;
+
+ guint gobn;
+ guint quant;
+
+ GstRtpH263PayMB **macroblocks;
+ guint nmacroblocs;
+};
+
+struct _GstRtpH263PayPackage
+{
+ guint8 *payload_start;
+ guint8 *payload_end;
+ guint payload_len;
+ guint8 sbit;
+ guint8 ebit;
+ GstBuffer *outbuf;
+ gboolean marker;
+
+ GstRtpH263PayHeaderMode mode;
+
+ /*
+ * mode B,C data
+ */
+
+ guint16 mba;
+ guint nmvd;
+ guint8 mvd[10];
+ guint gobn;
+ guint quant;
+};
+
+#define GST_H263_PICTURELAYER_PLSRC(buf) (((GstRtpH263PayPic *)(buf))->ptype_srcformat)
+#define GST_H263_PICTURELAYER_PLTYPE(buf) (((GstRtpH263PayPic *)(buf))->ptype_pictype)
+#define GST_H263_PICTURELAYER_PLUMV(buf) (((GstRtpH263PayPic *)(buf))->ptype_umvmode)
+#define GST_H263_PICTURELAYER_PLSAC(buf) (((GstRtpH263PayPic *)(buf))->ptype_sacmode)
+#define GST_H263_PICTURELAYER_PLAP(buf) (((GstRtpH263PayPic *)(buf))->ptype_apmode)
+
+/*
+ * TODO: PB frame relevant tables
+ */
+
+#define GST_RTP_H263_PAY_END(start, len) (((guint8 *)start) + ((guint)len))
+#define GST_RTP_H263_PAY_GOBN(gob) (((((guint8 *) gob)[2] >> 2) & 0x1f)
+
+GType gst_rtp_h263_pay_get_type (void);
+
+gboolean gst_rtp_h263_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_H263_PAY_H__ */
diff --git a/gst/rtp/gstrtph263pdepay.c b/gst/rtp/gstrtph263pdepay.c
new file mode 100755
index 0000000..e788e2f
--- /dev/null
+++ b/gst/rtp/gstrtph263pdepay.c
@@ -0,0 +1,395 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include "gstrtph263pdepay.h"
+
+static GstStaticPadTemplate gst_rtp_h263p_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-h263, " "variant = (string) \"itu\" ")
+ );
+
+static GstStaticPadTemplate gst_rtp_h263p_depay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"video\", "
+ "clock-rate = (int) [1, MAX], "
+ "encoding-name = (string) \"H263-1998\"; "
+ /* optional params */
+ /* NOTE all optional SDP params must be strings in the caps */
+ /*
+ "sqcif = (string) [1, 32], "
+ "qcif = (string) [1, 32], "
+ "cif = (string) [1, 32], "
+ "cif4 = (string) [1, 32], "
+ "cif16 = (string) [1, 32], "
+ "custom = (string) ANY, "
+ "f = (string) {0, 1},"
+ "i = (string) {0, 1},"
+ "j = (string) {0, 1},"
+ "t = (string) {0, 1},"
+ "k = (string) {1, 2, 3, 4},"
+ "n = (string) {1, 2, 3, 4},"
+ "p = (string) ANY,"
+ "par = (string) ANY, "
+ "cpcf = (string) ANY, "
+ "bpp = (string) [0, 65536], "
+ "hrd = (string) {0, 1}; "
+ */
+ "application/x-rtp, "
+ "media = (string) \"video\", "
+ "clock-rate = (int) [1, MAX], "
+ "encoding-name = (string) \"H263-2000\" "
+ /* optional params */
+ /* NOTE all optional SDP params must be strings in the caps */
+ /*
+ "profile = (string) [0, 10], "
+ "level = (string) {10, 20, 30, 40, 45, 50, 60, 70}, "
+ "interlace = (string) {0, 1};"
+ */
+ )
+ );
+
+#define gst_rtp_h263p_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpH263PDepay, gst_rtp_h263p_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_h263p_depay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_h263p_depay_change_state (GstElement *
+ element, GstStateChange transition);
+
+static GstBuffer *gst_rtp_h263p_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+gboolean gst_rtp_h263p_depay_setcaps (GstRTPBaseDepayload * filter,
+ GstCaps * caps);
+
+static void
+gst_rtp_h263p_depay_class_init (GstRtpH263PDepayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_h263p_depay_finalize;
+
+ gstelement_class->change_state = gst_rtp_h263p_depay_change_state;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_h263p_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_h263p_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP H263 depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts H263/+/++ video from RTP packets (RFC 4629)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ gstrtpbasedepayload_class->process = gst_rtp_h263p_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_h263p_depay_setcaps;
+}
+
+static void
+gst_rtp_h263p_depay_init (GstRtpH263PDepay * rtph263pdepay)
+{
+ rtph263pdepay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_h263p_depay_finalize (GObject * object)
+{
+ GstRtpH263PDepay *rtph263pdepay;
+
+ rtph263pdepay = GST_RTP_H263P_DEPAY (object);
+
+ g_object_unref (rtph263pdepay->adapter);
+ rtph263pdepay->adapter = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+gboolean
+gst_rtp_h263p_depay_setcaps (GstRTPBaseDepayload * filter, GstCaps * caps)
+{
+ GstCaps *srccaps = NULL;
+ GstStructure *structure = gst_caps_get_structure (caps, 0);
+ gint clock_rate;
+ const gchar *encoding_name = NULL;
+ gboolean res;
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 90000; /* default */
+ filter->clock_rate = clock_rate;
+
+ encoding_name = gst_structure_get_string (structure, "encoding-name");
+ if (encoding_name == NULL)
+ goto no_encoding_name;
+
+ if (g_ascii_strcasecmp (encoding_name, "H263-2000") == 0) {
+ /* always h263++ */
+ srccaps = gst_caps_new_simple ("video/x-h263",
+ "variant", G_TYPE_STRING, "itu",
+ "h263version", G_TYPE_STRING, "h263pp", NULL);
+ } else if (g_ascii_strcasecmp (encoding_name, "H263-1998") == 0) {
+ /* this can be H263 or H263+ depending on defined appendixes in the optional
+ * SDP params */
+ const gchar *F, *I, *J, *T, *K, *N, *P;
+ gboolean is_h263p = FALSE;
+
+ F = gst_structure_get_string (structure, "f");
+ if (F)
+ if (g_ascii_strcasecmp (F, "1") == 0)
+ is_h263p = TRUE;
+ I = gst_structure_get_string (structure, "i");
+ if (I)
+ if (g_ascii_strcasecmp (I, "1") == 0)
+ is_h263p = TRUE;
+ J = gst_structure_get_string (structure, "j");
+ if (J)
+ if (g_ascii_strcasecmp (J, "1") == 0)
+ is_h263p = TRUE;
+ T = gst_structure_get_string (structure, "t");
+ if (T)
+ if (g_ascii_strcasecmp (T, "1") == 0)
+ is_h263p = TRUE;
+ K = gst_structure_get_string (structure, "k");
+ if (K)
+ is_h263p = TRUE;
+ N = gst_structure_get_string (structure, "n");
+ if (N)
+ is_h263p = TRUE;
+ P = gst_structure_get_string (structure, "p");
+ if (P)
+ is_h263p = TRUE;
+
+ if (is_h263p) {
+ srccaps = gst_caps_new_simple ("video/x-h263",
+ "variant", G_TYPE_STRING, "itu",
+ "h263version", G_TYPE_STRING, "h263p", NULL);
+ } else {
+ srccaps = gst_caps_new_simple ("video/x-h263",
+ "variant", G_TYPE_STRING, "itu",
+ "h263version", G_TYPE_STRING, "h263", NULL);
+ }
+ }
+ if (!srccaps)
+ goto no_caps;
+
+ res = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (filter), srccaps);
+ gst_caps_unref (srccaps);
+
+ return res;
+
+ /* ERRORS */
+no_encoding_name:
+ {
+ GST_ERROR_OBJECT (filter, "no encoding-name");
+ return FALSE;
+ }
+no_caps:
+ {
+ GST_ERROR_OBJECT (filter, "invalid encoding-name");
+ return FALSE;
+ }
+}
+
+static GstBuffer *
+gst_rtp_h263p_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpH263PDepay *rtph263pdepay;
+ GstBuffer *outbuf;
+ gint payload_len;
+ guint8 *payload;
+ gboolean P, V, M;
+ guint header_len;
+ guint8 PLEN, PEBIT;
+ GstRTPBuffer rtp = { NULL };
+
+ rtph263pdepay = GST_RTP_H263P_DEPAY (depayload);
+
+ /* flush remaining data on discont */
+ if (GST_BUFFER_IS_DISCONT (buf)) {
+ GST_LOG_OBJECT (depayload, "DISCONT, flushing adapter");
+ gst_adapter_clear (rtph263pdepay->adapter);
+ rtph263pdepay->wait_start = TRUE;
+ }
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+ header_len = 2;
+
+ if (payload_len < header_len)
+ goto too_small;
+
+ payload = gst_rtp_buffer_get_payload (&rtp);
+
+ M = gst_rtp_buffer_get_marker (&rtp);
+
+ /* 0 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | RR |P|V| PLEN |PEBIT|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ P = (payload[0] & 0x04) == 0x04;
+ V = (payload[0] & 0x02) == 0x02;
+ PLEN = ((payload[0] & 0x1) << 5) | (payload[1] >> 3);
+ PEBIT = payload[1] & 0x7;
+
+ GST_LOG_OBJECT (depayload, "P %d, V %d, PLEN %d, PEBIT %d", P, V, PLEN,
+ PEBIT);
+
+ if (V) {
+ header_len++;
+ }
+ if (PLEN) {
+ header_len += PLEN;
+ }
+
+ if ((!P && payload_len < header_len) || (P && payload_len < header_len - 2))
+ goto too_small;
+
+ if (P) {
+ /* FIXME, have to make the packet writable hear. Better to reset these
+ * bytes when we copy the packet below */
+ rtph263pdepay->wait_start = FALSE;
+ header_len -= 2;
+ payload[header_len] = 0;
+ payload[header_len + 1] = 0;
+ }
+
+ if (rtph263pdepay->wait_start)
+ goto waiting_start;
+
+ if (payload_len < header_len)
+ goto too_small;
+
+ /* FIXME do not ignore the VRC header (See RFC 2429 section 4.2) */
+ /* FIXME actually use the RTP picture header when it is lost in the network */
+ /* for now strip off header */
+ payload += header_len;
+ payload_len -= header_len;
+
+ if (M) {
+ /* frame is completed: append to previous, push it out */
+ guint len, padlen;
+ guint avail;
+ GstMapInfo map;
+
+ GST_LOG_OBJECT (depayload, "Frame complete");
+
+ avail = gst_adapter_available (rtph263pdepay->adapter);
+ len = avail + payload_len;
+ padlen = (len % 4) + 4;
+
+ outbuf = gst_buffer_new_and_alloc (len + padlen);
+
+ gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+ memset (map.data + len, 0, padlen);
+
+ /* prepend previous data */
+ if (avail > 0) {
+ gst_adapter_copy (rtph263pdepay->adapter, map.data, 0, avail);
+ gst_adapter_flush (rtph263pdepay->adapter, avail);
+ }
+ memcpy (map.data + avail, payload, payload_len);
+ gst_buffer_unmap (outbuf, &map);
+ gst_rtp_buffer_unmap (&rtp);
+
+ return outbuf;
+
+ } else {
+ /* frame not completed: store in adapter */
+ outbuf = gst_buffer_new_and_alloc (payload_len);
+
+ GST_LOG_OBJECT (depayload, "Frame incomplete, storing %d", payload_len);
+ gst_buffer_fill (outbuf, 0, payload, payload_len);
+
+ gst_adapter_push (rtph263pdepay->adapter, outbuf);
+ gst_rtp_buffer_unmap (&rtp);
+ }
+ return NULL;
+
+too_small:
+ {
+ GST_ELEMENT_WARNING (rtph263pdepay, STREAM, DECODE,
+ ("Packet payload was too small"), (NULL));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+waiting_start:
+ {
+ GST_DEBUG_OBJECT (rtph263pdepay, "waiting for picture start");
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+}
+
+static GstStateChangeReturn
+gst_rtp_h263p_depay_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstRtpH263PDepay *rtph263pdepay;
+ GstStateChangeReturn ret;
+
+ rtph263pdepay = GST_RTP_H263P_DEPAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_adapter_clear (rtph263pdepay->adapter);
+ rtph263pdepay->wait_start = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+gboolean
+gst_rtp_h263p_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtph263pdepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_H263P_DEPAY);
+}
diff --git a/gst/rtp/gstrtph263pdepay.h b/gst/rtp/gstrtph263pdepay.h
new file mode 100755
index 0000000..bbdb2b0
--- /dev/null
+++ b/gst/rtp/gstrtph263pdepay.h
@@ -0,0 +1,62 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_H263P_DEPAY_H__
+#define __GST_RTP_H263P_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_H263P_DEPAY \
+ (gst_rtp_h263p_depay_get_type())
+#define GST_RTP_H263P_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_H263P_DEPAY,GstRtpH263PDepay))
+#define GST_RTP_H263P_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_H263P_DEPAY,GstRtpH263PDepayClass))
+#define GST_IS_RTP_H263P_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_H263P_DEPAY))
+#define GST_IS_RTP_H263P_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_H263P_DEPAY))
+
+typedef struct _GstRtpH263PDepay GstRtpH263PDepay;
+typedef struct _GstRtpH263PDepayClass GstRtpH263PDepayClass;
+
+struct _GstRtpH263PDepay
+{
+ GstRTPBaseDepayload depayload;
+
+ GstAdapter *adapter;
+ gboolean wait_start;
+};
+
+struct _GstRtpH263PDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_h263p_depay_get_type (void);
+
+gboolean gst_rtp_h263p_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_H263P_DEPAY_H__ */
diff --git a/gst/rtp/gstrtph263ppay.c b/gst/rtp/gstrtph263ppay.c
new file mode 100755
index 0000000..54adb20
--- /dev/null
+++ b/gst/rtp/gstrtph263ppay.c
@@ -0,0 +1,777 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtph263ppay.h"
+
+#define DEFAULT_FRAGMENTATION_MODE GST_FRAGMENTATION_MODE_NORMAL
+
+enum
+{
+ PROP_0,
+ PROP_FRAGMENTATION_MODE
+};
+
+#define GST_TYPE_FRAGMENTATION_MODE (gst_fragmentation_mode_get_type())
+static GType
+gst_fragmentation_mode_get_type (void)
+{
+ static GType fragmentation_mode_type = 0;
+ static const GEnumValue fragmentation_mode[] = {
+ {GST_FRAGMENTATION_MODE_NORMAL, "Normal", "normal"},
+ {GST_FRAGMENTATION_MODE_SYNC, "Fragment at sync points", "sync"},
+ {0, NULL, NULL},
+ };
+
+ if (!fragmentation_mode_type) {
+ fragmentation_mode_type =
+ g_enum_register_static ("GstFragmentationMode", fragmentation_mode);
+ }
+ return fragmentation_mode_type;
+}
+
+
+GST_DEBUG_CATEGORY_STATIC (rtph263ppay_debug);
+#define GST_CAT_DEFAULT rtph263ppay_debug
+
+static GstStaticPadTemplate gst_rtp_h263p_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-h263, variant = (string) itu")
+ );
+
+/*
+ * We also return these in getcaps() as required by the SDP caps
+ *
+ * width = (int) [16, 4096]
+ * height = (int) [16, 4096]
+ * "annex-f = (boolean) {true, false},"
+ * "annex-i = (boolean) {true, false},"
+ * "annex-j = (boolean) {true, false},"
+ * "annex-l = (boolean) {true, false},"
+ * "annex-t = (boolean) {true, false},"
+ * "annex-v = (boolean) {true, false}")
+ */
+
+
+static GstStaticPadTemplate gst_rtp_h263p_pay_src_template =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"video\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) 90000, " "encoding-name = (string) \"H263-1998\"; "
+ "application/x-rtp, "
+ "media = (string) \"video\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) 90000, " "encoding-name = (string) \"H263-2000\"")
+ );
+
+static void gst_rtp_h263p_pay_finalize (GObject * object);
+
+static void gst_rtp_h263p_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_rtp_h263p_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static gboolean gst_rtp_h263p_pay_setcaps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+static GstCaps *gst_rtp_h263p_pay_sink_getcaps (GstRTPBasePayload * payload,
+ GstPad * pad, GstCaps * filter);
+static GstFlowReturn gst_rtp_h263p_pay_handle_buffer (GstRTPBasePayload *
+ payload, GstBuffer * buffer);
+
+#define gst_rtp_h263p_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpH263PPay, gst_rtp_h263p_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_h263p_pay_class_init (GstRtpH263PPayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_h263p_pay_finalize;
+ gobject_class->set_property = gst_rtp_h263p_pay_set_property;
+ gobject_class->get_property = gst_rtp_h263p_pay_get_property;
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_h263p_pay_setcaps;
+ gstrtpbasepayload_class->get_caps = gst_rtp_h263p_pay_sink_getcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_h263p_pay_handle_buffer;
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_FRAGMENTATION_MODE, g_param_spec_enum ("fragmentation-mode",
+ "Fragmentation Mode",
+ "Packet Fragmentation Mode", GST_TYPE_FRAGMENTATION_MODE,
+ DEFAULT_FRAGMENTATION_MODE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_h263p_pay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_h263p_pay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class, "RTP H263 payloader",
+ "Codec/Payloader/Network/RTP",
+ "Payload-encodes H263/+/++ video in RTP packets (RFC 4629)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ GST_DEBUG_CATEGORY_INIT (rtph263ppay_debug, "rtph263ppay",
+ 0, "rtph263ppay (RFC 4629)");
+}
+
+static void
+gst_rtp_h263p_pay_init (GstRtpH263PPay * rtph263ppay)
+{
+ rtph263ppay->adapter = gst_adapter_new ();
+
+ rtph263ppay->fragmentation_mode = DEFAULT_FRAGMENTATION_MODE;
+}
+
+static void
+gst_rtp_h263p_pay_finalize (GObject * object)
+{
+ GstRtpH263PPay *rtph263ppay;
+
+ rtph263ppay = GST_RTP_H263P_PAY (object);
+
+ g_object_unref (rtph263ppay->adapter);
+ rtph263ppay->adapter = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rtp_h263p_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ gboolean res;
+ GstCaps *peercaps;
+ gchar *encoding_name = NULL;
+
+ g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
+
+ peercaps =
+ gst_pad_peer_query_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload), NULL);
+ if (peercaps) {
+ GstCaps *tcaps =
+ gst_pad_get_pad_template_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload));
+ GstCaps *intersect = gst_caps_intersect (peercaps, tcaps);
+ gst_caps_unref (tcaps);
+
+ gst_caps_unref (peercaps);
+ if (!gst_caps_is_empty (intersect)) {
+ GstStructure *s = gst_caps_get_structure (intersect, 0);
+ encoding_name = g_strdup (gst_structure_get_string (s, "encoding-name"));
+ }
+ gst_caps_unref (intersect);
+ }
+
+ if (!encoding_name)
+ encoding_name = g_strdup ("H263-1998");
+
+ gst_rtp_base_payload_set_options (payload, "video", TRUE,
+ (gchar *) encoding_name, 90000);
+ res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+ g_free (encoding_name);
+
+ return res;
+}
+
+static GstCaps *
+caps_append (GstCaps * caps, GstStructure * in_s, guint x, guint y, guint mpi)
+{
+ GstStructure *s;
+
+ if (!in_s)
+ return caps;
+
+ if (mpi < 1 || mpi > 32)
+ return caps;
+
+ s = gst_structure_copy (in_s);
+
+ gst_structure_set (s,
+ "width", GST_TYPE_INT_RANGE, 1, x,
+ "height", GST_TYPE_INT_RANGE, 1, y,
+ "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 1001 * mpi, NULL);
+
+ caps = gst_caps_merge_structure (caps, s);
+
+ return caps;
+}
+
+
+static GstCaps *
+gst_rtp_h263p_pay_sink_getcaps (GstRTPBasePayload * payload, GstPad * pad,
+ GstCaps * filter)
+{
+ GstRtpH263PPay *rtph263ppay;
+ GstCaps *caps = NULL, *templ;
+ GstCaps *peercaps = NULL;
+ GstCaps *intersect = NULL;
+ guint i;
+
+ rtph263ppay = GST_RTP_H263P_PAY (payload);
+
+ peercaps =
+ gst_pad_peer_query_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload), NULL);
+
+ /* if we're just outputting to udpsink or fakesink or so, we should also
+ * accept any input compatible with our sink template caps */
+ if (!peercaps || gst_caps_is_any (peercaps)) {
+ if (peercaps)
+ gst_caps_unref (peercaps);
+ return
+ gst_pad_get_pad_template_caps (GST_RTP_BASE_PAYLOAD_SINKPAD (payload));
+ }
+
+ /* We basically need to differentiate two use-cases here: One where there's
+ * a capsfilter after the payloader with caps created from an SDP; in this
+ * case the filter caps are fixed and we want to signal to an encoder what
+ * we want it to produce. The second case is simply payloader ! depayloader
+ * where we are dealing with the depayloader's template caps. In this case
+ * we should accept any input compatible with our sink template caps. */
+ if (!gst_caps_is_fixed (peercaps))
+ return
+ gst_pad_get_pad_template_caps (GST_RTP_BASE_PAYLOAD_SINKPAD (payload));
+
+ templ = gst_pad_get_pad_template_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload));
+ intersect = gst_caps_intersect (peercaps, templ);
+ gst_caps_unref (peercaps);
+ gst_caps_unref (templ);
+
+ if (gst_caps_is_empty (intersect))
+ return intersect;
+
+ caps = gst_caps_new_empty ();
+ for (i = 0; i < gst_caps_get_size (intersect); i++) {
+ GstStructure *s = gst_caps_get_structure (intersect, i);
+ const gchar *encoding_name = gst_structure_get_string (s, "encoding-name");
+
+ if (!strcmp (encoding_name, "H263-2000")) {
+ const gchar *profile_str = gst_structure_get_string (s, "profile");
+ const gchar *level_str = gst_structure_get_string (s, "level");
+ int profile = 0;
+ int level = 0;
+
+ if (profile_str && level_str) {
+ gboolean i = FALSE, j = FALSE, l = FALSE, t = FALSE, f = FALSE,
+ v = FALSE;
+ GstStructure *new_s = gst_structure_new ("video/x-h263",
+ "variant", G_TYPE_STRING, "itu",
+ NULL);
+
+ profile = atoi (profile_str);
+ level = atoi (level_str);
+
+ /* These profiles are defined in the H.263 Annex X */
+ switch (profile) {
+ case 0:
+ /* The Baseline Profile (Profile 0) */
+ break;
+ case 1:
+ /* H.320 Coding Efficiency Version 2 Backward-Compatibility Profile
+ * (Profile 1)
+ * Baseline + Annexes I, J, L.4 and T
+ */
+ i = j = l = t = TRUE;
+ break;
+ case 2:
+ /* Version 1 Backward-Compatibility Profile (Profile 2)
+ * Baseline + Annex F
+ */
+ i = j = l = t = f = TRUE;
+ break;
+ case 3:
+ /* Version 2 Interactive and Streaming Wireless Profile
+ * Baseline + Annexes I, J, T
+ */
+ i = j = t = TRUE;
+ break;
+ case 4:
+ /* Version 3 Interactive and Streaming Wireless Profile (Profile 4)
+ * Baseline + Annexes I, J, T, V, W.6.3.8,
+ */
+ /* Missing W.6.3.8 */
+ i = j = t = v = TRUE;
+ break;
+ case 5:
+ /* Conversational High Compression Profile (Profile 5)
+ * Baseline + Annexes F, I, J, L.4, T, D, U
+ */
+ /* Missing D, U */
+ f = i = j = l = t = TRUE;
+ break;
+ case 6:
+ /* Conversational Internet Profile (Profile 6)
+ * Baseline + Annexes F, I, J, L.4, T, D, U and
+ * K with arbitratry slice ordering
+ */
+ /* Missing D, U, K with arbitratry slice ordering */
+ f = i = j = l = t = TRUE;
+ break;
+ case 7:
+ /* Conversational Interlace Profile (Profile 7)
+ * Baseline + Annexes F, I, J, L.4, T, D, U, W.6.3.11
+ */
+ /* Missing D, U, W.6.3.11 */
+ f = i = j = l = t = TRUE;
+ break;
+ case 8:
+ /* High Latency Profile (Profile 8)
+ * Baseline + Annexes F, I, J, L.4, T, D, U, P.5, O.1.1 and
+ * K with arbitratry slice ordering
+ */
+ /* Missing D, U, P.5, O.1.1 */
+ f = i = j = l = t = TRUE;
+ break;
+ }
+
+
+ if (f || i || j || t || l || v) {
+ GValue list = { 0 };
+ GValue vstr = { 0 };
+
+ g_value_init (&list, GST_TYPE_LIST);
+ g_value_init (&vstr, G_TYPE_STRING);
+
+ g_value_set_static_string (&vstr, "h263");
+ gst_value_list_append_value (&list, &vstr);
+ g_value_set_static_string (&vstr, "h263p");
+ gst_value_list_append_value (&list, &vstr);
+
+ if (l || v) {
+ g_value_set_static_string (&vstr, "h263pp");
+ gst_value_list_append_value (&list, &vstr);
+ }
+ g_value_unset (&vstr);
+
+ gst_structure_set_value (new_s, "h263version", &list);
+ g_value_unset (&list);
+ } else {
+ gst_structure_set (new_s, "h263version", G_TYPE_STRING, "h263", NULL);
+ }
+
+
+ if (!f)
+ gst_structure_set (new_s, "annex-f", G_TYPE_BOOLEAN, FALSE, NULL);
+ if (!i)
+ gst_structure_set (new_s, "annex-i", G_TYPE_BOOLEAN, FALSE, NULL);
+ if (!j)
+ gst_structure_set (new_s, "annex-j", G_TYPE_BOOLEAN, FALSE, NULL);
+ if (!t)
+ gst_structure_set (new_s, "annex-t", G_TYPE_BOOLEAN, FALSE, NULL);
+ if (!l)
+ gst_structure_set (new_s, "annex-l", G_TYPE_BOOLEAN, FALSE, NULL);
+ if (!v)
+ gst_structure_set (new_s, "annex-v", G_TYPE_BOOLEAN, FALSE, NULL);
+
+
+ if (level <= 10 || level == 45) {
+ gst_structure_set (new_s,
+ "width", GST_TYPE_INT_RANGE, 1, 176,
+ "height", GST_TYPE_INT_RANGE, 1, 144,
+ "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 2002, NULL);
+ caps = gst_caps_merge_structure (caps, new_s);
+ } else if (level <= 20) {
+ GstStructure *s_copy = gst_structure_copy (new_s);
+
+ gst_structure_set (new_s,
+ "width", GST_TYPE_INT_RANGE, 1, 352,
+ "height", GST_TYPE_INT_RANGE, 1, 288,
+ "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 2002, NULL);
+ caps = gst_caps_merge_structure (caps, new_s);
+
+ gst_structure_set (s_copy,
+ "width", GST_TYPE_INT_RANGE, 1, 176,
+ "height", GST_TYPE_INT_RANGE, 1, 144,
+ "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 1001, NULL);
+ caps = gst_caps_merge_structure (caps, s_copy);
+ } else if (level <= 40) {
+
+ gst_structure_set (new_s,
+ "width", GST_TYPE_INT_RANGE, 1, 352,
+ "height", GST_TYPE_INT_RANGE, 1, 288,
+ "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 1001, NULL);
+ caps = gst_caps_merge_structure (caps, new_s);
+ } else if (level <= 50) {
+ GstStructure *s_copy = gst_structure_copy (new_s);
+
+ gst_structure_set (new_s,
+ "width", GST_TYPE_INT_RANGE, 1, 352,
+ "height", GST_TYPE_INT_RANGE, 1, 288,
+ "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 50, 1, NULL);
+ caps = gst_caps_merge_structure (caps, new_s);
+
+ gst_structure_set (s_copy,
+ "width", GST_TYPE_INT_RANGE, 1, 352,
+ "height", GST_TYPE_INT_RANGE, 1, 240,
+ "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 60000, 1001, NULL);
+ caps = gst_caps_merge_structure (caps, s_copy);
+ } else if (level <= 60) {
+ GstStructure *s_copy = gst_structure_copy (new_s);
+
+ gst_structure_set (new_s,
+ "width", GST_TYPE_INT_RANGE, 1, 720,
+ "height", GST_TYPE_INT_RANGE, 1, 288,
+ "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 50, 1, NULL);
+ caps = gst_caps_merge_structure (caps, new_s);
+
+ gst_structure_set (s_copy,
+ "width", GST_TYPE_INT_RANGE, 1, 720,
+ "height", GST_TYPE_INT_RANGE, 1, 240,
+ "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 60000, 1001, NULL);
+ caps = gst_caps_merge_structure (caps, s_copy);
+ } else if (level <= 70) {
+ GstStructure *s_copy = gst_structure_copy (new_s);
+
+ gst_structure_set (new_s,
+ "width", GST_TYPE_INT_RANGE, 1, 720,
+ "height", GST_TYPE_INT_RANGE, 1, 576,
+ "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 50, 1, NULL);
+ caps = gst_caps_merge_structure (caps, new_s);
+
+ gst_structure_set (s_copy,
+ "width", GST_TYPE_INT_RANGE, 1, 720,
+ "height", GST_TYPE_INT_RANGE, 1, 480,
+ "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 60000, 1001, NULL);
+ caps = gst_caps_merge_structure (caps, s_copy);
+ } else {
+ caps = gst_caps_merge_structure (caps, new_s);
+ }
+
+ } else {
+ GstStructure *new_s = gst_structure_new ("video/x-h263",
+ "variant", G_TYPE_STRING, "itu",
+ "h263version", G_TYPE_STRING, "h263",
+ NULL);
+
+ GST_DEBUG_OBJECT (rtph263ppay, "No profile or level specified"
+ " for H263-2000, defaulting to baseline H263");
+
+ caps = gst_caps_merge_structure (caps, new_s);
+ }
+ } else {
+ gboolean f = FALSE, i = FALSE, j = FALSE, t = FALSE;
+ /* FIXME: ffmpeg support the Appendix K too, how do we express it ?
+ * guint k;
+ */
+ const gchar *str;
+ GstStructure *new_s = gst_structure_new ("video/x-h263",
+ "variant", G_TYPE_STRING, "itu",
+ NULL);
+ gboolean added = FALSE;
+
+ str = gst_structure_get_string (s, "f");
+ if (str && !strcmp (str, "1"))
+ f = TRUE;
+
+ str = gst_structure_get_string (s, "i");
+ if (str && !strcmp (str, "1"))
+ i = TRUE;
+
+ str = gst_structure_get_string (s, "j");
+ if (str && !strcmp (str, "1"))
+ j = TRUE;
+
+ str = gst_structure_get_string (s, "t");
+ if (str && !strcmp (str, "1"))
+ t = TRUE;
+
+ if (f || i || j || t) {
+ GValue list = { 0 };
+ GValue vstr = { 0 };
+
+ g_value_init (&list, GST_TYPE_LIST);
+ g_value_init (&vstr, G_TYPE_STRING);
+
+ g_value_set_static_string (&vstr, "h263");
+ gst_value_list_append_value (&list, &vstr);
+ g_value_set_static_string (&vstr, "h263p");
+ gst_value_list_append_value (&list, &vstr);
+ g_value_unset (&vstr);
+
+ gst_structure_set_value (new_s, "h263version", &list);
+ g_value_unset (&list);
+ } else {
+ gst_structure_set (new_s, "h263version", G_TYPE_STRING, "h263", NULL);
+ }
+
+ if (!f)
+ gst_structure_set (new_s, "annex-f", G_TYPE_BOOLEAN, FALSE, NULL);
+ if (!i)
+ gst_structure_set (new_s, "annex-i", G_TYPE_BOOLEAN, FALSE, NULL);
+ if (!j)
+ gst_structure_set (new_s, "annex-j", G_TYPE_BOOLEAN, FALSE, NULL);
+ if (!t)
+ gst_structure_set (new_s, "annex-t", G_TYPE_BOOLEAN, FALSE, NULL);
+
+
+ str = gst_structure_get_string (s, "custom");
+ if (str) {
+ unsigned int xmax, ymax, mpi;
+ if (sscanf (str, "%u,%u,%u", &xmax, &ymax, &mpi) == 3) {
+ if (xmax % 4 && ymax % 4 && mpi >= 1 && mpi <= 32) {
+ caps = caps_append (caps, new_s, xmax, ymax, mpi);
+ added = TRUE;
+ } else {
+ GST_WARNING_OBJECT (rtph263ppay, "Invalid custom framesize/MPI"
+ " %u x %u at %u, ignoring", xmax, ymax, mpi);
+ }
+ } else {
+ GST_WARNING_OBJECT (rtph263ppay, "Invalid custom framesize/MPI: %s,"
+ " ignoring", str);
+ }
+ }
+
+ str = gst_structure_get_string (s, "16cif");
+ if (str) {
+ int mpi = atoi (str);
+ caps = caps_append (caps, new_s, 1408, 1152, mpi);
+ added = TRUE;
+ }
+
+ str = gst_structure_get_string (s, "4cif");
+ if (str) {
+ int mpi = atoi (str);
+ caps = caps_append (caps, new_s, 704, 576, mpi);
+ added = TRUE;
+ }
+
+ str = gst_structure_get_string (s, "cif");
+ if (str) {
+ int mpi = atoi (str);
+ caps = caps_append (caps, new_s, 352, 288, mpi);
+ added = TRUE;
+ }
+
+ str = gst_structure_get_string (s, "qcif");
+ if (str) {
+ int mpi = atoi (str);
+ caps = caps_append (caps, new_s, 176, 144, mpi);
+ added = TRUE;
+ }
+
+ str = gst_structure_get_string (s, "sqcif");
+ if (str) {
+ int mpi = atoi (str);
+ caps = caps_append (caps, new_s, 128, 96, mpi);
+ added = TRUE;
+ }
+
+ if (added)
+ gst_structure_free (new_s);
+ else
+ caps = gst_caps_merge_structure (caps, new_s);
+ }
+ }
+
+ gst_caps_unref (intersect);
+
+ return caps;
+}
+
+
+static void
+gst_rtp_h263p_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstRtpH263PPay *rtph263ppay;
+
+ rtph263ppay = GST_RTP_H263P_PAY (object);
+
+ switch (prop_id) {
+ case PROP_FRAGMENTATION_MODE:
+ rtph263ppay->fragmentation_mode = g_value_get_enum (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_rtp_h263p_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstRtpH263PPay *rtph263ppay;
+
+ rtph263ppay = GST_RTP_H263P_PAY (object);
+
+ switch (prop_id) {
+ case PROP_FRAGMENTATION_MODE:
+ g_value_set_enum (value, rtph263ppay->fragmentation_mode);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GstFlowReturn
+gst_rtp_h263p_pay_flush (GstRtpH263PPay * rtph263ppay)
+{
+ guint avail;
+ GstBuffer *outbuf;
+ GstFlowReturn ret;
+ gboolean fragmented;
+
+ avail = gst_adapter_available (rtph263ppay->adapter);
+ if (avail == 0)
+ return GST_FLOW_OK;
+
+ fragmented = FALSE;
+ /* This algorithm assumes the H263/+/++ encoder sends complete frames in each
+ * buffer */
+ /* With Fragmentation Mode at GST_FRAGMENTATION_MODE_NORMAL:
+ * This algorithm implements the Follow-on packets method for packetization.
+ * This assumes low packet loss network.
+ * With Fragmentation Mode at GST_FRAGMENTATION_MODE_SYNC:
+ * This algorithm separates large frames at synchronisation points (Segments)
+ * (See RFC 4629 section 6). It would be interesting to have a property such as network
+ * quality to select between both packetization methods */
+ /* TODO Add VRC supprt (See RFC 4629 section 5.2) */
+
+ while (avail > 0) {
+ guint towrite;
+ guint8 *payload;
+ guint payload_len;
+ gint header_len;
+ guint next_gop = 0;
+ gboolean found_gob = FALSE;
+ GstRTPBuffer rtp = { NULL };
+
+ if (rtph263ppay->fragmentation_mode == GST_FRAGMENTATION_MODE_SYNC) {
+ /* start after 1st gop possible */
+ guint parsed_len = 3;
+ const guint8 *parse_data = NULL;
+
+ parse_data = gst_adapter_map (rtph263ppay->adapter, avail);
+
+ /* Check if we have a gob or eos , eossbs */
+ /* FIXME EOS and EOSSBS packets should never contain any gobs and vice-versa */
+ if (avail >= 3 && *parse_data == 0 && *(parse_data + 1) == 0
+ && *(parse_data + 2) >= 0x80) {
+ GST_DEBUG_OBJECT (rtph263ppay, " Found GOB header");
+ found_gob = TRUE;
+ }
+ /* Find next and cut the packet accordingly */
+ /* TODO we should get as many gobs as possible until MTU is reached, this
+ * code seems to just get one GOB per packet */
+ while (parsed_len + 2 < avail) {
+ if (parse_data[parsed_len] == 0 && parse_data[parsed_len + 1] == 0
+ && parse_data[parsed_len + 2] >= 0x80) {
+ next_gop = parsed_len;
+ GST_DEBUG_OBJECT (rtph263ppay, " Next GOB Detected at : %d",
+ next_gop);
+ break;
+ }
+ parsed_len++;
+ }
+ gst_adapter_unmap (rtph263ppay->adapter);
+ }
+
+ /* for picture start frames (non-fragmented), we need to remove the first
+ * two 0x00 bytes and set P=1 */
+ header_len = (fragmented && !found_gob) ? 2 : 0;
+
+ towrite = MIN (avail, gst_rtp_buffer_calc_payload_len
+ (GST_RTP_BASE_PAYLOAD_MTU (rtph263ppay) - header_len, 0, 0));
+
+ if (next_gop > 0)
+ towrite = MIN (next_gop, towrite);
+
+ payload_len = header_len + towrite;
+
+ outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
+
+ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+ /* last fragment gets the marker bit set */
+ gst_rtp_buffer_set_marker (&rtp, avail > towrite ? 0 : 1);
+
+ payload = gst_rtp_buffer_get_payload (&rtp);
+
+ gst_adapter_copy (rtph263ppay->adapter, &payload[header_len], 0, towrite);
+
+ /* 0 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | RR |P|V| PLEN |PEBIT|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ /* if fragmented or gop header , write p bit =1 */
+ payload[0] = (fragmented && !found_gob) ? 0x00 : 0x04;
+ payload[1] = 0;
+
+ GST_BUFFER_TIMESTAMP (outbuf) = rtph263ppay->first_timestamp;
+ GST_BUFFER_DURATION (outbuf) = rtph263ppay->first_duration;
+ gst_rtp_buffer_unmap (&rtp);
+
+ gst_adapter_flush (rtph263ppay->adapter, towrite);
+
+ ret =
+ gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtph263ppay), outbuf);
+
+ avail -= towrite;
+ fragmented = TRUE;
+ }
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_rtp_h263p_pay_handle_buffer (GstRTPBasePayload * payload,
+ GstBuffer * buffer)
+{
+ GstRtpH263PPay *rtph263ppay;
+ GstFlowReturn ret;
+
+ rtph263ppay = GST_RTP_H263P_PAY (payload);
+
+ rtph263ppay->first_timestamp = GST_BUFFER_TIMESTAMP (buffer);
+ rtph263ppay->first_duration = GST_BUFFER_DURATION (buffer);
+
+ /* we always encode and flush a full picture */
+ gst_adapter_push (rtph263ppay->adapter, buffer);
+ ret = gst_rtp_h263p_pay_flush (rtph263ppay);
+
+ return ret;
+}
+
+gboolean
+gst_rtp_h263p_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtph263ppay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_H263P_PAY);
+}
diff --git a/gst/rtp/gstrtph263ppay.h b/gst/rtp/gstrtph263ppay.h
new file mode 100755
index 0000000..23ec8b8
--- /dev/null
+++ b/gst/rtp/gstrtph263ppay.h
@@ -0,0 +1,70 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_H263P_PAY_H__
+#define __GST_RTP_H263P_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_H263P_PAY \
+ (gst_rtp_h263p_pay_get_type())
+#define GST_RTP_H263P_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_H263P_PAY,GstRtpH263PPay))
+#define GST_RTP_H263P_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_H263P_PAY,GstRtpH263PPayClass))
+#define GST_IS_RTP_H263P_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_H263P_PAY))
+#define GST_IS_RTP_H263P_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_H263P_PAY))
+
+typedef struct _GstRtpH263PPay GstRtpH263PPay;
+typedef struct _GstRtpH263PPayClass GstRtpH263PPayClass;
+
+typedef enum
+{
+ GST_FRAGMENTATION_MODE_NORMAL = 0,
+ GST_FRAGMENTATION_MODE_SYNC = 1
+} GstFragmentationMode;
+
+struct _GstRtpH263PPay
+{
+ GstRTPBasePayload payload;
+
+ GstAdapter *adapter;
+ GstClockTime first_timestamp;
+ GstClockTime first_duration;
+ GstFragmentationMode fragmentation_mode;
+};
+
+struct _GstRtpH263PPayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_h263p_pay_get_type (void);
+
+gboolean gst_rtp_h263p_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_H263P_PAY_H__ */
diff --git a/gst/rtp/gstrtph264depay.c b/gst/rtp/gstrtph264depay.c
new file mode 100755
index 0000000..56b6410
--- /dev/null
+++ b/gst/rtp/gstrtph264depay.c
@@ -0,0 +1,1174 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <gst/base/gstbitreader.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include "gstrtph264depay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtph264depay_debug);
+#define GST_CAT_DEFAULT (rtph264depay_debug)
+
+/* This is what we'll default to when downstream hasn't
+ * expressed a restriction or preference via caps */
+#define DEFAULT_BYTE_STREAM TRUE
+#define DEFAULT_ACCESS_UNIT FALSE
+
+/* 3 zero bytes syncword */
+static const guint8 sync_bytes[] = { 0, 0, 0, 1 };
+
+static GstStaticPadTemplate gst_rtp_h264_depay_src_template =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-h264, "
+ "stream-format = (string) avc, alignment = (string) au; "
+ "video/x-h264, "
+ "stream-format = (string) byte-stream, alignment = (string) { nal, au }")
+ );
+
+static GstStaticPadTemplate gst_rtp_h264_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"video\", "
+ "clock-rate = (int) 90000, " "encoding-name = (string) \"H264\"")
+ /** optional parameters **/
+ /* "profile-level-id = (string) ANY, " */
+ /* "max-mbps = (string) ANY, " */
+ /* "max-fs = (string) ANY, " */
+ /* "max-cpb = (string) ANY, " */
+ /* "max-dpb = (string) ANY, " */
+ /* "max-br = (string) ANY, " */
+ /* "redundant-pic-cap = (string) { \"0\", \"1\" }, " */
+ /* "sprop-parameter-sets = (string) ANY, " */
+ /* "parameter-add = (string) { \"0\", \"1\" }, " */
+ /* "packetization-mode = (string) { \"0\", \"1\", \"2\" }, " */
+ /* "sprop-interleaving-depth = (string) ANY, " */
+ /* "sprop-deint-buf-req = (string) ANY, " */
+ /* "deint-buf-cap = (string) ANY, " */
+ /* "sprop-init-buf-time = (string) ANY, " */
+ /* "sprop-max-don-diff = (string) ANY, " */
+ /* "max-rcmd-nalu-size = (string) ANY " */
+ );
+
+#define gst_rtp_h264_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpH264Depay, gst_rtp_h264_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_h264_depay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_h264_depay_change_state (GstElement *
+ element, GstStateChange transition);
+
+static GstBuffer *gst_rtp_h264_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+static gboolean gst_rtp_h264_depay_setcaps (GstRTPBaseDepayload * filter,
+ GstCaps * caps);
+static gboolean gst_rtp_h264_depay_handle_event (GstRTPBaseDepayload * depay,
+ GstEvent * event);
+
+static void
+gst_rtp_h264_depay_class_init (GstRtpH264DepayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_h264_depay_finalize;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_h264_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_h264_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP H264 depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts H264 video from RTP packets (RFC 3984)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+ gstelement_class->change_state = gst_rtp_h264_depay_change_state;
+
+ gstrtpbasedepayload_class->process = gst_rtp_h264_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_h264_depay_setcaps;
+ gstrtpbasedepayload_class->handle_event = gst_rtp_h264_depay_handle_event;
+}
+
+static void
+gst_rtp_h264_depay_init (GstRtpH264Depay * rtph264depay)
+{
+ rtph264depay->adapter = gst_adapter_new ();
+ rtph264depay->picture_adapter = gst_adapter_new ();
+ rtph264depay->byte_stream = DEFAULT_BYTE_STREAM;
+ rtph264depay->merge = DEFAULT_ACCESS_UNIT;
+ rtph264depay->sps = g_ptr_array_new_with_free_func (
+ (GDestroyNotify) gst_buffer_unref);
+ rtph264depay->pps = g_ptr_array_new_with_free_func (
+ (GDestroyNotify) gst_buffer_unref);
+}
+
+static void
+gst_rtp_h264_depay_reset (GstRtpH264Depay * rtph264depay)
+{
+ gst_adapter_clear (rtph264depay->adapter);
+ rtph264depay->wait_start = TRUE;
+ gst_adapter_clear (rtph264depay->picture_adapter);
+ rtph264depay->picture_start = FALSE;
+ rtph264depay->last_keyframe = FALSE;
+ rtph264depay->last_ts = 0;
+ rtph264depay->current_fu_type = 0;
+ rtph264depay->new_codec_data = FALSE;
+ g_ptr_array_set_size (rtph264depay->sps, 0);
+ g_ptr_array_set_size (rtph264depay->pps, 0);
+}
+
+static void
+gst_rtp_h264_depay_finalize (GObject * object)
+{
+ GstRtpH264Depay *rtph264depay;
+
+ rtph264depay = GST_RTP_H264_DEPAY (object);
+
+ if (rtph264depay->codec_data)
+ gst_buffer_unref (rtph264depay->codec_data);
+
+ g_object_unref (rtph264depay->adapter);
+ g_object_unref (rtph264depay->picture_adapter);
+
+ g_ptr_array_free (rtph264depay->sps, TRUE);
+ g_ptr_array_free (rtph264depay->pps, TRUE);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_rtp_h264_depay_negotiate (GstRtpH264Depay * rtph264depay)
+{
+ GstCaps *caps;
+ gint byte_stream = -1;
+ gint merge = -1;
+
+ caps =
+ gst_pad_get_allowed_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (rtph264depay));
+
+ GST_DEBUG_OBJECT (rtph264depay, "allowed caps: %" GST_PTR_FORMAT, caps);
+
+ if (caps) {
+ if (gst_caps_get_size (caps) > 0) {
+ GstStructure *s = gst_caps_get_structure (caps, 0);
+ const gchar *str = NULL;
+
+ if ((str = gst_structure_get_string (s, "stream-format"))) {
+ if (strcmp (str, "avc") == 0) {
+ byte_stream = FALSE;
+ } else if (strcmp (str, "byte-stream") == 0) {
+ byte_stream = TRUE;
+ } else {
+ GST_DEBUG_OBJECT (rtph264depay, "unknown stream-format: %s", str);
+ }
+ }
+
+ if ((str = gst_structure_get_string (s, "alignment"))) {
+ if (strcmp (str, "au") == 0) {
+ merge = TRUE;
+ } else if (strcmp (str, "nal") == 0) {
+ merge = FALSE;
+ } else {
+ GST_DEBUG_OBJECT (rtph264depay, "unknown alignment: %s", str);
+ }
+ }
+ }
+ gst_caps_unref (caps);
+ }
+
+ if (byte_stream != -1) {
+ GST_DEBUG_OBJECT (rtph264depay, "downstream requires byte-stream %d",
+ byte_stream);
+ rtph264depay->byte_stream = byte_stream;
+ } else {
+ GST_DEBUG_OBJECT (rtph264depay, "defaulting to byte-stream %d",
+ DEFAULT_BYTE_STREAM);
+ rtph264depay->byte_stream = DEFAULT_BYTE_STREAM;
+ }
+ if (merge != -1) {
+ GST_DEBUG_OBJECT (rtph264depay, "downstream requires merge %d", merge);
+ rtph264depay->merge = merge;
+ } else {
+ GST_DEBUG_OBJECT (rtph264depay, "defaulting to merge %d",
+ DEFAULT_ACCESS_UNIT);
+ rtph264depay->merge = DEFAULT_ACCESS_UNIT;
+ }
+}
+
+/* Stolen from bad/gst/mpegtsdemux/payloader_parsers.c */
+/* variable length Exp-Golomb parsing according to H.264 spec 9.1*/
+static gboolean
+read_golomb (GstBitReader * br, guint32 * value)
+{
+ guint8 b, leading_zeros = -1;
+ *value = 1;
+
+ for (b = 0; !b; leading_zeros++) {
+ if (!gst_bit_reader_get_bits_uint8 (br, &b, 1))
+ return FALSE;
+ *value *= 2;
+ }
+
+ *value = (*value >> 1) - 1;
+ if (leading_zeros > 0) {
+ guint32 tmp = 0;
+ if (!gst_bit_reader_get_bits_uint32 (br, &tmp, leading_zeros))
+ return FALSE;
+ *value += tmp;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+parse_sps (GstMapInfo * map, guint32 * sps_id)
+{
+ GstBitReader br = GST_BIT_READER_INIT (map->data + 4,
+ map->size - 4);
+
+ if (map->size < 5)
+ return FALSE;
+
+ if (!read_golomb (&br, sps_id))
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+parse_pps (GstMapInfo * map, guint32 * sps_id, guint32 * pps_id)
+{
+ GstBitReader br = GST_BIT_READER_INIT (map->data + 1,
+ map->size - 1);
+
+ if (map->size < 2)
+ return FALSE;
+
+ if (!read_golomb (&br, pps_id))
+ return FALSE;
+ if (!read_golomb (&br, sps_id))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static gboolean
+gst_rtp_h264_set_src_caps (GstRtpH264Depay * rtph264depay)
+{
+ gboolean res;
+ GstCaps *srccaps;
+ guchar level = 0;
+ guchar profile_compat = G_MAXUINT8;
+
+ if (!rtph264depay->byte_stream &&
+ (!rtph264depay->new_codec_data ||
+ rtph264depay->sps->len == 0 || rtph264depay->pps->len == 0))
+ return TRUE;
+
+ srccaps = gst_caps_new_simple ("video/x-h264",
+ "stream-format", G_TYPE_STRING,
+ rtph264depay->byte_stream ? "byte-stream" : "avc",
+ "alignment", G_TYPE_STRING, rtph264depay->merge ? "au" : "nal", NULL);
+
+ if (!rtph264depay->byte_stream) {
+ GstBuffer *codec_data;
+ GstMapInfo map;
+ GstMapInfo nalmap;
+ guint8 *data;
+ guint len;
+ guint new_size;
+ guint i;
+
+ /* start with 7 bytes header */
+ len = 7;
+ /* count sps & pps */
+ for (i = 0; i < rtph264depay->sps->len; i++)
+ len += 2 + gst_buffer_get_size (g_ptr_array_index (rtph264depay->sps, i));
+ for (i = 0; i < rtph264depay->pps->len; i++)
+ len += 2 + gst_buffer_get_size (g_ptr_array_index (rtph264depay->pps, i));
+
+ codec_data = gst_buffer_new_and_alloc (len);
+ g_debug ("alloc_len: %u", len);
+ gst_buffer_map (codec_data, &map, GST_MAP_READWRITE);
+ data = map.data;
+
+ /* 8 bits version == 1 */
+ *data++ = 1;
+
+ /* According to: ISO/IEC 14496-15:2004(E) section 5.2.4.1
+ * The level is the max level of all SPSes
+ * A profile compat bit can only be set if all SPSes include that bit
+ */
+ for (i = 0; i < rtph264depay->sps->len; i++) {
+ gst_buffer_map (g_ptr_array_index (rtph264depay->sps, i), &nalmap,
+ GST_MAP_READ);
+ profile_compat &= nalmap.data[2];
+ level = MAX (level, nalmap.data[3]);
+ gst_buffer_unmap (g_ptr_array_index (rtph264depay->sps, i), &nalmap);
+ }
+
+ /* Assume all SPSes use the same profile, so extract from the first SPS */
+ gst_buffer_map (g_ptr_array_index (rtph264depay->sps, 0), &nalmap,
+ GST_MAP_READ);
+ *data++ = nalmap.data[1];
+ gst_buffer_unmap (g_ptr_array_index (rtph264depay->sps, 0), &nalmap);
+ *data++ = profile_compat;
+ *data++ = level;
+
+ /* 6 bits reserved | 2 bits lengthSizeMinusOn */
+ *data++ = 0xff;
+ /* 3 bits reserved | 5 bits numOfSequenceParameterSets */
+ *data++ = 0xe0 | (rtph264depay->sps->len & 0x1f);
+
+ /* copy all SPS */
+ for (i = 0; i < rtph264depay->sps->len; i++) {
+ gst_buffer_map (g_ptr_array_index (rtph264depay->sps, i), &nalmap,
+ GST_MAP_READ);
+
+ GST_DEBUG_OBJECT (rtph264depay, "copy SPS %d of length %u", i,
+ (guint) nalmap.size);
+ GST_WRITE_UINT16_BE (data, nalmap.size);
+ data += 2;
+ memcpy (data, nalmap.data, nalmap.size);
+ data += nalmap.size;
+ gst_buffer_unmap (g_ptr_array_index (rtph264depay->sps, i), &nalmap);
+ }
+
+ /* 8 bits numOfPictureParameterSets */
+ *data++ = rtph264depay->pps->len;
+ /* copy all PPS */
+ for (i = 0; i < rtph264depay->pps->len; i++) {
+ gst_buffer_map (g_ptr_array_index (rtph264depay->pps, i), &nalmap,
+ GST_MAP_READ);
+
+ GST_DEBUG_OBJECT (rtph264depay, "copy PPS %d of length %u", i,
+ (guint) nalmap.size);
+ GST_WRITE_UINT16_BE (data, nalmap.size);
+ data += 2;
+ memcpy (data, nalmap.data, nalmap.size);
+ data += nalmap.size;
+ gst_buffer_unmap (g_ptr_array_index (rtph264depay->pps, i), &nalmap);
+ }
+
+ new_size = data - map.data;
+ gst_buffer_unmap (codec_data, &map);
+ gst_buffer_set_size (codec_data, new_size);
+
+
+ gst_caps_set_simple (srccaps,
+ "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
+ gst_buffer_unref (codec_data);
+ }
+
+ res = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (rtph264depay),
+ srccaps);
+ gst_caps_unref (srccaps);
+
+ if (res)
+ rtph264depay->new_codec_data = FALSE;
+
+ return res;
+}
+
+gboolean
+gst_rtp_h264_add_sps_pps (GstElement * rtph264, GPtrArray * sps_array,
+ GPtrArray * pps_array, GstBuffer * nal)
+{
+ GstMapInfo map;
+ guchar type;
+ guint i;
+
+ gst_buffer_map (nal, &map, GST_MAP_READ);
+
+ type = map.data[0] & 0x1f;
+
+ if (type == 7) {
+ guint32 sps_id;
+
+ if (!parse_sps (&map, &sps_id)) {
+ GST_WARNING_OBJECT (rtph264, "Invalid SPS,"
+ " can't parse seq_parameter_set_id");
+ goto drop;
+ }
+
+ for (i = 0; i < sps_array->len; i++) {
+ GstBuffer *sps = g_ptr_array_index (sps_array, i);
+ GstMapInfo spsmap;
+ guint32 tmp_sps_id;
+
+ gst_buffer_map (sps, &spsmap, GST_MAP_READ);
+ parse_sps (&spsmap, &tmp_sps_id);
+
+ if (sps_id == tmp_sps_id) {
+ if (map.size == spsmap.size &&
+ memcmp (map.data, spsmap.data, spsmap.size) == 0) {
+ GST_LOG_OBJECT (rtph264, "Unchanged SPS %u, not updating", sps_id);
+ gst_buffer_unmap (sps, &spsmap);
+ goto drop;
+ } else {
+ gst_buffer_unmap (sps, &spsmap);
+ g_ptr_array_remove_index_fast (sps_array, i);
+ g_ptr_array_add (sps_array, nal);
+ GST_LOG_OBJECT (rtph264, "Modified SPS %u, replacing", sps_id);
+ goto done;
+ }
+ }
+ gst_buffer_unmap (sps, &spsmap);
+ }
+ GST_LOG_OBJECT (rtph264, "Adding new SPS %u", sps_id);
+ g_ptr_array_add (sps_array, nal);
+ } else if (type == 8) {
+ guint32 sps_id;
+ guint32 pps_id;
+
+ if (!parse_pps (&map, &sps_id, &pps_id)) {
+ GST_WARNING_OBJECT (rtph264, "Invalid PPS,"
+ " can't parse seq_parameter_set_id or pic_parameter_set_id");
+ goto drop;
+ }
+
+ for (i = 0; i < pps_array->len; i++) {
+ GstBuffer *pps = g_ptr_array_index (pps_array, i);
+ GstMapInfo ppsmap;
+ guint32 tmp_sps_id;
+ guint32 tmp_pps_id;
+
+
+ gst_buffer_map (pps, &ppsmap, GST_MAP_READ);
+ parse_pps (&ppsmap, &tmp_sps_id, &tmp_pps_id);
+
+ if (sps_id == tmp_sps_id && pps_id == tmp_pps_id) {
+ if (map.size == ppsmap.size &&
+ memcmp (map.data, ppsmap.data, ppsmap.size) == 0) {
+ GST_LOG_OBJECT (rtph264, "Unchanged PPS %u:%u, not updating", sps_id,
+ pps_id);
+ gst_buffer_unmap (pps, &ppsmap);
+ goto drop;
+ } else {
+ gst_buffer_unmap (pps, &ppsmap);
+ g_ptr_array_remove_index_fast (pps_array, i);
+ g_ptr_array_add (pps_array, nal);
+ GST_LOG_OBJECT (rtph264, "Modified PPS %u:%u, replacing",
+ sps_id, pps_id);
+ goto done;
+ }
+ }
+ gst_buffer_unmap (pps, &ppsmap);
+ }
+ GST_LOG_OBJECT (rtph264, "Adding new PPS %u:%i", sps_id, pps_id);
+ g_ptr_array_add (pps_array, nal);
+ } else {
+ goto drop;
+ }
+
+done:
+ gst_buffer_unmap (nal, &map);
+
+ return TRUE;
+
+drop:
+ gst_buffer_unmap (nal, &map);
+ gst_buffer_unref (nal);
+
+ return FALSE;
+}
+
+
+static void
+gst_rtp_h264_depay_add_sps_pps (GstRtpH264Depay * rtph264depay, GstBuffer * nal)
+{
+ if (gst_rtp_h264_add_sps_pps (GST_ELEMENT (rtph264depay),
+ rtph264depay->sps, rtph264depay->pps, nal))
+ rtph264depay->new_codec_data = TRUE;
+}
+
+static gboolean
+gst_rtp_h264_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ gint clock_rate;
+ GstStructure *structure = gst_caps_get_structure (caps, 0);
+ GstRtpH264Depay *rtph264depay;
+ const gchar *ps;
+ GstBuffer *codec_data;
+ GstMapInfo map;
+ guint8 *ptr;
+
+ rtph264depay = GST_RTP_H264_DEPAY (depayload);
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 90000;
+ depayload->clock_rate = clock_rate;
+
+ /* Base64 encoded, comma separated config NALs */
+ ps = gst_structure_get_string (structure, "sprop-parameter-sets");
+
+ /* negotiate with downstream w.r.t. output format and alignment */
+ gst_rtp_h264_depay_negotiate (rtph264depay);
+
+ if (rtph264depay->byte_stream && ps != NULL) {
+ /* for bytestream we only need the parameter sets but we don't error out
+ * when they are not there, we assume they are in the stream. */
+ gchar **params;
+ guint len, total;
+ gint i;
+
+ params = g_strsplit (ps, ",", 0);
+
+ /* count total number of bytes in base64. Also include the sync bytes in
+ * front of the params. */
+ len = 0;
+ for (i = 0; params[i]; i++) {
+ len += strlen (params[i]);
+ len += sizeof (sync_bytes);
+ }
+ /* we seriously overshoot the length, but it's fine. */
+ codec_data = gst_buffer_new_and_alloc (len);
+
+ gst_buffer_map (codec_data, &map, GST_MAP_WRITE);
+ ptr = map.data;
+ total = 0;
+ for (i = 0; params[i]; i++) {
+ guint save = 0;
+ gint state = 0;
+
+ GST_DEBUG_OBJECT (depayload, "decoding param %d (%s)", i, params[i]);
+ memcpy (ptr, sync_bytes, sizeof (sync_bytes));
+ ptr += sizeof (sync_bytes);
+ len =
+ g_base64_decode_step (params[i], strlen (params[i]), ptr, &state,
+ &save);
+ GST_DEBUG_OBJECT (depayload, "decoded %d bytes", len);
+ total += len + sizeof (sync_bytes);
+ ptr += len;
+ }
+ gst_buffer_unmap (codec_data, &map);
+ gst_buffer_resize (codec_data, 0, total);
+ g_strfreev (params);
+
+ /* keep the codec_data, we need to send it as the first buffer. We cannot
+ * push it in the adapter because the adapter might be flushed on discont.
+ */
+ if (rtph264depay->codec_data)
+ gst_buffer_unref (rtph264depay->codec_data);
+ rtph264depay->codec_data = codec_data;
+ } else if (!rtph264depay->byte_stream) {
+ gchar **params;
+ gint i;
+
+ if (ps == NULL)
+ goto incomplete_caps;
+
+ params = g_strsplit (ps, ",", 0);
+
+ GST_DEBUG_OBJECT (depayload, "we have %d params", g_strv_length (params));
+
+ /* start with 7 bytes header */
+ for (i = 0; params[i]; i++) {
+ GstBuffer *nal;
+ GstMapInfo nalmap;
+ gsize nal_len;
+ guint save = 0;
+ gint state = 0;
+
+ nal_len = strlen (params[i]);
+ nal = gst_buffer_new_and_alloc (nal_len);
+ gst_buffer_map (nal, &nalmap, GST_MAP_READWRITE);
+
+ nal_len =
+ g_base64_decode_step (params[i], nal_len, nalmap.data, &state, &save);
+
+ GST_DEBUG_OBJECT (depayload, "adding param %d as %s", i,
+ ((nalmap.data[0] & 0x1f) == 7) ? "SPS" : "PPS");
+
+ gst_buffer_unmap (nal, &nalmap);
+ gst_buffer_set_size (nal, nal_len);
+
+ gst_rtp_h264_depay_add_sps_pps (rtph264depay, nal);
+ }
+ g_strfreev (params);
+
+ if (rtph264depay->sps->len == 0 || rtph264depay->pps->len == 0)
+ goto incomplete_caps;
+ }
+
+ return gst_rtp_h264_set_src_caps (rtph264depay);
+
+ /* ERRORS */
+incomplete_caps:
+ {
+ GST_DEBUG_OBJECT (depayload, "we have incomplete caps,"
+ " doing setcaps later");
+ return TRUE;
+ }
+}
+
+static GstBuffer *
+gst_rtp_h264_complete_au (GstRtpH264Depay * rtph264depay,
+ GstClockTime * out_timestamp, gboolean * out_keyframe)
+{
+ guint outsize;
+ GstBuffer *outbuf;
+
+ /* we had a picture in the adapter and we completed it */
+ GST_DEBUG_OBJECT (rtph264depay, "taking completed AU");
+ outsize = gst_adapter_available (rtph264depay->picture_adapter);
+ outbuf = gst_adapter_take_buffer (rtph264depay->picture_adapter, outsize);
+
+ *out_timestamp = rtph264depay->last_ts;
+ *out_keyframe = rtph264depay->last_keyframe;
+
+ rtph264depay->last_keyframe = FALSE;
+ rtph264depay->picture_start = FALSE;
+
+ return outbuf;
+}
+
+/* SPS/PPS/IDR considered key, all others DELTA;
+ * so downstream waiting for keyframe can pick up at SPS/PPS/IDR */
+#define NAL_TYPE_IS_KEY(nt) (((nt) == 5) || ((nt) == 7) || ((nt) == 8))
+
+static GstBuffer *
+gst_rtp_h264_depay_handle_nal (GstRtpH264Depay * rtph264depay, GstBuffer * nal,
+ GstClockTime in_timestamp, gboolean marker)
+{
+ GstRTPBaseDepayload *depayload = GST_RTP_BASE_DEPAYLOAD (rtph264depay);
+ gint nal_type;
+ GstMapInfo map;
+ GstBuffer *outbuf = NULL;
+ GstClockTime out_timestamp;
+ gboolean keyframe, out_keyframe;
+
+ gst_buffer_map (nal, &map, GST_MAP_READ);
+ if (G_UNLIKELY (map.size < 5))
+ goto short_nal;
+
+ nal_type = map.data[4] & 0x1f;
+ GST_DEBUG_OBJECT (rtph264depay, "handle NAL type %d", nal_type);
+
+ keyframe = NAL_TYPE_IS_KEY (nal_type);
+
+ out_keyframe = keyframe;
+ out_timestamp = in_timestamp;
+
+ if (!rtph264depay->byte_stream) {
+ if (nal_type == 7 || nal_type == 8) {
+ gst_rtp_h264_depay_add_sps_pps (rtph264depay,
+ gst_buffer_copy_region (nal, GST_BUFFER_COPY_ALL,
+ 4, gst_buffer_get_size (nal) - 4));
+ gst_buffer_unmap (nal, &map);
+ gst_buffer_unref (nal);
+ return NULL;
+ } else if (rtph264depay->sps->len == 0 || rtph264depay->pps->len == 0) {
+ /* Down push down any buffer in non-bytestream mode if the SPS/PPS haven't
+ * go through yet
+ */
+ gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depayload),
+ gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+ gst_structure_new ("GstForceKeyUnit",
+ "all-headers", G_TYPE_BOOLEAN, TRUE, NULL)));
+ gst_buffer_unmap (nal, &map);
+ gst_buffer_unref (nal);
+ return NULL;
+ }
+
+ if (rtph264depay->new_codec_data &&
+ rtph264depay->sps->len > 0 && rtph264depay->pps->len > 0)
+ gst_rtp_h264_set_src_caps (rtph264depay);
+ }
+
+
+ if (rtph264depay->merge) {
+ gboolean start = FALSE, complete = FALSE;
+
+ /* marker bit isn't mandatory so in the following code we try to guess
+ * an AU boundary by detecting a new picture start */
+ if (!marker) {
+ /* consider a coded slices (IDR or not) to start a picture,
+ * (so ending the previous one) if first_mb_in_slice == 0
+ * (non-0 is part of previous one) */
+ /* NOTE this is not entirely according to Access Unit specs in 7.4.1.2.4,
+ * but in practice it works in sane cases, needs not much parsing,
+ * and also works with broken frame_num in NAL (where spec-wise would fail) */
+ /* FIXME: this code isn't correct for interlaced content as AUs should be
+ * constructed with pairs of fields and the guess here will just push out
+ * AUs with a single field in it */
+ if (nal_type == 1 || nal_type == 2 || nal_type == 5) {
+ /* we have a picture start */
+ start = TRUE;
+ if (map.data[5] & 0x80) {
+ /* first_mb_in_slice == 0 completes a picture */
+ complete = TRUE;
+ }
+ } else if (nal_type >= 6 && nal_type <= 9) {
+ /* SEI, SPS, PPS, AU terminate picture */
+ complete = TRUE;
+ }
+ GST_DEBUG_OBJECT (depayload, "start %d, complete %d", start, complete);
+
+ if (complete && rtph264depay->picture_start)
+ outbuf = gst_rtp_h264_complete_au (rtph264depay, &out_timestamp,
+ &out_keyframe);
+ }
+ /* add to adapter */
+ gst_buffer_unmap (nal, &map);
+
+ GST_DEBUG_OBJECT (depayload, "adding NAL to picture adapter");
+ gst_adapter_push (rtph264depay->picture_adapter, nal);
+ rtph264depay->last_ts = in_timestamp;
+ rtph264depay->last_keyframe |= keyframe;
+ rtph264depay->picture_start |= start;
+
+ if (marker)
+ outbuf = gst_rtp_h264_complete_au (rtph264depay, &out_timestamp,
+ &out_keyframe);
+ } else {
+ /* no merge, output is input nal */
+ GST_DEBUG_OBJECT (depayload, "using NAL as output");
+ outbuf = nal;
+ gst_buffer_unmap (nal, &map);
+ }
+
+ if (outbuf) {
+ /* prepend codec_data */
+ if (rtph264depay->codec_data) {
+ GST_DEBUG_OBJECT (depayload, "prepending codec_data");
+ outbuf = gst_buffer_append (rtph264depay->codec_data, outbuf);
+ rtph264depay->codec_data = NULL;
+ out_keyframe = TRUE;
+ }
+ outbuf = gst_buffer_make_writable (outbuf);
+
+ GST_BUFFER_TIMESTAMP (outbuf) = out_timestamp;
+
+ if (out_keyframe)
+ GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+ else
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+ }
+
+ return outbuf;
+
+ /* ERRORS */
+short_nal:
+ {
+ GST_WARNING_OBJECT (depayload, "dropping short NAL");
+ gst_buffer_unmap (nal, &map);
+ gst_buffer_unref (nal);
+ return NULL;
+ }
+}
+
+static GstBuffer *
+gst_rtp_h264_push_fragmentation_unit (GstRtpH264Depay * rtph264depay,
+ gboolean send)
+{
+ guint outsize;
+ GstMapInfo map;
+ GstBuffer *outbuf;
+
+ outsize = gst_adapter_available (rtph264depay->adapter);
+ outbuf = gst_adapter_take_buffer (rtph264depay->adapter, outsize);
+
+ gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+ GST_DEBUG_OBJECT (rtph264depay, "output %d bytes", outsize);
+
+ if (rtph264depay->byte_stream) {
+ memcpy (map.data, sync_bytes, sizeof (sync_bytes));
+ } else {
+ outsize -= 4;
+ map.data[0] = (outsize >> 24);
+ map.data[1] = (outsize >> 16);
+ map.data[2] = (outsize >> 8);
+ map.data[3] = (outsize);
+ }
+ gst_buffer_unmap (outbuf, &map);
+
+ rtph264depay->current_fu_type = 0;
+
+ outbuf = gst_rtp_h264_depay_handle_nal (rtph264depay, outbuf,
+ rtph264depay->fu_timestamp, rtph264depay->fu_marker);
+
+ if (send && outbuf) {
+ gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtph264depay), outbuf);
+ outbuf = NULL;
+ }
+ return outbuf;
+}
+
+static GstBuffer *
+gst_rtp_h264_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpH264Depay *rtph264depay;
+ GstBuffer *outbuf = NULL;
+ guint8 nal_unit_type;
+ GstRTPBuffer rtp = { NULL };
+
+ rtph264depay = GST_RTP_H264_DEPAY (depayload);
+
+ /* flush remaining data on discont */
+ if (GST_BUFFER_IS_DISCONT (buf)) {
+ gst_adapter_clear (rtph264depay->adapter);
+ rtph264depay->wait_start = TRUE;
+ rtph264depay->current_fu_type = 0;
+ }
+
+ {
+ gint payload_len;
+ guint8 *payload;
+ guint header_len;
+ guint8 nal_ref_idc;
+ GstMapInfo map;
+ guint outsize, nalu_size;
+ GstClockTime timestamp;
+ gboolean marker;
+
+ timestamp = GST_BUFFER_TIMESTAMP (buf);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ marker = gst_rtp_buffer_get_marker (&rtp);
+
+ GST_DEBUG_OBJECT (rtph264depay, "receiving %d bytes", payload_len);
+
+ if (payload_len == 0)
+ goto empty_packet;
+
+ /* +---------------+
+ * |0|1|2|3|4|5|6|7|
+ * +-+-+-+-+-+-+-+-+
+ * |F|NRI| Type |
+ * +---------------+
+ *
+ * F must be 0.
+ */
+ nal_ref_idc = (payload[0] & 0x60) >> 5;
+ nal_unit_type = payload[0] & 0x1f;
+
+ /* at least one byte header with type */
+ header_len = 1;
+
+ GST_DEBUG_OBJECT (rtph264depay, "NRI %d, Type %d", nal_ref_idc,
+ nal_unit_type);
+
+ /* If FU unit was being processed, but the current nal is of a different
+ * type. Assume that the remote payloader is buggy (didn't set the end bit
+ * when the FU ended) and send out what we gathered thusfar */
+ if (G_UNLIKELY (rtph264depay->current_fu_type != 0 &&
+ nal_unit_type != rtph264depay->current_fu_type))
+ gst_rtp_h264_push_fragmentation_unit (rtph264depay, TRUE);
+
+ switch (nal_unit_type) {
+ case 0:
+ case 30:
+ case 31:
+ /* undefined */
+ goto undefined_type;
+ case 25:
+ /* STAP-B Single-time aggregation packet 5.7.1 */
+ /* 2 byte extra header for DON */
+ header_len += 2;
+ /* fallthrough */
+ case 24:
+ {
+ /* strip headers */
+ payload += header_len;
+ payload_len -= header_len;
+
+ rtph264depay->wait_start = FALSE;
+
+
+ /* STAP-A Single-time aggregation packet 5.7.1 */
+ while (payload_len > 2) {
+ /* 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NALU Size |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ nalu_size = (payload[0] << 8) | payload[1];
+
+ /* dont include nalu_size */
+ if (nalu_size > (payload_len - 2))
+ nalu_size = payload_len - 2;
+
+ outsize = nalu_size + sizeof (sync_bytes);
+ outbuf = gst_buffer_new_and_alloc (outsize);
+
+ gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+ if (rtph264depay->byte_stream) {
+ memcpy (map.data, sync_bytes, sizeof (sync_bytes));
+ } else {
+ map.data[0] = map.data[1] = 0;
+ map.data[2] = payload[0];
+ map.data[3] = payload[1];
+ }
+
+ /* strip NALU size */
+ payload += 2;
+ payload_len -= 2;
+
+ memcpy (map.data + sizeof (sync_bytes), payload, nalu_size);
+ gst_buffer_unmap (outbuf, &map);
+
+ outbuf =
+ gst_rtp_h264_depay_handle_nal (rtph264depay, outbuf, timestamp,
+ marker);
+ if (outbuf)
+ gst_adapter_push (rtph264depay->adapter, outbuf);
+
+ payload += nalu_size;
+ payload_len -= nalu_size;
+ }
+
+ outsize = gst_adapter_available (rtph264depay->adapter);
+ if (outsize > 0) {
+ outbuf = gst_adapter_take_buffer (rtph264depay->adapter, outsize);
+ outbuf =
+ gst_rtp_h264_depay_handle_nal (rtph264depay, outbuf, timestamp,
+ marker);
+ }
+ break;
+ }
+ case 26:
+ /* MTAP16 Multi-time aggregation packet 5.7.2 */
+ // header_len = 5;
+ /* fallthrough, not implemented */
+ case 27:
+ /* MTAP24 Multi-time aggregation packet 5.7.2 */
+ // header_len = 6;
+ goto not_implemented;
+ break;
+ case 28:
+ case 29:
+ {
+ /* FU-A Fragmentation unit 5.8 */
+ /* FU-B Fragmentation unit 5.8 */
+ gboolean S, E;
+
+ /* +---------------+
+ * |0|1|2|3|4|5|6|7|
+ * +-+-+-+-+-+-+-+-+
+ * |S|E|R| Type |
+ * +---------------+
+ *
+ * R is reserved and always 0
+ */
+ S = (payload[1] & 0x80) == 0x80;
+ E = (payload[1] & 0x40) == 0x40;
+
+ GST_DEBUG_OBJECT (rtph264depay, "S %d, E %d", S, E);
+
+ if (rtph264depay->wait_start && !S)
+ goto waiting_start;
+
+ if (S) {
+ /* NAL unit starts here */
+ guint8 nal_header;
+
+ /* If a new FU unit started, while still processing an older one.
+ * Assume that the remote payloader is buggy (doesn't set the end
+ * bit) and send out what we've gathered thusfar */
+ if (G_UNLIKELY (rtph264depay->current_fu_type != 0))
+ gst_rtp_h264_push_fragmentation_unit (rtph264depay, TRUE);
+
+ rtph264depay->current_fu_type = nal_unit_type;
+ rtph264depay->fu_timestamp = timestamp;
+
+ rtph264depay->wait_start = FALSE;
+
+ /* reconstruct NAL header */
+ nal_header = (payload[0] & 0xe0) | (payload[1] & 0x1f);
+
+ /* strip type header, keep FU header, we'll reuse it to reconstruct
+ * the NAL header. */
+ payload += 1;
+ payload_len -= 1;
+
+ nalu_size = payload_len;
+ outsize = nalu_size + sizeof (sync_bytes);
+ outbuf = gst_buffer_new_and_alloc (outsize);
+
+ gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+ memcpy (map.data + sizeof (sync_bytes), payload, nalu_size);
+ map.data[sizeof (sync_bytes)] = nal_header;
+ gst_buffer_unmap (outbuf, &map);
+
+ GST_DEBUG_OBJECT (rtph264depay, "queueing %d bytes", outsize);
+
+ /* and assemble in the adapter */
+ gst_adapter_push (rtph264depay->adapter, outbuf);
+ } else {
+ /* strip off FU indicator and FU header bytes */
+ payload += 2;
+ payload_len -= 2;
+
+ outsize = payload_len;
+ outbuf = gst_buffer_new_and_alloc (outsize);
+ gst_buffer_fill (outbuf, 0, payload, outsize);
+
+ GST_DEBUG_OBJECT (rtph264depay, "queueing %d bytes", outsize);
+
+ /* and assemble in the adapter */
+ gst_adapter_push (rtph264depay->adapter, outbuf);
+ }
+
+ outbuf = NULL;
+ rtph264depay->fu_marker = marker;
+
+ /* if NAL unit ends, flush the adapter */
+ if (E)
+ outbuf = gst_rtp_h264_push_fragmentation_unit (rtph264depay, FALSE);
+ break;
+ }
+ default:
+ {
+ rtph264depay->wait_start = FALSE;
+
+ /* 1-23 NAL unit Single NAL unit packet per H.264 5.6 */
+ /* the entire payload is the output buffer */
+ nalu_size = payload_len;
+ outsize = nalu_size + sizeof (sync_bytes);
+ outbuf = gst_buffer_new_and_alloc (outsize);
+
+ gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+ if (rtph264depay->byte_stream) {
+ memcpy (map.data, sync_bytes, sizeof (sync_bytes));
+ } else {
+ map.data[0] = map.data[1] = 0;
+ map.data[2] = nalu_size >> 8;
+ map.data[3] = nalu_size & 0xff;
+ }
+ memcpy (map.data + sizeof (sync_bytes), payload, nalu_size);
+ gst_buffer_unmap (outbuf, &map);
+
+ outbuf = gst_rtp_h264_depay_handle_nal (rtph264depay, outbuf, timestamp,
+ marker);
+ break;
+ }
+ }
+ gst_rtp_buffer_unmap (&rtp);
+ }
+
+ return outbuf;
+
+ /* ERRORS */
+empty_packet:
+ {
+ GST_DEBUG_OBJECT (rtph264depay, "empty packet");
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+undefined_type:
+ {
+ GST_ELEMENT_WARNING (rtph264depay, STREAM, DECODE,
+ (NULL), ("Undefined packet type"));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+waiting_start:
+ {
+ GST_DEBUG_OBJECT (rtph264depay, "waiting for start");
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+not_implemented:
+ {
+ GST_ELEMENT_ERROR (rtph264depay, STREAM, FORMAT,
+ (NULL), ("NAL unit type %d not supported yet", nal_unit_type));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+}
+
+static gboolean
+gst_rtp_h264_depay_handle_event (GstRTPBaseDepayload * depay, GstEvent * event)
+{
+ GstRtpH264Depay *rtph264depay;
+
+ rtph264depay = GST_RTP_H264_DEPAY (depay);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_STOP:
+ gst_rtp_h264_depay_reset (rtph264depay);
+ break;
+ default:
+ break;
+ }
+
+ return
+ GST_RTP_BASE_DEPAYLOAD_CLASS (parent_class)->handle_event (depay, event);
+}
+
+static GstStateChangeReturn
+gst_rtp_h264_depay_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstRtpH264Depay *rtph264depay;
+ GstStateChangeReturn ret;
+
+ rtph264depay = GST_RTP_H264_DEPAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_rtp_h264_depay_reset (rtph264depay);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+gboolean
+gst_rtp_h264_depay_plugin_init (GstPlugin * plugin)
+{
+ GST_DEBUG_CATEGORY_INIT (rtph264depay_debug, "rtph264depay", 0,
+ "H264 Video RTP Depayloader");
+
+ return gst_element_register (plugin, "rtph264depay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_H264_DEPAY);
+}
diff --git a/gst/rtp/gstrtph264depay.h b/gst/rtp/gstrtph264depay.h
new file mode 100755
index 0000000..4895236
--- /dev/null
+++ b/gst/rtp/gstrtph264depay.h
@@ -0,0 +1,85 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_H264_DEPAY_H__
+#define __GST_RTP_H264_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_H264_DEPAY \
+ (gst_rtp_h264_depay_get_type())
+#define GST_RTP_H264_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_H264_DEPAY,GstRtpH264Depay))
+#define GST_RTP_H264_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_H264_DEPAY,GstRtpH264DepayClass))
+#define GST_IS_RTP_H264_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_H264_DEPAY))
+#define GST_IS_RTP_H264_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_H264_DEPAY))
+
+typedef struct _GstRtpH264Depay GstRtpH264Depay;
+typedef struct _GstRtpH264DepayClass GstRtpH264DepayClass;
+
+struct _GstRtpH264Depay
+{
+ GstRTPBaseDepayload depayload;
+
+ gboolean byte_stream;
+
+ GstBuffer *codec_data;
+ GstAdapter *adapter;
+ gboolean wait_start;
+
+ /* nal merging */
+ gboolean merge;
+ GstAdapter *picture_adapter;
+ gboolean picture_start;
+ GstClockTime last_ts;
+ gboolean last_keyframe;
+
+ /* Work around broken payloaders wrt. FU-A & FU-B */
+ guint8 current_fu_type;
+ GstClockTime fu_timestamp;
+ gboolean fu_marker;
+
+ /* misc */
+ GPtrArray *sps;
+ GPtrArray *pps;
+ gboolean new_codec_data;
+};
+
+struct _GstRtpH264DepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_h264_depay_get_type (void);
+
+gboolean gst_rtp_h264_depay_plugin_init (GstPlugin * plugin);
+
+gboolean gst_rtp_h264_add_sps_pps (GstElement * rtph264, GPtrArray * sps,
+ GPtrArray * pps, GstBuffer * nal);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_H264_DEPAY_H__ */
diff --git a/gst/rtp/gstrtph264pay.c b/gst/rtp/gstrtph264pay.c
new file mode 100755
index 0000000..665814a
--- /dev/null
+++ b/gst/rtp/gstrtph264pay.c
@@ -0,0 +1,1405 @@
+/* ex: set tabstop=2 shiftwidth=2 expandtab: */
+/* GStreamer
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/pbutils/pbutils.h>
+
+/* Included to not duplicate gst_rtp_h264_add_sps_pps () */
+#include "gstrtph264depay.h"
+
+#include "gstrtph264pay.h"
+
+
+#define IDR_TYPE_ID 5
+#define SPS_TYPE_ID 7
+#define PPS_TYPE_ID 8
+
+GST_DEBUG_CATEGORY_STATIC (rtph264pay_debug);
+#define GST_CAT_DEFAULT (rtph264pay_debug)
+
+/* references:
+ *
+ * RFC 3984
+ */
+
+static GstStaticPadTemplate gst_rtp_h264_pay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-h264, "
+ "stream-format = (string) avc, alignment = (string) au;"
+ "video/x-h264, "
+ "stream-format = (string) byte-stream, alignment = (string) { nal, au }")
+ );
+
+static GstStaticPadTemplate gst_rtp_h264_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"video\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) 90000, " "encoding-name = (string) \"H264\"")
+ );
+
+#define DEFAULT_SPROP_PARAMETER_SETS NULL
+#define DEFAULT_CONFIG_INTERVAL 0
+
+enum
+{
+ PROP_0,
+ PROP_SPROP_PARAMETER_SETS,
+ PROP_CONFIG_INTERVAL
+};
+
+#define IS_ACCESS_UNIT(x) (((x) > 0x00) && ((x) < 0x06))
+
+static void gst_rtp_h264_pay_finalize (GObject * object);
+
+static void gst_rtp_h264_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_rtp_h264_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static GstCaps *gst_rtp_h264_pay_getcaps (GstRTPBasePayload * payload,
+ GstPad * pad, GstCaps * filter);
+static gboolean gst_rtp_h264_pay_setcaps (GstRTPBasePayload * basepayload,
+ GstCaps * caps);
+static GstFlowReturn gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * pad,
+ GstBuffer * buffer);
+static gboolean gst_rtp_h264_pay_sink_event (GstRTPBasePayload * payload,
+ GstEvent * event);
+static GstStateChangeReturn gst_rtp_h264_pay_change_state (GstElement *
+ element, GstStateChange transition);
+
+#define gst_rtp_h264_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpH264Pay, gst_rtp_h264_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_h264_pay_class_init (GstRtpH264PayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gobject_class->set_property = gst_rtp_h264_pay_set_property;
+ gobject_class->get_property = gst_rtp_h264_pay_get_property;
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_SPROP_PARAMETER_SETS, g_param_spec_string ("sprop-parameter-sets",
+ "sprop-parameter-sets",
+ "The base64 sprop-parameter-sets to set in out caps (set to NULL to "
+ "extract from stream)",
+ DEFAULT_SPROP_PARAMETER_SETS,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_CONFIG_INTERVAL,
+ g_param_spec_uint ("config-interval",
+ "SPS PPS Send Interval",
+ "Send SPS and PPS Insertion Interval in seconds (sprop parameter sets "
+ "will be multiplexed in the data stream when detected.) (0 = disabled)",
+ 0, 3600, DEFAULT_CONFIG_INTERVAL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+ );
+
+ gobject_class->finalize = gst_rtp_h264_pay_finalize;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_h264_pay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_h264_pay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class, "RTP H264 payloader",
+ "Codec/Payloader/Network/RTP",
+ "Payload-encode H264 video into RTP packets (RFC 3984)",
+ "Laurent Glayal <spglegle@yahoo.fr>");
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_rtp_h264_pay_change_state);
+
+ gstrtpbasepayload_class->get_caps = gst_rtp_h264_pay_getcaps;
+ gstrtpbasepayload_class->set_caps = gst_rtp_h264_pay_setcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_h264_pay_handle_buffer;
+ gstrtpbasepayload_class->sink_event = gst_rtp_h264_pay_sink_event;
+
+ GST_DEBUG_CATEGORY_INIT (rtph264pay_debug, "rtph264pay", 0,
+ "H264 RTP Payloader");
+}
+
+static void
+gst_rtp_h264_pay_init (GstRtpH264Pay * rtph264pay)
+{
+ rtph264pay->queue = g_array_new (FALSE, FALSE, sizeof (guint));
+ rtph264pay->profile = 0;
+ rtph264pay->sps = g_ptr_array_new_with_free_func (
+ (GDestroyNotify) gst_buffer_unref);
+ rtph264pay->pps = g_ptr_array_new_with_free_func (
+ (GDestroyNotify) gst_buffer_unref);
+ rtph264pay->last_spspps = -1;
+ rtph264pay->spspps_interval = DEFAULT_CONFIG_INTERVAL;
+ rtph264pay->delta_unit = FALSE;
+ rtph264pay->discont = FALSE;
+
+ rtph264pay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_h264_pay_clear_sps_pps (GstRtpH264Pay * rtph264pay)
+{
+ g_ptr_array_set_size (rtph264pay->sps, 0);
+ g_ptr_array_set_size (rtph264pay->pps, 0);
+}
+
+static void
+gst_rtp_h264_pay_finalize (GObject * object)
+{
+ GstRtpH264Pay *rtph264pay;
+
+ rtph264pay = GST_RTP_H264_PAY (object);
+
+ g_array_free (rtph264pay->queue, TRUE);
+
+ g_ptr_array_free (rtph264pay->sps, TRUE);
+ g_ptr_array_free (rtph264pay->pps, TRUE);
+
+ g_free (rtph264pay->sprop_parameter_sets);
+
+ g_object_unref (rtph264pay->adapter);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static const gchar all_levels[][4] = {
+ "1",
+ "1b",
+ "1.1",
+ "1.2",
+ "1.3",
+ "2",
+ "2.1",
+ "2.2",
+ "3",
+ "3.1",
+ "3.2",
+ "4",
+ "4.1",
+ "4.2",
+ "5",
+ "5.1"
+};
+
+static GstCaps *
+gst_rtp_h264_pay_getcaps (GstRTPBasePayload * payload, GstPad * pad,
+ GstCaps * filter)
+{
+ GstCaps *template_caps;
+ GstCaps *allowed_caps;
+ GstCaps *caps, *icaps;
+ gboolean append_unrestricted;
+ guint i;
+
+ allowed_caps =
+ gst_pad_peer_query_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload), NULL);
+
+ if (allowed_caps == NULL)
+ return NULL;
+
+ template_caps =
+ gst_static_pad_template_get_caps (&gst_rtp_h264_pay_sink_template);
+
+ if (gst_caps_is_any (allowed_caps)) {
+ caps = gst_caps_ref (template_caps);
+ goto done;
+ }
+
+ if (gst_caps_is_empty (allowed_caps)) {
+ caps = gst_caps_ref (allowed_caps);
+ goto done;
+ }
+
+ caps = gst_caps_new_empty ();
+
+ append_unrestricted = FALSE;
+ for (i = 0; i < gst_caps_get_size (allowed_caps); i++) {
+ GstStructure *s = gst_caps_get_structure (allowed_caps, i);
+ GstStructure *new_s = gst_structure_new_empty ("video/x-h264");
+ const gchar *profile_level_id;
+
+ profile_level_id = gst_structure_get_string (s, "profile-level-id");
+
+ if (profile_level_id && strlen (profile_level_id) == 6) {
+ const gchar *profile;
+ const gchar *level;
+ long int spsint;
+ guint8 sps[3];
+
+ spsint = strtol (profile_level_id, NULL, 16);
+ sps[0] = spsint >> 16;
+ sps[1] = spsint >> 8;
+ sps[2] = spsint;
+
+ profile = gst_codec_utils_h264_get_profile (sps, 3);
+ level = gst_codec_utils_h264_get_level (sps, 3);
+
+ if (profile && level) {
+ GST_LOG_OBJECT (payload, "In caps, have profile %s and level %s",
+ profile, level);
+
+ if (!strcmp (profile, "constrained-baseline"))
+ gst_structure_set (new_s, "profile", G_TYPE_STRING, profile, NULL);
+ else {
+ GValue val = { 0, };
+ GValue profiles = { 0, };
+
+ g_value_init (&profiles, GST_TYPE_LIST);
+ g_value_init (&val, G_TYPE_STRING);
+
+ g_value_set_static_string (&val, profile);
+ gst_value_list_append_value (&profiles, &val);
+
+ g_value_set_static_string (&val, "constrained-baseline");
+ gst_value_list_append_value (&profiles, &val);
+
+ gst_structure_take_value (new_s, "profile", &profiles);
+ }
+
+ if (!strcmp (level, "1"))
+ gst_structure_set (new_s, "level", G_TYPE_STRING, level, NULL);
+ else {
+ GValue levels = { 0, };
+ GValue val = { 0, };
+ int j;
+
+ g_value_init (&levels, GST_TYPE_LIST);
+ g_value_init (&val, G_TYPE_STRING);
+
+ for (j = 0; j < G_N_ELEMENTS (all_levels); j++) {
+ g_value_set_static_string (&val, all_levels[j]);
+ gst_value_list_prepend_value (&levels, &val);
+ if (!strcmp (level, all_levels[j]))
+ break;
+ }
+ gst_structure_take_value (new_s, "level", &levels);
+ }
+ } else {
+ /* Invalid profile-level-id means baseline */
+
+ gst_structure_set (new_s,
+ "profile", G_TYPE_STRING, "constrained-baseline", NULL);
+ }
+ } else {
+ /* No profile-level-id means baseline or unrestricted */
+
+ gst_structure_set (new_s,
+ "profile", G_TYPE_STRING, "constrained-baseline", NULL);
+ append_unrestricted = TRUE;
+ }
+
+ caps = gst_caps_merge_structure (caps, new_s);
+ }
+
+ if (append_unrestricted) {
+ caps =
+ gst_caps_merge_structure (caps, gst_structure_new ("video/x-h264", NULL,
+ NULL));
+ }
+
+ icaps = gst_caps_intersect (caps, template_caps);
+ gst_caps_unref (caps);
+ caps = icaps;
+
+done:
+
+ gst_caps_unref (template_caps);
+ gst_caps_unref (allowed_caps);
+
+ GST_LOG_OBJECT (payload, "returning caps %" GST_PTR_FORMAT, caps);
+ return caps;
+}
+
+/* take the currently configured SPS and PPS lists and set them on the caps as
+ * sprop-parameter-sets */
+static gboolean
+gst_rtp_h264_pay_set_sps_pps (GstRTPBasePayload * basepayload)
+{
+ GstRtpH264Pay *payloader = GST_RTP_H264_PAY (basepayload);
+ gchar *profile;
+ gchar *set;
+ GString *sprops;
+ guint count;
+ gboolean res;
+ GstMapInfo map;
+ guint i;
+
+ sprops = g_string_new ("");
+ count = 0;
+
+ /* build the sprop-parameter-sets */
+ for (i = 0; i < payloader->sps->len; i++) {
+ GstBuffer *sps_buf =
+ GST_BUFFER_CAST (g_ptr_array_index (payloader->sps, i));
+
+ gst_buffer_map (sps_buf, &map, GST_MAP_READ);
+ set = g_base64_encode (map.data, map.size);
+ gst_buffer_unmap (sps_buf, &map);
+
+ g_string_append_printf (sprops, "%s%s", count ? "," : "", set);
+ g_free (set);
+ count++;
+ }
+ for (i = 0; i < payloader->pps->len; i++) {
+ GstBuffer *pps_buf =
+ GST_BUFFER_CAST (g_ptr_array_index (payloader->pps, i));
+
+ gst_buffer_map (pps_buf, &map, GST_MAP_READ);
+ set = g_base64_encode (map.data, map.size);
+ gst_buffer_unmap (pps_buf, &map);
+
+ g_string_append_printf (sprops, "%s%s", count ? "," : "", set);
+ g_free (set);
+ count++;
+ }
+
+ if (G_LIKELY (count)) {
+ if (payloader->profile != 0) {
+ /* profile is 24 bit. Force it to respect the limit */
+ profile = g_strdup_printf ("%06x", payloader->profile & 0xffffff);
+ /* combine into output caps */
+ res = gst_rtp_base_payload_set_outcaps (basepayload,
+ "packetization-mode", G_TYPE_STRING, "1",
+ "profile-level-id", G_TYPE_STRING, profile,
+ "sprop-parameter-sets", G_TYPE_STRING, sprops->str, NULL);
+ g_free (profile);
+ } else {
+ res = gst_rtp_base_payload_set_outcaps (basepayload,
+ "packetization-mode", G_TYPE_STRING, "1",
+ "sprop-parameter-sets", G_TYPE_STRING, sprops->str, NULL);
+ }
+
+ } else {
+ res = gst_rtp_base_payload_set_outcaps (basepayload, NULL);
+ }
+ g_string_free (sprops, TRUE);
+
+ return res;
+}
+
+
+static gboolean
+gst_rtp_h264_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
+{
+ GstRtpH264Pay *rtph264pay;
+ GstStructure *str;
+ const GValue *value;
+ GstMapInfo map;
+ guint8 *data;
+ gsize size;
+ GstBuffer *buffer;
+ const gchar *alignment, *stream_format;
+
+ rtph264pay = GST_RTP_H264_PAY (basepayload);
+
+ str = gst_caps_get_structure (caps, 0);
+
+ /* we can only set the output caps when we found the sprops and profile
+ * NALs */
+ gst_rtp_base_payload_set_options (basepayload, "video", TRUE, "H264", 90000);
+
+ rtph264pay->alignment = GST_H264_ALIGNMENT_UNKNOWN;
+ alignment = gst_structure_get_string (str, "alignment");
+ if (alignment) {
+ if (g_str_equal (alignment, "au"))
+ rtph264pay->alignment = GST_H264_ALIGNMENT_AU;
+ if (g_str_equal (alignment, "nal"))
+ rtph264pay->alignment = GST_H264_ALIGNMENT_NAL;
+ }
+
+ rtph264pay->stream_format = GST_H264_STREAM_FORMAT_UNKNOWN;
+ stream_format = gst_structure_get_string (str, "stream-format");
+ if (stream_format) {
+ if (g_str_equal (stream_format, "avc"))
+ rtph264pay->stream_format = GST_H264_STREAM_FORMAT_AVC;
+ if (g_str_equal (stream_format, "byte-stream"))
+ rtph264pay->stream_format = GST_H264_STREAM_FORMAT_BYTESTREAM;
+ }
+
+ /* packetized AVC video has a codec_data */
+ if ((value = gst_structure_get_value (str, "codec_data"))) {
+ guint num_sps, num_pps;
+ gint i, nal_size;
+
+ GST_DEBUG_OBJECT (rtph264pay, "have packetized h264");
+
+ buffer = gst_value_get_buffer (value);
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+ data = map.data;
+ size = map.size;
+
+ /* parse the avcC data */
+ if (size < 7)
+ goto avcc_too_small;
+ /* parse the version, this must be 1 */
+ if (data[0] != 1)
+ goto wrong_version;
+
+ /* AVCProfileIndication */
+ /* profile_compat */
+ /* AVCLevelIndication */
+ rtph264pay->profile = (data[1] << 16) | (data[2] << 8) | data[3];
+ GST_DEBUG_OBJECT (rtph264pay, "profile %06x", rtph264pay->profile);
+
+ /* 6 bits reserved | 2 bits lengthSizeMinusOne */
+ /* this is the number of bytes in front of the NAL units to mark their
+ * length */
+ rtph264pay->nal_length_size = (data[4] & 0x03) + 1;
+ GST_DEBUG_OBJECT (rtph264pay, "nal length %u", rtph264pay->nal_length_size);
+ /* 3 bits reserved | 5 bits numOfSequenceParameterSets */
+ num_sps = data[5] & 0x1f;
+ GST_DEBUG_OBJECT (rtph264pay, "num SPS %u", num_sps);
+
+ data += 6;
+ size -= 6;
+
+ /* create the sprop-parameter-sets */
+ for (i = 0; i < num_sps; i++) {
+ GstBuffer *sps_buf;
+
+ if (size < 2)
+ goto avcc_error;
+
+ nal_size = (data[0] << 8) | data[1];
+ data += 2;
+ size -= 2;
+
+ GST_LOG_OBJECT (rtph264pay, "SPS %d size %d", i, nal_size);
+
+ if (size < nal_size)
+ goto avcc_error;
+
+ /* make a buffer out of it and add to SPS list */
+ sps_buf = gst_buffer_new_and_alloc (nal_size);
+ gst_buffer_fill (sps_buf, 0, data, nal_size);
+ gst_rtp_h264_add_sps_pps (GST_ELEMENT (rtph264pay), rtph264pay->sps,
+ rtph264pay->pps, sps_buf);
+ data += nal_size;
+ size -= nal_size;
+ }
+ if (size < 1)
+ goto avcc_error;
+
+ /* 8 bits numOfPictureParameterSets */
+ num_pps = data[0];
+ data += 1;
+ size -= 1;
+
+ GST_DEBUG_OBJECT (rtph264pay, "num PPS %u", num_pps);
+ for (i = 0; i < num_pps; i++) {
+ GstBuffer *pps_buf;
+
+ if (size < 2)
+ goto avcc_error;
+
+ nal_size = (data[0] << 8) | data[1];
+ data += 2;
+ size -= 2;
+
+ GST_LOG_OBJECT (rtph264pay, "PPS %d size %d", i, nal_size);
+
+ if (size < nal_size)
+ goto avcc_error;
+
+ /* make a buffer out of it and add to PPS list */
+ pps_buf = gst_buffer_new_and_alloc (nal_size);
+ gst_buffer_fill (pps_buf, 0, data, nal_size);
+ gst_rtp_h264_add_sps_pps (GST_ELEMENT (rtph264pay), rtph264pay->sps,
+ rtph264pay->pps, pps_buf);
+
+ data += nal_size;
+ size -= nal_size;
+ }
+
+ /* and update the caps with the collected data */
+ if (!gst_rtp_h264_pay_set_sps_pps (basepayload))
+ goto set_sps_pps_failed;
+
+ gst_buffer_unmap (buffer, &map);
+ } else {
+ GST_DEBUG_OBJECT (rtph264pay, "have bytestream h264");
+ }
+
+ return TRUE;
+
+avcc_too_small:
+ {
+ GST_ERROR_OBJECT (rtph264pay, "avcC size %" G_GSIZE_FORMAT " < 7", size);
+ goto error;
+ }
+wrong_version:
+ {
+ GST_ERROR_OBJECT (rtph264pay, "wrong avcC version");
+ goto error;
+ }
+avcc_error:
+ {
+ GST_ERROR_OBJECT (rtph264pay, "avcC too small ");
+ goto error;
+ }
+set_sps_pps_failed:
+ {
+ GST_ERROR_OBJECT (rtph264pay, "failed to set sps/pps");
+ goto error;
+ }
+error:
+ {
+ gst_buffer_unmap (buffer, &map);
+ return FALSE;
+ }
+}
+
+static void
+gst_rtp_h264_pay_parse_sprop_parameter_sets (GstRtpH264Pay * rtph264pay)
+{
+ const gchar *ps;
+ gchar **params;
+ guint len;
+ gint i;
+ GstBuffer *buf;
+
+ ps = rtph264pay->sprop_parameter_sets;
+ if (ps == NULL)
+ return;
+
+ gst_rtp_h264_pay_clear_sps_pps (rtph264pay);
+
+ params = g_strsplit (ps, ",", 0);
+ len = g_strv_length (params);
+
+ GST_DEBUG_OBJECT (rtph264pay, "we have %d params", len);
+
+ for (i = 0; params[i]; i++) {
+ gsize nal_len;
+ GstMapInfo map;
+ guint8 *nalp;
+ guint save = 0;
+ gint state = 0;
+
+ nal_len = strlen (params[i]);
+ buf = gst_buffer_new_and_alloc (nal_len);
+
+ gst_buffer_map (buf, &map, GST_MAP_WRITE);
+ nalp = map.data;
+ nal_len = g_base64_decode_step (params[i], nal_len, nalp, &state, &save);
+ gst_buffer_unmap (buf, &map);
+ gst_buffer_resize (buf, 0, nal_len);
+
+ if (!nal_len) {
+ gst_buffer_unref (buf);
+ continue;
+ }
+
+ gst_rtp_h264_add_sps_pps (GST_ELEMENT (rtph264pay), rtph264pay->sps,
+ rtph264pay->pps, buf);
+ }
+ g_strfreev (params);
+}
+
+static guint
+next_start_code (const guint8 * data, guint size)
+{
+ /* Boyer-Moore string matching algorithm, in a degenerative
+ * sense because our search 'alphabet' is binary - 0 & 1 only.
+ * This allow us to simplify the general BM algorithm to a very
+ * simple form. */
+ /* assume 1 is in the 3th byte */
+ guint offset = 2;
+
+ while (offset < size) {
+ if (1 == data[offset]) {
+ unsigned int shift = offset;
+
+ if (0 == data[--shift]) {
+ if (0 == data[--shift]) {
+ return shift;
+ }
+ }
+ /* The jump is always 3 because of the 1 previously matched.
+ * All the 0's must be after this '1' matched at offset */
+ offset += 3;
+ } else if (0 == data[offset]) {
+ /* maybe next byte is 1? */
+ offset++;
+ } else {
+ /* can jump 3 bytes forward */
+ offset += 3;
+ }
+ /* at each iteration, we rescan in a backward manner until
+ * we match 0.0.1 in reverse order. Since our search string
+ * has only 2 'alpabets' (i.e. 0 & 1), we know that any
+ * mismatch will force us to shift a fixed number of steps */
+ }
+ GST_DEBUG ("Cannot find next NAL start code. returning %u", size);
+
+ return size;
+}
+
+static gboolean
+gst_rtp_h264_pay_decode_nal (GstRtpH264Pay * payloader,
+ const guint8 * data, guint size, GstClockTime dts, GstClockTime pts)
+{
+ guint8 header, type;
+ gboolean updated;
+
+ /* default is no update */
+ updated = FALSE;
+
+ GST_DEBUG ("NAL payload len=%u", size);
+
+ header = data[0];
+ type = header & 0x1f;
+
+ /* We record the timestamp of the last SPS/PPS so
+ * that we can insert them at regular intervals and when needed. */
+ if (SPS_TYPE_ID == type || PPS_TYPE_ID == type) {
+ GstBuffer *nal;
+
+ /* encode the entire SPS NAL in base64 */
+ GST_DEBUG ("Found %s %x %x %x Len=%u", type == SPS_TYPE_ID ? "SPS" : "PPS",
+ (header >> 7), (header >> 5) & 3, type, size);
+
+ nal = gst_buffer_new_allocate (NULL, size, NULL);
+ gst_buffer_fill (nal, 0, data, size);
+
+ updated = gst_rtp_h264_add_sps_pps (GST_ELEMENT (payloader),
+ payloader->sps, payloader->pps, nal);
+
+ /* remember when we last saw SPS */
+ if (updated && pts != -1)
+ payloader->last_spspps = pts;
+ } else {
+ GST_DEBUG ("NAL: %x %x %x Len = %u", (header >> 7),
+ (header >> 5) & 3, type, size);
+ }
+
+ return updated;
+}
+
+static GstFlowReturn
+gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
+ GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au,
+ gboolean delta_unit, gboolean discont);
+
+static GstFlowReturn
+gst_rtp_h264_pay_send_sps_pps (GstRTPBasePayload * basepayload,
+ GstRtpH264Pay * rtph264pay, GstClockTime dts, GstClockTime pts)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ gboolean sent_all_sps_pps = TRUE;
+ guint i;
+
+ for (i = 0; i < rtph264pay->sps->len; i++) {
+ GstBuffer *sps_buf =
+ GST_BUFFER_CAST (g_ptr_array_index (rtph264pay->sps, i));
+
+ GST_DEBUG_OBJECT (rtph264pay, "inserting SPS in the stream");
+ /* resend SPS */
+ ret = gst_rtp_h264_pay_payload_nal (basepayload, gst_buffer_ref (sps_buf),
+ dts, pts, FALSE, FALSE, FALSE);
+ /* Not critical here; but throw a warning */
+ if (ret != GST_FLOW_OK) {
+ sent_all_sps_pps = FALSE;
+ GST_WARNING ("Problem pushing SPS");
+ }
+ }
+ for (i = 0; i < rtph264pay->pps->len; i++) {
+ GstBuffer *pps_buf =
+ GST_BUFFER_CAST (g_ptr_array_index (rtph264pay->pps, i));
+
+ GST_DEBUG_OBJECT (rtph264pay, "inserting PPS in the stream");
+ /* resend PPS */
+ ret = gst_rtp_h264_pay_payload_nal (basepayload, gst_buffer_ref (pps_buf),
+ dts, pts, FALSE, FALSE, FALSE);
+ /* Not critical here; but throw a warning */
+ if (ret != GST_FLOW_OK) {
+ sent_all_sps_pps = FALSE;
+ GST_WARNING ("Problem pushing PPS");
+ }
+ }
+
+ if (pts != -1 && sent_all_sps_pps)
+ rtph264pay->last_spspps = pts;
+
+ return ret;
+}
+
+/* @delta_unit: if %FALSE the first packet sent won't have the
+ * GST_BUFFER_FLAG_DELTA_UNIT flag.
+ * @discont: if %TRUE the first packet sent will have the
+ * GST_BUFFER_FLAG_DISCONT flag.
+ */
+static GstFlowReturn
+gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
+ GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au,
+ gboolean delta_unit, gboolean discont)
+{
+ GstRtpH264Pay *rtph264pay;
+ GstFlowReturn ret;
+ guint8 nalHeader;
+ guint8 nalType;
+ guint packet_len, payload_len, mtu;
+ GstBuffer *outbuf;
+ guint8 *payload;
+ GstBufferList *list = NULL;
+ gboolean send_spspps;
+ GstRTPBuffer rtp = { NULL };
+ guint size = gst_buffer_get_size (paybuf);
+
+ rtph264pay = GST_RTP_H264_PAY (basepayload);
+ mtu = GST_RTP_BASE_PAYLOAD_MTU (rtph264pay);
+
+ gst_buffer_extract (paybuf, 0, &nalHeader, 1);
+ nalType = nalHeader & 0x1f;
+
+ GST_DEBUG_OBJECT (rtph264pay, "Processing Buffer with NAL TYPE=%d", nalType);
+
+ /* should set src caps before pushing stuff,
+ * and if we did not see enough SPS/PPS, that may not be the case */
+ if (G_UNLIKELY (!gst_pad_has_current_caps (GST_RTP_BASE_PAYLOAD_SRCPAD
+ (basepayload))))
+ gst_rtp_h264_pay_set_sps_pps (basepayload);
+
+ send_spspps = FALSE;
+
+ /* check if we need to emit an SPS/PPS now */
+ if (nalType == IDR_TYPE_ID && rtph264pay->spspps_interval > 0) {
+ if (rtph264pay->last_spspps != -1) {
+ guint64 diff;
+
+ GST_LOG_OBJECT (rtph264pay,
+ "now %" GST_TIME_FORMAT ", last SPS/PPS %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (pts), GST_TIME_ARGS (rtph264pay->last_spspps));
+
+ /* calculate diff between last SPS/PPS in milliseconds */
+ if (pts > rtph264pay->last_spspps)
+ diff = pts - rtph264pay->last_spspps;
+ else
+ diff = 0;
+
+ GST_DEBUG_OBJECT (rtph264pay,
+ "interval since last SPS/PPS %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (diff));
+
+ /* bigger than interval, queue SPS/PPS */
+ if (GST_TIME_AS_SECONDS (diff) >= rtph264pay->spspps_interval) {
+ GST_DEBUG_OBJECT (rtph264pay, "time to send SPS/PPS");
+ send_spspps = TRUE;
+ }
+ } else {
+ /* no know previous SPS/PPS time, send now */
+ GST_DEBUG_OBJECT (rtph264pay, "no previous SPS/PPS time, send now");
+ send_spspps = TRUE;
+ }
+ }
+
+ if (send_spspps || rtph264pay->send_spspps) {
+ /* we need to send SPS/PPS now first. FIXME, don't use the pts for
+ * checking when we need to send SPS/PPS but convert to running_time first. */
+ rtph264pay->send_spspps = FALSE;
+ ret = gst_rtp_h264_pay_send_sps_pps (basepayload, rtph264pay, dts, pts);
+ if (ret != GST_FLOW_OK) {
+ gst_buffer_unref (paybuf);
+ return ret;
+ }
+ }
+
+ packet_len = gst_rtp_buffer_calc_packet_len (size, 0, 0);
+
+ if (packet_len < mtu) {
+ /* will fit in one packet */
+ GST_DEBUG_OBJECT (basepayload,
+ "NAL Unit fit in one packet datasize=%d mtu=%d", size, mtu);
+
+ /* create buffer without payload containing only the RTP header
+ * (memory block at index 0) */
+ outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
+
+ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+ /* only set the marker bit on packets containing access units */
+ if (IS_ACCESS_UNIT (nalType) && end_of_au) {
+ gst_rtp_buffer_set_marker (&rtp, 1);
+ }
+
+ /* timestamp the outbuffer */
+ GST_BUFFER_PTS (outbuf) = pts;
+ GST_BUFFER_DTS (outbuf) = dts;
+
+ if (!delta_unit)
+ /* Only the first packet sent should not have the flag */
+ delta_unit = TRUE;
+ else
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+
+ if (discont) {
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+ /* Only the first packet sent should have the flag */
+ discont = FALSE;
+ }
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ /* insert payload memory block */
+ outbuf = gst_buffer_append (outbuf, paybuf);
+
+ /* push the buffer to the next element */
+ ret = gst_rtp_base_payload_push (basepayload, outbuf);
+ } else {
+ /* fragmentation Units FU-A */
+ guint limitedSize;
+ int ii = 0, start = 1, end = 0, pos = 0;
+
+ GST_DEBUG_OBJECT (basepayload,
+ "NAL Unit DOES NOT fit in one packet datasize=%d mtu=%d", size, mtu);
+
+ pos++;
+ size--;
+
+ ret = GST_FLOW_OK;
+
+ GST_DEBUG_OBJECT (basepayload, "Using FU-A fragmentation for data size=%d",
+ size);
+
+ /* We keep 2 bytes for FU indicator and FU Header */
+ payload_len = gst_rtp_buffer_calc_payload_len (mtu - 2, 0, 0);
+
+ list = gst_buffer_list_new_sized ((size / payload_len) + 1);
+
+ while (end == 0) {
+ limitedSize = size < payload_len ? size : payload_len;
+ GST_DEBUG_OBJECT (basepayload,
+ "Inside FU-A fragmentation limitedSize=%d iteration=%d", limitedSize,
+ ii);
+
+ /* use buffer lists
+ * create buffer without payload containing only the RTP header
+ * (memory block at index 0) */
+ outbuf = gst_rtp_buffer_new_allocate (2, 0, 0);
+
+ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+ GST_BUFFER_DTS (outbuf) = dts;
+ GST_BUFFER_PTS (outbuf) = pts;
+ payload = gst_rtp_buffer_get_payload (&rtp);
+
+ if (limitedSize == size) {
+ GST_DEBUG_OBJECT (basepayload, "end size=%d iteration=%d", size, ii);
+ end = 1;
+ }
+ if (IS_ACCESS_UNIT (nalType)) {
+ gst_rtp_buffer_set_marker (&rtp, end && end_of_au);
+ }
+
+ /* FU indicator */
+ payload[0] = (nalHeader & 0x60) | 28;
+
+ /* FU Header */
+ payload[1] = (start << 7) | (end << 6) | (nalHeader & 0x1f);
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ /* insert payload memory block */
+ gst_buffer_append (outbuf,
+ gst_buffer_copy_region (paybuf, GST_BUFFER_COPY_MEMORY, pos,
+ limitedSize));
+
+ if (!delta_unit)
+ /* Only the first packet sent should not have the flag */
+ delta_unit = TRUE;
+ else
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+
+ if (discont) {
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+ /* Only the first packet sent should have the flag */
+ discont = FALSE;
+ }
+
+ /* add the buffer to the buffer list */
+ gst_buffer_list_add (list, outbuf);
+
+
+ size -= limitedSize;
+ pos += limitedSize;
+ ii++;
+ start = 0;
+ }
+
+ ret = gst_rtp_base_payload_push_list (basepayload, list);
+ gst_buffer_unref (paybuf);
+ }
+ return ret;
+}
+
+static GstFlowReturn
+gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer)
+{
+ GstRtpH264Pay *rtph264pay;
+ GstFlowReturn ret;
+ gsize size;
+ guint nal_len, i;
+ GstMapInfo map;
+ const guint8 *data;
+ GstClockTime dts, pts;
+ GArray *nal_queue;
+ gboolean avc;
+ GstBuffer *paybuf = NULL;
+ gsize skip;
+ gboolean delayed_not_delta_unit = FALSE;
+ gboolean delayed_discont = FALSE;
+
+ rtph264pay = GST_RTP_H264_PAY (basepayload);
+
+ /* the input buffer contains one or more NAL units */
+
+ avc = rtph264pay->stream_format == GST_H264_STREAM_FORMAT_AVC;
+
+ if (avc) {
+ /* In AVC mode, there is no adapter, so nothign to flush */
+ if (buffer == NULL)
+ return GST_FLOW_OK;
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+ data = map.data;
+ size = map.size;
+ pts = GST_BUFFER_PTS (buffer);
+ dts = GST_BUFFER_DTS (buffer);
+ rtph264pay->delta_unit = GST_BUFFER_FLAG_IS_SET (buffer,
+ GST_BUFFER_FLAG_DELTA_UNIT);
+ rtph264pay->discont = GST_BUFFER_IS_DISCONT (buffer);
+ GST_DEBUG_OBJECT (basepayload, "got %" G_GSIZE_FORMAT " bytes", size);
+ } else {
+ dts = gst_adapter_prev_dts (rtph264pay->adapter, NULL);
+ pts = gst_adapter_prev_pts (rtph264pay->adapter, NULL);
+ if (buffer) {
+ if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
+ if (gst_adapter_available (rtph264pay->adapter) == 0)
+ rtph264pay->delta_unit = FALSE;
+ else
+ /* This buffer contains a key frame but the adapter isn't empty. So
+ * we'll purge it first by sending a first packet and then the second
+ * one won't have the DELTA_UNIT flag. */
+ delayed_not_delta_unit = TRUE;
+ }
+
+ if (GST_BUFFER_IS_DISCONT (buffer)) {
+ if (gst_adapter_available (rtph264pay->adapter) == 0)
+ rtph264pay->discont = TRUE;
+ else
+ /* This buffer has the DISCONT flag but the adapter isn't empty. So
+ * we'll purge it first by sending a first packet and then the second
+ * one will have the DISCONT flag set. */
+ delayed_discont = TRUE;
+ }
+
+ if (!GST_CLOCK_TIME_IS_VALID (dts))
+ dts = GST_BUFFER_DTS (buffer);
+ if (!GST_CLOCK_TIME_IS_VALID (pts))
+ pts = GST_BUFFER_PTS (buffer);
+
+ gst_adapter_push (rtph264pay->adapter, buffer);
+ }
+ size = gst_adapter_available (rtph264pay->adapter);
+ /* Nothing to do here if the adapter is empty, e.g. on EOS */
+ if (size == 0)
+ return GST_FLOW_OK;
+ data = gst_adapter_map (rtph264pay->adapter, size);
+ GST_DEBUG_OBJECT (basepayload,
+ "got %" G_GSIZE_FORMAT " bytes (%" G_GSIZE_FORMAT ")", size,
+ buffer ? gst_buffer_get_size (buffer) : 0);
+ }
+
+ ret = GST_FLOW_OK;
+
+ /* now loop over all NAL units and put them in a packet
+ * FIXME, we should really try to pack multiple NAL units into one RTP packet
+ * if we can, especially for the config packets that wont't cause decoder
+ * latency. */
+ if (avc) {
+ guint nal_length_size;
+ gsize offset = 0;
+
+ nal_length_size = rtph264pay->nal_length_size;
+
+ while (size > nal_length_size) {
+ gint i;
+ gboolean end_of_au = FALSE;
+
+ nal_len = 0;
+ for (i = 0; i < nal_length_size; i++) {
+ nal_len = ((nal_len << 8) + data[i]);
+ }
+
+ /* skip the length bytes, make sure we don't run past the buffer size */
+ data += nal_length_size;
+ offset += nal_length_size;
+ size -= nal_length_size;
+
+ if (size >= nal_len) {
+ GST_DEBUG_OBJECT (basepayload, "got NAL of size %u", nal_len);
+ } else {
+ nal_len = size;
+ GST_DEBUG_OBJECT (basepayload, "got incomplete NAL of size %u",
+ nal_len);
+ }
+
+ /* If we're at the end of the buffer, then we're at the end of the
+ * access unit
+ */
+ if (rtph264pay->alignment == GST_H264_ALIGNMENT_AU
+ && size - nal_len <= nal_length_size) {
+ end_of_au = TRUE;
+ }
+
+ paybuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY, offset,
+ nal_len);
+ ret =
+ gst_rtp_h264_pay_payload_nal (basepayload, paybuf, dts, pts,
+ end_of_au, rtph264pay->delta_unit, rtph264pay->discont);
+
+ if (!rtph264pay->delta_unit)
+ /* Only the first outgoing packet doesn't have the DELTA_UNIT flag */
+ rtph264pay->delta_unit = TRUE;
+
+ if (rtph264pay->discont)
+ /* Only the first outgoing packet have the DISCONT flag */
+ rtph264pay->discont = FALSE;
+
+ if (ret != GST_FLOW_OK)
+ break;
+
+ data += nal_len;
+ offset += nal_len;
+ size -= nal_len;
+ }
+ } else {
+ guint next;
+ gboolean update = FALSE;
+
+ /* get offset of first start code */
+ next = next_start_code (data, size);
+
+ /* skip to start code, if no start code is found, next will be size and we
+ * will not collect data. */
+ data += next;
+ size -= next;
+ nal_queue = rtph264pay->queue;
+ skip = next;
+
+ /* array must be empty when we get here */
+ g_assert (nal_queue->len == 0);
+
+ GST_DEBUG_OBJECT (basepayload,
+ "found first start at %u, bytes left %" G_GSIZE_FORMAT, next, size);
+
+ /* first pass to locate NALs and parse SPS/PPS */
+ while (size > 4) {
+ /* skip start code */
+ data += 3;
+ size -= 3;
+
+ /* use next_start_code() to scan buffer.
+ * next_start_code() returns the offset in data,
+ * starting from zero to the first byte of 0.0.0.1
+ * If no start code is found, it returns the value of the
+ * 'size' parameter.
+ * data is unchanged by the call to next_start_code()
+ */
+ next = next_start_code (data, size);
+
+ /* nal or au aligned input needs no delaying until next time */
+ if (next == size && buffer != NULL &&
+ rtph264pay->alignment == GST_H264_ALIGNMENT_UNKNOWN) {
+ /* Didn't find the start of next NAL and it's not EOS,
+ * handle it next time */
+ break;
+ }
+
+ /* nal length is distance to next start code */
+ nal_len = next;
+
+ GST_DEBUG_OBJECT (basepayload, "found next start at %u of size %u", next,
+ nal_len);
+
+ if (rtph264pay->sprop_parameter_sets != NULL) {
+ /* explicitly set profile and sprop, use those */
+ if (rtph264pay->update_caps) {
+ if (!gst_rtp_base_payload_set_outcaps (basepayload,
+ "sprop-parameter-sets", G_TYPE_STRING,
+ rtph264pay->sprop_parameter_sets, NULL))
+ goto caps_rejected;
+
+ /* parse SPS and PPS from provided parameter set (for insertion) */
+ gst_rtp_h264_pay_parse_sprop_parameter_sets (rtph264pay);
+
+ rtph264pay->update_caps = FALSE;
+
+ GST_DEBUG ("outcaps update: sprop-parameter-sets=%s",
+ rtph264pay->sprop_parameter_sets);
+ }
+ } else {
+ /* We know our stream is a valid H264 NAL packet,
+ * go parse it for SPS/PPS to enrich the caps */
+ /* order: make sure to check nal */
+ update =
+ gst_rtp_h264_pay_decode_nal (rtph264pay, data, nal_len, dts, pts)
+ || update;
+ }
+ /* move to next NAL packet */
+ data += nal_len;
+ size -= nal_len;
+
+ g_array_append_val (nal_queue, nal_len);
+ }
+
+ /* if has new SPS & PPS, update the output caps */
+ if (G_UNLIKELY (update))
+ if (!gst_rtp_h264_pay_set_sps_pps (basepayload))
+ goto caps_rejected;
+
+ /* second pass to payload and push */
+
+ if (nal_queue->len != 0)
+ gst_adapter_flush (rtph264pay->adapter, skip);
+
+ for (i = 0; i < nal_queue->len; i++) {
+ guint size;
+ gboolean end_of_au = FALSE;
+
+ nal_len = g_array_index (nal_queue, guint, i);
+ /* skip start code */
+ gst_adapter_flush (rtph264pay->adapter, 3);
+
+ /* Trim the end unless we're the last NAL in the stream.
+ * In case we're not at the end of the buffer we know the next block
+ * starts with 0x000001 so all the 0x00 bytes at the end of this one are
+ * trailing 0x0 that can be discarded */
+ size = nal_len;
+ data = gst_adapter_map (rtph264pay->adapter, size);
+ if (i + 1 != nal_queue->len || buffer != NULL)
+ for (; size > 1 && data[size - 1] == 0x0; size--)
+ /* skip */ ;
+
+
+ /* If it's the last nal unit we have in non-bytestream mode, we can
+ * assume it's the end of an access-unit
+ *
+ * FIXME: We need to wait until the next packet or EOS to
+ * actually payload the NAL so we can know if the current NAL is
+ * the last one of an access unit or not if we are in bytestream mode
+ */
+ if ((rtph264pay->alignment == GST_H264_ALIGNMENT_AU || buffer == NULL) &&
+ i == nal_queue->len - 1)
+ end_of_au = TRUE;
+ paybuf = gst_adapter_take_buffer (rtph264pay->adapter, size);
+ g_assert (paybuf);
+
+ /* put the data in one or more RTP packets */
+ ret =
+ gst_rtp_h264_pay_payload_nal (basepayload, paybuf, dts, pts,
+ end_of_au, rtph264pay->delta_unit, rtph264pay->discont);
+
+ if (delayed_not_delta_unit) {
+ rtph264pay->delta_unit = FALSE;
+ delayed_not_delta_unit = FALSE;
+ } else {
+ /* Only the first outgoing packet doesn't have the DELTA_UNIT flag */
+ rtph264pay->delta_unit = TRUE;
+ }
+
+ if (delayed_discont) {
+ rtph264pay->discont = TRUE;
+ delayed_discont = FALSE;
+ } else {
+ /* Only the first outgoing packet have the DISCONT flag */
+ rtph264pay->discont = FALSE;
+ }
+
+ if (ret != GST_FLOW_OK) {
+ break;
+ }
+
+ /* move to next NAL packet */
+ /* Skips the trailing zeros */
+ gst_adapter_flush (rtph264pay->adapter, nal_len - size);
+ }
+ g_array_set_size (nal_queue, 0);
+ }
+
+done:
+ if (avc) {
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+ } else {
+ gst_adapter_unmap (rtph264pay->adapter);
+ }
+
+ return ret;
+
+caps_rejected:
+ {
+ GST_WARNING_OBJECT (basepayload, "Could not set outcaps");
+ g_array_set_size (nal_queue, 0);
+ ret = GST_FLOW_NOT_NEGOTIATED;
+ goto done;
+ }
+}
+
+static gboolean
+gst_rtp_h264_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+ gboolean res;
+ const GstStructure *s;
+ GstRtpH264Pay *rtph264pay = GST_RTP_H264_PAY (payload);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_STOP:
+ gst_adapter_clear (rtph264pay->adapter);
+ break;
+ case GST_EVENT_CUSTOM_DOWNSTREAM:
+ s = gst_event_get_structure (event);
+ if (gst_structure_has_name (s, "GstForceKeyUnit")) {
+ gboolean resend_codec_data;
+
+ if (gst_structure_get_boolean (s, "all-headers",
+ &resend_codec_data) && resend_codec_data)
+ rtph264pay->send_spspps = TRUE;
+ }
+ break;
+ case GST_EVENT_EOS:
+ {
+ /* call handle_buffer with NULL to flush last NAL from adapter
+ * in byte-stream mode
+ */
+ gst_rtp_h264_pay_handle_buffer (payload, NULL);
+ break;
+ }
+ case GST_EVENT_STREAM_START:
+ GST_DEBUG_OBJECT (rtph264pay, "New stream detected => Clear SPS and PPS");
+ gst_rtp_h264_pay_clear_sps_pps (rtph264pay);
+ break;
+ default:
+ break;
+ }
+
+ res = GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
+
+ return res;
+}
+
+static GstStateChangeReturn
+gst_rtp_h264_pay_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret;
+ GstRtpH264Pay *rtph264pay = GST_RTP_H264_PAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ rtph264pay->send_spspps = FALSE;
+ gst_adapter_clear (rtph264pay->adapter);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ rtph264pay->last_spspps = -1;
+ gst_rtp_h264_pay_clear_sps_pps (rtph264pay);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static void
+gst_rtp_h264_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstRtpH264Pay *rtph264pay;
+
+ rtph264pay = GST_RTP_H264_PAY (object);
+
+ switch (prop_id) {
+ case PROP_SPROP_PARAMETER_SETS:
+ g_free (rtph264pay->sprop_parameter_sets);
+ rtph264pay->sprop_parameter_sets = g_value_dup_string (value);
+ rtph264pay->update_caps = TRUE;
+ break;
+ case PROP_CONFIG_INTERVAL:
+ rtph264pay->spspps_interval = g_value_get_uint (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_rtp_h264_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstRtpH264Pay *rtph264pay;
+
+ rtph264pay = GST_RTP_H264_PAY (object);
+
+ switch (prop_id) {
+ case PROP_SPROP_PARAMETER_SETS:
+ g_value_set_string (value, rtph264pay->sprop_parameter_sets);
+ break;
+ case PROP_CONFIG_INTERVAL:
+ g_value_set_uint (value, rtph264pay->spspps_interval);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+gboolean
+gst_rtp_h264_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtph264pay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_H264_PAY);
+}
diff --git a/gst/rtp/gstrtph264pay.h b/gst/rtp/gstrtph264pay.h
new file mode 100755
index 0000000..44f7af4
--- /dev/null
+++ b/gst/rtp/gstrtph264pay.h
@@ -0,0 +1,95 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_H264_PAY_H__
+#define __GST_RTP_H264_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_H264_PAY \
+ (gst_rtp_h264_pay_get_type())
+#define GST_RTP_H264_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_H264_PAY,GstRtpH264Pay))
+#define GST_RTP_H264_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_H264_PAY,GstRtpH264PayClass))
+#define GST_IS_RTP_H264_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_H264_PAY))
+#define GST_IS_RTP_H264_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_H264_PAY))
+
+typedef struct _GstRtpH264Pay GstRtpH264Pay;
+typedef struct _GstRtpH264PayClass GstRtpH264PayClass;
+
+typedef enum
+{
+ GST_H264_STREAM_FORMAT_UNKNOWN,
+ GST_H264_STREAM_FORMAT_BYTESTREAM,
+ GST_H264_STREAM_FORMAT_AVC
+} GstH264StreamFormat;
+
+typedef enum
+{
+ GST_H264_ALIGNMENT_UNKNOWN,
+ GST_H264_ALIGNMENT_NAL,
+ GST_H264_ALIGNMENT_AU
+} GstH264Alignment;
+
+struct _GstRtpH264Pay
+{
+ GstRTPBasePayload payload;
+
+ guint profile;
+ GPtrArray *sps, *pps;
+
+ GstH264StreamFormat stream_format;
+ GstH264Alignment alignment;
+ guint nal_length_size;
+ GArray *queue;
+
+ gchar *sprop_parameter_sets;
+ gboolean update_caps;
+
+ GstAdapter *adapter;
+
+ guint spspps_interval;
+ gboolean send_spspps;
+ GstClockTime last_spspps;
+
+ /* TRUE if the next NALU processed should have the DELTA_UNIT flag */
+ gboolean delta_unit;
+ /* TRUE if the next NALU processed should have the DISCONT flag */
+ gboolean discont;
+};
+
+struct _GstRtpH264PayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_h264_pay_get_type (void);
+
+gboolean gst_rtp_h264_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_H264_PAY_H__ */
diff --git a/gst/rtp/gstrtpilbcdepay.c b/gst/rtp/gstrtpilbcdepay.c
new file mode 100755
index 0000000..5c7dc25
--- /dev/null
+++ b/gst/rtp/gstrtpilbcdepay.c
@@ -0,0 +1,237 @@
+/* GStreamer
+ * Copyright (C) <2006> Philippe Khalaf <burger@speedy.org>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include "gstrtpilbcdepay.h"
+
+/* RtpiLBCDepay signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+#define DEFAULT_MODE GST_ILBC_MODE_30
+
+enum
+{
+ PROP_0,
+ PROP_MODE
+};
+
+/* FIXME, mode should be string because it is a parameter in SDP fmtp */
+static GstStaticPadTemplate gst_rtp_ilbc_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "clock-rate = (int) 8000, "
+ "encoding-name = (string) \"ILBC\"")
+ /* "mode = (string) { \"20\", \"30\" }" */
+ );
+
+static GstStaticPadTemplate gst_rtp_ilbc_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-iLBC, " "mode = (int) { 20, 30 }")
+ );
+
+static void gst_ilbc_depay_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_ilbc_depay_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec);
+
+static GstBuffer *gst_rtp_ilbc_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+static gboolean gst_rtp_ilbc_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+
+#define gst_rtp_ilbc_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPiLBCDepay, gst_rtp_ilbc_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+#define GST_TYPE_ILBC_MODE (gst_ilbc_mode_get_type())
+static GType
+gst_ilbc_mode_get_type (void)
+{
+ static GType ilbc_mode_type = 0;
+ static const GEnumValue ilbc_modes[] = {
+ {GST_ILBC_MODE_20, "20ms frames", "20ms"},
+ {GST_ILBC_MODE_30, "30ms frames", "30ms"},
+ {0, NULL, NULL},
+ };
+
+ if (!ilbc_mode_type) {
+ ilbc_mode_type = g_enum_register_static ("iLBCMode", ilbc_modes);
+ }
+ return ilbc_mode_type;
+}
+
+static void
+gst_rtp_ilbc_depay_class_init (GstRTPiLBCDepayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gobject_class->set_property = gst_ilbc_depay_set_property;
+ gobject_class->get_property = gst_ilbc_depay_get_property;
+
+ /* FIXME, mode is in the caps */
+ g_object_class_install_property (gobject_class, PROP_MODE,
+ g_param_spec_enum ("mode", "Mode", "iLBC frame mode",
+ GST_TYPE_ILBC_MODE, DEFAULT_MODE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_ilbc_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_ilbc_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP iLBC depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts iLBC audio from RTP packets (RFC 3952)",
+ "Philippe Kalaf <philippe.kalaf@collabora.co.uk>");
+
+ gstrtpbasedepayload_class->process = gst_rtp_ilbc_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_ilbc_depay_setcaps;
+}
+
+static void
+gst_rtp_ilbc_depay_init (GstRTPiLBCDepay * rtpilbcdepay)
+{
+ /* Set default mode */
+ rtpilbcdepay->mode = DEFAULT_MODE;
+}
+
+static gboolean
+gst_rtp_ilbc_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstRTPiLBCDepay *rtpilbcdepay = GST_RTP_ILBC_DEPAY (depayload);
+ GstCaps *srccaps;
+ GstStructure *structure;
+ const gchar *mode_str = NULL;
+ gint mode, clock_rate;
+ gboolean ret;
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ mode = rtpilbcdepay->mode;
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 8000;
+ depayload->clock_rate = clock_rate;
+
+ /* parse mode, if we can */
+ mode_str = gst_structure_get_string (structure, "mode");
+ if (mode_str) {
+ mode = strtol (mode_str, NULL, 10);
+ if (mode != 20 && mode != 30)
+ mode = rtpilbcdepay->mode;
+ }
+
+ rtpilbcdepay->mode = mode;
+
+ srccaps = gst_caps_new_simple ("audio/x-iLBC",
+ "mode", G_TYPE_INT, rtpilbcdepay->mode, NULL);
+ ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+
+ GST_DEBUG ("set caps on source: %" GST_PTR_FORMAT " (ret=%d)", srccaps, ret);
+ gst_caps_unref (srccaps);
+
+ return ret;
+}
+
+static GstBuffer *
+gst_rtp_ilbc_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstBuffer *outbuf;
+ gboolean marker;
+ GstRTPBuffer rtp = { NULL };
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ marker = gst_rtp_buffer_get_marker (&rtp);
+
+ GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d",
+ gst_buffer_get_size (buf), marker,
+ gst_rtp_buffer_get_timestamp (&rtp), gst_rtp_buffer_get_seq (&rtp));
+
+ outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ if (marker && outbuf) {
+ /* mark start of talkspurt with RESYNC */
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+ }
+
+ return outbuf;
+}
+
+static void
+gst_ilbc_depay_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ GstRTPiLBCDepay *rtpilbcdepay = GST_RTP_ILBC_DEPAY (object);
+
+ switch (prop_id) {
+ case PROP_MODE:
+ rtpilbcdepay->mode = g_value_get_enum (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_ilbc_depay_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ GstRTPiLBCDepay *rtpilbcdepay = GST_RTP_ILBC_DEPAY (object);
+
+ switch (prop_id) {
+ case PROP_MODE:
+ g_value_set_enum (value, rtpilbcdepay->mode);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+gboolean
+gst_rtp_ilbc_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpilbcdepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_ILBC_DEPAY);
+}
diff --git a/gst/rtp/gstrtpilbcdepay.h b/gst/rtp/gstrtpilbcdepay.h
new file mode 100755
index 0000000..01fd225
--- /dev/null
+++ b/gst/rtp/gstrtpilbcdepay.h
@@ -0,0 +1,65 @@
+/* GStreamer
+ * Copyright (C) <2006> Philippe Khalaf <burger@speedy.org>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_ILBC_DEPAY_H__
+#define __GST_RTP_ILBC_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRTPiLBCDepay GstRTPiLBCDepay;
+typedef struct _GstRTPiLBCDepayClass GstRTPiLBCDepayClass;
+
+#define GST_TYPE_RTP_ILBC_DEPAY \
+ (gst_rtp_ilbc_depay_get_type())
+#define GST_RTP_ILBC_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_ILBC_DEPAY,GstRTPiLBCDepay))
+#define GST_RTP_ILBC_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_ILBC_DEPAY,GstRTPiLBCDepayClass))
+#define GST_IS_RTP_ILBC_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_ILBC_DEPAY))
+#define GST_IS_RTP_ILBC_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_ILBC_DEPAY))
+
+typedef enum {
+ GST_ILBC_MODE_20 = 20,
+ GST_ILBC_MODE_30 = 30
+} GstiLBCMode;
+
+struct _GstRTPiLBCDepay
+{
+ GstRTPBaseDepayload depayload;
+
+ GstiLBCMode mode;
+};
+
+struct _GstRTPiLBCDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_ilbc_depay_get_type (void);
+
+gboolean gst_rtp_ilbc_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_ILBC_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpilbcpay.c b/gst/rtp/gstrtpilbcpay.c
new file mode 100755
index 0000000..7d6ea28
--- /dev/null
+++ b/gst/rtp/gstrtpilbcpay.c
@@ -0,0 +1,217 @@
+/* GStreamer
+ * Copyright (C) <2006> Philippe Khalaf <burger@speedy.org>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include "gstrtpilbcpay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpilbcpay_debug);
+#define GST_CAT_DEFAULT (rtpilbcpay_debug)
+
+static GstStaticPadTemplate gst_rtp_ilbc_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-iLBC, " "mode = (int) {20, 30}")
+ );
+
+static GstStaticPadTemplate gst_rtp_ilbc_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) 8000, "
+ "encoding-name = (string) \"ILBC\", "
+ "mode = (string) { \"20\", \"30\" }")
+ );
+
+
+static GstCaps *gst_rtp_ilbc_pay_sink_getcaps (GstRTPBasePayload * payload,
+ GstPad * pad, GstCaps * filter);
+static gboolean gst_rtp_ilbc_pay_sink_setcaps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+
+#define gst_rtp_ilbc_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPILBCPay, gst_rtp_ilbc_pay,
+ GST_TYPE_RTP_BASE_AUDIO_PAYLOAD);
+
+static void
+gst_rtp_ilbc_pay_class_init (GstRTPILBCPayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ GST_DEBUG_CATEGORY_INIT (rtpilbcpay_debug, "rtpilbcpay", 0,
+ "iLBC audio RTP payloader");
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_ilbc_pay_sink_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_ilbc_pay_src_template));
+
+ gst_element_class_set_static_metadata (gstelement_class, "RTP iLBC Payloader",
+ "Codec/Payloader/Network/RTP",
+ "Packetize iLBC audio streams into RTP packets",
+ "Philippe Kalaf <philippe.kalaf@collabora.co.uk>");
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_ilbc_pay_sink_setcaps;
+ gstrtpbasepayload_class->get_caps = gst_rtp_ilbc_pay_sink_getcaps;
+}
+
+static void
+gst_rtp_ilbc_pay_init (GstRTPILBCPay * rtpilbcpay)
+{
+ GstRTPBasePayload *rtpbasepayload;
+ GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+ rtpbasepayload = GST_RTP_BASE_PAYLOAD (rtpilbcpay);
+ rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpilbcpay);
+
+ /* we don't set the payload type, it should be set by the application using
+ * the pt property or the default 96 will be used */
+ rtpbasepayload->clock_rate = 8000;
+
+ rtpilbcpay->mode = -1;
+
+ /* tell rtpbaseaudiopayload that this is a frame based codec */
+ gst_rtp_base_audio_payload_set_frame_based (rtpbaseaudiopayload);
+}
+
+static gboolean
+gst_rtp_ilbc_pay_sink_setcaps (GstRTPBasePayload * rtpbasepayload,
+ GstCaps * caps)
+{
+ GstRTPILBCPay *rtpilbcpay;
+ GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+ gboolean ret;
+ gint mode;
+ gchar *mode_str;
+ GstStructure *structure;
+ const char *payload_name;
+
+ rtpilbcpay = GST_RTP_ILBC_PAY (rtpbasepayload);
+ rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpbasepayload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ payload_name = gst_structure_get_name (structure);
+ if (g_ascii_strcasecmp ("audio/x-iLBC", payload_name))
+ goto wrong_caps;
+
+ if (!gst_structure_get_int (structure, "mode", &mode))
+ goto no_mode;
+
+ if (mode != 20 && mode != 30)
+ goto wrong_mode;
+
+ gst_rtp_base_payload_set_options (rtpbasepayload, "audio", TRUE, "ILBC",
+ 8000);
+ /* set options for this frame based audio codec */
+ gst_rtp_base_audio_payload_set_frame_options (rtpbaseaudiopayload,
+ mode, mode == 30 ? 50 : 38);
+
+ mode_str = g_strdup_printf ("%d", mode);
+ ret =
+ gst_rtp_base_payload_set_outcaps (rtpbasepayload, "mode", G_TYPE_STRING,
+ mode_str, NULL);
+ g_free (mode_str);
+
+ if (mode != rtpilbcpay->mode && rtpilbcpay->mode != -1)
+ goto mode_changed;
+
+ rtpilbcpay->mode = mode;
+
+ return ret;
+
+ /* ERRORS */
+wrong_caps:
+ {
+ GST_ERROR_OBJECT (rtpilbcpay, "expected audio/x-iLBC, received %s",
+ payload_name);
+ return FALSE;
+ }
+no_mode:
+ {
+ GST_ERROR_OBJECT (rtpilbcpay, "did not receive a mode");
+ return FALSE;
+ }
+wrong_mode:
+ {
+ GST_ERROR_OBJECT (rtpilbcpay, "mode must be 20 or 30, received %d", mode);
+ return FALSE;
+ }
+mode_changed:
+ {
+ GST_ERROR_OBJECT (rtpilbcpay, "Mode has changed from %d to %d! "
+ "Mode cannot change while streaming", rtpilbcpay->mode, mode);
+ return FALSE;
+ }
+}
+
+/* we return the padtemplate caps with the mode field fixated to a value if we
+ * can */
+static GstCaps *
+gst_rtp_ilbc_pay_sink_getcaps (GstRTPBasePayload * rtppayload, GstPad * pad,
+ GstCaps * filter)
+{
+ GstCaps *otherpadcaps;
+ GstCaps *caps;
+
+ otherpadcaps = gst_pad_get_allowed_caps (rtppayload->srcpad);
+ caps = gst_pad_get_pad_template_caps (pad);
+
+ if (otherpadcaps) {
+ if (!gst_caps_is_empty (otherpadcaps)) {
+ GstStructure *structure;
+ const gchar *mode_str;
+ gint mode;
+
+ structure = gst_caps_get_structure (otherpadcaps, 0);
+
+ /* parse mode, if we can */
+ mode_str = gst_structure_get_string (structure, "mode");
+ if (mode_str) {
+ mode = strtol (mode_str, NULL, 10);
+ if (mode == 20 || mode == 30) {
+ caps = gst_caps_make_writable (caps);
+ structure = gst_caps_get_structure (caps, 0);
+ gst_structure_set (structure, "mode", G_TYPE_INT, mode, NULL);
+ }
+ }
+ }
+ gst_caps_unref (otherpadcaps);
+ }
+ return caps;
+}
+
+gboolean
+gst_rtp_ilbc_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpilbcpay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_ILBC_PAY);
+}
diff --git a/gst/rtp/gstrtpilbcpay.h b/gst/rtp/gstrtpilbcpay.h
new file mode 100755
index 0000000..14363c0
--- /dev/null
+++ b/gst/rtp/gstrtpilbcpay.h
@@ -0,0 +1,60 @@
+/* GStreamer
+ * Copyright (C) <2006> Philippe Khalaf <burger@speedy.org>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_ILBC_PAY_H__
+#define __GST_RTP_ILBC_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_ILBC_PAY \
+ (gst_rtp_ilbc_pay_get_type())
+#define GST_RTP_ILBC_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_ILBC_PAY,GstRTPILBCPay))
+#define GST_RTP_ILBC_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_ILBC_PAY,GstRTPILBCPayClass))
+#define GST_IS_RTP_ILBC_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_ILBC_PAY))
+#define GST_IS_RTP_ILBC_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_ILBC_PAY))
+
+typedef struct _GstRTPILBCPay GstRTPILBCPay;
+typedef struct _GstRTPILBCPayClass GstRTPILBCPayClass;
+
+struct _GstRTPILBCPay
+{
+ GstRTPBaseAudioPayload audiopayload;
+
+ gint mode;
+};
+
+struct _GstRTPILBCPayClass
+{
+ GstRTPBaseAudioPayloadClass parent_class;
+};
+
+GType gst_rtp_ilbc_pay_get_type (void);
+
+gboolean gst_rtp_ilbc_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_ILBC_PAY_H__ */
diff --git a/gst/rtp/gstrtpj2kdepay.c b/gst/rtp/gstrtpj2kdepay.c
new file mode 100755
index 0000000..9829258
--- /dev/null
+++ b/gst/rtp/gstrtpj2kdepay.c
@@ -0,0 +1,646 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <string.h>
+#include "gstrtpj2kdepay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpj2kdepay_debug);
+#define GST_CAT_DEFAULT (rtpj2kdepay_debug)
+
+static GstStaticPadTemplate gst_rtp_j2k_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("image/x-jpc")
+ );
+
+static GstStaticPadTemplate gst_rtp_j2k_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"video\", "
+ "clock-rate = (int) 90000, " "encoding-name = (string) \"JPEG2000\"")
+ );
+
+typedef enum
+{
+ J2K_MARKER = 0xFF,
+ J2K_MARKER_SOC = 0x4F,
+ J2K_MARKER_SOT = 0x90,
+ J2K_MARKER_SOP = 0x91,
+ J2K_MARKER_SOD = 0x93,
+ J2K_MARKER_EOC = 0xD9
+} RtpJ2KMarker;
+
+enum
+{
+ PROP_0,
+ PROP_LAST
+};
+
+#define gst_rtp_j2k_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpJ2KDepay, gst_rtp_j2k_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_j2k_depay_finalize (GObject * object);
+
+static void gst_rtp_j2k_depay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_rtp_j2k_depay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static GstStateChangeReturn
+gst_rtp_j2k_depay_change_state (GstElement * element,
+ GstStateChange transition);
+
+static gboolean gst_rtp_j2k_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_j2k_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+
+static void
+gst_rtp_j2k_depay_class_init (GstRtpJ2KDepayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_j2k_depay_finalize;
+
+ gobject_class->set_property = gst_rtp_j2k_depay_set_property;
+ gobject_class->get_property = gst_rtp_j2k_depay_get_property;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_j2k_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_j2k_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP JPEG 2000 depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts JPEG 2000 video from RTP packets (RFC 5371)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ gstelement_class->change_state = gst_rtp_j2k_depay_change_state;
+
+ gstrtpbasedepayload_class->set_caps = gst_rtp_j2k_depay_setcaps;
+ gstrtpbasedepayload_class->process = gst_rtp_j2k_depay_process;
+
+ GST_DEBUG_CATEGORY_INIT (rtpj2kdepay_debug, "rtpj2kdepay", 0,
+ "J2K Video RTP Depayloader");
+}
+
+static void
+gst_rtp_j2k_depay_init (GstRtpJ2KDepay * rtpj2kdepay)
+{
+ rtpj2kdepay->pu_adapter = gst_adapter_new ();
+ rtpj2kdepay->t_adapter = gst_adapter_new ();
+ rtpj2kdepay->f_adapter = gst_adapter_new ();
+}
+
+static void
+store_mheader (GstRtpJ2KDepay * rtpj2kdepay, guint idx, GstBuffer * buf)
+{
+ GstBuffer *old;
+
+ GST_DEBUG_OBJECT (rtpj2kdepay, "storing main header %p at index %u", buf,
+ idx);
+ if ((old = rtpj2kdepay->MH[idx]))
+ gst_buffer_unref (old);
+ rtpj2kdepay->MH[idx] = buf;
+}
+
+static void
+clear_mheaders (GstRtpJ2KDepay * rtpj2kdepay)
+{
+ guint i;
+
+ for (i = 0; i < 8; i++)
+ store_mheader (rtpj2kdepay, i, NULL);
+}
+
+static void
+gst_rtp_j2k_depay_reset (GstRtpJ2KDepay * rtpj2kdepay)
+{
+ clear_mheaders (rtpj2kdepay);
+ gst_adapter_clear (rtpj2kdepay->pu_adapter);
+ gst_adapter_clear (rtpj2kdepay->t_adapter);
+ gst_adapter_clear (rtpj2kdepay->f_adapter);
+ rtpj2kdepay->next_frag = 0;
+}
+
+static void
+gst_rtp_j2k_depay_finalize (GObject * object)
+{
+ GstRtpJ2KDepay *rtpj2kdepay;
+
+ rtpj2kdepay = GST_RTP_J2K_DEPAY (object);
+
+ clear_mheaders (rtpj2kdepay);
+
+ g_object_unref (rtpj2kdepay->pu_adapter);
+ g_object_unref (rtpj2kdepay->t_adapter);
+ g_object_unref (rtpj2kdepay->f_adapter);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rtp_j2k_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstStructure *structure;
+ gint clock_rate;
+ GstCaps *outcaps;
+ gboolean res;
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 90000;
+ depayload->clock_rate = clock_rate;
+
+ outcaps =
+ gst_caps_new_simple ("image/x-jpc", "framerate", GST_TYPE_FRACTION, 0, 1,
+ "fields", G_TYPE_INT, 1, "colorspace", G_TYPE_STRING, "sYUV", NULL);
+ res = gst_pad_set_caps (depayload->srcpad, outcaps);
+ gst_caps_unref (outcaps);
+
+ return res;
+}
+
+static void
+gst_rtp_j2k_depay_clear_pu (GstRtpJ2KDepay * rtpj2kdepay)
+{
+ gst_adapter_clear (rtpj2kdepay->pu_adapter);
+ rtpj2kdepay->have_sync = FALSE;
+}
+
+static GstFlowReturn
+gst_rtp_j2k_depay_flush_pu (GstRTPBaseDepayload * depayload)
+{
+ GstRtpJ2KDepay *rtpj2kdepay;
+ GstBuffer *mheader;
+ guint avail, MHF, mh_id;
+
+ rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload);
+
+ /* take all available buffers */
+ avail = gst_adapter_available (rtpj2kdepay->pu_adapter);
+ if (avail == 0)
+ goto done;
+
+ MHF = rtpj2kdepay->pu_MHF;
+ mh_id = rtpj2kdepay->last_mh_id;
+
+ GST_DEBUG_OBJECT (rtpj2kdepay, "flushing PU of size %u", avail);
+
+ if (MHF == 0) {
+ GList *packets, *walk;
+
+ packets = gst_adapter_take_list (rtpj2kdepay->pu_adapter, avail);
+ /* append packets */
+ for (walk = packets; walk; walk = g_list_next (walk)) {
+ GstBuffer *buf = GST_BUFFER_CAST (walk->data);
+ GST_DEBUG_OBJECT (rtpj2kdepay,
+ "append pu packet of size %" G_GSIZE_FORMAT,
+ gst_buffer_get_size (buf));
+ gst_adapter_push (rtpj2kdepay->t_adapter, buf);
+ }
+ g_list_free (packets);
+ } else {
+ /* we have a header */
+ GST_DEBUG_OBJECT (rtpj2kdepay, "keeping header %u", mh_id);
+ /* we managed to see the start and end of the header, take all from
+ * adapter and keep in header */
+ mheader = gst_adapter_take_buffer (rtpj2kdepay->pu_adapter, avail);
+
+ store_mheader (rtpj2kdepay, mh_id, mheader);
+ }
+
+done:
+ rtpj2kdepay->have_sync = FALSE;
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_rtp_j2k_depay_flush_tile (GstRTPBaseDepayload * depayload)
+{
+ GstRtpJ2KDepay *rtpj2kdepay;
+ guint avail, mh_id;
+ GList *packets, *walk;
+ guint8 end[2];
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstMapInfo map;
+ GstBuffer *buf;
+
+ rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload);
+
+ /* flush pending PU */
+ gst_rtp_j2k_depay_flush_pu (depayload);
+
+ /* take all available buffers */
+ avail = gst_adapter_available (rtpj2kdepay->t_adapter);
+ if (avail == 0)
+ goto done;
+
+ mh_id = rtpj2kdepay->last_mh_id;
+
+ GST_DEBUG_OBJECT (rtpj2kdepay, "flushing tile of size %u", avail);
+
+ if (gst_adapter_available (rtpj2kdepay->f_adapter) == 0) {
+ GstBuffer *mheader;
+
+ /* we need a header now */
+ if ((mheader = rtpj2kdepay->MH[mh_id]) == NULL)
+ goto waiting_header;
+
+ /* push header in the adapter */
+ GST_DEBUG_OBJECT (rtpj2kdepay, "pushing header %u", mh_id);
+ gst_adapter_push (rtpj2kdepay->f_adapter, gst_buffer_ref (mheader));
+ }
+
+ /* check for last bytes */
+ gst_adapter_copy (rtpj2kdepay->t_adapter, end, avail - 2, 2);
+
+ /* now append the tile packets to the frame */
+ packets = gst_adapter_take_list (rtpj2kdepay->t_adapter, avail);
+ for (walk = packets; walk; walk = g_list_next (walk)) {
+ buf = GST_BUFFER_CAST (walk->data);
+
+ if (walk == packets) {
+ /* first buffer should contain the SOT */
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+
+ if (map.size < 12)
+ goto invalid_tile;
+
+ if (map.data[0] == 0xff && map.data[1] == J2K_MARKER_SOT) {
+ guint Psot, nPsot;
+
+ if (end[0] == 0xff && end[1] == J2K_MARKER_EOC)
+ nPsot = avail - 2;
+ else
+ nPsot = avail;
+
+ Psot = GST_READ_UINT32_BE (&map.data[6]);
+ if (Psot != nPsot && Psot != 0) {
+ /* Psot must match the size of the tile */
+ GST_DEBUG_OBJECT (rtpj2kdepay, "set Psot from %u to %u", Psot, nPsot);
+ gst_buffer_unmap (buf, &map);
+
+ buf = gst_buffer_make_writable (buf);
+
+ gst_buffer_map (buf, &map, GST_MAP_WRITE);
+ GST_WRITE_UINT32_BE (&map.data[6], nPsot);
+ }
+ }
+ gst_buffer_unmap (buf, &map);
+ }
+
+ GST_DEBUG_OBJECT (rtpj2kdepay, "append pu packet of size %" G_GSIZE_FORMAT,
+ gst_buffer_get_size (buf));
+ gst_adapter_push (rtpj2kdepay->f_adapter, buf);
+ }
+ g_list_free (packets);
+
+done:
+ rtpj2kdepay->last_tile = -1;
+
+ return ret;
+
+ /* errors */
+waiting_header:
+ {
+ GST_DEBUG_OBJECT (rtpj2kdepay, "waiting for header %u", mh_id);
+ gst_adapter_clear (rtpj2kdepay->t_adapter);
+ rtpj2kdepay->last_tile = -1;
+ return ret;
+ }
+invalid_tile:
+ {
+ GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE, ("Invalid tile"), (NULL));
+ gst_buffer_unmap (buf, &map);
+ gst_adapter_clear (rtpj2kdepay->t_adapter);
+ rtpj2kdepay->last_tile = -1;
+ return ret;
+ }
+}
+
+static GstFlowReturn
+gst_rtp_j2k_depay_flush_frame (GstRTPBaseDepayload * depayload)
+{
+ GstRtpJ2KDepay *rtpj2kdepay;
+ guint8 end[2];
+ guint avail;
+
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload);
+
+ /* flush pending tile */
+ gst_rtp_j2k_depay_flush_tile (depayload);
+
+ /* last buffer take all data out of the adapter */
+ avail = gst_adapter_available (rtpj2kdepay->f_adapter);
+ if (avail == 0)
+ goto done;
+
+ if (avail > 2) {
+ GList *list, *walk;
+ GstBufferList *buflist;
+
+ /* take the last bytes of the JPEG 2000 data to see if there is an EOC
+ * marker */
+ gst_adapter_copy (rtpj2kdepay->f_adapter, end, avail - 2, 2);
+
+ if (end[0] != 0xff && end[1] != 0xd9) {
+ GstBuffer *outbuf;
+
+ end[0] = 0xff;
+ end[1] = 0xd9;
+
+ GST_DEBUG_OBJECT (rtpj2kdepay, "no EOC marker, adding one");
+
+ /* no EOI marker, add one */
+ outbuf = gst_buffer_new_and_alloc (2);
+ gst_buffer_fill (outbuf, 0, end, 2);
+
+ gst_adapter_push (rtpj2kdepay->f_adapter, outbuf);
+ avail += 2;
+ }
+
+ GST_DEBUG_OBJECT (rtpj2kdepay, "pushing buffer list of %u bytes", avail);
+ list = gst_adapter_take_list (rtpj2kdepay->f_adapter, avail);
+
+ buflist = gst_buffer_list_new ();
+
+ for (walk = list; walk; walk = g_list_next (walk))
+ gst_buffer_list_add (buflist, GST_BUFFER_CAST (walk->data));
+
+ g_list_free (list);
+
+ ret = gst_rtp_base_depayload_push_list (depayload, buflist);
+ } else {
+ GST_WARNING_OBJECT (rtpj2kdepay, "empty packet");
+ gst_adapter_clear (rtpj2kdepay->f_adapter);
+ }
+
+ /* we accept any mh_id now */
+ rtpj2kdepay->last_mh_id = -1;
+
+ /* reset state */
+ rtpj2kdepay->next_frag = 0;
+ rtpj2kdepay->have_sync = FALSE;
+
+done:
+ /* we can't keep headers with mh_id of 0 */
+ store_mheader (rtpj2kdepay, 0, NULL);
+
+ return ret;
+}
+
+static GstBuffer *
+gst_rtp_j2k_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpJ2KDepay *rtpj2kdepay;
+ guint8 *payload;
+ guint MHF, mh_id, frag_offset, tile, payload_len, j2klen;
+ gint gap;
+ guint32 rtptime;
+ GstRTPBuffer rtp = { NULL };
+
+ rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+
+ /* we need at least a header */
+ if (payload_len < 8)
+ goto empty_packet;
+
+ rtptime = gst_rtp_buffer_get_timestamp (&rtp);
+
+ /* new timestamp marks new frame */
+ if (rtpj2kdepay->last_rtptime != rtptime) {
+ rtpj2kdepay->last_rtptime = rtptime;
+ /* flush pending frame */
+ gst_rtp_j2k_depay_flush_frame (depayload);
+ }
+
+ /*
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |tp |MHF|mh_id|T| priority | tile number |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |reserved | fragment offset |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ MHF = (payload[0] & 0x30) >> 4;
+ mh_id = (payload[0] & 0xe) >> 1;
+
+ if (rtpj2kdepay->last_mh_id == -1)
+ rtpj2kdepay->last_mh_id = mh_id;
+ else if (rtpj2kdepay->last_mh_id != mh_id)
+ goto wrong_mh_id;
+
+ tile = (payload[2] << 8) | payload[3];
+ frag_offset = (payload[5] << 16) | (payload[6] << 8) | payload[7];
+ j2klen = payload_len - 8;
+
+ GST_DEBUG_OBJECT (rtpj2kdepay, "MHF %u, tile %u, frag %u, expected %u", MHF,
+ tile, frag_offset, rtpj2kdepay->next_frag);
+
+ /* calculate the gap between expected frag */
+ gap = frag_offset - rtpj2kdepay->next_frag;
+ /* calculate next frag */
+ rtpj2kdepay->next_frag = frag_offset + j2klen;
+
+ if (gap != 0) {
+ GST_DEBUG_OBJECT (rtpj2kdepay, "discont of %d, clear PU", gap);
+ /* discont, clear pu adapter and resync */
+ gst_rtp_j2k_depay_clear_pu (rtpj2kdepay);
+ }
+
+ /* check for sync code */
+ if (j2klen > 2 && payload[8] == 0xff) {
+ guint marker = payload[9];
+
+ /* packets must start with SOC, SOT or SOP */
+ switch (marker) {
+ case J2K_MARKER_SOC:
+ GST_DEBUG_OBJECT (rtpj2kdepay, "found SOC packet");
+ /* flush the previous frame, should have happened when the timestamp
+ * changed above. */
+ gst_rtp_j2k_depay_flush_frame (depayload);
+ rtpj2kdepay->have_sync = TRUE;
+ break;
+ case J2K_MARKER_SOT:
+ /* flush the previous tile */
+ gst_rtp_j2k_depay_flush_tile (depayload);
+ GST_DEBUG_OBJECT (rtpj2kdepay, "found SOT packet");
+ rtpj2kdepay->have_sync = TRUE;
+ /* we sync on the tile now */
+ rtpj2kdepay->last_tile = tile;
+ break;
+ case J2K_MARKER_SOP:
+ GST_DEBUG_OBJECT (rtpj2kdepay, "found SOP packet");
+ /* flush the previous PU */
+ gst_rtp_j2k_depay_flush_pu (depayload);
+ if (rtpj2kdepay->last_tile != tile) {
+ /* wrong tile, we lose sync and we need a new SOT or SOC to regain
+ * sync. First flush out the previous tile if we have one. */
+ if (rtpj2kdepay->last_tile != -1)
+ gst_rtp_j2k_depay_flush_tile (depayload);
+ /* now we have no more valid tile and no sync */
+ rtpj2kdepay->last_tile = -1;
+ rtpj2kdepay->have_sync = FALSE;
+ } else {
+ rtpj2kdepay->have_sync = TRUE;
+ }
+ break;
+ default:
+ GST_DEBUG_OBJECT (rtpj2kdepay, "no sync packet 0x%02d", marker);
+ break;
+ }
+ }
+
+ if (rtpj2kdepay->have_sync) {
+ GstBuffer *pu_frag;
+
+ if (gst_adapter_available (rtpj2kdepay->pu_adapter) == 0) {
+ /* first part of pu, record state */
+ GST_DEBUG_OBJECT (rtpj2kdepay, "first PU");
+ rtpj2kdepay->pu_MHF = MHF;
+ }
+ /* and push in pu adapter */
+ GST_DEBUG_OBJECT (rtpj2kdepay, "push pu of size %u in adapter", j2klen);
+ pu_frag = gst_rtp_buffer_get_payload_subbuffer (&rtp, 8, -1);
+ gst_adapter_push (rtpj2kdepay->pu_adapter, pu_frag);
+
+ if (MHF & 2) {
+ /* last part of main header received, we can flush it */
+ GST_DEBUG_OBJECT (rtpj2kdepay, "header end, flush pu");
+ gst_rtp_j2k_depay_flush_pu (depayload);
+ }
+ } else {
+ GST_DEBUG_OBJECT (rtpj2kdepay, "discard packet, no sync");
+ }
+
+ /* marker bit finishes the frame */
+ if (gst_rtp_buffer_get_marker (&rtp)) {
+ GST_DEBUG_OBJECT (rtpj2kdepay, "marker set, last buffer");
+ /* then flush frame */
+ gst_rtp_j2k_depay_flush_frame (depayload);
+ }
+ gst_rtp_buffer_unmap (&rtp);
+
+ return NULL;
+
+ /* ERRORS */
+empty_packet:
+ {
+ GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE,
+ ("Empty Payload."), (NULL));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+wrong_mh_id:
+ {
+ GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE,
+ ("Invalid mh_id %u, expected %u", mh_id, rtpj2kdepay->last_mh_id),
+ (NULL));
+ gst_rtp_j2k_depay_clear_pu (rtpj2kdepay);
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+}
+
+static void
+gst_rtp_j2k_depay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_rtp_j2k_depay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GstStateChangeReturn
+gst_rtp_j2k_depay_change_state (GstElement * element, GstStateChange transition)
+{
+ GstRtpJ2KDepay *rtpj2kdepay;
+ GstStateChangeReturn ret;
+
+ rtpj2kdepay = GST_RTP_J2K_DEPAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_rtp_j2k_depay_reset (rtpj2kdepay);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_rtp_j2k_depay_reset (rtpj2kdepay);
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+gboolean
+gst_rtp_j2k_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpj2kdepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_J2K_DEPAY);
+}
diff --git a/gst/rtp/gstrtpj2kdepay.h b/gst/rtp/gstrtpj2kdepay.h
new file mode 100755
index 0000000..e5b9d6b
--- /dev/null
+++ b/gst/rtp/gstrtpj2kdepay.h
@@ -0,0 +1,75 @@
+/* GStreamer
+ * Copyright (C) <2009> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_J2K_DEPAY_H__
+#define __GST_RTP_J2K_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_J2K_DEPAY \
+ (gst_rtp_j2k_depay_get_type())
+#define GST_RTP_J2K_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_J2K_DEPAY,GstRtpJ2KDepay))
+#define GST_RTP_J2K_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_J2K_DEPAY,GstRtpJ2KDepayClass))
+#define GST_IS_RTP_J2K_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_J2K_DEPAY))
+#define GST_IS_RTP_J2K_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_J2K_DEPAY))
+
+typedef struct _GstRtpJ2KDepay GstRtpJ2KDepay;
+typedef struct _GstRtpJ2KDepayClass GstRtpJ2KDepayClass;
+
+struct _GstRtpJ2KDepay
+{
+ GstRTPBaseDepayload depayload;
+
+ guint64 last_rtptime;
+ guint last_mh_id;
+ guint last_tile;
+
+ GstBuffer *MH[8];
+
+ guint pu_MHF;
+ GstAdapter *pu_adapter;
+ GstAdapter *t_adapter;
+ GstAdapter *f_adapter;
+
+ guint next_frag;
+ gboolean have_sync;
+
+ gint width, height;
+};
+
+struct _GstRtpJ2KDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_j2k_depay_get_type (void);
+
+gboolean gst_rtp_j2k_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_J2K_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpj2kpay.c b/gst/rtp/gstrtpj2kpay.c
new file mode 100755
index 0000000..98880b2
--- /dev/null
+++ b/gst/rtp/gstrtpj2kpay.c
@@ -0,0 +1,536 @@
+/* GStreamer
+ * Copyright (C) 2009 Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpj2kpay
+ *
+ * Payload encode JPEG 2000 pictures into RTP packets according to RFC 5371.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc5371.txt
+ *
+ * The payloader takes a JPEG 2000 picture, scans the header for packetization
+ * units and constructs the RTP packet header followed by the actual JPEG 2000
+ * codestream.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpj2kpay.h"
+
+static GstStaticPadTemplate gst_rtp_j2k_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("image/x-jpc")
+ );
+
+static GstStaticPadTemplate gst_rtp_j2k_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ " media = (string) \"video\", "
+ " payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ " clock-rate = (int) 90000, "
+ " encoding-name = (string) \"JPEG2000\"")
+ );
+
+GST_DEBUG_CATEGORY_STATIC (rtpj2kpay_debug);
+#define GST_CAT_DEFAULT (rtpj2kpay_debug)
+
+/*
+ * RtpJ2KMarker:
+ * @J2K_MARKER: Prefix for JPEG 2000 marker
+ * @J2K_MARKER_SOC: Start of Codestream
+ * @J2K_MARKER_SOT: Start of tile
+ * @J2K_MARKER_EOC: End of Codestream
+ *
+ * Identifers for markers in JPEG 2000 codestreams
+ */
+typedef enum
+{
+ J2K_MARKER = 0xFF,
+ J2K_MARKER_SOC = 0x4F,
+ J2K_MARKER_SOT = 0x90,
+ J2K_MARKER_SOP = 0x91,
+ J2K_MARKER_EPH = 0x92,
+ J2K_MARKER_SOD = 0x93,
+ J2K_MARKER_EOC = 0xD9
+} RtpJ2KMarker;
+
+enum
+{
+ PROP_0,
+ PROP_LAST
+};
+
+typedef struct
+{
+ guint tp:2;
+ guint MHF:2;
+ guint mh_id:3;
+ guint T:1;
+ guint priority:8;
+ guint tile:16;
+ guint offset:24;
+} RtpJ2KHeader;
+
+#define HEADER_SIZE 8
+
+static void gst_rtp_j2k_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_rtp_j2k_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static gboolean gst_rtp_j2k_pay_setcaps (GstRTPBasePayload * basepayload,
+ GstCaps * caps);
+
+static GstFlowReturn gst_rtp_j2k_pay_handle_buffer (GstRTPBasePayload * pad,
+ GstBuffer * buffer);
+
+#define gst_rtp_j2k_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpJ2KPay, gst_rtp_j2k_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_j2k_pay_class_init (GstRtpJ2KPayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gobject_class->set_property = gst_rtp_j2k_pay_set_property;
+ gobject_class->get_property = gst_rtp_j2k_pay_get_property;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_j2k_pay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_j2k_pay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP JPEG 2000 payloader", "Codec/Payloader/Network/RTP",
+ "Payload-encodes JPEG 2000 pictures into RTP packets (RFC 5371)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_j2k_pay_setcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_j2k_pay_handle_buffer;
+
+ GST_DEBUG_CATEGORY_INIT (rtpj2kpay_debug, "rtpj2kpay", 0,
+ "JPEG 2000 RTP Payloader");
+}
+
+static void
+gst_rtp_j2k_pay_init (GstRtpJ2KPay * pay)
+{
+}
+
+static gboolean
+gst_rtp_j2k_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
+{
+ GstStructure *caps_structure = gst_caps_get_structure (caps, 0);
+ GstRtpJ2KPay *pay;
+ gint width = 0, height = 0;
+ gboolean res;
+
+ pay = GST_RTP_J2K_PAY (basepayload);
+
+ /* these properties are not mandatory, we can get them from the stream */
+ if (gst_structure_get_int (caps_structure, "height", &height)) {
+ pay->height = height;
+ }
+ if (gst_structure_get_int (caps_structure, "width", &width)) {
+ pay->width = width;
+ }
+
+ gst_rtp_base_payload_set_options (basepayload, "video", TRUE, "JPEG2000",
+ 90000);
+ res = gst_rtp_base_payload_set_outcaps (basepayload, NULL);
+
+ return res;
+}
+
+
+static guint
+gst_rtp_j2k_pay_header_size (const guint8 * data, guint offset)
+{
+ return data[offset] << 8 | data[offset + 1];
+}
+
+static RtpJ2KMarker
+gst_rtp_j2k_pay_scan_marker (const guint8 * data, guint size, guint * offset)
+{
+ while ((data[(*offset)++] != J2K_MARKER) && ((*offset) < size));
+
+ if (G_UNLIKELY ((*offset) >= size)) {
+ return J2K_MARKER_EOC;
+ } else {
+ guint8 marker = data[(*offset)++];
+ return marker;
+ }
+}
+
+typedef struct
+{
+ RtpJ2KHeader header;
+ gboolean bitstream;
+ guint n_tiles;
+ guint next_sot;
+ gboolean force_packet;
+} RtpJ2KState;
+
+static guint
+find_pu_end (GstRtpJ2KPay * pay, const guint8 * data, guint size,
+ guint offset, RtpJ2KState * state)
+{
+ gboolean cut_sop = FALSE;
+ RtpJ2KMarker marker;
+
+ /* parse the j2k header for 'start of codestream' */
+ GST_LOG_OBJECT (pay, "checking from offset %u", offset);
+ while (offset < size) {
+ marker = gst_rtp_j2k_pay_scan_marker (data, size, &offset);
+
+ if (state->bitstream) {
+ /* parsing bitstream, only look for SOP */
+ switch (marker) {
+ case J2K_MARKER_SOP:
+ GST_LOG_OBJECT (pay, "found SOP at %u", offset);
+ if (cut_sop)
+ return offset - 2;
+ cut_sop = TRUE;
+ break;
+ case J2K_MARKER_EPH:
+ /* just skip over EPH */
+ GST_LOG_OBJECT (pay, "found EPH at %u", offset);
+ break;
+ default:
+ if (offset >= state->next_sot) {
+ GST_LOG_OBJECT (pay, "reached next SOT at %u", offset);
+ state->bitstream = FALSE;
+ state->force_packet = TRUE;
+ if (marker == J2K_MARKER_EOC && state->next_sot + 2 <= size)
+ /* include EOC but never go past the max size */
+ return state->next_sot + 2;
+ else
+ return state->next_sot;
+ }
+ break;
+ }
+ } else {
+ switch (marker) {
+ case J2K_MARKER_SOC:
+ GST_LOG_OBJECT (pay, "found SOC at %u", offset);
+ state->header.MHF = 1;
+ break;
+ case J2K_MARKER_SOT:
+ {
+ guint len, Psot;
+
+ GST_LOG_OBJECT (pay, "found SOT at %u", offset);
+ /* we found SOT but also had a header first */
+ if (state->header.MHF) {
+ state->force_packet = TRUE;
+ return offset - 2;
+ }
+
+ /* parse SOT but do some sanity checks first */
+ len = gst_rtp_j2k_pay_header_size (data, offset);
+ GST_LOG_OBJECT (pay, "SOT length %u", len);
+ if (len < 8)
+ return size;
+ if (offset + len >= size)
+ return size;
+
+ if (state->n_tiles == 0)
+ /* first tile, T is valid */
+ state->header.T = 0;
+ else
+ /* more tiles, T becomes invalid */
+ state->header.T = 1;
+ state->header.tile = GST_READ_UINT16_BE (&data[offset + 2]);
+ state->n_tiles++;
+
+ /* get offset of next tile, if it's 0, it goes all the way to the end of
+ * the data */
+ Psot = GST_READ_UINT32_BE (&data[offset + 4]);
+ if (Psot == 0)
+ state->next_sot = size;
+ else
+ state->next_sot = offset - 2 + Psot;
+
+ offset += len;
+ GST_LOG_OBJECT (pay, "Isot %u, Psot %u, next %u", state->header.tile,
+ Psot, state->next_sot);
+ break;
+ }
+ case J2K_MARKER_SOD:
+ GST_LOG_OBJECT (pay, "found SOD at %u", offset);
+ /* can't have more tiles now */
+ state->n_tiles = 0;
+ /* go to bitstream parsing */
+ state->bitstream = TRUE;
+ /* cut at the next SOP or else include all data */
+ cut_sop = TRUE;
+ /* force a new packet when we see SOP, this can be optional but the
+ * spec recommends packing headers separately */
+ state->force_packet = TRUE;
+ break;
+ case J2K_MARKER_EOC:
+ GST_LOG_OBJECT (pay, "found EOC at %u", offset);
+ return offset;
+ default:
+ {
+ guint len = gst_rtp_j2k_pay_header_size (data, offset);
+ GST_LOG_OBJECT (pay, "skip 0x%02x len %u", marker, len);
+ offset += len;
+ break;
+ }
+ }
+ }
+ }
+ GST_DEBUG_OBJECT (pay, "reached end of data");
+ return size;
+}
+
+static GstFlowReturn
+gst_rtp_j2k_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer)
+{
+ GstRtpJ2KPay *pay;
+ GstClockTime timestamp;
+ GstFlowReturn ret = GST_FLOW_ERROR;
+ RtpJ2KState state;
+ GstBufferList *list = NULL;
+ GstMapInfo map;
+ guint mtu, max_size;
+ guint offset;
+ guint end, pos;
+
+ pay = GST_RTP_J2K_PAY (basepayload);
+ mtu = GST_RTP_BASE_PAYLOAD_MTU (pay);
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+ timestamp = GST_BUFFER_TIMESTAMP (buffer);
+ offset = pos = end = 0;
+
+ GST_LOG_OBJECT (pay,
+ "got buffer size %" G_GSIZE_FORMAT ", timestamp %" GST_TIME_FORMAT,
+ map.size, GST_TIME_ARGS (timestamp));
+
+ /* do some header defaults first */
+ state.header.tp = 0; /* only progressive scan */
+ state.header.MHF = 0; /* no header */
+ state.header.mh_id = 0; /* always 0 for now */
+ state.header.T = 1; /* invalid tile */
+ state.header.priority = 255; /* always 255 for now */
+ state.header.tile = 0; /* no tile number */
+ state.header.offset = 0; /* offset of 0 */
+ state.bitstream = FALSE;
+ state.n_tiles = 0;
+ state.next_sot = 0;
+ state.force_packet = FALSE;
+
+ /* get max packet length */
+ max_size = gst_rtp_buffer_calc_payload_len (mtu - HEADER_SIZE, 0, 0);
+
+ list = gst_buffer_list_new_sized ((mtu / max_size) + 1);
+
+ do {
+ GstBuffer *outbuf;
+ guint8 *header;
+ guint payload_size;
+ guint pu_size;
+ GstRTPBuffer rtp = { NULL };
+
+ /* try to pack as much as we can */
+ do {
+ /* see how much we have scanned already */
+ pu_size = end - offset;
+ GST_DEBUG_OBJECT (pay, "scanned pu size %u", pu_size);
+
+ /* we need to make a new packet */
+ if (state.force_packet) {
+ GST_DEBUG_OBJECT (pay, "need to force a new packet");
+ state.force_packet = FALSE;
+ pos = end;
+ break;
+ }
+
+ /* else see if we have enough */
+ if (pu_size > max_size) {
+ if (pos != offset)
+ /* the packet became too large, use previous scanpos */
+ pu_size = pos - offset;
+ else
+ /* the already scanned data was already too big, make sure we start
+ * scanning from the last searched position */
+ pos = end;
+
+ GST_DEBUG_OBJECT (pay, "max size exceeded pu_size %u", pu_size);
+ break;
+ }
+
+ pos = end;
+
+ /* exit when finished */
+ if (pos == map.size)
+ break;
+
+ /* scan next packetization unit and fill in the header */
+ end = find_pu_end (pay, map.data, map.size, pos, &state);
+ } while (TRUE);
+
+ while (pu_size > 0) {
+ guint packet_size, data_size;
+ GstBuffer *paybuf;
+
+ /* calculate the packet size */
+ packet_size =
+ gst_rtp_buffer_calc_packet_len (pu_size + HEADER_SIZE, 0, 0);
+
+ if (packet_size > mtu) {
+ GST_DEBUG_OBJECT (pay, "needed packet size %u clamped to MTU %u",
+ packet_size, mtu);
+ packet_size = mtu;
+ } else {
+ GST_DEBUG_OBJECT (pay, "needed packet size %u fits in MTU %u",
+ packet_size, mtu);
+ }
+
+ /* get total payload size and data size */
+ payload_size = gst_rtp_buffer_calc_payload_len (packet_size, 0, 0);
+ data_size = payload_size - HEADER_SIZE;
+
+ /* make buffer for header */
+ outbuf = gst_rtp_buffer_new_allocate (HEADER_SIZE, 0, 0);
+
+ GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
+
+ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+ /* get pointer to header */
+ header = gst_rtp_buffer_get_payload (&rtp);
+
+ pu_size -= data_size;
+ if (pu_size == 0) {
+ /* reached the end of a packetization unit */
+ if (state.header.MHF) {
+ /* we were doing a header, see if all fit in one packet or if
+ * we had to fragment it */
+ if (offset == 0)
+ state.header.MHF = 3;
+ else
+ state.header.MHF = 2;
+ }
+ if (end >= map.size)
+ gst_rtp_buffer_set_marker (&rtp, TRUE);
+ }
+
+ /*
+ * RtpJ2KHeader:
+ * @tp: type (0 progressive, 1 odd field, 2 even field)
+ * @MHF: Main Header Flag
+ * @mh_id: Main Header Identification
+ * @T: Tile field invalidation flag
+ * @priority: priority
+ * @tile number: the tile number of the payload
+ * @reserved: set to 0
+ * @fragment offset: the byte offset of the current payload
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |tp |MHF|mh_id|T| priority | tile number |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |reserved | fragment offset |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ header[0] = (state.header.tp << 6) | (state.header.MHF << 4) |
+ (state.header.mh_id << 1) | state.header.T;
+ header[1] = state.header.priority;
+ header[2] = state.header.tile >> 8;
+ header[3] = state.header.tile & 0xff;
+ header[4] = 0;
+ header[5] = state.header.offset >> 16;
+ header[6] = (state.header.offset >> 8) & 0xff;
+ header[7] = state.header.offset & 0xff;
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ /* make subbuffer of j2k data */
+ paybuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
+ offset, data_size);
+
+ outbuf = gst_buffer_append (outbuf, paybuf);
+
+ gst_buffer_list_add (list, outbuf);
+
+ /* reset header for next round */
+ state.header.MHF = 0;
+ state.header.T = 1;
+ state.header.tile = 0;
+
+ offset += data_size;
+ }
+ offset = pos;
+ } while (offset < map.size);
+
+ gst_buffer_unref (buffer);
+
+ /* push the whole buffer list at once */
+ ret = gst_rtp_base_payload_push_list (basepayload, list);
+
+ return ret;
+}
+
+static void
+gst_rtp_j2k_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_rtp_j2k_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+gboolean
+gst_rtp_j2k_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpj2kpay", GST_RANK_SECONDARY,
+ GST_TYPE_RTP_J2K_PAY);
+}
diff --git a/gst/rtp/gstrtpj2kpay.h b/gst/rtp/gstrtpj2kpay.h
new file mode 100755
index 0000000..7160a62
--- /dev/null
+++ b/gst/rtp/gstrtpj2kpay.h
@@ -0,0 +1,61 @@
+/* GStreamer
+ * Copyright (C) 2009 Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_J2K_PAY_H__
+#define __GST_RTP_J2K_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_J2K_PAY \
+ (gst_rtp_j2k_pay_get_type())
+#define GST_RTP_J2K_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_J2K_PAY,GstRtpJ2KPay))
+#define GST_RTP_J2K_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_J2K_PAY,GstRtpJ2KPayClass))
+#define GST_IS_RTP_J2K_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_J2K_PAY))
+#define GST_IS_RTP_J2K_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_J2K_PAY))
+
+typedef struct _GstRtpJ2KPay GstRtpJ2KPay;
+typedef struct _GstRtpJ2KPayClass GstRtpJ2KPayClass;
+
+struct _GstRtpJ2KPay
+{
+ GstRTPBasePayload payload;
+
+ gint height;
+ gint width;
+};
+
+struct _GstRtpJ2KPayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_j2k_pay_get_type (void);
+
+gboolean gst_rtp_j2k_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_J2K_PAY_H__ */
diff --git a/gst/rtp/gstrtpjpegdepay.c b/gst/rtp/gstrtpjpegdepay.c
new file mode 100755
index 0000000..57055e8
--- /dev/null
+++ b/gst/rtp/gstrtpjpegdepay.c
@@ -0,0 +1,790 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gstrtpjpegdepay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpjpegdepay_debug);
+#define GST_CAT_DEFAULT (rtpjpegdepay_debug)
+
+static GstStaticPadTemplate gst_rtp_jpeg_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("image/jpeg")
+ );
+
+static GstStaticPadTemplate gst_rtp_jpeg_depay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"video\", "
+ "clock-rate = (int) 90000, " "encoding-name = (string) \"JPEG\"; "
+ /* optional SDP attributes */
+ /*
+ * "a-framerate = (string) 0.00, "
+ * "x-framerate = (string) 0.00, "
+ * "x-dimensions = (string) \"1234,1234\", "
+ */
+ "application/x-rtp, "
+ "media = (string) \"video\", "
+ "payload = (int) " GST_RTP_PAYLOAD_JPEG_STRING ", "
+ "clock-rate = (int) 90000"
+ /* optional SDP attributes */
+ /*
+ * "a-framerate = (string) 0.00, "
+ * "x-framerate = (string) 0.00, "
+ * "x-dimensions = (string) \"1234,1234\""
+ */
+ )
+ );
+
+#define gst_rtp_jpeg_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpJPEGDepay, gst_rtp_jpeg_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_jpeg_depay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_jpeg_depay_change_state (GstElement *
+ element, GstStateChange transition);
+
+static gboolean gst_rtp_jpeg_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+
+static void
+gst_rtp_jpeg_depay_class_init (GstRtpJPEGDepayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_jpeg_depay_finalize;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_jpeg_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_jpeg_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP JPEG depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts JPEG video from RTP packets (RFC 2435)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ gstelement_class->change_state = gst_rtp_jpeg_depay_change_state;
+
+ gstrtpbasedepayload_class->set_caps = gst_rtp_jpeg_depay_setcaps;
+ gstrtpbasedepayload_class->process = gst_rtp_jpeg_depay_process;
+
+ GST_DEBUG_CATEGORY_INIT (rtpjpegdepay_debug, "rtpjpegdepay", 0,
+ "JPEG Video RTP Depayloader");
+}
+
+static void
+gst_rtp_jpeg_depay_init (GstRtpJPEGDepay * rtpjpegdepay)
+{
+ rtpjpegdepay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_jpeg_depay_reset (GstRtpJPEGDepay * depay)
+{
+ gint i;
+
+ depay->width = 0;
+ depay->height = 0;
+ depay->media_width = 0;
+ depay->media_height = 0;
+ depay->frate_num = 0;
+ depay->frate_denom = 1;
+ depay->discont = TRUE;
+
+ for (i = 0; i < 255; i++) {
+ g_free (depay->qtables[i]);
+ depay->qtables[i] = NULL;
+ }
+
+ gst_adapter_clear (depay->adapter);
+}
+
+static void
+gst_rtp_jpeg_depay_finalize (GObject * object)
+{
+ GstRtpJPEGDepay *rtpjpegdepay;
+
+ rtpjpegdepay = GST_RTP_JPEG_DEPAY (object);
+
+ gst_rtp_jpeg_depay_reset (rtpjpegdepay);
+
+ g_object_unref (rtpjpegdepay->adapter);
+ rtpjpegdepay->adapter = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static const int zigzag[] = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63
+};
+
+/*
+ * Table K.1 from JPEG spec.
+ */
+static const int jpeg_luma_quantizer[64] = {
+ 16, 11, 10, 16, 24, 40, 51, 61,
+ 12, 12, 14, 19, 26, 58, 60, 55,
+ 14, 13, 16, 24, 40, 57, 69, 56,
+ 14, 17, 22, 29, 51, 87, 80, 62,
+ 18, 22, 37, 56, 68, 109, 103, 77,
+ 24, 35, 55, 64, 81, 104, 113, 92,
+ 49, 64, 78, 87, 103, 121, 120, 101,
+ 72, 92, 95, 98, 112, 100, 103, 99
+};
+
+/*
+ * Table K.2 from JPEG spec.
+ */
+static const int jpeg_chroma_quantizer[64] = {
+ 17, 18, 24, 47, 99, 99, 99, 99,
+ 18, 21, 26, 66, 99, 99, 99, 99,
+ 24, 26, 56, 99, 99, 99, 99, 99,
+ 47, 66, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+};
+
+/* Call MakeTables with the Q factor and a guint8[128] return array
+ */
+static void
+MakeTables (GstRtpJPEGDepay * rtpjpegdepay, gint Q, guint8 qtable[128])
+{
+ gint i;
+ guint factor;
+
+ factor = CLAMP (Q, 1, 99);
+
+ if (Q < 50)
+ Q = 5000 / factor;
+ else
+ Q = 200 - factor * 2;
+
+ for (i = 0; i < 64; i++) {
+ gint lq = (jpeg_luma_quantizer[zigzag[i]] * Q + 50) / 100;
+ gint cq = (jpeg_chroma_quantizer[zigzag[i]] * Q + 50) / 100;
+
+ /* Limit the quantizers to 1 <= q <= 255 */
+ qtable[i] = CLAMP (lq, 1, 255);
+ qtable[i + 64] = CLAMP (cq, 1, 255);
+ }
+}
+
+static const guint8 lum_dc_codelens[] = {
+ 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const guint8 lum_dc_symbols[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+};
+
+static const guint8 lum_ac_codelens[] = {
+ 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
+};
+
+static const guint8 lum_ac_symbols[] = {
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+};
+
+static const guint8 chm_dc_codelens[] = {
+ 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
+};
+
+static const guint8 chm_dc_symbols[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+};
+
+static const guint8 chm_ac_codelens[] = {
+ 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
+};
+
+static const guint8 chm_ac_symbols[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+};
+
+static guint8 *
+MakeQuantHeader (guint8 * p, guint8 * qt, gint size, gint tableNo)
+{
+ *p++ = 0xff;
+ *p++ = 0xdb; /* DQT */
+ *p++ = 0; /* length msb */
+ *p++ = size + 3; /* length lsb */
+ *p++ = tableNo;
+ memcpy (p, qt, size);
+
+ return (p + size);
+}
+
+static guint8 *
+MakeHuffmanHeader (guint8 * p, const guint8 * codelens, int ncodes,
+ const guint8 * symbols, int nsymbols, int tableNo, int tableClass)
+{
+ *p++ = 0xff;
+ *p++ = 0xc4; /* DHT */
+ *p++ = 0; /* length msb */
+ *p++ = 3 + ncodes + nsymbols; /* length lsb */
+ *p++ = (tableClass << 4) | tableNo;
+ memcpy (p, codelens, ncodes);
+ p += ncodes;
+ memcpy (p, symbols, nsymbols);
+ p += nsymbols;
+
+ return (p);
+}
+
+static guint8 *
+MakeDRIHeader (guint8 * p, guint16 dri)
+{
+ *p++ = 0xff;
+ *p++ = 0xdd; /* DRI */
+ *p++ = 0x0; /* length msb */
+ *p++ = 4; /* length lsb */
+ *p++ = dri >> 8; /* dri msb */
+ *p++ = dri & 0xff; /* dri lsb */
+
+ return (p);
+}
+
+/*
+ * Arguments:
+ * type, width, height: as supplied in RTP/JPEG header
+ * qt: quantization tables as either derived from
+ * the Q field using MakeTables() or as specified
+ * in section 4.2.
+ * dri: restart interval in MCUs, or 0 if no restarts.
+ *
+ * p: pointer to return area
+ *
+ * Return value:
+ * The length of the generated headers.
+ *
+ * Generate a frame and scan headers that can be prepended to the
+ * RTP/JPEG data payload to produce a JPEG compressed image in
+ * interchange format (except for possible trailing garbage and
+ * absence of an EOI marker to terminate the scan).
+ */
+static guint
+MakeHeaders (guint8 * p, int type, int width, int height, guint8 * qt,
+ guint precision, guint16 dri)
+{
+ guint8 *start = p;
+ gint size;
+
+ *p++ = 0xff;
+ *p++ = 0xd8; /* SOI */
+
+ size = ((precision & 1) ? 128 : 64);
+ p = MakeQuantHeader (p, qt, size, 0);
+ qt += size;
+
+ size = ((precision & 2) ? 128 : 64);
+ p = MakeQuantHeader (p, qt, size, 1);
+ qt += size;
+
+ if (dri != 0)
+ p = MakeDRIHeader (p, dri);
+
+ *p++ = 0xff;
+ *p++ = 0xc0; /* SOF */
+ *p++ = 0; /* length msb */
+ *p++ = 17; /* length lsb */
+ *p++ = 8; /* 8-bit precision */
+ *p++ = height >> 8; /* height msb */
+ *p++ = height; /* height lsb */
+ *p++ = width >> 8; /* width msb */
+ *p++ = width; /* width lsb */
+ *p++ = 3; /* number of components */
+ *p++ = 0; /* comp 0 */
+ if ((type & 0x3f) == 0)
+ *p++ = 0x21; /* hsamp = 2, vsamp = 1 */
+ else
+ *p++ = 0x22; /* hsamp = 2, vsamp = 2 */
+ *p++ = 0; /* quant table 0 */
+ *p++ = 1; /* comp 1 */
+ *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
+ *p++ = 1; /* quant table 1 */
+ *p++ = 2; /* comp 2 */
+ *p++ = 0x11; /* hsamp = 1, vsamp = 1 */
+ *p++ = 1; /* quant table 1 */
+
+ p = MakeHuffmanHeader (p, lum_dc_codelens,
+ sizeof (lum_dc_codelens), lum_dc_symbols, sizeof (lum_dc_symbols), 0, 0);
+ p = MakeHuffmanHeader (p, lum_ac_codelens,
+ sizeof (lum_ac_codelens), lum_ac_symbols, sizeof (lum_ac_symbols), 0, 1);
+ p = MakeHuffmanHeader (p, chm_dc_codelens,
+ sizeof (chm_dc_codelens), chm_dc_symbols, sizeof (chm_dc_symbols), 1, 0);
+ p = MakeHuffmanHeader (p, chm_ac_codelens,
+ sizeof (chm_ac_codelens), chm_ac_symbols, sizeof (chm_ac_symbols), 1, 1);
+
+ *p++ = 0xff;
+ *p++ = 0xda; /* SOS */
+ *p++ = 0; /* length msb */
+ *p++ = 12; /* length lsb */
+ *p++ = 3; /* 3 components */
+ *p++ = 0; /* comp 0 */
+ *p++ = 0; /* huffman table 0 */
+ *p++ = 1; /* comp 1 */
+ *p++ = 0x11; /* huffman table 1 */
+ *p++ = 2; /* comp 2 */
+ *p++ = 0x11; /* huffman table 1 */
+ *p++ = 0; /* first DCT coeff */
+ *p++ = 63; /* last DCT coeff */
+ *p++ = 0; /* sucessive approx. */
+
+ return (p - start);
+};
+
+static gboolean
+gst_rtp_jpeg_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstRtpJPEGDepay *rtpjpegdepay;
+ GstStructure *structure;
+ gint clock_rate;
+ const gchar *media_attr;
+
+ rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
+
+ structure = gst_caps_get_structure (caps, 0);
+ GST_DEBUG_OBJECT (rtpjpegdepay, "Caps set: %" GST_PTR_FORMAT, caps);
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 90000;
+ depayload->clock_rate = clock_rate;
+
+ /* reset defaults */
+ rtpjpegdepay->width = 0;
+ rtpjpegdepay->height = 0;
+ rtpjpegdepay->media_width = 0;
+ rtpjpegdepay->media_height = 0;
+ rtpjpegdepay->frate_num = 0;
+ rtpjpegdepay->frate_denom = 1;
+
+ /* check for optional SDP attributes */
+ if ((media_attr = gst_structure_get_string (structure, "x-dimensions"))) {
+ gint w, h;
+
+ if (sscanf (media_attr, "%d,%d", &w, &h) == 2) {
+ rtpjpegdepay->media_width = w;
+ rtpjpegdepay->media_height = h;
+ }
+ }
+
+ /* try to get a framerate */
+ media_attr = gst_structure_get_string (structure, "a-framerate");
+ if (!media_attr)
+ media_attr = gst_structure_get_string (structure, "x-framerate");
+
+ if (media_attr) {
+ GValue src = { 0 };
+ GValue dest = { 0 };
+ gchar *s;
+
+ /* canonicalise floating point string so we can handle framerate strings
+ * in the form "24.930" or "24,930" irrespective of the current locale */
+ s = g_strdup (media_attr);
+ g_strdelimit (s, ",", '.');
+
+ /* convert the float to a fraction */
+ g_value_init (&src, G_TYPE_DOUBLE);
+ g_value_set_double (&src, g_ascii_strtod (s, NULL));
+ g_value_init (&dest, GST_TYPE_FRACTION);
+ g_value_transform (&src, &dest);
+
+ rtpjpegdepay->frate_num = gst_value_get_fraction_numerator (&dest);
+ rtpjpegdepay->frate_denom = gst_value_get_fraction_denominator (&dest);
+
+ g_free (s);
+ }
+
+ return TRUE;
+}
+
+static GstBuffer *
+gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpJPEGDepay *rtpjpegdepay;
+ GstBuffer *outbuf;
+ gint payload_len, header_len;
+ guint8 *payload;
+ guint frag_offset;
+ gint Q;
+ guint type, width, height;
+ guint16 dri, precision, length;
+ guint8 *qtable;
+ GstRTPBuffer rtp = { NULL };
+
+ rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload);
+
+ if (GST_BUFFER_IS_DISCONT (buf)) {
+ GST_DEBUG_OBJECT (depayload, "DISCONT, reset adapter");
+ gst_adapter_clear (rtpjpegdepay->adapter);
+ rtpjpegdepay->discont = TRUE;
+ }
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+
+ if (payload_len < 8)
+ goto empty_packet;
+
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ header_len = 0;
+
+ /* 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type-specific | Fragment Offset |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type | Q | Width | Height |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3];
+ type = payload[4];
+ Q = payload[5];
+ width = payload[6] * 8;
+ height = payload[7] * 8;
+
+ /* allow frame dimensions > 2040, passed in SDP session or media attributes
+ * from gstrtspsrc.c (gst_rtspsrc_sdp_attributes_to_caps), or in caps */
+ if (!width)
+ width = rtpjpegdepay->media_width;
+
+ if (!height)
+ height = rtpjpegdepay->media_height;
+
+ if (width == 0 || height == 0)
+ goto invalid_dimension;
+
+ GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u",
+ frag_offset, type, Q, width, height);
+
+ header_len += 8;
+ payload += 8;
+ payload_len -= 8;
+
+ dri = 0;
+ if (type > 63) {
+ if (payload_len < 4)
+ goto empty_packet;
+
+ /* 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Restart Interval |F|L| Restart Count |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ dri = (payload[0] << 8) | payload[1];
+
+ GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri);
+
+ payload += 4;
+ header_len += 4;
+ payload_len -= 4;
+ }
+
+ if (Q >= 128 && frag_offset == 0) {
+ if (payload_len < 4)
+ goto empty_packet;
+
+ /* 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | MBZ | Precision | Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Quantization Table Data |
+ * | ... |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ precision = payload[1];
+ length = (payload[2] << 8) | payload[3];
+
+ GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT,
+ precision, length);
+
+ if (Q == 255 && length == 0)
+ goto empty_packet;
+
+ payload += 4;
+ header_len += 4;
+ payload_len -= 4;
+
+ if (length > payload_len)
+ goto empty_packet;
+
+ if (length > 0)
+ qtable = payload;
+ else
+ qtable = rtpjpegdepay->qtables[Q];
+
+ payload += length;
+ header_len += length;
+ payload_len -= length;
+ } else {
+ length = 0;
+ qtable = NULL;
+ precision = 0;
+ }
+
+ if (frag_offset == 0) {
+ GstMapInfo map;
+ guint size;
+
+ if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) {
+ GstCaps *outcaps;
+
+ outcaps =
+ gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION,
+ rtpjpegdepay->frate_num, rtpjpegdepay->frate_denom, "width",
+ G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
+ gst_pad_set_caps (depayload->srcpad, outcaps);
+ gst_caps_unref (outcaps);
+
+ rtpjpegdepay->width = width;
+ rtpjpegdepay->height = height;
+ }
+
+ GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT,
+ length);
+
+ /* first packet */
+ if (length == 0) {
+ if (Q < 128) {
+ /* no quant table, see if we have one cached */
+ qtable = rtpjpegdepay->qtables[Q];
+ if (!qtable) {
+ GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q);
+ /* make and cache the table */
+ qtable = g_new (guint8, 128);
+ MakeTables (rtpjpegdepay, Q, qtable);
+ rtpjpegdepay->qtables[Q] = qtable;
+ } else {
+ GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q);
+ }
+ /* all 8 bit quantizers */
+ precision = 0;
+ } else {
+ if (!qtable)
+ goto no_qtable;
+ }
+ }
+
+ /* I think we can get here with a NULL qtable, so make sure we don't
+ go dereferencing it in MakeHeaders if we do */
+ if (!qtable)
+ goto no_qtable;
+
+ /* max header length, should be big enough */
+ outbuf = gst_buffer_new_and_alloc (1000);
+ gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+ size = MakeHeaders (map.data, type, width, height, qtable, precision, dri);
+ gst_buffer_unmap (outbuf, &map);
+ gst_buffer_resize (outbuf, 0, size);
+
+ GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size);
+
+ gst_adapter_push (rtpjpegdepay->adapter, outbuf);
+ }
+
+ /* take JPEG data, push in the adapter */
+ GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len);
+ outbuf = gst_rtp_buffer_get_payload_subbuffer (&rtp, header_len, -1);
+ gst_adapter_push (rtpjpegdepay->adapter, outbuf);
+ outbuf = NULL;
+
+ if (gst_rtp_buffer_get_marker (&rtp)) {
+ guint avail;
+ guint8 end[2];
+ GstMapInfo map;
+
+ /* last buffer take all data out of the adapter */
+ avail = gst_adapter_available (rtpjpegdepay->adapter);
+ GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer");
+
+ if (avail < 2)
+ goto invalid_packet;
+
+ /* take the last bytes of the jpeg data to see if there is an EOI
+ * marker */
+ gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2);
+
+ if (end[0] != 0xff && end[1] != 0xd9) {
+ GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one");
+
+ /* no EOI marker, add one */
+ outbuf = gst_buffer_new_and_alloc (2);
+ gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+ map.data[0] = 0xff;
+ map.data[1] = 0xd9;
+ gst_buffer_unmap (outbuf, &map);
+
+ gst_adapter_push (rtpjpegdepay->adapter, outbuf);
+ avail += 2;
+ }
+ outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail);
+
+ if (rtpjpegdepay->discont) {
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+ rtpjpegdepay->discont = FALSE;
+ }
+
+ GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail);
+ }
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ return outbuf;
+
+ /* ERRORS */
+empty_packet:
+ {
+ GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE,
+ ("Empty Payload."), (NULL));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+invalid_dimension:
+ {
+ GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT,
+ ("Invalid Dimension %dx%d.", width, height), (NULL));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+no_qtable:
+ {
+ GST_WARNING_OBJECT (rtpjpegdepay, "no qtable");
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+invalid_packet:
+ {
+ GST_WARNING_OBJECT (rtpjpegdepay, "invalid packet");
+ gst_adapter_flush (rtpjpegdepay->adapter,
+ gst_adapter_available (rtpjpegdepay->adapter));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+}
+
+
+static GstStateChangeReturn
+gst_rtp_jpeg_depay_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstRtpJPEGDepay *rtpjpegdepay;
+ GstStateChangeReturn ret;
+
+ rtpjpegdepay = GST_RTP_JPEG_DEPAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_rtp_jpeg_depay_reset (rtpjpegdepay);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+
+gboolean
+gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpjpegdepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_JPEG_DEPAY);
+}
diff --git a/gst/rtp/gstrtpjpegdepay.h b/gst/rtp/gstrtpjpegdepay.h
new file mode 100755
index 0000000..cb74f12
--- /dev/null
+++ b/gst/rtp/gstrtpjpegdepay.h
@@ -0,0 +1,70 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_JPEG_DEPAY_H__
+#define __GST_RTP_JPEG_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_JPEG_DEPAY \
+ (gst_rtp_jpeg_depay_get_type())
+#define GST_RTP_JPEG_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_JPEG_DEPAY,GstRtpJPEGDepay))
+#define GST_RTP_JPEG_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_JPEG_DEPAY,GstRtpJPEGDepayClass))
+#define GST_IS_RTP_JPEG_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_JPEG_DEPAY))
+#define GST_IS_RTP_JPEG_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_JPEG_DEPAY))
+
+typedef struct _GstRtpJPEGDepay GstRtpJPEGDepay;
+typedef struct _GstRtpJPEGDepayClass GstRtpJPEGDepayClass;
+
+struct _GstRtpJPEGDepay
+{
+ GstRTPBaseDepayload depayload;
+
+ GstAdapter *adapter;
+ gboolean discont;
+
+ /* cached quant tables */
+ guint8 * qtables[255];
+ gint frate_num;
+ gint frate_denom;
+ gint media_width;
+ gint media_height;
+ gint width, height;
+};
+
+struct _GstRtpJPEGDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_jpeg_depay_get_type (void);
+
+gboolean gst_rtp_jpeg_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_JPEG_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpjpegpay.c b/gst/rtp/gstrtpjpegpay.c
new file mode 100755
index 0000000..bf4ed55
--- /dev/null
+++ b/gst/rtp/gstrtpjpegpay.c
@@ -0,0 +1,996 @@
+/* GStreamer
+ * Copyright (C) 2008 Axis Communications <dev-gstreamer@axis.com>
+ * @author Bjorn Ostby <bjorn.ostby@axis.com>
+ * @author Peter Kjellerstedt <peter.kjellerstedt@axis.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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpjpegpay
+ *
+ * Payload encode JPEG pictures into RTP packets according to RFC 2435.
+ * For detailed information see: http://www.rfc-editor.org/rfc/rfc2435.txt
+ *
+ * The payloader takes a JPEG picture, scans the header for quantization
+ * tables (if needed) and constructs the RTP packet header followed by
+ * the actual JPEG entropy scan.
+ *
+ * The payloader assumes that correct width and height is found in the caps.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpjpegpay.h"
+
+static GstStaticPadTemplate gst_rtp_jpeg_pay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("image/jpeg; " "video/x-jpeg")
+ );
+
+static GstStaticPadTemplate gst_rtp_jpeg_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ " media = (string) \"video\", "
+ " payload = (int) 26 , "
+ " clock-rate = (int) 90000, "
+ " encoding-name = (string) \"JPEG\", "
+ " width = (int) [ 1, 65536 ], " " height = (int) [ 1, 65536 ]")
+ );
+
+GST_DEBUG_CATEGORY_STATIC (rtpjpegpay_debug);
+#define GST_CAT_DEFAULT (rtpjpegpay_debug)
+
+/*
+ * QUANT_PREFIX_LEN:
+ *
+ * Prefix length in the header before the quantization tables:
+ * Two size bytes and one byte for precision
+ */
+#define QUANT_PREFIX_LEN 3
+
+
+typedef enum _RtpJpegMarker RtpJpegMarker;
+
+/*
+ * RtpJpegMarker:
+ * @JPEG_MARKER: Prefix for JPEG marker
+ * @JPEG_MARKER_SOI: Start of Image marker
+ * @JPEG_MARKER_JFIF: JFIF marker
+ * @JPEG_MARKER_CMT: Comment marker
+ * @JPEG_MARKER_DQT: Define Quantization Table marker
+ * @JPEG_MARKER_SOF: Start of Frame marker
+ * @JPEG_MARKER_DHT: Define Huffman Table marker
+ * @JPEG_MARKER_SOS: Start of Scan marker
+ * @JPEG_MARKER_EOI: End of Image marker
+ * @JPEG_MARKER_DRI: Define Restart Interval marker
+ * @JPEG_MARKER_H264: H264 marker
+ *
+ * Identifers for markers in JPEG header
+ */
+enum _RtpJpegMarker
+{
+ JPEG_MARKER = 0xFF,
+ JPEG_MARKER_SOI = 0xD8,
+ JPEG_MARKER_JFIF = 0xE0,
+ JPEG_MARKER_CMT = 0xFE,
+ JPEG_MARKER_DQT = 0xDB,
+ JPEG_MARKER_SOF = 0xC0,
+ JPEG_MARKER_DHT = 0xC4,
+ JPEG_MARKER_SOS = 0xDA,
+ JPEG_MARKER_EOI = 0xD9,
+ JPEG_MARKER_DRI = 0xDD,
+ JPEG_MARKER_H264 = 0xE4
+};
+
+#define DEFAULT_JPEG_QUANT 255
+
+#define DEFAULT_JPEG_QUALITY 255
+#define DEFAULT_JPEG_TYPE 1
+
+enum
+{
+ PROP_0,
+ PROP_JPEG_QUALITY,
+ PROP_JPEG_TYPE
+};
+
+enum
+{
+ Q_TABLE_0 = 0,
+ Q_TABLE_1,
+ Q_TABLE_MAX /* only support for two tables at the moment */
+};
+
+typedef struct _RtpJpegHeader RtpJpegHeader;
+
+/*
+ * RtpJpegHeader:
+ * @type_spec: type specific
+ * @offset: fragment offset
+ * @type: type field
+ * @q: quantization table for this frame
+ * @width: width of image in 8-pixel multiples
+ * @height: height of image in 8-pixel multiples
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type-specific | Fragment Offset |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type | Q | Width | Height |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+struct _RtpJpegHeader
+{
+ guint type_spec:8;
+ guint offset:24;
+ guint8 type;
+ guint8 q;
+ guint8 width;
+ guint8 height;
+};
+
+/*
+ * RtpQuantHeader
+ * @mbz: must be zero
+ * @precision: specify size of quantization tables
+ * @length: length of quantization data
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | MBZ | Precision | Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Quantization Table Data |
+ * | ... |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+typedef struct
+{
+ guint8 mbz;
+ guint8 precision;
+ guint16 length;
+} RtpQuantHeader;
+
+typedef struct
+{
+ guint8 size;
+ const guint8 *data;
+} RtpQuantTable;
+
+/*
+ * RtpRestartMarkerHeader:
+ * @restartInterval: number of MCUs that appear between restart markers
+ * @restartFirstLastCount: a combination of the first packet mark in the chunk
+ * last packet mark in the chunk and the position of the
+ * first restart interval in the current "chunk"
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Restart Interval |F|L| Restart Count |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * The restart marker header is implemented according to the following
+ * methodology specified in section 3.1.7 of rfc2435.txt.
+ *
+ * "If the restart intervals in a frame are not guaranteed to be aligned
+ * with packet boundaries, the F (first) and L (last) bits MUST be set
+ * to 1 and the Restart Count MUST be set to 0x3FFF. This indicates
+ * that a receiver MUST reassemble the entire frame before decoding it."
+ *
+ */
+
+typedef struct
+{
+ guint16 restart_interval;
+ guint16 restart_count;
+} RtpRestartMarkerHeader;
+
+typedef struct
+{
+ guint8 id;
+ guint8 samp;
+ guint8 qt;
+} CompInfo;
+
+/* FIXME: restart marker header currently unsupported */
+
+static void gst_rtp_jpeg_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+
+static void gst_rtp_jpeg_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static gboolean gst_rtp_jpeg_pay_setcaps (GstRTPBasePayload * basepayload,
+ GstCaps * caps);
+
+static GstFlowReturn gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * pad,
+ GstBuffer * buffer);
+
+#define gst_rtp_jpeg_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpJPEGPay, gst_rtp_jpeg_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_jpeg_pay_class_init (GstRtpJPEGPayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gobject_class->set_property = gst_rtp_jpeg_pay_set_property;
+ gobject_class->get_property = gst_rtp_jpeg_pay_get_property;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_jpeg_pay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_jpeg_pay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class, "RTP JPEG payloader",
+ "Codec/Payloader/Network/RTP",
+ "Payload-encodes JPEG pictures into RTP packets (RFC 2435)",
+ "Axis Communications <dev-gstreamer@axis.com>");
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_jpeg_pay_setcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_jpeg_pay_handle_buffer;
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_JPEG_QUALITY,
+ g_param_spec_int ("quality", "Quality",
+ "Quality factor on JPEG data (unused)", 0, 255, 255,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_JPEG_TYPE,
+ g_param_spec_int ("type", "Type",
+ "Default JPEG Type, overwritten by SOF when present", 0, 255,
+ DEFAULT_JPEG_TYPE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ GST_DEBUG_CATEGORY_INIT (rtpjpegpay_debug, "rtpjpegpay", 0,
+ "Motion JPEG RTP Payloader");
+}
+
+static void
+gst_rtp_jpeg_pay_init (GstRtpJPEGPay * pay)
+{
+ pay->quality = DEFAULT_JPEG_QUALITY;
+ pay->quant = DEFAULT_JPEG_QUANT;
+ pay->type = DEFAULT_JPEG_TYPE;
+ pay->width = -1;
+ pay->height = -1;
+}
+
+static gboolean
+gst_rtp_jpeg_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
+{
+ GstStructure *caps_structure = gst_caps_get_structure (caps, 0);
+ GstRtpJPEGPay *pay;
+ gboolean res;
+ gint width = -1, height = -1;
+ gint num = 0, denom;
+ gchar *rate = NULL;
+ gchar *dim = NULL;
+
+ pay = GST_RTP_JPEG_PAY (basepayload);
+
+ /* these properties are mandatory, but they might be adjusted by the SOF, if there
+ * is one. */
+ if (!gst_structure_get_int (caps_structure, "height", &height) || height <= 0) {
+ goto invalid_dimension;
+ }
+
+ if (!gst_structure_get_int (caps_structure, "width", &width) || width <= 0) {
+ goto invalid_dimension;
+ }
+
+ if (gst_structure_get_fraction (caps_structure, "framerate", &num, &denom) &&
+ (num < 0 || denom <= 0)) {
+ goto invalid_framerate;
+ }
+
+ if (height > 2040 || width > 2040) {
+ pay->height = 0;
+ pay->width = 0;
+ } else {
+ pay->height = GST_ROUND_UP_8 (height) / 8;
+ pay->width = GST_ROUND_UP_8 (width) / 8;
+ }
+
+ gst_rtp_base_payload_set_options (basepayload, "video", TRUE, "JPEG", 90000);
+
+ if (num > 0) {
+ gdouble framerate;
+ gst_util_fraction_to_double (num, denom, &framerate);
+ rate = g_strdup_printf ("%f", framerate);
+ }
+
+ if (pay->width == 0) {
+ GST_DEBUG_OBJECT (pay,
+ "width or height are greater than 2040, adding x-dimensions to caps");
+ dim = g_strdup_printf ("%d,%d", width, height);
+ }
+
+ if (rate != NULL && dim != NULL) {
+ res = gst_rtp_base_payload_set_outcaps (basepayload, "a-framerate",
+ G_TYPE_STRING, rate, "x-dimensions", G_TYPE_STRING, dim, NULL);
+ } else if (rate != NULL && dim == NULL) {
+ res = gst_rtp_base_payload_set_outcaps (basepayload, "a-framerate",
+ G_TYPE_STRING, rate, NULL);
+ } else if (rate == NULL && dim != NULL) {
+ res = gst_rtp_base_payload_set_outcaps (basepayload, "x-dimensions",
+ G_TYPE_STRING, dim, NULL);
+ } else {
+ res = gst_rtp_base_payload_set_outcaps (basepayload, NULL);
+ }
+
+ if (dim != NULL)
+ g_free (dim);
+ if (rate != NULL)
+ g_free (rate);
+
+ return res;
+
+ /* ERRORS */
+invalid_dimension:
+ {
+ GST_ERROR_OBJECT (pay, "Invalid width/height from caps");
+ return FALSE;
+ }
+invalid_framerate:
+ {
+ GST_ERROR_OBJECT (pay, "Invalid framerate from caps");
+ return FALSE;
+ }
+}
+
+static guint
+gst_rtp_jpeg_pay_header_size (const guint8 * data, guint offset)
+{
+ return data[offset] << 8 | data[offset + 1];
+}
+
+static guint
+gst_rtp_jpeg_pay_read_quant_table (const guint8 * data, guint size,
+ guint offset, RtpQuantTable tables[])
+{
+ guint quant_size, tab_size;
+ guint8 prec;
+ guint8 id;
+
+ if (offset + 2 > size)
+ goto too_small;
+
+ quant_size = gst_rtp_jpeg_pay_header_size (data, offset);
+ if (quant_size < 2)
+ goto small_quant_size;
+
+ /* clamp to available data */
+ if (offset + quant_size > size)
+ quant_size = size - offset;
+
+ offset += 2;
+ quant_size -= 2;
+
+ while (quant_size > 0) {
+ /* not enough to read the id */
+ if (offset + 1 > size)
+ break;
+
+ id = data[offset] & 0x0f;
+ if (id == 15)
+ /* invalid id received - corrupt data */
+ goto invalid_id;
+
+ prec = (data[offset] & 0xf0) >> 4;
+ if (prec)
+ tab_size = 128;
+ else
+ tab_size = 64;
+
+ /* there is not enough for the table */
+ if (quant_size < tab_size + 1)
+ goto no_table;
+
+ GST_LOG ("read quant table %d, tab_size %d, prec %02x", id, tab_size, prec);
+
+ tables[id].size = tab_size;
+ tables[id].data = &data[offset + 1];
+
+ tab_size += 1;
+ quant_size -= tab_size;
+ offset += tab_size;
+ }
+done:
+ return offset + quant_size;
+
+ /* ERRORS */
+too_small:
+ {
+ GST_WARNING ("not enough data");
+ return size;
+ }
+small_quant_size:
+ {
+ GST_WARNING ("quant_size too small (%u < 2)", quant_size);
+ return size;
+ }
+invalid_id:
+ {
+ GST_WARNING ("invalid id");
+ goto done;
+ }
+no_table:
+ {
+ GST_WARNING ("not enough data for table (%u < %u)", quant_size,
+ tab_size + 1);
+ goto done;
+ }
+}
+
+static gboolean
+gst_rtp_jpeg_pay_read_sof (GstRtpJPEGPay * pay, const guint8 * data,
+ guint size, guint * offset, CompInfo info[], RtpQuantTable tables[],
+ gulong tables_elements)
+{
+ guint sof_size, off;
+ guint width, height, infolen;
+ CompInfo elem;
+ gint i, j;
+
+ off = *offset;
+
+ /* we need at least 17 bytes for the SOF */
+ if (off + 17 > size)
+ goto wrong_size;
+
+ sof_size = gst_rtp_jpeg_pay_header_size (data, off);
+ if (sof_size < 17)
+ goto wrong_length;
+
+ *offset += sof_size;
+
+ /* skip size */
+ off += 2;
+
+ /* precision should be 8 */
+ if (data[off++] != 8)
+ goto bad_precision;
+
+ /* read dimensions */
+ height = data[off] << 8 | data[off + 1];
+ width = data[off + 2] << 8 | data[off + 3];
+ off += 4;
+
+ GST_LOG_OBJECT (pay, "got dimensions %ux%u", height, width);
+
+ if (height == 0) {
+ goto invalid_dimension;
+ }
+ if (height > 2040) {
+ height = 0;
+ }
+ if (width == 0) {
+ goto invalid_dimension;
+ }
+ if (width > 2040) {
+ width = 0;
+ }
+
+ if (height == 0 || width == 0) {
+ pay->height = 0;
+ pay->width = 0;
+ } else {
+ pay->height = GST_ROUND_UP_8 (height) / 8;
+ pay->width = GST_ROUND_UP_8 (width) / 8;
+ }
+
+ /* we only support 3 components */
+ if (data[off++] != 3)
+ goto bad_components;
+
+ infolen = 0;
+ for (i = 0; i < 3; i++) {
+ elem.id = data[off++];
+ elem.samp = data[off++];
+ elem.qt = data[off++];
+ GST_LOG_OBJECT (pay, "got comp %d, samp %02x, qt %d", elem.id, elem.samp,
+ elem.qt);
+ /* insertion sort from the last element to the first */
+ for (j = infolen; j > 1; j--) {
+ if (G_LIKELY (info[j - 1].id < elem.id))
+ break;
+ info[j] = info[j - 1];
+ }
+ info[j] = elem;
+ infolen++;
+ }
+
+ /* see that the components are supported */
+ if (info[0].samp == 0x21)
+ pay->type = 0;
+ else if (info[0].samp == 0x22)
+ pay->type = 1;
+ else
+ goto invalid_comp;
+
+ if (!(info[1].samp == 0x11))
+ goto invalid_comp;
+
+ if (!(info[2].samp == 0x11))
+ goto invalid_comp;
+
+ /* the other components are free to use any quant table but they have to
+ * have the same table id */
+ if (info[1].qt != info[2].qt) {
+ /* Some MJPG (like the one from the Logitech C-920 camera) uses different
+ * quant tables for component 1 and 2 but both tables contain the exact
+ * same data, so we could consider them as being the same tables */
+ if (!(info[1].qt < tables_elements &&
+ info[2].qt < tables_elements &&
+ tables[info[1].qt].size > 0 &&
+ tables[info[1].qt].size == tables[info[2].qt].size &&
+ memcmp (tables[info[1].qt].data, tables[info[2].qt].data,
+ tables[info[1].qt].size) == 0))
+ goto invalid_comp;
+ }
+
+ return TRUE;
+
+ /* ERRORS */
+wrong_size:
+ {
+ GST_ELEMENT_WARNING (pay, STREAM, FORMAT,
+ ("Wrong size %u (needed %u).", size, off + 17), (NULL));
+ return FALSE;
+ }
+wrong_length:
+ {
+ GST_ELEMENT_WARNING (pay, STREAM, FORMAT,
+ ("Wrong SOF length %u.", sof_size), (NULL));
+ return FALSE;
+ }
+bad_precision:
+ {
+ GST_ELEMENT_WARNING (pay, STREAM, FORMAT,
+ ("Wrong precision, expecting 8."), (NULL));
+ return FALSE;
+ }
+invalid_dimension:
+ {
+ GST_ELEMENT_WARNING (pay, STREAM, FORMAT,
+ ("Wrong dimension, size %ux%u", width, height), (NULL));
+ return FALSE;
+ }
+bad_components:
+ {
+ GST_ELEMENT_WARNING (pay, STREAM, FORMAT,
+ ("Wrong number of components"), (NULL));
+ return FALSE;
+ }
+invalid_comp:
+ {
+ GST_ELEMENT_WARNING (pay, STREAM, FORMAT, ("Invalid component"), (NULL));
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_rtp_jpeg_pay_read_dri (GstRtpJPEGPay * pay, const guint8 * data,
+ guint size, guint * offset, RtpRestartMarkerHeader * dri)
+{
+ guint dri_size, off;
+
+ off = *offset;
+
+ /* we need at least 4 bytes for the DRI */
+ if (off + 4 > size)
+ goto wrong_size;
+
+ dri_size = gst_rtp_jpeg_pay_header_size (data, off);
+ if (dri_size < 4)
+ goto wrong_length;
+
+ *offset += dri_size;
+ off += 2;
+
+ dri->restart_interval = g_htons ((data[off] << 8) | (data[off + 1]));
+ dri->restart_count = g_htons (0xFFFF);
+
+ return dri->restart_interval > 0;
+
+wrong_size:
+ {
+ GST_WARNING ("not enough data for DRI");
+ *offset = size;
+ return FALSE;
+ }
+wrong_length:
+ {
+ GST_WARNING ("DRI size too small (%u)", dri_size);
+ *offset += dri_size;
+ return FALSE;
+ }
+}
+
+static RtpJpegMarker
+gst_rtp_jpeg_pay_scan_marker (const guint8 * data, guint size, guint * offset)
+{
+ while ((data[(*offset)++] != JPEG_MARKER) && ((*offset) < size));
+
+ if (G_UNLIKELY ((*offset) >= size)) {
+ GST_LOG ("found EOI marker");
+ return JPEG_MARKER_EOI;
+ } else {
+ guint8 marker;
+
+ marker = data[*offset];
+ GST_LOG ("found 0x%02x marker at offset %u", marker, *offset);
+ (*offset)++;
+ return marker;
+ }
+}
+
+#define RTP_HEADER_LEN 12
+
+static GstFlowReturn
+gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer)
+{
+ GstRtpJPEGPay *pay;
+ GstClockTime timestamp;
+ GstFlowReturn ret = GST_FLOW_ERROR;
+ RtpJpegHeader jpeg_header;
+ RtpQuantHeader quant_header;
+ RtpRestartMarkerHeader restart_marker_header;
+ RtpQuantTable tables[15] = { {0, NULL}, };
+ CompInfo info[3] = { {0,}, };
+ guint quant_data_size;
+ GstMapInfo map;
+ guint8 *data;
+ gsize size;
+ guint mtu, max_payload_size;
+ guint bytes_left;
+ guint jpeg_header_size = 0;
+ guint offset;
+ gboolean frame_done;
+ gboolean sos_found, sof_found, dqt_found, dri_found;
+ gint i;
+ GstBufferList *list = NULL;
+ gboolean discont;
+
+ pay = GST_RTP_JPEG_PAY (basepayload);
+ mtu = GST_RTP_BASE_PAYLOAD_MTU (pay);
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+ data = map.data;
+ size = map.size;
+ timestamp = GST_BUFFER_TIMESTAMP (buffer);
+ offset = 0;
+ discont = GST_BUFFER_IS_DISCONT (buffer);
+
+ GST_LOG_OBJECT (pay, "got buffer size %" G_GSIZE_FORMAT
+ " , timestamp %" GST_TIME_FORMAT, size, GST_TIME_ARGS (timestamp));
+
+ /* parse the jpeg header for 'start of scan' and read quant tables if needed */
+ sos_found = FALSE;
+ dqt_found = FALSE;
+ sof_found = FALSE;
+ dri_found = FALSE;
+
+ while (!sos_found && (offset < size)) {
+ GST_LOG_OBJECT (pay, "checking from offset %u", offset);
+ switch (gst_rtp_jpeg_pay_scan_marker (data, size, &offset)) {
+ case JPEG_MARKER_JFIF:
+ case JPEG_MARKER_CMT:
+ case JPEG_MARKER_DHT:
+ case JPEG_MARKER_H264:
+ GST_LOG_OBJECT (pay, "skipping marker");
+ offset += gst_rtp_jpeg_pay_header_size (data, offset);
+ break;
+ case JPEG_MARKER_SOF:
+ if (!gst_rtp_jpeg_pay_read_sof (pay, data, size, &offset, info, tables,
+ G_N_ELEMENTS (tables)))
+ goto invalid_format;
+ sof_found = TRUE;
+ break;
+ case JPEG_MARKER_DQT:
+ GST_LOG ("DQT found");
+ offset = gst_rtp_jpeg_pay_read_quant_table (data, size, offset, tables);
+ dqt_found = TRUE;
+ break;
+ case JPEG_MARKER_SOS:
+ sos_found = TRUE;
+ GST_LOG_OBJECT (pay, "SOS found");
+ jpeg_header_size = offset + gst_rtp_jpeg_pay_header_size (data, offset);
+ break;
+ case JPEG_MARKER_EOI:
+ GST_WARNING_OBJECT (pay, "EOI reached before SOS!");
+ break;
+ case JPEG_MARKER_SOI:
+ GST_LOG_OBJECT (pay, "SOI found");
+ break;
+ case JPEG_MARKER_DRI:
+ GST_LOG_OBJECT (pay, "DRI found");
+ if (gst_rtp_jpeg_pay_read_dri (pay, data, size, &offset,
+ &restart_marker_header))
+ dri_found = TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ if (!dqt_found || !sof_found)
+ goto unsupported_jpeg;
+
+ /* by now we should either have negotiated the width/height or the SOF header
+ * should have filled us in */
+ if (pay->width < 0 || pay->height < 0) {
+ goto no_dimension;
+ }
+
+ GST_LOG_OBJECT (pay, "header size %u", jpeg_header_size);
+
+ size -= jpeg_header_size;
+ data += jpeg_header_size;
+ offset = 0;
+
+ if (dri_found)
+ pay->type += 64;
+
+ /* prepare stuff for the jpeg header */
+ jpeg_header.type_spec = 0;
+ jpeg_header.type = pay->type;
+ jpeg_header.q = pay->quant;
+ jpeg_header.width = pay->width;
+ jpeg_header.height = pay->height;
+
+ /* collect the quant headers sizes */
+ quant_header.mbz = 0;
+ quant_header.precision = 0;
+ quant_header.length = 0;
+ quant_data_size = 0;
+
+ if (pay->quant > 127) {
+ /* for the Y and U component, look up the quant table and its size. quant
+ * tables for U and V should be the same */
+ for (i = 0; i < 2; i++) {
+ guint qsize;
+ guint qt;
+
+ qt = info[i].qt;
+ if (qt >= G_N_ELEMENTS (tables))
+ goto invalid_quant;
+
+ qsize = tables[qt].size;
+ if (qsize == 0)
+ goto invalid_quant;
+
+ quant_header.precision |= (qsize == 64 ? 0 : (1 << i));
+ quant_data_size += qsize;
+ }
+ quant_header.length = g_htons (quant_data_size);
+ quant_data_size += sizeof (quant_header);
+ }
+
+ GST_LOG_OBJECT (pay, "quant_data size %u", quant_data_size);
+
+ bytes_left = sizeof (jpeg_header) + quant_data_size + size;
+
+ if (dri_found)
+ bytes_left += sizeof (restart_marker_header);
+
+ max_payload_size = mtu - (RTP_HEADER_LEN + sizeof (jpeg_header));
+ list = gst_buffer_list_new_sized ((bytes_left / max_payload_size) + 1);
+
+ frame_done = FALSE;
+ do {
+ GstBuffer *outbuf;
+ guint8 *payload;
+ guint payload_size;
+ guint header_size;
+ GstBuffer *paybuf;
+ GstRTPBuffer rtp = { NULL };
+ guint rtp_header_size = gst_rtp_buffer_calc_header_len (0);
+
+ /* The available room is the packet MTU, minus the RTP header length. */
+ payload_size =
+ (bytes_left < (mtu - rtp_header_size) ? bytes_left :
+ (mtu - rtp_header_size));
+
+ header_size = sizeof (jpeg_header) + quant_data_size;
+ if (dri_found)
+ header_size += sizeof (restart_marker_header);
+
+ outbuf = gst_rtp_buffer_new_allocate (header_size, 0, 0);
+
+ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+ if (payload_size == bytes_left) {
+ GST_LOG_OBJECT (pay, "last packet of frame");
+ frame_done = TRUE;
+ gst_rtp_buffer_set_marker (&rtp, 1);
+ }
+
+ payload = gst_rtp_buffer_get_payload (&rtp);
+
+ /* update offset */
+#if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
+ jpeg_header.offset = ((offset & 0x0000FF) << 16) |
+ ((offset & 0xFF0000) >> 16) | (offset & 0x00FF00);
+#else
+ jpeg_header.offset = offset;
+#endif
+ memcpy (payload, &jpeg_header, sizeof (jpeg_header));
+ payload += sizeof (jpeg_header);
+ payload_size -= sizeof (jpeg_header);
+
+ if (dri_found) {
+ memcpy (payload, &restart_marker_header, sizeof (restart_marker_header));
+ payload += sizeof (restart_marker_header);
+ payload_size -= sizeof (restart_marker_header);
+ }
+
+ /* only send quant table with first packet */
+ if (G_UNLIKELY (quant_data_size > 0)) {
+ memcpy (payload, &quant_header, sizeof (quant_header));
+ payload += sizeof (quant_header);
+
+ /* copy the quant tables for luma and chrominance */
+ for (i = 0; i < 2; i++) {
+ guint qsize;
+ guint qt;
+
+ qt = info[i].qt;
+ qsize = tables[qt].size;
+ memcpy (payload, tables[qt].data, qsize);
+
+ GST_LOG_OBJECT (pay, "component %d using quant %d, size %d", i, qt,
+ qsize);
+
+ payload += qsize;
+ }
+ payload_size -= quant_data_size;
+ bytes_left -= quant_data_size;
+ quant_data_size = 0;
+ }
+ GST_LOG_OBJECT (pay, "sending payload size %d", payload_size);
+ gst_rtp_buffer_unmap (&rtp);
+
+ /* create a new buf to hold the payload */
+ paybuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
+ jpeg_header_size + offset, payload_size);
+
+ /* join memory parts */
+ outbuf = gst_buffer_append (outbuf, paybuf);
+
+ GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
+
+ if (discont) {
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+ /* Only the first outputted buffer has the DISCONT flag */
+ discont = FALSE;
+ }
+
+ /* and add to list */
+ gst_buffer_list_insert (list, -1, outbuf);
+
+ bytes_left -= payload_size;
+ offset += payload_size;
+ data += payload_size;
+ }
+ while (!frame_done);
+
+ /* push the whole buffer list at once */
+ ret = gst_rtp_base_payload_push_list (basepayload, list);
+
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+
+ return ret;
+
+ /* ERRORS */
+unsupported_jpeg:
+ {
+ GST_ELEMENT_WARNING (pay, STREAM, FORMAT, ("Unsupported JPEG"), (NULL));
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+ return GST_FLOW_OK;
+ }
+no_dimension:
+ {
+ GST_ELEMENT_WARNING (pay, STREAM, FORMAT, ("No size given"), (NULL));
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+ return GST_FLOW_OK;
+ }
+invalid_format:
+ {
+ /* error was posted */
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+ return GST_FLOW_OK;
+ }
+invalid_quant:
+ {
+ GST_ELEMENT_WARNING (pay, STREAM, FORMAT, ("Invalid quant tables"), (NULL));
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+ return GST_FLOW_OK;
+ }
+}
+
+static void
+gst_rtp_jpeg_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstRtpJPEGPay *rtpjpegpay;
+
+ rtpjpegpay = GST_RTP_JPEG_PAY (object);
+
+ switch (prop_id) {
+ case PROP_JPEG_QUALITY:
+ rtpjpegpay->quality = g_value_get_int (value);
+ GST_DEBUG_OBJECT (object, "quality = %d", rtpjpegpay->quality);
+ break;
+ case PROP_JPEG_TYPE:
+ rtpjpegpay->type = g_value_get_int (value);
+ GST_DEBUG_OBJECT (object, "type = %d", rtpjpegpay->type);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_rtp_jpeg_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstRtpJPEGPay *rtpjpegpay;
+
+ rtpjpegpay = GST_RTP_JPEG_PAY (object);
+
+ switch (prop_id) {
+ case PROP_JPEG_QUALITY:
+ g_value_set_int (value, rtpjpegpay->quality);
+ break;
+ case PROP_JPEG_TYPE:
+ g_value_set_int (value, rtpjpegpay->type);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+gboolean
+gst_rtp_jpeg_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpjpegpay", GST_RANK_SECONDARY,
+ GST_TYPE_RTP_JPEG_PAY);
+}
diff --git a/gst/rtp/gstrtpjpegpay.h b/gst/rtp/gstrtpjpegpay.h
new file mode 100755
index 0000000..4d65ea7
--- /dev/null
+++ b/gst/rtp/gstrtpjpegpay.h
@@ -0,0 +1,63 @@
+/* GStreamer
+ * Copyright (C) 2008 Axis Communications <dev-gstreamer@axis.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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_JPEG_PAY_H__
+#define __GST_RTP_JPEG_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_RTP_JPEG_PAY \
+ (gst_rtp_jpeg_pay_get_type())
+#define GST_RTP_JPEG_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_JPEG_PAY,GstRtpJPEGPay))
+#define GST_RTP_JPEG_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_JPEG_PAY,GstRtpJPEGPayClass))
+#define GST_IS_RTP_JPEG_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_JPEG_PAY))
+#define GST_IS_RTP_JPEG_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_JPEG_PAY))
+typedef struct _GstRtpJPEGPay GstRtpJPEGPay;
+typedef struct _GstRtpJPEGPayClass GstRtpJPEGPayClass;
+
+struct _GstRtpJPEGPay
+{
+ GstRTPBasePayload payload;
+
+ guint8 quality;
+ guint8 type;
+
+ gint height;
+ gint width;
+
+ guint8 quant;
+};
+
+struct _GstRtpJPEGPayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_jpeg_pay_get_type (void);
+
+gboolean gst_rtp_jpeg_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_JPEG_PAY_H__ */
diff --git a/gst/rtp/gstrtpmp1sdepay.c b/gst/rtp/gstrtpmp1sdepay.c
new file mode 100755
index 0000000..63545e7
--- /dev/null
+++ b/gst/rtp/gstrtpmp1sdepay.c
@@ -0,0 +1,142 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <string.h>
+#include "gstrtpmp1sdepay.h"
+
+/* RtpMP1SDepay signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0,
+ PROP_LAST
+};
+
+static GstStaticPadTemplate gst_rtp_mp1s_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/mpeg,systemstream=(boolean)true")
+ );
+
+/* The spec says video/MP1S but I have seen streams with other/MP1S so we will
+ * allow them both */
+static GstStaticPadTemplate gst_rtp_mp1s_depay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"other\", "
+ "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"MP1S\";"
+ "application/x-rtp, "
+ "media = (string) \"video\", "
+ "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"MP1S\"")
+ );
+
+G_DEFINE_TYPE (GstRtpMP1SDepay, gst_rtp_mp1s_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_mp1s_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_mp1s_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+
+static void
+gst_rtp_mp1s_depay_class_init (GstRtpMP1SDepayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gstrtpbasedepayload_class->process = gst_rtp_mp1s_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_mp1s_depay_setcaps;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mp1s_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mp1s_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP MPEG1 System Stream depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts MPEG1 System Streams from RTP packets (RFC 3555)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+}
+
+static void
+gst_rtp_mp1s_depay_init (GstRtpMP1SDepay * rtpmp1sdepay)
+{
+}
+
+static gboolean
+gst_rtp_mp1s_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstCaps *srccaps;
+ GstStructure *structure;
+ gint clock_rate;
+ gboolean res;
+
+ structure = gst_caps_get_structure (caps, 0);
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 90000; /* default */
+ depayload->clock_rate = clock_rate;
+
+ srccaps = gst_caps_new_simple ("video/mpeg",
+ "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
+ res = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+ gst_caps_unref (srccaps);
+
+ return res;
+}
+
+static GstBuffer *
+gst_rtp_mp1s_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstBuffer *outbuf;
+ GstRTPBuffer rtp = { NULL };
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+ outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
+ gst_rtp_buffer_unmap (&rtp);
+
+ if (outbuf)
+ GST_DEBUG ("gst_rtp_mp1s_depay_chain: pushing buffer of size %"
+ G_GSIZE_FORMAT, gst_buffer_get_size (outbuf));
+
+ return outbuf;
+}
+
+gboolean
+gst_rtp_mp1s_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpmp1sdepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_MP1S_DEPAY);
+}
diff --git a/gst/rtp/gstrtpmp1sdepay.h b/gst/rtp/gstrtpmp1sdepay.h
new file mode 100755
index 0000000..582933b
--- /dev/null
+++ b/gst/rtp/gstrtpmp1sdepay.h
@@ -0,0 +1,58 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MP1S_DEPAY_H__
+#define __GST_RTP_MP1S_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MP1S_DEPAY \
+ (gst_rtp_mp1s_depay_get_type())
+#define GST_RTP_MP1S_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MP1S_DEPAY,GstRtpMP1SDepay))
+#define GST_RTP_MP1S_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MP1S_DEPAY,GstRtpMP1SDepayClass))
+#define GST_IS_RTP_MP1S_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MP1S_DEPAY))
+#define GST_IS_RTP_MP1S_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MP1S_DEPAY))
+typedef struct _GstRtpMP1SDepay GstRtpMP1SDepay;
+typedef struct _GstRtpMP1SDepayClass GstRtpMP1SDepayClass;
+
+struct _GstRtpMP1SDepay
+{
+ GstRTPBaseDepayload depayload;
+};
+
+struct _GstRtpMP1SDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_mp1s_depay_get_type (void);
+
+gboolean gst_rtp_mp1s_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MP1S_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpmp2tdepay.c b/gst/rtp/gstrtpmp2tdepay.c
new file mode 100755
index 0000000..345d906
--- /dev/null
+++ b/gst/rtp/gstrtpmp2tdepay.c
@@ -0,0 +1,243 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <string.h>
+#include "gstrtpmp2tdepay.h"
+
+/* RtpMP2TDepay signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+#define DEFAULT_SKIP_FIRST_BYTES 0
+
+enum
+{
+ PROP_0,
+ PROP_SKIP_FIRST_BYTES
+};
+
+static GstStaticPadTemplate gst_rtp_mp2t_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/mpegts,"
+ "packetsize=(int)188," "systemstream=(boolean)true")
+ );
+
+static GstStaticPadTemplate gst_rtp_mp2t_depay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"video\", "
+ "clock-rate = (int) [1, MAX ], "
+ "encoding-name = (string) { MP2T, MP2T-ES } ;"
+ /* All optional parameters
+ *
+ * "profile-level-id=[1,MAX]"
+ * "config="
+ */
+ "application/x-rtp, "
+ "media = (string) \"video\", "
+ "payload = (int) " GST_RTP_PAYLOAD_MP2T_STRING ", "
+ "clock-rate = (int) [1, MAX ]")
+ );
+
+G_DEFINE_TYPE (GstRtpMP2TDepay, gst_rtp_mp2t_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_mp2t_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_mp2t_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+
+static void gst_rtp_mp2t_depay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_rtp_mp2t_depay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void
+gst_rtp_mp2t_depay_class_init (GstRtpMP2TDepayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gstrtpbasedepayload_class->process = gst_rtp_mp2t_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_mp2t_depay_setcaps;
+
+ gobject_class->set_property = gst_rtp_mp2t_depay_set_property;
+ gobject_class->get_property = gst_rtp_mp2t_depay_get_property;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mp2t_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mp2t_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP MPEG Transport Stream depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts MPEG2 TS from RTP packets (RFC 2250)",
+ "Wim Taymans <wim.taymans@gmail.com>, "
+ "Thijs Vermeir <thijs.vermeir@barco.com>");
+
+ g_object_class_install_property (gobject_class, PROP_SKIP_FIRST_BYTES,
+ g_param_spec_uint ("skip-first-bytes",
+ "Skip first bytes",
+ "The amount of bytes that need to be skipped at the beginning of the payload",
+ 0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+}
+
+static void
+gst_rtp_mp2t_depay_init (GstRtpMP2TDepay * rtpmp2tdepay)
+{
+ rtpmp2tdepay->skip_first_bytes = DEFAULT_SKIP_FIRST_BYTES;
+}
+
+static gboolean
+gst_rtp_mp2t_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstCaps *srccaps;
+ GstStructure *structure;
+ gint clock_rate;
+ gboolean res;
+
+ structure = gst_caps_get_structure (caps, 0);
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 90000; /* default */
+ depayload->clock_rate = clock_rate;
+
+ srccaps = gst_caps_new_simple ("video/mpegts",
+ "packetsize", G_TYPE_INT, 188,
+ "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
+ res = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+ gst_caps_unref (srccaps);
+
+ return res;
+}
+
+static GstBuffer *
+gst_rtp_mp2t_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpMP2TDepay *rtpmp2tdepay;
+ GstBuffer *outbuf;
+ gint payload_len, leftover;
+ GstRTPBuffer rtp = { NULL };
+
+ rtpmp2tdepay = GST_RTP_MP2T_DEPAY (depayload);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+
+ if (G_UNLIKELY (payload_len <= rtpmp2tdepay->skip_first_bytes))
+ goto empty_packet;
+
+ payload_len -= rtpmp2tdepay->skip_first_bytes;
+
+ /* RFC 2250
+ *
+ * 2. Encapsulation of MPEG System and Transport Streams
+ *
+ * For MPEG2 Transport Streams the RTP payload will contain an integral
+ * number of MPEG transport packets.
+ */
+ leftover = payload_len % 188;
+ if (G_UNLIKELY (leftover)) {
+ GST_WARNING ("We don't have an integral number of buffers (leftover: %d)",
+ leftover);
+
+ payload_len -= leftover;
+ }
+
+ outbuf =
+ gst_rtp_buffer_get_payload_subbuffer (&rtp,
+ rtpmp2tdepay->skip_first_bytes, payload_len);
+
+ gst_rtp_buffer_unmap (&rtp);
+ if (outbuf)
+ GST_DEBUG ("gst_rtp_mp2t_depay_chain: pushing buffer of size %"
+ G_GSIZE_FORMAT, gst_buffer_get_size (outbuf));
+
+ return outbuf;
+
+ /* ERRORS */
+empty_packet:
+ {
+ GST_ELEMENT_WARNING (rtpmp2tdepay, STREAM, DECODE,
+ (NULL), ("Packet was empty"));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+}
+
+static void
+gst_rtp_mp2t_depay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstRtpMP2TDepay *rtpmp2tdepay;
+
+ rtpmp2tdepay = GST_RTP_MP2T_DEPAY (object);
+
+ switch (prop_id) {
+ case PROP_SKIP_FIRST_BYTES:
+ rtpmp2tdepay->skip_first_bytes = g_value_get_uint (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_rtp_mp2t_depay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstRtpMP2TDepay *rtpmp2tdepay;
+
+ rtpmp2tdepay = GST_RTP_MP2T_DEPAY (object);
+
+ switch (prop_id) {
+ case PROP_SKIP_FIRST_BYTES:
+ g_value_set_uint (value, rtpmp2tdepay->skip_first_bytes);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+gboolean
+gst_rtp_mp2t_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpmp2tdepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_MP2T_DEPAY);
+}
diff --git a/gst/rtp/gstrtpmp2tdepay.h b/gst/rtp/gstrtpmp2tdepay.h
new file mode 100755
index 0000000..aa936dc
--- /dev/null
+++ b/gst/rtp/gstrtpmp2tdepay.h
@@ -0,0 +1,60 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MP2T_DEPAY_H__
+#define __GST_RTP_MP2T_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MP2T_DEPAY \
+ (gst_rtp_mp2t_depay_get_type())
+#define GST_RTP_MP2T_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MP2T_DEPAY,GstRtpMP2TDepay))
+#define GST_RTP_MP2T_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MP2T_DEPAY,GstRtpMP2TDepayClass))
+#define GST_IS_RTP_MP2T_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MP2T_DEPAY))
+#define GST_IS_RTP_MP2T_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MP2T_DEPAY))
+typedef struct _GstRtpMP2TDepay GstRtpMP2TDepay;
+typedef struct _GstRtpMP2TDepayClass GstRtpMP2TDepayClass;
+
+struct _GstRtpMP2TDepay
+{
+ GstRTPBaseDepayload depayload;
+
+ guint8 skip_first_bytes;
+};
+
+struct _GstRtpMP2TDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_mp2t_depay_get_type (void);
+
+gboolean gst_rtp_mp2t_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MP2T_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpmp2tpay.c b/gst/rtp/gstrtpmp2tpay.c
new file mode 100755
index 0000000..1c6ec51
--- /dev/null
+++ b/gst/rtp/gstrtpmp2tpay.c
@@ -0,0 +1,234 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpmp2tpay.h"
+
+static GstStaticPadTemplate gst_rtp_mp2t_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/mpegts,"
+ "packetsize=(int)188," "systemstream=(boolean)true")
+ );
+
+static GstStaticPadTemplate gst_rtp_mp2t_pay_src_template =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"video\", "
+ "payload = (int) " GST_RTP_PAYLOAD_MP2T_STRING ", "
+ "clock-rate = (int) 90000, " "encoding-name = (string) \"MP2T\" ; "
+ "application/x-rtp, "
+ "media = (string) \"video\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) 90000, " "encoding-name = (string) \"MP2T\"")
+ );
+
+static gboolean gst_rtp_mp2t_pay_setcaps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+static GstFlowReturn gst_rtp_mp2t_pay_handle_buffer (GstRTPBasePayload *
+ payload, GstBuffer * buffer);
+static GstFlowReturn gst_rtp_mp2t_pay_flush (GstRTPMP2TPay * rtpmp2tpay);
+static void gst_rtp_mp2t_pay_finalize (GObject * object);
+
+#define gst_rtp_mp2t_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPMP2TPay, gst_rtp_mp2t_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_mp2t_pay_class_init (GstRTPMP2TPayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_mp2t_pay_finalize;
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_mp2t_pay_setcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_mp2t_pay_handle_buffer;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mp2t_pay_sink_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mp2t_pay_src_template));
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP MPEG2 Transport Stream payloader", "Codec/Payloader/Network/RTP",
+ "Payload-encodes MPEG2 TS into RTP packets (RFC 2250)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+}
+
+static void
+gst_rtp_mp2t_pay_init (GstRTPMP2TPay * rtpmp2tpay)
+{
+ GST_RTP_BASE_PAYLOAD (rtpmp2tpay)->clock_rate = 90000;
+ GST_RTP_BASE_PAYLOAD_PT (rtpmp2tpay) = GST_RTP_PAYLOAD_MP2T;
+
+ rtpmp2tpay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_mp2t_pay_finalize (GObject * object)
+{
+ GstRTPMP2TPay *rtpmp2tpay;
+
+ rtpmp2tpay = GST_RTP_MP2T_PAY (object);
+
+ g_object_unref (rtpmp2tpay->adapter);
+ rtpmp2tpay->adapter = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rtp_mp2t_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ gboolean res;
+
+ gst_rtp_base_payload_set_options (payload, "video", TRUE, "MP2T", 90000);
+ res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+
+ return res;
+}
+
+static GstFlowReturn
+gst_rtp_mp2t_pay_flush (GstRTPMP2TPay * rtpmp2tpay)
+{
+ guint avail, mtu;
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstBuffer *outbuf;
+
+ avail = gst_adapter_available (rtpmp2tpay->adapter);
+
+ mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpmp2tpay);
+
+ while (avail > 0 && (ret == GST_FLOW_OK)) {
+ guint towrite;
+ guint payload_len;
+ guint packet_len;
+ GstBuffer *paybuf;
+
+ /* this will be the total length of the packet */
+ packet_len = gst_rtp_buffer_calc_packet_len (avail, 0, 0);
+
+ /* fill one MTU or all available bytes */
+ towrite = MIN (packet_len, mtu);
+
+ /* this is the payload length */
+ payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
+ payload_len -= payload_len % 188;
+
+ /* need whole packets */
+ if (!payload_len)
+ break;
+
+ /* create buffer to hold the payload */
+ outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
+
+ /* get payload */
+ paybuf = gst_adapter_take_buffer_fast (rtpmp2tpay->adapter, payload_len);
+ outbuf = gst_buffer_append (outbuf, paybuf);
+ avail -= payload_len;
+
+ GST_BUFFER_TIMESTAMP (outbuf) = rtpmp2tpay->first_ts;
+ GST_BUFFER_DURATION (outbuf) = rtpmp2tpay->duration;
+
+ GST_DEBUG_OBJECT (rtpmp2tpay, "pushing buffer of size %u",
+ (guint) gst_buffer_get_size (outbuf));
+
+ ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpmp2tpay), outbuf);
+ }
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_rtp_mp2t_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer)
+{
+ GstRTPMP2TPay *rtpmp2tpay;
+ guint size, avail, packet_len;
+ GstClockTime timestamp, duration;
+ GstFlowReturn ret;
+
+ rtpmp2tpay = GST_RTP_MP2T_PAY (basepayload);
+
+ size = gst_buffer_get_size (buffer);
+ timestamp = GST_BUFFER_TIMESTAMP (buffer);
+ duration = GST_BUFFER_DURATION (buffer);
+
+again:
+ ret = GST_FLOW_OK;
+ avail = gst_adapter_available (rtpmp2tpay->adapter);
+
+ /* Initialize new RTP payload */
+ if (avail == 0) {
+ rtpmp2tpay->first_ts = timestamp;
+ rtpmp2tpay->duration = duration;
+ }
+
+ /* get packet length of previous data and this new data */
+ packet_len = gst_rtp_buffer_calc_packet_len (avail + size, 0, 0);
+
+ /* if this buffer is going to overflow the packet, flush what we have,
+ * or if upstream is handing us several packets, to keep latency low */
+ if (!size || gst_rtp_base_payload_is_filled (basepayload,
+ packet_len, rtpmp2tpay->duration + duration)) {
+ ret = gst_rtp_mp2t_pay_flush (rtpmp2tpay);
+ rtpmp2tpay->first_ts = timestamp;
+ rtpmp2tpay->duration = duration;
+
+ /* keep filling the payload */
+ } else {
+ if (GST_CLOCK_TIME_IS_VALID (duration))
+ rtpmp2tpay->duration += duration;
+ }
+
+ /* copy buffer to adapter */
+ if (buffer) {
+ gst_adapter_push (rtpmp2tpay->adapter, buffer);
+ buffer = NULL;
+ }
+
+ if (size >= (188 * 2)) {
+ size = 0;
+ goto again;
+ }
+
+ return ret;
+
+}
+
+gboolean
+gst_rtp_mp2t_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpmp2tpay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_MP2T_PAY);
+}
diff --git a/gst/rtp/gstrtpmp2tpay.h b/gst/rtp/gstrtpmp2tpay.h
new file mode 100755
index 0000000..12f4959
--- /dev/null
+++ b/gst/rtp/gstrtpmp2tpay.h
@@ -0,0 +1,64 @@
+/* GStreamer
+ * Copyright (C) <2007> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_RTP_MP2T_PAY_H__
+#define __GST_RTP_MP2T_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRTPMP2TPay GstRTPMP2TPay;
+typedef struct _GstRTPMP2TPayClass GstRTPMP2TPayClass;
+
+#define GST_TYPE_RTP_MP2T_PAY \
+ (gst_rtp_mp2t_pay_get_type())
+#define GST_RTP_MP2T_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MP2T_PAY,GstRTPMP2TPay))
+#define GST_RTP_MP2T_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MP2T_PAY,GstRTPMP2TPayClass))
+#define GST_IS_RTP_MP2T_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MP2T_PAY))
+#define GST_IS_RTP_MP2T_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MP2T_PAY))
+
+struct _GstRTPMP2TPay
+{
+ GstRTPBasePayload payload;
+
+ GstAdapter *adapter;
+ GstClockTime first_ts;
+ GstClockTime duration;
+};
+
+struct _GstRTPMP2TPayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_mp2t_pay_get_type (void);
+
+gboolean gst_rtp_mp2t_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MP2T_PAY_H__ */
diff --git a/gst/rtp/gstrtpmp4adepay.c b/gst/rtp/gstrtpmp4adepay.c
new file mode 100755
index 0000000..e70d5b3
--- /dev/null
+++ b/gst/rtp/gstrtpmp4adepay.c
@@ -0,0 +1,445 @@
+/* GStreamer
+ * Copyright (C) <2007> Nokia Corporation (contact <stefan.kost@nokia.com>)
+ * <2007> Wim Taymans <wim.taymans@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 version 2 as published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/base/gstbitreader.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <string.h>
+#include "gstrtpmp4adepay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmp4adepay_debug);
+#define GST_CAT_DEFAULT (rtpmp4adepay_debug)
+
+static GstStaticPadTemplate gst_rtp_mp4a_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/mpeg,"
+ "mpegversion = (int) 4," "framed = (boolean) true, "
+ "stream-format = (string) raw")
+ );
+
+static GstStaticPadTemplate gst_rtp_mp4a_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "clock-rate = (int) [1, MAX ], "
+ "encoding-name = (string) \"MP4A-LATM\""
+ /* All optional parameters
+ *
+ * "profile-level-id=[1,MAX]"
+ * "config="
+ */
+ )
+ );
+
+#define gst_rtp_mp4a_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpMP4ADepay, gst_rtp_mp4a_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_mp4a_depay_finalize (GObject * object);
+
+static gboolean gst_rtp_mp4a_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_mp4a_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+
+static GstStateChangeReturn gst_rtp_mp4a_depay_change_state (GstElement *
+ element, GstStateChange transition);
+
+
+static void
+gst_rtp_mp4a_depay_class_init (GstRtpMP4ADepayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_mp4a_depay_finalize;
+
+ gstelement_class->change_state = gst_rtp_mp4a_depay_change_state;
+
+ gstrtpbasedepayload_class->process = gst_rtp_mp4a_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_mp4a_depay_setcaps;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mp4a_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mp4a_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP MPEG4 audio depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts MPEG4 audio from RTP packets (RFC 3016)",
+ "Nokia Corporation (contact <stefan.kost@nokia.com>), "
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ GST_DEBUG_CATEGORY_INIT (rtpmp4adepay_debug, "rtpmp4adepay", 0,
+ "MPEG4 audio RTP Depayloader");
+}
+
+static void
+gst_rtp_mp4a_depay_init (GstRtpMP4ADepay * rtpmp4adepay)
+{
+ rtpmp4adepay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_mp4a_depay_finalize (GObject * object)
+{
+ GstRtpMP4ADepay *rtpmp4adepay;
+
+ rtpmp4adepay = GST_RTP_MP4A_DEPAY (object);
+
+ g_object_unref (rtpmp4adepay->adapter);
+ rtpmp4adepay->adapter = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static const guint aac_sample_rates[] = { 96000, 88200, 64000, 48000,
+ 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350
+};
+
+static gboolean
+gst_rtp_mp4a_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstStructure *structure;
+ GstRtpMP4ADepay *rtpmp4adepay;
+ GstCaps *srccaps;
+ const gchar *str;
+ gint clock_rate;
+ gint object_type;
+ gint channels = 2; /* default */
+ gboolean res;
+
+ rtpmp4adepay = GST_RTP_MP4A_DEPAY (depayload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 90000; /* default */
+ depayload->clock_rate = clock_rate;
+
+ if (!gst_structure_get_int (structure, "object", &object_type))
+ object_type = 2; /* AAC LC default */
+
+ srccaps = gst_caps_new_simple ("audio/mpeg",
+ "mpegversion", G_TYPE_INT, 4,
+ "framed", G_TYPE_BOOLEAN, TRUE, "channels", G_TYPE_INT, channels,
+ "stream-format", G_TYPE_STRING, "raw", NULL);
+
+ if ((str = gst_structure_get_string (structure, "config"))) {
+ GValue v = { 0 };
+
+ g_value_init (&v, GST_TYPE_BUFFER);
+ if (gst_value_deserialize (&v, str)) {
+ GstBuffer *buffer;
+ GstMapInfo map;
+ guint8 *data;
+ gsize size;
+ gint i;
+ guint32 rate = 0;
+ guint8 obj_type = 0, sr_idx = 0, channels = 0;
+ GstBitReader br;
+
+ buffer = gst_value_get_buffer (&v);
+ gst_buffer_ref (buffer);
+ g_value_unset (&v);
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+ data = map.data;
+ size = map.size;
+
+ if (size < 2) {
+ GST_WARNING_OBJECT (depayload, "config too short (%d < 2)",
+ (gint) size);
+ goto bad_config;
+ }
+
+ /* Parse StreamMuxConfig according to ISO/IEC 14496-3:
+ *
+ * audioMuxVersion == 0 (1 bit)
+ * allStreamsSameTimeFraming == 1 (1 bit)
+ * numSubFrames == rtpmp4adepay->numSubFrames (6 bits)
+ * numProgram == 0 (4 bits)
+ * numLayer == 0 (3 bits)
+ *
+ * We only require audioMuxVersion == 0;
+ *
+ * The remaining bit of the second byte and the rest of the bits are used
+ * for audioSpecificConfig which we need to set in codec_info.
+ */
+ if ((data[0] & 0x80) != 0x00) {
+ GST_WARNING_OBJECT (depayload, "unknown audioMuxVersion 1");
+ goto bad_config;
+ }
+
+ rtpmp4adepay->numSubFrames = (data[0] & 0x3F);
+
+ GST_LOG_OBJECT (rtpmp4adepay, "numSubFrames %d",
+ rtpmp4adepay->numSubFrames);
+
+ /* shift rest of string 15 bits down */
+ size -= 2;
+ for (i = 0; i < size; i++) {
+ data[i] = ((data[i + 1] & 1) << 7) | ((data[i + 2] & 0xfe) >> 1);
+ }
+
+ gst_bit_reader_init (&br, data, size);
+
+ /* any object type is fine, we need to copy it to the profile-level-id field. */
+ if (!gst_bit_reader_get_bits_uint8 (&br, &obj_type, 5))
+ goto bad_config;
+ if (obj_type == 0) {
+ GST_WARNING_OBJECT (depayload, "invalid object type 0");
+ goto bad_config;
+ }
+
+ if (!gst_bit_reader_get_bits_uint8 (&br, &sr_idx, 4))
+ goto bad_config;
+ if (sr_idx >= G_N_ELEMENTS (aac_sample_rates) && sr_idx != 15) {
+ GST_WARNING_OBJECT (depayload, "invalid sample rate index %d", sr_idx);
+ goto bad_config;
+ }
+ GST_LOG_OBJECT (rtpmp4adepay, "sample rate index %u", sr_idx);
+
+ if (!gst_bit_reader_get_bits_uint8 (&br, &channels, 4))
+ goto bad_config;
+ if (channels > 7) {
+ GST_WARNING_OBJECT (depayload, "invalid channels %u", (guint) channels);
+ goto bad_config;
+ }
+
+ /* rtp rate depends on sampling rate of the audio */
+ if (sr_idx == 15) {
+ /* index of 15 means we get the rate in the next 24 bits */
+ if (!gst_bit_reader_get_bits_uint32 (&br, &rate, 24))
+ goto bad_config;
+ } else if (sr_idx >= G_N_ELEMENTS (aac_sample_rates)) {
+ goto bad_config;
+ } else {
+ /* else use the rate from the table */
+ rate = aac_sample_rates[sr_idx];
+ }
+
+ rtpmp4adepay->frame_len = 1024;
+
+ switch (obj_type) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 6:
+ case 7:
+ {
+ guint8 frameLenFlag = 0;
+
+ if (gst_bit_reader_get_bits_uint8 (&br, &frameLenFlag, 1))
+ if (frameLenFlag)
+ rtpmp4adepay->frame_len = 960;
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* ignore remaining bit, we're only interested in full bytes */
+ gst_buffer_resize (buffer, 0, size);
+ gst_buffer_unmap (buffer, &map);
+ data = NULL;
+
+ gst_caps_set_simple (srccaps,
+ "channels", G_TYPE_INT, (gint) channels,
+ "rate", G_TYPE_INT, (gint) rate,
+ "codec_data", GST_TYPE_BUFFER, buffer, NULL);
+ bad_config:
+ if (data)
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+ } else {
+ g_warning ("cannot convert config to buffer");
+ }
+ }
+ res = gst_pad_set_caps (depayload->srcpad, srccaps);
+ gst_caps_unref (srccaps);
+
+ return res;
+}
+
+static GstBuffer *
+gst_rtp_mp4a_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpMP4ADepay *rtpmp4adepay;
+ GstBuffer *outbuf;
+ GstRTPBuffer rtp = { NULL };
+ GstMapInfo map;
+
+ rtpmp4adepay = GST_RTP_MP4A_DEPAY (depayload);
+
+ /* flush remaining data on discont */
+ if (GST_BUFFER_IS_DISCONT (buf)) {
+ gst_adapter_clear (rtpmp4adepay->adapter);
+ }
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+ outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
+
+ outbuf = gst_buffer_make_writable (outbuf);
+ GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
+ gst_adapter_push (rtpmp4adepay->adapter, outbuf);
+
+ /* RTP marker bit indicates the last packet of the AudioMuxElement => create
+ * and push a buffer */
+ if (gst_rtp_buffer_get_marker (&rtp)) {
+ guint avail;
+ guint i;
+ guint8 *data;
+ guint pos;
+ GstClockTime timestamp;
+
+ avail = gst_adapter_available (rtpmp4adepay->adapter);
+ timestamp = gst_adapter_prev_pts (rtpmp4adepay->adapter, NULL);
+
+ GST_LOG_OBJECT (rtpmp4adepay, "have marker and %u available", avail);
+
+ outbuf = gst_adapter_take_buffer (rtpmp4adepay->adapter, avail);
+ gst_buffer_map (outbuf, &map, GST_MAP_READ);
+ data = map.data;
+ /* position in data we are at */
+ pos = 0;
+
+ /* looping through the number of sub-frames in the audio payload */
+ for (i = 0; i <= rtpmp4adepay->numSubFrames; i++) {
+ /* determine payload length and set buffer data pointer accordingly */
+ guint skip;
+ guint data_len;
+ GstBuffer *tmp = NULL;
+
+ /* each subframe starts with a variable length encoding */
+ data_len = 0;
+ for (skip = 0; skip < avail; skip++) {
+ data_len += data[skip];
+ if (data[skip] != 0xff)
+ break;
+ }
+ skip++;
+
+ /* this can not be possible, we have not enough data or the length
+ * decoding failed because we ran out of data. */
+ if (skip + data_len > avail)
+ goto wrong_size;
+
+ GST_LOG_OBJECT (rtpmp4adepay,
+ "subframe %u, header len %u, data len %u, left %u", i, skip, data_len,
+ avail);
+
+ /* take data out, skip the header */
+ pos += skip;
+ tmp = gst_buffer_copy_region (outbuf, GST_BUFFER_COPY_MEMORY, pos,
+ data_len);
+
+ /* skip data too */
+ skip += data_len;
+ pos += data_len;
+
+ /* update our pointers whith what we consumed */
+ data += skip;
+ avail -= skip;
+
+ GST_BUFFER_TIMESTAMP (tmp) = timestamp;
+ gst_rtp_base_depayload_push (depayload, tmp);
+
+ /* shift ts for next buffers */
+ if (rtpmp4adepay->frame_len && timestamp != -1
+ && depayload->clock_rate != 0) {
+ timestamp +=
+ gst_util_uint64_scale_int (rtpmp4adepay->frame_len, GST_SECOND,
+ depayload->clock_rate);
+ }
+ }
+
+ /* just a check that lengths match */
+ if (avail) {
+ GST_ELEMENT_WARNING (depayload, STREAM, DECODE,
+ ("Packet invalid"), ("Not all payload consumed: "
+ "possible wrongly encoded packet."));
+ }
+
+ gst_buffer_unmap (outbuf, &map);
+ gst_buffer_unref (outbuf);
+ }
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+
+ /* ERRORS */
+wrong_size:
+ {
+ GST_ELEMENT_WARNING (rtpmp4adepay, STREAM, DECODE,
+ ("Packet did not validate"), ("wrong packet size"));
+ gst_buffer_unmap (outbuf, &map);
+ gst_buffer_unref (outbuf);
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+}
+
+static GstStateChangeReturn
+gst_rtp_mp4a_depay_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstRtpMP4ADepay *rtpmp4adepay;
+ GstStateChangeReturn ret;
+
+ rtpmp4adepay = GST_RTP_MP4A_DEPAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_adapter_clear (rtpmp4adepay->adapter);
+ rtpmp4adepay->frame_len = 0;
+ rtpmp4adepay->numSubFrames = 0;
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ default:
+ break;
+ }
+ return ret;
+}
+
+gboolean
+gst_rtp_mp4a_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpmp4adepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_MP4A_DEPAY);
+}
diff --git a/gst/rtp/gstrtpmp4adepay.h b/gst/rtp/gstrtpmp4adepay.h
new file mode 100755
index 0000000..b44349f
--- /dev/null
+++ b/gst/rtp/gstrtpmp4adepay.h
@@ -0,0 +1,62 @@
+/* GStreamer
+ * Copyright (C) <2007> Nokia Corporation (contact <stefan.kost@nokia.com>)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MP4A_DEPAY_H__
+#define __GST_RTP_MP4A_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MP4A_DEPAY \
+ (gst_rtp_mp4a_depay_get_type())
+#define GST_RTP_MP4A_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MP4A_DEPAY,GstRtpMP4ADepay))
+#define GST_RTP_MP4A_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MP4A_DEPAY,GstRtpMP4ADepayClass))
+#define GST_IS_RTP_MP4A_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MP4A_DEPAY))
+#define GST_IS_RTP_MP4A_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MP4A_DEPAY))
+
+typedef struct _GstRtpMP4ADepay GstRtpMP4ADepay;
+typedef struct _GstRtpMP4ADepayClass GstRtpMP4ADepayClass;
+
+struct _GstRtpMP4ADepay
+{
+ GstRTPBaseDepayload depayload;
+ GstAdapter *adapter;
+ guint8 numSubFrames;
+ guint frame_len;
+};
+
+struct _GstRtpMP4ADepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_mp4a_depay_get_type (void);
+
+gboolean gst_rtp_mp4a_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MP4A_DEPAY_H__ */
+
diff --git a/gst/rtp/gstrtpmp4apay.c b/gst/rtp/gstrtpmp4apay.c
new file mode 100755
index 0000000..17a80a8
--- /dev/null
+++ b/gst/rtp/gstrtpmp4apay.c
@@ -0,0 +1,452 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpmp4apay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmp4apay_debug);
+#define GST_CAT_DEFAULT (rtpmp4apay_debug)
+
+/* FIXME: add framed=(boolean)true once our encoders have this field set
+ * on their output caps */
+static GstStaticPadTemplate gst_rtp_mp4a_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/mpeg, mpegversion=(int)4, "
+ "stream-format=(string)raw")
+ );
+
+static GstStaticPadTemplate gst_rtp_mp4a_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) [1, MAX ], "
+ "encoding-name = (string) \"MP4A-LATM\""
+ /* All optional parameters
+ *
+ * "cpresent = (string) \"0\""
+ * "config="
+ */
+ )
+ );
+
+static void gst_rtp_mp4a_pay_finalize (GObject * object);
+
+static gboolean gst_rtp_mp4a_pay_setcaps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+static GstFlowReturn gst_rtp_mp4a_pay_handle_buffer (GstRTPBasePayload *
+ payload, GstBuffer * buffer);
+
+#define gst_rtp_mp4a_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpMP4APay, gst_rtp_mp4a_pay, GST_TYPE_RTP_BASE_PAYLOAD)
+
+ static void gst_rtp_mp4a_pay_class_init (GstRtpMP4APayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_mp4a_pay_finalize;
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_mp4a_pay_setcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_mp4a_pay_handle_buffer;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mp4a_pay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mp4a_pay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP MPEG4 audio payloader", "Codec/Payloader/Network/RTP",
+ "Payload MPEG4 audio as RTP packets (RFC 3016)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ GST_DEBUG_CATEGORY_INIT (rtpmp4apay_debug, "rtpmp4apay", 0,
+ "MP4A-LATM RTP Payloader");
+}
+
+static void
+gst_rtp_mp4a_pay_init (GstRtpMP4APay * rtpmp4apay)
+{
+ rtpmp4apay->rate = 90000;
+ rtpmp4apay->profile = g_strdup ("1");
+}
+
+static void
+gst_rtp_mp4a_pay_finalize (GObject * object)
+{
+ GstRtpMP4APay *rtpmp4apay;
+
+ rtpmp4apay = GST_RTP_MP4A_PAY (object);
+
+ g_free (rtpmp4apay->params);
+ rtpmp4apay->params = NULL;
+
+ if (rtpmp4apay->config)
+ gst_buffer_unref (rtpmp4apay->config);
+ rtpmp4apay->config = NULL;
+
+ g_free (rtpmp4apay->profile);
+ rtpmp4apay->profile = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static const unsigned int sampling_table[16] = {
+ 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+ 16000, 12000, 11025, 8000, 7350, 0, 0, 0
+};
+
+static gboolean
+gst_rtp_mp4a_pay_parse_audio_config (GstRtpMP4APay * rtpmp4apay,
+ GstBuffer * buffer)
+{
+ GstMapInfo map;
+ guint8 *data;
+ gsize size;
+ guint8 objectType;
+ guint8 samplingIdx;
+ guint8 channelCfg;
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+ data = map.data;
+ size = map.size;
+
+ if (size < 2)
+ goto too_short;
+
+ /* any object type is fine, we need to copy it to the profile-level-id field. */
+ objectType = (data[0] & 0xf8) >> 3;
+ if (objectType == 0)
+ goto invalid_object;
+
+ samplingIdx = ((data[0] & 0x07) << 1) | ((data[1] & 0x80) >> 7);
+ /* only fixed values for now */
+ if (samplingIdx > 12 && samplingIdx != 15)
+ goto wrong_freq;
+
+ channelCfg = ((data[1] & 0x78) >> 3);
+ if (channelCfg > 7)
+ goto wrong_channels;
+
+ /* rtp rate depends on sampling rate of the audio */
+ if (samplingIdx == 15) {
+ if (size < 5)
+ goto too_short;
+
+ /* index of 15 means we get the rate in the next 24 bits */
+ rtpmp4apay->rate = ((data[1] & 0x7f) << 17) |
+ ((data[2]) << 9) | ((data[3]) << 1) | ((data[4] & 0x80) >> 7);
+ } else {
+ /* else use the rate from the table */
+ rtpmp4apay->rate = sampling_table[samplingIdx];
+ }
+ /* extra rtp params contain the number of channels */
+ g_free (rtpmp4apay->params);
+ rtpmp4apay->params = g_strdup_printf ("%d", channelCfg);
+ /* audio stream type */
+ rtpmp4apay->streamtype = "5";
+ /* profile */
+ g_free (rtpmp4apay->profile);
+ rtpmp4apay->profile = g_strdup_printf ("%d", objectType);
+
+ GST_DEBUG_OBJECT (rtpmp4apay,
+ "objectType: %d, samplingIdx: %d (%d), channelCfg: %d", objectType,
+ samplingIdx, rtpmp4apay->rate, channelCfg);
+
+ gst_buffer_unmap (buffer, &map);
+
+ return TRUE;
+
+ /* ERROR */
+too_short:
+ {
+ GST_ELEMENT_ERROR (rtpmp4apay, STREAM, FORMAT,
+ (NULL),
+ ("config string too short, expected 2 bytes, got %" G_GSIZE_FORMAT,
+ size));
+ gst_buffer_unmap (buffer, &map);
+ return FALSE;
+ }
+invalid_object:
+ {
+ GST_ELEMENT_ERROR (rtpmp4apay, STREAM, FORMAT,
+ (NULL), ("invalid object type 0"));
+ gst_buffer_unmap (buffer, &map);
+ return FALSE;
+ }
+wrong_freq:
+ {
+ GST_ELEMENT_ERROR (rtpmp4apay, STREAM, NOT_IMPLEMENTED,
+ (NULL), ("unsupported frequency index %d", samplingIdx));
+ gst_buffer_unmap (buffer, &map);
+ return FALSE;
+ }
+wrong_channels:
+ {
+ GST_ELEMENT_ERROR (rtpmp4apay, STREAM, NOT_IMPLEMENTED,
+ (NULL), ("unsupported number of channels %d, must < 8", channelCfg));
+ gst_buffer_unmap (buffer, &map);
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_rtp_mp4a_pay_new_caps (GstRtpMP4APay * rtpmp4apay)
+{
+ gchar *config;
+ GValue v = { 0 };
+ gboolean res;
+
+ g_value_init (&v, GST_TYPE_BUFFER);
+ gst_value_set_buffer (&v, rtpmp4apay->config);
+ config = gst_value_serialize (&v);
+
+ res = gst_rtp_base_payload_set_outcaps (GST_RTP_BASE_PAYLOAD (rtpmp4apay),
+ "cpresent", G_TYPE_STRING, "0", "config", G_TYPE_STRING, config, NULL);
+
+ g_value_unset (&v);
+ g_free (config);
+
+ return res;
+}
+
+static gboolean
+gst_rtp_mp4a_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ GstRtpMP4APay *rtpmp4apay;
+ GstStructure *structure;
+ const GValue *codec_data;
+ gboolean res, framed = TRUE;
+ const gchar *stream_format;
+
+ rtpmp4apay = GST_RTP_MP4A_PAY (payload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ /* this is already handled by the template caps, but it is better
+ * to leave here to have meaningful warning messages when linking
+ * fails */
+ stream_format = gst_structure_get_string (structure, "stream-format");
+ if (stream_format) {
+ if (strcmp (stream_format, "raw") != 0) {
+ GST_WARNING_OBJECT (rtpmp4apay, "AAC's stream-format must be 'raw', "
+ "%s is not supported", stream_format);
+ return FALSE;
+ }
+ } else {
+ GST_WARNING_OBJECT (rtpmp4apay, "AAC's stream-format not specified, "
+ "assuming 'raw'");
+ }
+
+ codec_data = gst_structure_get_value (structure, "codec_data");
+ if (codec_data) {
+ GST_LOG_OBJECT (rtpmp4apay, "got codec_data");
+ if (G_VALUE_TYPE (codec_data) == GST_TYPE_BUFFER) {
+ GstBuffer *buffer, *cbuffer;
+ GstMapInfo map;
+ GstMapInfo cmap;
+ guint i;
+
+ buffer = gst_value_get_buffer (codec_data);
+ GST_LOG_OBJECT (rtpmp4apay, "configuring codec_data");
+
+ /* parse buffer */
+ res = gst_rtp_mp4a_pay_parse_audio_config (rtpmp4apay, buffer);
+
+ if (!res)
+ goto config_failed;
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+ /* make the StreamMuxConfig, we need 15 bits for the header */
+ cbuffer = gst_buffer_new_and_alloc (map.size + 2);
+ gst_buffer_map (cbuffer, &cmap, GST_MAP_WRITE);
+
+ memset (cmap.data, 0, map.size + 2);
+
+ /* Create StreamMuxConfig according to ISO/IEC 14496-3:
+ *
+ * audioMuxVersion == 0 (1 bit)
+ * allStreamsSameTimeFraming == 1 (1 bit)
+ * numSubFrames == numSubFrames (6 bits)
+ * numProgram == 0 (4 bits)
+ * numLayer == 0 (3 bits)
+ */
+ cmap.data[0] = 0x40;
+ cmap.data[1] = 0x00;
+
+ /* append the config bits, shifting them 1 bit left */
+ for (i = 0; i < map.size; i++) {
+ cmap.data[i + 1] |= ((map.data[i] & 0x80) >> 7);
+ cmap.data[i + 2] |= ((map.data[i] & 0x7f) << 1);
+ }
+
+ gst_buffer_unmap (cbuffer, &cmap);
+ gst_buffer_unmap (buffer, &map);
+
+ /* now we can configure the buffer */
+ if (rtpmp4apay->config)
+ gst_buffer_unref (rtpmp4apay->config);
+ rtpmp4apay->config = cbuffer;
+ }
+ }
+
+ if (gst_structure_get_boolean (structure, "framed", &framed) && !framed) {
+ GST_WARNING_OBJECT (payload, "Need framed AAC data as input!");
+ }
+
+ gst_rtp_base_payload_set_options (payload, "audio", TRUE, "MP4A-LATM",
+ rtpmp4apay->rate);
+
+ res = gst_rtp_mp4a_pay_new_caps (rtpmp4apay);
+
+ return res;
+
+ /* ERRORS */
+config_failed:
+ {
+ GST_DEBUG_OBJECT (rtpmp4apay, "failed to parse config");
+ return FALSE;
+ }
+}
+
+/* we expect buffers as exactly one complete AU
+ */
+static GstFlowReturn
+gst_rtp_mp4a_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer)
+{
+ GstRtpMP4APay *rtpmp4apay;
+ GstFlowReturn ret;
+ GstBuffer *outbuf;
+ guint count, mtu;
+ GstMapInfo map;
+ gsize size;
+ guint8 *data;
+ gboolean fragmented;
+ GstClockTime timestamp;
+
+ ret = GST_FLOW_OK;
+
+ rtpmp4apay = GST_RTP_MP4A_PAY (basepayload);
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+ size = map.size;
+ data = map.data;
+
+ timestamp = GST_BUFFER_TIMESTAMP (buffer);
+
+ fragmented = FALSE;
+ mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpmp4apay);
+
+ while (size > 0) {
+ guint towrite;
+ guint8 *payload;
+ guint payload_len;
+ guint packet_len;
+ GstRTPBuffer rtp = { NULL };
+
+ /* this will be the total lenght of the packet */
+ packet_len = gst_rtp_buffer_calc_packet_len (size, 0, 0);
+
+ if (!fragmented) {
+ /* first packet calculate space for the packet including the header */
+ count = size;
+ while (count >= 0xff) {
+ packet_len++;
+ count -= 0xff;
+ }
+ packet_len++;
+ }
+
+ /* fill one MTU or all available bytes */
+ towrite = MIN (packet_len, mtu);
+
+ /* this is the payload length */
+ payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
+
+ GST_DEBUG_OBJECT (rtpmp4apay,
+ "avail %" G_GSIZE_FORMAT ", towrite %d, packet_len %d, payload_len %d",
+ size, towrite, packet_len, payload_len);
+
+ /* create buffer to hold the payload. */
+ outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
+
+ /* copy payload */
+ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+ payload = gst_rtp_buffer_get_payload (&rtp);
+
+ if (!fragmented) {
+ /* first packet write the header */
+ count = size;
+ while (count >= 0xff) {
+ *payload++ = 0xff;
+ payload_len--;
+ count -= 0xff;
+ }
+ *payload++ = count;
+ payload_len--;
+ }
+
+ /* copy data to payload */
+ memcpy (payload, data, payload_len);
+ data += payload_len;
+ size -= payload_len;
+
+ /* marker only if the packet is complete */
+ gst_rtp_buffer_set_marker (&rtp, size == 0);
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ /* copy incomming timestamp (if any) to outgoing buffers */
+ GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
+
+ ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpmp4apay), outbuf);
+
+ fragmented = TRUE;
+ }
+
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+
+ return ret;
+}
+
+gboolean
+gst_rtp_mp4a_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpmp4apay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_MP4A_PAY);
+}
diff --git a/gst/rtp/gstrtpmp4apay.h b/gst/rtp/gstrtpmp4apay.h
new file mode 100755
index 0000000..49d9b65
--- /dev/null
+++ b/gst/rtp/gstrtpmp4apay.h
@@ -0,0 +1,65 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MP4A_PAY_H__
+#define __GST_RTP_MP4A_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MP4A_PAY \
+ (gst_rtp_mp4a_pay_get_type())
+#define GST_RTP_MP4A_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MP4A_PAY,GstRtpMP4APay))
+#define GST_RTP_MP4A_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MP4A_PAY,GstRtpMP4APayClass))
+#define GST_IS_RTP_MP4A_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MP4A_PAY))
+#define GST_IS_RTP_MP4A_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MP4A_PAY))
+
+typedef struct _GstRtpMP4APay GstRtpMP4APay;
+typedef struct _GstRtpMP4APayClass GstRtpMP4APayClass;
+
+struct _GstRtpMP4APay
+{
+ GstRTPBasePayload payload;
+
+ gint rate;
+ gchar *params;
+ gchar *profile;
+ const gchar *streamtype;
+ GstBuffer *config;
+};
+
+struct _GstRtpMP4APayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_mp4a_pay_get_type (void);
+
+gboolean gst_rtp_mp4a_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MP4A_PAY_H__ */
diff --git a/gst/rtp/gstrtpmp4gdepay.c b/gst/rtp/gstrtpmp4gdepay.c
new file mode 100755
index 0000000..db472da
--- /dev/null
+++ b/gst/rtp/gstrtpmp4gdepay.c
@@ -0,0 +1,774 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpmp4gdepay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmp4gdepay_debug);
+#define GST_CAT_DEFAULT (rtpmp4gdepay_debug)
+
+static GstStaticPadTemplate gst_rtp_mp4g_depay_src_template =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/mpeg,"
+ "mpegversion=(int) 4,"
+ "systemstream=(boolean)false;"
+ "audio/mpeg," "mpegversion=(int) 4, " "stream-format=(string)raw")
+ );
+
+static GstStaticPadTemplate gst_rtp_mp4g_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) { \"video\", \"audio\", \"application\" }, "
+ "clock-rate = (int) [1, MAX ], "
+ "encoding-name = (string) \"MPEG4-GENERIC\", "
+ /* required string params */
+ /* "streamtype = (string) { \"4\", \"5\" }, " Not set by Wowza 4 = video, 5 = audio */
+ /* "profile-level-id = (string) [1,MAX], " */
+ /* "config = (string) [1,MAX]" */
+ "mode = (string) { \"generic\", \"CELP-cbr\", \"CELP-vbr\", \"AAC-lbr\", \"AAC-hbr\" } "
+ /* Optional general parameters */
+ /* "objecttype = (string) [1,MAX], " */
+ /* "constantsize = (string) [1,MAX], " *//* constant size of each AU */
+ /* "constantduration = (string) [1,MAX], " *//* constant duration of each AU */
+ /* "maxdisplacement = (string) [1,MAX], " */
+ /* "de-interleavebuffersize = (string) [1,MAX], " */
+ /* Optional configuration parameters */
+ /* "sizelength = (string) [1, 32], " */
+ /* "indexlength = (string) [1, 32], " */
+ /* "indexdeltalength = (string) [1, 32], " */
+ /* "ctsdeltalength = (string) [1, 32], " */
+ /* "dtsdeltalength = (string) [1, 32], " */
+ /* "randomaccessindication = (string) {0, 1}, " */
+ /* "streamstateindication = (string) [0, 32], " */
+ /* "auxiliarydatasizelength = (string) [0, 32]" */ )
+ );
+
+/* simple bitstream parser */
+typedef struct
+{
+ const guint8 *data;
+ const guint8 *end;
+ gint head; /* bitpos in the cache of next bit */
+ guint64 cache; /* cached bytes */
+} GstBsParse;
+
+static void
+gst_bs_parse_init (GstBsParse * bs, const guint8 * data, guint size)
+{
+ bs->data = data;
+ bs->end = data + size;
+ bs->head = 0;
+ bs->cache = 0xffffffff;
+}
+
+static guint32
+gst_bs_parse_read (GstBsParse * bs, guint n)
+{
+ guint32 res = 0;
+ gint shift;
+
+ if (n == 0)
+ return res;
+
+ /* fill up the cache if we need to */
+ while (bs->head < n) {
+ if (bs->data >= bs->end) {
+ /* we're at the end, can't produce more than head number of bits */
+ n = bs->head;
+ break;
+ }
+ /* shift bytes in cache, moving the head bits of the cache left */
+ bs->cache = (bs->cache << 8) | *bs->data++;
+ bs->head += 8;
+ }
+
+ /* bring the required bits down and truncate */
+ if ((shift = bs->head - n) > 0)
+ res = bs->cache >> shift;
+ else
+ res = bs->cache;
+
+ /* mask out required bits */
+ if (n < 32)
+ res &= (1 << n) - 1;
+
+ bs->head = shift;
+
+ return res;
+}
+
+
+#define gst_rtp_mp4g_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpMP4GDepay, gst_rtp_mp4g_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_mp4g_depay_finalize (GObject * object);
+
+static gboolean gst_rtp_mp4g_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_mp4g_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+static gboolean gst_rtp_mp4g_depay_handle_event (GstRTPBaseDepayload * filter,
+ GstEvent * event);
+
+static GstStateChangeReturn gst_rtp_mp4g_depay_change_state (GstElement *
+ element, GstStateChange transition);
+
+
+static void
+gst_rtp_mp4g_depay_class_init (GstRtpMP4GDepayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_mp4g_depay_finalize;
+
+ gstelement_class->change_state = gst_rtp_mp4g_depay_change_state;
+
+ gstrtpbasedepayload_class->process = gst_rtp_mp4g_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_mp4g_depay_setcaps;
+ gstrtpbasedepayload_class->handle_event = gst_rtp_mp4g_depay_handle_event;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mp4g_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mp4g_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP MPEG4 ES depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts MPEG4 elementary streams from RTP packets (RFC 3640)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ GST_DEBUG_CATEGORY_INIT (rtpmp4gdepay_debug, "rtpmp4gdepay", 0,
+ "MP4-generic RTP Depayloader");
+}
+
+static void
+gst_rtp_mp4g_depay_init (GstRtpMP4GDepay * rtpmp4gdepay)
+{
+ rtpmp4gdepay->adapter = gst_adapter_new ();
+ rtpmp4gdepay->packets = g_queue_new ();
+}
+
+static void
+gst_rtp_mp4g_depay_finalize (GObject * object)
+{
+ GstRtpMP4GDepay *rtpmp4gdepay;
+
+ rtpmp4gdepay = GST_RTP_MP4G_DEPAY (object);
+
+ g_object_unref (rtpmp4gdepay->adapter);
+ rtpmp4gdepay->adapter = NULL;
+ g_queue_free (rtpmp4gdepay->packets);
+ rtpmp4gdepay->packets = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gint
+gst_rtp_mp4g_depay_parse_int (GstStructure * structure, const gchar * field,
+ gint def)
+{
+ const gchar *str;
+ gint res;
+
+ if ((str = gst_structure_get_string (structure, field)))
+ return atoi (str);
+
+ if (gst_structure_get_int (structure, field, &res))
+ return res;
+
+ return def;
+}
+
+static gboolean
+gst_rtp_mp4g_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstStructure *structure;
+ GstRtpMP4GDepay *rtpmp4gdepay;
+ GstCaps *srccaps = NULL;
+ const gchar *str;
+ gint clock_rate;
+ gint someint;
+ gboolean res;
+
+ rtpmp4gdepay = GST_RTP_MP4G_DEPAY (depayload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 90000; /* default */
+ depayload->clock_rate = clock_rate;
+
+ if ((str = gst_structure_get_string (structure, "media"))) {
+ if (strcmp (str, "audio") == 0) {
+ srccaps = gst_caps_new_simple ("audio/mpeg",
+ "mpegversion", G_TYPE_INT, 4, "stream-format", G_TYPE_STRING, "raw",
+ NULL);
+ } else if (strcmp (str, "video") == 0) {
+ srccaps = gst_caps_new_simple ("video/mpeg",
+ "mpegversion", G_TYPE_INT, 4,
+ "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+ }
+ }
+ if (srccaps == NULL)
+ goto unknown_media;
+
+ /* these values are optional and have a default value of 0 (no header) */
+ rtpmp4gdepay->sizelength =
+ gst_rtp_mp4g_depay_parse_int (structure, "sizelength", 0);
+ rtpmp4gdepay->indexlength =
+ gst_rtp_mp4g_depay_parse_int (structure, "indexlength", 0);
+ rtpmp4gdepay->indexdeltalength =
+ gst_rtp_mp4g_depay_parse_int (structure, "indexdeltalength", 0);
+ rtpmp4gdepay->ctsdeltalength =
+ gst_rtp_mp4g_depay_parse_int (structure, "ctsdeltalength", 0);
+ rtpmp4gdepay->dtsdeltalength =
+ gst_rtp_mp4g_depay_parse_int (structure, "dtsdeltalength", 0);
+ someint =
+ gst_rtp_mp4g_depay_parse_int (structure, "randomaccessindication", 0);
+ rtpmp4gdepay->randomaccessindication = someint > 0 ? 1 : 0;
+ rtpmp4gdepay->streamstateindication =
+ gst_rtp_mp4g_depay_parse_int (structure, "streamstateindication", 0);
+ rtpmp4gdepay->auxiliarydatasizelength =
+ gst_rtp_mp4g_depay_parse_int (structure, "auxiliarydatasizelength", 0);
+ rtpmp4gdepay->constantSize =
+ gst_rtp_mp4g_depay_parse_int (structure, "constantsize", 0);
+ rtpmp4gdepay->constantDuration =
+ gst_rtp_mp4g_depay_parse_int (structure, "constantduration", 0);
+ rtpmp4gdepay->maxDisplacement =
+ gst_rtp_mp4g_depay_parse_int (structure, "maxdisplacement", 0);
+
+
+ /* get config string */
+ if ((str = gst_structure_get_string (structure, "config"))) {
+ GValue v = { 0 };
+
+ g_value_init (&v, GST_TYPE_BUFFER);
+ if (gst_value_deserialize (&v, str)) {
+ GstBuffer *buffer;
+
+ buffer = gst_value_get_buffer (&v);
+ gst_caps_set_simple (srccaps,
+ "codec_data", GST_TYPE_BUFFER, buffer, NULL);
+ g_value_unset (&v);
+ } else {
+ g_warning ("cannot convert config to buffer");
+ }
+ }
+
+ res = gst_pad_set_caps (depayload->srcpad, srccaps);
+ gst_caps_unref (srccaps);
+
+ return res;
+
+ /* ERRORS */
+unknown_media:
+ {
+ GST_DEBUG_OBJECT (rtpmp4gdepay, "Unknown media type");
+ return FALSE;
+ }
+}
+
+static void
+gst_rtp_mp4g_depay_clear_queue (GstRtpMP4GDepay * rtpmp4gdepay)
+{
+ GstBuffer *outbuf;
+
+ while ((outbuf = g_queue_pop_head (rtpmp4gdepay->packets)))
+ gst_buffer_unref (outbuf);
+}
+
+static void
+gst_rtp_mp4g_depay_reset (GstRtpMP4GDepay * rtpmp4gdepay)
+{
+ gst_adapter_clear (rtpmp4gdepay->adapter);
+ rtpmp4gdepay->max_AU_index = -1;
+ rtpmp4gdepay->next_AU_index = -1;
+ rtpmp4gdepay->prev_AU_index = -1;
+ rtpmp4gdepay->prev_rtptime = -1;
+ rtpmp4gdepay->last_AU_index = -1;
+ gst_rtp_mp4g_depay_clear_queue (rtpmp4gdepay);
+}
+
+static void
+gst_rtp_mp4g_depay_flush_queue (GstRtpMP4GDepay * rtpmp4gdepay)
+{
+ GstBuffer *outbuf;
+ gboolean discont = FALSE;
+ guint AU_index;
+
+ while ((outbuf = g_queue_pop_head (rtpmp4gdepay->packets))) {
+ AU_index = GST_BUFFER_OFFSET (outbuf);
+
+ GST_DEBUG_OBJECT (rtpmp4gdepay, "next available AU_index %u", AU_index);
+
+ if (rtpmp4gdepay->next_AU_index != AU_index) {
+ GST_DEBUG_OBJECT (rtpmp4gdepay, "discont, expected AU_index %u",
+ rtpmp4gdepay->next_AU_index);
+ discont = TRUE;
+ }
+
+ if (discont) {
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+ discont = FALSE;
+ }
+
+ GST_DEBUG_OBJECT (rtpmp4gdepay, "pushing AU_index %u", AU_index);
+ gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpmp4gdepay), outbuf);
+ rtpmp4gdepay->next_AU_index = AU_index + 1;
+ }
+}
+
+static void
+gst_rtp_mp4g_depay_queue (GstRtpMP4GDepay * rtpmp4gdepay, GstBuffer * outbuf)
+{
+ guint AU_index = GST_BUFFER_OFFSET (outbuf);
+
+ if (rtpmp4gdepay->next_AU_index == -1) {
+ GST_DEBUG_OBJECT (rtpmp4gdepay, "Init AU counter %u", AU_index);
+ rtpmp4gdepay->next_AU_index = AU_index;
+ }
+
+ if (rtpmp4gdepay->next_AU_index == AU_index) {
+ GST_DEBUG_OBJECT (rtpmp4gdepay, "pushing expected AU_index %u", AU_index);
+
+ /* we received the expected packet, push it and flush as much as we can from
+ * the queue */
+ gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpmp4gdepay), outbuf);
+ rtpmp4gdepay->next_AU_index++;
+
+ while ((outbuf = g_queue_peek_head (rtpmp4gdepay->packets))) {
+ AU_index = GST_BUFFER_OFFSET (outbuf);
+
+ GST_DEBUG_OBJECT (rtpmp4gdepay, "next available AU_index %u", AU_index);
+
+ if (rtpmp4gdepay->next_AU_index == AU_index) {
+ GST_DEBUG_OBJECT (rtpmp4gdepay, "pushing expected AU_index %u",
+ AU_index);
+ outbuf = g_queue_pop_head (rtpmp4gdepay->packets);
+ gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpmp4gdepay),
+ outbuf);
+ rtpmp4gdepay->next_AU_index++;
+ } else {
+ GST_DEBUG_OBJECT (rtpmp4gdepay, "waiting for next AU_index %u",
+ rtpmp4gdepay->next_AU_index);
+ break;
+ }
+ }
+ } else {
+ GList *list;
+
+ GST_DEBUG_OBJECT (rtpmp4gdepay, "queueing AU_index %u", AU_index);
+
+ /* loop the list to skip strictly smaller AU_index buffers */
+ for (list = rtpmp4gdepay->packets->head; list; list = g_list_next (list)) {
+ guint idx;
+ gint gap;
+
+ idx = GST_BUFFER_OFFSET (GST_BUFFER_CAST (list->data));
+
+ /* compare the new seqnum to the one in the buffer */
+ gap = (gint) (idx - AU_index);
+
+ GST_DEBUG_OBJECT (rtpmp4gdepay, "compare with AU_index %u, gap %d", idx,
+ gap);
+
+ /* AU_index <= idx, we can stop looking */
+ if (G_LIKELY (gap > 0))
+ break;
+ }
+ if (G_LIKELY (list))
+ g_queue_insert_before (rtpmp4gdepay->packets, list, outbuf);
+ else
+ g_queue_push_tail (rtpmp4gdepay->packets, outbuf);
+ }
+}
+
+static GstBuffer *
+gst_rtp_mp4g_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpMP4GDepay *rtpmp4gdepay;
+ GstBuffer *outbuf = NULL;
+ GstClockTime timestamp;
+ GstRTPBuffer rtp = { NULL };
+
+ rtpmp4gdepay = GST_RTP_MP4G_DEPAY (depayload);
+
+ /* flush remaining data on discont */
+ if (GST_BUFFER_IS_DISCONT (buf)) {
+ GST_DEBUG_OBJECT (rtpmp4gdepay, "received DISCONT");
+ gst_adapter_clear (rtpmp4gdepay->adapter);
+ }
+
+ timestamp = GST_BUFFER_TIMESTAMP (buf);
+
+ {
+ gint payload_len, payload_AU;
+ guint8 *payload;
+ guint32 rtptime;
+ guint AU_headers_len;
+ guint AU_size, AU_index, AU_index_delta, payload_AU_size;
+ gboolean M;
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+ payload = gst_rtp_buffer_get_payload (&rtp);
+
+ GST_DEBUG_OBJECT (rtpmp4gdepay, "received payload of %d", payload_len);
+
+ rtptime = gst_rtp_buffer_get_timestamp (&rtp);
+ M = gst_rtp_buffer_get_marker (&rtp);
+
+ if (rtpmp4gdepay->sizelength > 0) {
+ gint num_AU_headers, AU_headers_bytes, i;
+ GstBsParse bs;
+
+ if (payload_len < 2)
+ goto short_payload;
+
+ /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- .. -+-+-+-+-+-+-+-+-+-+
+ * |AU-headers-length|AU-header|AU-header| |AU-header|padding|
+ * | | (1) | (2) | | (n) * | bits |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- .. -+-+-+-+-+-+-+-+-+-+
+ *
+ * The length is 2 bytes and contains the length of the following
+ * AU-headers in bits.
+ */
+ AU_headers_len = (payload[0] << 8) | payload[1];
+ AU_headers_bytes = (AU_headers_len + 7) / 8;
+ num_AU_headers = AU_headers_len / 16;
+
+ GST_DEBUG_OBJECT (rtpmp4gdepay, "AU headers len %d, bytes %d, num %d",
+ AU_headers_len, AU_headers_bytes, num_AU_headers);
+
+ /* skip header */
+ payload += 2;
+ payload_len -= 2;
+
+ if (payload_len < AU_headers_bytes)
+ goto short_payload;
+
+ /* skip special headers, point to first payload AU */
+ payload_AU = 2 + AU_headers_bytes;
+ payload_AU_size = payload_len - AU_headers_bytes;
+
+ if (G_UNLIKELY (rtpmp4gdepay->auxiliarydatasizelength)) {
+ gint aux_size;
+
+ /* point the bitstream parser to the first auxiliary data bit */
+ gst_bs_parse_init (&bs, payload + AU_headers_bytes,
+ payload_len - AU_headers_bytes);
+ aux_size =
+ gst_bs_parse_read (&bs, rtpmp4gdepay->auxiliarydatasizelength);
+ /* convert to bytes */
+ aux_size = (aux_size + 7) / 8;
+ /* AU data then follows auxiliary data */
+ if (payload_AU_size < aux_size)
+ goto short_payload;
+ payload_AU += aux_size;
+ payload_AU_size -= aux_size;
+ }
+
+ /* point the bitstream parser to the first AU header bit */
+ gst_bs_parse_init (&bs, payload, payload_len);
+ AU_index = AU_index_delta = 0;
+
+ for (i = 0; i < num_AU_headers && payload_AU_size > 0; i++) {
+ /* parse AU header
+ * +---------------------------------------+
+ * | AU-size |
+ * +---------------------------------------+
+ * | AU-Index / AU-Index-delta |
+ * +---------------------------------------+
+ * | CTS-flag |
+ * +---------------------------------------+
+ * | CTS-delta |
+ * +---------------------------------------+
+ * | DTS-flag |
+ * +---------------------------------------+
+ * | DTS-delta |
+ * +---------------------------------------+
+ * | RAP-flag |
+ * +---------------------------------------+
+ * | Stream-state |
+ * +---------------------------------------+
+ */
+ AU_size = gst_bs_parse_read (&bs, rtpmp4gdepay->sizelength);
+
+ /* calculate the AU_index, which is only on the first AU of the packet
+ * and the AU_index_delta on the other AUs. This will be used to
+ * reconstruct the AU ordering when interleaving. */
+ if (i == 0) {
+ AU_index = gst_bs_parse_read (&bs, rtpmp4gdepay->indexlength);
+
+ GST_DEBUG_OBJECT (rtpmp4gdepay, "AU index %u", AU_index);
+
+ if (AU_index == 0 && rtpmp4gdepay->prev_AU_index == 0) {
+ gint diff;
+ gint cd;
+
+ /* if we see two consecutive packets with AU_index of 0, we can
+ * assume we have constantDuration packets. Since we don't have
+ * the index we must use the AU duration to calculate the
+ * index. Get the diff between the timestamps first, this can be
+ * positive or negative. */
+ if (rtpmp4gdepay->prev_rtptime <= rtptime)
+ diff = rtptime - rtpmp4gdepay->prev_rtptime;
+ else
+ diff = -(rtpmp4gdepay->prev_rtptime - rtptime);
+
+ /* if no constantDuration was given, make one */
+ if (rtpmp4gdepay->constantDuration != 0) {
+ cd = rtpmp4gdepay->constantDuration;
+ GST_DEBUG_OBJECT (depayload, "using constantDuration %d", cd);
+ } else if (rtpmp4gdepay->prev_AU_num > 0) {
+ /* use number of packets and of previous frame */
+ cd = diff / rtpmp4gdepay->prev_AU_num;
+ GST_DEBUG_OBJECT (depayload, "guessing constantDuration %d", cd);
+ } else {
+ /* assume this frame has the same number of packets as the
+ * previous one */
+ cd = diff / num_AU_headers;
+ GST_DEBUG_OBJECT (depayload, "guessing constantDuration %d", cd);
+ }
+
+ if (cd > 0) {
+ /* get the number of packets by dividing with the duration */
+ diff /= cd;
+ } else {
+ diff = 0;
+ }
+
+ rtpmp4gdepay->last_AU_index += diff;
+ rtpmp4gdepay->prev_AU_index = AU_index;
+
+ AU_index = rtpmp4gdepay->last_AU_index;
+
+ GST_DEBUG_OBJECT (rtpmp4gdepay, "diff %d, AU index %u", diff,
+ AU_index);
+ } else {
+ rtpmp4gdepay->prev_AU_index = AU_index;
+ rtpmp4gdepay->last_AU_index = AU_index;
+ }
+
+ /* keep track of the higest AU_index */
+ if (rtpmp4gdepay->max_AU_index != -1
+ && rtpmp4gdepay->max_AU_index <= AU_index) {
+ GST_DEBUG_OBJECT (rtpmp4gdepay, "new interleave group, flushing");
+ /* a new interleave group started, flush */
+ gst_rtp_mp4g_depay_flush_queue (rtpmp4gdepay);
+ }
+ if (G_UNLIKELY (!rtpmp4gdepay->maxDisplacement &&
+ rtpmp4gdepay->max_AU_index != -1
+ && rtpmp4gdepay->max_AU_index >= AU_index)) {
+ GstBuffer *outbuf;
+
+ /* some broken non-interleaved streams have AU-index jumping around
+ * all over the place, apparently assuming receiver disregards */
+ GST_DEBUG_OBJECT (rtpmp4gdepay, "non-interleaved broken AU indices;"
+ " forcing continuous flush");
+ /* reset AU to avoid repeated DISCONT in such case */
+ outbuf = g_queue_peek_head (rtpmp4gdepay->packets);
+ if (G_LIKELY (outbuf)) {
+ rtpmp4gdepay->next_AU_index = GST_BUFFER_OFFSET (outbuf);
+ gst_rtp_mp4g_depay_flush_queue (rtpmp4gdepay);
+ }
+ /* rebase next_AU_index to current rtp's first AU_index */
+ rtpmp4gdepay->next_AU_index = AU_index;
+ }
+ rtpmp4gdepay->prev_rtptime = rtptime;
+ rtpmp4gdepay->prev_AU_num = num_AU_headers;
+ } else {
+ AU_index_delta =
+ gst_bs_parse_read (&bs, rtpmp4gdepay->indexdeltalength);
+ AU_index += AU_index_delta + 1;
+ }
+ /* keep track of highest AU_index */
+ if (rtpmp4gdepay->max_AU_index == -1
+ || AU_index > rtpmp4gdepay->max_AU_index)
+ rtpmp4gdepay->max_AU_index = AU_index;
+
+ /* the presentation time offset, a 2s-complement value, we need this to
+ * calculate the timestamp on the output packet. */
+ if (rtpmp4gdepay->ctsdeltalength > 0) {
+ if (gst_bs_parse_read (&bs, 1))
+ gst_bs_parse_read (&bs, rtpmp4gdepay->ctsdeltalength);
+ }
+ /* the decoding time offset, a 2s-complement value */
+ if (rtpmp4gdepay->dtsdeltalength > 0) {
+ if (gst_bs_parse_read (&bs, 1))
+ gst_bs_parse_read (&bs, rtpmp4gdepay->dtsdeltalength);
+ }
+ /* RAP-flag to indicate that the AU contains a keyframe */
+ if (rtpmp4gdepay->randomaccessindication)
+ gst_bs_parse_read (&bs, 1);
+ /* stream-state */
+ if (rtpmp4gdepay->streamstateindication > 0)
+ gst_bs_parse_read (&bs, rtpmp4gdepay->streamstateindication);
+
+ GST_DEBUG_OBJECT (rtpmp4gdepay, "size %d, index %d, delta %d", AU_size,
+ AU_index, AU_index_delta);
+
+ /* fragmented pakets have the AU_size set to the size of the
+ * unfragmented AU. */
+ if (AU_size > payload_AU_size)
+ AU_size = payload_AU_size;
+
+ /* collect stuff in the adapter, strip header from payload and push in
+ * the adapter */
+ outbuf =
+ gst_rtp_buffer_get_payload_subbuffer (&rtp, payload_AU, AU_size);
+ gst_adapter_push (rtpmp4gdepay->adapter, outbuf);
+
+ if (M) {
+ guint avail;
+
+ /* packet is complete, flush */
+ avail = gst_adapter_available (rtpmp4gdepay->adapter);
+
+ outbuf = gst_adapter_take_buffer (rtpmp4gdepay->adapter, avail);
+
+ /* copy some of the fields we calculated above on the buffer. We also
+ * copy the AU_index so that we can sort the packets in our queue. */
+ GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
+ GST_BUFFER_OFFSET (outbuf) = AU_index;
+
+ /* make sure we don't use the timestamp again for other AUs in this
+ * RTP packet. */
+ timestamp = -1;
+
+ GST_DEBUG_OBJECT (depayload,
+ "pushing buffer of size %" G_GSIZE_FORMAT,
+ gst_buffer_get_size (outbuf));
+
+ gst_rtp_mp4g_depay_queue (rtpmp4gdepay, outbuf);
+
+ }
+ payload_AU += AU_size;
+ payload_AU_size -= AU_size;
+ }
+ } else {
+ /* push complete buffer in adapter */
+ outbuf = gst_rtp_buffer_get_payload_subbuffer (&rtp, 0, payload_len);
+ gst_adapter_push (rtpmp4gdepay->adapter, outbuf);
+
+ /* if this was the last packet of the VOP, create and push a buffer */
+ if (M) {
+ guint avail;
+
+ avail = gst_adapter_available (rtpmp4gdepay->adapter);
+
+ outbuf = gst_adapter_take_buffer (rtpmp4gdepay->adapter, avail);
+
+ GST_DEBUG ("gst_rtp_mp4g_depay_chain: pushing buffer of size %"
+ G_GSIZE_FORMAT, gst_buffer_get_size (outbuf));
+
+ gst_rtp_buffer_unmap (&rtp);
+ return outbuf;
+ }
+ }
+ }
+
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+
+ /* ERRORS */
+short_payload:
+ {
+ GST_ELEMENT_WARNING (rtpmp4gdepay, STREAM, DECODE,
+ ("Packet payload was too short."), (NULL));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+}
+
+static gboolean
+gst_rtp_mp4g_depay_handle_event (GstRTPBaseDepayload * filter, GstEvent * event)
+{
+ gboolean ret;
+ GstRtpMP4GDepay *rtpmp4gdepay;
+
+ rtpmp4gdepay = GST_RTP_MP4G_DEPAY (filter);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_STOP:
+ gst_rtp_mp4g_depay_reset (rtpmp4gdepay);
+ break;
+ default:
+ break;
+ }
+
+ ret =
+ GST_RTP_BASE_DEPAYLOAD_CLASS (parent_class)->handle_event (filter, event);
+
+ return ret;
+}
+
+static GstStateChangeReturn
+gst_rtp_mp4g_depay_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstRtpMP4GDepay *rtpmp4gdepay;
+ GstStateChangeReturn ret;
+
+ rtpmp4gdepay = GST_RTP_MP4G_DEPAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_rtp_mp4g_depay_reset (rtpmp4gdepay);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_rtp_mp4g_depay_reset (rtpmp4gdepay);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+gboolean
+gst_rtp_mp4g_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpmp4gdepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_MP4G_DEPAY);
+}
diff --git a/gst/rtp/gstrtpmp4gdepay.h b/gst/rtp/gstrtpmp4gdepay.h
new file mode 100755
index 0000000..5d5997a
--- /dev/null
+++ b/gst/rtp/gstrtpmp4gdepay.h
@@ -0,0 +1,86 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MP4G_DEPAY_H__
+#define __GST_RTP_MP4G_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MP4G_DEPAY \
+ (gst_rtp_mp4g_depay_get_type())
+#define GST_RTP_MP4G_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MP4G_DEPAY,GstRtpMP4GDepay))
+#define GST_RTP_MP4G_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MP4G_DEPAY,GstRtpMP4GDepayClass))
+#define GST_IS_RTP_MP4G_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MP4G_DEPAY))
+#define GST_IS_RTP_MP4G_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MP4G_DEPAY))
+
+typedef struct _GstRtpMP4GDepay GstRtpMP4GDepay;
+typedef struct _GstRtpMP4GDepayClass GstRtpMP4GDepayClass;
+
+struct _GstRtpMP4GDepay
+{
+ GstRTPBaseDepayload depayload;
+
+ gint profile_level_id;
+ gint streamtype;
+
+ gint constantSize;
+ gint constantDuration;
+ gint maxDisplacement;
+
+ gint sizelength;
+ gint indexlength;
+ gint indexdeltalength;
+ gint ctsdeltalength;
+ gint dtsdeltalength;
+ gint randomaccessindication;
+ gint streamstateindication;
+ gint auxiliarydatasizelength;
+
+ guint max_AU_index;
+ guint prev_AU_index;
+ guint last_AU_index;
+ guint next_AU_index;
+ guint32 prev_rtptime;
+ guint prev_AU_num;
+
+ GQueue *packets;
+
+ GstAdapter *adapter;
+};
+
+struct _GstRtpMP4GDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_mp4g_depay_get_type (void);
+
+gboolean gst_rtp_mp4g_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MP4G_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpmp4gpay.c b/gst/rtp/gstrtpmp4gpay.c
new file mode 100755
index 0000000..e374e5c
--- /dev/null
+++ b/gst/rtp/gstrtpmp4gpay.c
@@ -0,0 +1,641 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/base/gstbitreader.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpmp4gpay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmp4gpay_debug);
+#define GST_CAT_DEFAULT (rtpmp4gpay_debug)
+
+static GstStaticPadTemplate gst_rtp_mp4g_pay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/mpeg,"
+ "mpegversion=(int) 4,"
+ "systemstream=(boolean)false;"
+ "audio/mpeg," "mpegversion=(int) 4, " "stream-format=(string) raw")
+ );
+
+static GstStaticPadTemplate gst_rtp_mp4g_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) { \"video\", \"audio\", \"application\" }, "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) [1, MAX ], "
+ "encoding-name = (string) \"MPEG4-GENERIC\", "
+ /* required string params */
+ "streamtype = (string) { \"4\", \"5\" }, " /* 4 = video, 5 = audio */
+ /* "profile-level-id = (string) [1,MAX], " */
+ /* "config = (string) [1,MAX]" */
+ "mode = (string) { \"generic\", \"CELP-cbr\", \"CELP-vbr\", \"AAC-lbr\", \"AAC-hbr\" } "
+ /* Optional general parameters */
+ /* "objecttype = (string) [1,MAX], " */
+ /* "constantsize = (string) [1,MAX], " *//* constant size of each AU */
+ /* "constantduration = (string) [1,MAX], " *//* constant duration of each AU */
+ /* "maxdisplacement = (string) [1,MAX], " */
+ /* "de-interleavebuffersize = (string) [1,MAX], " */
+ /* Optional configuration parameters */
+ /* "sizelength = (string) [1, 16], " *//* max 16 bits, should be enough... */
+ /* "indexlength = (string) [1, 8], " */
+ /* "indexdeltalength = (string) [1, 8], " */
+ /* "ctsdeltalength = (string) [1, 64], " */
+ /* "dtsdeltalength = (string) [1, 64], " */
+ /* "randomaccessindication = (string) {0, 1}, " */
+ /* "streamstateindication = (string) [0, 64], " */
+ /* "auxiliarydatasizelength = (string) [0, 64]" */ )
+ );
+
+
+static void gst_rtp_mp4g_pay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_mp4g_pay_change_state (GstElement * element,
+ GstStateChange transition);
+
+static gboolean gst_rtp_mp4g_pay_setcaps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+static GstFlowReturn gst_rtp_mp4g_pay_handle_buffer (GstRTPBasePayload *
+ payload, GstBuffer * buffer);
+static gboolean gst_rtp_mp4g_pay_sink_event (GstRTPBasePayload * payload,
+ GstEvent * event);
+
+#define gst_rtp_mp4g_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpMP4GPay, gst_rtp_mp4g_pay, GST_TYPE_RTP_BASE_PAYLOAD)
+
+ static void gst_rtp_mp4g_pay_class_init (GstRtpMP4GPayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_mp4g_pay_finalize;
+
+ gstelement_class->change_state = gst_rtp_mp4g_pay_change_state;
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_mp4g_pay_setcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_mp4g_pay_handle_buffer;
+ gstrtpbasepayload_class->sink_event = gst_rtp_mp4g_pay_sink_event;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mp4g_pay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mp4g_pay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP MPEG4 ES payloader",
+ "Codec/Payloader/Network/RTP",
+ "Payload MPEG4 elementary streams as RTP packets (RFC 3640)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ GST_DEBUG_CATEGORY_INIT (rtpmp4gpay_debug, "rtpmp4gpay", 0,
+ "MP4-generic RTP Payloader");
+}
+
+static void
+gst_rtp_mp4g_pay_init (GstRtpMP4GPay * rtpmp4gpay)
+{
+ rtpmp4gpay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_mp4g_pay_reset (GstRtpMP4GPay * rtpmp4gpay)
+{
+ GST_DEBUG_OBJECT (rtpmp4gpay, "reset");
+
+ gst_adapter_clear (rtpmp4gpay->adapter);
+ rtpmp4gpay->offset = 0;
+}
+
+static void
+gst_rtp_mp4g_pay_cleanup (GstRtpMP4GPay * rtpmp4gpay)
+{
+ gst_rtp_mp4g_pay_reset (rtpmp4gpay);
+
+ g_free (rtpmp4gpay->params);
+ rtpmp4gpay->params = NULL;
+
+ if (rtpmp4gpay->config)
+ gst_buffer_unref (rtpmp4gpay->config);
+ rtpmp4gpay->config = NULL;
+
+ g_free (rtpmp4gpay->profile);
+ rtpmp4gpay->profile = NULL;
+
+ rtpmp4gpay->streamtype = NULL;
+ rtpmp4gpay->mode = NULL;
+
+ rtpmp4gpay->frame_len = 0;
+}
+
+static void
+gst_rtp_mp4g_pay_finalize (GObject * object)
+{
+ GstRtpMP4GPay *rtpmp4gpay;
+
+ rtpmp4gpay = GST_RTP_MP4G_PAY (object);
+
+ gst_rtp_mp4g_pay_cleanup (rtpmp4gpay);
+
+ g_object_unref (rtpmp4gpay->adapter);
+ rtpmp4gpay->adapter = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static const unsigned int sampling_table[16] = {
+ 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+ 16000, 12000, 11025, 8000, 7350, 0, 0, 0
+};
+
+static gboolean
+gst_rtp_mp4g_pay_parse_audio_config (GstRtpMP4GPay * rtpmp4gpay,
+ GstBuffer * buffer)
+{
+ GstMapInfo map;
+ guint8 objectType = 0;
+ guint8 samplingIdx = 0;
+ guint8 channelCfg = 0;
+ GstBitReader br;
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+ gst_bit_reader_init (&br, map.data, map.size);
+
+ /* any object type is fine, we need to copy it to the profile-level-id field. */
+ if (!gst_bit_reader_get_bits_uint8 (&br, &objectType, 5))
+ goto too_short;
+ if (objectType == 0)
+ goto invalid_object;
+
+ if (!gst_bit_reader_get_bits_uint8 (&br, &samplingIdx, 4))
+ goto too_short;
+ /* only fixed values for now */
+ if (samplingIdx > 12 && samplingIdx != 15)
+ goto wrong_freq;
+
+ if (!gst_bit_reader_get_bits_uint8 (&br, &channelCfg, 4))
+ goto too_short;
+ if (channelCfg > 7)
+ goto wrong_channels;
+
+ /* rtp rate depends on sampling rate of the audio */
+ if (samplingIdx == 15) {
+ guint32 rate = 0;
+
+ /* index of 15 means we get the rate in the next 24 bits */
+ if (!gst_bit_reader_get_bits_uint32 (&br, &rate, 24))
+ goto too_short;
+
+ rtpmp4gpay->rate = rate;
+ } else {
+ /* else use the rate from the table */
+ rtpmp4gpay->rate = sampling_table[samplingIdx];
+ }
+
+ rtpmp4gpay->frame_len = 1024;
+
+ switch (objectType) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 6:
+ case 7:
+ {
+ guint8 frameLenFlag = 0;
+
+ if (gst_bit_reader_get_bits_uint8 (&br, &frameLenFlag, 1))
+ if (frameLenFlag)
+ rtpmp4gpay->frame_len = 960;
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* extra rtp params contain the number of channels */
+ g_free (rtpmp4gpay->params);
+ rtpmp4gpay->params = g_strdup_printf ("%d", channelCfg);
+ /* audio stream type */
+ rtpmp4gpay->streamtype = "5";
+ /* mode only high bitrate for now */
+ rtpmp4gpay->mode = "AAC-hbr";
+ /* profile */
+ g_free (rtpmp4gpay->profile);
+ rtpmp4gpay->profile = g_strdup_printf ("%d", objectType);
+
+ GST_DEBUG_OBJECT (rtpmp4gpay,
+ "objectType: %d, samplingIdx: %d (%d), channelCfg: %d, frame_len %d",
+ objectType, samplingIdx, rtpmp4gpay->rate, channelCfg,
+ rtpmp4gpay->frame_len);
+
+ gst_buffer_unmap (buffer, &map);
+ return TRUE;
+
+ /* ERROR */
+too_short:
+ {
+ GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, FORMAT,
+ (NULL), ("config string too short"));
+ gst_buffer_unmap (buffer, &map);
+ return FALSE;
+ }
+invalid_object:
+ {
+ GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, FORMAT,
+ (NULL), ("invalid object type"));
+ gst_buffer_unmap (buffer, &map);
+ return FALSE;
+ }
+wrong_freq:
+ {
+ GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, NOT_IMPLEMENTED,
+ (NULL), ("unsupported frequency index %d", samplingIdx));
+ gst_buffer_unmap (buffer, &map);
+ return FALSE;
+ }
+wrong_channels:
+ {
+ GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, NOT_IMPLEMENTED,
+ (NULL), ("unsupported number of channels %d, must < 8", channelCfg));
+ gst_buffer_unmap (buffer, &map);
+ return FALSE;
+ }
+}
+
+#define VOS_STARTCODE 0x000001B0
+
+static gboolean
+gst_rtp_mp4g_pay_parse_video_config (GstRtpMP4GPay * rtpmp4gpay,
+ GstBuffer * buffer)
+{
+ GstMapInfo map;
+ guint32 code;
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+ if (map.size < 5)
+ goto too_short;
+
+ code = GST_READ_UINT32_BE (map.data);
+
+ g_free (rtpmp4gpay->profile);
+ if (code == VOS_STARTCODE) {
+ /* get profile */
+ rtpmp4gpay->profile = g_strdup_printf ("%d", (gint) map.data[4]);
+ } else {
+ GST_ELEMENT_WARNING (rtpmp4gpay, STREAM, FORMAT,
+ (NULL), ("profile not found in config string, assuming \'1\'"));
+ rtpmp4gpay->profile = g_strdup ("1");
+ }
+
+ /* fixed rate */
+ rtpmp4gpay->rate = 90000;
+ /* video stream type */
+ rtpmp4gpay->streamtype = "4";
+ /* no params for video */
+ rtpmp4gpay->params = NULL;
+ /* mode */
+ rtpmp4gpay->mode = "generic";
+
+ GST_LOG_OBJECT (rtpmp4gpay, "profile %s", rtpmp4gpay->profile);
+
+ gst_buffer_unmap (buffer, &map);
+
+ return TRUE;
+
+ /* ERROR */
+too_short:
+ {
+ GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, FORMAT,
+ (NULL), ("config string too short"));
+ gst_buffer_unmap (buffer, &map);
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_rtp_mp4g_pay_new_caps (GstRtpMP4GPay * rtpmp4gpay)
+{
+ gchar *config;
+ GValue v = { 0 };
+ gboolean res;
+
+#define MP4GCAPS \
+ "streamtype", G_TYPE_STRING, rtpmp4gpay->streamtype, \
+ "profile-level-id", G_TYPE_STRING, rtpmp4gpay->profile, \
+ "mode", G_TYPE_STRING, rtpmp4gpay->mode, \
+ "config", G_TYPE_STRING, config, \
+ "sizelength", G_TYPE_STRING, "13", \
+ "indexlength", G_TYPE_STRING, "3", \
+ "indexdeltalength", G_TYPE_STRING, "3", \
+ NULL
+
+ g_value_init (&v, GST_TYPE_BUFFER);
+ gst_value_set_buffer (&v, rtpmp4gpay->config);
+ config = gst_value_serialize (&v);
+
+ /* hmm, silly */
+ if (rtpmp4gpay->params) {
+ res = gst_rtp_base_payload_set_outcaps (GST_RTP_BASE_PAYLOAD (rtpmp4gpay),
+ "encoding-params", G_TYPE_STRING, rtpmp4gpay->params, MP4GCAPS);
+ } else {
+ res = gst_rtp_base_payload_set_outcaps (GST_RTP_BASE_PAYLOAD (rtpmp4gpay),
+ MP4GCAPS);
+ }
+
+ g_value_unset (&v);
+ g_free (config);
+
+#undef MP4GCAPS
+ return res;
+}
+
+static gboolean
+gst_rtp_mp4g_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ GstRtpMP4GPay *rtpmp4gpay;
+ GstStructure *structure;
+ const GValue *codec_data;
+ const gchar *media_type = NULL;
+ gboolean res;
+
+ rtpmp4gpay = GST_RTP_MP4G_PAY (payload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ codec_data = gst_structure_get_value (structure, "codec_data");
+ if (codec_data) {
+ GST_LOG_OBJECT (rtpmp4gpay, "got codec_data");
+ if (G_VALUE_TYPE (codec_data) == GST_TYPE_BUFFER) {
+ GstBuffer *buffer;
+ const gchar *name;
+
+ buffer = gst_value_get_buffer (codec_data);
+ GST_LOG_OBJECT (rtpmp4gpay, "configuring codec_data");
+
+ name = gst_structure_get_name (structure);
+
+ /* parse buffer */
+ if (!strcmp (name, "audio/mpeg")) {
+ res = gst_rtp_mp4g_pay_parse_audio_config (rtpmp4gpay, buffer);
+ media_type = "audio";
+ } else if (!strcmp (name, "video/mpeg")) {
+ res = gst_rtp_mp4g_pay_parse_video_config (rtpmp4gpay, buffer);
+ media_type = "video";
+ } else {
+ res = FALSE;
+ }
+ if (!res)
+ goto config_failed;
+
+ /* now we can configure the buffer */
+ if (rtpmp4gpay->config)
+ gst_buffer_unref (rtpmp4gpay->config);
+
+ rtpmp4gpay->config = gst_buffer_copy (buffer);
+ }
+ }
+ if (media_type == NULL)
+ goto config_failed;
+
+ gst_rtp_base_payload_set_options (payload, media_type, TRUE, "MPEG4-GENERIC",
+ rtpmp4gpay->rate);
+
+ res = gst_rtp_mp4g_pay_new_caps (rtpmp4gpay);
+
+ return res;
+
+ /* ERRORS */
+config_failed:
+ {
+ GST_DEBUG_OBJECT (rtpmp4gpay, "failed to parse config");
+ return FALSE;
+ }
+}
+
+static GstFlowReturn
+gst_rtp_mp4g_pay_flush (GstRtpMP4GPay * rtpmp4gpay)
+{
+ guint avail, total;
+ GstBuffer *outbuf;
+ GstFlowReturn ret;
+ guint mtu;
+
+ /* the data available in the adapter is either smaller
+ * than the MTU or bigger. In the case it is smaller, the complete
+ * adapter contents can be put in one packet. In the case the
+ * adapter has more than one MTU, we need to fragment the MPEG data
+ * over multiple packets. */
+ total = avail = gst_adapter_available (rtpmp4gpay->adapter);
+
+ ret = GST_FLOW_OK;
+ mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpmp4gpay);
+
+ while (avail > 0) {
+ guint towrite;
+ guint8 *payload;
+ guint payload_len;
+ guint packet_len;
+ GstRTPBuffer rtp = { NULL };
+ GstBuffer *paybuf;
+
+ /* this will be the total lenght of the packet */
+ packet_len = gst_rtp_buffer_calc_packet_len (avail, 0, 0);
+
+ /* fill one MTU or all available bytes, we need 4 spare bytes for
+ * the AU header. */
+ towrite = MIN (packet_len, mtu - 4);
+
+ /* this is the payload length */
+ payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
+
+ GST_DEBUG_OBJECT (rtpmp4gpay,
+ "avail %d, towrite %d, packet_len %d, payload_len %d", avail, towrite,
+ packet_len, payload_len);
+
+ /* create buffer to hold the payload, also make room for the 4 header bytes. */
+ outbuf = gst_rtp_buffer_new_allocate (4, 0, 0);
+
+ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+ /* copy payload */
+ payload = gst_rtp_buffer_get_payload (&rtp);
+
+ /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- .. -+-+-+-+-+-+-+-+-+-+
+ * |AU-headers-length|AU-header|AU-header| |AU-header|padding|
+ * | | (1) | (2) | | (n) | bits |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- .. -+-+-+-+-+-+-+-+-+-+
+ */
+ /* AU-headers-length, we only have 1 AU-header */
+ payload[0] = 0x00;
+ payload[1] = 0x10; /* we use 16 bits for the header */
+
+ /* +---------------------------------------+
+ * | AU-size |
+ * +---------------------------------------+
+ * | AU-Index / AU-Index-delta |
+ * +---------------------------------------+
+ * | CTS-flag |
+ * +---------------------------------------+
+ * | CTS-delta |
+ * +---------------------------------------+
+ * | DTS-flag |
+ * +---------------------------------------+
+ * | DTS-delta |
+ * +---------------------------------------+
+ * | RAP-flag |
+ * +---------------------------------------+
+ * | Stream-state |
+ * +---------------------------------------+
+ */
+ /* The AU-header, no CTS, DTS, RAP, Stream-state
+ *
+ * AU-size is always the total size of the AU, not the fragmented size
+ */
+ payload[2] = (total & 0x1fe0) >> 5;
+ payload[3] = (total & 0x1f) << 3; /* we use 13 bits for the size, 3 bits index */
+
+ /* marker only if the packet is complete */
+ gst_rtp_buffer_set_marker (&rtp, avail <= payload_len);
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ paybuf = gst_adapter_take_buffer_fast (rtpmp4gpay->adapter, payload_len);
+ outbuf = gst_buffer_append (outbuf, paybuf);
+
+ GST_BUFFER_TIMESTAMP (outbuf) = rtpmp4gpay->first_timestamp;
+ GST_BUFFER_DURATION (outbuf) = rtpmp4gpay->first_duration;
+
+ if (rtpmp4gpay->frame_len) {
+ GST_BUFFER_OFFSET (outbuf) = rtpmp4gpay->offset;
+ rtpmp4gpay->offset += rtpmp4gpay->frame_len;
+ }
+
+ if (rtpmp4gpay->discont) {
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+ /* Only the first outputted buffer has the DISCONT flag */
+ rtpmp4gpay->discont = FALSE;
+ }
+
+ ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpmp4gpay), outbuf);
+
+ avail -= payload_len;
+ }
+
+ return ret;
+}
+
+/* we expect buffers as exactly one complete AU
+ */
+static GstFlowReturn
+gst_rtp_mp4g_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer)
+{
+ GstRtpMP4GPay *rtpmp4gpay;
+
+ rtpmp4gpay = GST_RTP_MP4G_PAY (basepayload);
+
+ rtpmp4gpay->first_timestamp = GST_BUFFER_TIMESTAMP (buffer);
+ rtpmp4gpay->first_duration = GST_BUFFER_DURATION (buffer);
+ rtpmp4gpay->discont = GST_BUFFER_IS_DISCONT (buffer);
+
+ /* we always encode and flush a full AU */
+ gst_adapter_push (rtpmp4gpay->adapter, buffer);
+
+ return gst_rtp_mp4g_pay_flush (rtpmp4gpay);
+}
+
+static gboolean
+gst_rtp_mp4g_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+ GstRtpMP4GPay *rtpmp4gpay;
+
+ rtpmp4gpay = GST_RTP_MP4G_PAY (payload);
+
+ GST_DEBUG ("Got event: %s", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEGMENT:
+ case GST_EVENT_EOS:
+ /* This flush call makes sure that the last buffer is always pushed
+ * to the base payloader */
+ gst_rtp_mp4g_pay_flush (rtpmp4gpay);
+ break;
+ case GST_EVENT_FLUSH_STOP:
+ gst_rtp_mp4g_pay_reset (rtpmp4gpay);
+ break;
+ default:
+ break;
+ }
+
+ /* let parent handle event too */
+ return GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
+}
+
+static GstStateChangeReturn
+gst_rtp_mp4g_pay_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret;
+ GstRtpMP4GPay *rtpmp4gpay;
+
+ rtpmp4gpay = GST_RTP_MP4G_PAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_rtp_mp4g_pay_cleanup (rtpmp4gpay);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_rtp_mp4g_pay_cleanup (rtpmp4gpay);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+gboolean
+gst_rtp_mp4g_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpmp4gpay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_MP4G_PAY);
+}
diff --git a/gst/rtp/gstrtpmp4gpay.h b/gst/rtp/gstrtpmp4gpay.h
new file mode 100755
index 0000000..7506fad
--- /dev/null
+++ b/gst/rtp/gstrtpmp4gpay.h
@@ -0,0 +1,74 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MP4G_PAY_H__
+#define __GST_RTP_MP4G_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MP4G_PAY \
+ (gst_rtp_mp4g_pay_get_type())
+#define GST_RTP_MP4G_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MP4G_PAY,GstRtpMP4GPay))
+#define GST_RTP_MP4G_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MP4G_PAY,GstRtpMP4GPayClass))
+#define GST_IS_RTP_MP4G_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MP4G_PAY))
+#define GST_IS_RTP_MP4G_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MP4G_PAY))
+
+typedef struct _GstRtpMP4GPay GstRtpMP4GPay;
+typedef struct _GstRtpMP4GPayClass GstRtpMP4GPayClass;
+
+struct _GstRtpMP4GPay
+{
+ GstRTPBasePayload payload;
+
+ GstAdapter *adapter;
+ GstClockTime first_timestamp;
+ GstClockTime first_duration;
+ gboolean discont;
+ GstClockTime duration;
+ guint64 offset;
+
+ gint rate;
+ gchar *params;
+ gchar *profile;
+ const gchar *streamtype;
+ const gchar *mode;
+ GstBuffer *config;
+ guint frame_len;
+};
+
+struct _GstRtpMP4GPayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_mp4g_pay_get_type (void);
+
+gboolean gst_rtp_mp4g_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MP4G_PAY_H__ */
diff --git a/gst/rtp/gstrtpmp4vdepay.c b/gst/rtp/gstrtpmp4vdepay.c
new file mode 100755
index 0000000..3ff58d5
--- /dev/null
+++ b/gst/rtp/gstrtpmp4vdepay.c
@@ -0,0 +1,226 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <string.h>
+#include "gstrtpmp4vdepay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmp4vdepay_debug);
+#define GST_CAT_DEFAULT (rtpmp4vdepay_debug)
+
+static GstStaticPadTemplate gst_rtp_mp4v_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/mpeg,"
+ "mpegversion=(int) 4," "systemstream=(boolean)false")
+ );
+
+static GstStaticPadTemplate gst_rtp_mp4v_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"video\", "
+ "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"MP4V-ES\""
+ /* All optional parameters
+ *
+ * "profile-level-id=[1,MAX]"
+ * "config="
+ */
+ )
+ );
+
+#define gst_rtp_mp4v_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpMP4VDepay, gst_rtp_mp4v_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_mp4v_depay_finalize (GObject * object);
+
+static gboolean gst_rtp_mp4v_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_mp4v_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+
+static GstStateChangeReturn gst_rtp_mp4v_depay_change_state (GstElement *
+ element, GstStateChange transition);
+
+static void
+gst_rtp_mp4v_depay_class_init (GstRtpMP4VDepayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_mp4v_depay_finalize;
+
+ gstelement_class->change_state = gst_rtp_mp4v_depay_change_state;
+
+ gstrtpbasedepayload_class->process = gst_rtp_mp4v_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_mp4v_depay_setcaps;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mp4v_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mp4v_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP MPEG4 video depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts MPEG4 video from RTP packets (RFC 3016)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ GST_DEBUG_CATEGORY_INIT (rtpmp4vdepay_debug, "rtpmp4vdepay", 0,
+ "MPEG4 video RTP Depayloader");
+}
+
+static void
+gst_rtp_mp4v_depay_init (GstRtpMP4VDepay * rtpmp4vdepay)
+{
+ rtpmp4vdepay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_mp4v_depay_finalize (GObject * object)
+{
+ GstRtpMP4VDepay *rtpmp4vdepay;
+
+ rtpmp4vdepay = GST_RTP_MP4V_DEPAY (object);
+
+ g_object_unref (rtpmp4vdepay->adapter);
+ rtpmp4vdepay->adapter = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rtp_mp4v_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstStructure *structure;
+ GstCaps *srccaps;
+ const gchar *str;
+ gint clock_rate;
+ gboolean res;
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 90000; /* default */
+ depayload->clock_rate = clock_rate;
+
+ srccaps = gst_caps_new_simple ("video/mpeg",
+ "mpegversion", G_TYPE_INT, 4,
+ "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+
+ if ((str = gst_structure_get_string (structure, "config"))) {
+ GValue v = { 0 };
+
+ g_value_init (&v, GST_TYPE_BUFFER);
+ if (gst_value_deserialize (&v, str)) {
+ GstBuffer *buffer;
+
+ buffer = gst_value_get_buffer (&v);
+ gst_caps_set_simple (srccaps,
+ "codec_data", GST_TYPE_BUFFER, buffer, NULL);
+ /* caps takes ref */
+ g_value_unset (&v);
+ } else {
+ g_warning ("cannot convert config to buffer");
+ }
+ }
+ res = gst_pad_set_caps (depayload->srcpad, srccaps);
+ gst_caps_unref (srccaps);
+
+ return res;
+}
+
+static GstBuffer *
+gst_rtp_mp4v_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpMP4VDepay *rtpmp4vdepay;
+ GstBuffer *pbuf, *outbuf = NULL;
+ GstRTPBuffer rtp = { NULL };
+ gboolean marker;
+
+ rtpmp4vdepay = GST_RTP_MP4V_DEPAY (depayload);
+
+ /* flush remaining data on discont */
+ if (GST_BUFFER_IS_DISCONT (buf))
+ gst_adapter_clear (rtpmp4vdepay->adapter);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+ pbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
+ marker = gst_rtp_buffer_get_marker (&rtp);
+ gst_rtp_buffer_unmap (&rtp);
+
+ gst_adapter_push (rtpmp4vdepay->adapter, pbuf);
+
+ /* if this was the last packet of the VOP, create and push a buffer */
+ if (marker) {
+ guint avail;
+
+ avail = gst_adapter_available (rtpmp4vdepay->adapter);
+ outbuf = gst_adapter_take_buffer (rtpmp4vdepay->adapter, avail);
+
+ GST_DEBUG ("gst_rtp_mp4v_depay_chain: pushing buffer of size %"
+ G_GSIZE_FORMAT, gst_buffer_get_size (outbuf));
+ }
+ return outbuf;
+}
+
+static GstStateChangeReturn
+gst_rtp_mp4v_depay_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstRtpMP4VDepay *rtpmp4vdepay;
+ GstStateChangeReturn ret;
+
+ rtpmp4vdepay = GST_RTP_MP4V_DEPAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_adapter_clear (rtpmp4vdepay->adapter);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ default:
+ break;
+ }
+ return ret;
+}
+
+gboolean
+gst_rtp_mp4v_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpmp4vdepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_MP4V_DEPAY);
+}
diff --git a/gst/rtp/gstrtpmp4vdepay.h b/gst/rtp/gstrtpmp4vdepay.h
new file mode 100755
index 0000000..436e0db
--- /dev/null
+++ b/gst/rtp/gstrtpmp4vdepay.h
@@ -0,0 +1,61 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MP4V_DEPAY_H__
+#define __GST_RTP_MP4V_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MP4V_DEPAY \
+ (gst_rtp_mp4v_depay_get_type())
+#define GST_RTP_MP4V_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MP4V_DEPAY,GstRtpMP4VDepay))
+#define GST_RTP_MP4V_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MP4V_DEPAY,GstRtpMP4VDepayClass))
+#define GST_IS_RTP_MP4V_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MP4V_DEPAY))
+#define GST_IS_RTP_MP4V_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MP4V_DEPAY))
+
+typedef struct _GstRtpMP4VDepay GstRtpMP4VDepay;
+typedef struct _GstRtpMP4VDepayClass GstRtpMP4VDepayClass;
+
+struct _GstRtpMP4VDepay
+{
+ GstRTPBaseDepayload depayload;
+
+ GstAdapter *adapter;
+};
+
+struct _GstRtpMP4VDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_mp4v_depay_get_type (void);
+
+gboolean gst_rtp_mp4v_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MP4V_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpmp4vpay.c b/gst/rtp/gstrtpmp4vpay.c
new file mode 100755
index 0000000..1ed1ac5
--- /dev/null
+++ b/gst/rtp/gstrtpmp4vpay.c
@@ -0,0 +1,617 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpmp4vpay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmp4vpay_debug);
+#define GST_CAT_DEFAULT (rtpmp4vpay_debug)
+
+static GstStaticPadTemplate gst_rtp_mp4v_pay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/mpeg,"
+ "mpegversion=(int) 4, systemstream=(boolean)false;" "video/x-divx")
+ );
+
+static GstStaticPadTemplate gst_rtp_mp4v_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"video\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"MP4V-ES\""
+ /* two string params
+ *
+ "profile-level-id = (string) [1,MAX]"
+ "config = (string) [1,MAX]"
+ */
+ )
+ );
+
+#define DEFAULT_CONFIG_INTERVAL 0
+
+enum
+{
+ PROP_0,
+ PROP_CONFIG_INTERVAL
+};
+
+
+static void gst_rtp_mp4v_pay_finalize (GObject * object);
+
+static void gst_rtp_mp4v_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_rtp_mp4v_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static gboolean gst_rtp_mp4v_pay_setcaps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+static GstFlowReturn gst_rtp_mp4v_pay_handle_buffer (GstRTPBasePayload *
+ payload, GstBuffer * buffer);
+static gboolean gst_rtp_mp4v_pay_sink_event (GstRTPBasePayload * pay,
+ GstEvent * event);
+
+#define gst_rtp_mp4v_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpMP4VPay, gst_rtp_mp4v_pay, GST_TYPE_RTP_BASE_PAYLOAD)
+
+ static void gst_rtp_mp4v_pay_class_init (GstRtpMP4VPayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gobject_class->set_property = gst_rtp_mp4v_pay_set_property;
+ gobject_class->get_property = gst_rtp_mp4v_pay_get_property;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mp4v_pay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mp4v_pay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP MPEG4 Video payloader", "Codec/Payloader/Network/RTP",
+ "Payload MPEG-4 video as RTP packets (RFC 3016)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CONFIG_INTERVAL,
+ g_param_spec_uint ("config-interval", "Config Send Interval",
+ "Send Config Insertion Interval in seconds (configuration headers "
+ "will be multiplexed in the data stream when detected.) (0 = disabled)",
+ 0, 3600, DEFAULT_CONFIG_INTERVAL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+ );
+
+ gobject_class->finalize = gst_rtp_mp4v_pay_finalize;
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_mp4v_pay_setcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_mp4v_pay_handle_buffer;
+ gstrtpbasepayload_class->sink_event = gst_rtp_mp4v_pay_sink_event;
+
+ GST_DEBUG_CATEGORY_INIT (rtpmp4vpay_debug, "rtpmp4vpay", 0,
+ "MP4 video RTP Payloader");
+}
+
+static void
+gst_rtp_mp4v_pay_init (GstRtpMP4VPay * rtpmp4vpay)
+{
+ rtpmp4vpay->adapter = gst_adapter_new ();
+ rtpmp4vpay->rate = 90000;
+ rtpmp4vpay->profile = 1;
+ rtpmp4vpay->need_config = TRUE;
+ rtpmp4vpay->config_interval = DEFAULT_CONFIG_INTERVAL;
+ rtpmp4vpay->last_config = -1;
+
+ rtpmp4vpay->config = NULL;
+}
+
+static void
+gst_rtp_mp4v_pay_finalize (GObject * object)
+{
+ GstRtpMP4VPay *rtpmp4vpay;
+
+ rtpmp4vpay = GST_RTP_MP4V_PAY (object);
+
+ if (rtpmp4vpay->config) {
+ gst_buffer_unref (rtpmp4vpay->config);
+ rtpmp4vpay->config = NULL;
+ }
+ g_object_unref (rtpmp4vpay->adapter);
+ rtpmp4vpay->adapter = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rtp_mp4v_pay_new_caps (GstRtpMP4VPay * rtpmp4vpay)
+{
+ gchar *profile, *config;
+ GValue v = { 0 };
+ gboolean res;
+
+ profile = g_strdup_printf ("%d", rtpmp4vpay->profile);
+ g_value_init (&v, GST_TYPE_BUFFER);
+ gst_value_set_buffer (&v, rtpmp4vpay->config);
+ config = gst_value_serialize (&v);
+
+ res = gst_rtp_base_payload_set_outcaps (GST_RTP_BASE_PAYLOAD (rtpmp4vpay),
+ "profile-level-id", G_TYPE_STRING, profile,
+ "config", G_TYPE_STRING, config, NULL);
+
+ g_value_unset (&v);
+
+ g_free (profile);
+ g_free (config);
+
+ return res;
+}
+
+static gboolean
+gst_rtp_mp4v_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ GstRtpMP4VPay *rtpmp4vpay;
+ GstStructure *structure;
+ const GValue *codec_data;
+ gboolean res;
+
+ rtpmp4vpay = GST_RTP_MP4V_PAY (payload);
+
+ gst_rtp_base_payload_set_options (payload, "video", TRUE, "MP4V-ES",
+ rtpmp4vpay->rate);
+
+ res = TRUE;
+
+ structure = gst_caps_get_structure (caps, 0);
+ codec_data = gst_structure_get_value (structure, "codec_data");
+ if (codec_data) {
+ GST_LOG_OBJECT (rtpmp4vpay, "got codec_data");
+ if (G_VALUE_TYPE (codec_data) == GST_TYPE_BUFFER) {
+ GstBuffer *buffer;
+
+ buffer = gst_value_get_buffer (codec_data);
+
+ if (gst_buffer_get_size (buffer) < 5)
+ goto done;
+
+ gst_buffer_extract (buffer, 4, &rtpmp4vpay->profile, 1);
+ GST_LOG_OBJECT (rtpmp4vpay, "configuring codec_data, profile %d",
+ rtpmp4vpay->profile);
+
+ if (rtpmp4vpay->config)
+ gst_buffer_unref (rtpmp4vpay->config);
+ rtpmp4vpay->config = gst_buffer_copy (buffer);
+ res = gst_rtp_mp4v_pay_new_caps (rtpmp4vpay);
+ }
+ }
+
+done:
+ return res;
+}
+
+static void
+gst_rtp_mp4v_pay_empty (GstRtpMP4VPay * rtpmp4vpay)
+{
+ gst_adapter_clear (rtpmp4vpay->adapter);
+}
+
+#define RTP_HEADER_LEN 12
+
+static GstFlowReturn
+gst_rtp_mp4v_pay_flush (GstRtpMP4VPay * rtpmp4vpay)
+{
+ guint avail, mtu;
+ GstBuffer *outbuf;
+ GstBuffer *outbuf_data = NULL;
+ GstFlowReturn ret;
+ GstBufferList *list = NULL;
+
+ /* the data available in the adapter is either smaller
+ * than the MTU or bigger. In the case it is smaller, the complete
+ * adapter contents can be put in one packet. In the case the
+ * adapter has more than one MTU, we need to split the MP4V data
+ * over multiple packets. */
+ avail = gst_adapter_available (rtpmp4vpay->adapter);
+
+ if (rtpmp4vpay->config == NULL && rtpmp4vpay->need_config) {
+ /* when we don't have a config yet, flush things out */
+ gst_adapter_flush (rtpmp4vpay->adapter, avail);
+ avail = 0;
+ }
+
+ if (!avail)
+ return GST_FLOW_OK;
+
+ mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpmp4vpay);
+
+ /* Use buffer lists. Each frame will be put into a list
+ * of buffers and the whole list will be pushed downstream
+ * at once */
+ list = gst_buffer_list_new_sized ((avail / (mtu - RTP_HEADER_LEN)) + 1);
+
+ while (avail > 0) {
+ guint towrite;
+ guint payload_len;
+ guint packet_len;
+ GstRTPBuffer rtp = { NULL };
+
+ /* this will be the total lenght of the packet */
+ packet_len = gst_rtp_buffer_calc_packet_len (avail, 0, 0);
+
+ /* fill one MTU or all available bytes */
+ towrite = MIN (packet_len, mtu);
+
+ /* this is the payload length */
+ payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
+
+ /* create buffer without payload. The payload will be put
+ * in next buffer instead. Both buffers will be merged */
+ outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
+
+ /* Take buffer with the payload from the adapter */
+ outbuf_data = gst_adapter_take_buffer_fast (rtpmp4vpay->adapter,
+ payload_len);
+
+ avail -= payload_len;
+
+ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+ gst_rtp_buffer_set_marker (&rtp, avail == 0);
+ gst_rtp_buffer_unmap (&rtp);
+
+ outbuf = gst_buffer_append (outbuf, outbuf_data);
+
+ GST_BUFFER_TIMESTAMP (outbuf) = rtpmp4vpay->first_timestamp;
+
+ /* add to list */
+ gst_buffer_list_insert (list, -1, outbuf);
+ }
+
+ /* push the whole buffer list at once */
+ ret =
+ gst_rtp_base_payload_push_list (GST_RTP_BASE_PAYLOAD (rtpmp4vpay), list);
+
+ return ret;
+}
+
+#define VOS_STARTCODE 0x000001B0
+#define VOS_ENDCODE 0x000001B1
+#define USER_DATA_STARTCODE 0x000001B2
+#define GOP_STARTCODE 0x000001B3
+#define VISUAL_OBJECT_STARTCODE 0x000001B5
+#define VOP_STARTCODE 0x000001B6
+
+static gboolean
+gst_rtp_mp4v_pay_depay_data (GstRtpMP4VPay * enc, guint8 * data, guint size,
+ gint * strip, gboolean * vopi)
+{
+ guint32 code;
+ gboolean result;
+ *vopi = FALSE;
+
+ *strip = 0;
+
+ if (size < 5)
+ return FALSE;
+
+ code = GST_READ_UINT32_BE (data);
+ GST_DEBUG_OBJECT (enc, "start code 0x%08x", code);
+
+ switch (code) {
+ case VOS_STARTCODE:
+ case 0x00000101:
+ {
+ gint i;
+ guint8 profile;
+ gboolean newprofile = FALSE;
+ gboolean equal;
+
+ if (code == VOS_STARTCODE) {
+ /* profile_and_level_indication */
+ profile = data[4];
+
+ GST_DEBUG_OBJECT (enc, "VOS profile 0x%08x", profile);
+
+ if (profile != enc->profile) {
+ newprofile = TRUE;
+ enc->profile = profile;
+ }
+ }
+
+ /* up to the next GOP_STARTCODE or VOP_STARTCODE is
+ * the config information */
+ code = 0xffffffff;
+ for (i = 5; i < size - 4; i++) {
+ code = (code << 8) | data[i];
+ if (code == GOP_STARTCODE || code == VOP_STARTCODE)
+ break;
+ }
+ i -= 3;
+ /* see if config changed */
+ equal = FALSE;
+ if (enc->config) {
+ if (gst_buffer_get_size (enc->config) == i) {
+ equal = gst_buffer_memcmp (enc->config, 0, data, i) == 0;
+ }
+ }
+ /* if config string changed or new profile, make new caps */
+ if (!equal || newprofile) {
+ if (enc->config)
+ gst_buffer_unref (enc->config);
+ enc->config = gst_buffer_new_and_alloc (i);
+
+ gst_buffer_fill (enc->config, 0, data, i);
+
+ gst_rtp_mp4v_pay_new_caps (enc);
+ }
+ *strip = i;
+ /* we need to flush out the current packet. */
+ result = TRUE;
+ break;
+ }
+ case VOP_STARTCODE:
+ GST_DEBUG_OBJECT (enc, "VOP");
+ /* VOP startcode, we don't have to flush the packet */
+ result = FALSE;
+ /* vop-coding-type == I-frame */
+ if (size > 4 && (data[4] >> 6 == 0)) {
+ GST_DEBUG_OBJECT (enc, "VOP-I");
+ *vopi = TRUE;
+ }
+ break;
+ case GOP_STARTCODE:
+ GST_DEBUG_OBJECT (enc, "GOP");
+ *vopi = TRUE;
+ result = TRUE;
+ break;
+ case 0x00000100:
+ enc->need_config = FALSE;
+ result = TRUE;
+ break;
+ default:
+ if (code >= 0x20 && code <= 0x2f) {
+ GST_DEBUG_OBJECT (enc, "short header");
+ result = FALSE;
+ } else {
+ GST_DEBUG_OBJECT (enc, "other startcode");
+ /* all other startcodes need a flush */
+ result = TRUE;
+ }
+ break;
+ }
+ return result;
+}
+
+/* we expect buffers starting on startcodes.
+ */
+static GstFlowReturn
+gst_rtp_mp4v_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer)
+{
+ GstRtpMP4VPay *rtpmp4vpay;
+ GstFlowReturn ret;
+ guint avail;
+ guint packet_len;
+ GstMapInfo map;
+ gsize size;
+ gboolean flush;
+ gint strip;
+ GstClockTime timestamp, duration;
+ gboolean vopi;
+ gboolean send_config;
+
+ ret = GST_FLOW_OK;
+ send_config = FALSE;
+
+ rtpmp4vpay = GST_RTP_MP4V_PAY (basepayload);
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+ size = map.size;
+ timestamp = GST_BUFFER_TIMESTAMP (buffer);
+ duration = GST_BUFFER_DURATION (buffer);
+ avail = gst_adapter_available (rtpmp4vpay->adapter);
+
+ if (duration == -1)
+ duration = 0;
+
+ /* empty buffer, take timestamp */
+ if (avail == 0) {
+ rtpmp4vpay->first_timestamp = timestamp;
+ rtpmp4vpay->duration = 0;
+ }
+
+ /* depay incomming data and see if we need to start a new RTP
+ * packet */
+ flush =
+ gst_rtp_mp4v_pay_depay_data (rtpmp4vpay, map.data, size, &strip, &vopi);
+ gst_buffer_unmap (buffer, &map);
+
+ if (strip) {
+ /* strip off config if requested */
+ if (!(rtpmp4vpay->config_interval > 0)) {
+ GstBuffer *subbuf;
+
+ GST_LOG_OBJECT (rtpmp4vpay, "stripping config at %d, size %d", strip,
+ (gint) size - strip);
+
+ /* strip off header */
+ subbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY, strip,
+ size - strip);
+ GST_BUFFER_TIMESTAMP (subbuf) = timestamp;
+ gst_buffer_unref (buffer);
+ buffer = subbuf;
+
+ size = gst_buffer_get_size (buffer);
+ } else {
+ GST_LOG_OBJECT (rtpmp4vpay, "found config in stream");
+ rtpmp4vpay->last_config = timestamp;
+ }
+ }
+
+ /* there is a config request, see if we need to insert it */
+ if (vopi && (rtpmp4vpay->config_interval > 0) && rtpmp4vpay->config) {
+ if (rtpmp4vpay->last_config != -1) {
+ guint64 diff;
+
+ GST_LOG_OBJECT (rtpmp4vpay,
+ "now %" GST_TIME_FORMAT ", last VOP-I %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (timestamp), GST_TIME_ARGS (rtpmp4vpay->last_config));
+
+ /* calculate diff between last config in milliseconds */
+ if (timestamp > rtpmp4vpay->last_config) {
+ diff = timestamp - rtpmp4vpay->last_config;
+ } else {
+ diff = 0;
+ }
+
+ GST_DEBUG_OBJECT (rtpmp4vpay,
+ "interval since last config %" GST_TIME_FORMAT, GST_TIME_ARGS (diff));
+
+ /* bigger than interval, queue config */
+ /* FIXME should convert timestamps to running time */
+ if (GST_TIME_AS_SECONDS (diff) >= rtpmp4vpay->config_interval) {
+ GST_DEBUG_OBJECT (rtpmp4vpay, "time to send config");
+ send_config = TRUE;
+ }
+ } else {
+ /* no known previous config time, send now */
+ GST_DEBUG_OBJECT (rtpmp4vpay, "no previous config time, send now");
+ send_config = TRUE;
+ }
+
+ if (send_config) {
+ /* we need to send config now first */
+ GST_LOG_OBJECT (rtpmp4vpay, "inserting config in stream");
+
+ /* insert header */
+ buffer = gst_buffer_append (gst_buffer_ref (rtpmp4vpay->config), buffer);
+
+ GST_BUFFER_TIMESTAMP (buffer) = timestamp;
+ size = gst_buffer_get_size (buffer);
+
+ if (timestamp != -1) {
+ rtpmp4vpay->last_config = timestamp;
+ }
+ }
+ }
+
+ /* if we need to flush, do so now */
+ if (flush) {
+ ret = gst_rtp_mp4v_pay_flush (rtpmp4vpay);
+ rtpmp4vpay->first_timestamp = timestamp;
+ rtpmp4vpay->duration = 0;
+ avail = 0;
+ }
+
+ /* get packet length of data and see if we exceeded MTU. */
+ packet_len = gst_rtp_buffer_calc_packet_len (avail + size, 0, 0);
+
+ if (gst_rtp_base_payload_is_filled (basepayload,
+ packet_len, rtpmp4vpay->duration + duration)) {
+ ret = gst_rtp_mp4v_pay_flush (rtpmp4vpay);
+ rtpmp4vpay->first_timestamp = timestamp;
+ rtpmp4vpay->duration = 0;
+ }
+
+ /* push new data */
+ gst_adapter_push (rtpmp4vpay->adapter, buffer);
+
+ rtpmp4vpay->duration += duration;
+
+ return ret;
+}
+
+static gboolean
+gst_rtp_mp4v_pay_sink_event (GstRTPBasePayload * pay, GstEvent * event)
+{
+ GstRtpMP4VPay *rtpmp4vpay;
+
+ rtpmp4vpay = GST_RTP_MP4V_PAY (pay);
+
+ GST_DEBUG ("Got event: %s", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEGMENT:
+ case GST_EVENT_EOS:
+ /* This flush call makes sure that the last buffer is always pushed
+ * to the base payloader */
+ gst_rtp_mp4v_pay_flush (rtpmp4vpay);
+ break;
+ case GST_EVENT_FLUSH_STOP:
+ gst_rtp_mp4v_pay_empty (rtpmp4vpay);
+ break;
+ default:
+ break;
+ }
+
+ /* let parent handle event too */
+ return GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (pay, event);
+}
+
+static void
+gst_rtp_mp4v_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstRtpMP4VPay *rtpmp4vpay;
+
+ rtpmp4vpay = GST_RTP_MP4V_PAY (object);
+
+ switch (prop_id) {
+ case PROP_CONFIG_INTERVAL:
+ rtpmp4vpay->config_interval = g_value_get_uint (value);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gst_rtp_mp4v_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstRtpMP4VPay *rtpmp4vpay;
+
+ rtpmp4vpay = GST_RTP_MP4V_PAY (object);
+
+ switch (prop_id) {
+ case PROP_CONFIG_INTERVAL:
+ g_value_set_uint (value, rtpmp4vpay->config_interval);
+ break;
+ default:
+ break;
+ }
+}
+
+gboolean
+gst_rtp_mp4v_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpmp4vpay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_MP4V_PAY);
+}
diff --git a/gst/rtp/gstrtpmp4vpay.h b/gst/rtp/gstrtpmp4vpay.h
new file mode 100755
index 0000000..a974a91
--- /dev/null
+++ b/gst/rtp/gstrtpmp4vpay.h
@@ -0,0 +1,74 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MP4V_PAY_H__
+#define __GST_RTP_MP4V_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MP4V_PAY \
+ (gst_rtp_mp4v_pay_get_type())
+#define GST_RTP_MP4V_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MP4V_PAY,GstRtpMP4VPay))
+#define GST_RTP_MP4V_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MP4V_PAY,GstRtpMP4VPayClass))
+#define GST_IS_RTP_MP4V_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MP4V_PAY))
+#define GST_IS_RTP_MP4V_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MP4V_PAY))
+
+typedef struct _GstRtpMP4VPay GstRtpMP4VPay;
+typedef struct _GstRtpMP4VPayClass GstRtpMP4VPayClass;
+
+struct _GstRtpMP4VPay
+{
+ GstRTPBasePayload payload;
+
+ GstAdapter *adapter;
+ GstClockTime first_timestamp;
+ GstClockTime duration;
+
+ gint rate;
+ gint profile;
+ GstBuffer *config;
+ gboolean send_config;
+ gboolean need_config;
+
+ /* naming might be confusing with send_config; but naming matches h264
+ * payloader */
+ guint config_interval;
+ GstClockTime last_config;
+};
+
+struct _GstRtpMP4VPayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_mp4v_pay_get_type (void);
+
+gboolean gst_rtp_mp4v_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MP4V_PAY_H__ */
diff --git a/gst/rtp/gstrtpmpadepay.c b/gst/rtp/gstrtpmpadepay.c
new file mode 100755
index 0000000..b77ac06
--- /dev/null
+++ b/gst/rtp/gstrtpmpadepay.c
@@ -0,0 +1,181 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <string.h>
+#include "gstrtpmpadepay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmpadepay_debug);
+#define GST_CAT_DEFAULT (rtpmpadepay_debug)
+
+static GstStaticPadTemplate gst_rtp_mpa_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/mpeg, " "mpegversion = (int) 1")
+ );
+
+static GstStaticPadTemplate gst_rtp_mpa_depay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_MPA_STRING ", "
+ "clock-rate = (int) 90000 ;"
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "encoding-name = (string) \"MPA\", clock-rate = (int) [1, MAX]")
+ );
+
+#define gst_rtp_mpa_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpMPADepay, gst_rtp_mpa_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_mpa_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_mpa_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+
+static void
+gst_rtp_mpa_depay_class_init (GstRtpMPADepayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ GST_DEBUG_CATEGORY_INIT (rtpmpadepay_debug, "rtpmpadepay", 0,
+ "MPEG Audio RTP Depayloader");
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mpa_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mpa_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP MPEG audio depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts MPEG audio from RTP packets (RFC 2038)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ gstrtpbasedepayload_class->set_caps = gst_rtp_mpa_depay_setcaps;
+ gstrtpbasedepayload_class->process = gst_rtp_mpa_depay_process;
+}
+
+static void
+gst_rtp_mpa_depay_init (GstRtpMPADepay * rtpmpadepay)
+{
+}
+
+static gboolean
+gst_rtp_mpa_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstStructure *structure;
+ GstCaps *outcaps;
+ gint clock_rate;
+ gboolean res;
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 90000;
+ depayload->clock_rate = clock_rate;
+
+ outcaps =
+ gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 1, NULL);
+ res = gst_pad_set_caps (depayload->srcpad, outcaps);
+ gst_caps_unref (outcaps);
+
+ return res;
+}
+
+static GstBuffer *
+gst_rtp_mpa_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpMPADepay *rtpmpadepay;
+ GstBuffer *outbuf;
+ GstRTPBuffer rtp = { NULL };
+ gint payload_len;
+#if 0
+ guint8 *payload;
+ guint16 frag_offset;
+#endif
+ gboolean marker;
+
+ rtpmpadepay = GST_RTP_MPA_DEPAY (depayload);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+
+ if (payload_len <= 4)
+ goto empty_packet;
+
+#if 0
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ /* strip off header
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | MBZ | Frag_offset |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ frag_offset = (payload[2] << 8) | payload[3];
+#endif
+
+ /* subbuffer skipping the 4 header bytes */
+ outbuf = gst_rtp_buffer_get_payload_subbuffer (&rtp, 4, -1);
+ marker = gst_rtp_buffer_get_marker (&rtp);
+
+ if (marker) {
+ /* mark start of talkspurt with RESYNC */
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+ }
+ GST_DEBUG_OBJECT (rtpmpadepay,
+ "gst_rtp_mpa_depay_chain: pushing buffer of size %" G_GSIZE_FORMAT "",
+ gst_buffer_get_size (outbuf));
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ /* FIXME, we can push half mpeg frames when they are split over multiple
+ * RTP packets */
+ return outbuf;
+
+ /* ERRORS */
+empty_packet:
+ {
+ GST_ELEMENT_WARNING (rtpmpadepay, STREAM, DECODE,
+ ("Empty Payload."), (NULL));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+}
+
+gboolean
+gst_rtp_mpa_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpmpadepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_MPA_DEPAY);
+}
diff --git a/gst/rtp/gstrtpmpadepay.h b/gst/rtp/gstrtpmpadepay.h
new file mode 100755
index 0000000..1070d77
--- /dev/null
+++ b/gst/rtp/gstrtpmpadepay.h
@@ -0,0 +1,58 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MPA_DEPAY_H__
+#define __GST_RTP_MPA_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MPA_DEPAY \
+ (gst_rtp_mpa_depay_get_type())
+#define GST_RTP_MPA_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MPA_DEPAY,GstRtpMPADepay))
+#define GST_RTP_MPA_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MPA_DEPAY,GstRtpMPADepayClass))
+#define GST_IS_RTP_MPA_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MPA_DEPAY))
+#define GST_IS_RTP_MPA_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MPA_DEPAY))
+
+typedef struct _GstRtpMPADepay GstRtpMPADepay;
+typedef struct _GstRtpMPADepayClass GstRtpMPADepayClass;
+
+struct _GstRtpMPADepay
+{
+ GstRTPBaseDepayload depayload;
+};
+
+struct _GstRtpMPADepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_mpa_depay_get_type (void);
+
+gboolean gst_rtp_mpa_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MPA_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpmpapay.c b/gst/rtp/gstrtpmpapay.c
new file mode 100755
index 0000000..2a7061c
--- /dev/null
+++ b/gst/rtp/gstrtpmpapay.c
@@ -0,0 +1,329 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpmpapay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmpapay_debug);
+#define GST_CAT_DEFAULT (rtpmpapay_debug)
+
+static GstStaticPadTemplate gst_rtp_mpa_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/mpeg, " "mpegversion = (int) 1")
+ );
+
+static GstStaticPadTemplate gst_rtp_mpa_pay_src_template =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_MPA_STRING ", "
+ "clock-rate = (int) 90000; "
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) 90000, " "encoding-name = (string) \"MPA\"")
+ );
+
+static void gst_rtp_mpa_pay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_mpa_pay_change_state (GstElement * element,
+ GstStateChange transition);
+
+static gboolean gst_rtp_mpa_pay_setcaps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+static gboolean gst_rtp_mpa_pay_sink_event (GstRTPBasePayload * payload,
+ GstEvent * event);
+static GstFlowReturn gst_rtp_mpa_pay_flush (GstRtpMPAPay * rtpmpapay);
+static GstFlowReturn gst_rtp_mpa_pay_handle_buffer (GstRTPBasePayload * payload,
+ GstBuffer * buffer);
+
+#define gst_rtp_mpa_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpMPAPay, gst_rtp_mpa_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_mpa_pay_class_init (GstRtpMPAPayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ GST_DEBUG_CATEGORY_INIT (rtpmpapay_debug, "rtpmpapay", 0,
+ "MPEG Audio RTP Depayloader");
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_mpa_pay_finalize;
+
+ gstelement_class->change_state = gst_rtp_mpa_pay_change_state;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mpa_pay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mpa_pay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP MPEG audio payloader", "Codec/Payloader/Network/RTP",
+ "Payload MPEG audio as RTP packets (RFC 2038)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_mpa_pay_setcaps;
+ gstrtpbasepayload_class->sink_event = gst_rtp_mpa_pay_sink_event;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_mpa_pay_handle_buffer;
+}
+
+static void
+gst_rtp_mpa_pay_init (GstRtpMPAPay * rtpmpapay)
+{
+ rtpmpapay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_mpa_pay_finalize (GObject * object)
+{
+ GstRtpMPAPay *rtpmpapay;
+
+ rtpmpapay = GST_RTP_MPA_PAY (object);
+
+ g_object_unref (rtpmpapay->adapter);
+ rtpmpapay->adapter = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_rtp_mpa_pay_reset (GstRtpMPAPay * pay)
+{
+ pay->first_ts = -1;
+ pay->duration = 0;
+ gst_adapter_clear (pay->adapter);
+ GST_DEBUG_OBJECT (pay, "reset depayloader");
+}
+
+static gboolean
+gst_rtp_mpa_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ gboolean res;
+
+ gst_rtp_base_payload_set_options (payload, "audio", TRUE, "MPA", 90000);
+ res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+
+ return res;
+}
+
+static gboolean
+gst_rtp_mpa_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+ gboolean ret;
+ GstRtpMPAPay *rtpmpapay;
+
+ rtpmpapay = GST_RTP_MPA_PAY (payload);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_EOS:
+ /* make sure we push the last packets in the adapter on EOS */
+ gst_rtp_mpa_pay_flush (rtpmpapay);
+ break;
+ case GST_EVENT_FLUSH_STOP:
+ gst_rtp_mpa_pay_reset (rtpmpapay);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_rtp_mpa_pay_flush (GstRtpMPAPay * rtpmpapay)
+{
+ guint avail;
+ GstBuffer *outbuf;
+ GstFlowReturn ret;
+ guint16 frag_offset;
+
+ /* the data available in the adapter is either smaller
+ * than the MTU or bigger. In the case it is smaller, the complete
+ * adapter contents can be put in one packet. In the case the
+ * adapter has more than one MTU, we need to split the MPA data
+ * over multiple packets. The frag_offset in each packet header
+ * needs to be updated with the position in the MPA frame. */
+ avail = gst_adapter_available (rtpmpapay->adapter);
+
+ ret = GST_FLOW_OK;
+
+ frag_offset = 0;
+ while (avail > 0) {
+ guint towrite;
+ guint8 *payload;
+ guint payload_len;
+ guint packet_len;
+ GstRTPBuffer rtp = { NULL };
+ GstBuffer *paybuf;
+
+ /* this will be the total length of the packet */
+ packet_len = gst_rtp_buffer_calc_packet_len (4 + avail, 0, 0);
+
+ /* fill one MTU or all available bytes */
+ towrite = MIN (packet_len, GST_RTP_BASE_PAYLOAD_MTU (rtpmpapay));
+
+ /* this is the payload length */
+ payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
+
+ /* create buffer to hold the payload */
+ outbuf = gst_rtp_buffer_new_allocate (4, 0, 0);
+
+ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+ payload_len -= 4;
+
+ gst_rtp_buffer_set_payload_type (&rtp, GST_RTP_PAYLOAD_MPA);
+
+ /*
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | MBZ | Frag_offset |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ payload[0] = 0;
+ payload[1] = 0;
+ payload[2] = frag_offset >> 8;
+ payload[3] = frag_offset & 0xff;
+
+ avail -= payload_len;
+ frag_offset += payload_len;
+
+ if (avail == 0)
+ gst_rtp_buffer_set_marker (&rtp, TRUE);
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ paybuf = gst_adapter_take_buffer_fast (rtpmpapay->adapter, payload_len);
+ outbuf = gst_buffer_append (outbuf, paybuf);
+
+ GST_BUFFER_TIMESTAMP (outbuf) = rtpmpapay->first_ts;
+ GST_BUFFER_DURATION (outbuf) = rtpmpapay->duration;
+
+ ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpmpapay), outbuf);
+ }
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_rtp_mpa_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer)
+{
+ GstRtpMPAPay *rtpmpapay;
+ GstFlowReturn ret;
+ guint size, avail;
+ guint packet_len;
+ GstClockTime duration, timestamp;
+
+ rtpmpapay = GST_RTP_MPA_PAY (basepayload);
+
+ size = gst_buffer_get_size (buffer);
+ duration = GST_BUFFER_DURATION (buffer);
+ timestamp = GST_BUFFER_TIMESTAMP (buffer);
+
+ if (GST_BUFFER_IS_DISCONT (buffer)) {
+ GST_DEBUG_OBJECT (rtpmpapay, "DISCONT");
+ gst_rtp_mpa_pay_reset (rtpmpapay);
+ }
+
+ avail = gst_adapter_available (rtpmpapay->adapter);
+
+ /* get packet length of previous data and this new data,
+ * payload length includes a 4 byte header */
+ packet_len = gst_rtp_buffer_calc_packet_len (4 + avail + size, 0, 0);
+
+ /* if this buffer is going to overflow the packet, flush what we
+ * have. */
+ if (gst_rtp_base_payload_is_filled (basepayload,
+ packet_len, rtpmpapay->duration + duration)) {
+ ret = gst_rtp_mpa_pay_flush (rtpmpapay);
+ avail = 0;
+ } else {
+ ret = GST_FLOW_OK;
+ }
+
+ if (avail == 0) {
+ GST_DEBUG_OBJECT (rtpmpapay,
+ "first packet, save timestamp %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (timestamp));
+ rtpmpapay->first_ts = timestamp;
+ rtpmpapay->duration = 0;
+ }
+
+ gst_adapter_push (rtpmpapay->adapter, buffer);
+ rtpmpapay->duration = duration;
+
+ return ret;
+}
+
+static GstStateChangeReturn
+gst_rtp_mpa_pay_change_state (GstElement * element, GstStateChange transition)
+{
+ GstRtpMPAPay *rtpmpapay;
+ GstStateChangeReturn ret;
+
+ rtpmpapay = GST_RTP_MPA_PAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_rtp_mpa_pay_reset (rtpmpapay);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_rtp_mpa_pay_reset (rtpmpapay);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+gboolean
+gst_rtp_mpa_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpmpapay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_MPA_PAY);
+}
diff --git a/gst/rtp/gstrtpmpapay.h b/gst/rtp/gstrtpmpapay.h
new file mode 100755
index 0000000..db29852
--- /dev/null
+++ b/gst/rtp/gstrtpmpapay.h
@@ -0,0 +1,63 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MPA_PAY_H__
+#define __GST_RTP_MPA_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MPA_PAY \
+ (gst_rtp_mpa_pay_get_type())
+#define GST_RTP_MPA_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MPA_PAY,GstRtpMPAPay))
+#define GST_RTP_MPA_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MPA_PAY,GstRtpMPAPayClass))
+#define GST_IS_RTP_MPA_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MPA_PAY))
+#define GST_IS_RTP_MPA_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MPA_PAY))
+
+typedef struct _GstRtpMPAPay GstRtpMPAPay;
+typedef struct _GstRtpMPAPayClass GstRtpMPAPayClass;
+
+struct _GstRtpMPAPay
+{
+ GstRTPBasePayload payload;
+
+ GstAdapter *adapter;
+ GstClockTime first_ts;
+ GstClockTime duration;
+};
+
+struct _GstRtpMPAPayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_mpa_pay_get_type (void);
+
+gboolean gst_rtp_mpa_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MPA_PAY_H__ */
diff --git a/gst/rtp/gstrtpmparobustdepay.c b/gst/rtp/gstrtpmparobustdepay.c
new file mode 100755
index 0000000..afdd2ba
--- /dev/null
+++ b/gst/rtp/gstrtpmparobustdepay.c
@@ -0,0 +1,814 @@
+/* GStreamer
+ * Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+ * Copyright (C) <2010> Nokia Corporation
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <stdio.h>
+#include <string.h>
+#include "gstrtpmparobustdepay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmparobustdepay_debug);
+#define GST_CAT_DEFAULT (rtpmparobustdepay_debug)
+
+static GstStaticPadTemplate gst_rtp_mpa_robust_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/mpeg, " "mpegversion = (int) 1")
+ );
+
+static GstStaticPadTemplate gst_rtp_mpa_robust_depay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "clock-rate = (int) 90000, "
+ "encoding-name = (string) \"MPA-ROBUST\" " "; "
+ /* draft versions appear still in use out there */
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "clock-rate = (int) [1, MAX], "
+ "encoding-name = (string) { \"X-MP3-DRAFT-00\", \"X-MP3-DRAFT-01\", "
+ " \"X-MP3-DRAFT-02\", \"X-MP3-DRAFT-03\", \"X-MP3-DRAFT-04\", "
+ " \"X-MP3-DRAFT-05\", \"X-MP3-DRAFT-06\" }")
+ );
+
+typedef struct _GstADUFrame
+{
+ guint32 header;
+ gint size;
+ gint side_info;
+ gint data_size;
+ gint layer;
+ gint backpointer;
+
+ GstBuffer *buffer;
+} GstADUFrame;
+
+#define gst_rtp_mpa_robust_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpMPARobustDepay, gst_rtp_mpa_robust_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static GstStateChangeReturn gst_rtp_mpa_robust_change_state (GstElement *
+ element, GstStateChange transition);
+
+static gboolean gst_rtp_mpa_robust_depay_setcaps (GstRTPBaseDepayload *
+ depayload, GstCaps * caps);
+static GstBuffer *gst_rtp_mpa_robust_depay_process (GstRTPBaseDepayload *
+ depayload, GstBuffer * buf);
+
+static void
+gst_rtp_mpa_robust_depay_finalize (GObject * object)
+{
+ GstRtpMPARobustDepay *rtpmpadepay;
+
+ rtpmpadepay = (GstRtpMPARobustDepay *) object;
+
+ g_object_unref (rtpmpadepay->adapter);
+ g_queue_free (rtpmpadepay->adu_frames);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_rtp_mpa_robust_depay_class_init (GstRtpMPARobustDepayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ GST_DEBUG_CATEGORY_INIT (rtpmparobustdepay_debug, "rtpmparobustdepay", 0,
+ "Robust MPEG Audio RTP Depayloader");
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_mpa_robust_depay_finalize;
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_rtp_mpa_robust_change_state);
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mpa_robust_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mpa_robust_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP MPEG audio depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts MPEG audio from RTP packets (RFC 5219)",
+ "Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>");
+
+ gstrtpbasedepayload_class->set_caps = gst_rtp_mpa_robust_depay_setcaps;
+ gstrtpbasedepayload_class->process = gst_rtp_mpa_robust_depay_process;
+}
+
+static void
+gst_rtp_mpa_robust_depay_init (GstRtpMPARobustDepay * rtpmpadepay)
+{
+ rtpmpadepay->adapter = gst_adapter_new ();
+ rtpmpadepay->adu_frames = g_queue_new ();
+}
+
+static gboolean
+gst_rtp_mpa_robust_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps)
+{
+ GstRtpMPARobustDepay *rtpmpadepay;
+ GstStructure *structure;
+ GstCaps *outcaps;
+ gint clock_rate, draft;
+ gboolean res;
+ const gchar *encoding;
+
+ rtpmpadepay = GST_RTP_MPA_ROBUST_DEPAY (depayload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 90000;
+ depayload->clock_rate = clock_rate;
+
+ rtpmpadepay->has_descriptor = TRUE;
+ if ((encoding = gst_structure_get_string (structure, "encoding-name"))) {
+ if (sscanf (encoding, "X-MP3-DRAFT-%d", &draft) && (draft == 0))
+ rtpmpadepay->has_descriptor = FALSE;
+ }
+
+ outcaps =
+ gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 1, NULL);
+ res = gst_pad_set_caps (depayload->srcpad, outcaps);
+ gst_caps_unref (outcaps);
+
+ return res;
+}
+
+/* thanks again go to mp3parse ... */
+
+static const guint mp3types_bitrates[2][3][16] = {
+ {
+ {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448,},
+ {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384,},
+ {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320,}
+ },
+ {
+ {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256,},
+ {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,},
+ {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,}
+ },
+};
+
+static const guint mp3types_freqs[3][3] = { {44100, 48000, 32000},
+{22050, 24000, 16000},
+{11025, 12000, 8000}
+};
+
+static inline guint
+mp3_type_frame_length_from_header (GstElement * mp3parse, guint32 header,
+ guint * put_version, guint * put_layer, guint * put_channels,
+ guint * put_bitrate, guint * put_samplerate, guint * put_mode,
+ guint * put_crc)
+{
+ guint length;
+ gulong mode, samplerate, bitrate, layer, channels, padding, crc;
+ gulong version;
+ gint lsf, mpg25;
+
+ if (header & (1 << 20)) {
+ lsf = (header & (1 << 19)) ? 0 : 1;
+ mpg25 = 0;
+ } else {
+ lsf = 1;
+ mpg25 = 1;
+ }
+
+ version = 1 + lsf + mpg25;
+
+ layer = 4 - ((header >> 17) & 0x3);
+
+ crc = (header >> 16) & 0x1;
+
+ bitrate = (header >> 12) & 0xF;
+ bitrate = mp3types_bitrates[lsf][layer - 1][bitrate] * 1000;
+ /* The caller has ensured we have a valid header, so bitrate can't be
+ zero here. */
+ if (bitrate == 0) {
+ GST_DEBUG_OBJECT (mp3parse, "invalid bitrate");
+ return 0;
+ }
+
+ samplerate = (header >> 10) & 0x3;
+ samplerate = mp3types_freqs[lsf + mpg25][samplerate];
+
+ padding = (header >> 9) & 0x1;
+
+ mode = (header >> 6) & 0x3;
+ channels = (mode == 3) ? 1 : 2;
+
+ switch (layer) {
+ case 1:
+ length = 4 * ((bitrate * 12) / samplerate + padding);
+ break;
+ case 2:
+ length = (bitrate * 144) / samplerate + padding;
+ break;
+ default:
+ case 3:
+ length = (bitrate * 144) / (samplerate << lsf) + padding;
+ break;
+ }
+
+ GST_LOG_OBJECT (mp3parse, "Calculated mp3 frame length of %u bytes", length);
+ GST_LOG_OBJECT (mp3parse, "samplerate = %lu, bitrate = %lu, version = %lu, "
+ "layer = %lu, channels = %lu, mode = %lu", samplerate, bitrate, version,
+ layer, channels, mode);
+
+ if (put_version)
+ *put_version = version;
+ if (put_layer)
+ *put_layer = layer;
+ if (put_channels)
+ *put_channels = channels;
+ if (put_bitrate)
+ *put_bitrate = bitrate;
+ if (put_samplerate)
+ *put_samplerate = samplerate;
+ if (put_mode)
+ *put_mode = mode;
+ if (put_crc)
+ *put_crc = crc;
+
+ GST_LOG_OBJECT (mp3parse, "size = %u", length);
+ return length;
+}
+
+/* generate empty/silent/dummy frame that mimics @frame,
+ * except for rate, where maximum possible is selected */
+static GstADUFrame *
+gst_rtp_mpa_robust_depay_generate_dummy_frame (GstRtpMPARobustDepay *
+ rtpmpadepay, GstADUFrame * frame)
+{
+ GstADUFrame *dummy;
+ GstMapInfo map;
+
+ dummy = g_slice_dup (GstADUFrame, frame);
+
+ /* go for maximum bitrate */
+ dummy->header = (frame->header & ~(0xf << 12)) | (0xe << 12);
+ dummy->size =
+ mp3_type_frame_length_from_header (GST_ELEMENT_CAST (rtpmpadepay),
+ dummy->header, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ dummy->data_size = dummy->size - 4 - dummy->side_info;
+ dummy->backpointer = 0;
+
+ dummy->buffer = gst_buffer_new_and_alloc (dummy->side_info + 4);
+
+ gst_buffer_map (dummy->buffer, &map, GST_MAP_WRITE);
+ memset (map.data, 0, map.size);
+ GST_WRITE_UINT32_BE (map.data, dummy->header);
+ gst_buffer_unmap (dummy->buffer, &map);
+
+ GST_BUFFER_TIMESTAMP (dummy->buffer) = GST_BUFFER_TIMESTAMP (frame->buffer);
+
+ return dummy;
+}
+
+/* validates and parses @buf, and queues for further transformation if valid,
+ * otherwise discards @buf
+ * Takes ownership of @buf. */
+static gboolean
+gst_rtp_mpa_robust_depay_queue_frame (GstRtpMPARobustDepay * rtpmpadepay,
+ GstBuffer * buf)
+{
+ GstADUFrame *frame = NULL;
+ guint version, layer, channels, size;
+ guint crc;
+ GstMapInfo map;
+
+ g_return_val_if_fail (buf != NULL, FALSE);
+
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+
+ if (map.size < 6)
+ goto corrupt_frame;
+
+ frame = g_slice_new0 (GstADUFrame);
+ frame->header = GST_READ_UINT32_BE (map.data);
+
+ size = mp3_type_frame_length_from_header (GST_ELEMENT_CAST (rtpmpadepay),
+ frame->header, &version, &layer, &channels, NULL, NULL, NULL, &crc);
+ if (!size)
+ goto corrupt_frame;
+
+ frame->size = size;
+ frame->layer = layer;
+ if (version == 1 && channels == 2)
+ frame->side_info = 32;
+ else if ((version == 1 && channels == 1) || (version >= 2 && channels == 2))
+ frame->side_info = 17;
+ else if (version >= 2 && channels == 1)
+ frame->side_info = 9;
+ else {
+ g_assert_not_reached ();
+ goto corrupt_frame;
+ }
+
+ /* backpointer */
+ if (layer == 3) {
+ frame->backpointer = GST_READ_UINT16_BE (map.data + 4);
+ frame->backpointer >>= 7;
+ GST_LOG_OBJECT (rtpmpadepay, "backpointer: %d", frame->backpointer);
+ }
+
+ if (!crc)
+ frame->side_info += 2;
+
+ GST_LOG_OBJECT (rtpmpadepay, "side info: %d", frame->side_info);
+ frame->data_size = frame->size - 4 - frame->side_info;
+
+ /* some size validation checks */
+ if (4 + frame->side_info > map.size)
+ goto corrupt_frame;
+
+ /* ADU data would then extend past MP3 frame,
+ * even using past byte reservoir */
+ if (-frame->backpointer + (gint) (map.size) > frame->size)
+ goto corrupt_frame;
+
+ gst_buffer_unmap (buf, &map);
+
+ /* ok, take buffer and queue */
+ frame->buffer = buf;
+ g_queue_push_tail (rtpmpadepay->adu_frames, frame);
+
+ return TRUE;
+
+ /* ERRORS */
+corrupt_frame:
+ {
+ GST_DEBUG_OBJECT (rtpmpadepay, "frame is corrupt");
+ gst_buffer_unmap (buf, &map);
+ gst_buffer_unref (buf);
+ if (frame)
+ g_slice_free (GstADUFrame, frame);
+ return FALSE;
+ }
+}
+
+static inline void
+gst_rtp_mpa_robust_depay_free_frame (GstADUFrame * frame)
+{
+ if (frame->buffer)
+ gst_buffer_unref (frame->buffer);
+ g_slice_free (GstADUFrame, frame);
+}
+
+static inline void
+gst_rtp_mpa_robust_depay_dequeue_frame (GstRtpMPARobustDepay * rtpmpadepay)
+{
+ GstADUFrame *head;
+
+ GST_LOG_OBJECT (rtpmpadepay, "dequeueing ADU frame");
+
+ if (rtpmpadepay->adu_frames->head == rtpmpadepay->cur_adu_frame)
+ rtpmpadepay->cur_adu_frame = NULL;
+
+ head = g_queue_pop_head (rtpmpadepay->adu_frames);
+ g_assert (head->buffer);
+ gst_rtp_mpa_robust_depay_free_frame (head);
+
+ return;
+}
+
+/* returns TRUE if at least one new ADU frame was enqueued for MP3 conversion.
+ * Takes ownership of @buf. */
+static gboolean
+gst_rtp_mpa_robust_depay_deinterleave (GstRtpMPARobustDepay * rtpmpadepay,
+ GstBuffer * buf)
+{
+ gboolean ret = FALSE;
+ GstMapInfo map;
+ guint val, iindex, icc;
+
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+ val = GST_READ_UINT16_BE (map.data) >> 5;
+ gst_buffer_unmap (buf, &map);
+
+ iindex = val >> 3;
+ icc = val & 0x7;
+
+ GST_LOG_OBJECT (rtpmpadepay, "sync: 0x%x, index: %u, cycle count: %u",
+ val, iindex, icc);
+
+ /* basic case; no interleaving ever seen */
+ if (val == 0x7ff && rtpmpadepay->last_icc < 0) {
+ ret = gst_rtp_mpa_robust_depay_queue_frame (rtpmpadepay, buf);
+ } else {
+ if (G_UNLIKELY (rtpmpadepay->last_icc < 0)) {
+ rtpmpadepay->last_icc = icc;
+ rtpmpadepay->last_ii = iindex;
+ }
+ if (icc != rtpmpadepay->last_icc || iindex == rtpmpadepay->last_ii) {
+ gint i;
+
+ for (i = 0; i < 256; ++i) {
+ if (rtpmpadepay->deinter[i] != NULL) {
+ ret |= gst_rtp_mpa_robust_depay_queue_frame (rtpmpadepay,
+ rtpmpadepay->deinter[i]);
+ rtpmpadepay->deinter[i] = NULL;
+ }
+ }
+ }
+ /* rewrite buffer sync header */
+ gst_buffer_map (buf, &map, GST_MAP_READWRITE);
+ val = GST_READ_UINT16_BE (map.data);
+ val = (0x7ff << 5) | val;
+ GST_WRITE_UINT16_BE (map.data, val);
+ gst_buffer_unmap (buf, &map);
+ /* store and keep track of last indices */
+ rtpmpadepay->last_icc = icc;
+ rtpmpadepay->last_ii = iindex;
+ rtpmpadepay->deinter[iindex] = buf;
+ }
+
+ return ret;
+}
+
+/* Head ADU frame corresponds to mp3_frame (i.e. in header in side-info) that
+ * is currently being written
+ * cur_adu_frame refers to ADU frame whose data should be bytewritten next
+ * (possibly starting from offset rather than start 0) (and is typicall tail
+ * at time of last push round).
+ * If at start, position where it should start writing depends on (data) sizes
+ * of previous mp3 frames (corresponding to foregoing ADU frames) kept in size,
+ * and its backpointer */
+static GstFlowReturn
+gst_rtp_mpa_robust_depay_push_mp3_frames (GstRtpMPARobustDepay * rtpmpadepay)
+{
+ GstBuffer *buf;
+ GstADUFrame *frame, *head;
+ gint av;
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ while (1) {
+ GstMapInfo map;
+
+ if (G_UNLIKELY (!rtpmpadepay->cur_adu_frame)) {
+ rtpmpadepay->cur_adu_frame = rtpmpadepay->adu_frames->head;
+ rtpmpadepay->offset = 0;
+ rtpmpadepay->size = 0;
+ }
+
+ if (G_UNLIKELY (!rtpmpadepay->cur_adu_frame))
+ break;
+
+ frame = (GstADUFrame *) rtpmpadepay->cur_adu_frame->data;
+ head = (GstADUFrame *) rtpmpadepay->adu_frames->head->data;
+
+ /* special case: non-layer III are sent straight through */
+ if (G_UNLIKELY (frame->layer != 3)) {
+ GST_DEBUG_OBJECT (rtpmpadepay, "layer %d frame, sending as-is",
+ frame->layer);
+ gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpmpadepay),
+ frame->buffer);
+ frame->buffer = NULL;
+ /* and remove it from any further consideration */
+ g_slice_free (GstADUFrame, frame);
+ g_queue_delete_link (rtpmpadepay->adu_frames, rtpmpadepay->cur_adu_frame);
+ rtpmpadepay->cur_adu_frame = NULL;
+ continue;
+ }
+
+ if (rtpmpadepay->offset == gst_buffer_get_size (frame->buffer)) {
+ if (g_list_next (rtpmpadepay->cur_adu_frame)) {
+ rtpmpadepay->size += frame->data_size;
+ rtpmpadepay->cur_adu_frame = g_list_next (rtpmpadepay->cur_adu_frame);
+ frame = (GstADUFrame *) rtpmpadepay->cur_adu_frame->data;
+ rtpmpadepay->offset = 0;
+ GST_LOG_OBJECT (rtpmpadepay,
+ "moving to next ADU frame, size %d, side_info %d, backpointer %d",
+ frame->size, frame->side_info, frame->backpointer);
+ /* layer I and II packets have no bitreservoir and must be sent as-is;
+ * so flush any pending frame */
+ if (G_UNLIKELY (frame->layer != 3 && rtpmpadepay->mp3_frame))
+ goto flush;
+ } else {
+ break;
+ }
+ }
+
+ if (G_UNLIKELY (!rtpmpadepay->mp3_frame)) {
+ GST_LOG_OBJECT (rtpmpadepay,
+ "setting up new MP3 frame of size %d, side_info %d",
+ head->size, head->side_info);
+ rtpmpadepay->mp3_frame = gst_byte_writer_new_with_size (head->size, TRUE);
+ /* 0-fill possible gaps */
+ gst_byte_writer_fill_unchecked (rtpmpadepay->mp3_frame, 0, head->size);
+ gst_byte_writer_set_pos (rtpmpadepay->mp3_frame, 0);
+ /* bytewriter corresponds to head frame,
+ * i.e. the header and the side info must match */
+ g_assert (4 + head->side_info <= head->size);
+ gst_buffer_map (head->buffer, &map, GST_MAP_READ);
+ gst_byte_writer_put_data_unchecked (rtpmpadepay->mp3_frame,
+ map.data, 4 + head->side_info);
+ gst_buffer_unmap (head->buffer, &map);
+ }
+
+ buf = frame->buffer;
+ av = gst_byte_writer_get_remaining (rtpmpadepay->mp3_frame);
+ GST_LOG_OBJECT (rtpmpadepay, "current mp3 frame remaining: %d", av);
+ GST_LOG_OBJECT (rtpmpadepay, "accumulated ADU frame data_size: %d",
+ rtpmpadepay->size);
+
+ if (rtpmpadepay->offset) {
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+ /* no need to position, simply append */
+ g_assert (map.size > rtpmpadepay->offset);
+ av = MIN (av, map.size - rtpmpadepay->offset);
+ GST_LOG_OBJECT (rtpmpadepay,
+ "appending %d bytes from ADU frame at offset %d", av,
+ rtpmpadepay->offset);
+ gst_byte_writer_put_data_unchecked (rtpmpadepay->mp3_frame,
+ map.data + rtpmpadepay->offset, av);
+ rtpmpadepay->offset += av;
+ gst_buffer_unmap (buf, &map);
+ } else {
+ gint pos, tpos;
+
+ /* position writing according to ADU frame backpointer */
+ pos = gst_byte_writer_get_pos (rtpmpadepay->mp3_frame);
+ tpos = rtpmpadepay->size - frame->backpointer + 4 + head->side_info;
+ GST_LOG_OBJECT (rtpmpadepay, "current MP3 frame at position %d, "
+ "starting new ADU frame data at offset %d", pos, tpos);
+ if (tpos < pos) {
+ GstADUFrame *dummy;
+
+ /* try to insert as few frames as possible,
+ * so go for a reasonably large dummy frame size */
+ GST_LOG_OBJECT (rtpmpadepay,
+ "overlapping previous data; inserting dummy frame");
+ dummy =
+ gst_rtp_mpa_robust_depay_generate_dummy_frame (rtpmpadepay, frame);
+ g_queue_insert_before (rtpmpadepay->adu_frames,
+ rtpmpadepay->cur_adu_frame, dummy);
+ /* offset is known to be zero, so we can shift current one */
+ rtpmpadepay->cur_adu_frame = rtpmpadepay->cur_adu_frame->prev;
+ if (!rtpmpadepay->size) {
+ g_assert (rtpmpadepay->cur_adu_frame ==
+ rtpmpadepay->adu_frames->head);
+ GST_LOG_OBJECT (rtpmpadepay, "... which is new head frame");
+ gst_byte_writer_free (rtpmpadepay->mp3_frame);
+ rtpmpadepay->mp3_frame = NULL;
+ }
+ /* ... and continue adding that empty one immediately,
+ * and then see if that provided enough extra space */
+ continue;
+ } else if (tpos >= pos + av) {
+ /* ADU frame no longer needs current MP3 frame; move to its end */
+ GST_LOG_OBJECT (rtpmpadepay, "passed current MP3 frame");
+ gst_byte_writer_set_pos (rtpmpadepay->mp3_frame, pos + av);
+ } else {
+ /* position and append */
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+ GST_LOG_OBJECT (rtpmpadepay, "adding to current MP3 frame");
+ gst_byte_writer_set_pos (rtpmpadepay->mp3_frame, tpos);
+ av -= (tpos - pos);
+ g_assert (map.size >= 4 + frame->side_info);
+ av = MIN (av, map.size - 4 - frame->side_info);
+ gst_byte_writer_put_data_unchecked (rtpmpadepay->mp3_frame,
+ map.data + 4 + frame->side_info, av);
+ rtpmpadepay->offset += av + 4 + frame->side_info;
+ gst_buffer_unmap (buf, &map);
+ }
+ }
+
+ /* if mp3 frame filled, send on its way */
+ if (gst_byte_writer_get_remaining (rtpmpadepay->mp3_frame) == 0) {
+ flush:
+ buf = gst_byte_writer_free_and_get_buffer (rtpmpadepay->mp3_frame);
+ rtpmpadepay->mp3_frame = NULL;
+ GST_BUFFER_TIMESTAMP (buf) = GST_BUFFER_TIMESTAMP (head->buffer);
+ /* no longer need head ADU frame header and side info */
+ /* NOTE maybe head == current, then size and offset go off a bit,
+ * but current gets reset to NULL, and then also offset and size */
+ rtpmpadepay->size -= head->data_size;
+ gst_rtp_mpa_robust_depay_dequeue_frame (rtpmpadepay);
+ /* send */
+ ret = gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpmpadepay),
+ buf);
+ }
+ }
+
+ return ret;
+}
+
+/* process ADU frame @buf through:
+ * - deinterleaving
+ * - converting to MP3 frames
+ * Takes ownership of @buf.
+ */
+static GstFlowReturn
+gst_rtp_mpa_robust_depay_submit_adu (GstRtpMPARobustDepay * rtpmpadepay,
+ GstBuffer * buf)
+{
+ if (gst_rtp_mpa_robust_depay_deinterleave (rtpmpadepay, buf))
+ return gst_rtp_mpa_robust_depay_push_mp3_frames (rtpmpadepay);
+
+ return GST_FLOW_OK;
+}
+
+static GstBuffer *
+gst_rtp_mpa_robust_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf)
+{
+ GstRtpMPARobustDepay *rtpmpadepay;
+ gint payload_len, offset;
+ guint8 *payload;
+ gboolean cont, dtype;
+ guint av, size;
+ GstClockTime timestamp;
+ GstRTPBuffer rtp = { NULL };
+
+ rtpmpadepay = GST_RTP_MPA_ROBUST_DEPAY (depayload);
+
+ timestamp = GST_BUFFER_TIMESTAMP (buf);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+ if (payload_len <= 1)
+ goto short_read;
+
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ offset = 0;
+ GST_LOG_OBJECT (rtpmpadepay, "payload_len: %d", payload_len);
+
+ /* strip off descriptor
+ *
+ * 0 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |C|T| ADU size |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * C: if 1, data is continuation
+ * T: if 1, size is 14 bits, otherwise 6 bits
+ * ADU size: size of following packet (not including descriptor)
+ */
+ while (payload_len) {
+ if (G_LIKELY (rtpmpadepay->has_descriptor)) {
+ cont = ! !(payload[offset] & 0x80);
+ dtype = ! !(payload[offset] & 0x40);
+ if (dtype) {
+ size = (payload[offset] & 0x3f) << 8 | payload[offset + 1];
+ payload_len--;
+ offset++;
+ } else if (payload_len >= 2) {
+ size = (payload[offset] & 0x3f);
+ payload_len -= 2;
+ offset += 2;
+ } else {
+ goto short_read;
+ }
+ } else {
+ cont = FALSE;
+ dtype = -1;
+ size = payload_len;
+ }
+
+ GST_LOG_OBJECT (rtpmpadepay, "offset %d has cont: %d, dtype: %d, size: %d",
+ offset, cont, dtype, size);
+
+ buf = gst_rtp_buffer_get_payload_subbuffer (&rtp, offset,
+ MIN (size, payload_len));
+
+ if (cont) {
+ av = gst_adapter_available (rtpmpadepay->adapter);
+ if (G_UNLIKELY (!av)) {
+ GST_DEBUG_OBJECT (rtpmpadepay,
+ "discarding continuation fragment without prior fragment");
+ gst_buffer_unref (buf);
+ } else {
+ av += gst_buffer_get_size (buf);
+ gst_adapter_push (rtpmpadepay->adapter, buf);
+ if (av == size) {
+ timestamp = gst_adapter_prev_pts (rtpmpadepay->adapter, NULL);
+ buf = gst_adapter_take_buffer (rtpmpadepay->adapter, size);
+ GST_BUFFER_TIMESTAMP (buf) = timestamp;
+ gst_rtp_mpa_robust_depay_submit_adu (rtpmpadepay, buf);
+ } else if (av > size) {
+ GST_DEBUG_OBJECT (rtpmpadepay,
+ "assembled ADU size %d larger than expected %d; discarding",
+ av, size);
+ gst_adapter_clear (rtpmpadepay->adapter);
+ }
+ }
+ size = payload_len;
+ } else {
+ /* not continuation, first fragment or whole ADU */
+ if (payload_len == size) {
+ /* whole ADU */
+ GST_BUFFER_TIMESTAMP (buf) = timestamp;
+ gst_rtp_mpa_robust_depay_submit_adu (rtpmpadepay, buf);
+ } else if (payload_len < size) {
+ /* first fragment */
+ gst_adapter_push (rtpmpadepay->adapter, buf);
+ size = payload_len;
+ }
+ }
+
+ offset += size;
+ payload_len -= size;
+
+ /* timestamp applies to first payload, no idea for subsequent ones */
+ timestamp = GST_CLOCK_TIME_NONE;
+ }
+ gst_rtp_buffer_unmap (&rtp);
+
+ return NULL;
+
+ /* ERRORS */
+short_read:
+ {
+ GST_ELEMENT_WARNING (rtpmpadepay, STREAM, DECODE,
+ (NULL), ("Packet contains invalid data"));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+}
+
+static GstStateChangeReturn
+gst_rtp_mpa_robust_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstStateChangeReturn ret;
+ GstRtpMPARobustDepay *rtpmpadepay;
+
+ rtpmpadepay = GST_RTP_MPA_ROBUST_DEPAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ rtpmpadepay->last_ii = -1;
+ rtpmpadepay->last_icc = -1;
+ rtpmpadepay->size = 0;
+ rtpmpadepay->offset = 0;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ if (ret != GST_STATE_CHANGE_SUCCESS)
+ return ret;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ {
+ gint i;
+
+ gst_adapter_clear (rtpmpadepay->adapter);
+ for (i = 0; i < G_N_ELEMENTS (rtpmpadepay->deinter); i++) {
+ gst_buffer_replace (&rtpmpadepay->deinter[i], NULL);
+ }
+ rtpmpadepay->cur_adu_frame = NULL;
+ g_queue_foreach (rtpmpadepay->adu_frames,
+ (GFunc) gst_rtp_mpa_robust_depay_free_frame, NULL);
+ g_queue_clear (rtpmpadepay->adu_frames);
+ if (rtpmpadepay->mp3_frame)
+ gst_byte_writer_free (rtpmpadepay->mp3_frame);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+gboolean
+gst_rtp_mpa_robust_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpmparobustdepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_MPA_ROBUST_DEPAY);
+}
diff --git a/gst/rtp/gstrtpmparobustdepay.h b/gst/rtp/gstrtpmparobustdepay.h
new file mode 100755
index 0000000..fc9ec0b
--- /dev/null
+++ b/gst/rtp/gstrtpmparobustdepay.h
@@ -0,0 +1,78 @@
+/* GStreamer
+ * Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+ * Copyright (C) <2010> Nokia Corporation
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MPA_ROBUST_DEPAY_H__
+#define __GST_RTP_MPA_ROBUST_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+#include <gst/base/gstadapter.h>
+#include <gst/base/gstbytewriter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MPA_ROBUST_DEPAY \
+ (gst_rtp_mpa_robust_depay_get_type())
+#define GST_RTP_MPA_ROBUST_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MPA_ROBUST_DEPAY,GstRtpMPARobustDepay))
+#define GST_RTP_MPA_ROBUST_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MPA_ROBUST_DEPAY,GstRtpMPARobustDepayClass))
+#define GST_IS_RTP_MPA_ROBUST_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MPA_ROBUST_DEPAY))
+#define GST_IS_RTP_MPA_ROBUST_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MPA_ROBUST_DEPAY))
+
+typedef struct _GstRtpMPARobustDepay GstRtpMPARobustDepay;
+typedef struct _GstRtpMPARobustDepayClass GstRtpMPARobustDepayClass;
+
+struct _GstRtpMPARobustDepay
+{
+ GstRTPBaseDepayload depayload;
+
+ GstAdapter *adapter;
+ gboolean has_descriptor;
+
+ /* last interleave index */
+ gint last_ii;
+ /* last interleave cycle count */
+ gint last_icc;
+ /* buffers pending deinterleaving */
+ GstBuffer *deinter[256];
+
+ /* ADU buffers pending MP3 transformation */
+ GQueue *adu_frames;
+ GList *cur_adu_frame;
+ gint offset;
+ gint size;
+ GstByteWriter *mp3_frame;
+};
+
+struct _GstRtpMPARobustDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_mpa_robust_depay_get_type (void);
+
+gboolean gst_rtp_mpa_robust_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MPA_ROBUST_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpmpvdepay.c b/gst/rtp/gstrtpmpvdepay.c
new file mode 100755
index 0000000..7d8646c
--- /dev/null
+++ b/gst/rtp/gstrtpmpvdepay.c
@@ -0,0 +1,198 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <string.h>
+#include "gstrtpmpvdepay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmpvdepay_debug);
+#define GST_CAT_DEFAULT (rtpmpvdepay_debug)
+
+/* FIXME, we set the mpeg version to 2, we should ideally be looking at contents
+ * of the stream to figure out the version */
+static GstStaticPadTemplate gst_rtp_mpv_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS
+ ("video/mpeg, mpegversion = (int) 2, systemstream = (boolean) FALSE")
+ );
+
+static GstStaticPadTemplate gst_rtp_mpv_depay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"video\", "
+ "clock-rate = (int) 90000, " "encoding-name = (string) \"MPV\";"
+ "application/x-rtp, "
+ "media = (string) \"video\", "
+ "payload = (int) " GST_RTP_PAYLOAD_MPV_STRING ", "
+ "clock-rate = (int) 90000")
+ );
+
+G_DEFINE_TYPE (GstRtpMPVDepay, gst_rtp_mpv_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_mpv_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_mpv_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+
+static void
+gst_rtp_mpv_depay_class_init (GstRtpMPVDepayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mpv_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mpv_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP MPEG video depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts MPEG video from RTP packets (RFC 2250)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ gstrtpbasedepayload_class->set_caps = gst_rtp_mpv_depay_setcaps;
+ gstrtpbasedepayload_class->process = gst_rtp_mpv_depay_process;
+
+ GST_DEBUG_CATEGORY_INIT (rtpmpvdepay_debug, "rtpmpvdepay", 0,
+ "MPEG Video RTP Depayloader");
+}
+
+static void
+gst_rtp_mpv_depay_init (GstRtpMPVDepay * rtpmpvdepay)
+{
+}
+
+static gboolean
+gst_rtp_mpv_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstStructure *structure;
+ gint clock_rate;
+ GstCaps *outcaps;
+ gboolean res;
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 90000; /* default */
+ depayload->clock_rate = clock_rate;
+
+ outcaps = gst_caps_new_simple ("video/mpeg",
+ "mpegversion", G_TYPE_INT, 2,
+ "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+ res = gst_pad_set_caps (depayload->srcpad, outcaps);
+ gst_caps_unref (outcaps);
+
+ return res;
+}
+
+static GstBuffer *
+gst_rtp_mpv_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpMPVDepay *rtpmpvdepay;
+ GstBuffer *outbuf;
+ GstRTPBuffer rtp = { NULL };
+
+ rtpmpvdepay = GST_RTP_MPV_DEPAY (depayload);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ {
+ gint payload_len, payload_header;
+ guint8 *payload;
+ guint8 T;
+
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ payload_header = 0;
+
+ if (payload_len <= 4)
+ goto empty_packet;
+
+ /* 3.4 MPEG Video-specific header
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | MBZ |T| TR | |N|S|B|E| P | | BFC | | FFC |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * AN FBV FFV
+ */
+ T = (payload[0] & 0x04);
+
+ payload_len -= 4;
+ payload_header += 4;
+ payload += 4;
+
+ if (T) {
+ /*
+ * 3.4.1 MPEG-2 Video-specific header extension
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |X|E|f_[0,0]|f_[0,1]|f_[1,0]|f_[1,1]| DC| PS|T|P|C|Q|V|A|R|H|G|D|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ if (payload_len <= 4)
+ goto empty_packet;
+
+ payload_len -= 4;
+ payload_header += 4;
+ payload += 4;
+ }
+
+ outbuf = gst_rtp_buffer_get_payload_subbuffer (&rtp, payload_header, -1);
+
+ if (outbuf) {
+ GST_DEBUG_OBJECT (rtpmpvdepay,
+ "gst_rtp_mpv_depay_chain: pushing buffer of size %" G_GSIZE_FORMAT,
+ gst_buffer_get_size (outbuf));
+ }
+ return outbuf;
+ }
+
+ return NULL;
+
+ /* ERRORS */
+empty_packet:
+ {
+ GST_ELEMENT_WARNING (rtpmpvdepay, STREAM, DECODE,
+ (NULL), ("Empty payload."));
+ return NULL;
+ }
+}
+
+gboolean
+gst_rtp_mpv_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpmpvdepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_MPV_DEPAY);
+}
diff --git a/gst/rtp/gstrtpmpvdepay.h b/gst/rtp/gstrtpmpvdepay.h
new file mode 100755
index 0000000..80f6c43
--- /dev/null
+++ b/gst/rtp/gstrtpmpvdepay.h
@@ -0,0 +1,58 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_MPV_DEPAY_H__
+#define __GST_RTP_MPV_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_MPV_DEPAY \
+ (gst_rtp_mpv_depay_get_type())
+#define GST_RTP_MPV_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MPV_DEPAY,GstRtpMPVDepay))
+#define GST_RTP_MPV_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MPV_DEPAY,GstRtpMPVDepayClass))
+#define GST_IS_RTP_MPV_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MPV_DEPAY))
+#define GST_IS_RTP_MPV_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MPV_DEPAY))
+
+typedef struct _GstRtpMPVDepay GstRtpMPVDepay;
+typedef struct _GstRtpMPVDepayClass GstRtpMPVDepayClass;
+
+struct _GstRtpMPVDepay
+{
+ GstRTPBaseDepayload depayload;
+};
+
+struct _GstRtpMPVDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_mpv_depay_get_type (void);
+
+gboolean gst_rtp_mpv_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MPV_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpmpvpay.c b/gst/rtp/gstrtpmpvpay.c
new file mode 100755
index 0000000..0751bcd
--- /dev/null
+++ b/gst/rtp/gstrtpmpvpay.c
@@ -0,0 +1,313 @@
+/* GStreamer
+ * Copyright (C) <2007> Thijs Vermeir <thijsvermeir@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpmpvpay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpmpvpay_debug);
+#define GST_CAT_DEFAULT (rtpmpvpay_debug)
+
+static GstStaticPadTemplate gst_rtp_mpv_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/mpeg, "
+ "mpegversion = (int) 2, systemstream = (boolean) FALSE")
+ );
+
+static GstStaticPadTemplate gst_rtp_mpv_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"video\", "
+ "payload = (int) " GST_RTP_PAYLOAD_MPV_STRING ", "
+ "clock-rate = (int) 90000, " "encoding-name = (string) \"MPV\"")
+ );
+
+static GstStateChangeReturn gst_rtp_mpv_pay_change_state (GstElement * element,
+ GstStateChange transition);
+
+static void gst_rtp_mpv_pay_finalize (GObject * object);
+
+static GstFlowReturn gst_rtp_mpv_pay_flush (GstRTPMPVPay * rtpmpvpay);
+static gboolean gst_rtp_mpv_pay_setcaps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+static GstFlowReturn gst_rtp_mpv_pay_handle_buffer (GstRTPBasePayload *
+ payload, GstBuffer * buffer);
+static gboolean gst_rtp_mpv_pay_sink_event (GstRTPBasePayload * payload,
+ GstEvent * event);
+
+#define gst_rtp_mpv_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRTPMPVPay, gst_rtp_mpv_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_mpv_pay_class_init (GstRTPMPVPayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_mpv_pay_finalize;
+
+ gstelement_class->change_state = gst_rtp_mpv_pay_change_state;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mpv_pay_sink_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_mpv_pay_src_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP MPEG2 ES video payloader", "Codec/Payloader/Network/RTP",
+ "Payload-encodes MPEG2 ES into RTP packets (RFC 2250)",
+ "Thijs Vermeir <thijsvermeir@gmail.com>");
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_mpv_pay_setcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_mpv_pay_handle_buffer;
+ gstrtpbasepayload_class->sink_event = gst_rtp_mpv_pay_sink_event;
+
+ GST_DEBUG_CATEGORY_INIT (rtpmpvpay_debug, "rtpmpvpay", 0,
+ "MPEG2 ES Video RTP Payloader");
+}
+
+static void
+gst_rtp_mpv_pay_init (GstRTPMPVPay * rtpmpvpay)
+{
+ GST_RTP_BASE_PAYLOAD (rtpmpvpay)->clock_rate = 90000;
+ GST_RTP_BASE_PAYLOAD_PT (rtpmpvpay) = GST_RTP_PAYLOAD_MPV;
+
+ rtpmpvpay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_mpv_pay_finalize (GObject * object)
+{
+ GstRTPMPVPay *rtpmpvpay;
+
+ rtpmpvpay = GST_RTP_MPV_PAY (object);
+
+ g_object_unref (rtpmpvpay->adapter);
+ rtpmpvpay->adapter = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_rtp_mpv_pay_reset (GstRTPMPVPay * pay)
+{
+ pay->first_ts = -1;
+ pay->duration = 0;
+ gst_adapter_clear (pay->adapter);
+ GST_DEBUG_OBJECT (pay, "reset depayloader");
+}
+
+static gboolean
+gst_rtp_mpv_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ gst_rtp_base_payload_set_options (payload, "video", FALSE, "MPV", 90000);
+ return gst_rtp_base_payload_set_outcaps (payload, NULL);
+}
+
+static gboolean
+gst_rtp_mpv_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+ gboolean ret;
+ GstRTPMPVPay *rtpmpvpay;
+
+ rtpmpvpay = GST_RTP_MPV_PAY (payload);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_EOS:
+ /* make sure we push the last packets in the adapter on EOS */
+ gst_rtp_mpv_pay_flush (rtpmpvpay);
+ break;
+ case GST_EVENT_FLUSH_STOP:
+ gst_rtp_mpv_pay_reset (rtpmpvpay);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_rtp_mpv_pay_flush (GstRTPMPVPay * rtpmpvpay)
+{
+ GstBuffer *outbuf;
+ GstFlowReturn ret;
+ guint avail;
+
+ guint8 *payload;
+
+ avail = gst_adapter_available (rtpmpvpay->adapter);
+
+ ret = GST_FLOW_OK;
+
+ while (avail > 0) {
+ guint towrite;
+ guint packet_len;
+ guint payload_len;
+ GstRTPBuffer rtp = { NULL };
+ GstBuffer *paybuf;
+
+ packet_len = gst_rtp_buffer_calc_packet_len (avail + 4, 0, 0);
+
+ towrite = MIN (packet_len, GST_RTP_BASE_PAYLOAD_MTU (rtpmpvpay));
+
+ payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
+
+ outbuf = gst_rtp_buffer_new_allocate (4, 0, 0);
+
+ payload_len -= 4;
+
+ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ /* enable MPEG Video-specific header
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | MBZ |T| TR | |N|S|B|E| P | | BFC | | FFC |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * AN FBV FFV
+ */
+
+ /* fill in the MPEG Video-specific header
+ * data is set to 0x0 here
+ */
+ memset (payload, 0x0, 4);
+
+ avail -= payload_len;
+
+ gst_rtp_buffer_set_marker (&rtp, avail == 0);
+ gst_rtp_buffer_unmap (&rtp);
+
+ paybuf = gst_adapter_take_buffer_fast (rtpmpvpay->adapter, payload_len);
+ outbuf = gst_buffer_append (outbuf, paybuf);
+
+ GST_BUFFER_TIMESTAMP (outbuf) = rtpmpvpay->first_ts;
+
+ ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpmpvpay), outbuf);
+ }
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_rtp_mpv_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer)
+{
+ GstRTPMPVPay *rtpmpvpay;
+ guint avail, packet_len;
+ GstClockTime timestamp, duration;
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ rtpmpvpay = GST_RTP_MPV_PAY (basepayload);
+
+ timestamp = GST_BUFFER_TIMESTAMP (buffer);
+ duration = GST_BUFFER_DURATION (buffer);
+
+ if (GST_BUFFER_IS_DISCONT (buffer)) {
+ GST_DEBUG_OBJECT (rtpmpvpay, "DISCONT");
+ gst_rtp_mpv_pay_reset (rtpmpvpay);
+ }
+
+ avail = gst_adapter_available (rtpmpvpay->adapter);
+
+ if (duration == -1)
+ duration = 0;
+
+ if (rtpmpvpay->first_ts == GST_CLOCK_TIME_NONE || avail == 0)
+ rtpmpvpay->first_ts = timestamp;
+
+ if (avail == 0) {
+ rtpmpvpay->duration = duration;
+ } else {
+ rtpmpvpay->duration += duration;
+ }
+
+ gst_adapter_push (rtpmpvpay->adapter, buffer);
+ avail = gst_adapter_available (rtpmpvpay->adapter);
+
+ /* get packet length of previous data and this new data,
+ * payload length includes a 4 byte MPEG video-specific header */
+ packet_len = gst_rtp_buffer_calc_packet_len (avail, 4, 0);
+ GST_LOG_OBJECT (rtpmpvpay, "available %d, rtp packet length %d", avail,
+ packet_len);
+
+ if (gst_rtp_base_payload_is_filled (basepayload,
+ packet_len, rtpmpvpay->duration)) {
+ ret = gst_rtp_mpv_pay_flush (rtpmpvpay);
+ } else {
+ rtpmpvpay->first_ts = timestamp;
+ }
+
+ return ret;
+}
+
+static GstStateChangeReturn
+gst_rtp_mpv_pay_change_state (GstElement * element, GstStateChange transition)
+{
+ GstRTPMPVPay *rtpmpvpay;
+ GstStateChangeReturn ret;
+
+ rtpmpvpay = GST_RTP_MPV_PAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_rtp_mpv_pay_reset (rtpmpvpay);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_rtp_mpv_pay_reset (rtpmpvpay);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+
+gboolean
+gst_rtp_mpv_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpmpvpay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_MPV_PAY);
+}
diff --git a/gst/rtp/gstrtpmpvpay.h b/gst/rtp/gstrtpmpvpay.h
new file mode 100755
index 0000000..bcebad9
--- /dev/null
+++ b/gst/rtp/gstrtpmpvpay.h
@@ -0,0 +1,64 @@
+/* GStreamer
+ * Copyright (C) <2007> Thijs Vermeir <thijsvermeir@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_RTP_MPV_PAY_H__
+#define __GST_RTP_MPV_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRTPMPVPay GstRTPMPVPay;
+typedef struct _GstRTPMPVPayClass GstRTPMPVPayClass;
+
+#define GST_TYPE_RTP_MPV_PAY \
+ (gst_rtp_mpv_pay_get_type())
+#define GST_RTP_MPV_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_MPV_PAY,GstRTPMPVPay))
+#define GST_RTP_MPV_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_MPV_PAY,GstRTPMPVPayClass))
+#define GST_IS_RTP_MPV_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_MPV_PAY))
+#define GST_IS_RTP_MPV_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_MPV_PAY))
+
+struct _GstRTPMPVPay
+{
+ GstRTPBasePayload payload;
+
+ GstAdapter *adapter;
+ GstClockTime first_ts;
+ GstClockTime duration;
+};
+
+struct _GstRTPMPVPayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_mpv_pay_get_type (void);
+
+gboolean gst_rtp_mpv_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_MPV_PAY_H__ */
diff --git a/gst/rtp/gstrtppcmadepay.c b/gst/rtp/gstrtppcmadepay.c
new file mode 100755
index 0000000..8f96250
--- /dev/null
+++ b/gst/rtp/gstrtppcmadepay.c
@@ -0,0 +1,165 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@indt.org.br>
+ * Copyright (C) <2005> Zeeshan Ali <zeenix@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include "gstrtppcmadepay.h"
+
+/* RtpPcmaDepay signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0
+};
+
+static GstStaticPadTemplate gst_rtp_pcma_depay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_PCMA_STRING ", "
+ "clock-rate = (int) 8000;"
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "clock-rate = (int) [1, MAX ], encoding-name = (string) \"PCMA\"")
+ );
+
+static GstStaticPadTemplate gst_rtp_pcma_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-alaw, channels = (int) 1, rate = (int) [1, MAX ]")
+ );
+
+static GstBuffer *gst_rtp_pcma_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+static gboolean gst_rtp_pcma_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+
+#define gst_rtp_pcma_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpPcmaDepay, gst_rtp_pcma_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_pcma_depay_class_init (GstRtpPcmaDepayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_pcma_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_pcma_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP PCMA depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts PCMA audio from RTP packets",
+ "Edgard Lima <edgard.lima@indt.org.br>, Zeeshan Ali <zeenix@gmail.com>");
+
+ gstrtpbasedepayload_class->process = gst_rtp_pcma_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_pcma_depay_setcaps;
+}
+
+static void
+gst_rtp_pcma_depay_init (GstRtpPcmaDepay * rtppcmadepay)
+{
+ GstRTPBaseDepayload *depayload;
+
+ depayload = GST_RTP_BASE_DEPAYLOAD (rtppcmadepay);
+
+ gst_pad_use_fixed_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload));
+}
+
+static gboolean
+gst_rtp_pcma_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstCaps *srccaps;
+ GstStructure *structure;
+ gboolean ret;
+ gint clock_rate;
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 8000; /* default */
+ depayload->clock_rate = clock_rate;
+
+ srccaps = gst_caps_new_simple ("audio/x-alaw",
+ "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, clock_rate, NULL);
+ ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+ gst_caps_unref (srccaps);
+
+ return ret;
+}
+
+static GstBuffer *
+gst_rtp_pcma_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstBuffer *outbuf = NULL;
+ gboolean marker;
+ guint len;
+ GstRTPBuffer rtp = { NULL };
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ marker = gst_rtp_buffer_get_marker (&rtp);
+
+ GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d",
+ gst_buffer_get_size (buf), marker,
+ gst_rtp_buffer_get_timestamp (&rtp), gst_rtp_buffer_get_seq (&rtp));
+
+ len = gst_rtp_buffer_get_payload_len (&rtp);
+ outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
+ gst_rtp_buffer_unmap (&rtp);
+
+ if (outbuf) {
+ GST_BUFFER_DURATION (outbuf) =
+ gst_util_uint64_scale_int (len, GST_SECOND, depayload->clock_rate);
+
+ if (marker) {
+ /* mark start of talkspurt with RESYNC */
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+ }
+ }
+
+
+ return outbuf;
+}
+
+gboolean
+gst_rtp_pcma_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtppcmadepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_PCMA_DEPAY);
+}
diff --git a/gst/rtp/gstrtppcmadepay.h b/gst/rtp/gstrtppcmadepay.h
new file mode 100755
index 0000000..7ea0f45
--- /dev/null
+++ b/gst/rtp/gstrtppcmadepay.h
@@ -0,0 +1,53 @@
+/* GStreamer
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@indt.org.br>
+ *
+ * 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
+ */
+
+#ifndef __GST_RTP_PCMA_DEPAY_H__
+#define __GST_RTP_PCMA_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRtpPcmaDepay GstRtpPcmaDepay;
+typedef struct _GstRtpPcmaDepayClass GstRtpPcmaDepayClass;
+
+#define GST_TYPE_RTP_PCMA_DEPAY \
+ (gst_rtp_pcma_depay_get_type())
+#define GST_RTP_PCMA_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_PCMA_DEPAY,GstRtpPcmaDepay))
+#define GST_RTP_PCMA_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_PCMA_DEPAY,GstRtpPcmaDepayClass))
+#define GST_IS_RTP_PCMA_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_PCMA_DEPAY))
+#define GST_IS_RTP_PCMA_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_PCMA_DEPAY))
+
+struct _GstRtpPcmaDepay
+{
+ GstRTPBaseDepayload depayload;
+};
+
+struct _GstRtpPcmaDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_pcma_depay_get_type (void);
+
+gboolean gst_rtp_pcma_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_PCMA_DEPAY_H__ */
diff --git a/gst/rtp/gstrtppcmapay.c b/gst/rtp/gstrtppcmapay.c
new file mode 100755
index 0000000..7ec7e59
--- /dev/null
+++ b/gst/rtp/gstrtppcmapay.c
@@ -0,0 +1,116 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@indt.org.br>
+ * Copyright (C) <2005> Nokia Corporation <kai.vehmanen@nokia.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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtppcmapay.h"
+
+static GstStaticPadTemplate gst_rtp_pcma_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-alaw, channels=(int)1, rate=(int)8000")
+ );
+
+static GstStaticPadTemplate gst_rtp_pcma_pay_src_template =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_PCMA_STRING ", "
+ "clock-rate = (int) 8000, " "encoding-name = (string) \"PCMA\"; "
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"PCMA\"")
+ );
+
+static gboolean gst_rtp_pcma_pay_setcaps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+
+#define gst_rtp_pcma_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpPcmaPay, gst_rtp_pcma_pay,
+ GST_TYPE_RTP_BASE_AUDIO_PAYLOAD);
+
+static void
+gst_rtp_pcma_pay_class_init (GstRtpPcmaPayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_pcma_pay_sink_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_pcma_pay_src_template));
+
+ gst_element_class_set_static_metadata (gstelement_class, "RTP PCMA payloader",
+ "Codec/Payloader/Network/RTP",
+ "Payload-encodes PCMA audio into a RTP packet",
+ "Edgard Lima <edgard.lima@indt.org.br>");
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_pcma_pay_setcaps;
+}
+
+static void
+gst_rtp_pcma_pay_init (GstRtpPcmaPay * rtppcmapay)
+{
+ GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+ rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtppcmapay);
+
+ GST_RTP_BASE_PAYLOAD (rtppcmapay)->clock_rate = 8000;
+
+ /* tell rtpbaseaudiopayload that this is a sample based codec */
+ gst_rtp_base_audio_payload_set_sample_based (rtpbaseaudiopayload);
+
+ /* octet-per-sample is 1 for PCM */
+ gst_rtp_base_audio_payload_set_sample_options (rtpbaseaudiopayload, 1);
+}
+
+static gboolean
+gst_rtp_pcma_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ gboolean res;
+
+ payload->pt = GST_RTP_PAYLOAD_PCMA;
+
+ gst_rtp_base_payload_set_options (payload, "audio", FALSE, "PCMA", 8000);
+ res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+
+ return res;
+}
+
+gboolean
+gst_rtp_pcma_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtppcmapay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_PCMA_PAY);
+}
diff --git a/gst/rtp/gstrtppcmapay.h b/gst/rtp/gstrtppcmapay.h
new file mode 100755
index 0000000..5fde1bf
--- /dev/null
+++ b/gst/rtp/gstrtppcmapay.h
@@ -0,0 +1,54 @@
+/* GStreamer
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@indt.org.br>
+ *
+ * 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
+ */
+
+
+#ifndef __GST_RTP_PCMA_PAY_H__
+#define __GST_RTP_PCMA_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRtpPcmaPay GstRtpPcmaPay;
+typedef struct _GstRtpPcmaPayClass GstRtpPcmaPayClass;
+
+#define GST_TYPE_RTP_PCMA_PAY \
+ (gst_rtp_pcma_pay_get_type())
+#define GST_RTP_PCMA_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_PCMA_PAY,GstRtpPcmaPay))
+#define GST_RTP_PCMA_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_PCMA_PAY,GstRtpPcmaPayClass))
+#define GST_IS_RTP_PCMA_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_PCMA_PAY))
+#define GST_IS_RTP_PCMA_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_PCMA_PAY))
+
+struct _GstRtpPcmaPay
+{
+ GstRTPBaseAudioPayload audiopayload;
+};
+
+struct _GstRtpPcmaPayClass
+{
+ GstRTPBaseAudioPayloadClass parent_class;
+};
+
+GType gst_rtp_pcma_pay_get_type (void);
+
+gboolean gst_rtp_pcma_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_PCMA_PAY_H__ */
diff --git a/gst/rtp/gstrtppcmudepay.c b/gst/rtp/gstrtppcmudepay.c
new file mode 100755
index 0000000..e75c282
--- /dev/null
+++ b/gst/rtp/gstrtppcmudepay.c
@@ -0,0 +1,165 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@indt.org.br>
+ * Copyright (C) <2005> Zeeshan Ali <zeenix@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include "gstrtppcmudepay.h"
+
+/* RtpPcmuDepay signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0
+};
+
+static GstStaticPadTemplate gst_rtp_pcmu_depay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_PCMU_STRING ", "
+ "clock-rate = (int) 8000; "
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "encoding-name = (string) \"PCMU\", clock-rate = (int) [1, MAX ]")
+ );
+
+static GstStaticPadTemplate gst_rtp_pcmu_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-mulaw, "
+ "channels = (int) 1, rate = (int) [1, MAX ]")
+ );
+
+static GstBuffer *gst_rtp_pcmu_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+static gboolean gst_rtp_pcmu_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+
+#define gst_rtp_pcmu_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpPcmuDepay, gst_rtp_pcmu_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_pcmu_depay_class_init (GstRtpPcmuDepayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_pcmu_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_pcmu_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP PCMU depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts PCMU audio from RTP packets",
+ "Edgard Lima <edgard.lima@indt.org.br>, Zeeshan Ali <zeenix@gmail.com>");
+
+ gstrtpbasedepayload_class->process = gst_rtp_pcmu_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_pcmu_depay_setcaps;
+}
+
+static void
+gst_rtp_pcmu_depay_init (GstRtpPcmuDepay * rtppcmudepay)
+{
+ GstRTPBaseDepayload *depayload;
+
+ depayload = GST_RTP_BASE_DEPAYLOAD (rtppcmudepay);
+
+ gst_pad_use_fixed_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload));
+}
+
+static gboolean
+gst_rtp_pcmu_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstCaps *srccaps;
+ GstStructure *structure;
+ gboolean ret;
+ gint clock_rate;
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 8000; /* default */
+ depayload->clock_rate = clock_rate;
+
+ srccaps = gst_caps_new_simple ("audio/x-mulaw",
+ "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, clock_rate, NULL);
+ ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+ gst_caps_unref (srccaps);
+
+ return ret;
+}
+
+static GstBuffer *
+gst_rtp_pcmu_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstBuffer *outbuf = NULL;
+ guint len;
+ gboolean marker;
+ GstRTPBuffer rtp = { NULL };
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ marker = gst_rtp_buffer_get_marker (&rtp);
+
+ GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d",
+ gst_buffer_get_size (buf), marker,
+ gst_rtp_buffer_get_timestamp (&rtp), gst_rtp_buffer_get_seq (&rtp));
+
+ len = gst_rtp_buffer_get_payload_len (&rtp);
+ outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
+ gst_rtp_buffer_unmap (&rtp);
+
+ if (outbuf) {
+ GST_BUFFER_DURATION (outbuf) =
+ gst_util_uint64_scale_int (len, GST_SECOND, depayload->clock_rate);
+
+ if (marker) {
+ /* mark start of talkspurt with RESYNC */
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+ }
+ }
+
+ return outbuf;
+}
+
+gboolean
+gst_rtp_pcmu_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtppcmudepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_PCMU_DEPAY);
+}
diff --git a/gst/rtp/gstrtppcmudepay.h b/gst/rtp/gstrtppcmudepay.h
new file mode 100755
index 0000000..922ceb9
--- /dev/null
+++ b/gst/rtp/gstrtppcmudepay.h
@@ -0,0 +1,53 @@
+/* GStreamer
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@indt.org.br>
+ *
+ * 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
+ */
+
+#ifndef __GST_RTP_PCMU_DEPAY_H__
+#define __GST_RTP_PCMU_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRtpPcmuDepay GstRtpPcmuDepay;
+typedef struct _GstRtpPcmuDepayClass GstRtpPcmuDepayClass;
+
+#define GST_TYPE_RTP_PCMU_DEPAY \
+ (gst_rtp_pcmu_depay_get_type())
+#define GST_RTP_PCMU_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_PCMU_DEPAY,GstRtpPcmuDepay))
+#define GST_RTP_PCMU_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_PCMU_DEPAY,GstRtpPcmuDepayClass))
+#define GST_IS_RTP_PCMU_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_PCMU_DEPAY))
+#define GST_IS_RTP_PCMU_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_PCMU_DEPAY))
+
+struct _GstRtpPcmuDepay
+{
+ GstRTPBaseDepayload depayload;
+};
+
+struct _GstRtpPcmuDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_pcmu_depay_get_type (void);
+
+gboolean gst_rtp_pcmu_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_PCMU_DEPAY_H__ */
diff --git a/gst/rtp/gstrtppcmupay.c b/gst/rtp/gstrtppcmupay.c
new file mode 100755
index 0000000..3d69cb3
--- /dev/null
+++ b/gst/rtp/gstrtppcmupay.c
@@ -0,0 +1,116 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@indt.org.br>
+ * Copyright (C) <2005> Nokia Corporation <kai.vehmanen@nokia.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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtppcmupay.h"
+
+static GstStaticPadTemplate gst_rtp_pcmu_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-mulaw, channels=(int)1, rate=(int)8000")
+ );
+
+static GstStaticPadTemplate gst_rtp_pcmu_pay_src_template =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_PCMU_STRING ", "
+ "clock-rate = (int) 8000, " "encoding-name = (string) \"PCMU\"; "
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"PCMU\"")
+ );
+
+static gboolean gst_rtp_pcmu_pay_setcaps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+
+#define gst_rtp_pcmu_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpPcmuPay, gst_rtp_pcmu_pay,
+ GST_TYPE_RTP_BASE_AUDIO_PAYLOAD);
+
+static void
+gst_rtp_pcmu_pay_class_init (GstRtpPcmuPayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_pcmu_pay_sink_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_pcmu_pay_src_template));
+
+ gst_element_class_set_static_metadata (gstelement_class, "RTP PCMU payloader",
+ "Codec/Payloader/Network/RTP",
+ "Payload-encodes PCMU audio into a RTP packet",
+ "Edgard Lima <edgard.lima@indt.org.br>");
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_pcmu_pay_setcaps;
+}
+
+static void
+gst_rtp_pcmu_pay_init (GstRtpPcmuPay * rtppcmupay)
+{
+ GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+ rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtppcmupay);
+
+ GST_RTP_BASE_PAYLOAD (rtppcmupay)->clock_rate = 8000;
+
+ /* tell rtpbaseaudiopayload that this is a sample based codec */
+ gst_rtp_base_audio_payload_set_sample_based (rtpbaseaudiopayload);
+
+ /* octet-per-sample is 1 for PCM */
+ gst_rtp_base_audio_payload_set_sample_options (rtpbaseaudiopayload, 1);
+}
+
+static gboolean
+gst_rtp_pcmu_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ gboolean res;
+
+ payload->pt = GST_RTP_PAYLOAD_PCMU;
+
+ gst_rtp_base_payload_set_options (payload, "audio", FALSE, "PCMU", 8000);
+ res = gst_rtp_base_payload_set_outcaps (payload, NULL);
+
+ return res;
+}
+
+gboolean
+gst_rtp_pcmu_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtppcmupay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_PCMU_PAY);
+}
diff --git a/gst/rtp/gstrtppcmupay.h b/gst/rtp/gstrtppcmupay.h
new file mode 100755
index 0000000..58da803
--- /dev/null
+++ b/gst/rtp/gstrtppcmupay.h
@@ -0,0 +1,54 @@
+/* GStreamer
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@indt.org.br>
+ *
+ * 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
+ */
+
+
+#ifndef __GST_RTP_PCMU_PAY_H__
+#define __GST_RTP_PCMU_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRtpPcmuPay GstRtpPcmuPay;
+typedef struct _GstRtpPcmuPayClass GstRtpPcmuPayClass;
+
+#define GST_TYPE_RTP_PCMU_PAY \
+ (gst_rtp_pcmu_pay_get_type())
+#define GST_RTP_PCMU_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_PCMU_PAY,GstRtpPcmuPay))
+#define GST_RTP_PCMU_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_PCMU_PAY,GstRtpPcmuPayClass))
+#define GST_IS_RTP_PCMU_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_PCMU_PAY))
+#define GST_IS_RTP_PCMU_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_PCMU_PAY))
+
+struct _GstRtpPcmuPay
+{
+ GstRTPBaseAudioPayload audiopayload;
+};
+
+struct _GstRtpPcmuPayClass
+{
+ GstRTPBaseAudioPayloadClass parent_class;
+};
+
+GType gst_rtp_pcmu_pay_get_type (void);
+
+gboolean gst_rtp_pcmu_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_PCMU_PAY_H__ */
diff --git a/gst/rtp/gstrtpqcelpdepay.c b/gst/rtp/gstrtpqcelpdepay.c
new file mode 100755
index 0000000..fc88f4a
--- /dev/null
+++ b/gst/rtp/gstrtpqcelpdepay.c
@@ -0,0 +1,435 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include "gstrtpqcelpdepay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpqcelpdepay_debug);
+#define GST_CAT_DEFAULT (rtpqcelpdepay_debug)
+
+/* references:
+ *
+ * RFC 2658 - RTP Payload Format for PureVoice(tm) Audio
+ */
+#define FRAME_DURATION (20 * GST_MSECOND)
+
+/* RtpQCELPDepay signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0
+};
+
+static GstStaticPadTemplate gst_rtp_qcelp_depay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "clock-rate = (int) 8000, "
+ "encoding-name = (string) \"QCELP\"; "
+ "application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_QCELP_STRING ", "
+ "clock-rate = (int) 8000")
+ );
+
+static GstStaticPadTemplate gst_rtp_qcelp_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/qcelp, " "channels = (int) 1," "rate = (int) 8000")
+ );
+
+static void gst_rtp_qcelp_depay_finalize (GObject * object);
+
+static gboolean gst_rtp_qcelp_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_qcelp_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+
+#define gst_rtp_qcelp_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpQCELPDepay, gst_rtp_qcelp_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_qcelp_depay_class_init (GstRtpQCELPDepayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_qcelp_depay_finalize;
+
+ gstrtpbasedepayload_class->process = gst_rtp_qcelp_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_qcelp_depay_setcaps;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_qcelp_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_qcelp_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP QCELP depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts QCELP (PureVoice) audio from RTP packets (RFC 2658)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ GST_DEBUG_CATEGORY_INIT (rtpqcelpdepay_debug, "rtpqcelpdepay", 0,
+ "QCELP RTP Depayloader");
+}
+
+static void
+gst_rtp_qcelp_depay_init (GstRtpQCELPDepay * rtpqcelpdepay)
+{
+}
+
+static void
+gst_rtp_qcelp_depay_finalize (GObject * object)
+{
+ GstRtpQCELPDepay *depay;
+
+ depay = GST_RTP_QCELP_DEPAY (object);
+
+ if (depay->packets != NULL) {
+ g_ptr_array_foreach (depay->packets, (GFunc) gst_buffer_unref, NULL);
+ g_ptr_array_free (depay->packets, TRUE);
+ depay->packets = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static gboolean
+gst_rtp_qcelp_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstCaps *srccaps;
+ gboolean res;
+
+ srccaps = gst_caps_new_simple ("audio/qcelp",
+ "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL);
+ res = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+ gst_caps_unref (srccaps);
+
+ return res;
+}
+
+static const gint frame_size[16] = {
+ 1, 4, 8, 17, 35, -8, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0
+};
+
+/* get the frame length, 0 is invalid, negative values are invalid but can be
+ * recovered from. */
+static gint
+get_frame_len (GstRtpQCELPDepay * depay, guint8 frame_type)
+{
+ if (frame_type >= G_N_ELEMENTS (frame_size))
+ return 0;
+
+ return frame_size[frame_type];
+}
+
+static guint
+count_packets (GstRtpQCELPDepay * depay, guint8 * data, guint size)
+{
+ guint count = 0;
+
+ while (size > 0) {
+ gint frame_len;
+
+ frame_len = get_frame_len (depay, data[0]);
+
+ /* 0 is invalid and we throw away the remainder of the frames */
+ if (frame_len == 0)
+ break;
+
+ if (frame_len < 0)
+ frame_len = -frame_len;
+
+ if (frame_len > size)
+ break;
+
+ size -= frame_len;
+ data += frame_len;
+ count++;
+ }
+ return count;
+}
+
+static void
+flush_packets (GstRtpQCELPDepay * depay)
+{
+ guint i, size;
+
+ GST_DEBUG_OBJECT (depay, "flushing packets");
+
+ size = depay->packets->len;
+
+ for (i = 0; i < size; i++) {
+ GstBuffer *outbuf;
+
+ outbuf = g_ptr_array_index (depay->packets, i);
+ g_ptr_array_index (depay->packets, i) = NULL;
+
+ gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (depay), outbuf);
+ }
+
+ /* and reset interleaving state */
+ depay->interleaved = FALSE;
+ depay->bundling = 0;
+}
+
+static void
+add_packet (GstRtpQCELPDepay * depay, guint LLL, guint NNN, guint index,
+ GstBuffer * outbuf)
+{
+ guint idx;
+ GstBuffer *old;
+
+ /* figure out the position in the array, note that index is never 0 because we
+ * push those packets immediately. */
+ idx = NNN + ((LLL + 1) * (index - 1));
+
+ GST_DEBUG_OBJECT (depay, "adding packet at index %u", idx);
+ /* free old buffer (should not happen) */
+ old = g_ptr_array_index (depay->packets, idx);
+ if (old)
+ gst_buffer_unref (old);
+
+ /* store new buffer */
+ g_ptr_array_index (depay->packets, idx) = outbuf;
+}
+
+static GstBuffer *
+create_erasure_buffer (GstRtpQCELPDepay * depay)
+{
+ GstBuffer *outbuf;
+ GstMapInfo map;
+
+ outbuf = gst_buffer_new_and_alloc (1);
+ gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
+ map.data[0] = 14;
+ gst_buffer_unmap (outbuf, &map);
+
+ return outbuf;
+}
+
+static GstBuffer *
+gst_rtp_qcelp_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpQCELPDepay *depay;
+ GstBuffer *outbuf;
+ GstClockTime timestamp;
+ guint payload_len, offset, index;
+ guint8 *payload;
+ guint LLL, NNN;
+ GstRTPBuffer rtp = { NULL };
+
+ depay = GST_RTP_QCELP_DEPAY (depayload);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+
+ if (payload_len < 2)
+ goto too_small;
+
+ timestamp = GST_BUFFER_TIMESTAMP (buf);
+
+ payload = gst_rtp_buffer_get_payload (&rtp);
+
+ /* 0 1 2 3 4 5 6 7
+ * +-+-+-+-+-+-+-+-+
+ * |RR | LLL | NNN |
+ * +-+-+-+-+-+-+-+-+
+ */
+ /* RR = payload[0] >> 6; */
+ LLL = (payload[0] & 0x38) >> 3;
+ NNN = (payload[0] & 0x07);
+
+ payload_len--;
+ payload++;
+
+ GST_DEBUG_OBJECT (depay, "LLL %u, NNN %u", LLL, NNN);
+
+ if (LLL > 5)
+ goto invalid_lll;
+
+ if (NNN > LLL)
+ goto invalid_nnn;
+
+ if (LLL != 0) {
+ /* we are interleaved */
+ if (!depay->interleaved) {
+ guint size;
+
+ GST_DEBUG_OBJECT (depay, "starting interleaving group");
+ /* bundling is not allowed to change in one interleave group */
+ depay->bundling = count_packets (depay, payload, payload_len);
+ GST_DEBUG_OBJECT (depay, "got bundling of %u", depay->bundling);
+ /* we have one bundle where NNN goes from 0 to L, we don't store the index
+ * 0 frames, so L+1 packets. Each packet has 'bundling - 1' packets */
+ size = (depay->bundling - 1) * (LLL + 1);
+ /* create the array to hold the packets */
+ if (depay->packets == NULL)
+ depay->packets = g_ptr_array_sized_new (size);
+ GST_DEBUG_OBJECT (depay, "created packet array of size %u", size);
+ g_ptr_array_set_size (depay->packets, size);
+ /* we were previously not interleaved, figure out how much space we
+ * need to deinterleave */
+ depay->interleaved = TRUE;
+ }
+ } else {
+ /* we are not interleaved */
+ if (depay->interleaved) {
+ GST_DEBUG_OBJECT (depay, "stopping interleaving");
+ /* flush packets if we were previously interleaved */
+ flush_packets (depay);
+ }
+ depay->bundling = 0;
+ }
+
+ index = 0;
+ offset = 1;
+
+ while (payload_len > 0) {
+ gint frame_len;
+ gboolean do_erasure;
+
+ frame_len = get_frame_len (depay, payload[0]);
+ GST_DEBUG_OBJECT (depay, "got frame len %d", frame_len);
+
+ if (frame_len == 0)
+ goto invalid_frame;
+
+ if (frame_len < 0) {
+ /* need to add an erasure frame but we can recover */
+ frame_len = -frame_len;
+ do_erasure = TRUE;
+ } else {
+ do_erasure = FALSE;
+ }
+
+ if (frame_len > payload_len)
+ goto invalid_frame;
+
+ if (do_erasure) {
+ /* create erasure frame */
+ outbuf = create_erasure_buffer (depay);
+ } else {
+ /* each frame goes into its buffer */
+ outbuf = gst_rtp_buffer_get_payload_subbuffer (&rtp, offset, frame_len);
+ }
+
+ GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
+ GST_BUFFER_DURATION (outbuf) = FRAME_DURATION;
+
+ if (!depay->interleaved || index == 0) {
+ /* not interleaved or first frame in packet, just push */
+ gst_rtp_base_depayload_push (depayload, outbuf);
+
+ if (timestamp != -1)
+ timestamp += FRAME_DURATION;
+ } else {
+ /* put in interleave buffer */
+ add_packet (depay, LLL, NNN, index, outbuf);
+
+ if (timestamp != -1)
+ timestamp += (FRAME_DURATION * (LLL + 1));
+ }
+
+ payload_len -= frame_len;
+ payload += frame_len;
+ offset += frame_len;
+ index++;
+
+ /* discard excess packets */
+ if (depay->bundling > 0 && depay->bundling <= index)
+ break;
+ }
+ while (index < depay->bundling) {
+ GST_DEBUG_OBJECT (depay, "filling with erasure buffer");
+ /* fill remainder with erasure packets */
+ outbuf = create_erasure_buffer (depay);
+ add_packet (depay, LLL, NNN, index, outbuf);
+ index++;
+ }
+ if (depay->interleaved && LLL == NNN) {
+ GST_DEBUG_OBJECT (depay, "interleave group ended, flushing");
+ /* we have the complete interleave group, flush */
+ flush_packets (depay);
+ }
+
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+
+ /* ERRORS */
+too_small:
+ {
+ GST_ELEMENT_WARNING (depay, STREAM, DECODE,
+ (NULL), ("QCELP RTP payload too small (%d)", payload_len));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+invalid_lll:
+ {
+ GST_ELEMENT_WARNING (depay, STREAM, DECODE,
+ (NULL), ("QCELP RTP invalid LLL received (%d)", LLL));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+invalid_nnn:
+ {
+ GST_ELEMENT_WARNING (depay, STREAM, DECODE,
+ (NULL), ("QCELP RTP invalid NNN received (%d)", NNN));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+invalid_frame:
+ {
+ GST_ELEMENT_WARNING (depay, STREAM, DECODE,
+ (NULL), ("QCELP RTP invalid frame received"));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+}
+
+gboolean
+gst_rtp_qcelp_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpqcelpdepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_QCELP_DEPAY);
+}
diff --git a/gst/rtp/gstrtpqcelpdepay.h b/gst/rtp/gstrtpqcelpdepay.h
new file mode 100755
index 0000000..ade274d
--- /dev/null
+++ b/gst/rtp/gstrtpqcelpdepay.h
@@ -0,0 +1,62 @@
+/* GStreamer
+ * Copyright (C) <2010> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_QCELP_DEPAY_H__
+#define __GST_RTP_QCELP_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_QCELP_DEPAY \
+ (gst_rtp_qcelp_depay_get_type())
+#define GST_RTP_QCELP_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_QCELP_DEPAY,GstRtpQCELPDepay))
+#define GST_RTP_QCELP_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_QCELP_DEPAY,GstRtpQCELPDepayClass))
+#define GST_IS_RTP_QCELP_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_QCELP_DEPAY))
+#define GST_IS_RTP_QCELP_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_QCELP_DEPAY))
+
+typedef struct _GstRtpQCELPDepay GstRtpQCELPDepay;
+typedef struct _GstRtpQCELPDepayClass GstRtpQCELPDepayClass;
+
+struct _GstRtpQCELPDepay
+{
+ GstRTPBaseDepayload depayload;
+
+ gboolean interleaved;
+ guint bundling;
+ GPtrArray *packets;
+};
+
+struct _GstRtpQCELPDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_qcelp_depay_get_type (void);
+
+gboolean gst_rtp_qcelp_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_QCELP_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpqdmdepay.c b/gst/rtp/gstrtpqdmdepay.c
new file mode 100755
index 0000000..ba85018
--- /dev/null
+++ b/gst/rtp/gstrtpqdmdepay.c
@@ -0,0 +1,416 @@
+/* GStreamer
+ * Copyright (C) <2009> Edward Hervey <bilboed@bilboed.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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include "gstrtpqdmdepay.h"
+
+GST_DEBUG_CATEGORY (rtpqdm2depay_debug);
+#define GST_CAT_DEFAULT rtpqdm2depay_debug
+
+static GstStaticPadTemplate gst_rtp_qdm2_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-qdm2")
+ );
+
+static GstStaticPadTemplate gst_rtp_qdm2_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", " "encoding-name = (string)\"X-QDM\"")
+ );
+
+#define gst_rtp_qdm2_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpQDM2Depay, gst_rtp_qdm2_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static const guint8 headheader[20] = {
+ 0x0, 0x0, 0x0, 0xc, 0x66, 0x72, 0x6d, 0x61,
+ 0x51, 0x44, 0x4d, 0x32, 0x0, 0x0, 0x0, 0x24,
+ 0x51, 0x44, 0x43, 0x41
+};
+
+static void gst_rtp_qdm2_depay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_qdm2_depay_change_state (GstElement *
+ element, GstStateChange transition);
+
+static GstBuffer *gst_rtp_qdm2_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+gboolean gst_rtp_qdm2_depay_setcaps (GstRTPBaseDepayload * filter,
+ GstCaps * caps);
+
+static void
+gst_rtp_qdm2_depay_class_init (GstRtpQDM2DepayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gstrtpbasedepayload_class->process = gst_rtp_qdm2_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_qdm2_depay_setcaps;
+
+ gobject_class->finalize = gst_rtp_qdm2_depay_finalize;
+
+ gstelement_class->change_state = gst_rtp_qdm2_depay_change_state;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_qdm2_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_qdm2_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP QDM2 depayloader",
+ "Codec/Depayloader/Network/RTP",
+ "Extracts QDM2 audio from RTP packets (no RFC)",
+ "Edward Hervey <bilboed@bilboed.com>");
+}
+
+static void
+gst_rtp_qdm2_depay_init (GstRtpQDM2Depay * rtpqdm2depay)
+{
+ rtpqdm2depay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_qdm2_depay_finalize (GObject * object)
+{
+ GstRtpQDM2Depay *rtpqdm2depay;
+
+ rtpqdm2depay = GST_RTP_QDM2_DEPAY (object);
+
+ g_object_unref (rtpqdm2depay->adapter);
+ rtpqdm2depay->adapter = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/* only on the sink */
+gboolean
+gst_rtp_qdm2_depay_setcaps (GstRTPBaseDepayload * filter, GstCaps * caps)
+{
+ GstStructure *structure = gst_caps_get_structure (caps, 0);
+ gint clock_rate;
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 44100; /* default */
+ filter->clock_rate = clock_rate;
+
+ /* will set caps later */
+
+ return TRUE;
+}
+
+static void
+flush_data (GstRtpQDM2Depay * depay)
+{
+ guint i;
+ guint avail;
+
+ if ((avail = gst_adapter_available (depay->adapter)))
+ gst_adapter_flush (depay->adapter, avail);
+
+ GST_DEBUG ("Flushing %d packets", depay->nbpackets);
+
+ for (i = 0; depay->packets[i]; i++) {
+ QDM2Packet *pack = depay->packets[i];
+ guint32 crc = 0;
+ int i = 0;
+ GstBuffer *buf;
+ guint8 *data;
+
+ /* CRC is the sum of everything (including first bytes) */
+
+ data = pack->data;
+
+ if (G_UNLIKELY (data == NULL))
+ continue;
+
+ /* If the packet size is bigger than 0xff, we need 2 bytes to store the size */
+ if (depay->packetsize > 0xff) {
+ /* Expanded size 0x02 | 0x80 */
+ data[0] = 0x82;
+ GST_WRITE_UINT16_BE (data + 1, depay->packetsize - 3);
+ } else {
+ data[0] = 0x2;
+ data[1] = depay->packetsize - 2;
+ }
+
+ /* Calculate CRC */
+ for (; i < depay->packetsize; i++)
+ crc += data[i];
+
+ GST_DEBUG ("CRC is 0x%x", crc);
+
+ /* Write CRC */
+ if (depay->packetsize > 0xff)
+ GST_WRITE_UINT16_BE (data + 3, crc);
+ else
+ GST_WRITE_UINT16_BE (data + 2, crc);
+
+ GST_MEMDUMP ("Extracted packet", data, depay->packetsize);
+
+ buf = gst_buffer_new ();
+ gst_buffer_append_memory (buf,
+ gst_memory_new_wrapped (0, data, depay->packetsize, 0,
+ depay->packetsize, data, g_free));
+
+ gst_adapter_push (depay->adapter, buf);
+
+ pack->data = NULL;
+ }
+}
+
+static void
+add_packet (GstRtpQDM2Depay * depay, guint32 pid, guint32 len, guint8 * data)
+{
+ QDM2Packet *packet;
+
+ if (G_UNLIKELY (!depay->configured))
+ return;
+
+ GST_DEBUG ("pid:%d, len:%d, data:%p", pid, len, data);
+
+ if (G_UNLIKELY (depay->packets[pid] == NULL)) {
+ depay->packets[pid] = g_malloc0 (sizeof (QDM2Packet));
+ depay->nbpackets = MAX (depay->nbpackets, pid + 1);
+ }
+ packet = depay->packets[pid];
+
+ GST_DEBUG ("packet:%p", packet);
+ GST_DEBUG ("packet->data:%p", packet->data);
+
+ if (G_UNLIKELY (packet->data == NULL)) {
+ packet->data = g_malloc0 (depay->packetsize);
+ /* We leave space for the header/crc */
+ if (depay->packetsize > 0xff)
+ packet->offs = 5;
+ else
+ packet->offs = 4;
+ }
+
+ /* Finally copy the data over */
+ memcpy (packet->data + packet->offs, data, len);
+ packet->offs += len;
+}
+
+static GstBuffer *
+gst_rtp_qdm2_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpQDM2Depay *rtpqdm2depay;
+ GstBuffer *outbuf = NULL;
+ guint16 seq;
+ GstRTPBuffer rtp = { NULL };
+
+ rtpqdm2depay = GST_RTP_QDM2_DEPAY (depayload);
+
+ {
+ gint payload_len;
+ guint8 *payload;
+ guint avail;
+ guint pos = 0;
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+ if (payload_len < 3)
+ goto bad_packet;
+
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ seq = gst_rtp_buffer_get_seq (&rtp);
+ if (G_UNLIKELY (seq != rtpqdm2depay->nextseq)) {
+ GST_DEBUG ("GAP in sequence number, Resetting data !");
+ /* Flush previous data */
+ flush_data (rtpqdm2depay);
+ /* And store new timestamp */
+ rtpqdm2depay->ptimestamp = rtpqdm2depay->timestamp;
+ rtpqdm2depay->timestamp = GST_BUFFER_TIMESTAMP (buf);
+ /* And that previous data will be pushed at the bottom */
+ }
+ rtpqdm2depay->nextseq = seq + 1;
+
+ GST_DEBUG ("Payload size %d 0x%x sequence:%d", payload_len, payload_len,
+ seq);
+
+ GST_MEMDUMP ("Incoming payload", payload, payload_len);
+
+ while (pos < payload_len) {
+ switch (payload[pos]) {
+ case 0x80:{
+ GST_DEBUG ("Unrecognized 0x80 marker, skipping 12 bytes");
+ pos += 12;
+ }
+ break;
+ case 0xff:
+ /* HEADERS */
+ GST_DEBUG ("Headers");
+ /* Store the incoming timestamp */
+ rtpqdm2depay->ptimestamp = rtpqdm2depay->timestamp;
+ rtpqdm2depay->timestamp = GST_BUFFER_TIMESTAMP (buf);
+ /* flush the internal data if needed */
+ flush_data (rtpqdm2depay);
+ if (G_UNLIKELY (!rtpqdm2depay->configured)) {
+ guint8 *ourdata;
+ GstBuffer *codecdata;
+ GstMapInfo cmap;
+ GstCaps *caps;
+
+ /* First bytes are unknown */
+ GST_MEMDUMP ("Header", payload + pos, 32);
+ ourdata = payload + pos + 10;
+ pos += 10;
+ rtpqdm2depay->channs = GST_READ_UINT32_BE (payload + pos + 4);
+ rtpqdm2depay->samplerate = GST_READ_UINT32_BE (payload + pos + 8);
+ rtpqdm2depay->bitrate = GST_READ_UINT32_BE (payload + pos + 12);
+ rtpqdm2depay->blocksize = GST_READ_UINT32_BE (payload + pos + 16);
+ rtpqdm2depay->framesize = GST_READ_UINT32_BE (payload + pos + 20);
+ rtpqdm2depay->packetsize = GST_READ_UINT32_BE (payload + pos + 24);
+ /* 16 bit empty block (0x02 0x00) */
+ pos += 30;
+ GST_DEBUG
+ ("channs:%d, samplerate:%d, bitrate:%d, blocksize:%d, framesize:%d, packetsize:%d",
+ rtpqdm2depay->channs, rtpqdm2depay->samplerate,
+ rtpqdm2depay->bitrate, rtpqdm2depay->blocksize,
+ rtpqdm2depay->framesize, rtpqdm2depay->packetsize);
+
+ /* Caps */
+ codecdata = gst_buffer_new_and_alloc (48);
+ gst_buffer_map (codecdata, &cmap, GST_MAP_WRITE);
+ memcpy (cmap.data, headheader, 20);
+ memcpy (cmap.data + 20, ourdata, 28);
+ gst_buffer_unmap (codecdata, &cmap);
+
+ caps = gst_caps_new_simple ("audio/x-qdm2",
+ "samplesize", G_TYPE_INT, 16,
+ "rate", G_TYPE_INT, rtpqdm2depay->samplerate,
+ "channels", G_TYPE_INT, rtpqdm2depay->channs,
+ "codec_data", GST_TYPE_BUFFER, codecdata, NULL);
+ gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), caps);
+ gst_caps_unref (caps);
+ rtpqdm2depay->configured = TRUE;
+ } else {
+ GST_DEBUG ("Already configured, skipping headers");
+ pos += 40;
+ }
+ break;
+ default:{
+ /* Shuffled packet contents */
+ guint packetid = payload[pos++];
+ guint packettype = payload[pos++];
+ guint packlen = payload[pos++];
+ guint hsize = 2;
+
+ GST_DEBUG ("Packet id:%d, type:0x%x, len:%d",
+ packetid, packettype, packlen);
+
+ /* Packets bigger than 0xff bytes have a type with the high bit set */
+ if (G_UNLIKELY (packettype & 0x80)) {
+ packettype &= 0x7f;
+ packlen <<= 8;
+ packlen |= payload[pos++];
+ hsize = 3;
+ GST_DEBUG ("Packet id:%d, type:0x%x, len:%d",
+ packetid, packettype, packlen);
+ }
+
+ if (packettype > 0x7f) {
+ GST_ERROR ("HOUSTON WE HAVE A PROBLEM !!!!");
+ }
+ add_packet (rtpqdm2depay, packetid, packlen + hsize,
+ payload + pos - hsize);
+ pos += packlen;
+ }
+ }
+ }
+
+ GST_DEBUG ("final pos %d", pos);
+
+ avail = gst_adapter_available (rtpqdm2depay->adapter);
+ if (G_UNLIKELY (avail)) {
+ GST_DEBUG ("Pushing out %d bytes of collected data", avail);
+ outbuf = gst_adapter_take_buffer (rtpqdm2depay->adapter, avail);
+ GST_BUFFER_TIMESTAMP (outbuf) = rtpqdm2depay->ptimestamp;
+ GST_DEBUG ("Outgoing buffer timestamp %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (rtpqdm2depay->ptimestamp));
+ }
+ }
+
+ gst_rtp_buffer_unmap (&rtp);
+ return outbuf;
+
+ /* ERRORS */
+bad_packet:
+ {
+ GST_ELEMENT_WARNING (rtpqdm2depay, STREAM, DECODE,
+ (NULL), ("Packet was too short"));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+}
+
+static GstStateChangeReturn
+gst_rtp_qdm2_depay_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstRtpQDM2Depay *rtpqdm2depay;
+ GstStateChangeReturn ret;
+
+ rtpqdm2depay = GST_RTP_QDM2_DEPAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_adapter_clear (rtpqdm2depay->adapter);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+gboolean
+gst_rtp_qdm2_depay_plugin_init (GstPlugin * plugin)
+{
+ GST_DEBUG_CATEGORY_INIT (rtpqdm2depay_debug, "rtpqdm2depay", 0,
+ "RTP QDM2 depayloader");
+
+ return gst_element_register (plugin, "rtpqdm2depay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_QDM2_DEPAY);
+}
diff --git a/gst/rtp/gstrtpqdmdepay.h b/gst/rtp/gstrtpqdmdepay.h
new file mode 100755
index 0000000..8a6b2b2
--- /dev/null
+++ b/gst/rtp/gstrtpqdmdepay.h
@@ -0,0 +1,85 @@
+/* GStreamer
+ * Copyright (C) <2009> Edward Hervey <bilboed@bilboed.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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_QDM2_DEPAY_H__
+#define __GST_RTP_QDM2_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_QDM2_DEPAY \
+ (gst_rtp_qdm2_depay_get_type())
+#define GST_RTP_QDM2_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_QDM2_DEPAY,GstRtpQDM2Depay))
+#define GST_RTP_QDM2_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_QDM2_DEPAY,GstRtpQDM2DepayClass))
+#define GST_IS_RTP_QDM2_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_QDM2_DEPAY))
+#define GST_IS_RTP_QDM2_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_QDM2_DEPAY))
+
+typedef struct _GstRtpQDM2Depay GstRtpQDM2Depay;
+typedef struct _GstRtpQDM2DepayClass GstRtpQDM2DepayClass;
+
+typedef struct _QDM2Packet {
+ guint8* data;
+ guint offs; /* Starts at 4 to give room for the prefix */
+} QDM2Packet;
+
+#define MAX_SCRAMBLED_PACKETS 64
+
+struct _GstRtpQDM2Depay
+{
+ GstRTPBaseDepayload depayload;
+
+ GstAdapter *adapter;
+
+ guint16 nextseq;
+ gboolean configured;
+
+ GstClockTime timestamp; /* Timestamp of current incoming data */
+ GstClockTime ptimestamp; /* Timestamp of data stored in the adapter */
+
+ guint32 channs;
+ guint32 samplerate;
+ guint32 bitrate;
+ guint32 blocksize;
+ guint32 framesize;
+ guint32 packetsize;
+
+ guint nbpackets; /* Number of packets to unscramble */
+
+ QDM2Packet *packets[MAX_SCRAMBLED_PACKETS];
+};
+
+struct _GstRtpQDM2DepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_qdm2_depay_get_type (void);
+
+gboolean gst_rtp_qdm2_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_QDM2_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpsbcdepay.c b/gst/rtp/gstrtpsbcdepay.c
new file mode 100755
index 0000000..28c00fc
--- /dev/null
+++ b/gst/rtp/gstrtpsbcdepay.c
@@ -0,0 +1,287 @@
+/*
+ * GStreamer RTP SBC depayloader
+ *
+ * Copyright (C) 2012 Collabora Ltd.
+ * @author: Arun Raghavan <arun.raghavan@collabora.co.uk>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include "gstrtpsbcdepay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpsbcdepay_debug);
+#define GST_CAT_DEFAULT (rtpsbcdepay_debug)
+
+static GstStaticPadTemplate gst_rtp_sbc_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-sbc, "
+ "rate = (int) { 16000, 32000, 44100, 48000 }, "
+ "channels = (int) [ 1, 2 ], "
+ "mode = (string) { mono, dual, stereo, joint }, "
+ "blocks = (int) { 4, 8, 12, 16 }, "
+ "subbands = (int) { 4, 8 }, "
+ "allocation-method = (string) { snr, loudness }, "
+ "bitpool = (int) [ 2, 64 ]")
+ );
+
+static GstStaticPadTemplate gst_rtp_sbc_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) audio,"
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) { 16000, 32000, 44100, 48000 },"
+ "encoding-name = (string) SBC")
+ );
+
+#define gst_rtp_sbc_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpSbcDepay, gst_rtp_sbc_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_sbc_depay_finalize (GObject * object);
+
+static gboolean gst_rtp_sbc_depay_setcaps (GstRTPBaseDepayload * base,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_sbc_depay_process (GstRTPBaseDepayload * base,
+ GstBuffer * in);
+
+static void
+gst_rtp_sbc_depay_class_init (GstRtpSbcDepayClass * klass)
+{
+ GstRTPBaseDepayloadClass *gstbasertpdepayload_class =
+ GST_RTP_BASE_DEPAYLOAD_CLASS (klass);
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = gst_rtp_sbc_depay_finalize;
+
+ gstbasertpdepayload_class->set_caps = gst_rtp_sbc_depay_setcaps;
+ gstbasertpdepayload_class->process = gst_rtp_sbc_depay_process;
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_rtp_sbc_depay_src_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_rtp_sbc_depay_sink_template));
+
+ GST_DEBUG_CATEGORY_INIT (rtpsbcdepay_debug, "rtpsbcdepay", 0,
+ "SBC Audio RTP Depayloader");
+
+ gst_element_class_set_static_metadata (element_class,
+ "RTP SBC audio depayloader",
+ "Codec/Depayloader/Network/RTP",
+ "Extracts SBC audio from RTP packets",
+ "Arun Raghavan <arun.raghavan@collabora.co.uk>");
+}
+
+static void
+gst_rtp_sbc_depay_init (GstRtpSbcDepay * rtpsbcdepay)
+{
+ rtpsbcdepay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_sbc_depay_finalize (GObject * object)
+{
+ GstRtpSbcDepay *depay = GST_RTP_SBC_DEPAY (object);
+
+ gst_object_unref (depay->adapter);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/* FIXME: This duplicates similar functionality rtpsbcpay, but there isn't a
+ * simple way to consolidate the two. This is best done by moving the function
+ * to the codec-utils library in gst-plugins-base when these elements move to
+ * GStreamer. */
+static int
+gst_rtp_sbc_depay_get_params (GstRtpSbcDepay * depay, const guint8 * data,
+ gint size, int *framelen, int *samples)
+{
+ int blocks, channel_mode, channels, subbands, bitpool;
+ int length;
+
+ if (size < 3) {
+ /* Not enough data for the header */
+ return -1;
+ }
+
+ /* Sanity check */
+ if (data[0] != 0x9c) {
+ GST_WARNING_OBJECT (depay, "Bad packet: couldn't find syncword");
+ return -2;
+ }
+
+ blocks = (data[1] >> 4) & 0x3;
+ blocks = (blocks + 1) * 4;
+ channel_mode = (data[1] >> 2) & 0x3;
+ channels = channel_mode ? 2 : 1;
+ subbands = (data[1] & 0x1);
+ subbands = (subbands + 1) * 4;
+ bitpool = data[2];
+
+ length = 4 + ((4 * subbands * channels) / 8);
+
+ if (channel_mode == 0 || channel_mode == 1) {
+ /* Mono || Dual channel */
+ length += ((blocks * channels * bitpool)
+ + 4 /* round up */ ) / 8;
+ } else {
+ /* Stereo || Joint stereo */
+ gboolean joint = (channel_mode == 3);
+
+ length += ((joint * subbands) + (blocks * bitpool)
+ + 4 /* round up */ ) / 8;
+ }
+
+ *framelen = length;
+ *samples = blocks * subbands;
+
+ return 0;
+}
+
+static gboolean
+gst_rtp_sbc_depay_setcaps (GstRTPBaseDepayload * base, GstCaps * caps)
+{
+ GstRtpSbcDepay *depay = GST_RTP_SBC_DEPAY (base);
+ GstStructure *structure;
+ GstCaps *outcaps, *oldcaps;
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "clock-rate", &depay->rate))
+ goto bad_caps;
+
+ outcaps = gst_caps_new_simple ("audio/x-sbc", "rate", G_TYPE_INT,
+ depay->rate, NULL);
+
+ gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (base), outcaps);
+
+ oldcaps = gst_pad_get_current_caps (GST_RTP_BASE_DEPAYLOAD_SINKPAD (base));
+ if (oldcaps && !gst_caps_can_intersect (oldcaps, caps)) {
+ /* Caps have changed, flush old data */
+ gst_adapter_clear (depay->adapter);
+ }
+
+ gst_caps_unref (outcaps);
+
+ return TRUE;
+
+bad_caps:
+ GST_WARNING_OBJECT (depay, "Can't support the caps we got: %"
+ GST_PTR_FORMAT, caps);
+ return FALSE;
+}
+
+static GstBuffer *
+gst_rtp_sbc_depay_process (GstRTPBaseDepayload * base, GstBuffer * in)
+{
+ GstRtpSbcDepay *depay = GST_RTP_SBC_DEPAY (base);
+ GstBuffer *data = NULL;
+ GstRTPBuffer rtp = { NULL };
+
+ gboolean fragment, start, last;
+ guint8 nframes;
+ guint8 *payload;
+ guint payload_len;
+
+ gst_rtp_buffer_map (in, GST_MAP_READ, &rtp);
+
+ GST_LOG_OBJECT (depay, "Got %" G_GSIZE_FORMAT " bytes",
+ gst_buffer_get_size (in));
+
+ if (gst_rtp_buffer_get_marker (&rtp)) {
+ /* Marker isn't supposed to be set */
+ GST_WARNING_OBJECT (depay, "Marker bit was set");
+ goto bad_packet;
+ }
+
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+
+ fragment = payload[0] & 0x80;
+ start = payload[0] & 0x40;
+ last = payload[0] & 0x20;
+ nframes = payload[0] & 0x0f;
+
+ payload += 1;
+ payload_len -= 1;
+
+ data = gst_rtp_buffer_get_payload_subbuffer (&rtp, 1, -1);
+
+ if (fragment) {
+ /* Got a packet with a fragment */
+ GST_LOG_OBJECT (depay, "Got fragment");
+
+ if (start && gst_adapter_available (depay->adapter)) {
+ GST_WARNING_OBJECT (depay, "Missing last fragment");
+ gst_adapter_clear (depay->adapter);
+
+ } else if (!start && !gst_adapter_available (depay->adapter)) {
+ GST_WARNING_OBJECT (depay, "Missing start fragment");
+ gst_buffer_unref (data);
+ data = NULL;
+ goto out;
+ }
+
+ gst_adapter_push (depay->adapter, data);
+
+ if (last) {
+ data = gst_adapter_take_buffer (depay->adapter,
+ gst_adapter_available (depay->adapter));
+ } else
+ data = NULL;
+
+ } else {
+ /* !fragment */
+ gint framelen, samples;
+
+ GST_LOG_OBJECT (depay, "Got %d frames", nframes);
+
+ if (gst_rtp_sbc_depay_get_params (depay, payload,
+ payload_len, &framelen, &samples) < 0) {
+ gst_adapter_clear (depay->adapter);
+ goto bad_packet;
+ }
+
+ GST_LOG_OBJECT (depay, "Got payload of %d", payload_len);
+
+ if (nframes * framelen > (gint) payload_len) {
+ GST_WARNING_OBJECT (depay, "Short packet");
+ goto bad_packet;
+ } else if (nframes * framelen < (gint) payload_len) {
+ GST_WARNING_OBJECT (depay, "Junk at end of packet");
+ }
+ }
+
+out:
+ gst_rtp_buffer_unmap (&rtp);
+ return data;
+
+bad_packet:
+ GST_ELEMENT_WARNING (depay, STREAM, DECODE,
+ ("Received invalid RTP payload, dropping"), (NULL));
+ goto out;
+}
+
+gboolean
+gst_rtp_sbc_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpsbcdepay", GST_RANK_SECONDARY,
+ GST_TYPE_RTP_SBC_DEPAY);
+}
diff --git a/gst/rtp/gstrtpsbcdepay.h b/gst/rtp/gstrtpsbcdepay.h
new file mode 100755
index 0000000..4147a31
--- /dev/null
+++ b/gst/rtp/gstrtpsbcdepay.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Collabora Ltd.
+ *
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __GST_RTP_SBC_DEPAY_H
+#define __GST_RTP_SBC_DEPAY_H
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_RTP_SBC_DEPAY \
+ (gst_rtp_sbc_depay_get_type())
+#define GST_RTP_SBC_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_SBC_DEPAY,\
+ GstRtpSbcDepay))
+#define GST_RTP_SBC_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_SBC_DEPAY,\
+ GstRtpSbcDepayClass))
+#define GST_IS_RTP_SBC_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_SBC_DEPAY))
+#define GST_IS_RTP_SBC_DEPAY_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_SBC_DEPAY))
+typedef struct _GstRtpSbcDepay GstRtpSbcDepay;
+typedef struct _GstRtpSbcDepayClass GstRtpSbcDepayClass;
+
+struct _GstRtpSbcDepay
+{
+ GstRTPBaseDepayload base;
+
+ int rate;
+ GstAdapter *adapter;
+};
+
+struct _GstRtpSbcDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_sbc_depay_get_type (void);
+
+gboolean gst_rtp_sbc_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif
diff --git a/gst/rtp/gstrtpsbcpay.c b/gst/rtp/gstrtpsbcpay.c
new file mode 100755
index 0000000..8a8f5cd
--- /dev/null
+++ b/gst/rtp/gstrtpsbcpay.c
@@ -0,0 +1,350 @@
+/* GStreamer RTP SBC payloader
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gstrtpsbcpay.h"
+#include <math.h>
+#include <string.h>
+
+#define RTP_SBC_PAYLOAD_HEADER_SIZE 1
+#define DEFAULT_MIN_FRAMES 0
+#define RTP_SBC_HEADER_TOTAL (12 + RTP_SBC_PAYLOAD_HEADER_SIZE)
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+
+/* FIXME: this seems all a bit over the top for a single byte.. */
+struct rtp_payload
+{
+ guint8 frame_count:4;
+ guint8 rfa0:1;
+ guint8 is_last_fragment:1;
+ guint8 is_first_fragment:1;
+ guint8 is_fragmented:1;
+} __attribute__ ((packed));
+
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+
+struct rtp_payload
+{
+ guint8 is_fragmented:1;
+ guint8 is_first_fragment:1;
+ guint8 is_last_fragment:1;
+ guint8 rfa0:1;
+ guint8 frame_count:4;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+enum
+{
+ PROP_0,
+ PROP_MIN_FRAMES
+};
+
+GST_DEBUG_CATEGORY_STATIC (gst_rtp_sbc_pay_debug);
+#define GST_CAT_DEFAULT gst_rtp_sbc_pay_debug
+
+#define parent_class gst_rtp_sbc_pay_parent_class
+G_DEFINE_TYPE (GstRtpSBCPay, gst_rtp_sbc_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static GstStaticPadTemplate gst_rtp_sbc_pay_sink_factory =
+GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-sbc, "
+ "rate = (int) { 16000, 32000, 44100, 48000 }, "
+ "channels = (int) [ 1, 2 ], "
+ "channel-mode = (string) { mono, dual, stereo, joint }, "
+ "blocks = (int) { 4, 8, 12, 16 }, "
+ "subbands = (int) { 4, 8 }, "
+ "allocation-method = (string) { snr, loudness }, "
+ "bitpool = (int) [ 2, 64 ]")
+ );
+
+static GstStaticPadTemplate gst_rtp_sbc_pay_src_factory =
+GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) audio,"
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) { 16000, 32000, 44100, 48000 },"
+ "encoding-name = (string) SBC")
+ );
+
+static void gst_rtp_sbc_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_rtp_sbc_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static gint
+gst_rtp_sbc_pay_get_frame_len (gint subbands, gint channels,
+ gint blocks, gint bitpool, const gchar * channel_mode)
+{
+ gint len;
+ gint join;
+
+ len = 4 + (4 * subbands * channels) / 8;
+
+ if (strcmp (channel_mode, "mono") == 0 || strcmp (channel_mode, "dual") == 0)
+ len += ((blocks * channels * bitpool) + 7) / 8;
+ else {
+ join = strcmp (channel_mode, "joint") == 0 ? 1 : 0;
+ len += ((join * subbands + blocks * bitpool) + 7) / 8;
+ }
+
+ return len;
+}
+
+static gboolean
+gst_rtp_sbc_pay_set_caps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ GstRtpSBCPay *sbcpay;
+ gint rate, subbands, channels, blocks, bitpool;
+ gint frame_len;
+ const gchar *channel_mode;
+ GstStructure *structure;
+
+ sbcpay = GST_RTP_SBC_PAY (payload);
+
+ structure = gst_caps_get_structure (caps, 0);
+ if (!gst_structure_get_int (structure, "rate", &rate))
+ return FALSE;
+ if (!gst_structure_get_int (structure, "channels", &channels))
+ return FALSE;
+ if (!gst_structure_get_int (structure, "blocks", &blocks))
+ return FALSE;
+ if (!gst_structure_get_int (structure, "bitpool", &bitpool))
+ return FALSE;
+ if (!gst_structure_get_int (structure, "subbands", &subbands))
+ return FALSE;
+
+ channel_mode = gst_structure_get_string (structure, "channel-mode");
+ if (!channel_mode)
+ return FALSE;
+
+ frame_len = gst_rtp_sbc_pay_get_frame_len (subbands, channels, blocks,
+ bitpool, channel_mode);
+
+ sbcpay->frame_length = frame_len;
+
+ gst_rtp_base_payload_set_options (payload, "audio", TRUE, "SBC", rate);
+
+ GST_DEBUG_OBJECT (payload, "calculated frame length: %d ", frame_len);
+
+ return gst_rtp_base_payload_set_outcaps (payload, NULL);
+}
+
+static GstFlowReturn
+gst_rtp_sbc_pay_flush_buffers (GstRtpSBCPay * sbcpay)
+{
+ GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+ guint available;
+ guint max_payload;
+ GstBuffer *outbuf;
+ guint8 *payload_data;
+ guint frame_count;
+ guint payload_length;
+ struct rtp_payload *payload;
+
+ if (sbcpay->frame_length == 0) {
+ GST_ERROR_OBJECT (sbcpay, "Frame length is 0");
+ return GST_FLOW_ERROR;
+ }
+
+ available = gst_adapter_available (sbcpay->adapter);
+
+ max_payload =
+ gst_rtp_buffer_calc_payload_len (GST_RTP_BASE_PAYLOAD_MTU (sbcpay) -
+ RTP_SBC_PAYLOAD_HEADER_SIZE, 0, 0);
+
+ max_payload = MIN (max_payload, available);
+ frame_count = max_payload / sbcpay->frame_length;
+ payload_length = frame_count * sbcpay->frame_length;
+ if (payload_length == 0) /* Nothing to send */
+ return GST_FLOW_OK;
+
+ outbuf = gst_rtp_buffer_new_allocate (payload_length +
+ RTP_SBC_PAYLOAD_HEADER_SIZE, 0, 0);
+
+ /* get payload */
+ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+
+ gst_rtp_buffer_set_payload_type (&rtp, GST_RTP_BASE_PAYLOAD_PT (sbcpay));
+
+ /* write header and copy data into payload */
+ payload_data = gst_rtp_buffer_get_payload (&rtp);
+ payload = (struct rtp_payload *) payload_data;
+ memset (payload, 0, sizeof (struct rtp_payload));
+ payload->frame_count = frame_count;
+
+ gst_adapter_copy (sbcpay->adapter, payload_data +
+ RTP_SBC_PAYLOAD_HEADER_SIZE, 0, payload_length);
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ gst_adapter_flush (sbcpay->adapter, payload_length);
+
+ /* FIXME: what about duration? */
+ GST_BUFFER_TIMESTAMP (outbuf) = sbcpay->timestamp;
+ GST_DEBUG_OBJECT (sbcpay, "Pushing %d bytes", payload_length);
+
+ return gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (sbcpay), outbuf);
+}
+
+static GstFlowReturn
+gst_rtp_sbc_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
+{
+ GstRtpSBCPay *sbcpay;
+ guint available;
+
+ /* FIXME check for negotiation */
+
+ sbcpay = GST_RTP_SBC_PAY (payload);
+ sbcpay->timestamp = GST_BUFFER_TIMESTAMP (buffer);
+
+ gst_adapter_push (sbcpay->adapter, buffer);
+
+ available = gst_adapter_available (sbcpay->adapter);
+ if (available + RTP_SBC_HEADER_TOTAL >=
+ GST_RTP_BASE_PAYLOAD_MTU (sbcpay) ||
+ (available > (sbcpay->min_frames * sbcpay->frame_length)))
+ return gst_rtp_sbc_pay_flush_buffers (sbcpay);
+
+ return GST_FLOW_OK;
+}
+
+static gboolean
+gst_rtp_sbc_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+ GstRtpSBCPay *sbcpay = GST_RTP_SBC_PAY (payload);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_EOS:
+ gst_rtp_sbc_pay_flush_buffers (sbcpay);
+ break;
+ default:
+ break;
+ }
+
+ return GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
+}
+
+static void
+gst_rtp_sbc_pay_finalize (GObject * object)
+{
+ GstRtpSBCPay *sbcpay = GST_RTP_SBC_PAY (object);
+
+ g_object_unref (sbcpay->adapter);
+
+ GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
+}
+
+static void
+gst_rtp_sbc_pay_class_init (GstRtpSBCPayClass * klass)
+{
+ GstRTPBasePayloadClass *payload_class = GST_RTP_BASE_PAYLOAD_CLASS (klass);
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = gst_rtp_sbc_pay_finalize;
+ gobject_class->set_property = gst_rtp_sbc_pay_set_property;
+ gobject_class->get_property = gst_rtp_sbc_pay_get_property;
+
+ payload_class->set_caps = GST_DEBUG_FUNCPTR (gst_rtp_sbc_pay_set_caps);
+ payload_class->handle_buffer =
+ GST_DEBUG_FUNCPTR (gst_rtp_sbc_pay_handle_buffer);
+ payload_class->sink_event = GST_DEBUG_FUNCPTR (gst_rtp_sbc_pay_sink_event);
+
+ /* properties */
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_MIN_FRAMES,
+ g_param_spec_int ("min-frames", "minimum frame number",
+ "Minimum quantity of frames to send in one packet "
+ "(-1 for maximum allowed by the mtu)",
+ -1, G_MAXINT, DEFAULT_MIN_FRAMES, G_PARAM_READWRITE));
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_rtp_sbc_pay_sink_factory));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_rtp_sbc_pay_src_factory));
+
+ gst_element_class_set_static_metadata (element_class, "RTP packet payloader",
+ "Codec/Payloader/Network", "Payload SBC audio as RTP packets",
+ "Thiago Sousa Santos <thiagoss@lcc.ufcg.edu.br>");
+
+ GST_DEBUG_CATEGORY_INIT (gst_rtp_sbc_pay_debug, "rtpsbcpay", 0,
+ "RTP SBC payloader");
+}
+
+static void
+gst_rtp_sbc_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstRtpSBCPay *sbcpay;
+
+ sbcpay = GST_RTP_SBC_PAY (object);
+
+ switch (prop_id) {
+ case PROP_MIN_FRAMES:
+ sbcpay->min_frames = g_value_get_int (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_rtp_sbc_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstRtpSBCPay *sbcpay;
+
+ sbcpay = GST_RTP_SBC_PAY (object);
+
+ switch (prop_id) {
+ case PROP_MIN_FRAMES:
+ g_value_set_int (value, sbcpay->min_frames);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_rtp_sbc_pay_init (GstRtpSBCPay * self)
+{
+ self->adapter = gst_adapter_new ();
+ self->frame_length = 0;
+ self->timestamp = 0;
+
+ self->min_frames = DEFAULT_MIN_FRAMES;
+}
+
+gboolean
+gst_rtp_sbc_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpsbcpay", GST_RANK_NONE,
+ GST_TYPE_RTP_SBC_PAY);
+}
diff --git a/gst/rtp/gstrtpsbcpay.h b/gst/rtp/gstrtpsbcpay.h
new file mode 100755
index 0000000..42cf02e
--- /dev/null
+++ b/gst/rtp/gstrtpsbcpay.h
@@ -0,0 +1,64 @@
+/* GStreamer RTP SBC payloader
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_SBC_PAY \
+ (gst_rtp_sbc_pay_get_type())
+#define GST_RTP_SBC_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_SBC_PAY,\
+ GstRtpSBCPay))
+#define GST_RTP_SBC_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_SBC_PAY,\
+ GstRtpSBCPayClass))
+#define GST_IS_RTP_SBC_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_SBC_PAY))
+#define GST_IS_RTP_SBC_PAY_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_SBC_PAY))
+
+typedef struct _GstRtpSBCPay GstRtpSBCPay;
+typedef struct _GstRtpSBCPayClass GstRtpSBCPayClass;
+
+struct _GstRtpSBCPay {
+ GstRTPBasePayload base;
+
+ GstAdapter *adapter;
+ GstClockTime timestamp;
+
+ guint frame_length;
+
+ guint min_frames;
+};
+
+struct _GstRtpSBCPayClass {
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_sbc_pay_get_type(void);
+
+gboolean gst_rtp_sbc_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
diff --git a/gst/rtp/gstrtpsirendepay.c b/gst/rtp/gstrtpsirendepay.c
new file mode 100755
index 0000000..1bbbda7
--- /dev/null
+++ b/gst/rtp/gstrtpsirendepay.c
@@ -0,0 +1,123 @@
+/*
+ * Siren Depayloader Gst Element
+ *
+ * @author: Youness Alaoui <kakaroto@kakaroto.homelinux.net>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include "gstrtpsirendepay.h"
+
+static GstStaticPadTemplate gst_rtp_siren_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "clock-rate = (int) 16000, "
+ "encoding-name = (string) \"SIREN\"")
+ /* This is the default, so the peer doesn't have to specify it */
+ /* " "dct-length = (int) 320") */
+ );
+
+static GstStaticPadTemplate gst_rtp_siren_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-siren, " "dct-length = (int) 320")
+ );
+
+static GstBuffer *gst_rtp_siren_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+static gboolean gst_rtp_siren_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+
+G_DEFINE_TYPE (GstRTPSirenDepay, gst_rtp_siren_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_siren_depay_class_init (GstRTPSirenDepayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gstrtpbasedepayload_class->process = gst_rtp_siren_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_siren_depay_setcaps;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_siren_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_siren_depay_sink_template));
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP Siren packet depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts Siren audio from RTP packets",
+ "Philippe Kalaf <philippe.kalaf@collabora.co.uk>");
+}
+
+static void
+gst_rtp_siren_depay_init (GstRTPSirenDepay * rtpsirendepay)
+{
+
+}
+
+static gboolean
+gst_rtp_siren_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstCaps *srccaps;
+ gboolean ret;
+
+ srccaps = gst_caps_new_simple ("audio/x-siren",
+ "dct-length", G_TYPE_INT, 320, NULL);
+ ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+
+ GST_DEBUG ("set caps on source: %" GST_PTR_FORMAT " (ret=%d)", srccaps, ret);
+ gst_caps_unref (srccaps);
+
+ /* always fixed clock rate of 16000 */
+ depayload->clock_rate = 16000;
+
+ return ret;
+}
+
+static GstBuffer *
+gst_rtp_siren_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstBuffer *outbuf;
+ GstRTPBuffer rtp = { NULL };
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+ outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
+ gst_rtp_buffer_unmap (&rtp);
+
+ return outbuf;
+}
+
+gboolean
+gst_rtp_siren_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpsirendepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_SIREN_DEPAY);
+}
diff --git a/gst/rtp/gstrtpsirendepay.h b/gst/rtp/gstrtpsirendepay.h
new file mode 100755
index 0000000..d1ffb11
--- /dev/null
+++ b/gst/rtp/gstrtpsirendepay.h
@@ -0,0 +1,59 @@
+/*
+ * Siren Depayloader Gst Element
+ *
+ * @author: Youness Alaoui <kakaroto@kakaroto.homelinux.net>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_SIREN_DEPAY_H__
+#define __GST_RTP_SIREN_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS typedef struct _GstRTPSirenDepay GstRTPSirenDepay;
+typedef struct _GstRTPSirenDepayClass GstRTPSirenDepayClass;
+
+#define GST_TYPE_RTP_SIREN_DEPAY \
+ (gst_rtp_siren_depay_get_type())
+#define GST_RTP_SIREN_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_SIREN_DEPAY,GstRTPSirenDepay))
+#define GST_RTP_SIREN_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_SIREN_DEPAY,GstRTPSirenDepayClass))
+#define GST_IS_RTP_SIREN_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_SIREN_DEPAY))
+#define GST_IS_RTP_SIREN_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_SIREN_DEPAY))
+
+
+struct _GstRTPSirenDepay
+{
+ GstRTPBaseDepayload depayload;
+
+};
+
+struct _GstRTPSirenDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_siren_depay_get_type (void);
+
+gboolean gst_rtp_siren_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_SIREN_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpsirenpay.c b/gst/rtp/gstrtpsirenpay.c
new file mode 100755
index 0000000..2277fec
--- /dev/null
+++ b/gst/rtp/gstrtpsirenpay.c
@@ -0,0 +1,147 @@
+/*
+ * Siren Payloader Gst Element
+ *
+ * @author: Youness Alaoui <kakaroto@kakaroto.homelinux.net>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstrtpsirenpay.h"
+#include <gst/rtp/gstrtpbuffer.h>
+
+GST_DEBUG_CATEGORY_STATIC (rtpsirenpay_debug);
+#define GST_CAT_DEFAULT (rtpsirenpay_debug)
+
+static GstStaticPadTemplate gst_rtp_siren_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-siren, " "dct-length = (int) 320")
+ );
+
+static GstStaticPadTemplate gst_rtp_siren_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) 16000, "
+ "encoding-name = (string) \"SIREN\", "
+ "bitrate = (string) \"16000\", " "dct-length = (int) 320")
+ );
+
+static gboolean gst_rtp_siren_pay_setcaps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+
+G_DEFINE_TYPE (GstRTPSirenPay, gst_rtp_siren_pay,
+ GST_TYPE_RTP_BASE_AUDIO_PAYLOAD);
+
+static void
+gst_rtp_siren_pay_class_init (GstRTPSirenPayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_siren_pay_setcaps;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_siren_pay_sink_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_siren_pay_src_template));
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP Payloader for Siren Audio", "Codec/Payloader/Network/RTP",
+ "Packetize Siren audio streams into RTP packets",
+ "Youness Alaoui <kakaroto@kakaroto.homelinux.net>");
+
+ GST_DEBUG_CATEGORY_INIT (rtpsirenpay_debug, "rtpsirenpay", 0,
+ "siren audio RTP payloader");
+}
+
+static void
+gst_rtp_siren_pay_init (GstRTPSirenPay * rtpsirenpay)
+{
+ GstRTPBasePayload *rtpbasepayload;
+ GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+
+ rtpbasepayload = GST_RTP_BASE_PAYLOAD (rtpsirenpay);
+ rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpsirenpay);
+
+ /* we don't set the payload type, it should be set by the application using
+ * the pt property or the default 96 will be used */
+ rtpbasepayload->clock_rate = 16000;
+
+ /* tell rtpbaseaudiopayload that this is a frame based codec */
+ gst_rtp_base_audio_payload_set_frame_based (rtpbaseaudiopayload);
+}
+
+static gboolean
+gst_rtp_siren_pay_setcaps (GstRTPBasePayload * rtpbasepayload, GstCaps * caps)
+{
+ GstRTPSirenPay *rtpsirenpay;
+ GstRTPBaseAudioPayload *rtpbaseaudiopayload;
+ gint dct_length;
+ GstStructure *structure;
+ const char *payload_name;
+
+ rtpsirenpay = GST_RTP_SIREN_PAY (rtpbasepayload);
+ rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpbasepayload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ gst_structure_get_int (structure, "dct-length", &dct_length);
+ if (dct_length != 320)
+ goto wrong_dct;
+
+ payload_name = gst_structure_get_name (structure);
+ if (g_ascii_strcasecmp ("audio/x-siren", payload_name))
+ goto wrong_caps;
+
+ gst_rtp_base_payload_set_options (rtpbasepayload, "audio", TRUE, "SIREN",
+ 16000);
+ /* set options for this frame based audio codec */
+ gst_rtp_base_audio_payload_set_frame_options (rtpbaseaudiopayload, 20, 40);
+
+ return gst_rtp_base_payload_set_outcaps (rtpbasepayload, NULL);
+
+ /* ERRORS */
+wrong_dct:
+ {
+ GST_ERROR_OBJECT (rtpsirenpay, "dct-length must be 320, received %d",
+ dct_length);
+ return FALSE;
+ }
+wrong_caps:
+ {
+ GST_ERROR_OBJECT (rtpsirenpay, "expected audio/x-siren, received %s",
+ payload_name);
+ return FALSE;
+ }
+}
+
+gboolean
+gst_rtp_siren_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpsirenpay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_SIREN_PAY);
+}
diff --git a/gst/rtp/gstrtpsirenpay.h b/gst/rtp/gstrtpsirenpay.h
new file mode 100755
index 0000000..eaba5b5
--- /dev/null
+++ b/gst/rtp/gstrtpsirenpay.h
@@ -0,0 +1,57 @@
+/*
+ * Siren Payloader Gst Element
+ *
+ * @author: Youness Alaoui <kakaroto@kakaroto.homelinux.net>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_SIREN_PAY_H__
+#define __GST_RTP_SIREN_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbaseaudiopayload.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_RTP_SIREN_PAY \
+ (gst_rtp_siren_pay_get_type())
+#define GST_RTP_SIREN_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_SIREN_PAY,GstRTPSirenPay))
+#define GST_RTP_SIREN_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_SIREN_PAY,GstRTPSirenPayClass))
+#define GST_IS_RTP_SIREN_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_SIREN_PAY))
+#define GST_IS_RTP_SIREN_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_SIREN_PAY))
+typedef struct _GstRTPSirenPay GstRTPSirenPay;
+typedef struct _GstRTPSirenPayClass GstRTPSirenPayClass;
+
+struct _GstRTPSirenPay
+{
+ GstRTPBaseAudioPayload audiopayload;
+};
+
+struct _GstRTPSirenPayClass
+{
+ GstRTPBaseAudioPayloadClass parent_class;
+};
+
+GType gst_rtp_siren_pay_get_type (void);
+
+gboolean gst_rtp_siren_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+#endif /* __GST_RTP_SIREN_PAY_H__ */
diff --git a/gst/rtp/gstrtpspeexdepay.c b/gst/rtp/gstrtpspeexdepay.c
new file mode 100755
index 0000000..efe7357
--- /dev/null
+++ b/gst/rtp/gstrtpspeexdepay.c
@@ -0,0 +1,225 @@
+/* GStreamer
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@indt.org.br>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpspeexdepay.h"
+
+/* RtpSPEEXDepay signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0
+};
+
+static GstStaticPadTemplate gst_rtp_speex_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "clock-rate = (int) [6000, 48000], "
+ "encoding-name = (string) \"SPEEX\"")
+ /* "encoding-params = (string) \"1\"" */
+ );
+
+static GstStaticPadTemplate gst_rtp_speex_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-speex")
+ );
+
+static GstBuffer *gst_rtp_speex_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+static gboolean gst_rtp_speex_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+
+G_DEFINE_TYPE (GstRtpSPEEXDepay, gst_rtp_speex_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void
+gst_rtp_speex_depay_class_init (GstRtpSPEEXDepayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gstrtpbasedepayload_class->process = gst_rtp_speex_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_speex_depay_setcaps;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_speex_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_speex_depay_sink_template));
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP Speex depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts Speex audio from RTP packets",
+ "Edgard Lima <edgard.lima@indt.org.br>");
+}
+
+static void
+gst_rtp_speex_depay_init (GstRtpSPEEXDepay * rtpspeexdepay)
+{
+}
+
+static gint
+gst_rtp_speex_depay_get_mode (gint rate)
+{
+ if (rate > 25000)
+ return 2;
+ else if (rate > 12500)
+ return 1;
+ else
+ return 0;
+}
+
+/* len 4 bytes LE,
+ * vendor string (len bytes),
+ * user_len 4 (0) bytes LE
+ */
+static const gchar gst_rtp_speex_comment[] =
+ "\045\0\0\0Depayloaded with GStreamer speexdepay\0\0\0\0";
+
+static gboolean
+gst_rtp_speex_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstStructure *structure;
+ GstRtpSPEEXDepay *rtpspeexdepay;
+ gint clock_rate, nb_channels;
+ GstBuffer *buf;
+ GstMapInfo map;
+ guint8 *data;
+ const gchar *params;
+ GstCaps *srccaps;
+ gboolean res;
+
+ rtpspeexdepay = GST_RTP_SPEEX_DEPAY (depayload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ goto no_clockrate;
+ depayload->clock_rate = clock_rate;
+
+ if (!(params = gst_structure_get_string (structure, "encoding-params")))
+ nb_channels = 1;
+ else {
+ nb_channels = atoi (params);
+ }
+
+ /* construct minimal header and comment packet for the decoder */
+ buf = gst_buffer_new_and_alloc (80);
+ gst_buffer_map (buf, &map, GST_MAP_WRITE);
+ data = map.data;
+ memcpy (data, "Speex ", 8);
+ data += 8;
+ memcpy (data, "1.1.12", 7);
+ data += 20;
+ GST_WRITE_UINT32_LE (data, 1); /* version */
+ data += 4;
+ GST_WRITE_UINT32_LE (data, 80); /* header_size */
+ data += 4;
+ GST_WRITE_UINT32_LE (data, clock_rate); /* rate */
+ data += 4;
+ GST_WRITE_UINT32_LE (data, gst_rtp_speex_depay_get_mode (clock_rate)); /* mode */
+ data += 4;
+ GST_WRITE_UINT32_LE (data, 4); /* mode_bitstream_version */
+ data += 4;
+ GST_WRITE_UINT32_LE (data, nb_channels); /* nb_channels */
+ data += 4;
+ GST_WRITE_UINT32_LE (data, -1); /* bitrate */
+ data += 4;
+ GST_WRITE_UINT32_LE (data, 0xa0); /* frame_size */
+ data += 4;
+ GST_WRITE_UINT32_LE (data, 0); /* VBR */
+ data += 4;
+ GST_WRITE_UINT32_LE (data, 1); /* frames_per_packet */
+ data += 4;
+ GST_WRITE_UINT32_LE (data, 0); /* extra_headers */
+ data += 4;
+ GST_WRITE_UINT32_LE (data, 0); /* reserved1 */
+ data += 4;
+ GST_WRITE_UINT32_LE (data, 0); /* reserved2 */
+ gst_buffer_unmap (buf, &map);
+
+ srccaps = gst_caps_new_empty_simple ("audio/x-speex");
+ res = gst_pad_set_caps (depayload->srcpad, srccaps);
+ gst_caps_unref (srccaps);
+
+ gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpspeexdepay), buf);
+
+ buf = gst_buffer_new_and_alloc (sizeof (gst_rtp_speex_comment));
+ gst_buffer_fill (buf, 0, gst_rtp_speex_comment,
+ sizeof (gst_rtp_speex_comment));
+
+ gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpspeexdepay), buf);
+
+ return res;
+
+ /* ERRORS */
+no_clockrate:
+ {
+ GST_DEBUG_OBJECT (depayload, "no clock-rate specified");
+ return FALSE;
+ }
+}
+
+static GstBuffer *
+gst_rtp_speex_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstBuffer *outbuf = NULL;
+ GstRTPBuffer rtp = { NULL };
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d",
+ gst_buffer_get_size (buf),
+ gst_rtp_buffer_get_marker (&rtp),
+ gst_rtp_buffer_get_timestamp (&rtp), gst_rtp_buffer_get_seq (&rtp));
+
+ /* nothing special to be done */
+ outbuf = gst_rtp_buffer_get_payload_buffer (&rtp);
+ gst_rtp_buffer_unmap (&rtp);
+
+ if (outbuf)
+ GST_BUFFER_DURATION (outbuf) = 20 * GST_MSECOND;
+
+ return outbuf;
+}
+
+gboolean
+gst_rtp_speex_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpspeexdepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_SPEEX_DEPAY);
+}
diff --git a/gst/rtp/gstrtpspeexdepay.h b/gst/rtp/gstrtpspeexdepay.h
new file mode 100755
index 0000000..f78d32c
--- /dev/null
+++ b/gst/rtp/gstrtpspeexdepay.h
@@ -0,0 +1,53 @@
+/* GStreamer
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@indt.org.br>
+ *
+ * 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
+ */
+
+#ifndef __GST_RTP_SPEEX_DEPAY_H__
+#define __GST_RTP_SPEEX_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRtpSPEEXDepay GstRtpSPEEXDepay;
+typedef struct _GstRtpSPEEXDepayClass GstRtpSPEEXDepayClass;
+
+#define GST_TYPE_RTP_SPEEX_DEPAY \
+ (gst_rtp_speex_depay_get_type())
+#define GST_RTP_SPEEX_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_SPEEX_DEPAY,GstRtpSPEEXDepay))
+#define GST_RTP_SPEEX_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_SPEEX_DEPAY,GstRtpSPEEXDepayClass))
+#define GST_IS_RTP_SPEEX_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_SPEEX_DEPAY))
+#define GST_IS_RTP_SPEEX_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_SPEEX_DEPAY))
+
+struct _GstRtpSPEEXDepay
+{
+ GstRTPBaseDepayload depayload;
+};
+
+struct _GstRtpSPEEXDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_speex_depay_get_type (void);
+
+gboolean gst_rtp_speex_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_SPEEX_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpspeexpay.c b/gst/rtp/gstrtpspeexpay.c
new file mode 100755
index 0000000..1f83866
--- /dev/null
+++ b/gst/rtp/gstrtpspeexpay.c
@@ -0,0 +1,352 @@
+/* GStreamer
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@indt.org.br>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpspeexpay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpspeexpay_debug);
+#define GST_CAT_DEFAULT (rtpspeexpay_debug)
+
+static GstStaticPadTemplate gst_rtp_speex_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-speex, "
+ "rate = (int) [ 6000, 48000 ], " "channels = (int) 1")
+ );
+
+static GstStaticPadTemplate gst_rtp_speex_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) [ 6000, 48000 ], "
+ "encoding-name = (string) \"SPEEX\", "
+ "encoding-params = (string) \"1\"")
+ );
+
+static GstStateChangeReturn gst_rtp_speex_pay_change_state (GstElement *
+ element, GstStateChange transition);
+
+static gboolean gst_rtp_speex_pay_setcaps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+static GstCaps *gst_rtp_speex_pay_getcaps (GstRTPBasePayload * payload,
+ GstPad * pad, GstCaps * filter);
+static GstFlowReturn gst_rtp_speex_pay_handle_buffer (GstRTPBasePayload *
+ payload, GstBuffer * buffer);
+
+#define gst_rtp_speex_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpSPEEXPay, gst_rtp_speex_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static void
+gst_rtp_speex_pay_class_init (GstRtpSPEEXPayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gstelement_class->change_state = gst_rtp_speex_pay_change_state;
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_speex_pay_setcaps;
+ gstrtpbasepayload_class->get_caps = gst_rtp_speex_pay_getcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_speex_pay_handle_buffer;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_speex_pay_sink_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_speex_pay_src_template));
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP Speex payloader", "Codec/Payloader/Network/RTP",
+ "Payload-encodes Speex audio into a RTP packet",
+ "Edgard Lima <edgard.lima@indt.org.br>");
+
+ GST_DEBUG_CATEGORY_INIT (rtpspeexpay_debug, "rtpspeexpay", 0,
+ "Speex RTP Payloader");
+}
+
+static void
+gst_rtp_speex_pay_init (GstRtpSPEEXPay * rtpspeexpay)
+{
+ GST_RTP_BASE_PAYLOAD (rtpspeexpay)->clock_rate = 8000;
+ GST_RTP_BASE_PAYLOAD_PT (rtpspeexpay) = 110; /* Create String */
+}
+
+static gboolean
+gst_rtp_speex_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ /* don't configure yet, we wait for the ident packet */
+ return TRUE;
+}
+
+
+static GstCaps *
+gst_rtp_speex_pay_getcaps (GstRTPBasePayload * payload, GstPad * pad,
+ GstCaps * filter)
+{
+ GstCaps *otherpadcaps;
+ GstCaps *caps;
+
+ otherpadcaps = gst_pad_get_allowed_caps (payload->srcpad);
+ caps = gst_pad_get_pad_template_caps (pad);
+
+ if (otherpadcaps) {
+ if (!gst_caps_is_empty (otherpadcaps)) {
+ GstStructure *ps;
+ GstStructure *s;
+ gint clock_rate;
+
+ ps = gst_caps_get_structure (otherpadcaps, 0);
+ caps = gst_caps_make_writable (caps);
+ s = gst_caps_get_structure (caps, 0);
+
+ if (gst_structure_get_int (ps, "clock-rate", &clock_rate)) {
+ gst_structure_fixate_field_nearest_int (s, "rate", clock_rate);
+ }
+ }
+ gst_caps_unref (otherpadcaps);
+ }
+
+ if (filter) {
+ GstCaps *tcaps = caps;
+
+ caps = gst_caps_intersect_full (filter, tcaps, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (tcaps);
+ }
+
+ return caps;
+}
+
+static gboolean
+gst_rtp_speex_pay_parse_ident (GstRtpSPEEXPay * rtpspeexpay,
+ const guint8 * data, guint size)
+{
+ guint32 version, header_size, rate, mode, nb_channels;
+ GstRTPBasePayload *payload;
+ gchar *cstr;
+ gboolean res;
+
+ /* we need the header string (8), the version string (20), the version
+ * and the header length. */
+ if (size < 36)
+ goto too_small;
+
+ if (!g_str_has_prefix ((const gchar *) data, "Speex "))
+ goto wrong_header;
+
+ /* skip header and version string */
+ data += 28;
+
+ version = GST_READ_UINT32_LE (data);
+ if (version != 1)
+ goto wrong_version;
+
+ data += 4;
+ /* ensure sizes */
+ header_size = GST_READ_UINT32_LE (data);
+ if (header_size < 80)
+ goto header_too_small;
+
+ if (size < header_size)
+ goto payload_too_small;
+
+ data += 4;
+ rate = GST_READ_UINT32_LE (data);
+ data += 4;
+ mode = GST_READ_UINT32_LE (data);
+ data += 8;
+ nb_channels = GST_READ_UINT32_LE (data);
+
+ GST_DEBUG_OBJECT (rtpspeexpay, "rate %d, mode %d, nb_channels %d",
+ rate, mode, nb_channels);
+
+ payload = GST_RTP_BASE_PAYLOAD (rtpspeexpay);
+
+ gst_rtp_base_payload_set_options (payload, "audio", FALSE, "SPEEX", rate);
+ cstr = g_strdup_printf ("%d", nb_channels);
+ res = gst_rtp_base_payload_set_outcaps (payload, "encoding-params",
+ G_TYPE_STRING, cstr, NULL);
+ g_free (cstr);
+
+ return res;
+
+ /* ERRORS */
+too_small:
+ {
+ GST_DEBUG_OBJECT (rtpspeexpay,
+ "ident packet too small, need at least 32 bytes");
+ return FALSE;
+ }
+wrong_header:
+ {
+ GST_DEBUG_OBJECT (rtpspeexpay,
+ "ident packet does not start with \"Speex \"");
+ return FALSE;
+ }
+wrong_version:
+ {
+ GST_DEBUG_OBJECT (rtpspeexpay, "can only handle version 1, have version %d",
+ version);
+ return FALSE;
+ }
+header_too_small:
+ {
+ GST_DEBUG_OBJECT (rtpspeexpay,
+ "header size too small, need at least 80 bytes, " "got only %d",
+ header_size);
+ return FALSE;
+ }
+payload_too_small:
+ {
+ GST_DEBUG_OBJECT (rtpspeexpay,
+ "payload too small, need at least %d bytes, got only %d", header_size,
+ size);
+ return FALSE;
+ }
+}
+
+static GstFlowReturn
+gst_rtp_speex_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer)
+{
+ GstRtpSPEEXPay *rtpspeexpay;
+ guint payload_len;
+ GstMapInfo map;
+ GstBuffer *outbuf;
+ guint8 *payload;
+ GstClockTime timestamp, duration;
+ GstFlowReturn ret;
+ GstRTPBuffer rtp = { NULL };
+
+ rtpspeexpay = GST_RTP_SPEEX_PAY (basepayload);
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+
+ switch (rtpspeexpay->packet) {
+ case 0:
+ /* ident packet. We need to parse the headers to construct the RTP
+ * properties. */
+ if (!gst_rtp_speex_pay_parse_ident (rtpspeexpay, map.data, map.size))
+ goto parse_error;
+
+ ret = GST_FLOW_OK;
+ goto done;
+ case 1:
+ /* comment packet, we ignore it */
+ ret = GST_FLOW_OK;
+ goto done;
+ default:
+ /* other packets go in the payload */
+ break;
+ }
+
+ if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_GAP)) {
+ ret = GST_FLOW_OK;
+ goto done;
+ }
+
+ timestamp = GST_BUFFER_TIMESTAMP (buffer);
+ duration = GST_BUFFER_DURATION (buffer);
+
+ /* FIXME, only one SPEEX frame per RTP packet for now */
+ payload_len = map.size;
+
+ outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
+ /* FIXME, assert for now */
+ g_assert (payload_len <= GST_RTP_BASE_PAYLOAD_MTU (rtpspeexpay));
+
+ /* copy timestamp and duration */
+ GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
+ GST_BUFFER_DURATION (outbuf) = duration;
+
+ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+ /* get payload */
+ payload = gst_rtp_buffer_get_payload (&rtp);
+
+ /* copy data in payload */
+ memcpy (&payload[0], map.data, map.size);
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ ret = gst_rtp_base_payload_push (basepayload, outbuf);
+
+done:
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+
+ rtpspeexpay->packet++;
+
+ return ret;
+
+ /* ERRORS */
+parse_error:
+ {
+ GST_ELEMENT_ERROR (rtpspeexpay, STREAM, DECODE, (NULL),
+ ("Error parsing first identification packet."));
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+ return GST_FLOW_ERROR;
+ }
+}
+
+static GstStateChangeReturn
+gst_rtp_speex_pay_change_state (GstElement * element, GstStateChange transition)
+{
+ GstRtpSPEEXPay *rtpspeexpay;
+ GstStateChangeReturn ret;
+
+ rtpspeexpay = GST_RTP_SPEEX_PAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ rtpspeexpay->packet = 0;
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+gboolean
+gst_rtp_speex_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpspeexpay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_SPEEX_PAY);
+}
diff --git a/gst/rtp/gstrtpspeexpay.h b/gst/rtp/gstrtpspeexpay.h
new file mode 100755
index 0000000..253978e
--- /dev/null
+++ b/gst/rtp/gstrtpspeexpay.h
@@ -0,0 +1,56 @@
+/* GStreamer
+ * Copyright (C) <2005> Edgard Lima <edgard.lima@indt.org.br>
+ *
+ * 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
+ */
+
+
+#ifndef __GST_RTP_SPEEX_PAY_H__
+#define __GST_RTP_SPEEX_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRtpSPEEXPay GstRtpSPEEXPay;
+typedef struct _GstRtpSPEEXPayClass GstRtpSPEEXPayClass;
+
+#define GST_TYPE_RTP_SPEEX_PAY \
+ (gst_rtp_speex_pay_get_type())
+#define GST_RTP_SPEEX_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_SPEEX_PAY,GstRtpSPEEXPay))
+#define GST_RTP_SPEEX_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_SPEEX_PAY,GstRtpSPEEXPayClass))
+#define GST_IS_RTP_SPEEX_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_SPEEX_PAY))
+#define GST_IS_RTP_SPEEX_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_SPEEX_PAY))
+
+struct _GstRtpSPEEXPay
+{
+ GstRTPBasePayload payload;
+
+ guint64 packet;
+};
+
+struct _GstRtpSPEEXPayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_speex_pay_get_type (void);
+
+gboolean gst_rtp_speex_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_SPEEX_PAY_H__ */
diff --git a/gst/rtp/gstrtpstreamdepay.c b/gst/rtp/gstrtpstreamdepay.c
new file mode 100755
index 0000000..26a2e32
--- /dev/null
+++ b/gst/rtp/gstrtpstreamdepay.c
@@ -0,0 +1,219 @@
+/* GStreamer
+ * Copyright (C) 2013 Sebastian Dröge <sebastian@centricular.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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpstreamdepay
+ *
+ * Implements stream depayloading of RTP and RTCP packets for connection-oriented
+ * transport protocols according to RFC4571.
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 audiotestsrc ! "audio/x-raw,rate=48000" ! vorbisenc ! rtpvorbispay config-interval=1 ! rtpstreampay ! tcpserversink port=5678
+ * gst-launch-1.0 tcpclientsrc port=5678 host=127.0.0.1 do-timestamp=true ! "application/x-rtp-stream,media=audio,clock-rate=48000,encoding-name=VORBIS" ! rtpstreamdepay ! rtpvorbisdepay ! decodebin ! audioconvert ! audioresample ! autoaudiosink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstrtpstreamdepay.h"
+
+GST_DEBUG_CATEGORY (gst_rtp_stream_depay_debug);
+#define GST_CAT_DEFAULT gst_rtp_stream_depay_debug
+
+static GstStaticPadTemplate src_template =
+ GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp; application/x-rtcp;"
+ "application/x-srtp; application/x-srtcp")
+ );
+
+static GstStaticPadTemplate sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp-stream; application/x-rtcp-stream;"
+ "application/x-srtp-stream; application/x-srtcp-stream")
+ );
+
+#define parent_class gst_rtp_stream_depay_parent_class
+G_DEFINE_TYPE (GstRtpStreamDepay, gst_rtp_stream_depay, GST_TYPE_BASE_PARSE);
+
+static gboolean gst_rtp_stream_depay_set_sink_caps (GstBaseParse * parse,
+ GstCaps * caps);
+static GstCaps *gst_rtp_stream_depay_get_sink_caps (GstBaseParse * parse,
+ GstCaps * filter);
+static GstFlowReturn gst_rtp_stream_depay_handle_frame (GstBaseParse * parse,
+ GstBaseParseFrame * frame, gint * skipsize);
+
+static void
+gst_rtp_stream_depay_class_init (GstRtpStreamDepayClass * klass)
+{
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+ GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass);
+
+ GST_DEBUG_CATEGORY_INIT (gst_rtp_stream_depay_debug, "rtpstreamdepay", 0,
+ "RTP stream depayloader");
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP Stream Depayloading", "Codec/Depayloader/Network",
+ "Depayloads RTP/RTCP packets for streaming protocols according to RFC4571",
+ "Sebastian Dröge <sebastian@centricular.com>");
+
+ parse_class->set_sink_caps =
+ GST_DEBUG_FUNCPTR (gst_rtp_stream_depay_set_sink_caps);
+ parse_class->get_sink_caps =
+ GST_DEBUG_FUNCPTR (gst_rtp_stream_depay_get_sink_caps);
+ parse_class->handle_frame =
+ GST_DEBUG_FUNCPTR (gst_rtp_stream_depay_handle_frame);
+}
+
+static void
+gst_rtp_stream_depay_init (GstRtpStreamDepay * self)
+{
+ gst_base_parse_set_min_frame_size (GST_BASE_PARSE (self), 2);
+}
+
+static gboolean
+gst_rtp_stream_depay_set_sink_caps (GstBaseParse * parse, GstCaps * caps)
+{
+ GstCaps *othercaps;
+ GstStructure *structure;
+ gboolean ret;
+
+ othercaps = gst_caps_copy (caps);
+ structure = gst_caps_get_structure (othercaps, 0);
+
+ if (gst_structure_has_name (structure, "application/x-rtp-stream"))
+ gst_structure_set_name (structure, "application/x-rtp");
+ else if (gst_structure_has_name (structure, "application/x-rtcp-stream"))
+ gst_structure_set_name (structure, "application/x-rtcp");
+ else if (gst_structure_has_name (structure, "application/x-srtp-stream"))
+ gst_structure_set_name (structure, "application/x-srtp");
+ else
+ gst_structure_set_name (structure, "application/x-srtcp");
+
+ ret = gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), othercaps);
+ gst_caps_unref (othercaps);
+
+ return ret;
+}
+
+static GstCaps *
+gst_rtp_stream_depay_get_sink_caps (GstBaseParse * parse, GstCaps * filter)
+{
+ GstCaps *peerfilter = NULL, *peercaps, *templ;
+ GstCaps *res;
+ GstStructure *structure;
+ guint i, n;
+
+ if (filter) {
+ peerfilter = gst_caps_copy (filter);
+ n = gst_caps_get_size (peerfilter);
+ for (i = 0; i < n; i++) {
+ structure = gst_caps_get_structure (peerfilter, i);
+
+ if (gst_structure_has_name (structure, "application/x-rtp-stream"))
+ gst_structure_set_name (structure, "application/x-rtp");
+ else if (gst_structure_has_name (structure, "application/x-rtcp-stream"))
+ gst_structure_set_name (structure, "application/x-rtcp");
+ else if (gst_structure_has_name (structure, "application/x-srtp-stream"))
+ gst_structure_set_name (structure, "application/x-srtp");
+ else
+ gst_structure_set_name (structure, "application/x-srtcp");
+ }
+ }
+
+ templ = gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse));
+ peercaps =
+ gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), peerfilter);
+
+ if (peercaps) {
+ /* Rename structure names */
+ peercaps = gst_caps_make_writable (peercaps);
+ n = gst_caps_get_size (peercaps);
+ for (i = 0; i < n; i++) {
+ structure = gst_caps_get_structure (peercaps, i);
+
+ if (gst_structure_has_name (structure, "application/x-rtp"))
+ gst_structure_set_name (structure, "application/x-rtp-stream");
+ else if (gst_structure_has_name (structure, "application/x-rtcp"))
+ gst_structure_set_name (structure, "application/x-rtcp-stream");
+ else if (gst_structure_has_name (structure, "application/x-srtp"))
+ gst_structure_set_name (structure, "application/x-srtp-stream");
+ else
+ gst_structure_set_name (structure, "application/x-srtcp-stream");
+ }
+
+ res = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (peercaps);
+ } else {
+ res = templ;
+ }
+
+ if (filter) {
+ GstCaps *intersection;
+
+ intersection =
+ gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (res);
+ res = intersection;
+
+ gst_caps_unref (peerfilter);
+ }
+
+ return res;
+}
+
+static GstFlowReturn
+gst_rtp_stream_depay_handle_frame (GstBaseParse * parse,
+ GstBaseParseFrame * frame, gint * skipsize)
+{
+ gsize buf_size;
+ guint16 size;
+
+ if (gst_buffer_extract (frame->buffer, 0, &size, 2) != 2)
+ return GST_FLOW_ERROR;
+
+ size = GUINT16_FROM_BE (size);
+ buf_size = gst_buffer_get_size (frame->buffer);
+
+ /* Need more data */
+ if (size + 2 > buf_size)
+ return GST_FLOW_OK;
+
+ frame->out_buffer =
+ gst_buffer_copy_region (frame->buffer, GST_BUFFER_COPY_ALL, 2, size);
+
+ return gst_base_parse_finish_frame (parse, frame, size + 2);
+}
+
+gboolean
+gst_rtp_stream_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpstreamdepay",
+ GST_RANK_NONE, GST_TYPE_RTP_STREAM_DEPAY);
+}
diff --git a/gst/rtp/gstrtpstreamdepay.h b/gst/rtp/gstrtpstreamdepay.h
new file mode 100755
index 0000000..b6011cb
--- /dev/null
+++ b/gst/rtp/gstrtpstreamdepay.h
@@ -0,0 +1,57 @@
+/* GStreamer
+ * Copyright (C) 2013 Sebastian Dröge <sebastian@centricular.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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_STREAM_DEPAY_H__
+#define __GST_RTP_STREAM_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbaseparse.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_STREAM_DEPAY \
+ (gst_rtp_stream_depay_get_type())
+#define GST_RTP_STREAM_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_STREAM_DEPAY,GstRtpStreamDepay))
+#define GST_RTP_STREAM_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_STREAM_DEPAY,GstRtpStreamDepayClass))
+#define GST_IS_RTP_STREAM_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_STREAM_DEPAY))
+#define GST_IS_RTP_STREAM_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_STREAM_DEPAY))
+
+typedef struct _GstRtpStreamDepay GstRtpStreamDepay;
+typedef struct _GstRtpStreamDepayClass GstRtpStreamDepayClass;
+
+struct _GstRtpStreamDepay
+{
+ GstBaseParse parent;
+};
+
+struct _GstRtpStreamDepayClass
+{
+ GstBaseParseClass parent_class;
+};
+
+GType gst_rtp_stream_depay_get_type (void);
+gboolean gst_rtp_stream_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif
diff --git a/gst/rtp/gstrtpstreampay.c b/gst/rtp/gstrtpstreampay.c
new file mode 100755
index 0000000..117f678
--- /dev/null
+++ b/gst/rtp/gstrtpstreampay.c
@@ -0,0 +1,287 @@
+/*
+ * GStreamer
+ * Copyright (C) 2013 Sebastian Dröge <sebastian@centricular.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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-rtpstreampay
+ *
+ * Implements stream payloading of RTP and RTCP packets for connection-oriented
+ * transport protocols according to RFC4571.
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch-1.0 audiotestsrc ! "audio/x-raw,rate=48000" ! vorbisenc ! rtpvorbispay config-interval=1 ! rtpstreampay ! tcpserversink port=5678
+ * gst-launch-1.0 tcpclientsrc port=5678 host=127.0.0.1 do-timestamp=true ! "application/x-rtp-stream,media=audio,clock-rate=48000,encoding-name=VORBIS" ! rtpstreamdepay ! rtpvorbisdepay ! decodebin ! audioconvert ! audioresample ! autoaudiosink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstrtpstreampay.h"
+
+#define GST_CAT_DEFAULT gst_rtp_stream_pay_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp; application/x-rtcp; "
+ "application/x-srtp; application/x-srtcp")
+ );
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp-stream; application/x-rtcp-stream; "
+ "application/x-srtp-stream; application/x-srtcp-stream")
+ );
+
+#define parent_class gst_rtp_stream_pay_parent_class
+G_DEFINE_TYPE (GstRtpStreamPay, gst_rtp_stream_pay, GST_TYPE_ELEMENT);
+
+static gboolean gst_rtp_stream_pay_sink_query (GstPad * pad, GstObject * parent,
+ GstQuery * query);
+static GstFlowReturn gst_rtp_stream_pay_sink_chain (GstPad * pad,
+ GstObject * parent, GstBuffer * inbuf);
+static gboolean gst_rtp_stream_pay_sink_event (GstPad * pad, GstObject * parent,
+ GstEvent * event);
+
+static void
+gst_rtp_stream_pay_class_init (GstRtpStreamPayClass * klass)
+{
+ GstElementClass *gstelement_class;
+
+ GST_DEBUG_CATEGORY_INIT (gst_rtp_stream_pay_debug, "rtpstreampay", 0,
+ "RTP stream payloader");
+
+ gstelement_class = (GstElementClass *) klass;
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP Stream Payloading", "Codec/Payloader/Network",
+ "Payloads RTP/RTCP packets for streaming protocols according to RFC4571",
+ "Sebastian Dröge <sebastian@centricular.com>");
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&sink_template));
+}
+
+static void
+gst_rtp_stream_pay_init (GstRtpStreamPay * self)
+{
+ self->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
+ gst_pad_set_chain_function (self->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_rtp_stream_pay_sink_chain));
+ gst_pad_set_event_function (self->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_rtp_stream_pay_sink_event));
+ gst_pad_set_query_function (self->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_rtp_stream_pay_sink_query));
+ gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
+
+ self->srcpad = gst_pad_new_from_static_template (&src_template, "src");
+ gst_pad_use_fixed_caps (self->srcpad);
+ gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
+}
+
+static GstCaps *
+gst_rtp_stream_pay_sink_get_caps (GstRtpStreamPay * self, GstCaps * filter)
+{
+ GstCaps *peerfilter = NULL, *peercaps, *templ;
+ GstCaps *res;
+ GstStructure *structure;
+ guint i, n;
+
+ if (filter) {
+ peerfilter = gst_caps_copy (filter);
+ n = gst_caps_get_size (peerfilter);
+ for (i = 0; i < n; i++) {
+ structure = gst_caps_get_structure (peerfilter, i);
+
+ if (gst_structure_has_name (structure, "application/x-rtp"))
+ gst_structure_set_name (structure, "application/x-rtp-stream");
+ else if (gst_structure_has_name (structure, "application/x-rtcp"))
+ gst_structure_set_name (structure, "application/x-rtcp-stream");
+ else if (gst_structure_has_name (structure, "application/x-srtp"))
+ gst_structure_set_name (structure, "application/x-srtp-stream");
+ else
+ gst_structure_set_name (structure, "application/x-srtcp-stream");
+ }
+ }
+
+ templ = gst_pad_get_pad_template_caps (self->sinkpad);
+ peercaps = gst_pad_peer_query_caps (self->srcpad, peerfilter);
+
+ if (peercaps) {
+ /* Rename structure names */
+ peercaps = gst_caps_make_writable (peercaps);
+ n = gst_caps_get_size (peercaps);
+ for (i = 0; i < n; i++) {
+ structure = gst_caps_get_structure (peercaps, i);
+
+ if (gst_structure_has_name (structure, "application/x-rtp-stream"))
+ gst_structure_set_name (structure, "application/x-rtp");
+ else if (gst_structure_has_name (structure, "application/x-rtcp-stream"))
+ gst_structure_set_name (structure, "application/x-rtcp");
+ else if (gst_structure_has_name (structure, "application/x-srtp-stream"))
+ gst_structure_set_name (structure, "application/x-srtp");
+ else
+ gst_structure_set_name (structure, "application/x-srtcp");
+ }
+
+ res = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (peercaps);
+ } else {
+ res = templ;
+ }
+
+ if (filter) {
+ GstCaps *intersection;
+
+ intersection =
+ gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (res);
+ res = intersection;
+
+ gst_caps_unref (peerfilter);
+ }
+
+ return res;
+}
+
+static gboolean
+gst_rtp_stream_pay_sink_query (GstPad * pad, GstObject * parent,
+ GstQuery * query)
+{
+ GstRtpStreamPay *self = GST_RTP_STREAM_PAY (parent);
+ gboolean ret;
+
+ GST_LOG_OBJECT (pad, "Handling query of type '%s'",
+ gst_query_type_get_name (GST_QUERY_TYPE (query)));
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_CAPS:
+ {
+ GstCaps *caps;
+
+ gst_query_parse_caps (query, &caps);
+ caps = gst_rtp_stream_pay_sink_get_caps (self, caps);
+ gst_query_set_caps_result (query, caps);
+ gst_caps_unref (caps);
+ ret = TRUE;
+ break;
+ }
+ default:
+ ret = gst_pad_query_default (pad, parent, query);
+ }
+
+ return ret;
+}
+
+static gboolean
+gst_rtp_stream_pay_sink_set_caps (GstRtpStreamPay * self, GstCaps * caps)
+{
+ GstCaps *othercaps;
+ GstStructure *structure;
+ gboolean ret;
+
+ othercaps = gst_caps_copy (caps);
+ structure = gst_caps_get_structure (othercaps, 0);
+
+ if (gst_structure_has_name (structure, "application/x-rtp"))
+ gst_structure_set_name (structure, "application/x-rtp-stream");
+ else if (gst_structure_has_name (structure, "application/x-rtcp"))
+ gst_structure_set_name (structure, "application/x-rtcp-stream");
+ else if (gst_structure_has_name (structure, "application/x-srtp"))
+ gst_structure_set_name (structure, "application/x-srtp-stream");
+ else
+ gst_structure_set_name (structure, "application/x-srtcp-stream");
+
+ ret = gst_pad_set_caps (self->srcpad, othercaps);
+ gst_caps_unref (othercaps);
+
+ return ret;
+}
+
+static gboolean
+gst_rtp_stream_pay_sink_event (GstPad * pad, GstObject * parent,
+ GstEvent * event)
+{
+ GstRtpStreamPay *self = GST_RTP_STREAM_PAY (parent);
+ gboolean ret;
+
+ GST_LOG_OBJECT (pad, "Got %s event", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_CAPS:
+ {
+ GstCaps *caps;
+
+ gst_event_parse_caps (event, &caps);
+ ret = gst_rtp_stream_pay_sink_set_caps (self, caps);
+ gst_event_unref (event);
+ break;
+ }
+ default:
+ ret = gst_pad_event_default (pad, parent, event);
+ break;
+ }
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_rtp_stream_pay_sink_chain (GstPad * pad, GstObject * parent,
+ GstBuffer * inbuf)
+{
+ GstRtpStreamPay *self = GST_RTP_STREAM_PAY (parent);
+ GstBuffer *outbuf;
+ gsize size;
+ guint8 size16[2];
+
+ size = gst_buffer_get_size (inbuf);
+ if (size > G_MAXUINT16) {
+ GST_ELEMENT_ERROR (self, CORE, FAILED, (NULL),
+ ("Only buffers up to %d bytes supported, got %" G_GSIZE_FORMAT,
+ G_MAXUINT16, size));
+ gst_buffer_unref (inbuf);
+ return GST_FLOW_ERROR;
+ }
+
+ outbuf = gst_buffer_new_and_alloc (2);
+
+ GST_WRITE_UINT16_BE (size16, size);
+ gst_buffer_fill (outbuf, 0, size16, 2);
+
+ gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_ALL, 0, -1);
+
+ gst_buffer_unref (inbuf);
+
+ return gst_pad_push (self->srcpad, outbuf);
+}
+
+gboolean
+gst_rtp_stream_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpstreampay",
+ GST_RANK_NONE, GST_TYPE_RTP_STREAM_PAY);
+}
diff --git a/gst/rtp/gstrtpstreampay.h b/gst/rtp/gstrtpstreampay.h
new file mode 100755
index 0000000..a9436a8
--- /dev/null
+++ b/gst/rtp/gstrtpstreampay.h
@@ -0,0 +1,54 @@
+/*
+ * GStreamer
+ * Copyright (C) 2013 Sebastian Dröge <sebastian@centricular.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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_STREAM_PAY_H__
+#define __GST_RTP_STREAM_PAY_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_STREAM_PAY (gst_rtp_stream_pay_get_type())
+#define GST_RTP_STREAM_PAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_STREAM_PAY,GstRtpStreamPay))
+#define GST_IS_RTP_STREAM_PAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_STREAM_PAY))
+#define GST_RTP_STREAM_PAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_RTP_STREAM_PAY,GstRtpStreamPayClass))
+#define GST_IS_RTP_STREAM_PAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_RTP_STREAM_PAY))
+#define GST_RTP_STREAM_PAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_RTP_STREAM_PAY,GstRtpStreamPayClass))
+
+typedef struct _GstRtpStreamPay GstRtpStreamPay;
+typedef struct _GstRtpStreamPayClass GstRtpStreamPayClass;
+
+struct _GstRtpStreamPay {
+ GstElement parent;
+
+ GstPad *srcpad, *sinkpad;
+};
+
+struct _GstRtpStreamPayClass {
+ GstElementClass parent_class;
+};
+
+GType gst_rtp_stream_pay_get_type (void);
+
+gboolean gst_rtp_stream_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_STREAM_PAY_H__ */
diff --git a/gst/rtp/gstrtpsv3vdepay.c b/gst/rtp/gstrtpsv3vdepay.c
new file mode 100755
index 0000000..7e3bc89
--- /dev/null
+++ b/gst/rtp/gstrtpsv3vdepay.c
@@ -0,0 +1,323 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include "gstrtpsv3vdepay.h"
+
+GST_DEBUG_CATEGORY (rtpsv3vdepay_debug);
+#define GST_CAT_DEFAULT rtpsv3vdepay_debug
+
+static GstStaticPadTemplate gst_rtp_sv3v_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-svq, " "svqversion = (int) 3")
+ );
+
+static GstStaticPadTemplate gst_rtp_sv3v_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"video\", "
+ "clock-rate = (int) 90000, "
+ "encoding-name = (string) { \"X-SV3V-ES\", \"X-SORENSON-VIDEO\" , \"X-SORENSONVIDEO\" , \"X-SorensonVideo\" }")
+ );
+
+#define gst_rtp_sv3v_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpSV3VDepay, gst_rtp_sv3v_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static void gst_rtp_sv3v_depay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_sv3v_depay_change_state (GstElement *
+ element, GstStateChange transition);
+
+static GstBuffer *gst_rtp_sv3v_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+gboolean gst_rtp_sv3v_depay_setcaps (GstRTPBaseDepayload * filter,
+ GstCaps * caps);
+
+static void
+gst_rtp_sv3v_depay_class_init (GstRtpSV3VDepayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gstrtpbasedepayload_class->process = gst_rtp_sv3v_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_sv3v_depay_setcaps;
+
+ gobject_class->finalize = gst_rtp_sv3v_depay_finalize;
+
+ gstelement_class->change_state = gst_rtp_sv3v_depay_change_state;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_sv3v_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_sv3v_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP SVQ3 depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts SVQ3 video from RTP packets (no RFC)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+}
+
+static void
+gst_rtp_sv3v_depay_init (GstRtpSV3VDepay * rtpsv3vdepay)
+{
+ rtpsv3vdepay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_sv3v_depay_finalize (GObject * object)
+{
+ GstRtpSV3VDepay *rtpsv3vdepay;
+
+ rtpsv3vdepay = GST_RTP_SV3V_DEPAY (object);
+
+ g_object_unref (rtpsv3vdepay->adapter);
+ rtpsv3vdepay->adapter = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/* only on the sink */
+gboolean
+gst_rtp_sv3v_depay_setcaps (GstRTPBaseDepayload * filter, GstCaps * caps)
+{
+ GstStructure *structure = gst_caps_get_structure (caps, 0);
+ gint clock_rate;
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 90000; /* default */
+ filter->clock_rate = clock_rate;
+
+ /* will set caps later */
+
+ return TRUE;
+}
+
+static GstBuffer *
+gst_rtp_sv3v_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpSV3VDepay *rtpsv3vdepay;
+ static struct
+ {
+ guint width, height;
+ } resolutions[7] = {
+ {
+ 160, 128}, {
+ 128, 96}, {
+ 176, 144}, {
+ 352, 288}, {
+ 704, 576}, {
+ 240, 180}, {
+ 320, 240}
+ };
+ gint payload_len;
+ guint8 *payload;
+ gboolean M;
+ gboolean C, S, E;
+ GstBuffer *outbuf = NULL;
+ guint16 seq;
+ GstRTPBuffer rtp = { NULL };
+
+ rtpsv3vdepay = GST_RTP_SV3V_DEPAY (depayload);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ /* flush on sequence number gaps */
+ seq = gst_rtp_buffer_get_seq (&rtp);
+
+ GST_DEBUG ("timestamp %" GST_TIME_FORMAT ", sequence number:%d",
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), seq);
+
+ if (seq != rtpsv3vdepay->nextseq) {
+ GST_DEBUG ("Sequence discontinuity, clearing adapter");
+ gst_adapter_clear (rtpsv3vdepay->adapter);
+ }
+ rtpsv3vdepay->nextseq = seq + 1;
+
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+ if (payload_len < 3)
+ goto bad_packet;
+
+ payload = gst_rtp_buffer_get_payload (&rtp);
+
+ M = gst_rtp_buffer_get_marker (&rtp);
+
+ /* This is all a guess:
+ * 1 1 1 1 1 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |0|C|S|E|0|0|0|0|0|0|0|0|0|0|0|0|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * C: config, packet contains config info
+ * S: start, packet contains start of frame
+ * E: end, packet contains end of frame
+ */
+ /* this seems to indicate a packet with a config string sent before each
+ * keyframe */
+ C = (payload[0] & 0x40) == 0x40;
+
+ /* redundant with the RTP marker bit */
+ S = (payload[0] & 0x20) == 0x20;
+ E = (payload[0] & 0x10) == 0x10;
+
+ GST_DEBUG ("M:%d, C:%d, S:%d, E:%d", M, C, S, E);
+
+ GST_MEMDUMP ("incoming buffer", payload, payload_len);
+
+ if (G_UNLIKELY (C)) {
+ GstCaps *caps;
+ GstBuffer *codec_data;
+ GstMapInfo cmap;
+ guint8 res;
+
+ GST_DEBUG ("Configuration packet");
+
+ /* if we already have caps, we don't need to do anything. FIXME, check if
+ * something changed. */
+ if (G_UNLIKELY (gst_pad_has_current_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD
+ (depayload)))) {
+ GST_DEBUG ("Already configured, skipping config parsing");
+ goto beach;
+ }
+
+ res = payload[2] >> 5;
+
+ /* width and height, according to http://wiki.multimedia.cx/index.php?title=Sorenson_Video_1#Stream_Format_And_Header */
+ if (G_LIKELY (res < 7)) {
+ rtpsv3vdepay->width = resolutions[res].width;
+ rtpsv3vdepay->height = resolutions[res].height;
+ } else {
+ /* extended width/height, they're contained in the following 24bit */
+ rtpsv3vdepay->width = ((payload[2] & 0x1f) << 7) | (payload[3] >> 1);
+ rtpsv3vdepay->height =
+ (payload[3] & 0x1) << 11 | payload[4] << 3 | (payload[5] >> 5);
+ }
+
+ /* CodecData needs to be 'SEQH' + len (32bit) + data according to
+ * ffmpeg's libavcodec/svq3.c:svq3_decode_init */
+ codec_data = gst_buffer_new_and_alloc (payload_len + 6);
+ gst_buffer_map (codec_data, &cmap, GST_MAP_WRITE);
+ memcpy (cmap.data, "SEQH", 4);
+ GST_WRITE_UINT32_LE (cmap.data + 4, payload_len - 2);
+ memcpy (cmap.data + 8, payload + 2, payload_len - 2);
+ GST_MEMDUMP ("codec_data", cmap.data, gst_buffer_get_size (codec_data));
+ gst_buffer_unmap (codec_data, &cmap);
+
+ caps = gst_caps_new_simple ("video/x-svq",
+ "svqversion", G_TYPE_INT, 3,
+ "width", G_TYPE_INT, rtpsv3vdepay->width,
+ "height", G_TYPE_INT, rtpsv3vdepay->height,
+ "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
+ gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), caps);
+ gst_caps_unref (caps);
+
+ GST_DEBUG ("Depayloader now configured");
+
+ rtpsv3vdepay->configured = TRUE;
+
+ goto beach;
+ }
+
+ if (G_LIKELY (rtpsv3vdepay->configured)) {
+ GstBuffer *tmpbuf;
+
+ GST_DEBUG ("Storing incoming payload");
+ /* store data in adapter, stip off 2 bytes header */
+ tmpbuf = gst_rtp_buffer_get_payload_subbuffer (&rtp, 2, -1);
+ gst_adapter_push (rtpsv3vdepay->adapter, tmpbuf);
+
+ if (G_UNLIKELY (M)) {
+ /* frame is completed: push contents of adapter */
+ guint avail;
+
+ avail = gst_adapter_available (rtpsv3vdepay->adapter);
+ GST_DEBUG ("Returning completed output buffer [%d bytes]", avail);
+ outbuf = gst_adapter_take_buffer (rtpsv3vdepay->adapter, avail);
+ }
+ }
+
+beach:
+ gst_rtp_buffer_unmap (&rtp);
+ return outbuf;
+
+ /* ERRORS */
+bad_packet:
+ {
+ GST_ELEMENT_WARNING (rtpsv3vdepay, STREAM, DECODE,
+ (NULL), ("Packet was too short"));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+}
+
+static GstStateChangeReturn
+gst_rtp_sv3v_depay_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstRtpSV3VDepay *rtpsv3vdepay;
+ GstStateChangeReturn ret;
+
+ rtpsv3vdepay = GST_RTP_SV3V_DEPAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_adapter_clear (rtpsv3vdepay->adapter);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+gboolean
+gst_rtp_sv3v_depay_plugin_init (GstPlugin * plugin)
+{
+ GST_DEBUG_CATEGORY_INIT (rtpsv3vdepay_debug, "rtpsv3vdepay", 0,
+ "RTP SV3V depayloader");
+
+ return gst_element_register (plugin, "rtpsv3vdepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_SV3V_DEPAY);
+}
diff --git a/gst/rtp/gstrtpsv3vdepay.h b/gst/rtp/gstrtpsv3vdepay.h
new file mode 100755
index 0000000..428684a
--- /dev/null
+++ b/gst/rtp/gstrtpsv3vdepay.h
@@ -0,0 +1,67 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_SV3V_DEPAY_H__
+#define __GST_RTP_SV3V_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_SV3V_DEPAY \
+ (gst_rtp_sv3v_depay_get_type())
+#define GST_RTP_SV3V_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_SV3V_DEPAY,GstRtpSV3VDepay))
+#define GST_RTP_SV3V_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_SV3V_DEPAY,GstRtpSV3VDepayClass))
+#define GST_IS_RTP_SV3V_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_SV3V_DEPAY))
+#define GST_IS_RTP_SV3V_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_SV3V_DEPAY))
+
+typedef struct _GstRtpSV3VDepay GstRtpSV3VDepay;
+typedef struct _GstRtpSV3VDepayClass GstRtpSV3VDepayClass;
+
+struct _GstRtpSV3VDepay
+{
+ GstRTPBaseDepayload depayload;
+
+ GstAdapter *adapter;
+
+ gboolean configured;
+
+ guint16 nextseq;
+ guint width;
+ guint height;
+};
+
+struct _GstRtpSV3VDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_sv3v_depay_get_type (void);
+
+gboolean gst_rtp_sv3v_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_SV3V_DEPAY_H__ */
diff --git a/gst/rtp/gstrtptheoradepay.c b/gst/rtp/gstrtptheoradepay.c
new file mode 100755
index 0000000..ccfe12d
--- /dev/null
+++ b/gst/rtp/gstrtptheoradepay.c
@@ -0,0 +1,656 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/tag/tag.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <string.h>
+#include "gstrtptheoradepay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtptheoradepay_debug);
+#define GST_CAT_DEFAULT (rtptheoradepay_debug)
+
+static GstStaticPadTemplate gst_rtp_theora_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"video\", "
+ "clock-rate = (int) 90000, " "encoding-name = (string) \"THEORA\""
+ /* All required parameters
+ *
+ * "sampling = (string) { "YCbCr-4:2:0", "YCbCr-4:2:2", "YCbCr-4:4:4" } "
+ * "width = (string) [1, 1048561] (multiples of 16) "
+ * "height = (string) [1, 1048561] (multiples of 16) "
+ * "delivery-method = (string) { inline, in_band, out_band/<specific_name> } "
+ * "configuration = (string) ANY"
+ */
+ /* All optional parameters
+ *
+ * "configuration-uri ="
+ */
+ )
+ );
+
+static GstStaticPadTemplate gst_rtp_theora_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-theora")
+ );
+
+#define gst_rtp_theora_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpTheoraDepay, gst_rtp_theora_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_theora_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_theora_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+static gboolean gst_rtp_theora_depay_packet_lost (GstRTPBaseDepayload *
+ depayload, GstEvent * event);
+
+static void gst_rtp_theora_depay_finalize (GObject * object);
+
+static void
+gst_rtp_theora_depay_class_init (GstRtpTheoraDepayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_theora_depay_finalize;
+
+ gstrtpbasedepayload_class->process = gst_rtp_theora_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_theora_depay_setcaps;
+ gstrtpbasedepayload_class->packet_lost = gst_rtp_theora_depay_packet_lost;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_theora_depay_sink_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_theora_depay_src_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP Theora depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts Theora video from RTP packets (draft-01 of RFC XXXX)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ GST_DEBUG_CATEGORY_INIT (rtptheoradepay_debug, "rtptheoradepay", 0,
+ "Theora RTP Depayloader");
+}
+
+static void
+gst_rtp_theora_depay_init (GstRtpTheoraDepay * rtptheoradepay)
+{
+ rtptheoradepay->adapter = gst_adapter_new ();
+}
+
+static void
+gst_rtp_theora_depay_finalize (GObject * object)
+{
+ GstRtpTheoraDepay *rtptheoradepay = GST_RTP_THEORA_DEPAY (object);
+
+ g_object_unref (rtptheoradepay->adapter);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rtp_theora_depay_parse_configuration (GstRtpTheoraDepay * rtptheoradepay,
+ GstBuffer * confbuf)
+{
+ GstBuffer *buf;
+ guint32 num_headers;
+ GstMapInfo map;
+ guint8 *data;
+ gsize size;
+ gint i, j;
+
+ gst_buffer_map (confbuf, &map, GST_MAP_READ);
+ data = map.data;
+ size = map.size;
+
+ GST_DEBUG_OBJECT (rtptheoradepay, "config size %" G_GSIZE_FORMAT, size);
+
+ /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Number of packed headers |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Packed header |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Packed header |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | .... |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ if (size < 4)
+ goto too_small;
+
+ num_headers = GST_READ_UINT32_BE (data);
+ size -= 4;
+ data += 4;
+
+ GST_DEBUG_OBJECT (rtptheoradepay, "have %u headers", num_headers);
+
+ /* 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Ident | length ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. | n. of headers | length1 | length2 ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. | Identification Header ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .................................................................
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. | Comment Header ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .................................................................
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. Comment Header |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Setup Header ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .................................................................
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. Setup Header |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ for (i = 0; i < num_headers; i++) {
+ guint32 ident;
+ guint16 length;
+ guint8 n_headers, b;
+ GstRtpTheoraConfig *conf;
+ guint *h_sizes;
+ guint extra = 1;
+
+ if (size < 6)
+ goto too_small;
+
+ ident = (data[0] << 16) | (data[1] << 8) | data[2];
+ length = (data[3] << 8) | data[4];
+ n_headers = data[5];
+ size -= 6;
+ data += 6;
+
+ GST_DEBUG_OBJECT (rtptheoradepay,
+ "header %d, ident 0x%08x, length %u, left %" G_GSIZE_FORMAT, i, ident,
+ length, size);
+
+ /* FIXME check if we already got this ident */
+
+ /* length might also include count of following size fields */
+ if (size < length && size + 1 != length)
+ goto too_small;
+
+ /* read header sizes we read 2 sizes, the third size (for which we allocate
+ * space) must be derived from the total packed header length. */
+ h_sizes = g_newa (guint, n_headers + 1);
+ for (j = 0; j < n_headers; j++) {
+ guint h_size;
+
+ h_size = 0;
+ do {
+ if (size < 1)
+ goto too_small;
+ b = *data++;
+ size--;
+ extra++;
+ h_size = (h_size << 7) | (b & 0x7f);
+ } while (b & 0x80);
+ GST_DEBUG_OBJECT (rtptheoradepay, "headers %d: size: %u", j, h_size);
+ h_sizes[j] = h_size;
+ length -= h_size;
+ }
+ /* last header length is the remaining space */
+ GST_DEBUG_OBJECT (rtptheoradepay, "last header size: %u", length);
+ h_sizes[j] = length;
+
+ GST_DEBUG_OBJECT (rtptheoradepay, "preparing headers");
+ conf = g_new0 (GstRtpTheoraConfig, 1);
+ conf->ident = ident;
+
+ for (j = 0; j <= n_headers; j++) {
+ guint h_size;
+
+ h_size = h_sizes[j];
+ if (size < h_size) {
+ if (j != n_headers || size + extra != h_size) {
+ goto too_small;
+ } else {
+ /* otherwise means that overall length field contained total length,
+ * including extra fields */
+ h_size -= extra;
+ }
+ }
+
+ GST_DEBUG_OBJECT (rtptheoradepay, "reading header %d, size %u", j,
+ h_size);
+
+ buf = gst_buffer_new_and_alloc (h_size);
+ gst_buffer_fill (buf, 0, data, h_size);
+ conf->headers = g_list_append (conf->headers, buf);
+ data += h_size;
+ size -= h_size;
+ }
+ rtptheoradepay->configs = g_list_append (rtptheoradepay->configs, conf);
+ }
+
+ gst_buffer_unmap (confbuf, &map);
+ return TRUE;
+
+ /* ERRORS */
+too_small:
+ {
+ GST_DEBUG_OBJECT (rtptheoradepay, "configuration too small");
+ gst_buffer_unmap (confbuf, &map);
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_rtp_theora_depay_parse_inband_configuration (GstRtpTheoraDepay *
+ rtptheoradepay, guint ident, guint8 * configuration, guint size,
+ guint length)
+{
+ GstBuffer *confbuf;
+ GstMapInfo map;
+
+ if (G_UNLIKELY (size < 4))
+ return FALSE;
+
+ /* transform inline to out-of-band and parse that one */
+ confbuf = gst_buffer_new_and_alloc (size + 9);
+ gst_buffer_map (confbuf, &map, GST_MAP_WRITE);
+ /* 1 header */
+ GST_WRITE_UINT32_BE (map.data, 1);
+ /* write Ident */
+ GST_WRITE_UINT24_BE (map.data + 4, ident);
+ /* write sort-of-length */
+ GST_WRITE_UINT16_BE (map.data + 7, length);
+ /* copy remainder */
+ memcpy (map.data + 9, configuration, size);
+ gst_buffer_unmap (confbuf, &map);
+
+ return gst_rtp_theora_depay_parse_configuration (rtptheoradepay, confbuf);
+}
+
+static gboolean
+gst_rtp_theora_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstStructure *structure;
+ GstRtpTheoraDepay *rtptheoradepay;
+ GstCaps *srccaps;
+ const gchar *configuration;
+ gboolean res;
+
+ rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload);
+
+ rtptheoradepay->needs_keyframe = FALSE;
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ /* read and parse configuration string */
+ configuration = gst_structure_get_string (structure, "configuration");
+ if (configuration) {
+ GstBuffer *confbuf;
+ guint8 *data;
+ gsize size;
+
+ /* deserialize base64 to buffer */
+ data = g_base64_decode (configuration, &size);
+
+ confbuf = gst_buffer_new ();
+ gst_buffer_append_memory (confbuf,
+ gst_memory_new_wrapped (0, data, size, 0, size, data, g_free));
+
+ if (!gst_rtp_theora_depay_parse_configuration (rtptheoradepay, confbuf))
+ goto invalid_configuration;
+ }
+
+ /* set caps on pad and on header */
+ srccaps = gst_caps_new_empty_simple ("video/x-theora");
+ res = gst_pad_set_caps (depayload->srcpad, srccaps);
+ gst_caps_unref (srccaps);
+
+ /* Clock rate is always 90000 according to draft-barbato-avt-rtp-theora-01 */
+ depayload->clock_rate = 90000;
+
+ return res;
+
+ /* ERRORS */
+invalid_configuration:
+ {
+ GST_ERROR_OBJECT (rtptheoradepay, "invalid configuration specified");
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_rtp_theora_depay_switch_codebook (GstRtpTheoraDepay * rtptheoradepay,
+ guint32 ident)
+{
+ GList *walk;
+ gboolean res = FALSE;
+
+ for (walk = rtptheoradepay->configs; walk; walk = g_list_next (walk)) {
+ GstRtpTheoraConfig *conf = (GstRtpTheoraConfig *) walk->data;
+
+ if (conf->ident == ident) {
+ GList *headers;
+
+ /* FIXME, remove pads, create new pad.. */
+
+ /* push out all the headers */
+ for (headers = conf->headers; headers; headers = g_list_next (headers)) {
+ GstBuffer *header = GST_BUFFER_CAST (headers->data);
+
+ gst_buffer_ref (header);
+ gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtptheoradepay),
+ header);
+ }
+ /* remember the current config */
+ rtptheoradepay->config = conf;
+ res = TRUE;
+ }
+ }
+ if (!res) {
+ /* we don't know about the headers, figure out an alternative method for
+ * getting the codebooks. FIXME, fail for now. */
+ }
+ return res;
+}
+
+static GstBuffer *
+gst_rtp_theora_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpTheoraDepay *rtptheoradepay;
+ GstBuffer *outbuf;
+ GstFlowReturn ret;
+ gint payload_len;
+ guint8 *payload, *to_free = NULL;
+ guint32 header, ident;
+ guint8 F, TDT, packets;
+ GstRTPBuffer rtp = { NULL };
+ guint length;
+
+ rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+
+ GST_DEBUG_OBJECT (depayload, "got RTP packet of size %d", payload_len);
+
+ /* we need at least 4 bytes for the packet header */
+ if (G_UNLIKELY (payload_len < 4))
+ goto packet_short;
+
+ payload = gst_rtp_buffer_get_payload (&rtp);
+
+ header = GST_READ_UINT32_BE (payload);
+ /*
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Ident | F |TDT|# pkts.|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * F: Fragment type (0=none, 1=start, 2=cont, 3=end)
+ * TDT: Theora data type (0=theora, 1=config, 2=comment, 3=reserved)
+ * pkts: number of packets.
+ */
+ TDT = (header & 0x30) >> 4;
+ if (G_UNLIKELY (TDT == 3))
+ goto ignore_reserved;
+
+ ident = (header >> 8) & 0xffffff;
+ F = (header & 0xc0) >> 6;
+ packets = (header & 0xf);
+
+ GST_DEBUG_OBJECT (depayload, "ident: 0x%08x, F: %d, TDT: %d, packets: %d",
+ ident, F, TDT, packets);
+
+ if (TDT == 0) {
+ gboolean do_switch = FALSE;
+
+ /* we have a raw payload, find the codebook for the ident */
+ if (!rtptheoradepay->config) {
+ /* we don't have an active codebook, find the codebook and
+ * activate it */
+ do_switch = TRUE;
+ } else if (rtptheoradepay->config->ident != ident) {
+ /* codebook changed */
+ do_switch = TRUE;
+ }
+ if (do_switch) {
+ if (!gst_rtp_theora_depay_switch_codebook (rtptheoradepay, ident))
+ goto switch_failed;
+ }
+ }
+
+ /* skip header */
+ payload += 4;
+ payload_len -= 4;
+
+ /* fragmented packets, assemble */
+ if (F != 0) {
+ GstBuffer *vdata;
+ guint headerskip;
+
+ if (F == 1) {
+ /* if we start a packet, clear adapter and start assembling. */
+ gst_adapter_clear (rtptheoradepay->adapter);
+ GST_DEBUG_OBJECT (depayload, "start assemble");
+ rtptheoradepay->assembling = TRUE;
+ }
+
+ if (!rtptheoradepay->assembling)
+ goto no_output;
+
+ /* first assembled packet, reuse 2 bytes to store the length */
+ headerskip = (F == 1 ? 4 : 6);
+ /* skip header and length. */
+ vdata = gst_rtp_buffer_get_payload_subbuffer (&rtp, headerskip, -1);
+
+ GST_DEBUG_OBJECT (depayload, "assemble theora packet");
+ gst_adapter_push (rtptheoradepay->adapter, vdata);
+
+ /* packet is not complete, we are done */
+ if (F != 3)
+ goto no_output;
+
+ /* construct assembled buffer */
+ payload_len = gst_adapter_available (rtptheoradepay->adapter);
+ payload = gst_adapter_take (rtptheoradepay->adapter, payload_len);
+
+ /* use this length */
+ length = payload_len - 2;
+
+ to_free = payload;
+ } else {
+ /* read length from data */
+ length = 0;
+ }
+
+ GST_DEBUG_OBJECT (depayload, "assemble done, payload_len %d", payload_len);
+
+ /* we not assembling anymore now */
+ rtptheoradepay->assembling = FALSE;
+ gst_adapter_clear (rtptheoradepay->adapter);
+
+ /* payload now points to a length with that many theora data bytes.
+ * Iterate over the packets and send them out.
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | length | theora data ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. theora data |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | length | next theora packet data ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. theora data |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*
+ */
+ while (payload_len >= 2) {
+ if (length == 0)
+ length = GST_READ_UINT16_BE (payload);
+
+ payload += 2;
+ payload_len -= 2;
+
+ GST_DEBUG_OBJECT (depayload, "read length %u, avail: %d", length,
+ payload_len);
+
+ /* skip packet if something odd happens */
+ if (G_UNLIKELY (length > payload_len))
+ goto length_short;
+
+ /* handle in-band configuration */
+ if (G_UNLIKELY (TDT == 1)) {
+ GST_DEBUG_OBJECT (rtptheoradepay, "in-band configuration");
+ if (!gst_rtp_theora_depay_parse_inband_configuration (rtptheoradepay,
+ ident, payload, payload_len, length))
+ goto invalid_configuration;
+ goto no_output;
+ }
+
+ /* create buffer for packet */
+ if (G_UNLIKELY (to_free)) {
+ outbuf =
+ gst_buffer_new_wrapped_full (0, to_free, (payload - to_free) + length,
+ payload - to_free, length, to_free, g_free);
+ to_free = NULL;
+ } else {
+ outbuf = gst_buffer_new_and_alloc (length);
+ gst_buffer_fill (outbuf, 0, payload, length);
+ }
+
+ if (payload_len > 0 && (payload[0] & 0xC0) == 0x0) {
+ rtptheoradepay->needs_keyframe = FALSE;
+ } else {
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+ }
+
+ payload += length;
+ payload_len -= length;
+ /* make sure to read next length */
+ length = 0;
+
+ ret = gst_rtp_base_depayload_push (depayload, outbuf);
+ if (ret != GST_FLOW_OK)
+ break;
+ }
+
+ if (rtptheoradepay->needs_keyframe)
+ goto request_keyframe;
+
+out:
+no_output:
+
+ gst_rtp_buffer_unmap (&rtp);
+ g_free (to_free);
+ return NULL;
+
+ /* ERORRS */
+switch_failed:
+ {
+ GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
+ (NULL), ("Could not switch codebooks"));
+ goto request_config;
+ }
+packet_short:
+ {
+ GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
+ (NULL), ("Packet was too short (%d < 4)", payload_len));
+ goto request_keyframe;
+ }
+ignore_reserved:
+ {
+ GST_WARNING_OBJECT (rtptheoradepay, "reserved TDT ignored");
+ goto out;
+ }
+length_short:
+ {
+ GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
+ (NULL), ("Packet contains invalid data"));
+ goto request_keyframe;
+ }
+invalid_configuration:
+ {
+ /* fatal, as we otherwise risk carrying on without output */
+ GST_ELEMENT_ERROR (rtptheoradepay, STREAM, DECODE,
+ (NULL), ("Packet contains invalid configuration"));
+ goto request_config;
+ }
+request_config:
+ {
+ gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depayload),
+ gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+ gst_structure_new ("GstForceKeyUnit",
+ "all-headers", G_TYPE_BOOLEAN, TRUE, NULL)));
+ goto out;
+ }
+request_keyframe:
+ {
+ rtptheoradepay->needs_keyframe = TRUE;
+ gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depayload),
+ gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+ gst_structure_new_empty ("GstForceKeyUnit")));
+ goto out;
+ }
+}
+
+gboolean
+gst_rtp_theora_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtptheoradepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_THEORA_DEPAY);
+}
+
+static gboolean
+gst_rtp_theora_depay_packet_lost (GstRTPBaseDepayload * depayload,
+ GstEvent * event)
+{
+ GstRtpTheoraDepay *rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload);
+ guint seqnum = 0;
+
+ gst_structure_get_uint (gst_event_get_structure (event), "seqnum", &seqnum);
+ GST_LOG_OBJECT (depayload, "Requested keyframe because frame with seqnum %u"
+ " is missing", seqnum);
+ rtptheoradepay->needs_keyframe = TRUE;
+
+ gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depayload),
+ gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+ gst_structure_new_empty ("GstForceKeyUnit")));
+
+ return TRUE;
+}
diff --git a/gst/rtp/gstrtptheoradepay.h b/gst/rtp/gstrtptheoradepay.h
new file mode 100755
index 0000000..2b0b260
--- /dev/null
+++ b/gst/rtp/gstrtptheoradepay.h
@@ -0,0 +1,72 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_THEORA_DEPAY_H__
+#define __GST_RTP_THEORA_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_THEORA_DEPAY \
+ (gst_rtp_theora_depay_get_type())
+#define GST_RTP_THEORA_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_THEORA_DEPAY,GstRtpTheoraDepay))
+#define GST_RTP_THEORA_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_THEORA_DEPAY,GstRtpTheoraDepayClass))
+#define GST_IS_RTP_THEORA_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_THEORA_DEPAY))
+#define GST_IS_RTP_THEORA_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_THEORA_DEPAY))
+
+typedef struct _GstRtpTheoraDepay GstRtpTheoraDepay;
+typedef struct _GstRtpTheoraDepayClass GstRtpTheoraDepayClass;
+
+typedef struct _GstRtpTheoraConfig {
+ guint32 ident;
+ GList *headers;
+} GstRtpTheoraConfig;
+
+struct _GstRtpTheoraDepay
+{
+ GstRTPBaseDepayload parent;
+
+ GList *configs;
+ GstRtpTheoraConfig *config;
+
+ GstAdapter *adapter;
+ gboolean assembling;
+
+ gboolean needs_keyframe;
+};
+
+struct _GstRtpTheoraDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_theora_depay_get_type (void);
+
+gboolean gst_rtp_theora_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_THEORA_DEPAY_H__ */
diff --git a/gst/rtp/gstrtptheorapay.c b/gst/rtp/gstrtptheorapay.c
new file mode 100755
index 0000000..10055c0
--- /dev/null
+++ b/gst/rtp/gstrtptheorapay.c
@@ -0,0 +1,947 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "fnv1hash.h"
+#include "gstrtptheorapay.h"
+
+#define THEORA_ID_LEN 42
+
+GST_DEBUG_CATEGORY_STATIC (rtptheorapay_debug);
+#define GST_CAT_DEFAULT (rtptheorapay_debug)
+
+/* references:
+ * http://svn.xiph.org/trunk/theora/doc/draft-ietf-avt-rtp-theora-01.txt
+ */
+
+static GstStaticPadTemplate gst_rtp_theora_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"video\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) 90000, " "encoding-name = (string) \"THEORA\""
+ /* All required parameters
+ *
+ * "sampling = (string) { "YCbCr-4:2:0", "YCbCr-4:2:2", "YCbCr-4:4:4" } "
+ * "width = (string) [1, 1048561] (multiples of 16) "
+ * "height = (string) [1, 1048561] (multiples of 16) "
+ * "configuration = (string) ANY"
+ */
+ /* All optional parameters
+ *
+ * "configuration-uri ="
+ * "delivery-method = (string) { inline, in_band, out_band/<specific_name> } "
+ */
+ )
+ );
+
+static GstStaticPadTemplate gst_rtp_theora_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-theora")
+ );
+
+#define DEFAULT_CONFIG_INTERVAL 0
+
+enum
+{
+ PROP_0,
+ PROP_CONFIG_INTERVAL
+};
+
+#define gst_rtp_theora_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpTheoraPay, gst_rtp_theora_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static gboolean gst_rtp_theora_pay_setcaps (GstRTPBasePayload * basepayload,
+ GstCaps * caps);
+static GstStateChangeReturn gst_rtp_theora_pay_change_state (GstElement *
+ element, GstStateChange transition);
+static GstFlowReturn gst_rtp_theora_pay_handle_buffer (GstRTPBasePayload * pad,
+ GstBuffer * buffer);
+static gboolean gst_rtp_theora_pay_sink_event (GstRTPBasePayload * payload,
+ GstEvent * event);
+
+static gboolean gst_rtp_theora_pay_parse_id (GstRTPBasePayload * basepayload,
+ guint8 * data, guint size);
+static gboolean gst_rtp_theora_pay_finish_headers (GstRTPBasePayload *
+ basepayload);
+
+static void gst_rtp_theora_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_rtp_theora_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void
+gst_rtp_theora_pay_class_init (GstRtpTheoraPayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gstelement_class->change_state = gst_rtp_theora_pay_change_state;
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_theora_pay_setcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_theora_pay_handle_buffer;
+ gstrtpbasepayload_class->sink_event = gst_rtp_theora_pay_sink_event;
+
+ gobject_class->set_property = gst_rtp_theora_pay_set_property;
+ gobject_class->get_property = gst_rtp_theora_pay_get_property;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_theora_pay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_theora_pay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP Theora payloader", "Codec/Payloader/Network/RTP",
+ "Payload-encode Theora video into RTP packets (draft-01 RFC XXXX)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ GST_DEBUG_CATEGORY_INIT (rtptheorapay_debug, "rtptheorapay", 0,
+ "Theora RTP Payloader");
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CONFIG_INTERVAL,
+ g_param_spec_uint ("config-interval", "Config Send Interval",
+ "Send Config Insertion Interval in seconds (configuration headers "
+ "will be multiplexed in the data stream when detected.) (0 = disabled)",
+ 0, 3600, DEFAULT_CONFIG_INTERVAL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+ );
+}
+
+static void
+gst_rtp_theora_pay_init (GstRtpTheoraPay * rtptheorapay)
+{
+ rtptheorapay->last_config = GST_CLOCK_TIME_NONE;
+}
+
+static void
+gst_rtp_theora_pay_clear_packet (GstRtpTheoraPay * rtptheorapay)
+{
+ if (rtptheorapay->packet)
+ gst_buffer_unref (rtptheorapay->packet);
+ rtptheorapay->packet = NULL;
+}
+
+static void
+gst_rtp_theora_pay_cleanup (GstRtpTheoraPay * rtptheorapay)
+{
+ g_list_foreach (rtptheorapay->headers, (GFunc) gst_mini_object_unref, NULL);
+ g_list_free (rtptheorapay->headers);
+ rtptheorapay->headers = NULL;
+
+ gst_rtp_theora_pay_clear_packet (rtptheorapay);
+
+ if (rtptheorapay->config_data)
+ g_free (rtptheorapay->config_data);
+ rtptheorapay->config_data = NULL;
+ rtptheorapay->last_config = GST_CLOCK_TIME_NONE;
+}
+
+static gboolean
+gst_rtp_theora_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
+{
+ GstRtpTheoraPay *rtptheorapay;
+ GstStructure *s;
+ const GValue *array;
+ gint asize, i;
+ GstBuffer *buf;
+ GstMapInfo map;
+
+ rtptheorapay = GST_RTP_THEORA_PAY (basepayload);
+
+ s = gst_caps_get_structure (caps, 0);
+
+ rtptheorapay->need_headers = TRUE;
+
+ if ((array = gst_structure_get_value (s, "streamheader")) == NULL)
+ goto done;
+
+ if (G_VALUE_TYPE (array) != GST_TYPE_ARRAY)
+ goto done;
+
+ if ((asize = gst_value_array_get_size (array)) < 3)
+ goto done;
+
+ for (i = 0; i < asize; i++) {
+ const GValue *value;
+
+ value = gst_value_array_get_value (array, i);
+ if ((buf = gst_value_get_buffer (value)) == NULL)
+ goto null_buffer;
+
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+ /* no data packets allowed */
+ if (map.size < 1)
+ goto invalid_streamheader;
+
+ /* we need packets with id 0x80, 0x81, 0x82 */
+ if (map.data[0] != 0x80 + i)
+ goto invalid_streamheader;
+
+ if (i == 0) {
+ /* identification, we need to parse this in order to get the clock rate. */
+ if (G_UNLIKELY (!gst_rtp_theora_pay_parse_id (basepayload, map.data,
+ map.size)))
+ goto parse_id_failed;
+ }
+ GST_DEBUG_OBJECT (rtptheorapay, "collecting header %d", i);
+ rtptheorapay->headers =
+ g_list_append (rtptheorapay->headers, gst_buffer_ref (buf));
+ gst_buffer_unmap (buf, &map);
+ }
+ if (!gst_rtp_theora_pay_finish_headers (basepayload))
+ goto finish_failed;
+
+done:
+ return TRUE;
+
+ /* ERRORS */
+null_buffer:
+ {
+ GST_WARNING_OBJECT (rtptheorapay, "streamheader with null buffer received");
+ return FALSE;
+ }
+invalid_streamheader:
+ {
+ GST_WARNING_OBJECT (rtptheorapay, "unable to parse initial header");
+ gst_buffer_unmap (buf, &map);
+ return FALSE;
+ }
+parse_id_failed:
+ {
+ GST_WARNING_OBJECT (rtptheorapay, "unable to parse initial header");
+ gst_buffer_unmap (buf, &map);
+ return FALSE;
+ }
+finish_failed:
+ {
+ GST_WARNING_OBJECT (rtptheorapay, "unable to finish headers");
+ return FALSE;
+ }
+}
+
+static void
+gst_rtp_theora_pay_reset_packet (GstRtpTheoraPay * rtptheorapay, guint8 TDT)
+{
+ guint payload_len;
+ GstRTPBuffer rtp = { NULL };
+
+ GST_DEBUG_OBJECT (rtptheorapay, "reset packet");
+
+ rtptheorapay->payload_pos = 4;
+ gst_rtp_buffer_map (rtptheorapay->packet, GST_MAP_READ, &rtp);
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+ gst_rtp_buffer_unmap (&rtp);
+ rtptheorapay->payload_left = payload_len - 4;
+ rtptheorapay->payload_duration = 0;
+ rtptheorapay->payload_F = 0;
+ rtptheorapay->payload_TDT = TDT;
+ rtptheorapay->payload_pkts = 0;
+}
+
+static void
+gst_rtp_theora_pay_init_packet (GstRtpTheoraPay * rtptheorapay, guint8 TDT,
+ GstClockTime timestamp)
+{
+ GST_DEBUG_OBJECT (rtptheorapay, "starting new packet, TDT: %d", TDT);
+
+ if (rtptheorapay->packet)
+ gst_buffer_unref (rtptheorapay->packet);
+
+ /* new packet allocate max packet size */
+ rtptheorapay->packet =
+ gst_rtp_buffer_new_allocate_len (GST_RTP_BASE_PAYLOAD_MTU
+ (rtptheorapay), 0, 0);
+ gst_rtp_theora_pay_reset_packet (rtptheorapay, TDT);
+
+ GST_BUFFER_TIMESTAMP (rtptheorapay->packet) = timestamp;
+}
+
+static GstFlowReturn
+gst_rtp_theora_pay_flush_packet (GstRtpTheoraPay * rtptheorapay)
+{
+ GstFlowReturn ret;
+ guint8 *payload;
+ guint hlen;
+ GstRTPBuffer rtp = { NULL };
+
+ /* check for empty packet */
+ if (!rtptheorapay->packet || rtptheorapay->payload_pos <= 4)
+ return GST_FLOW_OK;
+
+ GST_DEBUG_OBJECT (rtptheorapay, "flushing packet");
+
+ gst_rtp_buffer_map (rtptheorapay->packet, GST_MAP_WRITE, &rtp);
+
+ /* fix header */
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ /*
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Ident | F |TDT|# pkts.|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * F: Fragment type (0=none, 1=start, 2=cont, 3=end)
+ * TDT: Theora data type (0=theora, 1=config, 2=comment, 3=reserved)
+ * pkts: number of packets.
+ */
+ payload[0] = (rtptheorapay->payload_ident >> 16) & 0xff;
+ payload[1] = (rtptheorapay->payload_ident >> 8) & 0xff;
+ payload[2] = (rtptheorapay->payload_ident) & 0xff;
+ payload[3] = (rtptheorapay->payload_F & 0x3) << 6 |
+ (rtptheorapay->payload_TDT & 0x3) << 4 |
+ (rtptheorapay->payload_pkts & 0xf);
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ /* shrink the buffer size to the last written byte */
+ hlen = gst_rtp_buffer_calc_header_len (0);
+ gst_buffer_resize (rtptheorapay->packet, 0, hlen + rtptheorapay->payload_pos);
+
+ GST_BUFFER_DURATION (rtptheorapay->packet) = rtptheorapay->payload_duration;
+
+ /* push, this gives away our ref to the packet, so clear it. */
+ ret =
+ gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtptheorapay),
+ rtptheorapay->packet);
+ rtptheorapay->packet = NULL;
+
+ return ret;
+}
+
+static gboolean
+gst_rtp_theora_pay_finish_headers (GstRTPBasePayload * basepayload)
+{
+ GstRtpTheoraPay *rtptheorapay = GST_RTP_THEORA_PAY (basepayload);
+ GList *walk;
+ guint length, size, n_headers, configlen, extralen;
+ gchar *wstr, *hstr, *configuration;
+ guint8 *data, *config;
+ guint32 ident;
+ gboolean res;
+
+ GST_DEBUG_OBJECT (rtptheorapay, "finish headers");
+
+ if (!rtptheorapay->headers) {
+ GST_DEBUG_OBJECT (rtptheorapay, "We need 2 headers but have none");
+ goto no_headers;
+ }
+
+ /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Number of packed headers |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Packed header |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Packed header |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | .... |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * We only construct a config containing 1 packed header like this:
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Ident | length ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. | n. of headers | length1 | length2 ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. | Identification Header ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .................................................................
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. | Comment Header ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .................................................................
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. Comment Header |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Setup Header ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .................................................................
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. Setup Header |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ /* we need 4 bytes for the number of headers (which is always 1), 3 bytes for
+ * the ident, 2 bytes for length, 1 byte for n. of headers. */
+ size = 4 + 3 + 2 + 1;
+
+ /* count the size of the headers first and update the hash */
+ length = 0;
+ n_headers = 0;
+ ident = fnv1_hash_32_new ();
+ extralen = 1;
+ for (walk = rtptheorapay->headers; walk; walk = g_list_next (walk)) {
+ GstBuffer *buf = GST_BUFFER_CAST (walk->data);
+ GstMapInfo map;
+ guint bsize;
+
+ bsize = gst_buffer_get_size (buf);
+ length += bsize;
+ n_headers++;
+
+ /* count number of bytes needed for length fields, we don't need this for
+ * the last header. */
+ if (g_list_next (walk)) {
+ do {
+ size++;
+ extralen++;
+ bsize >>= 7;
+ } while (bsize);
+ }
+ /* update hash */
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+ ident = fnv1_hash_32_update (ident, map.data, map.size);
+ gst_buffer_unmap (buf, &map);
+ }
+
+ /* packet length is header size + packet length */
+ configlen = size + length;
+ config = data = g_malloc (configlen);
+
+ /* number of packed headers, we only pack 1 header */
+ data[0] = 0;
+ data[1] = 0;
+ data[2] = 0;
+ data[3] = 1;
+
+ ident = fnv1_hash_32_to_24 (ident);
+ rtptheorapay->payload_ident = ident;
+ GST_DEBUG_OBJECT (rtptheorapay, "ident 0x%08x", ident);
+
+ /* take lower 3 bytes */
+ data[4] = (ident >> 16) & 0xff;
+ data[5] = (ident >> 8) & 0xff;
+ data[6] = ident & 0xff;
+
+ /* store length of all theora headers */
+ data[7] = ((length) >> 8) & 0xff;
+ data[8] = (length) & 0xff;
+
+ /* store number of headers minus one. */
+ data[9] = n_headers - 1;
+ data += 10;
+
+ /* store length for each header */
+ for (walk = rtptheorapay->headers; walk; walk = g_list_next (walk)) {
+ GstBuffer *buf = GST_BUFFER_CAST (walk->data);
+ guint bsize, size, temp;
+ guint flag;
+
+ /* only need to store the length when it's not the last header */
+ if (!g_list_next (walk))
+ break;
+
+ bsize = gst_buffer_get_size (buf);
+
+ /* calc size */
+ size = 0;
+ do {
+ size++;
+ bsize >>= 7;
+ } while (bsize);
+ temp = size;
+
+ bsize = gst_buffer_get_size (buf);
+ /* write the size backwards */
+ flag = 0;
+ while (size) {
+ size--;
+ data[size] = (bsize & 0x7f) | flag;
+ bsize >>= 7;
+ flag = 0x80; /* Flag bit on all bytes of the length except the last */
+ }
+ data += temp;
+ }
+
+ /* copy header data */
+ for (walk = rtptheorapay->headers; walk; walk = g_list_next (walk)) {
+ GstBuffer *buf = GST_BUFFER_CAST (walk->data);
+
+ gst_buffer_extract (buf, 0, data, gst_buffer_get_size (buf));
+ data += gst_buffer_get_size (buf);
+ gst_buffer_unref (buf);
+ }
+ g_list_free (rtptheorapay->headers);
+ rtptheorapay->headers = NULL;
+ rtptheorapay->need_headers = FALSE;
+
+ /* serialize to base64 */
+ configuration = g_base64_encode (config, configlen);
+
+ /* store for later re-sending */
+ if (rtptheorapay->config_data)
+ g_free (rtptheorapay->config_data);
+ rtptheorapay->config_size = configlen - 4 - 3 - 2;
+ rtptheorapay->config_data = g_malloc (rtptheorapay->config_size);
+ rtptheorapay->config_extra_len = extralen;
+ memcpy (rtptheorapay->config_data, config + 4 + 3 + 2,
+ rtptheorapay->config_size);
+
+ g_free (config);
+
+ /* configure payloader settings */
+ wstr = g_strdup_printf ("%d", rtptheorapay->width);
+ hstr = g_strdup_printf ("%d", rtptheorapay->height);
+ gst_rtp_base_payload_set_options (basepayload, "video", TRUE, "THEORA",
+ 90000);
+ res =
+ gst_rtp_base_payload_set_outcaps (basepayload, "sampling", G_TYPE_STRING,
+ "YCbCr-4:2:0", "width", G_TYPE_STRING, wstr, "height", G_TYPE_STRING,
+ hstr, "configuration", G_TYPE_STRING, configuration, "delivery-method",
+ G_TYPE_STRING, "inline",
+ /* don't set the other defaults
+ */
+ NULL);
+ g_free (wstr);
+ g_free (hstr);
+ g_free (configuration);
+
+ return res;
+
+ /* ERRORS */
+no_headers:
+ {
+ GST_DEBUG_OBJECT (rtptheorapay, "finish headers");
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_rtp_theora_pay_parse_id (GstRTPBasePayload * basepayload, guint8 * data,
+ guint size)
+{
+ GstRtpTheoraPay *rtptheorapay;
+ gint width, height;
+
+ rtptheorapay = GST_RTP_THEORA_PAY (basepayload);
+
+ if (G_UNLIKELY (size < 42))
+ goto too_short;
+
+ if (G_UNLIKELY (memcmp (data, "\200theora", 7)))
+ goto invalid_start;
+ data += 7;
+
+ if (G_UNLIKELY (data[0] != 3))
+ goto invalid_version;
+ if (G_UNLIKELY (data[1] != 2))
+ goto invalid_version;
+ data += 3;
+
+ width = GST_READ_UINT16_BE (data) << 4;
+ data += 2;
+ height = GST_READ_UINT16_BE (data) << 4;
+ data += 2;
+
+ /* FIXME, parse pixel format */
+
+ /* store values */
+ rtptheorapay->width = width;
+ rtptheorapay->height = height;
+
+ return TRUE;
+
+ /* ERRORS */
+too_short:
+ {
+ GST_ELEMENT_ERROR (basepayload, STREAM, DECODE,
+ (NULL),
+ ("Identification packet is too short, need at least 42, got %d", size));
+ return FALSE;
+ }
+invalid_start:
+ {
+ GST_ELEMENT_ERROR (basepayload, STREAM, DECODE,
+ (NULL), ("Invalid header start in identification packet"));
+ return FALSE;
+ }
+invalid_version:
+ {
+ GST_ELEMENT_ERROR (basepayload, STREAM, DECODE,
+ (NULL), ("Invalid version"));
+ return FALSE;
+ }
+}
+
+static GstFlowReturn
+gst_rtp_theora_pay_payload_buffer (GstRtpTheoraPay * rtptheorapay, guint8 TDT,
+ guint8 * data, guint size, GstClockTime timestamp, GstClockTime duration,
+ guint not_in_length)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ guint newsize;
+ guint packet_len;
+ GstClockTime newduration;
+ gboolean flush;
+ guint plen;
+ guint8 *ppos, *payload;
+ gboolean fragmented;
+ GstRTPBuffer rtp = { NULL };
+
+ /* size increases with packet length and 2 bytes size eader. */
+ newduration = rtptheorapay->payload_duration;
+ if (duration != GST_CLOCK_TIME_NONE)
+ newduration += duration;
+
+ newsize = rtptheorapay->payload_pos + 2 + size;
+ packet_len = gst_rtp_buffer_calc_packet_len (newsize, 0, 0);
+
+ /* check buffer filled against length and max latency */
+ flush = gst_rtp_base_payload_is_filled (GST_RTP_BASE_PAYLOAD (rtptheorapay),
+ packet_len, newduration);
+ /* we can store up to 15 theora packets in one RTP packet. */
+ flush |= (rtptheorapay->payload_pkts == 15);
+ /* flush if we have a new TDT */
+ if (rtptheorapay->packet)
+ flush |= (rtptheorapay->payload_TDT != TDT);
+ if (flush)
+ ret = gst_rtp_theora_pay_flush_packet (rtptheorapay);
+
+ /* create new packet if we must */
+ if (!rtptheorapay->packet) {
+ gst_rtp_theora_pay_init_packet (rtptheorapay, TDT, timestamp);
+ }
+
+ gst_rtp_buffer_map (rtptheorapay->packet, GST_MAP_WRITE, &rtp);
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ ppos = payload + rtptheorapay->payload_pos;
+ fragmented = FALSE;
+
+ /* put buffer in packet, it either fits completely or needs to be fragmented
+ * over multiple RTP packets. */
+ do {
+ plen = MIN (rtptheorapay->payload_left - 2, size);
+
+ GST_DEBUG_OBJECT (rtptheorapay, "append %u bytes", plen);
+
+ /* data is copied in the payload with a 2 byte length header */
+ ppos[0] = ((plen - not_in_length) >> 8) & 0xff;
+ ppos[1] = ((plen - not_in_length) & 0xff);
+ if (plen)
+ memcpy (&ppos[2], data, plen);
+
+ /* only first (only) configuration cuts length field */
+ /* NOTE: spec (if any) is not clear on this ... */
+ not_in_length = 0;
+
+ size -= plen;
+ data += plen;
+
+ rtptheorapay->payload_pos += plen + 2;
+ rtptheorapay->payload_left -= plen + 2;
+
+ if (fragmented) {
+ if (size == 0)
+ /* last fragment, set F to 0x3. */
+ rtptheorapay->payload_F = 0x3;
+ else
+ /* fragment continues, set F to 0x2. */
+ rtptheorapay->payload_F = 0x2;
+ } else {
+ if (size > 0) {
+ /* fragmented packet starts, set F to 0x1, mark ourselves as
+ * fragmented. */
+ rtptheorapay->payload_F = 0x1;
+ fragmented = TRUE;
+ }
+ }
+ if (fragmented) {
+ gst_rtp_buffer_unmap (&rtp);
+ /* fragmented packets are always flushed and have ptks of 0 */
+ rtptheorapay->payload_pkts = 0;
+ ret = gst_rtp_theora_pay_flush_packet (rtptheorapay);
+
+ if (size > 0) {
+ /* start new packet and get pointers. TDT stays the same. */
+ gst_rtp_theora_pay_init_packet (rtptheorapay,
+ rtptheorapay->payload_TDT, timestamp);
+ gst_rtp_buffer_map (rtptheorapay->packet, GST_MAP_WRITE, &rtp);
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ ppos = payload + rtptheorapay->payload_pos;
+ }
+ } else {
+ /* unfragmented packet, update stats for next packet, size == 0 and we
+ * exit the while loop */
+ rtptheorapay->payload_pkts++;
+ if (duration != GST_CLOCK_TIME_NONE)
+ rtptheorapay->payload_duration += duration;
+ }
+ } while (size);
+
+ if (rtp.buffer)
+ gst_rtp_buffer_unmap (&rtp);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_rtp_theora_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer)
+{
+ GstRtpTheoraPay *rtptheorapay;
+ GstFlowReturn ret;
+ GstMapInfo map;
+ gsize size;
+ guint8 *data;
+ GstClockTime duration, timestamp;
+ guint8 TDT;
+ gboolean keyframe = FALSE;
+
+ rtptheorapay = GST_RTP_THEORA_PAY (basepayload);
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+ data = map.data;
+ size = map.size;
+ duration = GST_BUFFER_DURATION (buffer);
+ timestamp = GST_BUFFER_TIMESTAMP (buffer);
+
+ GST_DEBUG_OBJECT (rtptheorapay, "size %" G_GSIZE_FORMAT
+ ", duration %" GST_TIME_FORMAT, size, GST_TIME_ARGS (duration));
+
+ /* find packet type */
+ if (size == 0) {
+ TDT = 0;
+ keyframe = FALSE;
+ } else if (data[0] & 0x80) {
+ /* header */
+ if (data[0] == 0x80) {
+ /* identification, we need to parse this in order to get the clock rate.
+ */
+ if (G_UNLIKELY (!gst_rtp_theora_pay_parse_id (basepayload, data, size)))
+ goto parse_id_failed;
+ TDT = 1;
+ } else if (data[0] == 0x81) {
+ /* comment */
+ TDT = 2;
+ } else if (data[0] == 0x82) {
+ /* setup */
+ TDT = 1;
+ } else
+ goto unknown_header;
+ } else {
+ /* data */
+ TDT = 0;
+ keyframe = ((data[0] & 0x40) == 0);
+ }
+
+ /* we need to collect the headers and construct a config string from them */
+ if (TDT != 0) {
+ GST_DEBUG_OBJECT (rtptheorapay, "collecting header, buffer %p", buffer);
+ /* append header to the list of headers */
+ gst_buffer_unmap (buffer, &map);
+ rtptheorapay->headers = g_list_append (rtptheorapay->headers, buffer);
+ ret = GST_FLOW_OK;
+ goto done;
+ } else if (rtptheorapay->headers) {
+ if (rtptheorapay->need_headers) {
+ if (!gst_rtp_theora_pay_finish_headers (basepayload))
+ goto header_error;
+ } else {
+ g_list_free_full (rtptheorapay->headers,
+ (GDestroyNotify) gst_buffer_unref);
+ rtptheorapay->headers = NULL;
+ }
+ }
+
+ /* there is a config request, see if we need to insert it */
+ if (keyframe && (rtptheorapay->config_interval > 0) &&
+ rtptheorapay->config_data) {
+ gboolean send_config = FALSE;
+
+ if (rtptheorapay->last_config != -1) {
+ guint64 diff;
+
+ GST_LOG_OBJECT (rtptheorapay,
+ "now %" GST_TIME_FORMAT ", last VOP-I %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (timestamp), GST_TIME_ARGS (rtptheorapay->last_config));
+
+ /* calculate diff between last config in milliseconds */
+ if (timestamp > rtptheorapay->last_config) {
+ diff = timestamp - rtptheorapay->last_config;
+ } else {
+ diff = 0;
+ }
+
+ GST_DEBUG_OBJECT (rtptheorapay,
+ "interval since last config %" GST_TIME_FORMAT, GST_TIME_ARGS (diff));
+
+ /* bigger than interval, queue config */
+ /* FIXME should convert timestamps to running time */
+ if (GST_TIME_AS_SECONDS (diff) >= rtptheorapay->config_interval) {
+ GST_DEBUG_OBJECT (rtptheorapay, "time to send config");
+ send_config = TRUE;
+ }
+ } else {
+ /* no known previous config time, send now */
+ GST_DEBUG_OBJECT (rtptheorapay, "no previous config time, send now");
+ send_config = TRUE;
+ }
+
+ if (send_config) {
+ /* we need to send config now first */
+ /* different TDT type forces flush */
+ gst_rtp_theora_pay_payload_buffer (rtptheorapay, 1,
+ rtptheorapay->config_data, rtptheorapay->config_size,
+ timestamp, GST_CLOCK_TIME_NONE, rtptheorapay->config_extra_len);
+
+ if (timestamp != -1) {
+ rtptheorapay->last_config = timestamp;
+ }
+ }
+ }
+
+ ret = gst_rtp_theora_pay_payload_buffer (rtptheorapay, TDT, data, size,
+ timestamp, duration, 0);
+
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+
+done:
+ return ret;
+
+ /* ERRORS */
+parse_id_failed:
+ {
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+ return GST_FLOW_ERROR;
+ }
+unknown_header:
+ {
+ GST_ELEMENT_WARNING (rtptheorapay, STREAM, DECODE,
+ (NULL), ("Ignoring unknown header received"));
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+ return GST_FLOW_OK;
+ }
+header_error:
+ {
+ GST_ELEMENT_WARNING (rtptheorapay, STREAM, DECODE,
+ (NULL), ("Error initializing header config"));
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+ return GST_FLOW_OK;
+ }
+}
+
+static gboolean
+gst_rtp_theora_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+ GstRtpTheoraPay *rtptheorapay = GST_RTP_THEORA_PAY (payload);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_STOP:
+ gst_rtp_theora_pay_clear_packet (rtptheorapay);
+ break;
+ default:
+ break;
+ }
+ /* false to let parent handle event as well */
+ return GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
+}
+
+static GstStateChangeReturn
+gst_rtp_theora_pay_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstRtpTheoraPay *rtptheorapay;
+
+ GstStateChangeReturn ret;
+
+ rtptheorapay = GST_RTP_THEORA_PAY (element);
+
+ switch (transition) {
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_rtp_theora_pay_cleanup (rtptheorapay);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+static void
+gst_rtp_theora_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstRtpTheoraPay *rtptheorapay;
+
+ rtptheorapay = GST_RTP_THEORA_PAY (object);
+
+ switch (prop_id) {
+ case PROP_CONFIG_INTERVAL:
+ rtptheorapay->config_interval = g_value_get_uint (value);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gst_rtp_theora_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstRtpTheoraPay *rtptheorapay;
+
+ rtptheorapay = GST_RTP_THEORA_PAY (object);
+
+ switch (prop_id) {
+ case PROP_CONFIG_INTERVAL:
+ g_value_set_uint (value, rtptheorapay->config_interval);
+ break;
+ default:
+ break;
+ }
+}
+
+gboolean
+gst_rtp_theora_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtptheorapay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_THEORA_PAY);
+}
diff --git a/gst/rtp/gstrtptheorapay.h b/gst/rtp/gstrtptheorapay.h
new file mode 100755
index 0000000..0a1d472
--- /dev/null
+++ b/gst/rtp/gstrtptheorapay.h
@@ -0,0 +1,84 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_THEORA_PAY_H__
+#define __GST_RTP_THEORA_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_THEORA_PAY \
+ (gst_rtp_theora_pay_get_type())
+#define GST_RTP_THEORA_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_THEORA_PAY,GstRtpTheoraPay))
+#define GST_RTP_THEORA_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_THEORA_PAY,GstRtpTheoraPayClass))
+#define GST_IS_RTP_THEORA_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_THEORA_PAY))
+#define GST_IS_RTP_THEORA_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_THEORA_PAY))
+
+typedef struct _GstRtpTheoraPay GstRtpTheoraPay;
+typedef struct _GstRtpTheoraPayClass GstRtpTheoraPayClass;
+
+struct _GstRtpTheoraPay
+{
+ GstRTPBasePayload payload;
+
+ /* the headers */
+ gboolean need_headers;
+ GList *headers;
+
+ /* queues of buffers along with some stats. */
+ GstBuffer *packet;
+ guint payload_pos;
+ guint payload_left;
+ guint32 payload_ident;
+ guint8 payload_F;
+ guint8 payload_TDT;
+ guint payload_pkts;
+ GstClockTime payload_timestamp;
+ GstClockTime payload_duration;
+
+ /* config (re-sending) */
+ guint8 *config_data;
+ guint config_size;
+ guint config_extra_len;
+ guint config_interval;
+ GstClockTime last_config;
+
+ gint width;
+ gint height;
+};
+
+struct _GstRtpTheoraPayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_theora_pay_get_type (void);
+
+gboolean gst_rtp_theora_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_THEORA_PAY_H__ */
diff --git a/gst/rtp/gstrtpvorbisdepay.c b/gst/rtp/gstrtpvorbisdepay.c
new file mode 100755
index 0000000..313a6ed
--- /dev/null
+++ b/gst/rtp/gstrtpvorbisdepay.c
@@ -0,0 +1,706 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/tag/tag.h>
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <string.h>
+#include "gstrtpvorbisdepay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpvorbisdepay_debug);
+#define GST_CAT_DEFAULT (rtpvorbisdepay_debug)
+
+/* references:
+ * http://www.rfc-editor.org/rfc/rfc5215.txt
+ */
+
+static GstStaticPadTemplate gst_rtp_vorbis_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"VORBIS\""
+ /* All required parameters
+ *
+ * "encoding-params = (string) <num channels>"
+ * "configuration = (string) ANY"
+ */
+ )
+ );
+
+static GstStaticPadTemplate gst_rtp_vorbis_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-vorbis")
+ );
+
+#define gst_rtp_vorbis_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpVorbisDepay, gst_rtp_vorbis_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_vorbis_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_vorbis_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+
+static void gst_rtp_vorbis_depay_finalize (GObject * object);
+
+static GstStateChangeReturn gst_rtp_vorbis_depay_change_state (GstElement *
+ element, GstStateChange transition);
+
+static void
+gst_rtp_vorbis_depay_class_init (GstRtpVorbisDepayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gobject_class->finalize = gst_rtp_vorbis_depay_finalize;
+
+ gstelement_class->change_state = gst_rtp_vorbis_depay_change_state;
+
+ gstrtpbasedepayload_class->process = gst_rtp_vorbis_depay_process;
+ gstrtpbasedepayload_class->set_caps = gst_rtp_vorbis_depay_setcaps;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_vorbis_depay_sink_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_vorbis_depay_src_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP Vorbis depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts Vorbis Audio from RTP packets (RFC 5215)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ GST_DEBUG_CATEGORY_INIT (rtpvorbisdepay_debug, "rtpvorbisdepay", 0,
+ "Vorbis RTP Depayloader");
+}
+
+static void
+gst_rtp_vorbis_depay_init (GstRtpVorbisDepay * rtpvorbisdepay)
+{
+ rtpvorbisdepay->adapter = gst_adapter_new ();
+}
+
+static void
+free_config (GstRtpVorbisConfig * conf)
+{
+ GList *headers;
+
+ for (headers = conf->headers; headers; headers = g_list_next (headers)) {
+ GstBuffer *header = GST_BUFFER_CAST (headers->data);
+
+ gst_buffer_unref (header);
+ }
+ g_list_free (conf->headers);
+ g_free (conf);
+}
+
+static void
+free_indents (GstRtpVorbisDepay * rtpvorbisdepay)
+{
+ GList *walk;
+
+ for (walk = rtpvorbisdepay->configs; walk; walk = g_list_next (walk)) {
+ free_config ((GstRtpVorbisConfig *) walk->data);
+ }
+ g_list_free (rtpvorbisdepay->configs);
+ rtpvorbisdepay->configs = NULL;
+}
+
+static void
+gst_rtp_vorbis_depay_finalize (GObject * object)
+{
+ GstRtpVorbisDepay *rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (object);
+
+ g_object_unref (rtpvorbisdepay->adapter);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/* takes ownership of confbuf */
+static gboolean
+gst_rtp_vorbis_depay_parse_configuration (GstRtpVorbisDepay * rtpvorbisdepay,
+ GstBuffer * confbuf)
+{
+ GstBuffer *buf;
+ guint32 num_headers;
+ GstMapInfo map;
+ guint8 *data;
+ gsize size;
+ guint offset;
+ gint i, j;
+
+ gst_buffer_map (confbuf, &map, GST_MAP_READ);
+ data = map.data;
+ size = map.size;
+
+ GST_DEBUG_OBJECT (rtpvorbisdepay, "config size %" G_GSIZE_FORMAT, size);
+
+ /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Number of packed headers |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Packed header |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Packed header |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | .... |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ if (size < 4)
+ goto too_small;
+
+ num_headers = GST_READ_UINT32_BE (data);
+ size -= 4;
+ data += 4;
+ offset = 4;
+
+ GST_DEBUG_OBJECT (rtpvorbisdepay, "have %u headers", num_headers);
+
+ /* 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Ident | length ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. | n. of headers | length1 | length2 ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. | Identification Header ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .................................................................
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. | Comment Header ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .................................................................
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. Comment Header |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Setup Header ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .................................................................
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. Setup Header |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ for (i = 0; i < num_headers; i++) {
+ guint32 ident;
+ guint16 length;
+ guint8 n_headers, b;
+ GstRtpVorbisConfig *conf;
+ guint *h_sizes;
+ guint extra = 1;
+
+ if (size < 6)
+ goto too_small;
+
+ ident = (data[0] << 16) | (data[1] << 8) | data[2];
+ length = (data[3] << 8) | data[4];
+ n_headers = data[5];
+ size -= 6;
+ data += 6;
+ offset += 6;
+
+ GST_DEBUG_OBJECT (rtpvorbisdepay,
+ "header %d, ident 0x%08x, length %u, left %" G_GSIZE_FORMAT, i, ident,
+ length, size);
+
+ /* FIXME check if we already got this ident */
+
+ /* length might also include count of following size fields */
+ if (size < length && size + 1 != length)
+ goto too_small;
+
+ /* read header sizes we read 2 sizes, the third size (for which we allocate
+ * space) must be derived from the total packed header length. */
+ h_sizes = g_newa (guint, n_headers + 1);
+ for (j = 0; j < n_headers; j++) {
+ guint h_size;
+
+ h_size = 0;
+ do {
+ if (size < 1)
+ goto too_small;
+ b = *data++;
+ offset++;
+ extra++;
+ size--;
+ h_size = (h_size << 7) | (b & 0x7f);
+ } while (b & 0x80);
+ GST_DEBUG_OBJECT (rtpvorbisdepay, "headers %d: size: %u", j, h_size);
+
+ if (length < h_size)
+ goto too_small;
+
+ h_sizes[j] = h_size;
+ length -= h_size;
+ }
+ /* last header length is the remaining space */
+ GST_DEBUG_OBJECT (rtpvorbisdepay, "last header size: %u", length);
+ h_sizes[j] = length;
+
+ GST_DEBUG_OBJECT (rtpvorbisdepay, "preparing headers");
+ conf = g_new0 (GstRtpVorbisConfig, 1);
+ conf->ident = ident;
+
+ for (j = 0; j <= n_headers; j++) {
+ guint h_size;
+
+ h_size = h_sizes[j];
+ if (size < h_size) {
+ if (j != n_headers || size + extra != h_size) {
+ free_config (conf);
+ goto too_small;
+ } else {
+ /* otherwise means that overall length field contained total length,
+ * including extra fields */
+ h_size -= extra;
+ }
+ }
+
+ GST_DEBUG_OBJECT (rtpvorbisdepay, "reading header %d, size %u", j,
+ h_size);
+
+ buf = gst_buffer_copy_region (confbuf, GST_BUFFER_COPY_MEMORY, offset,
+ h_size);
+ conf->headers = g_list_append (conf->headers, buf);
+ offset += h_size;
+ size -= h_size;
+ }
+ rtpvorbisdepay->configs = g_list_append (rtpvorbisdepay->configs, conf);
+ }
+
+ gst_buffer_unmap (confbuf, &map);
+ gst_buffer_unref (confbuf);
+
+ return TRUE;
+
+ /* ERRORS */
+too_small:
+ {
+ GST_DEBUG_OBJECT (rtpvorbisdepay, "configuration too small");
+ gst_buffer_unmap (confbuf, &map);
+ gst_buffer_unref (confbuf);
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_rtp_vorbis_depay_parse_inband_configuration (GstRtpVorbisDepay *
+ rtpvorbisdepay, guint ident, guint8 * configuration, guint size,
+ guint length)
+{
+ GstBuffer *confbuf;
+ GstMapInfo map;
+
+ if (G_UNLIKELY (size < 4))
+ return FALSE;
+
+ /* transform inline to out-of-band and parse that one */
+ confbuf = gst_buffer_new_and_alloc (size + 9);
+ gst_buffer_map (confbuf, &map, GST_MAP_WRITE);
+ /* 1 header */
+ GST_WRITE_UINT32_BE (map.data, 1);
+ /* write Ident */
+ GST_WRITE_UINT24_BE (map.data + 4, ident);
+ /* write sort-of-length */
+ GST_WRITE_UINT16_BE (map.data + 7, length);
+ /* copy remainder */
+ memcpy (map.data + 9, configuration, size);
+ gst_buffer_unmap (confbuf, &map);
+
+ return gst_rtp_vorbis_depay_parse_configuration (rtpvorbisdepay, confbuf);
+}
+
+static gboolean
+gst_rtp_vorbis_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstStructure *structure;
+ GstRtpVorbisDepay *rtpvorbisdepay;
+ GstCaps *srccaps;
+ const gchar *configuration;
+ gint clock_rate;
+ gboolean res;
+
+ rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (depayload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ /* get clockrate */
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ goto no_rate;
+
+ /* read and parse configuration string */
+ configuration = gst_structure_get_string (structure, "configuration");
+ if (configuration) {
+ GstBuffer *confbuf;
+ guint8 *data;
+ gsize size;
+
+ /* deserialize base64 to buffer */
+ data = g_base64_decode (configuration, &size);
+
+ confbuf = gst_buffer_new ();
+ gst_buffer_append_memory (confbuf,
+ gst_memory_new_wrapped (0, data, size, 0, size, data, g_free));
+ if (!gst_rtp_vorbis_depay_parse_configuration (rtpvorbisdepay, confbuf))
+ goto invalid_configuration;
+ } else {
+ GST_WARNING_OBJECT (rtpvorbisdepay, "no configuration specified");
+ }
+
+ /* caps seem good, configure element */
+ depayload->clock_rate = clock_rate;
+
+ /* set caps on pad and on header */
+ srccaps = gst_caps_new_empty_simple ("audio/x-vorbis");
+ res = gst_pad_set_caps (depayload->srcpad, srccaps);
+ gst_caps_unref (srccaps);
+
+ return res;
+
+ /* ERRORS */
+invalid_configuration:
+ {
+ GST_ERROR_OBJECT (rtpvorbisdepay, "invalid configuration specified");
+ return FALSE;
+ }
+no_rate:
+ {
+ GST_ERROR_OBJECT (rtpvorbisdepay, "no clock-rate specified");
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_rtp_vorbis_depay_switch_codebook (GstRtpVorbisDepay * rtpvorbisdepay,
+ guint32 ident)
+{
+ GList *walk;
+ gboolean res = FALSE;
+
+ GST_DEBUG_OBJECT (rtpvorbisdepay, "Looking up code book ident 0x%08x", ident);
+ for (walk = rtpvorbisdepay->configs; walk; walk = g_list_next (walk)) {
+ GstRtpVorbisConfig *conf = (GstRtpVorbisConfig *) walk->data;
+
+ if (conf->ident == ident) {
+ GList *headers;
+
+ /* FIXME, remove pads, create new pad.. */
+
+ /* push out all the headers */
+ for (headers = conf->headers; headers; headers = g_list_next (headers)) {
+ GstBuffer *header = GST_BUFFER_CAST (headers->data);
+
+ gst_buffer_ref (header);
+ gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpvorbisdepay),
+ header);
+ }
+ /* remember the current config */
+ rtpvorbisdepay->config = conf;
+ res = TRUE;
+ }
+ }
+ if (!res) {
+ /* we don't know about the headers, figure out an alternative method for
+ * getting the codebooks. FIXME, fail for now. */
+ }
+ return res;
+}
+
+static GstBuffer *
+gst_rtp_vorbis_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpVorbisDepay *rtpvorbisdepay;
+ GstBuffer *outbuf;
+ GstFlowReturn ret;
+ gint payload_len;
+ guint8 *payload, *to_free = NULL;
+ guint32 header, ident;
+ guint8 F, VDT, packets;
+ GstRTPBuffer rtp = { NULL };
+ guint length;
+
+ rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (depayload);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+
+ GST_DEBUG_OBJECT (depayload, "got RTP packet of size %d", payload_len);
+
+ /* we need at least 4 bytes for the packet header */
+ if (G_UNLIKELY (payload_len < 4))
+ goto packet_short;
+
+ payload = gst_rtp_buffer_get_payload (&rtp);
+
+ header = GST_READ_UINT32_BE (payload);
+ /*
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Ident | F |VDT|# pkts.|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * F: Fragment type (0=none, 1=start, 2=cont, 3=end)
+ * VDT: Vorbis data type (0=vorbis, 1=config, 2=comment, 3=reserved)
+ * pkts: number of packets.
+ */
+ VDT = (header & 0x30) >> 4;
+ if (G_UNLIKELY (VDT == 3))
+ goto ignore_reserved;
+
+ GST_DEBUG_OBJECT (depayload, "header: 0x%08x", header);
+ ident = (header >> 8) & 0xffffff;
+ F = (header & 0xc0) >> 6;
+ packets = (header & 0xf);
+
+ if (VDT == 0) {
+ gboolean do_switch = FALSE;
+
+ /* we have a raw payload, find the codebook for the ident */
+ if (!rtpvorbisdepay->config) {
+ /* we don't have an active codebook, find the codebook and
+ * activate it */
+ GST_DEBUG_OBJECT (rtpvorbisdepay, "No active codebook, switching");
+ do_switch = TRUE;
+ } else if (rtpvorbisdepay->config->ident != ident) {
+ /* codebook changed */
+ GST_DEBUG_OBJECT (rtpvorbisdepay, "codebook changed, switching");
+ do_switch = TRUE;
+ }
+ if (do_switch) {
+ if (!gst_rtp_vorbis_depay_switch_codebook (rtpvorbisdepay, ident))
+ goto switch_failed;
+ }
+ }
+
+ /* skip header */
+ payload += 4;
+ payload_len -= 4;
+
+ GST_DEBUG_OBJECT (depayload, "ident: %u, F: %d, VDT: %d, packets: %d", ident,
+ F, VDT, packets);
+
+ /* fragmented packets, assemble */
+ if (F != 0) {
+ GstBuffer *vdata;
+ guint headerskip;
+
+ if (F == 1) {
+ /* if we start a packet, clear adapter and start assembling. */
+ gst_adapter_clear (rtpvorbisdepay->adapter);
+ GST_DEBUG_OBJECT (depayload, "start assemble");
+ rtpvorbisdepay->assembling = TRUE;
+ }
+
+ if (!rtpvorbisdepay->assembling)
+ goto no_output;
+
+ /* first assembled packet, reuse 2 bytes to store the length */
+ headerskip = (F == 1 ? 4 : 6);
+ /* skip header and length. */
+ vdata = gst_rtp_buffer_get_payload_subbuffer (&rtp, headerskip, -1);
+
+ GST_DEBUG_OBJECT (depayload, "assemble vorbis packet");
+ gst_adapter_push (rtpvorbisdepay->adapter, vdata);
+
+ /* packet is not complete, we are done */
+ if (F != 3)
+ goto no_output;
+
+ /* construct assembled buffer */
+ payload_len = gst_adapter_available (rtpvorbisdepay->adapter);
+ payload = gst_adapter_take (rtpvorbisdepay->adapter, payload_len);
+
+ /* use this length */
+ length = payload_len - 2;
+
+ to_free = payload;
+ } else {
+ /* read length from data */
+ length = 0;
+ }
+
+ GST_DEBUG_OBJECT (depayload, "assemble done");
+
+ /* we not assembling anymore now */
+ rtpvorbisdepay->assembling = FALSE;
+ gst_adapter_clear (rtpvorbisdepay->adapter);
+
+ /* payload now points to a length with that many vorbis data bytes.
+ * Iterate over the packets and send them out.
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | length | vorbis data ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. vorbis data |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | length | next vorbis packet data ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. vorbis data |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*
+ */
+ while (payload_len > 2) {
+ if (length == 0)
+ length = GST_READ_UINT16_BE (payload);
+
+ payload += 2;
+ payload_len -= 2;
+
+ GST_DEBUG_OBJECT (depayload, "read length %u, avail: %d", length,
+ payload_len);
+
+ /* skip packet if something odd happens */
+ if (G_UNLIKELY (length > payload_len))
+ goto length_short;
+
+ /* handle in-band configuration */
+ if (G_UNLIKELY (VDT == 1)) {
+ GST_DEBUG_OBJECT (rtpvorbisdepay, "in-band configuration");
+ if (!gst_rtp_vorbis_depay_parse_inband_configuration (rtpvorbisdepay,
+ ident, payload, payload_len, length))
+ goto invalid_configuration;
+ goto no_output;
+ }
+
+ /* create buffer for packet */
+ if (G_UNLIKELY (to_free)) {
+ outbuf = gst_buffer_new ();
+ gst_buffer_append_memory (outbuf,
+ gst_memory_new_wrapped (0, to_free,
+ (payload - to_free) + length, payload - to_free, length, to_free,
+ g_free));
+ to_free = NULL;
+ } else {
+ outbuf = gst_buffer_new_and_alloc (length);
+ gst_buffer_fill (outbuf, 0, payload, length);
+ }
+
+ payload += length;
+ payload_len -= length;
+ /* make sure to read next length */
+ length = 0;
+
+ ret = gst_rtp_base_depayload_push (depayload, outbuf);
+ if (ret != GST_FLOW_OK)
+ break;
+ }
+
+ g_free (to_free);
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ return NULL;
+
+no_output:
+ {
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+ /* ERORRS */
+switch_failed:
+ {
+ GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
+ (NULL), ("Could not switch codebooks"));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+packet_short:
+ {
+ GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
+ (NULL), ("Packet was too short (%d < 4)", payload_len));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+ignore_reserved:
+ {
+ GST_WARNING_OBJECT (rtpvorbisdepay, "reserved VDT ignored");
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+length_short:
+ {
+ GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
+ (NULL), ("Packet contains invalid data"));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+invalid_configuration:
+ {
+ /* fatal, as we otherwise risk carrying on without output */
+ GST_ELEMENT_ERROR (rtpvorbisdepay, STREAM, DECODE,
+ (NULL), ("Packet contains invalid configuration"));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+}
+
+static GstStateChangeReturn
+gst_rtp_vorbis_depay_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstRtpVorbisDepay *rtpvorbisdepay;
+ GstStateChangeReturn ret;
+
+ rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ free_indents (rtpvorbisdepay);
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+gboolean
+gst_rtp_vorbis_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpvorbisdepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_VORBIS_DEPAY);
+}
diff --git a/gst/rtp/gstrtpvorbisdepay.h b/gst/rtp/gstrtpvorbisdepay.h
new file mode 100755
index 0000000..a343d04
--- /dev/null
+++ b/gst/rtp/gstrtpvorbisdepay.h
@@ -0,0 +1,70 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_VORBIS_DEPAY_H__
+#define __GST_RTP_VORBIS_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_VORBIS_DEPAY \
+ (gst_rtp_vorbis_depay_get_type())
+#define GST_RTP_VORBIS_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_VORBIS_DEPAY,GstRtpVorbisDepay))
+#define GST_RTP_VORBIS_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_VORBIS_DEPAY,GstRtpVorbisDepayClass))
+#define GST_IS_RTP_VORBIS_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_VORBIS_DEPAY))
+#define GST_IS_RTP_VORBIS_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_VORBIS_DEPAY))
+
+typedef struct _GstRtpVorbisDepay GstRtpVorbisDepay;
+typedef struct _GstRtpVorbisDepayClass GstRtpVorbisDepayClass;
+
+typedef struct _GstRtpVorbisConfig {
+ guint32 ident;
+ GList *headers;
+} GstRtpVorbisConfig;
+
+struct _GstRtpVorbisDepay
+{
+ GstRTPBaseDepayload parent;
+
+ GList *configs;
+ GstRtpVorbisConfig *config;
+
+ GstAdapter *adapter;
+ gboolean assembling;
+};
+
+struct _GstRtpVorbisDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_vorbis_depay_get_type (void);
+
+gboolean gst_rtp_vorbis_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_VORBIS_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpvorbispay.c b/gst/rtp/gstrtpvorbispay.c
new file mode 100755
index 0000000..a89b3a6
--- /dev/null
+++ b/gst/rtp/gstrtpvorbispay.c
@@ -0,0 +1,943 @@
+/* GStreamer
+ * Copyright (C) <2006> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "fnv1hash.h"
+#include "gstrtpvorbispay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpvorbispay_debug);
+#define GST_CAT_DEFAULT (rtpvorbispay_debug)
+
+/* references:
+ * http://www.rfc-editor.org/rfc/rfc5215.txt
+ */
+
+static GstStaticPadTemplate gst_rtp_vorbis_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"audio\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"VORBIS\""
+ /* All required parameters
+ *
+ * "encoding-params = (string) <num channels>"
+ * "configuration = (string) ANY"
+ */
+ )
+ );
+
+static GstStaticPadTemplate gst_rtp_vorbis_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-vorbis")
+ );
+
+#define DEFAULT_CONFIG_INTERVAL 0
+
+enum
+{
+ PROP_0,
+ PROP_CONFIG_INTERVAL
+};
+
+#define gst_rtp_vorbis_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpVorbisPay, gst_rtp_vorbis_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static gboolean gst_rtp_vorbis_pay_setcaps (GstRTPBasePayload * basepayload,
+ GstCaps * caps);
+static GstStateChangeReturn gst_rtp_vorbis_pay_change_state (GstElement *
+ element, GstStateChange transition);
+static GstFlowReturn gst_rtp_vorbis_pay_handle_buffer (GstRTPBasePayload * pad,
+ GstBuffer * buffer);
+static gboolean gst_rtp_vorbis_pay_sink_event (GstRTPBasePayload * payload,
+ GstEvent * event);
+
+static gboolean gst_rtp_vorbis_pay_parse_id (GstRTPBasePayload * basepayload,
+ guint8 * data, guint size);
+static gboolean gst_rtp_vorbis_pay_finish_headers (GstRTPBasePayload *
+ basepayload);
+
+static void gst_rtp_vorbis_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_rtp_vorbis_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void
+gst_rtp_vorbis_pay_class_init (GstRtpVorbisPayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gstelement_class->change_state = gst_rtp_vorbis_pay_change_state;
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_vorbis_pay_setcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_vorbis_pay_handle_buffer;
+ gstrtpbasepayload_class->sink_event = gst_rtp_vorbis_pay_sink_event;
+
+ gobject_class->set_property = gst_rtp_vorbis_pay_set_property;
+ gobject_class->get_property = gst_rtp_vorbis_pay_get_property;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_vorbis_pay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_vorbis_pay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP Vorbis payloader",
+ "Codec/Payloader/Network/RTP",
+ "Payload-encode Vorbis audio into RTP packets (RFC 5215)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ GST_DEBUG_CATEGORY_INIT (rtpvorbispay_debug, "rtpvorbispay", 0,
+ "Vorbis RTP Payloader");
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CONFIG_INTERVAL,
+ g_param_spec_uint ("config-interval", "Config Send Interval",
+ "Send Config Insertion Interval in seconds (configuration headers "
+ "will be multiplexed in the data stream when detected.) (0 = disabled)",
+ 0, 3600, DEFAULT_CONFIG_INTERVAL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+ );
+}
+
+static void
+gst_rtp_vorbis_pay_init (GstRtpVorbisPay * rtpvorbispay)
+{
+ rtpvorbispay->last_config = GST_CLOCK_TIME_NONE;
+}
+
+static void
+gst_rtp_vorbis_pay_clear_packet (GstRtpVorbisPay * rtpvorbispay)
+{
+ if (rtpvorbispay->packet)
+ gst_buffer_unref (rtpvorbispay->packet);
+ rtpvorbispay->packet = NULL;
+}
+
+static void
+gst_rtp_vorbis_pay_cleanup (GstRtpVorbisPay * rtpvorbispay)
+{
+ g_list_foreach (rtpvorbispay->headers, (GFunc) gst_mini_object_unref, NULL);
+ g_list_free (rtpvorbispay->headers);
+ rtpvorbispay->headers = NULL;
+
+ gst_rtp_vorbis_pay_clear_packet (rtpvorbispay);
+
+ if (rtpvorbispay->config_data)
+ g_free (rtpvorbispay->config_data);
+ rtpvorbispay->config_data = NULL;
+ rtpvorbispay->last_config = GST_CLOCK_TIME_NONE;
+}
+
+static gboolean
+gst_rtp_vorbis_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
+{
+ GstRtpVorbisPay *rtpvorbispay;
+ GstStructure *s;
+ const GValue *array;
+ gint asize, i;
+ GstBuffer *buf;
+ GstMapInfo map;
+
+ rtpvorbispay = GST_RTP_VORBIS_PAY (basepayload);
+
+ s = gst_caps_get_structure (caps, 0);
+
+ rtpvorbispay->need_headers = TRUE;
+
+ if ((array = gst_structure_get_value (s, "streamheader")) == NULL)
+ goto done;
+
+ if (G_VALUE_TYPE (array) != GST_TYPE_ARRAY)
+ goto done;
+
+ if ((asize = gst_value_array_get_size (array)) < 3)
+ goto done;
+
+ for (i = 0; i < asize; i++) {
+ const GValue *value;
+
+ value = gst_value_array_get_value (array, i);
+ if ((buf = gst_value_get_buffer (value)) == NULL)
+ goto null_buffer;
+
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+ if (map.size < 1)
+ goto invalid_streamheader;
+
+ /* no data packets allowed */
+ if ((map.data[0] & 1) == 0)
+ goto invalid_streamheader;
+
+ /* we need packets with id 1, 3, 5 */
+ if (map.data[0] != (i * 2) + 1)
+ goto invalid_streamheader;
+
+ if (i == 0) {
+ /* identification, we need to parse this in order to get the clock rate. */
+ if (G_UNLIKELY (!gst_rtp_vorbis_pay_parse_id (basepayload, map.data,
+ map.size)))
+ goto parse_id_failed;
+ }
+ GST_DEBUG_OBJECT (rtpvorbispay, "collecting header %d", i);
+ rtpvorbispay->headers =
+ g_list_append (rtpvorbispay->headers, gst_buffer_ref (buf));
+ gst_buffer_unmap (buf, &map);
+ }
+ if (!gst_rtp_vorbis_pay_finish_headers (basepayload))
+ goto finish_failed;
+
+done:
+ return TRUE;
+
+ /* ERRORS */
+null_buffer:
+ {
+ GST_WARNING_OBJECT (rtpvorbispay, "streamheader with null buffer received");
+ return FALSE;
+ }
+invalid_streamheader:
+ {
+ GST_WARNING_OBJECT (rtpvorbispay, "unable to parse initial header");
+ gst_buffer_unmap (buf, &map);
+ return FALSE;
+ }
+parse_id_failed:
+ {
+ GST_WARNING_OBJECT (rtpvorbispay, "unable to parse initial header");
+ gst_buffer_unmap (buf, &map);
+ return FALSE;
+ }
+finish_failed:
+ {
+ GST_WARNING_OBJECT (rtpvorbispay, "unable to finish headers");
+ return FALSE;
+ }
+}
+
+static void
+gst_rtp_vorbis_pay_reset_packet (GstRtpVorbisPay * rtpvorbispay, guint8 VDT)
+{
+ guint payload_len;
+ GstRTPBuffer rtp = { NULL };
+
+ GST_LOG_OBJECT (rtpvorbispay, "reset packet");
+
+ rtpvorbispay->payload_pos = 4;
+ gst_rtp_buffer_map (rtpvorbispay->packet, GST_MAP_READ, &rtp);
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+ gst_rtp_buffer_unmap (&rtp);
+ rtpvorbispay->payload_left = payload_len - 4;
+ rtpvorbispay->payload_duration = 0;
+ rtpvorbispay->payload_F = 0;
+ rtpvorbispay->payload_VDT = VDT;
+ rtpvorbispay->payload_pkts = 0;
+}
+
+static void
+gst_rtp_vorbis_pay_init_packet (GstRtpVorbisPay * rtpvorbispay, guint8 VDT,
+ GstClockTime timestamp)
+{
+ GST_LOG_OBJECT (rtpvorbispay, "starting new packet, VDT: %d", VDT);
+
+ if (rtpvorbispay->packet)
+ gst_buffer_unref (rtpvorbispay->packet);
+
+ /* new packet allocate max packet size */
+ rtpvorbispay->packet =
+ gst_rtp_buffer_new_allocate_len (GST_RTP_BASE_PAYLOAD_MTU
+ (rtpvorbispay), 0, 0);
+ gst_rtp_vorbis_pay_reset_packet (rtpvorbispay, VDT);
+
+ GST_BUFFER_TIMESTAMP (rtpvorbispay->packet) = timestamp;
+}
+
+static GstFlowReturn
+gst_rtp_vorbis_pay_flush_packet (GstRtpVorbisPay * rtpvorbispay)
+{
+ GstFlowReturn ret;
+ guint8 *payload;
+ guint hlen;
+ GstRTPBuffer rtp = { NULL };
+
+ /* check for empty packet */
+ if (!rtpvorbispay->packet || rtpvorbispay->payload_pos <= 4)
+ return GST_FLOW_OK;
+
+ GST_LOG_OBJECT (rtpvorbispay, "flushing packet");
+
+ gst_rtp_buffer_map (rtpvorbispay->packet, GST_MAP_WRITE, &rtp);
+
+ /* fix header */
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ /*
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Ident | F |VDT|# pkts.|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * F: Fragment type (0=none, 1=start, 2=cont, 3=end)
+ * VDT: Vorbis data type (0=vorbis, 1=config, 2=comment, 3=reserved)
+ * pkts: number of packets.
+ */
+ payload[0] = (rtpvorbispay->payload_ident >> 16) & 0xff;
+ payload[1] = (rtpvorbispay->payload_ident >> 8) & 0xff;
+ payload[2] = (rtpvorbispay->payload_ident) & 0xff;
+ payload[3] = (rtpvorbispay->payload_F & 0x3) << 6 |
+ (rtpvorbispay->payload_VDT & 0x3) << 4 |
+ (rtpvorbispay->payload_pkts & 0xf);
+
+ gst_rtp_buffer_unmap (&rtp);
+
+ /* shrink the buffer size to the last written byte */
+ hlen = gst_rtp_buffer_calc_header_len (0);
+ gst_buffer_resize (rtpvorbispay->packet, 0, hlen + rtpvorbispay->payload_pos);
+
+ GST_BUFFER_DURATION (rtpvorbispay->packet) = rtpvorbispay->payload_duration;
+
+ /* push, this gives away our ref to the packet, so clear it. */
+ ret =
+ gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpvorbispay),
+ rtpvorbispay->packet);
+ rtpvorbispay->packet = NULL;
+
+ return ret;
+}
+
+static gboolean
+gst_rtp_vorbis_pay_finish_headers (GstRTPBasePayload * basepayload)
+{
+ GstRtpVorbisPay *rtpvorbispay = GST_RTP_VORBIS_PAY (basepayload);
+ GList *walk;
+ guint length, size, n_headers, configlen, extralen;
+ gchar *cstr, *configuration;
+ guint8 *data, *config;
+ guint32 ident;
+ gboolean res;
+
+ GST_DEBUG_OBJECT (rtpvorbispay, "finish headers");
+
+ if (!rtpvorbispay->headers)
+ goto no_headers;
+
+ /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Number of packed headers |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Packed header |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Packed header |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | .... |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * We only construct a config containing 1 packed header like this:
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Ident | length ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. | n. of headers | length1 | length2 ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. | Identification Header ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .................................................................
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. | Comment Header ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .................................................................
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. Comment Header |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Setup Header ..
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .................................................................
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * .. Setup Header |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ /* we need 4 bytes for the number of headers (which is always 1), 3 bytes for
+ * the ident, 2 bytes for length, 1 byte for n. of headers. */
+ size = 4 + 3 + 2 + 1;
+
+ /* count the size of the headers first and update the hash */
+ length = 0;
+ n_headers = 0;
+ ident = fnv1_hash_32_new ();
+ extralen = 1;
+ for (walk = rtpvorbispay->headers; walk; walk = g_list_next (walk)) {
+ GstBuffer *buf = GST_BUFFER_CAST (walk->data);
+ GstMapInfo map;
+ guint bsize;
+
+ bsize = gst_buffer_get_size (buf);
+ length += bsize;
+ n_headers++;
+
+ /* count number of bytes needed for length fields, we don't need this for
+ * the last header. */
+ if (g_list_next (walk)) {
+ do {
+ size++;
+ extralen++;
+ bsize >>= 7;
+ } while (bsize);
+ }
+ /* update hash */
+ gst_buffer_map (buf, &map, GST_MAP_READ);
+ ident = fnv1_hash_32_update (ident, map.data, map.size);
+ gst_buffer_unmap (buf, &map);
+ }
+
+ /* packet length is header size + packet length */
+ configlen = size + length;
+ config = data = g_malloc (configlen);
+
+ /* number of packed headers, we only pack 1 header */
+ data[0] = 0;
+ data[1] = 0;
+ data[2] = 0;
+ data[3] = 1;
+
+ ident = fnv1_hash_32_to_24 (ident);
+ rtpvorbispay->payload_ident = ident;
+ GST_DEBUG_OBJECT (rtpvorbispay, "ident 0x%08x", ident);
+
+ /* take lower 3 bytes */
+ data[4] = (ident >> 16) & 0xff;
+ data[5] = (ident >> 8) & 0xff;
+ data[6] = ident & 0xff;
+
+ /* store length of all vorbis headers */
+ data[7] = ((length) >> 8) & 0xff;
+ data[8] = (length) & 0xff;
+
+ /* store number of headers minus one. */
+ data[9] = n_headers - 1;
+ data += 10;
+
+ /* store length for each header */
+ for (walk = rtpvorbispay->headers; walk; walk = g_list_next (walk)) {
+ GstBuffer *buf = GST_BUFFER_CAST (walk->data);
+ guint bsize, size, temp;
+ guint flag;
+
+ /* only need to store the length when it's not the last header */
+ if (!g_list_next (walk))
+ break;
+
+ bsize = gst_buffer_get_size (buf);
+
+ /* calc size */
+ size = 0;
+ do {
+ size++;
+ bsize >>= 7;
+ } while (bsize);
+ temp = size;
+
+ bsize = gst_buffer_get_size (buf);
+ /* write the size backwards */
+ flag = 0;
+ while (size) {
+ size--;
+ data[size] = (bsize & 0x7f) | flag;
+ bsize >>= 7;
+ flag = 0x80; /* Flag bit on all bytes of the length except the last */
+ }
+ data += temp;
+ }
+
+ /* copy header data */
+ for (walk = rtpvorbispay->headers; walk; walk = g_list_next (walk)) {
+ GstBuffer *buf = GST_BUFFER_CAST (walk->data);
+
+ gst_buffer_extract (buf, 0, data, gst_buffer_get_size (buf));
+ data += gst_buffer_get_size (buf);
+ gst_buffer_unref (buf);
+ }
+ g_list_free (rtpvorbispay->headers);
+ rtpvorbispay->headers = NULL;
+ rtpvorbispay->need_headers = FALSE;
+
+ /* serialize to base64 */
+ configuration = g_base64_encode (config, configlen);
+
+ /* store for later re-sending */
+ if (rtpvorbispay->config_data)
+ g_free (rtpvorbispay->config_data);
+ rtpvorbispay->config_size = configlen - 4 - 3 - 2;
+ rtpvorbispay->config_data = g_malloc (rtpvorbispay->config_size);
+ rtpvorbispay->config_extra_len = extralen;
+ memcpy (rtpvorbispay->config_data, config + 4 + 3 + 2,
+ rtpvorbispay->config_size);
+
+ g_free (config);
+
+ /* configure payloader settings */
+ cstr = g_strdup_printf ("%d", rtpvorbispay->channels);
+ gst_rtp_base_payload_set_options (basepayload, "audio", TRUE, "VORBIS",
+ rtpvorbispay->rate);
+ res =
+ gst_rtp_base_payload_set_outcaps (basepayload, "encoding-params",
+ G_TYPE_STRING, cstr, "configuration", G_TYPE_STRING, configuration, NULL);
+ g_free (cstr);
+ g_free (configuration);
+
+ return res;
+
+ /* ERRORS */
+no_headers:
+ {
+ GST_DEBUG_OBJECT (rtpvorbispay, "finish headers");
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_rtp_vorbis_pay_parse_id (GstRTPBasePayload * basepayload, guint8 * data,
+ guint size)
+{
+ GstRtpVorbisPay *rtpvorbispay = GST_RTP_VORBIS_PAY (basepayload);
+ guint8 channels;
+ gint32 rate, version;
+
+ if (G_UNLIKELY (size < 16))
+ goto too_short;
+
+ if (G_UNLIKELY (memcmp (data, "\001vorbis", 7)))
+ goto invalid_start;
+ data += 7;
+
+ if (G_UNLIKELY ((version = GST_READ_UINT32_LE (data)) != 0))
+ goto invalid_version;
+ data += 4;
+
+ if (G_UNLIKELY ((channels = *data++) < 1))
+ goto invalid_channels;
+
+ if (G_UNLIKELY ((rate = GST_READ_UINT32_LE (data)) < 1))
+ goto invalid_rate;
+
+ /* all fine, store the values */
+ rtpvorbispay->channels = channels;
+ rtpvorbispay->rate = rate;
+
+ return TRUE;
+
+ /* ERRORS */
+too_short:
+ {
+ GST_ELEMENT_ERROR (basepayload, STREAM, DECODE,
+ ("Identification packet is too short, need at least 16, got %d", size),
+ (NULL));
+ return FALSE;
+ }
+invalid_start:
+ {
+ GST_ELEMENT_ERROR (basepayload, STREAM, DECODE,
+ ("Invalid header start in identification packet"), (NULL));
+ return FALSE;
+ }
+invalid_version:
+ {
+ GST_ELEMENT_ERROR (basepayload, STREAM, DECODE,
+ ("Invalid version, expected 0, got %d", version), (NULL));
+ return FALSE;
+ }
+invalid_rate:
+ {
+ GST_ELEMENT_ERROR (basepayload, STREAM, DECODE,
+ ("Invalid rate %d", rate), (NULL));
+ return FALSE;
+ }
+invalid_channels:
+ {
+ GST_ELEMENT_ERROR (basepayload, STREAM, DECODE,
+ ("Invalid channels %d", channels), (NULL));
+ return FALSE;
+ }
+}
+
+static GstFlowReturn
+gst_rtp_vorbis_pay_payload_buffer (GstRtpVorbisPay * rtpvorbispay, guint8 VDT,
+ guint8 * data, guint size, GstClockTime timestamp, GstClockTime duration,
+ guint not_in_length)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ guint newsize;
+ guint packet_len;
+ GstClockTime newduration;
+ gboolean flush;
+ guint plen;
+ guint8 *ppos, *payload;
+ gboolean fragmented;
+ GstRTPBuffer rtp = { NULL };
+
+ /* size increases with packet length and 2 bytes size eader. */
+ newduration = rtpvorbispay->payload_duration;
+ if (duration != GST_CLOCK_TIME_NONE)
+ newduration += duration;
+
+ newsize = rtpvorbispay->payload_pos + 2 + size;
+ packet_len = gst_rtp_buffer_calc_packet_len (newsize, 0, 0);
+
+ /* check buffer filled against length and max latency */
+ flush = gst_rtp_base_payload_is_filled (GST_RTP_BASE_PAYLOAD (rtpvorbispay),
+ packet_len, newduration);
+ /* we can store up to 15 vorbis packets in one RTP packet. */
+ flush |= (rtpvorbispay->payload_pkts == 15);
+ /* flush if we have a new VDT */
+ if (rtpvorbispay->packet)
+ flush |= (rtpvorbispay->payload_VDT != VDT);
+ if (flush)
+ ret = gst_rtp_vorbis_pay_flush_packet (rtpvorbispay);
+
+ /* create new packet if we must */
+ if (!rtpvorbispay->packet) {
+ gst_rtp_vorbis_pay_init_packet (rtpvorbispay, VDT, timestamp);
+ }
+
+ gst_rtp_buffer_map (rtpvorbispay->packet, GST_MAP_WRITE, &rtp);
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ ppos = payload + rtpvorbispay->payload_pos;
+ fragmented = FALSE;
+
+ /* put buffer in packet, it either fits completely or needs to be fragmented
+ * over multiple RTP packets. */
+ do {
+ plen = MIN (rtpvorbispay->payload_left - 2, size);
+
+ GST_LOG_OBJECT (rtpvorbispay, "append %u bytes", plen);
+
+ /* data is copied in the payload with a 2 byte length header */
+ ppos[0] = ((plen - not_in_length) >> 8) & 0xff;
+ ppos[1] = ((plen - not_in_length) & 0xff);
+ if (plen)
+ memcpy (&ppos[2], data, plen);
+
+ /* only first (only) configuration cuts length field */
+ /* NOTE: spec (if any) is not clear on this ... */
+ not_in_length = 0;
+
+ size -= plen;
+ data += plen;
+
+ rtpvorbispay->payload_pos += plen + 2;
+ rtpvorbispay->payload_left -= plen + 2;
+
+ if (fragmented) {
+ if (size == 0)
+ /* last fragment, set F to 0x3. */
+ rtpvorbispay->payload_F = 0x3;
+ else
+ /* fragment continues, set F to 0x2. */
+ rtpvorbispay->payload_F = 0x2;
+ } else {
+ if (size > 0) {
+ /* fragmented packet starts, set F to 0x1, mark ourselves as
+ * fragmented. */
+ rtpvorbispay->payload_F = 0x1;
+ fragmented = TRUE;
+ }
+ }
+ if (fragmented) {
+ gst_rtp_buffer_unmap (&rtp);
+ /* fragmented packets are always flushed and have ptks of 0 */
+ rtpvorbispay->payload_pkts = 0;
+ ret = gst_rtp_vorbis_pay_flush_packet (rtpvorbispay);
+
+ if (size > 0) {
+ /* start new packet and get pointers. VDT stays the same. */
+ gst_rtp_vorbis_pay_init_packet (rtpvorbispay,
+ rtpvorbispay->payload_VDT, timestamp);
+ gst_rtp_buffer_map (rtpvorbispay->packet, GST_MAP_WRITE, &rtp);
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ ppos = payload + rtpvorbispay->payload_pos;
+ }
+ } else {
+ /* unfragmented packet, update stats for next packet, size == 0 and we
+ * exit the while loop */
+ rtpvorbispay->payload_pkts++;
+ if (duration != GST_CLOCK_TIME_NONE)
+ rtpvorbispay->payload_duration += duration;
+ }
+ } while (size);
+
+ if (rtp.buffer)
+ gst_rtp_buffer_unmap (&rtp);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_rtp_vorbis_pay_handle_buffer (GstRTPBasePayload * basepayload,
+ GstBuffer * buffer)
+{
+ GstRtpVorbisPay *rtpvorbispay;
+ GstFlowReturn ret;
+ GstMapInfo map;
+ gsize size;
+ guint8 *data;
+ GstClockTime duration, timestamp;
+ guint8 VDT;
+
+ rtpvorbispay = GST_RTP_VORBIS_PAY (basepayload);
+
+ gst_buffer_map (buffer, &map, GST_MAP_READ);
+ data = map.data;
+ size = map.size;
+ duration = GST_BUFFER_DURATION (buffer);
+ timestamp = GST_BUFFER_TIMESTAMP (buffer);
+
+ GST_LOG_OBJECT (rtpvorbispay, "size %" G_GSIZE_FORMAT
+ ", duration %" GST_TIME_FORMAT, size, GST_TIME_ARGS (duration));
+
+ if (G_UNLIKELY (size < 1))
+ goto wrong_size;
+
+ /* find packet type */
+ if (data[0] & 1) {
+ /* header */
+ if (data[0] == 1) {
+ /* identification, we need to parse this in order to get the clock rate. */
+ if (G_UNLIKELY (!gst_rtp_vorbis_pay_parse_id (basepayload, data, size)))
+ goto parse_id_failed;
+ VDT = 1;
+ } else if (data[0] == 3) {
+ /* comment */
+ VDT = 2;
+ } else if (data[0] == 5) {
+ /* setup */
+ VDT = 1;
+ } else
+ goto unknown_header;
+ } else
+ /* data */
+ VDT = 0;
+
+ /* we need to collect the headers and construct a config string from them */
+ if (VDT != 0) {
+ GST_DEBUG_OBJECT (rtpvorbispay, "collecting header");
+ /* append header to the list of headers */
+ gst_buffer_unmap (buffer, &map);
+ rtpvorbispay->headers = g_list_append (rtpvorbispay->headers, buffer);
+ ret = GST_FLOW_OK;
+ goto done;
+ } else if (rtpvorbispay->headers) {
+ if (rtpvorbispay->need_headers) {
+ if (!gst_rtp_vorbis_pay_finish_headers (basepayload))
+ goto header_error;
+ } else {
+ g_list_free_full (rtpvorbispay->headers,
+ (GDestroyNotify) gst_buffer_unref);
+ rtpvorbispay->headers = NULL;
+ }
+ }
+
+ /* there is a config request, see if we need to insert it */
+ if (rtpvorbispay->config_interval > 0 && rtpvorbispay->config_data) {
+ gboolean send_config = FALSE;
+
+ if (rtpvorbispay->last_config != -1) {
+ guint64 diff;
+
+ GST_LOG_OBJECT (rtpvorbispay,
+ "now %" GST_TIME_FORMAT ", last config %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (timestamp), GST_TIME_ARGS (rtpvorbispay->last_config));
+
+ /* calculate diff between last config in milliseconds */
+ if (timestamp > rtpvorbispay->last_config) {
+ diff = timestamp - rtpvorbispay->last_config;
+ } else {
+ diff = 0;
+ }
+
+ GST_DEBUG_OBJECT (rtpvorbispay,
+ "interval since last config %" GST_TIME_FORMAT, GST_TIME_ARGS (diff));
+
+ /* bigger than interval, queue config */
+ /* FIXME should convert timestamps to running time */
+ if (GST_TIME_AS_SECONDS (diff) >= rtpvorbispay->config_interval) {
+ GST_DEBUG_OBJECT (rtpvorbispay, "time to send config");
+ send_config = TRUE;
+ }
+ } else {
+ /* no known previous config time, send now */
+ GST_DEBUG_OBJECT (rtpvorbispay, "no previous config time, send now");
+ send_config = TRUE;
+ }
+
+ if (send_config) {
+ /* we need to send config now first */
+ /* different TDT type forces flush */
+ gst_rtp_vorbis_pay_payload_buffer (rtpvorbispay, 1,
+ rtpvorbispay->config_data, rtpvorbispay->config_size,
+ timestamp, GST_CLOCK_TIME_NONE, rtpvorbispay->config_extra_len);
+
+ if (timestamp != -1) {
+ rtpvorbispay->last_config = timestamp;
+ }
+ }
+ }
+
+ ret = gst_rtp_vorbis_pay_payload_buffer (rtpvorbispay, VDT, data, size,
+ timestamp, duration, 0);
+
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+
+done:
+ return ret;
+
+ /* ERRORS */
+wrong_size:
+ {
+ GST_ELEMENT_WARNING (rtpvorbispay, STREAM, DECODE,
+ ("Invalid packet size (1 < %" G_GSIZE_FORMAT ")", size), (NULL));
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+ return GST_FLOW_OK;
+ }
+parse_id_failed:
+ {
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+ return GST_FLOW_ERROR;
+ }
+unknown_header:
+ {
+ GST_ELEMENT_WARNING (rtpvorbispay, STREAM, DECODE,
+ (NULL), ("Ignoring unknown header received"));
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+ return GST_FLOW_OK;
+ }
+header_error:
+ {
+ GST_ELEMENT_WARNING (rtpvorbispay, STREAM, DECODE,
+ (NULL), ("Error initializing header config"));
+ gst_buffer_unmap (buffer, &map);
+ gst_buffer_unref (buffer);
+ return GST_FLOW_OK;
+ }
+}
+
+static gboolean
+gst_rtp_vorbis_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+ GstRtpVorbisPay *rtpvorbispay = GST_RTP_VORBIS_PAY (payload);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_STOP:
+ gst_rtp_vorbis_pay_clear_packet (rtpvorbispay);
+ break;
+ default:
+ break;
+ }
+ /* false to let parent handle event as well */
+ return GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
+}
+
+static GstStateChangeReturn
+gst_rtp_vorbis_pay_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstRtpVorbisPay *rtpvorbispay;
+ GstStateChangeReturn ret;
+
+ rtpvorbispay = GST_RTP_VORBIS_PAY (element);
+
+ switch (transition) {
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_rtp_vorbis_pay_cleanup (rtpvorbispay);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+static void
+gst_rtp_vorbis_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstRtpVorbisPay *rtpvorbispay;
+
+ rtpvorbispay = GST_RTP_VORBIS_PAY (object);
+
+ switch (prop_id) {
+ case PROP_CONFIG_INTERVAL:
+ rtpvorbispay->config_interval = g_value_get_uint (value);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gst_rtp_vorbis_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstRtpVorbisPay *rtpvorbispay;
+
+ rtpvorbispay = GST_RTP_VORBIS_PAY (object);
+
+ switch (prop_id) {
+ case PROP_CONFIG_INTERVAL:
+ g_value_set_uint (value, rtpvorbispay->config_interval);
+ break;
+ default:
+ break;
+ }
+}
+
+gboolean
+gst_rtp_vorbis_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpvorbispay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_VORBIS_PAY);
+}
diff --git a/gst/rtp/gstrtpvorbispay.h b/gst/rtp/gstrtpvorbispay.h
new file mode 100755
index 0000000..8f0974a
--- /dev/null
+++ b/gst/rtp/gstrtpvorbispay.h
@@ -0,0 +1,84 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_VORBIS_PAY_H__
+#define __GST_RTP_VORBIS_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_VORBIS_PAY \
+ (gst_rtp_vorbis_pay_get_type())
+#define GST_RTP_VORBIS_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_VORBIS_PAY,GstRtpVorbisPay))
+#define GST_RTP_VORBIS_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_VORBIS_PAY,GstRtpVorbisPayClass))
+#define GST_IS_RTP_VORBIS_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_VORBIS_PAY))
+#define GST_IS_RTP_VORBIS_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_VORBIS_PAY))
+
+typedef struct _GstRtpVorbisPay GstRtpVorbisPay;
+typedef struct _GstRtpVorbisPayClass GstRtpVorbisPayClass;
+
+struct _GstRtpVorbisPay
+{
+ GstRTPBasePayload payload;
+
+ /* the headers */
+ gboolean need_headers;
+ GList *headers;
+
+ /* queues of buffers along with some stats. */
+ GstBuffer *packet;
+ guint payload_pos;
+ guint payload_left;
+ guint32 payload_ident;
+ guint8 payload_F;
+ guint8 payload_VDT;
+ guint payload_pkts;
+ GstClockTime payload_timestamp;
+ GstClockTime payload_duration;
+
+ /* config (re-sending) */
+ guint8 *config_data;
+ guint config_size;
+ guint config_extra_len;
+ guint config_interval;
+ GstClockTime last_config;
+
+ gint rate;
+ gint channels;
+};
+
+struct _GstRtpVorbisPayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_vorbis_pay_get_type (void);
+
+gboolean gst_rtp_vorbis_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_VORBIS_PAY_H__ */
diff --git a/gst/rtp/gstrtpvp8depay.c b/gst/rtp/gstrtpvp8depay.c
new file mode 100755
index 0000000..cafdad5
--- /dev/null
+++ b/gst/rtp/gstrtpvp8depay.c
@@ -0,0 +1,296 @@
+/* gstrtpvp8depay.c - Source for GstRtpVP8Depay
+ * Copyright (C) 2011 Sjoerd Simons <sjoerd@luon.net>
+ * Copyright (C) 2011 Collabora Ltd.
+ * Contact: Youness Alaoui <youness.alaoui@collabora.co.uk>
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gstrtpvp8depay.h"
+
+#include <gst/video/video.h>
+
+#include <stdio.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_rtp_vp8_depay_debug);
+#define GST_CAT_DEFAULT gst_rtp_vp8_depay_debug
+
+static void gst_rtp_vp8_depay_dispose (GObject * object);
+static GstBuffer *gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+static GstStateChangeReturn gst_rtp_vp8_depay_change_state (GstElement *
+ element, GstStateChange transition);
+static gboolean gst_rtp_vp8_depay_handle_event (GstRTPBaseDepayload * depay,
+ GstEvent * event);
+
+G_DEFINE_TYPE (GstRtpVP8Depay, gst_rtp_vp8_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static GstStaticPadTemplate gst_rtp_vp8_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-vp8"));
+
+static GstStaticPadTemplate gst_rtp_vp8_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "clock-rate = (int) 90000,"
+ "media = (string) \"video\","
+ "encoding-name = (string) { \"VP8\", \"VP8-DRAFT-IETF-01\" }"));
+
+static void
+gst_rtp_vp8_depay_init (GstRtpVP8Depay * self)
+{
+ self->adapter = gst_adapter_new ();
+ self->started = FALSE;
+}
+
+static void
+gst_rtp_vp8_depay_class_init (GstRtpVP8DepayClass * gst_rtp_vp8_depay_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (gst_rtp_vp8_depay_class);
+ GstElementClass *element_class = GST_ELEMENT_CLASS (gst_rtp_vp8_depay_class);
+ GstRTPBaseDepayloadClass *depay_class =
+ (GstRTPBaseDepayloadClass *) (gst_rtp_vp8_depay_class);
+
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_rtp_vp8_depay_sink_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_rtp_vp8_depay_src_template));
+
+ gst_element_class_set_static_metadata (element_class, "RTP VP8 depayloader",
+ "Codec/Depayloader/Network/RTP",
+ "Extracts VP8 video from RTP packets)",
+ "Sjoerd Simons <sjoerd@luon.net>");
+
+ object_class->dispose = gst_rtp_vp8_depay_dispose;
+
+ element_class->change_state = gst_rtp_vp8_depay_change_state;
+
+ depay_class->process = gst_rtp_vp8_depay_process;
+ depay_class->handle_event = gst_rtp_vp8_depay_handle_event;
+
+ GST_DEBUG_CATEGORY_INIT (gst_rtp_vp8_depay_debug, "rtpvp8depay", 0,
+ "VP8 Video RTP Depayloader");
+}
+
+static void
+gst_rtp_vp8_depay_dispose (GObject * object)
+{
+ GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (object);
+
+ if (self->adapter != NULL)
+ g_object_unref (self->adapter);
+ self->adapter = NULL;
+
+ /* release any references held by the object here */
+
+ if (G_OBJECT_CLASS (gst_rtp_vp8_depay_parent_class)->dispose)
+ G_OBJECT_CLASS (gst_rtp_vp8_depay_parent_class)->dispose (object);
+}
+
+static GstBuffer *
+gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depay, GstBuffer * buf)
+{
+ GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (depay);
+ GstBuffer *payload;
+ guint8 *data;
+ guint hdrsize;
+ guint size;
+ GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
+
+ if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
+ GST_LOG_OBJECT (self, "Discontinuity, flushing adapter");
+ gst_adapter_clear (self->adapter);
+ self->started = FALSE;
+ }
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtpbuffer);
+ size = gst_rtp_buffer_get_payload_len (&rtpbuffer);
+
+ /* At least one header and one vp8 byte */
+ if (G_UNLIKELY (size < 2))
+ goto too_small;
+
+ data = gst_rtp_buffer_get_payload (&rtpbuffer);
+
+ if (G_UNLIKELY (!self->started)) {
+ /* Check if this is the start of a VP8 frame, otherwise bail */
+ /* S=1 and PartID= 0 */
+ if ((data[0] & 0x1F) != 0x10)
+ goto done;
+
+ self->started = TRUE;
+ }
+
+ hdrsize = 1;
+ /* Check X optional header */
+ if ((data[0] & 0x80) != 0) {
+ hdrsize++;
+ /* Check I optional header */
+ if ((data[1] & 0x80) != 0) {
+ if (G_UNLIKELY (size < 3))
+ goto too_small;
+ hdrsize++;
+ /* Check for 16 bits PictureID */
+ if ((data[2] & 0x80) != 0)
+ hdrsize++;
+ }
+ /* Check L optional header */
+ if ((data[1] & 0x40) != 0)
+ hdrsize++;
+ /* Check T or K optional headers */
+ if ((data[1] & 0x20) != 0 || (data[1] & 0x10) != 0)
+ hdrsize++;
+ }
+ GST_DEBUG_OBJECT (depay, "hdrsize %u, size %u", hdrsize, size);
+
+ if (G_UNLIKELY (hdrsize >= size))
+ goto too_small;
+
+ payload = gst_rtp_buffer_get_payload_subbuffer (&rtpbuffer, hdrsize, -1);
+ gst_adapter_push (self->adapter, payload);
+
+ /* Marker indicates that it was the last rtp packet for this frame */
+ if (gst_rtp_buffer_get_marker (&rtpbuffer)) {
+ GstBuffer *out;
+ guint8 flag0;
+
+ gst_adapter_copy (self->adapter, &flag0, 0, 1);
+
+ out = gst_adapter_take_buffer (self->adapter,
+ gst_adapter_available (self->adapter));
+
+ self->started = FALSE;
+ gst_rtp_buffer_unmap (&rtpbuffer);
+
+ /* mark keyframes */
+ out = gst_buffer_make_writable (out);
+ if ((flag0 & 0x01)) {
+ GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DELTA_UNIT);
+
+ if (!self->caps_sent) {
+ gst_buffer_unref (out);
+ out = NULL;
+ GST_INFO_OBJECT (self, "Dropping inter-frame before intra-frame");
+ gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depay),
+ gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE,
+ TRUE, 0));
+ }
+ } else {
+ GstMapInfo info;
+
+ GST_BUFFER_FLAG_UNSET (out, GST_BUFFER_FLAG_DELTA_UNIT);
+
+ if (gst_buffer_map (out, &info, GST_MAP_READ)) {
+ guint profile, width, height;
+
+ profile = (flag0 & 0x0e) >> 1;
+ width = GST_READ_UINT16_LE (info.data + 6) & 0x3fff;
+ height = GST_READ_UINT16_LE (info.data + 8) & 0x3fff;
+ gst_buffer_unmap (out, &info);
+
+ if (G_UNLIKELY (self->last_width != width ||
+ self->last_height != height || self->last_profile != profile)) {
+ gchar profile_str[3];
+ GstCaps *srccaps;
+
+ snprintf (profile_str, 3, "%u", profile);
+ srccaps = gst_caps_new_simple ("video/x-vp8",
+ "framerate", GST_TYPE_FRACTION, 0, 1,
+ "height", G_TYPE_INT, height,
+ "width", G_TYPE_INT, width,
+ "profile", G_TYPE_STRING, profile_str, NULL);
+
+ gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depay), srccaps);
+ gst_caps_unref (srccaps);
+
+ self->caps_sent = TRUE;
+ self->last_width = width;
+ self->last_height = height;
+ self->last_profile = profile;
+ }
+ }
+ }
+
+ return out;
+ }
+
+done:
+ gst_rtp_buffer_unmap (&rtpbuffer);
+ return NULL;
+
+too_small:
+ GST_LOG_OBJECT (self, "Invalid rtp packet (too small), ignoring");
+ gst_adapter_clear (self->adapter);
+ self->started = FALSE;
+
+ goto done;
+}
+
+static GstStateChangeReturn
+gst_rtp_vp8_depay_change_state (GstElement * element, GstStateChange transition)
+{
+ GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ self->last_profile = -1;
+ self->last_height = -1;
+ self->last_width = -1;
+ self->caps_sent = FALSE;
+ break;
+ default:
+ break;
+ }
+
+ return
+ GST_ELEMENT_CLASS (gst_rtp_vp8_depay_parent_class)->change_state (element,
+ transition);
+}
+
+static gboolean
+gst_rtp_vp8_depay_handle_event (GstRTPBaseDepayload * depay, GstEvent * event)
+{
+ GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (depay);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_STOP:
+ self->last_profile = -1;
+ self->last_height = -1;
+ self->last_width = -1;
+ break;
+ default:
+ break;
+ }
+
+ return
+ GST_RTP_BASE_DEPAYLOAD_CLASS
+ (gst_rtp_vp8_depay_parent_class)->handle_event (depay, event);
+}
+
+gboolean
+gst_rtp_vp8_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpvp8depay",
+ GST_RANK_MARGINAL, GST_TYPE_RTP_VP8_DEPAY);
+}
diff --git a/gst/rtp/gstrtpvp8depay.h b/gst/rtp/gstrtpvp8depay.h
new file mode 100755
index 0000000..258546a
--- /dev/null
+++ b/gst/rtp/gstrtpvp8depay.h
@@ -0,0 +1,69 @@
+/*
+ * gstrtpvp8depay.h - Header for GstRtpVP8Depay
+ * Copyright (C) 2011 Sjoerd Simons <sjoerd@luon.net>
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GST_RTP_VP8_DEPAY_H__
+#define __GST_RTP_VP8_DEPAY_H__
+
+#include <gst/base/gstadapter.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_VP8_DEPAY \
+ (gst_rtp_vp8_depay_get_type())
+#define GST_RTP_VP8_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_RTP_VP8_DEPAY, GstRtpVP8Depay))
+#define GST_RTP_VP8_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_RTP_VP8_DEPAY, \
+ GstRtpVP8DepayClass))
+#define GST_IS_RTP_VP8_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_RTP_VP8_DEPAY))
+#define GST_IS_RTP_VP8_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_RTP_VP8_DEPAY))
+#define GST_RTP_VP8_DEPAY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTP_VP8_DEPAY, \
+ GstRtpVP8DepayClass))
+
+typedef struct _GstRtpVP8Depay GstRtpVP8Depay;
+typedef struct _GstRtpVP8DepayClass GstRtpVP8DepayClass;
+
+struct _GstRtpVP8DepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+struct _GstRtpVP8Depay
+{
+ GstRTPBaseDepayload parent;
+ GstAdapter *adapter;
+ gboolean started;
+
+ gboolean caps_sent;
+ gint last_profile;
+ gint last_width;
+ gint last_height;
+};
+
+GType gst_rtp_vp8_depay_get_type (void);
+
+gboolean gst_rtp_vp8_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* #ifndef __GST_RTP_VP8_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpvp8pay.c b/gst/rtp/gstrtpvp8pay.c
new file mode 100755
index 0000000..133c2fd
--- /dev/null
+++ b/gst/rtp/gstrtpvp8pay.c
@@ -0,0 +1,539 @@
+/*
+ * gstrtpvp8pay.c - Source for GstRtpVP8Pay
+ * Copyright (C) 2011 Sjoerd Simons <sjoerd@luon.net>
+ * Copyright (C) 2011 Collabora Ltd.
+ * Contact: Youness Alaoui <youness.alaoui@collabora.co.uk>
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gst/base/gstbitreader.h>
+#include <gst/rtp/gstrtppayloads.h>
+#include <gst/rtp/gstrtpbuffer.h>
+#include "dboolhuff.h"
+#include "gstrtpvp8pay.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_rtp_vp8_pay_debug);
+#define GST_CAT_DEFAULT gst_rtp_vp8_pay_debug
+
+#define DEFAULT_PICTURE_ID_MODE VP8_PAY_NO_PICTURE_ID
+
+enum
+{
+ PROP_0,
+ PROP_PICTURE_ID_MODE
+};
+
+#define GST_TYPE_RTP_VP8_PAY_PICTURE_ID_MODE (gst_rtp_vp8_pay_picture_id_mode_get_type())
+static GType
+gst_rtp_vp8_pay_picture_id_mode_get_type (void)
+{
+ static GType mode_type = 0;
+ static const GEnumValue modes[] = {
+ {VP8_PAY_NO_PICTURE_ID, "No Picture ID", "none"},
+ {VP8_PAY_PICTURE_ID_7BITS, "7-bit Picture ID", "7-bit"},
+ {VP8_PAY_PICTURE_ID_15BITS, "15-bit Picture ID", "15-bit"},
+ {0, NULL, NULL},
+ };
+
+ if (!mode_type) {
+ mode_type = g_enum_register_static ("GstVP8RTPPayMode", modes);
+ }
+ return mode_type;
+}
+
+static void gst_rtp_vp8_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_rtp_vp8_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+
+static GstFlowReturn gst_rtp_vp8_pay_handle_buffer (GstRTPBasePayload * payload,
+ GstBuffer * buffer);
+static gboolean gst_rtp_vp8_pay_sink_event (GstRTPBasePayload * payload,
+ GstEvent * event);
+static gboolean gst_rtp_vp8_pay_set_caps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+
+G_DEFINE_TYPE (GstRtpVP8Pay, gst_rtp_vp8_pay, GST_TYPE_RTP_BASE_PAYLOAD);
+
+static GstStaticPadTemplate gst_rtp_vp8_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ","
+ "clock-rate = (int) 90000, encoding-name = (string) { \"VP8\", \"VP8-DRAFT-IETF-01\" }"));
+
+static GstStaticPadTemplate gst_rtp_vp8_pay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-vp8"));
+
+static void
+gst_rtp_vp8_pay_init (GstRtpVP8Pay * obj)
+{
+ obj->picture_id_mode = DEFAULT_PICTURE_ID_MODE;
+ if (obj->picture_id_mode == VP8_PAY_PICTURE_ID_7BITS)
+ obj->picture_id = g_random_int_range (0, G_MAXUINT8) & 0x7F;
+ else if (obj->picture_id_mode == VP8_PAY_PICTURE_ID_15BITS)
+ obj->picture_id = g_random_int_range (0, G_MAXUINT16) & 0x7FFF;
+}
+
+static void
+gst_rtp_vp8_pay_class_init (GstRtpVP8PayClass * gst_rtp_vp8_pay_class)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (gst_rtp_vp8_pay_class);
+ GstElementClass *element_class = GST_ELEMENT_CLASS (gst_rtp_vp8_pay_class);
+ GstRTPBasePayloadClass *pay_class =
+ GST_RTP_BASE_PAYLOAD_CLASS (gst_rtp_vp8_pay_class);
+
+ gobject_class->set_property = gst_rtp_vp8_pay_set_property;
+ gobject_class->get_property = gst_rtp_vp8_pay_get_property;
+
+ g_object_class_install_property (gobject_class, PROP_PICTURE_ID_MODE,
+ g_param_spec_enum ("picture-id-mode", "Picture ID Mode",
+ "The picture ID mode for payloading",
+ GST_TYPE_RTP_VP8_PAY_PICTURE_ID_MODE, DEFAULT_PICTURE_ID_MODE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_rtp_vp8_pay_sink_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_rtp_vp8_pay_src_template));
+
+ gst_element_class_set_static_metadata (element_class, "RTP VP8 payloader",
+ "Codec/Payloader/Network/RTP",
+ "Puts VP8 video in RTP packets)", "Sjoerd Simons <sjoerd@luon.net>");
+
+ pay_class->handle_buffer = gst_rtp_vp8_pay_handle_buffer;
+ pay_class->sink_event = gst_rtp_vp8_pay_sink_event;
+ pay_class->set_caps = gst_rtp_vp8_pay_set_caps;
+
+ GST_DEBUG_CATEGORY_INIT (gst_rtp_vp8_pay_debug, "rtpvp8pay", 0,
+ "VP8 Video RTP Payloader");
+}
+
+static void
+gst_rtp_vp8_pay_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ GstRtpVP8Pay *rtpvp8pay = GST_RTP_VP8_PAY (object);
+
+ switch (prop_id) {
+ case PROP_PICTURE_ID_MODE:
+ rtpvp8pay->picture_id_mode = g_value_get_enum (value);
+ if (rtpvp8pay->picture_id_mode == VP8_PAY_PICTURE_ID_7BITS)
+ rtpvp8pay->picture_id = g_random_int_range (0, G_MAXUINT8) & 0x7F;
+ else if (rtpvp8pay->picture_id_mode == VP8_PAY_PICTURE_ID_15BITS)
+ rtpvp8pay->picture_id = g_random_int_range (0, G_MAXUINT16) & 0x7FFF;
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_rtp_vp8_pay_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ GstRtpVP8Pay *rtpvp8pay = GST_RTP_VP8_PAY (object);
+
+ switch (prop_id) {
+ case PROP_PICTURE_ID_MODE:
+ g_value_set_enum (value, rtpvp8pay->picture_id_mode);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+gst_rtp_vp8_pay_parse_frame (GstRtpVP8Pay * self, GstBuffer * buffer,
+ gsize buffer_size)
+{
+ GstMapInfo map = GST_MAP_INFO_INIT;
+ GstBitReader reader;
+ guint8 *data;
+ gsize size;
+ int i;
+ gboolean keyframe;
+ guint32 partition0_size;
+ guint8 version;
+ guint8 tmp8 = 0;
+ guint8 partitions;
+ guint offset;
+ BOOL_DECODER bc;
+ guint8 *pdata;
+
+ if (G_UNLIKELY (buffer_size < 3))
+ goto error;
+
+ if (!gst_buffer_map (buffer, &map, GST_MAP_READ) || !map.data)
+ goto error;
+
+ data = map.data;
+ size = map.size;
+
+ gst_bit_reader_init (&reader, data, size);
+
+ self->is_keyframe = keyframe = ((data[0] & 0x1) == 0);
+ version = (data[0] >> 1) & 0x7;
+
+ if (G_UNLIKELY (version > 3)) {
+ GST_ERROR_OBJECT (self, "Unknown VP8 version %u", version);
+ goto error;
+ }
+
+ /* keyframe, version and show_frame use 5 bits */
+ partition0_size = data[2] << 11 | data[1] << 3 | (data[0] >> 5);
+
+ /* Include the uncompressed data blob in the first partition */
+ offset = keyframe ? 10 : 3;
+ partition0_size += offset;
+
+ if (!gst_bit_reader_skip (&reader, 24))
+ goto error;
+
+ if (keyframe) {
+ /* check start tag: 0x9d 0x01 0x2a */
+ if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp8, 8) || tmp8 != 0x9d)
+ goto error;
+
+ if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp8, 8) || tmp8 != 0x01)
+ goto error;
+
+ if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp8, 8) || tmp8 != 0x2a)
+ goto error;
+
+ /* Skip horizontal size code (16 bits) vertical size code (16 bits) */
+ if (!gst_bit_reader_skip (&reader, 32))
+ goto error;
+ }
+
+ offset = keyframe ? 10 : 3;
+ vp8dx_start_decode (&bc, data + offset, size - offset);
+
+ if (keyframe) {
+ /* color space (1 bit) and clamping type (1 bit) */
+ vp8dx_decode_bool (&bc, 0x80);
+ vp8dx_decode_bool (&bc, 0x80);
+ }
+
+ /* segmentation_enabled */
+ if (vp8dx_decode_bool (&bc, 0x80)) {
+ guint8 update_mb_segmentation_map = vp8dx_decode_bool (&bc, 0x80);
+ guint8 update_segment_feature_data = vp8dx_decode_bool (&bc, 0x80);
+
+ if (update_segment_feature_data) {
+ /* skip segment feature mode */
+ vp8dx_decode_bool (&bc, 0x80);
+
+ /* quantizer update */
+ for (i = 0; i < 4; i++) {
+ /* skip flagged quantizer value (7 bits) and sign (1 bit) */
+ if (vp8dx_decode_bool (&bc, 0x80))
+ vp8_decode_value (&bc, 8);
+ }
+
+ /* loop filter update */
+ for (i = 0; i < 4; i++) {
+ /* skip flagged lf update value (6 bits) and sign (1 bit) */
+ if (vp8dx_decode_bool (&bc, 0x80))
+ vp8_decode_value (&bc, 7);
+ }
+ }
+
+ if (update_mb_segmentation_map) {
+ /* segment prob update */
+ for (i = 0; i < 3; i++) {
+ /* skip flagged segment prob */
+ if (vp8dx_decode_bool (&bc, 0x80))
+ vp8_decode_value (&bc, 8);
+ }
+ }
+ }
+
+ /* skip filter type (1 bit), loop filter level (6 bits) and
+ * sharpness level (3 bits) */
+ vp8_decode_value (&bc, 1);
+ vp8_decode_value (&bc, 6);
+ vp8_decode_value (&bc, 3);
+
+ /* loop_filter_adj_enabled */
+ if (vp8dx_decode_bool (&bc, 0x80)) {
+
+ /* delta update */
+ if (vp8dx_decode_bool (&bc, 0x80)) {
+
+ for (i = 0; i < 8; i++) {
+ /* 8 updates, 1 bit indicate whether there is one and if follow by a
+ * 7 bit update */
+ if (vp8dx_decode_bool (&bc, 0x80))
+ vp8_decode_value (&bc, 7);
+ }
+ }
+ }
+
+ if (vp8dx_bool_error (&bc))
+ goto error;
+
+ tmp8 = vp8_decode_value (&bc, 2);
+
+ partitions = 1 << tmp8;
+
+ /* Check if things are still sensible */
+ if (partition0_size + (partitions - 1) * 3 >= size)
+ goto error;
+
+ /* partition data is right after the mode partition */
+ pdata = data + partition0_size;
+
+ /* Set up mapping */
+ self->n_partitions = partitions + 1;
+ self->partition_offset[0] = 0;
+ self->partition_size[0] = partition0_size + (partitions - 1) * 3;
+
+ self->partition_offset[1] = self->partition_size[0];
+ for (i = 1; i < partitions; i++) {
+ guint psize = (pdata[2] << 16 | pdata[1] << 8 | pdata[0]);
+
+ pdata += 3;
+ self->partition_size[i] = psize;
+ self->partition_offset[i + 1] = self->partition_offset[i] + psize;
+ }
+
+ /* Check that our partition offsets and sizes don't go outsize the buffer
+ * size. */
+ if (self->partition_offset[i] >= size)
+ goto error;
+
+ self->partition_size[i] = size - self->partition_offset[i];
+
+ self->partition_offset[i + 1] = size;
+
+ gst_buffer_unmap (buffer, &map);
+ return TRUE;
+
+error:
+ GST_DEBUG ("Failed to parse frame");
+ if (map.memory != NULL) {
+ gst_buffer_unmap (buffer, &map);
+ }
+ return FALSE;
+}
+
+static guint
+gst_rtp_vp8_offset_to_partition (GstRtpVP8Pay * self, guint offset)
+{
+ int i;
+
+ for (i = 0; i < self->n_partitions; i++) {
+ if (offset >= self->partition_offset[i] &&
+ offset < self->partition_offset[i + 1])
+ return i;
+ }
+
+ return i;
+}
+
+static gsize
+gst_rtp_vp8_calc_header_len (GstRtpVP8Pay * self)
+{
+ switch (self->picture_id_mode) {
+ case VP8_PAY_PICTURE_ID_7BITS:
+ return 3;
+ case VP8_PAY_PICTURE_ID_15BITS:
+ return 4;
+ case VP8_PAY_NO_PICTURE_ID:
+ default:
+ return 1;
+ }
+}
+
+/* When growing the vp8 header keep max payload len calculation in sync */
+static GstBuffer *
+gst_rtp_vp8_create_header_buffer (GstRtpVP8Pay * self, guint8 partid,
+ gboolean start, gboolean mark, GstBuffer * in)
+{
+ GstBuffer *out;
+ guint8 *p;
+ GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
+
+ out = gst_rtp_buffer_new_allocate (gst_rtp_vp8_calc_header_len (self), 0, 0);
+ gst_rtp_buffer_map (out, GST_MAP_READWRITE, &rtpbuffer);
+ p = gst_rtp_buffer_get_payload (&rtpbuffer);
+ /* X=0,R=0,N=0,S=start,PartID=partid */
+ p[0] = (start << 4) | partid;
+ if (self->picture_id_mode != VP8_PAY_NO_PICTURE_ID) {
+ /* Enable X=1 */
+ p[0] |= 0x80;
+ /* X: I=1,L=0,T=0,K=0,RSV=0 */
+ p[1] = 0x80;
+ if (self->picture_id_mode == VP8_PAY_PICTURE_ID_7BITS) {
+ /* I: 7 bit picture_id */
+ p[2] = self->picture_id & 0x7F;
+ } else {
+ /* I: 15 bit picture_id */
+ p[2] = 0x80 | ((self->picture_id & 0x7FFF) >> 8);
+ p[3] = self->picture_id & 0xFF;
+ }
+ }
+
+ gst_rtp_buffer_set_marker (&rtpbuffer, mark);
+
+ gst_rtp_buffer_unmap (&rtpbuffer);
+
+ GST_BUFFER_DURATION (out) = GST_BUFFER_DURATION (in);
+ GST_BUFFER_PTS (out) = GST_BUFFER_PTS (in);
+
+ return out;
+}
+
+
+static guint
+gst_rtp_vp8_payload_next (GstRtpVP8Pay * self, GstBufferList * list,
+ guint offset, GstBuffer * buffer, gsize buffer_size, gsize max_payload_len)
+{
+ guint partition;
+ GstBuffer *header;
+ GstBuffer *sub;
+ GstBuffer *out;
+ gboolean mark;
+ gsize remaining;
+ gsize available;
+
+ remaining = buffer_size - offset;
+ available = max_payload_len;
+ if (available > remaining)
+ available = remaining;
+
+ partition = gst_rtp_vp8_offset_to_partition (self, offset);
+ g_assert (partition < self->n_partitions);
+
+ mark = (remaining == available);
+ /* whole set of partitions, payload them and done */
+ header = gst_rtp_vp8_create_header_buffer (self, partition,
+ offset == self->partition_offset[partition], mark, buffer);
+ sub = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset, available);
+
+ out = gst_buffer_append (header, sub);
+
+ gst_buffer_list_insert (list, -1, out);
+
+ return available;
+}
+
+
+static GstFlowReturn
+gst_rtp_vp8_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
+{
+ GstRtpVP8Pay *self = GST_RTP_VP8_PAY (payload);
+ GstFlowReturn ret;
+ GstBufferList *list;
+ gsize size, max_paylen;
+ guint offset, mtu, vp8_hdr_len;
+
+ size = gst_buffer_get_size (buffer);
+
+ if (G_UNLIKELY (!gst_rtp_vp8_pay_parse_frame (self, buffer, size))) {
+ GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
+ ("Failed to parse VP8 frame"));
+ return GST_FLOW_ERROR;
+ }
+
+ mtu = GST_RTP_BASE_PAYLOAD_MTU (payload);
+ vp8_hdr_len = gst_rtp_vp8_calc_header_len (self);
+ max_paylen = gst_rtp_buffer_calc_payload_len (mtu - vp8_hdr_len, 0, 0);
+
+ list = gst_buffer_list_new_sized ((size / max_paylen) + 1);
+
+ offset = 0;
+ while (offset < size) {
+ offset +=
+ gst_rtp_vp8_payload_next (self, list, offset, buffer, size, max_paylen);
+ }
+
+ ret = gst_rtp_base_payload_push_list (payload, list);
+
+ /* Incremenent and wrap the picture id if it overflows */
+ if ((self->picture_id_mode == VP8_PAY_PICTURE_ID_7BITS &&
+ ++self->picture_id >= 0x80) ||
+ (self->picture_id_mode == VP8_PAY_PICTURE_ID_15BITS &&
+ ++self->picture_id >= 0x8000))
+ self->picture_id = 0;
+
+ gst_buffer_unref (buffer);
+
+ return ret;
+}
+
+static gboolean
+gst_rtp_vp8_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+ GstRtpVP8Pay *self = GST_RTP_VP8_PAY (payload);
+
+ if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_START) {
+ if (self->picture_id_mode == VP8_PAY_PICTURE_ID_7BITS)
+ self->picture_id = g_random_int_range (0, G_MAXUINT8) & 0x7F;
+ else if (self->picture_id_mode == VP8_PAY_PICTURE_ID_15BITS)
+ self->picture_id = g_random_int_range (0, G_MAXUINT16) & 0x7FFF;
+ }
+
+ return GST_RTP_BASE_PAYLOAD_CLASS (gst_rtp_vp8_pay_parent_class)->sink_event
+ (payload, event);
+}
+
+static gboolean
+gst_rtp_vp8_pay_set_caps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ GstCaps *src_caps;
+ GstStructure *s;
+ char *encoding_name;
+
+ src_caps = gst_pad_get_allowed_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload));
+ if (src_caps) {
+ src_caps = gst_caps_make_writable (src_caps);
+ src_caps = gst_caps_truncate (src_caps);
+ s = gst_caps_get_structure (src_caps, 0);
+ gst_structure_fixate_field_string (s, "encoding-name", "VP8");
+ encoding_name = g_strdup (gst_structure_get_string (s, "encoding-name"));
+ gst_caps_unref (src_caps);
+ } else {
+ encoding_name = g_strdup ("VP8-DRAFT-IETF-01");
+ }
+
+ gst_rtp_base_payload_set_options (payload, "video", TRUE,
+ encoding_name, 90000);
+ g_free (encoding_name);
+ return gst_rtp_base_payload_set_outcaps (payload, NULL);
+}
+
+gboolean
+gst_rtp_vp8_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpvp8pay",
+ GST_RANK_MARGINAL, GST_TYPE_RTP_VP8_PAY);
+}
diff --git a/gst/rtp/gstrtpvp8pay.h b/gst/rtp/gstrtpvp8pay.h
new file mode 100755
index 0000000..2472060
--- /dev/null
+++ b/gst/rtp/gstrtpvp8pay.h
@@ -0,0 +1,74 @@
+/*
+ * gstrtpvp8pay.h - Header for GstRtpVP8Pay
+ * Copyright (C) 2011 Sjoerd Simons <sjoerd@luon.net>
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GST_RTP_VP8_PAY_H__
+#define __GST_RTP_VP8_PAY_H__
+
+#include <gst/rtp/gstrtpbasepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_VP8_PAY \
+ (gst_rtp_vp8_pay_get_type())
+#define GST_RTP_VP8_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_RTP_VP8_PAY, GstRtpVP8Pay))
+#define GST_RTP_VP8_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_RTP_VP8_PAY, GstRtpVP8PayClass))
+#define GST_IS_RTP_VP8_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_RTP_VP8_PAY))
+#define GST_IS_RTP_VP8_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_RTP_VP8_PAY))
+#define GST_RTP_VP8_PAY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTP_VP8_PAY, GstRtpVP8PayClass))
+
+typedef struct _GstRtpVP8Pay GstRtpVP8Pay;
+typedef struct _GstRtpVP8PayClass GstRtpVP8PayClass;
+typedef enum _PictureIDMode PictureIDMode;
+
+enum _PictureIDMode {
+ VP8_PAY_NO_PICTURE_ID,
+ VP8_PAY_PICTURE_ID_7BITS,
+ VP8_PAY_PICTURE_ID_15BITS,
+};
+
+struct _GstRtpVP8PayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+struct _GstRtpVP8Pay
+{
+ GstRTPBasePayload parent;
+ gboolean is_keyframe;
+ gint n_partitions;
+ /* Treat frame header & tag & partition size block as the first partition,
+ * folowed by max. 8 data partitions. last offset is the end of the buffer */
+ guint partition_offset[10];
+ guint partition_size[9];
+ PictureIDMode picture_id_mode;
+ guint16 picture_id;
+};
+
+GType gst_rtp_vp8_pay_get_type (void);
+
+gboolean gst_rtp_vp8_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* #ifndef __GST_RTP_VP8_PAY_H__ */
diff --git a/gst/rtp/gstrtpvrawdepay.c b/gst/rtp/gstrtpvrawdepay.c
new file mode 100755
index 0000000..ee106c5
--- /dev/null
+++ b/gst/rtp/gstrtpvrawdepay.c
@@ -0,0 +1,668 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include "gstrtpvrawdepay.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtpvrawdepay_debug);
+#define GST_CAT_DEFAULT (rtpvrawdepay_debug)
+
+static GstStaticPadTemplate gst_rtp_vraw_depay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-raw")
+ );
+
+static GstStaticPadTemplate gst_rtp_vraw_depay_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"video\", "
+ "clock-rate = (int) 90000, "
+ "encoding-name = (string) \"RAW\", "
+ "sampling = (string) { \"RGB\", \"RGBA\", \"BGR\", \"BGRA\", "
+ "\"YCbCr-4:4:4\", \"YCbCr-4:2:2\", \"YCbCr-4:2:0\", "
+ "\"YCbCr-4:1:1\" },"
+ /* we cannot express these as strings
+ * "width = (string) [1 32767],"
+ * "height = (string) [1 32767],"
+ */
+ "depth = (string) { \"8\", \"10\", \"12\", \"16\" }")
+ );
+
+#define gst_rtp_vraw_depay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpVRawDepay, gst_rtp_vraw_depay,
+ GST_TYPE_RTP_BASE_DEPAYLOAD);
+
+static gboolean gst_rtp_vraw_depay_setcaps (GstRTPBaseDepayload * depayload,
+ GstCaps * caps);
+static GstBuffer *gst_rtp_vraw_depay_process (GstRTPBaseDepayload * depayload,
+ GstBuffer * buf);
+
+static GstStateChangeReturn gst_rtp_vraw_depay_change_state (GstElement *
+ element, GstStateChange transition);
+
+static gboolean gst_rtp_vraw_depay_handle_event (GstRTPBaseDepayload * filter,
+ GstEvent * event);
+
+static void
+gst_rtp_vraw_depay_class_init (GstRtpVRawDepayClass * klass)
+{
+ GstElementClass *gstelement_class;
+ GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
+
+ gstelement_class->change_state = gst_rtp_vraw_depay_change_state;
+
+ gstrtpbasedepayload_class->set_caps = gst_rtp_vraw_depay_setcaps;
+ gstrtpbasedepayload_class->process = gst_rtp_vraw_depay_process;
+ gstrtpbasedepayload_class->handle_event = gst_rtp_vraw_depay_handle_event;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_vraw_depay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_vraw_depay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP Raw Video depayloader", "Codec/Depayloader/Network/RTP",
+ "Extracts raw video from RTP packets (RFC 4175)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ GST_DEBUG_CATEGORY_INIT (rtpvrawdepay_debug, "rtpvrawdepay", 0,
+ "raw video RTP Depayloader");
+}
+
+static void
+gst_rtp_vraw_depay_init (GstRtpVRawDepay * rtpvrawdepay)
+{
+}
+
+static void
+gst_rtp_vraw_depay_reset (GstRtpVRawDepay * rtpvrawdepay)
+{
+ if (rtpvrawdepay->outbuf) {
+ gst_video_frame_unmap (&rtpvrawdepay->frame);
+ gst_buffer_unref (rtpvrawdepay->outbuf);
+ rtpvrawdepay->outbuf = NULL;
+ }
+ rtpvrawdepay->timestamp = -1;
+ if (rtpvrawdepay->pool) {
+ gst_buffer_pool_set_active (rtpvrawdepay->pool, FALSE);
+ gst_object_unref (rtpvrawdepay->pool);
+ rtpvrawdepay->pool = NULL;
+ }
+}
+
+static GstFlowReturn
+gst_rtp_vraw_depay_negotiate_pool (GstRtpVRawDepay * depay, GstCaps * caps,
+ GstVideoInfo * info)
+{
+ GstQuery *query;
+ GstBufferPool *pool = NULL;
+ guint size, min, max;
+ GstStructure *config;
+
+ /* find a pool for the negotiated caps now */
+ query = gst_query_new_allocation (caps, TRUE);
+
+ if (!gst_pad_peer_query (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depay), query)) {
+ /* not a problem, we use the defaults of query */
+ GST_DEBUG_OBJECT (depay, "could not get downstream ALLOCATION hints");
+ }
+
+ if (gst_query_get_n_allocation_pools (query) > 0) {
+ /* we got configuration from our peer, parse them */
+ gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
+ } else {
+ GST_DEBUG_OBJECT (depay, "didn't get downstream pool hints");
+ size = info->size;
+ min = max = 0;
+ }
+
+ if (pool == NULL) {
+ /* we did not get a pool, make one ourselves then */
+ pool = gst_video_buffer_pool_new ();
+ }
+
+ if (depay->pool)
+ gst_object_unref (depay->pool);
+ depay->pool = pool;
+
+ config = gst_buffer_pool_get_config (pool);
+ gst_buffer_pool_config_set_params (config, caps, size, min, max);
+ if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
+ /* just set the metadata, if the pool can support it we will transparently use
+ * it through the video info API. We could also see if the pool support this
+ * metadata and only activate it then. */
+ gst_buffer_pool_config_add_option (config,
+ GST_BUFFER_POOL_OPTION_VIDEO_META);
+ }
+
+ gst_buffer_pool_set_config (pool, config);
+ /* and activate */
+ gst_buffer_pool_set_active (pool, TRUE);
+
+ gst_query_unref (query);
+
+ return GST_FLOW_OK;
+}
+
+static gboolean
+gst_rtp_vraw_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
+{
+ GstStructure *structure;
+ GstRtpVRawDepay *rtpvrawdepay;
+ gint clock_rate;
+ const gchar *str;
+ gint format, width, height, depth, pgroup, xinc, yinc;
+ GstCaps *srccaps;
+ gboolean res;
+ GstFlowReturn ret;
+
+ rtpvrawdepay = GST_RTP_VRAW_DEPAY (depayload);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ xinc = yinc = 1;
+
+ if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
+ clock_rate = 90000; /* default */
+ depayload->clock_rate = clock_rate;
+
+ if (!(str = gst_structure_get_string (structure, "width")))
+ goto no_width;
+ width = atoi (str);
+
+ if (!(str = gst_structure_get_string (structure, "height")))
+ goto no_height;
+ height = atoi (str);
+
+ if (!(str = gst_structure_get_string (structure, "depth")))
+ goto no_depth;
+ depth = atoi (str);
+
+ /* optional interlace value but we don't handle interlaced
+ * formats yet */
+ if (gst_structure_get_string (structure, "interlace"))
+ goto interlaced;
+
+ if (!(str = gst_structure_get_string (structure, "sampling")))
+ goto no_sampling;
+
+ if (!strcmp (str, "RGB")) {
+ format = GST_VIDEO_FORMAT_RGB;
+ pgroup = 3;
+ } else if (!strcmp (str, "RGBA")) {
+ format = GST_VIDEO_FORMAT_RGBA;
+ pgroup = 4;
+ } else if (!strcmp (str, "BGR")) {
+ format = GST_VIDEO_FORMAT_BGR;
+ pgroup = 3;
+ } else if (!strcmp (str, "BGRA")) {
+ format = GST_VIDEO_FORMAT_BGRA;
+ pgroup = 4;
+ } else if (!strcmp (str, "YCbCr-4:4:4")) {
+ format = GST_VIDEO_FORMAT_AYUV;
+ pgroup = 3;
+ } else if (!strcmp (str, "YCbCr-4:2:2")) {
+ if (depth == 8) {
+ format = GST_VIDEO_FORMAT_UYVY;
+ pgroup = 4;
+ } else if (depth == 10) {
+ format = GST_VIDEO_FORMAT_UYVP;
+ pgroup = 5;
+ } else
+ goto unknown_format;
+ xinc = 2;
+ } else if (!strcmp (str, "YCbCr-4:2:0")) {
+ format = GST_VIDEO_FORMAT_I420;
+ pgroup = 6;
+ xinc = yinc = 2;
+ } else if (!strcmp (str, "YCbCr-4:1:1")) {
+ format = GST_VIDEO_FORMAT_Y41B;
+ pgroup = 6;
+ xinc = 4;
+ } else {
+ goto unknown_format;
+ }
+
+ gst_video_info_init (&rtpvrawdepay->vinfo);
+ gst_video_info_set_format (&rtpvrawdepay->vinfo, format, width, height);
+ GST_VIDEO_INFO_FPS_N (&rtpvrawdepay->vinfo) = 0;
+ GST_VIDEO_INFO_FPS_D (&rtpvrawdepay->vinfo) = 1;
+
+ rtpvrawdepay->pgroup = pgroup;
+ rtpvrawdepay->xinc = xinc;
+ rtpvrawdepay->yinc = yinc;
+
+ srccaps = gst_video_info_to_caps (&rtpvrawdepay->vinfo);
+ res = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps);
+ gst_caps_unref (srccaps);
+
+ GST_DEBUG_OBJECT (depayload, "width %d, height %d, format %d", width, height,
+ format);
+ GST_DEBUG_OBJECT (depayload, "xinc %d, yinc %d, pgroup %d",
+ xinc, yinc, pgroup);
+
+ /* negotiate a bufferpool */
+ if ((ret = gst_rtp_vraw_depay_negotiate_pool (rtpvrawdepay, srccaps,
+ &rtpvrawdepay->vinfo)) != GST_FLOW_OK)
+ goto no_bufferpool;
+
+ return res;
+
+ /* ERRORS */
+no_width:
+ {
+ GST_ERROR_OBJECT (depayload, "no width specified");
+ return FALSE;
+ }
+no_height:
+ {
+ GST_ERROR_OBJECT (depayload, "no height specified");
+ return FALSE;
+ }
+no_depth:
+ {
+ GST_ERROR_OBJECT (depayload, "no depth specified");
+ return FALSE;
+ }
+interlaced:
+ {
+ GST_ERROR_OBJECT (depayload, "interlaced formats not supported yet");
+ return FALSE;
+ }
+no_sampling:
+ {
+ GST_ERROR_OBJECT (depayload, "no sampling specified");
+ return FALSE;
+ }
+unknown_format:
+ {
+ GST_ERROR_OBJECT (depayload, "unknown sampling format '%s'", str);
+ return FALSE;
+ }
+no_bufferpool:
+ {
+ GST_DEBUG_OBJECT (depayload, "no bufferpool");
+ return FALSE;
+ }
+}
+
+static GstBuffer *
+gst_rtp_vraw_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+{
+ GstRtpVRawDepay *rtpvrawdepay;
+ guint8 *payload, *p0, *yp, *up, *vp, *headers;
+ guint32 timestamp;
+ guint cont, ystride, uvstride, pgroup, payload_len;
+ gint width, height, xinc, yinc;
+ GstRTPBuffer rtp = { NULL };
+ GstVideoFrame *frame;
+ gboolean marker;
+ GstBuffer *outbuf = NULL;
+
+ rtpvrawdepay = GST_RTP_VRAW_DEPAY (depayload);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
+
+ timestamp = gst_rtp_buffer_get_timestamp (&rtp);
+
+ if (timestamp != rtpvrawdepay->timestamp || rtpvrawdepay->outbuf == NULL) {
+ GstBuffer *new_buffer;
+ GstFlowReturn ret;
+
+ GST_LOG_OBJECT (depayload, "new frame with timestamp %u", timestamp);
+ /* new timestamp, flush old buffer and create new output buffer */
+ if (rtpvrawdepay->outbuf) {
+ gst_video_frame_unmap (&rtpvrawdepay->frame);
+ gst_rtp_base_depayload_push (depayload, rtpvrawdepay->outbuf);
+ rtpvrawdepay->outbuf = NULL;
+ }
+
+ if (gst_pad_check_reconfigure (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload))) {
+ GstCaps *caps;
+
+ caps =
+ gst_pad_get_current_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload));
+ gst_rtp_vraw_depay_negotiate_pool (rtpvrawdepay, caps,
+ &rtpvrawdepay->vinfo);
+ gst_caps_unref (caps);
+ }
+
+ ret =
+ gst_buffer_pool_acquire_buffer (rtpvrawdepay->pool, &new_buffer, NULL);
+
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
+ goto alloc_failed;
+
+ /* clear timestamp from alloc... */
+ GST_BUFFER_TIMESTAMP (new_buffer) = -1;
+
+ if (!gst_video_frame_map (&rtpvrawdepay->frame, &rtpvrawdepay->vinfo,
+ new_buffer, GST_MAP_WRITE | GST_VIDEO_FRAME_MAP_FLAG_NO_REF)) {
+ gst_buffer_unref (new_buffer);
+ goto invalid_frame;
+ }
+
+ rtpvrawdepay->outbuf = new_buffer;
+ rtpvrawdepay->timestamp = timestamp;
+ }
+
+ frame = &rtpvrawdepay->frame;
+
+ g_assert (frame->buffer != NULL);
+
+ /* get pointer and strides of the planes */
+ p0 = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+ yp = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
+ up = GST_VIDEO_FRAME_COMP_DATA (frame, 1);
+ vp = GST_VIDEO_FRAME_COMP_DATA (frame, 2);
+
+ ystride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
+ uvstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1);
+
+ pgroup = rtpvrawdepay->pgroup;
+ width = GST_VIDEO_INFO_WIDTH (&rtpvrawdepay->vinfo);
+ height = GST_VIDEO_INFO_HEIGHT (&rtpvrawdepay->vinfo);
+ xinc = rtpvrawdepay->xinc;
+ yinc = rtpvrawdepay->yinc;
+
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+
+ if (payload_len < 3)
+ goto short_packet;
+
+ /* skip extended seqnum */
+ payload += 2;
+ payload_len -= 2;
+
+ /* remember header position */
+ headers = payload;
+
+ /* find data start */
+ do {
+ if (payload_len < 6)
+ goto short_packet;
+
+ cont = payload[4] & 0x80;
+
+ payload += 6;
+ payload_len -= 6;
+ } while (cont);
+
+ while (TRUE) {
+ guint length, line, offs, plen;
+ guint8 *datap;
+
+ /* stop when we run out of data */
+ if (payload_len == 0)
+ break;
+
+ /* read length and cont. This should work because we iterated the headers
+ * above. */
+ length = (headers[0] << 8) | headers[1];
+ line = ((headers[2] & 0x7f) << 8) | headers[3];
+ offs = ((headers[4] & 0x7f) << 8) | headers[5];
+ cont = headers[4] & 0x80;
+ headers += 6;
+
+ /* length must be a multiple of pgroup */
+ if (length % pgroup != 0)
+ goto wrong_length;
+
+ if (length > payload_len)
+ length = payload_len;
+
+ /* sanity check */
+ if (line > (height - yinc)) {
+ GST_WARNING_OBJECT (depayload, "skipping line %d: out of range", line);
+ goto next;
+ }
+ if (offs > (width - xinc)) {
+ GST_WARNING_OBJECT (depayload, "skipping offset %d: out of range", offs);
+ goto next;
+ }
+
+ /* calculate the maximim amount of bytes we can use per line */
+ if (offs + ((length / pgroup) * xinc) > width) {
+ plen = ((width - offs) * pgroup) / xinc;
+ GST_WARNING_OBJECT (depayload, "clipping length %d, offset %d, plen %d",
+ length, offs, plen);
+ } else
+ plen = length;
+
+ GST_LOG_OBJECT (depayload,
+ "writing length %u/%u, line %u, offset %u, remaining %u", plen, length,
+ line, offs, payload_len);
+
+ switch (GST_VIDEO_INFO_FORMAT (&rtpvrawdepay->vinfo)) {
+ case GST_VIDEO_FORMAT_RGB:
+ case GST_VIDEO_FORMAT_RGBA:
+ case GST_VIDEO_FORMAT_BGR:
+ case GST_VIDEO_FORMAT_BGRA:
+ case GST_VIDEO_FORMAT_UYVY:
+ case GST_VIDEO_FORMAT_UYVP:
+ /* samples are packed just like gstreamer packs them */
+ offs /= xinc;
+ datap = p0 + (line * ystride) + (offs * pgroup);
+
+ memcpy (datap, payload, plen);
+ break;
+ case GST_VIDEO_FORMAT_AYUV:
+ {
+ gint i;
+ guint8 *p;
+
+ datap = p0 + (line * ystride) + (offs * 4);
+ p = payload;
+
+ /* samples are packed in order Cb-Y-Cr for both interlaced and
+ * progressive frames */
+ for (i = 0; i < plen; i += pgroup) {
+ *datap++ = 0;
+ *datap++ = p[1];
+ *datap++ = p[0];
+ *datap++ = p[2];
+ p += pgroup;
+ }
+ break;
+ }
+ case GST_VIDEO_FORMAT_I420:
+ {
+ gint i;
+ guint uvoff;
+ guint8 *yd1p, *yd2p, *udp, *vdp, *p;
+
+ yd1p = yp + (line * ystride) + (offs);
+ yd2p = yd1p + ystride;
+ uvoff = (line / yinc * uvstride) + (offs / xinc);
+
+ udp = up + uvoff;
+ vdp = vp + uvoff;
+ p = payload;
+
+ /* line 0/1: Y00-Y01-Y10-Y11-Cb00-Cr00 Y02-Y03-Y12-Y13-Cb01-Cr01 ... */
+ for (i = 0; i < plen; i += pgroup) {
+ *yd1p++ = p[0];
+ *yd1p++ = p[1];
+ *yd2p++ = p[2];
+ *yd2p++ = p[3];
+ *udp++ = p[4];
+ *vdp++ = p[5];
+ p += pgroup;
+ }
+ break;
+ }
+ case GST_VIDEO_FORMAT_Y41B:
+ {
+ gint i;
+ guint uvoff;
+ guint8 *ydp, *udp, *vdp, *p;
+
+ ydp = yp + (line * ystride) + (offs);
+ uvoff = (line / yinc * uvstride) + (offs / xinc);
+
+ udp = up + uvoff;
+ vdp = vp + uvoff;
+ p = payload;
+
+ /* Samples are packed in order Cb0-Y0-Y1-Cr0-Y2-Y3 for both interlaced
+ * and progressive scan lines */
+ for (i = 0; i < plen; i += pgroup) {
+ *udp++ = p[0];
+ *ydp++ = p[1];
+ *ydp++ = p[2];
+ *vdp++ = p[3];
+ *ydp++ = p[4];
+ *ydp++ = p[5];
+ p += pgroup;
+ }
+ break;
+ }
+ default:
+ goto unknown_sampling;
+ }
+
+ next:
+ if (!cont)
+ break;
+
+ payload += length;
+ payload_len -= length;
+ }
+
+ marker = gst_rtp_buffer_get_marker (&rtp);
+ gst_rtp_buffer_unmap (&rtp);
+
+ if (marker) {
+ GST_LOG_OBJECT (depayload, "marker, flushing frame");
+ gst_video_frame_unmap (&rtpvrawdepay->frame);
+ outbuf = rtpvrawdepay->outbuf;
+ rtpvrawdepay->outbuf = NULL;
+ rtpvrawdepay->timestamp = -1;
+ }
+ return outbuf;
+
+ /* ERRORS */
+unknown_sampling:
+ {
+ GST_ELEMENT_ERROR (depayload, STREAM, FORMAT,
+ (NULL), ("unimplemented sampling"));
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+alloc_failed:
+ {
+ GST_WARNING_OBJECT (depayload, "failed to alloc output buffer");
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+invalid_frame:
+ {
+ GST_ERROR_OBJECT (depayload, "could not map video frame");
+ return NULL;
+ }
+wrong_length:
+ {
+ GST_WARNING_OBJECT (depayload, "length not multiple of pgroup");
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+short_packet:
+ {
+ GST_WARNING_OBJECT (depayload, "short packet");
+ gst_rtp_buffer_unmap (&rtp);
+ return NULL;
+ }
+}
+
+static gboolean
+gst_rtp_vraw_depay_handle_event (GstRTPBaseDepayload * filter, GstEvent * event)
+{
+ gboolean ret;
+ GstRtpVRawDepay *rtpvrawdepay;
+
+ rtpvrawdepay = GST_RTP_VRAW_DEPAY (filter);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_STOP:
+ gst_rtp_vraw_depay_reset (rtpvrawdepay);
+ break;
+ default:
+ break;
+ }
+
+ ret =
+ GST_RTP_BASE_DEPAYLOAD_CLASS (parent_class)->handle_event (filter, event);
+
+ return ret;
+}
+
+static GstStateChangeReturn
+gst_rtp_vraw_depay_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstRtpVRawDepay *rtpvrawdepay;
+ GstStateChangeReturn ret;
+
+ rtpvrawdepay = GST_RTP_VRAW_DEPAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_rtp_vraw_depay_reset (rtpvrawdepay);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_rtp_vraw_depay_reset (rtpvrawdepay);
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+gboolean
+gst_rtp_vraw_depay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpvrawdepay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_VRAW_DEPAY);
+}
diff --git a/gst/rtp/gstrtpvrawdepay.h b/gst/rtp/gstrtpvrawdepay.h
new file mode 100755
index 0000000..18ca755
--- /dev/null
+++ b/gst/rtp/gstrtpvrawdepay.h
@@ -0,0 +1,71 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_VRAW_DEPAY_H__
+#define __GST_RTP_VRAW_DEPAY_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideometa.h>
+#include <gst/video/gstvideopool.h>
+#include <gst/rtp/gstrtpbasedepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_VRAW_DEPAY \
+ (gst_rtp_vraw_depay_get_type())
+#define GST_RTP_VRAW_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_VRAW_DEPAY,GstRtpVRawDepay))
+#define GST_RTP_VRAW_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_VRAW_DEPAY,GstRtpVRawDepayClass))
+#define GST_IS_RTP_VRAW_DEPAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_VRAW_DEPAY))
+#define GST_IS_RTP_VRAW_DEPAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_VRAW_DEPAY))
+
+typedef struct _GstRtpVRawDepay GstRtpVRawDepay;
+typedef struct _GstRtpVRawDepayClass GstRtpVRawDepayClass;
+
+struct _GstRtpVRawDepay
+{
+ GstRTPBaseDepayload payload;
+
+ GstBufferPool *pool;
+ GstVideoInfo vinfo;
+
+ GstVideoFrame frame;
+ GstBuffer *outbuf;
+ guint32 timestamp;
+
+ gint pgroup;
+ gint xinc, yinc;
+};
+
+struct _GstRtpVRawDepayClass
+{
+ GstRTPBaseDepayloadClass parent_class;
+};
+
+GType gst_rtp_vraw_depay_get_type (void);
+
+gboolean gst_rtp_vraw_depay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_VRAW_DEPAY_H__ */
diff --git a/gst/rtp/gstrtpvrawpay.c b/gst/rtp/gstrtpvrawpay.c
new file mode 100755
index 0000000..c03c8d2
--- /dev/null
+++ b/gst/rtp/gstrtpvrawpay.c
@@ -0,0 +1,647 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#include "gstrtpvrawpay.h"
+
+enum
+{
+ PROP_CHUNKS_PER_FRAME = 1
+};
+
+#define DEFAULT_CHUNKS_PER_FRAME 10
+
+GST_DEBUG_CATEGORY_STATIC (rtpvrawpay_debug);
+#define GST_CAT_DEFAULT (rtpvrawpay_debug)
+
+static GstStaticPadTemplate gst_rtp_vraw_pay_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-raw, "
+ "format = (string) { RGB, RGBA, BGR, BGRA, AYUV, UYVY, I420, Y41B, UYVP }, "
+ "width = (int) [ 1, 32767 ], " "height = (int) [ 1, 32767 ]; ")
+ );
+
+static GstStaticPadTemplate gst_rtp_vraw_pay_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-rtp, "
+ "media = (string) \"video\", "
+ "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
+ "clock-rate = (int) 90000, "
+ "encoding-name = (string) \"RAW\","
+ "sampling = (string) { \"RGB\", \"RGBA\", \"BGR\", \"BGRA\", "
+ "\"YCbCr-4:4:4\", \"YCbCr-4:2:2\", \"YCbCr-4:2:0\", "
+ "\"YCbCr-4:1:1\" },"
+ /* we cannot express these as strings
+ * "width = (string) [1 32767],"
+ * "height = (string) [1 32767],"
+ */
+ "depth = (string) { \"8\", \"10\", \"12\", \"16\" },"
+ "colorimetry = (string) { \"BT601-5\", \"BT709-2\", \"SMPTE240M\" }"
+ /* optional
+ * interlace =
+ * top-field-first =
+ * chroma-position = (string)
+ * gamma = (float)
+ */
+ )
+ );
+
+static gboolean gst_rtp_vraw_pay_setcaps (GstRTPBasePayload * payload,
+ GstCaps * caps);
+static GstFlowReturn gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload *
+ payload, GstBuffer * buffer);
+static void gst_rtp_vraw_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_rtp_vraw_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+
+G_DEFINE_TYPE (GstRtpVRawPay, gst_rtp_vraw_pay, GST_TYPE_RTP_BASE_PAYLOAD)
+
+ static void gst_rtp_vraw_pay_class_init (GstRtpVRawPayClass * klass)
+{
+ GstRTPBasePayloadClass *gstrtpbasepayload_class;
+ GstElementClass *gstelement_class;
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+
+ gobject_class->set_property = gst_rtp_vraw_pay_set_property;
+ gobject_class->get_property = gst_rtp_vraw_pay_get_property;
+
+ g_object_class_install_property (gobject_class,
+ PROP_CHUNKS_PER_FRAME,
+ g_param_spec_int ("chunks-per-frame", "Chunks per Frame",
+ "Split and send out each frame in multiple chunks to reduce overhead",
+ 1, G_MAXINT, DEFAULT_CHUNKS_PER_FRAME,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+ );
+
+ gstrtpbasepayload_class->set_caps = gst_rtp_vraw_pay_setcaps;
+ gstrtpbasepayload_class->handle_buffer = gst_rtp_vraw_pay_handle_buffer;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_vraw_pay_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_rtp_vraw_pay_sink_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "RTP Raw Video payloader", "Codec/Payloader/Network/RTP",
+ "Payload raw video as RTP packets (RFC 4175)",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
+ GST_DEBUG_CATEGORY_INIT (rtpvrawpay_debug, "rtpvrawpay", 0,
+ "Raw video RTP Payloader");
+}
+
+static void
+gst_rtp_vraw_pay_init (GstRtpVRawPay * rtpvrawpay)
+{
+ rtpvrawpay->chunks_per_frame = DEFAULT_CHUNKS_PER_FRAME;
+}
+
+static gboolean
+gst_rtp_vraw_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
+{
+ GstRtpVRawPay *rtpvrawpay;
+ gboolean res;
+ gint pgroup, xinc, yinc;
+ const gchar *depthstr, *samplingstr, *colorimetrystr;
+ gchar *wstr, *hstr;
+ GstVideoInfo info;
+
+ rtpvrawpay = GST_RTP_VRAW_PAY (payload);
+
+ if (!gst_video_info_from_caps (&info, caps))
+ goto invalid_caps;
+
+ rtpvrawpay->vinfo = info;
+
+ if (gst_video_colorimetry_matches (&info.colorimetry,
+ GST_VIDEO_COLORIMETRY_BT601)) {
+ colorimetrystr = "BT601-5";
+ } else if (gst_video_colorimetry_matches (&info.colorimetry,
+ GST_VIDEO_COLORIMETRY_BT709)) {
+ colorimetrystr = "BT709-2";
+ } else if (gst_video_colorimetry_matches (&info.colorimetry,
+ GST_VIDEO_COLORIMETRY_SMPTE240M)) {
+ colorimetrystr = "SMPTE240M";
+ } else {
+ colorimetrystr = "SMPTE240M";
+ }
+
+ xinc = yinc = 1;
+
+ /* these values are the only thing we can do */
+ depthstr = "8";
+
+ switch (GST_VIDEO_INFO_FORMAT (&info)) {
+ case GST_VIDEO_FORMAT_RGBA:
+ samplingstr = "RGBA";
+ pgroup = 4;
+ break;
+ case GST_VIDEO_FORMAT_BGRA:
+ samplingstr = "BGRA";
+ pgroup = 4;
+ break;
+ case GST_VIDEO_FORMAT_RGB:
+ samplingstr = "RGB";
+ pgroup = 3;
+ break;
+ case GST_VIDEO_FORMAT_BGR:
+ samplingstr = "BGR";
+ pgroup = 3;
+ break;
+ case GST_VIDEO_FORMAT_AYUV:
+ samplingstr = "YCbCr-4:4:4";
+ pgroup = 3;
+ break;
+ case GST_VIDEO_FORMAT_UYVY:
+ samplingstr = "YCbCr-4:2:2";
+ pgroup = 4;
+ xinc = 2;
+ break;
+ case GST_VIDEO_FORMAT_Y41B:
+ samplingstr = "YCbCr-4:1:1";
+ pgroup = 6;
+ xinc = 4;
+ break;
+ case GST_VIDEO_FORMAT_I420:
+ samplingstr = "YCbCr-4:2:0";
+ pgroup = 6;
+ xinc = yinc = 2;
+ break;
+ case GST_VIDEO_FORMAT_UYVP:
+ samplingstr = "YCbCr-4:2:2";
+ pgroup = 5;
+ xinc = 2;
+ depthstr = "10";
+ break;
+ default:
+ goto unknown_format;
+ break;
+ }
+
+ if (GST_VIDEO_INFO_IS_INTERLACED (&info)) {
+ yinc *= 2;
+ }
+
+ rtpvrawpay->pgroup = pgroup;
+ rtpvrawpay->xinc = xinc;
+ rtpvrawpay->yinc = yinc;
+
+ GST_DEBUG_OBJECT (payload, "width %d, height %d, sampling %s",
+ GST_VIDEO_INFO_WIDTH (&info), GST_VIDEO_INFO_HEIGHT (&info), samplingstr);
+ GST_DEBUG_OBJECT (payload, "xinc %d, yinc %d, pgroup %d", xinc, yinc, pgroup);
+
+ wstr = g_strdup_printf ("%d", GST_VIDEO_INFO_WIDTH (&info));
+ hstr = g_strdup_printf ("%d", GST_VIDEO_INFO_HEIGHT (&info));
+
+ gst_rtp_base_payload_set_options (payload, "video", TRUE, "RAW", 90000);
+ if (GST_VIDEO_INFO_IS_INTERLACED (&info)) {
+ res = gst_rtp_base_payload_set_outcaps (payload, "sampling", G_TYPE_STRING,
+ samplingstr, "depth", G_TYPE_STRING, depthstr, "width", G_TYPE_STRING,
+ wstr, "height", G_TYPE_STRING, hstr, "colorimetry", G_TYPE_STRING,
+ colorimetrystr, "interlace", G_TYPE_STRING, "true", NULL);
+ } else {
+ res = gst_rtp_base_payload_set_outcaps (payload, "sampling", G_TYPE_STRING,
+ samplingstr, "depth", G_TYPE_STRING, depthstr, "width", G_TYPE_STRING,
+ wstr, "height", G_TYPE_STRING, hstr, "colorimetry", G_TYPE_STRING,
+ colorimetrystr, NULL);
+ }
+ g_free (wstr);
+ g_free (hstr);
+
+ return res;
+
+ /* ERRORS */
+invalid_caps:
+ {
+ GST_ERROR_OBJECT (payload, "could not parse caps");
+ return FALSE;
+ }
+unknown_format:
+ {
+ GST_ERROR_OBJECT (payload, "unknown caps format");
+ return FALSE;
+ }
+}
+
+static GstFlowReturn
+gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
+{
+ GstRtpVRawPay *rtpvrawpay;
+ GstFlowReturn ret = GST_FLOW_OK;
+ gfloat packets_per_packline;
+ guint pgroups_per_packet;
+ guint packlines_per_list, buffers_per_list;
+ guint lines_delay; /* after how many packed lines we push out a buffer list */
+ guint last_line; /* last pack line number we pushed out a buffer list */
+ guint line, offset;
+ guint8 *p0, *yp, *up, *vp;
+ guint ystride, uvstride;
+ guint xinc, yinc;
+ guint pgroup;
+ guint mtu;
+ guint width, height;
+ gint field, fields;
+ GstVideoFormat format;
+ GstVideoFrame frame;
+ gint interlaced;
+ gboolean use_buffer_lists;
+ GstBufferList *list = NULL;
+ GstRTPBuffer rtp = { NULL, };
+
+ rtpvrawpay = GST_RTP_VRAW_PAY (payload);
+
+ gst_video_frame_map (&frame, &rtpvrawpay->vinfo, buffer, GST_MAP_READ);
+
+ GST_LOG_OBJECT (rtpvrawpay, "new frame of %" G_GSIZE_FORMAT " bytes",
+ gst_buffer_get_size (buffer));
+
+ /* get pointer and strides of the planes */
+ p0 = GST_VIDEO_FRAME_PLANE_DATA (&frame, 0);
+ yp = GST_VIDEO_FRAME_COMP_DATA (&frame, 0);
+ up = GST_VIDEO_FRAME_COMP_DATA (&frame, 1);
+ vp = GST_VIDEO_FRAME_COMP_DATA (&frame, 2);
+
+ ystride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 0);
+ uvstride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 1);
+
+ mtu = GST_RTP_BASE_PAYLOAD_MTU (payload);
+
+ /* amount of bytes for one pixel */
+ pgroup = rtpvrawpay->pgroup;
+ width = GST_VIDEO_INFO_WIDTH (&rtpvrawpay->vinfo);
+ height = GST_VIDEO_INFO_HEIGHT (&rtpvrawpay->vinfo);
+
+ interlaced = GST_VIDEO_INFO_IS_INTERLACED (&rtpvrawpay->vinfo);
+
+ format = GST_VIDEO_INFO_FORMAT (&rtpvrawpay->vinfo);
+
+ yinc = rtpvrawpay->yinc;
+ xinc = rtpvrawpay->xinc;
+
+ /* after how many packed lines we push out a buffer list */
+ lines_delay = GST_ROUND_UP_4 (height / rtpvrawpay->chunks_per_frame);
+
+ /* calculate how many buffers we expect to store in a single buffer list */
+ pgroups_per_packet = (mtu - (12 + 14)) / pgroup;
+ packets_per_packline = width / (xinc * pgroups_per_packet * 1.0);
+ packlines_per_list = height / (yinc * rtpvrawpay->chunks_per_frame);
+ buffers_per_list = packlines_per_list * packets_per_packline;
+ buffers_per_list = GST_ROUND_UP_8 (buffers_per_list);
+
+ use_buffer_lists = (rtpvrawpay->chunks_per_frame < (height / yinc));
+
+ fields = 1 + interlaced;
+
+ /* start with line 0, offset 0 */
+ for (field = 0; field < fields; field++) {
+ line = field;
+ offset = 0;
+ last_line = 0;
+
+ if (use_buffer_lists)
+ list = gst_buffer_list_new_sized (buffers_per_list);
+
+ /* write all lines */
+ while (line < height) {
+ guint left, pack_line;
+ GstBuffer *out;
+ guint8 *outdata, *headers;
+ gboolean next_line, complete = FALSE;
+ guint length, cont, pixels;
+
+ /* get the max allowed payload length size, we try to fill the complete MTU */
+ left = gst_rtp_buffer_calc_payload_len (mtu, 0, 0);
+ out = gst_rtp_buffer_new_allocate (left, 0, 0);
+
+ if (field == 0) {
+ GST_BUFFER_TIMESTAMP (out) = GST_BUFFER_TIMESTAMP (buffer);
+ } else {
+ GST_BUFFER_TIMESTAMP (out) = GST_BUFFER_TIMESTAMP (buffer) +
+ GST_BUFFER_DURATION (buffer) / 2;
+ }
+
+ gst_rtp_buffer_map (out, GST_MAP_WRITE, &rtp);
+ outdata = gst_rtp_buffer_get_payload (&rtp);
+
+ GST_LOG_OBJECT (rtpvrawpay, "created buffer of size %u for MTU %u", left,
+ mtu);
+
+ /*
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Extended Sequence Number | Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |F| Line No |C| Offset |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Length |F| Line No |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |C| Offset | .
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ .
+ * . .
+ * . Two (partial) lines of video data .
+ * . .
+ * +---------------------------------------------------------------+
+ */
+
+ /* need 2 bytes for the extended sequence number */
+ *outdata++ = 0;
+ *outdata++ = 0;
+ left -= 2;
+
+ /* the headers start here */
+ headers = outdata;
+
+ /* make sure we can fit at least *one* header and pixel */
+ if (!(left > (6 + pgroup))) {
+ gst_rtp_buffer_unmap (&rtp);
+ gst_buffer_unref (out);
+ goto too_small;
+ }
+
+ /* while we can fit at least one header and one pixel */
+ while (left > (6 + pgroup)) {
+ /* we need a 6 bytes header */
+ left -= 6;
+
+ /* get how may bytes we need for the remaining pixels */
+ pixels = width - offset;
+ length = (pixels * pgroup) / xinc;
+
+ if (left >= length) {
+ /* pixels and header fit completely, we will write them and skip to the
+ * next line. */
+ next_line = TRUE;
+ } else {
+ /* line does not fit completely, see how many pixels fit */
+ pixels = (left / pgroup) * xinc;
+ length = (pixels * pgroup) / xinc;
+ next_line = FALSE;
+ }
+ GST_LOG_OBJECT (rtpvrawpay, "filling %u bytes in %u pixels", length,
+ pixels);
+ left -= length;
+
+ /* write length */
+ *outdata++ = (length >> 8) & 0xff;
+ *outdata++ = length & 0xff;
+
+ /* write line no */
+ *outdata++ = ((line >> 8) & 0x7f) | ((field << 7) & 0x80);
+ *outdata++ = line & 0xff;
+
+ if (next_line) {
+ /* go to next line we do this here to make the check below easier */
+ line += yinc;
+ }
+
+ /* calculate continuation marker */
+ cont = (left > (6 + pgroup) && line < height) ? 0x80 : 0x00;
+
+ /* write offset and continuation marker */
+ *outdata++ = ((offset >> 8) & 0x7f) | cont;
+ *outdata++ = offset & 0xff;
+
+ if (next_line) {
+ /* reset offset */
+ offset = 0;
+ GST_LOG_OBJECT (rtpvrawpay, "go to next line %u", line);
+ } else {
+ offset += pixels;
+ GST_LOG_OBJECT (rtpvrawpay, "next offset %u", offset);
+ }
+
+ if (!cont)
+ break;
+ }
+ GST_LOG_OBJECT (rtpvrawpay, "consumed %u bytes",
+ (guint) (outdata - headers));
+
+ /* second pass, read headers and write the data */
+ while (TRUE) {
+ guint offs, lin;
+
+ /* read length and cont */
+ length = (headers[0] << 8) | headers[1];
+ lin = ((headers[2] & 0x7f) << 8) | headers[3];
+ offs = ((headers[4] & 0x7f) << 8) | headers[5];
+ cont = headers[4] & 0x80;
+ pixels = length / pgroup;
+ headers += 6;
+
+ GST_LOG_OBJECT (payload,
+ "writing length %u, line %u, offset %u, cont %d", length, lin, offs,
+ cont);
+
+ switch (format) {
+ case GST_VIDEO_FORMAT_RGB:
+ case GST_VIDEO_FORMAT_RGBA:
+ case GST_VIDEO_FORMAT_BGR:
+ case GST_VIDEO_FORMAT_BGRA:
+ case GST_VIDEO_FORMAT_UYVY:
+ case GST_VIDEO_FORMAT_UYVP:
+ offs /= xinc;
+ memcpy (outdata, p0 + (lin * ystride) + (offs * pgroup), length);
+ outdata += length;
+ break;
+ case GST_VIDEO_FORMAT_AYUV:
+ {
+ gint i;
+ guint8 *datap;
+
+ datap = p0 + (lin * ystride) + (offs * 4);
+
+ for (i = 0; i < pixels; i++) {
+ *outdata++ = datap[2];
+ *outdata++ = datap[1];
+ *outdata++ = datap[3];
+ datap += 4;
+ }
+ break;
+ }
+ case GST_VIDEO_FORMAT_I420:
+ {
+ gint i;
+ guint uvoff;
+ guint8 *yd1p, *yd2p, *udp, *vdp;
+
+ yd1p = yp + (lin * ystride) + (offs);
+ yd2p = yd1p + ystride;
+ uvoff = (lin / yinc * uvstride) + (offs / xinc);
+ udp = up + uvoff;
+ vdp = vp + uvoff;
+
+ for (i = 0; i < pixels; i++) {
+ *outdata++ = *yd1p++;
+ *outdata++ = *yd1p++;
+ *outdata++ = *yd2p++;
+ *outdata++ = *yd2p++;
+ *outdata++ = *udp++;
+ *outdata++ = *vdp++;
+ }
+ break;
+ }
+ case GST_VIDEO_FORMAT_Y41B:
+ {
+ gint i;
+ guint uvoff;
+ guint8 *ydp, *udp, *vdp;
+
+ ydp = yp + (lin * ystride) + offs;
+ uvoff = (lin / yinc * uvstride) + (offs / xinc);
+ udp = up + uvoff;
+ vdp = vp + uvoff;
+
+ for (i = 0; i < pixels; i++) {
+ *outdata++ = *udp++;
+ *outdata++ = *ydp++;
+ *outdata++ = *ydp++;
+ *outdata++ = *vdp++;
+ *outdata++ = *ydp++;
+ *outdata++ = *ydp++;
+ }
+ break;
+ }
+ default:
+ gst_rtp_buffer_unmap (&rtp);
+ gst_buffer_unref (out);
+ goto unknown_sampling;
+ }
+
+ if (!cont)
+ break;
+ }
+
+ if (line >= height) {
+ GST_LOG_OBJECT (rtpvrawpay, "field/frame complete, set marker");
+ gst_rtp_buffer_set_marker (&rtp, TRUE);
+ complete = TRUE;
+ }
+ gst_rtp_buffer_unmap (&rtp);
+ if (left > 0) {
+ GST_LOG_OBJECT (rtpvrawpay, "we have %u bytes left", left);
+ gst_buffer_resize (out, 0, gst_buffer_get_size (out) - left);
+ }
+
+ /* Now either push out the buffer directly */
+ if (!use_buffer_lists) {
+ ret = gst_rtp_base_payload_push (payload, out);
+ continue;
+ }
+
+ /* or add the buffer to buffer list ... */
+ gst_buffer_list_add (list, out);
+
+ /* .. and check if we need to push out the list */
+ pack_line = (line - field) / fields;
+ if (complete || (pack_line > last_line && pack_line % lines_delay == 0)) {
+ GST_LOG_OBJECT (rtpvrawpay, "pushing list of %u buffers up to pack "
+ "line %u", gst_buffer_list_length (list), pack_line);
+ ret = gst_rtp_base_payload_push_list (payload, list);
+ list = NULL;
+ if (!complete)
+ list = gst_buffer_list_new_sized (buffers_per_list);
+ last_line = pack_line;
+ }
+ }
+
+ }
+
+ gst_video_frame_unmap (&frame);
+ gst_buffer_unref (buffer);
+
+ return ret;
+
+ /* ERRORS */
+unknown_sampling:
+ {
+ GST_ELEMENT_ERROR (payload, STREAM, FORMAT,
+ (NULL), ("unimplemented sampling"));
+ gst_video_frame_unmap (&frame);
+ gst_buffer_unref (buffer);
+ return GST_FLOW_NOT_SUPPORTED;
+ }
+too_small:
+ {
+ GST_ELEMENT_ERROR (payload, RESOURCE, NO_SPACE_LEFT,
+ (NULL), ("not enough space to send at least one pixel"));
+ gst_video_frame_unmap (&frame);
+ gst_buffer_unref (buffer);
+ return GST_FLOW_NOT_SUPPORTED;
+ }
+}
+
+static void
+gst_rtp_vraw_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstRtpVRawPay *rtpvrawpay;
+
+ rtpvrawpay = GST_RTP_VRAW_PAY (object);
+
+ switch (prop_id) {
+ case PROP_CHUNKS_PER_FRAME:
+ rtpvrawpay->chunks_per_frame = g_value_get_int (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_rtp_vraw_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstRtpVRawPay *rtpvrawpay;
+
+ rtpvrawpay = GST_RTP_VRAW_PAY (object);
+
+ switch (prop_id) {
+ case PROP_CHUNKS_PER_FRAME:
+ g_value_set_int (value, rtpvrawpay->chunks_per_frame);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+gboolean
+gst_rtp_vraw_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rtpvrawpay",
+ GST_RANK_SECONDARY, GST_TYPE_RTP_VRAW_PAY);
+}
diff --git a/gst/rtp/gstrtpvrawpay.h b/gst/rtp/gstrtpvrawpay.h
new file mode 100755
index 0000000..3fd2442
--- /dev/null
+++ b/gst/rtp/gstrtpvrawpay.h
@@ -0,0 +1,67 @@
+/* GStreamer
+ * Copyright (C) <2008> Wim Taymans <wim.taymans@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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_VRAW_PAY_H__
+#define __GST_RTP_VRAW_PAY_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/rtp/gstrtpbasepayload.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTP_VRAW_PAY \
+ (gst_rtp_vraw_pay_get_type())
+#define GST_RTP_VRAW_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_VRAW_PAY,GstRtpVRawPay))
+#define GST_RTP_VRAW_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_VRAW_PAY,GstRtpVRawPayClass))
+#define GST_IS_RTP_VRAW_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_VRAW_PAY))
+#define GST_IS_RTP_VRAW_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_VRAW_PAY))
+
+typedef struct _GstRtpVRawPay GstRtpVRawPay;
+typedef struct _GstRtpVRawPayClass GstRtpVRawPayClass;
+
+struct _GstRtpVRawPay
+{
+ GstRTPBasePayload payload;
+
+ GstVideoInfo vinfo;
+
+ gint pgroup;
+ gint xinc, yinc;
+
+ /* properties */
+ guint chunks_per_frame;
+};
+
+struct _GstRtpVRawPayClass
+{
+ GstRTPBasePayloadClass parent_class;
+};
+
+GType gst_rtp_vraw_pay_get_type (void);
+
+gboolean gst_rtp_vraw_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_VRAW_PAY_H__ */