Remove various unported plugins

If they were not ported after 4+ years it seems unlikely that anybody is
ever going to need them again. They're still in the GIT history if
needed.

https://bugzilla.gnome.org/show_bug.cgi?id=774530
This commit is contained in:
Sebastian Dröge 2016-12-21 11:00:47 +02:00
parent 0fdd4e2539
commit 9b5de05399
225 changed files with 15 additions and 56120 deletions

View file

@ -94,9 +94,6 @@
/* Define to enable Android Media (used by androidmedia). */
#mesondefine HAVE_ANDROID_MEDIA
/* Define to enable AirPort Express Wireless sink (used by apexsink). */
#mesondefine HAVE_APEXSINK
/* Define to enable Apple video (used by applemedia). */
#mesondefine HAVE_APPLE_MEDIA
@ -229,12 +226,6 @@
/* Define to 1 if you have the <fcntl.h> header file. */
#mesondefine HAVE_FCNTL_H
/* FIONREAD ioctl found in sys/filio.h */
#mesondefine HAVE_FIONREAD_IN_SYS_FILIO
/* FIONREAD ioctl found in sys/ioclt.h */
#mesondefine HAVE_FIONREAD_IN_SYS_IOCTL
/* Define to enable Flite plugin (used by flite). */
#mesondefine HAVE_FLITE
@ -322,12 +313,6 @@
/* Define if libusb 1.x is installed */
#mesondefine HAVE_LIBUSB
/* Define to enable libvisual visualization library (used by libvisual). */
#mesondefine HAVE_LIBVISUAL
/* Define to enable Linear Systems SDI plugin (used by linsys). */
#mesondefine HAVE_LINSYS
/* Define if we have liblrdf */
#mesondefine HAVE_LRDF
@ -364,9 +349,6 @@
/* Define to enable MythTV client plugins (used by mythtvsrc). */
#mesondefine HAVE_MYTHTV
/* Define to enable nas plug-in (used by nassink). */
#mesondefine HAVE_NAS
/* Define to enable neon http client plugins (used by neonhttpsrc). */
#mesondefine HAVE_NEON
@ -454,9 +436,6 @@
/* Define to enable Schroedinger video codec (used by schro). */
#mesondefine HAVE_SCHRO
/* Define to enable SDL plug-in (used by sdlvideosink sdlaudiosink). */
#mesondefine HAVE_SDL
/* Define to enable POSIX shared memory source and sink (used by shm). */
#mesondefine HAVE_SHM
@ -466,9 +445,6 @@
/* Define to enable sndfile plug-in (used by sfdec sfenc). */
#mesondefine HAVE_SNDFILE
/* Define to enable sndio audio (used by sndio). */
#mesondefine HAVE_SNDIO
/* Define to enable soundtouch plug-in (used by soundtouch). */
#mesondefine HAVE_SOUNDTOUCH
@ -523,9 +499,6 @@
/* Define if libtiger is available */
#mesondefine HAVE_TIGER
/* Define to enable timidity midi soft synth plugin (used by timidity). */
#mesondefine HAVE_TIMIDITY
/* Define to 1 if you have the <unistd.h> header file. */
#mesondefine HAVE_UNISTD_H
@ -574,12 +547,6 @@
/* Define to 1 if you have the <windows.h> header file. */
#mesondefine HAVE_WINDOWS_H
/* Define to enable Windows internet library (used by wininet). */
#mesondefine HAVE_WININET
/* Define to 1 if you have the <wininet.h> header file. */
#mesondefine HAVE_WININET_H
/* Define to enable Winks plug-in (used by winks). */
#mesondefine HAVE_WINKS
@ -595,9 +562,6 @@
/* Define if you have X11 library */
#mesondefine HAVE_X11
/* Define to enable xvid plugins (used by xvid). */
#mesondefine HAVE_XVID
/* Define to enable ZBar barcode detector (used by zbar). */
#mesondefine HAVE_ZBAR
@ -607,9 +571,6 @@
/* library dir */
#mesondefine LIBDIR
/* directory in which the detected libvisual's plugins are located */
#mesondefine LIBVISUAL_PLUGINSBASEDIR
/* gettext locale dir */
#mesondefine LOCALEDIR
@ -668,9 +629,6 @@
/* the target CPU */
#mesondefine TARGET_CPU
/* Define location of timidity.cfg */
#mesondefine TIMIDITY_CFG
/* Use Mali FB EGL platform */
#mesondefine USE_EGL_MALI_FB

View file

@ -164,16 +164,8 @@ AX_CREATE_STDINT_H
AC_CHECK_HEADERS([pthread.h], HAVE_PTHREAD_H=yes)
AM_CONDITIONAL(HAVE_PTHREAD_H, test "x$HAVE_PTHREAD_H" = "xyes")
if test "x$HAVE_PTHREAD_H" != "xyes"; then
GST_PLUGINS_SELECTED=`echo $GST_PLUGINS_SELECTED | $SED -e s/dccp//`
fi
dnl *** checks for types/defines ***
dnl Check for FIONREAD ioctl declaration
dnl used in gst/dccp
GST_CHECK_FIONREAD
dnl *** checks for structures ***
dnl *** checks for compiler characteristics ***
@ -467,21 +459,6 @@ dnl used in examples
AG_GST_DEFAULT_ELEMENTS
dnl *** plug-ins to include ***
dnl Non ported plugins (non-dependant, then dependant)
dnl Make sure you have a space before and after all plugins
GST_PLUGINS_NONPORTED=" cdxaparse \
dccp faceoverlay \
hdvparse \
mve nuvdemux \
patchdetect \
sdi tta \
linsys \
apexsink \
nas sdl timidity \
wininet \
xvid sndio libvisual"
AC_SUBST(GST_PLUGINS_NONPORTED)
dnl these are all the gst plug-ins, compilable without additional libs
AG_GST_CHECK_PLUGIN(accurip)
@ -498,13 +475,10 @@ AG_GST_CHECK_PLUGIN(audiovisualizers)
AG_GST_CHECK_PLUGIN(autoconvert)
AG_GST_CHECK_PLUGIN(bayer)
AG_GST_CHECK_PLUGIN(camerabin2)
AG_GST_CHECK_PLUGIN(cdxaparse)
AG_GST_CHECK_PLUGIN(coloreffects)
AG_GST_CHECK_PLUGIN(dccp)
AG_GST_CHECK_PLUGIN(debugutils)
AG_GST_CHECK_PLUGIN(dvbsuboverlay)
AG_GST_CHECK_PLUGIN(dvdspu)
AG_GST_CHECK_PLUGIN(faceoverlay)
AG_GST_CHECK_PLUGIN(festival)
AG_GST_CHECK_PLUGIN(fieldanalysis)
AG_GST_CHECK_PLUGIN(freeverb)
@ -512,7 +486,6 @@ AG_GST_CHECK_PLUGIN(frei0r)
AG_GST_CHECK_PLUGIN(gaudieffects)
AG_GST_CHECK_PLUGIN(geometrictransform)
AG_GST_CHECK_PLUGIN(gdp)
AG_GST_CHECK_PLUGIN(hdvparse)
AG_GST_CHECK_PLUGIN(id3tag)
AG_GST_CHECK_PLUGIN(inter)
AG_GST_CHECK_PLUGIN(interlace)
@ -526,17 +499,13 @@ AG_GST_CHECK_PLUGIN(mpegdemux)
AG_GST_CHECK_PLUGIN(mpegtsdemux)
AG_GST_CHECK_PLUGIN(mpegtsmux)
AG_GST_CHECK_PLUGIN(mpegpsmux)
AG_GST_CHECK_PLUGIN(mve)
AG_GST_CHECK_PLUGIN(mxf)
AG_GST_CHECK_PLUGIN(netsim)
AG_GST_CHECK_PLUGIN(nuvdemux)
AG_GST_CHECK_PLUGIN(onvif)
AG_GST_CHECK_PLUGIN(patchdetect)
AG_GST_CHECK_PLUGIN(pcapparse)
AG_GST_CHECK_PLUGIN(pnm)
AG_GST_CHECK_PLUGIN(rawparse)
AG_GST_CHECK_PLUGIN(removesilence)
AG_GST_CHECK_PLUGIN(sdi)
AG_GST_CHECK_PLUGIN(sdp)
AG_GST_CHECK_PLUGIN(segmentclip)
AG_GST_CHECK_PLUGIN(siren)
@ -545,7 +514,6 @@ AG_GST_CHECK_PLUGIN(speed)
AG_GST_CHECK_PLUGIN(subenc)
AG_GST_CHECK_PLUGIN(stereo)
AG_GST_CHECK_PLUGIN(timecode)
AG_GST_CHECK_PLUGIN(tta)
AG_GST_CHECK_PLUGIN(videofilters)
AG_GST_CHECK_PLUGIN(videoparsers)
AG_GST_CHECK_PLUGIN(videosignal)
@ -600,13 +568,6 @@ if test "x$HAVE_WINSOCK2_H" = "xyes"; then
AC_SUBST(WINSOCK2_LIBS)
fi
if test "x$HAVE_PTHREAD_H" = "xyes"; then
DCCP_LIBS="$DCCP_LIBS $PTHREAD_LIBS"
AC_SUBST(DCCP_LIBS)
else
AG_GST_DISABLE_PLUGIN(dccp)
fi
dnl *** opengl ***
AC_ARG_ENABLE([opengl],
[ --enable-opengl Enable Desktop OpenGL support @<:@default=auto@:>@],
@ -2098,24 +2059,6 @@ AG_GST_CHECK_FEATURE(VOAACENC, [vo-aacenc library], vo-aacenc, [
AG_GST_PKG_CHECK_MODULES(VOAACENC, vo-aacenc >= 0.1.0)
])
dnl *** apexsink ***
translit(dnm, m, l) AM_CONDITIONAL(USE_APEXSINK, true)
AG_GST_CHECK_FEATURE(APEXSINK, [AirPort Express Wireless sink], apexsink, [
PKG_CHECK_MODULES(APEXSINK, [ openssl >= 0.9.5 libcrypto ], [
HAVE_APEXSINK="yes"
saved_LIBS="$LIBS"
LIBS=""
AC_SEARCH_LIBS(socket, [socket], [ ], [ APEXSINK="no" ])
AC_SEARCH_LIBS(gethostbyname, [nsl], [ ], [ APEXSINK="no" ])
APEXSINK_LIBS="$APEXSINK_LIBS $LIBS"
LIBS="$saved_LIBS"
AC_SUBST(APEXSINK_CFLAGS)
AC_SUBST(APEXSINK_LIBS)
], [
APEXSINK="no"
])
])
dnl *** bs2b ***
translit(dnm, m, l) AM_CONDITIONAL(USE_BS2B, true)
AG_GST_CHECK_FEATURE(BS2B, [bs2b], bs2b, [
@ -2525,19 +2468,6 @@ AG_GST_CHECK_FEATURE(TTML, [TTML plugin], ttml, [
fi
])
dnl *** linsys ***
translit(dnm, m, l) AM_CONDITIONAL(USE_LINSYS, true)
AG_GST_CHECK_FEATURE(LINSYS, [Linear Systems SDI plugin], linsys, [
case "$host" in
*-*linux*)
HAVE_LINSYS=yes
;;
*)
HAVE_LINSYS=no
;;
esac
])
dnl *** modplug ***
translit(dnm, m, l) AM_CONDITIONAL(USE_MODPLUG, true)
AG_GST_CHECK_FEATURE(MODPLUG, modplug, modplug, [
@ -2745,21 +2675,6 @@ AG_GST_CHECK_FEATURE(MUSEPACK, [musepackdec], musepack, [
], [HAVE_MUSEPACK="no"])])
])
dnl *** nas ***
translit(dnm, m, l) AM_CONDITIONAL(USE_NAS, true)
AG_GST_CHECK_FEATURE(NAS, [nas plug-in], nassink, [
HAVE_NAS="no"
if test "x$HAVE_X" = "xyes"; then
save_cppflags=$CFLAGS
CPPFLAGS="$CPPFLAGS $X_CFLAGS"
AG_GST_CHECK_LIBHEADER(NAS, audio, AuOpenServer, $X_LIBS, audio/audiolib.h,
NAS_LIBS="$X_LIBS -laudio" NAS_CFLAGS="$X_CFLAGS")
CPPFLAGS="$save_cppflags"
fi
AC_SUBST(NAS_CFLAGS)
AC_SUBST(NAS_LIBS)
])
dnl *** neon ***
translit(dnm, m, l) AM_CONDITIONAL(USE_NEON, true)
AG_GST_CHECK_FEATURE(NEON, [neon http client plugins], neonhttpsrc, [
@ -2901,20 +2816,6 @@ AG_GST_CHECK_FEATURE(OPUS, [opus], opus, [
AC_SUBST(OPUS_LIBS)
])
dnl *** pvr ***
translit(dnm, m, l) AM_CONDITIONAL(USE_PVR, true)
AG_GST_CHECK_FEATURE(PVR, [pvrvideosink], pvr, [
PKG_CHECK_MODULES([PVR], [libtimemmgr], HAVE_PVR=yes, HAVE_PVR=no)
AC_SUBST(PVR_CFLAGS)
AC_SUBST(PVR_LIBS)
])
AC_ARG_WITH([pvr-external-headers],
AS_HELP_STRING([--with-pvr-external-headers],[Use system installed PVR2D headers]),
[AS_IF([test "x$with_pvr_external_headers" = "xno"],
[PVR_CFLAGS="$PVR_CFLAGS -I\$(srcdir)/pvr_includes"])],
[PVR_CFLAGS="$PVR_CFLAGS -I\$(srcdir)/pvr_includes"])
dnl *** rsvg ***
translit(dnm, m, l) AM_CONDITIONAL(USE_RSVG, true)
AG_GST_CHECK_FEATURE(RSVG, [rsvg decoder], rsvg, [
@ -3077,50 +2978,6 @@ AG_GST_CHECK_FEATURE(VULKAN, [Vulkan elements], vulkan, [
], [])
])
dnl *** libvisual ***
translit(dnm, m, l) AM_CONDITIONAL(USE_LIBVISUAL, true)
AG_GST_CHECK_FEATURE(LIBVISUAL, [libvisual visualization library], libvisual, [
AG_GST_PKG_CHECK_MODULES(LIBVISUAL, libvisual-0.4 >= 0.4.0)
if test x$HAVE_LIBVISUAL = xyes; then
LIBVIS_PLUGINSDIR="`$PKG_CONFIG --variable=pluginsbasedir libvisual-0.4`"
fi
AC_MSG_NOTICE([libvisual pluginsdir: $LIBVIS_PLUGINSDIR])
if test x$LIBVIS_PLUGINSDIR != x; then
AC_DEFINE_UNQUOTED(LIBVISUAL_PLUGINSBASEDIR,
"$LIBVIS_PLUGINSDIR",
[directory in which the detected libvisual's plugins are located])
fi
])
dnl *** timidity ***
translit(dnm, m, l) AM_CONDITIONAL(USE_TIMIDITY, true)
AG_GST_CHECK_FEATURE(TIMIDITY, [timidity midi soft synth plugin], timidity, [
PKG_CHECK_MODULES(TIMIDITY, libtimidity, [
HAVE_TIMIDITY="yes",
AC_MSG_CHECKING([for timidity.cfg])
timidity_cfg=""
if test -r /etc/timidity.cfg; then
timidity_cfg=/etc/timidity.cfg
elif test -r /etc/timidity/timidity.cfg; then
timidity_cfg=/etc/timidity/timidity.cfg
elif test -r /usr/share/timidity/timidity.cfg; then
timidity_cfg=/usr/share/timidity/timidity.cfg
elif test -r /usr/local/share/timidity/timidity.cfg; then
timidity_cfg=/usr/local/share/timidity/timidity.cfg
fi
if test "x$timidity_cfg" != "x"; then
AC_MSG_RESULT($timidity_cfg)
AC_DEFINE_UNQUOTED(TIMIDITY_CFG, "$timidity_cfg", [Define location of timidity.cfg])
else
AC_MSG_RESULT([not found])
fi
], [
HAVE_TIMIDITY="no"
])
AC_SUBST(TIMIDITY_CFLAGS)
AC_SUBST(TIMIDITY_LIBS)
])
dnl *** teletextdec ***
translit(dnm, m, l) AM_CONDITIONAL(USE_TELETEXTDEC, true)
AG_GST_CHECK_FEATURE(TELETEXTDEC, [Teletext decoder], teletextdec, [
@ -3149,12 +3006,6 @@ AG_GST_CHECK_FEATURE(WILDMIDI, [wildmidi midi soft synth plugin], wildmidi, [
AC_SUBST(WILDMIDI_LIBS)
])
dnl *** SDL ***
translit(dnm, m, l) AM_CONDITIONAL(USE_SDL, true)
AG_GST_CHECK_FEATURE(SDL, [SDL plug-in], sdlvideosink sdlaudiosink, [
AM_PATH_SDL(, HAVE_SDL=yes, HAVE_SDL=no)
])
dnl **** Smooth Streaming ****
translit(dnm, m, l) AM_CONDITIONAL(USE_SMOOTHSTREAMING, true)
AG_GST_CHECK_FEATURE(SMOOTHSTREAMING, [Smooth Streaming plug-in], smoothstreaming, [
@ -3247,36 +3098,6 @@ AG_GST_CHECK_FEATURE(GME, [gme decoder], gme, [
fi
])
dnl *** XVID ***
translit(dnm, m, l) AM_CONDITIONAL(USE_XVID, true)
AG_GST_CHECK_FEATURE(XVID, [xvid plugins], xvid, [
HAVE_XVID=no
AC_CHECK_HEADER(xvid.h, [
OLD_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBM"
AC_CHECK_LIB(xvidcore, xvid_encore, [
AC_CHECK_LIB(xvidcore, xvid_decore, [
AC_CHECK_LIB(xvidcore, xvid_global, [
AC_MSG_CHECKING([for up-to-date XviD API version])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <xvid.h>]], [[
#if XVID_API_MAJOR(XVID_API) != 4
#error "Incompatible XviD API version"
#endif
#if XVID_API_MAJOR(XVID_API) == 4 && XVID_API_MINOR(XVID_API) < 3
#error "Incompatible XviD API version"
#endif
]])],[ AC_MSG_RESULT(yes)
XVID_LIBS="-lxvidcore $LIBM"
AC_SUBST(XVID_LIBS)
HAVE_XVID=yes
],[AC_MSG_RESULT(no) ])
], )
], )
], )
LIBS="$OLD_LIBS"
], )
])
dnl *** dvb ***
translit(dnm, m, l) AM_CONDITIONAL(USE_DVB, true)
AG_GST_CHECK_FEATURE(DVB, [DVB Source], dvb, [
@ -3295,16 +3116,6 @@ AG_GST_CHECK_FEATURE(DVB, [DVB Source], dvb, [
], [HAVE_DVB="no"])
])
dnl *** wininet ***
translit(dnm, m, l) AM_CONDITIONAL(USE_WININET, true)
AG_GST_CHECK_FEATURE(WININET, [Windows internet library], wininet, [
AC_MSG_CHECKING([Checking for windows internet support])
AC_CHECK_HEADERS([windows.h wininet.h],
[HAVE_WININET="yes"], [HAVE_WININET="no"],
[AC_INCLUDES_DEFAULT
#include <windows.h>])
])
dnl *** acm ***
translit(dnm, m, l) AM_CONDITIONAL(USE_ACM, true)
AG_GST_CHECK_FEATURE(ACM, [Windows ACM library], acm, [
@ -3398,19 +3209,6 @@ AG_GST_CHECK_FEATURE(SPANDSP, [Spandsp], spandsp, [
AC_SUBST(SPANDSP_CFLAGS)
AC_SUBST(SPANDSP_LIBS)
dnl *** sndio ***
translit(dnm, m, l) AM_CONDITIONAL(USE_SNDIO, true)
AG_GST_CHECK_FEATURE(SNDIO, [sndio audio], sndio, [
AC_CHECK_HEADER(sndio.h, HAVE_SNDIO="yes", HAVE_SNDIO="no")
if test "x$HAVE_SNDIO" = "xyes"; then
AC_CHECK_LIB(sndio, sio_open, HAVE_SNDIO="yes", HAVE_SNDIO="no")
if test "x$HAVE_SNDIO" = "xyes"; then
SNDIO_LIBS=-lsndio
AC_SUBST(SNDIO_LIBS)
fi
fi
])
dnl *** hls-crypto ***
AC_ARG_WITH([hls-crypto],
AS_HELP_STRING([--with-hls-crypto=auto|nettle|libgcrypt|openssl], [
@ -3509,7 +3307,6 @@ dnl but we still need to set the conditionals
AM_CONDITIONAL(USE_ASSRENDER, false)
AM_CONDITIONAL(USE_VOAMRWBENC, false)
AM_CONDITIONAL(USE_VOAACENC, false)
AM_CONDITIONAL(USE_APEXSINK, false)
AM_CONDITIONAL(USE_BS2B, false)
AM_CONDITIONAL(USE_BZ2, false)
AM_CONDITIONAL(USE_CHROMAPRINT, false)
@ -3544,12 +3341,10 @@ AM_CONDITIONAL(USE_LADSPA, false)
AM_CONDITIONAL(USE_LV2, false)
AM_CONDITIONAL(USE_LIBDE265, false)
AM_CONDITIONAL(USE_LIBMMS, false)
AM_CONDITIONAL(USE_LINSYS, false)
AM_CONDITIONAL(USE_MODPLUG, false)
AM_CONDITIONAL(USE_MPEG2ENC, false)
AM_CONDITIONAL(USE_MPLEX, false)
AM_CONDITIONAL(USE_MUSEPACK, false)
AM_CONDITIONAL(USE_NAS, false)
AM_CONDITIONAL(USE_NEON, false)
AM_CONDITIONAL(USE_OFA, false)
AM_CONDITIONAL(USE_OPENAL, false)
@ -3558,12 +3353,8 @@ AM_CONDITIONAL(USE_OPENEXR, false)
AM_CONDITIONAL(USE_OPENJPEG, false)
AM_CONDITIONAL(USE_OPENNI2, false)
AM_CONDITIONAL(USE_OPUS, false)
AM_CONDITIONAL(USE_PVR, false)
AM_CONDITIONAL(USE_QT, false)
AM_CONDITIONAL(USE_LIBVISUAL, false)
AM_CONDITIONAL(USE_TIMIDITY, false)
AM_CONDITIONAL(USE_WILDMIDI, false)
AM_CONDITIONAL(USE_SDL, false)
AM_CONDITIONAL(USE_SMOOTHSTREAMING, false)
AM_CONDITIONAL(USE_SNDFILE, false)
AM_CONDITIONAL(USE_SOUNDTOUCH, false)
@ -3571,9 +3362,7 @@ AM_CONDITIONAL(USE_SPANDSP, false)
AM_CONDITIONAL(USE_SPC, false)
AM_CONDITIONAL(USE_SRTP, false)
AM_CONDITIONAL(USE_GME, false)
AM_CONDITIONAL(USE_XVID, false)
AM_CONDITIONAL(USE_DVB, false)
AM_CONDITIONAL(USE_WININET, false)
AM_CONDITIONAL(USE_ACM, false)
AM_CONDITIONAL(USE_VDPAU, false)
AM_CONDITIONAL(USE_SBC, false)
@ -3582,7 +3371,6 @@ AM_CONDITIONAL(USE_ZBAR, false)
AM_CONDITIONAL(USE_RSVG, false)
AM_CONDITIONAL(USE_RTMP, false)
AM_CONDITIONAL(USE_TELETEXTDEC, false)
AM_CONDITIONAL(USE_SNDIO, false)
AM_CONDITIONAL(USE_UVCH264, false)
AM_CONDITIONAL(USE_WEBP, false)
AM_CONDITIONAL(USE_WEBRTCDSP, false)
@ -3690,13 +3478,10 @@ gst/audiovisualizers/Makefile
gst/autoconvert/Makefile
gst/bayer/Makefile
gst/camerabin2/Makefile
gst/cdxaparse/Makefile
gst/coloreffects/Makefile
gst/dccp/Makefile
gst/debugutils/Makefile
gst/dvbsuboverlay/Makefile
gst/dvdspu/Makefile
gst/faceoverlay/Makefile
gst/festival/Makefile
gst/fieldanalysis/Makefile
gst/freeverb/Makefile
@ -3704,7 +3489,6 @@ gst/frei0r/Makefile
gst/gaudieffects/Makefile
gst/geometrictransform/Makefile
gst/gdp/Makefile
gst/hdvparse/Makefile
gst/id3tag/Makefile
gst/inter/Makefile
gst/interlace/Makefile
@ -3719,17 +3503,13 @@ gst/mpegtsdemux/Makefile
gst/mpegtsmux/Makefile
gst/mpegtsmux/tsmux/Makefile
gst/mpegpsmux/Makefile
gst/mve/Makefile
gst/mxf/Makefile
gst/netsim/Makefile
gst/nuvdemux/Makefile
gst/onvif/Makefile
gst/patchdetect/Makefile
gst/pcapparse/Makefile
gst/pnm/Makefile
gst/rawparse/Makefile
gst/removesilence/Makefile
gst/sdi/Makefile
gst/sdp/Makefile
gst/segmentclip/Makefile
gst/siren/Makefile
@ -3737,7 +3517,6 @@ gst/smooth/Makefile
gst/speed/Makefile
gst/subenc/Makefile
gst/stereo/Makefile
gst/tta/Makefile
gst/timecode/Makefile
gst/videofilters/Makefile
gst/videoparsers/Makefile
@ -3787,7 +3566,6 @@ sys/dshowvideosink/Makefile
sys/dvb/Makefile
sys/fbdev/Makefile
sys/kms/Makefile
sys/linsys/Makefile
sys/msdk/Makefile
sys/nvenc/Makefile
sys/opensles/Makefile
@ -3796,9 +3574,7 @@ sys/tinyalsa/Makefile
sys/uvch264/Makefile
sys/vcd/Makefile
sys/vdpau/Makefile
sys/pvr2d/Makefile
sys/wasapi/Makefile
sys/wininet/Makefile
sys/winks/Makefile
sys/winscreencap/Makefile
tests/Makefile
@ -3835,7 +3611,6 @@ tests/icles/Makefile
ext/voamrwbenc/Makefile
ext/voaacenc/Makefile
ext/assrender/Makefile
ext/apexsink/Makefile
ext/bs2b/Makefile
ext/bz2/Makefile
ext/chromaprint/Makefile
@ -3861,13 +3636,11 @@ ext/ladspa/Makefile
ext/lv2/Makefile
ext/libde265/Makefile
ext/libmms/Makefile
ext/libvisual/Makefile
ext/Makefile
ext/modplug/Makefile
ext/mpeg2enc/Makefile
ext/mplex/Makefile
ext/musepack/Makefile
ext/nas/Makefile
ext/neon/Makefile
ext/ofa/Makefile
ext/openal/Makefile
@ -3883,23 +3656,20 @@ ext/resindvd/Makefile
ext/rtmp/Makefile
ext/sbc/Makefile
ext/schroedinger/Makefile
ext/sdl/Makefile
ext/smoothstreaming/Makefile
ext/sndfile/Makefile
ext/soundtouch/Makefile
ext/spandsp/Makefile
ext/sndio/Makefile
ext/srtp/Makefile
ext/teletextdec/Makefile
ext/gme/Makefile
ext/spc/Makefile
ext/timidity/Makefile
ext/wildmidi/Makefile
ext/vulkan/Makefile
ext/vulkan/xcb/Makefile
ext/vulkan/wayland/Makefile
ext/webp/Makefile
ext/x265/Makefile
ext/xvid/Makefile
ext/zbar/Makefile
ext/dtls/Makefile
ext/webrtcdsp/Makefile

View file

@ -103,10 +103,7 @@ EXTRA_HFILES = \
$(top_srcdir)/ext/rtmp/gstrtmpsink.h \
$(top_srcdir)/ext/spandsp/gstspanplc.h \
$(top_srcdir)/ext/spandsp/gstdtmfdetect.h \
$(top_srcdir)/ext/sdl/sdlaudiosink.h \
$(top_srcdir)/ext/sdl/sdlvideosink.h \
$(top_srcdir)/ext/timidity/gsttimidity.h \
$(top_srcdir)/ext/timidity/gstwildmidi.h \
$(top_srcdir)/ext/wildmidi/gstwildmidi.h \
$(top_srcdir)/ext/voaacenc/gstvoaacenc.h \
$(top_srcdir)/ext/voamrwbenc/gstvoamrwbenc.h \
$(top_srcdir)/ext/webrtcdsp/gstwebrtcdsp.h \
@ -121,10 +118,6 @@ EXTRA_HFILES = \
$(top_srcdir)/gst/audiovisualizers/gstwavescope.h \
$(top_srcdir)/gst/camerabin2/gstcamerabin2.h \
$(top_srcdir)/gst/coloreffects/gstcoloreffects.h \
$(top_srcdir)/gst/dccp/gstdccpclientsink.h \
$(top_srcdir)/gst/dccp/gstdccpclientsrc.h \
$(top_srcdir)/gst/dccp/gstdccpserversink.h \
$(top_srcdir)/gst/dccp/gstdccpserversrc.h \
$(top_srcdir)/gst/debugutils/fpsdisplaysink.h \
$(top_srcdir)/gst/dvdspu/gstdvdspu.h \
$(top_srcdir)/gst/festival/gstfestival.h \
@ -156,7 +149,6 @@ EXTRA_HFILES = \
$(top_srcdir)/gst/mpegtsmux/mpegtsmux.h \
$(top_srcdir)/gst/mxf/mxfdemux.h \
$(top_srcdir)/gst/mxf/mxfmux.h \
$(top_srcdir)/gst/nuvdemux/gstnuvdemux.h \
$(top_srcdir)/gst/pcapparse/gstpcapparse.h \
$(top_srcdir)/gst/rawparse/gstaudioparse.h \
$(top_srcdir)/gst/rawparse/gstvideoparse.h \

View file

@ -835,62 +835,6 @@ GST_TYPE_DC1394
gst_dc1394_get_type
</SECTION>
<SECTION>
<FILE>element-dccpclientsink</FILE>
<TITLE>dccpclientsink</TITLE>
GstDCCPClientSink
<SUBSECTION Standard>
GstDCCPClientSinkClass
GST_DCCP_CLIENT_SINK
GST_DCCP_CLIENT_SINK_CLASS
GST_IS_DCCP_CLIENT_SINK
GST_IS_DCCP_CLIENT_SINK_CLASS
GST_TYPE_DCCP_CLIENT_SINK
gst_dccp_client_sink_get_type
</SECTION>
<SECTION>
<FILE>element-dccpclientsrc</FILE>
<TITLE>dccpclientsrc</TITLE>
GstDCCPClientSrc
<SUBSECTION Standard>
GstDCCPClientSrcClass
GST_DCCP_CLIENT_SRC
GST_DCCP_CLIENT_SRC_CLASS
GST_IS_DCCP_CLIENT_SRC
GST_IS_DCCP_CLIENT_SRC_CLASS
GST_TYPE_DCCP_CLIENT_SRC
gst_dccp_client_src_get_type
</SECTION>
<SECTION>
<FILE>element-dccpserversink</FILE>
<TITLE>dccpserversink</TITLE>
GstDCCPServerSink
<SUBSECTION Standard>
GstDCCPServerSinkClass
GST_DCCP_SERVER_SINK
GST_DCCP_SERVER_SINK_CLASS
GST_IS_DCCP_SERVER_SINK
GST_IS_DCCP_SERVER_SINK_CLASS
GST_TYPE_DCCP_SERVER_SINK
gst_dccp_server_sink_get_type
</SECTION>
<SECTION>
<FILE>element-dccpserversrc</FILE>
<TITLE>dccpserversrc</TITLE>
GstDCCPServerSrc
<SUBSECTION Standard>
GstDCCPServerSrcClass
GST_DCCP_SERVER_SRC
GST_DCCP_SERVER_SRC_CLASS
GST_IS_DCCP_SERVER_SRC
GST_IS_DCCP_SERVER_SRC_CLASS
GST_TYPE_DCCP_SERVER_SRC
gst_dccp_server_src_get_type
</SECTION>
<SECTION>
<FILE>element-debugspy</FILE>
<TITLE>debugspy</TITLE>
@ -2817,21 +2761,6 @@ GST_TYPE_NET_SIM
gst_net_sim_get_type
</SECTION>
<SECTION>
<FILE>element-nuvdemux</FILE>
<TITLE>nuvdemux</TITLE>
GstNuvDemux
<SUBSECTION Standard>
GstNuvDemuxClass
GstNuvDemuxState
GST_NUV_DEMUX
GST_NUV_DEMUX_CLASS
GST_IS_NUV_DEMUX
GST_IS_NUV_DEMUX_CLASS
GST_TYPE_NUV_DEMUX
gst_nuv_demux_get_type
</SECTION>
<SECTION>
<FILE>element-neonhttpsrc</FILE>
<TITLE>neonhttpsrc</TITLE>
@ -3296,37 +3225,6 @@ GST_TYPE_RTP_ONVIF_TIMESTAMP
gst_rtp_onvif_timestamp_get_type
</SECTION>
<SECTION>
<FILE>element-sdlaudiosink</FILE>
<TITLE>sdlaudiosink</TITLE>
GstSDLAudioSink
<SUBSECTION Standard>
GstSDLAudioSinkClass
GST_SDLAUDIOSINK
GST_SDLAUDIOSINK_CLASS
GST_IS_SDLAUDIOSINK
GST_IS_SDLAUDIOSINK_CLASS
GST_TYPE_SDLAUDIOSINK
gst_sdlaudio_sink_get_type
<SUBSECTION Private>
gstsdl_semaphore
</SECTION>
<SECTION>
<FILE>element-sdlvideosink</FILE>
<TITLE>sdlvideosink</TITLE>
GstSDLVideoSink
<SUBSECTION Standard>
GstSDLVideoSinkFlags
GstSDLVideoSinkClass
GST_SDLVIDEOSINK
GST_SDLVIDEOSINK_CLASS
GST_IS_SDLVIDEOSINK
GST_IS_SDLVIDEOSINK_CLASS
GST_TYPE_SDLVIDEOSINK
gst_sdlvideosink_get_type
</SECTION>
<SECTION>
<FILE>element-sdpdemux</FILE>
<TITLE>sdpdemux</TITLE>
@ -3841,20 +3739,6 @@ GST_TYPE_TONE_GENERATE_SRC
gst_tone_generate_src_get_type
</SECTION>
<SECTION>
<FILE>element-timidity</FILE>
<TITLE>timidity</TITLE>
GstTimidity
<SUBSECTION Standard>
GstTimidityClass
GST_TIMIDITY
GST_TIMIDITY_CLASS
GST_IS_TIMIDITY
GST_IS_TIMIDITY_CLASS
GST_TYPE_TIMIDITY
gst_timidity_get_type
</SECTION>
<SECTION>
<FILE>element-tunnel</FILE>
<TITLE>tunnel</TITLE>

View file

@ -32,38 +32,6 @@ gint64 arg2
gint64 arg3
</SIGNAL>
<SIGNAL>
<NAME>GstDCCPClientSrc::connected</NAME>
<RETURNS>void</RETURNS>
<FLAGS>f</FLAGS>
GstDCCPClientSrc *gstdccpclientsrc
gint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstDCCPServerSink::connected</NAME>
<RETURNS>void</RETURNS>
<FLAGS>f</FLAGS>
GstDCCPServerSink *gstdccpserversink
gint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstDCCPClientSink::connected</NAME>
<RETURNS>void</RETURNS>
<FLAGS>f</FLAGS>
GstDCCPClientSink *gstdccpclientsink
gint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstDCCPServerSrc::connected</NAME>
<RETURNS>void</RETURNS>
<FLAGS>f</FLAGS>
GstDCCPServerSrc *gstdccpserversrc
gint arg1
</SIGNAL>
<SIGNAL>
<NAME>GstCameraBin::img-done</NAME>
<RETURNS>gboolean</RETURNS>

View file

@ -10,12 +10,6 @@ else
VOAMRWBENC_DIR =
endif
if USE_APEXSINK
APEXSINK_DIR = apexsink
else
APEXSINK_DIR =
endif
if USE_BS2B
BS2B_DIR=bs2b
else
@ -178,12 +172,6 @@ else
LIBMMS_DIR=
endif
if USE_LIBVISUAL
LIBVISUAL_DIR=libvisual
else
LIBVISUAL_DIR=
endif
if USE_MODPLUG
MODPLUG_DIR=modplug
else
@ -208,12 +196,6 @@ else
MUSEPACK_DIR=
endif
if USE_NAS
NAS_DIR=nas
else
NAS_DIR=
endif
if USE_NEON
NEON_DIR=neon
else
@ -274,18 +256,12 @@ else
RSVG_DIR=
endif
if USE_TIMIDITY
TIMIDITY_DIR=timidity
endif
if USE_WILDMIDI
TIMIDITY_DIR=timidity
WILDMIDI_DIR=wildmidi
endif
if !USE_WILDMIDI
if !USE_TIMIDITY
TIMIDITY_DIR=
endif
WILDMIDI_DIR=
endif
if USE_FLUIDSYNTH
@ -304,12 +280,6 @@ else
SCHRO_DIR=
endif
if USE_SDL
SDL_DIR=sdl
else
SDL_DIR=
endif
if USE_SMOOTHSTREAMING
SMOOTHSTREAMING_DIR = smoothstreaming
else
@ -328,12 +298,6 @@ else
SNDFILE_DIR=
endif
if USE_SNDIO
SNDIO_DIR = sndio
else
SNDIO_DIR =
endif
if USE_SOUNDTOUCH
SOUNDTOUCH_DIR=soundtouch
else
@ -370,12 +334,6 @@ else
TELETEXTDEC_DIR=
endif
if USE_XVID
XVID_DIR=xvid
else
XVID_DIR=
endif
if USE_ZBAR
ZBAR_DIR=zbar
else
@ -434,7 +392,6 @@ SUBDIRS=\
$(VOAACENC_DIR) \
$(ASSRENDER_DIR) \
$(VOAMRWBENC_DIR) \
$(APEXSINK_DIR) \
$(AUDIOFILE_DIR) \
$(BS2B_DIR) \
$(BZ2_DIR) \
@ -463,12 +420,10 @@ SUBDIRS=\
$(LV2_DIR) \
$(LIBDE265_DIR) \
$(LIBMMS_DIR) \
$(LIBVISUAL_DIR) \
$(MODPLUG_DIR) \
$(MPEG2ENC_DIR) \
$(MPLEX_DIR) \
$(MUSEPACK_DIR) \
$(NAS_DIR) \
$(NEON_DIR) \
$(OFA_DIR) \
$(OPENAL_DIR) \
@ -481,19 +436,16 @@ SUBDIRS=\
$(RSVG_DIR) \
$(SBC_DIR) \
$(SCHRO_DIR) \
$(SDL_DIR) \
$(SMOOTHSTREAMING_DIR) \
$(SMOOTHWAVE_DIR) \
$(SNDFILE_DIR) \
$(SNDIO_DIR) \
$(SOUNDTOUCH_DIR) \
$(SPANDSP_DIR) \
$(GME_DIR) \
$(SPC_DIR) \
$(SRTP_DIR) \
$(TELETEXTDEC_DIR) \
$(TIMIDITY_DIR) \
$(XVID_DIR) \
$(WILDMIDI_DIR) \
$(ZBAR_DIR) \
$(RTMP_DIR) \
$(HLS_DIR) \
@ -506,7 +458,6 @@ SUBDIRS=\
DIST_SUBDIRS = \
assrender \
apexsink \
bs2b \
bz2 \
chromaprint \
@ -527,7 +478,6 @@ DIST_SUBDIRS = \
kate \
libde265 \
libmms \
libvisual \
lv2 \
daala \
dts \
@ -538,7 +488,6 @@ DIST_SUBDIRS = \
mpeg2enc \
mplex \
musepack \
nas \
neon \
ofa \
openal \
@ -552,20 +501,17 @@ DIST_SUBDIRS = \
resindvd \
sbc \
schroedinger \
sdl \
smoothstreaming \
sndfile \
sndio \
soundtouch \
spandsp \
spc \
srtp \
gme \
teletextdec \
timidity \
wildmidi \
voaacenc \
voamrwbenc \
xvid \
zbar \
rtmp \
webp \

View file

@ -1,165 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

View file

@ -1,12 +0,0 @@
plugin_LTLIBRARIES = libgstapexsink.la
libgstapexsink_la_SOURCES = gstapexplugin.c gstapexraop.c gstapexsink.c
libgstapexsink_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \
$(GST_BASE_CFLAGS) $(GST_CFLAGS) $(APEXSINK_CFLAGS)
libgstapexsink_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
-lgstaudio-$(GST_API_VERSION) -lgstinterfaces-$(GST_API_VERSION) \
$(GST_BASE_LIBS) $(GST_LIBS) $(APEXSINK_LIBS)
libgstapexsink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstapexsink_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
noinst_HEADERS = gstapexraop.h gstapexsink.h

View file

@ -1,44 +0,0 @@
/* GStreamer AirPort Express Plugin
*
* Copyright (C) 2008 Jérémie Bernard [GRemi] <gremimail@gmail.com>
*
* gstapexpugin.c
*
* 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/gst.h>
#include <gstapexsink.h>
static gboolean
plugin_init (GstPlugin * plugin)
{
return gst_element_register (plugin, GST_APEX_SINK_NAME, GST_RANK_NONE,
GST_TYPE_APEX_SINK);
}
/* plugin export resolution */
GST_PLUGIN_DEFINE
(GST_VERSION_MAJOR,
GST_VERSION_MINOR,
apexsink,
"Apple AirPort Express Plugin",
plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

View file

@ -1,798 +0,0 @@
/* GStreamer - Remote Audio Access Protocol (RAOP) as used in Apple iTunes to stream music to the Airport Express (ApEx) -
*
* RAOP is based on the Real Time Streaming Protocol (RTSP) but with an extra challenge-response RSA based authentication step.
* This interface accepts RAW PCM data and set it as AES encrypted ALAC while performing emission.
*
* Copyright (C) 2008 Jérémie Bernard [GRemi] <gremimail@gmail.com>
*
* gstapexraop.c
*
* 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 "gstapexraop.h"
/* private constants */
#define GST_APEX_RAOP_VOLUME_MIN -144
#define GST_APEX_RAOP_VOLUME_MAX 0
#define GST_APEX_RAOP_HDR_DEFAULT_LENGTH 1024
#define GST_APEX_RAOP_SDP_DEFAULT_LENGTH 2048
const static gchar GST_APEX_RAOP_RSA_PUBLIC_MOD[] =
"59dE8qLieItsH1WgjrcFRKj6eUWqi+bGLOX1HL3U3GhC/j0Qg90u3sG/1CUtwC"
"5vOYvfDmFI6oSFXi5ELabWJmT2dKHzBJKa3k9ok+8t9ucRqMd6DZHJ2YCCLlDR"
"KSKv6kDqnw4UwPdpOMXziC/AMj3Z/lUVX1G7WSHCAWKf1zNS1eLvqr+boEjXuB"
"OitnZ/bDzPHrTOZz0Dew0uowxf/+sG+NCK3eQJVxqcaJ/vEHKIVd2M+5qL71yJ"
"Q+87X6oV3eaYvt3zWZYD6z5vYTcrtij2VZ9Zmni/UAaHqn9JdsBWLUEpVviYnh"
"imNVvYFZeCXg/IdTQ+x4IRdiXNv5hEew==";
const static gchar GST_APEX_RAOP_RSA_PUBLIC_EXP[] = "AQAB";
const static gchar GST_APEX_RAOP_USER_AGENT[] =
"iTunes/4.6 (Macintosh; U; PPC Mac OS X 10.3)";
const static guchar GST_APEX_RAOP_FRAME_HEADER[] = { // Used by gen. 1
0x24, 0x00, 0x00, 0x00,
0xF0, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
const static int GST_APEX_RAOP_FRAME_HEADER_SIZE = 16; // Used by gen. 1
const static int GST_APEX_RTP_FRAME_HEADER_SIZE = 12; // Used by gen. 2
const static int GST_APEX_RAOP_ALAC_HEADER_SIZE = 3;
/* string extra utility */
static gint
g_strdel (gchar * str, gchar rc)
{
int i = 0, j = 0, len, num = 0;
len = strlen (str);
while (i < len) {
if (str[i] == rc) {
for (j = i; j < len; j++)
str[j] = str[j + 1];
len--;
num++;
} else {
i++;
}
}
return num;
}
/* socket utilities */
static int
gst_apexraop_send (int desc, void *data, size_t len)
{
int total = 0, bytesleft = len, n = 0;
while (total < len) {
n = send (desc, ((const char *) data) + total, bytesleft, 0);
if (n == -1)
break;
total += n;
bytesleft -= n;
}
return n == -1 ? -1 : total;
}
static int
gst_apexraop_recv (int desc, void *data, size_t len)
{
memset (data, 0, len);
return recv (desc, data, len, 0);
}
/* public opaque handle resolution */
typedef struct
{
guchar aes_ky[AES_BLOCK_SIZE]; /* AES random key */
guchar aes_iv[AES_BLOCK_SIZE]; /* AES random initial vector */
guchar url_abspath[16]; /* header url random absolute path addon, ANNOUNCE id */
gint cseq; /* header rtsp inc cseq */
guchar cid[24]; /* header client instance id */
gchar *session; /* header raop negotiated session id, once SETUP performed */
gchar *ua; /* header user agent */
GstApExJackType jack_type; /* APEX connected jack type, once ANNOUNCE performed */
GstApExJackStatus jack_status; /* APEX connected jack status, once ANNOUNCE performed */
GstApExGeneration generation; /* Different devices accept different audio streams */
GstApExTransportProtocol transport_protocol; /* For media stream, not RAOP/RTSP */
gchar *host; /* APEX target ip */
guint ctrl_port; /* APEX target control port */
guint data_port; /* APEX negotiated data port, once SETUP performed */
int ctrl_sd; /* control socket */
struct sockaddr_in ctrl_sd_in;
int data_sd; /* data socket */
struct sockaddr_in data_sd_in;
short rtp_seq_num; /* RTP sequence number, used by gen. 2 */
int rtp_timestamp; /* RTP timestamp, used by gen. 2 */
}
_GstApExRAOP;
/* raop apex struct allocation */
GstApExRAOP *
gst_apexraop_new (const gchar * host,
const guint16 port,
const GstApExGeneration generation,
const GstApExTransportProtocol transport_protocol)
{
_GstApExRAOP *apexraop;
apexraop = (_GstApExRAOP *) g_malloc0 (sizeof (_GstApExRAOP));
apexraop->host = g_strdup (host);
apexraop->ctrl_port = port;
apexraop->ua = g_strdup (GST_APEX_RAOP_USER_AGENT);
apexraop->jack_type = GST_APEX_JACK_TYPE_UNDEFINED;
apexraop->jack_status = GST_APEX_JACK_STATUS_DISCONNECTED;
apexraop->generation = generation;
apexraop->transport_protocol = transport_protocol;
apexraop->rtp_seq_num = 0;
apexraop->rtp_timestamp = 0;
return (GstApExRAOP *) apexraop;
}
/* raop apex struct freeing */
void
gst_apexraop_free (GstApExRAOP * con)
{
_GstApExRAOP *conn;
conn = (_GstApExRAOP *) con;
g_free (conn->host);
g_free (conn->session);
g_free (conn->ua);
g_free (conn);
}
/* host affectation */
void
gst_apexraop_set_host (GstApExRAOP * con, const gchar * host)
{
_GstApExRAOP *conn;
conn = (_GstApExRAOP *) con;
g_free (conn->host);
conn->host = g_strdup (host);
}
/* host reader */
gchar *
gst_apexraop_get_host (GstApExRAOP * con)
{
_GstApExRAOP *conn;
conn = (_GstApExRAOP *) con;
return g_strdup (conn->host);
}
/* control port affectation */
void
gst_apexraop_set_port (GstApExRAOP * con, const guint16 port)
{
_GstApExRAOP *conn;
conn = (_GstApExRAOP *) con;
conn->ctrl_port = port;
}
/* control port reader */
guint16
gst_apexraop_get_port (GstApExRAOP * con)
{
_GstApExRAOP *conn;
conn = (_GstApExRAOP *) con;
return conn->ctrl_port;
}
/* user agent affectation */
void
gst_apexraop_set_useragent (GstApExRAOP * con, const gchar * useragent)
{
_GstApExRAOP *conn;
conn = (_GstApExRAOP *) con;
g_free (conn->ua);
conn->ua = g_strdup (useragent);
}
/* user agent reader */
gchar *
gst_apexraop_get_useragent (GstApExRAOP * con)
{
_GstApExRAOP *conn;
conn = (_GstApExRAOP *) con;
return g_strdup (conn->ua);
}
/* raop apex connection sequence */
GstRTSPStatusCode
gst_apexraop_connect (GstApExRAOP * con)
{
gchar *ac, *ky, *iv, *s, inaddr[INET_ADDRSTRLEN],
creq[GST_APEX_RAOP_SDP_DEFAULT_LENGTH],
hreq[GST_APEX_RAOP_HDR_DEFAULT_LENGTH], *req;
RSA *rsa;
guchar *mod, *exp, rsakey[512];
union gst_randbytes
{
struct asvals
{
guint32 url_key;
guint64 conn_id;
guchar challenge[16];
} v;
guchar buf[4 + 8 + 16];
} randbuf;
gsize size;
struct sockaddr_in ioaddr;
socklen_t iolen;
GstRTSPStatusCode res;
_GstApExRAOP *conn;
conn = (_GstApExRAOP *) con;
if ((conn->ctrl_sd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
return GST_RTSP_STS_DESTINATION_UNREACHABLE;
conn->ctrl_sd_in.sin_family = AF_INET;
conn->ctrl_sd_in.sin_port = htons (conn->ctrl_port);
if (!inet_aton (conn->host, &conn->ctrl_sd_in.sin_addr)) {
struct hostent *hp = (struct hostent *) gethostbyname (conn->host);
if (hp == NULL)
return GST_RTSP_STS_DESTINATION_UNREACHABLE;
memcpy (&conn->ctrl_sd_in.sin_addr, hp->h_addr, hp->h_length);
}
if (connect (conn->ctrl_sd, (struct sockaddr *) &conn->ctrl_sd_in,
sizeof (conn->ctrl_sd_in)) < 0)
return GST_RTSP_STS_DESTINATION_UNREACHABLE;
RAND_bytes (randbuf.buf, sizeof (randbuf));
sprintf ((gchar *) conn->url_abspath, "%u", randbuf.v.url_key);
sprintf ((char *) conn->cid, "%16" G_GINT64_MODIFIER "x", randbuf.v.conn_id);
RAND_bytes (conn->aes_ky, AES_BLOCK_SIZE);
RAND_bytes (conn->aes_iv, AES_BLOCK_SIZE);
rsa = RSA_new ();
mod = g_base64_decode (GST_APEX_RAOP_RSA_PUBLIC_MOD, &size);
rsa->n = BN_bin2bn (mod, size, NULL);
exp = g_base64_decode (GST_APEX_RAOP_RSA_PUBLIC_EXP, &size);
rsa->e = BN_bin2bn (exp, size, NULL);
size =
RSA_public_encrypt (AES_BLOCK_SIZE, conn->aes_ky, rsakey, rsa,
RSA_PKCS1_OAEP_PADDING);
ky = g_base64_encode (rsakey, size);
iv = g_base64_encode (conn->aes_iv, AES_BLOCK_SIZE);
g_strdel (ky, '=');
g_strdel (iv, '=');
iolen = sizeof (struct sockaddr);
getsockname (conn->ctrl_sd, (struct sockaddr *) &ioaddr, &iolen);
inet_ntop (AF_INET, &(ioaddr.sin_addr), inaddr, INET_ADDRSTRLEN);
ac = g_base64_encode (randbuf.v.challenge, 16);
g_strdel (ac, '=');
sprintf (creq,
"v=0\r\n"
"o=iTunes %s 0 IN IP4 %s\r\n"
"s=iTunes\r\n"
"c=IN IP4 %s\r\n"
"t=0 0\r\n"
"m=audio 0 RTP/AVP 96\r\n"
"a=rtpmap:96 AppleLossless\r\n"
"a=fmtp:96 %d 0 %d 40 10 14 %d 255 0 0 %d\r\n"
"a=rsaaeskey:%s\r\n"
"a=aesiv:%s\r\n",
conn->url_abspath,
inaddr,
conn->host,
conn->generation == GST_APEX_GENERATION_ONE
? GST_APEX_RAOP_V1_SAMPLES_PER_FRAME
: GST_APEX_RAOP_V2_SAMPLES_PER_FRAME,
GST_APEX_RAOP_BYTES_PER_CHANNEL * 8,
GST_APEX_RAOP_CHANNELS, GST_APEX_RAOP_BITRATE, ky, iv);
sprintf (hreq,
"ANNOUNCE rtsp://%s/%s RTSP/1.0\r\n"
"CSeq: %d\r\n"
"Client-Instance: %s\r\n"
"User-Agent: %s\r\n"
"Content-Type: application/sdp\r\n"
"Content-Length: %u\r\n"
"Apple-Challenge: %s\r\n",
conn->host,
conn->url_abspath, ++conn->cseq, conn->cid, conn->ua,
(guint) strlen (creq), ac);
RSA_free (rsa);
g_free (ky);
g_free (iv);
g_free (ac);
g_free (mod);
g_free (exp);
req = g_strconcat (hreq, "\r\n", creq, NULL);
if (gst_apexraop_send (conn->ctrl_sd, req, strlen (req)) <= 0) {
g_free (req);
return GST_RTSP_STS_GONE;
}
g_free (req);
if (gst_apexraop_recv (conn->ctrl_sd, hreq,
GST_APEX_RAOP_HDR_DEFAULT_LENGTH) <= 0)
return GST_RTSP_STS_GONE;
{
int tmp;
sscanf (hreq, "%*s %d", &tmp);
res = (GstRTSPStatusCode) tmp;
}
if (res != GST_RTSP_STS_OK)
return res;
s = g_strrstr (hreq, "Audio-Jack-Status");
if (s != NULL) {
gchar status[128];
sscanf (s, "%*s %s", status);
if (strcmp (status, "connected;") == 0)
conn->jack_status = GST_APEX_JACK_STATUS_CONNECTED;
else if (strcmp (status, "disconnected;") == 0)
conn->jack_status = GST_APEX_JACK_STATUS_DISCONNECTED;
else
conn->jack_status = GST_APEX_JACK_STATUS_UNDEFINED;
s = g_strrstr (s, "type=");
if (s != NULL) {
strtok (s, "=");
s = strtok (NULL, "\n");
if (strcmp (s, "analog"))
conn->jack_type = GST_APEX_JACK_TYPE_ANALOG;
else if (strcmp (s, "digital"))
conn->jack_type = GST_APEX_JACK_TYPE_DIGITAL;
else
conn->jack_type = GST_APEX_JACK_TYPE_UNDEFINED;
}
}
sprintf (hreq,
"SETUP rtsp://%s/%s RTSP/1.0\r\n"
"CSeq: %d\r\n"
"Client-Instance: %s\r\n"
"User-Agent: %s\r\n"
"Transport: RTP/AVP/TCP;unicast;interleaved=0-1;mode=record\r\n"
"\r\n", conn->host, conn->url_abspath, ++conn->cseq, conn->cid, conn->ua);
if (gst_apexraop_send (conn->ctrl_sd, hreq, strlen (hreq)) <= 0)
return GST_RTSP_STS_GONE;
if (gst_apexraop_recv (conn->ctrl_sd, hreq,
GST_APEX_RAOP_HDR_DEFAULT_LENGTH) <= 0)
return GST_RTSP_STS_GONE;
{
int tmp;
sscanf (hreq, "%*s %d", &tmp);
res = (GstRTSPStatusCode) tmp;
}
if (res != GST_RTSP_STS_OK)
return res;
s = g_strrstr (hreq, "Session");
if (s != NULL) {
gchar session[128];
sscanf (s, "%*s %s", session);
conn->session = g_strdup (session);
} else
return GST_RTSP_STS_PRECONDITION_FAILED;
s = g_strrstr (hreq, "server_port");
if (s != NULL) {
sscanf (s, "server_port=%d", &conn->data_port);
} else
return GST_RTSP_STS_PRECONDITION_FAILED;
sprintf (hreq,
"RECORD rtsp://%s/%s RTSP/1.0\r\n"
"CSeq: %d\r\n"
"Client-Instance: %s\r\n"
"User-Agent: %s\r\n"
"Session: %s\r\n"
"Range: npt=0-\r\n"
"RTP-Info: seq=0;rtptime=0\r\n"
"\r\n",
conn->host,
conn->url_abspath, ++conn->cseq, conn->cid, conn->ua, conn->session);
if (gst_apexraop_send (conn->ctrl_sd, hreq, strlen (hreq)) <= 0)
return GST_RTSP_STS_GONE;
if (gst_apexraop_recv (conn->ctrl_sd, hreq,
GST_APEX_RAOP_HDR_DEFAULT_LENGTH) <= 0)
return GST_RTSP_STS_GONE;
{
int tmp;
sscanf (hreq, "%*s %d", &tmp);
res = (GstRTSPStatusCode) tmp;
}
if (res != GST_RTSP_STS_OK)
return res;
if (conn->transport_protocol == GST_APEX_TCP) {
if ((conn->data_sd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
return GST_RTSP_STS_DESTINATION_UNREACHABLE;
} else if (conn->transport_protocol == GST_APEX_UDP) {
if ((conn->data_sd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
return GST_RTSP_STS_DESTINATION_UNREACHABLE;
} else
return GST_RTSP_STS_METHOD_NOT_ALLOWED;
conn->data_sd_in.sin_family = AF_INET;
conn->data_sd_in.sin_port = htons (conn->data_port);
memcpy (&conn->data_sd_in.sin_addr, &conn->ctrl_sd_in.sin_addr,
sizeof (conn->ctrl_sd_in.sin_addr));
if (connect (conn->data_sd, (struct sockaddr *) &conn->data_sd_in,
sizeof (conn->data_sd_in)) < 0)
return GST_RTSP_STS_DESTINATION_UNREACHABLE;
return res;
}
/* raop apex jack type access */
GstApExJackType
gst_apexraop_get_jacktype (GstApExRAOP * con)
{
_GstApExRAOP *conn;
conn = (_GstApExRAOP *) con;
if (!conn)
return GST_APEX_JACK_TYPE_UNDEFINED;
return conn->jack_type;
}
/* raop apex jack status access */
GstApExJackStatus
gst_apexraop_get_jackstatus (GstApExRAOP * con)
{
_GstApExRAOP *conn;
conn = (_GstApExRAOP *) con;
if (!conn)
return GST_APEX_JACK_STATUS_UNDEFINED;
return conn->jack_status;
}
/* raop apex generation access */
GstApExGeneration
gst_apexraop_get_generation (GstApExRAOP * con)
{
_GstApExRAOP *conn;
conn = (_GstApExRAOP *) con;
if (!conn)
return GST_APEX_GENERATION_ONE;
return conn->generation;
}
/* raop apex transport protocol access */
GstApExTransportProtocol
gst_apexraop_get_transport_protocol (GstApExRAOP * con)
{
_GstApExRAOP *conn;
conn = (_GstApExRAOP *) con;
if (!conn)
return GST_APEX_TCP;
return conn->transport_protocol;
}
/* raop apex sockets close */
void
gst_apexraop_close (GstApExRAOP * con)
{
gchar hreq[GST_APEX_RAOP_HDR_DEFAULT_LENGTH];
_GstApExRAOP *conn;
conn = (_GstApExRAOP *) con;
sprintf (hreq,
"TEARDOWN rtsp://%s/%s RTSP/1.0\r\n"
"CSeq: %d\r\n"
"Client-Instance: %s\r\n"
"User-Agent: %s\r\n"
"Session: %s\r\n"
"\r\n",
conn->host,
conn->url_abspath, ++conn->cseq, conn->cid, conn->ua, conn->session);
gst_apexraop_send (conn->ctrl_sd, hreq, strlen (hreq));
gst_apexraop_recv (conn->ctrl_sd, hreq, GST_APEX_RAOP_HDR_DEFAULT_LENGTH);
if (conn->ctrl_sd != 0)
close (conn->ctrl_sd);
if (conn->data_sd != 0)
close (conn->data_sd);
}
/* raop apex volume set */
GstRTSPStatusCode
gst_apexraop_set_volume (GstApExRAOP * con, const guint volume)
{
gint v;
gchar creq[GST_APEX_RAOP_SDP_DEFAULT_LENGTH],
hreq[GST_APEX_RAOP_HDR_DEFAULT_LENGTH], *req, vol[128];
GstRTSPStatusCode res;
_GstApExRAOP *conn;
conn = (_GstApExRAOP *) con;
v = GST_APEX_RAOP_VOLUME_MIN + (GST_APEX_RAOP_VOLUME_MAX -
GST_APEX_RAOP_VOLUME_MIN) * volume / 100.;
sprintf (vol, "volume: %d.000000\r\n", v);
sprintf (creq, "%s\r\n", vol);
sprintf (hreq,
"SET_PARAMETER rtsp://%s/%s RTSP/1.0\r\n"
"CSeq: %d\r\n"
"Client-Instance: %s\r\n"
"User-Agent: %s\r\n"
"Session: %s\r\n"
"Content-Type: text/parameters\r\n"
"Content-Length: %u\r\n",
conn->host,
conn->url_abspath,
++conn->cseq, conn->cid, conn->ua, conn->session, (guint) strlen (creq)
);
req = g_strconcat (hreq, "\r\n", creq, NULL);
if (gst_apexraop_send (conn->ctrl_sd, req, strlen (req)) <= 0) {
g_free (req);
return GST_RTSP_STS_GONE;
}
g_free (req);
if (gst_apexraop_recv (conn->ctrl_sd, hreq,
GST_APEX_RAOP_HDR_DEFAULT_LENGTH) <= 0)
return GST_RTSP_STS_GONE;
{
int tmp;
sscanf (hreq, "%*s %d", &tmp);
res = (GstRTSPStatusCode) tmp;
}
return res;
}
/* raop apex raw data alac encapsulation, encryption and emission, http://wiki.multimedia.cx/index.php?title=Apple_Lossless_Audio_Coding */
static void inline
gst_apexraop_write_bits (guchar * buffer, int data, int numbits,
int *bit_offset, int *byte_offset)
{
const static guchar masks[] =
{ 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };
if (((*bit_offset) != 0) && (((*bit_offset) + numbits) > 8)) {
gint numwritebits;
guchar bitstowrite;
numwritebits = 8 - (*bit_offset);
bitstowrite =
(guchar) ((data >> (numbits - numwritebits)) << (8 - (*bit_offset) -
numwritebits));
buffer[(*byte_offset)] |= bitstowrite;
numbits -= numwritebits;
(*bit_offset) = 0;
(*byte_offset)++;
}
while (numbits >= 8) {
guchar bitstowrite;
bitstowrite = (guchar) ((data >> (numbits - 8)) & 0xFF);
buffer[(*byte_offset)] |= bitstowrite;
numbits -= 8;
(*bit_offset) = 0;
(*byte_offset)++;
}
if (numbits > 0) {
guchar bitstowrite;
bitstowrite =
(guchar) ((data & masks[numbits]) << (8 - (*bit_offset) - numbits));
buffer[(*byte_offset)] |= bitstowrite;
(*bit_offset) += numbits;
if ((*bit_offset) == 8) {
(*byte_offset)++;
(*bit_offset) = 0;
}
}
}
guint
gst_apexraop_write (GstApExRAOP * con, gpointer rawdata, guint length)
{
guchar *buffer, *frame_data;
gushort len;
gint bit_offset, byte_offset, i, out_len, res;
EVP_CIPHER_CTX aes_ctx;
_GstApExRAOP *conn = (_GstApExRAOP *) con;
const int frame_header_size = conn->generation == GST_APEX_GENERATION_ONE
? GST_APEX_RAOP_FRAME_HEADER_SIZE : GST_APEX_RTP_FRAME_HEADER_SIZE;
buffer =
(guchar *) g_malloc0 (frame_header_size +
GST_APEX_RAOP_ALAC_HEADER_SIZE + length);
if (conn->generation == GST_APEX_GENERATION_ONE) {
g_assert (frame_header_size == GST_APEX_RAOP_FRAME_HEADER_SIZE);
memcpy (buffer, GST_APEX_RAOP_FRAME_HEADER, frame_header_size);
len = length + frame_header_size + GST_APEX_RAOP_ALAC_HEADER_SIZE - 4;
buffer[2] = len >> 8;
buffer[3] = len & 0xff;
} else {
/* Gen. 2 uses RTP-like header (RFC 3550). */
short network_seq_num;
int network_timestamp, unknown_const;
static gboolean first = TRUE;
buffer[0] = 0x80;
if (first) {
buffer[1] = 0xe0;
first = FALSE;
} else
buffer[1] = 0x60;
network_seq_num = htons (conn->rtp_seq_num++);
memcpy (buffer + 2, &network_seq_num, 2);
network_timestamp = htons (conn->rtp_timestamp);
memcpy (buffer + 4, &network_timestamp, 4);
conn->rtp_timestamp += GST_APEX_RAOP_V2_SAMPLES_PER_FRAME;
unknown_const = 0xdeadbeef;
memcpy (buffer + 8, &unknown_const, 4);
}
bit_offset = 0;
byte_offset = 0;
frame_data = buffer + frame_header_size;
gst_apexraop_write_bits (frame_data, 1, 3, &bit_offset, &byte_offset); /* channels, 0 mono, 1 stereo */
gst_apexraop_write_bits (frame_data, 0, 4, &bit_offset, &byte_offset); /* unknown */
gst_apexraop_write_bits (frame_data, 0, 8, &bit_offset, &byte_offset); /* unknown (12 bits) */
gst_apexraop_write_bits (frame_data, 0, 4, &bit_offset, &byte_offset);
gst_apexraop_write_bits (frame_data, 0, 1, &bit_offset, &byte_offset); /* has size flag */
gst_apexraop_write_bits (frame_data, 0, 2, &bit_offset, &byte_offset); /* unknown */
gst_apexraop_write_bits (frame_data, 1, 1, &bit_offset, &byte_offset); /* no compression flag */
for (i = 0; i < length; i += 2) {
gst_apexraop_write_bits (frame_data, ((guchar *) rawdata)[i + 1], 8,
&bit_offset, &byte_offset);
gst_apexraop_write_bits (frame_data, ((guchar *) rawdata)[i], 8,
&bit_offset, &byte_offset);
}
EVP_CIPHER_CTX_init (&aes_ctx);
EVP_CipherInit_ex (&aes_ctx, EVP_aes_128_cbc (), NULL, conn->aes_ky,
conn->aes_iv, AES_ENCRYPT);
EVP_CipherUpdate (&aes_ctx, frame_data, &out_len, frame_data, /*( */
GST_APEX_RAOP_ALAC_HEADER_SIZE +
length /*) / AES_BLOCK_SIZE * AES_BLOCK_SIZE */ );
EVP_CIPHER_CTX_cleanup (&aes_ctx);
res =
gst_apexraop_send (conn->data_sd, buffer,
frame_header_size + GST_APEX_RAOP_ALAC_HEADER_SIZE + length);
g_free (buffer);
return (guint) ((res >=
(frame_header_size +
GST_APEX_RAOP_ALAC_HEADER_SIZE)) ? (res -
frame_header_size - GST_APEX_RAOP_ALAC_HEADER_SIZE) : 0);
}
/* raop apex buffer flush */
GstRTSPStatusCode
gst_apexraop_flush (GstApExRAOP * con)
{
gchar hreq[GST_APEX_RAOP_HDR_DEFAULT_LENGTH];
GstRTSPStatusCode res;
_GstApExRAOP *conn;
conn = (_GstApExRAOP *) con;
sprintf (hreq,
"FLUSH rtsp://%s/%s RTSP/1.0\r\n"
"CSeq: %d\r\n"
"Client-Instance: %s\r\n"
"User-Agent: %s\r\n"
"Session: %s\r\n"
"RTP-Info: seq=%d;rtptime=%d\r\n"
"\r\n",
conn->host,
conn->url_abspath,
++conn->cseq,
conn->cid,
conn->ua, conn->session, conn->rtp_seq_num, conn->rtp_timestamp);
if (gst_apexraop_send (conn->ctrl_sd, hreq, strlen (hreq)) <= 0)
return GST_RTSP_STS_GONE;
if (gst_apexraop_recv (conn->ctrl_sd, hreq,
GST_APEX_RAOP_HDR_DEFAULT_LENGTH) <= 0)
return GST_RTSP_STS_GONE;
{
int tmp;
sscanf (hreq, "%*s %d", &tmp);
res = (GstRTSPStatusCode) tmp;
}
return res;
}

View file

@ -1,148 +0,0 @@
/* GStreamer - Remote Audio Access Protocol (RAOP) as used in Apple iTunes to stream music to the Airport Express (ApEx) -
*
* RAOP is based on the Real Time Streaming Protocol (RTSP) but with an extra challenge-response RSA based authentication step.
* This interface accepts RAW PCM data and set it as AES encrypted ALAC while performing emission.
*
* Copyright (C) 2008 Jérémie Bernard [GRemi] <gremimail@gmail.com>
*
* gstapexraop.h
*
* 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_APEXRAOP_H__
#define __GST_APEXRAOP_H__
#include <gst/gst.h>
#include <gst/rtsp/gstrtspdefs.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
G_BEGIN_DECLS
/* raop fixed parameters */
#define GST_APEX_RAOP_BITRATE 44100
#define GST_APEX_RAOP_V1_SAMPLES_PER_FRAME 4096
#define GST_APEX_RAOP_V2_SAMPLES_PER_FRAME 352
#define GST_APEX_RAOP_BYTES_PER_CHANNEL 2
#define GST_APEX_RAOP_CHANNELS 2
#define GST_APEX_RAOP_BYTES_PER_SAMPLE (GST_APEX_RAOP_CHANNELS * GST_APEX_RAOP_BYTES_PER_CHANNEL)
/* gst associated caps fields specification */
#define GST_APEX_RAOP_INPUT_TYPE "audio/x-raw-int"
#define GST_APEX_RAOP_INPUT_WIDTH "16"
#define GST_APEX_RAOP_INPUT_DEPTH GST_APEX_RAOP_INPUT_WIDTH
#define GST_APEX_RAOP_INPUT_ENDIAN "LITTLE_ENDIAN"
#define GST_APEX_RAOP_INPUT_CHANNELS "2"
#define GST_APEX_RAOP_INPUT_BIT_RATE "44100"
#define GST_APEX_RAOP_INPUT_SIGNED "TRUE"
typedef enum
{
GST_APEX_JACK_TYPE_UNDEFINED = 0,
GST_APEX_JACK_TYPE_ANALOG,
GST_APEX_JACK_TYPE_DIGITAL,
}
GstApExJackType;
typedef enum
{
GST_APEX_JACK_STATUS_UNDEFINED = 0,
GST_APEX_JACK_STATUS_DISCONNECTED,
GST_APEX_JACK_STATUS_CONNECTED,
}
GstApExJackStatus;
typedef enum
{
GST_APEX_GENERATION_ONE = 1,
GST_APEX_GENERATION_TWO,
}
GstApExGeneration;
typedef enum
{
GST_APEX_TCP = 0,
GST_APEX_UDP,
}
GstApExTransportProtocol;
/* raop context handle */
typedef struct
{
} GstApExRAOP;
/* host might be null and port might be 0 while instanciating */
GstApExRAOP *gst_apexraop_new (const gchar * host,
const guint16 port,
const GstApExGeneration generation,
const GstApExTransportProtocol transport_protocol);
void gst_apexraop_free (GstApExRAOP * conn);
/* must not be connected yet while setting the host target */
void gst_apexraop_set_host (GstApExRAOP * conn, const gchar * host);
gchar *gst_apexraop_get_host (GstApExRAOP * conn);
/* must not be connected yet while setting the port target */
void gst_apexraop_set_port (GstApExRAOP * conn, const guint16 port);
guint16 gst_apexraop_get_port (GstApExRAOP * conn);
/* optional affectation, default iTunes user agent internaly used */
void gst_apexraop_set_useragent (GstApExRAOP * conn, const gchar * useragent);
gchar *gst_apexraop_get_useragent (GstApExRAOP * conn);
/* once allocation and configuration performed, manages the raop ANNOUNCE, SETUP and RECORD sequences,
* open both ctrl and data channels */
GstRTSPStatusCode gst_apexraop_connect (GstApExRAOP * conn);
/* close the currently used session, manages raop TEARDOWN sequence and closes the used sockets */
void gst_apexraop_close (GstApExRAOP * conn);
/* once connected, set the apex target volume, manages SET_PARAMETER sequence */
GstRTSPStatusCode gst_apexraop_set_volume (GstApExRAOP * conn,
const guint volume);
/* write raw samples typed as defined by the fixed raop parameters, flush the apex buffer */
guint gst_apexraop_write (GstApExRAOP * conn, gpointer rawdata, guint length);
GstRTSPStatusCode gst_apexraop_flush (GstApExRAOP * conn);
/* retrieve the connected apex jack type and status */
GstApExJackType gst_apexraop_get_jacktype (GstApExRAOP * conn);
GstApExJackStatus gst_apexraop_get_jackstatus (GstApExRAOP * conn);
/* retrieve the generation */
GstApExGeneration gst_apexraop_get_generation (GstApExRAOP * conn);
/* retrieve the transport protocol */
GstApExTransportProtocol gst_apexraop_get_transport_protocol (GstApExRAOP * conn);
G_END_DECLS
#endif

View file

@ -1,665 +0,0 @@
/* GStreamer - AirPort Express Audio Sink -
*
* Remote Audio Access Protocol (RAOP) as used in Apple iTunes to stream music to the Airport Express (ApEx) -
* RAOP is based on the Real Time Streaming Protocol (RTSP) but with an extra challenge-response RSA based authentication step.
*
* RAW PCM input only as defined by the following GST_STATIC_PAD_TEMPLATE
*
* Copyright (C) 2008 Jérémie Bernard [GRemi] <gremimail@gmail.com>
*
* gstapexsink.c
*
* 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 "gstapexsink.h"
GST_DEBUG_CATEGORY_STATIC (apexsink_debug);
#define GST_CAT_DEFAULT apexsink_debug
static GstStaticPadTemplate gst_apexsink_sink_factory = GST_STATIC_PAD_TEMPLATE
("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS
(GST_APEX_RAOP_INPUT_TYPE ","
"width = (int) " GST_APEX_RAOP_INPUT_WIDTH ","
"depth = (int) " GST_APEX_RAOP_INPUT_DEPTH ","
"endianness = (int) " GST_APEX_RAOP_INPUT_ENDIAN ","
"channels = (int) " GST_APEX_RAOP_INPUT_CHANNELS ","
"rate = (int) " GST_APEX_RAOP_INPUT_BIT_RATE ","
"signed = (boolean) " GST_APEX_RAOP_INPUT_SIGNED)
);
enum
{
APEX_PROP_HOST = 1,
APEX_PROP_PORT,
APEX_PROP_VOLUME,
APEX_PROP_JACK_TYPE,
APEX_PROP_JACK_STATUS,
APEX_PROP_GENERATION,
APEX_PROP_TRANSPORT_PROTOCOL,
};
#define DEFAULT_APEX_HOST ""
#define DEFAULT_APEX_PORT 5000
#define DEFAULT_APEX_VOLUME 1.0
#define DEFAULT_APEX_JACK_TYPE GST_APEX_JACK_TYPE_UNDEFINED
#define DEFAULT_APEX_JACK_STATUS GST_APEX_JACK_STATUS_UNDEFINED
#define DEFAULT_APEX_GENERATION GST_APEX_GENERATION_ONE
#define DEFAULT_APEX_TRANSPORT_PROTOCOL GST_APEX_TCP
/* genum apex jack resolution */
GType
gst_apexsink_jackstatus_get_type (void)
{
static GType jackstatus_type = 0;
static const GEnumValue jackstatus[] = {
{GST_APEX_JACK_STATUS_UNDEFINED, "GST_APEX_JACK_STATUS_UNDEFINED",
"Jack status undefined"},
{GST_APEX_JACK_STATUS_DISCONNECTED, "GST_APEX_JACK_STATUS_DISCONNECTED",
"Jack disconnected"},
{GST_APEX_JACK_STATUS_CONNECTED, "GST_APEX_JACK_STATUS_CONNECTED",
"Jack connected"},
{0, NULL, NULL},
};
if (!jackstatus_type) {
jackstatus_type = g_enum_register_static ("GstApExJackStatus", jackstatus);
}
return jackstatus_type;
}
GType
gst_apexsink_jacktype_get_type (void)
{
static GType jacktype_type = 0;
static const GEnumValue jacktype[] = {
{GST_APEX_JACK_TYPE_UNDEFINED, "GST_APEX_JACK_TYPE_UNDEFINED",
"Undefined jack type"},
{GST_APEX_JACK_TYPE_ANALOG, "GST_APEX_JACK_TYPE_ANALOG", "Analog jack"},
{GST_APEX_JACK_TYPE_DIGITAL, "GST_APEX_JACK_TYPE_DIGITAL", "Digital jack"},
{0, NULL, NULL},
};
if (!jacktype_type) {
jacktype_type = g_enum_register_static ("GstApExJackType", jacktype);
}
return jacktype_type;
}
GType
gst_apexsink_generation_get_type (void)
{
static GType generation_type = 0;
static const GEnumValue generation[] = {
{GST_APEX_GENERATION_ONE, "generation-one",
"First generation (e.g., original AirPort Express)"},
{GST_APEX_GENERATION_TWO, "generation-two",
"Second generation (e.g., Apple TV v2)"},
{0, NULL, NULL},
};
if (!generation_type) {
generation_type = g_enum_register_static ("GstApExGeneration", generation);
}
return generation_type;
}
GType
gst_apexsink_transport_protocol_get_type (void)
{
static GType transport_protocol_type = 0;
static const GEnumValue transport_protocol[] = {
{GST_APEX_TCP, "tcp", "TCP"},
{GST_APEX_UDP, "udp", "UDP"},
{0, NULL, NULL},
};
if (!transport_protocol_type) {
transport_protocol_type =
g_enum_register_static ("GstApExTransportProtocol", transport_protocol);
}
return transport_protocol_type;
}
static void gst_apexsink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_apexsink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_apexsink_finalise (GObject * object);
static gboolean gst_apexsink_open (GstAudioSink * asink);
static gboolean gst_apexsink_prepare (GstAudioSink * asink,
GstRingBufferSpec * spec);
static guint gst_apexsink_write (GstAudioSink * asink, gpointer data,
guint length);
static gboolean gst_apexsink_unprepare (GstAudioSink * asink);
static guint gst_apexsink_delay (GstAudioSink * asink);
static void gst_apexsink_reset (GstAudioSink * asink);
static gboolean gst_apexsink_close (GstAudioSink * asink);
static GstStateChangeReturn gst_apexsink_change_state (GstElement * element,
GstStateChange transition);
/* mixer interface standard api */
static void gst_apexsink_interfaces_init (GType type);
static void gst_apexsink_implements_interface_init (GstImplementsInterfaceClass
* iface);
static void gst_apexsink_mixer_interface_init (GstMixerInterface * iface);
static gboolean gst_apexsink_interface_supported (GstImplementsInterface *
iface, GType iface_type);
static const GList *gst_apexsink_mixer_list_tracks (GstMixer * mixer);
static void gst_apexsink_mixer_set_volume (GstMixer * mixer,
GstMixerTrack * track, gint * volumes);
static void gst_apexsink_mixer_get_volume (GstMixer * mixer,
GstMixerTrack * track, gint * volumes);
GST_BOILERPLATE_FULL (GstApExSink, gst_apexsink, GstAudioSink,
GST_TYPE_AUDIO_SINK, gst_apexsink_interfaces_init);
/* apex sink interface(s) stuff */
static void
gst_apexsink_interfaces_init (GType type)
{
static const GInterfaceInfo implements_interface_info =
{ (GInterfaceInitFunc) gst_apexsink_implements_interface_init, NULL,
NULL
};
static const GInterfaceInfo mixer_interface_info =
{ (GInterfaceInitFunc) gst_apexsink_mixer_interface_init, NULL, NULL };
g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,
&implements_interface_info);
g_type_add_interface_static (type, GST_TYPE_MIXER, &mixer_interface_info);
}
static void
gst_apexsink_implements_interface_init (GstImplementsInterfaceClass * iface)
{
iface->supported = gst_apexsink_interface_supported;
}
static void
gst_apexsink_mixer_interface_init (GstMixerInterface * iface)
{
GST_MIXER_TYPE (iface) = GST_MIXER_SOFTWARE;
iface->list_tracks = gst_apexsink_mixer_list_tracks;
iface->set_volume = gst_apexsink_mixer_set_volume;
iface->get_volume = gst_apexsink_mixer_get_volume;
}
static gboolean
gst_apexsink_interface_supported (GstImplementsInterface * iface,
GType iface_type)
{
g_return_val_if_fail (iface_type == GST_TYPE_MIXER, FALSE);
return TRUE;
}
static const GList *
gst_apexsink_mixer_list_tracks (GstMixer * mixer)
{
GstApExSink *apexsink = GST_APEX_SINK (mixer);
return apexsink->tracks;
}
static void
gst_apexsink_mixer_set_volume (GstMixer * mixer, GstMixerTrack * track,
gint * volumes)
{
GstApExSink *apexsink = GST_APEX_SINK (mixer);
apexsink->volume = volumes[0];
if (apexsink->gst_apexraop != NULL)
gst_apexraop_set_volume (apexsink->gst_apexraop, apexsink->volume);
}
static void
gst_apexsink_mixer_get_volume (GstMixer * mixer, GstMixerTrack * track,
gint * volumes)
{
GstApExSink *apexsink = GST_APEX_SINK (mixer);
volumes[0] = apexsink->volume;
}
/* sink base init */
static void
gst_apexsink_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_set_static_metadata (element_class,
"Apple AirPort Express Audio Sink", "Sink/Audio/Wireless",
"Output stream to an AirPort Express",
"Jérémie Bernard [GRemi] <gremimail@gmail.com>");
gst_element_class_add_static_pad_template (element_class,
&gst_apexsink_sink_factory);
}
/* sink class init */
static void
gst_apexsink_class_init (GstApExSinkClass * klass)
{
GST_DEBUG_CATEGORY_INIT (apexsink_debug, GST_APEX_SINK_NAME, 0,
"AirPort Express sink");
parent_class = g_type_class_peek_parent (klass);
((GObjectClass *) klass)->get_property =
GST_DEBUG_FUNCPTR (gst_apexsink_get_property);
((GObjectClass *) klass)->set_property =
GST_DEBUG_FUNCPTR (gst_apexsink_set_property);
((GObjectClass *) klass)->finalize =
GST_DEBUG_FUNCPTR (gst_apexsink_finalise);
((GstAudioSinkClass *) klass)->open = GST_DEBUG_FUNCPTR (gst_apexsink_open);
((GstAudioSinkClass *) klass)->prepare =
GST_DEBUG_FUNCPTR (gst_apexsink_prepare);
((GstAudioSinkClass *) klass)->write = GST_DEBUG_FUNCPTR (gst_apexsink_write);
((GstAudioSinkClass *) klass)->unprepare =
GST_DEBUG_FUNCPTR (gst_apexsink_unprepare);
((GstAudioSinkClass *) klass)->delay = GST_DEBUG_FUNCPTR (gst_apexsink_delay);
((GstAudioSinkClass *) klass)->reset = GST_DEBUG_FUNCPTR (gst_apexsink_reset);
((GstAudioSinkClass *) klass)->close = GST_DEBUG_FUNCPTR (gst_apexsink_close);
((GstElementClass *) klass)->change_state =
GST_DEBUG_FUNCPTR (gst_apexsink_change_state);
g_object_class_install_property ((GObjectClass *) klass, APEX_PROP_HOST,
g_param_spec_string ("host", "Host", "AirPort Express target host",
DEFAULT_APEX_HOST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property ((GObjectClass *) klass, APEX_PROP_PORT,
g_param_spec_uint ("port", "Port", "AirPort Express target port", 0,
32000, DEFAULT_APEX_PORT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/* we need to expose the volume as a double for playbin. Internally we keep
* it as an int between 0 and 100, where 75 corresponds to 1.0.
* FIXME we should store the volume as a double. */
g_object_class_install_property ((GObjectClass *) klass, APEX_PROP_VOLUME,
g_param_spec_double ("volume", "Volume", "AirPort Express target volume",
0.0, 10.0, DEFAULT_APEX_VOLUME,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property ((GObjectClass *) klass, APEX_PROP_JACK_TYPE,
g_param_spec_enum ("jack-type", "Jack Type",
"AirPort Express connected jack type", GST_APEX_SINK_JACKTYPE_TYPE,
DEFAULT_APEX_JACK_TYPE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property ((GObjectClass *) klass,
APEX_PROP_JACK_STATUS, g_param_spec_enum ("jack-status", "Jack Status",
"AirPort Express jack connection status",
GST_APEX_SINK_JACKSTATUS_TYPE, DEFAULT_APEX_JACK_STATUS,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property ((GObjectClass *) klass,
APEX_PROP_GENERATION, g_param_spec_enum ("generation", "Generation",
"AirPort device generation",
GST_APEX_SINK_GENERATION_TYPE, DEFAULT_APEX_GENERATION,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property ((GObjectClass *) klass,
APEX_PROP_TRANSPORT_PROTOCOL, g_param_spec_enum ("transport-protocol",
"Transport Protocol", "AirPort transport protocol",
GST_APEX_SINK_TRANSPORT_PROTOCOL_TYPE,
DEFAULT_APEX_TRANSPORT_PROTOCOL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
/* sink plugin instance init */
static void
gst_apexsink_init (GstApExSink * apexsink, GstApExSinkClass * g_class)
{
GstMixerTrack *track = NULL;
track = g_object_new (GST_TYPE_MIXER_TRACK, NULL);
track->label = g_strdup ("Airport Express");
track->num_channels = GST_APEX_RAOP_CHANNELS;
track->min_volume = 0;
track->max_volume = 100;
track->flags = GST_MIXER_TRACK_OUTPUT;
apexsink->host = g_strdup (DEFAULT_APEX_HOST);
apexsink->port = DEFAULT_APEX_PORT;
apexsink->volume = CLAMP (DEFAULT_APEX_VOLUME * 75, 0, 100);
apexsink->gst_apexraop = NULL;
apexsink->tracks = g_list_append (apexsink->tracks, track);
apexsink->clock = gst_system_clock_obtain ();
apexsink->clock_id = NULL;
GST_INFO_OBJECT (apexsink,
"ApEx sink default initialization, target=\"%s\", port=\"%d\", volume=\"%d%%\"",
apexsink->host, apexsink->port, apexsink->volume);
}
/* apex sink set property */
static void
gst_apexsink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstApExSink *sink = GST_APEX_SINK (object);
switch (prop_id) {
case APEX_PROP_HOST:
if (sink->gst_apexraop == NULL) {
g_free (sink->host);
sink->host = g_value_dup_string (value);
GST_INFO_OBJECT (sink, "ApEx sink target set to \"%s\"", sink->host);
} else {
G_OBJECT_WARN_INVALID_PSPEC (object, "host", prop_id, pspec);
}
break;
case APEX_PROP_PORT:
if (sink->gst_apexraop == NULL) {
sink->port = g_value_get_uint (value);
GST_INFO_OBJECT (sink, "ApEx port set to \"%d\"", sink->port);
} else {
G_OBJECT_WARN_INVALID_PSPEC (object, "port", prop_id, pspec);
}
break;
case APEX_PROP_VOLUME:
{
gdouble volume;
volume = g_value_get_double (value);
volume *= 75.0;
sink->volume = CLAMP (volume, 0, 100);
if (sink->gst_apexraop != NULL)
gst_apexraop_set_volume (sink->gst_apexraop, sink->volume);
GST_INFO_OBJECT (sink, "ApEx volume set to \"%d%%\"", sink->volume);
break;
}
case APEX_PROP_GENERATION:
if (sink->gst_apexraop == NULL) {
sink->generation = g_value_get_enum (value);
GST_INFO_OBJECT (sink, "ApEx generation set to \"%d\"",
sink->generation);
} else {
GST_WARNING_OBJECT (sink,
"SET-PROPERTY : generation property may not be set when apexsink opened !");
}
break;
case APEX_PROP_TRANSPORT_PROTOCOL:
if (sink->gst_apexraop == NULL) {
sink->transport_protocol = g_value_get_enum (value);
GST_INFO_OBJECT (sink, "ApEx transport protocol set to \"%d\"",
sink->transport_protocol);
} else {
GST_WARNING_OBJECT (sink,
"SET-PROPERTY : transport protocol property may not be set when apexsink opened !");
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/* apex sink get property */
static void
gst_apexsink_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstApExSink *sink = GST_APEX_SINK (object);
switch (prop_id) {
case APEX_PROP_HOST:
g_value_set_string (value, sink->host);
break;
case APEX_PROP_PORT:
g_value_set_uint (value, sink->port);
break;
case APEX_PROP_VOLUME:
g_value_set_double (value, ((gdouble) sink->volume) / 75.0);
break;
case APEX_PROP_JACK_TYPE:
g_value_set_enum (value, gst_apexraop_get_jacktype (sink->gst_apexraop));
break;
case APEX_PROP_JACK_STATUS:
g_value_set_enum (value,
gst_apexraop_get_jackstatus (sink->gst_apexraop));
break;
case APEX_PROP_GENERATION:
g_value_set_enum (value,
gst_apexraop_get_generation (sink->gst_apexraop));
break;
case APEX_PROP_TRANSPORT_PROTOCOL:
g_value_set_enum (value,
gst_apexraop_get_transport_protocol (sink->gst_apexraop));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/* apex sink finalize */
static void
gst_apexsink_finalise (GObject * object)
{
GstApExSink *sink = GST_APEX_SINK (object);
if (sink->tracks) {
g_list_foreach (sink->tracks, (GFunc) g_object_unref, NULL);
g_list_free (sink->tracks);
sink->tracks = NULL;
}
gst_object_unref (sink->clock);
g_free (sink->host);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
/* sink open : open the device */
static gboolean
gst_apexsink_open (GstAudioSink * asink)
{
int res;
GstApExSink *apexsink = (GstApExSink *) asink;
apexsink->gst_apexraop = gst_apexraop_new (apexsink->host,
apexsink->port, apexsink->generation, apexsink->transport_protocol);
if ((res = gst_apexraop_connect (apexsink->gst_apexraop)) != GST_RTSP_STS_OK) {
GST_ERROR_OBJECT (apexsink,
"%s : network or RAOP failure, connection refused or timeout, RTSP code=%d",
apexsink->host, res);
return FALSE;
}
GST_INFO_OBJECT (apexsink,
"OPEN : ApEx sink successfully connected to \"%s:%d\", ANNOUNCE, SETUP and RECORD requests performed",
apexsink->host, apexsink->port);
switch (gst_apexraop_get_jackstatus (apexsink->gst_apexraop)) {
case GST_APEX_JACK_STATUS_CONNECTED:
GST_INFO_OBJECT (apexsink, "OPEN : ApEx jack is connected");
break;
case GST_APEX_JACK_STATUS_DISCONNECTED:
GST_WARNING_OBJECT (apexsink, "OPEN : ApEx jack is disconnected !");
break;
default:
GST_WARNING_OBJECT (apexsink, "OPEN : ApEx jack status is undefined !");
break;
}
switch (gst_apexraop_get_jacktype (apexsink->gst_apexraop)) {
case GST_APEX_JACK_TYPE_ANALOG:
GST_INFO_OBJECT (apexsink, "OPEN : ApEx jack type is analog");
break;
case GST_APEX_JACK_TYPE_DIGITAL:
GST_INFO_OBJECT (apexsink, "OPEN : ApEx jack type is digital");
break;
default:
GST_WARNING_OBJECT (apexsink, "OPEN : ApEx jack type is undefined !");
break;
}
if ((res =
gst_apexraop_set_volume (apexsink->gst_apexraop,
apexsink->volume)) != GST_RTSP_STS_OK) {
GST_WARNING_OBJECT (apexsink,
"%s : could not set initial volume to \"%d%%\", RTSP code=%d",
apexsink->host, apexsink->volume, res);
} else {
GST_INFO_OBJECT (apexsink,
"OPEN : ApEx sink successfully set volume to \"%d%%\"",
apexsink->volume);
}
return TRUE;
}
/* prepare sink : configure the device with the specified format */
static gboolean
gst_apexsink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
{
GstApExSink *apexsink = (GstApExSink *) asink;
GstApExGeneration gen = gst_apexraop_get_generation (apexsink->gst_apexraop);
apexsink->latency_time = spec->latency_time;
spec->segsize = gen == GST_APEX_GENERATION_ONE
? GST_APEX_RAOP_V1_SAMPLES_PER_FRAME * GST_APEX_RAOP_BYTES_PER_SAMPLE
: GST_APEX_RAOP_V2_SAMPLES_PER_FRAME * GST_APEX_RAOP_BYTES_PER_SAMPLE;
spec->segtotal = 2;
memset (spec->silence_sample, 0, sizeof (spec->silence_sample));
GST_INFO_OBJECT (apexsink,
"PREPARE : ApEx sink ready to stream at %dHz, %d bytes per sample, %d channels, %d bytes segments (%dkB/s)",
spec->rate, spec->bytes_per_sample, spec->channels, spec->segsize,
spec->rate * spec->bytes_per_sample / 1000);
return TRUE;
}
/* sink write : write samples to the device */
static guint
gst_apexsink_write (GstAudioSink * asink, gpointer data, guint length)
{
guint written;
GstApExSink *apexsink = (GstApExSink *) asink;
if ((written =
gst_apexraop_write (apexsink->gst_apexraop, data,
length)) != length) {
GST_INFO_OBJECT (apexsink,
"WRITE : %d of %d bytes sent, skipping frame samples...", written,
length);
} else {
GST_INFO_OBJECT (apexsink, "WRITE : %d bytes sent", length);
/* NOTE, previous calculation subtracted apexsink->latency_time from this;
* however, the value below is less than apexsink->latency_time for generation 2.
* In this case, the number went negative (actualy wrapped around into a big number).
*/
apexsink->clock_id = gst_clock_new_single_shot_id (apexsink->clock,
(GstClockTime) (gst_clock_get_time (apexsink->clock) +
((length * 1000000000.)
/ (GST_APEX_RAOP_BITRATE * GST_APEX_RAOP_BYTES_PER_SAMPLE))));
gst_clock_id_wait (apexsink->clock_id, NULL);
gst_clock_id_unref (apexsink->clock_id);
apexsink->clock_id = NULL;
}
return length;
}
/* unprepare sink : undo operations done by prepare */
static gboolean
gst_apexsink_unprepare (GstAudioSink * asink)
{
GST_INFO_OBJECT (asink, "UNPREPARE");
return TRUE;
}
/* delay sink : get the estimated number of samples written but not played yet by the device */
static guint
gst_apexsink_delay (GstAudioSink * asink)
{
GST_LOG_OBJECT (asink, "DELAY");
return 0;
}
/* reset sink : unblock writes and flush the device */
static void
gst_apexsink_reset (GstAudioSink * asink)
{
int res;
GstApExSink *apexsink = (GstApExSink *) asink;
GST_INFO_OBJECT (apexsink, "RESET : flushing buffer...");
if ((res = gst_apexraop_flush (apexsink->gst_apexraop)) == GST_RTSP_STS_OK) {
GST_INFO_OBJECT (apexsink, "RESET : ApEx buffer flush success");
} else {
GST_WARNING_OBJECT (apexsink,
"RESET : could not flush ApEx buffer, RTSP code=%d", res);
}
}
/* sink close : close the device */
static gboolean
gst_apexsink_close (GstAudioSink * asink)
{
GstApExSink *apexsink = (GstApExSink *) asink;
gst_apexraop_close (apexsink->gst_apexraop);
gst_apexraop_free (apexsink->gst_apexraop);
GST_INFO_OBJECT (apexsink, "CLOSE : ApEx sink closed connection");
return TRUE;
}
static GstStateChangeReturn
gst_apexsink_change_state (GstElement * element, GstStateChange transition)
{
GstApExSink *apexsink = (GstApExSink *) element;
if (apexsink->clock_id && transition == GST_STATE_CHANGE_PAUSED_TO_READY) {
gst_clock_id_unschedule (apexsink->clock_id);
gst_clock_id_unref (apexsink->clock_id);
apexsink->clock_id = NULL;
}
return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
}

View file

@ -1,98 +0,0 @@
/* GStreamer - AirPort Express (ApEx) Audio Sink -
*
* Remote Audio Access Protocol (RAOP) as used in Apple iTunes to stream music to the Airport Express (ApEx) -
* RAOP is based on the Real Time Streaming Protocol (RTSP) but with an extra challenge-response RSA based authentication step.
*
* RAW PCM input only as defined by the following GST_STATIC_PAD_TEMPLATE regarding the expected gstapexraop input format.
*
* Copyright (C) 2008 Jérémie Bernard [GRemi] <gremimail@gmail.com>
*
* gstapexsink.h
*
* 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_APEXSINK_H__
#define __GST_APEXSINK_H__
#include "gstapexraop.h"
#include <gst/audio/gstaudiosink.h>
#include <gst/interfaces/mixer.h>
G_BEGIN_DECLS
/* standard gstreamer macros */
#define GST_TYPE_APEX_SINK (gst_apexsink_get_type())
#define GST_APEX_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_APEX_SINK,GstApExSink))
#define GST_APEX_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_APEX_SINK,GstApExSinkClass))
#define GST_IS_APEX_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_APEX_SINK))
#define GST_IS_APEX_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_APEX_SINK))
#define GST_APEX_SINK_CAST(obj) ((GstApExSink*)(obj))
#define GST_APEX_SINK_NAME "apexsink"
#define GST_APEX_SINK_JACKTYPE_TYPE (gst_apexsink_jacktype_get_type())
#define GST_APEX_SINK_JACKSTATUS_TYPE (gst_apexsink_jackstatus_get_type())
#define GST_APEX_SINK_GENERATION_TYPE (gst_apexsink_generation_get_type())
#define GST_APEX_SINK_TRANSPORT_PROTOCOL_TYPE (gst_apexsink_transport_protocol_get_type())
/* ApEx classes declaration */
typedef struct _GstApExSink GstApExSink;
typedef struct _GstApExSinkClass GstApExSinkClass;
struct _GstApExSink
{
/* base definition */
GstAudioSink sink;
/* public read/write sink properties */
gchar *host;
guint port;
guint volume;
GstApExGeneration generation;
GstApExTransportProtocol transport_protocol;
/* private attributes :
* latency time local copy
* tracks list of the mixer interface
* clock for sleeping
* clock ID for sleeping / canceling sleep
*/
guint64 latency_time;
GList *tracks;
GstClock *clock;
GstClockID clock_id;
/* private apex client */
GstApExRAOP *gst_apexraop;
};
struct _GstApExSinkClass
{
GstAudioSinkClass parent_class;
};
/* genums */
GType gst_apexsink_jackstatus_get_type (void);
GType gst_apexsink_jacktype_get_type (void);
GType gst_apexsink_generation_get_type (void);
GType gst_apexsink_transport_protocol_get_type (void);
/* audio sink standard api */
GType gst_apexsink_get_type (void);
G_END_DECLS
#endif

View file

@ -1,15 +0,0 @@
plugin_LTLIBRARIES = libgstlibvisualgl.la
libgstlibvisualgl_la_SOURCES = visual-gl.c
libgstlibvisualgl_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(LIBVISUAL_CFLAGS) \
-I$(top_srcdir)/gst-libs \
-I$(top_srcdir)/gst-libs/gst/gl
libgstlibvisualgl_la_LIBADD = \
$(top_builddir)/gst-libs/gst/gl/libgstgl-$(GST_API_VERSION).la \
$(GST_PLUGINS_BASE_LIBS) $(GST_LIBS) $(LIBVISUAL_LIBS)
libgstlibvisualgl_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstlibvisualgl_la_LIBTOOLFLAGS = --tag=disable-static

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,3 @@
#subdir('apexsink')
subdir('assrender')
#subdir('bs2b')
subdir('bz2')
@ -25,13 +24,11 @@ subdir('kate')
#subdir('ladspa')
subdir('libde265')
subdir('libmms')
#subdir('libvisual')
#subdir('lv2')
#subdir('modplug')
#subdir('mpeg2enc')
#subdir('mplex')
#subdir('musepack')
#subdir('nas')
#subdir('neon')
#subdir('ofa')
#subdir('openal')
@ -41,16 +38,13 @@ subdir('openh264')
subdir('openjpeg')
#subdir('openni2')
subdir('opus')
#subdir('qt')
subdir('resindvd')
subdir('rsvg')
subdir('rtmp')
subdir('sbc')
subdir('schroedinger')
#subdir('sdl')
subdir('smoothstreaming')
#subdir('sndfile')
#subdir('sndio')
if cc.get_id() != 'msvc'
# soundtouch doesn't do exporting of symbols for DLLs and I'm not sure how to
# do that for C++ classes. -- Nirbheek
@ -62,7 +56,7 @@ endif
#subdir('spc')
subdir('srtp')
#subdir('teletextdec')
#subdir('timidity')
#subdir('wildmidi')
subdir('ttml')
subdir('voaacenc')
#subdir('voamrwbenc')
@ -71,5 +65,4 @@ subdir('wayland')
#subdir('webrtcdsp')
subdir('webp')
subdir('x265')
#subdir('xvid')
subdir('zbar')

View file

@ -1,11 +0,0 @@
plugin_LTLIBRARIES = libgstnassink.la
libgstnassink_la_SOURCES = nassink.c
libgstnassink_la_CFLAGS = \
$(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(NAS_CFLAGS)
libgstnassink_la_LIBADD = \
$(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) $(NAS_LIBS)
libgstnassink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstnassink_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
noinst_HEADERS = nassink.h

View file

@ -1,583 +0,0 @@
/* GStreamer
* Copyright (C) <2003> Laurent Vivier <Laurent.Vivier@bull.net>
* Copyright (C) <2004> Arwed v. Merkatz <v.merkatz@gmx.net>
*
* Based on esdsink.c:
* Copyright (C) <2001> Richard Boulton <richard-gst@tartarus.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 <gst/gst.h>
#include <string.h>
#include <audio/audiolib.h>
#include <audio/soundlib.h>
#include "nassink.h"
#define NAS_SOUND_PORT_DURATION (2)
GST_DEBUG_CATEGORY_STATIC (nas_debug);
#define GST_CAT_DEFAULT nas_debug
enum
{
ARG_0,
ARG_MUTE,
ARG_HOST
};
#define DEFAULT_MUTE FALSE
#define DEFAULT_HOST NULL
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-int, "
"endianness = (int) BYTE_ORDER, "
"signed = (boolean) TRUE, "
"width = (int) 16, "
"depth = (int) 16, "
"rate = (int) [ 1000, 96000 ], "
"channels = (int) [ 1, 2 ]; "
"audio/x-raw-int, "
"signed = (boolean) FALSE, "
"width = (int) 8, "
"depth = (int) 8, "
"rate = (int) [ 1000, 96000 ], " "channels = (int) [ 1, 2 ]")
);
static void gst_nas_sink_finalize (GObject * object);
static gboolean gst_nas_sink_open (GstAudioSink * sink);
static gboolean gst_nas_sink_close (GstAudioSink * sink);
static gboolean gst_nas_sink_prepare (GstAudioSink * sink,
GstRingBufferSpec * spec);
static gboolean gst_nas_sink_unprepare (GstAudioSink * sink);
static guint gst_nas_sink_write (GstAudioSink * asink, gpointer data,
guint length);
static guint gst_nas_sink_delay (GstAudioSink * asink);
static void gst_nas_sink_reset (GstAudioSink * asink);
static GstCaps *gst_nas_sink_getcaps (GstBaseSink * pad);
static void gst_nas_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_nas_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void NAS_flush (GstNasSink * sink);
static void NAS_sendData (GstNasSink * sink, AuUint32 numBytes);
static AuBool NAS_EventHandler (AuServer * aud, AuEvent * ev,
AuEventHandlerRec * handler);
static AuDeviceID NAS_getDevice (AuServer * aud, int numTracks);
GST_BOILERPLATE (GstNasSink, gst_nas_sink, GstAudioSink, GST_TYPE_AUDIO_SINK);
static void
gst_nas_sink_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_static_pad_template (element_class, &sink_factory);
gst_element_class_set_static_metadata (element_class, "NAS audio sink",
"Sink/Audio",
"Plays audio to a Network Audio Server",
"Laurent Vivier <Laurent.Vivier@bull.net>, "
"Arwed v. Merkatz <v.merkatz@gmx.net>");
}
static void
gst_nas_sink_class_init (GstNasSinkClass * klass)
{
GObjectClass *gobject_class;
GstBaseSinkClass *gstbasesink_class;
GstAudioSinkClass *gstaudiosink_class;
gobject_class = (GObjectClass *) klass;
gstbasesink_class = (GstBaseSinkClass *) klass;
gstaudiosink_class = (GstAudioSinkClass *) klass;
gobject_class->set_property = gst_nas_sink_set_property;
gobject_class->get_property = gst_nas_sink_get_property;
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_nas_sink_finalize);
g_object_class_install_property (gobject_class, ARG_MUTE,
g_param_spec_boolean ("mute", "mute", "Whether to mute playback",
DEFAULT_MUTE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, ARG_HOST,
g_param_spec_string ("host", "host",
"host running the NAS daemon (name of X/Terminal, default is "
"$AUDIOSERVER or $DISPLAY)", DEFAULT_HOST,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_nas_sink_getcaps);
gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_nas_sink_open);
gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_nas_sink_close);
gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_nas_sink_prepare);
gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_nas_sink_unprepare);
gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_nas_sink_write);
gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_nas_sink_delay);
gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_nas_sink_reset);
}
static void
gst_nas_sink_init (GstNasSink * nassink, GstNasSinkClass * klass)
{
/* properties will automatically be set to their default values */
nassink->audio = NULL;
nassink->flow = AuNone;
nassink->need_data = 0;
}
static void
gst_nas_sink_finalize (GObject * object)
{
GstNasSink *nassink = GST_NAS_SINK (object);
g_free (nassink->host);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static GstCaps *
gst_nas_sink_getcaps (GstBaseSink * bsink)
{
GstNasSink *nassink = GST_NAS_SINK (bsink);
const GstCaps *templatecaps;
AuServer *server;
GstCaps *fixated, *caps;
int i;
server = nassink->audio;
templatecaps = gst_static_pad_template_get_caps (&sink_factory);
if (server == NULL)
return gst_caps_copy (templatecaps);
fixated = gst_caps_copy (templatecaps);
for (i = 0; i < gst_caps_get_size (fixated); i++) {
GstStructure *structure;
gint min, max;
min = AuServerMinSampleRate (server);
max = AuServerMaxSampleRate (server);
structure = gst_caps_get_structure (fixated, i);
if (min == max)
gst_structure_set (structure, "rate", G_TYPE_INT, max, NULL);
else
gst_structure_set (structure, "rate", GST_TYPE_INT_RANGE, min, max, NULL);
}
caps = gst_caps_intersect (fixated, templatecaps);
gst_caps_unref (fixated);
if (nassink->audio == NULL)
AuCloseServer (server);
return caps;
}
static gint
gst_nas_sink_sink_get_format (const GstRingBufferSpec * spec)
{
gint result;
switch (spec->format) {
case GST_U8:
result = AuFormatLinearUnsigned8;
break;
case GST_S8:
result = AuFormatLinearSigned8;
break;
case GST_S16_LE:
result = AuFormatLinearSigned16LSB;
break;
case GST_S16_BE:
result = AuFormatLinearSigned16MSB;
break;
case GST_U16_LE:
result = AuFormatLinearUnsigned16LSB;
break;
case GST_U16_BE:
result = AuFormatLinearUnsigned16MSB;
break;
default:
result = 0;
break;
}
return result;
}
static gboolean
gst_nas_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
{
GstNasSink *sink = GST_NAS_SINK (asink);
AuElement elements[2];
AuUint32 buf_samples;
unsigned char format;
format = gst_nas_sink_sink_get_format (spec);
if (format == 0) {
GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL),
("Unable to get format %d", spec->format));
return FALSE;
}
GST_DEBUG_OBJECT (sink, "Format: %d %d\n", spec->format, format);
sink->flow = AuGetScratchFlow (sink->audio, NULL);
if (sink->flow == 0) {
GST_DEBUG_OBJECT (sink, "couldn't get flow");
return FALSE;
}
buf_samples = spec->rate * NAS_SOUND_PORT_DURATION;
/*
spec->segsize = gst_util_uint64_scale (buf_samples * spec->bytes_per_sample,
spec->latency_time, GST_SECOND / GST_USECOND);
spec->segsize -= spec->segsize % spec->bytes_per_sample;
spec->segtotal = spec->buffer_time / spec->latency_time;
*/
spec->segsize = buf_samples * spec->bytes_per_sample;
spec->segtotal = 1;
memset (spec->silence_sample, 0, spec->bytes_per_sample);
GST_DEBUG_OBJECT (sink, "Bytes per sample %d", spec->bytes_per_sample);
GST_DEBUG_OBJECT (sink, "Rate %d Format %d tracks %d bufs %d %d/%d w %d",
spec->rate, format, spec->channels, (gint) buf_samples, spec->segsize,
spec->segtotal, spec->width);
AuMakeElementImportClient (&elements[0], /* element */
spec->rate, /* rate */
format, /* format */
spec->channels, /* number of tracks */
AuTrue, /* discart */
buf_samples, /* max samples */
(AuUint32) (buf_samples / 100 * AuSoundPortLowWaterMark),
/* low water mark */
0, /* num actions */
NULL);
sink->device = NAS_getDevice (sink->audio, spec->channels);
if (sink->device == AuNone) {
GST_DEBUG_OBJECT (sink, "no device with %i tracks found", spec->channels);
return FALSE;
}
AuMakeElementExportDevice (&elements[1], /* element */
0, /* input */
sink->device, /* device */
spec->rate, /* rate */
AuUnlimitedSamples, /* num samples */
0, /* num actions */
NULL); /* actions */
AuSetElements (sink->audio, /* server */
sink->flow, /* flow ID */
AuTrue, /* clocked */
2, /* num elements */
elements, /* elements */
NULL);
AuRegisterEventHandler (sink->audio, /* server */
AuEventHandlerIDMask, /* value mask */
0, /* type */
sink->flow, /* flow ID */
NAS_EventHandler, /* callback */
(AuPointer) sink); /* data */
AuStartFlow (sink->audio, sink->flow, NULL);
return TRUE;
}
static gboolean
gst_nas_sink_unprepare (GstAudioSink * asink)
{
GstNasSink *sink = GST_NAS_SINK (asink);
if (sink->flow != AuNone) {
AuBool clocked;
int num_elements;
AuStatus status;
AuElement *oldelems;
GST_DEBUG_OBJECT (sink, "flushing buffer");
NAS_flush (sink);
oldelems =
AuGetElements (sink->audio, sink->flow, &clocked, &num_elements,
&status);
if (num_elements > 0) {
GST_DEBUG_OBJECT (sink, "GetElements status: %i", status);
if (oldelems)
AuFreeElements (sink->audio, num_elements, oldelems);
}
AuStopFlow (sink->audio, sink->flow, NULL);
AuReleaseScratchFlow (sink->audio, sink->flow, NULL);
sink->flow = AuNone;
}
sink->need_data = 0;
return TRUE;
}
static guint
gst_nas_sink_delay (GstAudioSink * asink)
{
GST_DEBUG_OBJECT (asink, "nas_sink_delay");
return 0;
}
static void
gst_nas_sink_reset (GstAudioSink * asink)
{
GstNasSink *sink = GST_NAS_SINK (asink);
GST_DEBUG_OBJECT (sink, "reset");
if (sink->flow != AuNone)
AuStopFlow (sink->audio, sink->flow, NULL);
}
static guint
gst_nas_sink_write (GstAudioSink * asink, gpointer data, guint length)
{
GstNasSink *nassink = GST_NAS_SINK (asink);
int used = 0;
NAS_flush (nassink);
if (!nassink->mute && nassink->audio != NULL && nassink->flow != AuNone) {
if (nassink->need_data == 0)
return 0;
used = nassink->need_data > length ? length : nassink->need_data;
AuWriteElement (nassink->audio, nassink->flow, 0, used, data, AuFalse,
NULL);
nassink->need_data -= used;
if (used == length)
AuSync (nassink->audio, AuFalse);
} else
used = length;
return used;
}
static void
gst_nas_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstNasSink *nassink;
nassink = GST_NAS_SINK (object);
switch (prop_id) {
case ARG_MUTE:
nassink->mute = g_value_get_boolean (value);
break;
case ARG_HOST:
g_free (nassink->host);
nassink->host = g_value_dup_string (value);
if (nassink->host == NULL)
nassink->host = g_strdup (g_getenv ("AUDIOSERVER"));
if (nassink->host == NULL)
nassink->host = g_strdup (g_getenv ("DISPLAY"));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_nas_sink_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstNasSink *nassink;
nassink = GST_NAS_SINK (object);
switch (prop_id) {
case ARG_MUTE:
g_value_set_boolean (value, nassink->mute);
break;
case ARG_HOST:
g_value_set_string (value, nassink->host);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_nas_sink_open (GstAudioSink * asink)
{
GstNasSink *sink = GST_NAS_SINK (asink);
GST_DEBUG_OBJECT (sink, "opening, host = '%s'", GST_STR_NULL (sink->host));
/* Open Server */
sink->audio = AuOpenServer (sink->host, 0, NULL, 0, NULL, NULL);
if (sink->audio == NULL) {
GST_DEBUG_OBJECT (sink, "opening failed");
return FALSE;
}
sink->flow = AuNone;
sink->need_data = 0;
/* Start a flow */
GST_DEBUG_OBJECT (asink, "opened audio device");
return TRUE;
}
static gboolean
gst_nas_sink_close (GstAudioSink * asink)
{
GstNasSink *sink = GST_NAS_SINK (asink);
if (sink->audio) {
AuCloseServer (sink->audio);
sink->audio = NULL;
}
GST_DEBUG_OBJECT (sink, "closed audio device");
return TRUE;
}
static void
NAS_flush (GstNasSink * sink)
{
AuEvent ev;
AuNextEvent (sink->audio, AuTrue, &ev);
AuDispatchEvent (sink->audio, &ev);
}
static void
NAS_sendData (GstNasSink * sink, AuUint32 numBytes)
{
sink->need_data += numBytes;
return;
}
static AuBool
NAS_EventHandler (AuServer * aud, AuEvent * ev, AuEventHandlerRec * handler)
{
GstNasSink *sink = (GstNasSink *) handler->data;
AuElementNotifyEvent *notify;
switch (ev->type) {
case AuEventTypeElementNotify:
notify = (AuElementNotifyEvent *) ev;
switch (notify->kind) {
case AuElementNotifyKindLowWater:
NAS_sendData (sink, notify->num_bytes);
break;
case AuElementNotifyKindState:
switch (notify->cur_state) {
case AuStateStop:
if (sink->flow != AuNone) {
if (notify->reason == AuReasonEOF)
AuStopFlow (handler->aud, sink->flow, NULL);
AuReleaseScratchFlow (handler->aud, sink->flow, NULL);
sink->flow = AuNone;
}
AuUnregisterEventHandler (handler->aud, handler);
break;
case AuStatePause:
switch (notify->reason) {
case AuReasonUnderrun:
case AuReasonOverrun:
case AuReasonEOF:
case AuReasonWatermark:
NAS_sendData (sink, notify->num_bytes);
break;
case AuReasonHardware:
if (AuSoundRestartHardwarePauses)
AuStartFlow (handler->aud, sink->flow, NULL);
else
AuStopFlow (handler->aud, sink->flow, NULL);
break;
}
break;
}
break;
}
break;
}
return AuTrue;
}
static AuDeviceID
NAS_getDevice (AuServer * aud, int numTracks)
{
int i;
for (i = 0; i < AuServerNumDevices (aud); i++) {
if ((AuDeviceKind (AuServerDevice (aud, i))
== AuComponentKindPhysicalOutput) &&
(AuDeviceNumTracks (AuServerDevice (aud, i)) == numTracks)) {
return AuDeviceIdentifier (AuServerDevice (aud, i));
}
}
return AuNone;
}
static gboolean
plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (nas_debug, "NAS", 0, NULL);
if (!gst_element_register (plugin, "nassink", GST_RANK_NONE,
GST_TYPE_NAS_SINK)) {
return FALSE;
}
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
nas,
"NAS (Network Audio System) support for GStreamer",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);

View file

@ -1,72 +0,0 @@
/* 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_NAS_SINK_H__
#define __GST_NAS_SINK_H__
#include <gst/gst.h>
#include <gst/audio/gstaudiosink.h>
G_BEGIN_DECLS
#define GST_TYPE_NAS_SINK \
(gst_nas_sink_get_type())
#define GST_NAS_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_NAS_SINK,GstNasSink))
#define GST_NAS_SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_NAS_SINK,GstNasSinkClass))
#define GST_IS_NAS_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_NAS_SINK))
#define GST_IS_NAS_SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_NAS_SINK))
typedef struct _GstNasSink GstNasSink;
typedef struct _GstNasSinkClass GstNasSinkClass;
struct _GstNasSink {
GstAudioSink audiosink;
/*< private >*/
/* instance properties */
gboolean mute;
gchar* host;
/* Server info */
AuServer *audio;
AuFlowID flow;
AuDeviceID device;
/* buffer */
AuUint32 need_data;
};
struct _GstNasSinkClass {
GstAudioSinkClass parent_class;
};
GType gst_nas_sink_get_type(void);
G_END_DECLS
#endif /* __GST_NAS_SINK_H__ */

View file

@ -1,19 +0,0 @@
plugin_LTLIBRARIES = libgstsdl.la
libgstsdl_la_SOURCES = \
gstsdl.c \
sdlvideosink.c \
sdlaudiosink.c
libgstsdl_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(SDL_CFLAGS)
libgstsdl_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
-lgstvideo-$(GST_API_VERSION) \
-lgstaudio-$(GST_API_VERSION) \
-lgstinterfaces-$(GST_API_VERSION) \
$(SDL_LIBS)
libgstsdl_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstsdl_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
noinst_HEADERS = \
sdlvideosink.h \
sdlaudiosink.h

View file

@ -1,45 +0,0 @@
/* 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
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "sdlvideosink.h"
#include "sdlaudiosink.h"
GST_DEBUG_CATEGORY (sdl_debug);
static gboolean
plugin_init (GstPlugin * plugin)
{
if (!gst_element_register (plugin, "sdlvideosink", GST_RANK_NONE,
GST_TYPE_SDLVIDEOSINK) ||
!gst_element_register (plugin, "sdlaudiosink", GST_RANK_NONE,
GST_TYPE_SDLAUDIOSINK)) {
return FALSE;
}
GST_DEBUG_CATEGORY_INIT (sdl_debug, "sdl", 0, "SDL elements");
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
sdl,
"SDL (Simple DirectMedia Layer) support for GStreamer",
plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

View file

@ -1,439 +0,0 @@
/* 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
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "sdlaudiosink.h"
#include <SDL_byteorder.h>
#include <string.h>
#include <unistd.h>
#include <gst/glib-compat-private.h>
GST_DEBUG_CATEGORY_EXTERN (sdl_debug);
#define GST_CAT_DEFAULT sdl_debug
static void gst_sdlaudio_sink_dispose (GObject * object);
static GstCaps *gst_sdlaudio_sink_getcaps (GstBaseSink * bsink);
static gboolean gst_sdlaudio_sink_open (GstAudioSink * asink);
static gboolean gst_sdlaudio_sink_close (GstAudioSink * asink);
static gboolean gst_sdlaudio_sink_prepare (GstAudioSink * asink,
GstRingBufferSpec * spec);
static gboolean gst_sdlaudio_sink_unprepare (GstAudioSink * asink);
static guint gst_sdlaudio_sink_write (GstAudioSink * asink, gpointer data,
guint length);
#if 0
static guint gst_sdlaudio_sink_delay (GstAudioSink * asink);
static void gst_sdlaudio_sink_reset (GstAudioSink * asink);
#endif
/* SdlaudioSink signals and args */
enum
{
LAST_SIGNAL
};
#define SEMAPHORE_INIT(s,f) \
do { \
s.cond = g_cond_new(); \
s.mutex = g_mutex_new(); \
s.mutexflag = f; \
} while(0)
#define SEMAPHORE_CLOSE(s) \
do { \
if ( s.cond ) { \
g_cond_free(s.cond); \
s.cond = NULL; \
} \
if ( s.mutex ) { \
g_mutex_free(s.mutex); \
s.mutex = NULL; \
} \
} while(0)
#define SEMAPHORE_UP(s) \
do \
{ \
g_mutex_lock(s.mutex); \
s.mutexflag = TRUE; \
g_mutex_unlock(s.mutex); \
g_cond_signal(s.cond); \
} while(0)
#define SEMAPHORE_DOWN(s, e) \
do \
{ \
while (1) { \
g_mutex_lock(s.mutex); \
if (!s.mutexflag) { \
if ( e ) { \
g_mutex_unlock(s.mutex); \
break; \
} \
g_cond_wait(s.cond,s.mutex); \
} \
else { \
s.mutexflag = FALSE; \
g_mutex_unlock(s.mutex); \
break; \
} \
g_mutex_unlock(s.mutex); \
} \
} while(0)
static GstStaticPadTemplate sdlaudiosink_sink_factory =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-int, "
"endianness = (int) { " G_STRINGIFY (G_BYTE_ORDER) " }, "
"signed = (boolean) { TRUE, FALSE }, "
"width = (int) 16, "
"depth = (int) 16, "
"rate = (int) [ 1, MAX ], "
"channels = (int) [ 1, 2 ]; "
"audio/x-raw-int, "
"endianness = (int) { " G_STRINGIFY (G_BYTE_ORDER) " }, "
"signed = (boolean) { TRUE, FALSE }, "
"width = (int) 8, "
"depth = (int) 8, "
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]")
);
GST_BOILERPLATE (GstSDLAudioSink, gst_sdlaudio_sink, GstAudioSink,
GST_TYPE_AUDIO_SINK);
static void
gst_sdlaudio_sink_dispose (GObject * object)
{
GstSDLAudioSink *sdlaudiosink = GST_SDLAUDIOSINK (object);
SEMAPHORE_CLOSE (sdlaudiosink->semB);
SEMAPHORE_CLOSE (sdlaudiosink->semA);
if (sdlaudiosink->buffer) {
g_free (sdlaudiosink->buffer);
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gst_sdlaudio_sink_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_set_static_metadata (element_class, "SDL audio sink",
"Sink/Audio",
"Output to a sound card via SDLAUDIO",
"Edgard Lima <edgard.lima@indt.org.br>");
gst_element_class_add_static_pad_template (element_class,
&sdlaudiosink_sink_factory);
}
static void
gst_sdlaudio_sink_class_init (GstSDLAudioSinkClass * klass)
{
GObjectClass *gobject_class;
GstBaseSinkClass *gstbasesink_class;
GstAudioSinkClass *gstaudiosink_class;
gobject_class = (GObjectClass *) klass;
gstbasesink_class = (GstBaseSinkClass *) klass;
gstaudiosink_class = (GstAudioSinkClass *) klass;
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_dispose);
gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_getcaps);
gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_open);
gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_close);
gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_prepare);
gstaudiosink_class->unprepare =
GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_unprepare);
gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_write);
#if 0
gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_delay);
gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_reset);
#endif
}
static void
gst_sdlaudio_sink_init (GstSDLAudioSink * sdlaudiosink,
GstSDLAudioSinkClass * g_class)
{
GST_DEBUG ("initializing sdlaudiosink");
memset (&sdlaudiosink->fmt, 0, sizeof (SDL_AudioSpec));
sdlaudiosink->buffer = NULL;
sdlaudiosink->eos = FALSE;
SEMAPHORE_INIT (sdlaudiosink->semA, TRUE);
SEMAPHORE_INIT (sdlaudiosink->semB, FALSE);
}
static GstCaps *
gst_sdlaudio_sink_getcaps (GstBaseSink * bsink)
{
return gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD
(bsink)));
}
static gint
gst_sdlaudio_sink_get_format (GstBufferFormat fmt)
{
gint result = GST_UNKNOWN;
switch (fmt) {
case GST_U8:
result = AUDIO_U8;
break;
case GST_S8:
result = AUDIO_S8;
break;
case GST_S16_LE:
result = AUDIO_S16LSB;
break;
case GST_S16_BE:
result = AUDIO_S16MSB;
break;
case GST_U16_LE:
result = AUDIO_U16LSB;
break;
case GST_U16_BE:
result = AUDIO_U16MSB;
break;
default:
break;
}
return result;
}
static gboolean
gst_sdlaudio_sink_open (GstAudioSink * asink)
{
GstSDLAudioSink *sdlaudio;
sdlaudio = GST_SDLAUDIOSINK (asink);
if (SDL_Init (SDL_INIT_AUDIO) < 0) {
goto open_failed;
}
return TRUE;
open_failed:
{
GST_ELEMENT_ERROR (sdlaudio, LIBRARY, INIT,
("Unable to init SDL: %s\n", SDL_GetError ()), (NULL));
return FALSE;
}
}
static gboolean
gst_sdlaudio_sink_close (GstAudioSink * asink)
{
GstSDLAudioSink *sdlaudio = GST_SDLAUDIOSINK (asink);
sdlaudio->eos = TRUE;
SEMAPHORE_UP (sdlaudio->semA);
SEMAPHORE_UP (sdlaudio->semB);
SDL_QuitSubSystem (SDL_INIT_AUDIO);
return TRUE;
}
static guint
gst_sdlaudio_sink_write (GstAudioSink * asink, gpointer data, guint length)
{
GstSDLAudioSink *sdlaudio = GST_SDLAUDIOSINK (asink);
if (sdlaudio->fmt.size != length) {
GST_ERROR ("ring buffer segment length (%u) != sdl buffer len (%u)", length,
sdlaudio->fmt.size);
}
SEMAPHORE_DOWN (sdlaudio->semA, sdlaudio->eos);
if (!sdlaudio->eos)
memcpy (sdlaudio->buffer, data, length);
SEMAPHORE_UP (sdlaudio->semB);
return sdlaudio->fmt.size;
}
static void
mixaudio (void *unused, Uint8 * stream, int len)
{
GstSDLAudioSink *sdlaudio;
sdlaudio = GST_SDLAUDIOSINK (unused);
if (sdlaudio->fmt.size != len) {
GST_ERROR ("fmt buffer len (%u) != sdl callback len (%d)",
sdlaudio->fmt.size, len);
}
SEMAPHORE_DOWN (sdlaudio->semB, sdlaudio->eos);
if (!sdlaudio->eos)
SDL_MixAudio (stream, sdlaudio->buffer, sdlaudio->fmt.size,
SDL_MIX_MAXVOLUME);
SEMAPHORE_UP (sdlaudio->semA);
}
static gboolean
gst_sdlaudio_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
{
GstSDLAudioSink *sdlaudio;
gint power2 = -1;
sdlaudio = GST_SDLAUDIOSINK (asink);
sdlaudio->fmt.format = gst_sdlaudio_sink_get_format (spec->format);
if (sdlaudio->fmt.format == 0)
goto wrong_format;
if (spec->width != 16 && spec->width != 8)
goto dodgy_width;
sdlaudio->fmt.freq = spec->rate;
sdlaudio->fmt.channels = spec->channels;
sdlaudio->fmt.samples =
spec->segsize / (spec->channels * ((sdlaudio->fmt.format & 0xFF) >> 3));
sdlaudio->fmt.callback = mixaudio;
sdlaudio->fmt.userdata = sdlaudio;
GST_DEBUG ("set segsize: %d, segtotal: %d, samples: %d", spec->segsize,
spec->segtotal, sdlaudio->fmt.samples);
while (sdlaudio->fmt.samples) {
sdlaudio->fmt.samples >>= 1;
++power2;
}
sdlaudio->fmt.samples = 1;
sdlaudio->fmt.samples <<= power2;
GST_DEBUG ("set segsize: %d, segtotal: %d, samples: %d", spec->segsize,
spec->segtotal, sdlaudio->fmt.samples);
if (SDL_OpenAudio (&sdlaudio->fmt, NULL) < 0) {
goto unable_open;
}
spec->segsize = sdlaudio->fmt.size;
sdlaudio->buffer = g_malloc (sdlaudio->fmt.size);
memset (sdlaudio->buffer, sdlaudio->fmt.silence, sdlaudio->fmt.size);
GST_DEBUG ("set segsize: %d, segtotal: %d, samples: %d", spec->segsize,
spec->segtotal, sdlaudio->fmt.samples);
spec->bytes_per_sample =
spec->channels * ((sdlaudio->fmt.format & 0xFF) >> 3);
memset (spec->silence_sample, sdlaudio->fmt.silence, spec->bytes_per_sample);
SDL_PauseAudio (0);
return TRUE;
unable_open:
{
GST_ELEMENT_ERROR (sdlaudio, RESOURCE, OPEN_READ,
("Unable to open audio: %s", SDL_GetError ()), (NULL));
return FALSE;
}
wrong_format:
{
GST_ELEMENT_ERROR (sdlaudio, RESOURCE, OPEN_READ,
("Unable to get format %d", spec->format), (NULL));
return FALSE;
}
dodgy_width:
{
GST_ELEMENT_ERROR (sdlaudio, RESOURCE, OPEN_READ,
("unexpected width %d", spec->width), (NULL));
return FALSE;
}
}
static gboolean
gst_sdlaudio_sink_unprepare (GstAudioSink * asink)
{
SDL_CloseAudio ();
return TRUE;
#if 0
if (!gst_sdlaudio_sink_close (asink))
goto couldnt_close;
if (!gst_sdlaudio_sink_open (asink))
goto couldnt_reopen;
return TRUE;
couldnt_close:
{
GST_DEBUG ("Could not close the audio device");
return FALSE;
}
couldnt_reopen:
{
GST_DEBUG ("Could not reopen the audio device");
return FALSE;
}
#endif
}
#if 0
static guint
gst_sdlaudio_sink_delay (GstAudioSink * asink)
{
GstSDLAudioSink *sdlaudio;
sdlaudio = GST_SDLAUDIOSINK (asink);
return 0;
}
static void
gst_sdlaudio_sink_reset (GstAudioSink * asink)
{
}
#endif

View file

@ -1,65 +0,0 @@
/* 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_SDLAUDIOSINK_H__
#define __GST_SDLAUDIOSINK_H__
#include <gst/gst.h>
#include <gst/audio/gstaudiosink.h>
#include <SDL.h>
#include <SDL_audio.h>
G_BEGIN_DECLS
#define GST_TYPE_SDLAUDIOSINK (gst_sdlaudio_sink_get_type())
#define GST_SDLAUDIOSINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SDLAUDIOSINK,GstSDLAudioSink))
#define GST_SDLAUDIOSINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SDLAUDIOSINK,GstSDLAudioSinkClass))
#define GST_IS_SDLAUDIOSINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SDLAUDIOSINK))
#define GST_IS_SDLAUDIOSINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SDLAUDIOSINK))
typedef struct _GstSDLAudioSink GstSDLAudioSink;
typedef struct _GstSDLAudioSinkClass GstSDLAudioSinkClass;
typedef struct _gstsdl_semaphore {
GCond *cond;
GMutex *mutex;
gboolean mutexflag;
} gstsdl_semaphore;
struct _GstSDLAudioSink {
GstAudioSink sink;
SDL_AudioSpec fmt;
guint8 *buffer;
gstsdl_semaphore semA;
gstsdl_semaphore semB;
gboolean eos;
};
struct _GstSDLAudioSinkClass {
GstAudioSinkClass parent_class;
};
GType gst_sdlaudio_sink_get_type(void);
G_END_DECLS
#endif /* __GST_SDLAUDIOSINK_H__ */

File diff suppressed because it is too large Load diff

View file

@ -1,82 +0,0 @@
/* GStreamer SDL plugin
* Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.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_SDLVIDEOSINK_H__
#define __GST_SDLVIDEOSINK_H__
#include <gst/video/gstvideosink.h>
#include <SDL.h>
G_BEGIN_DECLS
#define GST_TYPE_SDLVIDEOSINK \
(gst_sdlvideosink_get_type())
#define GST_SDLVIDEOSINK(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SDLVIDEOSINK,GstSDLVideoSink))
#define GST_SDLVIDEOSINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SDLVIDEOSINK,GstSDLVideoSinkClass))
#define GST_IS_SDLVIDEOSINK(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SDLVIDEOSINK))
#define GST_IS_SDLVIDEOSINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SDLVIDEOSINK))
typedef enum {
GST_SDLVIDEOSINK_OPEN = (GST_ELEMENT_FLAG_LAST << 0),
GST_SDLVIDEOSINK_FLAG_LAST = (GST_ELEMENT_FLAG_LAST << 2),
} GstSDLVideoSinkFlags;
typedef struct _GstSDLVideoSink GstSDLVideoSink;
typedef struct _GstSDLVideoSinkClass GstSDLVideoSinkClass;
struct _GstSDLVideoSink {
GstVideoSink videosink;
guint32 format; /* the SDL format */
guint32 fourcc; /* our fourcc from the caps */
gint width, height; /* the size of the incoming YUV stream */
unsigned long xwindow_id;
gboolean is_xwindows;
gint framerate_n;
gint framerate_d;
gboolean full_screen;
gboolean init;
gboolean running;
GThread *event_thread;
SDL_Surface *screen;
SDL_Overlay *overlay;
SDL_Rect rect;
GMutex *lock;
};
struct _GstSDLVideoSinkClass {
GstVideoSinkClass parent_class;
};
GType gst_sdlvideosink_get_type(void);
G_END_DECLS
#endif /* __GST_SDLVIDEOSINK_H__ */

View file

@ -1,11 +0,0 @@
plugin_LTLIBRARIES = libgstsndio.la
libgstsndio_la_SOURCES = gstsndio.c sndiosink.c sndiosrc.c
libgstsndio_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
libgstsndio_la_LIBADD = \
$(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) \
$(SNDIO_LIBS)
libgstsndio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
noinst_HEADERS = sndiosink.h sndiosrc.h
EXTRA_DIST =

View file

@ -1,53 +0,0 @@
/*
* Copyright (C) <2008> Jacob Meuser <jakemsr@sdf.lonestar.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "sndiosink.h"
#include "sndiosrc.h"
#include "gst/gst-i18n-plugin.h"
GST_DEBUG_CATEGORY (gst_sndio_debug);
static gboolean
plugin_init (GstPlugin * plugin)
{
if (!gst_element_register (plugin, "sndiosrc", GST_RANK_PRIMARY,
GST_TYPE_SNDIOSRC) ||
!gst_element_register (plugin, "sndiosink", GST_RANK_PRIMARY,
GST_TYPE_SNDIOSINK)) {
return FALSE;
}
GST_DEBUG_CATEGORY_INIT (gst_sndio_debug, "sndio", 0, "sndio elements");
#ifdef ENABLE_NLS
GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
LOCALEDIR);
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
#endif /* ENABLE_NLS */
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"sndio",
"sndio support for GStreamer",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

View file

@ -1,527 +0,0 @@
/*
* Copyright (C) <2008> Jacob Meuser <jakemsr@sdf.lonestar.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/**
* SECTION:element-sndiosink
* @see_also: #GstAutoAudioSink
*
* <refsect2>
* <para>
* This element outputs sound to a sound card using sndio.
* </para>
* <para>
* Simple example pipeline that plays an Ogg/Vorbis file via sndio:
* <programlisting>
* gst-launch-1.0 -v filesrc location=foo.ogg ! decodebin ! audioconvert ! audioresample ! sndiosink
* </programlisting>
* </para>
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "sndiosink.h"
#include <unistd.h>
#include <errno.h>
#include <gst/gst-i18n-plugin.h>
GST_DEBUG_CATEGORY_EXTERN (gst_sndio_debug);
#define GST_CAT_DEFAULT gst_sndio_debug
enum
{
PROP_0,
PROP_HOST
};
static GstStaticPadTemplate sndio_sink_factory =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-int, "
"endianness = (int) { 1234, 4321 }, "
"signed = (boolean) { TRUE, FALSE }, "
"width = (int) { 8, 16, 24, 32 }, "
"depth = (int) { 8, 16, 24, 32 }, "
"rate = (int) [ 8000, 192000 ], " "channels = (int) [ 1, 16 ] ")
);
static void gst_sndiosink_finalize (GObject * object);
static GstCaps *gst_sndiosink_getcaps (GstBaseSink * bsink);
static gboolean gst_sndiosink_open (GstAudioSink * asink);
static gboolean gst_sndiosink_close (GstAudioSink * asink);
static gboolean gst_sndiosink_prepare (GstAudioSink * asink,
GstRingBufferSpec * spec);
static gboolean gst_sndiosink_unprepare (GstAudioSink * asink);
static guint gst_sndiosink_write (GstAudioSink * asink, gpointer data,
guint length);
static guint gst_sndiosink_delay (GstAudioSink * asink);
static void gst_sndiosink_reset (GstAudioSink * asink);
static void gst_sndiosink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_sndiosink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_sndiosink_cb (void *addr, int delta);
GST_BOILERPLATE (GstSndioSink, gst_sndiosink, GstAudioSink,
GST_TYPE_AUDIO_SINK);
static void
gst_sndiosink_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_set_static_metadata (element_class,
"Sndio audio sink",
"Sink/Audio",
"Plays audio through sndio", "Jacob Meuser <jakemsr@sdf.lonestar.org>");
gst_element_class_add_static_pad_template (element_class,
&sndio_sink_factory);
}
static void
gst_sndiosink_class_init (GstSndioSinkClass * klass)
{
GObjectClass *gobject_class;
GstBaseSinkClass *gstbasesink_class;
GstBaseAudioSinkClass *gstbaseaudiosink_class;
GstAudioSinkClass *gstaudiosink_class;
gobject_class = (GObjectClass *) klass;
gstbasesink_class = (GstBaseSinkClass *) klass;
gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass;
gstaudiosink_class = (GstAudioSinkClass *) klass;
parent_class = g_type_class_peek_parent (klass);
gobject_class->finalize = gst_sndiosink_finalize;
gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_sndiosink_getcaps);
gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_sndiosink_open);
gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_sndiosink_close);
gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_sndiosink_prepare);
gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_sndiosink_unprepare);
gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_sndiosink_write);
gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_sndiosink_delay);
gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_sndiosink_reset);
gobject_class->set_property = gst_sndiosink_set_property;
gobject_class->get_property = gst_sndiosink_get_property;
/* default value is filled in the _init method */
g_object_class_install_property (gobject_class, PROP_HOST,
g_param_spec_string ("host", "Host",
"Device or socket sndio will access", NULL, G_PARAM_READWRITE));
}
static void
gst_sndiosink_init (GstSndioSink * sndiosink, GstSndioSinkClass * klass)
{
sndiosink->hdl = NULL;
sndiosink->host = g_strdup (g_getenv ("AUDIODEVICE"));
}
static void
gst_sndiosink_finalize (GObject * object)
{
GstSndioSink *sndiosink = GST_SNDIOSINK (object);
gst_caps_replace (&sndiosink->cur_caps, NULL);
g_free (sndiosink->host);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static GstCaps *
gst_sndiosink_getcaps (GstBaseSink * bsink)
{
GstSndioSink *sndiosink;
sndiosink = GST_SNDIOSINK (bsink);
/* no hdl, we're done with the template caps */
if (sndiosink->cur_caps == NULL) {
GST_LOG_OBJECT (sndiosink, "getcaps called, returning template caps");
return NULL;
}
GST_LOG_OBJECT (sndiosink, "returning %" GST_PTR_FORMAT, sndiosink->cur_caps);
return gst_caps_ref (sndiosink->cur_caps);
}
static gboolean
gst_sndiosink_open (GstAudioSink * asink)
{
GstPadTemplate *pad_template;
GstSndioSink *sndiosink;
struct sio_par par;
struct sio_cap cap;
GArray *rates, *chans;
GValue rates_v = { 0 };
GValue chans_v = { 0 };
GValue value = { 0 };
struct sio_enc enc;
struct sio_conf conf;
int confs[SIO_NCONF];
int rate, chan;
int i, j, k;
int nconfs;
sndiosink = GST_SNDIOSINK (asink);
GST_DEBUG_OBJECT (sndiosink, "open");
/* conect */
sndiosink->hdl = sio_open (sndiosink->host, SIO_PLAY, 0);
if (sndiosink->hdl == NULL)
goto couldnt_connect;
/* Use sndio defaults as the only encodings, but get the supported
* sample rates and number of channels.
*/
if (!sio_getpar (sndiosink->hdl, &par))
goto no_server_info;
if (!sio_getcap (sndiosink->hdl, &cap))
goto no_server_info;
rates = g_array_new (FALSE, FALSE, sizeof (int));
chans = g_array_new (FALSE, FALSE, sizeof (int));
/* find confs that have the default encoding */
nconfs = 0;
for (i = 0; i < cap.nconf; i++) {
for (j = 0; j < SIO_NENC; j++) {
if (cap.confs[i].enc & (1 << j)) {
enc = cap.enc[j];
if (enc.bits == par.bits && enc.sig == par.sig && enc.le == par.le) {
confs[nconfs] = i;
nconfs++;
break;
}
}
}
}
/* find the rates and channels of the confs that have the default encoding */
for (i = 0; i < nconfs; i++) {
conf = cap.confs[confs[i]];
/* rates */
for (j = 0; j < SIO_NRATE; j++) {
if (conf.rate & (1 << j)) {
rate = cap.rate[j];
for (k = 0; k < rates->len && rate; k++) {
if (rate == g_array_index (rates, int, k))
rate = 0;
}
/* add in ascending order */
if (rate) {
for (k = 0; k < rates->len; k++) {
if (rate < g_array_index (rates, int, k))
{
g_array_insert_val (rates, k, rate);
break;
}
}
if (k == rates->len)
g_array_append_val (rates, rate);
}
}
}
/* channels */
for (j = 0; j < SIO_NCHAN; j++) {
if (conf.pchan & (1 << j)) {
chan = cap.pchan[j];
for (k = 0; k < chans->len && chan; k++) {
if (chan == g_array_index (chans, int, k))
chan = 0;
}
/* add in ascending order */
if (chan) {
for (k = 0; k < chans->len; k++) {
if (chan < g_array_index (chans, int, k))
{
g_array_insert_val (chans, k, chan);
break;
}
}
if (k == chans->len)
g_array_append_val (chans, chan);
}
}
}
}
/* not sure how this can happen, but it might */
if (cap.nconf == 0) {
g_array_append_val (rates, par.rate);
g_array_append_val (chans, par.pchan);
}
g_value_init (&rates_v, GST_TYPE_LIST);
g_value_init (&chans_v, GST_TYPE_LIST);
g_value_init (&value, G_TYPE_INT);
for (i = 0; i < rates->len; i++) {
g_value_set_int (&value, g_array_index (rates, int, i));
gst_value_list_append_value (&rates_v, &value);
}
for (i = 0; i < chans->len; i++) {
g_value_set_int (&value, g_array_index (chans, int, i));
gst_value_list_append_value (&chans_v, &value);
}
g_array_free (rates, TRUE);
g_array_free (chans, TRUE);
pad_template = gst_static_pad_template_get (&sndio_sink_factory);
sndiosink->cur_caps =
gst_caps_copy (gst_pad_template_get_caps (pad_template));
gst_object_unref (pad_template);
for (i = 0; i < sndiosink->cur_caps->structs->len; i++) {
GstStructure *s;
s = gst_caps_get_structure (sndiosink->cur_caps, i);
gst_structure_set (s, "endianness", G_TYPE_INT, par.le ? 1234 : 4321, NULL);
gst_structure_set (s, "signed", G_TYPE_BOOLEAN, par.sig ? TRUE : FALSE,
NULL);
gst_structure_set (s, "width", G_TYPE_INT, par.bits, NULL);
// gst_structure_set (s, "depth", G_TYPE_INT, par.bps * 8, NULL); /* XXX */
gst_structure_set_value (s, "rate", &rates_v);
gst_structure_set_value (s, "channels", &chans_v);
}
return TRUE;
/* ERRORS */
couldnt_connect:
{
GST_ELEMENT_ERROR (sndiosink, RESOURCE, OPEN_WRITE,
(_("Could not establish connection to sndio")),
("can't open connection to sndio"));
return FALSE;
}
no_server_info:
{
GST_ELEMENT_ERROR (sndiosink, RESOURCE, OPEN_WRITE,
(_("Failed to query sndio capabilities")),
("couldn't get sndio info!"));
return FALSE;
}
}
static gboolean
gst_sndiosink_close (GstAudioSink * asink)
{
GstSndioSink *sndiosink = GST_SNDIOSINK (asink);
GST_DEBUG_OBJECT (sndiosink, "close");
gst_caps_replace (&sndiosink->cur_caps, NULL);
sio_close (sndiosink->hdl);
sndiosink->hdl = NULL;
return TRUE;
}
static void
gst_sndiosink_cb (void *addr, int delta)
{
GstSndioSink *sndiosink = GST_SNDIOSINK ((GstAudioSink *) addr);
sndiosink->realpos += delta;
if (sndiosink->realpos >= sndiosink->playpos)
sndiosink->latency = 0;
else
sndiosink->latency = sndiosink->playpos - sndiosink->realpos;
}
static gboolean
gst_sndiosink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
{
GstSndioSink *sndiosink = GST_SNDIOSINK (asink);
struct sio_par par;
int spec_bpf;
GST_DEBUG_OBJECT (sndiosink, "prepare");
sndiosink->playpos = sndiosink->realpos = sndiosink->latency = 0;
sio_initpar (&par);
par.sig = spec->sign;
par.le = !spec->bigend;
par.bits = spec->width;
// par.bps = spec->depth / 8; /* XXX */
par.rate = spec->rate;
par.pchan = spec->channels;
spec_bpf = ((spec->width / 8) * spec->channels);
par.appbufsz = (spec->segsize * spec->segtotal) / spec_bpf;
if (!sio_setpar (sndiosink->hdl, &par))
goto cannot_configure;
sio_getpar (sndiosink->hdl, &par);
spec->sign = par.sig;
spec->bigend = !par.le;
spec->width = par.bits;
// spec->depth = par.bps * 8; /* XXX */
spec->rate = par.rate;
spec->channels = par.pchan;
sndiosink->bpf = par.bps * par.pchan;
spec->segsize = par.round * par.pchan * par.bps;
spec->segtotal = par.bufsz / par.round;
/* FIXME: this is wrong for signed ints (and the
* audioringbuffers should do it for us anyway) */
spec->silence_sample[0] = 0;
spec->silence_sample[1] = 0;
spec->silence_sample[2] = 0;
spec->silence_sample[3] = 0;
sio_onmove (sndiosink->hdl, gst_sndiosink_cb, sndiosink);
if (!sio_start (sndiosink->hdl))
goto cannot_start;
GST_INFO_OBJECT (sndiosink, "successfully opened connection to sndio");
return TRUE;
/* ERRORS */
cannot_configure:
{
GST_ELEMENT_ERROR (sndiosink, RESOURCE, OPEN_WRITE,
(_("Could not configure sndio")), ("can't configure sndio"));
return FALSE;
}
cannot_start:
{
GST_ELEMENT_ERROR (sndiosink, RESOURCE, OPEN_WRITE,
(_("Could not start sndio")), ("can't start sndio"));
return FALSE;
}
}
static gboolean
gst_sndiosink_unprepare (GstAudioSink * asink)
{
GstSndioSink *sndiosink = GST_SNDIOSINK (asink);
if (sndiosink->hdl == NULL)
return TRUE;
sio_stop (sndiosink->hdl);
return TRUE;
}
static guint
gst_sndiosink_write (GstAudioSink * asink, gpointer data, guint length)
{
GstSndioSink *sndiosink = GST_SNDIOSINK (asink);
guint done;
done = sio_write (sndiosink->hdl, data, length);
if (done == 0)
goto write_error;
sndiosink->playpos += (done / sndiosink->bpf);
data = (char *) data + done;
return done;
/* ERRORS */
write_error:
{
GST_ELEMENT_ERROR (sndiosink, RESOURCE, WRITE,
("Failed to write data to sndio"), GST_ERROR_SYSTEM);
return 0;
}
}
static guint
gst_sndiosink_delay (GstAudioSink * asink)
{
GstSndioSink *sndiosink = GST_SNDIOSINK (asink);
if (sndiosink->latency == (guint) - 1) {
GST_WARNING_OBJECT (asink, "couldn't get latency");
return 0;
}
GST_DEBUG_OBJECT (asink, "got latency: %u", sndiosink->latency);
return sndiosink->latency;
}
static void
gst_sndiosink_reset (GstAudioSink * asink)
{
/* no way to flush the buffers with sndio ? */
GST_DEBUG_OBJECT (asink, "reset called");
}
static void
gst_sndiosink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstSndioSink *sndiosink = GST_SNDIOSINK (object);
switch (prop_id) {
case PROP_HOST:
g_free (sndiosink->host);
sndiosink->host = g_value_dup_string (value);
break;
default:
break;
}
}
static void
gst_sndiosink_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstSndioSink *sndiosink = GST_SNDIOSINK (object);
switch (prop_id) {
case PROP_HOST:
g_value_set_string (value, sndiosink->host);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}

View file

@ -1,67 +0,0 @@
/*
* Copyright (C) <2008> Jacob Meuser <jakemsr@sdf.lonestar.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __GST_SNDIOSINK_H__
#define __GST_SNDIOSINK_H__
#include <sndio.h>
#include <gst/gst.h>
#include <gst/audio/gstaudiosink.h>
G_BEGIN_DECLS
#define GST_TYPE_SNDIOSINK \
(gst_sndiosink_get_type())
#define GST_SNDIOSINK(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SNDIOSINK,GstSndioSink))
#define GST_SNDIOSINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SNDIOSINK,GstSndioSinkClass))
#define GST_IS_SNDIOSINK(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SNDIOSINK))
#define GST_IS_SNDIOSINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SNDIOSINK))
typedef struct _GstSndioSink GstSndioSink;
typedef struct _GstSndioSinkClass GstSndioSinkClass;
struct _GstSndioSink {
GstAudioSink sink;
struct sio_hdl *hdl;
gchar *host;
/* bytes per frame */
int bpf;
/* frames counts */
volatile long long realpos;
volatile long long playpos;
volatile guint latency;
GstCaps *cur_caps;
};
struct _GstSndioSinkClass {
GstAudioSinkClass parent_class;
};
GType gst_sndiosink_get_type (void);
G_END_DECLS
#endif /* __GST_SNDIOSINK_H__ */

View file

@ -1,524 +0,0 @@
/*
* Copyright (C) <2008> Jacob Meuser <jakemsr@sdf.lonestar.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/**
* SECTION:element-sndiosrc
* @see_also: #GstAutoAudioSrc
*
* <refsect2>
* <para>
* This element retrieves samples from a sound card using sndio.
* </para>
* <para>
* Simple example pipeline that records an Ogg/Vorbis file via sndio:
* <programlisting>
* gst-launch-1.0 -v sndiosrc ! audioconvert ! vorbisenc ! oggmux ! filesink location=foo.ogg
* </programlisting>
* </para>
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "sndiosrc.h"
#include <unistd.h>
#include <errno.h>
#include <gst/gst-i18n-plugin.h>
GST_DEBUG_CATEGORY_EXTERN (gst_sndio_debug);
#define GST_CAT_DEFAULT gst_sndio_debug
enum
{
PROP_0,
PROP_HOST
};
static GstStaticPadTemplate sndio_src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-int, "
"endianness = (int) { 1234, 4321 }, "
"signed = (boolean) { TRUE, FALSE }, "
"width = (int) { 8, 16, 24, 32 }, "
"depth = (int) { 8, 16, 24, 32 }, "
"rate = (int) [ 8000, 192000 ], " "channels = (int) [ 1, 16 ] ")
);
static void gst_sndiosrc_finalize (GObject * object);
static GstCaps *gst_sndiosrc_getcaps (GstBaseSrc * bsrc);
static gboolean gst_sndiosrc_open (GstAudioSrc * asrc);
static gboolean gst_sndiosrc_close (GstAudioSrc * asrc);
static gboolean gst_sndiosrc_prepare (GstAudioSrc * asrc,
GstRingBufferSpec * spec);
static gboolean gst_sndiosrc_unprepare (GstAudioSrc * asrc);
static guint gst_sndiosrc_read (GstAudioSrc * asrc, gpointer data,
guint length);
static guint gst_sndiosrc_delay (GstAudioSrc * asrc);
static void gst_sndiosrc_reset (GstAudioSrc * asrc);
static void gst_sndiosrc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_sndiosrc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_sndiosrc_cb (void *addr, int delta);
GST_BOILERPLATE (GstSndioSrc, gst_sndiosrc, GstAudioSrc, GST_TYPE_AUDIO_SRC);
static void
gst_sndiosrc_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_set_static_metadata (element_class,
"Sndio audio source",
"Source/Audio",
"Records audio through sndio", "Jacob Meuser <jakemsr@sdf.lonestar.org>");
gst_element_class_add_static_pad_template (element_class, &sndio_src_factory);
}
static void
gst_sndiosrc_class_init (GstSndioSrcClass * klass)
{
GObjectClass *gobject_class;
GstBaseSrcClass *gstbasesrc_class;
GstBaseAudioSrcClass *gstbaseaudiosrc_class;
GstAudioSrcClass *gstaudiosrc_class;
gobject_class = (GObjectClass *) klass;
gstbasesrc_class = (GstBaseSrcClass *) klass;
gstbaseaudiosrc_class = (GstBaseAudioSrcClass *) klass;
gstaudiosrc_class = (GstAudioSrcClass *) klass;
parent_class = g_type_class_peek_parent (klass);
gobject_class->finalize = gst_sndiosrc_finalize;
gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_sndiosrc_getcaps);
gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_sndiosrc_open);
gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_sndiosrc_close);
gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_sndiosrc_prepare);
gstaudiosrc_class->unprepare = GST_DEBUG_FUNCPTR (gst_sndiosrc_unprepare);
gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_sndiosrc_read);
gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_sndiosrc_delay);
gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_sndiosrc_reset);
gobject_class->set_property = gst_sndiosrc_set_property;
gobject_class->get_property = gst_sndiosrc_get_property;
/* default value is filled in the _init method */
g_object_class_install_property (gobject_class, PROP_HOST,
g_param_spec_string ("host", "Host",
"Device or socket sndio will access", NULL, G_PARAM_READWRITE));
}
static void
gst_sndiosrc_init (GstSndioSrc * sndiosrc, GstSndioSrcClass * klass)
{
sndiosrc->hdl = NULL;
sndiosrc->host = g_strdup (g_getenv ("AUDIODEVICE"));
}
static void
gst_sndiosrc_finalize (GObject * object)
{
GstSndioSrc *sndiosrc = GST_SNDIOSRC (object);
gst_caps_replace (&sndiosrc->cur_caps, NULL);
g_free (sndiosrc->host);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static GstCaps *
gst_sndiosrc_getcaps (GstBaseSrc * bsrc)
{
GstSndioSrc *sndiosrc;
sndiosrc = GST_SNDIOSRC (bsrc);
/* no hdl, we're done with the template caps */
if (sndiosrc->cur_caps == NULL) {
GST_LOG_OBJECT (sndiosrc, "getcaps called, returning template caps");
return NULL;
}
GST_LOG_OBJECT (sndiosrc, "returning %" GST_PTR_FORMAT, sndiosrc->cur_caps);
return gst_caps_ref (sndiosrc->cur_caps);
}
static gboolean
gst_sndiosrc_open (GstAudioSrc * asrc)
{
GstPadTemplate *pad_template;
GstSndioSrc *sndiosrc;
struct sio_par par;
struct sio_cap cap;
GArray *rates, *chans;
GValue rates_v = { 0 };
GValue chans_v = { 0 };
GValue value = { 0 };
struct sio_enc enc;
struct sio_conf conf;
int confs[SIO_NCONF];
int rate, chan;
int i, j, k;
int nconfs;
sndiosrc = GST_SNDIOSRC (asrc);
GST_DEBUG_OBJECT (sndiosrc, "open");
/* connect */
sndiosrc->hdl = sio_open (sndiosrc->host, SIO_REC, 0);
if (sndiosrc->hdl == NULL)
goto couldnt_connect;
/* Use sndio defaults as the only encodings, but get the supported
* sample rates and number of channels.
*/
if (!sio_getpar (sndiosrc->hdl, &par))
goto no_server_info;
if (!sio_getcap (sndiosrc->hdl, &cap))
goto no_server_info;
rates = g_array_new (FALSE, FALSE, sizeof (int));
chans = g_array_new (FALSE, FALSE, sizeof (int));
/* find confs that have the default encoding */
nconfs = 0;
for (i = 0; i < cap.nconf; i++) {
for (j = 0; j < SIO_NENC; j++) {
if (cap.confs[i].enc & (1 << j)) {
enc = cap.enc[j];
if (enc.bits == par.bits && enc.sig == par.sig && enc.le == par.le) {
confs[nconfs] = i;
nconfs++;
break;
}
}
}
}
/* find the rates and channels of the confs that have the default encoding */
for (i = 0; i < nconfs; i++) {
conf = cap.confs[confs[i]];
/* rates */
for (j = 0; j < SIO_NRATE; j++) {
if (conf.rate & (1 << j)) {
rate = cap.rate[j];
for (k = 0; k < rates->len && rate; k++) {
if (rate == g_array_index (rates, int, k))
rate = 0;
}
/* add in ascending order */
if (rate) {
for (k = 0; k < rates->len; k++) {
if (rate < g_array_index (rates, int, k))
{
g_array_insert_val (rates, k, rate);
break;
}
}
if (k == rates->len)
g_array_append_val (rates, rate);
}
}
}
/* channels */
for (j = 0; j < SIO_NCHAN; j++) {
if (conf.rchan & (1 << j)) {
chan = cap.rchan[j];
for (k = 0; k < chans->len && chan; k++) {
if (chan == g_array_index (chans, int, k))
chan = 0;
}
/* add in ascending order */
if (chan) {
for (k = 0; k < chans->len; k++) {
if (chan < g_array_index (chans, int, k))
{
g_array_insert_val (chans, k, chan);
break;
}
}
if (k == chans->len)
g_array_append_val (chans, chan);
}
}
}
}
/* not sure how this can happen, but it might */
if (cap.nconf == 0) {
g_array_append_val (rates, par.rate);
g_array_append_val (chans, par.rchan);
}
g_value_init (&rates_v, GST_TYPE_LIST);
g_value_init (&chans_v, GST_TYPE_LIST);
g_value_init (&value, G_TYPE_INT);
for (i = 0; i < rates->len; i++) {
g_value_set_int (&value, g_array_index (rates, int, i));
gst_value_list_append_value (&rates_v, &value);
}
for (i = 0; i < chans->len; i++) {
g_value_set_int (&value, g_array_index (chans, int, i));
gst_value_list_append_value (&chans_v, &value);
}
g_array_free (rates, TRUE);
g_array_free (chans, TRUE);
pad_template = gst_static_pad_template_get (&sndio_src_factory);
sndiosrc->cur_caps = gst_caps_copy (gst_pad_template_get_caps (pad_template));
gst_object_unref (pad_template);
for (i = 0; i < sndiosrc->cur_caps->structs->len; i++) {
GstStructure *s;
s = gst_caps_get_structure (sndiosrc->cur_caps, i);
gst_structure_set (s, "endianness", G_TYPE_INT, par.le ? 1234 : 4321, NULL);
gst_structure_set (s, "signed", G_TYPE_BOOLEAN, par.sig ? TRUE : FALSE,
NULL);
gst_structure_set (s, "width", G_TYPE_INT, par.bits, NULL);
// gst_structure_set (s, "depth", G_TYPE_INT, par.bps * 8, NULL); /* XXX */
gst_structure_set_value (s, "rate", &rates_v);
gst_structure_set_value (s, "channels", &chans_v);
}
return TRUE;
/* ERRORS */
couldnt_connect:
{
GST_ELEMENT_ERROR (sndiosrc, RESOURCE, OPEN_READ,
(_("Could not establish connection to sndio")),
("can't open connection to sndio"));
return FALSE;
}
no_server_info:
{
GST_ELEMENT_ERROR (sndiosrc, RESOURCE, OPEN_READ,
(_("Failed to query sndio capabilities")),
("couldn't get sndio info!"));
return FALSE;
}
}
static gboolean
gst_sndiosrc_close (GstAudioSrc * asrc)
{
GstSndioSrc *sndiosrc = GST_SNDIOSRC (asrc);
GST_DEBUG_OBJECT (sndiosrc, "close");
gst_caps_replace (&sndiosrc->cur_caps, NULL);
sio_close (sndiosrc->hdl);
sndiosrc->hdl = NULL;
return TRUE;
}
static void
gst_sndiosrc_cb (void *addr, int delta)
{
GstSndioSrc *sndiosrc = GST_SNDIOSRC ((GstAudioSrc *) addr);
sndiosrc->realpos += delta;
if (sndiosrc->readpos >= sndiosrc->realpos)
sndiosrc->latency = 0;
else
sndiosrc->latency = sndiosrc->realpos - sndiosrc->readpos;
}
static gboolean
gst_sndiosrc_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec)
{
GstSndioSrc *sndiosrc = GST_SNDIOSRC (asrc);
struct sio_par par;
int spec_bpf;
GST_DEBUG_OBJECT (sndiosrc, "prepare");
sndiosrc->readpos = sndiosrc->realpos = sndiosrc->latency = 0;
sio_initpar (&par);
par.sig = spec->sign;
par.le = !spec->bigend;
par.bits = spec->width;
// par.bps = spec->depth / 8; /* XXX */
par.rate = spec->rate;
par.rchan = spec->channels;
spec_bpf = ((spec->width / 8) * spec->channels);
par.round = spec->segsize / spec_bpf;
par.appbufsz = (spec->segsize * spec->segtotal) / spec_bpf;
if (!sio_setpar (sndiosrc->hdl, &par))
goto cannot_configure;
sio_getpar (sndiosrc->hdl, &par);
spec->sign = par.sig;
spec->bigend = !par.le;
spec->width = par.bits;
// spec->depth = par.bps * 8; /* XXX */
spec->rate = par.rate;
spec->channels = par.rchan;
sndiosrc->bpf = par.bps * par.rchan;
spec->segsize = par.round * par.rchan * par.bps;
spec->segtotal = par.bufsz / par.round;
/* FIXME: this is wrong for signed ints (and the
* audioringbuffers should do it for us anyway) */
spec->silence_sample[0] = 0;
spec->silence_sample[1] = 0;
spec->silence_sample[2] = 0;
spec->silence_sample[3] = 0;
sio_onmove (sndiosrc->hdl, gst_sndiosrc_cb, sndiosrc);
if (!sio_start (sndiosrc->hdl))
goto cannot_start;
GST_INFO_OBJECT (sndiosrc, "successfully opened connection to sndio");
return TRUE;
/* ERRORS */
cannot_configure:
{
GST_ELEMENT_ERROR (sndiosrc, RESOURCE, OPEN_READ,
(_("Could not configure sndio")), ("can't configure sndio"));
return FALSE;
}
cannot_start:
{
GST_ELEMENT_ERROR (sndiosrc, RESOURCE, OPEN_READ,
(_("Could not start sndio")), ("can't start sndio"));
return FALSE;
}
}
static gboolean
gst_sndiosrc_unprepare (GstAudioSrc * asrc)
{
GstSndioSrc *sndiosrc = GST_SNDIOSRC (asrc);
if (sndiosrc->hdl == NULL)
return TRUE;
sio_stop (sndiosrc->hdl);
return TRUE;
}
static guint
gst_sndiosrc_read (GstAudioSrc * asrc, gpointer data, guint length)
{
GstSndioSrc *sndiosrc = GST_SNDIOSRC (asrc);
guint done;
done = sio_read (sndiosrc->hdl, data, length);
if (done == 0)
goto read_error;
sndiosrc->readpos += (done / sndiosrc->bpf);
data = (char *) data + done;
return done;
/* ERRORS */
read_error:
{
GST_ELEMENT_ERROR (sndiosrc, RESOURCE, READ,
("Failed to read data from sndio"), GST_ERROR_SYSTEM);
return 0;
}
}
static guint
gst_sndiosrc_delay (GstAudioSrc * asrc)
{
GstSndioSrc *sndiosrc = GST_SNDIOSRC (asrc);
if (sndiosrc->latency == (guint) - 1) {
GST_WARNING_OBJECT (asrc, "couldn't get latency");
return 0;
}
GST_DEBUG_OBJECT (asrc, "got latency: %u", sndiosrc->latency);
return sndiosrc->latency;
}
static void
gst_sndiosrc_reset (GstAudioSrc * asrc)
{
/* no way to flush the buffers with sndio ? */
GST_DEBUG_OBJECT (asrc, "reset called");
}
static void
gst_sndiosrc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstSndioSrc *sndiosrc = GST_SNDIOSRC (object);
switch (prop_id) {
case PROP_HOST:
g_free (sndiosrc->host);
sndiosrc->host = g_value_dup_string (value);
break;
default:
break;
}
}
static void
gst_sndiosrc_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstSndioSrc *sndiosrc = GST_SNDIOSRC (object);
switch (prop_id) {
case PROP_HOST:
g_value_set_string (value, sndiosrc->host);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}

View file

@ -1,67 +0,0 @@
/*
* Copyright (C) <2008> Jacob Meuser <jakemsr@sdf.lonestar.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __GST_SNDIOSRC_H__
#define __GST_SNDIOSRC_H__
#include <sndio.h>
#include <gst/gst.h>
#include <gst/audio/gstaudiosrc.h>
G_BEGIN_DECLS
#define GST_TYPE_SNDIOSRC \
(gst_sndiosrc_get_type())
#define GST_SNDIOSRC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SNDIOSRC,GstSndioSrc))
#define GST_SNDIOSRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SNDIOSRC,GstSndioSrcClass))
#define GST_IS_SNDIOSRC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SNDIOSRC))
#define GST_IS_SNDIOSRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SNDIOSRC))
typedef struct _GstSndioSrc GstSndioSrc;
typedef struct _GstSndioSrcClass GstSndioSrcClass;
struct _GstSndioSrc {
GstAudioSrc src;
struct sio_hdl *hdl;
gchar *host;
/* bytes per frame */
int bpf;
/* frames counts */
volatile long long realpos;
volatile long long readpos;
volatile guint latency;
GstCaps *cur_caps;
};
struct _GstSndioSrcClass {
GstAudioSrcClass parent_class;
};
GType gst_sndiosrc_get_type (void);
G_END_DECLS
#endif /* __GST_SNDIOSRC_H__ */

View file

@ -1,821 +0,0 @@
/*
* gsttimdity - timidity plugin for gstreamer
*
* Copyright 2007 Wouter Paesen <wouter@blue-gate.be>
*
* 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-timidity
* @see_also: wildmidi
*
* This element renders midi-files as audio streams using
* <ulink url="http://timidity.sourceforge.net/">Timidity</ulink>.
*
* <refsect2>
* <title>Example pipeline</title>
* |[
* gst-launch filesrc location=song.mid ! timidity ! alsasink
* ]| This example pipeline will parse the midi and render to raw audio which is
* played via alsa.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <gst/gst.h>
#include <string.h>
#include "gsttimidity.h"
#ifndef TIMIDITY_CFG
#define TIMIDITY_CFG "/etc/timidity.cfg"
#endif
GST_DEBUG_CATEGORY_STATIC (gst_timidity_debug);
#define GST_CAT_DEFAULT gst_timidity_debug
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
ARG_0,
/* FILL ME */
};
static gboolean gst_timidity_src_event (GstPad * pad, GstEvent * event);
static GstStateChangeReturn gst_timidity_change_state (GstElement * element,
GstStateChange transition);
static gboolean gst_timidity_activate (GstPad * pad);
static gboolean gst_timidity_activatepull (GstPad * pad, gboolean active);
static void gst_timidity_loop (GstPad * sinkpad);
static gboolean gst_timidity_src_query (GstPad * pad, GstQuery * query);
static gboolean gst_timidity_set_song_options (GstTimidity * timidity,
MidSongOptions * options);
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/midi; audio/riff-midi")
);
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-int, "
"rate = (int) 44100, "
"channels = (int) 2, "
"endianness = (int) LITTLE_ENDIAN, "
"width = (int) 16, " "depth = (int) 16, " "signed = (boolean) true"));
GST_BOILERPLATE (GstTimidity, gst_timidity, GstElement, GST_TYPE_ELEMENT);
static void
gst_timidity_base_init (gpointer gclass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
gst_element_class_add_static_pad_template (element_class, &src_factory);
gst_element_class_add_static_pad_template (element_class, &sink_factory);
gst_element_class_set_static_metadata (element_class, "Timidity",
"Codec/Decoder/Audio",
"Midi Synthesizer Element", "Wouter Paesen <wouter@blue-gate.be>");
}
/* initialize the plugin's class */
static void
gst_timidity_class_init (GstTimidityClass * klass)
{
GstElementClass *gstelement_class;
gstelement_class = (GstElementClass *) klass;
gstelement_class->change_state = gst_timidity_change_state;
}
/* initialize the new element
* instantiate pads and add them to element
* set functions
* initialize structure
*/
static void
gst_timidity_init (GstTimidity * filter, GstTimidityClass * g_class)
{
GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter);
/* initialise timidity library */
if (mid_init ((char *) TIMIDITY_CFG) == 0) {
filter->initialized = TRUE;
} else {
GST_WARNING ("can't initialize timidity with config: " TIMIDITY_CFG);
}
filter->sinkpad =
gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
"sink"), "sink");
gst_pad_set_activatepull_function (filter->sinkpad,
gst_timidity_activatepull);
gst_pad_set_activate_function (filter->sinkpad, gst_timidity_activate);
gst_pad_set_setcaps_function (filter->sinkpad, gst_pad_set_caps);
gst_pad_use_fixed_caps (filter->sinkpad);
gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
filter->srcpad =
gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
"src"), "src");
gst_pad_set_query_function (filter->srcpad, gst_timidity_src_query);
gst_pad_set_event_function (filter->srcpad, gst_timidity_src_event);
gst_pad_use_fixed_caps (filter->srcpad);
gst_pad_set_setcaps_function (filter->srcpad, gst_pad_set_caps);
gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
filter->song_options->buffer_size = 2048;
filter->song_options->rate = 44100;
filter->song_options->format = MID_AUDIO_S16LSB;
filter->song_options->channels = 2;
gst_timidity_set_song_options (filter, filter->song_options);
gst_segment_init (filter->o_segment, GST_FORMAT_DEFAULT);
}
static gboolean
gst_timidity_set_song_options (GstTimidity * timidity, MidSongOptions * options)
{
gint64 bps;
switch (options->format) {
case MID_AUDIO_U8:
case MID_AUDIO_S8:
bps = 1;
break;
case MID_AUDIO_U16LSB:
case MID_AUDIO_S16LSB:
case MID_AUDIO_U16MSB:
case MID_AUDIO_S16MSB:
bps = 2;
break;
default:
return FALSE;
}
bps *= options->channels;
if (options != timidity->song_options)
memcpy (timidity->song_options, options, sizeof (MidSongOptions));
timidity->bytes_per_frame = bps;
timidity->time_per_frame = GST_SECOND / (GstClockTime) options->rate;
return TRUE;
}
static gboolean
gst_timidity_src_convert (GstTimidity * timidity,
GstFormat src_format, gint64 src_value,
GstFormat * dest_format, gint64 * dest_value)
{
gboolean res = TRUE;
gint64 frames;
if (src_format == *dest_format) {
*dest_value = src_value;
goto done;
}
switch (src_format) {
case GST_FORMAT_TIME:
frames = src_value / timidity->time_per_frame;
break;
case GST_FORMAT_BYTES:
frames = src_value / (timidity->bytes_per_frame);
break;
case GST_FORMAT_DEFAULT:
frames = src_value;
break;
default:
res = FALSE;
goto done;
}
switch (*dest_format) {
case GST_FORMAT_TIME:
*dest_value = frames * timidity->time_per_frame;
break;
case GST_FORMAT_BYTES:
*dest_value = frames * timidity->bytes_per_frame;
break;
case GST_FORMAT_DEFAULT:
*dest_value = frames;
break;
default:
res = FALSE;
break;
}
done:
return res;
}
static gboolean
gst_timidity_src_query (GstPad * pad, GstQuery * query)
{
gboolean res = TRUE;
GstTimidity *timidity = GST_TIMIDITY (gst_pad_get_parent (pad));
GstFormat src_format, dst_format;
gint64 src_value, dst_value;
if (!timidity->song) {
gst_object_unref (timidity);
return FALSE;
}
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_DURATION:
gst_query_set_duration (query, GST_FORMAT_TIME,
GST_MSECOND * (gint64) mid_song_get_total_time (timidity->song));
break;
case GST_QUERY_POSITION:
gst_query_set_position (query, GST_FORMAT_TIME,
timidity->o_segment->last_stop * timidity->time_per_frame);
break;
case GST_QUERY_CONVERT:
gst_query_parse_convert (query, &src_format, &src_value,
&dst_format, NULL);
res =
gst_timidity_src_convert (timidity, src_format, src_value,
&dst_format, &dst_value);
if (res)
gst_query_set_convert (query, src_format, src_value, dst_format,
dst_value);
break;
case GST_QUERY_FORMATS:
gst_query_set_formats (query, 3,
GST_FORMAT_TIME, GST_FORMAT_BYTES, GST_FORMAT_DEFAULT);
break;
case GST_QUERY_SEGMENT:{
GstFormat format;
gint64 start, stop;
format = timidity->o_segment->format;
start =
gst_segment_to_stream_time (timidity->o_segment, format,
timidity->o_segment->start);
if ((stop = timidity->o_segment->stop) == -1)
stop = timidity->o_segment->duration;
else
stop = gst_segment_to_stream_time (timidity->o_segment, format, stop);
gst_query_set_segment (query, timidity->o_segment->rate, format, start,
stop);
res = TRUE;
break;
}
case GST_QUERY_SEEKING:
gst_query_set_seeking (query, timidity->o_segment->format,
TRUE, 0, timidity->o_len);
break;
default:
res = FALSE;
break;
}
gst_object_unref (timidity);
return res;
}
static gboolean
gst_timidity_get_upstream_size (GstTimidity * timidity, gint64 * size)
{
GstFormat format = GST_FORMAT_BYTES;
gboolean res = FALSE;
GstPad *peer = gst_pad_get_peer (timidity->sinkpad);
if (peer != NULL)
res = gst_pad_query_duration (peer, &format, size) && *size >= 0;
gst_object_unref (peer);
return res;
}
static GstSegment *
gst_timidity_get_segment (GstTimidity * timidity, GstFormat format,
gboolean update)
{
gint64 start = 0, stop = 0, time = 0;
GstSegment *segment = gst_segment_new ();
gst_timidity_src_convert (timidity,
timidity->o_segment->format, timidity->o_segment->start, &format, &start);
if (timidity->o_segment->stop == GST_CLOCK_TIME_NONE) {
stop = GST_CLOCK_TIME_NONE;
} else {
gst_timidity_src_convert (timidity,
timidity->o_segment->format, timidity->o_segment->stop, &format, &stop);
}
gst_timidity_src_convert (timidity,
timidity->o_segment->format, timidity->o_segment->time, &format, &time);
gst_segment_set_newsegment_full (segment, update,
timidity->o_segment->rate, timidity->o_segment->applied_rate,
format, start, stop, time);
segment->last_stop = time;
return segment;
}
static GstEvent *
gst_timidity_get_new_segment_event (GstTimidity * timidity, GstFormat format,
gboolean update)
{
GstSegment *segment;
GstEvent *event;
segment = gst_timidity_get_segment (timidity, format, update);
event = gst_event_new_new_segment_full (update,
segment->rate, segment->applied_rate, segment->format,
segment->start, segment->stop, segment->time);
gst_segment_free (segment);
return event;
}
static gboolean
gst_timidity_src_event (GstPad * pad, GstEvent * event)
{
gboolean res = FALSE;
GstTimidity *timidity = GST_TIMIDITY (gst_pad_get_parent (pad));
GST_DEBUG_OBJECT (pad, "%s event received", GST_EVENT_TYPE_NAME (event));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK:
{
gdouble rate;
GstFormat src_format, dst_format;
GstSeekFlags flags;
GstSeekType start_type, stop_type;
gint64 orig_start, start = 0, stop = 0;
gboolean flush, update;
if (!timidity->song)
break;
gst_event_parse_seek (event, &rate, &src_format, &flags,
&start_type, &orig_start, &stop_type, &stop);
dst_format = GST_FORMAT_DEFAULT;
gst_timidity_src_convert (timidity, src_format, orig_start,
&dst_format, &start);
gst_timidity_src_convert (timidity, src_format, stop, &dst_format, &stop);
flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
if (flush) {
GST_DEBUG ("performing flush");
gst_pad_push_event (timidity->srcpad, gst_event_new_flush_start ());
} else {
gst_pad_stop_task (timidity->sinkpad);
}
GST_PAD_STREAM_LOCK (timidity->sinkpad);
if (flush) {
gst_pad_push_event (timidity->srcpad, gst_event_new_flush_stop ());
}
gst_segment_set_seek (timidity->o_segment, rate, dst_format, flags,
start_type, start, stop_type, stop, &update);
if (flags & GST_SEEK_FLAG_SEGMENT) {
GST_DEBUG_OBJECT (timidity, "received segment seek %d, %d",
(gint) start_type, (gint) stop_type);
} else {
GST_DEBUG_OBJECT (timidity, "received normal seek %d",
(gint) start_type);
update = FALSE;
}
gst_pad_push_event (timidity->srcpad,
gst_timidity_get_new_segment_event (timidity, GST_FORMAT_TIME,
update));
timidity->o_seek = TRUE;
gst_pad_start_task (timidity->sinkpad,
(GstTaskFunction) gst_timidity_loop, timidity->sinkpad, NULL);
GST_PAD_STREAM_UNLOCK (timidity->sinkpad);
GST_DEBUG ("seek done");
}
res = TRUE;
break;
default:
break;
}
g_object_unref (timidity);
return res;
}
static gboolean
gst_timidity_activate (GstPad * sinkpad)
{
if (gst_pad_check_pull_range (sinkpad))
return gst_pad_activate_pull (sinkpad, TRUE);
return FALSE;
}
static gboolean
gst_timidity_activatepull (GstPad * pad, gboolean active)
{
if (active) {
return gst_pad_start_task (pad, (GstTaskFunction) gst_timidity_loop, pad,
NULL);
} else {
return gst_pad_stop_task (pad);
}
}
static GstBuffer *
gst_timidity_allocate_buffer (GstTimidity * timidity, gint64 samples)
{
return gst_buffer_new_and_alloc (samples * timidity->bytes_per_frame);
}
static GstBuffer *
gst_timidity_clip_buffer (GstTimidity * timidity, GstBuffer * buffer)
{
gint64 new_start, new_stop;
gint64 offset, length;
GstBuffer *out;
return buffer;
if (!gst_segment_clip (timidity->o_segment, GST_FORMAT_DEFAULT,
GST_BUFFER_OFFSET (buffer), GST_BUFFER_OFFSET_END (buffer),
&new_start, &new_stop)) {
gst_buffer_unref (buffer);
return NULL;
}
if (GST_BUFFER_OFFSET (buffer) == new_start &&
GST_BUFFER_OFFSET_END (buffer) == new_stop)
return buffer;
offset = new_start - GST_BUFFER_OFFSET (buffer);
length = new_stop - new_start;
out = gst_buffer_create_sub (buffer, offset * timidity->bytes_per_frame,
length * timidity->bytes_per_frame);
GST_BUFFER_OFFSET (out) = new_start;
GST_BUFFER_OFFSET_END (out) = new_stop;
GST_BUFFER_TIMESTAMP (out) = new_start * timidity->time_per_frame;
GST_BUFFER_DURATION (out) = (new_stop - new_start) * timidity->time_per_frame;
gst_buffer_unref (buffer);
return out;
}
/* generate audio data and advance internal timers */
static GstBuffer *
gst_timidity_fill_buffer (GstTimidity * timidity, GstBuffer * buffer)
{
size_t bytes_read;
gint64 samples;
bytes_read = mid_song_read_wave (timidity->song, GST_BUFFER_DATA (buffer),
GST_BUFFER_SIZE (buffer));
if (bytes_read == 0) {
gst_buffer_unref (buffer);
return NULL;
}
GST_BUFFER_OFFSET (buffer) =
timidity->o_segment->last_stop * timidity->bytes_per_frame;
GST_BUFFER_TIMESTAMP (buffer) =
timidity->o_segment->last_stop * timidity->time_per_frame;
if (bytes_read < GST_BUFFER_SIZE (buffer)) {
GstBuffer *old = buffer;
buffer = gst_buffer_create_sub (buffer, 0, bytes_read);
gst_buffer_unref (old);
}
samples = GST_BUFFER_SIZE (buffer) / timidity->bytes_per_frame;
timidity->o_segment->last_stop += samples;
GST_BUFFER_OFFSET_END (buffer) =
timidity->o_segment->last_stop * timidity->bytes_per_frame;
GST_BUFFER_DURATION (buffer) = samples * timidity->time_per_frame;
GST_DEBUG_OBJECT (timidity,
"generated buffer %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT
" (%" G_GINT64_FORMAT " samples)",
GST_TIME_ARGS ((guint64) GST_BUFFER_TIMESTAMP (buffer)),
GST_TIME_ARGS (((guint64) (GST_BUFFER_TIMESTAMP (buffer) +
GST_BUFFER_DURATION (buffer)))), samples);
return buffer;
}
static GstBuffer *
gst_timidity_get_buffer (GstTimidity * timidity)
{
GstBuffer *out;
out =
gst_timidity_fill_buffer (timidity,
gst_timidity_allocate_buffer (timidity, 256));
if (!out)
return NULL;
return gst_timidity_clip_buffer (timidity, out);
}
static void
gst_timidity_loop (GstPad * sinkpad)
{
GstTimidity *timidity = GST_TIMIDITY (GST_PAD_PARENT (sinkpad));
GstBuffer *out;
GstFlowReturn ret;
if (timidity->mididata_size == 0) {
if (!gst_timidity_get_upstream_size (timidity, &timidity->mididata_size)) {
GST_ELEMENT_ERROR (timidity, STREAM, DECODE, (NULL),
("Unable to get song length"));
goto paused;
}
g_free (timidity->mididata);
timidity->mididata = g_malloc (timidity->mididata_size);
timidity->mididata_offset = 0;
return;
}
if (timidity->mididata_offset < timidity->mididata_size) {
GstBuffer *buffer = NULL;
gint64 size;
GST_DEBUG_OBJECT (timidity, "loading song");
ret =
gst_pad_pull_range (timidity->sinkpad, timidity->mididata_offset,
-1, &buffer);
if (ret != GST_FLOW_OK) {
GST_ELEMENT_ERROR (timidity, STREAM, DECODE, (NULL),
("Unable to load song"));
goto paused;
}
size = timidity->mididata_size - timidity->mididata_offset;
if (GST_BUFFER_SIZE (buffer) < size)
size = GST_BUFFER_SIZE (buffer);
memmove (timidity->mididata + timidity->mididata_offset,
GST_BUFFER_DATA (buffer), size);
gst_buffer_unref (buffer);
timidity->mididata_offset += size;
GST_DEBUG_OBJECT (timidity, "Song loaded");
return;
}
if (!timidity->song) {
MidIStream *stream;
GstTagList *tags = NULL;
gchar *text;
GST_DEBUG_OBJECT (timidity, "Parsing song");
#if defined(LIBTIMIDITY_VERSION) && LIBTIMIDITY_VERSION < 0x000200L
stream =
mid_istream_open_mem (timidity->mididata, timidity->mididata_size, 0);
#else
stream = mid_istream_open_mem (timidity->mididata, timidity->mididata_size);
#endif
timidity->song = mid_song_load (stream, timidity->song_options);
mid_istream_close (stream);
if (!timidity->song) {
GST_ELEMENT_ERROR (timidity, STREAM, DECODE, (NULL),
("Unable to parse midi"));
goto paused;
}
mid_song_start (timidity->song);
timidity->o_len = (GST_MSECOND *
(GstClockTime) mid_song_get_total_time (timidity->song)) /
timidity->time_per_frame;
gst_segment_set_newsegment (timidity->o_segment, FALSE, 1.0,
GST_FORMAT_DEFAULT, 0, GST_CLOCK_TIME_NONE, 0);
gst_pad_push_event (timidity->srcpad,
gst_timidity_get_new_segment_event (timidity, GST_FORMAT_TIME, FALSE));
/* extract tags */
text = mid_song_get_meta (timidity->song, MID_SONG_TEXT);
if (text) {
tags = gst_tag_list_new ();
gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_TITLE, text, NULL);
//g_free (text);
}
text = mid_song_get_meta (timidity->song, MID_SONG_COPYRIGHT);
if (text) {
if (tags == NULL)
tags = gst_tag_list_new ();
gst_tag_list_add (tags, GST_TAG_MERGE_APPEND,
GST_TAG_COPYRIGHT, text, NULL);
//g_free (text);
}
if (tags) {
gst_element_found_tags (GST_ELEMENT (timidity), tags);
}
GST_DEBUG_OBJECT (timidity, "Parsing song done");
return;
}
if (timidity->o_segment_changed) {
GstSegment *segment = gst_timidity_get_segment (timidity, GST_FORMAT_TIME,
!timidity->o_new_segment);
GST_LOG_OBJECT (timidity,
"sending newsegment from %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT
", pos=%" GST_TIME_FORMAT, GST_TIME_ARGS ((guint64) segment->start),
GST_TIME_ARGS ((guint64) segment->stop),
GST_TIME_ARGS ((guint64) segment->time));
if (timidity->o_segment->flags & GST_SEEK_FLAG_SEGMENT) {
gst_element_post_message (GST_ELEMENT (timidity),
gst_message_new_segment_start (GST_OBJECT (timidity),
segment->format, segment->start));
}
gst_segment_free (segment);
timidity->o_segment_changed = FALSE;
return;
}
if (timidity->o_seek) {
/* perform a seek internally */
timidity->o_segment->last_stop = timidity->o_segment->time;
mid_song_seek (timidity->song,
(timidity->o_segment->last_stop * timidity->time_per_frame) /
GST_MSECOND);
}
out = gst_timidity_get_buffer (timidity);
if (!out) {
GST_LOG_OBJECT (timidity, "Song ended, generating eos");
gst_pad_push_event (timidity->srcpad, gst_event_new_eos ());
timidity->o_seek = FALSE;
goto paused;
}
if (timidity->o_seek) {
GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DISCONT);
timidity->o_seek = FALSE;
}
gst_buffer_set_caps (out, timidity->out_caps);
ret = gst_pad_push (timidity->srcpad, out);
if (ret == GST_FLOW_UNEXPECTED)
goto eos;
else if (ret < GST_FLOW_UNEXPECTED || ret == GST_FLOW_NOT_LINKED)
goto error;
return;
paused:
{
GST_DEBUG_OBJECT (timidity, "pausing task");
gst_pad_pause_task (timidity->sinkpad);
return;
}
eos:
{
gst_pad_push_event (timidity->srcpad, gst_event_new_eos ());
goto paused;
}
error:
{
GST_ELEMENT_FLOW_ERROR (timidity, ret);
gst_pad_push_event (timidity->srcpad, gst_event_new_eos ());
goto paused;
}
}
static GstStateChangeReturn
gst_timidity_change_state (GstElement * element, GstStateChange transition)
{
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GstTimidity *timidity = GST_TIMIDITY (element);
if (!timidity->initialized) {
GST_WARNING ("Timidity renderer is not initialized");
return GST_STATE_CHANGE_FAILURE;
}
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
timidity->out_caps =
gst_caps_copy (gst_pad_get_pad_template_caps (timidity->srcpad));
timidity->mididata = NULL;
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
timidity->mididata_size = 0;
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
if (timidity->song)
mid_song_free (timidity->song);
timidity->song = NULL;
timidity->mididata_size = 0;
if (timidity->mididata) {
g_free (timidity->mididata);
timidity->mididata = NULL;
}
break;
case GST_STATE_CHANGE_READY_TO_NULL:
gst_caps_unref (timidity->out_caps);
break;
default:
break;
}
return ret;
}
static gboolean
plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (gst_timidity_debug, "timidity",
0, "Timidity plugin");
return gst_element_register (plugin, "timidity",
GST_RANK_PRIMARY, GST_TYPE_TIMIDITY);
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
timidity,
"Timidity Plugin",
plugin_init, VERSION, "GPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

View file

@ -1,84 +0,0 @@
/*
* gsttimdity - timidity plugin for gstreamer
*
* Copyright 2007 Wouter Paesen <wouter@blue-gate.be>
*
* 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.
*
* Wrapper element for libtimidity. This element works in pull
* based mode because that's essentially how libtimidity works.
* We create a libtimidity stream that operates on the srcpad.
* The sinkpad is in pull mode.
*/
#ifndef __GST_TIMIDITY_H__
#define __GST_TIMIDITY_H__
#include <gst/gst.h>
#include <gst/base/gstadapter.h>
#include <timidity.h>
G_BEGIN_DECLS
#define GST_TYPE_TIMIDITY \
(gst_timidity_get_type())
#define GST_TIMIDITY(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TIMIDITY,GstTimidity))
#define GST_TIMIDITY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TIMIDITY,GstTimidityClass))
#define GST_IS_TIMIDITY(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TIMIDITY))
#define GST_IS_TIMIDITY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TIMIDITY))
typedef struct _GstTimidity GstTimidity;
typedef struct _GstTimidityClass GstTimidityClass;
struct _GstTimidity
{
GstElement element;
GstPad *sinkpad, *srcpad;
gboolean initialized;
/* input stream properties */
gint64 mididata_size, mididata_offset;
gchar *mididata;
gboolean mididata_filled;
MidSong *song;
/* output data */
gboolean o_new_segment, o_segment_changed, o_seek;
GstSegment o_segment[1];
gint64 o_len;
/* format of the stream */
MidSongOptions song_options[1];
gint64 bytes_per_frame;
GstClockTime time_per_frame;
GstCaps *out_caps;
};
struct _GstTimidityClass
{
GstElementClass parent_class;
};
GType gst_timidity_get_type (void);
G_END_DECLS
#endif /* __GST_TIMIDITY_H__ */

View file

@ -1,20 +1,6 @@
# plugindir is set in configure
plugin_LTLIBRARIES =
if USE_TIMIDITY
plugin_LTLIBRARIES += libgsttimidity.la
# sources used to compile this plug-in
libgsttimidity_la_SOURCES = gsttimidity.c
# flags used to compile this plugin
# add other _CFLAGS and _LIBS as needed
libgsttimidity_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) $(TIMIDITY_CFLAGS)
libgsttimidity_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) $(TIMIDITY_LIBS)
libgsttimidity_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgsttimidity_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
endif
if USE_WILDMIDI
plugin_LTLIBRARIES += libgstwildmidi.la
@ -29,5 +15,5 @@ libgstwildmidi_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstwildmidi_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
endif
noinst_HEADERS = gsttimidity.h gstwildmidi.h
noinst_HEADERS = gstwildmidi.h

View file

@ -1,9 +0,0 @@
plugin_LTLIBRARIES = libgstxvid.la
libgstxvid_la_SOURCES = gstxvidenc.c gstxviddec.c gstxvid.c
libgstxvid_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(XVID_CFLAGS)
libgstxvid_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(XVID_LIBS)
libgstxvid_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstxvid_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
noinst_HEADERS = gstxvidenc.h gstxviddec.h gstxvid.h

View file

@ -1,371 +0,0 @@
/* GStreamer xvid encoder/decoder plugin
* Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.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 <xvid.h>
#include <gst/video/video.h>
#include "gstxviddec.h"
#include "gstxvidenc.h"
gboolean
gst_xvid_init (void)
{
xvid_gbl_init_t xinit;
gint ret;
static gboolean is_init = FALSE;
/* only init once */
if (is_init == TRUE) {
return TRUE;
}
/* set up xvid initially (function pointers, CPU flags) */
gst_xvid_init_struct (xinit);
if ((ret = xvid_global (NULL, XVID_GBL_INIT, &xinit, NULL)) < 0) {
g_warning ("Failed to initialize XviD: %s (%d)", gst_xvid_error (ret), ret);
return FALSE;
}
GST_LOG ("Initted XviD version %d.%d.%d (API %d.%d)",
XVID_VERSION_MAJOR (XVID_VERSION),
XVID_VERSION_MINOR (XVID_VERSION),
XVID_VERSION_PATCH (XVID_VERSION),
XVID_API_MAJOR (XVID_API), XVID_API_MINOR (XVID_API));
is_init = TRUE;
return TRUE;
}
const gchar *
gst_xvid_error (int errorcode)
{
const gchar *error;
switch (errorcode) {
case XVID_ERR_FAIL:
error = "Operation failed";
break;
case 0:
error = "No error";
break;
case XVID_ERR_MEMORY:
error = "Memory allocation error";
break;
case XVID_ERR_FORMAT:
error = "File format not supported";
break;
case XVID_ERR_VERSION:
error = "Structure version not supported";
break;
default:
error = "Unknown error";
break;
}
return error;
}
gint
gst_xvid_structure_to_csp (GstStructure * structure)
{
const gchar *mime = gst_structure_get_name (structure);
gint xvid_cs = -1;
if (!strcmp (mime, "video/x-raw-yuv")) {
guint32 fourcc;
gst_structure_get_fourcc (structure, "format", &fourcc);
switch (fourcc) {
case GST_MAKE_FOURCC ('I', '4', '2', '0'):
xvid_cs = XVID_CSP_I420;
break;
case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
xvid_cs = XVID_CSP_YUY2;
break;
case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
xvid_cs = XVID_CSP_YV12;
break;
case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
xvid_cs = XVID_CSP_UYVY;
break;
case GST_MAKE_FOURCC ('Y', 'V', 'Y', 'U'):
xvid_cs = XVID_CSP_YVYU;
break;
}
} else {
gint depth, bpp, r_mask;
gst_structure_get_int (structure, "depth", &depth);
gst_structure_get_int (structure, "bpp", &bpp);
gst_structure_get_int (structure, "red_mask", &r_mask);
switch (depth) {
case 15:
xvid_cs = XVID_CSP_RGB555;
break;
case 16:
xvid_cs = XVID_CSP_RGB565;
break;
case 24:
if (bpp == 24) {
xvid_cs = XVID_CSP_BGR;
} else {
switch (r_mask) {
case 0xff000000:
xvid_cs = XVID_CSP_RGBA;
break;
#ifdef XVID_CSP_ARGB
case 0x00ff0000:
xvid_cs = XVID_CSP_ARGB;
break;
#endif
case 0x0000ff00:
xvid_cs = XVID_CSP_BGRA;
break;
case 0x000000ff:
xvid_cs = XVID_CSP_ABGR;
break;
}
}
break;
default:
break;
}
}
return xvid_cs;
}
GstCaps *
gst_xvid_csp_to_caps (gint csp, gint w, gint h)
{
GstStructure *structure = NULL;
switch (csp) {
case XVID_CSP_RGB555:
case XVID_CSP_RGB565:
case XVID_CSP_BGR:
case XVID_CSP_ABGR:
case XVID_CSP_BGRA:
#ifdef XVID_CSP_ARGB
case XVID_CSP_ARGB:
#endif
case XVID_CSP_RGBA:{
gint r_mask = 0, b_mask = 0, g_mask = 0,
endianness = 0, bpp = 0, depth = 0;
switch (csp) {
case XVID_CSP_RGB555:
r_mask = GST_VIDEO_COMP1_MASK_15_INT;
g_mask = GST_VIDEO_COMP2_MASK_15_INT;
b_mask = GST_VIDEO_COMP3_MASK_15_INT;
endianness = G_BYTE_ORDER;
depth = 15;
bpp = 16;
break;
case XVID_CSP_RGB565:
r_mask = GST_VIDEO_COMP1_MASK_16_INT;
g_mask = GST_VIDEO_COMP2_MASK_16_INT;
b_mask = GST_VIDEO_COMP3_MASK_16_INT;
endianness = G_BYTE_ORDER;
depth = 16;
bpp = 16;
break;
case XVID_CSP_BGR:
r_mask = 0x0000ff;
g_mask = 0x00ff00;
b_mask = 0xff0000;
endianness = G_BIG_ENDIAN;
depth = 24;
bpp = 24;
break;
case XVID_CSP_ABGR:
r_mask = 0x000000ff;
g_mask = 0x0000ff00;
b_mask = 0x00ff0000;
endianness = G_BIG_ENDIAN;
depth = 24;
bpp = 32;
break;
case XVID_CSP_BGRA:
r_mask = 0x0000ff00;
g_mask = 0x00ff0000;
b_mask = 0xff000000;
endianness = G_BIG_ENDIAN;
depth = 24;
bpp = 32;
break;
#ifdef XVID_CSP_ARGB
case XVID_CSP_ARGB:
r_mask = 0x00ff0000;
g_mask = 0x0000ff00;
b_mask = 0x000000ff;
endianness = G_BIG_ENDIAN;
depth = 24;
bpp = 32;
break;
#endif
case XVID_CSP_RGBA:
r_mask = 0xff000000;
g_mask = 0x00ff0000;
b_mask = 0x0000ff00;
endianness = G_BIG_ENDIAN;
depth = 24;
bpp = 32;
break;
}
structure = gst_structure_new ("video/x-raw-rgb",
"width", G_TYPE_INT, w,
"height", G_TYPE_INT, h,
"depth", G_TYPE_INT, depth,
"bpp", G_TYPE_INT, bpp,
"endianness", G_TYPE_INT, endianness,
"red_mask", G_TYPE_INT, r_mask,
"green_mask", G_TYPE_INT, g_mask,
"blue_mask", G_TYPE_INT, b_mask, NULL);
break;
}
case XVID_CSP_YUY2:
case XVID_CSP_YVYU:
case XVID_CSP_UYVY:
case XVID_CSP_I420:
case XVID_CSP_YV12:{
guint32 fourcc = 0;
switch (csp) {
case XVID_CSP_YUY2:
fourcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
break;
case XVID_CSP_YVYU:
fourcc = GST_MAKE_FOURCC ('Y', 'V', 'Y', 'U');
break;
case XVID_CSP_UYVY:
fourcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
break;
case XVID_CSP_I420:
fourcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
break;
case XVID_CSP_YV12:
fourcc = GST_MAKE_FOURCC ('Y', 'V', '1', '2');
break;
}
structure = gst_structure_new ("video/x-raw-yuv",
"width", G_TYPE_INT, w,
"height", G_TYPE_INT, h, "format", GST_TYPE_FOURCC, fourcc, NULL);
break;
}
}
return gst_caps_new_full (structure, NULL);
}
gint
gst_xvid_image_get_size (gint csp, gint width, gint height)
{
xvid_image_t dummy_im;
return gst_xvid_image_fill (&dummy_im, NULL, csp, width, height);
}
gint
gst_xvid_image_fill (xvid_image_t * im, void *ptr, gint csp,
gint width, gint height)
{
gint stride, h2, size = 0;
im->csp = csp;
switch (csp) {
case XVID_CSP_I420:
case XVID_CSP_YV12:
/* planar */
/* luma */
stride = GST_ROUND_UP_4 (width);
h2 = GST_ROUND_UP_2 (height);
im->stride[0] = stride;
im->plane[0] = ptr;
/* chroma */
im->plane[1] = ((guint8 *) im->plane[0]) + (stride * h2);
size += stride * height;
stride = GST_ROUND_UP_8 (width) / 2;
h2 = GST_ROUND_UP_2 (height) / 2;
im->stride[1] = stride;
im->plane[2] = ((guint8 *) im->plane[1]) + (stride * h2);
im->stride[2] = stride;
size += 2 * (stride * h2);
break;
case XVID_CSP_RGB555:
case XVID_CSP_RGB565:
case XVID_CSP_YUY2:
case XVID_CSP_UYVY:
case XVID_CSP_YVYU:
/* packed */
stride = GST_ROUND_UP_4 (width * 2);
im->plane[0] = ptr;
im->stride[0] = stride;
size = stride * height;
break;
case XVID_CSP_BGR:
stride = GST_ROUND_UP_4 (width * 3);
im->plane[0] = ptr;
im->stride[0] = stride;
size = stride * height * 2;
break;
case XVID_CSP_ABGR:
case XVID_CSP_BGRA:
case XVID_CSP_RGBA:
#ifdef XVID_CSP_ARGB
case XVID_CSP_ARGB:
#endif
stride = width * 4;
im->plane[0] = ptr;
im->stride[0] = stride;
size = stride * height;
break;
}
return size;
}
static gboolean
plugin_init (GstPlugin * plugin)
{
return (gst_element_register (plugin, "xvidenc",
GST_RANK_SECONDARY, GST_TYPE_XVIDENC) &&
gst_element_register (plugin, "xviddec",
GST_RANK_NONE, GST_TYPE_XVIDDEC));
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
xvid,
"XviD plugin library", plugin_init, VERSION, "GPL", GST_PACKAGE_NAME,
GST_PACKAGE_ORIGIN)

View file

@ -1,57 +0,0 @@
/* GStreamer xvid encoder/decoder plugin
* Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.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_XVID_H__
#define __GST_XVID_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define gst_xvid_init_struct(s) \
do { \
memset (&s, 0, sizeof(s)); \
s.version = XVID_VERSION; \
} while (0);
#define RGB_24_32_STATIC_CAPS(bpp, r_mask,g_mask,b_mask) \
"video/x-raw-rgb, " \
"width = (int) [ 0, MAX ], " \
"height = (int) [ 0, MAX], " \
"framerate = (fraction) [ 0, MAX], " \
"depth = (int) 24, " \
"bpp = (int) " G_STRINGIFY (bpp) ", " \
"endianness = (int) BIG_ENDIAN, " \
"red_mask = (int) " G_STRINGIFY (r_mask) ", " \
"green_mask = (int) " G_STRINGIFY (g_mask) ", " \
"blue_mask = (int) " G_STRINGIFY (b_mask)
extern const gchar *gst_xvid_error (int errorcode);
extern gboolean gst_xvid_init (void);
extern gint gst_xvid_structure_to_csp (GstStructure *structure);
extern GstCaps * gst_xvid_csp_to_caps (gint csp, gint w, gint h);
extern gint gst_xvid_image_get_size (gint csp,
gint width, gint height);
extern gint gst_xvid_image_fill (xvid_image_t * im, void * ptr, gint csp,
gint width, gint height);
G_END_DECLS
#endif /* __GST_XVID_H__ */

View file

@ -1,673 +0,0 @@
/* GStreamer xvid decoder plugin
* Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
* (C) 2006 Mark Nauwelaerts <manauw@skynet.be>
*
* 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 <xvid.h>
#include <gst/video/video.h>
#include "gstxviddec.h"
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-xvid, "
"width = (int) [ 0, MAX ], "
"height = (int) [ 0, MAX ], " "framerate = (fraction) [ 0/1, MAX ]; "
"video/mpeg, "
"mpegversion = (int) 4, "
"systemstream = (boolean) FALSE, "
"width = (int) [ 0, MAX ], "
"height = (int) [ 0, MAX ], " "framerate = (fraction) [ 0/1, MAX ]")
);
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ I420, YUY2, YV12, YVYU, UYVY }")
"; " RGB_24_32_STATIC_CAPS (32, 0x00ff0000, 0x0000ff00,
0x000000ff) "; " RGB_24_32_STATIC_CAPS (32, 0xff000000, 0x00ff0000,
0x0000ff00) "; " RGB_24_32_STATIC_CAPS (32, 0x0000ff00, 0x00ff0000,
0xff000000) "; " RGB_24_32_STATIC_CAPS (32, 0x000000ff, 0x0000ff00,
0x00ff0000) "; " RGB_24_32_STATIC_CAPS (24, 0x0000ff, 0x00ff00,
0xff0000) "; " GST_VIDEO_CAPS_RGB_15 "; " GST_VIDEO_CAPS_RGB_16)
);
GST_DEBUG_CATEGORY_STATIC (xviddec_debug);
#define GST_CAT_DEFAULT xviddec_debug
static void gst_xviddec_base_init (GstXvidDecClass * klass);
static void gst_xviddec_class_init (GstXvidDecClass * klass);
static void gst_xviddec_init (GstXvidDec * dec);
static void gst_xviddec_reset (GstXvidDec * dec);
static gboolean gst_xviddec_handle_sink_event (GstPad * pad, GstEvent * event);
static GstFlowReturn gst_xviddec_chain (GstPad * pad, GstBuffer * buf);
static gboolean gst_xviddec_setcaps (GstPad * pad, GstCaps * caps);
static void gst_xviddec_flush_buffers (GstXvidDec * dec, gboolean send);
static GstStateChangeReturn gst_xviddec_change_state (GstElement * element,
GstStateChange transition);
static GstElementClass *parent_class = NULL;
GType
gst_xviddec_get_type (void)
{
static GType xviddec_type = 0;
if (!xviddec_type) {
static const GTypeInfo xviddec_info = {
sizeof (GstXvidDecClass),
(GBaseInitFunc) gst_xviddec_base_init,
NULL,
(GClassInitFunc) gst_xviddec_class_init,
NULL,
NULL,
sizeof (GstXvidDec),
0,
(GInstanceInitFunc) gst_xviddec_init,
};
xviddec_type = g_type_register_static (GST_TYPE_ELEMENT,
"GstXvidDec", &xviddec_info, 0);
}
return xviddec_type;
}
static void
gst_xviddec_base_init (GstXvidDecClass * klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_add_static_pad_template (element_class, &sink_template);
gst_element_class_add_static_pad_template (element_class, &src_template);
gst_element_class_set_static_metadata (element_class, "XviD video decoder",
"Codec/Decoder/Video",
"XviD decoder based on xvidcore",
"Ronald Bultje <rbultje@ronald.bitfreak.net>");
}
static void
gst_xviddec_class_init (GstXvidDecClass * klass)
{
GstElementClass *gstelement_class = (GstElementClass *) klass;
parent_class = g_type_class_peek_parent (klass);
GST_DEBUG_CATEGORY_INIT (xviddec_debug, "xviddec", 0, "XviD decoder");
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_xviddec_change_state);
}
static void
gst_xviddec_init (GstXvidDec * dec)
{
/* create the sink pad */
dec->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
gst_pad_set_chain_function (dec->sinkpad,
GST_DEBUG_FUNCPTR (gst_xviddec_chain));
gst_pad_set_setcaps_function (dec->sinkpad,
GST_DEBUG_FUNCPTR (gst_xviddec_setcaps));
gst_pad_set_event_function (dec->sinkpad,
GST_DEBUG_FUNCPTR (gst_xviddec_handle_sink_event));
gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
/* create the src pad */
dec->srcpad = gst_pad_new_from_static_template (&src_template, "src");
gst_pad_use_fixed_caps (dec->srcpad);
gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
gst_xviddec_reset (dec);
}
static void
gst_xviddec_reset (GstXvidDec * dec)
{
/* size, etc. */
dec->width = dec->height = dec->csp = -1;
dec->fps_n = dec->par_n = -1;
dec->fps_d = dec->par_d = 1;
dec->next_ts = dec->next_dur = GST_CLOCK_TIME_NONE;
dec->outbuf_size = 0;
/* set xvid handle to NULL */
dec->handle = NULL;
/* no delayed timestamp to start with */
dec->have_ts = FALSE;
/* need keyframe to get going */
dec->waiting_for_key = TRUE;
}
static void
gst_xviddec_unset (GstXvidDec * dec)
{
/* release XviD decoder */
xvid_decore (dec->handle, XVID_DEC_DESTROY, NULL, NULL);
dec->handle = NULL;
}
static gboolean
gst_xviddec_handle_sink_event (GstPad * pad, GstEvent * event)
{
GstXvidDec *dec = GST_XVIDDEC (GST_PAD_PARENT (pad));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_EOS:
gst_xviddec_flush_buffers (dec, TRUE);
break;
case GST_EVENT_FLUSH_STOP:
gst_xviddec_flush_buffers (dec, FALSE);
break;
case GST_EVENT_NEWSEGMENT:
/* don't really mind about the actual segment info,
* but we do need to recover from this possible jump */
/* FIXME, NEWSEGMENT is not a discontinuity. A decoder
* should clip the output to the segment boundaries.
* Also the rate field of the segment can be used to
* optimize the decoding, like skipping B frames when
* playing at double speed.
* The DISCONT flag on buffers should be used to detect
* discontinuities.
*/
dec->waiting_for_key = TRUE;
break;
default:
break;
}
return gst_pad_push_event (dec->srcpad, event);
}
static gboolean
gst_xviddec_setup (GstXvidDec * dec)
{
xvid_dec_create_t xdec;
gint ret;
/* initialise parameters, see xvid documentation */
gst_xvid_init_struct (xdec);
/* let the decoder handle this, don't trust the container */
xdec.width = 0;
xdec.height = 0;
xdec.handle = NULL;
GST_DEBUG_OBJECT (dec, "Initializing xvid decoder with parameters "
"%dx%d@%d", dec->width, dec->height, dec->csp);
if ((ret = xvid_decore (NULL, XVID_DEC_CREATE, &xdec, NULL)) < 0) {
GST_WARNING_OBJECT (dec, "Initializing xvid decoder failed: %s (%d)",
gst_xvid_error (ret), ret);
return FALSE;
}
dec->handle = xdec.handle;
return TRUE;
}
static void
gst_xviddec_add_par (GstStructure * structure,
gint mux_par_n, gint mux_par_d, gint dec_par_n, gint dec_par_d)
{
/* muxer wins if decoder has nothing interesting to offer */
if (dec_par_n == dec_par_d) {
gst_structure_set (structure, "pixel-aspect-ratio", GST_TYPE_FRACTION,
mux_par_n, mux_par_d, NULL);
} else {
gst_structure_set (structure, "pixel-aspect-ratio", GST_TYPE_FRACTION,
dec_par_n, dec_par_d, NULL);
}
}
/* based on the decoder info, if provided, and xviddec info,
construct a caps and send on to src pad */
static gboolean
gst_xviddec_negotiate (GstXvidDec * dec, xvid_dec_stats_t * xstats)
{
gboolean ret;
gint par_width, par_height;
GstCaps *caps;
/* note: setcaps call with no xstats info,
so definitely need to negotiate then */
if (xstats && (xstats->type != XVID_TYPE_VOL
|| (xstats->type == XVID_TYPE_VOL
&& dec->width == xstats->data.vol.width
&& dec->height == xstats->data.vol.height)))
return TRUE;
switch (xstats ? xstats->data.vol.par : XVID_PAR_11_VGA) {
case XVID_PAR_11_VGA:
par_width = par_height = 1;
break;
case XVID_PAR_43_PAL:
case XVID_PAR_43_NTSC:
par_width = 4;
par_height = 3;
break;
case XVID_PAR_169_PAL:
case XVID_PAR_169_NTSC:
par_width = 16;
par_height = 9;
break;
case XVID_PAR_EXT:
default:
par_width = xstats->data.vol.par_width;
par_height = xstats->data.vol.par_height;
}
caps = gst_xvid_csp_to_caps (dec->csp, dec->width, dec->height);
/* can only provide framerate if we received one */
if (dec->fps_n != -1) {
gst_structure_set (gst_caps_get_structure (caps, 0), "framerate",
GST_TYPE_FRACTION, dec->fps_n, dec->fps_d, NULL);
}
gst_xviddec_add_par (gst_caps_get_structure (caps, 0),
dec->par_n, dec->par_d, par_width, par_height);
GST_LOG ("setting caps on source pad: %" GST_PTR_FORMAT, caps);
ret = gst_pad_set_caps (dec->srcpad, caps);
gst_caps_unref (caps);
return ret;
}
static GstFlowReturn
gst_xviddec_chain (GstPad * pad, GstBuffer * buf)
{
GstXvidDec *dec;
GstBuffer *outbuf = NULL;
xvid_dec_frame_t xframe;
xvid_dec_stats_t xstats;
gint ret;
guint8 *data, *dupe = NULL;
guint size;
GstFlowReturn fret;
dec = GST_XVIDDEC (GST_OBJECT_PARENT (pad));
if (!dec->handle)
goto not_negotiated;
fret = GST_FLOW_OK;
GST_LOG_OBJECT (dec, "Received buffer of time %" GST_TIME_FORMAT
" duration %" GST_TIME_FORMAT ", size %d",
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_SIZE (buf));
if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
/* FIXME: should we do anything here, like flush the decoder? */
}
data = GST_BUFFER_DATA (buf);
size = GST_BUFFER_SIZE (buf);
/* xvidcore overreads the input buffer, we need to alloc some extra padding
* to make things work reliably */
#define EXTRA_PADDING 16
if (EXTRA_PADDING > 0) {
dupe = g_malloc (size + EXTRA_PADDING);
memcpy (dupe, data, size);
memset (dupe + size, 0, EXTRA_PADDING);
data = dupe;
}
do { /* loop needed because xvidcore may return vol information */
/* decode and so ... */
gst_xvid_init_struct (xframe);
xframe.general = XVID_LOWDELAY;
xframe.bitstream = (void *) data;
xframe.length = size;
gst_xvid_init_struct (xstats);
if (outbuf == NULL) {
fret = gst_pad_alloc_buffer (dec->srcpad, GST_BUFFER_OFFSET_NONE,
dec->outbuf_size, GST_PAD_CAPS (dec->srcpad), &outbuf);
if (fret != GST_FLOW_OK)
goto done;
}
gst_xvid_image_fill (&xframe.output, GST_BUFFER_DATA (outbuf),
dec->csp, dec->width, dec->height);
ret = xvid_decore (dec->handle, XVID_DEC_DECODE, &xframe, &xstats);
if (ret < 0)
goto decode_error;
GST_LOG_OBJECT (dec, "xvid produced output, type %d, consumed %d",
xstats.type, ret);
if (xstats.type == XVID_TYPE_VOL)
gst_xviddec_negotiate (dec, &xstats);
data += ret;
size -= ret;
} while (xstats.type <= 0 && size > 0);
/* 1 byte is frequently left over */
if (size > 1) {
GST_WARNING_OBJECT (dec, "decoder did not consume all input");
}
/* FIXME, reflow the multiple return exit points */
if (xstats.type > 0) { /* some real output was produced */
if (G_UNLIKELY (dec->waiting_for_key)) {
if (xstats.type != XVID_TYPE_IVOP)
goto dropping;
dec->waiting_for_key = FALSE;
}
/* bframes can cause a delay in frames being returned
non keyframe timestamps can permute a bit between
encode and display order, but should match for keyframes */
if (dec->have_ts) {
GST_BUFFER_TIMESTAMP (outbuf) = dec->next_ts;
GST_BUFFER_DURATION (outbuf) = dec->next_dur;
dec->next_ts = GST_BUFFER_TIMESTAMP (buf);
dec->next_dur = GST_BUFFER_DURATION (buf);
} else {
GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
}
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (dec->srcpad));
GST_LOG_OBJECT (dec, "pushing buffer with pts %" GST_TIME_FORMAT
" duration %" GST_TIME_FORMAT,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));
fret = gst_pad_push (dec->srcpad, outbuf);
} else { /* no real output yet, delay in frames being returned */
if (G_UNLIKELY (dec->have_ts)) {
GST_WARNING_OBJECT (dec,
"xvid decoder produced no output, but timestamp %" GST_TIME_FORMAT
" already queued", GST_TIME_ARGS (dec->next_ts));
} else {
dec->have_ts = TRUE;
dec->next_ts = GST_BUFFER_TIMESTAMP (buf);
dec->next_dur = GST_BUFFER_DURATION (buf);
}
gst_buffer_unref (outbuf);
}
done:
g_free (dupe);
gst_buffer_unref (buf);
return fret;
/* ERRORS */
not_negotiated:
{
GST_ELEMENT_ERROR (dec, CORE, NEGOTIATION, (NULL),
("format wasn't negotiated before chain function"));
fret = GST_FLOW_NOT_NEGOTIATED;
goto done;
}
decode_error:
{
/* FIXME: shouldn't error out fatally/properly after N decoding errors? */
GST_ELEMENT_WARNING (dec, STREAM, DECODE, (NULL),
("Error decoding xvid frame: %s (%d)", gst_xvid_error (ret), ret));
if (outbuf)
gst_buffer_unref (outbuf);
goto done;
}
dropping:
{
GST_WARNING_OBJECT (dec, "Dropping non-keyframe (seek/init)");
if (outbuf)
gst_buffer_unref (outbuf);
goto done;
}
}
/* flush xvid encoder buffers caused by bframe usage;
not well tested */
static void
gst_xviddec_flush_buffers (GstXvidDec * dec, gboolean send)
{
#if 0
gint ret;
GstBuffer *outbuf = NULL;
xvid_dec_frame_t xframe;
xvid_dec_stats_t xstats;
#endif
GST_DEBUG_OBJECT (dec, "flushing buffers with send %d, have_ts %d",
send, dec->have_ts);
/* no need to flush if there is no delayed time-stamp */
if (!dec->have_ts)
return;
/* flushing must reset the timestamp keeping */
dec->have_ts = FALSE;
/* also no need to flush if no handle */
if (!dec->handle)
return;
/* unlike encoder, decoder does not seem to like flushing, disable for now */
#if 0
gst_xvid_init_struct (xframe);
gst_xvid_init_struct (xstats);
/* init a fake frame to force flushing */
xframe.bitstream = NULL;
xframe.length = -1;
ret = gst_xviddec_decode (dec, xframe, &outbuf, &xstats);
GST_DEBUG_OBJECT (dec, "received frame when flushing, type %d, size %d",
xstats.type, ret);
if (ret > 0 && send) {
/* we have some valid return frame, give it the delayed timestamp and send */
GST_BUFFER_TIMESTAMP (outbuf) = dec->next_ts;
GST_BUFFER_DURATION (outbuf) = dec->next_dur;
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (dec->srcpad));
gst_pad_push (dec->srcpad, outbuf);
return;
}
if (outbuf)
gst_buffer_unref (outbuf);
#else
return;
#endif
}
#if 0
static GstCaps *
gst_xviddec_src_getcaps (GstPad * pad)
{
GstXvidDec *dec = GST_XVIDDEC (GST_PAD_PARENT (pad));
GstCaps *caps;
gint csp[] = {
XVID_CSP_I420,
XVID_CSP_YV12,
XVID_CSP_YUY2,
XVID_CSP_UYVY,
XVID_CSP_YVYU,
XVID_CSP_BGRA,
XVID_CSP_ABGR,
XVID_CSP_RGBA,
#ifdef XVID_CSP_ARGB
XVID_CSP_ARGB,
#endif
XVID_CSP_BGR,
XVID_CSP_RGB555,
XVID_CSP_RGB565,
0
}, i;
if (!GST_PAD_CAPS (dec->sinkpad)) {
GstPadTemplate *templ = gst_static_pad_template_get (&src_template);
return gst_caps_copy (gst_pad_template_get_caps (templ));
}
caps = gst_caps_new_empty ();
for (i = 0; csp[i] != 0; i++) {
GstCaps *one = gst_xvid_csp_to_caps (csp[i], dec->width,
dec->height, dec->fps, dec->par);
gst_caps_append (caps, one);
}
return caps;
}
#endif
static gboolean
gst_xviddec_setcaps (GstPad * pad, GstCaps * caps)
{
GstXvidDec *dec = GST_XVIDDEC (GST_PAD_PARENT (pad));
GstStructure *structure;
GstCaps *allowed_caps;
const GValue *val;
GST_LOG_OBJECT (dec, "caps %" GST_PTR_FORMAT, caps);
/* if there's something old around, remove it */
if (dec->handle) {
gst_xviddec_unset (dec);
}
structure = gst_caps_get_structure (caps, 0);
gst_structure_get_int (structure, "width", &dec->width);
gst_structure_get_int (structure, "height", &dec->height);
/* perhaps some fps info */
val = gst_structure_get_value (structure, "framerate");
if ((val != NULL) && GST_VALUE_HOLDS_FRACTION (val)) {
dec->fps_n = gst_value_get_fraction_numerator (val);
dec->fps_d = gst_value_get_fraction_denominator (val);
} else {
dec->fps_n = -1;
dec->fps_d = 1;
}
/* perhaps some par info */
val = gst_structure_get_value (structure, "pixel-aspect-ratio");
if (val != NULL && GST_VALUE_HOLDS_FRACTION (val)) {
dec->par_n = gst_value_get_fraction_numerator (val);
dec->par_d = gst_value_get_fraction_denominator (val);
} else {
dec->par_n = 1;
dec->par_d = 1;
}
/* we try to find the preferred/accept csp */
allowed_caps = gst_pad_get_allowed_caps (dec->srcpad);
if (!allowed_caps) {
GST_DEBUG_OBJECT (dec, "... but no peer, using template caps");
/* need to copy because get_allowed_caps returns a ref,
and get_pad_template_caps doesn't */
allowed_caps = gst_caps_copy (gst_pad_get_pad_template_caps (dec->srcpad));
}
GST_LOG_OBJECT (dec, "allowed source caps %" GST_PTR_FORMAT, allowed_caps);
/* pick the first one ... */
structure = gst_caps_get_structure (allowed_caps, 0);
val = gst_structure_get_value (structure, "format");
if (val != NULL && G_VALUE_TYPE (val) == GST_TYPE_LIST) {
GValue temp = { 0, };
gst_value_init_and_copy (&temp, gst_value_list_get_value (val, 0));
gst_structure_set_value (structure, "format", &temp);
g_value_unset (&temp);
}
/* ... and use its info to get the csp */
dec->csp = gst_xvid_structure_to_csp (structure);
if (dec->csp == -1) {
GST_WARNING_OBJECT (dec, "failed to decide on colorspace, using I420");
dec->csp = XVID_CSP_I420;
}
dec->outbuf_size =
gst_xvid_image_get_size (dec->csp, dec->width, dec->height);
GST_LOG_OBJECT (dec, "csp=%d, outbuf_size=%d", dec->csp, dec->outbuf_size);
gst_caps_unref (allowed_caps);
/* now set up xvid ... */
if (!gst_xviddec_setup (dec)) {
GST_ELEMENT_ERROR (GST_ELEMENT (dec), LIBRARY, INIT, (NULL), (NULL));
return FALSE;
}
return gst_xviddec_negotiate (dec, NULL);
}
static GstStateChangeReturn
gst_xviddec_change_state (GstElement * element, GstStateChange transition)
{
GstXvidDec *dec = GST_XVIDDEC (element);
GstStateChangeReturn ret;
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
if (!gst_xvid_init ())
return GST_STATE_CHANGE_FAILURE;
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
if (ret == GST_STATE_CHANGE_FAILURE)
goto done;
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
gst_xviddec_flush_buffers (dec, FALSE);
if (dec->handle) {
gst_xviddec_unset (dec);
}
gst_xviddec_reset (dec);
break;
default:
break;
}
done:
return ret;
}

View file

@ -1,73 +0,0 @@
/* GStreamer xvid decoder plugin
* Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.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_XVIDDEC_H__
#define __GST_XVIDDEC_H__
#include <gst/gst.h>
#include "gstxvid.h"
G_BEGIN_DECLS
#define GST_TYPE_XVIDDEC \
(gst_xviddec_get_type())
#define GST_XVIDDEC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_XVIDDEC, GstXvidDec))
#define GST_XVIDDEC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_XVIDDEC, GstXvidDecClass))
#define GST_IS_XVIDDEC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_XVIDDEC))
#define GST_IS_XVIDDEC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_XVIDDEC))
typedef struct _GstXvidDec GstXvidDec;
typedef struct _GstXvidDecClass GstXvidDecClass;
struct _GstXvidDec {
GstElement element;
/* pads */
GstPad *sinkpad, *srcpad;
/* xvid handle */
void *handle;
/* video (output) settings */
gint csp;
gint width, height;
gint fps_n, fps_d, par_n, par_d;
gint outbuf_size;
/* whether in need for keyframe */
gboolean waiting_for_key;
/* retain some info on delayed frame */
gboolean have_ts;
GstClockTime next_ts, next_dur;
};
struct _GstXvidDecClass {
GstElementClass parent_class;
};
GType gst_xviddec_get_type(void);
G_END_DECLS
#endif /* __GST_XVIDDEC_H__ */

File diff suppressed because it is too large Load diff

View file

@ -1,137 +0,0 @@
/* GStreamer xvid encoder plugin
* Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.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_XVIDENC_H__
#define __GST_XVIDENC_H__
#include <gst/gst.h>
#include "gstxvid.h"
G_BEGIN_DECLS
#define GST_TYPE_XVIDENC \
(gst_xvidenc_get_type())
#define GST_XVIDENC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_XVIDENC, GstXvidEnc))
#define GST_XVIDENC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_XVIDENC, GstXvidEncClass))
#define GST_IS_XVIDENC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_XVIDENC))
#define GST_IS_XVIDENC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_XVIDENC))
typedef struct _GstXvidEnc GstXvidEnc;
typedef struct _GstXvidEncClass GstXvidEncClass;
struct _GstXvidEnc {
GstElement element;
/* pads */
GstPad *sinkpad, *srcpad;
/* xvid handle */
void *handle;
/* cache in place */
xvid_enc_frame_t *xframe_cache;
/* caps information */
gint csp;
gint width, height;
gint fbase;
gint fincr;
gint par_width;
gint par_height;
/* delayed buffers if bframe usage */
GQueue *delay;
/* encoding profile */
gint profile;
gint used_profile;
/* quantizer type; h263, MPEG */
gint quant_type;
/* encoding type; cbr, vbr, quant */
gint pass;
/* quality of encoded image */
gint bitrate;
gint quant;
/* gop */
gint max_key_interval;
gboolean closed_gop;
/* motion estimation */
gint motion;
gboolean me_chroma;
gint me_vhq;
gboolean me_quarterpel;
/* lumimasking */
gboolean lumimasking;
/* b-frames */
gint max_bframes;
gint bquant_ratio;
gint bquant_offset;
gint bframe_threshold;
/* misc */
gboolean gmc;
gboolean trellis;
gboolean interlaced;
gboolean cartoon;
gboolean greyscale;
gboolean hqacpred;
/* quantizer ranges */
gint max_iquant, min_iquant;
gint max_pquant, min_pquant;
gint max_bquant, min_bquant;
/* cbr (single pass) encoding */
gint reaction_delay_factor;
gint averaging_period;
gint buffer;
/* vbr (2pass) encoding */
gchar *filename;
gint keyframe_boost;
gint curve_compression_high;
gint curve_compression_low;
gint overflow_control_strength;
gint max_overflow_improvement;
gint max_overflow_degradation;
gint kfreduction;
gint kfthreshold;
gint container_frame_overhead;
};
struct _GstXvidEncClass {
GstElementClass parent_class;
};
GType gst_xvidenc_get_type(void);
G_END_DECLS
#endif /* __GST_XVIDENC_H__ */

View file

@ -1,10 +0,0 @@
plugin_LTLIBRARIES = libgstaudiobuffer.la
libgstaudiobuffer_la_SOURCES = gstaudioringbuffer.c
libgstaudiobuffer_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) \
$(GST_CFLAGS)
libgstaudiobuffer_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \
-lgstaudio-$(GST_API_VERSION)
libgstaudiobuffer_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstaudiobuffer_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)

File diff suppressed because it is too large Load diff

View file

@ -1,12 +0,0 @@
audiobuffer_sources = [
'gstaudioringbuffer.c',
]
gstaudiobuffer = library('gstaudiobuffer',
audiobuffer_sources,
c_args : gst_plugins_bad_args,
include_directories : [configinc, libsinc],
dependencies : [gstbase_dep, gstaudio_dep],
install : true,
install_dir : plugins_install_dir,
)

View file

@ -1,24 +0,0 @@
plugin_LTLIBRARIES = libgstcdxaparse.la
libgstcdxaparse_la_SOURCES = \
gstcdxaparse.c \
gstvcdparse.c
noinst_HEADERS = \
gstcdxaparse.h \
gstvcdparse.h
libgstcdxaparse_la_CFLAGS = \
$(GST_CFLAGS) \
$(GST_BASE_CFLAGS) \
$(GST_PLUGINS_BASE_CFLAGS)
libgstcdxaparse_la_LIBADD = \
$(GST_LIBS) \
$(GST_BASE_LIBS) \
$(GST_PLUGINS_BASE_LIBS) \
-lgstriff-@GST_API_VERSION@
libgstcdxaparse_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstcdxaparse_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)

View file

@ -1,585 +0,0 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* <2002> Wim Taymans <wim.taymans@chello.be>
* <2006> Tim-Philipp Müller <tim centricular 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
/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
* with newer GLib versions (>= 2.31.0) */
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include <string.h>
#include "gstcdxaparse.h"
#include "gstvcdparse.h"
#include <gst/riff/riff-ids.h>
#include <gst/riff/riff-read.h>
GST_DEBUG_CATEGORY (vcdparse_debug);
GST_DEBUG_CATEGORY_STATIC (cdxaparse_debug);
#define GST_CAT_DEFAULT cdxaparse_debug
static gboolean gst_cdxa_parse_sink_activate (GstPad * sinkpad);
static void gst_cdxa_parse_loop (GstPad * sinkpad);
static gboolean gst_cdxa_parse_sink_activate_pull (GstPad * sinkpad,
gboolean active);
static GstStateChangeReturn gst_cdxa_parse_change_state (GstElement * element,
GstStateChange transition);
static gboolean gst_cdxa_parse_src_event (GstPad * srcpad, GstEvent * event);
static gboolean gst_cdxa_parse_src_query (GstPad * srcpad, GstQuery * query);
static GstStaticPadTemplate sink_template_factory =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-cdxa")
);
static GstStaticPadTemplate src_template_factory =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/mpeg, " "systemstream = (boolean) TRUE")
);
GST_BOILERPLATE (GstCDXAParse, gst_cdxa_parse, GstElement, GST_TYPE_ELEMENT);
static void
gst_cdxa_parse_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_set_static_metadata (element_class, "(S)VCD parser",
"Codec/Parser",
"Parse a .dat file from (S)VCD into raw MPEG-1",
"Wim Taymans <wim.taymans@tvd.be>");
/* register src pads */
gst_element_class_add_static_pad_template (element_class,
&sink_template_factory);
gst_element_class_add_static_pad_template (element_class,
&src_template_factory);
}
static void
gst_cdxa_parse_class_init (GstCDXAParseClass * klass)
{
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_cdxa_parse_change_state);
}
static void
gst_cdxa_parse_init (GstCDXAParse * cdxaparse, GstCDXAParseClass * klass)
{
GstCaps *caps;
cdxaparse->sinkpad =
gst_pad_new_from_static_template (&sink_template_factory, "sink");
gst_pad_set_activate_function (cdxaparse->sinkpad,
GST_DEBUG_FUNCPTR (gst_cdxa_parse_sink_activate));
gst_pad_set_activatepull_function (cdxaparse->sinkpad,
GST_DEBUG_FUNCPTR (gst_cdxa_parse_sink_activate_pull));
gst_element_add_pad (GST_ELEMENT (cdxaparse), cdxaparse->sinkpad);
cdxaparse->srcpad =
gst_pad_new_from_static_template (&src_template_factory, "src");
gst_pad_set_event_function (cdxaparse->srcpad,
GST_DEBUG_FUNCPTR (gst_cdxa_parse_src_event));
gst_pad_set_query_function (cdxaparse->srcpad,
GST_DEBUG_FUNCPTR (gst_cdxa_parse_src_query));
caps = gst_caps_new_simple ("video/mpeg",
"systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
gst_pad_use_fixed_caps (cdxaparse->srcpad);
gst_pad_set_caps (cdxaparse->srcpad, caps);
gst_caps_unref (caps);
gst_element_add_pad (GST_ELEMENT (cdxaparse), cdxaparse->srcpad);
cdxaparse->state = GST_CDXA_PARSE_START;
cdxaparse->offset = 0;
cdxaparse->datasize = 0;
cdxaparse->datastart = -1;
}
#define HAVE_FOURCC(data,fourcc) (GST_READ_UINT32_LE((data))==(fourcc))
static gboolean
gst_cdxa_parse_stream_init (GstCDXAParse * cdxa)
{
GstFlowReturn flow_ret;
GstBuffer *buf = NULL;
guint8 *data;
flow_ret = gst_pad_pull_range (cdxa->sinkpad, cdxa->offset, 12, &buf);
if (flow_ret != GST_FLOW_OK)
return flow_ret;
if (GST_BUFFER_SIZE (buf) < 12)
goto wrong_type;
data = GST_BUFFER_DATA (buf);
if (!HAVE_FOURCC (data, GST_RIFF_TAG_RIFF)) {
GST_ERROR_OBJECT (cdxa, "Not a RIFF file");
goto wrong_type;
}
if (!HAVE_FOURCC (data + 8, GST_RIFF_RIFF_CDXA)) {
GST_ERROR_OBJECT (cdxa, "RIFF file does not have CDXA content");
goto wrong_type;
}
cdxa->offset += 12;
gst_buffer_unref (buf);
return TRUE;
wrong_type:
GST_ELEMENT_ERROR (cdxa, STREAM, WRONG_TYPE, (NULL), (NULL));
gst_buffer_unref (buf);
return FALSE;
}
static gboolean
gst_cdxa_parse_sink_activate (GstPad * sinkpad)
{
GstCDXAParse *cdxa = GST_CDXA_PARSE (GST_PAD_PARENT (sinkpad));
if (!gst_pad_check_pull_range (sinkpad) ||
!gst_pad_activate_pull (sinkpad, TRUE)) {
GST_DEBUG_OBJECT (cdxa, "No pull mode");
return FALSE;
}
/* If we can activate pull_range upstream, then read the header
* and see if it's really a RIFF CDXA file. */
GST_DEBUG_OBJECT (cdxa, "Activated pull mode. Reading RIFF header");
if (!gst_cdxa_parse_stream_init (cdxa))
return FALSE;
return TRUE;
}
static gboolean
gst_cdxa_parse_sink_activate_pull (GstPad * sinkpad, gboolean active)
{
if (active) {
/* if we have a scheduler we can start the task */
gst_pad_start_task (sinkpad, (GstTaskFunction) gst_cdxa_parse_loop,
sinkpad, NULL);
} else {
gst_pad_stop_task (sinkpad);
}
return TRUE;
}
/*
* A sector is 2352 bytes long and is composed of:
*
* ! sync ! header ! subheader ! data ... ! edc !
* ! 12 bytes ! 4 bytes ! 8 bytes ! 2324 bytes ! 4 bytes !
* !-------------------------------------------------------!
*
* We strip the data out of it and send it to the srcpad.
*
* sync : 00 FF FF FF FF FF FF FF FF FF FF 00
* header : hour minute second mode
* sub-header : track channel sub_mode coding repeat (4 bytes)
* edc : checksum
*/
/* FIXME: use define from gstcdxastrip.h */
#define GST_CDXA_SECTOR_SIZE 2352
#define GST_CDXA_DATA_SIZE 2324
#define GST_CDXA_HEADER_SIZE 24
/* FIXME: use version from gstcdxastrip.c */
static GstBuffer *
gst_cdxa_parse_strip (GstBuffer * buf)
{
GstBuffer *sub;
g_assert (GST_BUFFER_SIZE (buf) >= GST_CDXA_SECTOR_SIZE);
/* Skip CDXA headers, only keep data.
* FIXME: check sync, resync, ... */
sub = gst_buffer_create_sub (buf, GST_CDXA_HEADER_SIZE, GST_CDXA_DATA_SIZE);
gst_buffer_unref (buf);
return sub;
}
/* -1 = no sync (discard buffer),
* otherwise offset indicates syncpoint in buffer.
*/
static gint
gst_cdxa_parse_sync (GstBuffer * buf)
{
const guint8 sync_marker[12] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00
};
guint8 *data;
guint size;
size = GST_BUFFER_SIZE (buf);
data = GST_BUFFER_DATA (buf);
while (size >= 12) {
if (memcmp (data, sync_marker, 12) == 0) {
return (gint) (data - GST_BUFFER_DATA (buf));
}
--size;
++data;
}
return -1;
}
static void
gst_cdxa_parse_loop (GstPad * sinkpad)
{
GstFlowReturn flow_ret;
GstCDXAParse *cdxa;
GstBuffer *buf = NULL;
gint sync_offset = -1;
cdxa = GST_CDXA_PARSE (GST_PAD_PARENT (sinkpad));
if (cdxa->datasize <= 0) {
GstFormat format = GST_FORMAT_BYTES;
GstPad *peer;
if ((peer = gst_pad_get_peer (sinkpad))) {
if (!gst_pad_query_duration (peer, &format, &cdxa->datasize)) {
GST_DEBUG_OBJECT (cdxa, "Failed to query upstream size!");
gst_object_unref (peer);
goto pause;
}
gst_object_unref (peer);
}
GST_DEBUG_OBJECT (cdxa, "Upstream size: %" G_GINT64_FORMAT, cdxa->datasize);
}
do {
guint req;
req = 8 + GST_CDXA_SECTOR_SIZE; /* riff chunk header = 8 bytes */
buf = NULL;
flow_ret = gst_pad_pull_range (cdxa->sinkpad, cdxa->offset, req, &buf);
if (flow_ret != GST_FLOW_OK) {
GST_DEBUG_OBJECT (cdxa, "Pull flow: %s", gst_flow_get_name (flow_ret));
goto pause;
}
if (GST_BUFFER_SIZE (buf) < req) {
GST_DEBUG_OBJECT (cdxa, "Short read, only got %u/%u bytes",
GST_BUFFER_SIZE (buf), req);
goto eos;
}
sync_offset = gst_cdxa_parse_sync (buf);
gst_buffer_unref (buf);
buf = NULL;
if (sync_offset >= 0)
break;
cdxa->offset += req;
cdxa->bytes_skipped += req;
} while (1);
cdxa->offset += sync_offset;
cdxa->bytes_skipped += sync_offset;
/* first sync frame? */
if (cdxa->datastart < 0) {
GST_LOG_OBJECT (cdxa, "datastart=0x%" G_GINT64_MODIFIER "x", cdxa->offset);
cdxa->datastart = cdxa->offset;
cdxa->bytes_skipped = 0;
cdxa->bytes_sent = 0;
}
GST_DEBUG_OBJECT (cdxa, "pulling buffer at offset 0x%" G_GINT64_MODIFIER "x",
cdxa->offset);
buf = NULL;
flow_ret = gst_pad_pull_range (cdxa->sinkpad, cdxa->offset,
GST_CDXA_SECTOR_SIZE, &buf);
if (flow_ret != GST_FLOW_OK) {
GST_DEBUG_OBJECT (cdxa, "Flow: %s", gst_flow_get_name (flow_ret));
goto pause;
}
if (GST_BUFFER_SIZE (buf) < GST_CDXA_SECTOR_SIZE) {
GST_DEBUG_OBJECT (cdxa, "Short read, only got %u/%u bytes",
GST_BUFFER_SIZE (buf), GST_CDXA_SECTOR_SIZE);
goto eos;
}
buf = gst_cdxa_parse_strip (buf);
GST_DEBUG_OBJECT (cdxa, "pushing buffer %p", buf);
gst_buffer_set_caps (buf, GST_PAD_CAPS (cdxa->srcpad));
cdxa->offset += GST_BUFFER_SIZE (buf);
cdxa->bytes_sent += GST_BUFFER_SIZE (buf);
flow_ret = gst_pad_push (cdxa->srcpad, buf);
if (flow_ret != GST_FLOW_OK) {
GST_DEBUG_OBJECT (cdxa, "Push flow: %s", gst_flow_get_name (flow_ret));
goto pause;
}
return;
eos:
{
GST_DEBUG_OBJECT (cdxa, "Sending EOS");
if (buf)
gst_buffer_unref (buf);
buf = NULL;
gst_pad_push_event (cdxa->srcpad, gst_event_new_eos ());
/* fallthrough */
}
pause:
{
GST_DEBUG_OBJECT (cdxa, "Pausing");
gst_pad_pause_task (cdxa->sinkpad);
return;
}
}
static gint64
gst_cdxa_parse_convert_src_to_sink_offset (GstCDXAParse * cdxa, gint64 src)
{
gint64 sink;
sink = src + cdxa->datastart;
sink = gst_util_uint64_scale (sink, GST_CDXA_SECTOR_SIZE, GST_CDXA_DATA_SIZE);
/* FIXME: take into account skipped bytes */
GST_DEBUG_OBJECT (cdxa, "src offset=%" G_GINT64_FORMAT ", sink offset=%"
G_GINT64_FORMAT, src, sink);
return sink;
}
static gint64
gst_cdxa_parse_convert_sink_to_src_offset (GstCDXAParse * cdxa, gint64 sink)
{
gint64 src;
src = sink - cdxa->datastart;
src = gst_util_uint64_scale (src, GST_CDXA_DATA_SIZE, GST_CDXA_SECTOR_SIZE);
/* FIXME: take into account skipped bytes */
GST_DEBUG_OBJECT (cdxa, "sink offset=%" G_GINT64_FORMAT ", src offset=%"
G_GINT64_FORMAT, sink, src);
return src;
}
static gboolean
gst_cdxa_parse_do_seek (GstCDXAParse * cdxa, GstEvent * event)
{
GstSeekFlags flags;
GstSeekType start_type;
GstFormat format;
gint64 start, off, upstream_size;
gst_event_parse_seek (event, NULL, &format, &flags, &start_type, &start,
NULL, NULL);
if (format != GST_FORMAT_BYTES) {
GST_DEBUG_OBJECT (cdxa, "Can only handle seek in BYTES format");
return FALSE;
}
if (start_type != GST_SEEK_TYPE_SET) {
GST_DEBUG_OBJECT (cdxa, "Can only handle seek from start (SEEK_TYPE_SET)");
return FALSE;
}
GST_OBJECT_LOCK (cdxa);
off = gst_cdxa_parse_convert_src_to_sink_offset (cdxa, start);
upstream_size = cdxa->datasize;
GST_OBJECT_UNLOCK (cdxa);
if (off >= upstream_size) {
GST_DEBUG_OBJECT (cdxa, "Invalid target offset %" G_GINT64_FORMAT ", file "
"is only %" G_GINT64_FORMAT " bytes in size", off, upstream_size);
return FALSE;
}
/* unlock upstream pull_range */
gst_pad_push_event (cdxa->sinkpad, gst_event_new_flush_start ());
/* make sure our loop function exits */
gst_pad_push_event (cdxa->srcpad, gst_event_new_flush_start ());
/* wait for streaming to finish */
GST_PAD_STREAM_LOCK (cdxa->sinkpad);
/* prepare for streaming again */
gst_pad_push_event (cdxa->sinkpad, gst_event_new_flush_stop ());
gst_pad_push_event (cdxa->srcpad, gst_event_new_flush_stop ());
gst_pad_push_event (cdxa->srcpad,
gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
start, GST_CLOCK_TIME_NONE, 0));
GST_OBJECT_LOCK (cdxa);
cdxa->offset = off;
GST_OBJECT_UNLOCK (cdxa);
/* and restart */
gst_pad_start_task (cdxa->sinkpad,
(GstTaskFunction) gst_cdxa_parse_loop, cdxa->sinkpad, NULL);
GST_PAD_STREAM_UNLOCK (cdxa->sinkpad);
return TRUE;
}
static gboolean
gst_cdxa_parse_src_event (GstPad * srcpad, GstEvent * event)
{
GstCDXAParse *cdxa = GST_CDXA_PARSE (gst_pad_get_parent (srcpad));
gboolean res = FALSE;
GST_DEBUG_OBJECT (cdxa, "Handling %s event", GST_EVENT_TYPE_NAME (event));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK:
res = gst_cdxa_parse_do_seek (cdxa, event);
break;
default:
res = gst_pad_event_default (srcpad, event);
break;
}
gst_object_unref (cdxa);
return res;
}
static gboolean
gst_cdxa_parse_src_query (GstPad * srcpad, GstQuery * query)
{
GstCDXAParse *cdxa = GST_CDXA_PARSE (gst_pad_get_parent (srcpad));
gboolean res = FALSE;
GST_DEBUG_OBJECT (cdxa, "Handling %s query",
gst_query_type_get_name (GST_QUERY_TYPE (query)));
res = gst_pad_query_default (srcpad, query);
if (res) {
GstFormat format;
gint64 val;
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_DURATION:
gst_query_parse_duration (query, &format, &val);
if (format == GST_FORMAT_BYTES) {
val = gst_cdxa_parse_convert_sink_to_src_offset (cdxa, val);
gst_query_set_duration (query, format, val);
}
break;
case GST_QUERY_POSITION:
gst_query_parse_position (query, &format, &val);
if (format == GST_FORMAT_BYTES) {
val = gst_cdxa_parse_convert_sink_to_src_offset (cdxa, val);
gst_query_set_position (query, format, val);
}
break;
default:
break;
}
}
gst_object_unref (cdxa);
return res;
}
static GstStateChangeReturn
gst_cdxa_parse_change_state (GstElement * element, GstStateChange transition)
{
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GstCDXAParse *cdxa = GST_CDXA_PARSE (element);
switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED:
cdxa->state = GST_CDXA_PARSE_START;
break;
default:
break;
}
if (GST_ELEMENT_CLASS (parent_class)->change_state)
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
cdxa->state = GST_CDXA_PARSE_START;
cdxa->datasize = 0;
cdxa->datastart = -1;
break;
default:
break;
}
return ret;
}
static gboolean
plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (cdxaparse_debug, "cdxaparse", 0, "CDXA Parser");
GST_DEBUG_CATEGORY_INIT (vcdparse_debug, "vcdparse", 0, "VCD Parser");
if (!gst_element_register (plugin, "cdxaparse", GST_RANK_PRIMARY,
GST_TYPE_CDXA_PARSE))
return FALSE;
if (!gst_element_register (plugin, "vcdparse", GST_RANK_PRIMARY,
GST_TYPE_VCD_PARSE))
return FALSE;
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
cdxaparse,
"Parse a .dat file (VCD) into raw mpeg1",
plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

View file

@ -1,75 +0,0 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* <2002> Wim Tayans <wim.taymans@chello.be>
*
* 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_CDXA_PARSE_H__
#define __GST_CDXA_PARSE_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define GST_TYPE_CDXA_PARSE \
(gst_cdxa_parse_get_type())
#define GST_CDXA_PARSE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CDXA_PARSE,GstCDXAParse))
#define GST_CDXA_PARSE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CDXA_PARSE,GstCDXAParseClass))
#define GST_IS_CDXA_PARSE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CDXA_PARSE))
#define GST_IS_CDXA_PARSE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CDXA_PARSE))
typedef enum {
GST_CDXA_PARSE_START,
GST_CDXA_PARSE_FMT,
GST_CDXA_PARSE_OTHER,
GST_CDXA_PARSE_DATA,
} GstCDXAParseState;
typedef struct _GstCDXAParse GstCDXAParse;
typedef struct _GstCDXAParseClass GstCDXAParseClass;
struct _GstCDXAParse {
GstElement element;
/* pads */
GstPad *sinkpad;
GstPad *srcpad;
/* CDXA decoding state */
GstCDXAParseState state;
gint64 offset; /* current byte offset in file */
gint64 datasize; /* upstream size in bytes */
gint64 datastart; /* byte offset of first frame sync */
gint64 bytes_skipped;
gint64 bytes_sent;
};
struct _GstCDXAParseClass {
GstElementClass parent_class;
};
GType gst_cdxa_parse_get_type (void);
G_END_DECLS
#endif /* __GST_CDXA_PARSE_H__ */

View file

@ -1,409 +0,0 @@
/* GStreamer CDXA sync strippper / VCD parser
* Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
* Copyright (C) 2008 Tim-Philipp Müller <tim centricular 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 "gstvcdparse.h"
GST_DEBUG_CATEGORY_EXTERN (vcdparse_debug);
#define GST_CAT_DEFAULT vcdparse_debug
static gboolean gst_vcd_parse_sink_event (GstPad * pad, GstEvent * event);
static gboolean gst_vcd_parse_src_event (GstPad * pad, GstEvent * event);
static gboolean gst_vcd_parse_src_query (GstPad * pad, GstQuery * query);
static GstFlowReturn gst_vcd_parse_chain (GstPad * pad, GstBuffer * buf);
static GstStateChangeReturn gst_vcd_parse_change_state (GstElement * element,
GstStateChange transition);
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-vcd")
);
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/mpeg, systemstream = (boolean) TRUE")
);
GST_BOILERPLATE (GstVcdParse, gst_vcd_parse, GstElement, GST_TYPE_ELEMENT);
static void
gst_vcd_parse_base_init (gpointer klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_add_static_pad_template (element_class, &sink_factory);
gst_element_class_add_static_pad_template (element_class, &src_factory);
gst_element_class_set_static_metadata (element_class, "(S)VCD stream parser",
"Codec/Parser", "Strip (S)VCD stream from its sync headers",
"Tim-Philipp Müller <tim centricular net>, "
"Ronald Bultje <rbultje@ronald.bitfreak.net>");
}
static void
gst_vcd_parse_class_init (GstVcdParseClass * klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
element_class->change_state = GST_DEBUG_FUNCPTR (gst_vcd_parse_change_state);
}
static void
gst_vcd_parse_init (GstVcdParse * vcd, GstVcdParseClass * klass)
{
vcd->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
gst_pad_set_chain_function (vcd->sinkpad,
GST_DEBUG_FUNCPTR (gst_vcd_parse_chain));
gst_pad_set_event_function (vcd->sinkpad,
GST_DEBUG_FUNCPTR (gst_vcd_parse_sink_event));
gst_element_add_pad (GST_ELEMENT (vcd), vcd->sinkpad);
vcd->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
gst_pad_set_event_function (vcd->srcpad,
GST_DEBUG_FUNCPTR (gst_vcd_parse_src_event));
gst_pad_set_query_function (vcd->srcpad,
GST_DEBUG_FUNCPTR (gst_vcd_parse_src_query));
gst_pad_use_fixed_caps (vcd->srcpad);
gst_pad_set_caps (vcd->srcpad,
gst_static_pad_template_get_caps (&src_factory));
gst_element_add_pad (GST_ELEMENT (vcd), vcd->srcpad);
}
/* These conversion functions assume there's no junk between sectors */
static gint64
gst_vcd_parse_get_out_offset (gint64 in_offset)
{
gint64 out_offset, chunknum, rest;
if (in_offset == -1)
return -1;
if (G_UNLIKELY (in_offset < -1)) {
GST_WARNING ("unexpected/invalid in_offset %" G_GINT64_FORMAT, in_offset);
return in_offset;
}
chunknum = in_offset / GST_CDXA_SECTOR_SIZE;
rest = in_offset % GST_CDXA_SECTOR_SIZE;
out_offset = chunknum * GST_CDXA_DATA_SIZE;
if (rest > GST_CDXA_HEADER_SIZE) {
if (rest >= GST_CDXA_HEADER_SIZE + GST_CDXA_DATA_SIZE)
out_offset += GST_CDXA_DATA_SIZE;
else
out_offset += rest - GST_CDXA_HEADER_SIZE;
}
GST_LOG ("transformed in_offset %" G_GINT64_FORMAT " to out_offset %"
G_GINT64_FORMAT, in_offset, out_offset);
return out_offset;
}
static gint64
gst_vcd_parse_get_in_offset (gint64 out_offset)
{
gint64 in_offset, chunknum, rest;
if (out_offset == -1)
return -1;
if (G_UNLIKELY (out_offset < -1)) {
GST_WARNING ("unexpected/invalid out_offset %" G_GINT64_FORMAT, out_offset);
return out_offset;
}
chunknum = out_offset / GST_CDXA_DATA_SIZE;
rest = out_offset % GST_CDXA_DATA_SIZE;
in_offset = chunknum * GST_CDXA_SECTOR_SIZE;
if (rest > 0)
in_offset += GST_CDXA_HEADER_SIZE + rest;
GST_LOG ("transformed out_offset %" G_GINT64_FORMAT " to in_offset %"
G_GINT64_FORMAT, out_offset, in_offset);
return in_offset;
}
static gboolean
gst_vcd_parse_src_query (GstPad * pad, GstQuery * query)
{
GstVcdParse *vcd = GST_VCD_PARSE (gst_pad_get_parent (pad));
gboolean res = FALSE;
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_DURATION:{
GstFormat format;
gint64 dur;
/* first try upstream */
if (!gst_pad_query_default (pad, query))
break;
/* we can only handle BYTES */
gst_query_parse_duration (query, &format, &dur);
if (format != GST_FORMAT_BYTES)
break;
gst_query_set_duration (query, GST_FORMAT_BYTES,
gst_vcd_parse_get_out_offset (dur));
res = TRUE;
break;
}
case GST_QUERY_POSITION:{
GstFormat format;
gint64 pos;
/* first try upstream */
if (!gst_pad_query_default (pad, query))
break;
/* we can only handle BYTES */
gst_query_parse_position (query, &format, &pos);
if (format != GST_FORMAT_BYTES)
break;
gst_query_set_position (query, GST_FORMAT_BYTES,
gst_vcd_parse_get_out_offset (pos));
res = TRUE;
break;
}
default:
res = gst_pad_query_default (pad, query);
break;
}
gst_object_unref (vcd);
return res;
}
static gboolean
gst_vcd_parse_sink_event (GstPad * pad, GstEvent * event)
{
GstVcdParse *vcd = GST_VCD_PARSE (gst_pad_get_parent (pad));
gboolean res;
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_NEWSEGMENT:{
GstFormat format;
gboolean update;
gdouble rate, applied_rate;
gint64 start, stop, position;
gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
&format, &start, &stop, &position);
if (format == GST_FORMAT_BYTES) {
gst_event_unref (event);
event = gst_event_new_new_segment_full (update, rate, applied_rate,
GST_FORMAT_BYTES, gst_vcd_parse_get_out_offset (start),
gst_vcd_parse_get_out_offset (stop), position);
} else {
GST_WARNING_OBJECT (vcd, "newsegment event in non-byte format");
}
res = gst_pad_event_default (pad, event);
break;
}
case GST_EVENT_FLUSH_START:
gst_adapter_clear (vcd->adapter);
/* fall through */
default:
res = gst_pad_event_default (pad, event);
break;
}
gst_object_unref (vcd);
return res;
}
static gboolean
gst_vcd_parse_src_event (GstPad * pad, GstEvent * event)
{
GstVcdParse *vcd = GST_VCD_PARSE (gst_pad_get_parent (pad));
gboolean res;
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK:{
GstSeekType start_type, stop_type;
GstSeekFlags flags;
GstFormat format;
gdouble rate;
gint64 start, stop;
gst_event_parse_seek (event, &rate, &format, &flags, &start_type,
&start, &stop_type, &stop);
if (format == GST_FORMAT_BYTES) {
gst_event_unref (event);
if (start_type != GST_SEEK_TYPE_NONE)
start = gst_vcd_parse_get_in_offset (start);
if (stop_type != GST_SEEK_TYPE_NONE)
stop = gst_vcd_parse_get_in_offset (stop);
event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, start_type,
start, stop_type, stop);
} else {
GST_WARNING_OBJECT (vcd, "seek event in non-byte format");
}
res = gst_pad_event_default (pad, event);
break;
}
default:
res = gst_pad_event_default (pad, event);
break;
}
gst_object_unref (vcd);
return res;
}
/* -1 = no sync (discard buffer),
* otherwise offset indicates sync point in buffer */
static gint
gst_vcd_parse_sync (const guint8 * data, guint size)
{
const guint8 sync_marker[12] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00
};
guint off = 0;
while (size >= 12) {
if (memcmp (data, sync_marker, 12) == 0)
return off;
--size;
++data;
++off;
}
return -1;
}
static GstFlowReturn
gst_vcd_parse_chain (GstPad * pad, GstBuffer * buf)
{
GstVcdParse *vcd = GST_VCD_PARSE (GST_PAD_PARENT (pad));
GstFlowReturn flow = GST_FLOW_OK;
gst_adapter_push (vcd->adapter, buf);
buf = NULL;
while (gst_adapter_available (vcd->adapter) >= GST_CDXA_SECTOR_SIZE) {
const guint8 *data;
guint8 header[4 + 8];
gint sync_offset;
/* find sync (we could peek any size though really) */
data = gst_adapter_peek (vcd->adapter, GST_CDXA_SECTOR_SIZE);
sync_offset = gst_vcd_parse_sync (data, GST_CDXA_SECTOR_SIZE);
GST_LOG_OBJECT (vcd, "sync offset = %d", sync_offset);
if (sync_offset < 0) {
gst_adapter_flush (vcd->adapter, GST_CDXA_SECTOR_SIZE - 12);
continue; /* try again */
}
gst_adapter_flush (vcd->adapter, sync_offset);
if (gst_adapter_available (vcd->adapter) < GST_CDXA_SECTOR_SIZE) {
GST_LOG_OBJECT (vcd, "not enough data in adapter, waiting for more");
break;
}
GST_LOG_OBJECT (vcd, "have full sector");
/* have one sector: a sector is 2352 bytes long and is composed of:
*
* +-------------------------------------------------------+
* ! sync ! header ! subheader ! data ... ! edc !
* ! 12 bytes ! 4 bytes ! 8 bytes ! 2324 bytes ! 4 bytes !
* +-------------------------------------------------------+
*
* We strip the data out of it and send it to the srcpad.
*
* sync : 00 FF FF FF FF FF FF FF FF FF FF 00
* header : hour minute second mode
* sub-header : track channel sub_mode coding repeat (4 bytes)
* edc : checksum
*/
/* Skip CDXA header and edc footer, only keep data in the middle */
gst_adapter_copy (vcd->adapter, header, 12, sizeof (header));
gst_adapter_flush (vcd->adapter, GST_CDXA_HEADER_SIZE);
buf = gst_adapter_take_buffer (vcd->adapter, GST_CDXA_DATA_SIZE);
gst_adapter_flush (vcd->adapter, 4);
/* we could probably do something clever to keep track of buffer offsets */
buf = gst_buffer_make_metadata_writable (buf);
GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE;
GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
gst_buffer_set_caps (buf, GST_PAD_CAPS (vcd->srcpad));
flow = gst_pad_push (vcd->srcpad, buf);
buf = NULL;
if (G_UNLIKELY (flow != GST_FLOW_OK)) {
GST_DEBUG_OBJECT (vcd, "flow: %s", gst_flow_get_name (flow));
break;
}
}
return flow;
}
static GstStateChangeReturn
gst_vcd_parse_change_state (GstElement * element, GstStateChange transition)
{
GstStateChangeReturn res = GST_STATE_CHANGE_SUCCESS;
GstVcdParse *vcd = GST_VCD_PARSE (element);
switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED:
vcd->adapter = gst_adapter_new ();
break;
default:
break;
}
res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
case GST_STATE_CHANGE_READY_TO_NULL:
if (vcd->adapter) {
g_object_unref (vcd->adapter);
vcd->adapter = NULL;
}
break;
default:
break;
}
return res;
}

View file

@ -1,64 +0,0 @@
/* GStreamer CDXA sync strippper / VCD parser
* Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
* Copyright (C) 2008 Tim-Philipp Müller <tim centricular 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_VCD_PARSE_H__
#define __GST_VCD_PARSE_H__
#include <gst/gst.h>
#include <gst/base/gstadapter.h>
G_BEGIN_DECLS
#define GST_TYPE_VCD_PARSE \
(gst_vcd_parse_get_type())
#define GST_VCD_PARSE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VCD_PARSE,GstVcdParse))
#define GST_VCD_PARSE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VCD_PARSE,GstVcdParseClass))
#define GST_IS_VCD_PARSE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VCD_PARSE))
#define GST_IS_VCD_PARSE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VCD_PARSE))
#define GST_CDXA_SECTOR_SIZE 2352
#define GST_CDXA_DATA_SIZE 2324
#define GST_CDXA_HEADER_SIZE 24
typedef struct _GstVcdParse GstVcdParse;
typedef struct _GstVcdParseClass GstVcdParseClass;
struct _GstVcdParse {
GstElement element;
GstPad *sinkpad;
GstPad *srcpad;
GstAdapter *adapter;
};
struct _GstVcdParseClass {
GstElementClass element_class;
};
GType gst_vcd_parse_get_type (void);
G_END_DECLS
#endif /* __GST_VCD_PARSE_H__ */

View file

@ -1,13 +0,0 @@
cdxaparse_sources = [
'gstcdxaparse.c',
'gstvcdparse.c',
]
gstcdxaparse = library('gstcdxaparse',
cdxaparse_sources,
c_args : gst_plugins_bad_args,
include_directories : [configinc],
dependencies : [gstbase_dep, gstriff_dep],
install : true,
install_dir : plugins_install_dir,
)

View file

@ -1,25 +0,0 @@
# plugindir is set in configure
plugin_LTLIBRARIES = libgstdccp.la
# sources used to compile this plug-in
libgstdccp_la_SOURCES = gstdccpplugin.c \
gstdccp.c \
gstdccpserversink.c \
gstdccpserversrc.c \
gstdccpclientsink.c \
gstdccpclientsrc.c
# flags used to compile this plugin
libgstdccp_la_CFLAGS = $(GST_CFLAGS)
libgstdccp_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) $(DCCP_LIBS) $(WINSOCK2_LIBS)
libgstdccp_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstdccp_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
# headers we need but don't want installed
noinst_HEADERS = gstdccp.h \
gstdccpserversink.h \
gstdccpserversrc.h \
gstdccpclientsink.h \
gstdccpclientsrc.h \
gstdccp_common.h

View file

@ -1,560 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Leandro Melo de Sales <leandroal@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 "gstdccp.h"
#ifdef HAVE_FIONREAD_IN_SYS_FILIO
#include <sys/filio.h>
#endif
/*
* Resolves host to IP address
* @param element - the element
* @return a gchar pointer containing the ip address or NULL if it
* couldn't resolve the host to a IP adress
*/
gchar *
gst_dccp_host_to_ip (GstElement * element, const gchar * host)
{
struct hostent *hostinfo;
char **addrs;
gchar *ip;
struct in_addr addr;
GST_DEBUG_OBJECT (element, "resolving host %s", host);
/* first check if it already is an IP address */
#ifndef G_OS_WIN32
if (inet_aton (host, &addr)) {
#else
if ((addr.S_un.S_addr = inet_addr (host)) != INADDR_NONE) {
#endif
ip = g_strdup (host);
GST_DEBUG_OBJECT (element, "resolved to IP %s", ip);
return ip;
}
/* perform a name lookup */
if (!(hostinfo = gethostbyname (host))) {
GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND, (NULL),
("Could not find IP address for host \"%s\".", host));
return NULL;
}
if (hostinfo->h_addrtype != AF_INET) {
GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND, (NULL),
("host \"%s\" is not an IP host", host));
return NULL;
}
addrs = hostinfo->h_addr_list;
/* There could be more than one IP address, but we just return the first */
ip = g_strdup (inet_ntoa (*(struct in_addr *) *addrs));
return ip;
}
/*
* Read a buffer from the given socket
*
* @param this - the element that has the socket that will be read
* @param socket - the socket fd that will be read
* @param buf - the buffer with the data read from the socket
* @return GST_FLOW_OK if the read operation was successful
* or GST_FLOW_ERROR indicating a connection close or an error.
* Handle it with EOS.
*/
GstFlowReturn
gst_dccp_read_buffer (GstElement * this, int socket, GstBuffer ** buf)
{
fd_set testfds;
int maxfdp1;
gssize bytes_read;
#ifndef G_OS_WIN32
int readsize;
struct msghdr mh;
struct iovec iov;
#else
unsigned long readsize;
#endif
*buf = NULL;
/* do a blocking select on the socket */
FD_ZERO (&testfds);
FD_SET (socket, &testfds);
maxfdp1 = socket + 1;
/* no action (0) is also an error in our case */
if (select (maxfdp1, &testfds, NULL, NULL, 0) <= 0) {
GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
("select failed: %s", g_strerror (errno)));
return GST_FLOW_ERROR;
}
/* ask how much is available for reading on the socket */
#ifndef G_OS_WIN32
if (ioctl (socket, FIONREAD, &readsize) < 0) {
GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
("read FIONREAD value failed: %s", g_strerror (errno)));
#else
if (ioctlsocket (socket, FIONREAD, &readsize) == SOCKET_ERROR) {
GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL),
("read FIONREAD value failed: %s", g_strerror (WSAGetLastError ())));
#endif
return GST_FLOW_ERROR;
}
if (readsize == 0) {
GST_DEBUG_OBJECT (this, "Got EOS on socket stream");
return GST_FLOW_UNEXPECTED;
}
*buf = gst_buffer_new_and_alloc ((int) readsize);
#ifndef G_OS_WIN32
memset (&mh, 0, sizeof (mh));
mh.msg_name = NULL;
mh.msg_namelen = 0;
iov.iov_base = (char *) GST_BUFFER_DATA (*buf);
iov.iov_len = readsize;
mh.msg_iov = &iov;
mh.msg_iovlen = 1;
bytes_read = recvmsg (socket, &mh, 0);
#else
bytes_read =
recvfrom (socket, (char *) GST_BUFFER_DATA (*buf), (int) readsize, 0,
NULL, 0);
#endif
if (bytes_read != readsize) {
GST_DEBUG_OBJECT (this, "Error while reading data");
return GST_FLOW_ERROR;
}
GST_LOG_OBJECT (this, "bytes read %" G_GSSIZE_FORMAT, bytes_read);
GST_LOG_OBJECT (this, "returning buffer of size %d", GST_BUFFER_SIZE (*buf));
return GST_FLOW_OK;
}
/* Create a new DCCP socket
*
* @param element - the element
* @return the socket file descriptor
*/
gint
gst_dccp_create_new_socket (GstElement * element)
{
int sock_fd;
if ((sock_fd = socket (AF_INET, SOCK_DCCP, IPPROTO_DCCP)) < 0) {
GST_ELEMENT_ERROR (element, RESOURCE, OPEN_READ, (NULL), GST_ERROR_SYSTEM);
}
return sock_fd;
}
/* Connect to a server
* @param element - the element
* @param server_sin - a struct with a server address and port
* @param sock_fd - the socket to connect
* @return TRUE in case of successful connection, FALSE otherwise
*/
gboolean
gst_dccp_connect_to_server (GstElement * element, struct sockaddr_in server_sin,
int sock_fd)
{
#ifdef G_OS_WIN32
int errorCode;
#endif
GST_DEBUG_OBJECT (element, "connecting to server");
if (connect (sock_fd, (struct sockaddr *) &server_sin, sizeof (server_sin))) {
#ifdef G_OS_WIN32
errorCode = WSAGetLastError ();
switch (errorCode) {
case WSAECONNREFUSED:
GST_ELEMENT_ERROR (element, RESOURCE, OPEN_WRITE,
("Connection to %s:%d refused.", inet_ntoa (server_sin.sin_addr),
ntohs (server_sin.sin_port)), (NULL));
return FALSE;
break;
default:
GST_ELEMENT_ERROR (element, RESOURCE, OPEN_READ, (NULL),
("Connect to %s:%d failed: %s", inet_ntoa (server_sin.sin_addr),
ntohs (server_sin.sin_port), g_strerror (errorCode)));
return FALSE;
break;
}
#else
switch (errno) {
case ECONNREFUSED:
GST_ELEMENT_ERROR (element, RESOURCE, OPEN_WRITE,
("Connection to %s:%d refused.", inet_ntoa (server_sin.sin_addr),
ntohs (server_sin.sin_port)), (NULL));
return FALSE;
break;
default:
GST_ELEMENT_ERROR (element, RESOURCE, OPEN_READ, (NULL),
("Connect to %s:%d failed: %s", inet_ntoa (server_sin.sin_addr),
ntohs (server_sin.sin_port), g_strerror (errno)));
return FALSE;
break;
}
#endif
}
return TRUE;
}
/* FIXME support only one client */
/*
* Accept connection on the server socket.
*
* @param element - the element
* @param server_sock_fd - the server socket file descriptor
* @return the socket of the client connected to the server.
*/
gint
gst_dccp_server_wait_connections (GstElement * element, int server_sock_fd)
{
/* new client */
int client_sock_fd;
struct sockaddr_in client_address;
socklen_t client_address_len;
memset (&client_address, 0, sizeof (client_address));
client_address_len = 0;
if ((client_sock_fd =
accept (server_sock_fd, (struct sockaddr *) &client_address,
&client_address_len)) == -1) {
GST_ELEMENT_ERROR (element, RESOURCE, OPEN_WRITE, (NULL),
("Could not accept client on server socket %d: %s (%d)",
server_sock_fd, g_strerror (errno), errno));
return -1;
}
GST_DEBUG_OBJECT (element, "Added new client ip %s with fd %d.",
inet_ntoa (client_address.sin_addr), client_sock_fd);
return client_sock_fd;
}
/*
* Bind a server address.
*
* @param element - the element
* @param server_sock_fd - the server socket fd
* @param server_sin - the address and the port to bind the server on
* @return true in success, false otherwise.
*/
gboolean
gst_dccp_bind_server_socket (GstElement * element, int server_sock_fd,
struct sockaddr_in server_sin)
{
int ret;
GST_DEBUG_OBJECT (element, "Binding server socket to address.");
ret = bind (server_sock_fd, (struct sockaddr *) &server_sin,
sizeof (server_sin));
if (ret) {
switch (errno) {
default:
GST_ELEMENT_ERROR (element, RESOURCE, OPEN_READ, (NULL),
("Bind on port %d failed: %s", ntohs (server_sin.sin_port),
g_strerror (errno)));
return FALSE;
break;
}
}
return TRUE;
}
/*
* Listen on server socket.
*
* @param element - the element
* @param server_sock_fd - the server socket fd
* @return true in success, false otherwise.
*/
gboolean
gst_dccp_listen_server_socket (GstElement * element, int server_sock_fd)
{
GST_DEBUG_OBJECT (element, "Listening on server socket %d with queue of %d",
server_sock_fd, DCCP_BACKLOG);
if (listen (server_sock_fd, DCCP_BACKLOG) == -1) {
GST_ELEMENT_ERROR (element, RESOURCE, OPEN_READ, (NULL),
("Could not listen on server socket: %s", g_strerror (errno)));
return FALSE;
}
GST_DEBUG_OBJECT (element,
"Listened on server socket %d, returning from connection setup",
server_sock_fd);
return TRUE;
}
/* Write buffer to given socket incrementally.
*
* @param element - the element
* @param socket - the socket
* @param buf - the buffer that will be written
* @param size - the number of bytes of the buffer
* @param packet_size - the MTU
* @return the number of bytes written.
*/
static GstFlowReturn
gst_dccp_socket_write (GstElement * element, int socket, const void *buf,
size_t size, int packet_size)
{
size_t bytes_written = 0;
ssize_t wrote = 0;
#ifndef G_OS_WIN32
struct iovec iov;
struct msghdr mh;
memset (&mh, 0, sizeof (mh));
while (bytes_written < size) {
do {
mh.msg_name = NULL;
mh.msg_namelen = 0;
iov.iov_base = (char *) buf + bytes_written;
iov.iov_len = MIN (packet_size, size - bytes_written);
mh.msg_iov = &iov;
mh.msg_iovlen = 1;
wrote = sendmsg (socket, &mh, 0);
} while (wrote == -1 && errno == EAGAIN);
#else
int errorCode = 0;
while (bytes_written < size) {
do {
wrote = sendto (socket, (char *) buf + bytes_written,
MIN (packet_size, size - bytes_written), 0, NULL, 0);
errorCode = WSAGetLastError ();
} while (wrote == SOCKET_ERROR && errorCode == EAGAIN);
#endif
/* give up on error */
if (wrote >= 0)
bytes_written += wrote;
else
break;
}
if (wrote < 0)
GST_WARNING ("Error while writing.");
else
GST_LOG_OBJECT (element, "Wrote %" G_GSIZE_FORMAT " bytes succesfully.",
bytes_written);
if (bytes_written != size) {
GST_ELEMENT_ERROR (element, RESOURCE, WRITE,
("Error while sending data to socket %d.", socket),
("Only %" G_GSIZE_FORMAT " of %" G_GSIZE_FORMAT " bytes written: %s",
bytes_written, size, g_strerror (errno)));
return GST_FLOW_ERROR;
}
return GST_FLOW_OK;
}
/* Write buffer to given socket.
*
* @param this - the element
* @param buf - the buffer that will be written
* @param client_sock_fd - the client socket
* @param packet_size - the MTU
* @return GST_FLOW_OK if the send operation was successful, GST_FLOW_ERROR otherwise.
*/
GstFlowReturn
gst_dccp_send_buffer (GstElement * this, GstBuffer * buffer, int client_sock_fd,
int packet_size)
{
// size_t wrote;
gint size = 0;
guint8 *data;
size = GST_BUFFER_SIZE (buffer);
data = GST_BUFFER_DATA (buffer);
GST_LOG_OBJECT (this, "writing %d bytes", size);
if (packet_size < 0) {
return GST_FLOW_ERROR;
}
return gst_dccp_socket_write (this, client_sock_fd, data, size, packet_size);
}
/*
* Make address reusable.
* @param element - the element
* @param sock_fd - the socket
* @return TRUE if the operation was successful, FALSE otherwise.
*/
gboolean
gst_dccp_make_address_reusable (GstElement * element, int sock_fd)
{
int ret = 1;
/* make address reusable */
if (setsockopt (sock_fd, SOL_SOCKET, SO_REUSEADDR,
(void *) &ret, sizeof (ret)) < 0) {
GST_ELEMENT_ERROR (element, RESOURCE, SETTINGS, (NULL),
("Could not setsockopt: %s", g_strerror (errno)));
return FALSE;
}
return TRUE;
}
/*
* Set DCCP congestion control.
* @param element - the element
* @param sock_fd - the socket
* @param ccid - the ccid number
* @return TRUE if the operation was successful, FALSE otherwise.
*/
gboolean
gst_dccp_set_ccid (GstElement * element, int sock_fd, uint8_t ccid)
{
uint8_t ccids[4]; /* for getting the available CCIDs, should be large enough */
socklen_t len = sizeof (ccids);
int i, ret;
gboolean ccid_supported = FALSE;
/*
* Determine which CCIDs are available on the host
*/
#ifndef G_OS_WIN32
ret = getsockopt (sock_fd, SOL_DCCP, DCCP_SOCKOPT_AVAILABLE_CCIDS, &ccids,
&len);
#else
ret =
getsockopt (sock_fd, SOL_DCCP, DCCP_SOCKOPT_AVAILABLE_CCIDS,
(char *) &ccids, &len);
#endif
if (ret < 0) {
GST_ERROR_OBJECT (element, "Can not determine available CCIDs");
return FALSE;
}
for (i = 0; i < sizeof (ccids); i++) {
if (ccid == ccids[i]) {
ccid_supported = TRUE;
}
}
if (!ccid_supported) {
GST_ERROR_OBJECT (element, "CCID specified is not supported");
return FALSE;
}
#ifndef G_OS_WIN32
if (setsockopt (sock_fd, SOL_DCCP, DCCP_SOCKOPT_CCID, &ccid,
#else
if (setsockopt (sock_fd, SOL_DCCP, DCCP_SOCKOPT_CCID, (char *) &ccid,
#endif
sizeof (ccid)) < 0) {
GST_ERROR_OBJECT (element, "Can not set CCID");
return FALSE;
}
return TRUE;
}
#if 0
/*
* Get the current ccid of TX or RX half-connection. tx_or_rx parameter must be
* DCCP_SOCKOPT_TX_CCID or DCCP_SOCKOPT_RX_CCID.
* @return ccid or -1 on error or tx_or_rx not the correct option
*/
static uint8_t
gst_dccp_get_ccid (GstElement * element, int sock_fd, int tx_or_rx)
{
uint8_t ccid;
socklen_t ccidlen;
int ret;
switch (tx_or_rx) {
case DCCP_SOCKOPT_TX_CCID:
case DCCP_SOCKOPT_RX_CCID:
break;
default:
return -1;
}
ccidlen = sizeof (ccid);
#ifndef G_OS_WIN32
ret = getsockopt (sock_fd, SOL_DCCP, tx_or_rx, &ccid, &ccidlen);
#else
ret = getsockopt (sock_fd, SOL_DCCP, tx_or_rx, (char *) &ccid, &ccidlen);
#endif
if (ret < 0) {
GST_ERROR_OBJECT (element, "Can not determine available CCIDs");
return -1;
}
return ccid;
}
#endif
/*
* Get the socket MTU.
* @param element - the element
* @param sock - the socket
* @return the MTU if the operation was successful, -1 otherwise.
*/
gint
gst_dccp_get_max_packet_size (GstElement * element, int sock)
{
int size;
socklen_t sizelen = sizeof (size);
#ifndef G_OS_WIN32
if (getsockopt (sock, SOL_DCCP, DCCP_SOCKOPT_GET_CUR_MPS,
&size, &sizelen) < 0) {
#else
if (getsockopt (sock, SOL_DCCP, DCCP_SOCKOPT_GET_CUR_MPS,
(char *) &size, &sizelen) < 0) {
#endif
GST_ELEMENT_ERROR (element, RESOURCE, SETTINGS, (NULL),
("Could not get current MTU %d: %s", errno, g_strerror (errno)));
return -1;
}
GST_DEBUG_OBJECT (element, "MTU: %d", size);
return size;
}
void
gst_dccp_socket_close (GstElement * element, int *socket)
{
if (*socket >= 0) {
GST_DEBUG_OBJECT (element, "closing socket");
close (*socket);
*socket = -1;
}
}

View file

@ -1,94 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Leandro Melo de Sales <leandroal@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_DCCP_H__
#define __GST_DCCP_H__
#include <gst/gst.h>
#include <gst/base/gstadapter.h>
#include "gstdccp_common.h"
/* DCCP socket general options */
#define DCCP_BACKLOG 5
#ifndef SOCK_DCCP
#define SOCK_DCCP 6
#endif
#ifndef IPPROTO_DCCP
#define IPPROTO_DCCP 33
#endif
#ifndef SOL_DCCP
#define SOL_DCCP 269
#endif
/* dccp socket specific options */
#define DCCP_SOCKOPT_PACKET_SIZE 1 /* XXX deprecated, without effect */
#define DCCP_SOCKOPT_SERVICE 2
#define DCCP_SOCKOPT_CHANGE_L 3
#define DCCP_SOCKOPT_CHANGE_R 4
#define DCCP_SOCKOPT_GET_CUR_MPS 5
#define DCCP_SOCKOPT_SERVER_TIMEWAIT 6
#define DCCP_SOCKOPT_SEND_CSCOV 10
#define DCCP_SOCKOPT_RECV_CSCOV 11
#define DCCP_SOCKOPT_AVAILABLE_CCIDS 12
#define DCCP_SOCKOPT_CCID 13
#define DCCP_SOCKOPT_TX_CCID 14
#define DCCP_SOCKOPT_RX_CCID 15
#define DCCP_SOCKOPT_CCID_RX_INFO 128
#define DCCP_SOCKOPT_CCID_TX_INFO 192
/* Default parameters for the gst dccp element property */
#define DCCP_DEFAULT_PORT 5001
#define DCCP_DEFAULT_SOCK_FD -1
#define DCCP_DEFAULT_CLIENT_SOCK_FD -1
#define DCCP_DEFAULT_CLOSED TRUE
#define DCCP_DEFAULT_WAIT_CONNECTIONS FALSE
#define DCCP_DEFAULT_HOST "127.0.0.1"
#define DCCP_DEFAULT_CCID 2
#define DCCP_DELTA 100
gchar *gst_dccp_host_to_ip (GstElement * element, const gchar * host);
GstFlowReturn gst_dccp_read_buffer (GstElement * this, int socket,
GstBuffer ** buf);
gint gst_dccp_create_new_socket (GstElement * element);
gboolean gst_dccp_connect_to_server (GstElement * element,
struct sockaddr_in server_sin,
int sock_fd);
gint gst_dccp_server_wait_connections (GstElement * element, int server_sock_fd);
gboolean gst_dccp_bind_server_socket (GstElement * element, int server_sock_fd,
struct sockaddr_in server_sin);
gboolean gst_dccp_listen_server_socket (GstElement * element, int server_sock_fd);
gboolean gst_dccp_set_ccid (GstElement * element, int sock_fd, uint8_t ccid);
gint gst_dccp_get_max_packet_size(GstElement * element, int sock);
GstFlowReturn gst_dccp_send_buffer (GstElement * element, GstBuffer * buffer,
int client_sock_fd, int packet_size);
gboolean gst_dccp_make_address_reusable (GstElement * element, int sock_fd);
void gst_dccp_socket_close (GstElement * element, int * socket);
#endif /* __GST_DCCP_H__ */

View file

@ -1,56 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Leandro Melo de Sales <leandroal@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_DCCP_NET_H__
#define __GST_DCCP_NET_H__
#ifndef G_OS_WIN32
# include <netdb.h>
# include <sys/socket.h>
# include <netinet/in.h> /* sockaddr_in */
# include <arpa/inet.h>
# include <sys/ioctl.h>
#else
/* ws2_32.dll has getaddrinfo and freeaddrinfo on Windows XP and later.
* minwg32 headers check WINVER before allowing the use of these */
#ifndef WINVER
# define WINVER 0x0501
#endif
# include <winsock2.h>
# include <ws2tcpip.h>
#ifndef socklen_t
#define socklen_t int
#endif
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#endif /* __GST_DCCP_NET_H__ */

View file

@ -1,335 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Leandro Melo de Sales <leandroal@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-dccpclientsink
* @see_also: dccpserversrc, dccpclientsrc, dccpserversink
*
* This element connect to a DCCP server and send data to it.
* <ulink url="http://www.linuxfoundation.org/en/Net:DCCP">DCCP</ulink> (Datagram
* Congestion Control Protocol) is a Transport Layer protocol like
* TCP and UDP.
*
* <refsect2>
* <title>Example pipeline</title>
* <para>
* |[
* gst-launch -v filesrc location=music.mp3 ! mp3parse ! dccpclientsink host=localhost port=9011 ccid=2
* ]| Client
* |[
* gst-launch -v dccpserversrc port=9011 ccid=2 ! decodebin ! alsasink
* ]| Server
*
* This example pipeline will send a MP3 stream to the server using DCCP.
* The server will decode the MP3 and play it.
* Run the server pipeline first than the client pipeline.
* </para>
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstdccpclientsink.h"
#include "gstdccp.h"
/* signals */
enum
{
SIGNAL_CONNECTED,
LAST_SIGNAL
};
/* properties */
enum
{
PROP_0,
PROP_PORT,
PROP_HOST,
PROP_SOCK_FD,
PROP_CCID,
PROP_CLOSE_FD
};
static gboolean gst_dccp_client_sink_stop (GstBaseSink * bsink);
static gboolean gst_dccp_client_sink_start (GstBaseSink * bsink);
static GstFlowReturn gst_dccp_client_sink_render (GstBaseSink * bsink,
GstBuffer * buf);
static void gst_dccp_client_sink_finalize (GObject * gobject);
GST_DEBUG_CATEGORY_STATIC (dccpclientsink_debug);
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
GST_BOILERPLATE (GstDCCPClientSink, gst_dccp_client_sink, GstBaseSink,
GST_TYPE_BASE_SINK);
static guint gst_dccp_client_sink_signals[LAST_SIGNAL] = { 0 };
/*
* Write buffer to client socket.
*
* @return GST_FLOW_OK if the send operation was successful, GST_FLOW_ERROR otherwise.
*/
static GstFlowReturn
gst_dccp_client_sink_render (GstBaseSink * bsink, GstBuffer * buf)
{
GstDCCPClientSink *sink = GST_DCCP_CLIENT_SINK (bsink);
return gst_dccp_send_buffer (GST_ELEMENT (sink), buf, sink->sock_fd,
sink->pksize);
}
/*
* Set the value of a property for the client sink.
*/
static void
gst_dccp_client_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstDCCPClientSink *sink = GST_DCCP_CLIENT_SINK (object);
switch (prop_id) {
case PROP_PORT:
sink->port = g_value_get_int (value);
break;
case PROP_SOCK_FD:
sink->sock_fd = g_value_get_int (value);
break;
case PROP_HOST:
if (!g_value_get_string (value)) {
g_warning ("host property cannot be NULL");
break;
}
g_free (sink->host);
sink->host = g_strdup (g_value_get_string (value));
break;
case PROP_CLOSE_FD:
sink->closed = g_value_get_boolean (value);
break;
case PROP_CCID:
sink->ccid = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/*
* Get a given property value for the client sink.
*/
static void
gst_dccp_client_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstDCCPClientSink *sink = GST_DCCP_CLIENT_SINK (object);
switch (prop_id) {
case PROP_PORT:
g_value_set_int (value, sink->port);
break;
case PROP_SOCK_FD:
g_value_set_int (value, sink->sock_fd);
break;
case PROP_HOST:
g_value_set_string (value, sink->host);
break;
case PROP_CLOSE_FD:
g_value_set_boolean (value, sink->closed);
break;
case PROP_CCID:
g_value_set_int (value, sink->ccid);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_dccp_client_sink_finalize (GObject * gobject)
{
GstDCCPClientSink *this = GST_DCCP_CLIENT_SINK (gobject);
g_free (this->host);
G_OBJECT_CLASS (parent_class)->finalize (gobject);
}
/*
* Starts the element. If the sockfd property was not the default, this method
* will create a new socket and connect to the server.
*
* @param bsink - the element
* @return TRUE if the send operation was successful, FALSE otherwise.
*/
static gboolean
gst_dccp_client_sink_start (GstBaseSink * bsink)
{
GstDCCPClientSink *sink = GST_DCCP_CLIENT_SINK (bsink);
if (sink->sock_fd == DCCP_DEFAULT_SOCK_FD) {
gchar *ip = NULL;
/* look up name if we need to */
if (!(ip = gst_dccp_host_to_ip (GST_ELEMENT (sink), sink->host))) {
GST_ERROR_OBJECT (sink, "cannot resolve hostname");
gst_dccp_client_sink_stop (GST_BASE_SINK (sink));
return FALSE;
}
/* name the server socket */
memset (&sink->server_sin, 0, sizeof (sink->server_sin));
sink->server_sin.sin_family = AF_INET; /* network socket */
sink->server_sin.sin_port = htons (sink->port); /* on port */
sink->server_sin.sin_addr.s_addr = inet_addr (ip); /* on host ip */
g_free (ip);
/* create socket */
if ((sink->sock_fd = gst_dccp_create_new_socket (GST_ELEMENT (sink))) < 0) {
return FALSE;
}
if (!gst_dccp_set_ccid (GST_ELEMENT (sink), sink->sock_fd, sink->ccid)) {
gst_dccp_client_sink_stop (GST_BASE_SINK (sink));
return FALSE;
}
if (!gst_dccp_connect_to_server (GST_ELEMENT (sink), sink->server_sin,
sink->sock_fd)) {
gst_dccp_client_sink_stop (GST_BASE_SINK (sink));
return FALSE;
}
/* the socket is connected */
g_signal_emit (sink, gst_dccp_client_sink_signals[SIGNAL_CONNECTED], 0,
sink->sock_fd);
}
sink->pksize =
gst_dccp_get_max_packet_size (GST_ELEMENT (sink), sink->sock_fd);
return TRUE;
}
static void
gst_dccp_client_sink_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_static_pad_template (element_class, &sinktemplate);
gst_element_class_set_static_metadata (element_class, "DCCP client sink",
"Sink/Network",
"Send data as a client over the network via DCCP",
"E-Phone Team at Federal University of Campina Grande <leandroal@gmail.com>");
}
static void
gst_dccp_client_sink_init (GstDCCPClientSink * this,
GstDCCPClientSinkClass * g_class)
{
this->port = DCCP_DEFAULT_PORT;
this->host = g_strdup (DCCP_DEFAULT_HOST);
this->sock_fd = DCCP_DEFAULT_SOCK_FD;
this->closed = DCCP_DEFAULT_CLOSED;
this->ccid = DCCP_DEFAULT_CCID;
}
static gboolean
gst_dccp_client_sink_stop (GstBaseSink * bsink)
{
GstDCCPClientSink *sink;
sink = GST_DCCP_CLIENT_SINK (bsink);
if (sink->sock_fd != DCCP_DEFAULT_SOCK_FD && sink->closed) {
gst_dccp_socket_close (GST_ELEMENT (sink), &(sink->sock_fd));
}
return TRUE;
}
/*
* Define the gst class, callbacks, etc.
*/
static void
gst_dccp_client_sink_class_init (GstDCCPClientSinkClass * klass)
{
GObjectClass *gobject_class;
GstBaseSinkClass *gstbasesink_class;
gobject_class = (GObjectClass *) klass;
gstbasesink_class = (GstBaseSinkClass *) klass;
gobject_class->set_property = gst_dccp_client_sink_set_property;
gobject_class->get_property = gst_dccp_client_sink_get_property;
gobject_class->finalize = gst_dccp_client_sink_finalize;
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PORT,
g_param_spec_int ("port", "Port",
"The port to send the packets to", 0, G_MAXUINT16,
DCCP_DEFAULT_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_HOST,
g_param_spec_string ("host", "Host",
"The host IP address to send packets to", DCCP_DEFAULT_HOST,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_SOCK_FD,
g_param_spec_int ("sockfd", "Socket fd",
"The socket file descriptor", -1, G_MAXINT,
DCCP_DEFAULT_SOCK_FD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CLOSE_FD,
g_param_spec_boolean ("close-socket", "Close",
"Close socket at end of stream",
DCCP_DEFAULT_CLOSED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CCID,
g_param_spec_int ("ccid", "CCID",
"The Congestion Control IDentified to be used", 2, G_MAXINT,
DCCP_DEFAULT_CCID, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/* signals */
/**
* GstDccpClientSink::connected:
* @sink: the gstdccpclientsink element that emitted this signal
* @fd: the connected socket file descriptor
*
* Sign that the element has connected, return the fd of the socket.
*/
gst_dccp_client_sink_signals[SIGNAL_CONNECTED] =
g_signal_new ("connected", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GstDCCPClientSinkClass, connected), NULL, NULL,
gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
gstbasesink_class->start = gst_dccp_client_sink_start;
gstbasesink_class->stop = gst_dccp_client_sink_stop;
gstbasesink_class->render = gst_dccp_client_sink_render;
GST_DEBUG_CATEGORY_INIT (dccpclientsink_debug, "dccpclientsink", 0,
"DCCP Client Sink");
}

View file

@ -1,82 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Leandro Melo de Sales <leandroal@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_DCCP_CLIENT_SINK_H__
#define __GST_DCCP_CLIENT_SINK_H__
#include <gst/gst.h>
#include <gst/base/gstbasesink.h>
#include <gst/base/gstadapter.h>
G_BEGIN_DECLS
#include "gstdccp_common.h"
#define GST_TYPE_DCCP_CLIENT_SINK \
(gst_dccp_client_sink_get_type())
#define GST_DCCP_CLIENT_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DCCP_CLIENT_SINK,GstDCCPClientSink))
#define GST_DCCP_CLIENT_SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DCCP_CLIENT_SINK,GstDCCPClientSinkClass))
#define GST_IS_DCCP_CLIENT_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DCCP_CLIENT_SINK))
#define GST_IS_DCCP_CLIENT_SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DCCP_CLIENT_SINK))
typedef struct _GstDCCPClientSink GstDCCPClientSink;
typedef struct _GstDCCPClientSinkClass GstDCCPClientSinkClass;
/**
* GstDCCPClientSink:
*
* dccpclientsink object structure.
*/
struct _GstDCCPClientSink
{
GstBaseSink element;
/* server information */
int port;
gchar *host;
struct sockaddr_in server_sin;
/* socket */
int sock_fd;
gboolean closed;
int pksize;
GstCaps *caps;
uint8_t ccid;
};
struct _GstDCCPClientSinkClass
{
GstBaseSinkClass parent_class;
/* signals */
void (*connected) (GstElement *sink, gint fd);
};
GType gst_dccp_client_sink_get_type (void);
G_END_DECLS
#endif /* __GST_DCCP_CLIENT_SRC_H__ */

View file

@ -1,405 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Leandro Melo de Sales <leandroal@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-dccpclientsrc
* @see_also: dccpclientsink, dccpserversink, dccpserversrc
*
* This element connect to a DCCP server and send data to it.
* <ulink url="http://www.linuxfoundation.org/en/Net:DCCP">DCCP</ulink> (Datagram
* Congestion Control Protocol) is a Transport Layer protocol like
* TCP and UDP.
*
* <refsect2>
* <title>Example pipeline</title>
* <para>
* |[
* gst-launch -v dccpclientsrc host=localhost port=9011 ccid=2 ! decodebin ! alsasink
* ]| Client
* |[
* gst-launch -v filesrc location=music.mp3 ! mp3parse ! dccpserversink port=9011 ccid=2
* ]| Server
*
* This example pipeline will send a MP3 stream to the client using DCCP.
* The client will decode the MP3 and play it. Run the server pipeline
* first than the client pipeline. If you want, you can run more than one dccpclientsrc
* to connect to the same server (see wait-connections property at dccpserversink).
* </para>
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstdccpclientsrc.h"
#include "gstdccp.h"
#include <fcntl.h>
#ifdef HAVE_FIONREAD_IN_SYS_FILIO
#include <sys/filio.h>
#endif
#define DCCP_DEFAULT_CAPS NULL
/* signals */
enum
{
SIGNAL_CONNECTED,
LAST_SIGNAL
};
/* properties */
enum
{
PROP_0,
PROP_PORT,
PROP_HOST,
PROP_SOCK_FD,
PROP_CLOSED,
PROP_CCID,
PROP_CAPS
};
static gboolean gst_dccp_client_src_stop (GstBaseSrc * bsrc);
GST_DEBUG_CATEGORY_STATIC (dccpclientsrc_debug);
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
GST_BOILERPLATE (GstDCCPClientSrc, gst_dccp_client_src, GstPushSrc,
GST_TYPE_PUSH_SRC);
static guint gst_dccp_client_src_signals[LAST_SIGNAL] = { 0 };
/*
* Read a buffer from the client socket
*
* @return GST_FLOW_OK if the send operation was successful, GST_FLOW_ERROR otherwise.
*/
static GstFlowReturn
gst_dccp_client_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
{
GstDCCPClientSrc *src;
GstFlowReturn ret = GST_FLOW_OK;
src = GST_DCCP_CLIENT_SRC (psrc);
GST_LOG_OBJECT (src, "reading a buffer");
ret = gst_dccp_read_buffer (GST_ELEMENT (src), src->sock_fd, outbuf);
if (ret == GST_FLOW_OK) {
GST_LOG_OBJECT (src,
"Returning buffer from _get of size %d, ts %"
GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT
", offset %" G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
GST_BUFFER_SIZE (*outbuf),
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (*outbuf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (*outbuf)),
GST_BUFFER_OFFSET (*outbuf), GST_BUFFER_OFFSET_END (*outbuf));
if (!gst_caps_is_equal (src->caps, GST_CAPS_ANY)) {
gst_buffer_set_caps (*outbuf, src->caps);
}
}
return ret;
}
/*
* Set the value of a property for the client src.
*/
static void
gst_dccp_client_src_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstDCCPClientSrc *src = GST_DCCP_CLIENT_SRC (object);
switch (prop_id) {
case PROP_PORT:
src->port = g_value_get_int (value);
break;
case PROP_HOST:
if (!g_value_get_string (value)) {
g_warning ("host property cannot be NULL");
break;
}
g_free (src->host);
src->host = g_strdup (g_value_get_string (value));
break;
case PROP_SOCK_FD:
src->sock_fd = g_value_get_int (value);
break;
case PROP_CLOSED:
src->closed = g_value_get_boolean (value);
break;
case PROP_CCID:
src->ccid = g_value_get_int (value);
break;
case PROP_CAPS:
{
const GstCaps *new_caps_val = gst_value_get_caps (value);
GstCaps *new_caps;
GstCaps *old_caps;
if (new_caps_val == NULL) {
new_caps = gst_caps_new_any ();
} else {
new_caps = gst_caps_copy (new_caps_val);
}
old_caps = src->caps;
src->caps = new_caps;
if (old_caps)
gst_caps_unref (old_caps);
gst_pad_set_caps (GST_BASE_SRC (src)->srcpad, new_caps);
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/*
* Get a given property value for the client src.
*/
static void
gst_dccp_client_src_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstDCCPClientSrc *src = GST_DCCP_CLIENT_SRC (object);
switch (prop_id) {
case PROP_PORT:
g_value_set_int (value, src->port);
break;
case PROP_HOST:
g_value_set_string (value, src->host);
break;
case PROP_SOCK_FD:
g_value_set_int (value, src->sock_fd);
break;
case PROP_CLOSED:
g_value_set_boolean (value, src->closed);
break;
case PROP_CCID:
g_value_set_int (value, src->ccid);
break;
case PROP_CAPS:
gst_value_set_caps (value, src->caps);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/*
* Starts the element. If the sockfd property was not the default, this method
* will create a new socket and connect to the server.
*
* @param bsrc - the element
* @return TRUE if the send operation was successful, FALSE otherwise.
*/
static gboolean
gst_dccp_client_src_start (GstBaseSrc * bsrc)
{
GstDCCPClientSrc *src = GST_DCCP_CLIENT_SRC (bsrc);
if (src->sock_fd == DCCP_DEFAULT_SOCK_FD) {
gchar *ip = NULL;
/* look up name if we need to */
if (!(ip = gst_dccp_host_to_ip (GST_ELEMENT (src), src->host))) {
GST_ERROR_OBJECT (src, "cannot resolve hostname");
gst_dccp_client_src_stop (GST_BASE_SRC (src));
return FALSE;
}
/* name the server socket */
memset (&src->server_sin, 0, sizeof (src->server_sin));
src->server_sin.sin_family = AF_INET; /* network socket */
src->server_sin.sin_port = htons (src->port); /* on port */
src->server_sin.sin_addr.s_addr = inet_addr (ip); /* on host ip */
g_free (ip);
/* create socket */
if ((src->sock_fd = gst_dccp_create_new_socket (GST_ELEMENT (src))) < 0) {
return FALSE;
}
if (!gst_dccp_set_ccid (GST_ELEMENT (src), src->sock_fd, src->ccid)) {
gst_dccp_client_src_stop (GST_BASE_SRC (src));
return FALSE;
}
if (!gst_dccp_connect_to_server (GST_ELEMENT (src), src->server_sin,
src->sock_fd)) {
gst_dccp_client_src_stop (GST_BASE_SRC (src));
return FALSE;
}
/* the socket is connected */
g_signal_emit (src, gst_dccp_client_src_signals[SIGNAL_CONNECTED], 0,
src->sock_fd);
}
return TRUE;
}
static void
gst_dccp_client_src_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_static_pad_template (element_class, &srctemplate);
gst_element_class_set_static_metadata (element_class, "DCCP client source",
"Source/Network",
"Receive data as a client over the network via DCCP",
"E-Phone Team at Federal University of Campina Grande <leandroal@gmail.com>");
}
static void
gst_dccp_client_src_init (GstDCCPClientSrc * this,
GstDCCPClientSrcClass * g_class)
{
this->port = DCCP_DEFAULT_PORT;
this->host = g_strdup (DCCP_DEFAULT_HOST);
this->sock_fd = DCCP_DEFAULT_SOCK_FD;
this->closed = DCCP_DEFAULT_CLOSED;
this->ccid = DCCP_DEFAULT_CCID;
this->caps = NULL;
gst_base_src_set_format (GST_BASE_SRC (this), GST_FORMAT_TIME);
/* Checking if the version of the gstreamer is bigger that 0.10.15 */
#if ((GST_VERSION_MAJOR > 0) || \
(GST_VERSION_MAJOR == 0 && GST_VERSION_MINOR > 10) || \
(GST_VERSION_MAJOR == 0 && GST_VERSION_MINOR == 10 && GST_VERSION_MICRO >= 15))
gst_base_src_set_do_timestamp (GST_BASE_SRC (this), TRUE);
#endif
/* FIXME is this correct? */
gst_base_src_set_live (GST_BASE_SRC (this), TRUE);
}
static void
gst_dccp_client_src_finalize (GObject * gobject)
{
GstDCCPClientSrc *this = GST_DCCP_CLIENT_SRC (gobject);
if (this->caps) {
gst_caps_unref (this->caps);
this->caps = NULL;
}
g_free (this->host);
G_OBJECT_CLASS (parent_class)->finalize (gobject);
}
static gboolean
gst_dccp_client_src_stop (GstBaseSrc * bsrc)
{
GstDCCPClientSrc *src;
src = GST_DCCP_CLIENT_SRC (bsrc);
if (src->sock_fd != DCCP_DEFAULT_SOCK_FD && src->closed) {
gst_dccp_socket_close (GST_ELEMENT (src), &(src->sock_fd));
}
return TRUE;
}
/*
* Define the gst class, callbacks, etc.
*/
static void
gst_dccp_client_src_class_init (GstDCCPClientSrcClass * klass)
{
GObjectClass *gobject_class;
GstBaseSrcClass *gstbasesrc_class;
GstPushSrcClass *gstpush_src_class;
gobject_class = (GObjectClass *) klass;
gstbasesrc_class = (GstBaseSrcClass *) klass;
gstpush_src_class = (GstPushSrcClass *) klass;
gobject_class->set_property = gst_dccp_client_src_set_property;
gobject_class->get_property = gst_dccp_client_src_get_property;
gobject_class->finalize = gst_dccp_client_src_finalize;
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PORT,
g_param_spec_int ("port", "Port",
"The port to receive packets from", 0, G_MAXUINT16,
DCCP_DEFAULT_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_HOST,
g_param_spec_string ("host", "Host",
"The host IP address to receive packets from", DCCP_DEFAULT_HOST,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_SOCK_FD,
g_param_spec_int ("sockfd", "Socket fd",
"The socket file descriptor", -1, G_MAXINT, DCCP_DEFAULT_SOCK_FD,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CLOSED,
g_param_spec_boolean ("close-socket", "Close socket",
"Close socket at the end of stream", DCCP_DEFAULT_CLOSED,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CAPS,
g_param_spec_boxed ("caps", "Caps",
"The caps of the source pad", GST_TYPE_CAPS,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CCID,
g_param_spec_int ("ccid", "CCID",
"The Congestion Control IDentified to be used", 2, G_MAXINT,
DCCP_DEFAULT_CCID, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/* signals */
/**
* GstDccpClientSrc::connected:
* @src: the gstdccpclientsrc element that emitted this signal
* @fd: the connected socket file descriptor
*
* Reports that the element has connected, giving the fd of the socket
*/
gst_dccp_client_src_signals[SIGNAL_CONNECTED] =
g_signal_new ("connected", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GstDCCPClientSrcClass, connected), NULL, NULL,
gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
gstbasesrc_class->start = gst_dccp_client_src_start;
gstbasesrc_class->stop = gst_dccp_client_src_stop;
gstpush_src_class->create = gst_dccp_client_src_create;
GST_DEBUG_CATEGORY_INIT (dccpclientsrc_debug, "dccpclientsrc", 0,
"DCCP Client Source");
}

View file

@ -1,72 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Leandro Melo de Sales <leandroal@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_DCCP_CLIENT_SRC_H__
#define __GST_DCCP_CLIENT_SRC_H__
#include <gst/gst.h>
#include <gst/base/gstpushsrc.h>
#include <gst/base/gstbasesrc.h>
G_BEGIN_DECLS
#include "gstdccp_common.h"
#define GST_TYPE_DCCP_CLIENT_SRC \
(gst_dccp_client_src_get_type())
#define GST_DCCP_CLIENT_SRC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DCCP_CLIENT_SRC,GstDCCPClientSrc))
#define GST_DCCP_CLIENT_SRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DCCP_CLIENT_SRC,GstDCCPClientSrcClass))
#define GST_IS_DCCP_CLIENT_SRC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DCCP_CLIENT_SRC))
#define GST_IS_DCCP_CLIENT_SRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DCCP_CLIENT_SRC))
typedef struct _GstDCCPClientSrc GstDCCPClientSrc;
typedef struct _GstDCCPClientSrcClass GstDCCPClientSrcClass;
struct _GstDCCPClientSrc {
GstPushSrc element;
/* server information */
int port;
gchar *host;
struct sockaddr_in server_sin;
/* socket */
int sock_fd;
gboolean closed;
GstCaps *caps;
uint8_t ccid;
};
struct _GstDCCPClientSrcClass {
GstPushSrcClass parent_class;
/* signals */
void (*connected) (GstElement *src, gint fd);
};
GType gst_dccp_client_src_get_type (void);
G_END_DECLS
#endif /* __GST_DCCP_CLIENT_SRC_H__ */

View file

@ -1,60 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Leandro Melo de Sales <leandroal@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 "gstdccpclientsrc.h"
#include "gstdccpserversink.h"
#include "gstdccpclientsink.h"
#include "gstdccpserversrc.h"
GST_DEBUG_CATEGORY (dccp_debug);
static gboolean
plugin_init (GstPlugin * plugin)
{
if (!gst_element_register (plugin, "dccpclientsrc", GST_RANK_NONE,
GST_TYPE_DCCP_CLIENT_SRC))
return FALSE;
if (!gst_element_register (plugin, "dccpserversink", GST_RANK_NONE,
GST_TYPE_DCCP_SERVER_SINK))
return FALSE;
if (!gst_element_register (plugin, "dccpclientsink", GST_RANK_NONE,
GST_TYPE_DCCP_CLIENT_SINK))
return FALSE;
if (!gst_element_register (plugin, "dccpserversrc", GST_RANK_NONE,
GST_TYPE_DCCP_SERVER_SRC))
return FALSE;
GST_DEBUG_CATEGORY_INIT (dccp_debug, "dccp", 0, "DCCP calls");
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
dccp,
"transfer data over the network via DCCP.",
plugin_init, VERSION, GST_LICENSE, "DCCP",
"http://garage.maemo.org/projects/ephone")

View file

@ -1,465 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Leandro Melo de Sales <leandroal@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-dccpserversink
* @see_also: dccpclientsink, dccpclientsrc, dccpserversrc
*
* This element wait for connections from clients and send data to them.
* <ulink url="http://www.linuxfoundation.org/en/Net:DCCP">DCCP</ulink> (Datagram
* Congestion Control Protocol) is a Transport Layer protocol like
* TCP and UDP.
*
* <refsect2>
* <title>Example pipeline</title>
* <para>
* |[
* gst-launch -v dccpclientsrc host=localhost port=9011 ccid=2 ! decodebin ! alsasink
* ]| Client
* |[
* gst-launch -v filesrc location=music.mp3 ! mp3parse ! dccpserversink port=9011 ccid=2
* ]| Server
*
* This example pipeline will send a MP3 stream to the client using DCCP.
* The client will decode the MP3 and play it. Run the server pipeline
* first than the client pipeline. If you want, you can run more than one dccpclientsrc
* to connect to the same server (see wait-connections property at dccpserversink).
* </para>
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstdccpserversink.h"
#include "gstdccp.h"
#include <fcntl.h>
/* signals */
enum
{
SIGNAL_CONNECTED,
LAST_SIGNAL
};
/* properties */
enum
{
PROP_0,
PROP_PORT,
PROP_CLIENT_SOCK_FD,
PROP_CCID,
PROP_CLOSED,
PROP_WAIT_CONNECTIONS
};
static pthread_t accept_thread_id;
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static gboolean gst_dccp_server_sink_stop (GstBaseSink * bsink);
GST_DEBUG_CATEGORY_STATIC (dccpserversink_debug);
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
GST_BOILERPLATE (GstDCCPServerSink, gst_dccp_server_sink, GstBaseSink,
GST_TYPE_BASE_SINK);
static guint gst_dccp_server_sink_signals[LAST_SIGNAL] = { 0 };
/*
* Create a new client with the socket and the MTU
*
* @param element - the gstdccpserversink instance
* @param socket - the client socket
* @return the client
*/
static Client *
gst_dccp_server_create_client (GstElement * element, int socket)
{
Client *client = (Client *) g_malloc (sizeof (Client));
client->socket = socket;
client->pksize = gst_dccp_get_max_packet_size (element, client->socket);
client->flow_status = GST_FLOW_OK;
GST_DEBUG_OBJECT (element, "Creating a new client with fd %d and MTU %d.",
client->socket, client->pksize);
/* the socket is connected */
g_signal_emit (element, gst_dccp_server_sink_signals[SIGNAL_CONNECTED], 0,
socket);
return client;
}
/*
* Wait connections of new clients
*
* @param arg - the gstdccpserversink instance
*/
static void *
gst_dccp_server_accept_new_clients (void *arg)
{
GstDCCPServerSink *sink = (GstDCCPServerSink *) arg;
int newsockfd;
Client *client;
while (1) {
newsockfd =
gst_dccp_server_wait_connections (GST_ELEMENT (sink), sink->sock_fd);
client = gst_dccp_server_create_client (GST_ELEMENT (sink), newsockfd);
pthread_mutex_lock (&lock);
sink->clients = g_list_append (sink->clients, client);
pthread_mutex_unlock (&lock);
}
return NULL;
}
/*
* Send the buffer to a client
*
* @param arg - the client
*/
static void *
gst_dccp_server_send_buffer (void *arg)
{
Client *client = (Client *) arg;
GstDCCPServerSink *sink = client->server;
GstBuffer *buf = client->buf;
int client_sock_fd = client->socket;
int pksize = client->pksize;
if (gst_dccp_send_buffer (GST_ELEMENT (sink), buf, client_sock_fd,
pksize) == GST_FLOW_ERROR) {
client->flow_status = GST_FLOW_ERROR;
}
return NULL;
}
/* Remove clients with problems to send.
*
* @param arg - the gstdccpserversink instance
*/
static void *
gst_dccp_server_delete_dead_clients (void *arg)
{
GstDCCPServerSink *sink = (GstDCCPServerSink *) arg;
GList *tmp = NULL;
GList *l;
pthread_mutex_lock (&lock);
for (l = sink->clients; l != NULL; l = l->next) {
Client *client = (Client *) l->data;
if (client->flow_status == GST_FLOW_OK) {
tmp = g_list_append (tmp, client);
} else {
close (client->socket);
g_free (client);
}
}
g_list_free (sink->clients);
sink->clients = tmp;
pthread_mutex_unlock (&lock);
return 0;
}
static void
gst_dccp_server_sink_init (GstDCCPServerSink * this,
GstDCCPServerSinkClass * g_class)
{
this->port = DCCP_DEFAULT_PORT;
this->sock_fd = DCCP_DEFAULT_SOCK_FD;
this->client_sock_fd = DCCP_DEFAULT_CLIENT_SOCK_FD;
this->closed = DCCP_DEFAULT_CLOSED;
this->ccid = DCCP_DEFAULT_CCID;
this->wait_connections = DCCP_DEFAULT_WAIT_CONNECTIONS;
this->clients = NULL;
}
/*
* Starts the element. If the sockfd property was not the default, this method
* will wait for a client connection. If wait-connections property is true, it
* creates a thread to wait for new client connections.
*
* @param bsink - the element
* @return TRUE if the send operation was successful, FALSE otherwise.
*/
static gboolean
gst_dccp_server_sink_start (GstBaseSink * bsink)
{
GstDCCPServerSink *sink = GST_DCCP_SERVER_SINK (bsink);
Client *client;
if ((sink->sock_fd = gst_dccp_create_new_socket (GST_ELEMENT (sink))) < 0) {
return FALSE;
}
if (!gst_dccp_make_address_reusable (GST_ELEMENT (sink), sink->sock_fd)) {
return FALSE;
}
/* name the server socket */
memset (&sink->server_sin, 0, sizeof (sink->server_sin));
sink->server_sin.sin_family = AF_INET; /* network socket */
sink->server_sin.sin_port = htons (sink->port); /* on port */
sink->server_sin.sin_addr.s_addr = htonl (INADDR_ANY); /* for hosts */
if (!gst_dccp_bind_server_socket (GST_ELEMENT (sink), sink->sock_fd,
sink->server_sin)) {
return FALSE;
}
if (!gst_dccp_set_ccid (GST_ELEMENT (sink), sink->sock_fd, sink->ccid)) {
return FALSE;
}
if (!gst_dccp_listen_server_socket (GST_ELEMENT (sink), sink->sock_fd)) {
return FALSE;
}
if (sink->client_sock_fd == DCCP_DEFAULT_CLIENT_SOCK_FD) {
sink->client_sock_fd =
gst_dccp_server_wait_connections (GST_ELEMENT (sink), sink->sock_fd);
}
if (sink->client_sock_fd == -1) {
return FALSE;
}
client =
gst_dccp_server_create_client (GST_ELEMENT (sink), sink->client_sock_fd);
sink->clients = g_list_append (sink->clients, client);
pthread_mutex_init (&lock, NULL);
if (sink->wait_connections == TRUE) {
pthread_create (&accept_thread_id, NULL, gst_dccp_server_accept_new_clients,
sink);
pthread_detach (accept_thread_id);
}
return TRUE;
}
static GstFlowReturn
gst_dccp_server_sink_render (GstBaseSink * bsink, GstBuffer * buf)
{
GstDCCPServerSink *sink = GST_DCCP_SERVER_SINK (bsink);
pthread_t thread_id;
GList *l;
pthread_mutex_lock (&lock);
for (l = sink->clients; l != NULL; l = l->next) {
Client *client = (Client *) l->data;
client->buf = buf;
client->server = sink;
/* FIXME: are we really creating a new thread here for every single buffer
* and every single client? */
if (client->flow_status == GST_FLOW_OK) {
pthread_create (&thread_id, NULL, gst_dccp_server_send_buffer,
(void *) client);
pthread_detach (thread_id);
} else {
/* FIXME: what's the point of doing this in a separate thread if it
* keeps he global lock anyway while going through all the clients and
* waiting for close() to finish? */
pthread_create (&thread_id, NULL, gst_dccp_server_delete_dead_clients,
(void *) sink);
pthread_detach (thread_id);
}
}
pthread_mutex_unlock (&lock);
return GST_FLOW_OK;
}
static gboolean
gst_dccp_server_sink_stop (GstBaseSink * bsink)
{
GstDCCPServerSink *sink;
GList *l;
sink = GST_DCCP_SERVER_SINK (bsink);
if (sink->wait_connections == TRUE) {
pthread_cancel (accept_thread_id);
}
gst_dccp_socket_close (GST_ELEMENT (sink), &(sink->sock_fd));
pthread_mutex_lock (&lock);
for (l = sink->clients; l != NULL; l = l->next) {
Client *client = (Client *) l->data;
if (client->socket != DCCP_DEFAULT_CLIENT_SOCK_FD && sink->closed == TRUE) {
gst_dccp_socket_close (GST_ELEMENT (sink), &(client->socket));
}
g_free (client);
}
pthread_mutex_unlock (&lock);
return TRUE;
}
static void
gst_dccp_server_sink_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_static_pad_template (element_class, &sinktemplate);
gst_element_class_set_static_metadata (element_class, "DCCP server sink",
"Sink/Network",
"Send data as a server over the network via DCCP",
"E-Phone Team at Federal University of Campina Grande <leandroal@gmail.com>");
}
/*
* Set the value of a property for the server sink.
*/
static void
gst_dccp_server_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstDCCPServerSink *sink = GST_DCCP_SERVER_SINK (object);
switch (prop_id) {
case PROP_PORT:
sink->port = g_value_get_int (value);
break;
case PROP_CLIENT_SOCK_FD:
sink->client_sock_fd = g_value_get_int (value);
break;
case PROP_CLOSED:
sink->closed = g_value_get_boolean (value);
break;
case PROP_WAIT_CONNECTIONS:
sink->wait_connections = g_value_get_boolean (value);
break;
case PROP_CCID:
sink->ccid = g_value_get_int (value);
break;
default:
break;
}
}
static void
gst_dccp_server_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstDCCPServerSink *sink = GST_DCCP_SERVER_SINK (object);
switch (prop_id) {
case PROP_PORT:
g_value_set_int (value, sink->port);
break;
case PROP_CLIENT_SOCK_FD:
g_value_set_int (value, sink->client_sock_fd);
break;
case PROP_CLOSED:
g_value_set_boolean (value, sink->closed);
break;
case PROP_WAIT_CONNECTIONS:
g_value_set_boolean (value, sink->wait_connections);
break;
case PROP_CCID:
g_value_set_int (value, sink->ccid);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_dccp_server_sink_class_init (GstDCCPServerSinkClass * klass)
{
GObjectClass *gobject_class;
GstBaseSinkClass *gstbasesink_class;
gobject_class = (GObjectClass *) klass;
gstbasesink_class = (GstBaseSinkClass *) klass;
gobject_class->set_property = gst_dccp_server_sink_set_property;
gobject_class->get_property = gst_dccp_server_sink_get_property;
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PORT,
g_param_spec_int ("port", "Port",
"The port to listen to", 0, G_MAXUINT16,
DCCP_DEFAULT_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CLIENT_SOCK_FD,
g_param_spec_int ("sockfd", "Socket fd",
"The client socket file descriptor", -1, G_MAXINT,
DCCP_DEFAULT_CLIENT_SOCK_FD,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CLOSED,
g_param_spec_boolean ("close-socket", "Close",
"Close the client sockets at end of stream",
DCCP_DEFAULT_CLOSED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CCID,
g_param_spec_int ("ccid", "CCID",
"The Congestion Control IDentified to be used", 2, G_MAXINT,
DCCP_DEFAULT_CCID, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_WAIT_CONNECTIONS,
g_param_spec_boolean ("wait-connections", "Wait connections",
"Wait for many client connections",
DCCP_DEFAULT_WAIT_CONNECTIONS,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/* signals */
/**
* GstDccpServerSink::connected:
* @sink: the gstdccpserversink element that emitted this signal
* @fd: the connected socket file descriptor
*
* Reports that the element has connected, giving the fd of the socket
*/
gst_dccp_server_sink_signals[SIGNAL_CONNECTED] =
g_signal_new ("connected", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GstDCCPServerSinkClass, connected), NULL, NULL,
gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
gstbasesink_class->start = gst_dccp_server_sink_start;
gstbasesink_class->stop = gst_dccp_server_sink_stop;
gstbasesink_class->render = gst_dccp_server_sink_render;
GST_DEBUG_CATEGORY_INIT (dccpserversink_debug, "dccpserversink", 0,
"DCCP Server Sink");
}

View file

@ -1,91 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Leandro Melo de Sales <leandroal@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_DCCP_SERVER_SINK_H__
#define __GST_DCCP_SERVER_SINK_H__
#include <gst/gst.h>
#include <gst/base/gstbasesink.h>
#include <gst/base/gstadapter.h>
G_BEGIN_DECLS
#include "gstdccp_common.h"
#include <pthread.h>
#define GST_TYPE_DCCP_SERVER_SINK \
(gst_dccp_server_sink_get_type())
#define GST_DCCP_SERVER_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DCCP_SERVER_SINK,GstDCCPServerSink))
#define GST_DCCP_SERVER_SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DCCP_SERVER_SINK,GstDCCPServerSinkClass))
#define GST_IS_DCCP_SERVER_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DCCP_SERVER_SINK))
#define GST_IS_DCCP_SERVER_SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DCCP_SERVER_SINK))
typedef struct _GstDCCPServerSink GstDCCPServerSink;
typedef struct _GstDCCPServerSinkClass GstDCCPServerSinkClass;
typedef struct _Client Client;
struct _Client
{
GstDCCPServerSink *server;
GstBuffer * buf;
int socket;
int pksize;
GstFlowReturn flow_status;
};
struct _GstDCCPServerSink
{
GstBaseSink element;
/* server information */
int port;
struct sockaddr_in server_sin;
/* socket */
int sock_fd;
/* multiple clients */
GList *clients;
/* properties */
int client_sock_fd;
uint8_t ccid;
gboolean wait_connections;
gboolean closed;
};
struct _GstDCCPServerSinkClass
{
GstBaseSinkClass parent_class;
/* signals */
void (*connected) (GstElement *sink, gint fd);
};
GType gst_dccp_server_sink_get_type (void);
G_END_DECLS
#endif /* __GST_DCCP_SERVER_SINK_H__ */

View file

@ -1,390 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Leandro Melo de Sales <leandroal@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-dccpserversrc
* @see_also: dccpclientsink, dccpclientsrc, dccpserversink
*
* This element wait for connection from a client and receive data.
* <ulink url="http://www.linuxfoundation.org/en/Net:DCCP">DCCP</ulink> (Datagram
* Congestion Control Protocol) is a Transport Layer protocol like
* TCP and UDP.
*
* <refsect2>
* <title>Example pipeline</title>
* <para>
* |[
* gst-launch -v filesrc location=music.mp3 ! mp3parse ! dccpclientsink host=localhost port=9011 ccid=2
* ]| Client
* |[
* gst-launch -v dccpserversrc port=9011 ccid=2 ! decodebin ! alsasink
* ]| Server
*
* This example pipeline will send a MP3 stream to the server using DCCP.
* The server will decode the MP3 and play it.
* Run the server pipeline first than the client pipeline.
* </para>
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstdccpserversrc.h"
#include "gstdccp.h"
#include <fcntl.h>
#define DCCP_DEFAULT_CAPS NULL
/* signals */
enum
{
SIGNAL_CONNECTED,
LAST_SIGNAL
};
/* properties */
enum
{
PROP_0,
PROP_PORT,
PROP_CLIENT_SOCK_FD,
PROP_CLOSED,
PROP_CCID,
PROP_CAPS
};
static gboolean gst_dccp_server_src_stop (GstBaseSrc * bsrc);
GST_DEBUG_CATEGORY_STATIC (dccpserversrc_debug);
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
GST_BOILERPLATE (GstDCCPServerSrc, gst_dccp_server_src, GstPushSrc,
GST_TYPE_PUSH_SRC);
static guint gst_dccp_server_src_signals[LAST_SIGNAL] = { 0 };
/*
* Read a buffer from the server socket
*
* @return GST_FLOW_OK if the send operation was successful, GST_FLOW_ERROR otherwise.
*/
static GstFlowReturn
gst_dccp_server_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
{
GstDCCPServerSrc *src;
GstFlowReturn ret = GST_FLOW_OK;
src = GST_DCCP_SERVER_SRC (psrc);
GST_LOG_OBJECT (src, "reading a buffer");
ret = gst_dccp_read_buffer (GST_ELEMENT (src), src->client_sock_fd, outbuf);
if (ret == GST_FLOW_OK) {
GST_LOG_OBJECT (src,
"Returning buffer from _get of size %d, ts %"
GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT
", offset %" G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
GST_BUFFER_SIZE (*outbuf),
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (*outbuf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (*outbuf)),
GST_BUFFER_OFFSET (*outbuf), GST_BUFFER_OFFSET_END (*outbuf));
if (!gst_caps_is_equal (src->caps, GST_CAPS_ANY)) {
gst_buffer_set_caps (*outbuf, src->caps);
}
}
return ret;
}
/*
* Set the value of a property for the server src.
*/
static void
gst_dccp_server_src_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstDCCPServerSrc *src = GST_DCCP_SERVER_SRC (object);
switch (prop_id) {
case PROP_PORT:
src->port = g_value_get_int (value);
break;
case PROP_CLIENT_SOCK_FD:
src->client_sock_fd = g_value_get_int (value);
break;
case PROP_CLOSED:
src->closed = g_value_get_boolean (value);
break;
case PROP_CCID:
src->ccid = g_value_get_int (value);
break;
case PROP_CAPS:
{
const GstCaps *new_caps_val = gst_value_get_caps (value);
GstCaps *new_caps;
GstCaps *old_caps;
if (new_caps_val == NULL) {
new_caps = gst_caps_new_any ();
} else {
new_caps = gst_caps_copy (new_caps_val);
}
old_caps = src->caps;
src->caps = new_caps;
if (old_caps) {
gst_caps_unref (old_caps);
}
gst_pad_set_caps (GST_BASE_SRC (src)->srcpad, new_caps);
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/*
* Get a given property value for the server src.
*/
static void
gst_dccp_server_src_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstDCCPServerSrc *src = GST_DCCP_SERVER_SRC (object);
switch (prop_id) {
case PROP_PORT:
g_value_set_int (value, src->port);
break;
case PROP_CLIENT_SOCK_FD:
g_value_set_int (value, src->client_sock_fd);
break;
case PROP_CLOSED:
g_value_set_boolean (value, src->closed);
break;
case PROP_CAPS:
gst_value_set_caps (value, src->caps);
break;
case PROP_CCID:
g_value_set_int (value, src->ccid);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/*
* Starts the element. If the sockfd property was not the default, this method
* will create a new server socket and wait for a client connection.
*
* @param bsrc - the element
* @return TRUE if the send operation was successful, FALSE otherwise.
*/
static gboolean
gst_dccp_server_src_start (GstBaseSrc * bsrc)
{
GstDCCPServerSrc *src = GST_DCCP_SERVER_SRC (bsrc);
if (src->client_sock_fd == DCCP_DEFAULT_CLIENT_SOCK_FD) {
/* create socket */
if ((src->sock_fd = gst_dccp_create_new_socket (GST_ELEMENT (src))) < 0) {
return FALSE;
}
if (!gst_dccp_make_address_reusable (GST_ELEMENT (src), src->sock_fd)) {
return FALSE;
}
/* name the server socket */
memset (&src->server_sin, 0, sizeof (src->server_sin));
src->server_sin.sin_family = AF_INET; /* network socket */
src->server_sin.sin_port = htons (src->port); /* on port */
src->server_sin.sin_addr.s_addr = htonl (INADDR_ANY); /* for hosts */
if (!gst_dccp_bind_server_socket (GST_ELEMENT (src), src->sock_fd,
src->server_sin)) {
return FALSE;
}
if (!gst_dccp_set_ccid (GST_ELEMENT (src), src->sock_fd, src->ccid)) {
return FALSE;
}
if (!gst_dccp_listen_server_socket (GST_ELEMENT (src), src->sock_fd)) {
return FALSE;
}
src->client_sock_fd = gst_dccp_server_wait_connections (GST_ELEMENT (src),
src->sock_fd);
if (src->client_sock_fd == -1) {
return FALSE;
}
/* the socket is connected */
g_signal_emit (src, gst_dccp_server_src_signals[SIGNAL_CONNECTED], 0,
src->client_sock_fd);
}
return TRUE;
}
static void
gst_dccp_server_src_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_static_pad_template (element_class, &srctemplate);
gst_element_class_set_static_metadata (element_class, "DCCP server source",
"Source/Network",
"Receive data as a server over the network via DCCP",
"E-Phone Team at Federal University of Campina Grande <leandroal@gmail.com>");
}
static void
gst_dccp_server_src_init (GstDCCPServerSrc * this,
GstDCCPServerSrcClass * g_class)
{
this->port = DCCP_DEFAULT_PORT;
this->sock_fd = DCCP_DEFAULT_SOCK_FD;
this->client_sock_fd = DCCP_DEFAULT_CLIENT_SOCK_FD;
this->closed = DCCP_DEFAULT_CLOSED;
this->ccid = DCCP_DEFAULT_CCID;
this->caps = DCCP_DEFAULT_CAPS;
gst_base_src_set_format (GST_BASE_SRC (this), GST_FORMAT_TIME);
/* Checking if the version of the gstreamer is bigger that 0.10.15 */
#if ((GST_VERSION_MAJOR > 0) || \
(GST_VERSION_MAJOR == 0 && GST_VERSION_MINOR > 10) || \
(GST_VERSION_MAJOR == 0 && GST_VERSION_MINOR == 10 && GST_VERSION_MICRO >= 15))
gst_base_src_set_do_timestamp (GST_BASE_SRC (this), TRUE);
#endif
/* FIXME is this correct? */
gst_base_src_set_live (GST_BASE_SRC (this), TRUE);
}
static void
gst_dccp_server_src_finalize (GObject * gobject)
{
GstDCCPServerSrc *this = GST_DCCP_SERVER_SRC (gobject);
if (this->caps) {
gst_caps_unref (this->caps);
this->caps = NULL;
}
G_OBJECT_CLASS (parent_class)->finalize (gobject);
}
static gboolean
gst_dccp_server_src_stop (GstBaseSrc * bsrc)
{
GstDCCPServerSrc *src;
src = GST_DCCP_SERVER_SRC (bsrc);
gst_dccp_socket_close (GST_ELEMENT (src), &(src->sock_fd));
if (src->client_sock_fd != DCCP_DEFAULT_CLIENT_SOCK_FD && src->closed == TRUE) {
gst_dccp_socket_close (GST_ELEMENT (src), &(src->client_sock_fd));
}
return TRUE;
}
static void
gst_dccp_server_src_class_init (GstDCCPServerSrcClass * klass)
{
GObjectClass *gobject_class;
GstBaseSrcClass *gstbasesrc_class;
GstPushSrcClass *gstpush_src_class;
gobject_class = (GObjectClass *) klass;
gstbasesrc_class = (GstBaseSrcClass *) klass;
gstpush_src_class = (GstPushSrcClass *) klass;
gobject_class->set_property = gst_dccp_server_src_set_property;
gobject_class->get_property = gst_dccp_server_src_get_property;
gobject_class->finalize = gst_dccp_server_src_finalize;
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PORT,
g_param_spec_int ("port", "Port",
"The port to listen to", 0, G_MAXUINT16,
DCCP_DEFAULT_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CLIENT_SOCK_FD,
g_param_spec_int ("sockfd", "Socket fd",
"The client socket file descriptor", -1, G_MAXINT,
DCCP_DEFAULT_CLIENT_SOCK_FD,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CLOSED,
g_param_spec_boolean ("close-socket", "Close socket",
"Close client socket at the end of stream", DCCP_DEFAULT_CLOSED,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CCID,
g_param_spec_int ("ccid", "CCID",
"The Congestion Control IDentified to be used", 2, G_MAXINT,
DCCP_DEFAULT_CCID, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CAPS,
g_param_spec_boxed ("caps", "Caps",
"The caps of the source pad", GST_TYPE_CAPS,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/* signals */
/**
* GstDccpServerSrc::connected:
* @src: the gstdccpserversrc element that emitted this signal
* @fd: the connected socket file descriptor
*
* Reports that the element has connected, giving the fd of the socket
*/
gst_dccp_server_src_signals[SIGNAL_CONNECTED] =
g_signal_new ("connected", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GstDCCPServerSrcClass, connected), NULL, NULL,
gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
gstbasesrc_class->start = gst_dccp_server_src_start;
gstbasesrc_class->stop = gst_dccp_server_src_stop;
gstpush_src_class->create = gst_dccp_server_src_create;
GST_DEBUG_CATEGORY_INIT (dccpserversrc_debug, "dccpserversrc", 0,
"DCCP Server Source");
}

View file

@ -1,88 +0,0 @@
/* GStreamer
* Copyright (C) <2007> Leandro Melo de Sales <leandroal@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_DCCP_SERVER_SRC_H__
#define __GST_DCCP_SERVER_SRC_H__
#include <gst/gst.h>
#include <gst/base/gstpushsrc.h>
#include <gst/base/gstbasesrc.h>
G_BEGIN_DECLS
#include "gstdccp_common.h"
#define GST_TYPE_DCCP_SERVER_SRC \
(gst_dccp_server_src_get_type())
#define GST_DCCP_SERVER_SRC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DCCP_SERVER_SRC,GstDCCPServerSrc))
#define GST_DCCP_SERVER_SRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DCCP_SERVER_SRC,GstDCCPServerSrcClass))
#define GST_IS_DCCP_SERVER_SRC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DCCP_SERVER_SRC))
#define GST_IS_DCCP_SERVER_SRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DCCP_SERVER_SRC))
typedef struct _GstDCCPServerSrc GstDCCPServerSrc;
typedef struct _GstDCCPServerSrcClass GstDCCPServerSrcClass;
struct _GstDCCPServerSrc
{
GstPushSrc element;
/* server information */
int port;
struct sockaddr_in server_sin;
/* socket */
int sock_fd;
gboolean closed;
GstCaps *caps;
uint8_t ccid;
/* single client */
int client_sock_fd;
};
struct _GstDCCPServerSrcClass
{
GstPushSrcClass parent_class;
/* signals */
void (*connected) (GstElement *src, gint fd);
};
GType gst_dccp_server_src_get_type (void);
G_END_DECLS
#endif /* __GST_DCCP_SERVER_SRC_H__ */

View file

@ -1,17 +0,0 @@
dccp_sources = [
'gstdccpplugin.c',
'gstdccp.c',
'gstdccpserversink.c',
'gstdccpserversrc.c',
'gstdccpclientsink.c',
'gstdccpclientsrc.c',
]
gstdccp = library('gstdccp',
dccp_sources,
c_args : gst_plugins_bad_args,
include_directories : [configinc, libsinc],
dependencies : [gstbase_dep] + winsock2,
install : true,
install_dir : plugins_install_dir,
)

View file

@ -1,13 +0,0 @@
plugin_LTLIBRARIES = libgstfaceoverlay.la
# sources used to compile this plug-in
libgstfaceoverlay_la_SOURCES = gstfaceoverlay.c
# compiler and linker flags used to compile this plugin, set in configure.ac
libgstfaceoverlay_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
libgstfaceoverlay_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-@GST_API_VERSION@ $(GST_LIBS)
libgstfaceoverlay_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstfaceoverlay_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
# headers we need but don't want installed
noinst_HEADERS = gstfaceoverlay.h

View file

@ -1,452 +0,0 @@
/* GStreamer faceoverlay plugin
* Copyright (C) 2011 Laura Lucas Alday <lauralucas@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Alternatively, the contents of this file may be used under the
* GNU Lesser General Public License Version 2.1 (the "LGPL"), in
* which case the following provisions apply instead of the ones
* mentioned above:
*
* 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-faceoverlay
*
* Overlays a SVG image over a detected face in a video stream.
* x, y, w, and h properties are optional, and change the image position and
* size relative to the detected face position and size.
*
* <refsect2>
* <title>Example launch line</title>
* |[
* gst-launch autovideosrc ! videoconvert ! faceoverlay location=/path/to/gnome-video-effects/pixmaps/bow.svg x=-5 y=-15 w=0.3 h=0.1 ! videoconvert ! autovideosink
* ]|
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <gst/gst.h>
#include <gst/video/video.h>
#include <string.h>
#include "gstfaceoverlay.h"
GST_DEBUG_CATEGORY_STATIC (gst_face_overlay_debug);
#define GST_CAT_DEFAULT gst_face_overlay_debug
enum
{
PROP_0,
PROP_LOCATION,
PROP_X,
PROP_Y,
PROP_W,
PROP_H
};
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw-rgb; video/x-raw-yuv")
);
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw-rgb; video/x-raw-yuv")
);
GST_BOILERPLATE (GstFaceOverlay, gst_face_overlay, GstBin, GST_TYPE_BIN);
static void gst_face_overlay_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_face_overlay_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_face_overlay_message_handler (GstBin * bin,
GstMessage * message);
static GstStateChangeReturn gst_face_overlay_change_state (GstElement * element,
GstStateChange transition);
static gboolean gst_face_overlay_create_children (GstFaceOverlay * filter);
static gboolean
gst_face_overlay_create_children (GstFaceOverlay * filter)
{
GstElement *csp, *face_detect, *overlay;
GstPad *pad;
csp = gst_element_factory_make ("videoconvert", NULL);
face_detect = gst_element_factory_make ("facedetect", NULL);
overlay = gst_element_factory_make ("rsvgoverlay", NULL);
/* FIXME: post missing-plugin messages on NULL->READY if needed */
if (csp == NULL || face_detect == NULL || overlay == NULL)
goto missing_element;
g_object_set (face_detect, "display", FALSE, NULL);
gst_bin_add_many (GST_BIN (filter), face_detect, csp, overlay, NULL);
filter->svg_overlay = overlay;
if (!gst_element_link_many (face_detect, csp, overlay, NULL))
GST_ERROR_OBJECT (filter, "couldn't link elements");
pad = gst_element_get_static_pad (face_detect, "sink");
if (!gst_ghost_pad_set_target (GST_GHOST_PAD (filter->sinkpad), pad))
GST_ERROR_OBJECT (filter->sinkpad, "couldn't set sinkpad target");
gst_object_unref (pad);
pad = gst_element_get_static_pad (overlay, "src");
if (!gst_ghost_pad_set_target (GST_GHOST_PAD (filter->srcpad), pad))
GST_ERROR_OBJECT (filter->srcpad, "couldn't set srcpad target");
gst_object_unref (pad);
return TRUE;
/* ERRORS */
missing_element:
{
/* clean up */
if (csp == NULL)
GST_ERROR_OBJECT (filter, "videoconvert element not found");
else
gst_object_unref (csp);
if (face_detect == NULL)
GST_ERROR_OBJECT (filter, "facedetect element not found (opencv plugin)");
else
gst_object_unref (face_detect);
if (overlay == NULL)
GST_ERROR_OBJECT (filter, "rsvgoverlay element not found (rsvg plugin)");
else
gst_object_unref (overlay);
return FALSE;
}
}
static GstStateChangeReturn
gst_face_overlay_change_state (GstElement * element, GstStateChange transition)
{
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GstFaceOverlay *filter = GST_FACEOVERLAY (element);
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
if (filter->svg_overlay == NULL) {
GST_ELEMENT_ERROR (filter, CORE, MISSING_PLUGIN, (NULL),
("Some required plugins are missing, probably either the opencv "
"facedetect element or rsvgoverlay"));
return GST_STATE_CHANGE_FAILURE;
}
filter->update_svg = TRUE;
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
default:
break;
}
return ret;
}
static void
gst_face_overlay_handle_faces (GstFaceOverlay * filter, const GstStructure * s)
{
guint x, y, width, height;
gint svg_x, svg_y, svg_width, svg_height;
const GstStructure *face;
const GValue *faces_list, *face_val;
gchar *new_location = NULL;
gint face_count;
#if 0
/* optionally draw the image once every two messages for better performance */
filter->process_message = !filter->process_message;
if (!filter->process_message)
return;
#endif
faces_list = gst_structure_get_value (s, "faces");
face_count = gst_value_list_get_size (faces_list);
GST_LOG_OBJECT (filter, "face count: %d", face_count);
if (face_count == 0) {
GST_DEBUG_OBJECT (filter, "no face, clearing overlay");
g_object_set (filter->svg_overlay, "location", NULL, NULL);
GST_OBJECT_LOCK (filter);
filter->update_svg = TRUE;
GST_OBJECT_UNLOCK (filter);
return;
}
/* The last face in the list seems to be the right one, objects mistakenly
* detected as faces for a couple of frames seem to be in the list
* beginning. TODO: needs confirmation. */
face_val = gst_value_list_get_value (faces_list, face_count - 1);
face = gst_value_get_structure (face_val);
gst_structure_get_uint (face, "x", &x);
gst_structure_get_uint (face, "y", &y);
gst_structure_get_uint (face, "width", &width);
gst_structure_get_uint (face, "height", &height);
/* Apply x and y offsets relative to face position and size.
* Set image width and height as a fraction of face width and height.
* Cast to int since face position and size will never be bigger than
* G_MAX_INT and we may have negative values as svg_x or svg_y */
GST_OBJECT_LOCK (filter);
svg_x = (gint) x + (gint) (filter->x * width);
svg_y = (gint) y + (gint) (filter->y * height);
svg_width = (gint) (filter->w * width);
svg_height = (gint) (filter->h * height);
if (filter->update_svg) {
new_location = g_strdup (filter->location);
filter->update_svg = FALSE;
}
GST_OBJECT_UNLOCK (filter);
if (new_location != NULL) {
GST_DEBUG_OBJECT (filter, "set rsvgoverlay location=%s", new_location);
g_object_set (filter->svg_overlay, "location", new_location, NULL);
g_free (new_location);
}
GST_LOG_OBJECT (filter, "overlay dimensions: %d x %d @ %d,%d",
svg_width, svg_height, svg_x, svg_y);
g_object_set (filter->svg_overlay,
"x", svg_x, "y", svg_y, "width", svg_width, "height", svg_height, NULL);
}
static void
gst_face_overlay_message_handler (GstBin * bin, GstMessage * message)
{
if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT) {
const GstStructure *s = gst_message_get_structure (message);
if (gst_structure_has_name (s, "facedetect")) {
gst_face_overlay_handle_faces (GST_FACEOVERLAY (bin), s);
}
}
GST_BIN_CLASS (parent_class)->handle_message (bin, message);
}
static void
gst_face_overlay_base_init (gpointer gclass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
gst_element_class_set_static_metadata (element_class,
"faceoverlay",
"Filter/Editor/Video",
"Overlays SVG graphics over a detected face in a video stream",
"Laura Lucas Alday <lauralucas@gmail.com>");
gst_element_class_add_static_pad_template (element_class, &src_factory);
gst_element_class_add_static_pad_template (element_class, &sink_factory);
}
static void
gst_face_overlay_class_init (GstFaceOverlayClass * klass)
{
GObjectClass *gobject_class;
GstBinClass *gstbin_class;
GstElementClass *gstelement_class;
gobject_class = G_OBJECT_CLASS (klass);
gstbin_class = GST_BIN_CLASS (klass);
gstelement_class = GST_ELEMENT_CLASS (klass);
gobject_class->set_property = gst_face_overlay_set_property;
gobject_class->get_property = gst_face_overlay_get_property;
g_object_class_install_property (gobject_class, PROP_LOCATION,
g_param_spec_string ("location", "Location",
"Location of SVG file to use for face overlay",
"", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_X,
g_param_spec_float ("x", "face x offset",
"Specify image x relative to detected face x.", -G_MAXFLOAT,
G_MAXFLOAT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_Y,
g_param_spec_float ("y", "face y offset",
"Specify image y relative to detected face y.", -G_MAXFLOAT,
G_MAXFLOAT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_W,
g_param_spec_float ("w", "face width percent",
"Specify image width relative to face width.", 0, G_MAXFLOAT, 1,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_H,
g_param_spec_float ("h", "face height percent",
"Specify image height relative to face height.", 0, G_MAXFLOAT, 1,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gstbin_class->handle_message =
GST_DEBUG_FUNCPTR (gst_face_overlay_message_handler);
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_face_overlay_change_state);
}
static void
gst_face_overlay_init (GstFaceOverlay * filter, GstFaceOverlayClass * gclass)
{
GstPadTemplate *tmpl;
filter->x = 0;
filter->y = 0;
filter->w = 1;
filter->h = 1;
filter->svg_overlay = NULL;
filter->location = NULL;
filter->process_message = TRUE;
tmpl = gst_static_pad_template_get (&sink_factory);
filter->sinkpad = gst_ghost_pad_new_no_target_from_template ("sink", tmpl);
gst_object_unref (tmpl);
gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
tmpl = gst_static_pad_template_get (&src_factory);
filter->srcpad = gst_ghost_pad_new_no_target_from_template ("src", tmpl);
gst_object_unref (tmpl);
gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
gst_face_overlay_create_children (filter);
}
static void
gst_face_overlay_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstFaceOverlay *filter = GST_FACEOVERLAY (object);
switch (prop_id) {
case PROP_LOCATION:
GST_OBJECT_LOCK (filter);
g_free (filter->location);
filter->location = g_value_dup_string (value);
filter->update_svg = TRUE;
GST_OBJECT_UNLOCK (filter);
break;
case PROP_X:
GST_OBJECT_LOCK (filter);
filter->x = g_value_get_float (value);
GST_OBJECT_UNLOCK (filter);
break;
case PROP_Y:
GST_OBJECT_LOCK (filter);
filter->y = g_value_get_float (value);
GST_OBJECT_UNLOCK (filter);
break;
case PROP_W:
GST_OBJECT_LOCK (filter);
filter->w = g_value_get_float (value);
GST_OBJECT_UNLOCK (filter);
break;
case PROP_H:
GST_OBJECT_LOCK (filter);
filter->h = g_value_get_float (value);
GST_OBJECT_UNLOCK (filter);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_face_overlay_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstFaceOverlay *filter = GST_FACEOVERLAY (object);
switch (prop_id) {
case PROP_LOCATION:
GST_OBJECT_LOCK (filter);
g_value_set_string (value, filter->location);
GST_OBJECT_UNLOCK (filter);
break;
case PROP_X:
GST_OBJECT_LOCK (filter);
g_value_set_float (value, filter->x);
GST_OBJECT_UNLOCK (filter);
break;
case PROP_Y:
GST_OBJECT_LOCK (filter);
g_value_set_float (value, filter->y);
GST_OBJECT_UNLOCK (filter);
break;
case PROP_W:
GST_OBJECT_LOCK (filter);
g_value_set_float (value, filter->w);
GST_OBJECT_UNLOCK (filter);
break;
case PROP_H:
GST_OBJECT_LOCK (filter);
g_value_set_float (value, filter->h);
GST_OBJECT_UNLOCK (filter);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
faceoverlay_init (GstPlugin * faceoverlay)
{
GST_DEBUG_CATEGORY_INIT (gst_face_overlay_debug, "faceoverlay",
0, "SVG Face Overlay");
return gst_element_register (faceoverlay, "faceoverlay", GST_RANK_NONE,
GST_TYPE_FACEOVERLAY);
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
faceoverlay,
"SVG Face Overlay",
faceoverlay_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

View file

@ -1,94 +0,0 @@
/* GStreamer faceoverlay plugin
* Copyright (C) 2011 Laura Lucas Alday <lauralucas@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Alternatively, the contents of this file may be used under the
* GNU Lesser General Public License Version 2.1 (the "LGPL"), in
* which case the following provisions apply instead of the ones
* mentioned above:
*
* 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_FACEOVERLAY_H__
#define __GST_FACEOVERLAY_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define GST_TYPE_FACEOVERLAY \
(gst_face_overlay_get_type())
#define GST_FACEOVERLAY(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FACEOVERLAY,GstFaceOverlay))
#define GST_FACEOVERLAY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FACEOVERLAY,GstFaceOverlayClass))
#define GST_IS_FACEOVERLAY(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FACEOVERLAY))
#define GST_IS_FACEOVERLAY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FACEOVERLAY))
typedef struct _GstFaceOverlay GstFaceOverlay;
typedef struct _GstFaceOverlayClass GstFaceOverlayClass;
struct _GstFaceOverlay
{
GstBin parent;
GstPad *sinkpad, *srcpad;
GstElement *face_detect;
GstElement *colorspace;
GstElement *svg_overlay;
gboolean process_message;
gboolean update_svg;
gchar *location;
gfloat x;
gfloat y;
gfloat w;
gfloat h;
};
struct _GstFaceOverlayClass
{
GstBinClass parent_class;
};
GType gst_face_overlay_get_type (void);
G_END_DECLS
#endif /* __GST_FACEOVERLAY_H__ */

View file

@ -1,12 +0,0 @@
fover_sources = [
'gstfaceoverlay.c',
]
gstfaceoverlay = library('gstfaceoverlay',
fover_sources,
c_args : gst_plugins_bad_args,
include_directories : [configinc],
dependencies : [gstbase_dep, gstvideo_dep],
install : true,
install_dir : plugins_install_dir,
)

View file

@ -1,13 +0,0 @@
plugin_LTLIBRARIES = libgstpuzzle.la
libgstpuzzle_la_SOURCES = \
gstvideoimage.c \
gstpuzzle.c
libgstpuzzle_la_CFLAGS = $(GST_CFLAGS) $(LIBOIL_CFLAGS) -I$(top_srcdir)/gst/videofilter
libgstpuzzle_la_LIBADD =
libgstpuzzle_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(LIBOIL_LIBS)
libgstpuzzle_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
noinst_HEADERS = gstvideoimage.h

View file

@ -1,576 +0,0 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* <2003> David Schleef <ds@schleef.org>
* <2004> Benjamin Otte <otte@gnome.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 <gst/gst.h>
#include <gstvideofilter.h>
#include "gstvideoimage.h"
#include <string.h>
#define GST_TYPE_PUZZLE \
(gst_puzzle_get_type())
#define GST_PUZZLE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PUZZLE,GstPuzzle))
#define GST_PUZZLE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PUZZLE,GstPuzzleClass))
#define GST_IS_PUZZLE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PUZZLE))
#define GST_IS_PUZZLE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PUZZLE))
typedef struct _GstPuzzle GstPuzzle;
typedef struct _GstPuzzleClass GstPuzzleClass;
struct _GstPuzzle
{
GstVideofilter videofilter;
const GstVideoFormat *format;
/* properties */
guint rows;
guint columns;
guint tiles;
/* state */
guint *permutation;
guint position;
gboolean solved;
};
struct _GstPuzzleClass
{
GstVideofilterClass parent_class;
};
/* GstPuzzle signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_COLUMNS,
PROP_ROWS
/* FILL ME */
};
static void gst_puzzle_base_init (gpointer g_class);
static void gst_puzzle_class_init (gpointer g_class, gpointer class_data);
static void gst_puzzle_init (GTypeInstance * instance, gpointer g_class);
static void gst_puzzle_finalize (GObject * object);
static void gst_puzzle_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_puzzle_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_puzzle_setup (GstVideofilter * videofilter);
static void draw_puzzle (GstVideofilter * videofilter, void *destp, void *srcp);
static GstVideofilterClass *parent_class;
GType
gst_puzzle_get_type (void)
{
static GType puzzle_type = 0;
if (!puzzle_type) {
static const GTypeInfo puzzle_info = {
sizeof (GstPuzzleClass),
gst_puzzle_base_init,
NULL,
gst_puzzle_class_init,
NULL,
NULL,
sizeof (GstPuzzle),
0,
gst_puzzle_init,
};
puzzle_type = g_type_register_static (GST_TYPE_VIDEOFILTER,
"GstPuzzle", &puzzle_info, 0);
}
return puzzle_type;
}
static void
gst_puzzle_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
GstVideofilterClass *videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
int i;
GstVideofilterFormat *f;
gst_element_class_set_static_metadata (element_class, "A simple puzzle",
"Filter/Effect/Video/Games",
"A simple puzzle, use arrow keys and space to restart/solve",
"Benjamin Otte <otte@gnome.org>");
for (i = 0; i < gst_video_format_count; i++) {
f = g_new0 (GstVideofilterFormat, 1);
f->fourcc = gst_video_format_list[i].fourcc;
f->bpp = gst_video_format_list[i].bitspp;
f->filter_func = draw_puzzle;
if (gst_video_format_list[i].ext_caps) {
f->depth = gst_video_format_list[i].depth;
f->endianness =
gst_video_format_list[i].bitspp < 24 ? G_BYTE_ORDER : G_BIG_ENDIAN;
f->red_mask = gst_video_format_list[i].red_mask;
f->green_mask = gst_video_format_list[i].green_mask;
f->blue_mask = gst_video_format_list[i].blue_mask;
}
gst_videofilter_class_add_format (videofilter_class, f);
}
gst_videofilter_class_add_pad_templates (GST_VIDEOFILTER_CLASS (g_class));
}
static void
gst_puzzle_class_init (gpointer g_class, gpointer class_data)
{
GObjectClass *gobject_class;
GstVideofilterClass *videofilter_class;
gobject_class = G_OBJECT_CLASS (g_class);
videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
parent_class = g_type_class_peek_parent (g_class);
gobject_class->set_property = gst_puzzle_set_property;
gobject_class->get_property = gst_puzzle_get_property;
gobject_class->finalize = gst_puzzle_finalize;
g_object_class_install_property (gobject_class, PROP_ROWS,
g_param_spec_uint ("rows", "rows", "number of rows in puzzle",
1, G_MAXUINT, 4,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_COLUMNS,
g_param_spec_uint ("columns", "columns", "number of columns in puzzle",
1, G_MAXUINT, 4,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
videofilter_class->setup = gst_puzzle_setup;
}
static void
gst_puzzle_finalize (GObject * object)
{
GstPuzzle *puzzle;
puzzle = GST_PUZZLE (object);
g_free (puzzle->permutation);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void G_GNUC_UNUSED
gst_puzzle_solve (GstPuzzle * puzzle)
{
guint i;
for (i = 0; i < puzzle->tiles; i++) {
puzzle->permutation[i] = i;
}
puzzle->position = puzzle->tiles - 1;
puzzle->solved = TRUE;
}
static gboolean
gst_puzzle_is_solved (GstPuzzle * puzzle)
{
guint i;
if (puzzle->position != puzzle->tiles - 1)
return FALSE;
for (i = 0; i < puzzle->tiles; i++) {
if (puzzle->permutation[i] != i)
return FALSE;
}
return TRUE;
}
#if 0
static void
gst_puzzle_show (GstPuzzle * puzzle)
{
guint i;
for (i = 0; i < puzzle->tiles; i++) {
g_print ("%d ", puzzle->permutation[i]);
}
g_print ("\n");
}
#endif
static void
gst_puzzle_swap (GstPuzzle * puzzle, guint next)
{
guint tmp;
g_assert (next < puzzle->tiles);
tmp = puzzle->permutation[puzzle->position];
puzzle->permutation[puzzle->position] = puzzle->permutation[next];
puzzle->permutation[next] = tmp;
puzzle->position = next;
}
typedef enum
{
DIR_UP,
DIR_DOWN,
DIR_LEFT,
DIR_RIGHT
} GstPuzzleDirection;
static void
gst_puzzle_move (GstPuzzle * puzzle, GstPuzzleDirection dir)
{
guint next = puzzle->tiles;
switch (dir) {
case DIR_UP:
if (puzzle->position >= puzzle->columns)
next = puzzle->position - puzzle->columns;
break;
case DIR_DOWN:
if (puzzle->tiles - puzzle->position > puzzle->columns)
next = puzzle->position + puzzle->columns;
break;
case DIR_LEFT:
if ((puzzle->position % puzzle->columns) > 0)
next = puzzle->position - 1;
break;
case DIR_RIGHT:
if ((puzzle->position % puzzle->columns) < puzzle->columns - 1)
next = puzzle->position + 1;
break;
default:
g_assert_not_reached ();
}
if (next < puzzle->tiles) {
/* the move was valid */
gst_puzzle_swap (puzzle, next);
}
}
static void
gst_puzzle_shuffle (GstPuzzle * puzzle)
{
guint i;
do {
for (i = 0; i < 100 * puzzle->tiles; i++) {
gst_puzzle_move (puzzle, g_random_int_range (0, 4));
}
} while (gst_puzzle_is_solved (puzzle));
puzzle->solved = FALSE;
}
/* The nav event handler handles nav events, but still forwards them, so you
* should be able to even use puzzle while navigating a dvd menu. We return
* TRUE of course even when noone downstream handles the event.
*/
static gboolean
nav_event_handler (GstPad * pad, GstEvent * event)
{
GstPuzzle *puzzle;
GstVideofilter *filter;
const gchar *type;
gboolean result = FALSE;
gdouble x, y;
gint xpos = 0, ypos = 0;
puzzle = GST_PUZZLE (gst_pad_get_parent (pad));
filter = GST_VIDEOFILTER (puzzle);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_NAVIGATION:
/* translate the event */
if (gst_structure_get_double (event->event_data.structure.structure,
"pointer_x", &x) &&
gst_structure_get_double (event->event_data.structure.structure,
"pointer_y", &y)) {
gint width, height;
width = gst_videofilter_get_input_width (filter);
height = gst_videofilter_get_input_height (filter);
width = (width / puzzle->columns) & ~3;
height = (height / puzzle->rows) & ~3;
xpos = (int) x / width;
ypos = (int) y / height;
if (xpos >= 0 && xpos < puzzle->columns && ypos >= 0
&& ypos < puzzle->rows) {
GstEvent *copy;
guint lookup;
lookup = puzzle->permutation[ypos * puzzle->columns + xpos];
GST_DEBUG_OBJECT (puzzle, "translated %dx%d (%gx%g) to %dx%d (%gx%g)",
xpos, ypos, x, y,
lookup % puzzle->columns, lookup / puzzle->columns,
x + ((gint) (lookup % puzzle->columns) - xpos) * width,
y + ((gint) (lookup / puzzle->columns) - ypos) * height);
x += ((gint) (lookup % puzzle->columns) - xpos) * width;
y += ((gint) (lookup / puzzle->columns) - ypos) * height;
copy = gst_event_copy (event);
gst_structure_set (copy->event_data.structure.structure,
"pointer_x", G_TYPE_DOUBLE, x,
"pointer_y", G_TYPE_DOUBLE, y, NULL);
gst_event_unref (event);
event = copy;
}
}
/* handle the event. NOTE: it has already been translated! */
type = gst_structure_get_string (event->event_data.structure.structure,
"event");
if (g_str_equal (type, "key-press")) {
const gchar *key =
gst_structure_get_string (event->event_data.structure.structure,
"key");
if (g_str_equal (key, "space")) {
if (gst_puzzle_is_solved (puzzle)) {
gst_puzzle_shuffle (puzzle);
} else {
gst_puzzle_solve (puzzle);
}
} else {
if (puzzle->solved)
break;
if (g_str_equal (key, "Left")) {
gst_puzzle_move (puzzle, DIR_LEFT);
} else if (g_str_equal (key, "Right")) {
gst_puzzle_move (puzzle, DIR_RIGHT);
} else if (g_str_equal (key, "Up")) {
gst_puzzle_move (puzzle, DIR_UP);
} else if (g_str_equal (key, "Down")) {
gst_puzzle_move (puzzle, DIR_DOWN);
}
}
puzzle->solved = gst_puzzle_is_solved (puzzle);
} else if (g_str_equal (type, "mouse-button-press")) {
gint button;
if (gst_structure_get_int (event->event_data.structure.structure,
"button", &button)) {
if (button == 1) {
if (xpos >= 0 && xpos < puzzle->columns && ypos >= 0
&& ypos < puzzle->rows && !puzzle->solved) {
gst_puzzle_swap (puzzle, ypos * puzzle->columns + xpos);
puzzle->solved = gst_puzzle_is_solved (puzzle);
}
} else if (button == 2) {
if (puzzle->solved) {
gst_puzzle_shuffle (puzzle);
} else {
gst_puzzle_solve (puzzle);
}
puzzle->solved = gst_puzzle_is_solved (puzzle);
}
}
}
/* FIXME: only return TRUE for events we handle? */
result = TRUE;
break;
default:
break;
}
return gst_pad_event_default (pad, event) || result;
}
static void
gst_puzzle_create (GstPuzzle * puzzle)
{
guint i;
puzzle->tiles = puzzle->rows * puzzle->columns;
g_assert (puzzle->tiles);
g_free (puzzle->permutation);
puzzle->permutation = g_new (guint, puzzle->tiles);
for (i = 0; i < puzzle->tiles; i++) {
puzzle->permutation[i] = i;
}
puzzle->position = puzzle->tiles - 1;
/* shuffle a bit */
gst_puzzle_shuffle (puzzle);
}
static void
gst_puzzle_init (GTypeInstance * instance, gpointer g_class)
{
GstVideofilter *videofilter;
GstPuzzle *puzzle;
videofilter = GST_VIDEOFILTER (instance);
puzzle = GST_PUZZLE (instance);
/* FIXME: this is evil */
gst_pad_set_event_function (videofilter->srcpad, nav_event_handler);
/* set this so we don't crash when initializing */
puzzle->rows = 1;
puzzle->columns = 1;
}
static void
gst_puzzle_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstPuzzle *src;
g_return_if_fail (GST_IS_PUZZLE (object));
src = GST_PUZZLE (object);
GST_DEBUG ("gst_puzzle_set_property");
switch (prop_id) {
case PROP_COLUMNS:
src->columns = g_value_get_uint (value);
gst_puzzle_create (src);
break;
case PROP_ROWS:
src->rows = g_value_get_uint (value);
gst_puzzle_create (src);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_puzzle_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstPuzzle *src;
g_return_if_fail (GST_IS_PUZZLE (object));
src = GST_PUZZLE (object);
switch (prop_id) {
case PROP_COLUMNS:
g_value_set_uint (value, src->columns);
break;
case PROP_ROWS:
g_value_set_uint (value, src->rows);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_puzzle_setup (GstVideofilter * videofilter)
{
GstPuzzle *puzzle;
g_return_if_fail (GST_IS_PUZZLE (videofilter));
puzzle = GST_PUZZLE (videofilter);
puzzle->format = NULL;
}
static void
draw_puzzle (GstVideofilter * videofilter, void *destp, void *srcp)
{
GstPuzzle *puzzle;
int width, height;
guint i;
GstVideoImage dest, src;
puzzle = GST_PUZZLE (videofilter);
if (!puzzle->format) {
puzzle->format =
gst_video_format_find_by_structure (gst_caps_get_structure
(gst_pad_get_negotiated_caps (videofilter->sinkpad), 0));
}
width = gst_videofilter_get_input_width (videofilter);
height = gst_videofilter_get_input_height (videofilter);
gst_video_image_setup (&dest, puzzle->format, destp, width, height);
gst_video_image_setup (&src, puzzle->format, srcp, width, height);
/* use multiples of 4 here to get around drawing problems with YUV colorspaces */
width = (width / puzzle->columns) & ~3;
height = (height / puzzle->rows) & ~3;
if (width == 0 || height == 0) {
gst_video_image_copy_area (&dest, 0, 0, &src, 0, 0,
gst_videofilter_get_input_width (videofilter),
gst_videofilter_get_input_height (videofilter));
return;
}
if (width * puzzle->columns != gst_videofilter_get_input_width (videofilter)) {
guint w =
gst_videofilter_get_input_width (videofilter) - width * puzzle->columns;
gst_video_image_copy_area (&dest, width * puzzle->columns, 0, &src,
width * puzzle->columns, 0, w,
gst_videofilter_get_input_height (videofilter));
}
if (height * puzzle->rows != gst_videofilter_get_input_height (videofilter)) {
guint h =
gst_videofilter_get_input_height (videofilter) - height * puzzle->rows;
gst_video_image_copy_area (&dest, 0, height * puzzle->rows, &src, 0,
height * puzzle->rows, gst_videofilter_get_input_width (videofilter),
h);
}
for (i = 0; i < puzzle->tiles; i++) {
if (!puzzle->solved && i == puzzle->position) {
gst_video_image_draw_rectangle (&dest, width * (i % puzzle->columns),
height * (i / puzzle->columns), width, height,
&GST_VIDEO_COLOR_WHITE, TRUE);
} else {
gst_video_image_copy_area (&dest, width * (i % puzzle->columns),
height * (i / puzzle->columns), &src,
width * (puzzle->permutation[i] % puzzle->columns),
height * (puzzle->permutation[i] / puzzle->columns), width, height);
}
}
}
static gboolean
plugin_init (GstPlugin * plugin)
{
#ifdef HAVE_LIBOIL
oil_init ();
#endif
if (!gst_library_load ("gstvideofilter"))
return FALSE;
return gst_element_register (plugin, "puzzle", GST_RANK_NONE,
GST_TYPE_PUZZLE);
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
games,
"a collection of games to showcase features",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

View file

@ -1,946 +0,0 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* <2004> Benjamin Otte <otte@gnome.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 "gstvideoimage.h"
#ifdef HAVE_LIBOIL
#include <liboil/liboil.h>
#endif
#include <string.h>
const GstVideoColor GST_VIDEO_COLOR_WHITE = { 255, 128, 128, 255, 255, 255 };
const GstVideoColor GST_VIDEO_COLOR_YELLOW = { 226, 0, 155, 255, 255, 0 };
const GstVideoColor GST_VIDEO_COLOR_CYAN = { 179, 170, 0, 0, 255, 255 };
const GstVideoColor GST_VIDEO_COLOR_GREEN = { 150, 46, 21, 0, 255, 0 };
const GstVideoColor GST_VIDEO_COLOR_MAGENTA = { 105, 212, 235, 255, 0, 255 };
const GstVideoColor GST_VIDEO_COLOR_RED = { 76, 85, 255, 255, 0, 0 };
const GstVideoColor GST_VIDEO_COLOR_BLUE = { 29, 255, 107, 0, 0, 255 };
const GstVideoColor GST_VIDEO_COLOR_BLACK = { 16, 128, 128, 0, 0, 0 };
const GstVideoColor GST_VIDEO_COLOR_NEG_I = { 16, 198, 21, 0, 0, 128 };
const GstVideoColor GST_VIDEO_COLOR_POS_Q = { 16, 235, 198, 0, 128, 255 };
const GstVideoColor GST_VIDEO_COLOR_SUPER_BLACK = { 0, 128, 128, 0, 0, 0 };
const GstVideoColor GST_VIDEO_COLOR_DARK_GREY = { 32, 128, 128, 32, 32, 32 };
const GstVideoFormat *
gst_video_format_find_by_structure (const GstStructure * structure)
{
int i;
const char *media_type = gst_structure_get_name (structure);
int ret;
g_return_val_if_fail (structure, NULL);
if (strcmp (media_type, "video/x-raw-yuv") == 0) {
char *s;
int fourcc;
guint32 format;
ret = gst_structure_get_fourcc (structure, "format", &format);
if (!ret)
return NULL;
for (i = 0; i < gst_video_format_count; i++) {
s = gst_video_format_list[i].fourcc;
//g_print("testing " GST_FOURCC_FORMAT " and %s\n", GST_FOURCC_ARGS(format), s);
fourcc = GST_MAKE_FOURCC (s[0], s[1], s[2], s[3]);
if (fourcc == format) {
return gst_video_format_list + i;
}
}
} else if (strcmp (media_type, "video/x-raw-rgb") == 0) {
int red_mask;
int green_mask;
int blue_mask;
int depth;
int bpp;
ret = gst_structure_get_int (structure, "red_mask", &red_mask);
ret &= gst_structure_get_int (structure, "green_mask", &green_mask);
ret &= gst_structure_get_int (structure, "blue_mask", &blue_mask);
ret &= gst_structure_get_int (structure, "depth", &depth);
ret &= gst_structure_get_int (structure, "bpp", &bpp);
for (i = 0; i < gst_video_format_count; i++) {
if (strcmp (gst_video_format_list[i].fourcc, "RGB ") == 0 &&
gst_video_format_list[i].red_mask == red_mask &&
gst_video_format_list[i].green_mask == green_mask &&
gst_video_format_list[i].blue_mask == blue_mask &&
gst_video_format_list[i].depth == depth &&
gst_video_format_list[i].bitspp == bpp) {
return gst_video_format_list + i;
}
}
return NULL;
}
g_critical ("format not found for media type %s", media_type);
return NULL;
}
const GstVideoFormat *
gst_video_format_find_by_fourcc (int find_fourcc)
{
int i;
for (i = 0; i < gst_video_format_count; i++) {
char *s;
int fourcc;
s = gst_video_format_list[i].fourcc;
fourcc = GST_MAKE_FOURCC (s[0], s[1], s[2], s[3]);
if (find_fourcc == fourcc) {
/* If YUV format, it's good */
if (!gst_video_format_list[i].ext_caps) {
return gst_video_format_list + i;
}
return gst_video_format_list + i;
}
}
return NULL;
}
const GstVideoFormat *
gst_video_format_find_by_name (const char *name)
{
int i;
for (i = 0; i < gst_video_format_count; i++) {
if (strcmp (name, gst_video_format_list[i].name) == 0) {
return gst_video_format_list + i;
}
}
return NULL;
}
GstStructure *
gst_video_format_get_structure (const GstVideoFormat * format)
{
unsigned int fourcc;
g_return_val_if_fail (format, NULL);
fourcc =
GST_MAKE_FOURCC (format->fourcc[0], format->fourcc[1], format->fourcc[2],
format->fourcc[3]);
if (format->ext_caps) {
int endianness;
if (format->bitspp == 16) {
endianness = G_BYTE_ORDER;
} else {
endianness = G_BIG_ENDIAN;
}
return gst_structure_new ("video/x-raw-rgb",
"bpp", G_TYPE_INT, format->bitspp,
"endianness", G_TYPE_INT, endianness,
"depth", G_TYPE_INT, format->depth,
"red_mask", G_TYPE_INT, format->red_mask,
"green_mask", G_TYPE_INT, format->green_mask,
"blue_mask", G_TYPE_INT, format->blue_mask, NULL);
} else {
return gst_structure_new ("video/x-raw-yuv",
"format", GST_TYPE_FOURCC, fourcc, NULL);
}
}
/* returns the size in bytes for one video frame of the given dimensions
* given the fourcc in GstVideotestsrc */
guint
gst_video_format_get_size (const GstVideoFormat * format, guint w, guint h)
{
GstVideoImage p = { 0 };
g_return_val_if_fail (format != NULL, 0);
g_return_val_if_fail (w > 0, 0);
g_return_val_if_fail (h > 0, 0);
gst_video_image_setup (&p, format, NULL, w, h);
return (unsigned long) p.endptr;
}
void
gst_video_image_setup (GstVideoImage * image, const GstVideoFormat * format,
guint8 * data, guint w, guint h)
{
g_return_if_fail (image != NULL);
g_return_if_fail (format != NULL);
g_return_if_fail (w > 0);
g_return_if_fail (h > 0);
image->width = w;
image->height = h;
image->format = format;
format->paint_setup (image, data);
}
void
gst_video_image_paint_hline (GstVideoImage * image, gint x, gint y, gint w,
const GstVideoColor * c)
{
g_return_if_fail (image != NULL);
g_return_if_fail (c != NULL);
g_return_if_fail (w > 0);
/* check coords */
if (y < 0 || y >= image->height)
return;
if (x < 0) {
if (x + w < 0)
return;
w += x;
x = 0;
}
if (x >= image->width)
return;
if (x + w > image->width) {
w = image->width - x;
}
image->format->paint_hline (image, x, y, w, c);
}
void
gst_video_image_draw_rectangle (GstVideoImage * image, gint x, gint y,
gint w, gint h, const GstVideoColor * c, gboolean filled)
{
gint i;
g_return_if_fail (image != NULL);
g_return_if_fail (c != NULL);
g_return_if_fail (w > 0);
g_return_if_fail (h > 0);
/* check coords */
if (x < 0) {
if (x + w < 0)
return;
w += x;
x = 0;
}
if (x >= image->width)
return;
if (x + w > image->width) {
w = image->width - x;
}
if (y < 0) {
if (y + h < 0)
return;
h += y;
y = 0;
}
if (y >= image->height)
return;
if (y + h > image->height) {
y = image->height - y;
}
if (filled) {
for (i = 0; i < h; i++) {
image->format->paint_hline (image, x, y + i, w, c);
}
} else {
h--;
image->format->paint_hline (image, x, y, w, c);
for (i = 1; i < h; i++) {
image->format->paint_hline (image, x, y + i, 1, c);
image->format->paint_hline (image, x + w - 1, y + i, 1, c);
}
image->format->paint_hline (image, x, y + h, w, c);
}
}
void
gst_video_image_copy_hline (GstVideoImage * dest, gint xdest, gint ydest,
GstVideoImage * src, gint xsrc, gint ysrc, gint w)
{
g_return_if_fail (dest != NULL);
g_return_if_fail (src != NULL);
g_return_if_fail (dest->format == src->format);
g_return_if_fail (w > 0);
/* check width coords */
if (xdest >= dest->width)
return;
if (xsrc >= src->width)
return;
if (xdest < 0) {
xsrc -= xdest;
w += xdest;
xdest = 0;
}
if (xsrc < 0) {
xdest -= xsrc;
w += xsrc;
xsrc = 0;
}
if (w <= 0)
return;
if (xdest + w > dest->width)
w = dest->width - xdest;
if (xsrc + w > src->width)
w = src->width - xsrc;
/* check height coords */
if (ysrc >= src->height || ysrc < 0)
return;
if (ydest >= dest->height || ydest < 0)
return;
dest->format->copy_hline (dest, xdest, ydest, src, xsrc, ysrc, w);
}
void
gst_video_image_copy_area (GstVideoImage * dest, gint xdest, gint ydest,
GstVideoImage * src, gint xsrc, gint ysrc, gint w, gint h)
{
gint i;
g_return_if_fail (dest != NULL);
g_return_if_fail (src != NULL);
g_return_if_fail (dest->format == src->format);
g_return_if_fail (w > 0);
g_return_if_fail (h > 0);
/* check width coords */
if (xdest >= dest->width)
return;
if (xsrc >= src->width)
return;
if (xdest < 0) {
xsrc -= xdest;
w += xdest;
xdest = 0;
}
if (xsrc < 0) {
xdest -= xsrc;
w += xsrc;
xsrc = 0;
}
if (w <= 0)
return;
if (xdest + w > dest->width)
w = dest->width - xdest;
if (xsrc + w > src->width)
w = src->width - xsrc;
/* check height coords */
if (ydest >= dest->height)
return;
if (ysrc >= src->height)
return;
if (ydest < 0) {
ysrc -= ydest;
h += ydest;
ydest = 0;
}
if (ysrc < 0) {
ydest -= ysrc;
h += ysrc;
ysrc = 0;
}
if (h <= 0)
return;
if (ydest + h > dest->height)
h = dest->height - ydest;
if (ysrc + h > src->height)
h = src->height - ysrc;
for (i = 0; i < h; i++) {
dest->format->copy_hline (dest, xdest, ydest + i, src, xsrc, ysrc + i, w);
}
}
#define ROUND_UP_2(x) (((x)+1)&~1)
#define ROUND_UP_4(x) (((x)+3)&~3)
#define ROUND_UP_8(x) (((x)+7)&~7)
static void
paint_setup_I420 (GstVideoImage * p, char *dest)
{
p->yp = dest;
p->ystride = ROUND_UP_4 (p->width);
p->up = p->yp + p->ystride * ROUND_UP_2 (p->height);
p->ustride = ROUND_UP_8 (p->width) / 2;
p->vp = p->up + p->ustride * ROUND_UP_2 (p->height) / 2;
p->vstride = ROUND_UP_8 (p->ystride) / 2;
p->endptr = p->vp + p->vstride * ROUND_UP_2 (p->height) / 2;
}
static void
paint_hline_I420 (GstVideoImage * p, int x, int y, int w,
const GstVideoColor * c)
{
int x1 = x / 2;
int x2 = (x + w) / 2;
int offset = y * p->ystride;
int offset1 = (y / 2) * p->ustride;
memset (p->yp + offset + x, c->Y, w);
memset (p->up + offset1 + x1, c->U, x2 - x1);
memset (p->vp + offset1 + x1, c->V, x2 - x1);
}
static void
copy_hline_I420 (GstVideoImage * dest, int xdest, int ydest,
GstVideoImage * src, int xsrc, int ysrc, int w)
{
int destoffset = ydest * dest->ystride;
int destoffset1 = (ydest / 2) * dest->ustride;
int srcoffset = ysrc * src->ystride;
int srcoffset1 = (ysrc / 2) * src->ustride;
memcpy (dest->yp + destoffset + xdest, src->yp + srcoffset + xsrc, w);
memcpy (dest->up + destoffset1 + xdest / 2, src->up + srcoffset1 + xsrc / 2,
w / 2);
memcpy (dest->vp + destoffset1 + xdest / 2, src->vp + srcoffset1 + xsrc / 2,
w / 2);
}
static void
paint_setup_YV12 (GstVideoImage * p, char *dest)
{
p->yp = dest;
p->ystride = ROUND_UP_4 (p->width);
p->vp = p->yp + p->ystride * ROUND_UP_2 (p->height);
p->vstride = ROUND_UP_8 (p->ystride) / 2;
p->up = p->vp + p->vstride * ROUND_UP_2 (p->height) / 2;
p->ustride = ROUND_UP_8 (p->ystride) / 2;
p->endptr = p->up + p->ustride * ROUND_UP_2 (p->height) / 2;
}
static void
paint_setup_YUY2 (GstVideoImage * p, char *dest)
{
p->yp = dest;
p->up = dest + 1;
p->vp = dest + 3;
p->ystride = ROUND_UP_2 (p->width) * 2;
p->endptr = dest + p->ystride * p->height;
}
static void
paint_setup_UYVY (GstVideoImage * p, char *dest)
{
p->yp = dest + 1;
p->up = dest;
p->vp = dest + 2;
p->ystride = ROUND_UP_2 (p->width) * 2;
p->endptr = dest + p->ystride * p->height;
}
static void
paint_setup_YVYU (GstVideoImage * p, char *dest)
{
p->yp = dest;
p->up = dest + 3;
p->vp = dest + 1;
p->ystride = ROUND_UP_2 (p->width * 2);
p->endptr = dest + p->ystride * p->height;
}
#ifndef HAVE_LIBOIL
void
oil_splat_u8 (guint8 * dest, int dstr, guint8 val, int n)
{
int i;
for (i = 0; i < n; i++) {
*dest = val;
dest += dstr;
}
}
#endif
static void
paint_hline_YUY2 (GstVideoImage * p, int x, int y, int w,
const GstVideoColor * c)
{
int x1 = x / 2;
int x2 = (x + w) / 2;
int offset = y * p->ystride;
oil_splat_u8 (p->yp + offset + x * 2, 2, c->Y, w);
oil_splat_u8 (p->up + offset + x1 * 4, 4, c->U, x2 - x1);
oil_splat_u8 (p->vp + offset + x1 * 4, 4, c->V, x2 - x1);
}
static void
copy_hline_YUY2 (GstVideoImage * dest, int xdest, int ydest,
GstVideoImage * src, int xsrc, int ysrc, int w)
{
int destoffset = ydest * dest->ystride;
int srcoffset = ysrc * src->ystride;
memcpy (dest->yp + destoffset + xdest * 2, src->yp + srcoffset + xsrc * 2,
w * 2);
}
static void
paint_setup_IYU2 (GstVideoImage * p, char *dest)
{
/* untested */
p->yp = dest + 1;
p->up = dest + 0;
p->vp = dest + 2;
p->ystride = ROUND_UP_4 (p->width * 3);
p->endptr = dest + p->ystride * p->height;
}
static void
paint_hline_IYU2 (GstVideoImage * p, int x, int y, int w,
const GstVideoColor * c)
{
int offset;
offset = y * p->ystride;
oil_splat_u8 (p->yp + offset + x * 3, 3, c->Y, w);
oil_splat_u8 (p->up + offset + x * 3, 3, c->U, w);
oil_splat_u8 (p->vp + offset + x * 3, 3, c->V, w);
}
static void
copy_hline_IYU2 (GstVideoImage * dest, int xdest, int ydest,
GstVideoImage * src, int xsrc, int ysrc, int w)
{
int destoffset = ydest * dest->ystride;
int srcoffset = ydest * src->ystride;
memcpy (dest->yp + destoffset + xdest * 3, src->yp + srcoffset + xsrc * 3,
w * 3);
}
static void
paint_setup_Y41B (GstVideoImage * p, char *dest)
{
p->yp = dest;
p->ystride = ROUND_UP_4 (p->width);
p->up = p->yp + p->ystride * p->height;
p->ustride = ROUND_UP_8 (p->width) / 4;
p->vp = p->up + p->ustride * p->height;
p->vstride = ROUND_UP_8 (p->width) / 4;
p->endptr = p->vp + p->vstride * p->height;
}
static void
paint_hline_Y41B (GstVideoImage * p, int x, int y, int w,
const GstVideoColor * c)
{
int x1 = x / 4;
int x2 = (x + w) / 4;
int offset = y * p->ystride;
int offset1 = y * p->ustride;
memset (p->yp + offset + x, c->Y, w);
memset (p->up + offset1 + x1, c->U, x2 - x1);
memset (p->vp + offset1 + x1, c->V, x2 - x1);
}
static void
copy_hline_Y41B (GstVideoImage * dest, int xdest, int ydest,
GstVideoImage * src, int xsrc, int ysrc, int w)
{
int destoffset = ydest * dest->ystride;
int destoffset1 = ydest * dest->ustride;
int srcoffset = ysrc * src->ystride;
int srcoffset1 = ysrc * src->ustride;
memcpy (dest->yp + destoffset + xdest, src->yp + srcoffset + xsrc, w);
memcpy (dest->up + destoffset1 + xdest / 4, src->up + srcoffset1 + xsrc / 4,
w / 4);
memcpy (dest->vp + destoffset1 + xdest / 4, src->vp + srcoffset1 + xsrc / 4,
w / 4);
}
static void
paint_setup_Y42B (GstVideoImage * p, char *dest)
{
p->yp = dest;
p->ystride = ROUND_UP_4 (p->width);
p->up = p->yp + p->ystride * p->height;
p->ustride = ROUND_UP_8 (p->width) / 2;
p->vp = p->up + p->ustride * p->height;
p->vstride = ROUND_UP_8 (p->width) / 2;
p->endptr = p->vp + p->vstride * p->height;
}
static void
paint_hline_Y42B (GstVideoImage * p, int x, int y, int w,
const GstVideoColor * c)
{
int x1 = x / 2;
int x2 = (x + w) / 2;
int offset = y * p->ystride;
int offset1 = y * p->ustride;
memset (p->yp + offset + x, c->Y, w);
memset (p->up + offset1 + x1, c->U, x2 - x1);
memset (p->vp + offset1 + x1, c->V, x2 - x1);
}
static void
copy_hline_Y42B (GstVideoImage * dest, int xdest, int ydest,
GstVideoImage * src, int xsrc, int ysrc, int w)
{
int destoffset = ydest * dest->ystride;
int destoffset1 = ydest * dest->ustride;
int srcoffset = ysrc * src->ystride;
int srcoffset1 = ysrc * src->ustride;
memcpy (dest->yp + destoffset + xdest, src->yp + srcoffset + xsrc, w);
memcpy (dest->up + destoffset1 + xdest / 2, src->up + srcoffset1 + xsrc / 2,
w / 2);
memcpy (dest->vp + destoffset1 + xdest / 2, src->vp + srcoffset1 + xsrc / 2,
w / 2);
}
static void
paint_setup_Y800 (GstVideoImage * p, char *dest)
{
/* untested */
p->yp = dest;
p->ystride = ROUND_UP_4 (p->width);
p->endptr = dest + p->ystride * p->height;
}
static void
paint_hline_Y800 (GstVideoImage * p, int x, int y, int w,
const GstVideoColor * c)
{
int offset = y * p->ystride;
memset (p->yp + offset + x, c->Y, w);
}
static void
copy_hline_Y800 (GstVideoImage * dest, int xdest, int ydest,
GstVideoImage * src, int xsrc, int ysrc, int w)
{
int destoffset = ydest * dest->ystride;
int srcoffset = ysrc * src->ystride;
memcpy (dest->yp + destoffset + xdest, src->yp + srcoffset + xsrc, w);
}
static void
paint_setup_YVU9 (GstVideoImage * p, char *dest)
{
int h = ROUND_UP_4 (p->height);
p->yp = dest;
p->ystride = ROUND_UP_4 (p->width);
p->vp = p->yp + p->ystride * ROUND_UP_4 (p->height);
p->vstride = ROUND_UP_4 (p->ystride / 4);
p->up = p->vp + p->vstride * ROUND_UP_4 (h / 4);
p->ustride = ROUND_UP_4 (p->ystride / 4);
p->endptr = p->up + p->ustride * ROUND_UP_4 (h / 4);
}
static void
paint_setup_YUV9 (GstVideoImage * p, char *dest)
{
/* untested */
int h = ROUND_UP_4 (p->height);
p->yp = dest;
p->ystride = ROUND_UP_4 (p->width);
p->up = p->yp + p->ystride * h;
p->ustride = ROUND_UP_4 (p->ystride / 4);
p->vp = p->up + p->ustride * ROUND_UP_4 (h / 4);
p->vstride = ROUND_UP_4 (p->ystride / 4);
p->endptr = p->vp + p->vstride * ROUND_UP_4 (h / 4);
}
static void
paint_hline_YUV9 (GstVideoImage * p, int x, int y, int w,
const GstVideoColor * c)
{
int x1 = x / 4;
int x2 = (x + w) / 4;
int offset = y * p->ystride;
int offset1 = (y / 4) * p->ustride;
memset (p->yp + offset + x, c->Y, w);
memset (p->up + offset1 + x1, c->U, x2 - x1);
memset (p->vp + offset1 + x1, c->V, x2 - x1);
}
static void
copy_hline_YUV9 (GstVideoImage * dest, int xdest, int ydest,
GstVideoImage * src, int xsrc, int ysrc, int w)
{
int destoffset = ydest * dest->ystride;
int destoffset1 = ydest * dest->ustride;
int srcoffset = ysrc * src->ystride;
int srcoffset1 = ysrc * src->ustride;
memcpy (dest->yp + destoffset + xdest, src->yp + srcoffset + xsrc, w);
memcpy (dest->up + destoffset1 + xdest / 4, src->up + srcoffset1 + xsrc / 4,
w / 4);
memcpy (dest->vp + destoffset1 + xdest / 4, src->vp + srcoffset1 + xsrc / 4,
w / 4);
}
static void
paint_setup_xRGB8888 (GstVideoImage * p, char *dest)
{
p->yp = dest + 1;
p->up = dest + 2;
p->vp = dest + 3;
p->ystride = p->width * 4;
p->endptr = p->dest + p->ystride * p->height;
}
static void
paint_setup_xBGR8888 (GstVideoImage * p, char *dest)
{
p->yp = dest + 3;
p->up = dest + 2;
p->vp = dest + 1;
p->ystride = p->width * 4;
p->endptr = p->dest + p->ystride * p->height;
}
static void
paint_setup_RGBx8888 (GstVideoImage * p, char *dest)
{
p->yp = dest + 0;
p->up = dest + 1;
p->vp = dest + 2;
p->ystride = p->width * 4;
p->endptr = p->dest + p->ystride * p->height;
}
static void
paint_setup_BGRx8888 (GstVideoImage * p, char *dest)
{
p->yp = dest + 2;
p->up = dest + 1;
p->vp = dest + 0;
p->ystride = p->width * 4;
p->endptr = p->dest + p->ystride * p->height;
}
static void
paint_setup_RGB888 (GstVideoImage * p, char *dest)
{
p->yp = dest + 0;
p->up = dest + 1;
p->vp = dest + 2;
p->ystride = ROUND_UP_4 (p->width * 3);
p->endptr = p->dest + p->ystride * p->height;
}
static void
paint_setup_BGR888 (GstVideoImage * p, char *dest)
{
p->yp = dest + 2;
p->up = dest + 1;
p->vp = dest + 0;
p->ystride = ROUND_UP_4 (p->width * 3);
p->endptr = p->dest + p->ystride * p->height;
}
static void
paint_hline_str4 (GstVideoImage * p, int x, int y, int w,
const GstVideoColor * c)
{
int offset = y * p->ystride;
oil_splat_u8 (p->yp + offset + x * 4, 4, c->R, w);
oil_splat_u8 (p->up + offset + x * 4, 4, c->G, w);
oil_splat_u8 (p->vp + offset + x * 4, 4, c->B, w);
}
static void
copy_hline_str4 (GstVideoImage * dest, int xdest, int ydest,
GstVideoImage * src, int xsrc, int ysrc, int w)
{
int destoffset = ydest * dest->ystride;
int srcoffset = ysrc * src->ystride;
memcpy (dest->yp + destoffset + xdest * 4, src->yp + srcoffset + xsrc * 4,
w * 4);
}
static void
paint_hline_str3 (GstVideoImage * p, int x, int y, int w,
const GstVideoColor * c)
{
int offset = y * p->ystride;
oil_splat_u8 (p->yp + offset + x * 3, 3, c->R, w);
oil_splat_u8 (p->up + offset + x * 3, 3, c->G, w);
oil_splat_u8 (p->vp + offset + x * 3, 3, c->B, w);
}
static void
copy_hline_str3 (GstVideoImage * dest, int xdest, int ydest,
GstVideoImage * src, int xsrc, int ysrc, int w)
{
int destoffset = ydest * dest->ystride;
int srcoffset = ysrc * src->ystride;
memcpy (dest->yp + destoffset + xdest * 3, src->yp + srcoffset + xsrc * 3,
w * 3);
}
static void
paint_setup_RGB565 (GstVideoImage * p, char *dest)
{
p->yp = dest;
p->ystride = ROUND_UP_4 (p->width * 2);
p->endptr = p->dest + p->ystride * p->height;
}
static void
paint_hline_RGB565 (GstVideoImage * p, int x, int y, int w,
const GstVideoColor * c)
{
int offset = y * p->ystride;
unsigned int a, b;
a = (c->R & 0xf8) | (c->G >> 5);
b = ((c->G << 3) & 0xe0) | (c->B >> 3);
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
oil_splat_u8 (p->yp + offset + x * 2 + 0, 2, b, w);
oil_splat_u8 (p->yp + offset + x * 2 + 1, 2, a, w);
#else
oil_splat_u8 (p->yp + offset + x * 2 + 0, 2, a, w);
oil_splat_u8 (p->yp + offset + x * 2 + 1, 2, b, w);
#endif
}
static void
copy_hline_str2 (GstVideoImage * dest, int xdest, int ydest,
GstVideoImage * src, int xsrc, int ysrc, int w)
{
int destoffset = ydest * dest->ystride;
int srcoffset = ysrc * src->ystride;
memcpy (dest->yp + destoffset + xdest * 2, src->yp + srcoffset + xsrc * 2,
w * 2);
}
static void
paint_setup_xRGB1555 (GstVideoImage * p, char *dest)
{
p->yp = dest;
p->ystride = ROUND_UP_4 (p->width * 2);
p->endptr = p->dest + p->ystride * p->height;
}
static void
paint_hline_xRGB1555 (GstVideoImage * p, int x, int y, int w,
const GstVideoColor * c)
{
int offset = y * p->ystride;
unsigned int a, b;
a = ((c->R >> 1) & 0x7c) | (c->G >> 6);
b = ((c->G << 2) & 0xe0) | (c->B >> 3);
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
oil_splat_u8 (p->yp + offset + x * 2 + 0, 2, b, w);
oil_splat_u8 (p->yp + offset + x * 2 + 1, 2, a, w);
#else
oil_splat_u8 (p->yp + offset + x * 2 + 0, 2, a, w);
oil_splat_u8 (p->yp + offset + x * 2 + 1, 2, b, w);
#endif
}
const GstVideoFormat gst_video_format_list[] = {
/* packed */
{"YUY2", "YUY2", 16, paint_setup_YUY2, paint_hline_YUY2, copy_hline_YUY2},
{"UYVY", "UYVY", 16, paint_setup_UYVY, paint_hline_YUY2, copy_hline_YUY2},
{"Y422", "Y422", 16, paint_setup_UYVY, paint_hline_YUY2, copy_hline_YUY2},
{"UYNV", "UYNV", 16, paint_setup_UYVY, paint_hline_YUY2, copy_hline_YUY2}, /* FIXME: UYNV? */
{"YVYU", "YVYU", 16, paint_setup_YVYU, paint_hline_YUY2, copy_hline_YUY2},
/* interlaced */
/*{ "IUYV", "IUY2", 16, paint_setup_YVYU, paint_hline_YUY2 }, */
/* inverted */
/*{ "cyuv", "cyuv", 16, paint_setup_YVYU, paint_hline_YUY2 }, */
/*{ "Y41P", "Y41P", 12, paint_setup_YVYU, paint_hline_YUY2 }, */
/* interlaced */
/*{ "IY41", "IY41", 12, paint_setup_YVYU, paint_hline_YUY2 }, */
/*{ "Y211", "Y211", 8, paint_setup_YVYU, paint_hline_YUY2 }, */
/*{ "Y41T", "Y41T", 12, paint_setup_YVYU, paint_hline_YUY2 }, */
/*{ "Y42P", "Y42P", 16, paint_setup_YVYU, paint_hline_YUY2 }, */
/*{ "CLJR", "CLJR", 8, paint_setup_YVYU, paint_hline_YUY2 }, */
/*{ "IYU1", "IYU1", 12, paint_setup_YVYU, paint_hline_YUY2 }, */
{"IYU2", "IYU2", 24, paint_setup_IYU2, paint_hline_IYU2, copy_hline_IYU2},
/* planar */
/* YVU9 */
{"YVU9", "YVU9", 9, paint_setup_YVU9, paint_hline_YUV9, copy_hline_YUV9},
/* YUV9 */
{"YUV9", "YUV9", 9, paint_setup_YUV9, paint_hline_YUV9, copy_hline_YUV9},
/* IF09 */
/* YV12 */
{"YV12", "YV12", 12, paint_setup_YV12, paint_hline_I420, copy_hline_I420},
/* I420 */
{"I420", "I420", 12, paint_setup_I420, paint_hline_I420, copy_hline_I420},
/* NV12 */
/* NV21 */
/* CLPL */
/* Y41B */
{"Y41B", "Y41B", 12, paint_setup_Y41B, paint_hline_Y41B, copy_hline_Y41B},
/* Y42B */
{"Y42B", "Y42B", 16, paint_setup_Y42B, paint_hline_Y42B, copy_hline_Y42B},
/* Y800 grayscale */
{"Y800", "Y800", 8, paint_setup_Y800, paint_hline_Y800, copy_hline_Y800},
{"RGB ", "xRGB8888", 32, paint_setup_xRGB8888, paint_hline_str4,
copy_hline_str4,
1, 24, 0x00ff0000, 0x0000ff00, 0x000000ff},
{"RGB ", "xBGR8888", 32, paint_setup_xBGR8888, paint_hline_str4,
copy_hline_str4,
1, 24, 0x000000ff, 0x0000ff00, 0x00ff0000},
{"RGB ", "RGBx8888", 32, paint_setup_RGBx8888, paint_hline_str4,
copy_hline_str4,
1, 24, 0xff000000, 0x00ff0000, 0x0000ff00},
{"RGB ", "BGRx8888", 32, paint_setup_BGRx8888, paint_hline_str4,
copy_hline_str4,
1, 24, 0x0000ff00, 0x00ff0000, 0xff000000},
{"RGB ", "RGB888", 24, paint_setup_RGB888, paint_hline_str3, copy_hline_str3,
1, 24, 0x00ff0000, 0x0000ff00, 0x000000ff},
{"RGB ", "BGR888", 24, paint_setup_BGR888, paint_hline_str3, copy_hline_str3,
1, 24, 0x000000ff, 0x0000ff00, 0x00ff0000},
{"RGB ", "RGB565", 16, paint_setup_RGB565, paint_hline_RGB565,
copy_hline_str2,
1, 16, 0x0000f800, 0x000007e0, 0x0000001f},
{"RGB ", "xRGB1555", 16, paint_setup_xRGB1555, paint_hline_xRGB1555,
copy_hline_str2,
1, 15, 0x00007c00, 0x000003e0, 0x0000001f},
};
const guint gst_video_format_count = G_N_ELEMENTS (gst_video_format_list);

View file

@ -1,114 +0,0 @@
/* GStreamer
* Copyright (C) <2003> David A. Schleef <ds@schleef.org>
* <2004> Benjamin Otte <otte@gnome.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.
*/
#include <gst/gst.h>
#ifndef __GST_VIDEO_IMAGE_H__
#define __GST_VIDEO_IMAGE_H__
G_BEGIN_DECLS
typedef struct _GstVideoColor GstVideoColor;
typedef struct _GstVideoImage GstVideoImage;
typedef struct _GstVideoFormat GstVideoFormat;
struct _GstVideoColor {
int Y, U, V;
int R, G, B;
};
extern const GstVideoColor GST_VIDEO_COLOR_WHITE;
extern const GstVideoColor GST_VIDEO_COLOR_YELLOW;
extern const GstVideoColor GST_VIDEO_COLOR_CYAN;
extern const GstVideoColor GST_VIDEO_COLOR_GREEN;
extern const GstVideoColor GST_VIDEO_COLOR_MAGENTA;
extern const GstVideoColor GST_VIDEO_COLOR_RED;
extern const GstVideoColor GST_VIDEO_COLOR_BLUE;
extern const GstVideoColor GST_VIDEO_COLOR_BLACK;
extern const GstVideoColor GST_VIDEO_COLOR_NEG_I;
extern const GstVideoColor GST_VIDEO_COLOR_POS_Q;
extern const GstVideoColor GST_VIDEO_COLOR_SUPER_BLACK;
extern const GstVideoColor GST_VIDEO_COLOR_DARK_GREY;
struct _GstVideoImage
{
guint8 * dest; /* pointer to first byte of video data */
guint8 * yp, *up, *vp; /* pointers to first byte of each component
* for both packed/planar YUV and RGB */
guint8 * endptr; /* pointer to byte beyond last video data */
guint ystride;
guint ustride;
guint vstride;
guint width;
guint height;
const GstVideoFormat * format;
};
struct _GstVideoFormat
{
char * fourcc;
char * name;
int bitspp;
void (* paint_setup) (GstVideoImage * p, char *dest);
void (* paint_hline) (GstVideoImage * p, int x, int y, int w, const GstVideoColor *c);
void (* copy_hline) (GstVideoImage * dest, int destx, int desty,
GstVideoImage * src, int srcx, int srcy, int w);
int ext_caps;
int depth;
guint red_mask;
guint green_mask;
guint blue_mask;
};
const GstVideoFormat * gst_video_format_find_by_fourcc (int find_fourcc);
const GstVideoFormat * gst_video_format_find_by_name (const char *name);
const GstVideoFormat * gst_video_format_find_by_structure (const GstStructure *structure);
GstStructure * gst_video_format_get_structure (const GstVideoFormat *format);
guint gst_video_format_get_size (const GstVideoFormat *format,
guint w, guint h);
extern const GstVideoFormat gst_video_format_list[];
extern const guint gst_video_format_count;
void gst_video_image_setup (GstVideoImage *image,
const GstVideoFormat *format,
guint8 *data, guint w, guint h);
/* drawing operations */
void gst_video_image_draw_hline (GstVideoImage *image,
gint x, gint y, gint w,
const GstVideoColor *c);
void gst_video_image_draw_rectangle (GstVideoImage *image,
gint x, gint y, gint w, gint h,
const GstVideoColor *c, gboolean filled);
void gst_video_image_copy_hline (GstVideoImage *dest,
gint xdest, gint ydest,
GstVideoImage *src,
gint xsrc, gint ysrc, gint w);
void gst_video_image_copy_area (GstVideoImage *dest,
gint xdest, gint ydest,
GstVideoImage *src,
gint xsrc, gint ysrc,
gint w, gint h);
G_END_DECLS
#endif /* __GST_VIDEO_IMAGE_H__ */

View file

@ -1,13 +0,0 @@
games_sources = [
'gstvideoimage.c',
'gstpuzzle.c',
]
gstpuzzle = library('gstpuzzle',
games_sources,
c_args : gst_plugins_bad_args,
include_directories : [configinc],
dependencies : [gstbase_dep],
install : true,
install_dir : plugins_install_dir,
)

View file

@ -1,12 +0,0 @@
plugin_LTLIBRARIES = libgsthdvparse.la
libgsthdvparse_la_SOURCES = \
gsthdvparse.c
noinst_HEADERS = \
gsthdvparse.h
libgsthdvparse_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS)
libgsthdvparse_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) $(LIBM)
libgsthdvparse_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgsthdvparse_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)

View file

@ -1,888 +0,0 @@
/*
* 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.
*/
/**
* SECTION:element-HDVParse
*
* <refsect2>
* <title>Example launch line</title>
* <para>
* <programlisting>
* gst-launch -v -m filesrc ! mpegtsdemux ! hdvparse ! fakesink silent=TRUE
* </programlisting>
* </para>
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <math.h>
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
#include "gsthdvparse.h"
GST_DEBUG_CATEGORY_STATIC (gst_hdvparse_debug);
#define GST_CAT_DEFAULT gst_hdvparse_debug
/* Filter signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
PROP_0,
};
#define CLOCK_BASE 9LL
#define CLOCK_FREQ (CLOCK_BASE * 10000)
#define MPEGTIME_TO_GSTTIME(time) (gst_util_uint64_scale ((time), \
GST_MSECOND/10, CLOCK_BASE))
#define GSTTIME_TO_MPEGTIME(time) (gst_util_uint64_scale ((time), \
CLOCK_BASE, GST_MSECOND/10))
/* If set to 1, then extra validation will be applied to check
* for complete spec compliance wherever applicable. */
#define VALIDATE 0
/* Binary-coded decimal reading macro */
#define BCD(c) ( ((((c) >> 4) & 0x0f) * 10) + ((c) & 0x0f) )
/* Same as before, but with a mask */
#define BCD_M(c, mask) (BCD ((c) & (mask)))
/* the capabilities of the inputs and outputs.
*
* describe the real formats here.
*/
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("hdv/aux-v;hdv/aux-a")
);
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS
("hdv/aux-v,parsed=(boolean)True;hdv/aux-a,parsed=(boolean)True")
);
/* debug category for fltering log messages
*
* exchange the string 'Template HDVParse' with your description
*/
#define DEBUG_INIT(bla) \
GST_DEBUG_CATEGORY_INIT (gst_hdvparse_debug, "hdvparse", 0, "HDV private stream parser");
GST_BOILERPLATE_FULL (GstHDVParse, gst_hdvparse, GstBaseTransform,
GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
static GstFlowReturn gst_hdvparse_transform_ip (GstBaseTransform * base,
GstBuffer * outbuf);
static GstCaps *gst_hdvparse_transform_caps (GstBaseTransform * trans,
GstPadDirection dir, GstCaps * incaps);
/* GObject vmethod implementations */
static void
gst_hdvparse_base_init (gpointer klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_add_static_pad_template (element_class, &src_template);
gst_element_class_add_static_pad_template (element_class, &sink_template);
gst_element_class_set_static_metadata (element_class, "HDVParser",
"Data/Parser",
"HDV private stream Parser", "Edward Hervey <bilboed@bilboed.com>");
}
/* initialize the HDVParse's class */
static void
gst_hdvparse_class_init (GstHDVParseClass * klass)
{
GST_BASE_TRANSFORM_CLASS (klass)->transform_ip =
GST_DEBUG_FUNCPTR (gst_hdvparse_transform_ip);
GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
GST_DEBUG_FUNCPTR (gst_hdvparse_transform_caps);
}
/* initialize the new element
* initialize instance structure
*/
static void
gst_hdvparse_init (GstHDVParse * filter, GstHDVParseClass * klass)
{
GstBaseTransform *transform = GST_BASE_TRANSFORM (filter);
gst_base_transform_set_in_place (transform, TRUE);
gst_base_transform_set_passthrough (transform, TRUE);
}
static GstCaps *
gst_hdvparse_transform_caps (GstBaseTransform * trans, GstPadDirection dir,
GstCaps * incaps)
{
GstCaps *res = NULL;
GstStructure *st = gst_caps_get_structure (incaps, 0);
GST_WARNING_OBJECT (trans, "dir:%d, incaps:%" GST_PTR_FORMAT, dir, incaps);
if (dir == GST_PAD_SINK) {
res = gst_caps_new_simple (gst_structure_get_name (st),
"parsed", G_TYPE_BOOLEAN, TRUE, NULL);
} else {
res = gst_caps_new_simple (gst_structure_get_name (st), NULL);
}
return res;
}
static inline const gchar *
sfr_to_framerate (guint8 sfr)
{
switch (sfr) {
case 4:
return "30000/1001";
case 3:
return "25/1";
case 1:
return "24000/1001";
default:
return "RESERVED";
}
}
static GstFlowReturn
parse_dv_multi_pack (GstHDVParse * filter, guint8 * data, guint64 size,
GstStructure * st)
{
guint64 offs = 1;
while (size / 5) {
GST_LOG ("DV pack 0x%x", data[offs]);
switch (data[offs]) {
case 0x70:{
guint8 irispos, ae, agc, wbmode, whitebal, focusmode, focuspos;
irispos = data[offs + 1] & 0x3f;
ae = data[offs + 2] >> 4;
agc = data[offs + 2] & 0xf;
wbmode = data[offs + 3] >> 5;
whitebal = data[offs + 3] & 0x1f;
focusmode = data[offs + 4] >> 7;
focuspos = data[offs + 4] & 0x7f;
GST_LOG (" Consumer Camera 1");
GST_LOG (" Iris position %d (0x%x)", irispos, irispos);
/* Iris position = 2 ^ (IP/8) (for 0 < IP < 0x3C) */
if (irispos < 0x3c) {
GST_LOG (" IRIS F%0.2f", powf (2.0, (((float) irispos) / 8.0)));
gst_structure_set (st, "aperture-fnumber", G_TYPE_FLOAT,
powf (2.0, (((float) irispos) / 8.0)), NULL);
} else if (irispos == 0x3d) {
GST_LOG (" IRIS < 1.0");
} else if (irispos == 0x3e) {
GST_LOG (" IRIS closed");
}
/* AE Mode:
* 0 : Full automatic
* 1 : Gain Priority mode
* 2 : Shutter Priority mode
* 3 : Iris priority mode
* 4 : Manual
* ..: Reserved
* F : No information */
GST_LOG (" AE Mode: %d (0x%x)", ae, ae);
GST_LOG (" AGC: %d (0x%x)", agc, agc);
if (agc < 0xd) {
/* This is what the spec says.. but I'm not seeing the same on my camera :( */
GST_LOG (" Gain:%02.2fdB", (agc * 3.0) - 3.0);
gst_structure_set (st, "gain", G_TYPE_FLOAT, (agc * 3.0) - 3.0, NULL);
}
/* White balance mode
* 0 : Automatic
* 1 : hold
* 2 : one push
* 3 : pre-set
* 7 : no-information */
if (wbmode != 7)
GST_LOG (" White balance mode : %d (0x%x)", wbmode, wbmode);
/* White balance
* 0 : Candle
* 1 : Incandescent lamp
* 2 : low color temperature fluorescent lamp
* 3 : high color temperature fluorescent lamp
* 4 : sunlight
* 5 : cloudy weather
* F : No information
*/
if (whitebal != 0xf)
GST_LOG (" White balance : %d (0x%x)", whitebal, whitebal);
if (focuspos != 0x7f) {
GST_LOG (" Focus mode : %s", focusmode ? "MANUAL" : "AUTOMATIC");
GST_LOG (" Focus position: %d (0x%x)", focuspos, focuspos);
}
}
break;
case 0x71:{
guint8 v_pan, h_pan, focal_length, e_zoom;
gboolean is, zen;
v_pan = data[offs + 1] & 0x3f;
is = data[offs + 2] >> 7;
h_pan = data[offs + 2] & 0x7f;
focal_length = data[offs + 3];
zen = data[offs + 4] >> 7;
e_zoom = data[offs + 4] & 0x7f;
GST_LOG (" Consumer Camera 2");
if (v_pan != 0x3f)
GST_LOG (" Vertical Panning : %d (0x%d)", v_pan, v_pan);
if (h_pan != 0x7f)
GST_LOG (" Horizontal Panning : %d (0x%d)", h_pan, h_pan);
GST_LOG (" Stabilizer : %s", is ? "OFF" : "ON");
if (focal_length != 0xff)
GST_LOG (" Focal Length : %f mm",
(focal_length & 0x7f) * pow (10, focal_length & 0x80));
if (zen == 0)
GST_LOG (" Electric Zoom %02dd.%03d", e_zoom >> 5, e_zoom & 0x1f);
}
break;
case 0x7f:{
guint16 speed;
guint16 speedint;
GST_LOG (" Shutter");
if (data[offs + 1] != 0xff)
GST_LOG (" Shutter Speed (1) : %d, 0x%x",
data[offs + 1], data[offs + 1]);
if (data[offs + 2] != 0xff)
GST_LOG (" Shutter Speed (1) : %d, 0x%x",
data[offs + 2], data[offs + 2]);
speed = data[offs + 3] | (data[offs + 4] & 0x7f) << 8;
/* The shutter speed is 1/(CSS * horizontal scanning period) */
/* FIXME : 34000 is a value interpolated by observations */
speedint = (int) (34000.0 / (float) speed);
/* Only the highest two decimal digits are valid */
if (speedint > 100)
speedint = speedint / 10 * 10;
GST_LOG (" Shutter speed : 1/%d", speedint);
gst_structure_set (st, "shutter-speed", GST_TYPE_FRACTION,
1, speedint, NULL);
}
break;
default:
GST_MEMDUMP ("Unknown pack", data + offs, 5);
break;
}
size -= 5;
offs += 5;
}
return GST_FLOW_OK;
}
static GstFlowReturn
parse_video_frame (GstHDVParse * filter, guint8 * data, guint64 size,
GstStructure * st)
{
guint32 etn, bitrate;
guint8 nbframes, data_h, hdr_size, sfr, sdm;
guint8 aspect, framerate, profile, level, format, chroma;
guint8 gop_n, gop_m, cgms, recst, abst;
guint16 vbv_delay, width, height, vbv_buffer;
guint64 dts;
gboolean pf, tf, rf;
GST_LOG_OBJECT (filter, "Video Frame Pack");
/* Byte | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
* ---------------------------------
* 0 | Size (0x39) |
* ---------------------------------
* 1 | |
* 2 | ETN |
* 3 | |
* ---------------------------------
*/
if (data[0] != 0x39) {
GST_WARNING ("Invalid size for Video frame");
return GST_FLOW_ERROR;
}
etn = data[3] << 16 | data[2] << 8 | data[1];
GST_LOG_OBJECT (filter, " ETN : %" G_GUINT32_FORMAT, etn);
/* Pack-V Information
* ---------------------------------
* 4 | Number of Video Frames |
* ---------------------------------
* 5 | 0 | 0 | 0 | 0 | DATA-H |
* ---------------------------------
* 6 | VBV |
* 7 | DELAY |
* ---------------------------------
* 8 | HEADER SIZE |
* ---------------------------------
* 9 | |
* 10 | DTS |
* 11 | |
* 12 | |
* ----------------------------- |
* 13 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
* ---------------------------------
* 14 |PF |TF |RF | 0 | SFR |
* ---------------------------------
*/
nbframes = data[4];
if (VALIDATE && (data[5] >> 4))
return GST_FLOW_ERROR;
data_h = data[5] & 0xf;
vbv_delay = data[6] | data[7] << 8;
hdr_size = data[8];
dts = data[9] | data[10] << 8 | data[11] << 16 | data[12] << 24;
dts |= (guint64) (data[13] & 0x1) << 32;
if (G_UNLIKELY (VALIDATE && (data[13] & 0xfe))) {
return GST_FLOW_ERROR;
}
pf = data[14] & 0x80;
tf = data[14] & 0x40;
rf = data[14] & 0x20;
if (G_UNLIKELY (VALIDATE && (data[14] & 0x10)))
return GST_FLOW_ERROR;
sfr = data[14] & 0x07;
GST_LOG_OBJECT (filter, " Pack-V Information");
GST_LOG_OBJECT (filter, " Number of Video Frames : %d", nbframes);
GST_LOG_OBJECT (filter, " Leading PES-V picture type %s (0x%x)",
(data_h == 0x1) ? "I-picture" : "other", data_h);
GST_LOG_OBJECT (filter, " VBV Delay of first frame: %" G_GUINT32_FORMAT,
vbv_delay);
GST_LOG_OBJECT (filter, " Header Size:%d", hdr_size);
GST_LOG_OBJECT (filter, " DTS: %" GST_TIME_FORMAT " (%" G_GUINT64_FORMAT ")",
GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (dts)), dts);
GST_LOG_OBJECT (filter, " Video source : %s %s %s (0x%x 0x%x 0x%x)",
pf ? "Progressive" : "Interlaced",
tf ? "TFF" : "", rf ? "RFF" : "", pf, tf, rf);
GST_LOG_OBJECT (filter, " Source Frame Rate : %s (0x%x)",
sfr_to_framerate (sfr), sfr);
gst_structure_set (st, "DTS", G_TYPE_UINT64, MPEGTIME_TO_GSTTIME (dts),
"interlaced", G_TYPE_BOOLEAN, !pf, NULL);
/* Search Data Mode
* ---------------------------------
* 15 | Search Data Mode |
* ---------------------------------
*/
sdm = data[15];
GST_LOG_OBJECT (filter, " Search Data Mode : 0x%x", sdm);
GST_LOG_OBJECT (filter, " %s %s %s",
sdm & 0x2 ? "8x-Base" : "",
sdm & 0x4 ? "8x-Helper" : "", sdm & 0x10 ? "24x" : "");
/* Video Mode
* ---------------------------------
* 16 | Horizontal size |
* ----------------- |
* 17 | 0 | 0 | 0 | 0 | |
* ---------------------------------
* 18 | Vertical size |
* ----------------- |
* 19 | 0 | 0 | 0 | 0 | |
* ---------------------------------
* 20 | Aspect ratio | Frame Rate |
* ---------------------------------
* 21 | |
* 22 | bitrate |
* ------------------------- |
* 23 | 0 | 0 | 0 | 0 | 0 | 0 | |
* ---------------------------------
* 24 | VBV Buffer size |
* ------------------------- |
* 25 | 0 | 0 | 0 | 0 | 0 | 0 | |
* ---------------------------------
* 26 | 0 | Profile | Level |
* ---------------------------------
* 27 | 0 | Format |Chroma | 0 | 0 |
* ---------------------------------
* 28 | GOP N | GOP M |
* ---------------------------------
*/
width = data[16] | (data[17] & 0xf) << 8;
height = data[18] | (data[19] & 0xf) << 8;
if (VALIDATE && ((data[17] & 0xf0) || data[19] & 0xf0))
return GST_FLOW_ERROR;
aspect = data[20] >> 4;
framerate = data[20] & 0xf;
bitrate = data[21] | data[22] << 8 | (data[23] & 0x3) << 16;
if (VALIDATE && (data[23] & 0xfc))
return GST_FLOW_ERROR;
vbv_buffer = data[24] | (data[25] & 0x3) << 8;
if (VALIDATE && (data[25] & 0xfc))
return GST_FLOW_ERROR;
profile = (data[26] >> 4) & 0x7;
level = data[26] & 0xf;
format = (data[27] >> 4) & 0x7;
chroma = (data[27] >> 2) & 0x3;
gop_n = data[28] >> 3;
gop_m = data[28] & 0x7;
GST_LOG_OBJECT (filter, " Video Mode");
GST_LOG_OBJECT (filter, " width:%d, height:%d", width, height);
GST_LOG_OBJECT (filter, " Aspect Ratio : %s (0x%x)",
(aspect == 0x3) ? "16/9" : "RESERVED", aspect);
GST_LOG_OBJECT (filter, " Framerate: %s (0x%x)",
sfr_to_framerate (framerate), framerate);
GST_LOG_OBJECT (filter, " Bitrate: %d bit/s", bitrate * 400);
GST_LOG_OBJECT (filter, " VBV buffer Size : %d bits",
vbv_buffer * 16 * 1024);
GST_LOG_OBJECT (filter, " MPEG Profile : %s (0x%x)",
(profile == 0x4) ? "Main" : "RESERVED", profile);
GST_LOG_OBJECT (filter, " MPEG Level : %s (0x%x)",
(level == 0x6) ? "High-1440" : "RESERVED", level);
GST_LOG_OBJECT (filter, " Video format : %s (0x%x)",
(format == 0) ? "Component" : "Reserved", format);
GST_LOG_OBJECT (filter, " Chroma : %s (0x%x)",
(chroma == 0x1) ? "4:2:0" : "RESERVED", chroma);
GST_LOG_OBJECT (filter, " GOP N/M : %d / %d", gop_n, gop_m);
/* data availability
* ---------------------------------
* 29 | 0 | 0 | 0 | 0 | 0 |PE2|PE1|PE0|
* ---------------------------------
* PE0 : HD2 TTC is valid
* PE1 : REC DATE is valid
* PE2 : REC TIME is valid
*/
if (data[29] & 0x1) {
guint8 fr, sec, min, hr;
gboolean bf, df;
gchar *ttcs;
/* HD2 TTC
* ---------------------------------
* 30 |BF |DF |Tens Fr|Units of Frames|
* ---------------------------------
* 31 | 1 |Tens second|Units of Second|
* ---------------------------------
* 32 | 1 |Tens minute|Units of Minute|
* ---------------------------------
* 33 | 1 | 1 |Tens Hr|Units of Hours |
* ---------------------------------
*/
bf = data[30] >> 7;
df = (data[30] >> 6) & 0x1;
fr = BCD (data[30] & 0x3f);
sec = BCD (data[31] & 0x7f);
min = BCD (data[32] & 0x7f);
hr = BCD (data[33] & 0x3f);
GST_LOG_OBJECT (filter, " HD2 Title Time Code");
GST_LOG_OBJECT (filter, " BF:%d, Drop Frame:%d", bf, df);
ttcs = g_strdup_printf ("%02d:%02d:%02d.%02d", hr, min, sec, fr);
GST_LOG_OBJECT (filter, " Timecode %s", ttcs);
/* FIXME : Use framerate information from above to convert to GstClockTime */
gst_structure_set (st, "title-time-code", G_TYPE_STRING, ttcs, NULL);
g_free (ttcs);
}
if (data[29] & 0x2) {
gboolean ds, tm;
guint8 tz, day, dow, month, year;
GDate *date;
/* REC DATE
* ---------------------------------
* 34 |DS |TM |Tens TZ|Units of TimeZn|
* ---------------------------------
* 35 | 1 | 1 |Tens dy| Units of Days |
* ---------------------------------
* 36 | Week |TMN|Units of Months|
* ---------------------------------
* 37 | Tens of Years |Units of Years |
* ---------------------------------
*/
ds = data[34] >> 7;
tm = (data[34] >> 6) & 0x1;
tz = BCD (data[34] & 0x3f);
day = BCD (data[35] & 0x3f);
dow = data[36] >> 5;
month = BCD (data[36] & 0x1f);
year = BCD (data[37]);
GST_LOG_OBJECT (filter, " REC DATE");
GST_LOG_OBJECT (filter, " ds:%d, tm:%d", ds, tm);
GST_LOG_OBJECT (filter, " Timezone: %d", tz);
GST_LOG_OBJECT (filter, " Date: %d %02d/%02d/%04d", dow, day, month, year);
date = g_date_new_dmy (day, month, year);
gst_structure_set (st, "date", GST_TYPE_DATE, date,
"timezone", G_TYPE_INT, tz,
"daylight-saving", G_TYPE_BOOLEAN, ds, NULL);
g_date_free (date);
}
if (data[29] & 0x4) {
guint8 fr, sec, min, hr;
gchar *times;
/* REC TIME
* ---------------------------------
* 38 | 1 | 1 |Tens Fr|Units of Frames|
* ---------------------------------
* 39 | 1 |Tens second|Units of Second|
* ---------------------------------
* 40 | 1 |Tens minute|Units of Minute|
* ---------------------------------
* 41 | 1 | 1 |Tens Hr|Units of Hours |
* ---------------------------------
*/
fr = BCD (data[38] & 0x3f);
sec = BCD (data[39] & 0x7f);
min = BCD (data[40] & 0x7f);
hr = BCD (data[41] & 0x3f);
times = g_strdup_printf ("%02d:%02d:%02d", hr, min, sec);
GST_LOG_OBJECT (filter, " REC TIME %02d:%02d:%02d.%02d", hr, min, sec, fr);
gst_structure_set (st, "time", G_TYPE_STRING, times, NULL);
g_free (times);
}
/* MISC
* ---------------------------------
* 42 | CGMS |REC|ABS| 0 | 0 | 0 | 0 |
* ---------------------------------
*/
cgms = data[42] >> 6;
recst = (data[42] >> 5) & 0x1;
abst = (data[42] >> 4) & 0x1;
GST_LOG_OBJECT (filter, " CGMS:0x%x", cgms);
GST_LOG_OBJECT (filter, " Recording Start Point : %s",
(recst == 0) ? "PRESENT" : "ABSENT");
GST_LOG_OBJECT (filter, " ABST : %s",
(abst == 0) ? "DISCONTINUITY" : "NO DISCONTINUITY");
gst_structure_set (st, "recording-start-point", G_TYPE_BOOLEAN, !recst, NULL);
/* Extended DV Pack #1
* 43 - 47
*/
GST_LOG_OBJECT (filter, " Extended DV Pack #1 : 0x%x", data[43]);
/* Extended DV Pack #1
* 48 - 52
*/
GST_LOG_OBJECT (filter, " Extended DV Pack #2 : 0x%x", data[48]);
/* Extended DV Pack #1
* 53 - 57
*/
GST_LOG_OBJECT (filter, " Extended DV Pack #3 : 0x%x", data[53]);
return GST_FLOW_OK;
}
static GstFlowReturn
parse_audio_frame (GstHDVParse * filter, guint8 * data, guint64 size,
GstStructure * st)
{
guint32 etn;
guint8 nbmute, nbaau;
guint64 pts;
guint16 audio_comp;
guint8 bitrate, fs, compress, channel;
guint8 option, cgms;
gboolean acly, recst;
GST_LOG_OBJECT (filter, "Audio Frame Pack");
/* Byte | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
* ---------------------------------
* 0 | Size (0x0f) |
* ---------------------------------
* 1 | |
* 2 | ETN |
* 3 | |
* ---------------------------------
* 4 |Nb Audio Mute | Number of AAU |
* ---------------------------------
*/
if (data[0] != 0x0f) {
GST_WARNING ("Invalid size for audio frame");
return GST_FLOW_ERROR;
}
etn = data[3] << 16 | data[2] << 8 | data[1];
GST_LOG_OBJECT (filter, " ETN : %" G_GUINT32_FORMAT, etn);
/* Pack-A Information
* ---------------------------------
* 4 |Nb Audio Mute | Number of AAU |
* ---------------------------------
* 5 | |
* 6 | PTS |
* 7 | |
* 8 | |
* ----------------------------- |
* 9 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
* ---------------------------------
* 10 | Audio |
* 11 | Compensation |
* ---------------------------------
*/
/* Number of Audio Mute Frames */
nbmute = data[4] >> 4;
/* Number of AAU */
nbaau = data[4] & 0x0f;
/* PTS of the first AAU immediatly following */
pts = (data[5] | data[6] << 8 | data[7] << 16 | data[8] << 24);
pts |= (guint64) (data[9] & 0x1) << 32;
if (G_UNLIKELY (VALIDATE && (data[9] & 0xfe))) {
return GST_FLOW_ERROR;
}
/* Amount of compensation */
audio_comp = data[10] | data[11] << 8;
GST_LOG_OBJECT (filter, " Pack-A Information");
GST_LOG_OBJECT (filter, " Nb Audio Mute Frames : %d", nbmute);
GST_LOG_OBJECT (filter, " Nb AAU : %d", nbaau);
GST_LOG_OBJECT (filter,
" PTS : %" GST_TIME_FORMAT " (%" G_GUINT64_FORMAT ")",
GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (pts)), pts);
GST_LOG_OBJECT (filter, " Audio Compensation : %" G_GUINT32_FORMAT,
audio_comp);
/* Audio Mode
* ---------------------------------
* 12 | Bitrate Index | 0 |Samplerate |
* ---------------------------------
* 13 | Compression | Channels |
* ---------------------------------
* 14 | X | Anciliary Option |
* ---------------------------------
*
* X : Anciliary data present
*/
bitrate = data[12] >> 4;
fs = data[12] & 0x7;
if (G_UNLIKELY (VALIDATE && (data[12] & 0x08)))
return GST_FLOW_ERROR;
compress = data[13] >> 4;
channel = data[13] & 0xf;
acly = data[14] & 0x80;
option = data[14] & 0x7f;
GST_LOG_OBJECT (filter, " Audio Mode");
GST_LOG_OBJECT (filter, " Bitrate : %s (0x%x)",
(bitrate == 0xe) ? "384kbps" : "RESERVED", bitrate);
GST_LOG_OBJECT (filter, " Samplerate : %s (0x%x)",
(fs == 0x1) ? "48 kHz" : "RESERVED", fs);
GST_LOG_OBJECT (filter, " Compression : %s (0x%x)",
(compress == 0x2) ? "MPEG-1 Layer II" : "RESERVED", compress);
GST_LOG_OBJECT (filter, " Channels : %s (0x%x)",
(channel == 0) ? "Stereo" : "RESERVED", channel);
GST_LOG_OBJECT (filter, " Anciliary data %s %s (0x%x)",
acly ? "PRESENT" : "ABSENT",
(option == 0xc) ? "IEC 13818-3" : "ABSENT/RESERVED", option);
/*
* ---------------------------------
* 15 | CGMS | R | 0 | 0 | 0 | 0 | 0 |
* ---------------------------------
*
* R : Recording Start Point
*/
cgms = data[15] & 0xc0;
recst = data[15] & 0x20;
GST_LOG_OBJECT (filter, " Misc");
GST_LOG_OBJECT (filter, " CGMS : 0x%x", cgms);
GST_LOG_OBJECT (filter, " Recording Start Point %s",
(recst) ? "ABSENT" : "PRESENT");
gst_structure_set (st, "PTS", G_TYPE_UINT64, MPEGTIME_TO_GSTTIME (pts),
"recording-start-point", G_TYPE_BOOLEAN, !recst, NULL);
return GST_FLOW_OK;
}
static GstFlowReturn
gst_hdvparse_parse (GstHDVParse * filter, GstBuffer * buf)
{
GstFlowReturn res = GST_FLOW_OK;
guint8 *data = GST_BUFFER_DATA (buf);
guint64 offs = 0;
guint64 insize = GST_BUFFER_SIZE (buf);
GstStructure *st;
/* Byte | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
* ---------------------------------
* 0 | 0 | KEYWORD |
* (1) | LENGTH |
* ....
*
* KEYWORD :
* 0x00 - 0x3F : Constant length (5 bytes)
* 0x40 - 0x7F : Variable length (LENGTH + 1)
*
* LENGTH : if present, size of fields 1-N
*
* Known keyword values:
* 0x00-0x07 : AUX-V
* 0x08-0x3E : RESERVED
* 0x3F : AUX-N NO-INFO
* 0x40-0x43 : AUX-A
* 0x44-0x47 : AUX-V
* 0x48-0x4F : AUX-N
* 0x50-0x53 : AUX-SYS
* 0x54-0x7E : RESERVED
* 0x7F : AUX-N NULL PACK
*/
st = gst_structure_empty_new ("hdv-aux");
while (res == GST_FLOW_OK && (offs < insize)) {
guint8 kw = data[offs] & 0x7f;
guint8 size;
/* Variable size packs */
if (kw >= 0x40) {
size = data[offs + 1];
} else
size = 4;
/* Size validation */
GST_DEBUG ("kw:0x%x, insize:%" G_GUINT64_FORMAT ", offs:%" G_GUINT64_FORMAT
", size:%d", kw, insize, offs, size);
if (insize < offs + size) {
res = GST_FLOW_ERROR;
goto beach;
}
switch (kw) {
case 0x01:
GST_LOG ("BINARY GROUP");
offs += size + 1;
break;
case 0x07:
GST_LOG ("ETN pack");
break;
case 0x40:
GST_LOG ("Audio frame pack");
res = parse_audio_frame (filter, data + offs + 1, size, st);
offs += size + 2;
break;
case 0x3f:
GST_LOG ("NO INFO pack");
offs += size + 1;
break;
case 0x44:
GST_LOG ("Video frame pack");
res = parse_video_frame (filter, data + offs + 1, size, st);
offs += size + 2;
break;
case 0x48:
case 0x49:
case 0x4A:
case 0x4B:
GST_LOG ("DV multi-pack");
res = parse_dv_multi_pack (filter, data + offs + 1, size, st);
offs += size + 2;
break;
default:
GST_WARNING_OBJECT (filter, "Unknown AUX pack data of type 0x%x", kw);
res = GST_FLOW_ERROR;
}
}
beach:
if (gst_structure_n_fields (st)) {
GstMessage *msg;
/* Emit the element message */
msg = gst_message_new_element (GST_OBJECT (filter), st);
gst_element_post_message (GST_ELEMENT (filter), msg);
} else
gst_structure_free (st);
return res;
}
/* GstBaseTransform vmethod implementations */
static GstFlowReturn
gst_hdvparse_transform_ip (GstBaseTransform * base, GstBuffer * outbuf)
{
GstHDVParse *filter = GST_HDVPARSE (base);
return gst_hdvparse_parse (filter, outbuf);
}
/* entry point to initialize the plug-in
* initialize the plug-in itself
* register the element factories and other features
*/
static gboolean
HDVParse_init (GstPlugin * HDVParse)
{
return gst_element_register (HDVParse, "hdvparse", GST_RANK_NONE,
GST_TYPE_HDVPARSE);
}
/* gstreamer looks for this structure to register HDVParses
*
* exchange the string 'Template HDVParse' with you HDVParse description
*/
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
hdvparse,
"HDV private stream parser",
HDVParse_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/")

View file

@ -1,56 +0,0 @@
/*
* 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_HDVPARSE_H__
#define __GST_HDVPARSE_H__
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
G_BEGIN_DECLS
#define GST_TYPE_HDVPARSE \
(gst_hdvparse_get_type())
#define GST_HDVPARSE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_HDVPARSE,GstHDVParse))
#define GST_HDVPARSE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_HDVPARSE,GstHDVParseClass))
#define GST_IS_HDVPARSE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_HDVPARSE))
#define GST_IS_HDVPARSE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_HDVPARSE))
typedef struct _GstHDVParse GstHDVParse;
typedef struct _GstHDVParseClass GstHDVParseClass;
struct _GstHDVParse {
GstBaseTransform element;
};
struct _GstHDVParseClass {
GstBaseTransformClass parent_class;
};
GType gst_hdvparse_get_type (void);
G_END_DECLS
#endif /* __GST_HDVPARSE_H__ */

View file

@ -1,12 +0,0 @@
hdv_sources = [
'gsthdvparse.c'
]
gsthdvparse = library('gsthdvparse',
hdv_sources,
c_args : gst_plugins_bad_args,
include_directories : [configinc],
dependencies : [gstbase_dep, libm],
install : true,
install_dir : plugins_install_dir,
)

View file

@ -3,8 +3,6 @@ subdir('adpcmdec')
subdir('adpcmenc')
subdir('aiff')
subdir('asfmux')
# not ported to 1.0
#subdir('audiobuffer')
subdir('audiobuffersplit')
subdir('audiofxbad')
subdir('audiomixer')
@ -12,28 +10,18 @@ subdir('audiovisualizers')
subdir('autoconvert')
subdir('bayer')
subdir('camerabin2')
# did not work
#subdir('cdxaparse')
subdir('coloreffects')
subdir('compositor')
#did not work
#subdir('dccp')
subdir('debugutils')
subdir('dvbsuboverlay')
subdir('dvdspu')
# did not work
#subdir('faceoverlay')
subdir('festival')
subdir('fieldanalysis')
subdir('freeverb')
subdir('frei0r')
# did not work
#subdir('games')
subdir('gaudieffects')
subdir('gdp')
subdir('geometrictransform')
#did not work
#subdir('hdvparse')
subdir('id3tag')
subdir('inter')
subdir('interlace')
@ -43,30 +31,16 @@ subdir('jp2kdecimator')
subdir('jpegformat')
subdir('librfb')
subdir('midi')
#did not work
#subdir('mixmatrix')
subdir('mpegdemux')
subdir('mpegpsmux')
subdir('mpegtsdemux')
subdir('mpegtsmux')
#did not work
#subdir('mve')
subdir('mxf')
#did not work
#subdir('nuvdemux')
subdir('onvif')
#did not work
#subdir('overlay')
#did not work
#subdir('patchdetect')
subdir('pcapparse')
subdir('pnm')
subdir('rawparse')
subdir('removesilence')
#did not work
#subdir('rtjpeg')
#did not work
#subdir('sdi')
subdir('sdp')
subdir('segmentclip')
subdir('siren')
@ -75,10 +49,6 @@ subdir('smooth')
subdir('speed')
subdir('stereo')
subdir('subenc')
#did not work
#subdir('tta')
#did not work
#subdir('vbidec')
subdir('videofilters')
subdir('videoframe_audiolevel')
subdir('videoparsers')

View file

@ -1,9 +0,0 @@
plugin_LTLIBRARIES = libgstmixmatrix.la
libgstmixmatrix_la_SOURCES = mixmatrix.c
libgstmixmatrix_la_CFLAGS = $(GST_CFLAGS)
libgstmixmatrix_la_LIBADD =
libgstmixmatrix_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstmixmatrix_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)

View file

@ -1,12 +0,0 @@
mixmat_sources = [
'mixmatrix.c',
]
gstmixmatrix = library('gstmixmatrix',
mixmat_sources,
c_args : gst_plugins_bad_args,
include_directories : [configinc],
dependencies : [gstbase_dep],
install : true,
install_dir : plugins_install_dir,
)

View file

@ -1,530 +0,0 @@
/* GStreamer
* Copyright (C) 2002 Wim Taymans <wtay@chello.be>
*
* 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/gst.h>
#include <gst/bytestream/bytestream.h>
#include <gst/audio/audio.h>
#include <string.h>
#define GST_TYPE_MIXMATRIX \
(gst_mixmatrix_get_type())
#define GST_MIXMATRIX(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MIXMATRIX,GstMixMatrix))
#define GST_MIXMATRIX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MIXMATRIX,GstMixMatrix))
#define GST_IS_MIXMATRIX(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MIXMATRIX))
#define GST_IS_MIXMATRIX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MIXMATRIX))
typedef struct _GstMixMatrix GstMixMatrix;
typedef struct _GstMixMatrixClass GstMixMatrixClass;
struct _GstMixMatrix
{
GstElement element;
GstCaps *caps;
gint samplerate;
gint grpsize;
gint outsize;
GstPad **sinkpads;
GstByteStream **sinkbs;
gint sinkpadalloc;
GstPad **srcpads;
gint srcpadalloc;
gfloat **matrix;
};
struct _GstMixMatrixClass
{
GstElementClass parent_class;
void (*resize) (GstMixMatrix * mix);
};
enum
{
/* FILL ME */
RESIZE_SIGNAL,
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_SINKPADS,
PROP_SRCPADS,
PROP_MATRIXPTR
};
static GstStaticPadTemplate mixmatrix_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink_%u",
GST_PAD_SINK,
GST_PAD_REQUEST,
GST_STATIC_CAPS (GST_AUDIO_FLOAT_STANDARD_PAD_TEMPLATE_CAPS)
);
static GstStaticPadTemplate mixmatrix_src_template =
GST_STATIC_PAD_TEMPLATE ("src_%u",
GST_PAD_SRC,
GST_PAD_REQUEST,
GST_STATIC_CAPS (GST_AUDIO_FLOAT_STANDARD_PAD_TEMPLATE_CAPS)
);
static void gst_mixmatrix_class_init (GstMixMatrixClass * klass);
static void gst_mixmatrix_base_init (GstMixMatrixClass * klass);
static void gst_mixmatrix_init (GstMixMatrix * element);
static void gst_mixmatrix_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_mixmatrix_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstPad *gst_mixmatrix_request_new_pad (GstElement * element,
GstPadTemplate * temp, const gchar * name);
static GstPadLinkReturn gst_mixmatrix_connect (GstPad * pad,
const GstCaps * caps);
static void gst_mixmatrix_loop (GstElement * element);
static guint gst_mixmatrix_signals[LAST_SIGNAL] = { 0 };
static GstElementClass *parent_class = NULL;
GType
gst_mixmatrix_get_type (void)
{
static GType mixmatrix_type = 0;
if (!mixmatrix_type) {
static const GTypeInfo mixmatrix_info = {
sizeof (GstMixMatrixClass),
(GBaseInitFunc) gst_mixmatrix_base_init,
NULL,
(GClassInitFunc) gst_mixmatrix_class_init,
NULL,
NULL,
sizeof (GstMixMatrix),
0,
(GInstanceInitFunc) gst_mixmatrix_init,
};
mixmatrix_type =
g_type_register_static (GST_TYPE_ELEMENT, "GstMixMatrix",
&mixmatrix_info, 0);
}
return mixmatrix_type;
}
static void
gst_mixmatrix_base_init (GstMixMatrixClass * klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_add_static_pad_template (element_class,
&mixmatrix_sink_template);
gst_element_class_add_static_pad_template (element_class,
&mixmatrix_src_template);
gst_element_class_set_static_metadata (element_class, "Mixing Matrix",
"Filter/Editor/Audio", "Mix N audio channels together into M channels",
"Erik Walthinsen <omega@temple-baptist.com>");
}
static void
gst_mixmatrix_class_init (GstMixMatrixClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
parent_class = g_type_class_peek_parent (klass);
gst_mixmatrix_signals[RESIZE_SIGNAL] =
g_signal_new ("resize",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstMixMatrixClass, resize),
NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SINKPADS,
g_param_spec_int ("sinkpads", "Sink Pads",
"Number of sink pads in matrix", 0, G_MAXINT, 8,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SRCPADS,
g_param_spec_int ("srcpads", "Src Pads", "Number of src pads in matrix",
0, G_MAXINT, 8, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MATRIXPTR,
g_param_spec_pointer ("matrixptr", "Matrix Pointer",
"Pointer to gfloat mix matrix",
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
gobject_class->set_property = gst_mixmatrix_set_property;
gobject_class->get_property = gst_mixmatrix_get_property;
gstelement_class->request_new_pad = gst_mixmatrix_request_new_pad;
}
static gfloat **
mixmatrix_alloc_matrix (int x, int y)
{
gfloat **matrix;
int i;
GST_DEBUG ("mixmatrix: allocating a %dx%d matrix of floats\n", x, y);
matrix = g_new (gfloat *, x);
GST_DEBUG ("mixmatrix: %p: ", matrix);
for (i = 0; i < x; i++) {
matrix[i] = g_new (gfloat, y);
GST_DEBUG ("%p, ", matrix[i]);
}
GST_DEBUG ("\n");
return matrix;
}
static void
mixmatrix_free_matrix (gfloat ** matrix, int x)
{
int i;
for (i = 0; i < x; i++)
g_free (matrix[i]);
g_free (matrix);
}
static void
gst_mixmatrix_init (GstMixMatrix * mix)
{
mix->grpsize = 8;
mix->outsize = 1024;
/* start with zero pads */
mix->sinkpadalloc = mix->grpsize;
mix->srcpadalloc = mix->grpsize;
/* allocate the pads */
mix->sinkpads = g_new0 (GstPad *, mix->sinkpadalloc);
mix->sinkbs = g_new0 (GstByteStream *, mix->sinkpadalloc);
mix->srcpads = g_new0 (GstPad *, mix->srcpadalloc);
/* allocate a similarly sized matrix */
mix->matrix = mixmatrix_alloc_matrix (mix->sinkpadalloc, mix->srcpadalloc);
/* set the loop function that does all the work */
gst_element_set_loop_function (GST_ELEMENT (mix), gst_mixmatrix_loop);
}
#define ROUND_UP(val,bound) ((((val)/bound)+1)*bound)
static void **
grow_ptrlist (void **origlist, int origsize, int newsize)
{
void **newlist = g_new (void *, newsize);
memcpy (newlist, origlist, sizeof (void *) * origsize);
g_free (origlist);
return newlist;
}
void
mixmatrix_resize (GstMixMatrix * mix, int sinkpads, int srcpads)
{
int sinkresize = (sinkpads != mix->sinkpadalloc);
int srcresize = (srcpads != mix->srcpadalloc);
gfloat **newmatrix;
int i;
GST_DEBUG ("mixmatrix: resizing matrix!!!!\n");
/* check the sinkpads list */
if (sinkresize) {
mix->sinkpads =
(GstPad **) grow_ptrlist ((void **) mix->sinkpads, mix->sinkpadalloc,
sinkpads);
mix->sinkbs =
(GstByteStream **) grow_ptrlist ((void **) mix->sinkbs,
mix->sinkpadalloc, sinkpads);
}
/* check the srcpads list */
if (srcresize) {
mix->srcpads =
(GstPad **) grow_ptrlist ((void **) mix->srcpads, mix->srcpadalloc,
srcpads);
}
/* now resize the matrix if either has changed */
if (sinkresize || srcresize) {
/* allocate the new matrix */
newmatrix = mixmatrix_alloc_matrix (sinkpads, srcpads);
/* if only the srcpad count changed (y axis), we can just copy */
if (!sinkresize) {
memcpy (newmatrix, mix->matrix, sizeof (gfloat *) * sinkpads);
/* otherwise we have to copy line by line */
} else {
for (i = 0; i < mix->srcpadalloc; i++)
memcpy (newmatrix[i], mix->matrix[i],
sizeof (gfloat) * mix->srcpadalloc);
}
/* would signal here! */
/* free old matrix and replace it */
mixmatrix_free_matrix (mix->matrix, mix->sinkpadalloc);
mix->matrix = newmatrix;
}
mix->sinkpadalloc = sinkpads;
mix->srcpadalloc = srcpads;
}
#if 0
static gboolean
gst_mixmatrix_set_all_caps (GstMixMatrix * mix)
{
int i;
/* sink pads */
for (i = 0; i < mix->sinkpadalloc; i++) {
if (mix->sinkpads[i]) {
if (GST_PAD_CAPS (mix->sinkpads[i]) == NULL)
if (gst_pad_try_set_caps (mix->sinkpads[i], mix->caps) <= 0)
return FALSE;
}
}
/* src pads */
for (i = 0; i < mix->srcpadalloc; i++) {
if (mix->srcpads[i]) {
if (GST_PAD_CAPS (mix->srcpads[i]) == NULL)
if (gst_pad_try_set_caps (mix->srcpads[i], mix->caps) <= 0)
return FALSE;
}
}
return TRUE;
}
#endif
static GstPadLinkReturn
gst_mixmatrix_connect (GstPad * pad, const GstCaps * caps)
{
GstMixMatrix *mix = GST_MIXMATRIX (GST_PAD_PARENT (pad));
gint i;
for (i = 0; i < mix->srcpadalloc; i++) {
if (mix->srcpads[i]) {
if (GST_PAD_CAPS (mix->srcpads[i]) == NULL) {
if (gst_pad_try_set_caps (mix->srcpads[i], caps) <= 0) {
return GST_PAD_LINK_REFUSED;
}
}
}
}
mix->caps = gst_caps_copy (caps);
return GST_PAD_LINK_OK;
}
static GstPad *
gst_mixmatrix_request_new_pad (GstElement * element, GstPadTemplate * templ,
const gchar * name)
{
GstMixMatrix *mix;
gint padnum;
GstPad *pad = NULL;
g_return_val_if_fail (element != NULL, NULL);
g_return_val_if_fail (GST_IS_MIXMATRIX (element), NULL);
mix = GST_MIXMATRIX (element);
/* figure out if it's a sink pad */
if (sscanf (name, "sink_%u", &padnum)) {
/* check to see if it already exists */
if (padnum < mix->sinkpadalloc && mix->sinkpads[padnum])
return mix->sinkpads[padnum];
/* determine if it's bigger than the current size */
if (padnum >= mix->sinkpadalloc)
mixmatrix_resize (mix, ROUND_UP (padnum, mix->grpsize),
mix->sinkpadalloc);
pad = gst_pad_new_from_static_template (&mixmatrix_sink_template, name);
GST_PAD_ELEMENT_PRIVATE (pad) = GINT_TO_POINTER (padnum);
gst_element_add_pad (GST_ELEMENT (mix), pad);
/* g_signal_connect(G_OBJECT(pad), "unlink", G_CALLBACK(sink_unlinked), mix); */
gst_pad_set_link_function (pad, gst_mixmatrix_connect);
/* create a bytestream for it */
mix->sinkbs[padnum] = gst_bytestream_new (pad);
/* store away the pad and account for it */
mix->sinkpads[padnum] = pad;
}
/* or it's a src pad */
else if (sscanf (name, "src_%u", &padnum)) {
/* check to see if it already exists */
if (padnum < mix->srcpadalloc && mix->srcpads[padnum])
return mix->srcpads[padnum];
/* determine if it's bigger than the current size */
if (padnum >= mix->srcpadalloc)
mixmatrix_resize (mix, ROUND_UP (padnum, mix->grpsize), mix->srcpadalloc);
pad = gst_pad_new_from_static_template (&mixmatrix_src_template, name);
GST_PAD_ELEMENT_PRIVATE (pad) = GINT_TO_POINTER (padnum);
gst_element_add_pad (GST_ELEMENT (mix), pad);
/* g_signal_connect(G_OBJECT(pad), "unlink", G_CALLBACK(sink_unlinked), mix); */
/* gst_pad_set_link_function (pad, gst_mixmatrix_connect); */
/* store away the pad and account for it */
mix->srcpads[padnum] = pad;
}
return pad;
}
static void
gst_mixmatrix_loop (GstElement * element)
{
GstMixMatrix *mix = GST_MIXMATRIX (element);
int i, j, k;
GstBuffer **inbufs;
gfloat **infloats;
GstBuffer **outbufs;
gfloat **outfloats;
int bytesize = sizeof (gfloat) * mix->outsize;
gfloat gain;
/* create the output buffers */
outbufs = g_new (GstBuffer *, mix->srcpadalloc);
outfloats = g_new (gfloat *, mix->srcpadalloc);
for (i = 0; i < mix->srcpadalloc; i++) {
if (mix->srcpads[i] != NULL) {
outbufs[i] = gst_buffer_new_and_alloc (bytesize);
outfloats[i] = (gfloat *) GST_BUFFER_DATA (outbufs[i]);
memset (outfloats[i], 0, bytesize);
}
}
/* go through all the input buffers and pull them */
inbufs = g_new (GstBuffer *, mix->sinkpadalloc);
infloats = g_new (gfloat *, mix->sinkpadalloc);
for (i = 0; i < mix->sinkpadalloc; i++) {
if (mix->sinkpads[i] != NULL) {
gst_bytestream_read (mix->sinkbs[i], &inbufs[i], bytesize);
infloats[i] = (gfloat *) GST_BUFFER_DATA (inbufs[i]);
/* loop through each src pad */
for (j = 0; j < mix->srcpadalloc; j++) {
if (mix->srcpads[j] != NULL) {
/*
{
int z;
fprintf(stderr,"matrix is %p: ",mix->matrix);
for (z=0;z<mix->sinkpadalloc;z++)
fprintf(stderr,"%p, ",mix->matrix[i]);
fprintf(stderr,"\n");
}
fprintf(stderr,"attempting to get gain for %dx%d\n",i,j);
*/
gain = mix->matrix[i][j];
/* fprintf(stderr,"%d->%d=%0.2f ",i,j,gain); */
for (k = 0; k < mix->outsize; k++) {
outfloats[j][k] += infloats[i][k] * gain;
}
}
}
}
}
/* fprintf(stderr,"\n"); */
for (i = 0; i < mix->srcpadalloc; i++) {
if (mix->srcpads[i] != NULL) {
gst_pad_push (mix->srcpads[i], GST_DATA (outbufs[i]));
}
}
}
static void
gst_mixmatrix_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstMixMatrix *mix;
g_return_if_fail (GST_IS_MIXMATRIX (object));
mix = GST_MIXMATRIX (object);
switch (prop_id) {
default:
break;
}
}
static void
gst_mixmatrix_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstMixMatrix *mix;
g_return_if_fail (GST_IS_MIXMATRIX (object));
mix = GST_MIXMATRIX (object);
switch (prop_id) {
case PROP_SINKPADS:
g_value_set_int (value, mix->sinkpadalloc);
break;
case PROP_SRCPADS:
g_value_set_int (value, mix->srcpadalloc);
break;
case PROP_MATRIXPTR:
g_value_set_pointer (value, mix->matrix);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
plugin_init (GstPlugin * plugin)
{
if (!gst_library_load ("gstbytestream"))
return FALSE;
return gst_element_register (plugin, "mixmatrix",
GST_RANK_NONE, GST_TYPE_MIXMATRIX);
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
mixmatrix,
"An audio mixer matrix",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

View file

@ -1,21 +0,0 @@
plugin_LTLIBRARIES = libgstmve.la
libgstmve_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
libgstmve_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) $(LIBM)
libgstmve_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstmve_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
libgstmve_la_SOURCES = \
gstmve.c \
gstmvemux.c \
gstmvedemux.c \
mveaudiodec.c \
mvevideodec8.c \
mvevideodec16.c \
mveaudioenc.c \
mvevideoenc8.c \
mvevideoenc16.c
noinst_HEADERS = gstmvedemux.h gstmvemux.h mve.h
EXTRA_DIST = TODO

View file

@ -1,5 +0,0 @@
MVE TODO:
- seeking support
- split out decoders from demuxer into separate elements
- split out encoders from muxer into separate elements

View file

@ -1,46 +0,0 @@
/* GStreamer plugin for Interplay MVE movie files
*
* Copyright (C) 2006 Jens Granseuer <jensgr@gmx.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.
*
* For more information about the Interplay MVE format, visit:
* http://www.pcisys.net/~melanson/codecs/interplay-mve.txt
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "gstmvedemux.h"
#include "gstmvemux.h"
static gboolean
mve_plugin_init (GstPlugin * plugin)
{
return gst_element_register (plugin, "mvedemux", GST_RANK_PRIMARY,
GST_TYPE_MVE_DEMUX)
&& gst_element_register (plugin, "mvemux", GST_RANK_PRIMARY,
GST_TYPE_MVE_MUX);
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
mve,
"Interplay MVE movie format manipulation",
mve_plugin_init,
VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);

File diff suppressed because it is too large Load diff

View file

@ -1,114 +0,0 @@
/*
* GStreamer demultiplexer plugin for Interplay MVE movie files
*
* Copyright (C) 2006 Jens Granseuer <jensgr@gmx.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_MVE_DEMUX_H__
#define __GST_MVE_DEMUX_H__
#include <gst/gst.h>
#include <gst/base/gstadapter.h>
G_BEGIN_DECLS
#define GST_TYPE_MVE_DEMUX \
(gst_mve_demux_get_type())
#define GST_MVE_DEMUX(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MVE_DEMUX,GstMveDemux))
#define GST_MVE_DEMUX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MVE_DEMUX,GstMveDemuxClass))
#define GST_IS_MVE_DEMUX(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MVE_DEMUX))
#define GST_IS_MVE_DEMUX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MVE_DEMUX))
typedef struct _GstMveDemux GstMveDemux;
typedef struct _GstMveDemuxClass GstMveDemuxClass;
typedef struct _GstMveDemuxStream GstMveDemuxStream;
struct _GstMveDemux
{
GstElement element;
GstPad *sinkpad;
GstMveDemuxStream *video_stream;
GstMveDemuxStream *audio_stream;
gint state;
/* time per frame (1/framerate) */
GstClockTime frame_duration;
/* push based variables */
guint16 needed_bytes;
GstAdapter *adapter;
/* size of current chunk */
guint32 chunk_size;
/* offset in current chunk */
guint32 chunk_offset;
};
struct _GstMveDemuxClass
{
GstElementClass parent_class;
};
struct _GstMveDemuxStream {
/* shared properties */
GstCaps *caps;
GstPad *pad;
GstClockTime last_ts;
gint64 offset;
GstFlowReturn last_flow;
/* video properties */
guint16 width;
guint16 height;
guint8 bpp; /* bytes per pixel */
guint8 *code_map;
gboolean code_map_avail;
guint8 *back_buf1;
guint8 *back_buf2;
guint32 max_block_offset;
GstBuffer *palette;
GstBuffer *buffer;
/* audio properties */
guint16 sample_rate;
guint16 n_channels;
guint16 sample_size;
gboolean compression;
};
GType gst_mve_demux_get_type (void);
int ipvideo_decode_frame8 (const GstMveDemuxStream * s,
const unsigned char *data, unsigned short len);
int ipvideo_decode_frame16 (const GstMveDemuxStream * s,
const unsigned char *data, unsigned short len);
void ipaudio_uncompress (short *buffer,
unsigned short buf_len, const unsigned char *data, unsigned char channels);
G_END_DECLS
#endif /* __GST_MVE_DEMUX_H__ */

File diff suppressed because it is too large Load diff

View file

@ -1,127 +0,0 @@
/*
* Interplay MVE muxer plugin for GStreamer
* Copyright (C) 2006 Jens Granseuer <jensgr@gmx.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_MVE_MUX_H__
#define __GST_MVE_MUX_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define GST_TYPE_MVE_MUX \
(gst_mve_mux_get_type())
#define GST_MVE_MUX(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MVE_MUX,GstMveMux))
#define GST_MVE_MUX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MVE_MUX,GstMveMux))
#define GST_IS_MVE_MUX(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MVE_MUX))
#define GST_IS_MVE_MUX_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MVE_MUX))
typedef struct _GstMveMux GstMveMux;
typedef struct _GstMveMuxClass GstMveMuxClass;
struct _GstMveMux {
GstElement element;
GMutex *lock;
/* pads */
GstPad *source;
GstPad *videosink;
GstPad *audiosink;
gboolean audio_pad_connected;
gboolean audio_pad_eos;
gboolean video_pad_connected;
gboolean video_pad_eos;
guint64 stream_offset;
/* audio stream time, really */
GstClockTime stream_time;
guint timer;
gint state;
/* ticks per frame */
GstClockTime frame_duration;
/* video stream properties */
guint16 width, height;
guint16 screen_width, screen_height;
/* bits per pixel */
guint8 bpp;
/* previous frames */
GstBuffer *last_frame;
GstBuffer *second_last_frame;
/* number of encoded frames */
guint16 video_frames;
/* palette handling */
gboolean pal_changed;
guint16 pal_first_color;
guint16 pal_colors;
/* whether to use expensive opcodes */
gboolean quick_encoding;
/* audio stream properties */
/* bits per sample */
guint8 bps;
guint32 rate;
guint8 channels;
gboolean compression;
/* current audio stream time */
GstClockTime next_ts;
/* maximum audio time we know about */
GstClockTime max_ts;
/* sample bytes per frame */
guint16 spf;
/* number of frames to use for audio lead-in */
guint16 lead_frames;
/* number of encoded frames */
guint16 audio_frames;
/* current chunk */
guint8 *chunk_code_map;
GByteArray *chunk_video;
GByteArray *chunk_audio;
gboolean chunk_has_palette;
gboolean chunk_has_audio;
/* buffers for incoming data */
GQueue *audio_buffer;
GQueue *video_buffer;
};
struct _GstMveMuxClass {
GstElementClass parent_class;
};
GType gst_mve_mux_get_type (void);
GstFlowReturn mve_encode_frame8 (GstMveMux * mve,
GstBuffer * frame, const guint32 * palette, guint16 max_data);
GstFlowReturn mve_encode_frame16 (GstMveMux * mve,
GstBuffer * frame, guint16 max_data);
gint mve_compress_audio (guint8 * dest,
const guint8 * src, guint16 len, guint8 channels);
G_END_DECLS
#endif /* __GST_MVE_MUX_H__ */

View file

@ -1,20 +0,0 @@
mve_sources = [
'gstmve.c',
'gstmvemux.c',
'gstmvedemux.c',
'mveaudiodec.c',
'mvevideodec8.c',
'mvevideodec16.c',
'mveaudioenc.c',
'mvevideoenc8.c',
'mvevideoenc16.c',
]
gstmve = library('gstmve',
mve_sources,
c_args : gst_plugins_bad_args,
include_directories : [configinc, libsinc],
dependencies : [gstbase_dep, libm],
install : true,
install_dir : plugins_install_dir,
)

View file

@ -1,62 +0,0 @@
/*
* Interplay MVE movie definitions
*
* Copyright (C) 2006 Jens Granseuer <jensgr@gmx.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 __MVE_H__
#define __MVE_H__
#define MVE_PREAMBLE "Interplay MVE File\032\000\032\000\000\001\063\021"
#define MVE_PREAMBLE_SIZE 26
#define MVE_PALETTE_COUNT 256
/* MVE chunk types */
#define MVE_CHUNK_INIT_AUDIO 0x0000
#define MVE_CHUNK_AUDIO_ONLY 0x0001
#define MVE_CHUNK_INIT_VIDEO 0x0002
#define MVE_CHUNK_VIDEO 0x0003
#define MVE_CHUNK_SHUTDOWN 0x0004
#define MVE_CHUNK_END 0x0005
/* MVE segment opcodes */
#define MVE_OC_END_OF_STREAM 0x00
#define MVE_OC_END_OF_CHUNK 0x01
#define MVE_OC_CREATE_TIMER 0x02
#define MVE_OC_AUDIO_BUFFERS 0x03
#define MVE_OC_PLAY_AUDIO 0x04
#define MVE_OC_VIDEO_BUFFERS 0x05
#define MVE_OC_PLAY_VIDEO 0x07
#define MVE_OC_AUDIO_DATA 0x08
#define MVE_OC_AUDIO_SILENCE 0x09
#define MVE_OC_VIDEO_MODE 0x0A
#define MVE_OC_PALETTE 0x0C
#define MVE_OC_PALETTE_COMPRESSED 0x0D
#define MVE_OC_CODE_MAP 0x0F
#define MVE_OC_VIDEO_DATA 0x11
/* audio flags */
#define MVE_AUDIO_STEREO 0x0001
#define MVE_AUDIO_16BIT 0x0002
#define MVE_AUDIO_COMPRESSED 0x0004
/* video flags */
#define MVE_VIDEO_DELTA_FRAME 0x0001
#endif /* __MVE_H__ */

View file

@ -1,82 +0,0 @@
/*
* Copyright (c) 2003 The ffmpeg Project, Mike Melanson
*
* 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 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Interplay compressed audio codec by Mike Melanson (melanson@pcisys.net)
*/
#include "gstmvedemux.h"
static const short delta_table[256] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 47, 51, 56, 61,
66, 72, 79, 86, 94, 102, 112, 122, 133, 145, 158, 173, 189, 206, 225, 245,
267, 292, 318, 348, 379, 414, 452, 493, 538, 587, 640, 699, 763, 832, 908,
991,
1081, 1180, 1288, 1405, 1534, 1673, 1826, 1993, 2175, 2373, 2590, 2826, 3084,
3365, 3672, 4008,
4373, 4772, 5208, 5683, 6202, 6767, 7385, 8059, 8794, 9597, 10472, 11428,
12471, 13609, 14851, 16206,
17685, 19298, 21060, 22981, 25078, 27367, 29864, 32589, -29973, -26728,
-23186, -19322, -15105, -10503, -5481, -1,
1, 1, 5481, 10503, 15105, 19322, 23186, 26728, 29973, -32589, -29864, -27367,
-25078, -22981, -21060, -19298,
-17685, -16206, -14851, -13609, -12471, -11428, -10472, -9597, -8794, -8059,
-7385, -6767, -6202, -5683, -5208, -4772,
-4373, -4008, -3672, -3365, -3084, -2826, -2590, -2373, -2175, -1993, -1826,
-1673, -1534, -1405, -1288, -1180,
-1081, -991, -908, -832, -763, -699, -640, -587, -538, -493, -452, -414, -379,
-348, -318, -292,
-267, -245, -225, -206, -189, -173, -158, -145, -133, -122, -112, -102, -94,
-86, -79, -72,
-66, -61, -56, -51, -47, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34,
-33,
-32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18,
-17,
-16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1
};
void
ipaudio_uncompress (short *buffer, unsigned short buf_len,
const unsigned char *data, unsigned char channels)
{
int i, out = 0;
int predictor[2];
int channel_number = 0;
for (i = 0; i < channels; ++i) {
predictor[i] = GST_READ_UINT16_LE (data);
data += 2;
if (predictor[i] & 0x8000)
predictor[i] -= 0x10000;
buffer[out++] = predictor[i];
}
/* we count in 16-bit ints, so adjust the buffer size */
buf_len /= 2;
while (out < buf_len) {
predictor[channel_number] += delta_table[*data++];
if (predictor[channel_number] < -32768)
predictor[channel_number] = -32768;
else if (predictor[channel_number] > 32767)
predictor[channel_number] = 32767;
buffer[out++] = predictor[channel_number];
/* toggle channel */
channel_number ^= channels - 1;
}
}

View file

@ -1,154 +0,0 @@
/*
* Interplay MVE audio compressor
* Copyright (C) 2003, 2004 Alexander Belyakov <abel@krasu.ru>
* Copyright (C) 2006 Jens Granseuer <jensgr@gmx.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.
*/
#include <math.h>
#include <stdlib.h>
#include "gstmvemux.h"
static const gint32 dec_table[256] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37,
38, 39, 40, 41, 42, 43, 47, 51, 56, 61,
66, 72, 79, 86, 94, 102, 112,
122, 133, 145, 158, 173, 189, 206, 225, 245,
267, 292, 318, 348, 379,
414, 452, 493, 538, 587, 640, 699, 763, 832, 908, 991,
1081, 1180, 1288,
1405, 1534, 1673, 1826, 1993, 2175, 2373, 2590, 2826, 3084, 3365, 3672,
4008,
4373, 4772, 5208, 5683, 6202, 6767, 7385, 8059, 8794, 9597, 10472,
11428, 12471, 13609, 14851, 16206,
17685, 19298, 21060, 22981, 25078,
27367, 29864, 32589, 35563, 38808, 42350, 46214, 50431, 55033, 60055,
65535,
1, -65535, -60055, -55033, -50431, -46214, -42350, -38808, -35563,
-32589, -29864, -27367, -25078, -22981, -21060, -19298,
-17685, -16206,
-14851, -13609, -12471, -11428, -10472, -9597, -8794, -8059, -7385, -6767,
-6202, -5683, -5208, -4772,
-4373, -4008, -3672, -3365, -3084, -2826,
-2590, -2373, -2175, -1993, -1826, -1673, -1534, -1405, -1288, -1180,
-1081, -991, -908, -832, -763, -699, -640, -587, -538, -493, -452, -414,
-379, -348, -318, -292,
-267, -245, -225, -206, -189, -173, -158, -145,
-133, -122, -112, -102, -94, -86, -79, -72,
-66, -61, -56, -51, -47, -43,
-42, -41, -40, -39, -38, -37, -36, -35, -34, -33,
-32, -31, -30, -29,
-28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17,
-16, -15,
-14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1
};
/* This value could be non-optimal. Without knowledge of the value
distribution in the real signal, the actual optimum cannot be evaluated.
Should be somewhere between 11.458 and 11.542. */
static const gdouble DPCM_SCALE = 11.5131;
static gint8
mve_enc_delta (guint n)
{
if (n < 44)
return n;
return floor (DPCM_SCALE * log (n));
}
gint
mve_compress_audio (guint8 * dest, const guint8 * src, guint16 len,
guint8 channels)
{
gint16 prev[2], s;
gint delta, real_res;
gint cur_chan;
guint8 v;
for (cur_chan = 0; cur_chan < channels; ++cur_chan) {
prev[cur_chan] = GST_READ_UINT16_LE (src);
GST_WRITE_UINT16_LE (dest, prev[cur_chan]);
src += 2;
dest += 2;
len -= 2;
}
cur_chan = 0;
while (len > 0) {
s = GST_READ_UINT16_LE (src);
src += 2;
delta = s - prev[cur_chan];
if (delta >= 0)
v = mve_enc_delta (delta);
else
v = 256 - mve_enc_delta (-delta);
real_res = dec_table[v] + prev[cur_chan];
if (real_res < -32768 || real_res > 32767) {
/* correct overflow */
/* GST_DEBUG ("co:%d + %d = %d -> new v:%d, dec_table:%d will be %d",
prev[cur_chan], dec_table[v], real_res,
v, dec_table[v], prev[cur_chan]+dec_table[v]); */
if (s > 0) {
if (real_res > 32767)
--v;
} else {
if (real_res < -32768)
++v;
}
real_res = dec_table[v] + prev[cur_chan];
}
if (G_UNLIKELY (abs (real_res - s) > 32767)) {
GST_ERROR ("sign loss left unfixed in audio stream, deviation:%d",
real_res - s);
return -1;
}
*dest++ = v;
--len;
/* use previous output instead of input. That way output will not go too far from input. */
prev[cur_chan] += dec_table[v];
cur_chan = channels - 1 - cur_chan;
}
return 0;
}

View file

@ -1,849 +0,0 @@
/*
* Interplay MVE Video Decoder (16 bit)
* Copyright (C) 2003 the ffmpeg project, Mike Melanson
* (C) 2006 Jens Granseuer
*
* 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 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* For more information about the Interplay MVE format, visit:
* http://www.pcisys.net/~melanson/codecs/interplay-mve.txt
*/
#include "gstmvedemux.h"
#include <string.h>
#define PIXEL(s) GST_READ_UINT16_LE (s)
#define CHECK_STREAM(l, n) \
do { \
if (G_UNLIKELY (*(l) < (n))) { \
GST_ERROR ("wanted to read %d bytes from stream, %d available", (n), *(l)); \
return -1; \
} \
*(l) -= (n); \
} while (0)
/* copy an 8x8 block from the stream to the frame buffer */
static int
ipvideo_copy_block (const GstMveDemuxStream * s, unsigned short *frame,
const unsigned short *src, int offset)
{
int i;
int frame_offset;
frame_offset = frame - (unsigned short *) s->back_buf1 + offset;
if (G_UNLIKELY (frame_offset < 0)) {
GST_ERROR ("frame offset < 0 (%d)", frame_offset);
return -1;
} else if (G_UNLIKELY (frame_offset > s->max_block_offset)) {
GST_ERROR ("frame offset above limit (%d > %u)",
frame_offset, s->max_block_offset);
return -1;
}
for (i = 0; i < 8; ++i) {
memcpy (frame, src, 16);
frame += s->width;
src += s->width;
}
return 0;
}
static int
ipvideo_decode_0x2 (const GstMveDemuxStream * s, unsigned short *frame,
const unsigned char **data, unsigned short *len)
{
unsigned char B;
int x, y;
int offset;
/* copy block from 2 frames ago using a motion vector */
CHECK_STREAM (len, 1);
B = *(*data)++;
if (B < 56) {
x = 8 + (B % 7);
y = B / 7;
} else {
x = -14 + ((B - 56) % 29);
y = 8 + ((B - 56) / 29);
}
offset = y * s->width + x;
return ipvideo_copy_block (s, frame, frame + offset, offset);
}
static int
ipvideo_decode_0x3 (const GstMveDemuxStream * s, unsigned short *frame,
const unsigned char **data, unsigned short *len)
{
unsigned char B;
int x, y;
int offset;
/* copy 8x8 block from current frame from an up/left block */
CHECK_STREAM (len, 1);
B = *(*data)++;
if (B < 56) {
x = -(8 + (B % 7));
y = -(B / 7);
} else {
x = -(-14 + ((B - 56) % 29));
y = -(8 + ((B - 56) / 29));
}
offset = y * s->width + x;
return ipvideo_copy_block (s, frame, frame + offset, offset);
}
static int
ipvideo_decode_0x4 (const GstMveDemuxStream * s, unsigned short *frame,
const unsigned char **data, unsigned short *len)
{
int x, y;
unsigned char B;
int offset;
/* copy a block from the previous frame */
CHECK_STREAM (len, 1);
B = *(*data)++;
x = -8 + (B & 0x0F);
y = -8 + (B >> 4);
offset = y * s->width + x;
return ipvideo_copy_block (s, frame, frame +
((unsigned short *) s->back_buf2 - (unsigned short *) s->back_buf1) +
offset, offset);
}
static int
ipvideo_decode_0x5 (const GstMveDemuxStream * s, unsigned short *frame,
const unsigned char **data, unsigned short *len)
{
signed char x, y;
int offset;
/* copy a block from the previous frame using an expanded range */
CHECK_STREAM (len, 2);
x = (signed char) *(*data)++;
y = (signed char) *(*data)++;
offset = y * s->width + x;
return ipvideo_copy_block (s, frame, frame +
((unsigned short *) s->back_buf2 - (unsigned short *) s->back_buf1) +
offset, offset);
}
static int
ipvideo_decode_0x7 (const GstMveDemuxStream * s, unsigned short *frame,
const unsigned char **data, unsigned short *len)
{
int x, y;
unsigned short P0, P1;
unsigned int flags;
int bitmask;
/* 2-color encoding */
CHECK_STREAM (len, 4 + 2);
P0 = PIXEL (*data);
(*data) += 2;
P1 = PIXEL (*data);
(*data) += 2;
if (!(P0 & 0x8000)) {
/* need 8 more bytes from the stream */
CHECK_STREAM (len, 8 - 2);
for (y = 0; y < 8; ++y) {
flags = *(*data)++;
for (x = 0x01; x <= 0x80; x <<= 1) {
if (flags & x)
*frame++ = P1;
else
*frame++ = P0;
}
frame += s->width - 8;
}
} else {
P0 &= ~0x8000;
/* need 2 more bytes from the stream */
flags = ((*data)[1] << 8) | (*data)[0];
(*data) += 2;
bitmask = 0x0001;
for (y = 0; y < 8; y += 2) {
for (x = 0; x < 8; x += 2, bitmask <<= 1) {
if (flags & bitmask) {
*(frame + x) = P1;
*(frame + x + 1) = P1;
*(frame + s->width + x) = P1;
*(frame + s->width + x + 1) = P1;
} else {
*(frame + x) = P0;
*(frame + x + 1) = P0;
*(frame + s->width + x) = P0;
*(frame + s->width + x + 1) = P0;
}
}
frame += s->width * 2;
}
}
return 0;
}
static int
ipvideo_decode_0x8 (const GstMveDemuxStream * s, unsigned short *frame,
const unsigned char **data, unsigned short *len)
{
int x, y;
unsigned short P[8];
unsigned char B[8];
unsigned int flags = 0;
unsigned int bitmask = 0;
unsigned short P0 = 0, P1 = 0;
int lower_half = 0;
/* 2-color encoding for each 4x4 quadrant, or 2-color encoding on
* either top and bottom or left and right halves */
CHECK_STREAM (len, 6 + 10);
P[0] = PIXEL (*data);
(*data) += 2;
P[1] = PIXEL (*data);
(*data) += 2;
B[0] = *(*data)++;
B[1] = *(*data)++;
if (!(P[0] & 0x8000)) {
/* need 18 more bytes */
CHECK_STREAM (len, 18 - 10);
P[2] = PIXEL (*data);
(*data) += 2;
P[3] = PIXEL (*data);
(*data) += 2;
B[2] = *(*data)++;
B[3] = *(*data)++;
P[4] = PIXEL (*data);
(*data) += 2;
P[5] = PIXEL (*data);
(*data) += 2;
B[4] = *(*data)++;
B[5] = *(*data)++;
P[6] = PIXEL (*data);
(*data) += 2;
P[7] = PIXEL (*data);
(*data) += 2;
B[6] = *(*data)++;
B[7] = *(*data)++;
flags =
((B[0] & 0xF0) << 4) | ((B[4] & 0xF0) << 8) |
((B[0] & 0x0F)) | ((B[4] & 0x0F) << 4) |
((B[1] & 0xF0) << 20) | ((B[5] & 0xF0) << 24) |
((B[1] & 0x0F) << 16) | ((B[5] & 0x0F) << 20);
bitmask = 0x00000001;
lower_half = 0; /* still on top half */
for (y = 0; y < 8; ++y) {
/* time to reload flags? */
if (y == 4) {
flags =
((B[2] & 0xF0) << 4) | ((B[6] & 0xF0) << 8) |
((B[2] & 0x0F)) | ((B[6] & 0x0F) << 4) |
((B[3] & 0xF0) << 20) | ((B[7] & 0xF0) << 24) |
((B[3] & 0x0F) << 16) | ((B[7] & 0x0F) << 20);
bitmask = 0x00000001;
lower_half = 2;
}
/* get the pixel values ready for this quadrant */
P0 = P[lower_half + 0];
P1 = P[lower_half + 1];
for (x = 0; x < 8; ++x, bitmask <<= 1) {
if (x == 4) {
P0 = P[lower_half + 4];
P1 = P[lower_half + 5];
}
if (flags & bitmask)
*frame++ = P1;
else
*frame++ = P0;
}
frame += s->width - 8;
}
} else {
P[0] &= ~0x8000;
/* need 10 more bytes */
B[2] = *(*data)++;
B[3] = *(*data)++;
P[2] = PIXEL (*data);
(*data) += 2;
P[3] = PIXEL (*data);
(*data) += 2;
B[4] = *(*data)++;
B[5] = *(*data)++;
B[6] = *(*data)++;
B[7] = *(*data)++;
if (!(P[2] & 0x8000)) {
/* vertical split; left & right halves are 2-color encoded */
flags =
((B[0] & 0xF0) << 4) | ((B[4] & 0xF0) << 8) |
((B[0] & 0x0F)) | ((B[4] & 0x0F) << 4) |
((B[1] & 0xF0) << 20) | ((B[5] & 0xF0) << 24) |
((B[1] & 0x0F) << 16) | ((B[5] & 0x0F) << 20);
bitmask = 0x00000001;
for (y = 0; y < 8; ++y) {
/* time to reload flags? */
if (y == 4) {
flags =
((B[2] & 0xF0) << 4) | ((B[6] & 0xF0) << 8) |
((B[2] & 0x0F)) | ((B[6] & 0x0F) << 4) |
((B[3] & 0xF0) << 20) | ((B[7] & 0xF0) << 24) |
((B[3] & 0x0F) << 16) | ((B[7] & 0x0F) << 20);
bitmask = 0x00000001;
}
/* get the pixel values ready for this half */
P0 = P[0];
P1 = P[1];
for (x = 0; x < 8; ++x, bitmask <<= 1) {
if (x == 4) {
P0 = P[2];
P1 = P[3];
}
if (flags & bitmask)
*frame++ = P1;
else
*frame++ = P0;
}
frame += s->width - 8;
}
} else {
/* horizontal split; top & bottom halves are 2-color encoded */
P0 = P[0];
P1 = P[1];
for (y = 0; y < 8; ++y) {
flags = B[y];
if (y == 4) {
P0 = P[2] & ~0x8000;
P1 = P[3];
}
for (bitmask = 0x01; bitmask <= 0x80; bitmask <<= 1) {
if (flags & bitmask)
*frame++ = P1;
else
*frame++ = P0;
}
frame += s->width - 8;
}
}
}
return 0;
}
static int
ipvideo_decode_0x9 (const GstMveDemuxStream * s, unsigned short *frame,
const unsigned char **data, unsigned short *len)
{
int x, y;
unsigned short P[4];
unsigned char B[4];
unsigned int flags = 0;
int shifter = 0;
unsigned short pix;
/* 4-color encoding */
CHECK_STREAM (len, 8 + 4);
P[0] = PIXEL (*data);
(*data) += 2;
P[1] = PIXEL (*data);
(*data) += 2;
P[2] = PIXEL (*data);
(*data) += 2;
P[3] = PIXEL (*data);
(*data) += 2;
if (!(P[0] & 0x8000) && !(P[2] & 0x8000)) {
/* 1 of 4 colors for each pixel, need 16 more bytes */
CHECK_STREAM (len, 16 - 4);
for (y = 0; y < 8; ++y) {
/* get the next set of 8 2-bit flags */
flags = ((*data)[1] << 8) | (*data)[0];
(*data) += 2;
for (x = 0, shifter = 0; x < 8; ++x, shifter += 2) {
*frame++ = P[(flags >> shifter) & 0x03];
}
frame += s->width - 8;
}
} else if (!(P[0] & 0x8000) && (P[2] & 0x8000)) {
P[2] &= ~0x8000;
/* 1 of 4 colors for each 2x2 block, need 4 more bytes */
B[0] = *(*data)++;
B[1] = *(*data)++;
B[2] = *(*data)++;
B[3] = *(*data)++;
flags = (B[3] << 24) | (B[2] << 16) | (B[1] << 8) | B[0];
shifter = 0;
for (y = 0; y < 8; y += 2) {
for (x = 0; x < 8; x += 2, shifter += 2) {
pix = P[(flags >> shifter) & 0x03];
*(frame + x) = pix;
*(frame + x + 1) = pix;
*(frame + s->width + x) = pix;
*(frame + s->width + x + 1) = pix;
}
frame += s->width * 2;
}
} else if ((P[0] & 0x8000) && !(P[2] & 0x8000)) {
P[0] &= ~0x8000;
/* 1 of 4 colors for each 2x1 block, need 8 more bytes */
CHECK_STREAM (len, 8 - 4);
for (y = 0; y < 8; ++y) {
/* time to reload flags? */
if ((y == 0) || (y == 4)) {
B[0] = *(*data)++;
B[1] = *(*data)++;
B[2] = *(*data)++;
B[3] = *(*data)++;
flags = (B[3] << 24) | (B[2] << 16) | (B[1] << 8) | B[0];
shifter = 0;
}
for (x = 0; x < 8; x += 2, shifter += 2) {
pix = P[(flags >> shifter) & 0x03];
*(frame + x) = pix;
*(frame + x + 1) = pix;
}
frame += s->width;
}
} else {
P[0] &= ~0x8000;
P[2] &= ~0x8000;
/* 1 of 4 colors for each 1x2 block, need 8 more bytes */
CHECK_STREAM (len, 8 - 4);
for (y = 0; y < 8; y += 2) {
/* time to reload flags? */
if ((y == 0) || (y == 4)) {
B[0] = *(*data)++;
B[1] = *(*data)++;
B[2] = *(*data)++;
B[3] = *(*data)++;
flags = (B[3] << 24) | (B[2] << 16) | (B[1] << 8) | B[0];
shifter = 0;
}
for (x = 0; x < 8; ++x, shifter += 2) {
pix = P[(flags >> shifter) & 0x03];
*(frame + x) = pix;
*(frame + s->width + x) = pix;
}
frame += s->width * 2;
}
}
return 0;
}
static int
ipvideo_decode_0xa (const GstMveDemuxStream * s, unsigned short *frame,
const unsigned char **data, unsigned short *len)
{
int x, y;
unsigned short P[16];
unsigned char B[16];
int flags = 0;
int shifter = 0;
int index;
int split;
int lower_half;
/* 4-color encoding for each 4x4 quadrant, or 4-color encoding on
* either top and bottom or left and right halves */
CHECK_STREAM (len, 8 + 24);
P[0] = PIXEL (*data);
(*data) += 2;
P[1] = PIXEL (*data);
(*data) += 2;
P[2] = PIXEL (*data);
(*data) += 2;
P[3] = PIXEL (*data);
(*data) += 2;
if (!(P[0] & 0x8000)) {
/* 4-color encoding for each quadrant; need 40 more bytes */
CHECK_STREAM (len, 40 - 24);
B[0] = *(*data)++;
B[1] = *(*data)++;
B[2] = *(*data)++;
B[3] = *(*data)++;
for (y = 4; y < 16; y += 4) {
for (x = y; x < y + 4; ++x) {
P[x] = PIXEL (*data);
(*data) += 2;
}
for (x = y; x < y + 4; ++x)
B[x] = *(*data)++;
}
for (y = 0; y < 8; ++y) {
lower_half = (y >= 4) ? 4 : 0;
flags = (B[y + 8] << 8) | B[y];
for (x = 0, shifter = 0; x < 8; ++x, shifter += 2) {
split = (x >= 4) ? 8 : 0;
index = split + lower_half + ((flags >> shifter) & 0x03);
*frame++ = P[index];
}
frame += s->width - 8;
}
} else {
P[0] &= ~0x8000;
/* 4-color encoding for either left and right or top and bottom
* halves; need 24 more bytes */
memcpy (&B[0], *data, 8);
(*data) += 8;
P[4] = PIXEL (*data);
(*data) += 2;
P[5] = PIXEL (*data);
(*data) += 2;
P[6] = PIXEL (*data);
(*data) += 2;
P[7] = PIXEL (*data);
(*data) += 2;
memcpy (&B[8], *data, 8);
(*data) += 8;
if (!(P[4] & 0x8000)) {
/* block is divided into left and right halves */
for (y = 0; y < 8; ++y) {
flags = (B[y + 8] << 8) | B[y];
split = 0;
for (x = 0, shifter = 0; x < 8; ++x, shifter += 2) {
if (x == 4)
split = 4;
*frame++ = P[split + ((flags >> shifter) & 0x03)];
}
frame += s->width - 8;
}
} else {
P[4] &= ~0x8000;
/* block is divided into top and bottom halves */
split = 0;
for (y = 0; y < 8; ++y) {
flags = (B[y * 2 + 1] << 8) | B[y * 2];
if (y == 4)
split = 4;
for (x = 0, shifter = 0; x < 8; ++x, shifter += 2)
*frame++ = P[split + ((flags >> shifter) & 0x03)];
frame += s->width - 8;
}
}
}
return 0;
}
static int
ipvideo_decode_0xb (const GstMveDemuxStream * s, unsigned short *frame,
const unsigned char **data, unsigned short *len)
{
int x, y;
/* 64-color encoding (each pixel in block is a different color) */
CHECK_STREAM (len, 128);
for (y = 0; y < 8; ++y) {
for (x = 0; x < 8; ++x) {
*frame++ = PIXEL (*data);
(*data) += 2;
}
frame += s->width - 8;
}
return 0;
}
static int
ipvideo_decode_0xc (const GstMveDemuxStream * s, unsigned short *frame,
const unsigned char **data, unsigned short *len)
{
int x, y;
unsigned short pix;
/* 16-color block encoding: each 2x2 block is a different color */
CHECK_STREAM (len, 32);
for (y = 0; y < 8; y += 2) {
for (x = 0; x < 8; x += 2) {
pix = PIXEL (*data);
(*data) += 2;
*(frame + x) = pix;
*(frame + x + 1) = pix;
*(frame + s->width + x) = pix;
*(frame + s->width + x + 1) = pix;
}
frame += s->width * 2;
}
return 0;
}
static int
ipvideo_decode_0xd (const GstMveDemuxStream * s, unsigned short *frame,
const unsigned char **data, unsigned short *len)
{
int x, y;
unsigned short P[4];
unsigned char index = 0;
/* 4-color block encoding: each 4x4 block is a different color */
CHECK_STREAM (len, 8);
P[0] = PIXEL (*data);
(*data) += 2;
P[1] = PIXEL (*data);
(*data) += 2;
P[2] = PIXEL (*data);
(*data) += 2;
P[3] = PIXEL (*data);
(*data) += 2;
for (y = 0; y < 8; ++y) {
if (y < 4)
index = 0;
else
index = 2;
for (x = 0; x < 8; ++x) {
if (x == 4)
++index;
*frame++ = P[index];
}
frame += s->width - 8;
}
return 0;
}
static int
ipvideo_decode_0xe (const GstMveDemuxStream * s, unsigned short *frame,
const unsigned char **data, unsigned short *len)
{
int x, y;
unsigned short pix;
/* 1-color encoding: the whole block is 1 solid color */
CHECK_STREAM (len, 2);
pix = PIXEL (*data);
(*data) += 2;
for (y = 0; y < 8; ++y) {
for (x = 0; x < 8; ++x) {
*frame++ = pix;
}
frame += s->width - 8;
}
return 0;
}
static int
ipvideo_decode_0xf (const GstMveDemuxStream * s, unsigned short *frame,
const unsigned char **data, unsigned short *len)
{
int x, y;
unsigned short P[2];
/* dithered encoding */
CHECK_STREAM (len, 4);
P[0] = PIXEL (*data);
(*data) += 2;
P[1] = PIXEL (*data);
(*data) += 2;
for (y = 0; y < 8; ++y) {
for (x = 0; x < 4; ++x) {
*frame++ = P[y & 1];
*frame++ = P[(y & 1) ^ 1];
}
frame += s->width - 8;
}
return 0;
}
int
ipvideo_decode_frame16 (const GstMveDemuxStream * s, const unsigned char *data,
unsigned short len)
{
int rc = 0;
int x, y, xx, yy;
int index = 0;
unsigned short offset;
unsigned char opcode;
unsigned short *frame;
const unsigned char *data2;
unsigned short len2;
CHECK_STREAM (&len, 2);
offset = (data[1] << 8) | data[0];
data2 = data + offset;
len2 = len - offset + 2;
data += 2;
frame = (unsigned short *) s->back_buf1;
/* decoding is done in 8x8 blocks */
xx = s->width >> 3;
yy = s->height >> 3;
for (y = 0; y < yy; ++y) {
for (x = 0; x < xx; ++x) {
/* decoding map contains 4 bits of information per 8x8 block */
/* bottom nibble first, then top nibble */
if (index & 1)
opcode = s->code_map[index >> 1] >> 4;
else
opcode = s->code_map[index >> 1] & 0x0F;
++index;
/* GST_DEBUG ("block @ (%3d, %3d): encoding 0x%X, data ptr @ %p",
x, y, opcode, data); */
switch (opcode) {
case 0x0:
/* copy a block from the previous frame */
rc = ipvideo_copy_block (s, frame, frame +
((unsigned short *) s->back_buf2 -
(unsigned short *) s->back_buf1), 0);
break;
case 0x1:
/* copy block from 2 frames ago; since we switched the back
* buffers we don't actually have to do anything here */
break;
case 0x2:
rc = ipvideo_decode_0x2 (s, frame, &data2, &len2);
break;
case 0x3:
rc = ipvideo_decode_0x3 (s, frame, &data2, &len2);
break;
case 0x4:
rc = ipvideo_decode_0x4 (s, frame, &data2, &len2);
break;
case 0x5:
rc = ipvideo_decode_0x5 (s, frame, &data, &len);
break;
case 0x6:
/* mystery opcode? skip multiple blocks? */
GST_WARNING ("encountered unsupported opcode 0x6");
rc = -1;
break;
case 0x7:
rc = ipvideo_decode_0x7 (s, frame, &data, &len);
break;
case 0x8:
rc = ipvideo_decode_0x8 (s, frame, &data, &len);
break;
case 0x9:
rc = ipvideo_decode_0x9 (s, frame, &data, &len);
break;
case 0xa:
rc = ipvideo_decode_0xa (s, frame, &data, &len);
break;
case 0xb:
rc = ipvideo_decode_0xb (s, frame, &data, &len);
break;
case 0xc:
rc = ipvideo_decode_0xc (s, frame, &data, &len);
break;
case 0xd:
rc = ipvideo_decode_0xd (s, frame, &data, &len);
break;
case 0xe:
rc = ipvideo_decode_0xe (s, frame, &data, &len);
break;
case 0xf:
rc = ipvideo_decode_0xf (s, frame, &data, &len);
break;
}
if (rc != 0)
return rc;
frame += 8;
}
frame += 7 * s->width;
}
return 0;
}

View file

@ -1,802 +0,0 @@
/*
* Interplay MVE Video Decoder (8 bit)
* Copyright (C) 2003 the ffmpeg project, Mike Melanson
* (C) 2006 Jens Granseuer
*
* 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 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* For more information about the Interplay MVE format, visit:
* http://www.pcisys.net/~melanson/codecs/interplay-mve.txt
*/
#include "gstmvedemux.h"
#include <string.h>
#define CHECK_STREAM(l, n) \
do { \
if (G_UNLIKELY (*(l) < (n))) { \
GST_ERROR ("wanted to read %d bytes from stream, %d available", (n), *(l)); \
return -1; \
} \
*(l) -= (n); \
} while (0)
/* copy an 8x8 block from the stream to the frame buffer */
static int
ipvideo_copy_block (const GstMveDemuxStream * s, unsigned char *frame,
const unsigned char *src, int offset)
{
int i;
long frame_offset;
frame_offset = frame - s->back_buf1 + offset;
if (G_UNLIKELY (frame_offset < 0)) {
GST_ERROR ("frame offset < 0 (%ld)", frame_offset);
return -1;
} else if (G_UNLIKELY (frame_offset > s->max_block_offset)) {
GST_ERROR ("frame offset above limit (%ld > %u)",
frame_offset, s->max_block_offset);
return -1;
}
for (i = 0; i < 8; ++i) {
memcpy (frame, src, 8);
frame += s->width;
src += s->width;
}
return 0;
}
static int
ipvideo_decode_0x2 (const GstMveDemuxStream * s, unsigned char *frame,
const unsigned char **data, unsigned short *len)
{
unsigned char B;
int x, y;
int offset;
/* copy block from 2 frames ago using a motion vector */
CHECK_STREAM (len, 1);
B = *(*data)++;
if (B < 56) {
x = 8 + (B % 7);
y = B / 7;
} else {
x = -14 + ((B - 56) % 29);
y = 8 + ((B - 56) / 29);
}
offset = y * s->width + x;
return ipvideo_copy_block (s, frame, frame + offset, offset);
}
static int
ipvideo_decode_0x3 (const GstMveDemuxStream * s, unsigned char *frame,
const unsigned char **data, unsigned short *len)
{
unsigned char B;
int x, y;
int offset;
/* copy 8x8 block from current frame from an up/left block */
CHECK_STREAM (len, 1);
B = *(*data)++;
if (B < 56) {
x = -(8 + (B % 7));
y = -(B / 7);
} else {
x = -(-14 + ((B - 56) % 29));
y = -(8 + ((B - 56) / 29));
}
offset = y * s->width + x;
return ipvideo_copy_block (s, frame, frame + offset, offset);
}
static int
ipvideo_decode_0x4 (const GstMveDemuxStream * s, unsigned char *frame,
const unsigned char **data, unsigned short *len)
{
unsigned char B;
int x, y;
int offset;
/* copy a block from the previous frame */
CHECK_STREAM (len, 1);
B = *(*data)++;
x = -8 + (B & 0x0F);
y = -8 + (B >> 4);
offset = y * s->width + x;
return ipvideo_copy_block (s, frame,
frame + (s->back_buf2 - s->back_buf1) + offset, offset);
}
static int
ipvideo_decode_0x5 (const GstMveDemuxStream * s, unsigned char *frame,
const unsigned char **data, unsigned short *len)
{
signed char x, y;
int offset;
/* copy a block from the previous frame using an expanded range */
CHECK_STREAM (len, 2);
x = (signed char) *(*data)++;
y = (signed char) *(*data)++;
offset = y * s->width + x;
return ipvideo_copy_block (s, frame,
frame + (s->back_buf2 - s->back_buf1) + offset, offset);
}
static int
ipvideo_decode_0x7 (const GstMveDemuxStream * s, unsigned char *frame,
const unsigned char **data, unsigned short *len)
{
int x, y;
unsigned char P0, P1;
unsigned int flags;
int bitmask;
/* 2-color encoding */
CHECK_STREAM (len, 2 + 2);
P0 = *(*data)++;
P1 = *(*data)++;
if (P0 <= P1) {
/* need 8 more bytes from the stream */
CHECK_STREAM (len, 8 - 2);
for (y = 0; y < 8; ++y) {
flags = *(*data)++;
for (x = 0x01; x <= 0x80; x <<= 1) {
if (flags & x)
*frame++ = P1;
else
*frame++ = P0;
}
frame += s->width - 8;
}
} else {
/* need 2 more bytes from the stream */
flags = ((*data)[1] << 8) | (*data)[0];
(*data) += 2;
bitmask = 0x0001;
for (y = 0; y < 8; y += 2) {
for (x = 0; x < 8; x += 2, bitmask <<= 1) {
if (flags & bitmask) {
*(frame + x) = P1;
*(frame + x + 1) = P1;
*(frame + s->width + x) = P1;
*(frame + s->width + x + 1) = P1;
} else {
*(frame + x) = P0;
*(frame + x + 1) = P0;
*(frame + s->width + x) = P0;
*(frame + s->width + x + 1) = P0;
}
}
frame += s->width * 2;
}
}
return 0;
}
static int
ipvideo_decode_0x8 (const GstMveDemuxStream * s, unsigned char *frame,
const unsigned char **data, unsigned short *len)
{
int x, y;
unsigned char P[8];
unsigned char B[8];
unsigned int flags = 0;
unsigned int bitmask = 0;
unsigned char P0 = 0, P1 = 0;
int lower_half = 0;
/* 2-color encoding for each 4x4 quadrant, or 2-color encoding on
* either top and bottom or left and right halves */
CHECK_STREAM (len, 4 + 8);
P[0] = (*data)[0];
P[1] = (*data)[1];
B[0] = (*data)[2];
B[1] = (*data)[3];
(*data) += 4;
if (P[0] <= P[1]) {
/* need 12 more bytes */
CHECK_STREAM (len, 12 - 8);
P[2] = (*data)[0];
P[3] = (*data)[1];
B[2] = (*data)[2];
B[3] = (*data)[3];
P[4] = (*data)[4];
P[5] = (*data)[5];
B[4] = (*data)[6];
B[5] = (*data)[7];
P[6] = (*data)[8];
P[7] = (*data)[9];
B[6] = (*data)[10];
B[7] = (*data)[11];
(*data) += 12;
flags =
((B[0] & 0xF0) << 4) | ((B[4] & 0xF0) << 8) |
((B[0] & 0x0F)) | ((B[4] & 0x0F) << 4) |
((B[1] & 0xF0) << 20) | ((B[5] & 0xF0) << 24) |
((B[1] & 0x0F) << 16) | ((B[5] & 0x0F) << 20);
bitmask = 0x00000001;
lower_half = 0; /* still on top half */
for (y = 0; y < 8; ++y) {
/* time to reload flags? */
if (y == 4) {
flags =
((B[2] & 0xF0) << 4) | ((B[6] & 0xF0) << 8) |
((B[2] & 0x0F)) | ((B[6] & 0x0F) << 4) |
((B[3] & 0xF0) << 20) | ((B[7] & 0xF0) << 24) |
((B[3] & 0x0F) << 16) | ((B[7] & 0x0F) << 20);
bitmask = 0x00000001;
lower_half = 2;
}
/* get the pixel values ready for this quadrant */
P0 = P[lower_half + 0];
P1 = P[lower_half + 1];
for (x = 0; x < 8; ++x, bitmask <<= 1) {
if (x == 4) {
P0 = P[lower_half + 4];
P1 = P[lower_half + 5];
}
if (flags & bitmask)
*frame++ = P1;
else
*frame++ = P0;
}
frame += s->width - 8;
}
} else {
/* need 8 more bytes */
B[2] = (*data)[0];
B[3] = (*data)[1];
P[2] = (*data)[2];
P[3] = (*data)[3];
B[4] = (*data)[4];
B[5] = (*data)[5];
B[6] = (*data)[6];
B[7] = (*data)[7];
(*data) += 8;
if (P[2] <= P[3]) {
/* vertical split; left & right halves are 2-color encoded */
flags =
((B[0] & 0xF0) << 4) | ((B[4] & 0xF0) << 8) |
((B[0] & 0x0F)) | ((B[4] & 0x0F) << 4) |
((B[1] & 0xF0) << 20) | ((B[5] & 0xF0) << 24) |
((B[1] & 0x0F) << 16) | ((B[5] & 0x0F) << 20);
bitmask = 0x00000001;
for (y = 0; y < 8; ++y) {
/* time to reload flags? */
if (y == 4) {
flags =
((B[2] & 0xF0) << 4) | ((B[6] & 0xF0) << 8) |
((B[2] & 0x0F)) | ((B[6] & 0x0F) << 4) |
((B[3] & 0xF0) << 20) | ((B[7] & 0xF0) << 24) |
((B[3] & 0x0F) << 16) | ((B[7] & 0x0F) << 20);
bitmask = 0x00000001;
}
/* get the pixel values ready for this half */
P0 = P[0];
P1 = P[1];
for (x = 0; x < 8; ++x, bitmask <<= 1) {
if (x == 4) {
P0 = P[2];
P1 = P[3];
}
if (flags & bitmask)
*frame++ = P1;
else
*frame++ = P0;
}
frame += s->width - 8;
}
} else {
/* horizontal split; top & bottom halves are 2-color encoded */
P0 = P[0];
P1 = P[1];
for (y = 0; y < 8; ++y) {
flags = B[y];
if (y == 4) {
P0 = P[2];
P1 = P[3];
}
for (bitmask = 0x01; bitmask <= 0x80; bitmask <<= 1) {
if (flags & bitmask)
*frame++ = P1;
else
*frame++ = P0;
}
frame += s->width - 8;
}
}
}
return 0;
}
static int
ipvideo_decode_0x9 (const GstMveDemuxStream * s, unsigned char *frame,
const unsigned char **data, unsigned short *len)
{
int x, y;
unsigned char P[4];
unsigned char B[4];
unsigned long flags = 0;
int shifter = 0;
unsigned char pix;
/* 4-color encoding */
CHECK_STREAM (len, 4 + 4);
P[0] = (*data)[0];
P[1] = (*data)[1];
P[2] = (*data)[2];
P[3] = (*data)[3];
(*data) += 4;
if ((P[0] <= P[1]) && (P[2] <= P[3])) {
/* 1 of 4 colors for each pixel, need 16 more bytes */
CHECK_STREAM (len, 16 - 4);
for (y = 0; y < 8; ++y) {
/* get the next set of 8 2-bit flags */
flags = ((*data)[1] << 8) | (*data)[0];
(*data) += 2;
for (x = 0, shifter = 0; x < 8; ++x, shifter += 2) {
*frame++ = P[(flags >> shifter) & 0x03];
}
frame += s->width - 8;
}
} else if ((P[0] <= P[1]) && (P[2] > P[3])) {
/* 1 of 4 colors for each 2x2 block, need 4 more bytes */
B[0] = (*data)[0];
B[1] = (*data)[1];
B[2] = (*data)[2];
B[3] = (*data)[3];
(*data) += 4;
flags = (B[3] << 24) | (B[2] << 16) | (B[1] << 8) | B[0];
shifter = 0;
for (y = 0; y < 8; y += 2) {
for (x = 0; x < 8; x += 2, shifter += 2) {
pix = P[(flags >> shifter) & 0x03];
*(frame + x) = pix;
*(frame + x + 1) = pix;
*(frame + s->width + x) = pix;
*(frame + s->width + x + 1) = pix;
}
frame += s->width * 2;
}
} else if ((P[0] > P[1]) && (P[2] <= P[3])) {
/* 1 of 4 colors for each 2x1 block, need 8 more bytes */
CHECK_STREAM (len, 8 - 4);
for (y = 0; y < 8; ++y) {
/* time to reload flags? */
if ((y == 0) || (y == 4)) {
B[0] = (*data)[0];
B[1] = (*data)[1];
B[2] = (*data)[2];
B[3] = (*data)[3];
(*data) += 4;
flags = (B[3] << 24) | (B[2] << 16) | (B[1] << 8) | B[0];
shifter = 0;
}
for (x = 0; x < 8; x += 2, shifter += 2) {
pix = P[(flags >> shifter) & 0x03];
*(frame + x) = pix;
*(frame + x + 1) = pix;
}
frame += s->width;
}
} else {
/* 1 of 4 colors for each 1x2 block, need 8 more bytes */
CHECK_STREAM (len, 8 - 4);
for (y = 0; y < 8; y += 2) {
/* time to reload flags? */
if ((y == 0) || (y == 4)) {
B[0] = (*data)[0];
B[1] = (*data)[1];
B[2] = (*data)[2];
B[3] = (*data)[3];
(*data) += 4;
flags = (B[3] << 24) | (B[2] << 16) | (B[1] << 8) | B[0];
shifter = 0;
}
for (x = 0; x < 8; ++x, shifter += 2) {
pix = P[(flags >> shifter) & 0x03];
*(frame + x) = pix;
*(frame + s->width + x) = pix;
}
frame += s->width * 2;
}
}
return 0;
}
static int
ipvideo_decode_0xa (const GstMveDemuxStream * s, unsigned char *frame,
const unsigned char **data, unsigned short *len)
{
int x, y;
unsigned char P[16];
unsigned char B[16];
int flags = 0;
int shifter = 0;
int index;
int split;
int lower_half;
/* 4-color encoding for each 4x4 quadrant, or 4-color encoding on
* either top and bottom or left and right halves */
CHECK_STREAM (len, 8 + 16);
P[0] = (*data)[0];
P[1] = (*data)[1];
P[2] = (*data)[2];
P[3] = (*data)[3];
B[0] = (*data)[4];
B[1] = (*data)[5];
B[2] = (*data)[6];
B[3] = (*data)[7];
(*data) += 8;
if (P[0] <= P[1]) {
/* 4-color encoding for each quadrant; need 24 more bytes */
CHECK_STREAM (len, 24 - 16);
for (y = 4; y < 16; y += 4) {
for (x = y; x < y + 4; ++x)
P[x] = *(*data)++;
for (x = y; x < y + 4; ++x)
B[x] = *(*data)++;
}
for (y = 0; y < 8; ++y) {
lower_half = (y >= 4) ? 4 : 0;
flags = (B[y + 8] << 8) | B[y];
for (x = 0, shifter = 0; x < 8; ++x, shifter += 2) {
split = (x >= 4) ? 8 : 0;
index = split + lower_half + ((flags >> shifter) & 0x03);
*frame++ = P[index];
}
frame += s->width - 8;
}
} else {
/* 4-color encoding for either left and right or top and bottom
* halves; need 16 more bytes */
B[4] = (*data)[0];
B[5] = (*data)[1];
B[6] = (*data)[2];
B[7] = (*data)[3];
P[4] = (*data)[4];
P[5] = (*data)[5];
P[6] = (*data)[6];
P[7] = (*data)[7];
(*data) += 8;
memcpy (&B[8], *data, 8);
(*data) += 8;
if (P[4] <= P[5]) {
/* block is divided into left and right halves */
for (y = 0; y < 8; ++y) {
flags = (B[y + 8] << 8) | B[y];
split = 0;
for (x = 0, shifter = 0; x < 8; ++x, shifter += 2) {
if (x == 4)
split = 4;
*frame++ = P[split + ((flags >> shifter) & 0x03)];
}
frame += s->width - 8;
}
} else {
/* block is divided into top and bottom halves */
split = 0;
for (y = 0; y < 8; ++y) {
flags = (B[y * 2 + 1] << 8) | B[y * 2];
if (y == 4)
split = 4;
for (x = 0, shifter = 0; x < 8; ++x, shifter += 2)
*frame++ = P[split + ((flags >> shifter) & 0x03)];
frame += s->width - 8;
}
}
}
return 0;
}
static int
ipvideo_decode_0xb (const GstMveDemuxStream * s, unsigned char *frame,
const unsigned char **data, unsigned short *len)
{
int y;
/* 64-color encoding (each pixel in block is a different color) */
CHECK_STREAM (len, 64);
for (y = 0; y < 8; ++y) {
memcpy (frame, *data, 8);
frame += s->width;
(*data) += 8;
}
return 0;
}
static int
ipvideo_decode_0xc (const GstMveDemuxStream * s, unsigned char *frame,
const unsigned char **data, unsigned short *len)
{
int x, y;
unsigned char pix;
/* 16-color block encoding: each 2x2 block is a different color */
CHECK_STREAM (len, 16);
for (y = 0; y < 8; y += 2) {
for (x = 0; x < 8; x += 2) {
pix = *(*data)++;
*(frame + x) = pix;
*(frame + x + 1) = pix;
*(frame + s->width + x) = pix;
*(frame + s->width + x + 1) = pix;
}
frame += s->width * 2;
}
return 0;
}
static int
ipvideo_decode_0xd (const GstMveDemuxStream * s, unsigned char *frame,
const unsigned char **data, unsigned short *len)
{
int x, y;
unsigned char P[4];
unsigned char index = 0;
/* 4-color block encoding: each 4x4 block is a different color */
CHECK_STREAM (len, 4);
P[0] = (*data)[0];
P[1] = (*data)[1];
P[2] = (*data)[2];
P[3] = (*data)[3];
(*data) += 4;
for (y = 0; y < 8; ++y) {
if (y < 4)
index = 0;
else
index = 2;
for (x = 0; x < 8; ++x) {
if (x == 4)
++index;
*frame++ = P[index];
}
frame += s->width - 8;
}
return 0;
}
static int
ipvideo_decode_0xe (const GstMveDemuxStream * s, unsigned char *frame,
const unsigned char **data, unsigned short *len)
{
int y;
unsigned char pix;
/* 1-color encoding: the whole block is 1 solid color */
CHECK_STREAM (len, 1);
pix = *(*data)++;
for (y = 0; y < 8; ++y) {
memset (frame, pix, 8);
frame += s->width;
}
return 0;
}
static int
ipvideo_decode_0xf (const GstMveDemuxStream * s, unsigned char *frame,
const unsigned char **data, unsigned short *len)
{
int x, y;
unsigned char P[2];
/* dithered encoding */
CHECK_STREAM (len, 2);
P[0] = *(*data)++;
P[1] = *(*data)++;
for (y = 0; y < 8; ++y) {
for (x = 0; x < 4; ++x) {
*frame++ = P[y & 1];
*frame++ = P[(y & 1) ^ 1];
}
frame += s->width - 8;
}
return 0;
}
int
ipvideo_decode_frame8 (const GstMveDemuxStream * s, const unsigned char *data,
unsigned short len)
{
int rc = 0;
int x, y, xx, yy;
int index = 0;
unsigned char opcode;
unsigned char *frame;
frame = s->back_buf1;
/* decoding is done in 8x8 blocks */
xx = s->width >> 3;
yy = s->height >> 3;
for (y = 0; y < yy; ++y) {
for (x = 0; x < xx; ++x) {
/* decoding map contains 4 bits of information per 8x8 block */
/* bottom nibble first, then top nibble */
if (index & 1)
opcode = s->code_map[index >> 1] >> 4;
else
opcode = s->code_map[index >> 1] & 0x0F;
++index;
/* GST_DEBUG ("block @ (%3d, %3d): encoding 0x%X, data ptr @ %p",
x, y, opcode, data); */
switch (opcode) {
case 0x00:
/* copy a block from the previous frame */
rc = ipvideo_copy_block (s, frame,
frame + (s->back_buf2 - s->back_buf1), 0);
break;
case 0x01:
/* copy block from 2 frames ago; since we switched the back
* buffers we don't actually have to do anything here */
break;
case 0x02:
rc = ipvideo_decode_0x2 (s, frame, &data, &len);
break;
case 0x03:
rc = ipvideo_decode_0x3 (s, frame, &data, &len);
break;
case 0x04:
rc = ipvideo_decode_0x4 (s, frame, &data, &len);
break;
case 0x05:
rc = ipvideo_decode_0x5 (s, frame, &data, &len);
break;
case 0x06:
/* mystery opcode? skip multiple blocks? */
GST_WARNING ("encountered unsupported opcode 0x6");
rc = -1;
break;
case 0x07:
rc = ipvideo_decode_0x7 (s, frame, &data, &len);
break;
case 0x08:
rc = ipvideo_decode_0x8 (s, frame, &data, &len);
break;
case 0x09:
rc = ipvideo_decode_0x9 (s, frame, &data, &len);
break;
case 0x0a:
rc = ipvideo_decode_0xa (s, frame, &data, &len);
break;
case 0x0b:
rc = ipvideo_decode_0xb (s, frame, &data, &len);
break;
case 0x0c:
rc = ipvideo_decode_0xc (s, frame, &data, &len);
break;
case 0x0d:
rc = ipvideo_decode_0xd (s, frame, &data, &len);
break;
case 0x0e:
rc = ipvideo_decode_0xe (s, frame, &data, &len);
break;
case 0x0f:
rc = ipvideo_decode_0xf (s, frame, &data, &len);
break;
}
if (rc != 0)
return rc;
frame += 8;
}
frame += 7 * s->width;
}
return 0;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,10 +0,0 @@
plugin_LTLIBRARIES = libgstnuvdemux.la
libgstnuvdemux_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_CFLAGS)
libgstnuvdemux_la_LIBADD = $(GST_BASE_LIBS)
libgstnuvdemux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstnuvdemux_la_SOURCES = gstnuvdemux.c
libgstnuvdemux_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
noinst_HEADERS = gstnuvdemux.h

Some files were not shown because too many files have changed in this diff Show more