mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 16:50:47 +00:00
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:
parent
0fdd4e2539
commit
9b5de05399
225 changed files with 15 additions and 56120 deletions
|
@ -94,9 +94,6 @@
|
||||||
/* Define to enable Android Media (used by androidmedia). */
|
/* Define to enable Android Media (used by androidmedia). */
|
||||||
#mesondefine HAVE_ANDROID_MEDIA
|
#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). */
|
/* Define to enable Apple video (used by applemedia). */
|
||||||
#mesondefine HAVE_APPLE_MEDIA
|
#mesondefine HAVE_APPLE_MEDIA
|
||||||
|
|
||||||
|
@ -229,12 +226,6 @@
|
||||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||||
#mesondefine HAVE_FCNTL_H
|
#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). */
|
/* Define to enable Flite plugin (used by flite). */
|
||||||
#mesondefine HAVE_FLITE
|
#mesondefine HAVE_FLITE
|
||||||
|
|
||||||
|
@ -322,12 +313,6 @@
|
||||||
/* Define if libusb 1.x is installed */
|
/* Define if libusb 1.x is installed */
|
||||||
#mesondefine HAVE_LIBUSB
|
#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 */
|
/* Define if we have liblrdf */
|
||||||
#mesondefine HAVE_LRDF
|
#mesondefine HAVE_LRDF
|
||||||
|
|
||||||
|
@ -364,9 +349,6 @@
|
||||||
/* Define to enable MythTV client plugins (used by mythtvsrc). */
|
/* Define to enable MythTV client plugins (used by mythtvsrc). */
|
||||||
#mesondefine HAVE_MYTHTV
|
#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). */
|
/* Define to enable neon http client plugins (used by neonhttpsrc). */
|
||||||
#mesondefine HAVE_NEON
|
#mesondefine HAVE_NEON
|
||||||
|
|
||||||
|
@ -454,9 +436,6 @@
|
||||||
/* Define to enable Schroedinger video codec (used by schro). */
|
/* Define to enable Schroedinger video codec (used by schro). */
|
||||||
#mesondefine HAVE_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). */
|
/* Define to enable POSIX shared memory source and sink (used by shm). */
|
||||||
#mesondefine HAVE_SHM
|
#mesondefine HAVE_SHM
|
||||||
|
|
||||||
|
@ -466,9 +445,6 @@
|
||||||
/* Define to enable sndfile plug-in (used by sfdec sfenc). */
|
/* Define to enable sndfile plug-in (used by sfdec sfenc). */
|
||||||
#mesondefine HAVE_SNDFILE
|
#mesondefine HAVE_SNDFILE
|
||||||
|
|
||||||
/* Define to enable sndio audio (used by sndio). */
|
|
||||||
#mesondefine HAVE_SNDIO
|
|
||||||
|
|
||||||
/* Define to enable soundtouch plug-in (used by soundtouch). */
|
/* Define to enable soundtouch plug-in (used by soundtouch). */
|
||||||
#mesondefine HAVE_SOUNDTOUCH
|
#mesondefine HAVE_SOUNDTOUCH
|
||||||
|
|
||||||
|
@ -523,9 +499,6 @@
|
||||||
/* Define if libtiger is available */
|
/* Define if libtiger is available */
|
||||||
#mesondefine HAVE_TIGER
|
#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. */
|
/* Define to 1 if you have the <unistd.h> header file. */
|
||||||
#mesondefine HAVE_UNISTD_H
|
#mesondefine HAVE_UNISTD_H
|
||||||
|
|
||||||
|
@ -574,12 +547,6 @@
|
||||||
/* Define to 1 if you have the <windows.h> header file. */
|
/* Define to 1 if you have the <windows.h> header file. */
|
||||||
#mesondefine HAVE_WINDOWS_H
|
#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). */
|
/* Define to enable Winks plug-in (used by winks). */
|
||||||
#mesondefine HAVE_WINKS
|
#mesondefine HAVE_WINKS
|
||||||
|
|
||||||
|
@ -595,9 +562,6 @@
|
||||||
/* Define if you have X11 library */
|
/* Define if you have X11 library */
|
||||||
#mesondefine HAVE_X11
|
#mesondefine HAVE_X11
|
||||||
|
|
||||||
/* Define to enable xvid plugins (used by xvid). */
|
|
||||||
#mesondefine HAVE_XVID
|
|
||||||
|
|
||||||
/* Define to enable ZBar barcode detector (used by zbar). */
|
/* Define to enable ZBar barcode detector (used by zbar). */
|
||||||
#mesondefine HAVE_ZBAR
|
#mesondefine HAVE_ZBAR
|
||||||
|
|
||||||
|
@ -607,9 +571,6 @@
|
||||||
/* library dir */
|
/* library dir */
|
||||||
#mesondefine LIBDIR
|
#mesondefine LIBDIR
|
||||||
|
|
||||||
/* directory in which the detected libvisual's plugins are located */
|
|
||||||
#mesondefine LIBVISUAL_PLUGINSBASEDIR
|
|
||||||
|
|
||||||
/* gettext locale dir */
|
/* gettext locale dir */
|
||||||
#mesondefine LOCALEDIR
|
#mesondefine LOCALEDIR
|
||||||
|
|
||||||
|
@ -668,9 +629,6 @@
|
||||||
/* the target CPU */
|
/* the target CPU */
|
||||||
#mesondefine TARGET_CPU
|
#mesondefine TARGET_CPU
|
||||||
|
|
||||||
/* Define location of timidity.cfg */
|
|
||||||
#mesondefine TIMIDITY_CFG
|
|
||||||
|
|
||||||
/* Use Mali FB EGL platform */
|
/* Use Mali FB EGL platform */
|
||||||
#mesondefine USE_EGL_MALI_FB
|
#mesondefine USE_EGL_MALI_FB
|
||||||
|
|
||||||
|
|
232
configure.ac
232
configure.ac
|
@ -164,16 +164,8 @@ AX_CREATE_STDINT_H
|
||||||
AC_CHECK_HEADERS([pthread.h], HAVE_PTHREAD_H=yes)
|
AC_CHECK_HEADERS([pthread.h], HAVE_PTHREAD_H=yes)
|
||||||
AM_CONDITIONAL(HAVE_PTHREAD_H, test "x$HAVE_PTHREAD_H" = "xyes")
|
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 *** 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 structures ***
|
||||||
|
|
||||||
dnl *** checks for compiler characteristics ***
|
dnl *** checks for compiler characteristics ***
|
||||||
|
@ -467,21 +459,6 @@ dnl used in examples
|
||||||
AG_GST_DEFAULT_ELEMENTS
|
AG_GST_DEFAULT_ELEMENTS
|
||||||
|
|
||||||
dnl *** plug-ins to include ***
|
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
|
dnl these are all the gst plug-ins, compilable without additional libs
|
||||||
AG_GST_CHECK_PLUGIN(accurip)
|
AG_GST_CHECK_PLUGIN(accurip)
|
||||||
|
@ -498,13 +475,10 @@ AG_GST_CHECK_PLUGIN(audiovisualizers)
|
||||||
AG_GST_CHECK_PLUGIN(autoconvert)
|
AG_GST_CHECK_PLUGIN(autoconvert)
|
||||||
AG_GST_CHECK_PLUGIN(bayer)
|
AG_GST_CHECK_PLUGIN(bayer)
|
||||||
AG_GST_CHECK_PLUGIN(camerabin2)
|
AG_GST_CHECK_PLUGIN(camerabin2)
|
||||||
AG_GST_CHECK_PLUGIN(cdxaparse)
|
|
||||||
AG_GST_CHECK_PLUGIN(coloreffects)
|
AG_GST_CHECK_PLUGIN(coloreffects)
|
||||||
AG_GST_CHECK_PLUGIN(dccp)
|
|
||||||
AG_GST_CHECK_PLUGIN(debugutils)
|
AG_GST_CHECK_PLUGIN(debugutils)
|
||||||
AG_GST_CHECK_PLUGIN(dvbsuboverlay)
|
AG_GST_CHECK_PLUGIN(dvbsuboverlay)
|
||||||
AG_GST_CHECK_PLUGIN(dvdspu)
|
AG_GST_CHECK_PLUGIN(dvdspu)
|
||||||
AG_GST_CHECK_PLUGIN(faceoverlay)
|
|
||||||
AG_GST_CHECK_PLUGIN(festival)
|
AG_GST_CHECK_PLUGIN(festival)
|
||||||
AG_GST_CHECK_PLUGIN(fieldanalysis)
|
AG_GST_CHECK_PLUGIN(fieldanalysis)
|
||||||
AG_GST_CHECK_PLUGIN(freeverb)
|
AG_GST_CHECK_PLUGIN(freeverb)
|
||||||
|
@ -512,7 +486,6 @@ AG_GST_CHECK_PLUGIN(frei0r)
|
||||||
AG_GST_CHECK_PLUGIN(gaudieffects)
|
AG_GST_CHECK_PLUGIN(gaudieffects)
|
||||||
AG_GST_CHECK_PLUGIN(geometrictransform)
|
AG_GST_CHECK_PLUGIN(geometrictransform)
|
||||||
AG_GST_CHECK_PLUGIN(gdp)
|
AG_GST_CHECK_PLUGIN(gdp)
|
||||||
AG_GST_CHECK_PLUGIN(hdvparse)
|
|
||||||
AG_GST_CHECK_PLUGIN(id3tag)
|
AG_GST_CHECK_PLUGIN(id3tag)
|
||||||
AG_GST_CHECK_PLUGIN(inter)
|
AG_GST_CHECK_PLUGIN(inter)
|
||||||
AG_GST_CHECK_PLUGIN(interlace)
|
AG_GST_CHECK_PLUGIN(interlace)
|
||||||
|
@ -526,17 +499,13 @@ AG_GST_CHECK_PLUGIN(mpegdemux)
|
||||||
AG_GST_CHECK_PLUGIN(mpegtsdemux)
|
AG_GST_CHECK_PLUGIN(mpegtsdemux)
|
||||||
AG_GST_CHECK_PLUGIN(mpegtsmux)
|
AG_GST_CHECK_PLUGIN(mpegtsmux)
|
||||||
AG_GST_CHECK_PLUGIN(mpegpsmux)
|
AG_GST_CHECK_PLUGIN(mpegpsmux)
|
||||||
AG_GST_CHECK_PLUGIN(mve)
|
|
||||||
AG_GST_CHECK_PLUGIN(mxf)
|
AG_GST_CHECK_PLUGIN(mxf)
|
||||||
AG_GST_CHECK_PLUGIN(netsim)
|
AG_GST_CHECK_PLUGIN(netsim)
|
||||||
AG_GST_CHECK_PLUGIN(nuvdemux)
|
|
||||||
AG_GST_CHECK_PLUGIN(onvif)
|
AG_GST_CHECK_PLUGIN(onvif)
|
||||||
AG_GST_CHECK_PLUGIN(patchdetect)
|
|
||||||
AG_GST_CHECK_PLUGIN(pcapparse)
|
AG_GST_CHECK_PLUGIN(pcapparse)
|
||||||
AG_GST_CHECK_PLUGIN(pnm)
|
AG_GST_CHECK_PLUGIN(pnm)
|
||||||
AG_GST_CHECK_PLUGIN(rawparse)
|
AG_GST_CHECK_PLUGIN(rawparse)
|
||||||
AG_GST_CHECK_PLUGIN(removesilence)
|
AG_GST_CHECK_PLUGIN(removesilence)
|
||||||
AG_GST_CHECK_PLUGIN(sdi)
|
|
||||||
AG_GST_CHECK_PLUGIN(sdp)
|
AG_GST_CHECK_PLUGIN(sdp)
|
||||||
AG_GST_CHECK_PLUGIN(segmentclip)
|
AG_GST_CHECK_PLUGIN(segmentclip)
|
||||||
AG_GST_CHECK_PLUGIN(siren)
|
AG_GST_CHECK_PLUGIN(siren)
|
||||||
|
@ -545,7 +514,6 @@ AG_GST_CHECK_PLUGIN(speed)
|
||||||
AG_GST_CHECK_PLUGIN(subenc)
|
AG_GST_CHECK_PLUGIN(subenc)
|
||||||
AG_GST_CHECK_PLUGIN(stereo)
|
AG_GST_CHECK_PLUGIN(stereo)
|
||||||
AG_GST_CHECK_PLUGIN(timecode)
|
AG_GST_CHECK_PLUGIN(timecode)
|
||||||
AG_GST_CHECK_PLUGIN(tta)
|
|
||||||
AG_GST_CHECK_PLUGIN(videofilters)
|
AG_GST_CHECK_PLUGIN(videofilters)
|
||||||
AG_GST_CHECK_PLUGIN(videoparsers)
|
AG_GST_CHECK_PLUGIN(videoparsers)
|
||||||
AG_GST_CHECK_PLUGIN(videosignal)
|
AG_GST_CHECK_PLUGIN(videosignal)
|
||||||
|
@ -600,13 +568,6 @@ if test "x$HAVE_WINSOCK2_H" = "xyes"; then
|
||||||
AC_SUBST(WINSOCK2_LIBS)
|
AC_SUBST(WINSOCK2_LIBS)
|
||||||
fi
|
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 ***
|
dnl *** opengl ***
|
||||||
AC_ARG_ENABLE([opengl],
|
AC_ARG_ENABLE([opengl],
|
||||||
[ --enable-opengl Enable Desktop OpenGL support @<:@default=auto@:>@],
|
[ --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)
|
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 ***
|
dnl *** bs2b ***
|
||||||
translit(dnm, m, l) AM_CONDITIONAL(USE_BS2B, true)
|
translit(dnm, m, l) AM_CONDITIONAL(USE_BS2B, true)
|
||||||
AG_GST_CHECK_FEATURE(BS2B, [bs2b], bs2b, [
|
AG_GST_CHECK_FEATURE(BS2B, [bs2b], bs2b, [
|
||||||
|
@ -2525,19 +2468,6 @@ AG_GST_CHECK_FEATURE(TTML, [TTML plugin], ttml, [
|
||||||
fi
|
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 ***
|
dnl *** modplug ***
|
||||||
translit(dnm, m, l) AM_CONDITIONAL(USE_MODPLUG, true)
|
translit(dnm, m, l) AM_CONDITIONAL(USE_MODPLUG, true)
|
||||||
AG_GST_CHECK_FEATURE(MODPLUG, modplug, modplug, [
|
AG_GST_CHECK_FEATURE(MODPLUG, modplug, modplug, [
|
||||||
|
@ -2745,21 +2675,6 @@ AG_GST_CHECK_FEATURE(MUSEPACK, [musepackdec], musepack, [
|
||||||
], [HAVE_MUSEPACK="no"])])
|
], [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 ***
|
dnl *** neon ***
|
||||||
translit(dnm, m, l) AM_CONDITIONAL(USE_NEON, true)
|
translit(dnm, m, l) AM_CONDITIONAL(USE_NEON, true)
|
||||||
AG_GST_CHECK_FEATURE(NEON, [neon http client plugins], neonhttpsrc, [
|
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)
|
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 ***
|
dnl *** rsvg ***
|
||||||
translit(dnm, m, l) AM_CONDITIONAL(USE_RSVG, true)
|
translit(dnm, m, l) AM_CONDITIONAL(USE_RSVG, true)
|
||||||
AG_GST_CHECK_FEATURE(RSVG, [rsvg decoder], rsvg, [
|
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 ***
|
dnl *** teletextdec ***
|
||||||
translit(dnm, m, l) AM_CONDITIONAL(USE_TELETEXTDEC, true)
|
translit(dnm, m, l) AM_CONDITIONAL(USE_TELETEXTDEC, true)
|
||||||
AG_GST_CHECK_FEATURE(TELETEXTDEC, [Teletext decoder], teletextdec, [
|
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)
|
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 ****
|
dnl **** Smooth Streaming ****
|
||||||
translit(dnm, m, l) AM_CONDITIONAL(USE_SMOOTHSTREAMING, true)
|
translit(dnm, m, l) AM_CONDITIONAL(USE_SMOOTHSTREAMING, true)
|
||||||
AG_GST_CHECK_FEATURE(SMOOTHSTREAMING, [Smooth Streaming plug-in], smoothstreaming, [
|
AG_GST_CHECK_FEATURE(SMOOTHSTREAMING, [Smooth Streaming plug-in], smoothstreaming, [
|
||||||
|
@ -3247,36 +3098,6 @@ AG_GST_CHECK_FEATURE(GME, [gme decoder], gme, [
|
||||||
fi
|
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 ***
|
dnl *** dvb ***
|
||||||
translit(dnm, m, l) AM_CONDITIONAL(USE_DVB, true)
|
translit(dnm, m, l) AM_CONDITIONAL(USE_DVB, true)
|
||||||
AG_GST_CHECK_FEATURE(DVB, [DVB Source], dvb, [
|
AG_GST_CHECK_FEATURE(DVB, [DVB Source], dvb, [
|
||||||
|
@ -3295,16 +3116,6 @@ AG_GST_CHECK_FEATURE(DVB, [DVB Source], dvb, [
|
||||||
], [HAVE_DVB="no"])
|
], [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 ***
|
dnl *** acm ***
|
||||||
translit(dnm, m, l) AM_CONDITIONAL(USE_ACM, true)
|
translit(dnm, m, l) AM_CONDITIONAL(USE_ACM, true)
|
||||||
AG_GST_CHECK_FEATURE(ACM, [Windows ACM library], acm, [
|
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_CFLAGS)
|
||||||
AC_SUBST(SPANDSP_LIBS)
|
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 ***
|
dnl *** hls-crypto ***
|
||||||
AC_ARG_WITH([hls-crypto],
|
AC_ARG_WITH([hls-crypto],
|
||||||
AS_HELP_STRING([--with-hls-crypto=auto|nettle|libgcrypt|openssl], [
|
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_ASSRENDER, false)
|
||||||
AM_CONDITIONAL(USE_VOAMRWBENC, false)
|
AM_CONDITIONAL(USE_VOAMRWBENC, false)
|
||||||
AM_CONDITIONAL(USE_VOAACENC, false)
|
AM_CONDITIONAL(USE_VOAACENC, false)
|
||||||
AM_CONDITIONAL(USE_APEXSINK, false)
|
|
||||||
AM_CONDITIONAL(USE_BS2B, false)
|
AM_CONDITIONAL(USE_BS2B, false)
|
||||||
AM_CONDITIONAL(USE_BZ2, false)
|
AM_CONDITIONAL(USE_BZ2, false)
|
||||||
AM_CONDITIONAL(USE_CHROMAPRINT, false)
|
AM_CONDITIONAL(USE_CHROMAPRINT, false)
|
||||||
|
@ -3544,12 +3341,10 @@ AM_CONDITIONAL(USE_LADSPA, false)
|
||||||
AM_CONDITIONAL(USE_LV2, false)
|
AM_CONDITIONAL(USE_LV2, false)
|
||||||
AM_CONDITIONAL(USE_LIBDE265, false)
|
AM_CONDITIONAL(USE_LIBDE265, false)
|
||||||
AM_CONDITIONAL(USE_LIBMMS, false)
|
AM_CONDITIONAL(USE_LIBMMS, false)
|
||||||
AM_CONDITIONAL(USE_LINSYS, false)
|
|
||||||
AM_CONDITIONAL(USE_MODPLUG, false)
|
AM_CONDITIONAL(USE_MODPLUG, false)
|
||||||
AM_CONDITIONAL(USE_MPEG2ENC, false)
|
AM_CONDITIONAL(USE_MPEG2ENC, false)
|
||||||
AM_CONDITIONAL(USE_MPLEX, false)
|
AM_CONDITIONAL(USE_MPLEX, false)
|
||||||
AM_CONDITIONAL(USE_MUSEPACK, false)
|
AM_CONDITIONAL(USE_MUSEPACK, false)
|
||||||
AM_CONDITIONAL(USE_NAS, false)
|
|
||||||
AM_CONDITIONAL(USE_NEON, false)
|
AM_CONDITIONAL(USE_NEON, false)
|
||||||
AM_CONDITIONAL(USE_OFA, false)
|
AM_CONDITIONAL(USE_OFA, false)
|
||||||
AM_CONDITIONAL(USE_OPENAL, false)
|
AM_CONDITIONAL(USE_OPENAL, false)
|
||||||
|
@ -3558,12 +3353,8 @@ AM_CONDITIONAL(USE_OPENEXR, false)
|
||||||
AM_CONDITIONAL(USE_OPENJPEG, false)
|
AM_CONDITIONAL(USE_OPENJPEG, false)
|
||||||
AM_CONDITIONAL(USE_OPENNI2, false)
|
AM_CONDITIONAL(USE_OPENNI2, false)
|
||||||
AM_CONDITIONAL(USE_OPUS, false)
|
AM_CONDITIONAL(USE_OPUS, false)
|
||||||
AM_CONDITIONAL(USE_PVR, false)
|
|
||||||
AM_CONDITIONAL(USE_QT, false)
|
AM_CONDITIONAL(USE_QT, false)
|
||||||
AM_CONDITIONAL(USE_LIBVISUAL, false)
|
|
||||||
AM_CONDITIONAL(USE_TIMIDITY, false)
|
|
||||||
AM_CONDITIONAL(USE_WILDMIDI, false)
|
AM_CONDITIONAL(USE_WILDMIDI, false)
|
||||||
AM_CONDITIONAL(USE_SDL, false)
|
|
||||||
AM_CONDITIONAL(USE_SMOOTHSTREAMING, false)
|
AM_CONDITIONAL(USE_SMOOTHSTREAMING, false)
|
||||||
AM_CONDITIONAL(USE_SNDFILE, false)
|
AM_CONDITIONAL(USE_SNDFILE, false)
|
||||||
AM_CONDITIONAL(USE_SOUNDTOUCH, false)
|
AM_CONDITIONAL(USE_SOUNDTOUCH, false)
|
||||||
|
@ -3571,9 +3362,7 @@ AM_CONDITIONAL(USE_SPANDSP, false)
|
||||||
AM_CONDITIONAL(USE_SPC, false)
|
AM_CONDITIONAL(USE_SPC, false)
|
||||||
AM_CONDITIONAL(USE_SRTP, false)
|
AM_CONDITIONAL(USE_SRTP, false)
|
||||||
AM_CONDITIONAL(USE_GME, false)
|
AM_CONDITIONAL(USE_GME, false)
|
||||||
AM_CONDITIONAL(USE_XVID, false)
|
|
||||||
AM_CONDITIONAL(USE_DVB, false)
|
AM_CONDITIONAL(USE_DVB, false)
|
||||||
AM_CONDITIONAL(USE_WININET, false)
|
|
||||||
AM_CONDITIONAL(USE_ACM, false)
|
AM_CONDITIONAL(USE_ACM, false)
|
||||||
AM_CONDITIONAL(USE_VDPAU, false)
|
AM_CONDITIONAL(USE_VDPAU, false)
|
||||||
AM_CONDITIONAL(USE_SBC, false)
|
AM_CONDITIONAL(USE_SBC, false)
|
||||||
|
@ -3582,7 +3371,6 @@ AM_CONDITIONAL(USE_ZBAR, false)
|
||||||
AM_CONDITIONAL(USE_RSVG, false)
|
AM_CONDITIONAL(USE_RSVG, false)
|
||||||
AM_CONDITIONAL(USE_RTMP, false)
|
AM_CONDITIONAL(USE_RTMP, false)
|
||||||
AM_CONDITIONAL(USE_TELETEXTDEC, false)
|
AM_CONDITIONAL(USE_TELETEXTDEC, false)
|
||||||
AM_CONDITIONAL(USE_SNDIO, false)
|
|
||||||
AM_CONDITIONAL(USE_UVCH264, false)
|
AM_CONDITIONAL(USE_UVCH264, false)
|
||||||
AM_CONDITIONAL(USE_WEBP, false)
|
AM_CONDITIONAL(USE_WEBP, false)
|
||||||
AM_CONDITIONAL(USE_WEBRTCDSP, false)
|
AM_CONDITIONAL(USE_WEBRTCDSP, false)
|
||||||
|
@ -3690,13 +3478,10 @@ gst/audiovisualizers/Makefile
|
||||||
gst/autoconvert/Makefile
|
gst/autoconvert/Makefile
|
||||||
gst/bayer/Makefile
|
gst/bayer/Makefile
|
||||||
gst/camerabin2/Makefile
|
gst/camerabin2/Makefile
|
||||||
gst/cdxaparse/Makefile
|
|
||||||
gst/coloreffects/Makefile
|
gst/coloreffects/Makefile
|
||||||
gst/dccp/Makefile
|
|
||||||
gst/debugutils/Makefile
|
gst/debugutils/Makefile
|
||||||
gst/dvbsuboverlay/Makefile
|
gst/dvbsuboverlay/Makefile
|
||||||
gst/dvdspu/Makefile
|
gst/dvdspu/Makefile
|
||||||
gst/faceoverlay/Makefile
|
|
||||||
gst/festival/Makefile
|
gst/festival/Makefile
|
||||||
gst/fieldanalysis/Makefile
|
gst/fieldanalysis/Makefile
|
||||||
gst/freeverb/Makefile
|
gst/freeverb/Makefile
|
||||||
|
@ -3704,7 +3489,6 @@ gst/frei0r/Makefile
|
||||||
gst/gaudieffects/Makefile
|
gst/gaudieffects/Makefile
|
||||||
gst/geometrictransform/Makefile
|
gst/geometrictransform/Makefile
|
||||||
gst/gdp/Makefile
|
gst/gdp/Makefile
|
||||||
gst/hdvparse/Makefile
|
|
||||||
gst/id3tag/Makefile
|
gst/id3tag/Makefile
|
||||||
gst/inter/Makefile
|
gst/inter/Makefile
|
||||||
gst/interlace/Makefile
|
gst/interlace/Makefile
|
||||||
|
@ -3719,17 +3503,13 @@ gst/mpegtsdemux/Makefile
|
||||||
gst/mpegtsmux/Makefile
|
gst/mpegtsmux/Makefile
|
||||||
gst/mpegtsmux/tsmux/Makefile
|
gst/mpegtsmux/tsmux/Makefile
|
||||||
gst/mpegpsmux/Makefile
|
gst/mpegpsmux/Makefile
|
||||||
gst/mve/Makefile
|
|
||||||
gst/mxf/Makefile
|
gst/mxf/Makefile
|
||||||
gst/netsim/Makefile
|
gst/netsim/Makefile
|
||||||
gst/nuvdemux/Makefile
|
|
||||||
gst/onvif/Makefile
|
gst/onvif/Makefile
|
||||||
gst/patchdetect/Makefile
|
|
||||||
gst/pcapparse/Makefile
|
gst/pcapparse/Makefile
|
||||||
gst/pnm/Makefile
|
gst/pnm/Makefile
|
||||||
gst/rawparse/Makefile
|
gst/rawparse/Makefile
|
||||||
gst/removesilence/Makefile
|
gst/removesilence/Makefile
|
||||||
gst/sdi/Makefile
|
|
||||||
gst/sdp/Makefile
|
gst/sdp/Makefile
|
||||||
gst/segmentclip/Makefile
|
gst/segmentclip/Makefile
|
||||||
gst/siren/Makefile
|
gst/siren/Makefile
|
||||||
|
@ -3737,7 +3517,6 @@ gst/smooth/Makefile
|
||||||
gst/speed/Makefile
|
gst/speed/Makefile
|
||||||
gst/subenc/Makefile
|
gst/subenc/Makefile
|
||||||
gst/stereo/Makefile
|
gst/stereo/Makefile
|
||||||
gst/tta/Makefile
|
|
||||||
gst/timecode/Makefile
|
gst/timecode/Makefile
|
||||||
gst/videofilters/Makefile
|
gst/videofilters/Makefile
|
||||||
gst/videoparsers/Makefile
|
gst/videoparsers/Makefile
|
||||||
|
@ -3787,7 +3566,6 @@ sys/dshowvideosink/Makefile
|
||||||
sys/dvb/Makefile
|
sys/dvb/Makefile
|
||||||
sys/fbdev/Makefile
|
sys/fbdev/Makefile
|
||||||
sys/kms/Makefile
|
sys/kms/Makefile
|
||||||
sys/linsys/Makefile
|
|
||||||
sys/msdk/Makefile
|
sys/msdk/Makefile
|
||||||
sys/nvenc/Makefile
|
sys/nvenc/Makefile
|
||||||
sys/opensles/Makefile
|
sys/opensles/Makefile
|
||||||
|
@ -3796,9 +3574,7 @@ sys/tinyalsa/Makefile
|
||||||
sys/uvch264/Makefile
|
sys/uvch264/Makefile
|
||||||
sys/vcd/Makefile
|
sys/vcd/Makefile
|
||||||
sys/vdpau/Makefile
|
sys/vdpau/Makefile
|
||||||
sys/pvr2d/Makefile
|
|
||||||
sys/wasapi/Makefile
|
sys/wasapi/Makefile
|
||||||
sys/wininet/Makefile
|
|
||||||
sys/winks/Makefile
|
sys/winks/Makefile
|
||||||
sys/winscreencap/Makefile
|
sys/winscreencap/Makefile
|
||||||
tests/Makefile
|
tests/Makefile
|
||||||
|
@ -3835,7 +3611,6 @@ tests/icles/Makefile
|
||||||
ext/voamrwbenc/Makefile
|
ext/voamrwbenc/Makefile
|
||||||
ext/voaacenc/Makefile
|
ext/voaacenc/Makefile
|
||||||
ext/assrender/Makefile
|
ext/assrender/Makefile
|
||||||
ext/apexsink/Makefile
|
|
||||||
ext/bs2b/Makefile
|
ext/bs2b/Makefile
|
||||||
ext/bz2/Makefile
|
ext/bz2/Makefile
|
||||||
ext/chromaprint/Makefile
|
ext/chromaprint/Makefile
|
||||||
|
@ -3861,13 +3636,11 @@ ext/ladspa/Makefile
|
||||||
ext/lv2/Makefile
|
ext/lv2/Makefile
|
||||||
ext/libde265/Makefile
|
ext/libde265/Makefile
|
||||||
ext/libmms/Makefile
|
ext/libmms/Makefile
|
||||||
ext/libvisual/Makefile
|
|
||||||
ext/Makefile
|
ext/Makefile
|
||||||
ext/modplug/Makefile
|
ext/modplug/Makefile
|
||||||
ext/mpeg2enc/Makefile
|
ext/mpeg2enc/Makefile
|
||||||
ext/mplex/Makefile
|
ext/mplex/Makefile
|
||||||
ext/musepack/Makefile
|
ext/musepack/Makefile
|
||||||
ext/nas/Makefile
|
|
||||||
ext/neon/Makefile
|
ext/neon/Makefile
|
||||||
ext/ofa/Makefile
|
ext/ofa/Makefile
|
||||||
ext/openal/Makefile
|
ext/openal/Makefile
|
||||||
|
@ -3883,23 +3656,20 @@ ext/resindvd/Makefile
|
||||||
ext/rtmp/Makefile
|
ext/rtmp/Makefile
|
||||||
ext/sbc/Makefile
|
ext/sbc/Makefile
|
||||||
ext/schroedinger/Makefile
|
ext/schroedinger/Makefile
|
||||||
ext/sdl/Makefile
|
|
||||||
ext/smoothstreaming/Makefile
|
ext/smoothstreaming/Makefile
|
||||||
ext/sndfile/Makefile
|
ext/sndfile/Makefile
|
||||||
ext/soundtouch/Makefile
|
ext/soundtouch/Makefile
|
||||||
ext/spandsp/Makefile
|
ext/spandsp/Makefile
|
||||||
ext/sndio/Makefile
|
|
||||||
ext/srtp/Makefile
|
ext/srtp/Makefile
|
||||||
ext/teletextdec/Makefile
|
ext/teletextdec/Makefile
|
||||||
ext/gme/Makefile
|
ext/gme/Makefile
|
||||||
ext/spc/Makefile
|
ext/spc/Makefile
|
||||||
ext/timidity/Makefile
|
ext/wildmidi/Makefile
|
||||||
ext/vulkan/Makefile
|
ext/vulkan/Makefile
|
||||||
ext/vulkan/xcb/Makefile
|
ext/vulkan/xcb/Makefile
|
||||||
ext/vulkan/wayland/Makefile
|
ext/vulkan/wayland/Makefile
|
||||||
ext/webp/Makefile
|
ext/webp/Makefile
|
||||||
ext/x265/Makefile
|
ext/x265/Makefile
|
||||||
ext/xvid/Makefile
|
|
||||||
ext/zbar/Makefile
|
ext/zbar/Makefile
|
||||||
ext/dtls/Makefile
|
ext/dtls/Makefile
|
||||||
ext/webrtcdsp/Makefile
|
ext/webrtcdsp/Makefile
|
||||||
|
|
|
@ -103,10 +103,7 @@ EXTRA_HFILES = \
|
||||||
$(top_srcdir)/ext/rtmp/gstrtmpsink.h \
|
$(top_srcdir)/ext/rtmp/gstrtmpsink.h \
|
||||||
$(top_srcdir)/ext/spandsp/gstspanplc.h \
|
$(top_srcdir)/ext/spandsp/gstspanplc.h \
|
||||||
$(top_srcdir)/ext/spandsp/gstdtmfdetect.h \
|
$(top_srcdir)/ext/spandsp/gstdtmfdetect.h \
|
||||||
$(top_srcdir)/ext/sdl/sdlaudiosink.h \
|
$(top_srcdir)/ext/wildmidi/gstwildmidi.h \
|
||||||
$(top_srcdir)/ext/sdl/sdlvideosink.h \
|
|
||||||
$(top_srcdir)/ext/timidity/gsttimidity.h \
|
|
||||||
$(top_srcdir)/ext/timidity/gstwildmidi.h \
|
|
||||||
$(top_srcdir)/ext/voaacenc/gstvoaacenc.h \
|
$(top_srcdir)/ext/voaacenc/gstvoaacenc.h \
|
||||||
$(top_srcdir)/ext/voamrwbenc/gstvoamrwbenc.h \
|
$(top_srcdir)/ext/voamrwbenc/gstvoamrwbenc.h \
|
||||||
$(top_srcdir)/ext/webrtcdsp/gstwebrtcdsp.h \
|
$(top_srcdir)/ext/webrtcdsp/gstwebrtcdsp.h \
|
||||||
|
@ -121,10 +118,6 @@ EXTRA_HFILES = \
|
||||||
$(top_srcdir)/gst/audiovisualizers/gstwavescope.h \
|
$(top_srcdir)/gst/audiovisualizers/gstwavescope.h \
|
||||||
$(top_srcdir)/gst/camerabin2/gstcamerabin2.h \
|
$(top_srcdir)/gst/camerabin2/gstcamerabin2.h \
|
||||||
$(top_srcdir)/gst/coloreffects/gstcoloreffects.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/debugutils/fpsdisplaysink.h \
|
||||||
$(top_srcdir)/gst/dvdspu/gstdvdspu.h \
|
$(top_srcdir)/gst/dvdspu/gstdvdspu.h \
|
||||||
$(top_srcdir)/gst/festival/gstfestival.h \
|
$(top_srcdir)/gst/festival/gstfestival.h \
|
||||||
|
@ -156,7 +149,6 @@ EXTRA_HFILES = \
|
||||||
$(top_srcdir)/gst/mpegtsmux/mpegtsmux.h \
|
$(top_srcdir)/gst/mpegtsmux/mpegtsmux.h \
|
||||||
$(top_srcdir)/gst/mxf/mxfdemux.h \
|
$(top_srcdir)/gst/mxf/mxfdemux.h \
|
||||||
$(top_srcdir)/gst/mxf/mxfmux.h \
|
$(top_srcdir)/gst/mxf/mxfmux.h \
|
||||||
$(top_srcdir)/gst/nuvdemux/gstnuvdemux.h \
|
|
||||||
$(top_srcdir)/gst/pcapparse/gstpcapparse.h \
|
$(top_srcdir)/gst/pcapparse/gstpcapparse.h \
|
||||||
$(top_srcdir)/gst/rawparse/gstaudioparse.h \
|
$(top_srcdir)/gst/rawparse/gstaudioparse.h \
|
||||||
$(top_srcdir)/gst/rawparse/gstvideoparse.h \
|
$(top_srcdir)/gst/rawparse/gstvideoparse.h \
|
||||||
|
|
|
@ -835,62 +835,6 @@ GST_TYPE_DC1394
|
||||||
gst_dc1394_get_type
|
gst_dc1394_get_type
|
||||||
</SECTION>
|
</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>
|
<SECTION>
|
||||||
<FILE>element-debugspy</FILE>
|
<FILE>element-debugspy</FILE>
|
||||||
<TITLE>debugspy</TITLE>
|
<TITLE>debugspy</TITLE>
|
||||||
|
@ -2817,21 +2761,6 @@ GST_TYPE_NET_SIM
|
||||||
gst_net_sim_get_type
|
gst_net_sim_get_type
|
||||||
</SECTION>
|
</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>
|
<SECTION>
|
||||||
<FILE>element-neonhttpsrc</FILE>
|
<FILE>element-neonhttpsrc</FILE>
|
||||||
<TITLE>neonhttpsrc</TITLE>
|
<TITLE>neonhttpsrc</TITLE>
|
||||||
|
@ -3296,37 +3225,6 @@ GST_TYPE_RTP_ONVIF_TIMESTAMP
|
||||||
gst_rtp_onvif_timestamp_get_type
|
gst_rtp_onvif_timestamp_get_type
|
||||||
</SECTION>
|
</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>
|
<SECTION>
|
||||||
<FILE>element-sdpdemux</FILE>
|
<FILE>element-sdpdemux</FILE>
|
||||||
<TITLE>sdpdemux</TITLE>
|
<TITLE>sdpdemux</TITLE>
|
||||||
|
@ -3841,20 +3739,6 @@ GST_TYPE_TONE_GENERATE_SRC
|
||||||
gst_tone_generate_src_get_type
|
gst_tone_generate_src_get_type
|
||||||
</SECTION>
|
</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>
|
<SECTION>
|
||||||
<FILE>element-tunnel</FILE>
|
<FILE>element-tunnel</FILE>
|
||||||
<TITLE>tunnel</TITLE>
|
<TITLE>tunnel</TITLE>
|
||||||
|
|
|
@ -32,38 +32,6 @@ gint64 arg2
|
||||||
gint64 arg3
|
gint64 arg3
|
||||||
</SIGNAL>
|
</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>
|
<SIGNAL>
|
||||||
<NAME>GstCameraBin::img-done</NAME>
|
<NAME>GstCameraBin::img-done</NAME>
|
||||||
<RETURNS>gboolean</RETURNS>
|
<RETURNS>gboolean</RETURNS>
|
||||||
|
|
|
@ -10,12 +10,6 @@ else
|
||||||
VOAMRWBENC_DIR =
|
VOAMRWBENC_DIR =
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if USE_APEXSINK
|
|
||||||
APEXSINK_DIR = apexsink
|
|
||||||
else
|
|
||||||
APEXSINK_DIR =
|
|
||||||
endif
|
|
||||||
|
|
||||||
if USE_BS2B
|
if USE_BS2B
|
||||||
BS2B_DIR=bs2b
|
BS2B_DIR=bs2b
|
||||||
else
|
else
|
||||||
|
@ -178,12 +172,6 @@ else
|
||||||
LIBMMS_DIR=
|
LIBMMS_DIR=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if USE_LIBVISUAL
|
|
||||||
LIBVISUAL_DIR=libvisual
|
|
||||||
else
|
|
||||||
LIBVISUAL_DIR=
|
|
||||||
endif
|
|
||||||
|
|
||||||
if USE_MODPLUG
|
if USE_MODPLUG
|
||||||
MODPLUG_DIR=modplug
|
MODPLUG_DIR=modplug
|
||||||
else
|
else
|
||||||
|
@ -208,12 +196,6 @@ else
|
||||||
MUSEPACK_DIR=
|
MUSEPACK_DIR=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if USE_NAS
|
|
||||||
NAS_DIR=nas
|
|
||||||
else
|
|
||||||
NAS_DIR=
|
|
||||||
endif
|
|
||||||
|
|
||||||
if USE_NEON
|
if USE_NEON
|
||||||
NEON_DIR=neon
|
NEON_DIR=neon
|
||||||
else
|
else
|
||||||
|
@ -274,18 +256,12 @@ else
|
||||||
RSVG_DIR=
|
RSVG_DIR=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if USE_TIMIDITY
|
|
||||||
TIMIDITY_DIR=timidity
|
|
||||||
endif
|
|
||||||
|
|
||||||
if USE_WILDMIDI
|
if USE_WILDMIDI
|
||||||
TIMIDITY_DIR=timidity
|
WILDMIDI_DIR=wildmidi
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if !USE_WILDMIDI
|
if !USE_WILDMIDI
|
||||||
if !USE_TIMIDITY
|
WILDMIDI_DIR=
|
||||||
TIMIDITY_DIR=
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if USE_FLUIDSYNTH
|
if USE_FLUIDSYNTH
|
||||||
|
@ -304,12 +280,6 @@ else
|
||||||
SCHRO_DIR=
|
SCHRO_DIR=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if USE_SDL
|
|
||||||
SDL_DIR=sdl
|
|
||||||
else
|
|
||||||
SDL_DIR=
|
|
||||||
endif
|
|
||||||
|
|
||||||
if USE_SMOOTHSTREAMING
|
if USE_SMOOTHSTREAMING
|
||||||
SMOOTHSTREAMING_DIR = smoothstreaming
|
SMOOTHSTREAMING_DIR = smoothstreaming
|
||||||
else
|
else
|
||||||
|
@ -328,12 +298,6 @@ else
|
||||||
SNDFILE_DIR=
|
SNDFILE_DIR=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if USE_SNDIO
|
|
||||||
SNDIO_DIR = sndio
|
|
||||||
else
|
|
||||||
SNDIO_DIR =
|
|
||||||
endif
|
|
||||||
|
|
||||||
if USE_SOUNDTOUCH
|
if USE_SOUNDTOUCH
|
||||||
SOUNDTOUCH_DIR=soundtouch
|
SOUNDTOUCH_DIR=soundtouch
|
||||||
else
|
else
|
||||||
|
@ -370,12 +334,6 @@ else
|
||||||
TELETEXTDEC_DIR=
|
TELETEXTDEC_DIR=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if USE_XVID
|
|
||||||
XVID_DIR=xvid
|
|
||||||
else
|
|
||||||
XVID_DIR=
|
|
||||||
endif
|
|
||||||
|
|
||||||
if USE_ZBAR
|
if USE_ZBAR
|
||||||
ZBAR_DIR=zbar
|
ZBAR_DIR=zbar
|
||||||
else
|
else
|
||||||
|
@ -434,7 +392,6 @@ SUBDIRS=\
|
||||||
$(VOAACENC_DIR) \
|
$(VOAACENC_DIR) \
|
||||||
$(ASSRENDER_DIR) \
|
$(ASSRENDER_DIR) \
|
||||||
$(VOAMRWBENC_DIR) \
|
$(VOAMRWBENC_DIR) \
|
||||||
$(APEXSINK_DIR) \
|
|
||||||
$(AUDIOFILE_DIR) \
|
$(AUDIOFILE_DIR) \
|
||||||
$(BS2B_DIR) \
|
$(BS2B_DIR) \
|
||||||
$(BZ2_DIR) \
|
$(BZ2_DIR) \
|
||||||
|
@ -463,12 +420,10 @@ SUBDIRS=\
|
||||||
$(LV2_DIR) \
|
$(LV2_DIR) \
|
||||||
$(LIBDE265_DIR) \
|
$(LIBDE265_DIR) \
|
||||||
$(LIBMMS_DIR) \
|
$(LIBMMS_DIR) \
|
||||||
$(LIBVISUAL_DIR) \
|
|
||||||
$(MODPLUG_DIR) \
|
$(MODPLUG_DIR) \
|
||||||
$(MPEG2ENC_DIR) \
|
$(MPEG2ENC_DIR) \
|
||||||
$(MPLEX_DIR) \
|
$(MPLEX_DIR) \
|
||||||
$(MUSEPACK_DIR) \
|
$(MUSEPACK_DIR) \
|
||||||
$(NAS_DIR) \
|
|
||||||
$(NEON_DIR) \
|
$(NEON_DIR) \
|
||||||
$(OFA_DIR) \
|
$(OFA_DIR) \
|
||||||
$(OPENAL_DIR) \
|
$(OPENAL_DIR) \
|
||||||
|
@ -481,19 +436,16 @@ SUBDIRS=\
|
||||||
$(RSVG_DIR) \
|
$(RSVG_DIR) \
|
||||||
$(SBC_DIR) \
|
$(SBC_DIR) \
|
||||||
$(SCHRO_DIR) \
|
$(SCHRO_DIR) \
|
||||||
$(SDL_DIR) \
|
|
||||||
$(SMOOTHSTREAMING_DIR) \
|
$(SMOOTHSTREAMING_DIR) \
|
||||||
$(SMOOTHWAVE_DIR) \
|
$(SMOOTHWAVE_DIR) \
|
||||||
$(SNDFILE_DIR) \
|
$(SNDFILE_DIR) \
|
||||||
$(SNDIO_DIR) \
|
|
||||||
$(SOUNDTOUCH_DIR) \
|
$(SOUNDTOUCH_DIR) \
|
||||||
$(SPANDSP_DIR) \
|
$(SPANDSP_DIR) \
|
||||||
$(GME_DIR) \
|
$(GME_DIR) \
|
||||||
$(SPC_DIR) \
|
$(SPC_DIR) \
|
||||||
$(SRTP_DIR) \
|
$(SRTP_DIR) \
|
||||||
$(TELETEXTDEC_DIR) \
|
$(TELETEXTDEC_DIR) \
|
||||||
$(TIMIDITY_DIR) \
|
$(WILDMIDI_DIR) \
|
||||||
$(XVID_DIR) \
|
|
||||||
$(ZBAR_DIR) \
|
$(ZBAR_DIR) \
|
||||||
$(RTMP_DIR) \
|
$(RTMP_DIR) \
|
||||||
$(HLS_DIR) \
|
$(HLS_DIR) \
|
||||||
|
@ -506,7 +458,6 @@ SUBDIRS=\
|
||||||
|
|
||||||
DIST_SUBDIRS = \
|
DIST_SUBDIRS = \
|
||||||
assrender \
|
assrender \
|
||||||
apexsink \
|
|
||||||
bs2b \
|
bs2b \
|
||||||
bz2 \
|
bz2 \
|
||||||
chromaprint \
|
chromaprint \
|
||||||
|
@ -527,7 +478,6 @@ DIST_SUBDIRS = \
|
||||||
kate \
|
kate \
|
||||||
libde265 \
|
libde265 \
|
||||||
libmms \
|
libmms \
|
||||||
libvisual \
|
|
||||||
lv2 \
|
lv2 \
|
||||||
daala \
|
daala \
|
||||||
dts \
|
dts \
|
||||||
|
@ -538,7 +488,6 @@ DIST_SUBDIRS = \
|
||||||
mpeg2enc \
|
mpeg2enc \
|
||||||
mplex \
|
mplex \
|
||||||
musepack \
|
musepack \
|
||||||
nas \
|
|
||||||
neon \
|
neon \
|
||||||
ofa \
|
ofa \
|
||||||
openal \
|
openal \
|
||||||
|
@ -552,20 +501,17 @@ DIST_SUBDIRS = \
|
||||||
resindvd \
|
resindvd \
|
||||||
sbc \
|
sbc \
|
||||||
schroedinger \
|
schroedinger \
|
||||||
sdl \
|
|
||||||
smoothstreaming \
|
smoothstreaming \
|
||||||
sndfile \
|
sndfile \
|
||||||
sndio \
|
|
||||||
soundtouch \
|
soundtouch \
|
||||||
spandsp \
|
spandsp \
|
||||||
spc \
|
spc \
|
||||||
srtp \
|
srtp \
|
||||||
gme \
|
gme \
|
||||||
teletextdec \
|
teletextdec \
|
||||||
timidity \
|
wildmidi \
|
||||||
voaacenc \
|
voaacenc \
|
||||||
voamrwbenc \
|
voamrwbenc \
|
||||||
xvid \
|
|
||||||
zbar \
|
zbar \
|
||||||
rtmp \
|
rtmp \
|
||||||
webp \
|
webp \
|
||||||
|
|
|
@ -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.
|
|
|
@ -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
|
|
|
@ -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)
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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
|
@ -1,4 +1,3 @@
|
||||||
#subdir('apexsink')
|
|
||||||
subdir('assrender')
|
subdir('assrender')
|
||||||
#subdir('bs2b')
|
#subdir('bs2b')
|
||||||
subdir('bz2')
|
subdir('bz2')
|
||||||
|
@ -25,13 +24,11 @@ subdir('kate')
|
||||||
#subdir('ladspa')
|
#subdir('ladspa')
|
||||||
subdir('libde265')
|
subdir('libde265')
|
||||||
subdir('libmms')
|
subdir('libmms')
|
||||||
#subdir('libvisual')
|
|
||||||
#subdir('lv2')
|
#subdir('lv2')
|
||||||
#subdir('modplug')
|
#subdir('modplug')
|
||||||
#subdir('mpeg2enc')
|
#subdir('mpeg2enc')
|
||||||
#subdir('mplex')
|
#subdir('mplex')
|
||||||
#subdir('musepack')
|
#subdir('musepack')
|
||||||
#subdir('nas')
|
|
||||||
#subdir('neon')
|
#subdir('neon')
|
||||||
#subdir('ofa')
|
#subdir('ofa')
|
||||||
#subdir('openal')
|
#subdir('openal')
|
||||||
|
@ -41,16 +38,13 @@ subdir('openh264')
|
||||||
subdir('openjpeg')
|
subdir('openjpeg')
|
||||||
#subdir('openni2')
|
#subdir('openni2')
|
||||||
subdir('opus')
|
subdir('opus')
|
||||||
#subdir('qt')
|
|
||||||
subdir('resindvd')
|
subdir('resindvd')
|
||||||
subdir('rsvg')
|
subdir('rsvg')
|
||||||
subdir('rtmp')
|
subdir('rtmp')
|
||||||
subdir('sbc')
|
subdir('sbc')
|
||||||
subdir('schroedinger')
|
subdir('schroedinger')
|
||||||
#subdir('sdl')
|
|
||||||
subdir('smoothstreaming')
|
subdir('smoothstreaming')
|
||||||
#subdir('sndfile')
|
#subdir('sndfile')
|
||||||
#subdir('sndio')
|
|
||||||
if cc.get_id() != 'msvc'
|
if cc.get_id() != 'msvc'
|
||||||
# soundtouch doesn't do exporting of symbols for DLLs and I'm not sure how to
|
# soundtouch doesn't do exporting of symbols for DLLs and I'm not sure how to
|
||||||
# do that for C++ classes. -- Nirbheek
|
# do that for C++ classes. -- Nirbheek
|
||||||
|
@ -62,7 +56,7 @@ endif
|
||||||
#subdir('spc')
|
#subdir('spc')
|
||||||
subdir('srtp')
|
subdir('srtp')
|
||||||
#subdir('teletextdec')
|
#subdir('teletextdec')
|
||||||
#subdir('timidity')
|
#subdir('wildmidi')
|
||||||
subdir('ttml')
|
subdir('ttml')
|
||||||
subdir('voaacenc')
|
subdir('voaacenc')
|
||||||
#subdir('voamrwbenc')
|
#subdir('voamrwbenc')
|
||||||
|
@ -71,5 +65,4 @@ subdir('wayland')
|
||||||
#subdir('webrtcdsp')
|
#subdir('webrtcdsp')
|
||||||
subdir('webp')
|
subdir('webp')
|
||||||
subdir('x265')
|
subdir('x265')
|
||||||
#subdir('xvid')
|
|
||||||
subdir('zbar')
|
subdir('zbar')
|
||||||
|
|
|
@ -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
|
|
|
@ -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);
|
|
|
@ -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__ */
|
|
|
@ -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
|
|
|
@ -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)
|
|
|
@ -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
|
|
|
@ -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
|
@ -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__ */
|
|
|
@ -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 =
|
|
|
@ -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)
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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__ */
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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__ */
|
|
|
@ -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)
|
|
|
@ -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__ */
|
|
|
@ -1,20 +1,6 @@
|
||||||
# plugindir is set in configure
|
# plugindir is set in configure
|
||||||
plugin_LTLIBRARIES =
|
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
|
if USE_WILDMIDI
|
||||||
plugin_LTLIBRARIES += libgstwildmidi.la
|
plugin_LTLIBRARIES += libgstwildmidi.la
|
||||||
|
|
||||||
|
@ -29,5 +15,5 @@ libgstwildmidi_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||||
libgstwildmidi_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
|
libgstwildmidi_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
noinst_HEADERS = gsttimidity.h gstwildmidi.h
|
noinst_HEADERS = gstwildmidi.h
|
||||||
|
|
|
@ -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
|
|
|
@ -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)
|
|
|
@ -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__ */
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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
|
@ -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__ */
|
|
|
@ -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
|
@ -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,
|
|
||||||
)
|
|
|
@ -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)
|
|
|
@ -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)
|
|
|
@ -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__ */
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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__ */
|
|
||||||
|
|
|
@ -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,
|
|
||||||
)
|
|
|
@ -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
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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__ */
|
|
|
@ -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__ */
|
|
|
@ -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");
|
|
||||||
}
|
|
|
@ -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__ */
|
|
|
@ -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");
|
|
||||||
}
|
|
|
@ -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__ */
|
|
|
@ -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")
|
|
|
@ -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");
|
|
||||||
}
|
|
|
@ -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__ */
|
|
|
@ -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");
|
|
||||||
}
|
|
|
@ -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__ */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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,
|
|
||||||
)
|
|
|
@ -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
|
|
|
@ -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)
|
|
|
@ -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__ */
|
|
|
@ -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,
|
|
||||||
)
|
|
|
@ -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
|
|
|
@ -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)
|
|
|
@ -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);
|
|
|
@ -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__ */
|
|
|
@ -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,
|
|
||||||
)
|
|
|
@ -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)
|
|
|
@ -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/")
|
|
|
@ -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__ */
|
|
|
@ -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,
|
|
||||||
)
|
|
|
@ -3,8 +3,6 @@ subdir('adpcmdec')
|
||||||
subdir('adpcmenc')
|
subdir('adpcmenc')
|
||||||
subdir('aiff')
|
subdir('aiff')
|
||||||
subdir('asfmux')
|
subdir('asfmux')
|
||||||
# not ported to 1.0
|
|
||||||
#subdir('audiobuffer')
|
|
||||||
subdir('audiobuffersplit')
|
subdir('audiobuffersplit')
|
||||||
subdir('audiofxbad')
|
subdir('audiofxbad')
|
||||||
subdir('audiomixer')
|
subdir('audiomixer')
|
||||||
|
@ -12,28 +10,18 @@ subdir('audiovisualizers')
|
||||||
subdir('autoconvert')
|
subdir('autoconvert')
|
||||||
subdir('bayer')
|
subdir('bayer')
|
||||||
subdir('camerabin2')
|
subdir('camerabin2')
|
||||||
# did not work
|
|
||||||
#subdir('cdxaparse')
|
|
||||||
subdir('coloreffects')
|
subdir('coloreffects')
|
||||||
subdir('compositor')
|
subdir('compositor')
|
||||||
#did not work
|
|
||||||
#subdir('dccp')
|
|
||||||
subdir('debugutils')
|
subdir('debugutils')
|
||||||
subdir('dvbsuboverlay')
|
subdir('dvbsuboverlay')
|
||||||
subdir('dvdspu')
|
subdir('dvdspu')
|
||||||
# did not work
|
|
||||||
#subdir('faceoverlay')
|
|
||||||
subdir('festival')
|
subdir('festival')
|
||||||
subdir('fieldanalysis')
|
subdir('fieldanalysis')
|
||||||
subdir('freeverb')
|
subdir('freeverb')
|
||||||
subdir('frei0r')
|
subdir('frei0r')
|
||||||
# did not work
|
|
||||||
#subdir('games')
|
|
||||||
subdir('gaudieffects')
|
subdir('gaudieffects')
|
||||||
subdir('gdp')
|
subdir('gdp')
|
||||||
subdir('geometrictransform')
|
subdir('geometrictransform')
|
||||||
#did not work
|
|
||||||
#subdir('hdvparse')
|
|
||||||
subdir('id3tag')
|
subdir('id3tag')
|
||||||
subdir('inter')
|
subdir('inter')
|
||||||
subdir('interlace')
|
subdir('interlace')
|
||||||
|
@ -43,30 +31,16 @@ subdir('jp2kdecimator')
|
||||||
subdir('jpegformat')
|
subdir('jpegformat')
|
||||||
subdir('librfb')
|
subdir('librfb')
|
||||||
subdir('midi')
|
subdir('midi')
|
||||||
#did not work
|
|
||||||
#subdir('mixmatrix')
|
|
||||||
subdir('mpegdemux')
|
subdir('mpegdemux')
|
||||||
subdir('mpegpsmux')
|
subdir('mpegpsmux')
|
||||||
subdir('mpegtsdemux')
|
subdir('mpegtsdemux')
|
||||||
subdir('mpegtsmux')
|
subdir('mpegtsmux')
|
||||||
#did not work
|
|
||||||
#subdir('mve')
|
|
||||||
subdir('mxf')
|
subdir('mxf')
|
||||||
#did not work
|
|
||||||
#subdir('nuvdemux')
|
|
||||||
subdir('onvif')
|
subdir('onvif')
|
||||||
#did not work
|
|
||||||
#subdir('overlay')
|
|
||||||
#did not work
|
|
||||||
#subdir('patchdetect')
|
|
||||||
subdir('pcapparse')
|
subdir('pcapparse')
|
||||||
subdir('pnm')
|
subdir('pnm')
|
||||||
subdir('rawparse')
|
subdir('rawparse')
|
||||||
subdir('removesilence')
|
subdir('removesilence')
|
||||||
#did not work
|
|
||||||
#subdir('rtjpeg')
|
|
||||||
#did not work
|
|
||||||
#subdir('sdi')
|
|
||||||
subdir('sdp')
|
subdir('sdp')
|
||||||
subdir('segmentclip')
|
subdir('segmentclip')
|
||||||
subdir('siren')
|
subdir('siren')
|
||||||
|
@ -75,10 +49,6 @@ subdir('smooth')
|
||||||
subdir('speed')
|
subdir('speed')
|
||||||
subdir('stereo')
|
subdir('stereo')
|
||||||
subdir('subenc')
|
subdir('subenc')
|
||||||
#did not work
|
|
||||||
#subdir('tta')
|
|
||||||
#did not work
|
|
||||||
#subdir('vbidec')
|
|
||||||
subdir('videofilters')
|
subdir('videofilters')
|
||||||
subdir('videoframe_audiolevel')
|
subdir('videoframe_audiolevel')
|
||||||
subdir('videoparsers')
|
subdir('videoparsers')
|
||||||
|
|
|
@ -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)
|
|
||||||
|
|
|
@ -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,
|
|
||||||
)
|
|
|
@ -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)
|
|
|
@ -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
|
|
|
@ -1,5 +0,0 @@
|
||||||
MVE TODO:
|
|
||||||
- seeking support
|
|
||||||
- split out decoders from demuxer into separate elements
|
|
||||||
- split out encoders from muxer into separate elements
|
|
||||||
|
|
|
@ -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
|
@ -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__ */
|
|
1486
gst/mve/gstmvemux.c
1486
gst/mve/gstmvemux.c
File diff suppressed because it is too large
Load diff
|
@ -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__ */
|
|
|
@ -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,
|
|
||||||
)
|
|
|
@ -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__ */
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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
|
@ -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
Loading…
Reference in a new issue