diff options
author | Wim Taymans <wim.taymans@collabora.co.uk> | 2011-02-28 12:06:12 +0100 |
---|---|---|
committer | Wim Taymans <wim.taymans@collabora.co.uk> | 2011-02-28 12:06:12 +0100 |
commit | 2eb38991c6d67e47ef90246b2561588cf4b5f390 (patch) | |
tree | aa84497e9b719c9a2c1a5bf8657a3cdcae32c9d6 | |
parent | 670c883f401367e2591f446e63b5102cb2aba72f (diff) | |
parent | a68137c4dcdbf3dce5cd278403478aef1de62f59 (diff) |
Merge branch 'master' into 0.11
Conflicts:
configure.ac
win32/common/config.h
426 files changed, 39759 insertions, 11856 deletions
@@ -1,11 +1,7163 @@ +=== release 0.10.21 === + +2011-01-21 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * configure.ac: + releasing 0.10.21, "Pink Noise" + +2011-01-19 20:00:13 -0800 David Schleef <ds@schleef.org> + + * tools/gst-element-maker: + element-maker: Fix handling of debug category + +2011-01-19 18:26:30 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstflacparse.c: + flacparse: mind gst_buffer_unref not liking NULL + Fixes #639950. + +2011-01-18 18:18:03 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/mxf/mxfdemux.c: + mxfdemux: Fix unitialized variable warning + +2011-01-18 13:00:11 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * configure.ac: + * docs/plugins/gst-plugins-bad-plugins.args: + * docs/plugins/inspect/plugin-adpcmdec.xml: + * docs/plugins/inspect/plugin-adpcmenc.xml: + * docs/plugins/inspect/plugin-aiff.xml: + * docs/plugins/inspect/plugin-amrwbenc.xml: + * docs/plugins/inspect/plugin-apexsink.xml: + * docs/plugins/inspect/plugin-asfmux.xml: + * docs/plugins/inspect/plugin-assrender.xml: + * docs/plugins/inspect/plugin-audioparsersbad.xml: + * docs/plugins/inspect/plugin-autoconvert.xml: + * docs/plugins/inspect/plugin-bayer.xml: + * docs/plugins/inspect/plugin-bz2.xml: + * docs/plugins/inspect/plugin-camerabin.xml: + * docs/plugins/inspect/plugin-cdaudio.xml: + * docs/plugins/inspect/plugin-cdxaparse.xml: + * docs/plugins/inspect/plugin-celt.xml: + * docs/plugins/inspect/plugin-cog.xml: + * docs/plugins/inspect/plugin-coloreffects.xml: + * docs/plugins/inspect/plugin-colorspace.xml: + * docs/plugins/inspect/plugin-dataurisrc.xml: + * docs/plugins/inspect/plugin-dc1394.xml: + * docs/plugins/inspect/plugin-dccp.xml: + * docs/plugins/inspect/plugin-debugutilsbad.xml: + * docs/plugins/inspect/plugin-dfbvideosink.xml: + * docs/plugins/inspect/plugin-dirac.xml: + * docs/plugins/inspect/plugin-dtmf.xml: + * docs/plugins/inspect/plugin-dtsdec.xml: + * docs/plugins/inspect/plugin-dvb.xml: + * docs/plugins/inspect/plugin-dvbsuboverlay.xml: + * docs/plugins/inspect/plugin-dvdspu.xml: + * docs/plugins/inspect/plugin-faac.xml: + * docs/plugins/inspect/plugin-faad.xml: + * docs/plugins/inspect/plugin-fbdevsink.xml: + * docs/plugins/inspect/plugin-festival.xml: + * docs/plugins/inspect/plugin-freeze.xml: + * docs/plugins/inspect/plugin-frei0r.xml: + * docs/plugins/inspect/plugin-gaudieffects.xml: + * docs/plugins/inspect/plugin-geometrictransform.xml: + * docs/plugins/inspect/plugin-gsettings.xml: + * docs/plugins/inspect/plugin-gsm.xml: + * docs/plugins/inspect/plugin-gstsiren.xml: + * docs/plugins/inspect/plugin-h264parse.xml: + * docs/plugins/inspect/plugin-hdvparse.xml: + * docs/plugins/inspect/plugin-id3tag.xml: + * docs/plugins/inspect/plugin-interlace.xml: + * docs/plugins/inspect/plugin-invtelecine.xml: + * docs/plugins/inspect/plugin-ivfparse.xml: + * docs/plugins/inspect/plugin-jp2kdecimator.xml: + * docs/plugins/inspect/plugin-jpegformat.xml: + * docs/plugins/inspect/plugin-kate.xml: + * docs/plugins/inspect/plugin-ladspa.xml: + * docs/plugins/inspect/plugin-legacyresample.xml: + * docs/plugins/inspect/plugin-liveadder.xml: + * docs/plugins/inspect/plugin-mimic.xml: + * docs/plugins/inspect/plugin-mms.xml: + * docs/plugins/inspect/plugin-modplug.xml: + * docs/plugins/inspect/plugin-mpeg2enc.xml: + * docs/plugins/inspect/plugin-mpeg4videoparse.xml: + * docs/plugins/inspect/plugin-mpegdemux2.xml: + * docs/plugins/inspect/plugin-mpegpsmux.xml: + * docs/plugins/inspect/plugin-mpegtsmux.xml: + * docs/plugins/inspect/plugin-mpegvideoparse.xml: + * docs/plugins/inspect/plugin-mplex.xml: + * docs/plugins/inspect/plugin-musepack.xml: + * docs/plugins/inspect/plugin-musicbrainz.xml: + * docs/plugins/inspect/plugin-mve.xml: + * docs/plugins/inspect/plugin-mxf.xml: + * docs/plugins/inspect/plugin-mythtv.xml: + * docs/plugins/inspect/plugin-nas.xml: + * docs/plugins/inspect/plugin-neon.xml: + * docs/plugins/inspect/plugin-nsf.xml: + * docs/plugins/inspect/plugin-nuvdemux.xml: + * docs/plugins/inspect/plugin-ofa.xml: + * docs/plugins/inspect/plugin-opencv.xml: + * docs/plugins/inspect/plugin-pcapparse.xml: + * docs/plugins/inspect/plugin-pnm.xml: + * docs/plugins/inspect/plugin-qtmux.xml: + * docs/plugins/inspect/plugin-rawparse.xml: + * docs/plugins/inspect/plugin-real.xml: + * docs/plugins/inspect/plugin-resindvd.xml: + * docs/plugins/inspect/plugin-rfbsrc.xml: + * docs/plugins/inspect/plugin-rsvg.xml: + * docs/plugins/inspect/plugin-rtpmux.xml: + * docs/plugins/inspect/plugin-scaletempo.xml: + * docs/plugins/inspect/plugin-schro.xml: + * docs/plugins/inspect/plugin-sdl.xml: + * docs/plugins/inspect/plugin-sdp.xml: + * docs/plugins/inspect/plugin-segmentclip.xml: + * docs/plugins/inspect/plugin-shm.xml: + * docs/plugins/inspect/plugin-sndfile.xml: + * docs/plugins/inspect/plugin-soundtouch.xml: + * docs/plugins/inspect/plugin-speed.xml: + * docs/plugins/inspect/plugin-stereo.xml: + * docs/plugins/inspect/plugin-subenc.xml: + * docs/plugins/inspect/plugin-tta.xml: + * docs/plugins/inspect/plugin-vcdsrc.xml: + * docs/plugins/inspect/plugin-vdpau.xml: + * docs/plugins/inspect/plugin-videomaxrate.xml: + * docs/plugins/inspect/plugin-videomeasure.xml: + * docs/plugins/inspect/plugin-videosignal.xml: + * docs/plugins/inspect/plugin-vmnc.xml: + * docs/plugins/inspect/plugin-vp8.xml: + * docs/plugins/inspect/plugin-wildmidi.xml: + * docs/plugins/inspect/plugin-xvid.xml: + * docs/plugins/inspect/plugin-y4mdec.xml: + * docs/plugins/inspect/plugin-zbar.xml: + * win32/common/config.h: + 0.10.20.4 pre-release + +2011-01-14 16:30:11 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + audioparsers: baseparse: Be careful to not lose the event ref + Don't unref the event if it hasn't been handled, because the caller + assumes it is still valid and might reuse it. + I ran into this problem when transcoding an AVI (with mp3 inside) + to gpp. + https://bugzilla.gnome.org/show_bug.cgi?id=639555 + +2011-01-13 11:28:32 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/elements/qtmux.c: + test: qtmux: Tests qtmux reuse + Forces the use of qtmux after it has been put to PLAYING and back + to NULL once + https://bugzilla.gnome.org/show_bug.cgi?id=639338 + +2011-01-13 15:27:36 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/qtmux/gstqtmux.c: + qtmux: set src pads when starting file + ... rather than at _init time, so they are also available following a + pad (de)activation cycle. + https://bugzilla.gnome.org/show_bug.cgi?id=639338 + +2011-01-12 16:39:22 +0000 Vincent Penquerc'h <vincent.penquerch@collabora.co.uk> + + * ext/kate/gstkatetiger.c: + * ext/kate/gstkatetiger.h: + * ext/kate/gstkateutil.c: + kate: ensure the kate pad does not shoot ahead of the video pad + Sync both pads by waiting in the kate chain function. + Do not reset our internal segment from segment updates, in order + to be able to map video running time to kate running time, to + give libtiger the timestamp it expects. This allows us to use + running time to sync to video, which is The Right Way. + https://bugzilla.gnome.org/show_bug.cgi?id=600929 + +2011-01-13 18:35:15 -0200 Luciana Fujii Pontello <luciana@fujii.eti.br> + + * gst/camerabin/gstcamerabin.c: + camerabin: Enable conversion flags + Camerabin default should just work, so we need to enable audio, image + and video conversions. + https://bugzilla.gnome.org/show_bug.cgi?id=639456 + +2011-01-13 17:10:13 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/audioparsers/gstdcaparse.c: + dcaparse: fix sync word for 14-bit little endian coding + Fix copy'n'paste bug that made us look for the raw little endian + sync word twice instead of looking for the 14-bit LE sync word + as well. Fixes parsing of such streams (see #636234 for sample file). + +2011-01-13 16:27:04 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + docs: minor baseparse docs/comment fixes + Remove copy'n'paste leftovers. + +2011-01-13 13:36:09 +0200 Teemu Katajisto <teemu.katajisto@digia.com> + + * gst/camerabin/gstcamerabin.c: + camerabin: set pad-negotiation-mode to active for output-selector + Fixes #639413. + +2011-01-12 16:55:07 +0200 Stefan Kost <ensonic@users.sf.net> + + * gst/asfmux/gstasfmux.c: + asfmux: use g_error_free instead of g_free + +2011-01-12 16:50:51 +0200 Stefan Kost <ensonic@users.sf.net> + + * tests/examples/camerabin2/gst-camera2.c: + camerabin2: use g_error_free instead of g_free + +2011-01-12 11:57:29 +0100 Edward Hervey <edward.hervey@collabora.co.uk> + + * gst/y4m/gsty4mdec.c: + y4mdec: Default colorspace is I420 + https://bugzilla.gnome.org/show_bug.cgi?id=639296 + +2011-01-11 23:44:51 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * configure.ac: + * win32/common/config.h: + 0.10.20.3 pre-release + +2011-01-11 15:50:52 +0200 Stefan Kost <ensonic@users.sf.net> + + * common: + Automatic update of common submodule + From e572c87 to f94d739 + +2011-01-10 19:11:22 +0100 Edward Hervey <edward.hervey@collabora.co.uk> + + * gst/mpegdemux/mpegtspacketizer.c: + mpegtspacketizer: Don't forget the GType when using caps_new_simple() + +2011-01-10 16:36:45 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * common: + Automatic update of common submodule + From ccbaa85 to e572c87 + +2011-01-10 14:54:10 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * common: + Automatic update of common submodule + From 46445ad to ccbaa85 + +2011-01-10 11:25:47 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/mpegdemux/mpegtspacketizer.c: + mpegtsdemux: fix silly way of creating caps + +2011-01-10 11:18:52 +0000 Karol Sobczak <napewnotrafi@gmail.com> + + * gst/mpegdemux/mpegtspacketizer.c: + mpegtsdemux: fix re-syncing on invalid data after seek + Or possibly even at startup. If we couldn't find a sync within + the first few bytes, we'd just push more data into the adapter + but never discard any of the invalid data at the beginning, so + would never be able to re-sync. + https://bugzilla.gnome.org/show_bug.cgi?id=639063 + +2011-01-08 03:12:11 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * ext/cog/gstcogdownsample.c: + * ext/cog/gstcogutils.c: + * ext/schroedinger/gstschroenc.c: + * ext/schroedinger/gstschroparse.c: + * ext/schroedinger/gstschroutils.c: + cog, schroedinger: fix warnings when compiling with -DG_DISABLE_ASSERT + +2011-01-08 03:10:00 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * configure.ac: + * ext/cog/gstcogorc-dist.c: + * ext/cog/gstcogorc-dist.h: + * win32/common/config.h: + 0.10.20.2 pre-release + +2011-01-08 02:49:06 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * docs/plugins/gst-plugins-bad-plugins.args: + * docs/plugins/gst-plugins-bad-plugins.hierarchy: + * docs/plugins/inspect/plugin-adpcmdec.xml: + * docs/plugins/inspect/plugin-adpcmenc.xml: + * docs/plugins/inspect/plugin-aiff.xml: + * docs/plugins/inspect/plugin-amrwbenc.xml: + * docs/plugins/inspect/plugin-apexsink.xml: + * docs/plugins/inspect/plugin-asfmux.xml: + * docs/plugins/inspect/plugin-assrender.xml: + * docs/plugins/inspect/plugin-audioparsersbad.xml: + * docs/plugins/inspect/plugin-autoconvert.xml: + * docs/plugins/inspect/plugin-bayer.xml: + * docs/plugins/inspect/plugin-bz2.xml: + * docs/plugins/inspect/plugin-camerabin.xml: + * docs/plugins/inspect/plugin-cdaudio.xml: + * docs/plugins/inspect/plugin-cdxaparse.xml: + * docs/plugins/inspect/plugin-celt.xml: + * docs/plugins/inspect/plugin-cog.xml: + * docs/plugins/inspect/plugin-coloreffects.xml: + * docs/plugins/inspect/plugin-colorspace.xml: + * docs/plugins/inspect/plugin-dataurisrc.xml: + * docs/plugins/inspect/plugin-dc1394.xml: + * docs/plugins/inspect/plugin-dccp.xml: + * docs/plugins/inspect/plugin-debugutilsbad.xml: + * docs/plugins/inspect/plugin-dfbvideosink.xml: + * docs/plugins/inspect/plugin-dirac.xml: + * docs/plugins/inspect/plugin-dtmf.xml: + * docs/plugins/inspect/plugin-dtsdec.xml: + * docs/plugins/inspect/plugin-dvb.xml: + * docs/plugins/inspect/plugin-dvbsuboverlay.xml: + * docs/plugins/inspect/plugin-dvdspu.xml: + * docs/plugins/inspect/plugin-faac.xml: + * docs/plugins/inspect/plugin-faad.xml: + * docs/plugins/inspect/plugin-fbdevsink.xml: + * docs/plugins/inspect/plugin-festival.xml: + * docs/plugins/inspect/plugin-freeze.xml: + * docs/plugins/inspect/plugin-frei0r.xml: + * docs/plugins/inspect/plugin-gaudieffects.xml: + * docs/plugins/inspect/plugin-geometrictransform.xml: + * docs/plugins/inspect/plugin-gsettings.xml: + * docs/plugins/inspect/plugin-gsm.xml: + * docs/plugins/inspect/plugin-gstsiren.xml: + * docs/plugins/inspect/plugin-h264parse.xml: + * docs/plugins/inspect/plugin-hdvparse.xml: + * docs/plugins/inspect/plugin-id3tag.xml: + * docs/plugins/inspect/plugin-interlace.xml: + * docs/plugins/inspect/plugin-invtelecine.xml: + * docs/plugins/inspect/plugin-ivfparse.xml: + * docs/plugins/inspect/plugin-jp2kdecimator.xml: + * docs/plugins/inspect/plugin-jpegformat.xml: + * docs/plugins/inspect/plugin-kate.xml: + * docs/plugins/inspect/plugin-ladspa.xml: + * docs/plugins/inspect/plugin-legacyresample.xml: + * docs/plugins/inspect/plugin-liveadder.xml: + * docs/plugins/inspect/plugin-mimic.xml: + * docs/plugins/inspect/plugin-mms.xml: + * docs/plugins/inspect/plugin-modplug.xml: + * docs/plugins/inspect/plugin-mpeg2enc.xml: + * docs/plugins/inspect/plugin-mpeg4videoparse.xml: + * docs/plugins/inspect/plugin-mpegdemux2.xml: + * docs/plugins/inspect/plugin-mpegpsmux.xml: + * docs/plugins/inspect/plugin-mpegtsmux.xml: + * docs/plugins/inspect/plugin-mpegvideoparse.xml: + * docs/plugins/inspect/plugin-mplex.xml: + * docs/plugins/inspect/plugin-musepack.xml: + * docs/plugins/inspect/plugin-musicbrainz.xml: + * docs/plugins/inspect/plugin-mve.xml: + * docs/plugins/inspect/plugin-mxf.xml: + * docs/plugins/inspect/plugin-mythtv.xml: + * docs/plugins/inspect/plugin-nas.xml: + * docs/plugins/inspect/plugin-neon.xml: + * docs/plugins/inspect/plugin-nsf.xml: + * docs/plugins/inspect/plugin-nuvdemux.xml: + * docs/plugins/inspect/plugin-ofa.xml: + * docs/plugins/inspect/plugin-opencv.xml: + * docs/plugins/inspect/plugin-pcapparse.xml: + * docs/plugins/inspect/plugin-pnm.xml: + * docs/plugins/inspect/plugin-qtmux.xml: + * docs/plugins/inspect/plugin-rawparse.xml: + * docs/plugins/inspect/plugin-real.xml: + * docs/plugins/inspect/plugin-resindvd.xml: + * docs/plugins/inspect/plugin-rfbsrc.xml: + * docs/plugins/inspect/plugin-rsvg.xml: + * docs/plugins/inspect/plugin-rtpmux.xml: + * docs/plugins/inspect/plugin-scaletempo.xml: + * docs/plugins/inspect/plugin-schro.xml: + * docs/plugins/inspect/plugin-sdl.xml: + * docs/plugins/inspect/plugin-sdp.xml: + * docs/plugins/inspect/plugin-segmentclip.xml: + * docs/plugins/inspect/plugin-shm.xml: + * docs/plugins/inspect/plugin-sndfile.xml: + * docs/plugins/inspect/plugin-soundtouch.xml: + * docs/plugins/inspect/plugin-speed.xml: + * docs/plugins/inspect/plugin-stereo.xml: + * docs/plugins/inspect/plugin-subenc.xml: + * docs/plugins/inspect/plugin-tta.xml: + * docs/plugins/inspect/plugin-vcdsrc.xml: + * docs/plugins/inspect/plugin-vdpau.xml: + * docs/plugins/inspect/plugin-videomaxrate.xml: + * docs/plugins/inspect/plugin-videomeasure.xml: + * docs/plugins/inspect/plugin-videosignal.xml: + * docs/plugins/inspect/plugin-vmnc.xml: + * docs/plugins/inspect/plugin-vp8.xml: + * docs/plugins/inspect/plugin-wildmidi.xml: + * docs/plugins/inspect/plugin-xvid.xml: + * docs/plugins/inspect/plugin-y4mdec.xml: + * docs/plugins/inspect/plugin-zbar.xml: + docs: update docs + +2011-01-08 02:47:12 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * po/bg.po: + * po/ca.po: + * po/ja.po: + po: update translations + +2011-01-08 02:43:41 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/camerabin/Makefile.am: + * gst/camerabin/camerabingeneral.c: + * gst/camerabin/gstcamerabin-marshal.list: + * gst/camerabin/gstinputselector.c: + * gst/camerabin/gstinputselector.h: + camerabin: use private input-selector that still has "select-all" property + The "select-all" property was removed when input-selector was moved + to core, but camerabin uses this, so make camerabin use a private + copy until a better fix is found. + +2011-01-08 00:32:21 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * tests/check/Makefile.am: + tests: Makefile.am clean-up + Avoid duplicates GST_CHECK_CFLAGS and GST_OPTIONS_CFLAGS are already in + AM_CFLAGS. Add LDADD instead of GST_CHECK_LIBS for consistency. + +2011-01-08 00:19:06 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/smoothwave/demo-osssrc.c: + smoothwave: remove old 0.8 example containing code with sideeffects in g_return_if_fail() + May just as well remove it rather than fix it, so it doesn't show + up in greps for this any longer. + +2011-01-08 00:18:17 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * tests/check/elements/.gitignore: + tests: make git ignore new schroenc test binary + +2011-01-08 00:17:26 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * tests/check/Makefile.am: + tests: fix CFLAGS and LIBADD order in Makefile.am + +2011-01-08 00:08:11 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * tests/check/Makefile.am: + tests: never disable g_assert() and cast checks for the unit tests + The unit tests are riddled with g_assert() and friends, make sure we + don't disable assert and cast checks for the unit tests even if + this has been specified for the rest of the code base, e.g. via + --disable-glib-asserts. + +2011-01-08 00:01:01 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * ext/directfb/dfb-example.c: + directfb: don't put code with side-effects into g_assert() + It will all be turned into a NOOP if -DG_DISABLE_ASSERT is used + (as it is for pre-releases and releases). + +2011-01-07 23:57:21 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * ext/xvid/gstxvidenc.c: + xvidenc: don't put code with side effects into g_return_val_if_fail() + And don't use g_return*_if_fail() for error handling in elements. + +2011-01-07 18:49:02 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/mpegvideoparse/mpegpacketiser.c: + * gst/mpegvideoparse/mpegpacketiser.h: + * gst/mpegvideoparse/mpegvideoparse.c: + * gst/mpegvideoparse/mpegvideoparse.h: + Revert "mpegvideoparse: fix timestamp generation" + This reverts commit 2271608c4314d6d0a685c18c5c47d55495586159. + This patch needs more work so it doesn't cause grave playback + regressions (multi-second freezes) with some files that have + slightly broken timestamps but play fine everywhere else. + https://bugzilla.gnome.org/show_bug.cgi?id=636279 + https://bugzilla.gnome.org/show_bug.cgi?id=632222 + +2011-01-07 15:47:39 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * configure.ac: + configure: fix --disable-external + +2011-01-07 14:51:46 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * configure.ac: + configure: use $LIBM instead of hard-coding -lm + +2011-01-07 15:22:07 +0200 Stefan Kost <ensonic@users.sf.net> + + * gst-libs/gst/signalprocessor/gstsignalprocessor.c: + signalprocessor: don't leak the caps + +2011-01-07 02:10:33 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/mpegdemux/flutspmtinfo.c: + * gst/mpegdemux/gstmpegtsdemux.c: + mpegtsdemux: fix PAT and PMT info-related object leaks + +2011-01-06 12:51:27 +0100 Edward Hervey <edward.hervey@collabora.co.uk> + + * gst/jpegformat/gstjpegparse.c: + jpegparse: Fix unitialized variable on macosx + +2011-01-06 12:50:14 +0100 Edward Hervey <edward.hervey@collabora.co.uk> + + * gst/jp2kdecimator/jp2kcodestream.c: + jp2kdecimator: Fix unitialized variables on macosx + +2011-01-06 12:49:43 +0100 Edward Hervey <edward.hervey@collabora.co.uk> + + * gst/audioparsers/gstflacparse.c: + flacparse: Fix unitialized variable on macosx + +2010-12-15 15:58:48 -0800 David Schleef <ds@schleef.org> + + * gst/y4m/gsty4mdec.h: + y4mdec: Fix copyright + +2010-12-17 14:50:50 -0800 David Schleef <ds@schleef.org> + + * tools/element-templates/pushsrc: + * tools/gst-element-maker: + element-maker: improve pushsrc + +2011-01-05 16:43:45 +0100 Edward Hervey <edward.hervey@collabora.co.uk> + + * gst/y4m/gsty4mdec.c: + y4m: Fix unitialized variables on macosx + +2011-01-05 13:44:04 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/dvbsuboverlay/Makefile.am: + * gst/dvbsuboverlay/dvb-sub.c: + * gst/dvbsuboverlay/ffmpeg-colorspace.h: + dvbsuboverlay: some more minor clean-ups + +2011-01-04 16:03:01 +0100 Janne Grunau <janne.grunau@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: fix leak of "clear screen" DVBSubtitles structs + +2011-01-04 13:51:21 +0000 Janne Grunau <janne.grunau@collabora.co.uk> + + * gst/dvbsuboverlay/dvb-sub.c: + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: fix two minor deinitialization memory leaks + +2011-01-03 23:55:59 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * tests/examples/Makefile.am: + examples: dist camerabin2 example as well + https://bugzilla.gnome.org/show_bug.cgi?id=638604 + +2011-01-03 23:49:51 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/camerabin2/Makefile.am: + camerabin2: fix cflags and libs order in Makefile.am + +2011-01-03 23:47:33 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst-libs/gst/basecamerabinsrc/Makefile.am: + basecamerabinsrc: fix libs order in Makefile.am + +2011-01-03 23:46:02 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst-libs/gst/Makefile.am: + build: fix disting of experimental basecamerabinsrc lib used by camerabin2 + https://bugzilla.gnome.org/show_bug.cgi?id=638604 + +2011-01-03 17:10:36 -0600 Rob Clark <rob@ti.com> + + * sys/dvb/camswclient.c: + * sys/dvb/gstdvbsrc.c: + dvb: fix build errors on macosx + fixes the following compile errors: + cc1: warnings being treated as errors + camswclient.c: In function 'cam_sw_client_open': + camswclient.c:81: warning: implicit declaration of function 'strncpy' + camswclient.c:81: warning: incompatible implicit declaration of built-in function 'strncpy' + camswclient.c:89: warning: implicit declaration of function 'strerror' + camswclient.c:89: warning: nested extern declaration of 'strerror' + camswclient.c:89: warning: format '%s' expects type 'char *', but argument 9 has type 'int' + camswclient.c: In function 'send_ca_pmt': + camswclient.c:129: warning: implicit declaration of function 'memcpy' + camswclient.c:129: warning: incompatible implicit declaration of built-in + function 'memcpy' + gstdvbsrc.c:48:19: error: error.h: No such file or directory + Signed-off-by: Rob Clark <rob@ti.com> + +2011-01-03 20:05:52 +0100 Janne Grunau <janne.grunau@collabora.co.uk> + + * gst/dvbsuboverlay/dvb-sub.c: + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: remove unnecessary RGB -> YUV conversion by using YUV palettes + the default CLUTs still use RGB -> YUV conversions since the standard defines + them as RGBA values. + +2011-01-03 20:21:57 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * m4/Makefile.am: + * m4/esd.m4: + * m4/glib.m4: + * m4/gst-matroska.m4: + * m4/gst-shout2.m4: + * m4/gtk.m4: + * m4/ogg.m4: + * m4/vorbis.m4: + m4: remove some cruft + +2011-01-03 17:24:23 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/qtmux/gstqtmux.c: + * gst/qtmux/gstqtmux.h: + qtmux: adjust nasty case timestamp tracking + That is, all sorts of problems arise with re-ordered input timestamps that + tend to defy automagic handling for every case, so allow for a few variations + that can be tried depending on circumstances. + Also try to document accordingly. + Also fixes #638288. + +2010-12-30 21:48:41 +0200 Felipe Contreras <felipe.contreras@nokia.com> + + * gst/qtmux/gstqtmux.c: + qtmux: get rid of timestamp overprotectiveness + Signed-off-by: Felipe Contreras <felipe.contreras@nokia.com> + +2011-01-03 16:56:57 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/qtmux/atoms.c: + * gst/qtmux/atoms.h: + * gst/qtmux/atomsrecovery.c: + * gst/qtmux/gstqtmux.c: + qtmux: simplify and fix pts_offset storing + In particular, only write a ctts atom if and only if ever a non-zero offset. + +2011-01-03 10:43:15 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/qtmux/gstqtmux.c: + qtmux: add some more documentation + +2010-12-03 15:23:00 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/qtmux/atoms.c: + * gst/qtmux/atoms.h: + * gst/qtmux/gstqtmux.c: + * gst/qtmux/gstqtmux.h: + qtmux: remove large-file property + Rather, auto-determine if 64-bits fields are needed for a valid result, and + stick to plain 32-bits if not needed. + API: GstQTMux:large-file (removed) + +2011-01-03 18:13:37 +0200 Stefan Kost <ensonic@users.sf.net> + + * sys/dvb/README: + README: fix the example pipeline + Fix the obvious outdated parts. Still this README looks outdated and should be + updated or removed. + +2011-01-02 19:38:01 -0800 David Schleef <ds@schleef.org> + + * tools/gst-element-maker: + element-maker: Add debug category + +2011-01-02 16:13:56 -0800 David Schleef <ds@schleef.org> + + * gst/colorspace/colorspace.c: + colorspace: Disable matrixing on big-endian + It's broken until someone writes better Orc code. Fixes #631232. + +2010-12-05 03:29:42 -0800 David Schleef <ds@schleef.org> + + * gst/mpegtsmux/tsmux/tsmuxstream.c: + mpegtsmux: Set adaptation flag when appropriate + Specifically, when there's stuff to go into the adaptation + header. + +2010-11-17 17:49:17 -0800 David Schleef <ds@schleef.org> + + * gst/mpegtsmux/mpegtsmux.c: + * gst/mpegtsmux/tsmux/tsmuxstream.c: + * gst/mpegtsmux/tsmux/tsmuxstream.h: + mpegtsmux: Set random_access_indicator for keyframes + +2010-12-31 16:20:22 +0000 Vincent Penquerc'h <vincent.penquerch@collabora.co.uk> + + * ext/kate/gstkatetiger.c: + tiger: outline text by default, to make it easier to read + https://bugzilla.gnome.org/show_bug.cgi?id=638527 + +2011-01-02 15:11:52 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * LICENSE_readme: + * Makefile.am: + * configure.ac: + * docs/plugins/Makefile.am: + * docs/plugins/gst-plugins-bad-plugins-docs.sgml: + * docs/plugins/gst-plugins-bad-plugins-sections.txt: + * docs/plugins/gst-plugins-bad-plugins.args: + * docs/plugins/gst-plugins-bad-plugins.hierarchy: + * docs/plugins/inspect/plugin-jack.xml: + * ext/Makefile.am: + * ext/jack/.gitignore: + * ext/jack/Makefile.am: + * ext/jack/README: + * ext/jack/gstjack.c: + * ext/jack/gstjack.h: + * ext/jack/gstjackaudioclient.c: + * ext/jack/gstjackaudioclient.h: + * ext/jack/gstjackaudiosink.c: + * ext/jack/gstjackaudiosink.h: + * ext/jack/gstjackaudiosrc.c: + * ext/jack/gstjackaudiosrc.h: + * ext/jack/gstjackringbuffer.h: + * ext/jack/gstjackutil.c: + * ext/jack/gstjackutil.h: + * gst-plugins-bad.spec.in: + * tests/examples/Makefile.am: + * tests/examples/jack/Makefile.am: + * tests/examples/jack/jack_client.c: + jack: move plugin to gst-plugins-good + https://bugzilla.gnome.org/show_bug.cgi?id=621929 + +2011-01-02 13:52:36 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * ext/kate/gstkatedec.c: + * ext/kate/gstkatetiger.c: + * ext/kate/gstkateutil.c: + kate: fix caps and string leaks and some minor clean-ups + Don't leak source caps. Use GST_PTR_FORMAT to log caps, so + we don't need to leak strings from gst_caps_to_string(). + No need to use GST_DEBUG_FUNCPTR for vfuncs where the base + class will never look them up (like property getters/setters). + Don't use g_return_*_if_fail() for things that aren't directly + programming errors (by the application developer). + Fixes kate unit test under valgrind. + +2010-12-31 16:17:50 +0000 Vincent Penquerc'h <vincent.penquerch@collabora.co.uk> + + * ext/kate/gstkateutil.c: + kate: reenable the sending of a message for tags + https://bugzilla.gnome.org/show_bug.cgi?id=638412 + +2011-01-02 13:29:06 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/gaudieffects/Makefile.am: + gaudieffects: dist python examples + +2010-12-31 00:09:09 -0800 David Schleef <ds@schleef.org> + + * tools/gst-element-maker: + element-maker: Update FSF address + +2010-12-31 00:07:28 -0800 David Schleef <ds@schleef.org> + + * tools/Makefile.am: + * tools/gst-app-maker: + Add gst-app-maker + +2010-12-31 00:12:53 -0800 David Schleef <ds@schleef.org> + + * gst/dtmf/tone_detect.c: + dtmf: Fix build failure caused by previous commit + +2010-12-30 19:21:47 -0800 David Schleef <ds@schleef.org> + + * ext/cog/generate_tables.c: + * ext/cog/gstcms.c: + * ext/cog/gstcolorconvert.c: + cog: Use math-compat.h + +2010-12-30 19:21:21 -0800 David Schleef <ds@schleef.org> + + * gst/mpegdemux/gstmpegtsdemux.c: + mpegdemux: Fix c99-ism + +2010-12-30 19:12:23 -0800 David Schleef <ds@schleef.org> + + * gst/legacyresample/resample_functable.c: + * gst/legacyresample/resample_ref.c: + legacyresample: Use math-compat header + +2010-12-30 19:03:54 -0800 David Schleef <ds@schleef.org> + + * gst/gaudieffects/gstgaussblur.c: + * gst/geometrictransform/gstrotate.c: + change M_PI to G_PI + +2010-12-30 19:03:14 -0800 David Schleef <ds@schleef.org> + + * gst/frei0r/frei0r.h: + * gst/frei0r/gstfrei0r.h: + frei0r: convert uint32_t to guint32 + +2010-12-30 18:20:47 -0800 David Schleef <ds@schleef.org> + + * gst/dtmf/gstdtmfdetect.c: + * gst/dtmf/tone_detect.c: + * gst/dtmf/tone_detect.h: + dtmf: build fixes for MSVC + Use gint16 and G_PI. + +2010-12-30 18:19:47 -0800 David Schleef <ds@schleef.org> + + * gst/dtmf/tone_detect.c: + dtmf: reindent + +2010-12-30 18:02:06 -0800 David Schleef <ds@schleef.org> + + * gst/dataurisrc/gstdataurisrc.c: + dataurisrc: use g_ascii_strcasecmp() + +2010-12-31 01:38:02 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * Makefile.am: + * configure.ac: + * docs/plugins/Makefile.am: + * docs/plugins/gst-plugins-bad-plugins-docs.sgml: + * docs/plugins/gst-plugins-bad-plugins-sections.txt: + * docs/plugins/gst-plugins-bad-plugins.args: + * docs/plugins/gst-plugins-bad-plugins.hierarchy: + * docs/plugins/inspect/plugin-selector.xml: + * gst-plugins-bad.spec.in: + * gst/selector/.gitignore: + * gst/selector/Makefile.am: + * gst/selector/gstinputselector.c: + * gst/selector/gstinputselector.h: + * gst/selector/gstoutputselector.c: + * gst/selector/gstoutputselector.h: + * gst/selector/gstselector-marshal.list: + * gst/selector/gstselector.c: + * gst/selector/selector.vcproj: + * tests/check/Makefile.am: + * tests/check/elements/.gitignore: + * tests/check/elements/selector.c: + * tests/examples/Makefile.am: + * tests/examples/switch/.gitignore: + * tests/examples/switch/Makefile.am: + * tests/examples/switch/switcher.c: + * tests/icles/.gitignore: + * tests/icles/Makefile.am: + * tests/icles/output-selector-test.c: + selector: move input-selector and output-selector to core + https://bugzilla.gnome.org/show_bug.cgi?id=614306 + +2010-12-30 01:17:28 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * docs/plugins/gst-plugins-bad-plugins.args: + * docs/plugins/inspect/plugin-asfmux.xml: + * docs/plugins/inspect/plugin-audioparsersbad.xml: + * docs/plugins/inspect/plugin-autoconvert.xml: + * docs/plugins/inspect/plugin-bayer.xml: + * docs/plugins/inspect/plugin-coloreffects.xml: + * docs/plugins/inspect/plugin-colorspace.xml: + * docs/plugins/inspect/plugin-debugutilsbad.xml: + * docs/plugins/inspect/plugin-dvbsuboverlay.xml: + * docs/plugins/inspect/plugin-geometrictransform.xml: + * docs/plugins/inspect/plugin-interlace.xml: + * docs/plugins/inspect/plugin-jp2kdecimator.xml: + * docs/plugins/inspect/plugin-jpegformat.xml: + * docs/plugins/inspect/plugin-kate.xml: + * docs/plugins/inspect/plugin-opencv.xml: + * docs/plugins/inspect/plugin-qtmux.xml: + * docs/plugins/inspect/plugin-rsvg.xml: + * docs/plugins/inspect/plugin-videomeasure.xml: + * docs/plugins/inspect/plugin-y4mdec.xml: + * docs/plugins/inspect/plugin-zbar.xml: + docs: update plugin docs + +2010-12-30 01:14:29 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * Makefile.am: + * configure.ac: + * docs/plugins/Makefile.am: + * docs/plugins/gst-plugins-bad-plugins-docs.sgml: + * docs/plugins/gst-plugins-bad-plugins-sections.txt: + * docs/plugins/gst-plugins-bad-plugins.args: + * docs/plugins/gst-plugins-bad-plugins.hierarchy: + * docs/plugins/gst-plugins-bad-plugins.interfaces: + * docs/plugins/gst-plugins-bad-plugins.prerequisites: + * docs/plugins/inspect/plugin-valve.xml: + * gst-plugins-bad.spec.in: + * gst/valve/Makefile.am: + * gst/valve/gstvalve.c: + * gst/valve/gstvalve.h: + * tests/check/Makefile.am: + * tests/check/elements/.gitignore: + * tests/check/elements/valve.c: + valve: move valve element/plugin to core + https://bugzilla.gnome.org/show_bug.cgi?id=630808 + +2010-12-29 13:18:37 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstwrappercamerabinsrc.c: + camerabin2: Various leak fixes + Various leak fixes and some code reorganization + +2010-12-27 17:18:29 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/examples/camerabin2/.gitignore: + camerabin2: example: gitignore captured files + +2010-12-26 20:52:25 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstwrappercamerabinsrc.c: + wrappercamerabinsrc: Implement video capture renegotiate + Handle caps renegotiation from camerabin2's renegotiate event + to allow video capture to be done with the user's requested + resolution. + +2010-12-26 20:47:40 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/elements/camerabin2.c: + camerabin2: Add tests for video capture + Add a test for capturing multiple videos with different resolutions + in a sequence. + +2010-12-26 20:35:47 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstcamerabin2.c: + camerabin2: Fix renegotiate event pushing + Use a hack to make the event upstream to reach the camera source + instead of going downstream and being useless. + This was already fixed this way for image srcpad renegotiate and + video srcpad was left unfixed. + +2010-12-24 09:10:48 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstwrappercamerabinsrc.c: + * gst/camerabin2/gstwrappercamerabinsrc.h: + wrappercamerabinsrc: Refactor internal pipeline + Instead of linking 3 src pads from tee to the ghostpads, use 2 + srcpads and add an output-selector to completely split caps + negotiation of video/image modes. I don't think there is an + use case that would require image and video pads to be used + at the same time. + +2010-12-22 14:42:27 +0000 Vincent Penquerc'h <vincent.penquerch@collabora.co.uk> + + * configure.ac: + configure: use -pthread for xvid configure check + https://bugzilla.gnome.org/show_bug.cgi?id=637823 + https://bugzilla.gnome.org/show_bug.cgi?id=637308 + +2010-12-28 17:16:05 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/gstcamerabin.c: + camerabin: mode can be only image or video + No need to check if camerabin is on video mode if it isn't on + image mode as those are the only 2 modes available. + Additionally, if mode gets corrupted somehow and would be neither + image or video it would cause a null pointer dereferencing some + lines of code below, so this is safer. + +2010-12-28 16:55:11 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/gstcamerabin.c: + camerabin: Remove unused variable + +2010-12-27 16:58:26 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/asfmux/gstasf.c: + asfmux: Fix plugin package name/origin + +2010-12-27 13:20:28 +0100 Alessandro Decina <alessandro.d@gmail.com> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: fix compiler warnings + +2010-12-27 11:10:53 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/dvbsuboverlay/dvb-sub.c: + * gst/dvbsuboverlay/dvb-sub.h: + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: clean-up: allocate flat array of rectangles + instead of an array of pointers to individually-allocated rectangles. + +2010-12-23 18:18:50 +0000 Vincent Penquerc'h <vincent.penquerch@collabora.co.uk> + + * ext/kate/gstkatetiger.c: + * ext/kate/gstkatetiger.h: + tiger: fallback on headers in caps to initialize if headers are absent + When Totem switches streams, tiger will be reset, and start receiving + buffers from the middle of the stream, without being sent headers. + If this happens, try to get headers from the caps. + https://bugzilla.gnome.org/show_bug.cgi?id=638004 + +2010-12-26 17:19:00 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst-libs/gst/interfaces/photography.c: + photography: fix typo in property description + +2010-12-26 17:07:38 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * tests/examples/camerabin/gst-camera.c: + examples: fix gtk3 code path in camerabin example app + Just add rows via the combobox's model, which should work with + both gtk2 and gtk3, instead of using the gtk_combo_box_append_text() + convenience API (which was renamed to gtk_combo_box_text_append_text()). + Fixes compilation against gtk3 (there was a typo in the list store + variable name, spotted by Markus Vartiainen). + +2010-12-25 17:01:11 +0000 Vincent Penquerc'h <vincent.penquerch@collabora.co.uk> + + * ext/kate/gstkatetiger.c: + kate: if seeking with GST_SEEK_TYPE_CUR, flush everything + We don't know how to calculate the target, so be safe. + https://bugzilla.gnome.org/show_bug.cgi?id=600929 + +2010-12-25 16:44:03 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * ext/kate/gstkatetiger.c: + tiger: move #if #else bits outside of macro + Some compilers/preprocessors don't like if/else/endif preprocessor + directives in the middle of macros. + +2010-12-24 14:44:23 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/dvbsuboverlay/dvb-sub.c: + dvbsuboverlay: clean-up: merge private data struct into main struct + +2010-12-24 14:24:12 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/dvbsuboverlay/dvb-sub.c: + * gst/dvbsuboverlay/dvb-sub.h: + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: clean-up: dvb sub parser helper doesn't need to be a GObject + +2010-01-25 18:26:25 +0000 Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com> + + * ext/kate/gstkate.c: + tiger: Give tiger primary rank + +2010-01-25 18:58:38 +0000 Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com> + + * ext/kate/Makefile.am: + * ext/kate/gstkate.c: + * ext/kate/gstkatedec.c: + * ext/kate/gstkatedec.h: + * ext/kate/gstkateparse.c: + * ext/kate/gstkatespu.c: + * ext/kate/gstkatetiger.c: + * ext/kate/gstkatetiger.h: + * ext/kate/gstkateutil.c: + * ext/kate/gstkateutil.h: + kate: add segment tracking, and various other improvements + https://bugzilla.gnome.org/show_bug.cgi?id=600929 + +2010-12-24 10:15:46 +0000 Vincent Penquerc'h <vincent.penquerch@collabora.co.uk> + + * gst/mve/gstmvedemux.c: + mve: do not use the pad buffer allocation functions in demuxers + https://bugzilla.gnome.org/show_bug.cgi?id=637929 + +2010-12-24 09:50:00 +0000 Vincent Penquerc'h <vincent.penquerch@collabora.co.uk> + + * gst/mpegdemux/gstmpegtsdemux.c: + mpegdemux: do not use the pad buffer allocation functions in demuxers + https://bugzilla.gnome.org/show_bug.cgi?id=637931 + +2010-12-23 22:01:00 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/mpeg4videoparse/mpeg4videoparse.c: + mpeg4videoparse: try harder to make buffer metadata writable before modifying + Also, check buffer for NULL-ness before dereferencing it. + https://bugzilla.gnome.org/show_bug.cgi?id=637824 + +2010-12-22 11:44:55 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.c: + basecamerasrc: Notify earlier + Notify about ready-for-capture changes earlier to allow camerabin2 + to do the videobin state switching before the capture starts. + +2010-12-21 19:22:36 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstvideorecordingbin.c: + videorecordingbin: Fix leaks + +2010-12-21 11:04:00 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/elements/camerabin2.c: + camerabin2: Refactor tests + Refactor tests case so that the same tests can be run for different + camera sources. + +2010-12-20 18:30:32 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/elements/.gitignore: + tests: gitignore camerabin2 tests + Adds more camerabin2 elements tests to gitignore + +2010-12-20 18:09:26 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstwrappercamerabinsrc.c: + wrappercamerabinsrc: Add converters for viewfinder branch + Viewfinder branch should have converters as it has to work + always anyway. + +2010-12-20 14:20:35 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/Makefile.am: + * tests/check/elements/imagecapturebin.c: + imagecapturebin: Add another test case + Adds a test case to check if a sequence of buffers with different + caps can be pushed to imagecapturebin and saved correctly + +2010-12-20 02:59:14 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/Makefile.am: + * tests/check/elements/viewfinderbin.c: + viewfinderbin: Add basic check test + Adds minimum check test. It's not a very useful test, but at least + it allows us to run it under valgrind and check for leaks automatically + +2010-12-20 02:58:44 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstviewfinderbin.c: + viewfinderbin: Remove leaks + Removing various leaks from viewfinderbin + +2010-12-17 23:06:45 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstcamerabin2.c: + camerabin2: more logs + +2010-12-17 23:06:23 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/elements/camerabin2.c: + camerabin2: Small tests update + Increases timeout value so that tests won't fail with full + debug output. + Also removes buffer alloc from videotestsrc as this feature + isn't ready on camerabin2 + +2010-12-14 22:06:33 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/elements/camerabin2.c: + camerabin2: Adds tests for image capture with different caps + Adds a test that tries sucessive captures with different caps + +2010-12-16 00:40:25 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstwrappercamerabinsrc.c: + * gst/camerabin2/gstwrappercamerabinsrc.h: + wrappercamerabinsrc: Handle camerabin2 custom renegotiate events + +2010-12-15 14:05:54 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstcamerabin2.c: + camerabin2: Use custom renegotiate event + Adds a custom renegotiate event that is pushed to the camerasrc pad + that needs renegotiation due to the user selecting a new capture + caps for that pad. + This is a way of notifying the source that it should update its caps, even + if it doesn't use pad allocs. + +2010-12-16 22:49:24 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstwrappercamerabinsrc.c: + * gst/camerabin2/gstwrappercamerabinsrc.h: + wrappercamerabinsrc: Add local mode + +2010-12-14 18:42:51 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstcamerabin2.c: + camerabin2: Adds properties for capture caps + Adds properties for selecting caps for video and image captures + +2010-12-19 19:40:54 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst-libs/gst/Makefile.am: + basecamerabinsrc: Fix makefile building order + basecamerabinsrc must be built after photography interface + as it depends on it. + +2010-12-10 17:45:40 +0200 Teemu Katajisto <teemu.katajisto@digia.com> + + * gst/camerabin2/gstimagecapturebin.c: + camerabin2: remove abreviations from imagecapturebin + +2010-12-16 08:47:56 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.c: + basecamerasrc: Add some more logging + Adds some more logging and always assume capture has started before + start_capture is called. This helps on image captures that might + call finish_capture directly from start_capture or before start_capture + finishes. + +2010-12-15 22:35:16 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.c: + * gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.h: + * gst/camerabin2/gstwrappercamerabinsrc.c: + basecamerasrc: More cleanup + Remove old legacy code copied from camerabin(1) that should be handled + by caps negotiation on camerabin2 + +2010-12-15 14:07:15 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstwrappercamerabinsrc.c: + wrappercamerabinsrc: Remove unused variable + Remove wait_for_prepara variable that wasn't being used + +2010-12-14 17:23:10 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/Makefile.am: + * gst/camerabin2/gstcamerabin2.c: + * gst/camerabin2/gstplugin.c: + * gst/camerabin2/gstv4l2camerasrc.c: + * gst/camerabin2/gstv4l2camerasrc.h: + * gst/camerabin2/gstwrappercamerabinsrc.c: + * gst/camerabin2/gstwrappercamerabinsrc.h: + * tests/check/elements/camerabin2.c: + camerabin2: Rename v4l2camerasrc to wrappercamerabinsrc + Use a better name for the element that wraps single pad src element + into a 3pad source required by camerabin2. + +2010-12-14 16:59:54 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstv4l2camerasrc.c: + * gst/camerabin2/gstv4l2camerasrc.h: + v4l2camerasrc: remove video filter property code + Removes some unused custom video filter element property code + +2010-12-16 10:51:38 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstviewfinderbin.c: + viewfinderbin: Fix video-sink property again + Avoid switching the element on the set_property function, instead wait + for the next NULL -> READY transition. + +2010-12-14 14:48:28 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/elements/camerabin2.c: + camerabin2: Use videotestsrc on the tests + Use videotestsrc to avoid openning the camera device on the tests. + +2010-12-14 14:43:59 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstv4l2camerasrc.c: + v4l2camerasrc: add video-src property + Adds a property to select the src element to be used internally + on v4l2camerasrc. Yeah, I know, this element should have a better + name. + +2010-12-13 17:56:14 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/elements/camerabin2.c: + camerabin2: Add test for supported caps properties + Adds tests for checking that the supported caps properties work + as expected (using the respective pads get caps function) + +2010-12-14 08:44:36 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/PORTING: + camerabin2: adds PORTING document + Adds a PORTING document to explain the differences from + camerabin to camerabin2 and help application developers on + porting from one to another. + +2010-12-13 19:36:41 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * configure.ac: + * gst-libs/gst/Makefile.am: + * gst-libs/gst/basecamerabinsrc/Makefile.am: + * gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.c: + * gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.h: + * gst-libs/gst/basecamerabinsrc/gstcamerabin-enum.c: + * gst-libs/gst/basecamerabinsrc/gstcamerabin-enum.h: + * gst/camerabin2/Makefile.am: + * gst/camerabin2/gstbasecamerasrc.c: + * gst/camerabin2/gstbasecamerasrc.h: + * gst/camerabin2/gstcamerabin-enum.c: + * gst/camerabin2/gstcamerabin-enum.h: + * gst/camerabin2/gstcamerabin2.c: + * gst/camerabin2/gstv4l2camerasrc.c: + * gst/camerabin2/gstv4l2camerasrc.h: + * tests/check/Makefile.am: + * tests/check/elements/camerabin2.c: + camerabin2: Move basecamerasrc to gst-libs + Move the base camera src class to gst-libs/gst/basecamerabinsrc to + allow it to be included from the tests. + +2010-12-14 14:28:49 +0200 Teemu Katajisto <teemu.katajisto@digia.com> + + * gst/camerabin2/gstvideorecordingbin.c: + * gst/camerabin2/gstvideorecordingbin.h: + * tests/check/elements/videorecordingbin.c: + camerabin2: add videorecordingbin::video-muxer property + +2010-12-14 12:21:57 +0200 Teemu Katajisto <teemu.katajisto@digia.com> + + * gst/camerabin2/gstvideorecordingbin.c: + * gst/camerabin2/gstvideorecordingbin.h: + * tests/check/elements/videorecordingbin.c: + camerabin2: add videorecordingbin::video-encoder property + +2010-12-14 09:58:35 +0200 Teemu Katajisto <teemu.katajisto@digia.com> + + * gst/camerabin2/gstvideorecordingbin.c: + camerabin2: remove abbreviations from videorecordingbin + +2010-12-14 10:48:56 +0200 Teemu Katajisto <teemu.katajisto@digia.com> + + * gst/camerabin2/gstimagecapturebin.c: + camerabin2: imagecapturebin: release objects and memory allocations + +2010-12-13 16:36:19 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstcamerabin2.c: + * gst/camerabin2/gstcamerabin2.h: + camerabin2: Add camera-src property + Adds a property to select the camera source element to be used. + Changing only happens on the next NULL->READY transition + +2010-12-13 11:53:59 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstcamerabin2.c: + * gst/camerabin2/gstcamerabin2.h: + camerabin2: Rename variables + Use better name for the variables, making the code clearer. Also + keep a ref for some internal elements to avoid fetching them + by name when needed later. + +2010-12-12 23:03:21 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstbasecamerasrc.c: + * gst/camerabin2/gstcamerabin2.c: + camerabin2: Add properties for supported capture caps + Adds 2 property for getting the supported image/video capture + caps from the camera source. + +2010-12-12 20:46:16 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstbasecamerasrc.c: + * gst/camerabin2/gstcamerabin-enum.h: + * gst/camerabin2/gstv4l2camerasrc.c: + camerabin2: Put enums inside their classes .c + Remove global list of properties' enums and put them + inside their classes .c + +2010-12-12 19:33:24 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstcamerabin2.c: + * gst/camerabin2/gstviewfinderbin.c: + * gst/camerabin2/gstviewfinderbin.h: + * tests/check/elements/camerabin2.c: + viewfinderbin: Fixes to video-sink handling + Handle video-sink more carefully, checking if it should + be already added to the bin, and removing old ones when + replacing. + +2010-12-13 16:28:58 +0200 Teemu Katajisto <teemu.katajisto@digia.com> + + * gst/camerabin2/gstimagecapturebin.c: + * gst/camerabin2/gstimagecapturebin.h: + * tests/check/elements/imagecapturebin.c: + camerabin2: add imagecapturebin::image-muxer property + +2010-12-13 12:08:22 +0200 Teemu Katajisto <teemu.katajisto@digia.com> + + * gst/camerabin2/gstimagecapturebin.c: + * gst/camerabin2/gstimagecapturebin.h: + * tests/check/elements/imagecapturebin.c: + camerabin2: add imagecapturebin::image-encoder property + +2010-12-10 17:45:40 +0200 Teemu Katajisto <teemu.katajisto@digia.com> + + * gst/camerabin2/gstimagecapturebin.c: + camerabin2: remove abreviations from imagecapturebin + +2010-12-10 12:08:48 -0300 André Dieb Martins <andre.dieb@gmail.com> + + * gst/camerabin2/gstcamerabin2.c: + * gst/camerabin2/gstcamerabin2.h: + * gst/camerabin2/gstviewfinderbin.c: + * gst/camerabin2/gstviewfinderbin.h: + * tests/check/elements/camerabin2.c: + camerabin2: implement viewfinderbin::video-sink property to override default video output + +2010-12-09 14:13:13 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstbasecamerasrc.c: + basecamerasrc: Make construct_pipeline optional + Construct pipeline should be optional. Subclasses that don't + have internal elements don't need it. + +2010-12-09 12:23:01 +0200 Stefan Kost <ensonic@users.sf.net> + + * gst/camerabin2/gstbasecamerasrc.c: + * gst/camerabin2/gstbasecamerasrc.h: + basecamerasrc: write more details on the api docs + +2010-12-09 12:22:26 +0200 Stefan Kost <ensonic@users.sf.net> + + * gst/camerabin2/gstbasecamerasrc.h: + basecamerasrc: use the enum type for mode + +2010-12-09 12:21:16 +0200 Stefan Kost <ensonic@users.sf.net> + + * gst/camerabin2/gstbasecamerasrc.c: + basecamerasrc: comment cleanups + +2010-12-22 21:44:47 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/mpeg4videoparse/mpeg4videoparse.c: + mpeg4videoparse: ensure buffer metadata is writable before modifying it + https://bugzilla.gnome.org/show_bug.cgi?id=637824 + +2010-12-22 18:13:04 +0100 Edward Hervey <edward.hervey@collabora.co.uk> + + * gst/id3tag/gstid3mux.c: + id3mux: Set to GST_RANK_PRIMARY + We want it to take precedence over any other id3 formatter. + +2010-12-21 18:01:28 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/autoconvert/gstautoconvert.c: + autoconvert: Fix some more leaks and reorganize unref code + +2010-12-20 15:33:28 +0100 benjamin gaignard <benjamin.gaignard@stericsson> + + * gst/autoconvert/gstautoconvert.c: + autoconvert: Avoid some leaks in autoconvert + unref sink and src pad after gst_pad_by_direction calls unref + element if gst_auto_convert_activate_element failed. + See bug #637553. + +2010-12-21 17:03:43 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * tests/check/elements/asfmux.c: + asfmux: Fix buffer leak in the unit test + +2010-12-20 07:19:04 -0800 Saleem Abdulrasool <compnerd@compnerd.org> + + * tests/examples/camerabin/gst-camera.c: + camerabin: fix for latest GTK+ API changes + +2010-12-20 17:47:29 +0100 Edward Hervey <edward.hervey@collabora.co.uk> + + * common: + Automatic update of common submodule + From 169462a to 46445ad + +2010-12-20 11:06:52 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/elements/camerabin.c: + camerabin: Fix caps leaks + Fix some caps leaks on unit tests + +2010-12-20 09:37:22 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/elements/jifmux.c: + jifmux: Fix leaks on check test + Fix leaks in jifmux check test + +2010-12-20 13:51:03 +0200 Stefan Kost <ensonic@users.sf.net> + + * gst-libs/gst/interfaces/photography.c: + photography: use a flags type instead of the uint + Also use 0 as default and let the implementation set something that they support. + +2010-12-20 11:14:49 +0200 Hu Gang <gang.a.hu@intel.com> + + * gst-libs/gst/interfaces/photography.c: + * gst-libs/gst/interfaces/photography.h: + photography: add missing property and cabability flag for noise reduction + +2010-12-19 17:23:24 +0530 Olivier Crête <olivier.crete@collabora.co.uk> + + * tests/check/elements/autoconvert.c: + tests: Fix leak in autoconvert test + +2010-12-19 17:16:10 +0530 Olivier Crête <olivier.crete@collabora.co.uk> + + * gst/autoconvert/gstautoconvert.c: + autoconvert: Use gst_caps_can_intersect() + +2010-12-19 12:53:34 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/qtmux/gstqtmux.c: + qtmux: Free AtomInfo structs + +2010-12-19 12:50:30 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/qtmux/gstqtmux.c: + qtmux: Free tag string after use + +2010-12-19 12:12:25 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * tests/check/pipelines/tagschecking.c: + tagschecking: Fix some more memory leaks + +2010-12-19 12:12:12 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * tests/check/elements/imagecapturebin.c: + imagecapturebin: Don't leak message in the unit test + +2010-12-19 12:09:41 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/camerabin2/gstimagecapturebin.c: + imagecapturebin: Don't leak pad and sink + +2010-12-19 12:05:11 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/camerabin2/gstimagecapturebin.c: + imagecapturebin: Don't leak pad template created from static pad template + +2010-12-19 12:03:03 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/camerabin2/gstimagecapturebin.c: + imagecapturebin: Don't leak location string + +2010-12-19 12:00:25 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/jpegformat/gstjifmux.c: + jifmux: Don't leak taglist + +2010-12-19 11:38:03 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/autoconvert/gstautovideoconvert.c: + autovideoconvert: Don't leak pad templates created from static pad templates + +2010-12-19 11:20:25 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/autoconvert/gstautovideoconvert.c: + autovideoconvert: Add autoconvert child before chaining up to parent state change function + ...and remove/unlink autoconvert child when going back to NULL. + +2010-12-19 11:19:38 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * tests/check/Makefile.am: + states: Ignore more vdpau elements in the generic states test + +2010-12-19 11:17:47 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * Makefile.am: + * tests/check/Makefile.am: + * tests/check/elements/.gitignore: + * tests/check/elements/autocolorspace.c: + * tests/check/elements/autovideoconvert.c: + autovideoconvert: Rename and adjust unit test too + +2010-12-18 12:48:42 -0800 Leo Singer <leo.singer@ligo.org> + + * sys/applemedia/miovideosrc.c: + * sys/applemedia/qtkitvideosrc.m: + applemedia: fix compiler warning: redundant declaration of 'parent_class' + GST_BOILERPLATE_FULL declares parent_class as well. + https://bugzilla.gnome.org/show_bug.cgi?id=637532 + +2010-12-17 19:41:25 +0200 Lasse Laukkanen <lasse.laukkanen@digia.com> + + * gst/qtmux/gstqtmux.c: + qtmux: allow zero duration tracks + +2010-12-16 15:31:23 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/dvbsuboverlay/dvb-sub.c: + * gst/dvbsuboverlay/dvb-sub.h: + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: use GST_LOG etc. for logging + The dvbsub routines were originally designed as a mini lib with a + log callback (which from the looks of it in our case would always + be called and always assemble the string even with debug output + disabled). Some of these debug statements can probably be removed + or cleaned up some more. + +2010-12-16 00:19:13 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/dvbsuboverlay/ffmpeg-colorspace.h: + dvbsuboverlay: remove some unused defines + +2010-12-16 00:13:18 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: fix atomic access + +2010-12-16 15:33:45 +0000 Janne Grunau <janne.grunau@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: fix rendering artefacts + Initialize source x position for odd height special case. + +2010-12-16 11:29:07 +0100 Edward Hervey <edward.hervey@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: The enable property is a boolean and not an integer + +2010-12-16 09:56:00 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/autoconvert/Makefile.am: + * gst/autoconvert/gstautocolorspace.c: + * gst/autoconvert/gstautocolorspace.h: + * gst/autoconvert/gstautovideoconvert.c: + * gst/autoconvert/gstautovideoconvert.h: + * gst/autoconvert/plugin.c: + autoconvert: Rename autocolorspace to autovideoconvert + This doesn't just convert between color spaces. + +2010-12-15 12:45:38 -0800 David Schleef <ds@schleef.org> + + * tools/Makefile.am: + * tools/base.c: + * tools/element-maker: + * tools/element-templates/audiofilter: + * tools/element-templates/audiosink: + * tools/element-templates/audiosrc: + * tools/element-templates/base: + * tools/element-templates/baseaudiosink: + * tools/element-templates/baseaudiosrc: + * tools/element-templates/basertpdepayload: + * tools/element-templates/basertppayload: + * tools/element-templates/basesink: + * tools/element-templates/basesrc: + * tools/element-templates/basetransform: + * tools/element-templates/cddabasesrc: + * tools/element-templates/element: + * tools/element-templates/gobject: + * tools/element-templates/pushsrc: + * tools/element-templates/sinkpad: + * tools/element-templates/sinkpad-simple: + * tools/element-templates/srcpad: + * tools/element-templates/srcpad-simple: + * tools/element-templates/tagdemux: + * tools/element-templates/videosink: + * tools/gobject.c: + * tools/gst-element-maker: + * tools/gstaudiofilter.c: + * tools/gstaudiosink.c: + * tools/gstaudiosrc.c: + * tools/gstbaseaudiosink.c: + * tools/gstbaseaudiosrc.c: + * tools/gstbasertpdepayload.c: + * tools/gstbasertppayload.c: + * tools/gstbasesink.c: + * tools/gstbasesrc.c: + * tools/gstbasetransform.c: + * tools/gstcddabasesrc.c: + * tools/gstelement.c: + * tools/gstpushsrc.c: + * tools/gsttagdemux.c: + * tools/gstvideosink.c: + * tools/sinkpad-simple.c: + * tools/sinkpad.c: + * tools/srcpad-simple.c: + * tools/srcpad.c: + element-maker: Clean up directory + +2010-12-15 21:28:06 +0100 Benjamin Gaignard <benjamin.gaignard@stericsson.com> + + * gst/bayer/gstbayer2rgb.c: + bayer2rgb: Add framerate to the sink caps + Fixes bug #637224. + +2010-12-15 21:19:55 +0100 Benjamin Gaignard <benjamin.gaignard@stericsson.com> + + * tests/check/Makefile.am: + * tests/check/elements/autocolorspace.c: + autocolorspace: Add unit test + +2010-12-15 21:14:38 +0100 Benjamin Gaignard <benjamin.gaignard@stericsson.com> + + * gst/autoconvert/Makefile.am: + * gst/autoconvert/gstautocolorspace.c: + * gst/autoconvert/gstautocolorspace.h: + * gst/autoconvert/gstautoconvert.c: + * gst/autoconvert/plugin.c: + autocolorspace: Add autoconvert based video format convert element + Fixes bug #636106. + +2010-12-15 21:11:29 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: Rename DVB subtitling media type to subpicture/x-dvb + +2010-12-15 21:11:11 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/mpegdemux/gstmpegtsdemux.c: + mpegtsdemux: Rename DVB subtitling media type to subpicture/x-dvb + +2010-12-15 20:54:35 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: Don't draw anything on the video if the enable property is set to FALSE + +2010-12-15 20:53:21 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: Add #defines for the property default values + +2010-12-15 20:51:12 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: Use g_atomic_int_get() for reading the max_page_timeout field + +2010-12-15 20:49:57 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/mpegdemux/gstmpegtsdemux.c: + mpegtsdemux: Mark array static const and use G_N_ELEMENTS instead of sizeof + +2010-12-15 14:39:56 +0100 Janne Grunau <janne.grunau@collabora.co.uk> + + * gst/mpegdemux/gstmpegtsdemux.c: + mpegtsdemux: add DESC_DVB_SUBTITLING descriptor for language parsing + +2010-12-15 14:23:58 +0100 Janne Grunau <janne.grunau@collabora.co.uk> + + * gst/mpegdemux/gstmpegtsdemux.c: + mpegtsdemux: enable gather_pes only for DVB subtitle private streams + +2010-12-14 14:34:56 +0100 Janne Grunau <janne.grunau@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: use atomic instructions to set/get enable property + +2010-12-14 14:28:45 +0100 Janne Grunau <janne.grunau@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + * gst/dvbsuboverlay/gstdvbsuboverlay.h: + dvbsuboverlay: add property to limit page_time_out to a setable maximum + +2010-12-14 11:11:08 +0100 Janne Grunau <janne.grunau@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: implement display definition segment subtitle windows + simplifies subtitle scaling in blit_i420() + +2010-12-11 17:25:29 +0100 Janne Grunau <janne.grunau@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: scale subtitles according to the display size + Display size is either transmitted in the display definition segment or + implicitly defined to 720x576. The subtitle window information also present in + the display definition segment is not yet used. + +2010-12-11 17:10:25 +0100 Janne Grunau <janne.grunau@collabora.co.uk> + + * gst/dvbsuboverlay/dvb-sub.c: + * gst/dvbsuboverlay/dvb-sub.h: + dvbsuboverlay: implement display definition segment parsing + +2010-12-10 12:27:54 +0100 Janne Grunau <janne.grunau@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: fix luma stride for scaled subtitles (display width != width) + +2010-12-15 16:48:15 +0100 Edward Hervey <edward.hervey@collabora.co.uk> + + * ext/rsvg/gstrsvgoverlay.c: + rsvgoverlay: Don't set uint on an int property + +2010-12-15 14:56:19 +0200 Stefan Kost <ensonic@users.sf.net> + + * common: + Automatic update of common submodule + From 20742ae to 169462a + +2010-12-14 19:03:09 -0800 David Schleef <ds@schleef.org> + + * tools/Makefile.am: + * tools/element-maker: + * tools/gstaudiofilter.c: + * tools/gstaudiosink.c: + * tools/gstaudiosrc.c: + * tools/gstbaseaudiosink.c: + * tools/gstbaseaudiosrc.c: + * tools/gstbasertpdepayload.c: + * tools/gstbasertppayload.c: + * tools/gstbasesink.c: + * tools/gstbasesrc.c: + * tools/gstbasetransform.c: + * tools/gstcddabasesrc.c: + * tools/gstelement.c: + * tools/gstpushsrc.c: + * tools/gsttagdemux.c: + * tools/gstvideosink.c: + * tools/sinkpad-simple.c: + * tools/sinkpad.c: + * tools/srcpad-simple.c: + * tools/srcpad.c: + element-maker: improve generation of several classes + Better creation of pads, test and fix many other classes. Most + classes work now, although might not create functional elements. + +2010-12-13 23:32:30 -0800 David Schleef <ds@schleef.org> + + * configure.ac: + * gst/y4m/Makefile.am: + * gst/y4m/gsty4mdec.c: + * gst/y4m/gsty4mdec.h: + y4mdec: Add y4mdec + Feel the y4m love. It seeks. It works in pitivi. + +2010-12-13 23:15:05 +0000 Francis Rammeloo <francis.rammeloo@gmail.com> + + * sys/winscreencap/gstgdiscreencapsrc.c: + gdiscreencapsrc: fix memory leak + Structure members of ICONINFO struct filled by GetIconInfo() must + be deleted when no longer needed according to the API reference. + https://bugzilla.gnome.org/show_bug.cgi?id=611428 + +2010-12-13 16:23:37 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/jpegformat/gstjpegparse.c: + jpegparse: avoid leaking tag event + +2010-12-13 15:17:29 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstac3parse.c: + ac3parse: relax bsid checking + ... to the widest possible spec interpretation. + Fixes #637062. + +2010-12-13 16:23:45 +0200 Stefan Kost <ensonic@users.sf.net> + + * common: + Automatic update of common submodule + From 011bcc8 to 20742ae + +2010-12-12 23:34:02 +0000 Matthew Ife <matthew.ife@ukfast.co.uk> + + * gst/librfb/rfbdecoder.c: + * gst/librfb/rfbdecoder.h: + rfbsrc: fail more gracefully if source gets disconnected or geometry changes + Don't get caught in an infinite loop if the source gets disconnected and also + support gracefully failing upon detecting the frame geometry has increased + (rather than segfaulting). + https://bugzilla.gnome.org/show_bug.cgi?id=635397 + +2010-12-12 22:13:13 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/jpegformat/gstjpegparse.c: + jpegparse: avoid leaking converted comment string + +2010-12-12 12:01:38 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/videomeasure/gstvideomeasure_ssim.c: + ssim: Set classification to Filter/Analyzer/Video instead of Filter/Converter/Video + Fixes bug #636109. + +2010-12-12 02:24:00 +1100 Jan Schmidt <thaytan@noraisin.net> + + * gst/gaudieffects/burn-example.py: + * gst/gaudieffects/gstburn.c: + gaudieffects: Avoid divide by 0 in burn element + +2010-12-12 02:16:49 +1100 Jan Schmidt <thaytan@noraisin.net> + + * ext/resindvd/resindvdsrc.c: + * ext/resindvd/resindvdsrc.h: + resindvd: Defer pushing tag updates until streaming. + Push tag/title info updates in the streaming thread, avoiding + spurious losses of the downstream events when flushing. + See: https://bugzilla.gnome.org/show_bug.cgi?id=594222 + +2010-11-16 17:18:33 +1100 Jan Schmidt <thaytan@noraisin.net> + + * ext/resindvd/resindvdsrc.c: + resindvd: Attempt to use glib language setting for DVD menus/audio + +2010-11-16 17:09:06 +1100 Jan Schmidt <thaytan@noraisin.net> + + * ext/resindvd/resindvdsrc.c: + resindvd: Fix silly typo in button state tracking. + +2010-12-10 00:58:58 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/vtdec.c: + * sys/applemedia/vtenc.c: + applemedia: only enqueue buffers in the VideoToolbox callbacks + These callbacks may fire from any thread, hence we should only enqueue + buffers and let the streaming thread take care of the rest as soon as + the blocking encode or decode operation has finished. + +2010-11-19 15:53:55 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/coremediactx.h: + * sys/applemedia/cvapi.c: + * sys/applemedia/dynapi-internal.h: + * sys/applemedia/dynapi.c: + * sys/applemedia/dynapi.h: + applemedia: bring back Leopard compatibility + At least as far as miovideosrc is concerned. Turns out that CoreVideo's + CVPixelBufferGetIOSurface is not present in Leopard's version of CoreVideo. + We solve this by making it possible for symbols to be marked as optional. + +2010-11-29 13:47:11 +0100 Christian Berentsen <christian.berentsen@cisco.com> + + * sys/winks/ksvideohelpers.c: + winks: fix framerate fraction range mapping + Min and max may be slightly different but compress to the same fraction. + +2010-12-09 18:06:38 +0100 Wim Taymans <wim.taymans@collabora.co.uk> + + * ext/jp2k/gstjasperdec.c: + jasperdec: don't fail hard on decoding error + don't post an error and return GST_FLOW_ERROR on a simple decoding error. We can + just resume and continue decoding the next image. + +2010-12-09 11:54:17 +0100 Alessandro Decina <alessandro.decina@collabora.co.uk> + + * sys/applemedia/qtkitvideosrc.m: + qtkitvideosrc: reset the queue condition to NO_FRAMES in unlockStop. + Fixes a segfault in create: when going PLAYING -> PAUSED -> PLAYING. + +2010-12-09 11:04:19 +0100 Alessandro Decina <alessandro.decina@collabora.co.uk> + + * sys/applemedia/qtkitvideosrc.m: + qtkitvideosrc: run the mainRunLoop for a while if not running. + QTCaptureSession::addInput and QTCaptureSession::addOutput call + NSObject::performSelectorOnMainThread internally so they need the mainRunLoop to + run at least for a while to complete. + +2010-12-07 19:40:28 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstbasecamerasrc.c: + * gst/camerabin2/gstbasecamerasrc.h: + * gst/camerabin2/gstv4l2camerasrc.c: + * gst/camerabin2/gstv4l2camerasrc.h: + basecamerasrc: Remove ghostpads + Remove ghost pads from basecamerasrc. Different implementations + of camera sources might not use ghostpads and use default pads. + +2010-12-07 19:12:40 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstbasecamerasrc.c: + * gst/camerabin2/gstbasecamerasrc.h: + * gst/camerabin2/gstv4l2camerasrc.c: + basecamerasrc: Removing ununsed methods + Remove one unused method _finish_image_capture() + +2010-12-06 11:05:17 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/Makefile.am: + * tests/examples/Makefile.am: + camerabin2: Only run tests if experimental is enabled + Only run camerabin2 tests and build examples if experimental + plugins are enabled + +2010-12-06 10:06:37 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstbasecamerasrc.c: + * gst/camerabin2/gstv4l2camerasrc.c: + camerabin2: Cleanup + Removing commented code + +2010-12-05 11:18:09 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstbasecamerasrc.c: + * gst/camerabin2/gstbasecamerasrc.h: + * gst/camerabin2/gstv4l2camerasrc.c: + * gst/camerabin2/gstv4l2camerasrc.h: + basecamerasrc: Move start/stop capture signals to basecamerasrc + Move start/stop signals and ready-for-capture to basecamerasrc + as this should be present on all camera sources + +2010-12-04 10:15:34 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstbasecamerasrc.c: + * gst/camerabin2/gstbasecamerasrc.h: + * gst/camerabin2/gstv4l2camerasrc.c: + * gst/camerabin2/gstv4l2camerasrc.h: + basecamerasrc: Add mode property + Move mode property from v4l2camerasrc to basecamerasrc, as all + camera sources should handle it. + +2010-12-04 00:27:17 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstcamerabin2.c: + * gst/camerabin2/gstcamerabin2.h: + camerabin2: Reset all elements on video recording branch before capture + We need to reset the elements from the video recording branch, including + the queue and capsfilter in order to clear the eos state and activate + the pads. + This makes it possible to record multiple videos with camerabin2 in a + sequence, otherwise the source would get a unexpected return and + push EOS, stopping the whole pipeline. + +2010-12-03 12:13:07 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/elements/camerabin2.c: + camerabin2: Fix tests capture location creation + Fixes capture location creation to use multifilesink location + like strings. E.g. using capture_%d instead of capture_0 to let + camerabin2 handle the %d replacing + +2010-12-03 12:12:32 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstcamerabin2.c: + * gst/camerabin2/gstv4l2camerasrc.c: + camerabin2: More debug logs + Sprinkle some more debugging logs + +2010-12-03 12:11:59 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/examples/camerabin2/gst-camera2.c: + examples: camerabin2: Print more info + Add some printing for error/eos cases. + +2010-12-02 03:44:37 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstcamerabin2.c: + * gst/camerabin2/gstvideorecordingbin.c: + camerabin2: Various fixes + As video recording bin's state is locked, we should always + remember of setting it to NULL when camerabin2 goes to NULL + Be more careful when using elements that might not + have been created yet + And do not set location property recursively on videorecordingbin + +2010-12-02 03:08:52 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/Makefile.am: + * tests/check/elements/camerabin2.c: + camerabin2: Adding tests for camerabin2 + Adds some basic tests for camerabin2 + +2010-12-02 02:21:49 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/Makefile.am: + * tests/check/elements/.gitignore: + * tests/check/elements/imagecapturebin.c: + * tests/check/elements/videorecordingbin.c: + tests: camerabin2: adds tests for elements + Adds basic tests for both imagecapturebin and for + videorecordingbin elements + +2010-12-02 01:33:19 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstviewfinderbin.c: + viewfinderbin: Improve elements creation + Be more careful with cleanup of elements. Also add some logs and + improve docs a little. + +2010-12-02 00:19:05 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstcamerabin-enum.c: + * gst/camerabin2/gstcamerabin-enum.h: + camerabin2: remove unused code + General cleanup, removing unused bits + +2010-11-30 20:13:27 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * configure.ac: + * gst/camerabin2/gstcamerabin2.c: + * gst/camerabin2/gstcamerabin2.h: + * gst/camerabin2/gstimagecapturebin.c: + * gst/camerabin2/gstimagecapturebin.h: + * gst/camerabin2/gstvideorecordingbin.c: + * gst/camerabin2/gstvideorecordingbin.h: + camerabin2: adds location property + Adds a location property to enable applications to select + the captured files names. Locations are handled just like + multifilesink ones + Also disables -Wformat-nonliteral to allow to use non-literals + on g_strdup_printf on camerabin and generate a sequence of + locations for captures. + +2010-11-30 20:15:47 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstcamerabin2.c: + camerabin2: Fix set/get property function names + Add more consistency to the function names by using + gst_camera_bin as the other functions. + +2010-11-30 18:19:20 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstcamerabin2.c: + * gst/camerabin2/gstcamerabin2.h: + camerabin2: Handle vidbin state change individually + Keep vidbin state locked to avoid it going to playing without + being used and leaving an empty file created. + Check the docs on the code for details on the handling. + +2010-11-30 11:40:18 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * configure.ac: + * gst/camerabin2/gstcamerabin2.c: + camerabin2: Keep it under --enable-experimental + camerabin2 is still under heavy development, activate it only if + the --enable-experimental flag is on. + Also add a note to the docs. + +2010-11-30 11:06:33 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstcamerabin-enum.h: + * gst/camerabin2/gstv4l2camerasrc.c: + v4l2camerasrc: Add ready-for-capture property + Adds property that informs if v4l2camerasrc is available + for starting a new capture. + It is useful for applications to know (via deep-notify) when the + property changes and a new capture is possible. Note, however, that + starting a new capture from the notify callback will cause a deadlock. + +2010-11-30 09:28:50 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstcamerabin-enum.c: + * gst/camerabin2/gstcamerabin-enum.h: + * gst/camerabin2/gstcamerabin2.c: + * gst/camerabin2/gstcamerabin2.h: + * gst/camerabin2/gstv4l2camerasrc.c: + * gst/camerabin2/gstv4l2camerasrc.h: + camerabin2: Update v4l2camerasrc to use start/stop signals + Removes the old logic for v4l2camerasrc that used the mode + property switching to start/stop captures to make it identical + to camerabin2 behavior and to allow the future addition of + pausing a video recording. + This also removes the MODE_PREVIEW as it became useless. + +2010-11-29 18:53:34 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstcamerabin2.c: + * gst/camerabin2/gstcamerabin2.h: + camerabin2: Cleanup capturing flag + Cleanup capturing flag when the source switches back to the + viewfinder mode + +2010-11-29 18:24:35 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstv4l2camerasrc.h: + v4l2camerasrc: Remove unnecessary padding + +2010-11-29 15:49:26 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstv4l2camerasrc.c: + * gst/camerabin2/gstv4l2camerasrc.h: + v4l2camerasrc: Implement video capture + Implements video capture on v4l2camerasrc by using the mode property, + when mode is set to video, the pad probe pushes a new segment + and starts pushing buffers on the pad, when it the property is + sent back to preview, the pad probe pushes an EOS and stops + pushing buffers. + This is controlled by a Recording State variable, that is protected + by the GST_OBJECT_LOCK. I don't think locking for every buffer is + nice, so we could find an alternative lockless way here. + +2010-11-29 12:57:21 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstv4l2camerasrc.c: + v4l2camerasrc: Fix image capture + Once a image is captured, v4l2camerasrc should return to the + preview mode and stop capturing. + +2010-11-29 11:31:26 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstcamerabin-enum.c: + * gst/camerabin2/gstcamerabin2.c: + camerabin2: Keep mode definition at -enum file + Use 'mode' enum definition from gstcamerabin-enum file to avoid + conflicts between v4l2camerasrc and gstcamerabin2 modes. + For now there is a MODE_PREVIEW there that is only used on the + camerasrc, not sure if we are keeping it at the future, but for + now this works. + +2010-11-29 10:46:38 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstv4l2camerasrc.c: + v4l2camerasrc: Adds mode property + Adds mode property to v4l2camerasrc + +2010-11-29 10:45:30 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/camerabingeneral.c: + * gst/camerabin2/camerabingeneral.h: + * gst/camerabin2/gstcamerabin2.c: + * gst/camerabin2/gstv4l2camerasrc.c: + camerabin2: Adding debug categories + Adding debug categories to v4l2camerasrc and camerabin2, also + removing generic category from camerabingeneral. + +2010-11-26 23:55:12 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * configure.ac: + * tests/examples/Makefile.am: + * tests/examples/camerabin2/.gitignore: + * tests/examples/camerabin2/Makefile.am: + * tests/examples/camerabin2/gst-camera2.c: + * tests/examples/camerabin2/gst-camera2.h: + * tests/examples/camerabin2/gst-camera2.ui: + examples: Adds camerabin2 example + Adds gtk camerabin2 example app + +2010-11-26 17:24:58 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstcamerabin2.c: + * gst/camerabin2/gstcamerabin2.h: + camerabin2: Adding basic property and signals + Adds mode property to camerabin2, allowing users to + select between video and stills capture. Also adds + start/stop capture actions to trigger and stop + capturing + +2010-11-26 15:55:39 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstimagecapturebin.c: + * gst/camerabin2/gstvideorecordingbin.c: + camerabin2: Set filesink's async to FALSE + In order to preroll, camerabin2 should have its filesinks in + the imagecapturebin and videorecordingbin with async=FALSE. + +2010-11-26 14:51:30 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstcamerabin2.c: + camerabin2: Adding basic elements + Instantiating and linking basic elements on camerabin2 + so it at least shows the viewfinder when running. + +2010-11-26 10:14:46 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/Makefile.am: + * gst/camerabin2/gstcamerabin2.c: + * gst/camerabin2/gstcamerabin2.h: + * gst/camerabin2/gstplugin.c: + camerabin2: Adds a stub element for camerabin2 + Adds camerabin2 element, it is now a pile of stubs. + +2010-11-25 22:05:39 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstv4l2camerasrc.c: + camerabin2: v4l2camerasrc: Remove platform specific code + Remove platform specific code + +2010-11-25 21:49:47 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstbasecamerasrc.c: + * gst/camerabin2/gstv4l2camerasrc.c: + camerabin2: Removing uneeded properties + Removing uneeded and unregistered properties. + +2010-11-25 20:55:36 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstv4l2camerasrc.c: + camerabin2: v4l2camerasrc: Fix property warning + Avoid setting a property that doesn't exist. + +2010-11-25 20:53:04 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/gstv4l2camerasrc.c: + * gst/camerabin2/gstv4l2camerasrc.h: + camerabin2: v4l2camerasrc: Remove unused variable + Removed unused leftover variable + +2010-11-25 14:57:13 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/Makefile.am: + * gst/camerabin2/gstplugin.c: + * gst/camerabin2/gstvideorecordingbin.c: + * gst/camerabin2/gstvideorecordingbin.h: + camerabin2: Adds video recording bin + Adds an bin that is responsible for encoding and saving video + streams to files. + For now it is simply a ffmpegcolorspace ! theoraenc ! oggmux ! + filesink bin. + Still uncapable of recording audio. + +2010-11-25 13:00:50 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/Makefile.am: + * gst/camerabin2/camerabingeneral.c: + * gst/camerabin2/camerabingeneral.h: + * gst/camerabin2/gstbasecamerasrc.c: + * gst/camerabin2/gstbasecamerasrc.h: + * gst/camerabin2/gstcamerabin-enum.c: + * gst/camerabin2/gstcamerabin-enum.h: + * gst/camerabin2/gstplugin.c: + * gst/camerabin2/gstv4l2camerasrc.c: + * gst/camerabin2/gstv4l2camerasrc.h: + camerabin2: Adding v4l2camerasrc from robclark's branch + Adds 3-pad v4l2 camera source from Rob Clark's camerabin + branch on http://gitorious.org/robclark-gstreamer/gst-plugins-bad + +2010-11-24 20:31:33 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/Makefile.am: + * gst/camerabin2/gstimagecapturebin.c: + * gst/camerabin2/gstimagecapturebin.h: + * gst/camerabin2/gstplugin.c: + camerabin2: Adds new imagecapturebin + Adds an bin that is responsible for image captures. + It is a simple ffmpegcolorspace ! jpegenc ! jifmux ! multifilesink + for now. + +2010-11-24 20:15:38 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin2/Makefile.am: + * gst/camerabin2/gstplugin.c: + * gst/camerabin2/gstviewfinderbin.c: + * gst/camerabin2/gstviewfinderbin.h: + camerabin2: Move plugin init to a separate file + Moves plugin init to gstplugin.c to allow multiple + elements to register themselves. + +2010-11-24 17:28:57 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * configure.ac: + * gst/camerabin2/Makefile.am: + * gst/camerabin2/gstviewfinderbin.c: + * gst/camerabin2/gstviewfinderbin.h: + camerabin2: viewfinderbin: Adds viewfinderbin element + Adds viewfinder bin element, one of the modules of camerabin2 + that is responsible for displaying the video from the camera. + For now it is only a bin with ffmpegcolorspace ! videoscale ! + autovideosink + +2010-12-08 19:36:48 +0100 Alessandro Decina <alessandro.d@gmail.com> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: fix compiler warnings on OSX. + +2010-11-24 12:22:01 +0200 Stefan Kost <ensonic@users.sf.net> + + * tests/icles/output-selector-test.c: + output-selector-test: don't hardcode videosinks and use more colorspace conv. + Use autovideosink instead of hardcoded sinks. Use an additional colorspace + converter between videotestsrc and timeoverlay. + +2010-12-08 15:18:32 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * configure.ac: + configure: require released versions of core/base instead of old git + +2010-12-07 15:44:00 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/mpeg4videoparse/mpeg4videoparse.c: + mpeg4videoparse: re-use cleanup() in finalize() + ... and also favor finalize() rather than dispose(). + +2010-11-18 13:39:23 +0530 Arun Raghavan <arun.raghavan@collabora.co.uk> + + * gst/mpeg4videoparse/mpeg4videoparse.c: + * gst/mpeg4videoparse/mpeg4videoparse.h: + mpeg4videoparse: Set srcpad caps before forwarding newsegment + This holds all newsegement and most other events till there is enough + data to set srcpad caps, so that the downstream link is properly + negotiated before data starts flowing. + https://bugzilla.gnome.org/show_bug.cgi?id=635204 + +2010-11-18 23:29:51 +0530 Arun Raghavan <arun.raghavan@collabora.co.uk> + + * gst/mpeg4videoparse/mpeg4videoparse.c: + * gst/mpeg4videoparse/mpeg4videoparse.h: + mpeg4videoparse: Use sinkpad caps as base for srcpad caps + This way, we don't lose additional fields that come from upstream (like + profile/level for now). + https://bugzilla.gnome.org/show_bug.cgi?id=635202 + +2010-12-07 15:20:29 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/mpeg4videoparse/mpeg4videoparse.c: + mpeg4videoparse: minor fix to error handling + We weren't handling unparseable codec_data in some cases. + https://bugzilla.gnome.org/show_bug.cgi?id=635202 + +2010-12-07 17:17:44 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: Implement nearest neighbour scaling for the subpictures + This becomes necessary when SDTV subtitles are used for HDTV videos. + +2010-12-07 14:55:28 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/h264parse/gsth264parse.c: + h264parse: align code with comment + +2010-12-07 14:55:15 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/h264parse/gsth264parse.c: + h264parse: re-use reset() in finalize() + +2010-11-17 19:16:12 +0530 Arun Raghavan <arun.raghavan@collabora.co.uk> + + * gst/h264parse/gsth264parse.c: + * gst/h264parse/gsth264parse.h: + h264parse: Set srcpad caps before forwarding newsegment + This holds all newsegement and most other events till there is enough + data to set srcpad caps, so that the downstream link is properly + negotiated before data starts flowing. + https://bugzilla.gnome.org/show_bug.cgi?id=635205 + +2010-12-06 19:00:28 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/jpegformat/gstjpegparse.c: + jpegparse: try to convert comment tag to UTF-8 + +2010-12-06 18:19:20 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/jpegformat/gstjpegparse.c: + jpegparse: discard incomplete image + ... as determined when finding SOI next image before an EOI. + +2010-12-06 18:18:11 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/jpegformat/gstjpegparse.c: + jpegparse: avoid infinite loop when resyncing + +2010-12-06 22:48:09 +0530 Arun Raghavan <arun.raghavan@collabora.co.uk> + + * gst/rawparse/gstaudioparse.c: + audioparse: Allow implicit channel map for 1-/2-channel audio + This makes sure we don't set an empty channel map array for 1-/2-channel + audio, causing an assert later on. + +2010-12-06 17:08:55 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: Revert some parts of last commit that shouldn't be committed + +2010-12-06 17:05:28 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: Really choose the latest possible subpictures + And not the first subpictures that are still valid according to the + page timeout. + +2010-12-06 16:44:11 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: Refactor blending function and take average of all chroma values + +2010-12-03 17:35:36 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: Improve selection of current to be displayed subpictures + Drop all subpictures that are too old anyway and clear the currently + displayed subpictures if num_rects==0 happens. + +2010-12-03 16:21:15 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: Implement clipping of video buffers + Also don't clip subpicture buffers, they have no duration and + clipping them doesn't make much sense here. + +2010-12-03 16:08:13 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + * gst/dvbsuboverlay/gstdvbsuboverlay.h: + dvbsuboverlay: Clean up locking some more + +2010-12-03 16:05:56 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: Flush subtitles and all internal state when needed + +2010-12-03 15:52:21 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: Set the global library log function exactly once + And don't use one of the possibly many renderer instances, this is only + calling for crashes. + +2010-12-03 15:46:40 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + * gst/dvbsuboverlay/gstdvbsuboverlay.h: + dvbsuboverlay: Remove lots of commented out and unused code and clean up locking + +2010-12-01 09:59:14 +0200 Mart Raudsepp <mart.raudsepp@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: Fix more of the blending, so it looks quite good now + * libdvbsub gives us alpha channel already, not transparency level, so + don't do another "alpha = 255 - alpha", this is done by libdvbsub. + * Fix alpha channel handling in interpolation - assrender had an additional + 1bpp alpha bitmap as a possible mask, we don't. So don't use the palette + index array as alpha values; bug from quick code porting long ago to + changing pixel colors (assrender has a single pixel color for whole + regions or something, unlike dvbsub, which has indexed colors). + * Don't forget to reassign our YUV and other local pixel color variables + after shifting to work on the bottom part of a 2x2 subsample block, or + it's obviously very blocky. + Remaining issues in blending: + * Should probably be interpolating or doing something else useful with the + resulting U and V channels, so that most of the source pixel UV values would + actually be actually cared about, except for just one out of possibly four. + * Don't convert AYUV to ARGB in libdvbsub, and then back from ARGB to AYUV in + dvbsuboverlay for no reason + * Re-factor the whole thing to something more like textoverlay blending + * Related to that, perhaps cache the current spu in a good format for quick + blending on each frame, after which the more often called blending parts + might become more straightforward + +2010-12-01 07:26:03 +0200 Mart Raudsepp <mart.raudsepp@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: Fix blending bug regarding color channel addressing. + libdvbsub gives us ARGB ordered pixels right now, not RGBA. + +2010-12-01 07:20:07 +0200 Mart Raudsepp <mart.raudsepp@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: Do blending calls when appropriate + This gives us actually shown subtitles, however with bugs in the + current blitting code, resulting in very transparent subtitles. + +2010-12-01 07:06:35 +0200 Mart Raudsepp <mart.raudsepp@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: Implement fallback page_time_out honoring + The spec has a page_time_out in the page composition segment to ensure + subtitles don't get stuck on screen for too much longer than intended, + when future page composition segments get lost on bad reception, or other + problems. Honor it in the gst plugin side. + +2010-12-01 06:01:15 +0200 Mart Raudsepp <mart.raudsepp@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + * gst/dvbsuboverlay/gstdvbsuboverlay.h: + dvbsuboverlay: Implement subtitle queueing and syncing with video + Push incoming subtitle pages in a FIFO queue (pending_subtitles) + and dequeue the head when it's time to show it (when video running + time reaches the subtitle page running time). + Keep the subtitle page, that is supposed to be blended on top of video + currently, in a separate object variable (current_subtitle). As a + next step we can then pre-render current_subtitle to a better to blend + format. + +2010-12-01 05:49:22 +0200 Mart Raudsepp <mart.raudsepp@collabora.co.uk> + + * gst/dvbsuboverlay/dvb-sub.c: + dvbsuboverlay: Make the new dvb_subtitles_free() accept NULL + Don't crash if dvb_subtitles_free(NULL) gets passed, like most other + *_free functions are happy with. + +2010-12-01 05:26:02 +0200 Mart Raudsepp <mart.raudsepp@collabora.co.uk> + + * gst/dvbsuboverlay/dvb-sub.c: + * gst/dvbsuboverlay/dvb-sub.h: + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: Pass page_time_out and pts with the DVBSubtitles structure + Eases holding onto the information in gst plugins side queue of + DVBSubtitles, so we won't need to create yet another temporary struct + to keep the pts and page_time_out too. + And this really logically belongs at the toplevel information set anyway + and in that struct... + +2010-12-01 04:28:02 +0200 Mart Raudsepp <mart.raudsepp@collabora.co.uk> + + * gst/dvbsuboverlay/dvb-sub.c: + * gst/dvbsuboverlay/dvb-sub.h: + dvbsuboverlay: Make the libdvbsub callback handler responsible for memory cleanup + We want to allow queueing of raw region image data in the gst plugin side, + and keep the data around until we pop the item from the queue. So make + the callback handler responsible for memory cleanup, if one is installed. + +2010-11-30 04:45:54 +0200 Mart Raudsepp <mart.raudsepp@collabora.co.uk> + + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + dvbsuboverlay: Work with GstClockTime instead of PTS for subtitle timing + Abuse libdvbsub PTS tracking to just store our running time in it, to get + it back in the callbacks. As GStreamer does its own PTS handling behind our + back (especially for video), we should just sync with video per running time, + not try to do it with PTS, which doesn't seem well accessible for video chain. + We can later relabel dvb-sub.c pts naming convention if wanted, it's just + passing along guint64 values, which GstClockTime fortunately is too. + The current idea is to collect the regions returned by the callback into + a FIFO buffer and pop and pre-render the top one into a separate + quick-to-blend cached format, which is then appropriately blended in the + video chain until the next one on top of the stack reaches the video chains + running time (or the fallback timer hits). + +2010-11-30 03:56:32 +0200 Mart Raudsepp <mart.raudsepp@collabora.co.uk> + + * gst/dvbsuboverlay/dvb-sub.c: + dvbsuboverlay: Add FIXME note about non-constant PTS for a display set handling. + +2010-11-30 03:47:46 +0200 Mart Raudsepp <mart.raudsepp@collabora.co.uk> + + * gst/dvbsuboverlay/dvb-sub.c: + * gst/dvbsuboverlay/dvb-sub.h: + dvbsuboverlay: Remove dvb_sub_feed() API + GStreamer will only use dvb_sub_feed_with_pts, as it has its own PES filter + to do the header parsing. + +2010-11-29 20:55:30 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/dvbsuboverlay/TODO: + dvbsuboverlay: more TODO + +2010-11-29 20:10:17 +0000 Mart Raudsepp <mart.raudsepp@collabora.co.uk> + + * gst/mpegdemux/gstmpegtsdemux.c: + gstmpegtsdemux: add temporary **HACK** for dvb subs testing so dvbsuboverlay gets whole packets + <tpm> leio, what's the mpegts demux hack about? + <leio> my libdvbsub code can't handle cut packets + <leio> so the hack instructs the demuxer to gather full packets before pushing down, but it applies that to more PES packet types than just dvbsub, but I'm not sure if that's a bad thing + <leio> either way, needs a cleaner solution, either in demuxer, or I need to handle cut packets + <tpm> ok, but really it should be fixed in the overlay, right? + <tpm> or a parser be inserted + <leio> the problem is that I don't know from the first packet beforehand if it is a cut one or no + <leio> not + <leio> err, first buffer + <leio> just when I receive the next one I see if it has a valid timestamp on it or not + <leio> so I can't very well queue it up in the chain either, I might be blocking the very last subtitle for no reason or something + <tpm> but you could just drop/ignore packets until you find one, right? + <leio> find what? + <tpm> a complete packet? + <leio> the problem isn't that they aren't complete + <leio> the problem is that they are cut across multiple GstBuffers by the demuxer without the hack + <tpm> sure, I understand that + <tpm> but you can't easily determine if a GstBuffer contains he start fragment of a packet or not? + <leio> I guess I could parse the packet and see if its length is enough, just like the libdvbsub code eventually does too + <leio> I can, it has a timestamp if it's the first chunk + <leio> I just never know if I need to wait for more, without some parsing + <tpm> ah ok + <leio> while the demuxer could just give me an uncut one in the first place + <leio> like it always does for program streams + <leio> that gather_pes is always set in gstmpegdemux, but not in gstmpegtsdemux + +2010-11-29 20:06:07 +0000 Mart Raudsepp <mart.raudsepp@collabora.co.uk> + + * configure.ac: + * gst/dvbsuboverlay/Makefile.am: + * gst/dvbsuboverlay/TODO: + * gst/dvbsuboverlay/dvb-sub.c: + * gst/dvbsuboverlay/dvb-sub.h: + * gst/dvbsuboverlay/ffmpeg-colorspace.h: + * gst/dvbsuboverlay/gstdvbsuboverlay.c: + * gst/dvbsuboverlay/gstdvbsuboverlay.h: + dvbsuboverlay: initial version, work in progress + +2010-12-03 18:11:56 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstaacparse.c: + * gst/audioparsers/gstac3parse.c: + * gst/audioparsers/gstamrparse.c: + audioparsers: update some documentation + +2010-12-03 18:11:38 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * docs/plugins/Makefile.am: + * docs/plugins/gst-plugins-bad-plugins-docs.sgml: + * docs/plugins/gst-plugins-bad-plugins-sections.txt: + * gst/audioparsers/gstmpegaudioparse.c: + mpegaudioparse: add to documentation + +2010-12-03 18:11:09 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * docs/plugins/Makefile.am: + * docs/plugins/gst-plugins-bad-plugins-docs.sgml: + * docs/plugins/gst-plugins-bad-plugins-sections.txt: + * gst/audioparsers/gstdcaparse.c: + dcaparse: add to documentation + +2010-12-03 18:09:41 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * docs/plugins/Makefile.am: + * docs/plugins/gst-plugins-bad-plugins-docs.sgml: + * docs/plugins/gst-plugins-bad-plugins-sections.txt: + * gst/qtmux/gstqtmux.c: + qtmux: add documentation + +2010-11-08 19:58:31 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: increase keyframe awareness + ... which is not particular relevant for audio parsing, but more so + in video cases. In particular, auto-determine if dealing with video (caps). + +2010-12-03 17:46:27 +0100 Benjamin Gaignard <benjamin.gaignard@stericsson.com> + + * Android.mk: + * sys/audioflingersink/Android.mk: + * sys/audioflingersink/GstAndroid.cpp: + * sys/audioflingersink/audioflinger_wrapper.cpp: + * sys/audioflingersink/audioflinger_wrapper.h: + * sys/audioflingersink/gstaudioflingerringbuffer.h: + * sys/audioflingersink/gstaudioflingersink.c: + * sys/audioflingersink/gstaudioflingersink.h: + sys: Add android audioflingersink + +2010-12-03 17:42:46 +0100 Benjamin Gaignard <benjamin.gaignard@stericsson.com> + + * Android.mk: + * android/NOTICE: + * android/aacparse.mk: + * android/amrparse.mk: + * android/h264parse.mk: + * android/metadata.mk: + * android/qtmux.mk: + * android/sdpelem.mk: + Add build system for Android + +2010-12-02 15:45:02 +0200 Stefan Kost <ensonic@users.sf.net> + + * gst/camerabin/gstcamerabin.c: + camerabin: smal api doc update + +2010-12-02 05:39:14 -0300 Lasse Laukkanen <ext-lasse.2.laukkanen@nokia.com> + + * gst/camerabin/gstcamerabin.c: + camerabin: Avoid assertion on image finishing + As imgbin_finished() is scheduled from g_idle_add, it might + be run a little later than expected, this can lead to the application + setting camerabin to ready before imgbin_finished() runs. In this case, + the processing counter goes to 0 and an assertion happens. + This patch relaxes the imgbin_finished() check on the processing + counter. + +2010-12-01 23:14:56 -0800 David Schleef <ds@schleef.org> + + * tools/element-maker: + element-maker: Handle names with multiple underscores + +2010-12-01 23:04:57 -0800 David Schleef <ds@schleef.org> + + * gst/debugutils/Makefile.am: + * gst/debugutils/debugutilsbad.c: + * gst/debugutils/gstchopmydata.c: + * gst/debugutils/gstchopmydata.h: + chopmydata: Add new element + This element splits up a stream into randomly-sized buffers. + Useful (maybe) for testing parsers. + +2010-12-02 03:09:59 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/Makefile.am: + tests: Remove leftover comment + Remove comment that doesn't make sense anymore + +2010-12-01 23:21:33 +0100 Alessandro Decina <alessandro.d@gmail.com> + + * sys/applemedia/miovideosrc.c: + applemedia: don't use the deprecated g_strcasecmp function. + Replace g_strcasecmp with g_ascii_strcasecmp. + +2010-12-01 23:20:36 +0100 Alessandro Decina <alessandro.d@gmail.com> + + * gst/pcapparse/gstpcapparse.c: + * sys/applemedia/mioapi.c: + Fix compiler warnings with gcc 4.2.1 on OSX. + +2010-12-01 15:28:53 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstac3parse.c: + * gst/audioparsers/gstac3parse.h: + ac3parse: use proper EAC-3 caps + +2010-12-01 10:45:49 +0100 David Hoyt <dhoyt@llnl.gov> + + * gst/qtmux/gstqtmux.c: + qtmux: handle msvc ftruncate incompatibility + Fixes #636185. + +2010-10-09 17:39:36 -0700 David Schleef <ds@schleef.org> + + * tests/check/Makefile.am: + * tests/check/elements/schroenc.c: + Add a schroenc test + +2010-11-27 20:13:38 -0800 David Schleef <ds@schleef.org> + + * ext/dirac/gstdiracdec.cc: + * gst/liveadder/liveadder.c: + * gst/mpegpsmux/mpegpsmux.c: + * gst/pnm/gstpnmdec.c: + * gst/pnm/gstpnmenc.c: + Fix pad template memleaks + Pad templates returned by gst_static_pad_template_get() were not + being unreffed. + +2010-11-30 18:43:24 -0800 David Schleef <ds@schleef.org> + + * ext/vp8/gstvp8enc.c: + vp8enc: Readd setting of granulepos + Revert parts of last patch that removed setting of granulepos. + oggmux still requires correct granulepos in incoming packet. + +2010-11-29 20:21:31 -0800 David Schleef <ds@schleef.org> + + * ext/vp8/gstvp8enc.c: + vp8enc: Don't override timestamps set by base class + Because the base class does it correctly. + Fixes: #635720, #625558. + +2010-11-30 15:41:02 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: avoid unexpected stray metadata + +2010-11-30 15:40:28 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: use proper _NONE output value when applicable + +2010-11-15 20:03:01 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * configure.ac: + * gst/jp2kdecimator/Makefile.am: + * gst/jp2kdecimator/gstjp2kdecimator.c: + * gst/jp2kdecimator/gstjp2kdecimator.h: + * gst/jp2kdecimator/jp2kcodestream.c: + * gst/jp2kdecimator/jp2kcodestream.h: + jp2kdecimator: Add a JPEG2000 decimator element + This element drops information from JPEG2000 images without reencoding. + +2010-11-23 21:45:41 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * ext/jp2k/gstjasperenc.c: + jp2kenc: Emit SOP markers in every codestream packet + This makes parsing much easier, faster and more reliable. + +2010-11-27 16:07:19 -0600 Alejandro Gonzalez <agonzalez@dextratech.com> + + * gst/qtmux/gstqtmux.c: + qtmux: gst_qtmux_check_difference verify before subtract + Avoid negative overflow by checking the order of operands + on subtraction of unsigned integers. + https://bugzilla.gnome.org/show_bug.cgi?id=635878 + +2010-11-27 18:58:07 -0800 David Schleef <ds@schleef.org> + + * gst/mpegtsmux/mpegtsmux.c: + mpegtsmux: Fix some memleaks + +2010-11-15 11:37:39 -0800 David Schleef <ds@schleef.org> + + * ext/schroedinger/gstschroenc.c: + schroenc: minor memleak fix + +2010-11-25 19:31:35 +0100 Edward Hervey <bilboed@bilboed.com> + + * gst-libs/gst/signalprocessor/gstsignalprocessor.c: + signalprocessor: Remove dead assignments + +2010-11-25 19:31:03 +0100 Edward Hervey <bilboed@bilboed.com> + + * gst/videomeasure/gstvideomeasure_collector.c: + * gst/videomeasure/gstvideomeasure_ssim.c: + videomeasure: Remove dead assignments + +2010-11-25 19:25:27 +0100 Edward Hervey <bilboed@bilboed.com> + + * gst/tta/gstttadec.c: + * gst/tta/gstttaparse.c: + tta: Remove dead assignments and useless variable + +2010-11-25 19:24:56 +0100 Edward Hervey <bilboed@bilboed.com> + + * gst/stereo/gststereo.c: + stereo: Remove dead assignments + +2010-11-25 19:21:23 +0100 Edward Hervey <bilboed@bilboed.com> + + * gst/sdp/gstsdpdemux.c: + sdp: Remove useless variables + +2010-11-25 19:21:11 +0100 Edward Hervey <bilboed@bilboed.com> + + * gst/rtpmux/gstrtpmux.c: + rtpmux: Remove dead assignments + +2010-11-25 19:21:01 +0100 Edward Hervey <bilboed@bilboed.com> + + * gst/real/gstrealaudiodec.c: + * gst/real/gstrealvideodec.c: + real: Remove dead assignments + +2010-11-25 19:20:51 +0100 Edward Hervey <bilboed@bilboed.com> + + * gst/ivfparse/gstivfparse.c: + ivfparse: Remove dead assignments + +2010-11-25 19:06:49 +0100 Edward Hervey <bilboed@bilboed.com> + + * gst/freeze/gstfreeze.c: + freeze: Remove dead assignments + +2010-11-25 19:06:38 +0100 Edward Hervey <bilboed@bilboed.com> + + * gst/dvdspu/gstdvdspu.c: + dvdspu: Remove dead assignments + +2010-11-25 19:06:27 +0100 Edward Hervey <bilboed@bilboed.com> + + * gst/dtmf/gstrtpdtmfdepay.c: + dtmf: Remove dead assignments + +2010-11-25 19:01:42 +0100 Edward Hervey <bilboed@bilboed.com> + + * gst/dccp/gstdccp.c: + dccp: Remove dead assignments + +2010-11-25 18:56:42 +0100 Edward Hervey <bilboed@bilboed.com> + + * gst/audioparsers/gstaacparse.c: + * gst/audioparsers/gstamrparse.c: + * gst/audioparsers/gstbaseparse.c: + audioparsers: Remove dead assignments + +2010-11-25 18:52:47 +0100 Edward Hervey <bilboed@bilboed.com> + + * ext/vp8/gstvp8dec.c: + * ext/vp8/gstvp8enc.c: + vp8: Remove dead assignments + +2010-11-25 18:49:23 +0100 Edward Hervey <bilboed@bilboed.com> + + * ext/sdl/sdlaudiosink.c: + sdlaudiosink: Remove dead assignments + +2010-11-25 18:47:15 +0100 Edward Hervey <bilboed@bilboed.com> + + * ext/schroedinger/gstschrodec.c: + * ext/schroedinger/gstschroenc.c: + * ext/schroedinger/gstschroparse.c: + schroedinger: Remove dead assignments + +2010-11-25 18:43:30 +0100 Edward Hervey <bilboed@bilboed.com> + + * ext/mimic/gstmimenc.c: + mimenc: Remove dead assignment + +2010-11-25 18:43:18 +0100 Edward Hervey <bilboed@bilboed.com> + + * ext/cog/gstcogdownsample.c: + cogdownsample: Remove dead assignment + +2010-11-25 18:42:33 +0100 Edward Hervey <bilboed@bilboed.com> + + * ext/opencv/gstcvdilateerode.c: + * ext/opencv/gstcvlaplace.c: + * ext/opencv/gstcvsmooth.c: + * ext/opencv/gstcvsobel.c: + * ext/opencv/gstedgedetect.c: + * ext/opencv/gstfaceblur.c: + * ext/opencv/gstfacedetect.c: + * ext/opencv/gstopencvutils.c: + * ext/opencv/gstopencvvideofilter.c: + * ext/opencv/gstpyramidsegment.c: + * ext/opencv/gsttemplatematch.c: + * ext/opencv/gsttextwrite.c: + opencv: Remove dead assignments + ... and fix indentation + +2010-11-25 18:33:37 +0100 Edward Hervey <bilboed@bilboed.com> + + * ext/cog/gstcogcolorspace.c: + cogcolorspace: Remove dead assignment + +2010-11-25 18:30:56 +0100 Edward Hervey <bilboed@bilboed.com> + + * ext/cog/cogframe.c: + cogframe: Remove dead assignments + +2010-11-25 18:29:31 +0100 Edward Hervey <bilboed@bilboed.com> + + * ext/celt/gstceltenc.c: + celtenc: Initialize variable + In the case the tag_setter returns something, empty_tags would be + garbage value. + +2010-11-25 18:29:22 +0100 Edward Hervey <bilboed@bilboed.com> + + * ext/celt/gstceltenc.c: + celtenc: Remove dead assignment + +2010-11-25 18:26:21 +0100 Edward Hervey <bilboed@bilboed.com> + + * ext/assrender/gstassrender.c: + assrender: Remove dead assignments + +2010-11-25 17:14:23 +0100 Andoni Morales Alastruey <amorales@flumotion.com> + + * gst/audioparsers/gstbaseparse.c: + audioparse: fix possible division-by-zero + https://bugzilla.gnome.org/show_bug.cgi?id=635786 + +2010-10-23 01:56:04 +0200 Olivier Crête <olivier.crete@collabora.co.uk> + + * sys/shm/shmpipe.c: + shm: Don't pass the ShmPipe to the function closing the shm area + +2010-10-23 01:22:43 +0200 Olivier Crête <olivier.crete@collabora.co.uk> + + * sys/shm/shmpipe.c: + shm: Use the right counter when freeing buffers + +2010-10-23 01:12:49 +0200 Olivier Crête <olivier.crete@collabora.co.uk> + + * sys/shm/Makefile.am: + * sys/shm/shmalloc.h: + shmalloc: Manually decide to use GLib or not in the shmalloc + So make it easier for embedders to use it with or without Glib + +2010-10-20 22:49:59 +0200 Olivier Crête <olivier.crete@collabora.co.uk> + + * sys/shm/shmpipe.c: + shm: Remove duplicated arguement + +2010-10-20 22:39:21 +0200 Olivier Crête <olivier.crete@collabora.co.uk> + + * sys/shm/shmpipe.c: + shm: Fix socket leak on connect() error + +2010-10-20 22:28:13 +0200 Olivier Crête <olivier.crete@collabora.co.uk> + + * sys/shm/shmpipe.c: + * sys/shm/shmpipe.h: + shm: sp_client_recv returns negative on error, so make the retval signed + +2010-10-20 22:17:30 +0200 Olivier Crête <olivier.crete@collabora.co.uk> + + * sys/shm/shmpipe.c: + shm: Rename confusingly named variable + +2010-10-20 22:14:09 +0200 Olivier Crête <olivier.crete@collabora.co.uk> + + * sys/shm/shmpipe.c: + shm: Change permissions on old shm areas too + Change the permissions on old shm areas + +2010-10-20 22:01:36 +0200 Olivier Crête <olivier.crete@collabora.co.uk> + + * sys/shm/shmpipe.c: + shm: Use the macro for the last error too + +2010-10-20 21:52:31 +0200 Olivier Crête <olivier.crete@collabora.co.uk> + + * sys/shm/shmpipe.c: + shm: Use "ablock" for all ShmAllocBlock variables + Use the ablock variable name for ShmAllocBlocks and block for + ShmBlock + +2010-10-20 21:52:24 +0200 Olivier Crête <olivier.crete@collabora.co.uk> + + * sys/shm/shmpipe.h: + shm: Add more comments + +2010-10-20 21:41:15 +0200 Youness Alaoui <youness.alaoui@collabora.co.uk> + + * sys/shm/shmpipe.c: + shm: stylist improvements + +2010-10-20 21:33:24 +0200 Youness Alaoui <youness.alaoui@collabora.co.uk> + + * sys/shm/shmalloc.c: + shm: Explain some fields + Explain what some of the fields in the allocator actually mean + +2010-11-22 15:26:06 +0100 Robert Swain <robert.swain@collabora.co.uk> + + * gst/interlace/gstinterlace.c: + interlace: Fix buffer timestamp and duration + The field rate is twice the frame rate of the src pad and so the duration of + one output buffer is src_fps_d / (2 * src_fps_n). + +2010-11-22 10:29:56 +0100 Robert Swain <robert.swain@collabora.co.uk> + + * gst/interlace/gstinterlace.c: + interlace: Rename pattern property to field-pattern + This is mostly for clarity of what the property means and, I believe, makes the + pattern-offset property more comprehensible. + +2010-11-22 10:27:22 +0100 Robert Swain <robert.swain@collabora.co.uk> + + * gst/interlace/gstinterlace.c: + interlace: Add pattern offset property + This property allows one to start at any point within the field pattern after + a discontinuity (whenever gst_interlace_reset () is called). Thus with the + 2:3:3:2 pattern, for example, one can start at offset 2 and achieve 3:2:2:3 + or offset 1 and achieve 3:3:2:2. + +2010-11-19 17:01:41 -0300 Lasse Laukkanen <ext-lasse.2.laukkanen@nokia.com> + + * gst/camerabin/camerabinimage.c: + * gst/camerabin/camerabinimage.h: + * gst/camerabin/gstcamerabin.c: + camerabin: Create imagebin elements when image mode is set in camerabin NULL state + This patch refactors imagebin element creation and linking into separate functions, + and adds re-using also for imagebin internally created elements. + So this refactoring allows creating imagebin elements already in NULL state when + application sets the image mode, and next state change from NULL to READY will be faster. + This reduces first capture latency. + Earlier the elements were both created and linked in NULL to READY state change. + +2010-11-22 12:23:30 +0100 Andoni Morales Alastruey <amorales@flumotion.com> + + * gst/mpegdemux/mpegtspacketizer.c: + mpegtsparse: Create a sub-buffer with the section length + +2010-11-19 15:23:41 -0500 Josh Doe <josh@joshdoe.com> + + * ext/opencv/gstcvdilateerode.c: + * ext/opencv/gstcvequalizehist.c: + * ext/opencv/gstcvlaplace.c: + * ext/opencv/gstcvsmooth.c: + * ext/opencv/gstcvsobel.c: + * ext/opencv/gstedgedetect.c: + * ext/opencv/gstfaceblur.c: + * ext/opencv/gstopencvutils.c: + * ext/opencv/gstopencvutils.h: + * ext/opencv/gstpyramidsegment.c: + * ext/opencv/gsttemplatematch.c: + * ext/opencv/gsttextwrite.c: + opencv: fix caps issues and extend supported caps for some elements + Some elements had vague caps, such as "video/x-raw-rgb", which caused problems + at least with textwrite. For other elements, the underlying OpenCV functions + support more than just one image type, so I increased the number of supported + caps. + I created a utility function "gst_opencv_caps_from_cv_image_type", so each + element creates caps directly from OpenCV image types, such as CV_8UC1 for + 8-bit grayscale. This function uses gstvideo to create uniform caps. + https://bugzilla.gnome.org/show_bug.cgi?id=635304 + +2010-11-22 17:43:12 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/jpegformat/gstjpegparse.c: + jpegparse: Small optimization on tags parsing + Optimize a little avoiding copying a taglist when parsing xmp/exif + data. + +2010-09-17 09:52:12 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/selector/gstoutputselector.c: + outputselector: Avoid losing the last_buffer when switching + This patch makes outputselector take an extra ref when pushing + the last_buffer to avoid it losing it during the switch function. + This makes resend-latest properly work if the active-pad is changed + during the switch function buffer pushing (on a pad probe, for example). + https://bugzilla.gnome.org/show_bug.cgi?id=629917 + +2010-09-17 09:44:02 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/selector/gstoutputselector.c: + outputselector: Recheck pending switch after pushing buffer + This patch makes output-selector always recheck if there's a + pending pad switch after pushing a buffer, preventing that + it pushes a buffer on the 'wrong' pad. + https://bugzilla.gnome.org/show_bug.cgi?id=629917 + +2010-11-22 15:10:26 +0200 Olivier Aubert <olivier.aubert%40liris.cnrs.fr> + + * ext/rsvg/Makefile.am: + * ext/rsvg/gstrsvg.c: + * ext/rsvg/gstrsvgoverlay.c: + * ext/rsvg/gstrsvgoverlay.h: + rsvgoverlay: scalable and relative svg overlay with cairo + Add a cairo+librsvg based overlay element to the rsvg plugin. + +2010-11-22 17:06:05 +0200 Stefan Kost <ensonic@users.sf.net> + + * tests/check/Makefile.am: + make: remove traces or moved/removed plugins + +2010-11-22 17:05:23 +0200 Stefan Kost <ensonic@users.sf.net> + + * Makefile.am: + make: add missinf trailing \ to fix the build + +2010-11-21 23:11:19 -0800 David Schleef <ds@schleef.org> + + * gst/colorspace/colorspace.c: + colorspace: remove incorrect check + +2010-11-19 17:55:36 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/qtmux/gstqtmux.c: + qtmux: remove remnant of obsolete property + +2010-11-19 15:18:58 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * tests/check/elements/qtmux.c: + tests: qtmux: also unit test fragmented file cases + +2010-07-30 12:48:29 +0200 Marc-André Lureau <mlureau@flumotion.com> + + * gst/qtmux/gstqtmux.c: + * gst/qtmux/gstqtmux.h: + qtmux: allow specifying trak timescale + This is mainly because Smoothstreaming client are broken and don't + take the TimeScale property into account. + +2010-11-19 17:41:41 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/qtmux/atoms.c: + * gst/qtmux/atoms.h: + * gst/qtmux/gstqtmux.c: + qtmux: include sdtp atoms for ismv fragmented files + Based on patch by Marc-André Lureau <mlureau@flumotion.com> + +2010-11-19 19:17:45 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/qtmux/gstqtmux.c: + qtmux: enable default fragmented file for ismlmux + +2010-09-02 13:58:05 +0200 Marc-André Lureau <mlureau@flumotion.com> + + * gst/qtmux/atoms.h: + * gst/qtmux/ftypcc.h: + * gst/qtmux/gstqtmuxmap.c: + * gst/qtmux/gstqtmuxmap.h: + qtmux: add ismlmux, for fragmented isml major brand + +2010-11-19 14:44:45 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/qtmux/gstqtmux.c: + qtmux: finalize sinkpads list + +2010-07-22 19:40:07 +0200 Marc-André Lureau <mlureau@flumotion.com> + + * gst/qtmux/gstqtmux.c: + qtmux: add moov in streamheader + +2010-08-06 13:26:27 +0200 Marc-André Lureau <mlureau@flumotion.com> + + * gst/qtmux/gstqtmux.c: + * gst/qtmux/gstqtmux.h: + qtmux: add streamable property to avoid building fragmented mfra index + +2010-11-18 16:48:06 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/qtmux/atoms.c: + * gst/qtmux/atoms.h: + * gst/qtmux/gstqtmux.c: + * gst/qtmux/gstqtmux.h: + qtmux: add mfra to fragmented file + Based on patch by Marc-André Lureau <mlureau@flumotion.com> + +2010-11-15 15:17:59 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/qtmux/atoms.c: + * gst/qtmux/atoms.h: + * gst/qtmux/gstqtmux.c: + * gst/qtmux/gstqtmux.h: + qtmux: optionally create fragmented file + In this mode, an initial empty moov (containing only stream metadata) is written, + followed by fragments containing actual data (along with required metadata). + New fragments are started either at keyframe (if such are sparse) or when + property configured duration exceeded. + Based on patch by Marc-André Lureau <mlureau@flumotion.com> + Fixes #632911. + +2010-11-15 15:12:45 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/qtmux/atoms.c: + qtmux: use helper to set atom flags from given uint + +2010-11-09 16:49:07 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/qtmux/gstqtmux.c: + qtmux: refactor configuring and sending of moov + Based on patch by Marc-André Lureau <mlureau@flumotion.com> + +2010-11-09 15:54:44 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/qtmux/gstqtmux.c: + qtmux: refactor extra top-level atom handling + Also check a bit more for possible errors, and free proper items in such case. + +2010-11-09 15:01:15 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/qtmux/gstqtmux.c: + qtmux: refactor slightly using buffer helper + +2010-11-05 13:48:57 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/qtmux/gstqtmux.c: + qtmux: fix misinforming comment + +2010-11-05 12:08:15 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/qtmux/atoms.c: + * gst/qtmux/atoms.h: + * gst/qtmux/gstqtmux.c: + qtmux: delegate mvex handling to atoms + ... which keeps qtmux simpler. + +2009-09-28 16:11:35 +0200 Marc-André Lureau <mlureau@flumotion.com> + + * gst/qtmux/atoms.c: + * gst/qtmux/atoms.h: + * gst/qtmux/gstqtmux.c: + qtmux: add mvex/trex in header if fragmented + One "trex" is added per "trak". We don't support default values, + but the "trex" box is mandatory. + +2009-09-28 13:01:30 +0200 Marc-André Lureau <mlureau@flumotion.com> + + * gst/qtmux/fourcc.h: + qtmux: add a couple of fourcc for fragmented mp4 + +2010-11-05 11:08:01 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/qtmux/gstqtmux.c: + qtmux: avoid removing temp file when error occurred + +2009-09-30 17:16:30 +0200 Marc-André Lureau <mlureau@flumotion.com> + + * gst/qtmux/gstqtmux.c: + qtmux: truncate buffer file after each send + +2009-09-28 16:53:51 +0200 Marc-André Lureau <mlureau@flumotion.com> + + * gst/qtmux/gstqtmux.c: + qtmux: remove temp file when reset/finalize + +2010-08-18 02:00:10 +0530 Arun Raghavan <arun.raghavan@collabora.co.uk> + + * gst/jpegformat/gstjpegparse.c: + jpegformat: Push tags after setting srcpad caps + This patch defers emission of tag events till caps are set on the source + pad of jpegparse, so that these tags can be seen downstream. + https://bugzilla.gnome.org/show_bug.cgi?id=627211 + +2010-11-19 18:51:32 +0100 Alessandro Decina <alessandro.d@gmail.com> + + * gst/mpegdemux/mpegtsparse.c: + mpegtsparse: fix compiler warning + +2010-11-19 18:26:59 +0100 Andoni Morales Alastruey <amorales@flumotion.com> + + * gst/mpegdemux/mpegtspacketizer.c: + mpegtsparse: fix thinko + +2010-11-19 17:25:01 +0100 Andoni Morales Alastruey <amorales@flumotion.com> + + * gst/mpegdemux/mpegtspacketizer.c: + mpegtsparse: fix handling of TOT and TDT sections. Fixes #635281. + TDT and TOT sections, with PID=0x14, doesn't extend to several packets + and the section filter is not needed here and shouldn't be used at all + for these tables because the have a different structure. + For example, TDT tables were not parsed for odd hours because this bit + is the 'current_next_indicator' bit for the other sections, and the table + was discarded. + +2010-11-19 17:22:06 +0100 Andoni Morales Alastruey <amorales@flumotion.com> + + * gst/mpegdemux/mpegtsparse.c: + mpegtsparse: don't calculate the CRC for TOT tables. Fixes #635281. + TOT tables, with table_id=0x73, don't have a CRC, so don't calcute it + +2010-11-18 18:42:38 +0100 Andoni Morales Alastruey <amorales@flumotion.com> + + * sys/dvb/dvbbasebin.c: + dvbbasebin: Add TDT to the initial pids filter for dvbsrc. Fixes #635200. + +2010-11-16 17:35:36 +0100 VÃctor Manuel Jáquez Leal <vjaquez@igalia.com> + + * gst/jpegformat/gstjpegparse.c: + jpegparse: add gst_jpeg_parse_skip_marker () + https://bugzilla.gnome.org/show_bug.cgi?id=626618 + +2010-08-13 13:14:30 +0200 VÃctor Manuel Jáquez Leal <vjaquez@igalia.com> + + * gst/jpegformat/gstjpegparse.c: + jpegparse: use byte reader accessors + https://bugzilla.gnome.org/show_bug.cgi?id=626618 + +2010-11-17 10:49:30 +0100 VÃctor Manuel Jáquez Leal <vjaquez@igalia.com> + + * gst/jpegformat/gstjpegparse.c: + jpegparse: inline gst_jpeg_parse_sof () + No functional changes (hopefully). + https://bugzilla.gnome.org/show_bug.cgi?id=626618 + +2010-11-16 17:23:35 +0100 VÃctor Manuel Jáquez Leal <vjaquez@igalia.com> + + * gst/jpegformat/gstjpegparse.c: + jpegparse: fix typo + https://bugzilla.gnome.org/show_bug.cgi?id=626618 + +2010-11-18 10:58:06 -0300 Aleksey Lim <alsroot@member.fsf.org> + + * gst/camerabin/camerabinvideo.c: + * gst/camerabin/gstcamerabin.c: + camerabin: Do not use audio clock after stopping video capture + Adda provide clock function to camerabin to make it not + provide the audio clock of the record bin when no video + recording is happening + Fixes #613379 + +2010-11-17 16:23:42 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: use correct offset when adding index entry + ... bearing in mind that BUFFER_OFFSET is media specific and may not + reflect the basic offset after having been parsed. + +2010-11-17 14:30:09 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: enhancements for timestamp marked framed formats + That is, as such formats allow subclass to extract position from frame, + it is possible to extract duration (if not otherwise provided) + from (near) last frame, and a seek can fairly accurately target the required + position. + Fixes #631389. + +2010-11-16 17:06:14 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: refactor frame scanning peformed by _loop + +2010-11-16 18:04:00 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: slightly optimize sending of pending newsegment events + +2010-11-16 17:04:35 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: minor fixes and enhancements + Arrange for upstream as well as downstream flushing when seeking. + Also determine upstream size as well as seekability. Adjust some comments + to reality and employ debug statement in proper order. + +2010-11-17 15:33:36 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstaacparse.c: + aacparse: minor cleanups + +2010-11-17 15:24:37 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstaacparse.c: + aacparse: fix regression in ADIF src caps setting + +2010-11-16 12:11:53 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstflacparse.c: + * gst/audioparsers/gstflacparse.h: + flacparse: parse seektable + Fixes #631389 (partially). + +2010-11-16 12:08:54 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstflacparse.c: + flacparse: minor refactor and enable default baseparse segment clipping + +2010-11-12 00:40:33 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/celvideosrc.c: + * sys/applemedia/celvideosrc.h: + celvideosrc: fix nasty deadlock + We cannot call any CMBufferQueue functions while holding the lock that + our callback also depends on. So now we make use of CMBufferQueue's + trigger API in order to get notified when the queue has data. + +2010-11-11 23:41:44 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/cmapi.c: + * sys/applemedia/cmapi.h: + cmapi: cover CMBufferQueue's trigger API + +2010-11-11 21:42:03 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/celvideosrc.c: + celvideosrc: unlock should also notify + Otherwise we depend on being woken up by the CoreMedia queue getting + its next buffer. + +2010-11-10 23:16:51 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/vtdec.c: + * sys/applemedia/vtdec.h: + * sys/applemedia/vtenc.c: + * sys/applemedia/vtenc.h: + applemedia: don't push synchronously from callback + The codec that called us might be holding locks to shared resources, so + we should never push downstream from within its buffer callback. + Note that a GstBufferList is not used here because we need to preserve + the buffer metadata held by our GstBuffer subclasses. + +2010-11-10 20:52:47 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/vtenc.c: + vtenc: bump H.264 level from 1.3 to 3.0 + This should be turned into a property. + +2010-11-10 20:44:15 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/celvideosrc.c: + * sys/applemedia/celvideosrc.h: + celvideosrc: add basic device selection support + +2010-11-10 20:51:27 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/cvapi.c: + * sys/applemedia/cvapi.h: + cvapi: add wrapper for IO surface access + To be used in a future video sink for zero-copy rendering. + +2010-11-10 20:25:28 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/celapi.c: + * sys/applemedia/celapi.h: + celapi: add capture port type constants + +2010-11-09 22:43:14 +0200 Mart Raudsepp <mart.raudsepp@collabora.co.uk> + + * ext/assrender/gstassrender.c: + assrender: Remove unused src_stride variable from blit functions + +2010-11-09 18:10:43 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * Makefile.am: + * win32/common/libgstphotography.def: + win32: Adding photography interface .def file + Adds check-exports to -bad to have photography interface + .def file created + Fixes #578629 + +2010-11-09 19:38:25 +0100 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstmpegaudioparse.c: + mpegaudioparse: fix silly leak in _reset + +2010-11-08 23:54:31 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/celvideosrc.c: + * sys/applemedia/vtdec.c: + * sys/applemedia/vtenc.c: + * sys/applemedia/vth264decbin.c: + * sys/applemedia/vth264encbin.c: + applemedia: biplanar is actually NV12, not I420 + D'oh! + +2010-11-08 21:22:13 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/vtenc.c: + * sys/applemedia/vtenc.h: + vtenc: remove keyframe enforcement workaround + Was only needed for old iOS where the H.264 encoder didn't support + kVTEncodeFrameOptionKey_ForceKeyFrame. + +2010-11-08 18:56:52 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/cvapi.c: + * sys/applemedia/cvapi.h: + cvapi: add a few extra bits of wrapping + +2010-11-08 15:08:19 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/coremediabuffer.c: + * sys/applemedia/corevideobuffer.c: + * sys/applemedia/cvapi.h: + applemedia: lock CVPixelBuffer read-only + As per Apple's docs, this may improve performance by avoiding redundant + invalidations of existing caches of the buffer contents. + +2010-11-08 10:33:58 -0300 Lasse Laukkanen <ext-lasse.2.laukkanen@nokia.com> + + * tests/examples/camerabin/gst-camerabin-test.c: + examples: camerabin: Remove gstring leak + Simplify gst-camerabin-test by removing GString and replacing + with gchar for the filename handling. Also removes a leak of + the GString data. + +2010-11-08 16:00:21 +0200 Stefan Kost <ensonic@users.sf.net> + + * ext/rsvg/gstrsvgdec.c: + rsvgdec: avoid reffing the element in chain + +2010-11-08 15:45:48 +0200 Stefan Kost <ensonic@users.sf.net> + + * ext/rsvg/gstrsvgdec.c: + rsvgdec: add some minimal logging to track what it is doing + +2010-11-08 13:52:49 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/celvideosrc.c: + celvideosrc: put planar first in template caps + +2010-11-08 13:49:04 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/cvapi.h: + * sys/applemedia/vtdec.c: + * sys/applemedia/vtenc.c: + * sys/applemedia/vth264decbin.c: + * sys/applemedia/vth264encbin.c: + applemedia: improve vtenc/vtdec performance + Profiling of H.264 encode and decode revealed that conversions + between packed and planar were happening behind the scenes. + Hence we now choose I420 instead of YUY2. + +2010-10-22 18:07:00 +0300 Lasse Laukkanen <ext-lasse.2.laukkanen@nokia.com> + + * tests/examples/camerabin/gst-camerabin-test.c: + examples: add async bus handler to gst-camerabin-test + Splits the bus handler into sync and async, keeping the + prepare-xwindow handling at the sync for faster handling and + moving the others to the async handler + +2010-11-06 12:27:32 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * configure.ac: + configure: we still require Gtk+ >= 2.14.0 when compiling against 2.0 + The check for the minor version was dropped in one of the previous + commits. + +2010-11-05 16:51:57 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/celvideosrc.c: + * sys/applemedia/celvideosrc.h: + celvideosrc: measure fps when statistics is enabled + Also refactor timestamping slightly. + +2010-11-05 15:14:08 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/celvideosrc.c: + * sys/applemedia/celvideosrc.h: + celvideosrc: update to new Celestial and MediaToolbox APIs + This means celvideosrc is no longer compatible with iOS 3.x. + +2010-11-05 15:08:56 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/celvideosrc.c: + celvideosrc: fix debug category description + +2010-11-05 15:08:02 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/celapi.c: + * sys/applemedia/celapi.h: + celapi: update to reflect new API on iOS 4.x + Also add remaining property constants for device and stream. + +2010-11-05 15:07:38 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/mtapi.c: + * sys/applemedia/mtapi.h: + mtapi: update to reflect new API on iOS 4.x + Also add remaining property constants for device and stream. + +2010-11-05 10:56:51 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/colorspace/gstcolorspaceorc-dist.c: + * gst/colorspace/gstcolorspaceorc-dist.h: + colorspace: Update generated ORC sources + +2010-08-26 17:08:19 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/gstcamerabin-enum.h: + * gst/camerabin/gstcamerabin.c: + * gst/camerabin/gstcamerabin.h: + * tests/check/elements/camerabin.c: + camerabin: Adds 'idle' property + Adds 'idle', a read-only boolean property that tells applications + if there is any capturing/saving/encoding going on in camerabin. If + not, it is safe to set it to NULL and release resources without + losing data. + +2010-05-05 13:58:07 +0300 Lasse Laukkanen <ext-lasse.2.laukkanen@nokia.com> + + * gst/camerabin/gstcamerabin-enum.h: + * gst/camerabin/gstcamerabin.c: + * tests/check/elements/camerabin.c: + camerabin: Add "ready-for-capture" property + Add "ready-for-capture" property to indicate if preparing a new + capture is possible. + "ready-for-capture" changes before the 'image-done' signal, so + the application can be notified that it can do a new capture + even before the previous one has finished encoding/saving. + +2010-11-05 00:32:35 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * configure.ac: + configure: don't even check for Gtk+ if --disable-examples is specified + There are Gtk+-based examples in plugin dirs and tests/icles/ too, and + we want to disable those as well then. + +2010-11-05 00:24:31 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * configure.ac: + configure: add --with-gtk option and default to Gtk+ 2.0 while the 3.0 API is still in flux + https://bugzilla.gnome.org/show_bug.cgi?id=634014 + +2010-11-03 00:04:27 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * configure.ac: + * tests/Makefile.am: + * tests/check/Makefile.am: + * tests/check/elements/.gitignore: + * tests/check/elements/zbar.c: + * tests/files/Makefile.am: + * tests/files/barcode.png: + tests: add very simple zbar unit test + Not valgrind clean yet (could be zbar's fault though). + +2010-11-04 19:25:24 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/avfvideosrc.m: + * sys/applemedia/celvideosrc.c: + * sys/applemedia/miovideosrc.c: + * sys/applemedia/qtkitvideosrc.m: + applemedia: make video source element details consistent + Inspired by the v4l2src element details. + +2010-11-04 19:11:04 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/avfvideosrc.m: + * sys/applemedia/qtkitvideosrc.m: + applemedia: consistently use gst_element_class_set_details_simple + +2010-11-04 19:02:50 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/celvideosrc.c: + * sys/applemedia/celvideosrc.h: + celvideosrc: update e-mail address + +2010-11-04 18:59:44 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/Makefile.am: + * sys/applemedia/celvideosrc.c: + * sys/applemedia/celvideosrc.h: + * sys/applemedia/iphonecamerasrc.c: + * sys/applemedia/iphonecamerasrc.h: + * sys/applemedia/plugin.m: + applemedia: rename iphonecamerasrc to celvideosrc + This is in order to improve consistency with the other three sources. + +2010-11-04 17:58:36 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/avfvideosrc.m: + avfvideosrc: don't explicitly empty the buffer queue + We're holding the only reference to it so there's no need to explicitly + empty it right before letting go of our reference. + +2010-11-04 17:50:33 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/avfvideosrc.m: + avfvideosrc: make buffer offset start from zero + +2010-11-04 17:47:25 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/qtkitvideosrc.m: + qtkitvideosrc: implement zero-copy by using buffer-factory + This means we'll wrap each CoreVideo buffer inside a GstBuffer instead of + making a copy. + +2010-11-04 17:44:12 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/bufferfactory.h: + * sys/applemedia/bufferfactory.m: + bufferfactory: add support for wrapping CVBuffer + +2010-11-04 17:24:03 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/qtkitvideosrc.m: + qtkitvideosrc: fix up refcounting + Should keep a strong reference to the device, but we don't need to manage + the reference count of elements of an NSMutableArray as it takes care of + that for us. + +2010-11-04 17:16:05 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/qtkitvideosrc.m: + qtkitvideosrc: simplify timestamping algorithm + Aligning timestamps on duration boundaries, skipping frames and so forth + are clearly things that fall outside the scope of a video source. + +2010-11-04 14:14:09 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/Makefile.am: + * sys/applemedia/avfvideosrc.h: + * sys/applemedia/avfvideosrc.m: + * sys/applemedia/bufferfactory.h: + * sys/applemedia/bufferfactory.m: + * sys/applemedia/plugin.m: + applemedia: add new iOS video source based on AVFoundation + This element makes use of the documented AVFoundation framework made + available starting with iOS 4.0, and hence this means we can finally + capture video using a public API. + +2010-11-04 14:24:36 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/vtdec.c: + * sys/applemedia/vtenc.c: + * sys/applemedia/vth264decbin.c: + applemedia: fix stream-format caps used for H.264 + The stream-format's "avc-sample" member is now called just "avc". + +2010-11-04 14:29:37 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/miovideodevice.c: + * sys/applemedia/plugin.m: + * sys/applemedia/qtkitvideosrc.m: + applemedia: update e-mail addresses + +2010-11-04 14:18:29 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/colorspace/gstcolorspace.c: + colorspace: Inverse -base version check logic to actually make sense + +2010-11-03 18:34:28 -0400 Olivier Crête <olivier.crete@collabora.co.uk> + + * gst/pcapparse/gstpcapparse.c: + * gst/pcapparse/gstpcapparse.h: + pcapparse: Add support for Linux Cooked Capture (SLL) frames + +2010-11-03 18:23:27 -0400 Olivier Crête <olivier.crete@collabora.co.uk> + + * gst/pcapparse/gstpcapparse.c: + pcapparse: Fail on unknown version or linktype + The element only knows about major version 2 and only decodes linktype ethernet + +2010-11-03 18:02:49 -0400 Olivier Crête <olivier.crete@collabora.co.uk> + + * gst/pcapparse/gstpcapparse.c: + pcapparse: Send error GstMessage if stream doesn't have the expected magic + +2010-11-03 16:16:24 +0100 Andoni Morales Alastruey <amorales@flumotion.com> + + * gst/mpegdemux/mpegtsparse.c: + mpegtsparse: send TDT tables messages in a serialized event downstream + https://bugzilla.gnome.org/show_bug.cgi?id=633917 + +2010-11-03 15:37:48 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/colorspace/colorspace.c: + colorspace: Add support for IYU1 + +2010-11-03 15:12:42 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/colorspace/colorspace.c: + * gst/colorspace/gstcolorspaceorc.orc: + colorspace: First version of YUV9 and YVU9 implementation + +2010-11-03 09:20:15 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/colorspace/colorspace.c: + * gst/colorspace/gstcolorspace.c: + colorspace: Use GST_CHECK_PLUGINS_BASE_VERSION() instead of other hacks + +2010-10-18 15:32:14 +0200 Thijs Vermeir <thijsvermeir@gmail.com> + + * gst/mpegvideoparse/mpegpacketiser.c: + * gst/mpegvideoparse/mpegpacketiser.h: + * gst/mpegvideoparse/mpegvideoparse.c: + * gst/mpegvideoparse/mpegvideoparse.h: + mpegvideoparse: fix timestamp generation + Use information from the gop header and picture + header to calculate the picture timestamp. (time_code + and temporal_reference) and adapt to upstream timestamps if + provided. + https://bugzilla.gnome.org/show_bug.cgi?id=632222 + +2010-11-02 23:08:30 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/vtapi.h: + * sys/applemedia/vtdec.c: + * sys/applemedia/vtdec.h: + * sys/applemedia/vtenc.c: + * sys/applemedia/vtenc.h: + applemedia: switch vtapi to CFTypeRef style typedefs + +2010-11-02 22:53:33 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/applemedia/celapi.h: + * sys/applemedia/cmapi.c: + * sys/applemedia/cmapi.h: + * sys/applemedia/coremediabuffer.c: + * sys/applemedia/coremediabuffer.h: + * sys/applemedia/iphonecamerasrc.c: + * sys/applemedia/iphonecamerasrc.h: + * sys/applemedia/mioapi.h: + * sys/applemedia/miovideodevice.c: + * sys/applemedia/miovideodevice.h: + * sys/applemedia/miovideosrc.c: + * sys/applemedia/miovideosrc.h: + * sys/applemedia/mtapi.h: + * sys/applemedia/vtapi.h: + * sys/applemedia/vtdec.c: + * sys/applemedia/vtdec.h: + * sys/applemedia/vtenc.c: + applemedia: support public version of CoreMedia + Also rename the relevant API so we mirror the public API more closely, and + switch to CoreFoundation CFTypeRef style typedefs. We still support the old + private CoreMedia in order to not break OS X support. + This means that vtenc and vtdec are now compatible with iOS 4.x, and in + theory also future versions of OS X, where this API may turn public like + it has on iOS. + +2010-11-02 17:46:11 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * ext/zbar/gstzbar.c: + zbar: handle more formats that start with an 8-bit Y plane + We can handle most planar YUV layouts too, as long as we don't + tell zbar about the chroma planes. + +2010-11-02 17:18:52 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * ext/zbar/gstzbar.c: + * ext/zbar/gstzbar.h: + zbar: use correct stride + Fixes detection for images with a width that's not a multiple of four. + Based on patch by: Kaj-Michael Lang <milang@tal.org> + Based on patch by: Stefan Kost <ensonic@users.sf.net> + https://bugzilla.gnome.org/show_bug.cgi?id=630830 + +2010-11-02 16:54:59 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/colorspace/gstcolorspace.c: + colorspace: fix build with current git of gst-plugins-base + ifdef tests don't work so well if we define them in the code + above in case they aren't defined. + +2010-11-02 16:35:57 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * ext/zbar/gstzbar.c: + zbar: minor clean-up + Fix typo and use DEFAULT_FOO define for property default. + +2010-11-02 16:32:55 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * ext/zbar/gstzbar.c: + zbar: disable cache by default + Since it breaks still image bar code detection. + +2010-11-02 16:05:37 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/colorspace/colorspace.c: + * gst/colorspace/colorspace.h: + * gst/colorspace/gstcolorspace.c: + * gst/colorspace/gstcolorspace.h: + colorspace: Add support for 8 bit paletted RGB + This needs the 8 bit paletted support from -base + which will be committed after release. Without this + the 8 bit parts are disabled. + +2010-11-02 10:24:49 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/camerabinpreview.c: + camerabin: Add missing change to previous commits + Forgot to add this change to the latest commits. This fixes the build. + +2010-11-02 09:39:49 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/camerabinpreview.c: + camerabin: Fix leaks in the preview handling + Remember to unref the bus after adding the watch. + Remember to unref the element after getting it with + gst_bin_get_by_name. + +2010-11-02 09:38:20 -0300 Lasse Laukkanen <ext-lasse.2.laukkanen@nokia.com> + + * gst/camerabin/gstcamerabin.c: + camerabin: Do not leak a caps + gst_caps_replace doesn't take ownership, but refs the caps. So we + unref the remaining caps. + +2010-09-24 16:28:13 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/gstcamerabin.c: + camerabin: Reset pre-night-mode stored fps when mode changes + When switching between video/still modes the pre-night-mode fps + should be reset to prevent it being used in the incorrect mode, causing + the videosource to fail configuring itself + +2010-09-21 16:23:47 +0300 Teemu Katajisto <ext-teemu.katajisto@nokia.com> + + * tests/examples/camerabin/gst-camerabin-test.c: + examples: camerabin: add support for setting many post-processing elements + Instead of taking a single element as input for the image post + processing option, take a list of comma separated elements + that will be used. + +2010-09-20 11:54:20 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/gstcamerabin.c: + * gst/camerabin/gstcamerabin.h: + camerabin: Store app preferred capture parameters separately + Store width/height/fps for video captures in a separate variable + than the one that stores the currently used value. + This prevents the user preferences to be lost when resetting + the currently used dimensions for night mode, for example + +2010-09-20 08:42:41 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/gstcamerabin.c: + camerabin: cleanup used caps when going to NULL + Resets used caps so that camerabin doesn't try to use them + when restarting, where elements/properties might have changed + and the old caps be incompatible + +2010-09-09 10:50:59 +0300 Teemu Katajisto <ext-teemu.katajisto@nokia.com> + + * gst/camerabin/gstcamerabin.c: + camerabin: fix priority for idle_add function + Adds a higher priority to the idle_add function for when + the image bin finished the image capture. This reduces the + delay for the application to be notified about this. + +2010-11-01 23:04:44 +0200 Stefan Kost <ensonic@users.sf.net> + + * gst/selector/gstinputselector.c: + inputselector: log times in human readable form + +2010-11-01 22:40:36 +0200 Stefan Kost <ensonic@users.sf.net> + + * gst/selector/gstinputselector.c: + inputselector: move reoccuring logs to LOG and remove a double info + Less debug spew in DEBUG category. No need to log pad again if we use + GST_LOG_OBJECT(pad,...). + +2010-11-01 15:53:52 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * ext/cog/gstcogorc-dist.c: + * gst/colorspace/gstcolorspaceorc-dist.c: + * gst/colorspace/gstcolorspaceorc-dist.h: + cog, colorspace: update orc backup functions for latest changes + Should fix build on systems without the latest orc. + +2010-11-01 15:53:31 +0000 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * po/af.po: + * po/az.po: + * po/bg.po: + * po/ca.po: + * po/cs.po: + * po/da.po: + * po/de.po: + * po/el.po: + * po/en_GB.po: + * po/es.po: + * po/eu.po: + * po/fi.po: + * po/fr.po: + * po/gl.po: + * po/hu.po: + * po/id.po: + * po/it.po: + * po/ja.po: + * po/ky.po: + * po/lt.po: + * po/lv.po: + * po/mt.po: + * po/nb.po: + * po/nl.po: + * po/or.po: + * po/pl.po: + * po/pt_BR.po: + * po/ro.po: + * po/ru.po: + * po/sk.po: + * po/sl.po: + * po/sq.po: + * po/sr.po: + * po/sv.po: + * po/tr.po: + * po/uk.po: + * po/vi.po: + * po/zh_CN.po: + po: update for new translations + +2010-10-31 23:46:27 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/colorspace/colorspace.c: + * gst/colorspace/gstcolorspace.c: + colorspace: Add support for RGB15 and BGR15 + +2010-10-31 23:44:20 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/colorspace/colorspace.c: + * gst/colorspace/gstcolorspace.c: + colorspace: Add support for RGB16 and BGR16 + +2010-10-31 23:25:57 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/colorspace/colorspace.c: + * gst/colorspace/gstcolorspaceorc.orc: + colorspace: Add support for Y16 + +2010-10-31 23:25:40 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/colorspace/gstcolorspaceorc.orc: + colorspace: Fix Y800 ORC getline implementation + +2010-10-31 23:07:43 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/colorspace/colorspace.c: + * gst/colorspace/gstcolorspace.c: + * gst/colorspace/gstcolorspaceorc.orc: + colorspace: Add support for A420 + +2010-10-31 23:00:07 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/colorspace/colorspace.c: + colorspace: Add support for Y41B + +2010-10-31 22:39:38 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/colorspace/colorspace.c: + * gst/colorspace/colorspace.h: + * gst/colorspace/gstcolorspace.c: + * gst/colorspace/gstcolorspace.h: + colorspace: Add support for SDTV/HDTV YUV conversions + +2010-10-31 22:21:35 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/colorspace/colorspace.c: + colorspace: Add comment for the A420 getline/putline table row + +2010-10-31 20:40:09 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/colorspace/colorspace.c: + * gst/colorspace/colorspace.h: + colorspace: Add const to the source arrays and the getline/putline table + +2010-10-31 19:42:30 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/colorspace/colorspace.c: + colorspace: Make fast-path transform table const + +2010-10-31 19:39:33 +0100 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/colorspace/colorspace.c: + colorspace: Only do the I420->YUY2 conversion once per scanline in the fast path + +2010-10-29 14:08:58 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: use only upstream duration if it provides one + +2010-10-25 14:15:50 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: reflow update_bitrate code + ... which makes local variables represent real state better, and avoids + triggering unneeded updates/actions. + +2010-10-25 14:13:51 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: add some debug statements + +2010-10-28 18:51:02 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/gaudieffects/Makefile.am: + * gst/gaudieffects/gstplugin.c: + gaudieffects: Include gstcontroller header and add the required CFLAGS + +2010-10-27 14:57:36 +0200 Luis de Bethencourt <luis@debethencourt.com> + + * gst/gaudieffects/gstburn.c: + * gst/gaudieffects/gstburn.h: + * gst/gaudieffects/gstchromium.c: + * gst/gaudieffects/gstchromium.h: + * gst/gaudieffects/gstdilate.c: + * gst/gaudieffects/gstdilate.h: + * gst/gaudieffects/gstdodge.c: + * gst/gaudieffects/gstexclusion.c: + * gst/gaudieffects/gstexclusion.h: + * gst/gaudieffects/gstplugin.c: + * gst/gaudieffects/gstsolarize.c: + * gst/gaudieffects/gstsolarize.h: + gaudieffects: made filter parameters dynamic and controllable + +2010-07-01 15:07:41 +0200 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/winks/gstksvideodevice.c: + winks: work around shutdown deadlock + GetOverlappedResult() might never return with some drivers. Time out + after 1000 ms. We cannot really fix this without either: + 1) Controlling the streaming thread so we can do CancelIo() from that + thread. + 2) Switch to using IO completion ports. + +2010-06-11 18:04:58 +0200 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/winks/gstksvideodevice.c: + winks: remove JPEG validation hack + This should clearly not be done in a video source. + +2010-04-20 12:05:45 +0200 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/winks/ksvideohelpers.c: + winks: set PrioritySubClass to KSPRIORITY_NORMAL instead of 1 + In order to match the reference implementation. + +2010-04-20 11:59:23 +0200 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/winks/gstksvideodevice.c: + winks: retry when KsCreatePin fails with ERROR_NOT_READY + Turns out that the reference implementation does this, hence we need to + mirror this behaviour. This typically happens with hardware that takes + some time to initialize. + +2009-10-26 16:09:00 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/winks/ksvideohelpers.c: + winks: improve framerate fraction conversions + * For instance 7.5 fps should be represented as 15/2 instead of 7/1. + * Clamp AvgTimePerFrame and dwBitRate to account for rounding errors. + +2009-10-12 17:26:15 +0200 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/winks/gstksclock.c: + * sys/winks/gstksvideodevice.c: + * sys/winks/gstksvideodevice.h: + * sys/winks/gstksvideosrc.c: + * sys/winks/kshelpers.c: + * sys/winks/kshelpers.h: + * sys/winks/ksvideohelpers.c: + winks: improve error-handling + Most important part here is special-casing "device busy" so the application + is able to provide better feedback when another application is using the + device. + +2009-09-07 16:45:57 +0200 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/winks/gstksvideodevice.c: + * sys/winks/gstksvideodevice.h: + * sys/winks/gstksvideosrc.c: + winks: performance improvements + * Make the driver write directly into each GstBuffer to avoid memcpy(). + * Don't memset() the buffer before reusing it. + * Recycle memory by keeping two spare buffers. Two because the sink + downstream may keep a ref to the previous buffer. + Note that we align buffers on highest possible byte boundary (4096) so we + don't have to take into account what kind of alignment the driver requires. + +2009-09-07 16:09:34 +0200 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/winks/gstksclock.c: + * sys/winks/gstksclock.h: + * sys/winks/gstksvideodevice.c: + * sys/winks/gstksvideodevice.h: + * sys/winks/gstksvideosrc.c: + * sys/winks/gstksvideosrc.h: + winks: store priv pointer instead of looking it up + +2009-08-31 19:33:30 +0200 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/winks/gstksvideosrc.c: + winks: post error message on flow-unexpected + +2009-08-31 19:28:50 +0200 Andres Colubri <andres.colubri@gmail.com> + + * sys/winks/gstksvideosrc.c: + * sys/winks/gstksvideosrc.h: + winks: add property probing support + +2009-08-31 19:26:36 +0200 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/winks/gstksvideosrc.c: + * sys/winks/ksvideohelpers.c: + * sys/winks/ksvideohelpers.h: + winks: sort devices that look like cameras first + +2009-08-31 19:25:02 +0200 Knut Inge Hvidsten <knut.inge.hvidsten@tandberg.com> + + * sys/winks/ksvideohelpers.c: + winks: provide guessed pixel-aspect-ratio in caps + +2009-08-31 19:23:40 +0200 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/winks/gstksclock.c: + winks: only try to change state when actually open + +2009-08-31 19:22:40 +0200 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/winks/kshelpers.c: + * sys/winks/kshelpers.h: + * sys/winks/ksvideohelpers.c: + winks: ignore unsupported formats + +2010-10-28 16:14:34 +0200 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * sys/winks/gstksvideodevice.c: + * sys/winks/gstksvideosrc.c: + winks: adjust a couple of logging severities + Should clearly not be considered warnings, as they're quite common. + +2010-10-27 18:30:11 +0100 Ole André Vadla RavnÃ¥s <oravnas@cisco.com> + + * configure.ac: + * sys/Makefile.am: + * sys/applemedia/Makefile.am: + * sys/applemedia/celapi.c: + * sys/applemedia/celapi.h: + * sys/applemedia/cmapi.c: + * sys/applemedia/cmapi.h: + * sys/applemedia/coremediabuffer.c: + * sys/applemedia/coremediabuffer.h: + * sys/applemedia/coremediactx.c: + * sys/applemedia/coremediactx.h: + * sys/applemedia/corevideobuffer.c: + * sys/applemedia/corevideobuffer.h: + * sys/applemedia/cvapi.c: + * sys/applemedia/cvapi.h: + * sys/applemedia/dynapi-internal.h: + * sys/applemedia/dynapi.c: + * sys/applemedia/dynapi.h: + * sys/applemedia/iphonecamerasrc.c: + * sys/applemedia/iphonecamerasrc.h: + * sys/applemedia/mioapi.c: + * sys/applemedia/mioapi.h: + * sys/applemedia/miovideodevice.c: + * sys/applemedia/miovideodevice.h: + * sys/applemedia/miovideosrc.c: + * sys/applemedia/miovideosrc.h: + * sys/applemedia/mtapi.c: + * sys/applemedia/mtapi.h: + * sys/applemedia/plugin.m: + * sys/applemedia/qtkitvideosrc.h: + * sys/applemedia/qtkitvideosrc.m: + * sys/applemedia/vtapi.c: + * sys/applemedia/vtapi.h: + * sys/applemedia/vtdec.c: + * sys/applemedia/vtdec.h: + * sys/applemedia/vtenc.c: + * sys/applemedia/vtenc.h: + * sys/applemedia/vth264decbin.c: + * sys/applemedia/vth264decbin.h: + * sys/applemedia/vth264encbin.c: + * sys/applemedia/vth264encbin.h: + * sys/applemedia/vtutil.c: + * sys/applemedia/vtutil.h: + applemedia: New plugin for Apple multimedia APIs + Provides the following elements: + qtkitvideosrc: OS X video source relying on the QTKit API. Comes with + hard-coded caps as the API does not provide any way of querying for + formats supported by the hardware. Hasn't been tested a lot, but seems + to work. + miovideosrc: OS X video source which uses the undocumented/private + CoreMediaIOServices API, which is also the one used by iChat. + Present on latest version of Leopard and all versions of Snow Leopard. + Has been tested extensively with built-in cameras and TANDBERG's + PrecisionHD USB camera. + vtenc, vtdec: Generic codec wrappers which make use of the undocumented/ + private VideoToolbox API on OS X and iOS. List of codecs are currently + hard-coded to H.264 for vtenc, and H.264 + JPEG for vtdec. Can easily be + expanded by adding new entries to the lists, but haven't yet had time to + do that. Should probably also implement probing as available codecs depend + on the OS and its version, and there doesn't seem to be any way to + enumerate the available codecs. + vth264decbin, vth264encbin: Wrapper bins to make it easier to use + vtdec_h264/vtenc_h264 in live scenarios. + iphonecamerasrc: iPhone camera source relying on the undocumented/private + Celestial API. Tested on iOS 3.1 running on an iPhone 3GS. Stops working + after a few minutes, presumably because of a resource leak. Needs some + love. + Note that the iOS parts haven't yet been ported to iOS 4.x. + +2010-10-28 11:43:34 +0100 Sebastian Pölsterl <sebp@k-d-w.org> + + * gst/mpegdemux/mpegtsparse.c: + mpegtsparse: Add tag event emission. Fixes #627253 + +2010-10-27 13:17:10 +0100 Jan Schmidt <thaytan@noraisin.net> + + * common: + Automatic update of common submodule + From 7bbd708 to 011bcc8 + +2010-10-21 16:06:08 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/gstcamerabin.c: + camerabin: Check the source scene mode when creating it + As camerabin only gets notified of the changes from the + video source element, it should query the initial value + once the source is created so it initializes itself + correctly. + +2010-10-20 00:07:01 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * tests/check/Makefile.am: + tests: fix distcheck a bit more + Dist elements/parser.h header file, which fixes the 'make check' build. + +2010-10-19 23:40:36 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * tests/check/elements/valve.c: + tests: fix valve unit test + gst_buffer_pad_alloc() needs simple caps or NULL caps, + ANY caps are not allowed. + +2010-10-19 23:25:54 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/audioparsers/gstdcaparse.c: + dcaparse: init variable to make osx build bot happy + gstdcaparse.c: In function 'gst_dca_parse_check_valid_frame': + gstdcaparse.c:246: warning: 'best_sync' may be used uninitialized in this function + +2010-10-19 00:15:20 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/audioparsers/Makefile.am: + * gst/audioparsers/gstdcaparse.c: + * gst/audioparsers/gstdcaparse.h: + * gst/audioparsers/plugin.c: + audioparsers: add very basic dts/dca parser + Still some issues, e.g. with seekable queries in totem, but also + processing already-chunked input (created with matroskademux ! gdppay). + +2010-10-19 16:23:23 +0300 Stefan Kost <ensonic@users.sf.net> + + * ext/amrwbenc/gstamrwbenc.c: + * ext/apexsink/gstapexsink.c: + * ext/artsd/gstartsdsink.c: + * ext/audiofile/gstafsink.c: + * ext/audioresample/gstaudioresample.c: + * ext/bz2/gstbz2dec.c: + * ext/bz2/gstbz2enc.c: + * ext/cdaudio/gstcdaudio.c: + * ext/cog/gstcogmse.c: + * ext/cog/gstlogoinsert.c: + * ext/dc1394/gstdc1394.c: + * ext/dirac/gstdiracenc.cc: + * ext/directfb/dfbvideosink.c: + * ext/divx/gstdivxenc.c: + * ext/dts/gstdtsdec.c: + * ext/faac/gstfaac.c: + * ext/jack/gstjackaudiosink.c: + * ext/jack/gstjackaudiosrc.c: + * ext/kate/gstkatedec.c: + * ext/kate/gstkateenc.c: + * ext/kate/gstkatetag.c: + * ext/kate/gstkatetiger.c: + * ext/kate/gstkateutil.c: + * ext/libfame/gstlibfame.c: + * ext/modplug/gstmodplug.cc: + * ext/mpeg2enc/gstmpeg2encoptions.cc: + * ext/mplex/gstmplexjob.cc: + * ext/musicbrainz/gsttrm.c: + * ext/mythtv/gstmythtvsrc.c: + * ext/nas/nassink.c: + * ext/neon/gstneonhttpsrc.c: + * ext/ofa/gstofa.c: + * ext/opencv/gstedgedetect.c: + * ext/opencv/gstfaceblur.c: + * ext/opencv/gstfacedetect.c: + * ext/opencv/gstpyramidsegment.c: + * ext/opencv/gsttemplatematch.c: + * ext/resindvd/resindvdbin.c: + * ext/resindvd/resindvdsrc.c: + * ext/sdl/sdlvideosink.c: + * ext/shout/gstshout.c: + * ext/snapshot/gstsnapshot.c: + * ext/sndfile/gstsfsink.c: + * ext/soundtouch/gstpitch.cc: + * ext/tarkin/gsttarkindec.c: + * ext/tarkin/gsttarkinenc.c: + * ext/xvid/gstxvidenc.c: + * ext/zbar/gstzbar.c: + various (ext): add missing G_PARAM_STATIC_STRINGS flags + Canonicalize property names as needed. + +2010-10-19 16:24:12 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/videosignal/gstvideoanalyse.c: + videoanalyse: fix copy'n'paste off by one for param spec flags change + +2010-10-19 13:43:14 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/asfmux/gstasfmux.c: + * gst/autoconvert/gstautoconvert.c: + * gst/camerabin/camerabinimage.c: + * gst/camerabin/camerabinvideo.c: + * gst/dccp/gstdccpclientsink.c: + * gst/dccp/gstdccpclientsrc.c: + * gst/dccp/gstdccpserversink.c: + * gst/dccp/gstdccpserversrc.c: + * gst/dtmf/gstdtmfsrc.c: + * gst/dtmf/gstrtpdtmfdepay.c: + * gst/dtmf/gstrtpdtmfsrc.c: + * gst/filter/gstiir.c: + * gst/freeze/gstfreeze.c: + * gst/games/gstpuzzle.c: + * gst/gaudieffects/gstburn.c: + * gst/gaudieffects/gstchromium.c: + * gst/gaudieffects/gstdilate.c: + * gst/gaudieffects/gstdodge.c: + * gst/gaudieffects/gstexclusion.c: + * gst/gaudieffects/gstsolarize.c: + * gst/h264parse/gsth264parse.c: + * gst/id3tag/gstid3mux.c: + * gst/librfb/gstrfbsrc.c: + * gst/mixmatrix/mixmatrix.c: + * gst/mpeg4videoparse/mpeg4videoparse.c: + * gst/mpegdemux/flutspatinfo.c: + * gst/mpegdemux/flutspmtinfo.c: + * gst/mpegdemux/flutspmtstreaminfo.c: + * gst/mpegdemux/gstmpegtsdemux.c: + * gst/mpegdemux/mpegtsparse.c: + * gst/mpegtsmux/mpegtsmux.c: + * gst/mve/gstmvemux.c: + * gst/nsf/gstnsf.c: + * gst/passthrough/gstpassthrough.c: + * gst/pcapparse/gstpcapparse.c: + * gst/playondemand/gstplayondemand.c: + * gst/pnm/gstpnmenc.c: + * gst/qtmux/gstqtmoovrecover.c: + * gst/real/gstrealaudiodec.c: + * gst/real/gstrealvideodec.c: + * gst/rtpmux/gstrtpmux.c: + * gst/scaletempo/gstscaletempo.c: + * gst/sdp/gstsdpdemux.c: + * gst/selector/gstinputselector.c: + * gst/selector/gstoutputselector.c: + * gst/smooth/gstsmooth.c: + * gst/speed/gstspeed.c: + * gst/stereo/gststereo.c: + * gst/subenc/gstsrtenc.c: + * gst/vbidec/gstvbidec.c: + * gst/videodrop/gstvideodrop.c: + * gst/videomeasure/gstvideomeasure_collector.c: + * gst/videomeasure/gstvideomeasure_ssim.c: + * gst/videosignal/gstvideoanalyse.c: + * gst/videosignal/gstvideodetect.c: + * gst/videosignal/gstvideomark.c: + various (gst): add missing G_PARAM_STATIC_STRINGS flags + Canonicalize property names as needed. + +2010-10-19 15:30:02 +0300 Stefan Kost <ensonic@users.sf.net> + + * ext/artsd/gstartsdsink.c: + * ext/audiofile/gstafsink.c: + * ext/shout/gstshout.c: + * gst/smooth/gstsmooth.c: + various: wrap property registration and add a single fixme for long desc. + +2010-10-19 15:06:36 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/pnm/gstpnmenc.c: + pnmenc: remove stray " in doc comment + +2010-10-19 13:44:25 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/dtmf/gstdtmfsrc.c: + dtmfsrc: remove DEBUG_FUNCPTR from gobject vmethods + +2010-10-08 19:33:16 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/elements/jifmux.c: + tests: jifmux: Adds tests for the new tags + Adds tests for the new exif tags in -base + +2010-10-09 17:36:07 -0700 David Schleef <ds@schleef.org> + + * ext/dirac/gstdiracenc.cc: + * ext/schroedinger/gstschroenc.c: + * ext/vp8/gstvp8dec.c: + * ext/vp8/gstvp8enc.c: + * gst-libs/gst/video/gstbasevideocodec.c: + * gst-libs/gst/video/gstbasevideocodec.h: + * gst-libs/gst/video/gstbasevideodecoder.c: + * gst-libs/gst/video/gstbasevideodecoder.h: + * gst-libs/gst/video/gstbasevideoencoder.c: + * gst-libs/gst/video/gstbasevideoencoder.h: + basevideo: Move common fields/functions to basecodec + +2010-09-28 18:21:57 +0300 Kaj-Michael Lang <milang@tal.org> + + * ext/zbar/gstzbar.c: + * ext/zbar/gstzbar.h: + zbar: Make scanner cache optional + +2010-10-14 23:04:15 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst-libs/gst/interfaces/photography.h: + photography: actualy use the enum in the vmethods + If we introduce a new GstPhotographyNoiseReduction, lets also use it + in the vmethods + +2010-10-14 23:03:19 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst-libs/gst/interfaces/photography.h: + photography: retab interface struct fields + +2010-10-14 12:32:05 -0700 David Schleef <ds@schleef.org> + + * common: + Automatic update of common submodule + From 5a668bf to 7bbd708 + +2010-10-14 14:07:48 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/gstcamerabin-enum.h: + camerabin: Remove unused entry + Remove camerabin unused enum entry + +2010-10-14 13:41:00 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst-libs/gst/interfaces/photography.h: + photography: Avoid breaking ABI + Move the newly added functions/fields to the end of the structs + +2010-10-14 11:45:55 +0200 Thijs Vermeir <thijsvermeir@gmail.com> + + * gst/mpegvideoparse/mpegpacketiser.c: + mpegvideoparse: accelerate search for start code + As the startcode always starts with 0x000001 some iterations + can be skipped if values > 1 are detected. + ~ 70% faster on HD video stream. + https://bugzilla.gnome.org/show_bug.cgi?id=632130 + +2010-10-14 16:48:21 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstac3parse.c: + ac3parse: properly parse e-ac3 frame header + Also add a few debug statements. + +2010-10-14 11:24:42 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * ext/faad/gstfaad.c: + faad: reflow opening and closing decoder + In particular, this reconfigures quite forcefully when renegotiation is needed. + Fixes #631501. + +2010-10-13 17:47:29 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/qtmux/gstqtmux.c: + qtmux: prevent infinite loop when adjusting framerate + Fixes #632070. + +2010-10-12 21:46:37 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/elements/jifmux.c: + tests: jifmux: update tests to the new datetime api + Update jifmux tests to use new gstdatetime API in core + +2010-10-12 09:37:56 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/geometrictransform/Makefile.am: + * gst/geometrictransform/gstrotate.c: + * gst/geometrictransform/gstrotate.h: + * gst/geometrictransform/plugin.c: + geometrictransform: Adds rotate element + Adds a new rotate element to geometrictransform. It still + needs some work. But this is a good starting point. + Based on patch from Bert Douglas <bertd tplogic com> + +2010-10-13 11:00:01 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstflacparse.c: + flacparse: tweak setting buffer metadata; avoid timestamp jitter + Fixes #631993. + +2010-10-12 18:17:27 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * ext/faad/gstfaad.c: + * ext/faad/gstfaad.h: + faad: cater for renegotiation + At least, whenever either stream (e.g. ADTS) or upstream provides necessary + info for doing so. + Fixes #631501. + +2010-10-12 18:07:49 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstaacparse.c: + * gst/audioparsers/gstaacparse.h: + aacparse: streamline src caps setting + In particular, also set src caps whenever changes in stream warrant doing so. + +2010-10-12 16:13:07 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * sys/directdraw/gstdirectdrawsink.c: + directdrawsink: port GstXOverlay bits to new API + Don't use deprecated API. + +2010-10-12 16:35:55 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * tests/check/elements/faac.c: + faac: adjust unit test to faac modified output + +2010-10-10 12:32:33 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * tests/check/Makefile.am: + checks: remove variables from Makefile.am that aren't set + Remove some stuff that was copy'n'pasted from core but + doesn't apply here. The following vars aren't set: + CHECK_CFLAGS, CHECK_LIBS, GST_OBJ_CFLAGS, GST_OBJ_LIBS, + so we may just as well remove them. + +2010-10-12 12:11:37 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * tests/examples/camerabin/gst-camera.c: + examples: Fix compilation with GTK+ 3.0 + +2010-10-12 10:28:33 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * tests/check/elements/flacparse.c: + flacparse: Adjust unit tests to new flacparse behaviour + Garbage after frames is now included in the frames because flacparse + has no easy way to detect the real end of a frame. Decoders are + expected to everything after the frame because only decoding the + bitstream will reveal the real end of the frame. + Fixes bug #631814. + +2010-10-12 10:27:53 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/audioparsers/gstflacparse.c: + flacparse: Don't drop the last frame if it is followed by garbage + See bug #631814. + +2010-10-11 17:49:46 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: perform bitrate handling and posting after newsegment sending + +2010-10-11 17:36:19 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: immediately post subclass provided bitrate + +2010-10-11 17:06:48 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstflacparse.c: + flacparse: fix parsing with unknown framesizes + Fixes #631814 (mostly). + +2010-10-11 17:05:28 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * ext/faac/gstfaac.c: + * ext/faac/gstfaac.h: + faac: handle trailing encoder output + +2010-10-11 14:25:41 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * ext/gsettings/gstswitchsrc.c: + switchsrc: Set the GST_ELEMENT_IS_SOURCE flag + +2010-09-13 19:07:55 +0100 Damien Lespiau <damien.lespiau@intel.com> + + * sys/dvb/gstdvbsrc.c: + dvbsrc: Fix example usage, bandwidth=8 not 8MHz + The bandwidth property is enum that takes the values 8, 7, 6, AUTO not + 8MHz. + +2010-10-08 17:01:29 -0400 Olivier Crête <olivier.crete@collabora.co.uk> + + * sys/shm/shmalloc.h: + shm: Add C++ protection + Add c++ protection in the relevant places + +2010-10-08 12:44:45 -0700 David Schleef <ds@schleef.org> + + * common: + Automatic update of common submodule + From c4a8adc to 5a668bf + +2010-10-08 12:55:29 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * common: + Automatic update of common submodule + From 5e3c9bf to c4a8adc + +2010-10-07 23:37:36 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/audioparsers/gstflacparse.c: + flacparse: Simplify frame header parsing by using lookup tables + Based on a patch by Felipe Contreras. + See bug #631200. + +2010-10-07 23:28:08 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/audioparsers/gstflacparse.c: + * gst/audioparsers/gstflacparse.h: + flacparse: Don't parse the complete FLAC frames but only look for valid frame headers + Thanks to Felipe Contreras for the suggestion. This is partially + based on his patches and makes flacparse more than 3.5 times faster. + Looking for valid frame headers is unlikely to give false positives + because every frame header is at least 9 bytes long, contains a + 14 bit sync code and a 8 bit checksum over the first 8 bytes. + Fixes bug #631200. + +2010-10-07 11:59:30 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/sdp/gstsdpdemux.c: + sdpdemux: workaround internal rtspsrc failing state change + Fixes #630046. + +2010-10-07 10:34:48 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/rawparse/Makefile.am: + * gst/rawparse/gstaudioparse.c: + * gst/rawparse/gstaudioparse.h: + audioparse: Add support for setting the channel-positions + +2010-10-06 18:32:51 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/audioparsers/gstflacparse.c: + flacparse: Really post tags only after the initial newsegment event + The first newsegment event will be send by the first call to + gst_base_parse_push_buffer() if necessary, posting the tags + before that is not a good idea. Instead do it from the + GstBaseParse::pre_push_buffer vfunc. + +2010-10-06 16:54:16 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/coloreffects/gstchromahold.c: + chromahold: Fix hue calculation for red colors + Also make the calculation much more accurate... + +2010-10-06 15:21:09 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/coloreffects/gstchromahold.c: + chromahold: Make everything greyscale if the target color is grey + +2010-10-06 11:55:34 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/coloreffects/Makefile.am: + * gst/coloreffects/gstchromahold.c: + * gst/coloreffects/gstchromahold.h: + * gst/coloreffects/gstplugin.c: + chromahold: Add chromahold color effect + This effect converts all colors except a single one to + grey. The color is selected by an RGB triple and a + tolerance for the color matching in hue degree can be specified. + +2010-10-05 17:04:10 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/sdp/gstsdpdemux.c: + sdpdemux: fix and reflow some exits + +2010-10-05 16:56:49 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/sdp/gstsdpdemux.c: + sdpdemux: error out if no streams found in sdp message + +2010-10-05 16:47:51 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/sdp/gstsdpdemux.c: + sdpdemux: unbreak standard manager setup + +2010-10-05 11:44:48 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * tests/check/elements/.gitignore: + .gitignore: ignore more unit test binaries + +2010-10-05 11:42:42 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * Makefile.am: + * configure.ac: + * docs/plugins/gst-plugins-bad-plugins-docs.sgml: + * docs/plugins/inspect/plugin-alsaspdif.xml: + * ext/Makefile.am: + * ext/alsaspdif/Makefile.am: + * ext/alsaspdif/alsaspdifsink.c: + * ext/alsaspdif/alsaspdifsink.h: + * gst-plugins-bad.spec.in: + * m4/Makefile.am: + * m4/gst-alsa.m4: + alsaspdif: remove alsaspdifsink element + Remove alsaspdifsink, it's not needed any longer. alsasink in -base + has been able to handle SPDIF for a while now. + +2010-10-05 11:17:52 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + Revert "baseparse: add skip property" + This reverts commit b5a3d60363d837a10f0533c141ec93d10b742312. + Reverting this for now, since no one really seems to remember why this + property exists or what it could possibly be good for. It seems to have + been in the original mp3parse since the beginning of time and was back- + ported from there. + +2010-10-04 10:41:52 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/audioparsers/gstflacparse.c: + flacparse: Fix uninitialized variable compiler warnings + These warnings are wrong, the variables are only used if they were + initialized by the bit reader. + +2010-09-14 02:48:58 +0300 Felipe Contreras <felipe.contreras@gmail.com> + + * gst/audioparsers/gstflacparse.c: + flacparse: fix picture parsing + Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> + +2010-10-03 23:54:49 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/audioparsers/gstflacparse.c: + flacparse: Push tags before the header buffers are pushed + +2010-08-02 20:50:21 +0300 Felipe Contreras <felipe.contreras@gmail.com> + + * gst/audioparsers/gstflacparse.c: + flacparse: trivial caps fix + Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> + +2010-10-03 23:45:46 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/qtmux/gstqtmux.c: + qtmux: Add G_PARAM_STATIC_STRINGS + Add G_PARAM_STATIC_STRINGS to qtmux properties + +2010-10-03 23:14:53 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/Makefile.am: + tests: valve: Fix tests build + Adds missing cflags/libs to valve check test to + fix build + +2010-10-03 23:50:29 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + audioparser: Let the format string agree with the parameters to fix compiler warning + +2010-10-03 15:55:22 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * sys/vdpau/mpeg/gstvdpmpegdec.c: + vdpau: Check return values of the bitreader functions + +2010-10-03 15:41:20 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/audioparsers/gstac3parse.c: + ac3parse: Use unchecked versions of the bitreader get functions + We didn't check the return values anyway... + +2010-09-28 13:52:29 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/valve/gstvalve.c: + valve: no need to ref the object in _chain + Don't ref the pad in chain, like elsewhere + +2010-09-22 15:44:43 +0530 Arun Raghavan <arun.raghavan@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: Fix debug output + We lose the reference to the buffer after gst_pad_push(), so the debug + print should happen before. + https://bugzilla.gnome.org/show_bug.cgi?id=622276 + +2010-10-01 12:34:55 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * tests/check/Makefile.am: + * tests/check/elements/flacparse.c: + * tests/check/elements/parser.c: + * tests/check/elements/parser.h: + audioparsers: add flacparse unit test + ... and tweak parser test helper in the process. + +2010-09-29 16:12:42 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: support reverse playback + ... in pull mode or upstream driven. + +2010-09-27 12:16:43 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: remove done TODOs and update documentation + +2010-09-25 14:40:54 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: use determined seekability in answering SEEKING query + +2010-09-25 14:32:06 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: add skip property + +2010-09-25 13:59:39 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * tests/check/Makefile.am: + * tests/check/elements/ac3parse.c: + * tests/check/elements/mpegaudioparse.c: + audioparsers: add ac3parse and mpegaudioparse unit test + +2010-09-25 13:59:18 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/Makefile.am: + * gst/audioparsers/gstmpegaudioparse.c: + * gst/audioparsers/gstmpegaudioparse.h: + * gst/audioparsers/plugin.c: + mpegaudioparse: initial version + ... adequately equivalent to mp3parse, so lets boldly set it + to higher rank. + +2010-09-25 14:01:07 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstaacparse.c: + aacparse: set minimum frame size at _start + ... rather than one time at _init. + +2010-09-25 13:50:51 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * tests/check/Makefile.am: + * tests/check/elements/aacparse.c: + * tests/check/elements/aacparse_data.h: + * tests/check/elements/amrparse.c: + * tests/check/elements/amrparse_data.h: + * tests/check/elements/parser.c: + * tests/check/elements/parser.h: + audioparsers: refactor existing unit tests using common helper + +2010-09-22 15:07:09 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstaacparse.c: + * gst/audioparsers/gstac3parse.c: + * gst/audioparsers/gstamrparse.c: + * gst/audioparsers/gstbaseparse.c: + * gst/audioparsers/gstbaseparse.h: + baseparse: use _set_frame_props to configure frame lead_in and lead_out + ... provided a corresponding decoder with sufficient leading and following + frames to carry out full decoding for a particular segment. + +2010-09-22 14:13:17 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstaacparse.c: + * gst/audioparsers/gstac3parse.c: + * gst/audioparsers/gstamrparse.c: + * gst/audioparsers/gstbaseparse.c: + * gst/audioparsers/gstbaseparse.h: + * gst/audioparsers/gstflacparse.c: + baseparse: use _set_duration to configure duration update interval + ... as it logically belongs there as one or the other; either subclass + can provide a duration, or an estimate must be made (reguarly updated). + +2010-09-22 13:55:20 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: localize use of provided fps information + +2010-09-22 12:13:12 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: seek table and accurate seek support + +2010-09-21 13:57:10 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: proper and more extended segment and seek handling + That is, loop pause handling, segment seek support, newsegment for gaps, etc + +2010-09-21 10:57:04 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + * gst/audioparsers/gstbaseparse.h: + baseparse: add index support + +2010-09-21 09:59:56 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: refactor state reset + +2010-09-20 16:39:37 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: prevent indefinite resyncing + +2010-09-20 13:57:55 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: specific EOS handling if no output so far + +2010-09-20 13:31:57 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: adjust _set_frame_prop documentation and set default as claimed + +2010-09-20 13:30:54 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: fix bitrate copy-and-paste and update heuristic + +2010-09-17 18:33:29 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: post duration message if average bitrates is updated + +2010-09-17 18:24:22 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstaacparse.c: + * gst/audioparsers/gstbaseparse.c: + * gst/audioparsers/gstbaseparse.h: + baseparse: remove is_seekable vmethod and use a set_seek instead + Seekability, like duration, etc is unlikely to change (frequently), and + the default assumption covers most cases, so let subclass set when needed. + At the same time, allow subclass to indicate if it has seek-metadata (table) + available, and possibly have it provide an average bitrate. + +2010-09-17 17:35:40 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstac3parse.c: + ac3parse: remove redundant default is_seekable + +2010-09-17 17:21:46 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + * gst/audioparsers/gstbaseparse.h: + baseparse: add another hook for subclass prior to pushing buffer + ... and allow subclass to perform custom segment clipping, or to + emit tags or messages at this time. + +2010-09-17 17:19:37 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: 0 converts to 0 by default + +2010-09-16 18:56:46 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + * gst/audioparsers/gstbaseparse.h: + basepase: refactor conversion using helper function and export default convert + +2010-09-16 18:35:47 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: streamline query handling + +2010-09-16 11:51:20 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + * gst/audioparsers/gstbaseparse.h: + baseparse: cleanup struct and remove unused member + +2010-08-16 11:04:37 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/plugin.c: + audioparsers: increase ranks to enable auto-plugging + Because we can, and should, have some shakedown testing before having + these make it into -good later on ... + +2010-09-22 16:07:24 +0530 Arun Raghavan <arun.raghavan@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: Allow chaining of subclass event handlers + This allows the child class to chain its event handler with + GstBaseParse, so that subclasses don't have to duplicate all the default + event handling logic. + https://bugzilla.gnome.org/show_bug.cgi?id=622276 + +2010-09-30 17:48:35 -0400 Olivier Crête <olivier.crete@collabora.co.uk> + + * tests/check/elements/valve.c: + tests: Fix caps leak in the valve test + +2010-09-30 17:24:29 -0400 Olivier Crête <olivier.crete@collabora.co.uk> + + * tests/check/Makefile.am: + * tests/check/elements/.gitignore: + * tests/check/elements/valve.c: + valve: Add unit tests + Add a unit test for the valve element. + +2010-09-30 16:26:19 -0400 Olivier Crête <olivier.crete@collabora.co.uk> + + * gst/valve/gstvalve.c: + * gst/valve/gstvalve.h: + valve: Make the drop variable into an atomic. + Using an atomic allows us to avoid locking the whole object all time time. + As suggested by Stefan Kost. + +2010-09-30 16:22:04 -0400 Olivier Crête <olivier.crete@collabora.co.uk> + + * gst/valve/gstvalve.c: + valve: Correctly set the DISCONT flag after dropping buffers + +2010-09-30 16:16:47 -0400 Olivier Crête <olivier.crete@collabora.co.uk> + + * gst/valve/gstvalve.c: + valve: Remove superflous checking casts + +2010-09-30 16:13:23 -0400 Olivier Crête <olivier.crete@collabora.co.uk> + + * gst/valve/gstvalve.c: + valve: Fix style, improve comments + Minor improvements to the comments and break a few overly long lines + +2010-09-30 16:07:29 -0400 Olivier Crête <olivier.crete@collabora.co.uk> + + * gst/rtpmux/gstrtpdtmfmux.c: + * gst/rtpmux/gstrtpmux.c: + rtpmux: Improve documentation + Add an example pipeline, and try to explain a bit more what it does. + +2010-09-29 17:34:00 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/gstcamerabin.c: + camerabin: Do not wrongly fail when starting a capture + If the elements are in NULL/READY and changing state to + PAUSED/PLAYING while a capture is started + camerabin might not set the active_bin properly causing the + capture start to fail. + This patch fixes it by checking the current and pending state + of the branches instead of only the current one + +2010-09-29 10:13:06 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * ext/faad/gstfaad.c: + faad: reverse playback; cater for decoder delay + ... thereby actually using the gather and decode queues. + +2010-09-29 10:08:17 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * ext/faad/gstfaad.c: + faad: tweak output buffer timestamping + In particular, avoid packetised input leading to initial to non-0 output ts. + +2010-09-28 16:20:50 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/frei0r/gstfrei0r.c: + frei0r: Use static caps instead of converting strings to caps all the time + +2010-09-28 16:14:14 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/frei0r/gstfrei0r.c: + frei0r: Fix crashes if plugins don't provide correct property information + The vertigo plugin for example claims to have 3 properties but + the 3rd property does nothing and has a NULL name. + Fixes bug #630783. + Thanks to Martti Kühne for debugging this. + +2010-09-28 14:26:11 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/valve/gstvalve.c: + valve: move default: parst in the switch statement to the end + Now sure if it matters, but the previous form looks weired. + +2010-09-28 14:23:01 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/valve/gstvalve.c: + valve: move debug-category registration to type init + +2010-09-28 14:22:18 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/liveadder/liveadder.c: + liveadder: move debug-category registration to type init + +2010-09-28 14:17:45 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/liveadder/liveadder.c: + liveadder: GST_BOILERPLATE already sets parent_class + +2010-09-28 14:16:58 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/liveadder/liveadder.c: + liveadder: use base_init for pad_templates and element_details + +2010-09-28 14:15:57 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/liveadder/liveadder.c: + liveadder: use G_PARAM_STATIC_STRINGS on properties + +2010-09-28 14:15:13 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/valve/gstvalve.c: + valve: use G_PARAM_STATIC_STRINGS on properties + +2010-09-28 14:07:39 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/valve/gstvalve.c: + valve: GST_BOILERPLATE already sets parent_class + +2010-09-28 14:08:29 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/videomeasure/gstvideomeasure_collector.c: + videomeassure: GST_BOILERPLATE already sets parent_class + +2010-09-28 11:35:53 +0300 Hu Gang <gang.a.hu@intel.com> + + * docs/plugins/gst-plugins-bad-plugins-sections.txt: + * gst-libs/gst/interfaces/photography.c: + * gst-libs/gst/interfaces/photography.h: + * gst/camerabin/gstcamerabin-enum.h: + photography: extend photography iface + Add more color tone modes and add NoseReduction settings. + Fixes #616814. + +2010-09-26 20:41:25 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * ext/resindvd/resindvdsrc.c: + resindvdsrc: improve error messages on read erros + Provide i18n-ed error messages when a read error happens, + and point out that the error could be happening because the + DVD is scrambled. + https://bugzilla.gnome.org/show_bug.cgi?id=613633 + +2010-09-24 00:05:17 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * configure.ac: + configure: set plugin release datetime + +2010-09-25 12:33:58 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * ext/ofa/gstofa.c: + ofa: Call g_object_notify() after the fingerprint was created + +2010-09-25 10:46:34 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/frei0r/gstfrei0r.c: + * gst/frei0r/gstfrei0rfilter.c: + * gst/frei0r/gstfrei0rfilter.h: + * gst/frei0r/gstfrei0rmixer.c: + * gst/frei0r/gstfrei0rmixer.h: + * gst/frei0r/gstfrei0rsrc.c: + * gst/frei0r/gstfrei0rsrc.h: + frei0r: Fix scanning of plugin subdirectories and support different vendors + The frei0r spec specifies, that plugins can be in subdirectories inside + the main plugin directories to introduce new namespaces called vendors. + +2010-09-24 22:47:01 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/frei0r/frei0r.h: + frei0r: Update frei0r interface specification to 1.2 + +2010-09-24 22:43:51 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/frei0r/gstfrei0r.c: + frei0r: Add support for the FREI0R_PATH environment variable + This was added in version 1.2 of the spec and replaces the default + list of directories. + +2010-09-23 14:15:08 +0300 Lasse Laukkanen <ext-lasse.2.laukkanen@nokia.com> + + * gst/debugutils/fpsdisplaysink.c: + fpsdisplaysink: initialize interval_ts and last_frames_* counters + Initialize interval_ts to first QOS event timestamp, otherwise the + fps statistics are printed always after one rendered frame. + Also, initialize last_frames_* counters, the values are bogus e.g. after + PLAYING-NULL-PLAYING state change. + +2010-09-24 13:29:55 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/rtpmux/gstrtpdtmfmux.c: + rtpdtmfmux: remove unused variable + +2010-09-24 13:25:22 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/rtpmux/gstrtpdtmfmux.c: + rtpdtmfmux: remove unused signal boilerplate + +2010-09-24 13:24:48 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/rtpmux/gstrtpmux.c: + rtpmux: no need to ref pad in _chain() + +2010-09-22 23:41:32 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/examples/camerabin/gst-camera.c: + camerabin: example: make gst-camera use flags + Enable all convertion flags in gst-camera example app + for safety. + Fixes #603063 + +2010-09-22 23:39:07 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/camerabinvideo.c: + * gst/camerabin/gstcamerabin-enum.c: + * gst/camerabin/gstcamerabin-enum.h: + camerabin: Adds new video-colorspace-flag to flags + Adds a new flag to allow a colorspace convertion before + the video encoder element. + Fixes #603063 + +2010-09-22 22:39:49 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/camerabingeneral.c: + * gst/camerabin/camerabinpreview.c: + * gst/camerabin/camerabinvideo.c: + * gst/camerabin/gstcamerabin.c: + camerabin: Use link_full version for disabling hierarchy check + Disable hierarchy checks when linking because we are already + handling the element adding to bins and it should be done + correctly. + +2010-09-22 21:03:56 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/camerabinvideo.c: + * gst/camerabin/gstcamerabin.c: + camerabin: Set queues to silent + We currently don't use queues' signals, so set them + to silent. + +2010-09-22 11:57:28 -0700 David Schleef <ds@schleef.org> + + * ext/schroedinger/gstschrodec.c: + schrodec: Fix class definition + Class structures should include parent class, not the parent + instance structure. + +2010-09-22 16:41:33 +0200 Wim Taymans <wim.taymans@collabora.co.uk> + + * gst/pcapparse/gstpcapparse.c: + * gst/pcapparse/gstpcapparse.h: + pcapparse: fix weird caps code + Remove the weird (failing) code to figure out caps on the srcpad. + Add a caps property to decide what caps to put on the outgoing buffers. + Fix an event leak. + +2010-09-21 18:13:37 -0700 David Schleef <ds@schleef.org> + + * gst/colorspace/colorspace.c: + colorspace: quiet a GST_ERROR + +2010-09-21 19:07:05 +0200 Wim Taymans <wim.taymans@collabora.co.uk> + + * gst/sdp/gstsdpdemux.c: + * gst/sdp/gstsdpdemux.h: + sdpdemux: add property to disable redirect + Add a property to avoid redirection to the rtsp-sdp:// url but instead embeds an + rtspsrc element inside sdpdemux as the session manager. + Based on patch by Marco Ballesio. + Fixes #630046 + +2010-09-21 18:45:03 +0200 Edward Hervey <bilboed@bilboed.com> + + * ext/sdl/sdlvideosink.c: + sdlvideosink: Fix function prototype for touchy compilers + +2010-09-21 18:34:19 +0200 Edward Hervey <bilboed@bilboed.com> + + * common: + Automatic update of common submodule + From 080e025 to 5e3c9bf + +2010-09-21 16:31:07 +0200 Edward Hervey <bilboed@bilboed.com> + + * ext/sdl/sdlvideosink.c: + sdl: Port to new XOverlay API + Fixes #630253 + +2010-09-21 16:26:34 +0200 Edward Hervey <bilboed@bilboed.com> + + * sys/vdpau/gstvdpsink.c: + vdpau: Use the new XOverlay API + Fixes #630254 + +2010-09-21 10:59:42 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/examples/camerabin/gst-camera.c: + * tests/examples/camerabin/gst-camerabin-test.c: + camerabin: examples: do not use deprecated GstXOverlay functions + Replace the deprecated gst_x_overlay_set_xwindow_id with + gst_x_overlay_set_window_handle + Fixes #630255 + +2010-09-21 12:33:18 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * configure.ac: + configure: Use -DGST_DISABLE_DEPRECATED again for GIT versions + +2010-09-21 12:29:06 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * sys/dshowdecwrapper/gstdshowaudiodec.cpp: + * sys/dshowdecwrapper/gstdshowvideodec.cpp: + dshowdecwrapper: Don't use GST_FLOW_IS_FATAL() + And don't error out on UNEXPECTED + +2010-09-21 12:27:56 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * ext/spc/gstspc.c: + spc: Don't use GST_FLOW_IS_FATAL() + +2010-09-21 12:27:20 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * ext/mplex/gstmplex.cc: + mplex: Don't use GST_FLOW_IS_SUCCESS() + +2010-08-27 19:17:14 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * tests/icles/pitch-test.c: + pitch-test: Don't use deprecated GstController API + +2010-08-27 19:00:38 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * ext/timidity/gsttimidity.c: + timidity: Don't post an error message on the bus for UNEXPECTED + Also don't use GST_FLOW_IS_FATAL() + +2010-08-27 19:00:18 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * ext/timidity/gstwildmidi.c: + wildmidi: Don't use GST_FLOW_IS_FATAL() + +2010-08-27 18:58:23 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * ext/gme/gstgme.c: + gme: Post an error message on the bus for fatal errors + Also don't use GST_FLOW_IS_FATAL(). + +2010-08-27 18:56:23 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * ext/sndfile/gstsfsink.c: + sfsink: Don't use GST_FLOW_IS_FATAL() + +2010-08-27 18:52:54 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/tta/gstttaparse.c: + ttaparse: Don't post an error message on UNEXPECTED + Also don't use GST_FLOW_IS_FATAL() + +2010-08-27 18:51:59 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/sdp/gstsdpdemux.c: + sdpdemux: Don't use GST_FLOW_IS_SUCCESS() + +2010-08-27 18:51:24 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/rawparse/gstrawparse.c: + rawparse: Don't use GST_FLOW_IS_FATAL() + +2010-08-27 18:50:30 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/nuvdemux/gstnuvdemux.c: + nuvdemux: Don't use GST_FLOW_IS_FATAL() + And don't post an error message for WRONG_STATE or UNEXPECTED. + +2010-08-27 18:49:12 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/nsf/gstnsf.c: + * gst/nsf/nes_apu.c: + nsf: Don't use GST_FLOW_IS_FATAL() + +2010-08-27 18:48:25 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/mxf/mxfdemux.c: + mxfdemux: Don't use GST_FLOW_IS_FATAL() + +2010-08-27 18:47:03 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/mve/gstmvedemux.c: + * gst/mve/gstmvedemux.h: + mvedemux: Add proper flow return aggregation + NOT_LINKED should only be returned if all streams returned NOT_LINKED. + +2010-08-27 18:41:06 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/mpegdemux/gstmpegdemux.c: + * gst/mpegdemux/gstmpegtsdemux.c: + * gst/mpegdemux/mpegtsparse.c: + mpegdemux: Don't use GST_FLOW_IS_FATAL() + And fix some minor issues related to its usage. + +2010-08-27 18:36:26 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/autoconvert/gstautoconvert.c: + autoconvert: Don't use GST_FLOW_IS_FATAL() + +2010-08-27 18:35:10 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: Don't use GST_FLOW_IS_FATAL() + Also don't post an error message for UNEXPECTED and do it + for NOT_LINKED. + +2010-08-27 18:33:49 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/asfmux/gstasfparse.c: + asfparse: Don't use GST_FLOW_IS_FATAL() + Also don't push EOS downstream on WRONG_STATE, it will be dropped anyway. + +2010-08-27 18:32:46 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst-libs/gst/video/gstbasevideodecoder.c: + basevideodecoder: Don't use GST_FLOW_IS_SUCCESS() + +2010-08-27 18:32:33 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/aiff/aiffparse.c: + aiffparse: Don't use GST_FLOW_IS_FATAL() + +2010-09-20 21:46:49 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/gstcamerabin.c: + camerabin: Mention photography interface in docs + Add a note to docs about getting the videosource and accessing + its photography interface (in case it has it) + Fixes #616923 + +2010-08-25 14:04:59 +0300 Lasse Laukkanen <ext-lasse.2.laukkanen@nokia.com> + + * gst/camerabin/gstcamerabin.c: + camerabin: Adds missing variable initialization + Adds missing app_src_vid initialization + +2010-08-26 15:33:59 +0300 Teemu Katajisto <ext-teemu.katajisto@nokia.com> + + * gst/camerabin/gstcamerabin.c: + camerabin: check state change to playing for imagebin and videobin + Properly check and handle error cases related to imagebin and + videobin state changes. + +2010-06-28 21:48:26 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/camerabinimage.c: + camerabin: Remove useless src template pad + camerabin imagebin doesn't need a src template pad. + +2010-06-21 09:34:43 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/camerabinpreview.c: + * gst/camerabin/camerabinpreview.h: + * gst/camerabin/gstcamerabin.c: + camerabin: Forward tag events to preview pipeline + Forward tag events from image pipeline to preview pipeline so + that preview elements can use capture tags information + +2010-06-21 16:17:24 +0300 Hoseok Chang <hoseok.chang@nokia.com> + + * gst/camerabin/camerabinpreview.c: + * gst/camerabin/camerabinpreview.h: + * gst/camerabin/gstcamerabin-enum.h: + * gst/camerabin/gstcamerabin.c: + * gst/camerabin/gstcamerabin.h: + camerabin: add "preview-source-filter" property + Adds 'preview-source-filter' for adding an element to proccess + the preview images before posting them to the bus. + +2010-05-25 15:39:43 +0300 Lasse Laukkanen <ext-lasse.2.laukkanen@nokia.com> + + * tests/examples/camerabin/gst-camerabin-test.c: + camerabin: update tag names in test application to latest gst definitions + +2010-05-17 13:44:36 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/gstcamerabin.c: + * gst/camerabin/gstcamerabin.h: + camerabin: Make block-after-capture resetting more consistent + Adds another boolean to help controlling viewfinder blocking, + making it possible for the applications to reset the viewfinder + blocking after capture was started but before the blocking + actually happens. + +2010-05-12 21:11:27 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/gstcamerabin.c: + camerabin: Unblock the viewfinder when going to READY + Unblock the viewfinder when going to ready to avoid + blocking when setting camerabin to playing again and + attemping to capture. Keep the property as is. + +2010-09-20 17:19:33 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/gstcamerabin.c: + camerabin: add monitoring and support for photoiface zoom for video-source + Makes camerabin aware of changes in its videosource zoom property. + +2010-09-20 16:22:30 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/gstcamerabin.c: + * gst/camerabin/gstcamerabin.h: + * tests/check/elements/camerabin.c: + * tests/examples/camerabin/gst-camerabin-test.c: + camerabin: Change zoom property from int to float + Updates zoom property for a more natural type and + makes it consistent with the photography API + +2010-09-19 18:51:35 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst-libs/gst/interfaces/photography.c: + * gst-libs/gst/interfaces/photography.h: + photography: Add zoom property + Adds a property to set/get the zoom as a float + +2010-06-08 10:04:52 +0300 Lasse Laukkanen <ext-lasse.2.laukkanen@nokia.com> + + * gst/camerabin/gstcamerabin.c: + * gst/camerabin/gstcamerabin.h: + camerabin: remove caching photography interface settings + Camerabin doesn't implement photography interface, so we + don't need caching the video source properties anymore. + +2010-04-22 17:46:59 +0300 Teemu Katajisto <ext-teemu.katajisto@nokia.com> + + * tests/examples/camerabin/Makefile.am: + * tests/examples/camerabin/gst-camera.c: + * tests/examples/camerabin/gst-camerabin-test.c: + examples: camerabin: use photoiface properties through video-source + Fixes #616923 + +2010-04-22 14:03:34 +0300 Teemu Katajisto <ext-teemu.katajisto@nokia.com> + + * tests/check/elements/camerabin.c: + tests: camerabin: remove photoiface property/settings tests + Fixes #616923 + +2010-08-31 18:06:15 -0300 Teemu Katajisto <ext-teemu.katajisto@nokia.com> + + * gst/camerabin/Makefile.am: + * gst/camerabin/gstcamerabin.c: + * gst/camerabin/gstcamerabinphotography.c: + * gst/camerabin/gstcamerabinphotography.h: + camerabin: remove photography interface implementation from camerabin + Remove notify signal proxy for video-source. Application can use + video-source directly from now on to get notified of property changes. + Add monitoring scene-mode property change to select lowest possible + framerate for video capture when night mode is selected. + Fixes #616923 + +2010-04-29 12:44:29 +0300 Teemu Katajisto <ext-teemu.katajisto@nokia.com> + + * tests/examples/camerabin/gst-camerabin-test.c: + examples: camerabin: add --no-xwindow option and fix option handling + Add --no-xwindow option to not to create xwindow. Also fix zoom and + mute option types and filename string handling. + +2010-04-29 13:24:18 +0300 Lasse Laukkanen <ext-lasse.2.laukkanen@nokia.com> + + * gst-libs/gst/interfaces/photography.c: + * gst-libs/gst/interfaces/photography.h: + photography: Add image-preview-supported-caps interface property + Adds a readable property to gstphotography interface to query + what are the allowed preview caps supported. + Patch by Tommi Myöhänen <ext-tommi.1.myohanen@nokia.com> + +2010-09-20 12:34:06 -0700 David Schleef <ds@schleef.org> + + * gst-libs/gst/video/gstbasevideocodec.c: + * gst-libs/gst/video/gstbasevideocodec.h: + * gst-libs/gst/video/gstbasevideoutils.h: + basevideo: Remove unused code + +2010-09-20 11:26:59 -0700 David Schleef <ds@schleef.org> + + * gst-libs/gst/video/gstbasevideodecoder.c: + basevideo: Remove check for old -base + +2010-09-19 19:33:40 -0700 David Schleef <ds@schleef.org> + + * gst-libs/gst/video/gstbasevideoencoder.c: + * gst-libs/gst/video/gstbasevideoencoder.h: + * gst-libs/gst/video/gstbasevideoutils.h: + basevideo: Add handling of GstForceKeyUnit events + +2010-09-18 19:25:49 -0700 David Schleef <ds@schleef.org> + + * gst/invtelecine/gstinvtelecine.c: + invtelecine: Fix name of 30p/60i pattern + +2010-09-18 19:21:47 -0700 David Schleef <ds@schleef.org> + + * ext/schroedinger/gstschrodec.c: + * gst-libs/gst/video/gstbasevideodecoder.c: + * gst-libs/gst/video/gstbasevideodecoder.h: + basevideodecoder: add capture pattern handling + Move typical scan_for_sync() usage into base class, which just + calls gst_adapter_masked_scan_uint32(). + +2010-09-18 19:14:36 -0700 David Schleef <ds@schleef.org> + + * gst-libs/gst/video/gstbasevideodecoder.c: + basevideodecoder: Don't blow away field information + Also, set field flags correctly. + +2010-09-18 17:28:48 -0700 David Schleef <ds@schleef.org> + + * ext/schroedinger/gstschrodec.c: + * ext/vp8/gstvp8dec.c: + * gst-libs/gst/video/gstbasevideodecoder.c: + * gst-libs/gst/video/gstbasevideodecoder.h: + * gst-libs/gst/video/gstbasevideoutils.h: + basevideo: Move deadline to frame structure + +2010-09-18 14:57:32 -0700 David Schleef <ds@schleef.org> + + * gst/interlace/gstinterlace.c: + interlace: Add allow-rff property. Fix timestamping + +2010-09-18 13:32:07 -0700 David Schleef <ds@schleef.org> + + * gst/interlace/gstinterlace.c: + interlace: merge telecine into normal operation + +2010-09-08 15:08:50 +0200 Robert Swain <robert.swain@collabora.co.uk> + + * gst/interlace/gstinterlace.c: + interlace: Add telecine support + +2010-09-17 08:43:48 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * configure.ac: + * ext/cog/Makefile.am: + * ext/cog/cogvirtframe.c: + * ext/cog/gstcog.c: + * ext/cog/gstcogmse.c: + cog: Allow compilation without orc + Also don't ignore --disable-orc. Fixes bug #629897. + +2010-09-14 16:17:47 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/elements/camerabin.c: + camerabin: Adds a new test to check sequential capture of images + Adds a new test case that shoots a sequence of image capture + and check that the files are valid. + Also adds taglist checking capabilities to tests. + +2010-09-15 17:54:49 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/qtmux/atoms.c: + * gst/qtmux/atoms.h: + * gst/qtmux/fourcc.h: + * gst/qtmux/gstqtmux.c: + * gst/qtmux/gstqtmux.h: + qtmux: Follow xmp serialization guidelines closer + qt and isom variants have different ways of serializing + xmp, follow these guidelines. + Those can be found in Adobe's xmp docs. + +2010-09-15 21:47:09 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/colorspace/gstcolorspaceorc-dist.c: + * gst/colorspace/gstcolorspaceorc-dist.h: + colorspace: add orc-dist files + Should fix build without orc or too old orc. + +2010-09-15 17:51:26 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * gst/debugutils/gstchecksumsink.h: + checksumsink: fix up copyright in header file + +2010-09-12 14:59:42 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * pkgconfig/gstreamer-libs-uninstalled.pc.in: + * pkgconfig/gstreamer-libs.pc.in: + * pkgconfig/gstreamer-plugins-uninstalled.pc.in: + * pkgconfig/gstreamer-plugins.pc.in: + pkgconfig: remove some old unused files from 0.8 days + +2010-09-15 18:38:03 +0300 Stefan Kost <ensonic@users.sf.net> + + * Makefile.am: + metadata: add removed files to cruft vars + +2010-09-15 18:13:55 +0300 Stefan Kost <ensonic@users.sf.net> + + * tests/check/elements/jifmux.c: + tests: add missing stdio include + +2010-09-15 18:10:33 +0300 Stefan Kost <ensonic@users.sf.net> + + * configure.ac: + * docs/plugins/Makefile.am: + * docs/plugins/gst-plugins-bad-plugins-docs.sgml: + * docs/plugins/gst-plugins-bad-plugins-sections.txt: + * docs/plugins/inspect/plugin-metadata.xml: + * ext/Makefile.am: + * ext/metadata/.gitignore: + * ext/metadata/Makefile.am: + * ext/metadata/README: + * ext/metadata/TODO: + * ext/metadata/gstbasemetadata.c: + * ext/metadata/gstbasemetadata.h: + * ext/metadata/gstmetadata.c: + * ext/metadata/gstmetadatademux.c: + * ext/metadata/gstmetadatademux.h: + * ext/metadata/gstmetadatamux.c: + * ext/metadata/gstmetadatamux.h: + * ext/metadata/metadata.c: + * ext/metadata/metadata.h: + * ext/metadata/metadata_mapping.htm: + * ext/metadata/metadataexif.c: + * ext/metadata/metadataexif.h: + * ext/metadata/metadataiptc.c: + * ext/metadata/metadataiptc.h: + * ext/metadata/metadatamuxjpeg.c: + * ext/metadata/metadatamuxjpeg.h: + * ext/metadata/metadatamuxpng.c: + * ext/metadata/metadatamuxpng.h: + * ext/metadata/metadataparsejpeg.c: + * ext/metadata/metadataparsejpeg.h: + * ext/metadata/metadataparsepng.c: + * ext/metadata/metadataparsepng.h: + * ext/metadata/metadataparseutil.c: + * ext/metadata/metadataparseutil.h: + * ext/metadata/metadatatags.c: + * ext/metadata/metadatatags.h: + * ext/metadata/metadatatypes.c: + * ext/metadata/metadatatypes.h: + * ext/metadata/metadataxmp.c: + * ext/metadata/metadataxmp.h: + * tests/check/Makefile.am: + * tests/check/pipelines/.gitignore: + * tests/check/pipelines/metadata.c: + * tests/icles/Makefile.am: + metadata: remove metadata plugin + This plugins functionality is replaced by utility libraries in base for exif + and xmp. Jpeg images can use this via jpegformat plugin. + Fixes #486659 + +2010-09-14 11:28:56 -0700 David Schleef <ds@schleef.org> + + * gst/bayer/gstbayer2rgb.c: + bayer2rgb: Add format=bggr/etc. to caps + +2010-09-13 18:49:43 -0700 David Schleef <ds@schleef.org> + + * gst/colorspace/Makefile.am: + * gst/colorspace/colorspace.c: + * gst/colorspace/colorspace.h: + * gst/colorspace/gstcolorspace.c: + * gst/colorspace/gstcolorspace.h: + * gst/colorspace/gstcolorspaceorc.orc: + colorspace: Add conversion code + Work in progress. Colorspace handles most format conversion using + 3-stage getline/matrix/putline process using an AYUV or ARGB + intermediate, with most functions handled by Orc. There is also + a table of single-pass conversions, all handled by Orc. The plan + is to add optional stages for various chroma upsampling/downsampling + algorithms, dithering, and float/int16 intermediates, and then have + Orc create multi-stage functions at runtime. + +2010-09-13 12:48:50 -0700 David Schleef <ds@schleef.org> + + * configure.ac: + * gst/colorspace/Makefile.am: + * gst/colorspace/gstcolorspace.c: + * gst/colorspace/gstcolorspace.h: + * gst/colorspace/gstcolorspaceorc.orc: + * gst/colorspace/yuv2rgb.c: + * gst/colorspace/yuv2rgb.h: + colorspace: Revive element + Now based on Orc. + +2010-09-09 14:49:06 -0400 Tristan Matthews <le.businessman@gmail.com> + + * ext/jack/Makefile.am: + * ext/jack/gstjackaudiosink.c: + * ext/jack/gstjackaudiosrc.c: + jack: added translatable text for server not found error + +2010-08-09 14:32:57 +0200 Olivier Crête <olivier.crete@collabora.co.uk> + + * ext/celt/gstceltenc.c: + celtenc: Change bitrate to bits/sec + +2010-09-10 13:36:24 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/jpegformat/gstjifmux.c: + jifmux: Reset tags when going to READY + Reset the tagsetter tags when going to READY state + +2010-09-10 13:33:16 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/jpegformat/gstjifmux.c: + * gst/jpegformat/gstjpegparse.c: + jpegformat: Fix element description + Use saner categories for jifmux/jpegparse elements + +2010-09-10 11:31:46 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/gstcamerabin.c: + camerabin: Set tags to more elements + Remove check for 'Muxer' category when setting tags + for tagsetters. Set them to all tagsetters in the + pipelines. + +2010-09-10 18:35:27 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/sdp/gstsdpdemux.c: + sdpdemux: redirect SDP with an rtsp control URL + When we find an SDP with an rtsp:// url as the global control attribute or when + all streams have an rtsp:// control attribute, post an redirect message with an + rtsp-sdp:// url containing the SDP. + Fixes #628214 + +2010-09-10 10:29:38 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/geometrictransform/gstfisheye.c: + * gst/geometrictransform/gsttunnel.c: + geometrictransform: Fix build with debugging disabled + Add some ifdefs to prevent build failures due to unused + variables + +2010-09-09 23:59:17 +0300 Stefan Kost <ensonic@users.sf.net> + + * tests/check/Makefile.am: + * tests/check/generic/states.c: + tests: allow running state tests for all elements + Now one can use GST_NO_STATE_IGNORE_ELEMENTS=1 make generic/states.check + to try elements that would normaly be skipped. + +2010-09-09 17:18:06 +0200 Edward Hervey <bilboed@bilboed.com> + + * configure.ac: + configure.ac: Remove dependency on libswscale + It's not used in the gst opencv plugin. + +2010-09-09 15:03:24 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * configure.ac: + * ext/opencv/Makefile.am: + opencv: define CV_NO_BACKWARD_COMPATIBILITY to suppress warnings caused by compat header + Compile with -DCV_NO_BACKWARD_COMPATIBILITY for now, so that the compat header + doesn't get included, which causes compiler warnings that (it seems) can't be + switched off easily. As a result, we also specify a max. version in configure, + so the build doesn't break if our code doesn't compile against newer opencv + versions any more with that flag. + +2010-09-09 11:07:47 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * ext/opencv/Makefile.am: + opencv: avoid 'unused' compiler warnings with inline functions in opencv headers + Override CV_INLINE to avoid 'unused' gcc warnings. GLib will take care of defining + 'inline' sufficiently and OpenCV's define isn't good enough to avoid 'unused' + compiler warnings (at least in version 2.1.0). + +2010-09-09 10:27:49 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * ext/opencv/gstopencv.c: + opencv: update plugin source package name and origin + +2010-09-08 23:59:38 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * ext/opencv/gstfacedetect.c: + * ext/opencv/gstfacedetect.h: + facedetect: Add more parameters + Expose the parameters of cvHaarDetectObjects in facedetect + element. + +2010-09-08 14:59:54 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * ext/opencv/Makefile.am: + * ext/opencv/basicfilters/Makefile.am: + * ext/opencv/basicfilters/gstcvdilate.c: + * ext/opencv/basicfilters/gstcvdilate.h: + * ext/opencv/basicfilters/gstcvdilateerode.c: + * ext/opencv/basicfilters/gstcvdilateerode.h: + * ext/opencv/basicfilters/gstcvequalizehist.c: + * ext/opencv/basicfilters/gstcvequalizehist.h: + * ext/opencv/basicfilters/gstcverode.c: + * ext/opencv/basicfilters/gstcverode.h: + * ext/opencv/basicfilters/gstcvlaplace.c: + * ext/opencv/basicfilters/gstcvlaplace.h: + * ext/opencv/basicfilters/gstcvsmooth.c: + * ext/opencv/basicfilters/gstcvsmooth.h: + * ext/opencv/basicfilters/gstcvsobel.c: + * ext/opencv/basicfilters/gstcvsobel.h: + * ext/opencv/edgedetect/Makefile.am: + * ext/opencv/edgedetect/gstedgedetect.c: + * ext/opencv/edgedetect/gstedgedetect.h: + * ext/opencv/faceblur/Makefile.am: + * ext/opencv/faceblur/gstfaceblur.c: + * ext/opencv/faceblur/gstfaceblur.h: + * ext/opencv/facedetect/Makefile.am: + * ext/opencv/facedetect/gstfacedetect.c: + * ext/opencv/facedetect/gstfacedetect.h: + * ext/opencv/gstcvdilate.c: + * ext/opencv/gstcvdilate.h: + * ext/opencv/gstcvdilateerode.c: + * ext/opencv/gstcvdilateerode.h: + * ext/opencv/gstcvequalizehist.c: + * ext/opencv/gstcvequalizehist.h: + * ext/opencv/gstcverode.c: + * ext/opencv/gstcverode.h: + * ext/opencv/gstcvlaplace.c: + * ext/opencv/gstcvlaplace.h: + * ext/opencv/gstcvsmooth.c: + * ext/opencv/gstcvsmooth.h: + * ext/opencv/gstcvsobel.c: + * ext/opencv/gstcvsobel.h: + * ext/opencv/gstedgedetect.c: + * ext/opencv/gstedgedetect.h: + * ext/opencv/gstfaceblur.c: + * ext/opencv/gstfaceblur.h: + * ext/opencv/gstfacedetect.c: + * ext/opencv/gstfacedetect.h: + * ext/opencv/gstopencvutils.c: + * ext/opencv/gstpyramidsegment.c: + * ext/opencv/gstpyramidsegment.h: + * ext/opencv/gsttemplatematch.c: + * ext/opencv/gsttemplatematch.h: + * ext/opencv/gsttextwrite.c: + * ext/opencv/gsttextwrite.h: + * ext/opencv/pyramidsegment/Makefile.am: + * ext/opencv/pyramidsegment/gstpyramidsegment.c: + * ext/opencv/pyramidsegment/gstpyramidsegment.h: + * ext/opencv/templatematch/Makefile.am: + * ext/opencv/templatematch/gsttemplatematch.c: + * ext/opencv/templatematch/gsttemplatematch.h: + * ext/opencv/textwrite/Makefile.am: + * ext/opencv/textwrite/gsttextwrite.c: + * ext/opencv/textwrite/gsttextwrite.h: + opencv: Refactor files structure + Remove internal folders and put all code inside the main plugin + folder. Also fixes some building warnings. + +2010-09-08 00:08:44 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * configure.ac: + * docs/plugins/Makefile.am: + * docs/plugins/gst-plugins-bad-plugins-docs.sgml: + * docs/plugins/gst-plugins-bad-plugins-sections.txt: + * docs/plugins/gst-plugins-bad-plugins.args: + * docs/plugins/gst-plugins-bad-plugins.hierarchy: + * docs/plugins/gst-plugins-bad-plugins.interfaces: + * docs/plugins/gst-plugins-bad-plugins.prerequisites: + * docs/plugins/inspect/plugin-opencv.xml: + * ext/Makefile.am: + * ext/opencv/Makefile.am: + opencv: Adds new plugin opencv + Moves opencv plugin from http://github.com/Elleo/gst-opencv + into -bad module. + +2010-09-05 23:09:26 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * ext/opencv/facedetect/gstfacedetect.c: + facedetect: Post an useful message + Add a message to be post when faces are found on a frame that + contains all faces on a single message and also has + timestamp/running/segment times for that buffer so it + can be identified. + This message is called 'facedetect' and has a 'faces' list + of structures with all faces. + The old 'face' message is still posted for each face found, but + it is not really useful as it doesn't have any reference to the + buffer that generated it. + +2010-09-05 17:53:24 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * ext/opencv/facedetect/Makefile.am: + * ext/opencv/facedetect/gstfacedetect.c: + * ext/opencv/facedetect/gstfacedetect.h: + facedetect: Use GstOpencvVideoFilter as the base class + Port facedetect to use GstOpencvVideoFilter as the base class + to inherit all the goodness that GstBaseTransform/GstVideoFilter + already handles. + +2010-09-03 20:27:31 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * ext/opencv/Makefile.am: + * ext/opencv/basicfilters/Makefile.am: + * ext/opencv/basicfilters/gstcvdilate.c: + * ext/opencv/basicfilters/gstcvdilateerode.c: + * ext/opencv/basicfilters/gstcvdilateerode.h: + * ext/opencv/basicfilters/gstcvequalizehist.c: + * ext/opencv/basicfilters/gstcvequalizehist.h: + * ext/opencv/basicfilters/gstcverode.c: + * ext/opencv/basicfilters/gstcvlaplace.c: + * ext/opencv/basicfilters/gstcvlaplace.h: + * ext/opencv/basicfilters/gstcvsmooth.c: + * ext/opencv/basicfilters/gstcvsmooth.h: + * ext/opencv/basicfilters/gstcvsobel.c: + * ext/opencv/basicfilters/gstcvsobel.h: + * ext/opencv/gstopencvbasetrans.c: + * ext/opencv/gstopencvbasetrans.h: + * ext/opencv/gstopencvvideofilter.c: + * ext/opencv/gstopencvvideofilter.h: + opencvbasetrans: Use GstVideoFilter as the base class + Port from GstBaseTransform to GstVideoFilter as the base class. + +2010-05-24 19:28:59 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * ext/opencv/basicfilters/Makefile.am: + * ext/opencv/basicfilters/gstcvlaplace.c: + * ext/opencv/basicfilters/gstcvlaplace.h: + * ext/opencv/gstopencv.c: + * ext/opencv/gstopencvbasetrans.c: + * ext/opencv/gstopencvbasetrans.h: + cvlaplace: adds new cvlaplace element + Adds new cvlaplace element. + Also adds a new opencvbasetransform function to be overriden + by children classes: the cv_set_caps, it allows children classes + to know what are they going to handle and prepare properly. + +2010-05-19 20:11:39 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * ext/opencv/basicfilters/Makefile.am: + * ext/opencv/basicfilters/gstcvsobel.c: + * ext/opencv/basicfilters/gstcvsobel.h: + * ext/opencv/gstopencv.c: + * ext/opencv/gstopencvutils.c: + Adds new element cvsobel + +2010-05-17 19:04:49 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * ext/opencv/basicfilters/Makefile.am: + * ext/opencv/basicfilters/gstcvequalizehist.c: + * ext/opencv/basicfilters/gstcvequalizehist.h: + * ext/opencv/gstopencv.c: + Adds new element cvequalizehist + +2010-05-16 19:14:54 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * ext/opencv/basicfilters/Makefile.am: + * ext/opencv/basicfilters/gstcvdilate.c: + * ext/opencv/basicfilters/gstcvdilate.h: + * ext/opencv/basicfilters/gstcvdilateerode.c: + * ext/opencv/basicfilters/gstcvdilateerode.h: + * ext/opencv/basicfilters/gstcverode.c: + * ext/opencv/basicfilters/gstcverode.h: + * ext/opencv/gstopencv.c: + Adds new elements cvdilate and cverode + Adds 2 similar elements (so similar they have their own baseclass), + cvdilate and cverode. + +2010-05-16 17:03:51 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * ext/opencv/basicfilters/gstcvsmooth.c: + * ext/opencv/gstopencvbasetrans.c: + cvsmooth: Improve parameters docs + +2010-05-16 16:37:12 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * ext/opencv/basicfilters/gstcvsmooth.c: + cvsmooth: Deactivating blur-no-scale + Deactivate blur-no-scale because basetransform doesn't provide a way + to override getcaps for pads, always using templatecaps independent + of properties. + +2010-05-16 11:42:08 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * ext/opencv/basicfilters/gstcvsmooth.c: + * ext/opencv/gstopencvbasetrans.c: + * ext/opencv/gstopencvutils.c: + * ext/opencv/gstopencvutils.h: + cvsmooth: Add support for video/x-raw-gray + +2010-05-16 00:46:01 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * ext/opencv/Makefile.am: + * ext/opencv/gstopencvbasetrans.c: + * ext/opencv/gstopencvutils.c: + * ext/opencv/gstopencvutils.h: + Adding gstopencvutils + Adds a file to keep utilitary functions together + +2010-05-11 20:11:42 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * ext/opencv/Makefile.am: + * ext/opencv/basicfilters/gstcvsmooth.c: + * ext/opencv/basicfilters/gstcvsmooth.h: + * ext/opencv/gstopencv.c: + cvsmooth: Adds new element cvsmooth + Adds new cvsmooth element + +2010-05-05 01:24:54 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * ext/opencv/Makefile.am: + * ext/opencv/basicfilters/Makefile.am: + * ext/opencv/gstopencvbasetrans.c: + * ext/opencv/gstopencvbasetrans.h: + gstopencvbasetrans: Adds this new base class + Adds GstOpencvBaseTransform as base class for simple 1:1 + opencv filters + +2010-04-26 17:18:54 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * ext/opencv/pyramidsegment/gstpyramidsegment.c: + pyramidsegment: Allocate a new buffer for output + Use a newly allocated buffer for output, and release the intermediary + image used. + Also add a TODO for performance improvement + +2010-04-26 17:34:12 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * ext/opencv/faceblur/gstfaceblur.c: + * ext/opencv/facedetect/gstfacedetect.c: + * ext/opencv/templatematch/gsttemplatematch.c: + * ext/opencv/textwrite/gsttextwrite.c: + faceblur: facedetect: templatematch: textwrite: Set buffer to writable + These elements operates in place, set buffer to writable before + operating. + +2010-04-26 16:17:23 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * ext/opencv/edgedetect/gstedgedetect.c: + edgedetect: Fix chain buffer handling + Allocate a new output buffer instead of using the input buffer + pointing to the internal cvCEdge opencv's IplImage data, which + might change, consequently changing the buffer. + +2010-04-25 16:27:04 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * ext/opencv/edgedetect/gstedgedetect.c: + * ext/opencv/faceblur/gstfaceblur.c: + * ext/opencv/facedetect/gstfacedetect.c: + * ext/opencv/pyramidsegment/gstpyramidsegment.c: + * ext/opencv/templatematch/gsttemplatematch.c: + * ext/opencv/textwrite/gsttextwrite.c: + configure: enable -Werror to improve code + -Werror on git version is useful to keep code clean. + +2010-03-02 13:55:05 +0530 Sreerenj Balachandran <bsreerenj@gmailcom> + + * ext/opencv/textwrite/gsttextwrite.c: + * ext/opencv/textwrite/gsttextwrite.h: + Added the property for setting the RGB colours. modified: ext/opencv/textwrite/gsttextwrite.c modified: ext/opencv/textwrite/gsttextwrite.h + +2010-03-02 13:18:19 +0530 Sreerenj Balachandran <bsreerenj@gmailcom> + + * ext/opencv/textwrite/gsttextwrite.c: + * ext/opencv/textwrite/gsttextwrite.h: + Added the property for setting the "thickness" of font modified: ext/opencv/textwrite/gsttextwrite.c modified: ext/opencv/textwrite/gsttextwrite.h + +2010-03-02 12:45:58 +0530 Sreerenj Balachandran <bsreerenj@gmailcom> + + * ext/opencv/textwrite/gsttextwrite.c: + * ext/opencv/textwrite/gsttextwrite.h: + Added the property for setting x and y co-ordinates modified: ext/opencv/textwrite/gsttextwrite.c modified: ext/opencv/textwrite/gsttextwrite.h + +2010-03-02 12:41:25 +0530 Sreerenj Balachandran <bsreerenj@gmailcom> + + * ext/opencv/textwrite/gsttextwrite.c: + * ext/opencv/textwrite/gsttextwrite.h: + added the propery for setting x and y co-ordinates modified: ext/opencv/textwrite/gsttextwrite.c modified: ext/opencv/textwrite/gsttextwrite.h + +2010-02-28 14:36:35 +0000 Mike Sheldon <mike@mikeasoft.com> + + * ext/opencv/facedetect/gstfacedetect.c: + Apply Stefan's faceblur fixes to facedetect + +2010-02-28 14:32:00 +0000 Sreerenj Balachandran <bsreerenj@gmail.com> + + * ext/opencv/Makefile.am: + * ext/opencv/gstopencv.c: + * ext/opencv/textwrite/Makefile.am: + * ext/opencv/textwrite/gsttextwrite.c: + * ext/opencv/textwrite/gsttextwrite.h: + Add simple text overlay plugin + +2010-02-19 22:50:18 +0200 Stefan Kost <ensonic@users.sf.net> + + * ext/opencv/faceblur/gstfaceblur.c: + faceblur: fix handling of profile property. + Dup and free the string. Fixes leaking new values and avoids crashing + gst-inspect. + +2009-12-18 11:23:59 +0000 Mike Sheldon <mike@mikeasoft.com> + + * ext/opencv/templatematch/gsttemplatematch.h: + Fix includes in template matching element + +2009-05-26 12:59:04 +0100 Mike Sheldon <mike@mikeasoft.com> + + * ext/opencv/edgedetect/gstedgedetect.c: + * ext/opencv/edgedetect/gstedgedetect.h: + * ext/opencv/faceblur/gstfaceblur.c: + * ext/opencv/faceblur/gstfaceblur.h: + * ext/opencv/facedetect/gstfacedetect.c: + * ext/opencv/facedetect/gstfacedetect.h: + * ext/opencv/gstopencv.c: + * ext/opencv/pyramidsegment/gstpyramidsegment.c: + * ext/opencv/pyramidsegment/gstpyramidsegment.h: + * ext/opencv/templatematch/gsttemplatematch.c: + * ext/opencv/templatematch/gsttemplatematch.h: + Bring code in to line with general Gstreamer standards + +2009-05-25 12:57:11 +0100 Mike Sheldon <mike@mikeasoft.com> + + * ext/opencv/templatematch/gsttemplatematch.c: + Fix segfault in template match element if no template has been set Add template matching python example Add autotool, libtool and pkgconfig dependencies to debian control file + +2009-05-25 11:26:28 +0100 Mike Sheldon <mike@mikeasoft.com> + + * ext/opencv/Makefile.am: + * ext/opencv/faceblur/Makefile.am: + * ext/opencv/faceblur/gstfaceblur.c: + * ext/opencv/faceblur/gstfaceblur.h: + * ext/opencv/gstopencv.c: + Add a plugin for automatically blurring faces in videos and images + +2009-05-13 12:19:43 +0300 Noam <noam@duapov.(none)> + + * ext/opencv/templatematch/gsttemplatematch.c: + * ext/opencv/templatematch/gsttemplatematch.h: + Added control for changing method + +2009-05-13 11:55:31 +0300 Noam <noam@duapov.(none)> + + * ext/opencv/Makefile.am: + * ext/opencv/gstopencv.c: + * ext/opencv/templatematch/Makefile.am: + * ext/opencv/templatematch/gsttemplatematch.c: + * ext/opencv/templatematch/gsttemplatematch.h: + Added templatematch element + +2009-05-08 11:55:20 +0530 kapil <kapil@kapil-laptop.(none)> + + * ext/opencv/Makefile.am: + * ext/opencv/edgedetect/Makefile.am: + * ext/opencv/edgedetect/gstedgedetect.c: + * ext/opencv/edgedetect/gstedgedetect.h: + * ext/opencv/facedetect/Makefile.am: + * ext/opencv/facedetect/gstfacedetect.c: + * ext/opencv/facedetect/gstfacedetect.h: + * ext/opencv/gstopencv.c: + * ext/opencv/pyramidsegment/Makefile.am: + * ext/opencv/pyramidsegment/gstpyramidsegment.c: + * ext/opencv/pyramidsegment/gstpyramidsegment.h: + Registering all elements under opencv plugin + +2009-05-06 15:49:42 +0100 Mike Sheldon <mike@mikeasoft.com> + + * ext/opencv/facedetect/gstfacedetect.c: + Fix the profile parameter in the facedetect element to accept a string correctly + +2009-05-06 15:33:48 +0100 Mike Sheldon <mike@mikeasoft.com> + + * ext/opencv/edgedetect/gstedgedetect.c: + * ext/opencv/facedetect/gstfacedetect.c: + * ext/opencv/pyramidsegment/gstpyramidsegment.c: + Release OpenCV images when finalizing elements + +2009-05-06 16:38:15 +0530 kapil <kapil@kapil-laptop.(none)> + + * ext/opencv/edgedetect/gstedgedetect.h: + * ext/opencv/facedetect/gstfacedetect.h: + * ext/opencv/pyramidsegment/gstpyramidsegment.h: + Fixed compile errors + +2009-04-20 18:40:13 +0300 Mike Sheldon <mike@mikeasoft.com> + + * ext/opencv/facedetect/gstfacedetect.c: + Make face detect send a bus message when a face is detected Write a simple python example for face detection + +2009-04-18 23:43:37 +0300 Mike Sheldon <mike@mikeasoft.com> + + * ext/opencv/Makefile.am: + * ext/opencv/edgedetect/gstedgedetect.c: + * ext/opencv/edgedetect/gstedgedetect.h: + * ext/opencv/facedetect/Makefile.am: + * ext/opencv/facedetect/gstfacedetect.c: + * ext/opencv/facedetect/gstfacedetect.h: + * ext/opencv/pyramidsegment/gstpyramidsegment.c: + * ext/opencv/pyramidsegment/gstpyramidsegment.h: + Add face detection element Clean up some generated files Update a few old comments + +2008-12-18 23:48:40 +0000 Mike Sheldon <mike@mikeasoft.com> + + * ext/opencv/Makefile: + * ext/opencv/Makefile.in: + * ext/opencv/edgedetect/Makefile: + * ext/opencv/edgedetect/Makefile.in: + * ext/opencv/pyramidsegment/Makefile: + * ext/opencv/pyramidsegment/Makefile.in: + * Remove some autotools generated files + +2008-12-18 23:43:36 +0000 Mike Sheldon <mike@mikeasoft.com> + + * ext/opencv/Makefile: + * ext/opencv/Makefile.am: + * ext/opencv/Makefile.in: + * ext/opencv/edgedetect/Makefile: + * ext/opencv/edgedetect/Makefile.am: + * ext/opencv/edgedetect/Makefile.in: + * ext/opencv/edgedetect/gstedgedetect.c: + * ext/opencv/edgedetect/gstedgedetect.h: + * ext/opencv/pyramidsegment/Makefile: + * ext/opencv/pyramidsegment/Makefile.am: + * ext/opencv/pyramidsegment/Makefile.in: + * ext/opencv/pyramidsegment/gstpyramidsegment.c: + * ext/opencv/pyramidsegment/gstpyramidsegment.h: + * Make it possible to set threshold2 at runtime * Implement pyramid segmentation element * Make masking optional on edgedetect * Clean up edgedetect, add element details * Implemented edge detect element + +2010-09-08 16:57:57 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/id3tag/id3tag.c: + id3mux: Map GST_TAG_ALBUM_ARTIST + Map GST_TAG_ALBUM_ARTIST to TPE2 as it is done in + -base id3tag mappings. + +2010-08-09 00:15:03 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * common: + * configure.ac: + * tests/check/Makefile.am: + Use AG_GST_CHECK_GST_PLUGINS_{GOOD,UGLY,BAD,FFMPEG} macros from common + to find plugin directories for the various modules our unit tests depend + on in an uninstalled environment. This makes sure these plugins are found + even when distchecking (which happens from a subdirectory, which means + that the currently used trick to find the uninstalled directories of + these modules doesn't work in that case). + +2010-09-07 19:16:24 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * docs/plugins/gst-plugins-bad-plugins-docs.sgml: + docs: update plugin docs sgml file a bit + +2010-09-07 15:22:28 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * docs/plugins/.gitignore: + docs: add 2 new files to gitignore + Adds gst-plugins-bad-plugins.args.new and + gst-plugins-bad-plugins.signals.new to .gitignore + +2010-09-07 14:45:12 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/jpegformat/gstjifmux.c: + jifmux: Make it more colorspace smart + This makes it able to recombine rgb images, making it possible + to add tags to rgb jpegs as well. + Uses a simple strategy to check what are the possible colorspaces + and avoid adding jfif to ones that aren't YUV/Gray. + +2010-09-07 10:26:29 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/elements/jifmux.c: + tests: jifmux: Adds tests for new ppi tags + Adds tests to check if libexif can read our + EXIF_TAG_X/Y_RESOLUTION tags. + +2010-09-07 13:28:20 +0200 Robert Swain <robert.swain@collabora.co.uk> + + * gst/interlace/gstinterlace.c: + interlace: Fix element details + +2010-09-07 11:42:30 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * common: + Automatic update of common submodule + From c2e10bf to aa0d1d0 + +2010-09-07 11:34:35 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * docs/plugins/gst-plugins-bad-plugins.args: + * docs/plugins/gst-plugins-bad-plugins.hierarchy: + * docs/plugins/inspect/plugin-cog.xml: + * docs/plugins/inspect/plugin-debugutilsbad.xml: + * docs/plugins/inspect/plugin-interlace.xml: + * docs/plugins/inspect/plugin-sdl.xml: + * docs/plugins/inspect/plugin-videomeasure.xml: + * docs/plugins/inspect/plugin-videosignal.xml: + docs: update plugin introspection data for recent changes + +2010-09-07 11:28:44 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * docs/plugins/inspect/plugin-aacparse.xml: + * docs/plugins/inspect/plugin-aiffparse.xml: + * docs/plugins/inspect/plugin-amrparse.xml: + * docs/plugins/inspect/plugin-amrwb.xml: + * docs/plugins/inspect/plugin-dvbsrc.xml: + * docs/plugins/inspect/plugin-flacparse.xml: + * docs/plugins/inspect/plugin-gstrtpmanager.xml: + * docs/plugins/inspect/plugin-mpegtsparse.xml: + * docs/plugins/inspect/plugin-x264.xml: + docs: remove introspection files for plugins that have been merged, moved or renamed + The aacparse, amrparse, flacparse plugins have been merged into the audioparsersbad + plugin. The aiffparse plugin has been renamed to aiff since it also contains an + aiff muxer now. The amrwb plugin has been renamed to amrwbenc. The dvbsrc plugin + has been renamed to dvb. The gstrtpmanager plugin has moved to -good. The x264 + plugin has moved to -ugly. And the mpegtsparse plugin has been merged into the + mpegdemux2 plugin. + +2010-09-07 00:16:00 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * .gitignore: + * tests/examples/Makefile.am: + tests: fix distcheck by disting new jack example directory + Also add test binary to ignores. + +2010-09-06 17:17:54 -0400 Tristan Matthews <le.businessman@gmail.com> + + * configure.ac: + * tests/examples/Makefile.am: + * tests/examples/jack/Makefile.am: + * tests/examples/jack/jack_client.c: + examples: add test to demonstrate jack_client_t usage + +2010-09-06 16:11:31 -0400 Tristan Matthews <le.businessman@gmail.com> + + * ext/jack/gstjack.c: + * ext/jack/gstjack.h: + * ext/jack/gstjackaudioclient.c: + * ext/jack/gstjackaudioclient.h: + * ext/jack/gstjackaudiosink.c: + * ext/jack/gstjackaudiosink.h: + * ext/jack/gstjackaudiosrc.c: + * ext/jack/gstjackaudiosrc.h: + jack: added client property + +2010-06-17 16:26:07 -0400 Tristan Matthews <tristan@sat.qc.ca> + + * ext/jack/gstjackbin.c: + jack: removed unused file gstjackbin.c + This is a 0.8 leftover. + +2010-09-06 14:12:00 +0200 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + * gst/audioparsers/gstbaseparse.c: + baseparse: non-TIME seek event is simply not handled + +2010-09-06 09:28:46 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * configure.ac: + configure: Bump -core/-base requirements to 0.10.30.1 + We need 0.10.30.1 to have latest tags in core/base for jifmux + tests. + +2010-08-26 02:54:55 -0400 Youness Alaoui <youness.alaoui@collabora.co.uk> + + * gst/dtmf/gstdtmfsrc.c: + dtmfsrc: Make the dtmfsrc accept events sent with gst_element_send_event + The doc says to use gst_element_send_event on the pipeline, but if + we are to call it on the element itself, it's a noop. This should make it + handle the event properly before delegating it to basesrc. + +2010-09-05 16:30:05 +0200 Carl-Anton Ingmarsson <ca.ingmarsson@gmail.com> + + * sys/vdpau/gstvdpvideopostprocess.c: + vdpauvideopostprocess: set new framerate on output caps instead of input caps + It's not allowed to change the caps provided by the setcaps function. + https://bugzilla.gnome.org/show_bug.cgi?id=628326 + +2010-09-06 03:23:26 -0700 David Schleef <ds@schleef.org> + + * tools/element-maker: + element-maker: Take parameters on command line + Now it's actually useful. + +2010-09-06 03:04:13 -0700 David Schleef <ds@schleef.org> + + * gst/interlace/gstinterlace.c: + interlace: Add documentation + +2010-09-06 10:29:21 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * gst/debugutils/fpsdisplaysink.c: + fpsdisplay: Use G_GUINT64_FORMAT instead of %llu + Fixes compiler warnings on 64 bit architectures. + +2010-09-06 11:03:07 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/selector/gstinputselector.c: + inputselector: sync with copy in -base + Use _get_caps_reffed to avoid copies. + +2010-08-24 11:50:47 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/selector/gstoutputselector.c: + outputselector: move the debug init to the boilerplate macro + +2010-08-24 11:50:09 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/selector/gstinputselector.c: + inputselector: use GST_BOILERPLATE macro + +2010-08-24 11:26:52 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/debugutils/fpsdisplaysink.c: + * gst/debugutils/fpsdisplaysink.h: + fpsdisplaysink: don't add a g_mainloop dependency + Just update the fps-message from the probe handler. + +2010-08-18 11:35:44 +0300 Stefan Kost <ensonic@users.sf.net> + + * gst/debugutils/fpsdisplaysink.c: + fpsdisplaysink: small cleanup + Add one one example and lower the fon't size for the overlay. + +2010-08-23 09:51:25 -0500 Rob Clark <rob@ti.com> + + * gst/debugutils/fpsdisplaysink.c: + * gst/debugutils/fpsdisplaysink.h: + fpsdisplaysink: measure fps in terms of wall clock time + Measure fps in terms of system clock, rather than pipeline clock, to get + an accurate meaure of fps. + +2010-09-05 22:41:24 -0700 David Schleef <ds@schleef.org> + + * gst/debugutils/Makefile.am: + * gst/debugutils/debugutilsbad.c: + * gst/debugutils/gstchecksumsink.c: + * gst/debugutils/gstchecksumsink.h: + checksumsink: Add new element + +2010-09-05 22:30:54 -0700 David Schleef <ds@schleef.org> + + * gst/videomeasure/gstvideomeasure_ssim.c: + ssim: Add I420 support + +2010-09-05 21:34:30 -0700 David Schleef <ds@schleef.org> + + * gst/interlace/gstinterlace.c: + interlace: Add more formats + +2010-09-05 18:58:36 -0700 David Schleef <ds@schleef.org> + + * common: + Automatic update of common submodule + From d3d9acf to c2e10bf + +2010-09-05 23:40:08 +1000 Jan Schmidt <thaytan@noraisin.net> + + * docs/plugins/gst-plugins-bad-plugins.args.new: + * docs/plugins/gst-plugins-bad-plugins.signals.new: + Remove .new docs files from the repository + +2010-09-05 15:34:13 -0700 Jonathan Rosser <jonathan.rosser@rd.bbc.co.uk> + + * ext/cog/cogvirtframe.c: + cog: Fix cog_virt_frame_new_convert_u8() + Conversion was using uninitialized data instead of source frame. + Fixes #626425. + +2010-09-05 12:06:31 -0700 David Schleef <ds@schleef.org> + + * configure.ac: + * ext/cog/gstcogorc-dist.c: + cog: Fix generated Orc code + Also drop required Orc back down to 0.4.7. + +2010-08-30 21:22:14 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/camerabinimage.c: + * gst/camerabin/gstcamerabin.c: + camerabin: Use jifmux instead of metadatamux + Use jifmux element to write exif/xmp tags instead of metadatamux + +2010-08-30 21:21:49 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/camerabin/Makefile.am: + * gst/camerabin/gstcamerabin.c: + camerabin: Use new tags from -base + Replace private tags from metadata plugin with the new generic tags + from -base. + +2010-09-03 14:12:23 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/elements/camerabin.c: + camerabin: Refactor tests + The tests were done in 2 steps, first there was a suite + that generated the files (while checking that camerabin + was operating correctly). Then there was a second suite + that was run to check that all files were playable with + playbin2. Those second tests were not being run because + they were checking if camerabin was initialized, and it + never was as those tests didn't use a 'setup' function. + This commit refactors the tests by removing this second + suite and merging its validation with the first suite's + functions. + +2010-08-24 14:43:50 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/elements/jifmux.c: + tests: jifmux: Adds geo location tags tests + Adds some more tests for geo location tags. + Also use libexif constants for the exif tags' ids. + +2010-08-24 09:02:59 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/elements/jifmux.c: + tests: jifmux: Refactor testing code a little + Refactor testing code to allow testing for cases where the + same gstreamer tag is mapped to multiple exif tags. + +2010-08-23 11:57:37 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * tests/check/Makefile.am: + * tests/check/elements/jifmux.c: + jifmux: More tests for exif tags + Refactors some code and add some more tests for exif tags + +2010-09-02 11:18:27 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/jpegformat/gstjifmux.c: + jifmux: Do not limit the size of the image on 16bits + Use guint instead of guint16 to represent the size of the encoded image, + this would make some recombined images lose most of their data and + show like a big black image with a small line of content on top. + Also adds a minor log message. + +2010-08-21 17:01:29 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/jpegformat/gstjifmux.c: + * gst/jpegformat/gstjifmux.h: + jifmux: Set output pad caps + Set output pad caps to guarantee caps on the buffers being + pushed downstream. + +2010-08-20 08:34:35 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/jpegformat/gstjifmux.c: + jifmux: Detect EOI correctly + EOI are not always at the last 4 bytes. We need to search + the last 5 bytes to find the 0xFFD9 sequence as jpegenc seems + to round the buffer size to the next 4 multiple. + +2010-08-19 22:43:47 -0300 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + + * gst/jpegformat/gstjifmux.c: + jifmux: Put APP0 first always + Fixes the order of the APP0/APP1 markers. APP0 should + be first. + +2010-09-02 01:32:10 +0200 Carl-Anton Ingmarsson <ca.ingmarsson@gmail.com> + + * sys/vdpau/h264/gstvdph264dec.c: + vdpauh264dec: parse "pixel-aspect-ratio" from stream + +2010-09-02 01:04:15 +0200 Carl-Anton Ingmarsson <ca.ingmarsson@gmail.com> + + * sys/vdpau/basevideodecoder/gstbasevideodecoder.c: + * sys/vdpau/basevideodecoder/gstbasevideodecoder.h: + vdpau: remove non working unused code from GstBaseVideoDecoder + +2010-09-02 00:17:49 +0200 Carl-Anton Ingmarsson <ca.ingmarsson@gmail.com> + + * sys/vdpau/basevideodecoder/gstbasevideodecoder.c: + vdpau: GstBaseVideoDecoder set default par to 1/1 + +2010-09-01 23:47:21 +0200 Carl-Anton Ingmarsson <ca.ingmarsson@gmail.com> + + * sys/vdpau/basevideodecoder/gstbasevideodecoder.c: + * sys/vdpau/basevideodecoder/gstbasevideodecoder.h: + * sys/vdpau/h264/gstvdph264dec.c: + * sys/vdpau/mpeg/gstvdpmpegdec.c: + * sys/vdpau/mpeg/gstvdpmpegframe.c: + * sys/vdpau/mpeg/gstvdpmpegframe.h: + * sys/vdpau/mpeg4/gstmpeg4frame.h: + * sys/vdpau/mpeg4/gstvdpmpeg4dec.c: + * sys/vdpau/mpeg4/gstvdpmpeg4dec.h: + * sys/vdpau/mpeg4/mpeg4util.c: + vdpau: remove gst_base_video_decoder_get_current_frame + we now pass the current frame to GstBaseVideoDecoder::parse_data + also fixup some errors in vdpaumpeg4dec so that it now gives correct output + +2010-09-01 22:03:05 +0200 Carl-Anton Ingmarsson <ca.ingmarsson@gmail.com> + + * sys/vdpau/basevideodecoder/gstbasevideodecoder.c: + * sys/vdpau/basevideodecoder/gstbasevideodecoder.h: + * sys/vdpau/basevideodecoder/gstvideoframe.c: + * sys/vdpau/basevideodecoder/gstvideoframe.h: + vdpau: rework GstBaseVideoDecoder timestamping + timestamps are now chosen in the following order: + upstream -> parsed by decoder -> calculated from timestamp offset + we also check the timestamps supplied from upstream/decoder to see if they + atleast is increasing. + +2010-09-01 17:45:19 +0200 Carl-Anton Ingmarsson <ca.ingmarsson@gmail.com> + + * sys/vdpau/gstvdp/gstvdpdecoder.c: + vdpau: fix invalid unref + +2010-09-05 12:19:32 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * common: + Automatic update of common submodule + From ec60217 to d3d9acf + +2010-09-05 11:45:35 +0200 Edward Hervey <bilboed@bilboed.com> + + * configure.ac: + configure.ac: Bump orc requirement to 0.4.8.1 + 0.4.7 creates code with unavailable symbols + 0.4.8 creates buggy code + Let's use git head of orc (which still won't work because git head + of orc still claims to be 0.4.8) + This allows all the rest of -bad to build properly. + +2010-07-14 21:00:12 +0200 Edward Hervey <bilboed@bilboed.com> + + * ext/timidity/gsttimidity.c: + timidity: Fix unitialized variables (gcc 4.4.4) + +2010-09-04 11:35:16 -0700 David Schleef <ds@schleef.org> + + * ext/cog/gstcogorc-dist.c: + * ext/cog/gstcogorc-dist.h: + cog: update disted Orc files + +2010-08-26 22:03:20 -0700 David Schleef <ds@schleef.org> + + * ext/sdl/sdlvideosink.c: + sdlvideosink: Re-enable YVYU and UYVY + YVYU on my machine appears to be doing software conversion + (and doing it incorrectly). + +2010-08-26 20:15:43 -0700 David Schleef <ds@schleef.org> + + * tools/base.c: + * tools/element-maker: + element-maker: construct element names + +2010-08-22 21:43:20 -0700 David Schleef <ds@schleef.org> + + * configure.ac: + * gst/interlace/Makefile.am: + * gst/interlace/gstinterlace.c: + interlace: new element + +2010-08-20 17:24:23 -0700 David Schleef <ds@schleef.org> + + * ext/cog/gstcogcolorspace.c: + * ext/cog/gstcogorc.orc: + cog: Add fast paths for colorspace conversion + +2010-08-20 17:23:17 -0700 David Schleef <ds@schleef.org> + + * configure.ac: + configure: require Orc 0.4.7 + +2010-08-13 21:58:01 -0700 David Schleef <ds@schleef.org> + + * tools/element-maker: + * tools/gstelement.c: + element-maker: Fix up GstElement + +2010-08-13 21:54:54 -0700 David Schleef <ds@schleef.org> + + * ext/cog/cogvirtframe.c: + * ext/cog/gstcogcolorspace.c: + * ext/cog/gstcogorc.orc: + cog: Improvements in colorspace and scaler + Add fast paths for YUV->YUV conversions and Orc code for all. + Use Orc for horizontal resampling. + +2010-06-11 14:39:30 -0700 David Schleef <ds@schleef.org> + + * ext/cog/Makefile.am: + * ext/cog/gstcog.c: + * ext/cog/gstcogdownsample.c: + * ext/cog/gstcogfilter.c: + * ext/cog/gstcogmse.c: + * ext/cog/gstcogscale.c: + * ext/cog/gstcolorconvert.c: + * ext/cog/gstlogoinsert.c: + cog: minor cleanups + Improve element descriptions, remove unused files, code cleanup. + +2010-09-03 10:03:04 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * configure.ac: + * docs/plugins/gst-plugins-bad-plugins.args: + * docs/plugins/gst-plugins-bad-plugins.args.new: + * docs/plugins/gst-plugins-bad-plugins.hierarchy: + * docs/plugins/gst-plugins-bad-plugins.signals.new: + * docs/plugins/inspect/plugin-adpcmdec.xml: + * docs/plugins/inspect/plugin-adpcmenc.xml: + * docs/plugins/inspect/plugin-aiff.xml: + * docs/plugins/inspect/plugin-alsaspdif.xml: + * docs/plugins/inspect/plugin-amrwbenc.xml: + * docs/plugins/inspect/plugin-apexsink.xml: + * docs/plugins/inspect/plugin-asfmux.xml: + * docs/plugins/inspect/plugin-assrender.xml: + * docs/plugins/inspect/plugin-audioparsersbad.xml: + * docs/plugins/inspect/plugin-autoconvert.xml: + * docs/plugins/inspect/plugin-bayer.xml: + * docs/plugins/inspect/plugin-bz2.xml: + * docs/plugins/inspect/plugin-camerabin.xml: + * docs/plugins/inspect/plugin-cdaudio.xml: + * docs/plugins/inspect/plugin-cdxaparse.xml: + * docs/plugins/inspect/plugin-celt.xml: + * docs/plugins/inspect/plugin-cog.xml: + * docs/plugins/inspect/plugin-coloreffects.xml: + * docs/plugins/inspect/plugin-dataurisrc.xml: + * docs/plugins/inspect/plugin-dc1394.xml: + * docs/plugins/inspect/plugin-dccp.xml: + * docs/plugins/inspect/plugin-debugutilsbad.xml: + * docs/plugins/inspect/plugin-dfbvideosink.xml: + * docs/plugins/inspect/plugin-dirac.xml: + * docs/plugins/inspect/plugin-dtmf.xml: + * docs/plugins/inspect/plugin-dtsdec.xml: + * docs/plugins/inspect/plugin-dvb.xml: + * docs/plugins/inspect/plugin-dvdspu.xml: + * docs/plugins/inspect/plugin-faac.xml: + * docs/plugins/inspect/plugin-faad.xml: + * docs/plugins/inspect/plugin-fbdevsink.xml: + * docs/plugins/inspect/plugin-festival.xml: + * docs/plugins/inspect/plugin-freeze.xml: + * docs/plugins/inspect/plugin-frei0r.xml: + * docs/plugins/inspect/plugin-gaudieffects.xml: + * docs/plugins/inspect/plugin-geometrictransform.xml: + * docs/plugins/inspect/plugin-gsettings.xml: + * docs/plugins/inspect/plugin-gsm.xml: + * docs/plugins/inspect/plugin-gstsiren.xml: + * docs/plugins/inspect/plugin-h264parse.xml: + * docs/plugins/inspect/plugin-hdvparse.xml: + * docs/plugins/inspect/plugin-id3tag.xml: + * docs/plugins/inspect/plugin-invtelecine.xml: + * docs/plugins/inspect/plugin-ivfparse.xml: + * docs/plugins/inspect/plugin-jack.xml: + * docs/plugins/inspect/plugin-jpegformat.xml: + * docs/plugins/inspect/plugin-kate.xml: + * docs/plugins/inspect/plugin-ladspa.xml: + * docs/plugins/inspect/plugin-legacyresample.xml: + * docs/plugins/inspect/plugin-liveadder.xml: + * docs/plugins/inspect/plugin-metadata.xml: + * docs/plugins/inspect/plugin-mimic.xml: + * docs/plugins/inspect/plugin-mms.xml: + * docs/plugins/inspect/plugin-modplug.xml: + * docs/plugins/inspect/plugin-mpeg2enc.xml: + * docs/plugins/inspect/plugin-mpeg4videoparse.xml: + * docs/plugins/inspect/plugin-mpegdemux2.xml: + * docs/plugins/inspect/plugin-mpegpsmux.xml: + * docs/plugins/inspect/plugin-mpegtsmux.xml: + * docs/plugins/inspect/plugin-mpegvideoparse.xml: + * docs/plugins/inspect/plugin-mplex.xml: + * docs/plugins/inspect/plugin-musepack.xml: + * docs/plugins/inspect/plugin-musicbrainz.xml: + * docs/plugins/inspect/plugin-mve.xml: + * docs/plugins/inspect/plugin-mxf.xml: + * docs/plugins/inspect/plugin-mythtv.xml: + * docs/plugins/inspect/plugin-nas.xml: + * docs/plugins/inspect/plugin-neon.xml: + * docs/plugins/inspect/plugin-nsf.xml: + * docs/plugins/inspect/plugin-nuvdemux.xml: + * docs/plugins/inspect/plugin-ofa.xml: + * docs/plugins/inspect/plugin-pcapparse.xml: + * docs/plugins/inspect/plugin-pnm.xml: + * docs/plugins/inspect/plugin-qtmux.xml: + * docs/plugins/inspect/plugin-rawparse.xml: + * docs/plugins/inspect/plugin-real.xml: + * docs/plugins/inspect/plugin-resindvd.xml: + * docs/plugins/inspect/plugin-rfbsrc.xml: + * docs/plugins/inspect/plugin-rsvg.xml: + * docs/plugins/inspect/plugin-rtpmux.xml: + * docs/plugins/inspect/plugin-scaletempo.xml: + * docs/plugins/inspect/plugin-schro.xml: + * docs/plugins/inspect/plugin-sdl.xml: + * docs/plugins/inspect/plugin-sdp.xml: + * docs/plugins/inspect/plugin-segmentclip.xml: + * docs/plugins/inspect/plugin-selector.xml: + * docs/plugins/inspect/plugin-shm.xml: + * docs/plugins/inspect/plugin-sndfile.xml: + * docs/plugins/inspect/plugin-soundtouch.xml: + * docs/plugins/inspect/plugin-speed.xml: + * docs/plugins/inspect/plugin-stereo.xml: + * docs/plugins/inspect/plugin-subenc.xml: + * docs/plugins/inspect/plugin-tta.xml: + * docs/plugins/inspect/plugin-valve.xml: + * docs/plugins/inspect/plugin-vcdsrc.xml: + * docs/plugins/inspect/plugin-vdpau.xml: + * docs/plugins/inspect/plugin-videomaxrate.xml: + * docs/plugins/inspect/plugin-videomeasure.xml: + * docs/plugins/inspect/plugin-videosignal.xml: + * docs/plugins/inspect/plugin-vmnc.xml: + * docs/plugins/inspect/plugin-vp8.xml: + * docs/plugins/inspect/plugin-wildmidi.xml: + * docs/plugins/inspect/plugin-xvid.xml: + * docs/plugins/inspect/plugin-zbar.xml: + * win32/common/config.h: + Back to development + Temporarily disable -DGST_DISABLE_DEPRECATED for git builds until + the code is updated for the GST_FLOW_IS_* macro deprecations. + +2010-09-01 22:05:43 +0200 Andoni Morales Alastruey <ylatuya@gmail.com> + + * gst/mpegtsmux/tsmux/tsmux.c: + * gst/mpegtsmux/tsmux/tsmuxstream.c: + * gst/mpegtsmux/tsmux/tsmuxstream.h: + mpegtsmux: Initialize PES packet before getting the header size. + The PES header length is calculated before setting the dynamic flags, returning + a wrong value. Small frames that should be sent in a single TS packet are + spawned to a new packet because of that error. For audio streams where a single + frame can cope in one TS packet it introduces a huge overhead. + For a 100B packet, we prepare a TS packet with a payload of(100+9)B. Then, we + write the TS header using this value in tsmux_write_ts_header, and call + tsmux_stream_get_data(). The dynamic flags where not set yet and now + tsmux_stream_pes_header_length() returns 14B instead of 9B. The payload of the + TS packet is 114B, 5B more than what was calculated. 109B are sent in a first + packet and the remaining 5B are sent in another one. + Fixes bug #628548. + +2010-09-02 10:23:30 +0200 Sebastian Dröge <sebastian.droege@collabora.co.uk> + + * ext/cog/gstcogcolorspace.c: + cogcolorspace: Classify as Filter/Converter/Video instead of effect + Fixes bug #628570. + +2010-09-01 18:30:17 +0200 Thibault Saunier <tsaunier@gnome.org> + + * gst/videosignal/gstvideoanalyse.c: + videoanalyse: Use correct element classification + This is no effect but an analyzer. Fixes bug #628527. + === release 0.10.20 === -2010-09-03 Tim-Philipp Müller <tim.muller@collabora.co.uk> +2010-09-03 00:23:02 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + * ChangeLog: + * NEWS: + * RELEASE: * configure.ac: - releasing 0.10.20, "For it is a Human Number" + * ext/cog/gstcogorc-dist.c: + * ext/cog/gstcogorc-dist.h: + * gst-plugins-bad.doap: + * win32/common/config.h: + Release 0.10.20 + +2010-09-03 00:21:06 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> + + * docs/plugins/gst-plugins-bad-plugins.args: + * docs/plugins/gst-plugins-bad-plugins.hierarchy: + * docs/plugins/gst-plugins-bad-plugins.interfaces: + * docs/plugins/gst-plugins-bad-plugins.prerequisites: + * docs/plugins/inspect/plugin-adpcmdec.xml: + * docs/plugins/inspect/plugin-adpcmenc.xml: + * docs/plugins/inspect/plugin-aiff.xml: + * docs/plugins/inspect/plugin-alsaspdif.xml: + * docs/plugins/inspect/plugin-amrwbenc.xml: + * docs/plugins/inspect/plugin-apexsink.xml: + * docs/plugins/inspect/plugin-asfmux.xml: + * docs/plugins/inspect/plugin-assrender.xml: + * docs/plugins/inspect/plugin-audioparsersbad.xml: + * docs/plugins/inspect/plugin-autoconvert.xml: + * docs/plugins/inspect/plugin-bayer.xml: + * docs/plugins/inspect/plugin-bz2.xml: + * docs/plugins/inspect/plugin-camerabin.xml: + * docs/plugins/inspect/plugin-cdaudio.xml: + * docs/plugins/inspect/plugin-cdxaparse.xml: + * docs/plugins/inspect/plugin-celt.xml: + * docs/plugins/inspect/plugin-cog.xml: + * docs/plugins/inspect/plugin-coloreffects.xml: + * docs/plugins/inspect/plugin-dataurisrc.xml: + * docs/plugins/inspect/plugin-dc1394.xml: + * docs/plugins/inspect/plugin-dccp.xml: + * docs/plugins/inspect/plugin-debugutilsbad.xml: + * docs/plugins/inspect/plugin-dfbvideosink.xml: + * docs/plugins/inspect/plugin-dirac.xml: + * docs/plugins/inspect/plugin-dtmf.xml: + * docs/plugins/inspect/plugin-dtsdec.xml: + * docs/plugins/inspect/plugin-dvb.xml: + * docs/plugins/inspect/plugin-dvdspu.xml: + * docs/plugins/inspect/plugin-faac.xml: + * docs/plugins/inspect/plugin-faad.xml: + * docs/plugins/inspect/plugin-fbdevsink.xml: + * docs/plugins/inspect/plugin-festival.xml: + * docs/plugins/inspect/plugin-freeze.xml: + * docs/plugins/inspect/plugin-frei0r.xml: + * docs/plugins/inspect/plugin-gaudieffects.xml: + * docs/plugins/inspect/plugin-geometrictransform.xml: + * docs/plugins/inspect/plugin-gsettings.xml: + * docs/plugins/inspect/plugin-gsm.xml: + * docs/plugins/inspect/plugin-gstsiren.xml: + * docs/plugins/inspect/plugin-h264parse.xml: + * docs/plugins/inspect/plugin-hdvparse.xml: + * docs/plugins/inspect/plugin-id3tag.xml: + * docs/plugins/inspect/plugin-invtelecine.xml: + * docs/plugins/inspect/plugin-ivfparse.xml: + * docs/plugins/inspect/plugin-jack.xml: + * docs/plugins/inspect/plugin-jpegformat.xml: + * docs/plugins/inspect/plugin-kate.xml: + * docs/plugins/inspect/plugin-ladspa.xml: + * docs/plugins/inspect/plugin-legacyresample.xml: + * docs/plugins/inspect/plugin-liveadder.xml: + * docs/plugins/inspect/plugin-metadata.xml: + * docs/plugins/inspect/plugin-mimic.xml: + * docs/plugins/inspect/plugin-mms.xml: + * docs/plugins/inspect/plugin-modplug.xml: + * docs/plugins/inspect/plugin-mpeg2enc.xml: + * docs/plugins/inspect/plugin-mpeg4videoparse.xml: + * docs/plugins/inspect/plugin-mpegdemux2.xml: + * docs/plugins/inspect/plugin-mpegpsmux.xml: + * docs/plugins/inspect/plugin-mpegtsmux.xml: + * docs/plugins/inspect/plugin-mpegvideoparse.xml: + * docs/plugins/inspect/plugin-mplex.xml: + * docs/plugins/inspect/plugin-musepack.xml: + * docs/plugins/inspect/plugin-musicbrainz.xml: + * docs/plugins/inspect/plugin-mve.xml: + * docs/plugins/inspect/plugin-mxf.xml: + * docs/plugins/inspect/plugin-mythtv.xml: + * docs/plugins/inspect/plugin-nas.xml: + * docs/plugins/inspect/plugin-neon.xml: + * docs/plugins/inspect/plugin-nsf.xml: + * docs/plugins/inspect/plugin-nuvdemux.xml: + * docs/plugins/inspect/plugin-ofa.xml: + * docs/plugins/inspect/plugin-pcapparse.xml: + * docs/plugins/inspect/plugin-pnm.xml: + * docs/plugins/inspect/plugin-qtmux.xml: + * docs/plugins/inspect/plugin-rawparse.xml: + * docs/plugins/inspect/plugin-real.xml: + * docs/plugins/inspect/plugin-resindvd.xml: + * docs/plugins/inspect/plugin-rfbsrc.xml: + * docs/plugins/inspect/plugin-rsvg.xml: + * docs/plugins/inspect/plugin-rtpmux.xml: + * docs/plugins/inspect/plugin-scaletempo.xml: + * docs/plugins/inspect/plugin-schro.xml: + * docs/plugins/inspect/plugin-sdl.xml: + * docs/plugins/inspect/plugin-sdp.xml: + * docs/plugins/inspect/plugin-segmentclip.xml: + * docs/plugins/inspect/plugin-selector.xml: + * docs/plugins/inspect/plugin-shm.xml: + * docs/plugins/inspect/plugin-sndfile.xml: + * docs/plugins/inspect/plugin-soundtouch.xml: + * docs/plugins/inspect/plugin-speed.xml: + * docs/plugins/inspect/plugin-stereo.xml: + * docs/plugins/inspect/plugin-subenc.xml: + * docs/plugins/inspect/plugin-tta.xml: + * docs/plugins/inspect/plugin-valve.xml: + * docs/plugins/inspect/plugin-vcdsrc.xml: + * docs/plugins/inspect/plugin-vdpau.xml: + * docs/plugins/inspect/plugin-videomaxrate.xml: + * docs/plugins/inspect/plugin-videomeasure.xml: + * docs/plugins/inspect/plugin-videosignal.xml: + * docs/plugins/inspect/plugin-vmnc.xml: + * docs/plugins/inspect/plugin-vp8.xml: + * docs/plugins/inspect/plugin-wildmidi.xml: + * docs/plugins/inspect/plugin-xvid.xml: + * docs/plugins/inspect/plugin-zbar.xml: + docs: update for release -2010-09-03 00:03:50 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> +2010-09-03 00:19:33 +0100 Tim-Philipp Müller <tim.muller@collabora.co.uk> * po/LINGUAS: * po/el.po: diff --git a/LICENSE_readme b/LICENSE_readme index 718d6d23b..3afe96ebc 100644 --- a/LICENSE_readme +++ b/LICENSE_readme @@ -37,8 +37,6 @@ xvid libxvidcore (http://www.xvid.org/) Plugins derived from GPL code are as follows: dvdreadsrc libdvdread (http://www.dtek.chalmers.se/groups/dvd/) -jack libjack (http://jackit.sourceforge.net/) - Note libjack is LGPL, but plugin is GPL. monoscope None (Algorithm by Ralph Loader, Joerg Walter, Richard Boulton, and Andy Lo A Foe) rtjpeg None (Erik Walthinsen's algorithm) diff --git a/Makefile.am b/Makefile.am index 37b104d17..aaa72137d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -46,26 +46,42 @@ CRUFT_FILES = \ $(top_builddir)/common/shave-libtool \ $(top_builddir)/ext/alsaspdif/.libs/*.{so,dll,DLL,dylib} \ $(top_builddir)/ext/ivorbis/.libs/*.{so,dll,DLL,dylib} \ + $(top_builddir)/ext/jack/.libs/*.{so,dll,DLL,dylib} \ $(top_builddir)/gst/aacparse/.libs/*.{so,dll,DLL,dylib} \ $(top_builddir)/gst/amrparse/.libs/*.{so,dll,DLL,dylib} \ $(top_builddir)/gst/flacparse/.libs/*.{so,dll,DLL,dylib} \ - $(top_builddir)/gst/shapewipe/.libs/*.{so,dll,DLL,dylib} \ $(top_builddir)/gst/imagefreeze/.libs/*.{so,dll,DLL,dylib} \ + $(top_builddir)/gst/selector/.libs/*.{so,dll,DLL,dylib} \ + $(top_builddir)/gst/shapewipe/.libs/*.{so,dll,DLL,dylib} \ + $(top_builddir)/gst/valve/.libs/*.{so,dll,DLL,dylib} \ + $(top_builddir)/gst/videoparsers/.libs/libgsth263parse* \ $(top_builddir)/sys/oss4/.libs/*.{so,dll,DLL,dylib} \ + $(top_builddir)/tests/check/elements/autocolorspace \ $(top_builddir)/tests/check/elements/capssetter \ $(top_builddir)/tests/check/elements/imagefreeze \ + $(top_builddir)/tests/check/elements/selector \ + $(top_builddir)/tests/check/elements/valve \ $(top_builddir)/tests/check/pipelines/metadata \ - $(top_builddir)/tests/icles/test-oss4 + $(top_builddir)/tests/examples/jack/jack_client \ + $(top_builddir)/tests/examples/switch/switcher \ + $(top_builddir)/tests/icles/output-selector-test \ + $(top_builddir)/tests/icles/test-oss4 \ + $(top_builddir)/tests/icles/equalizer-test CRUFT_DIRS = \ $(top_srcdir)/gst/aacparse \ $(top_srcdir)/gst/amrparse \ $(top_srcdir)/gst/flacparse \ $(top_srcdir)/gst/imagefreeze \ + $(top_srcdir)/gst/selector \ $(top_srcdir)/gst/shapewipe \ + $(top_srcdir)/gst/valve \ $(top_srcdir)/tests/examples/shapewipe \ + $(top_srcdir)/tests/examples/switch \ + $(top_srcdir)/tests/examples/jack \ $(top_srcdir)/ext/alsaspdif \ $(top_srcdir)/ext/ivorbis \ + $(top_srcdir)/ext/jack \ $(top_srcdir)/ext/metadata include $(top_srcdir)/common/cruft.mak @@ -1,4 +1,196 @@ -This is GStreamer Bad Plug-ins 0.10.20, "For it is a Human Number" +This is GStreamer Bad Plug-ins 0.10.21, "Pink Noise" + +Changes since 0.10.20: + + * alsaspdif: removed alsaspdifsink element (replaced by alsasink device=spdif) + * metadata: remove metadata plugin + * jack: jack plugin has moved to gst-plugins-good (0.10.27) + * selector: input-selector and output-selector have moved to GStreamer core (0.10.32) + * valve: has moved to gstreamer core (0.10.32) + * applemedia: new plugin for Apple multimedia APIs (avfvideosrc, celvideosrc, qtkitvideosrc, miovideosrc, vth264decbin, vth264encbin, vtdec, vtenc) + * applemedia: new iOS video source based on AVFoundation + * y4mdec: new y4mdec element + * dcaparse: new dts/dca audio parser + * camerabin2: new camerabin element (work-in-progress, experimental) + * opencv: new plugin with elements facedetect, faceblur, edgedetect, cvsobel, cvsmooth, cvlaplace, cverode, cvequalizehist, cvdilate, textwrite, templatematch, pyramidsegment + * interlace: new element + * geometrictransform: new rotate element + * jp2kdecimator: add a JPEG2000 decimator element (drop details without reencoding) + * audioparsers: add dcaparse, a dts/dca parser, and mpegaudioparse (mp3parse replacement) + * autoconvert: add autovideoconvert, an autoconvert based video format converter + * checksumsink, chopmydata: new debug elements + * dvbsuboverlay: new element to overlay DVB subtitle + * rsvgoverlay: new element for scalable and relative svg overlay with cairo + * qtmux: add new ismlmux element, for fragmented isml major brand + * ac3parse: properly parse E-AC3 frame header and use proper EAC-3 caps + * ac3parse: relax BSID checking, performance improvements + * applemedia mtapi: update to reflect new API on iOS 4.x + * applemedia vtenc: bump H.264 level from 1.3 to 3.0 + * applemedia vtenc: remove keyframe enforcement workaround + * applemedia celapi: update to reflect new API on iOS 4.x + * applemedia cvapi: add wrapper for IO surface access + * audioparse: add support for setting the channel-positions + * audioparsers: increase ranks to enable auto-plugging (incl. new mp3 parser) + * baseparse: enhancements for timestamp marked framed formats + * baseparse: increase keyframe awareness + * baseparse: perform bitrate handling and posting after newsegment sending + * baseparse: post duration message if average bitrates is updated + * baseparse: prevent indefinite resyncing + * baseparse: add index support, seek table and accurate seek support + * baseparse: support reverse playback + * baseparse: use determined seekability in answering SEEKING query + * basevideo: Add handling of GstForceKeyUnit events + * basevideodecoder: add capture pattern handling; don't blow away field information + * bayer2rgb: add format=bggr/etc. to caps, add framerate to the sink caps + * camerabin: add "preview-source-filter","ready-for-capture", "idle" properties + * camerabin: change "zoom" property from int to float + * camerabin: enable all conversion flags by default to make it work out-of-the-box everywhere + * coloreffects: Add chromahold effect + * cog: improvements in colorspace and scaler; add fast paths for colorspace conversion + * colorspace: revive element and add support for many more pixellayouts/colorspaces + * colorspace: add support for SDTV/HDTV YUV conversions + * dtmfsrc: Make the dtmfsrc accept events sent with gst_element_send_event + * tools: misc. improvements to element-maker tool + * faac: handle trailing encoder output + * faad: support reverse playback; cater for decoder delay and renegotiation + * faad: tweak output buffer timestamping + * flacparse: don't drop the last frame if it is followed by garbage + * flacparse: don't parse the complete FLAC frames but only look for valid frame headers (for performance) + * flacparse: fix picture parsing, fix parsing with unknown framesizes + * flacparse: parse seektable + * frei0r: add support for the FREI0R_PATH environment variable + * frei0r: fix crashes if plugins don't provide correct property information + * frei0r: fix scanning of plugin subdirectories and support different vendors + * frei0r: update frei0r interface specification to 1.2 + * gaudieffects: avoid divide by 0 in burn element, make filter parameters dynamic and controllable + * id3mux: map GST_TAG_ALBUM_ARTIST, give PRIMARY rank + * invtelecine: Fix name of 30p/60i pattern + * jasperdec: don't fail hard on decoding error + * jifmux: detect EOI correctly; do not limit the size of the image on 16bits + * jp2kenc: Emit SOP markers in every codestream packet + * jpegparse: avoid infinite loop when resyncing; discard incomplete image + * kate: add segment tracking, and various other improvements + * kate: ensure the kate pad does not shoot ahead of the video pad + * mpegtsdemux: extract language for DVB subtitle streams + * mpegtsdemux: enable gather_pes only for DVB subtitle private streams + * mpegtsdemux: fix re-syncing on invalid data after seek + * mpegtsmux: Initialize PES packet before getting the header size + * mpegtsmux: Set adaptation flag when appropriate + * mpegtsmux: Set random_access_indicator for keyframes + * mpegtsparse: send TDT tables messages in a serialized event downstream + * ofa: Call g_object_notify() after the fingerprint was created + * pcapparse: Add support for Linux Cooked Capture (SLL) frames + * photography: add missing property and cabability flag for noise reduction + * photography: Add "zoom" and "image-preview-supported-caps" interface properties + * photography: add gst_photography_{set,get}_noise_reduction() and CAPS_NOISE_REDUCTION flag + * qtmux: add support for fragmented mp4 + * qtmux: add "streamable" property to avoid building fragmented mfra index + * qtmux: timestamp tracking fixes and many other fixes + * resindvd: attempt to use glib language setting for DVD menus/audio + * resindvd: improve error messages on read errors; button state tracking fixes + * rfbsrc: fail more gracefully if source gets disconnected or geometry changes + * sdlvideosink: re-enable YVYU and UYVY support + * sdpdemux: error out if no streams found in sdp message + * sdpdemux: redirect SDP with an rtsp control URL and add property to disable redirect + * ssim: add I420 support + * tiger: outline text by default, to make it easier to read + * winks: add property probing support; fix framerate fraction range mapping + * winks: ignore unsupported formats; work around shutdown deadlock + * winks: performance improvements + * zbar: make scanner cache optional, disable it by default + * zbar: use correct strides, support more formats + +Bugs fixed since 0.10.20: + + * 628609 : The qtwrapperaudiodec_samr decoder doesn't handle buffers containing many AMR frames properly + * 639296 : [y4mdec] Doesn't handle files which don't specify a colorspace + * 613379 : camerabin: Do not use audio clock after stopping video capture + * 636279 : REGRESSION: Video often freezes during playback of mpeg2 files + * 630255 : [examples] camerabin example still uses old GstXOverlay interface + * 631232 : [colorspace] AYUV/ARGB handling broken on big endian systems + * 627229 : fpsdisplaysink should not measure fps relative to pipeline clock + * 435120 : cairosvgoverlay + * 486659 : xmp/exif metadata handling + * 578629 : libgstphotography missing exports for MSVC + * 587223 : mpegtsdemux seg.fault due to invalid PMT_pid + * 598078 : osxvideosrc doesn't build in snow leopard x86_64 + * 600929 : [kate] tiger element doesn't handle segments and text/video synchronization properly + * 603063 : camerabin example fails to start recording + * 611428 : [gdiscreencapsrc] leaks memory (ICONINFO) + * 613633 : [resindvd] scrambled DVDs yield useless generic error message if dvdcss is not available + * 616814 : Photography interface extension: colour tone mode and noise reduction settings + * 616923 : camerabin: remove photography interface implementation + * 618045 : [cogcolorspace] No Y41B support + * 618542 : DVB subtitles support + * 625558 : [basevideoencoder] [vp8] encoder timestamps are wrong when there are gaps + * 626425 : cog_virt_frame_new_convert_u8 has bogus source data + * 627134 : photography interface: add API for capture correction + * 627211 : jpegformat: Push tags after setting srcpad caps + * 627253 : [mpegtsparse] Post tags of channel and currently running event + * 627992 : dtmfsrc doesn't support gst_element_send_event + * 628326 : vdpau: don't change structure in setcaps function + * 628527 : videoanalyse: classificication is wrong + * 628548 : [mpegtsmux] Initialize PES packet before getting the header size + * 628570 : cogcolorspace: element classificication is wrong + * 629554 : dvbsrc: Fix example usage, bandwidth=8 not 8MHz + * 629897 : [cog] Ignores --disable-orc and always requires orc + * 629910 : jpegparse: properly clean up comment string + * 629917 : [output-selector] Recheck pending_pad after pushing a buffer + * 630046 : sdpdemux: Add optional support for rtspsrc as session element + * 630253 : [sdl] Still uses old GstXOverlay interface + * 630254 : [vdpau] Still uses old GstXOverlay interface + * 630783 : [frei0r] Crashes if broken plugins don't give correct property information + * 630808 : valve: move to core + * 631200 : flacparse: major performance improvements + * 631389 : [flacparse] backport/check corner case fixes done in flacdec + * 631449 : [audioparse] doest not support several channel numbers + * 631501 : [faad] failed to dynamically switch from 2 audio channels to 6 + * 631814 : [flacparse] unit test failures + * 631993 : [flacparse] imperfect timestamping + * 632070 : qtmux: infinite loop + * 632668 : Gaudi Effects [review] + * 632885 : Gaudi Effects dynamically controllable parameters [review] + * 632911 : qtmux: add fragmented mp4 support (isml brand) + * 633466 : [katedec] Pushes events before the final caps are known + * 633917 : [mpegtsparse] [PATCH] Send TDT messages in an serialized event downstream + * 635200 : [dvbbasebin] [PATCH] Add TDT to the initial pids filter for dvbsrc + * 635202 : mpeg4videoparse: Minor fixes + * 635204 : mpeg4videoparse: Set srcpad caps before forwarding newsegment + * 635205 : h264parse: Set srcpad caps before forwarding newsegment + * 635229 : celtenc: uninitialized tags variable can cause segfault + * 635304 : [opencv] fix caps issues and extend supported caps for some elements [PATCH] + * 635397 : rfbsrc: avoid infinite loop if source gets disconnected and don't crash if frame geometry changes + * 635529 : interlace: Add pattern offset and fix timestamps + * 635720 : vp8enc incorrectly sets timestamps based on theoretical framerate + * 635786 : [audioparse] Fix division-by-zero exception + * 635878 : [qtmux] gst_qtmux_check_difference subtract 2 unsigned numbers without taking care of the result sign + * 636106 : autocolorspace: new plugin for auto space convertor selection + * 636109 : [SSIM] klass should be Filter/Effect/Video + * 636185 : qtmux: msvc incompatibility + * 637062 : [ac3parse] parse problems on some MTS streams + * 637224 : [bayer2rgb] missing framerate in sink caps + * 637308 : gst-plugins-bad did not find xvidcore on my box + * 637359 : Internal GStreamer error, during pcap to mp4 conversion + * 637403 : qtmux do not store 1st TS when detect 1st buffer + * 637486 : qtmux: error if no buffers have arrived to one pad at EOS + * 637532 : applemedia: redundant declaration of 'parent_class' + * 637590 : [PATCH] fix gst-plugins-bad compile against latest gtk+ + * 637824 : mpeg4videoparse: gst_buffer_is_metadata_writable warning (regression) + * 637929 : mve: do not use the pad buffer allocation functions in demuxers + * 637931 : mpegdemux: do not use the pad buffer allocation functions in demuxers + * 638004 : tiger: fallback on headers in caps to initialize if headers are absent + * 638288 : qtmux: fails to handle out-of-order buffers without duration + * 638412 : kate: reenable the sending of a message for tags + * 638527 : tiger: outline text by default, to make it easier to read + * 638604 : basecamerasrc isn't build by default but camerabin2 is and requires it + * 639063 : mpegtsparse: fix (re)sync with invalid data at beginning + * 639338 : [qtmux] Protect against copying a null caps + * 639413 : Camerabin should use output-selector:pad-negotiation-mode=active + * 639456 : [camerabin] Should have all conversion flags enabled by default + * 639555 : [audioparsers] Be careful to not lose the event ref + * 639950 : flacparse: avoid unref'ing NULL buffer + * 630830 : zbar: Fixes, single frame scan and width/stride fix + * 635281 : [mpegtsparse] TDT packets are only parsed for odd hours Changes since 0.10.19: @@ -1,5 +1,5 @@ -Release notes for GStreamer Bad Plug-ins 0.10.20 "For it is a Human Number" +Release notes for GStreamer Bad Plug-ins 0.10.21 "Pink Noise" @@ -60,122 +60,195 @@ contains a set of well-supported plug-ins, but might pose problems for Features of this release - * asfmux streaming fixes and improvements - * new video effects plugins: coloreffects, gaudieffects, geometrictransform - * new gsettings plugin with gsettings{audio,video}{src,sink} elements - * new ivfparse element - * new rtmpsrc element - * new shmsink and shmsrc elements for IPC using shared memory - * new videomaxrate element - * dshowvideosink improvements - * vdpau: H.264 and MPEG-4 decoder (not enabled for autoplugging yet though) - * vp8enc: support multipass encoding and keyframe-only mode - * neonhttpsrc: timeout properties and cookie support - * h264parse and mpegvideoparse: can periodically insert codec data into stream now - * build: require GLib >= 2.20, automake >= 1.10, autoconf >= 2.60, want orc - * asfmux: deprecate "is-live" property, replaced by new "streamable" property - * asfmux: don't set the 'seekable' flag in headers if we are streaming - * asfmux: put headers into "streamheader" field in output caps for streaming - * asfmux: write preroll info in the header at initialization - * bayer: support more formats in bayer2rgb, add rgb2bayer element - * camerabin: make viewfinder-sink property work with bins - * celt: add support for celt 0.8, remove support for celt < 0.5 - * celtenc: add "prediction" and "start band" properties - * coloreffects: new element with heat, sepia, xray and cross-process effects - * dshowvideosink: many fixes and improvements - * fpsdisplaysink: add "fps-update-interval" and read-only "max-fps"/"min-fps" properties - * frei0r: check for plugins in /usr/{local/,}lib{32,64}/frei0r-1 too - * gaudieffects: new plugin with burn, chromium, dilate, dodge, exclusion, gaussianblur and solarize video effect elements - * geometrictransform: new plugin with circle, diffuse, kaleidoscope, marble, pinch, sphere, twirl, and waterripple, fisheye, mirror, square, tunnel, bulge, stretch video effect elements - * gsettings: new GSettings plugin with audio/video sources and sinks (to replace gconf plugin) - * h264parse: add "config-interval" property to insert SPS/PPS at periodic intervals - * h264parse: handle 3-byte bytestream sync codes; process incoming timestamps more correctly - * id3mux: add support for beats-per-minute tag - * invtelecine: support more video formats, more pulldown formats, add "verify-field-flags" property - * ivfparse: add simple IVF parser element (simple framing for VP8 video data) - * jpegformat: add exif writing to jifmux and exif parsing to jpegparse - * jpegparse: skip extra 0xff markers, optimize jpeg image parsing - * mimic: lots of fixes and clean-ups - * mpeg4videoparse: add "config-interval" property to re-insert config in stream - * mpegtsmux: start pmt at 0x020; take all the pmt in the streamheaders - * mpegtsparse: actually work when we have small buffers coming in - * mpegvideoparse: apply previous timestamp when there isn't any newer - * neonhttpsrc: add "connect-timeout", "read-timeout" and "cookies" properties - * qtmux: write audio/video stream bitrates into header, if available - * qtmux: write track-number etc. tags even if count is not available - * rtmpsrc: new RTMP source element based on librtmp - * rtpdtmfmux: add priority sink pads and drop buffers on non-priority sink pads when something is incoming on the priority sink - * rtpmux: add support for GstBufferLists; aggregate incoming segments; fix buffer leak - * shm: add new shm-based shmsink and shmsrc elements for IPC using shared memory - * vdpau: add H.264 decoder and MPEG-4 part 2 decoder; countless other fixes and improvements - * videomaxrate: new plugin/element to limit videorate conditionally based on threshold - * vp8dec: mark discont buffers, set decoder deadline from the QoS information - * vp8enc: allow a maximum keyframe distance of 0, i.e. all frames are keyframes - * vp8enc: fix handling of invisible/alt ref frames - * vp8enc: add support for enabling automatic insertion of alt-ref frames by the encoder - * vp8enc: implement multipass encoding - * wildmidi: Add support for wildmidi 0.2.3 + * alsaspdif: removed alsaspdifsink element (replaced by alsasink device=spdif) + * metadata: remove metadata plugin + * jack: jack plugin has moved to gst-plugins-good (0.10.27) + * selector: input-selector and output-selector have moved to GStreamer core (0.10.32) + * valve: has moved to gstreamer core (0.10.32) + * applemedia: new plugin for Apple multimedia APIs (avfvideosrc, celvideosrc, qtkitvideosrc, miovideosrc, vth264decbin, vth264encbin, vtdec, vtenc) + * applemedia: new iOS video source based on AVFoundation + * y4mdec: new y4mdec element + * dcaparse: new dts/dca audio parser + * camerabin2: new camerabin element (work-in-progress, experimental) + * opencv: new plugin with elements facedetect, faceblur, edgedetect, cvsobel, cvsmooth, cvlaplace, cverode, cvequalizehist, cvdilate, textwrite, templatematch, pyramidsegment + * interlace: new element + * geometrictransform: new rotate element + * jp2kdecimator: add a JPEG2000 decimator element (drop details without reencoding) + * audioparsers: add dcaparse, a dts/dca parser, and mpegaudioparse (mp3parse replacement) + * autoconvert: add autovideoconvert, an autoconvert based video format converter + * checksumsink, chopmydata: new debug elements + * dvbsuboverlay: new element to overlay DVB subtitle + * rsvgoverlay: new element for scalable and relative svg overlay with cairo + * qtmux: add new ismlmux element, for fragmented isml major brand + * ac3parse: properly parse E-AC3 frame header and use proper EAC-3 caps + * ac3parse: relax BSID checking, performance improvements + * applemedia mtapi: update to reflect new API on iOS 4.x + * applemedia vtenc: bump H.264 level from 1.3 to 3.0 + * applemedia vtenc: remove keyframe enforcement workaround + * applemedia celapi: update to reflect new API on iOS 4.x + * applemedia cvapi: add wrapper for IO surface access + * audioparse: add support for setting the channel-positions + * audioparsers: increase ranks to enable auto-plugging (incl. new mp3 parser) + * baseparse: enhancements for timestamp marked framed formats + * baseparse: increase keyframe awareness + * baseparse: perform bitrate handling and posting after newsegment sending + * baseparse: post duration message if average bitrates is updated + * baseparse: prevent indefinite resyncing + * baseparse: add index support, seek table and accurate seek support + * baseparse: support reverse playback + * baseparse: use determined seekability in answering SEEKING query + * basevideo: Add handling of GstForceKeyUnit events + * basevideodecoder: add capture pattern handling; don't blow away field information + * bayer2rgb: add format=bggr/etc. to caps, add framerate to the sink caps + * camerabin: add "preview-source-filter","ready-for-capture", "idle" properties + * camerabin: change "zoom" property from int to float + * camerabin: enable all conversion flags by default to make it work out-of-the-box everywhere + * coloreffects: Add chromahold effect + * cog: improvements in colorspace and scaler; add fast paths for colorspace conversion + * colorspace: revive element and add support for many more pixellayouts/colorspaces + * colorspace: add support for SDTV/HDTV YUV conversions + * dtmfsrc: Make the dtmfsrc accept events sent with gst_element_send_event + * tools: misc. improvements to element-maker tool + * faac: handle trailing encoder output + * faad: support reverse playback; cater for decoder delay and renegotiation + * faad: tweak output buffer timestamping + * flacparse: don't drop the last frame if it is followed by garbage + * flacparse: don't parse the complete FLAC frames but only look for valid frame headers (for performance) + * flacparse: fix picture parsing, fix parsing with unknown framesizes + * flacparse: parse seektable + * frei0r: add support for the FREI0R_PATH environment variable + * frei0r: fix crashes if plugins don't provide correct property information + * frei0r: fix scanning of plugin subdirectories and support different vendors + * frei0r: update frei0r interface specification to 1.2 + * gaudieffects: avoid divide by 0 in burn element, make filter parameters dynamic and controllable + * id3mux: map GST_TAG_ALBUM_ARTIST, give PRIMARY rank + * invtelecine: Fix name of 30p/60i pattern + * jasperdec: don't fail hard on decoding error + * jifmux: detect EOI correctly; do not limit the size of the image on 16bits + * jp2kenc: Emit SOP markers in every codestream packet + * jpegparse: avoid infinite loop when resyncing; discard incomplete image + * kate: add segment tracking, and various other improvements + * kate: ensure the kate pad does not shoot ahead of the video pad + * mpegtsdemux: extract language for DVB subtitle streams + * mpegtsdemux: enable gather_pes only for DVB subtitle private streams + * mpegtsdemux: fix re-syncing on invalid data after seek + * mpegtsmux: Initialize PES packet before getting the header size + * mpegtsmux: Set adaptation flag when appropriate + * mpegtsmux: Set random_access_indicator for keyframes + * mpegtsparse: send TDT tables messages in a serialized event downstream + * ofa: Call g_object_notify() after the fingerprint was created + * pcapparse: Add support for Linux Cooked Capture (SLL) frames + * photography: add missing property and cabability flag for noise reduction + * photography: Add "zoom" and "image-preview-supported-caps" interface properties + * photography: add gst_photography_{set,get}_noise_reduction() and CAPS_NOISE_REDUCTION flag + * qtmux: add support for fragmented mp4 + * qtmux: add "streamable" property to avoid building fragmented mfra index + * qtmux: timestamp tracking fixes and many other fixes + * resindvd: attempt to use glib language setting for DVD menus/audio + * resindvd: improve error messages on read errors; button state tracking fixes + * rfbsrc: fail more gracefully if source gets disconnected or geometry changes + * sdlvideosink: re-enable YVYU and UYVY support + * sdpdemux: error out if no streams found in sdp message + * sdpdemux: redirect SDP with an rtsp control URL and add property to disable redirect + * ssim: add I420 support + * tiger: outline text by default, to make it easier to read + * winks: add property probing support; fix framerate fraction range mapping + * winks: ignore unsupported formats; work around shutdown deadlock + * winks: performance improvements + * zbar: make scanner cache optional, disable it by default + * zbar: use correct strides, support more formats Bugs fixed in this release - * 625908 : [geometrictransform] Some more configuration options for effects - * 625076 : neonhttpsrc: add connect-timeout and read-timeout properties - * 620746 : basevideodecoder: remove spurious warning - * 566614 : bayer2rgb: Make first line configurable - * 570428 : autogen.sh fails - * 574290 : [dshowvideosink] make set_xwindow_id() in PLAYING state work - * 579926 : [directshowvideosink] Doesn't update the last frame after a seek with the pipeline in PAUSED state. - * 580967 : shared memory based sink and source - * 591622 : [vdpau] needs better error/failure handling - * 602551 : dshowvideosink window close doesn't cause gst-launch to exit - * 602936 : [ mp4mux] Lipsync issue when converting mkv to mp4 using h264/aac - * 613346 : [dshowvideosink] Add support for updating video caps - * 616265 : Add a GSettings plugin that provides the same services as the GConf plugin - * 618336 : [mpegvideoparse] mpegvideoparse makes some streams unplayable - * 618522 : [asfmux][patch] Improve support for streaming - * 618921 : [dshowvideosink] Replace CoIntialize with CoInitializeEx for bettrer integration with GStreamer threads - * 618936 : [dshowvideosink] close the created window in ::stop() - * 620324 : Format warning in ivfparse - * 620717 : [geometrytransform] Incomplete template caps - * 620825 : [geometrytransform] Make properties controllable and threadsafe - * 620978 : insert NAL7/8 always when encountering I frame - * 621205 : [mpeg4videoparse] add config-interval property to insert mpeg4video config data in regular intervals - * 621348 : [vp8enc] Implement multipass encoding - * 621523 : [id3mux] write beats-per-minute tag - * 622369 : [rtmpsrc] crash if correct server but wrong video file name - * 622484 : [qtmux] missing track number tag when transcoding to aac - * 622690 : elements/jpegparse check fails - * 622692 : pipelines/metadata check fails - * 622725 : [mpgtsparse] Doesn't remove pids from pes_pids - * 623272 : [dshowvideosink] setting force-aspect-ratio has no effect after the sink's renderer has been configured - * 623365 : [qtmux and variant] Don't store codec tags - * 623550 : doesn't compile with celt 0.8 - * 623678 : qtmux: Write AAC/H.264 bitrate if available - * 623710 : [frei0r] Load frei0r plugins in /usr/lib64/frei0r-1 too - * 623713 : [dshowaudiodec][patch] Fix compilation error - * 623722 : gstwildmidi element update to newer library version - * 623802 : camerabin: Bin based viewfinder sink support is broken - * 623854 : jpegparse reads a wrong EXIF section size - * 623881 : aiffmux.c divide by zero - * 623883 : [winks] gstksvideosrc.c error on MSVC using gst_element_class_set_details() - * 625003 : [examples] Don't use GdkDraw - * 625138 : [dshowvideosrc] Don't use a range in the caps if min==max - * 625174 : neonhttpsrc: adds cookies support - * 625496 : qtmux - misc fix on btrt box - * 625722 : [geometrictransform] Some new effect elements for cheese - * 625817 : coloreffects: new plugin for lookup table color mapping - * 625959 : geometrictransform: make CircleGeometricTransform " radius " property relative - * 626049 : [vdpau] crashes in states.check unit test - * 626603 : generic/states check fails with gsettings element installed - * 626670 : gaudieffects: Fails to link inline functions properly - * 626815 : vp8dec: infinite loop if EOS event before started - * 627413 : jifmux causes broken jpeg images at least with some rgb pixel format - * 627918 : Do not install gst-camera.ui - * 627991 : rtpmux will freeze whenever a flush is sent - * 624212 : mp4mux produces incorrect frame rates when h264 input uses bframes - * 619158 : IVF parser plugin - * 619484 : vp8dec: s/IMG_FMT_I420/VPX_IMG_FMT_I420/ - * 621404 : [dvbsrc] Set stats-reporting-interval on construction + * 628609 : The qtwrapperaudiodec_samr decoder doesn't handle buffers containing many AMR frames properly + * 639296 : [y4mdec] Doesn't handle files which don't specify a colorspace + * 613379 : camerabin: Do not use audio clock after stopping video capture + * 636279 : REGRESSION: Video often freezes during playback of mpeg2 files + * 630255 : [examples] camerabin example still uses old GstXOverlay interface + * 631232 : [colorspace] AYUV/ARGB handling broken on big endian systems + * 627229 : fpsdisplaysink should not measure fps relative to pipeline clock + * 435120 : cairosvgoverlay + * 486659 : xmp/exif metadata handling + * 578629 : libgstphotography missing exports for MSVC + * 587223 : mpegtsdemux seg.fault due to invalid PMT_pid + * 598078 : osxvideosrc doesn't build in snow leopard x86_64 + * 600929 : [kate] tiger element doesn't handle segments and text/video synchronization properly + * 603063 : camerabin example fails to start recording + * 611428 : [gdiscreencapsrc] leaks memory (ICONINFO) + * 613633 : [resindvd] scrambled DVDs yield useless generic error message if dvdcss is not available + * 616814 : Photography interface extension: colour tone mode and noise reduction settings + * 616923 : camerabin: remove photography interface implementation + * 618045 : [cogcolorspace] No Y41B support + * 618542 : DVB subtitles support + * 625558 : [basevideoencoder] [vp8] encoder timestamps are wrong when there are gaps + * 626425 : cog_virt_frame_new_convert_u8 has bogus source data + * 627134 : photography interface: add API for capture correction + * 627211 : jpegformat: Push tags after setting srcpad caps + * 627253 : [mpegtsparse] Post tags of channel and currently running event + * 627992 : dtmfsrc doesn't support gst_element_send_event + * 628326 : vdpau: don't change structure in setcaps function + * 628527 : videoanalyse: classificication is wrong + * 628548 : [mpegtsmux] Initialize PES packet before getting the header size + * 628570 : cogcolorspace: element classificication is wrong + * 629554 : dvbsrc: Fix example usage, bandwidth=8 not 8MHz + * 629897 : [cog] Ignores --disable-orc and always requires orc + * 629910 : jpegparse: properly clean up comment string + * 629917 : [output-selector] Recheck pending_pad after pushing a buffer + * 630046 : sdpdemux: Add optional support for rtspsrc as session element + * 630253 : [sdl] Still uses old GstXOverlay interface + * 630254 : [vdpau] Still uses old GstXOverlay interface + * 630783 : [frei0r] Crashes if broken plugins don't give correct property information + * 630808 : valve: move to core + * 631200 : flacparse: major performance improvements + * 631389 : [flacparse] backport/check corner case fixes done in flacdec + * 631449 : [audioparse] doest not support several channel numbers + * 631501 : [faad] failed to dynamically switch from 2 audio channels to 6 + * 631814 : [flacparse] unit test failures + * 631993 : [flacparse] imperfect timestamping + * 632070 : qtmux: infinite loop + * 632668 : Gaudi Effects [review] + * 632885 : Gaudi Effects dynamically controllable parameters [review] + * 632911 : qtmux: add fragmented mp4 support (isml brand) + * 633466 : [katedec] Pushes events before the final caps are known + * 633917 : [mpegtsparse] [PATCH] Send TDT messages in an serialized event downstream + * 635200 : [dvbbasebin] [PATCH] Add TDT to the initial pids filter for dvbsrc + * 635202 : mpeg4videoparse: Minor fixes + * 635204 : mpeg4videoparse: Set srcpad caps before forwarding newsegment + * 635205 : h264parse: Set srcpad caps before forwarding newsegment + * 635229 : celtenc: uninitialized tags variable can cause segfault + * 635304 : [opencv] fix caps issues and extend supported caps for some elements [PATCH] + * 635397 : rfbsrc: avoid infinite loop if source gets disconnected and don't crash if frame geometry changes + * 635529 : interlace: Add pattern offset and fix timestamps + * 635720 : vp8enc incorrectly sets timestamps based on theoretical framerate + * 635786 : [audioparse] Fix division-by-zero exception + * 635878 : [qtmux] gst_qtmux_check_difference subtract 2 unsigned numbers without taking care of the result sign + * 636106 : autocolorspace: new plugin for auto space convertor selection + * 636109 : [SSIM] klass should be Filter/Effect/Video + * 636185 : qtmux: msvc incompatibility + * 637062 : [ac3parse] parse problems on some MTS streams + * 637224 : [bayer2rgb] missing framerate in sink caps + * 637308 : gst-plugins-bad did not find xvidcore on my box + * 637359 : Internal GStreamer error, during pcap to mp4 conversion + * 637403 : qtmux do not store 1st TS when detect 1st buffer + * 637486 : qtmux: error if no buffers have arrived to one pad at EOS + * 637532 : applemedia: redundant declaration of 'parent_class' + * 637590 : [PATCH] fix gst-plugins-bad compile against latest gtk+ + * 637824 : mpeg4videoparse: gst_buffer_is_metadata_writable warning (regression) + * 637929 : mve: do not use the pad buffer allocation functions in demuxers + * 637931 : mpegdemux: do not use the pad buffer allocation functions in demuxers + * 638004 : tiger: fallback on headers in caps to initialize if headers are absent + * 638288 : qtmux: fails to handle out-of-order buffers without duration + * 638412 : kate: reenable the sending of a message for tags + * 638527 : tiger: outline text by default, to make it easier to read + * 638604 : basecamerasrc isn't build by default but camerabin2 is and requires it + * 639063 : mpegtsparse: fix (re)sync with invalid data at beginning + * 639338 : [qtmux] Protect against copying a null caps + * 639413 : Camerabin should use output-selector:pad-negotiation-mode=active + * 639456 : [camerabin] Should have all conversion flags enabled by default + * 639555 : [audioparsers] Be careful to not lose the event ref + * 639950 : flacparse: avoid unref'ing NULL buffer + * 630830 : zbar: Fixes, single frame scan and width/stride fix + * 635281 : [mpegtsparse] TDT packets are only parsed for odd hours Download @@ -204,39 +277,61 @@ Applications Contributors to this release + * Alejandro Gonzalez + * Aleksey Lim * Alessandro Decina - * Andoni Morales * Andoni Morales Alastruey + * Andres Colubri + * André Dieb Martins * Arun Raghavan - * Austin Lund - * Bastien Nocera - * Benjamin Otte + * Benjamin Gaignard * Carl-Anton Ingmarsson + * Christian Berentsen + * Damien Lespiau * David Hoyt * David Schleef * Edward Hervey - * Filippo Argiolas + * Felipe Contreras + * Francis Rammeloo + * Hoseok Chang + * Hu Gang * Jan Schmidt - * Jonathan Matthew - * Julien Moutte + * Janne Grunau + * Jonathan Rosser + * Josh Doe + * Kaj-Michael Lang + * Karol Sobczak + * Knut Inge Hvidsten + * Lasse Laukkanen + * Leo Singer + * Luciana Fujii Pontello * Luis de Bethencourt * Marc-André Lureau * Mark Nauwelaerts - * Michael Smith + * Mart Raudsepp + * Matthew Ife + * Mike Sheldon + * Noam + * Ole André Vadla RavnÃ¥s + * Olivier Aubert * Olivier Crête - * Philip Jägenstedt - * Philippe Normand - * Raimo Jarvi + * Rob Clark * Robert Swain - * Sameer Naik + * Saleem Abdulrasool * Sebastian Dröge * Sebastian Pölsterl + * Sreerenj Balachandran * Stefan Kost + * Teemu Katajisto * Thiago Santos + * Thibault Saunier * Thijs Vermeir * Tim-Philipp Müller + * Tristan Matthews + * Vincent Penquerc'h * VÃctor Manuel Jáquez Leal + * Wim Taymans * Youness Alaoui - * Zaheer Abbas Merali - * РуÑлан Ижбулатов + * benjamin gaignard + * kapil Â
\ No newline at end of file diff --git a/common b/common -Subproject 011bcc8a0fc7f798ee874a7ba899123fb2470e2 +Subproject 1de7f6ab2d4bc1af69f06079cf0f4e2cbbfdc17 diff --git a/configure.ac b/configure.ac index 09e53aa12..d1bd4a928 100644 --- a/configure.ac +++ b/configure.ac @@ -178,7 +178,7 @@ AC_CHECK_FUNC(socket,,[AC_CHECK_LIB(socket,socket)]) AC_CHECK_FUNC(gethostbyname,,[AC_CHECK_LIB(nsl,gethostbyname)]) dnl GLib is required -AG_GST_GLIB_CHECK([2.20]) +AG_GST_GLIB_CHECK([2.22]) dnl checks for gstreamer dnl uninstalled is selected preferentially -- see pkg-config(1) @@ -266,7 +266,7 @@ dnl -Waggregate-return - libexif returns aggregates dnl -Wundef - Windows headers check _MSC_VER unconditionally AG_GST_SET_ERROR_CFLAGS($GST_GIT, [ -Wmissing-declarations -Wmissing-prototypes -Wredundant-decls - -Wwrite-strings -Wformat-nonliteral -Wformat-security -Wold-style-definition + -Wwrite-strings -Wformat-security -Wold-style-definition -Winit-self -Wmissing-include-dirs -Waddress -Wno-multichar -Wnested-externs]) @@ -293,6 +293,7 @@ AG_GST_CHECK_PLUGIN(audioparsers) AG_GST_CHECK_PLUGIN(autoconvert) AG_GST_CHECK_PLUGIN(bayer) AG_GST_CHECK_PLUGIN(camerabin) +AG_GST_CHECK_PLUGIN(camerabin2) AG_GST_CHECK_PLUGIN(cdxaparse) AG_GST_CHECK_PLUGIN(coloreffects) AG_GST_CHECK_PLUGIN(colorspace) @@ -300,6 +301,7 @@ AG_GST_CHECK_PLUGIN(dataurisrc) AG_GST_CHECK_PLUGIN(dccp) AG_GST_CHECK_PLUGIN(debugutils) AG_GST_CHECK_PLUGIN(dtmf) +AG_GST_CHECK_PLUGIN(dvbsuboverlay) AG_GST_CHECK_PLUGIN(dvdspu) AG_GST_CHECK_PLUGIN(festival) AG_GST_CHECK_PLUGIN(freeze) @@ -318,6 +320,7 @@ AG_GST_CHECK_PLUGIN(legacyresample) AG_GST_CHECK_PLUGIN(librfb) AG_GST_CHECK_PLUGIN(liveadder) AG_GST_CHECK_PLUGIN(mpegdemux) +AG_GST_CHECK_PLUGIN(mpegtsdemux) AG_GST_CHECK_PLUGIN(mpegtsmux) AG_GST_CHECK_PLUGIN(mpegpsmux) AG_GST_CHECK_PLUGIN(mpeg4videoparse) @@ -332,20 +335,21 @@ AG_GST_CHECK_PLUGIN(qtmux) AG_GST_CHECK_PLUGIN(rawparse) AG_GST_CHECK_PLUGIN(real) AG_GST_CHECK_PLUGIN(rtpmux) +AG_GST_CHECK_PLUGIN(rtpvp8) AG_GST_CHECK_PLUGIN(scaletempo) AG_GST_CHECK_PLUGIN(sdp) AG_GST_CHECK_PLUGIN(segmentclip) -AG_GST_CHECK_PLUGIN(selector) AG_GST_CHECK_PLUGIN(siren) AG_GST_CHECK_PLUGIN(speed) AG_GST_CHECK_PLUGIN(subenc) AG_GST_CHECK_PLUGIN(stereo) AG_GST_CHECK_PLUGIN(tta) -AG_GST_CHECK_PLUGIN(valve) AG_GST_CHECK_PLUGIN(videomaxrate) AG_GST_CHECK_PLUGIN(videomeasure) +AG_GST_CHECK_PLUGIN(videoparsers) AG_GST_CHECK_PLUGIN(videosignal) AG_GST_CHECK_PLUGIN(vmnc) +AG_GST_CHECK_PLUGIN(y4m) dnl *** plug-ins to exclude *** @@ -356,8 +360,9 @@ if test "x$HAVE_CPU_I386" != "xyes" && test "x$HAVE_CPU_X86_64" != "xyes"; then fi dnl disable experimental plug-ins -dnl if test "x$BUILD_EXPERIMENTAL" != "xyes"; then -dnl fi +if test "x$BUILD_EXPERIMENTAL" != "xyes"; then + AG_GST_DISABLE_PLUGIN(camerabin2) +fi # This will always succeed because we depend on GLib >= 2.16 PKG_CHECK_MODULES(GIO, gio-2.0 >= 2.16, HAVE_GIO=yes, HAVE_GIO=no) @@ -687,11 +692,11 @@ dnl *** DTS *** translit(dnm, m, l) AM_CONDITIONAL(USE_DTS, true) AG_GST_CHECK_FEATURE(DTS, [dts library], dtsdec, [ HAVE_DTS="yes" - AG_GST_CHECK_LIBHEADER(DTS, dca, dca_init, -lm, dca.h, - DTS_LIBS="-ldca -lm", HAVE_DTS="no") + AG_GST_CHECK_LIBHEADER(DTS, dca, dca_init, $LIBM, dca.h, + DTS_LIBS="-ldca $LIBM", HAVE_DTS="no") if test $HAVE_DTS = "no"; then - AG_GST_CHECK_LIBHEADER(DTS, dts_pic, dts_init, -lm, dts.h, - [ DTS_LIBS="-ldts_pic -lm" + AG_GST_CHECK_LIBHEADER(DTS, dts_pic, dts_init, $LIBM, dts.h, + [ DTS_LIBS="-ldts_pic $LIBM" AC_DEFINE(DTS_OLD, 1, [Define if an old libdts is used]) ]) fi @@ -748,7 +753,7 @@ return 0; AC_MSG_WARN([Wrong version of divx4linux installed]) ]) fi - LIBS="-lm" + LIBS="$LIBM" if test x$HAVE_DIVX = xyes; then AC_CHECK_LIB(divxencore, encore, , [ AC_MSG_WARN([Divx4linux encore libs not found]) @@ -762,8 +767,8 @@ return 0; ]) fi if test x$HAVE_DIVX = xyes; then - DIVXENC_LIBS="-ldivxencore -lm" - DIVXDEC_LIBS="-ldivxdecore -lm" + DIVXENC_LIBS="-ldivxencore $LIBM" + DIVXDEC_LIBS="-ldivxdecore $LIBM" AC_SUBST(DIVXENC_LIBS) AC_SUBST(DIVXDEC_LIBS) fi @@ -790,8 +795,8 @@ AG_GST_CHECK_FEATURE(EXIF, [exif], exif, [ dnl **** Free AAC Encoder (FAAC) **** translit(dnm, m, l) AM_CONDITIONAL(USE_FAAC, true) AG_GST_CHECK_FEATURE(FAAC, [AAC encoder plug-in], faac, [ - AG_GST_CHECK_LIBHEADER(FAAC, faac, faacEncOpen, -lm, faac.h, - FAAC_LIBS="-lfaac -lm") + AG_GST_CHECK_LIBHEADER(FAAC, faac, faacEncOpen, $LIBM, faac.h, + FAAC_LIBS="-lfaac $LIBM") AS_SCRUB_INCLUDE(FAAC_CFLAGS) AC_SUBST(FAAC_LIBS) ]) @@ -801,11 +806,11 @@ translit(dnm, m, l) AM_CONDITIONAL(USE_FAAD, true) AG_GST_CHECK_FEATURE(FAAD, [AAC decoder plug-in], faad, [ HAVE_FAAD="yes" faad_hdr="" - AG_GST_CHECK_LIBHEADER(FAAD, faad, faacDecOpen, -lm, faad.h, - FAAD_LIBS="-lfaad -lm", HAVE_FAAD="no") + AG_GST_CHECK_LIBHEADER(FAAD, faad, faacDecOpen, $LIBM, faad.h, + FAAD_LIBS="-lfaad $LIBM", HAVE_FAAD="no") if test $HAVE_FAAD = "no"; then - AG_GST_CHECK_LIBHEADER(FAAD, faad, NeAACDecOpen, -lm, neaacdec.h, - [ FAAD_LIBS="-lfaad -lm" + AG_GST_CHECK_LIBHEADER(FAAD, faad, NeAACDecOpen, $LIBM, neaacdec.h, + [ FAAD_LIBS="-lfaad $LIBM" AC_DEFINE(FAAD_IS_NEAAC, 1, [Define if AAC is using new api prefix]) faad_hdr="neaacdec.h" ], [ @@ -866,8 +871,8 @@ AG_GST_CHECK_FEATURE(FBDEV, [linux framebuffer], fbdevsink, [ dnl *** flite *** translit(dnm, m, l) AM_CONDITIONAL(USE_FLITE, true) AG_GST_CHECK_FEATURE(FLITE, [Flite plugin], flite, [ - AG_GST_CHECK_LIBHEADER(FLITE, flite, flite_init, -lm, flite/flite.h, - FLITE_LIBS="-lflite -lflite_cmu_us_kal -lflite_usenglish -lflite_cmulex -lm") + AG_GST_CHECK_LIBHEADER(FLITE, flite, flite_init, $LIBM, flite/flite.h, + FLITE_LIBS="-lflite -lflite_cmu_us_kal -lflite_usenglish -lflite_cmulex $LIBM") AC_SUBST(FLITE_CFLAGS) AC_SUBST(FLITE_LIBS) @@ -886,14 +891,6 @@ AG_GST_CHECK_FEATURE(GSM, [GSM library], gsmenc gsmdec, [ AC_SUBST(GSM_LIBS) ]) -dnl *** Jack *** -translit(dnm, m, l) AM_CONDITIONAL(USE_JACK, true) -AG_GST_CHECK_FEATURE(JACK, Jack, jack, [ - PKG_CHECK_MODULES(JACK, jack >= 0.99.10, HAVE_JACK="yes", HAVE_JACK="no") - AC_SUBST(JACK_CFLAGS) - AC_SUBST(JACK_LIBS) -]) - dnl *** jp2k *** translit(dnm, m, l) AM_CONDITIONAL(USE_JP2K, true) AG_GST_CHECK_FEATURE(JP2K, [jp2k], jp2kdec jp2kenc, [ @@ -997,7 +994,7 @@ PKG_CHECK_EXISTS(mjpegtools >= 1.6.1.93 mjpegtools < 1.8.0, [ OLD_CFLAGS="$CFLAGS" OLD_LIBS="$LIBS" CFLAGS="$MJPEG_CFLAGS" - LIBS="$LIBS $MJPEG_LIBS -lmjpegutils -lm -lpthread" + LIBS="$LIBS $MJPEG_LIBS -lmjpegutils $LIBM -lpthread" AC_CHECK_FUNC(mjpeg_loglev_t, [ mjpegtools_api=10903 ], [ @@ -1034,7 +1031,7 @@ AG_GST_CHECK_FEATURE(MPEG2ENC, [mpeg2enc], mpeg2enc, [ dnl check headers mpeg2enc_headers_ok=no AC_CHECK_HEADER([mpeg2encoder.hh], [ - MPEG2ENC_LIBS="$MPEG2ENC_LIBS -lmpeg2encpp -lm -lpthread" + MPEG2ENC_LIBS="$MPEG2ENC_LIBS -lmpeg2encpp $LIBM -lpthread" OLD_LIBS="$LIBS" LIBS="$LIBS $MPEG2ENC_LIBS" AC_MSG_CHECKING([for valid mpeg2enc objects]) @@ -1102,7 +1099,7 @@ AG_GST_CHECK_FEATURE(MPLEX, [mplex], mplex, [ OLD_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $MPLEX_CFLAGS" AC_CHECK_HEADER(interact.hpp, [ - MPLEX_LIBS="$MPLEX_LIBS -lmplex2 -lm" + MPLEX_LIBS="$MPLEX_LIBS -lmplex2 $LIBM" OLD_LIBS="$LIBS" LIBS="$LIBS $MPLEX_LIBS" OLD_LDFLAGS="$LDFLAGS" @@ -1433,7 +1430,7 @@ AG_GST_CHECK_FEATURE(XVID, [xvid plugins], xvid, [ HAVE_XVID=no AC_CHECK_HEADER(xvid.h, [ OLD_LIBS="$LIBS" - LIBS="-lm" + LIBS="-lpthread $LIBM" AC_CHECK_LIB(xvidcore, xvid_encore, [ AC_CHECK_LIB(xvidcore, xvid_decore, [ AC_CHECK_LIB(xvidcore, xvid_global, [ @@ -1443,7 +1440,7 @@ AG_GST_CHECK_FEATURE(XVID, [xvid plugins], xvid, [ #error "Incompatible XviD API version" #endif ],[ AC_MSG_RESULT(yes) - XVID_LIBS="-lxvidcore -lm" + XVID_LIBS="-lxvidcore $LIBM" AC_SUBST(XVID_LIBS) HAVE_XVID=yes ], AC_MSG_RESULT(no) ) @@ -1550,7 +1547,7 @@ AG_GST_CHECK_FEATURE(VP8, [VP8 decoder], vp8, [ HAVE_VP8_DECODER=no OLD_LIBS="$LIBS" - LIBS="$LIBS -lm -lpthread" + LIBS="$LIBS $LIBM -lpthread" AC_CHECK_LIB(vpx, vpx_codec_vp8_cx_algo, [ HAVE_VP8=yes AC_DEFINE(HAVE_VP8_ENCODER, 1, [Defined if the VP8 encoder is available]) @@ -1605,7 +1602,6 @@ AM_CONDITIONAL(USE_FAAD, false) AM_CONDITIONAL(USE_FBDEV, false) AM_CONDITIONAL(USE_FLITE, false) AM_CONDITIONAL(USE_GSM, false) -AM_CONDITIONAL(USE_JACK, false) AM_CONDITIONAL(USE_JP2K, false) AM_CONDITIONAL(USE_KATE, false) AM_CONDITIONAL(USE_TIGER, false) @@ -1622,6 +1618,7 @@ AM_CONDITIONAL(USE_MYTHTV, false) AM_CONDITIONAL(USE_NAS, false) AM_CONDITIONAL(USE_NEON, false) AM_CONDITIONAL(USE_OFA, false) +AM_CONDITIONAL(USE_OPENCV, false) AM_CONDITIONAL(USE_RSVG, false) AM_CONDITIONAL(USE_TIMIDITY, false) AM_CONDITIONAL(USE_WILDMIDI, false) @@ -1695,6 +1692,13 @@ dnl whatevertarget_LIBS and -L flags here affect the rest of the linking GST_ALL_LDFLAGS="-no-undefined" AC_SUBST(GST_ALL_LDFLAGS) +dnl GST_LIB_LDFLAGS +dnl linker flags shared by all libraries +dnl LDFLAGS modifier defining exported symbols from built libraries +dnl (export _gst_foo but not __gst_foo) +GST_LIB_LDFLAGS="-export-symbols-regex ^_?\(gst_\|Gst\|GST_\).*" +AC_SUBST(GST_LIB_LDFLAGS) + dnl this really should only contain flags, not libs - they get added before dnl whatevertarget_LIBS and -L flags here affect the rest of the linking GST_PLUGIN_LDFLAGS="-module -avoid-version -export-symbols-regex '^[_]*gst_plugin_desc\$\$' $GST_ALL_LDFLAGS" @@ -1718,6 +1722,7 @@ gst/audioparsers/Makefile gst/autoconvert/Makefile gst/bayer/Makefile gst/camerabin/Makefile +gst/camerabin2/Makefile gst/cdxaparse/Makefile gst/colorspace/Makefile gst/coloreffects/Makefile @@ -1725,6 +1730,7 @@ gst/dataurisrc/Makefile gst/dccp/Makefile gst/debugutils/Makefile gst/dtmf/Makefile +gst/dvbsuboverlay/Makefile gst/dvdspu/Makefile gst/festival/Makefile gst/freeze/Makefile @@ -1743,6 +1749,7 @@ gst/legacyresample/Makefile gst/librfb/Makefile gst/liveadder/Makefile gst/mpegdemux/Makefile +gst/mpegtsdemux/Makefile gst/mpegtsmux/Makefile gst/mpegtsmux/tsmux/Makefile gst/mpegpsmux/Makefile @@ -1758,22 +1765,25 @@ gst/qtmux/Makefile gst/rawparse/Makefile gst/real/Makefile gst/rtpmux/Makefile +gst/rtpvp8/Makefile gst/scaletempo/Makefile gst/sdp/Makefile gst/segmentclip/Makefile -gst/selector/Makefile gst/siren/Makefile gst/speed/Makefile gst/subenc/Makefile gst/stereo/Makefile gst/tta/Makefile -gst/valve/Makefile gst/videomaxrate/Makefile gst/videomeasure/Makefile +gst/videoparsers/Makefile gst/videosignal/Makefile gst/vmnc/Makefile +gst/y4m/Makefile gst-libs/Makefile gst-libs/gst/Makefile +gst-libs/gst/basecamerabinsrc/Makefile +gst-libs/gst/baseparse/Makefile gst-libs/gst/interfaces/Makefile gst-libs/gst/signalprocessor/Makefile gst-libs/gst/video/Makefile @@ -1804,11 +1814,10 @@ tests/check/Makefile tests/files/Makefile tests/examples/Makefile tests/examples/camerabin/Makefile +tests/examples/camerabin2/Makefile tests/examples/directfb/Makefile tests/examples/mxf/Makefile tests/examples/scaletempo/Makefile -tests/examples/switch/Makefile -tests/examples/jack/Makefile tests/icles/Makefile ext/amrwbenc/Makefile ext/assrender/Makefile @@ -1826,7 +1835,6 @@ ext/faac/Makefile ext/faad/Makefile ext/flite/Makefile ext/gsm/Makefile -ext/jack/Makefile ext/jp2k/Makefile ext/kate/Makefile ext/ladspa/Makefile diff --git a/docs/plugins/Makefile.am b/docs/plugins/Makefile.am index ff940df71..c9820cfd7 100644 --- a/docs/plugins/Makefile.am +++ b/docs/plugins/Makefile.am @@ -69,7 +69,7 @@ SCANOBJ_DEPS = \ $(top_builddir)/gst-libs/gst/interfaces/libgstphotography-@GST_MAJORMINOR@.la # Header files to ignore when scanning. -IGNORE_HFILES = +IGNORE_HFILES = IGNORE_CFILES = # we add all .h files of elements that have signals/args we want @@ -83,7 +83,7 @@ IGNORE_CFILES = # -> it just works (TM) (ensonic) # FIXME: not ported yet -# $(top_srcdir)/ext/gnomevfs/gstgnomevfssink.c +# $(top_srcdir)/ext/gnomevfs/gstgnomevfssink.c # example code that needs to be converted to xml and placed in xml/ EXAMPLE_CFILES = \ @@ -99,8 +99,6 @@ EXTRA_HFILES = \ $(top_srcdir)/ext/dts/gstdtsdec.h \ $(top_srcdir)/ext/faac/gstfaac.h \ $(top_srcdir)/ext/faad/gstfaad.h \ - $(top_srcdir)/ext/jack/gstjackaudiosrc.h \ - $(top_srcdir)/ext/jack/gstjackaudiosink.h \ $(top_srcdir)/ext/kate/gstkateenc.h \ $(top_srcdir)/ext/kate/gstkatedec.h \ $(top_srcdir)/ext/kate/gstkateparse.h \ @@ -126,6 +124,8 @@ EXTRA_HFILES = \ $(top_srcdir)/ext/opencv/gstpyramidsegment.h \ $(top_srcdir)/ext/opencv/gsttemplatematch.h \ $(top_srcdir)/ext/opencv/gsttextwrite.h \ + $(top_srcdir)/ext/rsvg/gstrsvgdec.h \ + $(top_srcdir)/ext/rsvg/gstrsvgoverlay.h \ $(top_srcdir)/ext/sdl/sdlaudiosink.h \ $(top_srcdir)/ext/sdl/sdlvideosink.h \ $(top_srcdir)/ext/theora/theoradec.h \ @@ -195,15 +195,12 @@ EXTRA_HFILES = \ $(top_srcdir)/gst/rtpmux/gstrtpdtmfmux.h \ $(top_srcdir)/gst/scaletempo/gstscaletempo.h \ $(top_srcdir)/gst/sdp/gstsdpdemux.h \ - $(top_srcdir)/gst/selector/gstinputselector.h \ - $(top_srcdir)/gst/selector/gstoutputselector.h \ $(top_srcdir)/gst/speed/gstspeed.h \ $(top_srcdir)/gst/stereo/gststereo.h \ $(top_srcdir)/gst/videomaxrate/videomaxrate.h \ $(top_srcdir)/gst/videosignal/gstvideoanalyse.h \ $(top_srcdir)/gst/videosignal/gstvideodetect.h \ $(top_srcdir)/gst/videosignal/gstvideomark.h \ - $(top_srcdir)/gst/valve/gstvalve.h \ $(top_srcdir)/sys/directdraw/gstdirectdrawsink.h \ $(top_srcdir)/sys/dvb/gstdvbsrc.h \ $(top_srcdir)/sys/shm/gstshmsink.h \ @@ -234,25 +231,6 @@ DOC_OVERRIDES = include $(top_srcdir)/common/gtk-doc-plugins.mak -# some additional clean rules from gtk-doc.mak -distclean-local: - rm -f $(REPORT_FILES) \ - $(DOC_MODULE)-decl-list.txt $(DOC_MODULE)-decl.txt - rm -rf tmpl/*.sgml.bak - rm -f $(DOC_MODULE).hierarchy - rm -f *.stamp || true - if test x"$(srcdir)" != x. ; then \ - rm -f $(DOC_MODULE)-docs.sgml ; \ - rm -f $(DOC_MODULE).types ; \ - rm -f $(DOC_MODULE).interfaces ; \ - rm -f $(DOC_MODULE)-overrides.txt ; \ - rm -f $(DOC_MODULE).prerequisites ; \ - rm -f $(DOC_MODULE)-sections.txt ; \ - rm -rf tmpl/*.sgml ; \ - fi - rm -rf *.o - - SUBDIRS = FIGURES_SOURCEFILES = camerabin.dot diff --git a/docs/plugins/gst-plugins-bad-plugins-docs.sgml b/docs/plugins/gst-plugins-bad-plugins-docs.sgml index 575afc1b1..5551d5c60 100644 --- a/docs/plugins/gst-plugins-bad-plugins-docs.sgml +++ b/docs/plugins/gst-plugins-bad-plugins-docs.sgml @@ -1,5 +1,5 @@ <?xml version="1.0"?> -<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [ <!ENTITY % version-entities SYSTEM "version.entities"> %version-entities; @@ -68,10 +68,7 @@ <xi:include href="xml/element-fpsdisplaysink.xml" /> <xi:include href="xml/element-freeze.xml" /> <xi:include href="xml/element-gaussianblur.xml" /> - <xi:include href="xml/element-input-selector.xml" /> <xi:include href="xml/element-ivfparse.xml" /> - <xi:include href="xml/element-jackaudiosrc.xml" /> - <xi:include href="xml/element-jackaudiosink.xml" /> <xi:include href="xml/element-jpegparse.xml" /> <xi:include href="xml/element-kaleidoscope.xml" /> <xi:include href="xml/element-kateenc.xml" /> @@ -93,11 +90,12 @@ <xi:include href="xml/element-mxfdemux.xml" /> <xi:include href="xml/element-mxfmux.xml" /> <xi:include href="xml/element-nuvdemux.xml" /> - <xi:include href="xml/element-output-selector.xml" /> <xi:include href="xml/element-pcapparse.xml" /> <xi:include href="xml/element-pinch.xml" /> <xi:include href="xml/element-pyramidsegment.xml" /> <xi:include href="xml/element-qtmux.xml" /> + <xi:include href="xml/element-rsvgdec.xml" /> + <xi:include href="xml/element-rsvgoverlay.xml" /> <xi:include href="xml/element-rtpdtmfdepay.xml" /> <xi:include href="xml/element-rtpdtmfsrc.xml" /> <xi:include href="xml/element-rtpdtmfmux.xml" /> @@ -122,7 +120,6 @@ <xi:include href="xml/element-trm.xml" /> <xi:include href="xml/element-tunnel.xml" /> <xi:include href="xml/element-twirl.xml" /> - <xi:include href="xml/element-valve.xml" /> <xi:include href="xml/element-videoanalyse.xml" /> <xi:include href="xml/element-videodetect.xml" /> <xi:include href="xml/element-videomark.xml" /> @@ -172,7 +169,6 @@ <xi:include href="xml/plugin-gsm.xml" /> <xi:include href="xml/plugin-h264parse.xml" /> <xi:include href="xml/plugin-ivfparse.xml" /> - <xi:include href="xml/plugin-jack.xml" /> <xi:include href="xml/plugin-jpegformat.xml" /> <xi:include href="xml/plugin-kate.xml" /> <xi:include href="xml/plugin-ladspa.xml" /> @@ -201,11 +197,11 @@ <xi:include href="xml/plugin-rawparse.xml" /> <xi:include href="xml/plugin-real.xml" /> <xi:include href="xml/plugin-rfbsrc.xml" /> + <xi:include href="xml/plugin-rsvg.xml" /> <xi:include href="xml/plugin-rtpmux.xml" /> <xi:include href="xml/plugin-scaletempo.xml" /> <xi:include href="xml/plugin-sdl.xml" /> <xi:include href="xml/plugin-sdp.xml" /> - <xi:include href="xml/plugin-selector.xml" /> <xi:include href="xml/plugin-shm.xml" /> <xi:include href="xml/plugin-sndfile.xml" /> <xi:include href="xml/plugin-soundtouch.xml" /> @@ -215,7 +211,6 @@ <xi:include href="xml/plugin-swfdec.xml" /> <xi:include href="xml/plugin-timidity.xml" /> <xi:include href="xml/plugin-tta.xml" /> - <xi:include href="xml/plugin-valve.xml" /> <xi:include href="xml/plugin-vcdsrc.xml" /> <xi:include href="xml/plugin-videomaxrate.xml" /> <xi:include href="xml/plugin-videosignal.xml" /> diff --git a/docs/plugins/gst-plugins-bad-plugins-sections.txt b/docs/plugins/gst-plugins-bad-plugins-sections.txt index fdfb78136..f85d0754d 100644 --- a/docs/plugins/gst-plugins-bad-plugins-sections.txt +++ b/docs/plugins/gst-plugins-bad-plugins-sections.txt @@ -792,26 +792,6 @@ gst_gauss_blur_plugin_init </SECTION> <SECTION> -<FILE>element-input-selector</FILE> -<TITLE>input-selector</TITLE> -GstInputSelector -<SUBSECTION Standard> -GstInputSelectorClass -GST_INPUT_SELECTOR -GST_INPUT_SELECTOR_CLASS -GST_IS_INPUT_SELECTOR -GST_IS_INPUT_SELECTOR_CLASS -GST_TYPE_INPUT_SELECTOR -gst_input_selector_get_type -GST_INPUT_SELECTOR_BROADCAST -GST_INPUT_SELECTOR_GET_COND -GST_INPUT_SELECTOR_GET_LOCK -GST_INPUT_SELECTOR_LOCK -GST_INPUT_SELECTOR_UNLOCK -GST_INPUT_SELECTOR_WAIT -</SECTION> - -<SECTION> <FILE>element-ivfparse</FILE> <TITLE>ivfparse</TITLE> GstIvfParse @@ -827,36 +807,6 @@ gst_ivf_parse_get_type </SECTION> <SECTION> -<FILE>element-jackaudiosrc</FILE> -<TITLE>jackaudiosrc</TITLE> -GstJackAudioSrc -<SUBSECTION Standard> -GstJackAudioSrcClass -GST_JACK_AUDIO_SRC -GST_JACK_AUDIO_SRC_CLASS -GST_JACK_AUDIO_SRC_GET_CLASS -GST_IS_JACK_AUDIO_SRC -GST_IS_JACK_AUDIO_SRC_CLASS -GST_TYPE_JACK_AUDIO_SRC -gst_jack_audio_src_get_type -</SECTION> - -<SECTION> -<FILE>element-jackaudiosink</FILE> -<TITLE>jackaudiosink</TITLE> -GstJackAudioSink -<SUBSECTION Standard> -GstJackAudioSinkClass -GST_JACK_AUDIO_SINK -GST_JACK_AUDIO_SINK_CLASS -GST_JACK_AUDIO_SINK_GET_CLASS -GST_IS_JACK_AUDIO_SINK -GST_IS_JACK_AUDIO_SINK_CLASS -GST_TYPE_JACK_AUDIO_SINK -gst_jack_audio_sink_get_type -</SECTION> - -<SECTION> <FILE>element-jpegparse</FILE> <TITLE>jpegparse</TITLE> GstJpegParse @@ -1180,20 +1130,6 @@ gst_nuv_demux_get_type </SECTION> <SECTION> -<FILE>element-output-selector</FILE> -<TITLE>output-selector</TITLE> -GstOutputSelector -<SUBSECTION Standard> -GstOutputSelectorClass -GST_OUTPUT_SELECTOR -GST_OUTPUT_SELECTOR_CLASS -GST_IS_OUTPUT_SELECTOR -GST_IS_OUTPUT_SELECTOR_CLASS -GST_TYPE_OUTPUT_SELECTOR -gst_output_selector_get_type -</SECTION> - -<SECTION> <FILE>element-pcapparse</FILE> <TITLE>pcapparse</TITLE> GstPcapParse @@ -1253,6 +1189,34 @@ gst_qt_mux_get_type </SECTION> <SECTION> +<FILE>element-rsvgoverlay</FILE> +<TITLE>rsvgoverlay</TITLE> +GstRsvgOverlay +<SUBSECTION Standard> +GstRsvgOverlayClass +GST_RSVG_OVERLAY +GST_RSVG_OVERLAY_CLASS +GST_IS_RSVG_OVERLAY +GST_IS_RSVG_OVERLAY_CLASS +GST_TYPE_RSVG_OVERLAY +gst_rsvg_overlay_get_type +</SECTION> + +<SECTION> +<FILE>element-rsvgdec</FILE> +<TITLE>rsvgdec</TITLE> +GstRsvgDec +<SUBSECTION Standard> +GstRsvgDecClass +GST_RSVG_DEC +GST_RSVG_DEC_CLASS +GST_IS_RSVG_DEC +GST_IS_RSVG_DEC_CLASS +GST_TYPE_RSVG_DEC +gst_rsvg_dec_get_type +</SECTION> + +<SECTION> <FILE>element-rtpdtmfdepay</FILE> <TITLE>rtpdtmfdepay</TITLE> GstRtpDTMFDepay @@ -1603,21 +1567,6 @@ gst_twirl_plugin_init </SECTION> <SECTION> -<FILE>element-valve</FILE> -<TITLE>valve</TITLE> -GstValve -<SUBSECTION Standard> -GstValveClass -GstValvePrivate -gst_valve_get_type -GST_IS_VALVE -GST_IS_VALVE_CLASS -GST_TYPE_VALVE -GST_VALVE -GST_VALVE_CLASS -</SECTION> - -<SECTION> <FILE>element-videoanalyse</FILE> <TITLE>videoanalyse</TITLE> GstVideoAnalyse diff --git a/docs/plugins/gst-plugins-bad-plugins.args b/docs/plugins/gst-plugins-bad-plugins.args index 4717bb9aa..f6f1b5816 100644 --- a/docs/plugins/gst-plugins-bad-plugins.args +++ b/docs/plugins/gst-plugins-bad-plugins.args @@ -41,7 +41,7 @@ <ARG> <NAME>GstXvidEnc::averaging-period</NAME> <TYPE>gint</TYPE> -<RANGE>[-1,100]</RANGE> +<RANGE>[G_MAXULONG,100]</RANGE> <FLAGS>rw</FLAGS> <NICK>Averaging Period</NICK> <BLURB>[CBR] Number of frames for which XviD averages bitrate.</BLURB> @@ -91,7 +91,7 @@ <ARG> <NAME>GstXvidEnc::buffer</NAME> <TYPE>gint</TYPE> -<RANGE>>= -1</RANGE> +<RANGE>>= G_MAXULONG</RANGE> <FLAGS>rw</FLAGS> <NICK>Buffer Size</NICK> <BLURB>[CBR] Size of the video buffers.</BLURB> @@ -121,7 +121,7 @@ <ARG> <NAME>GstXvidEnc::container-frame-overhead</NAME> <TYPE>gint</TYPE> -<RANGE>[-1,100]</RANGE> +<RANGE>[G_MAXULONG,100]</RANGE> <FLAGS>rw</FLAGS> <NICK>Container Frame Overhead</NICK> <BLURB>[PASS2] Average container overhead per frame.</BLURB> @@ -151,7 +151,7 @@ <ARG> <NAME>GstXvidEnc::flow-control-strength</NAME> <TYPE>gint</TYPE> -<RANGE>[-1,100]</RANGE> +<RANGE>[G_MAXULONG,100]</RANGE> <FLAGS>rw</FLAGS> <NICK>Flow Control Strength</NICK> <BLURB>[PASS2] Overflow control strength per frame.</BLURB> @@ -211,7 +211,7 @@ <ARG> <NAME>GstXvidEnc::keyframe-reduction</NAME> <TYPE>gint</TYPE> -<RANGE>[-1,100]</RANGE> +<RANGE>[G_MAXULONG,100]</RANGE> <FLAGS>rw</FLAGS> <NICK>Keyframe Reduction</NICK> <BLURB>[PASS2] Keyframe size reduction in % of those within threshold.</BLURB> @@ -221,7 +221,7 @@ <ARG> <NAME>GstXvidEnc::keyframe-threshold</NAME> <TYPE>gint</TYPE> -<RANGE>[-1,100]</RANGE> +<RANGE>[G_MAXULONG,100]</RANGE> <FLAGS>rw</FLAGS> <NICK>Keyframe Threshold</NICK> <BLURB>[PASS2] Distance between keyframes not to be subject to reduction.</BLURB> @@ -281,7 +281,7 @@ <ARG> <NAME>GstXvidEnc::max-overflow-degradation</NAME> <TYPE>gint</TYPE> -<RANGE>[-1,100]</RANGE> +<RANGE>[G_MAXULONG,100]</RANGE> <FLAGS>rw</FLAGS> <NICK>Max Overflow Degradation</NICK> <BLURB>[PASS2] Amount in % that flow control can decrease frame size compared to ideal curve.</BLURB> @@ -291,7 +291,7 @@ <ARG> <NAME>GstXvidEnc::max-overflow-improvement</NAME> <TYPE>gint</TYPE> -<RANGE>[-1,100]</RANGE> +<RANGE>[G_MAXULONG,100]</RANGE> <FLAGS>rw</FLAGS> <NICK>Max Overflow Improvement</NICK> <BLURB>[PASS2] Amount in % that flow control can increase frame size compared to ideal curve.</BLURB> @@ -421,7 +421,7 @@ <ARG> <NAME>GstXvidEnc::reaction-delay-factor</NAME> <TYPE>gint</TYPE> -<RANGE>[-1,100]</RANGE> +<RANGE>[G_MAXULONG,100]</RANGE> <FLAGS>rw</FLAGS> <NICK>Reaction Delay Factor</NICK> <BLURB>[CBR] Reaction delay factor.</BLURB> @@ -1539,36 +1539,6 @@ </ARG> <ARG> -<NAME>GstJackAudioSink::connect</NAME> -<TYPE>GstJackConnect</TYPE> -<RANGE></RANGE> -<FLAGS>rw</FLAGS> -<NICK>Connect</NICK> -<BLURB>Specify how the output ports will be connected.</BLURB> -<DEFAULT>Automatically connect ports to physical ports</DEFAULT> -</ARG> - -<ARG> -<NAME>GstJackAudioSink::server</NAME> -<TYPE>gchar*</TYPE> -<RANGE></RANGE> -<FLAGS>rw</FLAGS> -<NICK>Server</NICK> -<BLURB>The Jack server to connect to (NULL = default).</BLURB> -<DEFAULT>NULL</DEFAULT> -</ARG> - -<ARG> -<NAME>GstJackAudioSink::client</NAME> -<TYPE>JackClient*</TYPE> -<RANGE></RANGE> -<FLAGS>rw</FLAGS> -<NICK>JackClient</NICK> -<BLURB>Handle for jack client.</BLURB> -<DEFAULT></DEFAULT> -</ARG> - -<ARG> <NAME>GstDvbSrc::bandwidth</NAME> <TYPE>GstDvbSrcBandwidth</TYPE> <RANGE></RANGE> @@ -1731,7 +1701,7 @@ <ARG> <NAME>GstDvbSrc::diseqc-source</NAME> <TYPE>gint</TYPE> -<RANGE>[-1,7]</RANGE> +<RANGE>[G_MAXULONG,7]</RANGE> <FLAGS>rw</FLAGS> <NICK>diseqc source</NICK> <BLURB>DISEqC selected source (-1 disabled) (DVB-S).</BLURB> @@ -17175,7 +17145,7 @@ <FLAGS>rw</FLAGS> <NICK>Path where to search for RealPlayer codecs</NICK> <BLURB>Path where to search for RealPlayer codecs.</BLURB> -<DEFAULT>"/usr/lib/win32:/usr/lib/codecs:/usr/local/RealPlayer/codecs:/usr/local/lib/win32:/usr/local/lib/codecs"</DEFAULT> +<DEFAULT>"/usr/lib64/win32:/usr/lib64/codecs:/usr/local/lib64/win32:/usr/local/lib64/codecs"</DEFAULT> </ARG> <ARG> @@ -17215,7 +17185,7 @@ <FLAGS>rw</FLAGS> <NICK>Path where to search for RealPlayer codecs</NICK> <BLURB>Path where to search for RealPlayer codecs.</BLURB> -<DEFAULT>"/usr/lib/win32:/usr/lib/codecs:/usr/local/RealPlayer/codecs:/usr/local/lib/win32:/usr/local/lib/codecs"</DEFAULT> +<DEFAULT>"/usr/lib64/win32:/usr/lib64/codecs:/usr/local/lib64/win32:/usr/local/lib64/codecs"</DEFAULT> </ARG> <ARG> @@ -17871,7 +17841,7 @@ <ARG> <NAME>DvbBaseBin::diseqc-source</NAME> <TYPE>gint</TYPE> -<RANGE>[-1,7]</RANGE> +<RANGE>[G_MAXULONG,7]</RANGE> <FLAGS>rw</FLAGS> <NICK>diseqc source</NICK> <BLURB>DISEqC selected source (-1 disabled) (DVB-S).</BLURB> @@ -18019,6 +17989,16 @@ </ARG> <ARG> +<NAME>GstSDPDemux::redirect</NAME> +<TYPE>gboolean</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>Redirect</NICK> +<BLURB>Sends a redirection message instead of using a custom session element.</BLURB> +<DEFAULT>TRUE</DEFAULT> +</ARG> + +<ARG> <NAME>GstSpeexResample::quality</NAME> <TYPE>gint</TYPE> <RANGE>[0,10]</RANGE> @@ -18099,6 +18079,16 @@ </ARG> <ARG> +<NAME>GstAudioParse::channel-positions</NAME> +<TYPE>GValueArray*</TYPE> +<RANGE></RANGE> +<FLAGS>rw</FLAGS> +<NICK>Channel positions</NICK> +<BLURB>Channel positions used on the output.</BLURB> +<DEFAULT></DEFAULT> +</ARG> + +<ARG> <NAME>GstVideoParse::alpha-mask</NAME> <TYPE>gint</TYPE> <RANGE></RANGE> @@ -18454,56 +18444,6 @@ </ARG> <ARG> -<NAME>GstInputSelector::active-pad</NAME> -<TYPE>GstPad*</TYPE> -<RANGE></RANGE> -<FLAGS>rw</FLAGS> -<NICK>Active pad</NICK> -<BLURB>The currently active sink pad.</BLURB> -<DEFAULT></DEFAULT> -</ARG> - -<ARG> -<NAME>GstInputSelector::n-pads</NAME> -<TYPE>guint</TYPE> -<RANGE></RANGE> -<FLAGS>r</FLAGS> -<NICK>Number of Pads</NICK> -<BLURB>The number of sink pads.</BLURB> -<DEFAULT>0</DEFAULT> -</ARG> - -<ARG> -<NAME>GstInputSelector::select-all</NAME> -<TYPE>gboolean</TYPE> -<RANGE></RANGE> -<FLAGS>rw</FLAGS> -<NICK>Select all mode</NICK> -<BLURB>Forwards data from all input pads.</BLURB> -<DEFAULT>FALSE</DEFAULT> -</ARG> - -<ARG> -<NAME>GstOutputSelector::active-pad</NAME> -<TYPE>GstPad*</TYPE> -<RANGE></RANGE> -<FLAGS>rw</FLAGS> -<NICK>Active pad</NICK> -<BLURB>Currently active src pad.</BLURB> -<DEFAULT></DEFAULT> -</ARG> - -<ARG> -<NAME>GstOutputSelector::resend-latest</NAME> -<TYPE>gboolean</TYPE> -<RANGE></RANGE> -<FLAGS>rw</FLAGS> -<NICK>Resend latest buffer</NICK> -<BLURB>Resend latest buffer after a switch to a new pad.</BLURB> -<DEFAULT>FALSE</DEFAULT> -</ARG> - -<ARG> <NAME>GstGLTestSrc::is-live</NAME> <TYPE>gboolean</TYPE> <RANGE></RANGE> @@ -21916,11 +21856,11 @@ <ARG> <NAME>GstCeltEnc::bitrate</NAME> <TYPE>gint</TYPE> -<RANGE>[10,320]</RANGE> +<RANGE>[10000,320000]</RANGE> <FLAGS>rw</FLAGS> <NICK>Encoding Bit-rate</NICK> -<BLURB>Specify an encoding bit-rate (in Kbps).</BLURB> -<DEFAULT>64</DEFAULT> +<BLURB>Specify an encoding bit-rate (in bps).</BLURB> +<DEFAULT>64000</DEFAULT> </ARG> <ARG> @@ -21956,11 +21896,11 @@ <ARG> <NAME>GstCeltEnc::max-bitrate</NAME> <TYPE>gint</TYPE> -<RANGE>[10,320]</RANGE> +<RANGE>[10000,320000]</RANGE> <FLAGS>rw</FLAGS> <NICK>Maximum Encoding Bit-rate</NICK> -<BLURB>Specify a maximum encoding bit rate (in Kbps) for variable bit rate encoding.</BLURB> -<DEFAULT>64</DEFAULT> +<BLURB>Specify a maximum encoding bit rate (in bps) for variable bit rate encoding.</BLURB> +<DEFAULT>64000</DEFAULT> </ARG> <ARG> @@ -21984,36 +21924,6 @@ </ARG> <ARG> -<NAME>GstJackAudioSrc::connect</NAME> -<TYPE>GstJackConnect</TYPE> -<RANGE></RANGE> -<FLAGS>rw</FLAGS> -<NICK>Connect</NICK> -<BLURB>Specify how the input ports will be connected.</BLURB> -<DEFAULT>Automatically connect ports to physical ports</DEFAULT> -</ARG> - -<ARG> -<NAME>GstJackAudioSrc::server</NAME> -<TYPE>gchar*</TYPE> -<RANGE></RANGE> -<FLAGS>rw</FLAGS> -<NICK>Server</NICK> -<BLURB>The Jack server to connect to (NULL = default).</BLURB> -<DEFAULT>NULL</DEFAULT> -</ARG> - -<ARG> -<NAME>GstJackAudioSrc::client</NAME> -<TYPE>JackClient*</TYPE> -<RANGE></RANGE> -<FLAGS>rw</FLAGS> -<NICK>JackClient</NICK> -<BLURB>Handle for jack client.</BLURB> -<DEFAULT></DEFAULT> -</ARG> - -<ARG> <NAME>GstDCCPClientSrc::caps</NAME> <TYPE>GstCaps*</TYPE> <RANGE></RANGE> @@ -22066,7 +21976,7 @@ <ARG> <NAME>GstDCCPClientSrc::sockfd</NAME> <TYPE>gint</TYPE> -<RANGE>>= -1</RANGE> +<RANGE>>= G_MAXULONG</RANGE> <FLAGS>rw</FLAGS> <NICK>Socket fd</NICK> <BLURB>The socket file descriptor.</BLURB> @@ -22106,7 +22016,7 @@ <ARG> <NAME>GstDCCPServerSink::sockfd</NAME> <TYPE>gint</TYPE> -<RANGE>>= -1</RANGE> +<RANGE>>= G_MAXULONG</RANGE> <FLAGS>rw</FLAGS> <NICK>Socket fd</NICK> <BLURB>The client socket file descriptor.</BLURB> @@ -22166,7 +22076,7 @@ <ARG> <NAME>GstDCCPClientSink::sockfd</NAME> <TYPE>gint</TYPE> -<RANGE>>= -1</RANGE> +<RANGE>>= G_MAXULONG</RANGE> <FLAGS>rw</FLAGS> <NICK>Socket fd</NICK> <BLURB>The socket file descriptor.</BLURB> @@ -22226,7 +22136,7 @@ <ARG> <NAME>GstDCCPServerSrc::sockfd</NAME> <TYPE>gint</TYPE> -<RANGE>>= -1</RANGE> +<RANGE>>= G_MAXULONG</RANGE> <FLAGS>rw</FLAGS> <NICK>Socket fd</NICK> <BLURB>The client socket file descriptor.</BLURB> @@ -22286,7 +22196,7 @@ <ARG> <NAME>GstMpegTSDemux::program-number</NAME> <TYPE>gint</TYPE> -<RANGE>>= -1</RANGE> +<RANGE>>= G_MAXULONG</RANGE> <FLAGS>rw</FLAGS> <NICK>Program Number</NICK> <BLURB>Program number to demux for (-1 to ignore).</BLURB> @@ -22346,7 +22256,7 @@ <ARG> <NAME>GstPcapParse::dst-port</NAME> <TYPE>gint</TYPE> -<RANGE>[-1,65535]</RANGE> +<RANGE>[G_MAXULONG,65535]</RANGE> <FLAGS>rw</FLAGS> <NICK>Destination port</NICK> <BLURB>Destination port to restrict to.</BLURB> @@ -22366,7 +22276,7 @@ <ARG> <NAME>GstPcapParse::src-port</NAME> <TYPE>gint</TYPE> -<RANGE>[-1,65535]</RANGE> +<RANGE>[G_MAXULONG,65535]</RANGE> <FLAGS>rw</FLAGS> <NICK>Source port</NICK> <BLURB>Source port to restrict to.</BLURB> @@ -22374,6 +22284,16 @@ </ARG> <ARG> +<NAME>GstPcapParse::caps</NAME> +<TYPE>GstCaps*</TYPE> +<RANGE></RANGE> +<FLAGS>rw</FLAGS> +<NICK>Caps</NICK> +<BLURB>The caps of the source pad.</BLURB> +<DEFAULT></DEFAULT> +</ARG> + +<ARG> <NAME>MpegTsMux::m2ts-mode</NAME> <TYPE>gboolean</TYPE> <RANGE></RANGE> @@ -22524,6 +22444,46 @@ </ARG> <ARG> +<NAME>GstMJ2Mux::fragment-duration</NAME> +<TYPE>guint</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>Fragment duration</NICK> +<BLURB>Fragment durations in ms (produce a fragmented file if > 0).</BLURB> +<DEFAULT>0</DEFAULT> +</ARG> + +<ARG> +<NAME>GstMJ2Mux::streamable</NAME> +<TYPE>gboolean</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>Streamable</NICK> +<BLURB>If set to true, the output should be as if it is to be streamed and hence no indexes written or duration written.</BLURB> +<DEFAULT>FALSE</DEFAULT> +</ARG> + +<ARG> +<NAME>GstMJ2Mux::trak-timescale</NAME> +<TYPE>guint</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>Track timescale</NICK> +<BLURB>Timescale to use for the tracks (units per second, 0 is automatic).</BLURB> +<DEFAULT>0</DEFAULT> +</ARG> + +<ARG> +<NAME>GstMJ2Mux::dts-method</NAME> +<TYPE>GstQTMuxDtsMethods</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>dts-method</NICK> +<BLURB>Method to determine DTS time.</BLURB> +<DEFAULT>delta/duration</DEFAULT> +</ARG> + +<ARG> <NAME>GstGPPMux::faststart</NAME> <TYPE>gboolean</TYPE> <RANGE></RANGE> @@ -22584,6 +22544,46 @@ </ARG> <ARG> +<NAME>GstGPPMux::fragment-duration</NAME> +<TYPE>guint</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>Fragment duration</NICK> +<BLURB>Fragment durations in ms (produce a fragmented file if > 0).</BLURB> +<DEFAULT>0</DEFAULT> +</ARG> + +<ARG> +<NAME>GstGPPMux::streamable</NAME> +<TYPE>gboolean</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>Streamable</NICK> +<BLURB>If set to true, the output should be as if it is to be streamed and hence no indexes written or duration written.</BLURB> +<DEFAULT>FALSE</DEFAULT> +</ARG> + +<ARG> +<NAME>GstGPPMux::trak-timescale</NAME> +<TYPE>guint</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>Track timescale</NICK> +<BLURB>Timescale to use for the tracks (units per second, 0 is automatic).</BLURB> +<DEFAULT>0</DEFAULT> +</ARG> + +<ARG> +<NAME>GstGPPMux::dts-method</NAME> +<TYPE>GstQTMuxDtsMethods</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>dts-method</NICK> +<BLURB>Method to determine DTS time.</BLURB> +<DEFAULT>delta/duration</DEFAULT> +</ARG> + +<ARG> <NAME>GstMP4Mux::faststart</NAME> <TYPE>gboolean</TYPE> <RANGE></RANGE> @@ -22644,6 +22644,46 @@ </ARG> <ARG> +<NAME>GstMP4Mux::fragment-duration</NAME> +<TYPE>guint</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>Fragment duration</NICK> +<BLURB>Fragment durations in ms (produce a fragmented file if > 0).</BLURB> +<DEFAULT>0</DEFAULT> +</ARG> + +<ARG> +<NAME>GstMP4Mux::streamable</NAME> +<TYPE>gboolean</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>Streamable</NICK> +<BLURB>If set to true, the output should be as if it is to be streamed and hence no indexes written or duration written.</BLURB> +<DEFAULT>FALSE</DEFAULT> +</ARG> + +<ARG> +<NAME>GstMP4Mux::trak-timescale</NAME> +<TYPE>guint</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>Track timescale</NICK> +<BLURB>Timescale to use for the tracks (units per second, 0 is automatic).</BLURB> +<DEFAULT>0</DEFAULT> +</ARG> + +<ARG> +<NAME>GstMP4Mux::dts-method</NAME> +<TYPE>GstQTMuxDtsMethods</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>dts-method</NICK> +<BLURB>Method to determine DTS time.</BLURB> +<DEFAULT>delta/duration</DEFAULT> +</ARG> + +<ARG> <NAME>GstQTMux::faststart</NAME> <TYPE>gboolean</TYPE> <RANGE></RANGE> @@ -22704,6 +22744,46 @@ </ARG> <ARG> +<NAME>GstQTMux::fragment-duration</NAME> +<TYPE>guint</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>Fragment duration</NICK> +<BLURB>Fragment durations in ms (produce a fragmented file if > 0).</BLURB> +<DEFAULT>0</DEFAULT> +</ARG> + +<ARG> +<NAME>GstQTMux::streamable</NAME> +<TYPE>gboolean</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>Streamable</NICK> +<BLURB>If set to true, the output should be as if it is to be streamed and hence no indexes written or duration written.</BLURB> +<DEFAULT>FALSE</DEFAULT> +</ARG> + +<ARG> +<NAME>GstQTMux::trak-timescale</NAME> +<TYPE>guint</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>Track timescale</NICK> +<BLURB>Timescale to use for the tracks (units per second, 0 is automatic).</BLURB> +<DEFAULT>0</DEFAULT> +</ARG> + +<ARG> +<NAME>GstQTMux::dts-method</NAME> +<TYPE>GstQTMuxDtsMethods</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>dts-method</NICK> +<BLURB>Method to determine DTS time.</BLURB> +<DEFAULT>delta/duration</DEFAULT> +</ARG> + +<ARG> <NAME>GstAudioresample::filter-length</NAME> <TYPE>gint</TYPE> <RANGE>>= 0</RANGE> @@ -22895,12 +22975,12 @@ <ARG> <NAME>GstCameraBin::zoom</NAME> -<TYPE>gint</TYPE> -<RANGE>[100,1000]</RANGE> +<TYPE>gfloat</TYPE> +<RANGE>[1,10]</RANGE> <FLAGS>rw</FLAGS> <NICK>Zoom</NICK> -<BLURB>The zoom. 100 for 1x, 200 for 2x and so on.</BLURB> -<DEFAULT>100</DEFAULT> +<BLURB>The zoom. 1.0 for 1x, 2.0 for 2x and so on.</BLURB> +<DEFAULT>1</DEFAULT> </ARG> <ARG> @@ -23020,7 +23100,7 @@ <FLAGS>rw</FLAGS> <NICK>Flags</NICK> <BLURB>Flags to control behaviour.</BLURB> -<DEFAULT>Enable source crop and scale|Enable scale for viewfinder|Enable colorspace conversion for still image</DEFAULT> +<DEFAULT>Enable source crop and scale|Enable scale for viewfinder|Enable audio conversion for video capture|Enable colorspace conversion for still image|Enable colorspace conversion for video capture</DEFAULT> </ARG> <ARG> @@ -23104,6 +23184,36 @@ </ARG> <ARG> +<NAME>GstCameraBin::idle</NAME> +<TYPE>gboolean</TYPE> +<RANGE></RANGE> +<FLAGS>r</FLAGS> +<NICK>Indicates if data is being processed (recording/capturing/saving)</NICK> +<BLURB>Indicates if data is being processed (recording/capturing/saving).</BLURB> +<DEFAULT>TRUE</DEFAULT> +</ARG> + +<ARG> +<NAME>GstCameraBin::preview-source-filter</NAME> +<TYPE>GstElement*</TYPE> +<RANGE></RANGE> +<FLAGS>rw</FLAGS> +<NICK>preview source filter element</NICK> +<BLURB>Optional preview source filter GStreamer element.</BLURB> +<DEFAULT></DEFAULT> +</ARG> + +<ARG> +<NAME>GstCameraBin::ready-for-capture</NAME> +<TYPE>gboolean</TYPE> +<RANGE></RANGE> +<FLAGS>r</FLAGS> +<NICK>Indicates if preparing a new capture is possible</NICK> +<BLURB>Indicates if preparing a new capture is possible.</BLURB> +<DEFAULT>TRUE</DEFAULT> +</ARG> + +<ARG> <NAME>GstDTMFSrc::interval</NAME> <TYPE>guint</TYPE> <RANGE>[10,50]</RANGE> @@ -23166,7 +23276,7 @@ <ARG> <NAME>GstRTPDTMFSrc::seqnum-offset</NAME> <TYPE>gint</TYPE> -<RANGE>>= -1</RANGE> +<RANGE>>= G_MAXULONG</RANGE> <FLAGS>rw</FLAGS> <NICK>Sequence number Offset</NICK> <BLURB>Offset to add to all outgoing seqnum (-1 = random).</BLURB> @@ -23196,7 +23306,7 @@ <ARG> <NAME>GstRTPDTMFSrc::timestamp-offset</NAME> <TYPE>gint</TYPE> -<RANGE>>= -1</RANGE> +<RANGE>>= G_MAXULONG</RANGE> <FLAGS>rw</FLAGS> <NICK>Timestamp Offset</NICK> <BLURB>Offset to add to all outgoing timestamps (-1 = random).</BLURB> @@ -23246,7 +23356,7 @@ <ARG> <NAME>GstRTPMux::seqnum-offset</NAME> <TYPE>gint</TYPE> -<RANGE>>= -1</RANGE> +<RANGE>>= G_MAXULONG</RANGE> <FLAGS>rw</FLAGS> <NICK>Sequence number Offset</NICK> <BLURB>Offset to add to all outgoing seqnum (-1 = random).</BLURB> @@ -23266,7 +23376,7 @@ <ARG> <NAME>GstRTPMux::timestamp-offset</NAME> <TYPE>gint</TYPE> -<RANGE>>= -1</RANGE> +<RANGE>>= G_MAXULONG</RANGE> <FLAGS>rw</FLAGS> <NICK>Timestamp Offset</NICK> <BLURB>Offset to add to all outgoing timestamps (-1 = random).</BLURB> @@ -23274,16 +23384,6 @@ </ARG> <ARG> -<NAME>GstValve::drop</NAME> -<TYPE>gboolean</TYPE> -<RANGE></RANGE> -<FLAGS>rw</FLAGS> -<NICK>Drops all buffers if TRUE</NICK> -<BLURB>If this property if TRUE, the element will drop all buffers, if its FALSE, it will let them through.</BLURB> -<DEFAULT>FALSE</DEFAULT> -</ARG> - -<ARG> <NAME>GstAutoConvert::factories</NAME> <TYPE>gpointer</TYPE> <RANGE></RANGE> @@ -26410,7 +26510,7 @@ <FLAGS>rw</FLAGS> <NICK>physics</NICK> <BLURB>water density: from 1 to 4.</BLURB> -<DEFAULT>8.20075e-304</DEFAULT> +<DEFAULT>4.63015e-299</DEFAULT> </ARG> <ARG> @@ -26450,7 +26550,7 @@ <FLAGS>rw</FLAGS> <NICK>splash</NICK> <BLURB>make a big splash in the center.</BLURB> -<DEFAULT>0</DEFAULT> +<DEFAULT>7.7486e-304</DEFAULT> </ARG> <ARG> @@ -26460,7 +26560,7 @@ <FLAGS>rw</FLAGS> <NICK>splash</NICK> <BLURB>make a big splash in the center.</BLURB> -<DEFAULT>4.77773e-299</DEFAULT> +<DEFAULT>4.62957e-299</DEFAULT> </ARG> <ARG> @@ -26490,7 +26590,7 @@ <FLAGS>rw</FLAGS> <NICK>ratiox</NICK> <BLURB>x-ratio.</BLURB> -<DEFAULT>8.0843e+44</DEFAULT> +<DEFAULT>2.31928e-310</DEFAULT> </ARG> <ARG> @@ -26500,7 +26600,7 @@ <FLAGS>rw</FLAGS> <NICK>ratioy</NICK> <BLURB>y-ratio.</BLURB> -<DEFAULT>9.3207e+68</DEFAULT> +<DEFAULT>2.31928e-310</DEFAULT> </ARG> <ARG> @@ -26510,7 +26610,7 @@ <FLAGS>rw</FLAGS> <NICK>DelayTime</NICK> <BLURB>the delay time.</BLURB> -<DEFAULT>1.18576e-322</DEFAULT> +<DEFAULT>0</DEFAULT> </ARG> <ARG> @@ -26910,7 +27010,7 @@ <FLAGS>rw</FLAGS> <NICK>lupscale</NICK> <BLURB>multiplier for upscaling edge brightness.</BLURB> -<DEFAULT>1.34037e-317</DEFAULT> +<DEFAULT>0</DEFAULT> </ARG> <ARG> @@ -27080,7 +27180,7 @@ <FLAGS>rw</FLAGS> <NICK>blend</NICK> <BLURB>blend factor.</BLURB> -<DEFAULT>7.75038e-304</DEFAULT> +<DEFAULT>-6.17056e+303</DEFAULT> </ARG> <ARG> @@ -27090,7 +27190,7 @@ <FLAGS>rw</FLAGS> <NICK>fader</NICK> <BLURB>the fader position.</BLURB> -<DEFAULT>5.12056e+199</DEFAULT> +<DEFAULT>7.7486e-304</DEFAULT> </ARG> <ARG> @@ -27270,7 +27370,7 @@ <FLAGS>rw</FLAGS> <NICK>HSync</NICK> <BLURB>the hsync offset.</BLURB> -<DEFAULT>2.07558e-316</DEFAULT> +<DEFAULT>2.38039e-316</DEFAULT> </ARG> <ARG> @@ -27620,7 +27720,7 @@ <FLAGS>rwx</FLAGS> <NICK>Default font effect</NICK> <BLURB>Whether to apply an effect to text by default, for increased readability.</BLURB> -<DEFAULT>none</DEFAULT> +<DEFAULT>outline</DEFAULT> </ARG> <ARG> @@ -28474,146 +28574,6 @@ </ARG> <ARG> -<NAME>GstRtpBin::do-lost</NAME> -<TYPE>gboolean</TYPE> -<RANGE></RANGE> -<FLAGS>rw</FLAGS> -<NICK>Do Lost</NICK> -<BLURB>Send an event downstream when a packet is lost.</BLURB> -<DEFAULT>FALSE</DEFAULT> -</ARG> - -<ARG> -<NAME>GstRtpBin::latency</NAME> -<TYPE>guint</TYPE> -<RANGE></RANGE> -<FLAGS>rw</FLAGS> -<NICK>Buffer latency in ms</NICK> -<BLURB>Default amount of ms to buffer in the jitterbuffers.</BLURB> -<DEFAULT>200</DEFAULT> -</ARG> - -<ARG> -<NAME>GstRtpBin::sdes</NAME> -<TYPE>GstStructure*</TYPE> -<RANGE></RANGE> -<FLAGS>rw</FLAGS> -<NICK>SDES</NICK> -<BLURB>The SDES items of this session.</BLURB> -<DEFAULT></DEFAULT> -</ARG> - -<ARG> -<NAME>GstRtpJitterBuffer::do-lost</NAME> -<TYPE>gboolean</TYPE> -<RANGE></RANGE> -<FLAGS>rw</FLAGS> -<NICK>Do Lost</NICK> -<BLURB>Send an event downstream when a packet is lost.</BLURB> -<DEFAULT>FALSE</DEFAULT> -</ARG> - -<ARG> -<NAME>GstRtpJitterBuffer::drop-on-latency</NAME> -<TYPE>gboolean</TYPE> -<RANGE></RANGE> -<FLAGS>rw</FLAGS> -<NICK>Drop buffers when maximum latency is reached</NICK> -<BLURB>Tells the jitterbuffer to never exceed the given latency in size.</BLURB> -<DEFAULT>FALSE</DEFAULT> -</ARG> - -<ARG> -<NAME>GstRtpJitterBuffer::latency</NAME> -<TYPE>guint</TYPE> -<RANGE></RANGE> -<FLAGS>rw</FLAGS> -<NICK>Buffer latency in ms</NICK> -<BLURB>Amount of ms to buffer.</BLURB> -<DEFAULT>200</DEFAULT> -</ARG> - -<ARG> -<NAME>GstRtpJitterBuffer::ts-offset</NAME> -<TYPE>gint64</TYPE> -<RANGE></RANGE> -<FLAGS>rw</FLAGS> -<NICK>Timestamp Offset</NICK> -<BLURB>Adjust buffer timestamps with offset in nanoseconds.</BLURB> -<DEFAULT>0</DEFAULT> -</ARG> - -<ARG> -<NAME>GstRtpSession::bandwidth</NAME> -<TYPE>gdouble</TYPE> -<RANGE>>= 0</RANGE> -<FLAGS>rw</FLAGS> -<NICK>Bandwidth</NICK> -<BLURB>The bandwidth of the session.</BLURB> -<DEFAULT>64000</DEFAULT> -</ARG> - -<ARG> -<NAME>GstRtpSession::internal-session</NAME> -<TYPE>RTPSession*</TYPE> -<RANGE></RANGE> -<FLAGS>r</FLAGS> -<NICK>Internal Session</NICK> -<BLURB>The internal RTPSession object.</BLURB> -<DEFAULT></DEFAULT> -</ARG> - -<ARG> -<NAME>GstRtpSession::ntp-ns-base</NAME> -<TYPE>guint64</TYPE> -<RANGE></RANGE> -<FLAGS>rw</FLAGS> -<NICK>NTP base time</NICK> -<BLURB>The NTP base time corresponding to running_time 0.</BLURB> -<DEFAULT>0</DEFAULT> -</ARG> - -<ARG> -<NAME>GstRtpSession::num-active-sources</NAME> -<TYPE>guint</TYPE> -<RANGE></RANGE> -<FLAGS>r</FLAGS> -<NICK>Num Active Sources</NICK> -<BLURB>The number of active sources in the session.</BLURB> -<DEFAULT>0</DEFAULT> -</ARG> - -<ARG> -<NAME>GstRtpSession::num-sources</NAME> -<TYPE>guint</TYPE> -<RANGE></RANGE> -<FLAGS>r</FLAGS> -<NICK>Num Sources</NICK> -<BLURB>The number of sources in the session.</BLURB> -<DEFAULT>0</DEFAULT> -</ARG> - -<ARG> -<NAME>GstRtpSession::rtcp-fraction</NAME> -<TYPE>gdouble</TYPE> -<RANGE>>= 0</RANGE> -<FLAGS>rw</FLAGS> -<NICK>RTCP Fraction</NICK> -<BLURB>The fraction of the bandwidth used for RTCP.</BLURB> -<DEFAULT>3000</DEFAULT> -</ARG> - -<ARG> -<NAME>GstRtpSession::sdes</NAME> -<TYPE>GstStructure*</TYPE> -<RANGE></RANGE> -<FLAGS>rw</FLAGS> -<NICK>SDES</NICK> -<BLURB>The SDES items of this session.</BLURB> -<DEFAULT></DEFAULT> -</ARG> - -<ARG> <NAME>GstSSim::gauss-sigma</NAME> <TYPE>gfloat</TYPE> <RANGE>[G_MINFLOAT,10]</RANGE> @@ -43118,12 +43078,22 @@ <TYPE>gboolean</TYPE> <RANGE></RANGE> <FLAGS>rw</FLAGS> -<NICK>mesage</NICK> +<NICK>message</NICK> <BLURB>Post a barcode message for each detected code.</BLURB> <DEFAULT>TRUE</DEFAULT> </ARG> <ARG> +<NAME>GstZBar::cache</NAME> +<TYPE>gboolean</TYPE> +<RANGE></RANGE> +<FLAGS>rw</FLAGS> +<NICK>cache</NICK> +<BLURB>Enable or disable the inter-image result cache.</BLURB> +<DEFAULT>FALSE</DEFAULT> +</ARG> + +<ARG> <NAME>GstQTMoovRecover::broken-input</NAME> <TYPE>gchar*</TYPE> <RANGE></RANGE> @@ -45754,6 +45724,36 @@ </ARG> <ARG> +<NAME>GstPhotography::image-preview-supported-caps</NAME> +<TYPE>GstCaps*</TYPE> +<RANGE></RANGE> +<FLAGS>r</FLAGS> +<NICK>Image preview supported caps</NICK> +<BLURB>Caps describing supported image preview formats.</BLURB> +<DEFAULT></DEFAULT> +</ARG> + +<ARG> +<NAME>GstPhotography::noise-reduction</NAME> +<TYPE>GstPhotographyNoiseReduction</TYPE> +<RANGE></RANGE> +<FLAGS>rw</FLAGS> +<NICK>Noise Reduction settings</NICK> +<BLURB>Which noise reduction modes are enabled (0 = disabled).</BLURB> +<DEFAULT></DEFAULT> +</ARG> + +<ARG> +<NAME>GstPhotography::zoom</NAME> +<TYPE>gfloat</TYPE> +<RANGE>[1,10]</RANGE> +<FLAGS>rw</FLAGS> +<NICK>Zoom property</NICK> +<BLURB>How much the resulted image will be zoomed.</BLURB> +<DEFAULT>1</DEFAULT> +</ARG> + +<ARG> <NAME>GstWaterRipple::amplitude</NAME> <TYPE>gdouble</TYPE> <RANGE></RANGE> @@ -45946,7 +45946,7 @@ <ARG> <NAME>GstVideoMaxRate::average-period</NAME> <TYPE>guint64</TYPE> -<RANGE>[1,G_MAXINT64]</RANGE> +<RANGE>[1,G_MAXLONG]</RANGE> <FLAGS>rw</FLAGS> <NICK>Period over which to average</NICK> <BLURB>Period over which to average the framerate (in ns).</BLURB> @@ -46114,6 +46114,36 @@ </ARG> <ARG> +<NAME>GstSolarize::end</NAME> +<TYPE>guint</TYPE> +<RANGE><= 256</RANGE> +<FLAGS>rw</FLAGS> +<NICK>End</NICK> +<BLURB>End parameter.</BLURB> +<DEFAULT>185</DEFAULT> +</ARG> + +<ARG> +<NAME>GstSolarize::start</NAME> +<TYPE>guint</TYPE> +<RANGE><= 256</RANGE> +<FLAGS>rw</FLAGS> +<NICK>Start</NICK> +<BLURB>Start parameter.</BLURB> +<DEFAULT>50</DEFAULT> +</ARG> + +<ARG> +<NAME>GstSolarize::threshold</NAME> +<TYPE>guint</TYPE> +<RANGE><= 256</RANGE> +<FLAGS>rw</FLAGS> +<NICK>Threshold</NICK> +<BLURB>Threshold parameter.</BLURB> +<DEFAULT>127</DEFAULT> +</ARG> + +<ARG> <NAME>GstExclusion::silent</NAME> <TYPE>gboolean</TYPE> <RANGE></RANGE> @@ -46124,6 +46154,16 @@ </ARG> <ARG> +<NAME>GstExclusion::factor</NAME> +<TYPE>guint</TYPE> +<RANGE><= 175</RANGE> +<FLAGS>rw</FLAGS> +<NICK>Factor</NICK> +<BLURB>Exclusion factor parameter.</BLURB> +<DEFAULT>175</DEFAULT> +</ARG> + +<ARG> <NAME>GstDodge::silent</NAME> <TYPE>gboolean</TYPE> <RANGE></RANGE> @@ -46144,6 +46184,16 @@ </ARG> <ARG> +<NAME>GstDilate::erode</NAME> +<TYPE>gboolean</TYPE> +<RANGE></RANGE> +<FLAGS>rw</FLAGS> +<NICK>Erode</NICK> +<BLURB>Erode parameter.</BLURB> +<DEFAULT>FALSE</DEFAULT> +</ARG> + +<ARG> <NAME>GstChromium::silent</NAME> <TYPE>gboolean</TYPE> <RANGE></RANGE> @@ -46154,6 +46204,26 @@ </ARG> <ARG> +<NAME>GstChromium::edge-a</NAME> +<TYPE>guint</TYPE> +<RANGE><= 256</RANGE> +<FLAGS>rw</FLAGS> +<NICK>Edge A</NICK> +<BLURB>First edge parameter.</BLURB> +<DEFAULT>200</DEFAULT> +</ARG> + +<ARG> +<NAME>GstChromium::edge-b</NAME> +<TYPE>guint</TYPE> +<RANGE><= 256</RANGE> +<FLAGS>rw</FLAGS> +<NICK>Edge B</NICK> +<BLURB>Second edge parameter.</BLURB> +<DEFAULT>1</DEFAULT> +</ARG> + +<ARG> <NAME>GstBurn::silent</NAME> <TYPE>gboolean</TYPE> <RANGE></RANGE> @@ -46164,6 +46234,16 @@ </ARG> <ARG> +<NAME>GstBurn::adjustment</NAME> +<TYPE>guint</TYPE> +<RANGE><= 256</RANGE> +<FLAGS>rw</FLAGS> +<NICK>Adjustment</NICK> +<BLURB>Adjustment parameter.</BLURB> +<DEFAULT>175</DEFAULT> +</ARG> + +<ARG> <NAME>GaussBlur::sigma</NAME> <TYPE>gdouble</TYPE> <RANGE>[-20,20]</RANGE> @@ -46304,6 +46384,36 @@ </ARG> <ARG> +<NAME>GstInterlace::allow-rff</NAME> +<TYPE>gboolean</TYPE> +<RANGE></RANGE> +<FLAGS>rw</FLAGS> +<NICK>Allow Repeat-First-Field flags</NICK> +<BLURB>Allow generation of buffers with RFF flag set, i.e., duration of 3 fields.</BLURB> +<DEFAULT>FALSE</DEFAULT> +</ARG> + +<ARG> +<NAME>GstInterlace::field-pattern</NAME> +<TYPE>GstInterlacePattern</TYPE> +<RANGE></RANGE> +<FLAGS>rw</FLAGS> +<NICK>Field pattern</NICK> +<BLURB>The output field pattern.</BLURB> +<DEFAULT>2:3</DEFAULT> +</ARG> + +<ARG> +<NAME>GstInterlace::pattern-offset</NAME> +<TYPE>guint</TYPE> +<RANGE><= 12</RANGE> +<FLAGS>rw</FLAGS> +<NICK>Pattern offset</NICK> +<BLURB>The initial field pattern offset. Counts from 0.</BLURB> +<DEFAULT>0</DEFAULT> +</ARG> + +<ARG> <NAME>Gsttextwrite::colorB</NAME> <TYPE>gint</TYPE> <RANGE>[0,255]</RANGE> @@ -46484,6 +46594,56 @@ </ARG> <ARG> +<NAME>Gstfacedetect::flags</NAME> +<TYPE>GstOpencvFaceDetectFlags</TYPE> +<RANGE></RANGE> +<FLAGS>rw</FLAGS> +<NICK>Flags</NICK> +<BLURB>Flags to cvHaarDetectObjects.</BLURB> +<DEFAULT></DEFAULT> +</ARG> + +<ARG> +<NAME>Gstfacedetect::min-neighbors</NAME> +<TYPE>gint</TYPE> +<RANGE>>= 0</RANGE> +<FLAGS>rw</FLAGS> +<NICK>Mininum neighbors</NICK> +<BLURB>Minimum number (minus 1) of neighbor rectangles that makes up an object.</BLURB> +<DEFAULT>3</DEFAULT> +</ARG> + +<ARG> +<NAME>Gstfacedetect::min-size-height</NAME> +<TYPE>gint</TYPE> +<RANGE>>= 0</RANGE> +<FLAGS>rw</FLAGS> +<NICK>Minimum size height</NICK> +<BLURB>Minimum window height size.</BLURB> +<DEFAULT>0</DEFAULT> +</ARG> + +<ARG> +<NAME>Gstfacedetect::min-size-width</NAME> +<TYPE>gint</TYPE> +<RANGE>>= 0</RANGE> +<FLAGS>rw</FLAGS> +<NICK>Minimum size width</NICK> +<BLURB>Minimum window width size.</BLURB> +<DEFAULT>0</DEFAULT> +</ARG> + +<ARG> +<NAME>Gstfacedetect::scale-factor</NAME> +<TYPE>gdouble</TYPE> +<RANGE>[1.1,10]</RANGE> +<FLAGS>rw</FLAGS> +<NICK>Scale factor</NICK> +<BLURB>Factor by which the windows is scaled after each scan.</BLURB> +<DEFAULT>1.1</DEFAULT> +</ARG> + +<ARG> <NAME>Gstfaceblur::profile</NAME> <TYPE>gchar*</TYPE> <RANGE></RANGE> @@ -46546,7 +46706,7 @@ <ARG> <NAME>GstCvSobel::x-order</NAME> <TYPE>gint</TYPE> -<RANGE>>= -1</RANGE> +<RANGE>>= G_MAXULONG</RANGE> <FLAGS>rw</FLAGS> <NICK>x order</NICK> <BLURB>Order of the derivative x.</BLURB> @@ -46556,7 +46716,7 @@ <ARG> <NAME>GstCvSobel::y-order</NAME> <TYPE>gint</TYPE> -<RANGE>>= -1</RANGE> +<RANGE>>= G_MAXULONG</RANGE> <FLAGS>rw</FLAGS> <NICK>y order</NICK> <BLURB>Order of the derivative y.</BLURB> @@ -46623,3 +46783,273 @@ <DEFAULT>3</DEFAULT> </ARG> +<ARG> +<NAME>GstRotate::angle</NAME> +<TYPE>gdouble</TYPE> +<RANGE></RANGE> +<FLAGS>rw</FLAGS> +<NICK>angle</NICK> +<BLURB>Angle at which the arc starts in radians.</BLURB> +<DEFAULT>0</DEFAULT> +</ARG> + +<ARG> +<NAME>GstJP2kDecimator::max-decomposition-levels</NAME> +<TYPE>gint</TYPE> +<RANGE>[G_MAXULONG,32]</RANGE> +<FLAGS>rw</FLAGS> +<NICK>Maximum Number of Decomposition Levels</NICK> +<BLURB>Maximum number of decomposition levels to keep (-1 == all).</BLURB> +<DEFAULT>-1</DEFAULT> +</ARG> + +<ARG> +<NAME>GstJP2kDecimator::max-layers</NAME> +<TYPE>gint</TYPE> +<RANGE>[0,65535]</RANGE> +<FLAGS>rw</FLAGS> +<NICK>Maximum Number of Layers</NICK> +<BLURB>Maximum number of layers to keep (0 == all).</BLURB> +<DEFAULT>0</DEFAULT> +</ARG> + +<ARG> +<NAME>GstISMLMux::faststart</NAME> +<TYPE>gboolean</TYPE> +<RANGE></RANGE> +<FLAGS>rw</FLAGS> +<NICK>Format file to faststart</NICK> +<BLURB>If the file should be formated for faststart (headers first). .</BLURB> +<DEFAULT>FALSE</DEFAULT> +</ARG> + +<ARG> +<NAME>GstISMLMux::faststart-file</NAME> +<TYPE>gchar*</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>File to use for storing buffers</NICK> +<BLURB>File that will be used temporarily to store data from the stream when creating a faststart file. If null a filepath will be created automatically.</BLURB> +<DEFAULT>NULL</DEFAULT> +</ARG> + +<ARG> +<NAME>GstISMLMux::fragment-duration</NAME> +<TYPE>guint</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>Fragment duration</NICK> +<BLURB>Fragment durations in ms (produce a fragmented file if > 0).</BLURB> +<DEFAULT>2000</DEFAULT> +</ARG> + +<ARG> +<NAME>GstISMLMux::large-file</NAME> +<TYPE>gboolean</TYPE> +<RANGE></RANGE> +<FLAGS>rw</FLAGS> +<NICK>Support for large files</NICK> +<BLURB>Uses 64bits to some fields instead of 32bits, providing support for large files.</BLURB> +<DEFAULT>FALSE</DEFAULT> +</ARG> + +<ARG> +<NAME>GstISMLMux::moov-recovery-file</NAME> +<TYPE>gchar*</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>File to store data for posterior moov atom recovery</NICK> +<BLURB>File to be used to store data for moov atom making movie file recovery possible in case of a crash during muxing. Null for disabled. (Experimental).</BLURB> +<DEFAULT>NULL</DEFAULT> +</ARG> + +<ARG> +<NAME>GstISMLMux::movie-timescale</NAME> +<TYPE>guint</TYPE> +<RANGE>>= 1</RANGE> +<FLAGS>rwx</FLAGS> +<NICK>Movie timescale</NICK> +<BLURB>Timescale to use in the movie (units per second).</BLURB> +<DEFAULT>1000</DEFAULT> +</ARG> + +<ARG> +<NAME>GstISMLMux::presentation-time</NAME> +<TYPE>gboolean</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>Include presentation-time info</NICK> +<BLURB>Calculate and include presentation/composition time (in addition to decoding time) (use with caution).</BLURB> +<DEFAULT>FALSE</DEFAULT> +</ARG> + +<ARG> +<NAME>GstISMLMux::streamable</NAME> +<TYPE>gboolean</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>Streamable</NICK> +<BLURB>If set to true, the output should be as if it is to be streamed and hence no indexes written or duration written.</BLURB> +<DEFAULT>FALSE</DEFAULT> +</ARG> + +<ARG> +<NAME>GstISMLMux::trak-timescale</NAME> +<TYPE>guint</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>Track timescale</NICK> +<BLURB>Timescale to use for the tracks (units per second, 0 is automatic).</BLURB> +<DEFAULT>0</DEFAULT> +</ARG> + +<ARG> +<NAME>GstISMLMux::dts-method</NAME> +<TYPE>GstQTMuxDtsMethods</TYPE> +<RANGE></RANGE> +<FLAGS>rwx</FLAGS> +<NICK>dts-method</NICK> +<BLURB>Method to determine DTS time.</BLURB> +<DEFAULT>delta/duration</DEFAULT> +</ARG> + +<ARG> +<NAME>GstChopMyData::max-size</NAME> +<TYPE>gint</TYPE> +<RANGE>>= 1</RANGE> +<FLAGS>rw</FLAGS> +<NICK>max-size</NICK> +<BLURB>Maximum size of outgoing buffers.</BLURB> +<DEFAULT>4096</DEFAULT> +</ARG> + +<ARG> +<NAME>GstChopMyData::min-size</NAME> +<TYPE>gint</TYPE> +<RANGE>>= 1</RANGE> +<FLAGS>rw</FLAGS> +<NICK>max-size</NICK> +<BLURB>Minimum size of outgoing buffers.</BLURB> +<DEFAULT>1</DEFAULT> +</ARG> + +<ARG> +<NAME>GstChopMyData::step-size</NAME> +<TYPE>gint</TYPE> +<RANGE>>= 1</RANGE> +<FLAGS>rw</FLAGS> +<NICK>step-size</NICK> +<BLURB>Step increment for random buffer sizes.</BLURB> +<DEFAULT>4096</DEFAULT> +</ARG> + +<ARG> +<NAME>GstChromaHold::target-b</NAME> +<TYPE>guint</TYPE> +<RANGE><= 255</RANGE> +<FLAGS>rw</FLAGS> +<NICK>Target Blue</NICK> +<BLURB>The Blue target.</BLURB> +<DEFAULT>0</DEFAULT> +</ARG> + +<ARG> +<NAME>GstChromaHold::target-g</NAME> +<TYPE>guint</TYPE> +<RANGE><= 255</RANGE> +<FLAGS>rw</FLAGS> +<NICK>Target Green</NICK> +<BLURB>The Green target.</BLURB> +<DEFAULT>0</DEFAULT> +</ARG> + +<ARG> +<NAME>GstChromaHold::target-r</NAME> +<TYPE>guint</TYPE> +<RANGE><= 255</RANGE> +<FLAGS>rw</FLAGS> +<NICK>Target Red</NICK> +<BLURB>The Red target.</BLURB> +<DEFAULT>255</DEFAULT> +</ARG> + +<ARG> +<NAME>GstChromaHold::tolerance</NAME> +<TYPE>guint</TYPE> +<RANGE><= 180</RANGE> +<FLAGS>rw</FLAGS> +<NICK>Tolerance</NICK> +<BLURB>Tolerance for the target color.</BLURB> +<DEFAULT>30</DEFAULT> +</ARG> + +<ARG> +<NAME>GstDVBSubOverlay::enable</NAME> +<TYPE>gboolean</TYPE> +<RANGE></RANGE> +<FLAGS>rw</FLAGS> +<NICK>Enable</NICK> +<BLURB>Enable rendering of subtitles.</BLURB> +<DEFAULT>TRUE</DEFAULT> +</ARG> + +<ARG> +<NAME>GstDVBSubOverlay::max-page-timeout</NAME> +<TYPE>gint</TYPE> +<RANGE>>= 0</RANGE> +<FLAGS>rw</FLAGS> +<NICK>max-page-timeout</NICK> +<BLURB>Limit maximum display time of a subtitle page (0 - disabled, value in seconds).</BLURB> +<DEFAULT>0</DEFAULT> +</ARG> + +<ARG> +<NAME>GstRsvgOverlay::data</NAME> +<TYPE>gchar*</TYPE> +<RANGE></RANGE> +<FLAGS>w</FLAGS> +<NICK>data</NICK> +<BLURB>SVG data.</BLURB> +<DEFAULT>""</DEFAULT> +</ARG> + +<ARG> +<NAME>GstRsvgOverlay::fit-to-frame</NAME> +<TYPE>gboolean</TYPE> +<RANGE></RANGE> +<FLAGS>rw</FLAGS> +<NICK>fit to frame</NICK> +<BLURB>Fit the SVG to fill the whole frame.</BLURB> +<DEFAULT>TRUE</DEFAULT> +</ARG> + +<ARG> +<NAME>GstRsvgOverlay::location</NAME> +<TYPE>gchar*</TYPE> +<RANGE></RANGE> +<FLAGS>w</FLAGS> +<NICK>location</NICK> +<BLURB>SVG file location.</BLURB> +<DEFAULT>""</DEFAULT> +</ARG> + +<ARG> +<NAME>GstRsvgOverlay::x</NAME> +<TYPE>gint</TYPE> +<RANGE>>= 0</RANGE> +<FLAGS>rw</FLAGS> +<NICK>x offset</NICK> +<BLURB>Specify an x offset.</BLURB> +<DEFAULT>0</DEFAULT> +</ARG> + +<ARG> +<NAME>GstRsvgOverlay::y</NAME> +<TYPE>gint</TYPE> +<RANGE>>= 0</RANGE> +<FLAGS>rw</FLAGS> +<NICK>y offset</NICK> +<BLURB>Specify a y offset.</BLURB> +<DEFAULT>0</DEFAULT> +</ARG> + diff --git a/docs/plugins/gst-plugins-bad-plugins.hierarchy b/docs/plugins/gst-plugins-bad-plugins.hierarchy index c8888c290..84322e7d5 100644 --- a/docs/plugins/gst-plugins-bad-plugins.hierarchy +++ b/docs/plugins/gst-plugins-bad-plugins.hierarchy @@ -3,11 +3,14 @@ GObject GstObject GstBus GstClock + GstSystemClock + GstAudioClock GstElement ADPCMDec ADPCMEnc GstAiffMux GstAiffParse + GstAmrWbEnc GstAsfMux GstAsfParse GstAssRender @@ -15,37 +18,55 @@ GObject GstAacParse GstAc3Parse GstAmrParse + GstDcaParse GstFlacParse - GstBaseMetadata - GstMetadataDemux - GstMetadataMux + GstMpegAudioParse GstBaseRTPDepayload GstRtpDTMFDepay GstBaseRTPPayload GstRtpAsfPay GstBaseSink - AlsaSPDIFSink + GstBaseAudioSink + GstAudioSink + GstApExSink + GstNasSink + GstSDLAudioSink GstChecksumSink GstDCCPClientSink GstDCCPServerSink GstFBDEVSink + GstSFSink GstShmSink GstVideoSink GstDfbVideoSink + GstSDLVideoSink + VdpSink GstBaseSrc GstDTMFSrc GstDataURISrc GstPushSrc GstDCCPClientSrc GstDCCPServerSrc + GstDc1394 GstDvbSrc GstMMS + GstMythtvSrc + GstNeonhttpSrc GstRfbSrc GstShmSrc GstVCDSrc + frei0r-src-ising0r + frei0r-src-lissajous0r + frei0r-src-nois0r + frei0r-src-onecol0r + frei0r-src-partik0l + frei0r-src-plasma GstRTPDTMFSrc + GstSFSrc GstBaseTransform GstAudioFilter + GstBPMDetect + GstOFA GstStereo GstBayer2RGB GstCogScale @@ -62,8 +83,10 @@ GObject GstVideoFilter GaussBlur GstBurn + GstChromaHold GstChromium GstColorEffects + GstCsp GstDilate GstDodge GstExclusion @@ -82,6 +105,7 @@ GObject GstFisheye GstMarble GstMirror + GstRotate GstSquare GstOpencvVideoFilter GstCvDilateErode @@ -92,20 +116,97 @@ GObject GstCvSmooth GstCvSobel Gstfacedetect + GstRsvgOverlay GstSolarize GstVideoAnalyse GstVideoDetect GstVideoMark + GstZBar + frei0r-filter-3-point-color-balance + frei0r-filter-3dflippo + frei0r-filter-b + frei0r-filter-baltan + frei0r-filter-bluescreen0r + frei0r-filter-brightness + frei0r-filter-bw0r + frei0r-filter-cartoon + frei0r-filter-color-distance + frei0r-filter-contrast0r + frei0r-filter-curves + frei0r-filter-dealygrab + frei0r-filter-delay0r + frei0r-filter-distort0r + frei0r-filter-edgeglow + frei0r-filter-equaliz0r + frei0r-filter-flippo + frei0r-filter-g + frei0r-filter-gamma + frei0r-filter-glow + frei0r-filter-hueshift0r + frei0r-filter-invert0r + frei0r-filter-k-means-clustering + frei0r-filter-lens-correction + frei0r-filter-letterb0xed + frei0r-filter-levels + frei0r-filter-luminance + frei0r-filter-mask0mate + frei0r-filter-nervous + frei0r-filter-nosync0r + frei0r-filter-perspective + frei0r-filter-pixeliz0r + frei0r-filter-primaries + frei0r-filter-r + frei0r-filter-rgb-parade + frei0r-filter-saturat0r + frei0r-filter-scale0tilt + frei0r-filter-scanline0r + frei0r-filter-sobel + frei0r-filter-squareblur + frei0r-filter-tehroxx0r + frei0r-filter-threelay0r + frei0r-filter-threshold0r + frei0r-filter-tint0r + frei0r-filter-transparency + frei0r-filter-twolay0r + frei0r-filter-vectorscope + frei0r-filter-vertigo + frei0r-filter-water + frei0r-filter-white-balance GstVideoMaxRate + GstBaseVideoCodec + GstBaseVideoDecoder + GstSchroDec + GstVP8Dec + GstBaseVideoEncoder + GstDiracEnc + GstSchroEnc + GstVP8Enc + GstBaseVideoParse + GstSchroParse GstBin DvbBaseBin GstAutoConvert + GstAutoVideoConvert GstFPSDisplaySink + GstGSettingsSwitchSink + GstGSettingsAudioSink + GstGSettingsVideoSink + GstGSettingsSwitchSrc + GstGSettingsAudioSrc + GstGSettingsVideoSrc GstPipeline GstCameraBin GstQTMoovRecover GstSDPDemux + RsnDvdBin + GstBz2dec + GstBz2enc + GstCDAudio GstCDXAParse + GstCeltDec + GstCeltEnc + GstChopMyData + GstDVBSubOverlay GstDVDSpu GstDtsDec GstFaac @@ -113,34 +214,44 @@ GObject GstFestival GstFreeze GstGPPMux + GstGSMDec + GstGSMEnc GstH264Parse + GstISMLMux GstId3BaseMux GstId3Mux - GstInputSelector GstInterlace GstInvtelecine GstIvfParse + GstJP2kDecimator GstJifMux GstJpegParse GstKateDec GstKateEnc GstKateParse GstKateTag + GstKateTiger GstLiveAdder GstMJ2Mux GstMP4Mux GstMSE GstMXFDemux GstMXFMux + GstMimDec + GstMimEnc + GstModPlug + GstMpeg2enc GstMpeg4VParse GstMpegPSDemux GstMpegTSDemux + GstMplex + GstMusepackDec GstMveDemux GstMveMux GstNsfDec GstNuvDemux - GstOutputSelector GstPcapParse + GstPitch GstPnmdec GstPnmenc GstQTMux @@ -156,18 +267,170 @@ GObject GstSegmentClip GstAudioSegmentClip GstVideoSegmentClip + GstSignalProcessor + ladspa-Chorus1 + ladspa-Chorus2 + ladspa-G2reverb + ladspa-Mvchpf-1 + ladspa-Mvclpf-1 + ladspa-Mvclpf-2 + ladspa-Mvclpf-3 + ladspa-Mvclpf-4 + ladspa-Phaser1 + ladspa-Phaser1+LFO + ladspa-TripleChorus + ladspa-alias + ladspa-allpass-c + ladspa-allpass-l + ladspa-allpass-n + ladspa-amPitchshift + ladspa-amp + ladspa-amp-mono + ladspa-amp-stereo + ladspa-analogueOsc + ladspa-artificialLatency + ladspa-autoPhaser + ladspa-bandpass-a-iir + ladspa-bandpass-iir + ladspa-bodeShifter + ladspa-bodeShifterCV + ladspa-butthigh-iir + ladspa-buttlow-iir + ladspa-bwxover-iir + ladspa-chebstortion + ladspa-comb + ladspa-comb-c + ladspa-comb-l + ladspa-comb-n + ladspa-combSplitter + ladspa-const + ladspa-crossoverDist + ladspa-dcRemove + ladspa-decay + ladspa-decimator + ladspa-declip + ladspa-delay-5s + ladspa-delay-c + ladspa-delay-l + ladspa-delay-n + ladspa-delayorama + ladspa-diode + ladspa-divider + ladspa-dj-eq + ladspa-dj-eq-mono + ladspa-djFlanger + ladspa-dysonCompress + ladspa-fadDelay + ladspa-fastLookaheadLimiter + ladspa-flanger + ladspa-fmOsc + ladspa-foldover + ladspa-fourByFourPole + ladspa-foverdrive + ladspa-freqTracker + ladspa-gate + ladspa-giantFlange + ladspa-gong + ladspa-gongBeater + ladspa-gsm + ladspa-gverb + ladspa-hardLimiter + ladspa-harmonicGen + ladspa-hermesFilter + ladspa-highpass-iir + ladspa-hilbert + ladspa-hpf + ladspa-imp + ladspa-impulse-fc + ladspa-inv + ladspa-karaoke + ladspa-lcrDelay + ladspa-lfoPhaser + ladspa-lowpass-iir + ladspa-lpf + ladspa-lsFilter + ladspa-matrixMSSt + ladspa-matrixSpatialiser + ladspa-matrixStMS + ladspa-mbeq + ladspa-modDelay + ladspa-multivoiceChorus + ladspa-noise-white + ladspa-notch-iir + ladspa-pitchScale + ladspa-pitchScaleHQ + ladspa-plate + ladspa-pointerCastDistortion + ladspa-rateShifter + ladspa-retroFlange + ladspa-revdelay + ladspa-ringmod-1i1o1l + ladspa-ringmod-2i1o + ladspa-satanMaximiser + ladspa-sc1 + ladspa-sc2 + ladspa-sc3 + ladspa-sc4 + ladspa-sc4m + ladspa-se4 + ladspa-shaper + ladspa-sifter + ladspa-sinCos + ladspa-sine-faaa + ladspa-sine-faac + ladspa-sine-fcaa + ladspa-sine-fcac + ladspa-singlePara + ladspa-sinusWavewrapper + ladspa-smoothDecimate + ladspa-split + ladspa-stepMuxer + ladspa-surroundEncoder + ladspa-svf + ladspa-tap-autopan + ladspa-tap-chorusflanger + ladspa-tap-deesser + ladspa-tap-doubler + ladspa-tap-dynamics-m + ladspa-tap-dynamics-st + ladspa-tap-equalizer + ladspa-tap-equalizer-bw + ladspa-tap-limiter + ladspa-tap-pinknoise + ladspa-tap-pitch + ladspa-tap-reflector + ladspa-tap-reverb + ladspa-tap-rotspeak + ladspa-tap-sigmoid + ladspa-tap-stereo-echo + ladspa-tap-tremolo + ladspa-tap-tubewarmth + ladspa-tap-vibrato + ladspa-tapeDelay + ladspa-transient + ladspa-triplePara + ladspa-valve + ladspa-valveRect + ladspa-vynil + ladspa-waveTerrain + ladspa-xfade + ladspa-xfade4 + ladspa-zm1 GstSirenDec GstSirenEnc GstSpeed GstSrtEnc + GstTRM GstTemplateMatch GstTtaDec GstTtaParse GstVMncDec - GstValve GstVcdParse + GstVdpVideoPostProcess + GstWildmidi GstXvidDec GstXvidEnc + GstY4mDec Gstedgedetect Gstfaceblur Gstpyramidsegment @@ -176,8 +439,46 @@ GObject MpegTSParse MpegTsMux MpegVideoParse + SatBaseVideoDecoder + GstVdpDecoder + GstVdpH264Dec + GstVdpMpeg4Dec + GstVdpMpegDec + frei0r-mixer-addition + frei0r-mixer-alpha-injection + frei0r-mixer-alphaatop + frei0r-mixer-alphain + frei0r-mixer-alphaout + frei0r-mixer-alphaover + frei0r-mixer-alphaxor + frei0r-mixer-blend + frei0r-mixer-burn + frei0r-mixer-color-only + frei0r-mixer-composition + frei0r-mixer-darken + frei0r-mixer-difference + frei0r-mixer-divide + frei0r-mixer-dodge + frei0r-mixer-grain-extract + frei0r-mixer-grain-merge + frei0r-mixer-hardlight + frei0r-mixer-hue + frei0r-mixer-lighten + frei0r-mixer-multiply + frei0r-mixer-overlay + frei0r-mixer-rgb + frei0r-mixer-saturation + frei0r-mixer-screen + frei0r-mixer-softlight + frei0r-mixer-subtract + frei0r-mixer-uv-map + frei0r-mixer-value + frei0r-mixer-xfade0r GstPad + GstVdpOutputSrcPad + GstVdpVideoSrcPad GstPadTemplate + GstSignalProcessorPadTemplate GstPlugin GstPluginFeature GstElementFactory @@ -185,9 +486,11 @@ GObject GstTypeFindFactory GstRegistry GstRingBuffer + GstAudioSinkRingBuffer GstTask GstTaskPool GstSignalObject + GstVdpDevice MpegTsPatInfo MpegTsPmtInfo GInterface @@ -195,9 +498,11 @@ GInterface GstChildProxy GstColorBalance GstImplementsInterface + GstMixer GstNavigation GstPhotography GstPreset GstTagSetter GstURIHandler + GstXOverlay MXFDescriptiveMetadataFrameworkInterface diff --git a/docs/plugins/gst-plugins-bad-plugins.interfaces b/docs/plugins/gst-plugins-bad-plugins.interfaces index a135859ac..bfa93f055 100644 --- a/docs/plugins/gst-plugins-bad-plugins.interfaces +++ b/docs/plugins/gst-plugins-bad-plugins.interfaces @@ -1,25 +1,44 @@ GstBin GstChildProxy GstPipeline GstChildProxy +GstCameraBin GstChildProxy GstImplementsInterface GstColorBalance GstTagSetter GstQTMoovRecover GstChildProxy -GstCameraBin GstChildProxy GstImplementsInterface GstColorBalance GstTagSetter GstPhotography +GstGSettingsSwitchSink GstChildProxy +GstGSettingsAudioSink GstChildProxy +GstGSettingsVideoSink GstChildProxy +GstGSettingsSwitchSrc GstChildProxy +GstGSettingsAudioSrc GstChildProxy +GstGSettingsVideoSrc GstChildProxy +RsnDvdBin GstChildProxy GstURIHandler DvbBaseBin GstChildProxy GstURIHandler -GstSDPDemux GstChildProxy GstAutoConvert GstChildProxy +GstAutoVideoConvert GstChildProxy +GstSDPDemux GstChildProxy GstFPSDisplaySink GstChildProxy -GstXvidEnc GstPreset +GstMpeg2enc GstPreset +GstSDLVideoSink GstImplementsInterface GstXOverlay GstNavigation GstDfbVideoSink GstImplementsInterface GstNavigation GstColorBalance -GstKateEnc GstTagSetter -GstKateTag GstTagSetter +VdpSink GstImplementsInterface GstNavigation GstXOverlay +GstApExSink GstImplementsInterface GstMixer +GstCeltEnc GstTagSetter GstPreset +GstCDAudio GstURIHandler +GstMythtvSrc GstURIHandler GstMMS GstURIHandler +GstNeonhttpSrc GstURIHandler GstVCDSrc GstURIHandler GstDataURISrc GstURIHandler -GstMetadataMux GstTagSetter +GstAmrWbEnc GstPreset GstFaac GstPreset -GstAsfMux GstTagSetter +GstXvidEnc GstPreset +GstDiracEnc GstPreset +GstVP8Enc GstTagSetter GstPreset +GstKateEnc GstTagSetter +GstKateTag GstTagSetter +GstJifMux GstTagSetter GstId3BaseMux GstTagSetter GstId3Mux GstTagSetter -GstJifMux GstTagSetter GstQTMux GstTagSetter GstMP4Mux GstTagSetter +GstISMLMux GstTagSetter GstGPPMux GstTagSetter GstMJ2Mux GstTagSetter +GstAsfMux GstTagSetter diff --git a/docs/plugins/gst-plugins-bad-plugins.prerequisites b/docs/plugins/gst-plugins-bad-plugins.prerequisites index e9203c176..f55006018 100644 --- a/docs/plugins/gst-plugins-bad-plugins.prerequisites +++ b/docs/plugins/gst-plugins-bad-plugins.prerequisites @@ -1,6 +1,8 @@ GstChildProxy GstObject GstImplementsInterface GstElement -GstColorBalance GstImplementsInterface GstElement +GstXOverlay GstImplementsInterface GstElement GstTagSetter GstElement -GstPhotography GstImplementsInterface GstElement +GstColorBalance GstImplementsInterface GstElement +GstMixer GstImplementsInterface GstElement MXFDescriptiveMetadataFrameworkInterface MXFDescriptiveMetadata +GstPhotography GstImplementsInterface GstElement diff --git a/docs/plugins/inspect/plugin-adpcmdec.xml b/docs/plugins/inspect/plugin-adpcmdec.xml index d54ade1e2..fba62a5cf 100644 --- a/docs/plugins/inspect/plugin-adpcmdec.xml +++ b/docs/plugins/inspect/plugin-adpcmdec.xml @@ -3,7 +3,7 @@ <description>ADPCM decoder</description> <filename>../../gst/adpcmdec/.libs/libgstadpcmdec.so</filename> <basename>libgstadpcmdec.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-adpcmenc.xml b/docs/plugins/inspect/plugin-adpcmenc.xml index 0fc939eea..acfa8c7c1 100644 --- a/docs/plugins/inspect/plugin-adpcmenc.xml +++ b/docs/plugins/inspect/plugin-adpcmenc.xml @@ -3,7 +3,7 @@ <description>ADPCM encoder</description> <filename>../../gst/adpcmenc/.libs/libgstadpcmenc.so</filename> <basename>libgstadpcmenc.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-aiff.xml b/docs/plugins/inspect/plugin-aiff.xml index a8c33c11d..f616fff13 100644 --- a/docs/plugins/inspect/plugin-aiff.xml +++ b/docs/plugins/inspect/plugin-aiff.xml @@ -3,7 +3,7 @@ <description>Create and parse Audio Interchange File Format (AIFF) files</description> <filename>../../gst/aiff/.libs/libgstaiff.so</filename> <basename>libgstaiff.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-amrwbenc.xml b/docs/plugins/inspect/plugin-amrwbenc.xml index 27fefc0a7..e70e68bdf 100644 --- a/docs/plugins/inspect/plugin-amrwbenc.xml +++ b/docs/plugins/inspect/plugin-amrwbenc.xml @@ -3,7 +3,7 @@ <description>Adaptive Multi-Rate Wide-Band Encoder</description> <filename>../../ext/amrwbenc/.libs/libgstamrwbenc.so</filename> <basename>libgstamrwbenc.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>unknown</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-apexsink.xml b/docs/plugins/inspect/plugin-apexsink.xml index ab3db8a88..95dcedc7d 100644 --- a/docs/plugins/inspect/plugin-apexsink.xml +++ b/docs/plugins/inspect/plugin-apexsink.xml @@ -3,7 +3,7 @@ <description>Apple AirPort Express Plugin</description> <filename>../../ext/apexsink/.libs/libgstapexsink.so</filename> <basename>libgstapexsink.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-asfmux.xml b/docs/plugins/inspect/plugin-asfmux.xml index 6369c80d2..b9c21a78c 100644 --- a/docs/plugins/inspect/plugin-asfmux.xml +++ b/docs/plugins/inspect/plugin-asfmux.xml @@ -3,11 +3,11 @@ <description>ASF Muxer Plugin</description> <filename>../../gst/asfmux/.libs/libgstasfmux.so</filename> <basename>libgstasfmux.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> - <package>gsoc2009 package</package> - <origin>embedded.ufcg.edu.br</origin> + <package>GStreamer Bad Plug-ins git</package> + <origin>Unknown package origin</origin> <elements> <element> <name>asfmux</name> diff --git a/docs/plugins/inspect/plugin-assrender.xml b/docs/plugins/inspect/plugin-assrender.xml index 116548359..6786697f1 100644 --- a/docs/plugins/inspect/plugin-assrender.xml +++ b/docs/plugins/inspect/plugin-assrender.xml @@ -3,7 +3,7 @@ <description>ASS/SSA subtitle renderer</description> <filename>../../ext/assrender/.libs/libgstassrender.so</filename> <basename>libgstassrender.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-audioparsersbad.xml b/docs/plugins/inspect/plugin-audioparsersbad.xml index dd9373154..eb908af26 100644 --- a/docs/plugins/inspect/plugin-audioparsersbad.xml +++ b/docs/plugins/inspect/plugin-audioparsersbad.xml @@ -3,7 +3,7 @@ <description>audioparsers</description> <filename>../../gst/audioparsers/.libs/libgstaudioparsersbad.so</filename> <basename>libgstaudioparsersbad.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> @@ -41,13 +41,13 @@ <name>sink</name> <direction>sink</direction> <presence>always</presence> - <details>audio/x-ac3, framed=(boolean)false; audio/ac3, framed=(boolean)false</details> + <details>audio/x-ac3, framed=(boolean)false; audio/x-eac3, framed=(boolean)false; audio/ac3, framed=(boolean)false</details> </caps> <caps> <name>src</name> <direction>source</direction> <presence>always</presence> - <details>audio/x-ac3, framed=(boolean)true, channels=(int)[ 1, 6 ], rate=(int)[ 32000, 48000 ]; audio/ac3, framed=(boolean)true, channels=(int)[ 1, 6 ], rate=(int)[ 32000, 48000 ]</details> + <details>audio/x-ac3, framed=(boolean)true, channels=(int)[ 1, 6 ], rate=(int)[ 32000, 48000 ]; audio/x-eac3, framed=(boolean)true, channels=(int)[ 1, 6 ], rate=(int)[ 32000, 48000 ]</details> </caps> </pads> </element> @@ -73,6 +73,27 @@ </pads> </element> <element> + <name>dcaparse</name> + <longname>DTS Coherent Acoustics audio stream parser</longname> + <class>Codec/Parser/Audio</class> + <description>DCA parser</description> + <author>Tim-Philipp Müller <tim centricular net></author> + <pads> + <caps> + <name>sink</name> + <direction>sink</direction> + <presence>always</presence> + <details>audio/x-dts, framed=(boolean)false</details> + </caps> + <caps> + <name>src</name> + <direction>source</direction> + <presence>always</presence> + <details>audio/x-dts, framed=(boolean)true, channels=(int)[ 1, 8 ], rate=(int)[ 8000, 192000 ]</details> + </caps> + </pads> + </element> + <element> <name>flacparse</name> <longname>FLAC audio parser</longname> <class>Codec/Parser/Audio</class> @@ -93,5 +114,26 @@ </caps> </pads> </element> + <element> + <name>mpegaudioparse</name> + <longname>MPEG1 Audio Parser</longname> + <class>Codec/Parser/Audio</class> + <description>Parses and frames mpeg1 audio streams (levels 1-3), provides seek</description> + <author>Jan Schmidt <thaytan@mad.scientist.com>,Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk></author> + <pads> + <caps> + <name>sink</name> + <direction>sink</direction> + <presence>always</presence> + <details>audio/mpeg, mpegversion=(int)1, parsed=(boolean)false</details> + </caps> + <caps> + <name>src</name> + <direction>source</direction> + <presence>always</presence> + <details>audio/mpeg, mpegversion=(int)1, layer=(int)[ 1, 3 ], rate=(int)[ 8000, 48000 ], channels=(int)[ 1, 2 ], parsed=(boolean)true</details> + </caps> + </pads> + </element> </elements> </plugin>
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-autoconvert.xml b/docs/plugins/inspect/plugin-autoconvert.xml index ad4ff9bcb..0dd7873c1 100644 --- a/docs/plugins/inspect/plugin-autoconvert.xml +++ b/docs/plugins/inspect/plugin-autoconvert.xml @@ -3,7 +3,7 @@ <description>Selects convertor element based on caps</description> <filename>../../gst/autoconvert/.libs/libgstautoconvert.so</filename> <basename>libgstautoconvert.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> @@ -30,5 +30,26 @@ </caps> </pads> </element> + <element> + <name>autovideoconvert</name> + <longname>Select color space convertor based on caps</longname> + <class>Generic/Bin</class> + <description>Selects the right color space convertor based on the caps</description> + <author>Benjamin Gaignard <benjamin.gaignard@stericsson.com></author> + <pads> + <caps> + <name>sink</name> + <direction>sink</direction> + <presence>always</presence> + <details>ANY</details> + </caps> + <caps> + <name>src</name> + <direction>source</direction> + <presence>always</presence> + <details>ANY</details> + </caps> + </pads> + </element> </elements> </plugin>
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-bayer.xml b/docs/plugins/inspect/plugin-bayer.xml index 597f9585d..0bb15c67f 100644 --- a/docs/plugins/inspect/plugin-bayer.xml +++ b/docs/plugins/inspect/plugin-bayer.xml @@ -3,7 +3,7 @@ <description>Elements to convert Bayer images</description> <filename>../../gst/bayer/.libs/libgstbayer.so</filename> <basename>libgstbayer.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> @@ -20,7 +20,7 @@ <name>sink</name> <direction>sink</direction> <presence>always</presence> - <details>video/x-raw-bayer, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ]</details> + <details>video/x-raw-bayer, format=(string){ bggr, grbg, gbrg, rggb }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> <caps> <name>src</name> diff --git a/docs/plugins/inspect/plugin-bz2.xml b/docs/plugins/inspect/plugin-bz2.xml index b07dc7a38..a5af38ea4 100644 --- a/docs/plugins/inspect/plugin-bz2.xml +++ b/docs/plugins/inspect/plugin-bz2.xml @@ -3,7 +3,7 @@ <description>Compress or decompress streams</description> <filename>../../ext/bz2/.libs/libgstbz2.so</filename> <basename>libgstbz2.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-camerabin.xml b/docs/plugins/inspect/plugin-camerabin.xml index 0609afa40..91a386f10 100644 --- a/docs/plugins/inspect/plugin-camerabin.xml +++ b/docs/plugins/inspect/plugin-camerabin.xml @@ -3,7 +3,7 @@ <description>High level api for DC (Digital Camera) application</description> <filename>../../gst/camerabin/.libs/libgstcamerabin.so</filename> <basename>libgstcamerabin.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-cdaudio.xml b/docs/plugins/inspect/plugin-cdaudio.xml index 86ed0c8d8..b28ef3498 100644 --- a/docs/plugins/inspect/plugin-cdaudio.xml +++ b/docs/plugins/inspect/plugin-cdaudio.xml @@ -3,7 +3,7 @@ <description>Play CD audio through the CD Drive</description> <filename>../../ext/cdaudio/.libs/libgstcdaudio.so</filename> <basename>libgstcdaudio.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-cdxaparse.xml b/docs/plugins/inspect/plugin-cdxaparse.xml index b8e4da81f..a9480090e 100644 --- a/docs/plugins/inspect/plugin-cdxaparse.xml +++ b/docs/plugins/inspect/plugin-cdxaparse.xml @@ -3,7 +3,7 @@ <description>Parse a .dat file (VCD) into raw mpeg1</description> <filename>../../gst/cdxaparse/.libs/libgstcdxaparse.so</filename> <basename>libgstcdxaparse.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-celt.xml b/docs/plugins/inspect/plugin-celt.xml index 8cee66746..8b359667c 100644 --- a/docs/plugins/inspect/plugin-celt.xml +++ b/docs/plugins/inspect/plugin-celt.xml @@ -3,7 +3,7 @@ <description>CELT plugin library</description> <filename>../../ext/celt/.libs/libgstcelt.so</filename> <basename>libgstcelt.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-cog.xml b/docs/plugins/inspect/plugin-cog.xml index 627167002..bf0fd83dd 100644 --- a/docs/plugins/inspect/plugin-cog.xml +++ b/docs/plugins/inspect/plugin-cog.xml @@ -3,7 +3,7 @@ <description>Cog plugin</description> <filename>../../ext/cog/.libs/libgstcog.so</filename> <basename>libgstcog.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-coloreffects.xml b/docs/plugins/inspect/plugin-coloreffects.xml index 39760d45a..99d3a37b2 100644 --- a/docs/plugins/inspect/plugin-coloreffects.xml +++ b/docs/plugins/inspect/plugin-coloreffects.xml @@ -3,13 +3,34 @@ <description>Color Look-up Table filters</description> <filename>../../gst/coloreffects/.libs/libgstcoloreffects.so</filename> <basename>libgstcoloreffects.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> <origin>Unknown package origin</origin> <elements> <element> + <name>chromahold</name> + <longname>Chroma hold filter</longname> + <class>Filter/Effect/Video</class> + <description>Removes all color information except for one color</description> + <author>Sebastian Dröge <sebastian.droege@collabora.co.uk></author> + <pads> + <caps> + <name>sink</name> + <direction>sink</direction> + <presence>always</presence> + <details>video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> + </caps> + <caps> + <name>src</name> + <direction>source</direction> + <presence>always</presence> + <details>video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> + </caps> + </pads> + </element> + <element> <name>coloreffects</name> <longname>Color Look-up Table filter</longname> <class>Filter/Effect/Video</class> diff --git a/docs/plugins/inspect/plugin-colorspace.xml b/docs/plugins/inspect/plugin-colorspace.xml new file mode 100644 index 000000000..d8eeb1cc6 --- /dev/null +++ b/docs/plugins/inspect/plugin-colorspace.xml @@ -0,0 +1,34 @@ +<plugin> + <name>colorspace</name> + <description>Colorspace conversion</description> + <filename>../../gst/colorspace/.libs/libgstcolorspace.so</filename> + <basename>libgstcolorspace.so</basename> + <version>0.10.21.1</version> + <license>LGPL</license> + <source>gst-plugins-bad</source> + <package></package> + <origin></origin> + <elements> + <element> + <name>colorspace</name> + <longname> Colorspace converter</longname> + <class>Filter/Converter/Video</class> + <description>Converts video from one colorspace to another</description> + <author>GStreamer maintainers <gstreamer-devel@lists.sourceforge.net></author> + <pads> + <caps> + <name>sink</name> + <direction>sink</direction> + <presence>always</presence> + <details>video/x-raw-yuv, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ], format=(fourcc){ I420, NV12, NV21, YV12, YUY2, Y42B, Y444, YUV9, YVU9, Y41B, Y800, Y8 , GREY, Y16 , UYVY, YVYU, IYU1, v308, AYUV, v210, A420 }; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)16, endianness=(int)1234, red_mask=(int)63488, green_mask=(int)2016, blue_mask=(int)31, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)16, endianness=(int)1234, red_mask=(int)31, green_mask=(int)2016, blue_mask=(int)63488, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)15, endianness=(int)1234, red_mask=(int)31744, green_mask=(int)992, blue_mask=(int)31, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)15, endianness=(int)1234, red_mask=(int)31, green_mask=(int)992, blue_mask=(int)31744, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)4321, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)1234, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> + </caps> + <caps> + <name>src</name> + <direction>source</direction> + <presence>always</presence> + <details>video/x-raw-yuv, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ], format=(fourcc){ I420, NV12, NV21, YV12, YUY2, Y42B, Y444, YUV9, YVU9, Y41B, Y800, Y8 , GREY, Y16 , UYVY, YVYU, IYU1, v308, AYUV, v210, A420 }; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)16, endianness=(int)1234, red_mask=(int)63488, green_mask=(int)2016, blue_mask=(int)31, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)16, endianness=(int)1234, red_mask=(int)31, green_mask=(int)2016, blue_mask=(int)63488, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)15, endianness=(int)1234, red_mask=(int)31744, green_mask=(int)992, blue_mask=(int)31, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)15, endianness=(int)1234, red_mask=(int)31, green_mask=(int)992, blue_mask=(int)31744, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)4321, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)1234, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> + </caps> + </pads> + </element> + </elements> +</plugin>
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-dataurisrc.xml b/docs/plugins/inspect/plugin-dataurisrc.xml index 1ae558bdf..8945d1e04 100644 --- a/docs/plugins/inspect/plugin-dataurisrc.xml +++ b/docs/plugins/inspect/plugin-dataurisrc.xml @@ -3,7 +3,7 @@ <description>data: URI source</description> <filename>../../gst/dataurisrc/.libs/libgstdataurisrc.so</filename> <basename>libgstdataurisrc.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-dc1394.xml b/docs/plugins/inspect/plugin-dc1394.xml index cae9bfd91..c58f73244 100644 --- a/docs/plugins/inspect/plugin-dc1394.xml +++ b/docs/plugins/inspect/plugin-dc1394.xml @@ -3,7 +3,7 @@ <description>1394 IIDC Video Source</description> <filename>../../ext/dc1394/.libs/libgstdc1394.so</filename> <basename>libgstdc1394.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-dccp.xml b/docs/plugins/inspect/plugin-dccp.xml index 4972b5e22..3455b2463 100644 --- a/docs/plugins/inspect/plugin-dccp.xml +++ b/docs/plugins/inspect/plugin-dccp.xml @@ -3,7 +3,7 @@ <description>transfer data over the network via DCCP.</description> <filename>../../gst/dccp/.libs/libgstdccp.so</filename> <basename>libgstdccp.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>DCCP</package> diff --git a/docs/plugins/inspect/plugin-debugutilsbad.xml b/docs/plugins/inspect/plugin-debugutilsbad.xml index 70f7ffded..f8e716df4 100644 --- a/docs/plugins/inspect/plugin-debugutilsbad.xml +++ b/docs/plugins/inspect/plugin-debugutilsbad.xml @@ -3,7 +3,7 @@ <description>Collection of elements that may or may not be useful for debugging</description> <filename>../../gst/debugutils/.libs/libgstdebugutilsbad.so</filename> <basename>libgstdebugutilsbad.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> @@ -31,6 +31,27 @@ </pads> </element> <element> + <name>chopmydata</name> + <longname>FIXME</longname> + <class>Generic</class> + <description>FIXME</description> + <author>David Schleef <ds@schleef.org></author> + <pads> + <caps> + <name>sink</name> + <direction>sink</direction> + <presence>always</presence> + <details>ANY</details> + </caps> + <caps> + <name>src</name> + <direction>source</direction> + <presence>always</presence> + <details>ANY</details> + </caps> + </pads> + </element> + <element> <name>fpsdisplaysink</name> <longname>Measure and show framerate on videosink</longname> <class>Sink/Video</class> diff --git a/docs/plugins/inspect/plugin-dfbvideosink.xml b/docs/plugins/inspect/plugin-dfbvideosink.xml index 5c144291c..390dfbe72 100644 --- a/docs/plugins/inspect/plugin-dfbvideosink.xml +++ b/docs/plugins/inspect/plugin-dfbvideosink.xml @@ -3,7 +3,7 @@ <description>DirectFB video output plugin</description> <filename>../../ext/directfb/.libs/libgstdfbvideosink.so</filename> <basename>libgstdfbvideosink.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-dirac.xml b/docs/plugins/inspect/plugin-dirac.xml index 802141c47..0fd1f0522 100644 --- a/docs/plugins/inspect/plugin-dirac.xml +++ b/docs/plugins/inspect/plugin-dirac.xml @@ -3,7 +3,7 @@ <description>Dirac plugin</description> <filename>../../ext/dirac/.libs/libgstdirac.so</filename> <basename>libgstdirac.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-dtmf.xml b/docs/plugins/inspect/plugin-dtmf.xml index 92e5c83a4..f44eb4463 100644 --- a/docs/plugins/inspect/plugin-dtmf.xml +++ b/docs/plugins/inspect/plugin-dtmf.xml @@ -3,7 +3,7 @@ <description>DTMF plugins</description> <filename>../../gst/dtmf/.libs/libgstdtmf.so</filename> <basename>libgstdtmf.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-dtsdec.xml b/docs/plugins/inspect/plugin-dtsdec.xml index 82668fe7f..6b9fb5a00 100644 --- a/docs/plugins/inspect/plugin-dtsdec.xml +++ b/docs/plugins/inspect/plugin-dtsdec.xml @@ -3,7 +3,7 @@ <description>Decodes DTS audio streams</description> <filename>../../ext/dts/.libs/libgstdtsdec.so</filename> <basename>libgstdtsdec.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>GPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-dvb.xml b/docs/plugins/inspect/plugin-dvb.xml index 5042cff9b..ade259629 100644 --- a/docs/plugins/inspect/plugin-dvb.xml +++ b/docs/plugins/inspect/plugin-dvb.xml @@ -3,7 +3,7 @@ <description>DVB elements</description> <filename>../../sys/dvb/.libs/libgstdvb.so</filename> <basename>libgstdvb.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-dvbsuboverlay.xml b/docs/plugins/inspect/plugin-dvbsuboverlay.xml new file mode 100644 index 000000000..2341db716 --- /dev/null +++ b/docs/plugins/inspect/plugin-dvbsuboverlay.xml @@ -0,0 +1,40 @@ +<plugin> + <name>dvbsuboverlay</name> + <description>DVB subtitle renderer</description> + <filename>../../gst/dvbsuboverlay/.libs/libgstdvbsuboverlay.so</filename> + <basename>libgstdvbsuboverlay.so</basename> + <version>0.10.21.1</version> + <license>LGPL</license> + <source>gst-plugins-bad</source> + <package>GStreamer Bad Plug-ins git</package> + <origin>Unknown package origin</origin> + <elements> + <element> + <name>dvbsuboverlay</name> + <longname>DVB Subtitles Overlay</longname> + <class>Mixer/Video/Overlay/Subtitle</class> + <description>Renders DVB subtitles</description> + <author>Mart Raudsepp <mart.raudsepp@collabora.co.uk></author> + <pads> + <caps> + <name>text_sink</name> + <direction>sink</direction> + <presence>always</presence> + <details>subpicture/x-dvb</details> + </caps> + <caps> + <name>video_sink</name> + <direction>sink</direction> + <presence>always</presence> + <details>video/x-raw-yuv, format=(fourcc)I420, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> + </caps> + <caps> + <name>src</name> + <direction>source</direction> + <presence>always</presence> + <details>video/x-raw-yuv, format=(fourcc)I420, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> + </caps> + </pads> + </element> + </elements> +</plugin>
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-dvdspu.xml b/docs/plugins/inspect/plugin-dvdspu.xml index 596f920f5..17b178fce 100644 --- a/docs/plugins/inspect/plugin-dvdspu.xml +++ b/docs/plugins/inspect/plugin-dvdspu.xml @@ -3,7 +3,7 @@ <description>DVD Sub-picture Overlay element</description> <filename>../../gst/dvdspu/.libs/libgstdvdspu.so</filename> <basename>libgstdvdspu.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-faac.xml b/docs/plugins/inspect/plugin-faac.xml index cadf3d97d..22394b7b6 100644 --- a/docs/plugins/inspect/plugin-faac.xml +++ b/docs/plugins/inspect/plugin-faac.xml @@ -3,7 +3,7 @@ <description>Free AAC Encoder (FAAC)</description> <filename>../../ext/faac/.libs/libgstfaac.so</filename> <basename>libgstfaac.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-faad.xml b/docs/plugins/inspect/plugin-faad.xml index 3992320aa..2854eab4f 100644 --- a/docs/plugins/inspect/plugin-faad.xml +++ b/docs/plugins/inspect/plugin-faad.xml @@ -3,7 +3,7 @@ <description>Free AAC Decoder (FAAD)</description> <filename>../../ext/faad/.libs/libgstfaad.so</filename> <basename>libgstfaad.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>GPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-fbdevsink.xml b/docs/plugins/inspect/plugin-fbdevsink.xml index cde9fa996..76ec0e3df 100644 --- a/docs/plugins/inspect/plugin-fbdevsink.xml +++ b/docs/plugins/inspect/plugin-fbdevsink.xml @@ -3,7 +3,7 @@ <description>linux framebuffer video sink</description> <filename>../../sys/fbdev/.libs/libgstfbdevsink.so</filename> <basename>libgstfbdevsink.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-festival.xml b/docs/plugins/inspect/plugin-festival.xml index bad79a660..57f5814fd 100644 --- a/docs/plugins/inspect/plugin-festival.xml +++ b/docs/plugins/inspect/plugin-festival.xml @@ -3,7 +3,7 @@ <description>Synthesizes plain text into audio</description> <filename>../../gst/festival/.libs/libgstfestival.so</filename> <basename>libgstfestival.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-freeze.xml b/docs/plugins/inspect/plugin-freeze.xml index 79609c5e6..90462d08c 100644 --- a/docs/plugins/inspect/plugin-freeze.xml +++ b/docs/plugins/inspect/plugin-freeze.xml @@ -3,7 +3,7 @@ <description>Stream freezer</description> <filename>../../gst/freeze/.libs/libgstfreeze.so</filename> <basename>libgstfreeze.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-frei0r.xml b/docs/plugins/inspect/plugin-frei0r.xml index a5c89fed5..94f516fb5 100644 --- a/docs/plugins/inspect/plugin-frei0r.xml +++ b/docs/plugins/inspect/plugin-frei0r.xml @@ -3,7 +3,7 @@ <description>frei0r plugin library</description> <filename>../../gst/frei0r/.libs/libgstfrei0r.so</filename> <basename>libgstfrei0r.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-gaudieffects.xml b/docs/plugins/inspect/plugin-gaudieffects.xml index 7a650a9ef..a3c33a5a4 100644 --- a/docs/plugins/inspect/plugin-gaudieffects.xml +++ b/docs/plugins/inspect/plugin-gaudieffects.xml @@ -3,7 +3,7 @@ <description>Gaudi video effects.</description> <filename>../../gst/gaudieffects/.libs/libgstgaudieffects.so</filename> <basename>libgstgaudieffects.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer</package> diff --git a/docs/plugins/inspect/plugin-geometrictransform.xml b/docs/plugins/inspect/plugin-geometrictransform.xml index 440d2366b..d03c3057c 100644 --- a/docs/plugins/inspect/plugin-geometrictransform.xml +++ b/docs/plugins/inspect/plugin-geometrictransform.xml @@ -3,7 +3,7 @@ <description>Various geometric image transform elements</description> <filename>../../gst/geometrictransform/.libs/libgstgeometrictransform.so</filename> <basename>libgstgeometrictransform.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> @@ -178,6 +178,27 @@ </pads> </element> <element> + <name>rotate</name> + <longname>rotate</longname> + <class>Transform/Effect/Video</class> + <description>Warps the picture into an arc shaped form</description> + <author>Thiago Santos<thiago.sousa.santos@collabora.co.uk></author> + <pads> + <caps> + <name>sink</name> + <direction>sink</direction> + <presence>always</presence> + <details>video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-yuv, format=(fourcc)AYUV, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)4321, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)1234, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> + </caps> + <caps> + <name>src</name> + <direction>source</direction> + <presence>always</presence> + <details>video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-yuv, format=(fourcc)AYUV, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)4321, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)1234, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> + </caps> + </pads> + </element> + <element> <name>sphere</name> <longname>sphere</longname> <class>Transform/Effect/Video</class> diff --git a/docs/plugins/inspect/plugin-gsettings.xml b/docs/plugins/inspect/plugin-gsettings.xml index 19637c217..a009c25a2 100644 --- a/docs/plugins/inspect/plugin-gsettings.xml +++ b/docs/plugins/inspect/plugin-gsettings.xml @@ -3,7 +3,7 @@ <description>GSettings plugin</description> <filename>../../ext/gsettings/.libs/libgstgsettingselements.so</filename> <basename>libgstgsettingselements.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-gsm.xml b/docs/plugins/inspect/plugin-gsm.xml index dbc19234e..f89cfc2f7 100644 --- a/docs/plugins/inspect/plugin-gsm.xml +++ b/docs/plugins/inspect/plugin-gsm.xml @@ -3,7 +3,7 @@ <description>GSM encoder/decoder</description> <filename>../../ext/gsm/.libs/libgstgsm.so</filename> <basename>libgstgsm.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-gstsiren.xml b/docs/plugins/inspect/plugin-gstsiren.xml index d8219863c..bb15abe0f 100644 --- a/docs/plugins/inspect/plugin-gstsiren.xml +++ b/docs/plugins/inspect/plugin-gstsiren.xml @@ -3,7 +3,7 @@ <description>Siren encoder/decoder/payloader/depayloader plugins</description> <filename>../../gst/siren/.libs/libgstsiren.so</filename> <basename>libgstsiren.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-h264parse.xml b/docs/plugins/inspect/plugin-h264parse.xml index 1233f3401..14977a52c 100644 --- a/docs/plugins/inspect/plugin-h264parse.xml +++ b/docs/plugins/inspect/plugin-h264parse.xml @@ -3,7 +3,7 @@ <description>Element parsing raw h264 streams</description> <filename>../../gst/h264parse/.libs/libgsth264parse.so</filename> <basename>libgsth264parse.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-hdvparse.xml b/docs/plugins/inspect/plugin-hdvparse.xml index 74c445b43..2589fb6d9 100644 --- a/docs/plugins/inspect/plugin-hdvparse.xml +++ b/docs/plugins/inspect/plugin-hdvparse.xml @@ -3,7 +3,7 @@ <description>HDV private stream parser</description> <filename>../../gst/hdvparse/.libs/libgsthdvparse.so</filename> <basename>libgsthdvparse.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer</package> diff --git a/docs/plugins/inspect/plugin-id3tag.xml b/docs/plugins/inspect/plugin-id3tag.xml index 09dfe550d..ce7a2942c 100644 --- a/docs/plugins/inspect/plugin-id3tag.xml +++ b/docs/plugins/inspect/plugin-id3tag.xml @@ -3,7 +3,7 @@ <description>ID3 v1 and v2 muxing plugin</description> <filename>../../gst/id3tag/.libs/libgstid3tag.so</filename> <basename>libgstid3tag.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-interlace.xml b/docs/plugins/inspect/plugin-interlace.xml index f0858231e..d9865ec08 100644 --- a/docs/plugins/inspect/plugin-interlace.xml +++ b/docs/plugins/inspect/plugin-interlace.xml @@ -3,7 +3,7 @@ <description>Create an interlaced video stream</description> <filename>../../gst/interlace/.libs/libgstinterlace.so</filename> <basename>libgstinterlace.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> @@ -11,10 +11,10 @@ <elements> <element> <name>interlace</name> - <longname>Inverse Telecine filter</longname> + <longname>Interlace filter</longname> <class>Filter/Video</class> - <description>Detects and reconstructs progressive content from telecine video</description> - <author>Entropy Wave <ds@entropywave.com></author> + <description>Creates an interlaced video from progressive frames</description> + <author>David Schleef <ds@schleef.org></author> <pads> <caps> <name>sink</name> diff --git a/docs/plugins/inspect/plugin-invtelecine.xml b/docs/plugins/inspect/plugin-invtelecine.xml index ea96e0a8c..119cf474c 100644 --- a/docs/plugins/inspect/plugin-invtelecine.xml +++ b/docs/plugins/inspect/plugin-invtelecine.xml @@ -3,7 +3,7 @@ <description>Inverse Telecine</description> <filename>../../gst/invtelecine/.libs/libgstinvtelecine.so</filename> <basename>libgstinvtelecine.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-ivfparse.xml b/docs/plugins/inspect/plugin-ivfparse.xml index a8a93f42e..181f384b4 100644 --- a/docs/plugins/inspect/plugin-ivfparse.xml +++ b/docs/plugins/inspect/plugin-ivfparse.xml @@ -3,7 +3,7 @@ <description>IVF parser</description> <filename>../../gst/ivfparse/.libs/libgstivfparse.so</filename> <basename>libgstivfparse.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-jack.xml b/docs/plugins/inspect/plugin-jack.xml deleted file mode 100644 index baa370192..000000000 --- a/docs/plugins/inspect/plugin-jack.xml +++ /dev/null @@ -1,43 +0,0 @@ -<plugin> - <name>jack</name> - <description>Jack elements</description> - <filename>../../ext/jack/.libs/libgstjack.so</filename> - <basename>libgstjack.so</basename> - <version>0.10.20.1</version> - <license>LGPL</license> - <source>gst-plugins-bad</source> - <package>GStreamer Bad Plug-ins git</package> - <origin>Unknown package origin</origin> - <elements> - <element> - <name>jackaudiosink</name> - <longname>Audio Sink (Jack)</longname> - <class>Sink/Audio</class> - <description>Output to Jack</description> - <author>Wim Taymans <wim@fluendo.com></author> - <pads> - <caps> - <name>sink</name> - <direction>sink</direction> - <presence>always</presence> - <details>audio/x-raw-float, endianness=(int){ 1234 }, width=(int)32, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ]</details> - </caps> - </pads> - </element> - <element> - <name>jackaudiosrc</name> - <longname>Audio Source (Jack)</longname> - <class>Source/Audio</class> - <description>Input from Jack</description> - <author>Tristan Matthews <tristan@sat.qc.ca></author> - <pads> - <caps> - <name>src</name> - <direction>source</direction> - <presence>always</presence> - <details>audio/x-raw-float, endianness=(int){ 1234 }, width=(int)32, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ]</details> - </caps> - </pads> - </element> - </elements> -</plugin>
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-jp2kdecimator.xml b/docs/plugins/inspect/plugin-jp2kdecimator.xml new file mode 100644 index 000000000..1f0e7fdc2 --- /dev/null +++ b/docs/plugins/inspect/plugin-jp2kdecimator.xml @@ -0,0 +1,34 @@ +<plugin> + <name>jp2kdecimator</name> + <description>JPEG2000 decimator</description> + <filename>../../gst/jp2kdecimator/.libs/libgstjp2kdecimator.so</filename> + <basename>libgstjp2kdecimator.so</basename> + <version>0.10.21.1</version> + <license>LGPL</license> + <source>gst-plugins-bad</source> + <package>GStreamer Bad Plug-ins git</package> + <origin>Unknown package origin</origin> + <elements> + <element> + <name>jp2kdecimator</name> + <longname>JPEG2000 decimator</longname> + <class>Filter/Image</class> + <description>Removes information from JPEG2000 streams without recompression</description> + <author>Sebastian Dröge <sebastian.droege@collabora.co.uk></author> + <pads> + <caps> + <name>sink</name> + <direction>sink</direction> + <presence>always</presence> + <details>image/x-jpc</details> + </caps> + <caps> + <name>src</name> + <direction>source</direction> + <presence>always</presence> + <details>image/x-jpc</details> + </caps> + </pads> + </element> + </elements> +</plugin>
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-jpegformat.xml b/docs/plugins/inspect/plugin-jpegformat.xml index 2e770a2bf..d802193df 100644 --- a/docs/plugins/inspect/plugin-jpegformat.xml +++ b/docs/plugins/inspect/plugin-jpegformat.xml @@ -3,7 +3,7 @@ <description>JPEG interchange format plugin</description> <filename>../../gst/jpegformat/.libs/libgstjpegformat.so</filename> <basename>libgstjpegformat.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> @@ -11,9 +11,9 @@ <elements> <element> <name>jifmux</name> - <longname>JPEG stream parser</longname> - <class>Codec/Parser/Video</class> - <description>Parse JPEG images into single-frame buffers</description> + <longname>JPEG stream muxer</longname> + <class>Video/Muxer</class> + <description>Remuxes JPEG images with markers and tags</description> <author>Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be></author> <pads> <caps> @@ -33,7 +33,7 @@ <element> <name>jpegparse</name> <longname>JPEG stream parser</longname> - <class>Codec/Parser/Video</class> + <class>Video/Parser</class> <description>Parse JPEG images into single-frame buffers</description> <author>Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be></author> <pads> diff --git a/docs/plugins/inspect/plugin-kate.xml b/docs/plugins/inspect/plugin-kate.xml index 0cd8729d3..60db3590f 100644 --- a/docs/plugins/inspect/plugin-kate.xml +++ b/docs/plugins/inspect/plugin-kate.xml @@ -3,7 +3,7 @@ <description>Kate plugin</description> <filename>../../ext/kate/.libs/libgstkate.so</filename> <basename>libgstkate.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> @@ -110,13 +110,13 @@ <name>video_sink</name> <direction>sink</direction> <presence>always</presence> - <details>video/x-raw-rgb, bpp=(int)32, depth=(int)24</details> + <details>video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)1234, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> <caps> <name>src</name> <direction>source</direction> <presence>always</presence> - <details>video/x-raw-rgb, bpp=(int)32, depth=(int)24</details> + <details>video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)1234, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> </pads> </element> diff --git a/docs/plugins/inspect/plugin-ladspa.xml b/docs/plugins/inspect/plugin-ladspa.xml index 99861849c..c9511b7e0 100644 --- a/docs/plugins/inspect/plugin-ladspa.xml +++ b/docs/plugins/inspect/plugin-ladspa.xml @@ -3,7 +3,7 @@ <description>All LADSPA plugins</description> <filename>../../ext/ladspa/.libs/libgstladspa.so</filename> <basename>libgstladspa.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-legacyresample.xml b/docs/plugins/inspect/plugin-legacyresample.xml index 6a78c594e..c3ae53dfc 100644 --- a/docs/plugins/inspect/plugin-legacyresample.xml +++ b/docs/plugins/inspect/plugin-legacyresample.xml @@ -3,7 +3,7 @@ <description>Resamples audio</description> <filename>../../gst/legacyresample/.libs/libgstlegacyresample.so</filename> <basename>libgstlegacyresample.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-liveadder.xml b/docs/plugins/inspect/plugin-liveadder.xml index bccb1e76d..109a4762d 100644 --- a/docs/plugins/inspect/plugin-liveadder.xml +++ b/docs/plugins/inspect/plugin-liveadder.xml @@ -3,7 +3,7 @@ <description>Adds multiple live discontinuous streams</description> <filename>../../gst/liveadder/.libs/libgstliveadder.so</filename> <basename>libgstliveadder.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-mimic.xml b/docs/plugins/inspect/plugin-mimic.xml index 67d605f26..202795df1 100644 --- a/docs/plugins/inspect/plugin-mimic.xml +++ b/docs/plugins/inspect/plugin-mimic.xml @@ -3,7 +3,7 @@ <description>Mimic codec</description> <filename>../../ext/mimic/.libs/libgstmimic.so</filename> <basename>libgstmimic.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-mms.xml b/docs/plugins/inspect/plugin-mms.xml index dd0f37885..fd3d4d8cc 100644 --- a/docs/plugins/inspect/plugin-mms.xml +++ b/docs/plugins/inspect/plugin-mms.xml @@ -3,7 +3,7 @@ <description>Microsoft Multi Media Server streaming protocol support</description> <filename>../../ext/libmms/.libs/libgstmms.so</filename> <basename>libgstmms.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-modplug.xml b/docs/plugins/inspect/plugin-modplug.xml index 70e11f43b..0e717bb86 100644 --- a/docs/plugins/inspect/plugin-modplug.xml +++ b/docs/plugins/inspect/plugin-modplug.xml @@ -3,7 +3,7 @@ <description>.MOD audio decoding</description> <filename>../../ext/modplug/.libs/libgstmodplug.so</filename> <basename>libgstmodplug.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-mpeg2enc.xml b/docs/plugins/inspect/plugin-mpeg2enc.xml index 92dde048d..0797f9adf 100644 --- a/docs/plugins/inspect/plugin-mpeg2enc.xml +++ b/docs/plugins/inspect/plugin-mpeg2enc.xml @@ -3,7 +3,7 @@ <description>High-quality MPEG-1/2 video encoder</description> <filename>../../ext/mpeg2enc/.libs/libgstmpeg2enc.so</filename> <basename>libgstmpeg2enc.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>GPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-mpeg4videoparse.xml b/docs/plugins/inspect/plugin-mpeg4videoparse.xml index c3b91f1a9..5915e60fb 100644 --- a/docs/plugins/inspect/plugin-mpeg4videoparse.xml +++ b/docs/plugins/inspect/plugin-mpeg4videoparse.xml @@ -3,7 +3,7 @@ <description>MPEG-4 video parser</description> <filename>../../gst/mpeg4videoparse/.libs/libgstmpeg4videoparse.so</filename> <basename>libgstmpeg4videoparse.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-mpegdemux2.xml b/docs/plugins/inspect/plugin-mpegdemux2.xml index 2320d4e97..571a42f9b 100644 --- a/docs/plugins/inspect/plugin-mpegdemux2.xml +++ b/docs/plugins/inspect/plugin-mpegdemux2.xml @@ -3,7 +3,7 @@ <description>MPEG demuxers</description> <filename>../../gst/mpegdemux/.libs/libgstmpegdemux.so</filename> <basename>libgstmpegdemux.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>unknown</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-mpegpsmux.xml b/docs/plugins/inspect/plugin-mpegpsmux.xml index 74a7d9805..65b5036b7 100644 --- a/docs/plugins/inspect/plugin-mpegpsmux.xml +++ b/docs/plugins/inspect/plugin-mpegpsmux.xml @@ -3,7 +3,7 @@ <description>MPEG-PS muxer</description> <filename>../../gst/mpegpsmux/.libs/libgstmpegpsmux.so</filename> <basename>libgstmpegpsmux.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-mpegtsmux.xml b/docs/plugins/inspect/plugin-mpegtsmux.xml index a7ca0ac5a..291c001e6 100644 --- a/docs/plugins/inspect/plugin-mpegtsmux.xml +++ b/docs/plugins/inspect/plugin-mpegtsmux.xml @@ -3,7 +3,7 @@ <description>MPEG-TS muxer</description> <filename>../../gst/mpegtsmux/.libs/libgstmpegtsmux.so</filename> <basename>libgstmpegtsmux.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-mpegvideoparse.xml b/docs/plugins/inspect/plugin-mpegvideoparse.xml index 539501f83..2aa538681 100644 --- a/docs/plugins/inspect/plugin-mpegvideoparse.xml +++ b/docs/plugins/inspect/plugin-mpegvideoparse.xml @@ -3,7 +3,7 @@ <description>MPEG-1 and MPEG-2 video parser</description> <filename>../../gst/mpegvideoparse/.libs/libgstmpegvideoparse.so</filename> <basename>libgstmpegvideoparse.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-mplex.xml b/docs/plugins/inspect/plugin-mplex.xml index a608ea28a..1979969e8 100644 --- a/docs/plugins/inspect/plugin-mplex.xml +++ b/docs/plugins/inspect/plugin-mplex.xml @@ -3,7 +3,7 @@ <description>High-quality MPEG/DVD/SVCD/VCD video/audio multiplexer</description> <filename>../../ext/mplex/.libs/libgstmplex.so</filename> <basename>libgstmplex.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>GPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-musepack.xml b/docs/plugins/inspect/plugin-musepack.xml index 2164282de..027cda9b8 100644 --- a/docs/plugins/inspect/plugin-musepack.xml +++ b/docs/plugins/inspect/plugin-musepack.xml @@ -3,7 +3,7 @@ <description>Musepack decoder</description> <filename>../../ext/musepack/.libs/libgstmusepack.so</filename> <basename>libgstmusepack.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-musicbrainz.xml b/docs/plugins/inspect/plugin-musicbrainz.xml index 0e82b158a..c6a0668f9 100644 --- a/docs/plugins/inspect/plugin-musicbrainz.xml +++ b/docs/plugins/inspect/plugin-musicbrainz.xml @@ -3,7 +3,7 @@ <description>A TRM signature producer based on libmusicbrainz</description> <filename>../../ext/musicbrainz/.libs/libgsttrm.so</filename> <basename>libgsttrm.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-mve.xml b/docs/plugins/inspect/plugin-mve.xml index 037ed8041..82ead0da8 100644 --- a/docs/plugins/inspect/plugin-mve.xml +++ b/docs/plugins/inspect/plugin-mve.xml @@ -3,7 +3,7 @@ <description>Interplay MVE movie format manipulation</description> <filename>../../gst/mve/.libs/libgstmve.so</filename> <basename>libgstmve.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-mxf.xml b/docs/plugins/inspect/plugin-mxf.xml index 2b0fd106e..4428508c5 100644 --- a/docs/plugins/inspect/plugin-mxf.xml +++ b/docs/plugins/inspect/plugin-mxf.xml @@ -3,7 +3,7 @@ <description>MXF plugin library</description> <filename>../../gst/mxf/.libs/libgstmxf.so</filename> <basename>libgstmxf.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-mythtv.xml b/docs/plugins/inspect/plugin-mythtv.xml index 3ee461b91..c7c533fde 100644 --- a/docs/plugins/inspect/plugin-mythtv.xml +++ b/docs/plugins/inspect/plugin-mythtv.xml @@ -3,7 +3,7 @@ <description>lib MythTV src</description> <filename>../../ext/mythtv/.libs/libgstmythtvsrc.so</filename> <basename>libgstmythtvsrc.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-nas.xml b/docs/plugins/inspect/plugin-nas.xml index 4da798551..488c4b284 100644 --- a/docs/plugins/inspect/plugin-nas.xml +++ b/docs/plugins/inspect/plugin-nas.xml @@ -3,7 +3,7 @@ <description>NAS (Network Audio System) support for GStreamer</description> <filename>../../ext/nas/.libs/libgstnassink.so</filename> <basename>libgstnassink.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-neon.xml b/docs/plugins/inspect/plugin-neon.xml index a7b7a5a33..2fae2b689 100644 --- a/docs/plugins/inspect/plugin-neon.xml +++ b/docs/plugins/inspect/plugin-neon.xml @@ -3,7 +3,7 @@ <description>lib neon http client src</description> <filename>../../ext/neon/.libs/libgstneonhttpsrc.so</filename> <basename>libgstneonhttpsrc.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-nsf.xml b/docs/plugins/inspect/plugin-nsf.xml index 2ad014331..202071374 100644 --- a/docs/plugins/inspect/plugin-nsf.xml +++ b/docs/plugins/inspect/plugin-nsf.xml @@ -3,7 +3,7 @@ <description>Uses nosefart to decode .nsf files</description> <filename>../../gst/nsf/.libs/libgstnsf.so</filename> <basename>libgstnsf.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>GPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-nuvdemux.xml b/docs/plugins/inspect/plugin-nuvdemux.xml index ff9519f72..ae15d8c7e 100644 --- a/docs/plugins/inspect/plugin-nuvdemux.xml +++ b/docs/plugins/inspect/plugin-nuvdemux.xml @@ -3,7 +3,7 @@ <description>Demuxes MythTV NuppelVideo files</description> <filename>../../gst/nuvdemux/.libs/libgstnuvdemux.so</filename> <basename>libgstnuvdemux.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-ofa.xml b/docs/plugins/inspect/plugin-ofa.xml index c806613bc..cdc9589ac 100644 --- a/docs/plugins/inspect/plugin-ofa.xml +++ b/docs/plugins/inspect/plugin-ofa.xml @@ -3,7 +3,7 @@ <description>Calculate MusicIP fingerprint from audio files</description> <filename>../../ext/ofa/.libs/libgstofa.so</filename> <basename>libgstofa.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>GPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-opencv.xml b/docs/plugins/inspect/plugin-opencv.xml index cecc91d8b..6270b768a 100644 --- a/docs/plugins/inspect/plugin-opencv.xml +++ b/docs/plugins/inspect/plugin-opencv.xml @@ -3,11 +3,11 @@ <description>GStreamer OpenCV Plugins</description> <filename>../../ext/opencv/.libs/libgstopencv.so</filename> <basename>libgstopencv.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> - <package>OpenCv</package> - <origin>http://opencv.willowgarage.com</origin> + <package>GStreamer Bad Plug-ins git</package> + <origin>Unknown package origin</origin> <elements> <element> <name>cvdilate</name> @@ -20,13 +20,13 @@ <name>sink</name> <direction>sink</direction> <presence>always</presence> - <details>video/x-raw-rgb, depth=(int)24, bpp=(int)24; video/x-raw-gray</details> + <details>video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)1234, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)4321, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> <caps> <name>src</name> <direction>source</direction> <presence>always</presence> - <details>video/x-raw-rgb, depth=(int)24, bpp=(int)24; video/x-raw-gray</details> + <details>video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)1234, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)4321, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> </pads> </element> @@ -41,13 +41,13 @@ <name>sink</name> <direction>sink</direction> <presence>always</presence> - <details>video/x-raw-gray, depth=(int)8, bpp=(int)8</details> + <details>video/x-raw-gray, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> <caps> <name>src</name> <direction>source</direction> <presence>always</presence> - <details>video/x-raw-gray, depth=(int)8, bpp=(int)8</details> + <details>video/x-raw-gray, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> </pads> </element> @@ -62,13 +62,13 @@ <name>sink</name> <direction>sink</direction> <presence>always</presence> - <details>video/x-raw-rgb, depth=(int)24, bpp=(int)24; video/x-raw-gray</details> + <details>video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)1234, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)4321, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> <caps> <name>src</name> <direction>source</direction> <presence>always</presence> - <details>video/x-raw-rgb, depth=(int)24, bpp=(int)24; video/x-raw-gray</details> + <details>video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)1234, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)4321, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> </pads> </element> @@ -83,13 +83,13 @@ <name>sink</name> <direction>sink</direction> <presence>always</presence> - <details>video/x-raw-gray, depth=(int)8, bpp=(int)8</details> + <details>video/x-raw-gray, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> <caps> <name>src</name> <direction>source</direction> <presence>always</presence> - <details>video/x-raw-gray, depth=(int)16, bpp=(int)16, endianness=(int)4321</details> + <details>video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)1234, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> </pads> </element> @@ -104,13 +104,13 @@ <name>sink</name> <direction>sink</direction> <presence>always</presence> - <details>video/x-raw-rgb, depth=(int)24, bpp=(int)24; video/x-raw-gray, depth=(int)8, bpp=(int)8</details> + <details>video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> <caps> <name>src</name> <direction>source</direction> <presence>always</presence> - <details>video/x-raw-rgb, depth=(int)24, bpp=(int)24; video/x-raw-gray, depth=(int)8, bpp=(int)8</details> + <details>video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> </pads> </element> @@ -125,13 +125,13 @@ <name>sink</name> <direction>sink</direction> <presence>always</presence> - <details>video/x-raw-gray, depth=(int)8, bpp=(int)8</details> + <details>video/x-raw-gray, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> <caps> <name>src</name> <direction>source</direction> <presence>always</presence> - <details>video/x-raw-gray, depth=(int)16, bpp=(int)16, endianness=(int)4321</details> + <details>video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)1234, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> </pads> </element> @@ -146,13 +146,13 @@ <name>sink</name> <direction>sink</direction> <presence>always</presence> - <details>video/x-raw-rgb</details> + <details>video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> <caps> <name>src</name> <direction>source</direction> <presence>always</presence> - <details>video/x-raw-rgb</details> + <details>video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> </pads> </element> @@ -167,13 +167,13 @@ <name>sink</name> <direction>sink</direction> <presence>always</presence> - <details>video/x-raw-rgb</details> + <details>video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> <caps> <name>src</name> <direction>source</direction> <presence>always</presence> - <details>video/x-raw-rgb</details> + <details>video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> </pads> </element> @@ -209,13 +209,13 @@ <name>sink</name> <direction>sink</direction> <presence>always</presence> - <details>video/x-raw-rgb</details> + <details>video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> <caps> <name>src</name> <direction>source</direction> <presence>always</presence> - <details>video/x-raw-rgb</details> + <details>video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> </pads> </element> @@ -230,13 +230,13 @@ <name>sink</name> <direction>sink</direction> <presence>always</presence> - <details>video/x-raw-rgb</details> + <details>video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> <caps> <name>src</name> <direction>source</direction> <presence>always</presence> - <details>video/x-raw-rgb</details> + <details>video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> </pads> </element> @@ -251,13 +251,13 @@ <name>sink</name> <direction>sink</direction> <presence>always</presence> - <details>video/x-raw-rgb</details> + <details>video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> <caps> <name>src</name> <direction>source</direction> <presence>always</presence> - <details>ANY</details> + <details>video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> </pads> </element> diff --git a/docs/plugins/inspect/plugin-pcapparse.xml b/docs/plugins/inspect/plugin-pcapparse.xml index dfd303ef2..ebf840750 100644 --- a/docs/plugins/inspect/plugin-pcapparse.xml +++ b/docs/plugins/inspect/plugin-pcapparse.xml @@ -3,7 +3,7 @@ <description>Element parsing raw pcap streams</description> <filename>../../gst/pcapparse/.libs/libgstpcapparse.so</filename> <basename>libgstpcapparse.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer</package> diff --git a/docs/plugins/inspect/plugin-pnm.xml b/docs/plugins/inspect/plugin-pnm.xml index 04595bba1..c2beb4484 100644 --- a/docs/plugins/inspect/plugin-pnm.xml +++ b/docs/plugins/inspect/plugin-pnm.xml @@ -3,7 +3,7 @@ <description>PNM plugin</description> <filename>../../gst/pnm/.libs/libgstpnm.so</filename> <basename>libgstpnm.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-qtmux.xml b/docs/plugins/inspect/plugin-qtmux.xml index df9d6ed27..ea5a9ac81 100644 --- a/docs/plugins/inspect/plugin-qtmux.xml +++ b/docs/plugins/inspect/plugin-qtmux.xml @@ -3,7 +3,7 @@ <description>Quicktime Muxer plugin</description> <filename>../../gst/qtmux/.libs/libgstqtmux.so</filename> <basename>libgstqtmux.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> @@ -37,6 +37,33 @@ </pads> </element> <element> + <name>ismlmux</name> + <longname>ISML Muxer</longname> + <class>Codec/Muxer</class> + <description>Multiplex audio and video into a ISML file</description> + <author>Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br></author> + <pads> + <caps> + <name>audio_%d</name> + <direction>sink</direction> + <presence>request</presence> + <details>audio/mpeg, mpegversion=(int)1, layer=(int)3, channels=(int)[ 1, 2 ], rate=(int)[ 1, 2147483647 ]; audio/mpeg, mpegversion=(int)4, stream-format=(string)raw, channels=(int)[ 1, 8 ], rate=(int)[ 1, 2147483647 ]</details> + </caps> + <caps> + <name>video_%d</name> + <direction>sink</direction> + <presence>request</presence> + <details>video/mpeg, mpegversion=(int)4, systemstream=(boolean)false, width=(int)[ 16, 4096 ], height=(int)[ 16, 4096 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-divx, divxversion=(int)5, width=(int)[ 16, 4096 ], height=(int)[ 16, 4096 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-h264, stream-format=(string)avc, width=(int)[ 16, 4096 ], height=(int)[ 16, 4096 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> + </caps> + <caps> + <name>src</name> + <direction>source</direction> + <presence>always</presence> + <details>video/quicktime, variant=(string)iso</details> + </caps> + </pads> + </element> + <element> <name>mj2mux</name> <longname>MJ2 Muxer</longname> <class>Codec/Muxer</class> diff --git a/docs/plugins/inspect/plugin-rawparse.xml b/docs/plugins/inspect/plugin-rawparse.xml index 618542a51..0cbe1ce65 100644 --- a/docs/plugins/inspect/plugin-rawparse.xml +++ b/docs/plugins/inspect/plugin-rawparse.xml @@ -3,7 +3,7 @@ <description>Parses byte streams into raw frames</description> <filename>../../gst/rawparse/.libs/libgstrawparse.so</filename> <basename>libgstrawparse.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-real.xml b/docs/plugins/inspect/plugin-real.xml index 00f412312..44b59fe0a 100644 --- a/docs/plugins/inspect/plugin-real.xml +++ b/docs/plugins/inspect/plugin-real.xml @@ -3,7 +3,7 @@ <description>Decode REAL streams</description> <filename>../../gst/real/.libs/libgstreal.so</filename> <basename>libgstreal.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-resindvd.xml b/docs/plugins/inspect/plugin-resindvd.xml index fb20d4bc9..5081bcfec 100644 --- a/docs/plugins/inspect/plugin-resindvd.xml +++ b/docs/plugins/inspect/plugin-resindvd.xml @@ -3,7 +3,7 @@ <description>Resin DVD playback elements</description> <filename>../../ext/resindvd/.libs/libresindvd.so</filename> <basename>libresindvd.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>GPL</license> <source>gst-plugins-bad</source> <package>GStreamer</package> diff --git a/docs/plugins/inspect/plugin-rfbsrc.xml b/docs/plugins/inspect/plugin-rfbsrc.xml index 6c4436f78..245aadf9b 100644 --- a/docs/plugins/inspect/plugin-rfbsrc.xml +++ b/docs/plugins/inspect/plugin-rfbsrc.xml @@ -3,7 +3,7 @@ <description>Connects to a VNC server and decodes RFB stream</description> <filename>../../gst/librfb/.libs/libgstrfbsrc.so</filename> <basename>libgstrfbsrc.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-rsvg.xml b/docs/plugins/inspect/plugin-rsvg.xml index 389178317..3b94b9ea1 100644 --- a/docs/plugins/inspect/plugin-rsvg.xml +++ b/docs/plugins/inspect/plugin-rsvg.xml @@ -3,7 +3,7 @@ <description>RSVG plugin library</description> <filename>../../ext/rsvg/.libs/libgstrsvg.so</filename> <basename>libgstrsvg.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> @@ -30,5 +30,32 @@ </caps> </pads> </element> + <element> + <name>rsvgoverlay</name> + <longname>RSVG overlay</longname> + <class>Filter/Editor/Video</class> + <description>Overlays SVG graphics over a video stream</description> + <author>Olivier Aubert <olivier.aubert@liris.cnrs.fr></author> + <pads> + <caps> + <name>data_sink</name> + <direction>sink</direction> + <presence>always</presence> + <details>image/svg+xml; image/svg; text/plain</details> + </caps> + <caps> + <name>sink</name> + <direction>sink</direction> + <presence>always</presence> + <details>video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> + </caps> + <caps> + <name>src</name> + <direction>source</direction> + <presence>always</presence> + <details>video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> + </caps> + </pads> + </element> </elements> </plugin>
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-rtpmux.xml b/docs/plugins/inspect/plugin-rtpmux.xml index f88d523d3..27351aff9 100644 --- a/docs/plugins/inspect/plugin-rtpmux.xml +++ b/docs/plugins/inspect/plugin-rtpmux.xml @@ -3,7 +3,7 @@ <description>RTP Muxer plugins</description> <filename>../../gst/rtpmux/.libs/libgstrtpmux.so</filename> <basename>libgstrtpmux.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-scaletempo.xml b/docs/plugins/inspect/plugin-scaletempo.xml index 0530697ce..347dd9c3c 100644 --- a/docs/plugins/inspect/plugin-scaletempo.xml +++ b/docs/plugins/inspect/plugin-scaletempo.xml @@ -3,7 +3,7 @@ <description>Scale audio tempo in sync with playback rate</description> <filename>../../gst/scaletempo/.libs/libgstscaletempoplugin.so</filename> <basename>libgstscaletempoplugin.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer</package> diff --git a/docs/plugins/inspect/plugin-schro.xml b/docs/plugins/inspect/plugin-schro.xml index 43cbbc7ea..3bb341ad5 100644 --- a/docs/plugins/inspect/plugin-schro.xml +++ b/docs/plugins/inspect/plugin-schro.xml @@ -3,7 +3,7 @@ <description>Schroedinger plugin</description> <filename>../../ext/schroedinger/.libs/libgstschro.so</filename> <basename>libgstschro.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-sdl.xml b/docs/plugins/inspect/plugin-sdl.xml index ce8912d7a..b6a98cbc5 100644 --- a/docs/plugins/inspect/plugin-sdl.xml +++ b/docs/plugins/inspect/plugin-sdl.xml @@ -3,7 +3,7 @@ <description>SDL (Simple DirectMedia Layer) support for GStreamer</description> <filename>../../ext/sdl/.libs/libgstsdl.so</filename> <basename>libgstsdl.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-sdp.xml b/docs/plugins/inspect/plugin-sdp.xml index 462fc13af..77f4f631f 100644 --- a/docs/plugins/inspect/plugin-sdp.xml +++ b/docs/plugins/inspect/plugin-sdp.xml @@ -3,7 +3,7 @@ <description>configure streaming sessions using SDP</description> <filename>../../gst/sdp/.libs/libgstsdpelem.so</filename> <basename>libgstsdpelem.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-segmentclip.xml b/docs/plugins/inspect/plugin-segmentclip.xml index e9811458d..3e2e837b6 100644 --- a/docs/plugins/inspect/plugin-segmentclip.xml +++ b/docs/plugins/inspect/plugin-segmentclip.xml @@ -3,7 +3,7 @@ <description>Segment clip elements</description> <filename>../../gst/segmentclip/.libs/libgstsegmentclip.so</filename> <basename>libgstsegmentclip.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-selector.xml b/docs/plugins/inspect/plugin-selector.xml deleted file mode 100644 index b3b15c91d..000000000 --- a/docs/plugins/inspect/plugin-selector.xml +++ /dev/null @@ -1,55 +0,0 @@ -<plugin> - <name>selector</name> - <description>input/output stream selector elements</description> - <filename>../../gst/selector/.libs/libgstselector.so</filename> - <basename>libgstselector.so</basename> - <version>0.10.20.1</version> - <license>LGPL</license> - <source>gst-plugins-bad</source> - <package>GStreamer Bad Plug-ins git</package> - <origin>Unknown package origin</origin> - <elements> - <element> - <name>input-selector</name> - <longname>Input selector</longname> - <class>Generic</class> - <description>N-to-1 input stream selectoring</description> - <author>Julien Moutte <julien@moutte.net>, Jan Schmidt <thaytan@mad.scientist.com>, Wim Taymans <wim.taymans@gmail.com></author> - <pads> - <caps> - <name>sink%d</name> - <direction>sink</direction> - <presence>request</presence> - <details>ANY</details> - </caps> - <caps> - <name>src</name> - <direction>source</direction> - <presence>always</presence> - <details>ANY</details> - </caps> - </pads> - </element> - <element> - <name>output-selector</name> - <longname>Output selector</longname> - <class>Generic</class> - <description>1-to-N output stream selectoring</description> - <author>Stefan Kost <stefan.kost@nokia.com></author> - <pads> - <caps> - <name>sink</name> - <direction>sink</direction> - <presence>always</presence> - <details>ANY</details> - </caps> - <caps> - <name>src%d</name> - <direction>source</direction> - <presence>request</presence> - <details>ANY</details> - </caps> - </pads> - </element> - </elements> -</plugin>
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-shm.xml b/docs/plugins/inspect/plugin-shm.xml index 39025fc20..bd2f46df0 100644 --- a/docs/plugins/inspect/plugin-shm.xml +++ b/docs/plugins/inspect/plugin-shm.xml @@ -3,7 +3,7 @@ <description>shared memory sink source</description> <filename>../../sys/shm/.libs/libgstshm.so</filename> <basename>libgstshm.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-sndfile.xml b/docs/plugins/inspect/plugin-sndfile.xml index 4a46cbeff..bc014bd92 100644 --- a/docs/plugins/inspect/plugin-sndfile.xml +++ b/docs/plugins/inspect/plugin-sndfile.xml @@ -3,7 +3,7 @@ <description>use libsndfile to read and write audio from and to files</description> <filename>../../ext/sndfile/.libs/libgstsndfile.so</filename> <basename>libgstsndfile.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-soundtouch.xml b/docs/plugins/inspect/plugin-soundtouch.xml index 7ccf6a9c8..bc4817fac 100644 --- a/docs/plugins/inspect/plugin-soundtouch.xml +++ b/docs/plugins/inspect/plugin-soundtouch.xml @@ -3,7 +3,7 @@ <description>Audio Pitch Controller & BPM Detection</description> <filename>../../ext/soundtouch/.libs/libgstsoundtouch.so</filename> <basename>libgstsoundtouch.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-speed.xml b/docs/plugins/inspect/plugin-speed.xml index 5f2d5be4c..487a7f9d7 100644 --- a/docs/plugins/inspect/plugin-speed.xml +++ b/docs/plugins/inspect/plugin-speed.xml @@ -3,7 +3,7 @@ <description>Set speed/pitch on audio/raw streams (resampler)</description> <filename>../../gst/speed/.libs/libgstspeed.so</filename> <basename>libgstspeed.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-stereo.xml b/docs/plugins/inspect/plugin-stereo.xml index 97d55f70c..fc7f5e2c3 100644 --- a/docs/plugins/inspect/plugin-stereo.xml +++ b/docs/plugins/inspect/plugin-stereo.xml @@ -3,7 +3,7 @@ <description>Muck with the stereo signal, enhance it's 'stereo-ness'</description> <filename>../../gst/stereo/.libs/libgststereo.so</filename> <basename>libgststereo.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-subenc.xml b/docs/plugins/inspect/plugin-subenc.xml index 2a9ea5d1c..9c37f4ca8 100644 --- a/docs/plugins/inspect/plugin-subenc.xml +++ b/docs/plugins/inspect/plugin-subenc.xml @@ -3,7 +3,7 @@ <description>subtitle encoders</description> <filename>../../gst/subenc/.libs/libgstsubenc.so</filename> <basename>libgstsubenc.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-tta.xml b/docs/plugins/inspect/plugin-tta.xml index 242bbe82b..46fa202bc 100644 --- a/docs/plugins/inspect/plugin-tta.xml +++ b/docs/plugins/inspect/plugin-tta.xml @@ -3,7 +3,7 @@ <description>TTA lossless audio format handling</description> <filename>../../gst/tta/.libs/libgsttta.so</filename> <basename>libgsttta.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-valve.xml b/docs/plugins/inspect/plugin-valve.xml deleted file mode 100644 index c67f8cc6b..000000000 --- a/docs/plugins/inspect/plugin-valve.xml +++ /dev/null @@ -1,34 +0,0 @@ -<plugin> - <name>valve</name> - <description>Valve</description> - <filename>../../gst/valve/.libs/libgstvalve.so</filename> - <basename>libgstvalve.so</basename> - <version>0.10.20.1</version> - <license>LGPL</license> - <source>gst-plugins-bad</source> - <package>GStreamer Bad Plug-ins git</package> - <origin>Unknown package origin</origin> - <elements> - <element> - <name>valve</name> - <longname>Valve element</longname> - <class>Filter</class> - <description>This element drops all packets when drop is TRUE</description> - <author>Olivier Crete <olivier.crete@collabora.co.uk></author> - <pads> - <caps> - <name>sink</name> - <direction>sink</direction> - <presence>always</presence> - <details>ANY</details> - </caps> - <caps> - <name>src</name> - <direction>source</direction> - <presence>always</presence> - <details>ANY</details> - </caps> - </pads> - </element> - </elements> -</plugin>
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-vcdsrc.xml b/docs/plugins/inspect/plugin-vcdsrc.xml index 8211a90cb..0a89e414d 100644 --- a/docs/plugins/inspect/plugin-vcdsrc.xml +++ b/docs/plugins/inspect/plugin-vcdsrc.xml @@ -3,7 +3,7 @@ <description>Asynchronous read from VCD disk</description> <filename>../../sys/vcd/.libs/libgstvcdsrc.so</filename> <basename>libgstvcdsrc.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-vdpau.xml b/docs/plugins/inspect/plugin-vdpau.xml index ab1141f01..385e840b7 100644 --- a/docs/plugins/inspect/plugin-vdpau.xml +++ b/docs/plugins/inspect/plugin-vdpau.xml @@ -3,7 +3,7 @@ <description>Various elements utilizing VDPAU</description> <filename>../../sys/vdpau/.libs/libgstvdpau.so</filename> <basename>libgstvdpau.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer</package> diff --git a/docs/plugins/inspect/plugin-videomaxrate.xml b/docs/plugins/inspect/plugin-videomaxrate.xml index 11011b9f5..aced0ff96 100644 --- a/docs/plugins/inspect/plugin-videomaxrate.xml +++ b/docs/plugins/inspect/plugin-videomaxrate.xml @@ -3,7 +3,7 @@ <description>Drop extra frames</description> <filename>../../gst/videomaxrate/.libs/libgstvideomaxrate.so</filename> <basename>libgstvideomaxrate.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-videomeasure.xml b/docs/plugins/inspect/plugin-videomeasure.xml index 5efca8aa7..6f6287d7a 100644 --- a/docs/plugins/inspect/plugin-videomeasure.xml +++ b/docs/plugins/inspect/plugin-videomeasure.xml @@ -3,7 +3,7 @@ <description>Various video measurers</description> <filename>../../gst/videomeasure/.libs/libgstvideomeasure.so</filename> <basename>libgstvideomeasure.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> @@ -33,7 +33,7 @@ <element> <name>ssim</name> <longname>SSim</longname> - <class>Filter/Converter/Video</class> + <class>Filter/Analyzer/Video</class> <description>Calculate Y-SSIM for n+2 YUV video streams</description> <author>РуÑлан Ижбулатов <lrn1986 _at_ gmail _dot_ com></author> <pads> diff --git a/docs/plugins/inspect/plugin-videosignal.xml b/docs/plugins/inspect/plugin-videosignal.xml index 2300debb3..bed6211b1 100644 --- a/docs/plugins/inspect/plugin-videosignal.xml +++ b/docs/plugins/inspect/plugin-videosignal.xml @@ -3,7 +3,7 @@ <description>Various video signal analysers</description> <filename>../../gst/videosignal/.libs/libgstvideosignal.so</filename> <basename>libgstvideosignal.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-vmnc.xml b/docs/plugins/inspect/plugin-vmnc.xml index 7a7d4cd11..429756103 100644 --- a/docs/plugins/inspect/plugin-vmnc.xml +++ b/docs/plugins/inspect/plugin-vmnc.xml @@ -3,7 +3,7 @@ <description>VmWare Video Codec plugins</description> <filename>../../gst/vmnc/.libs/libgstvmnc.so</filename> <basename>libgstvmnc.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-vp8.xml b/docs/plugins/inspect/plugin-vp8.xml index 55387b38b..ce75b4273 100644 --- a/docs/plugins/inspect/plugin-vp8.xml +++ b/docs/plugins/inspect/plugin-vp8.xml @@ -3,7 +3,7 @@ <description>VP8 plugin</description> <filename>../../ext/vp8/.libs/libgstvp8.so</filename> <basename>libgstvp8.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-wildmidi.xml b/docs/plugins/inspect/plugin-wildmidi.xml index f68db86d0..0de455b49 100644 --- a/docs/plugins/inspect/plugin-wildmidi.xml +++ b/docs/plugins/inspect/plugin-wildmidi.xml @@ -3,7 +3,7 @@ <description>Wildmidi Plugin</description> <filename>../../ext/timidity/.libs/libgstwildmidi.so</filename> <basename>libgstwildmidi.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>GPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-xvid.xml b/docs/plugins/inspect/plugin-xvid.xml index 8ba36b5e6..16a9fea27 100644 --- a/docs/plugins/inspect/plugin-xvid.xml +++ b/docs/plugins/inspect/plugin-xvid.xml @@ -3,7 +3,7 @@ <description>XviD plugin library</description> <filename>../../ext/xvid/.libs/libgstxvid.so</filename> <basename>libgstxvid.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>GPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> diff --git a/docs/plugins/inspect/plugin-y4mdec.xml b/docs/plugins/inspect/plugin-y4mdec.xml new file mode 100644 index 000000000..ab20ae84e --- /dev/null +++ b/docs/plugins/inspect/plugin-y4mdec.xml @@ -0,0 +1,34 @@ +<plugin> + <name>y4mdec</name> + <description>FIXME</description> + <filename>../../gst/y4m/.libs/libgsty4mdec.so</filename> + <basename>libgsty4mdec.so</basename> + <version>0.10.21.1</version> + <license>LGPL</license> + <source>gst-plugins-bad</source> + <package>GStreamer Bad Plug-ins</package> + <origin>Unknown package origin</origin> + <elements> + <element> + <name>y4mdec</name> + <longname>YUV4MPEG demuxer/decoder</longname> + <class>Codec/Demuxer</class> + <description>Demuxes/decodes YUV4MPEG streams</description> + <author>David Schleef <ds@schleef.org></author> + <pads> + <caps> + <name>sink</name> + <direction>sink</direction> + <presence>always</presence> + <details>application/x-yuv4mpeg, y4mversion=(int)2</details> + </caps> + <caps> + <name>src</name> + <direction>source</direction> + <presence>always</presence> + <details>video/x-raw-yuv, format=(fourcc){ I420, Y42B, Y444 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> + </caps> + </pads> + </element> + </elements> +</plugin>
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-zbar.xml b/docs/plugins/inspect/plugin-zbar.xml index b33088313..b160fe54b 100644 --- a/docs/plugins/inspect/plugin-zbar.xml +++ b/docs/plugins/inspect/plugin-zbar.xml @@ -3,7 +3,7 @@ <description>zbar barcode scanner</description> <filename>../../ext/zbar/.libs/libgstzbar.so</filename> <basename>libgstzbar.so</basename> - <version>0.10.20.1</version> + <version>0.10.21.1</version> <license>LGPL</license> <source>gst-plugins-bad</source> <package>GStreamer Bad Plug-ins git</package> @@ -20,13 +20,13 @@ <name>sink</name> <direction>sink</direction> <presence>always</presence> - <details>video/x-raw-yuv, format=(fourcc){ Y800 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> + <details>video/x-raw-yuv, format=(fourcc){ Y800, I420, YV12, NV12, NV21, Y41B, Y42B }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> <caps> <name>src</name> <direction>source</direction> <presence>always</presence> - <details>video/x-raw-yuv, format=(fourcc){ Y800 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> + <details>video/x-raw-yuv, format=(fourcc){ Y800, I420, YV12, NV12, NV21, Y41B, Y42B }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details> </caps> </pads> </element> diff --git a/ext/Makefile.am b/ext/Makefile.am index a9a7c8b5f..9b670d4db 100644 --- a/ext/Makefile.am +++ b/ext/Makefile.am @@ -136,12 +136,6 @@ endif HERMES_DIR= # endif -if USE_JACK -JACK_DIR=jack -else -JACK_DIR= -endif - if USE_JP2K JP2K_DIR = jp2k else @@ -398,7 +392,6 @@ SUBDIRS=\ $(GSM_DIR) \ $(G729_DIR) \ $(HERMES_DIR) \ - $(JACK_DIR) \ $(JP2K_DIR) \ $(KATE_DIR) \ $(LADSPA_DIR) \ @@ -453,7 +446,6 @@ DIST_SUBDIRS = \ gsettings \ gsm \ ladspa \ - jack \ jp2k \ kate \ libmms \ diff --git a/ext/cog/generate_tables.c b/ext/cog/generate_tables.c index d775bcc21..033f23c39 100644 --- a/ext/cog/generate_tables.c +++ b/ext/cog/generate_tables.c @@ -2,6 +2,7 @@ #include "config.h" #include <glib.h> +#include <gst/math-compat.h> #include <math.h> #include "gstcms.h" diff --git a/ext/cog/gstcms.c b/ext/cog/gstcms.c index 8fd28c6ba..27648cbf8 100644 --- a/ext/cog/gstcms.c +++ b/ext/cog/gstcms.c @@ -22,6 +22,7 @@ #endif #include <gst/gst.h> +#include <gst/math-compat.h> #include "gstcms.h" #include "cogutils.h" diff --git a/ext/cog/gstcogdownsample.c b/ext/cog/gstcogdownsample.c index 5d6b4f9ed..8bec086c0 100644 --- a/ext/cog/gstcogdownsample.c +++ b/ext/cog/gstcogdownsample.c @@ -357,6 +357,7 @@ gst_cogdownsample_transform (GstBaseTransform * base_transform, break; default: g_assert_not_reached (); + return GST_FLOW_ERROR; } frame = cog_virt_frame_new_unpack (frame); diff --git a/ext/cog/gstcogorc-dist.c b/ext/cog/gstcogorc-dist.c index 01d791e39..4cd43b5be 100644 --- a/ext/cog/gstcogorc-dist.c +++ b/ext/cog/gstcogorc-dist.c @@ -21,6 +21,7 @@ typedef uint8_t orc_uint8; typedef uint16_t orc_uint16; typedef uint32_t orc_uint32; typedef uint64_t orc_uint64; +#define ORC_UINT64_C(x) UINT64_C(x) #elif defined(_MSC_VER) typedef signed __int8 orc_int8; typedef signed __int16 orc_int16; @@ -30,6 +31,7 @@ typedef unsigned __int8 orc_uint8; typedef unsigned __int16 orc_uint16; typedef unsigned __int32 orc_uint32; typedef unsigned __int64 orc_uint64; +#define ORC_UINT64_C(x) (x##Ui64) #else #include <limits.h> typedef signed char orc_int8; @@ -41,9 +43,11 @@ typedef unsigned int orc_uint32; #if INT_MAX == LONG_MAX typedef long long orc_int64; typedef unsigned long long orc_uint64; +#define ORC_UINT64_C(x) (x##ULL) #else typedef long orc_int64; typedef unsigned long orc_uint64; +#define ORC_UINT64_C(x) (x##UL) #endif #endif typedef union @@ -63,6 +67,7 @@ typedef union orc_int64 i; double f; orc_int32 x2[2]; + float x2f[2]; orc_int16 x4[4]; } orc_union64; #endif @@ -252,12 +257,12 @@ void cogorc_convert_I420_BGRA_avg (orc_uint32 * d1, const orc_uint8 * s1, #define ORC_CLAMP_UL(x) ORC_CLAMP(x,ORC_UL_MIN,ORC_UL_MAX) #define ORC_SWAP_W(x) ((((x)&0xff)<<8) | (((x)&0xff00)>>8)) #define ORC_SWAP_L(x) ((((x)&0xff)<<24) | (((x)&0xff00)<<8) | (((x)&0xff0000)>>8) | (((x)&0xff000000)>>24)) -#define ORC_SWAP_Q(x) ((((x)&0xffULL)<<56) | (((x)&0xff00ULL)<<40) | (((x)&0xff0000ULL)<<24) | (((x)&0xff000000ULL)<<8) | (((x)&0xff00000000ULL)>>8) | (((x)&0xff0000000000ULL)>>24) | (((x)&0xff000000000000ULL)>>40) | (((x)&0xff00000000000000ULL)>>56)) +#define ORC_SWAP_Q(x) ((((x)&ORC_UINT64_C(0xff))<<56) | (((x)&ORC_UINT64_C(0xff00))<<40) | (((x)&ORC_UINT64_C(0xff0000))<<24) | (((x)&ORC_UINT64_C(0xff000000))<<8) | (((x)&ORC_UINT64_C(0xff00000000))>>8) | (((x)&ORC_UINT64_C(0xff0000000000))>>24) | (((x)&ORC_UINT64_C(0xff000000000000))>>40) | (((x)&ORC_UINT64_C(0xff00000000000000))>>56)) #define ORC_PTR_OFFSET(ptr,offset) ((void *)(((unsigned char *)(ptr)) + (offset))) #define ORC_DENORMAL(x) ((x) & ((((x)&0x7f800000) == 0) ? 0xff800000 : 0xffffffff)) #define ORC_ISNAN(x) ((((x)&0x7f800000) == 0x7f800000) && (((x)&0x007fffff) != 0)) -#define ORC_DENORMAL_DOUBLE(x) ((x) & ((((x)&0x7ff0000000000000ULL) == 0) ? 0xfff0000000000000ULL : 0xffffffffffffffffULL)) -#define ORC_ISNAN_DOUBLE(x) ((((x)&0x7ff0000000000000ULL) == 0x7ff0000000000000ULL) && (((x)&0x000fffffffffffffULL) != 0)) +#define ORC_DENORMAL_DOUBLE(x) ((x) & ((((x)&ORC_UINT64_C(0x7ff0000000000000)) == 0) ? ORC_UINT64_C(0xfff0000000000000) : ORC_UINT64_C(0xffffffffffffffff))) +#define ORC_ISNAN_DOUBLE(x) ((((x)&ORC_UINT64_C(0x7ff0000000000000)) == ORC_UINT64_C(0x7ff0000000000000)) && (((x)&ORC_UINT64_C(0x000fffffffffffff)) != 0)) #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L #define ORC_RESTRICT restrict #elif defined(__GNUC__) && __GNUC__ >= 4 @@ -349,14 +354,6 @@ cogorc_memcpy_2d (orc_uint8 * d1, int d1_stride, const orc_uint8 * s1, orc_program_set_backup_function (p, _backup_cogorc_memcpy_2d); orc_program_add_destination (p, 1, "d1"); orc_program_add_source (p, 1, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_append_2 (p, "copyb", 0, ORC_VAR_D1, ORC_VAR_S1, ORC_VAR_D1, ORC_VAR_D1); @@ -454,14 +451,6 @@ cogorc_downsample_horiz_cosite_1tap (orc_uint8 * d1, const orc_uint16 * s1, _backup_cogorc_downsample_horiz_cosite_1tap); orc_program_add_destination (p, 1, "d1"); orc_program_add_source (p, 2, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_append_2 (p, "select0wb", 0, ORC_VAR_D1, ORC_VAR_S1, ORC_VAR_D1, ORC_VAR_D1); @@ -652,13 +641,6 @@ cogorc_downsample_horiz_cosite_3tap (orc_uint8 * d1, const orc_uint16 * s1, orc_program_add_source (p, 2, "s1"); orc_program_add_source (p, 2, "s2"); orc_program_add_constant (p, 4, 0x00000002, "c1"); - orc_program_add_constant (p, 0, 0x00000002, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 1, "t1"); orc_program_add_temporary (p, 1, "t2"); orc_program_add_temporary (p, 1, "t3"); @@ -842,14 +824,6 @@ cogorc_downsample_420_jpeg (orc_uint8 * d1, const orc_uint16 * s1, orc_program_add_destination (p, 1, "d1"); orc_program_add_source (p, 2, "s1"); orc_program_add_source (p, 2, "s2"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 1, "t2"); orc_program_add_temporary (p, 1, "t3"); @@ -977,14 +951,6 @@ cogorc_downsample_vert_halfsite_2tap (orc_uint8 * d1, const orc_uint8 * s1, orc_program_add_destination (p, 1, "d1"); orc_program_add_source (p, 1, "s1"); orc_program_add_source (p, 1, "s2"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_append_2 (p, "avgub", 0, ORC_VAR_D1, ORC_VAR_S1, ORC_VAR_S2, ORC_VAR_D1); @@ -1163,13 +1129,6 @@ cogorc_downsample_vert_cosite_3tap (orc_uint8 * d1, const orc_uint8 * s1, orc_program_add_source (p, 1, "s2"); orc_program_add_source (p, 1, "s3"); orc_program_add_constant (p, 4, 0x00000002, "c1"); - orc_program_add_constant (p, 0, 0x00000002, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 2, "t2"); orc_program_add_temporary (p, 2, "t3"); @@ -1405,11 +1364,6 @@ cogorc_downsample_vert_halfsite_4tap (orc_uint8 * d1, const orc_uint8 * s1, orc_program_add_constant (p, 4, 0x0000001a, "c1"); orc_program_add_constant (p, 4, 0x00000006, "c2"); orc_program_add_constant (p, 4, 0x00000020, "c3"); - orc_program_add_constant (p, 0, 0x00000006, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 2, "t2"); orc_program_add_temporary (p, 2, "t3"); @@ -1482,7 +1436,7 @@ cogorc_upsample_horiz_cosite_1tap (guint8 * d1, const orc_uint8 * s1, int n) /* 1: copyb */ var35 = var33; /* 2: mergebw */ - var34.i = ((orc_uint8) var35) | ((orc_uint8) var35 << 8); + var34.i = ((orc_uint8) var35 & 0x00ff) | ((orc_uint8) var35 << 8); /* 3: storew */ ptr0[i] = var34; } @@ -1511,7 +1465,7 @@ _backup_cogorc_upsample_horiz_cosite_1tap (OrcExecutor * ex) /* 1: copyb */ var35 = var33; /* 2: mergebw */ - var34.i = ((orc_uint8) var35) | ((orc_uint8) var35 << 8); + var34.i = ((orc_uint8) var35 & 0x00ff) | ((orc_uint8) var35 << 8); /* 3: storew */ ptr0[i] = var34; } @@ -1537,14 +1491,6 @@ cogorc_upsample_horiz_cosite_1tap (guint8 * d1, const orc_uint8 * s1, int n) _backup_cogorc_upsample_horiz_cosite_1tap); orc_program_add_destination (p, 2, "d1"); orc_program_add_source (p, 1, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 1, "t1"); orc_program_append_2 (p, "copyb", 0, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_D1, @@ -1600,7 +1546,7 @@ cogorc_upsample_horiz_cosite (guint8 * d1, const orc_uint8 * s1, /* 3: avgub */ var38 = ((orc_uint8) var37 + (orc_uint8) var35 + 1) >> 1; /* 4: mergebw */ - var36.i = ((orc_uint8) var37) | ((orc_uint8) var38 << 8); + var36.i = ((orc_uint8) var37 & 0x00ff) | ((orc_uint8) var38 << 8); /* 5: storew */ ptr0[i] = var36; } @@ -1637,7 +1583,7 @@ _backup_cogorc_upsample_horiz_cosite (OrcExecutor * ex) /* 3: avgub */ var38 = ((orc_uint8) var37 + (orc_uint8) var35 + 1) >> 1; /* 4: mergebw */ - var36.i = ((orc_uint8) var37) | ((orc_uint8) var38 << 8); + var36.i = ((orc_uint8) var37 & 0x00ff) | ((orc_uint8) var38 << 8); /* 5: storew */ ptr0[i] = var36; } @@ -1664,14 +1610,6 @@ cogorc_upsample_horiz_cosite (guint8 * d1, const orc_uint8 * s1, orc_program_add_destination (p, 2, "d1"); orc_program_add_source (p, 1, "s1"); orc_program_add_source (p, 1, "s2"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 1, "t1"); orc_program_add_temporary (p, 1, "t2"); @@ -1783,14 +1721,6 @@ cogorc_upsample_vert_avgub (orc_uint8 * d1, const orc_uint8 * s1, orc_program_add_destination (p, 1, "d1"); orc_program_add_source (p, 1, "s1"); orc_program_add_source (p, 1, "s2"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_append_2 (p, "avgub", 0, ORC_VAR_D1, ORC_VAR_S1, ORC_VAR_S2, ORC_VAR_D1); @@ -1883,14 +1813,6 @@ orc_unpack_yuyv_y (orc_uint8 * d1, const orc_uint16 * s1, int n) orc_program_set_backup_function (p, _backup_orc_unpack_yuyv_y); orc_program_add_destination (p, 1, "d1"); orc_program_add_source (p, 2, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_append_2 (p, "select0wb", 0, ORC_VAR_D1, ORC_VAR_S1, ORC_VAR_D1, ORC_VAR_D1); @@ -1988,14 +1910,6 @@ orc_unpack_yuyv_u (orc_uint8 * d1, const orc_uint32 * s1, int n) orc_program_set_backup_function (p, _backup_orc_unpack_yuyv_u); orc_program_add_destination (p, 1, "d1"); orc_program_add_source (p, 4, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_append_2 (p, "select0lw", 0, ORC_VAR_T1, ORC_VAR_S1, @@ -2096,14 +2010,6 @@ orc_unpack_yuyv_v (orc_uint8 * d1, const orc_uint32 * s1, int n) orc_program_set_backup_function (p, _backup_orc_unpack_yuyv_v); orc_program_add_destination (p, 1, "d1"); orc_program_add_source (p, 4, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_append_2 (p, "select1lw", 0, ORC_VAR_T1, ORC_VAR_S1, @@ -2167,13 +2073,14 @@ orc_pack_yuyv (orc_uint32 * d1, const guint8 * s1, const orc_uint8 * s2, /* 4: loadb */ var38 = ptr5[i]; /* 5: mergebw */ - var44.i = ((orc_uint8) var42) | ((orc_uint8) var38 << 8); + var44.i = ((orc_uint8) var42 & 0x00ff) | ((orc_uint8) var38 << 8); /* 6: loadb */ var39 = ptr6[i]; /* 7: mergebw */ - var45.i = ((orc_uint8) var43) | ((orc_uint8) var39 << 8); + var45.i = ((orc_uint8) var43 & 0x00ff) | ((orc_uint8) var39 << 8); /* 8: mergewl */ - var40.i = ((orc_uint16) var44.i) | ((orc_uint16) var45.i << 16); + var40.i = + ((orc_uint16) var44.i & 0x0000ffff) | ((orc_uint16) var45.i << 16); /* 9: storel */ ptr0[i] = var40; } @@ -2218,13 +2125,14 @@ _backup_orc_pack_yuyv (OrcExecutor * ex) /* 4: loadb */ var38 = ptr5[i]; /* 5: mergebw */ - var44.i = ((orc_uint8) var42) | ((orc_uint8) var38 << 8); + var44.i = ((orc_uint8) var42 & 0x00ff) | ((orc_uint8) var38 << 8); /* 6: loadb */ var39 = ptr6[i]; /* 7: mergebw */ - var45.i = ((orc_uint8) var43) | ((orc_uint8) var39 << 8); + var45.i = ((orc_uint8) var43 & 0x00ff) | ((orc_uint8) var39 << 8); /* 8: mergewl */ - var40.i = ((orc_uint16) var44.i) | ((orc_uint16) var45.i << 16); + var40.i = + ((orc_uint16) var44.i & 0x0000ffff) | ((orc_uint16) var45.i << 16); /* 9: storel */ ptr0[i] = var40; } @@ -2252,14 +2160,6 @@ orc_pack_yuyv (orc_uint32 * d1, const guint8 * s1, const orc_uint8 * s2, orc_program_add_source (p, 2, "s1"); orc_program_add_source (p, 1, "s2"); orc_program_add_source (p, 1, "s3"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 1, "t1"); orc_program_add_temporary (p, 1, "t2"); orc_program_add_temporary (p, 2, "t3"); @@ -2368,14 +2268,6 @@ orc_unpack_uyvy_y (orc_uint8 * d1, const orc_uint16 * s1, int n) orc_program_set_backup_function (p, _backup_orc_unpack_uyvy_y); orc_program_add_destination (p, 1, "d1"); orc_program_add_source (p, 2, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_append_2 (p, "select1wb", 0, ORC_VAR_D1, ORC_VAR_S1, ORC_VAR_D1, ORC_VAR_D1); @@ -2473,14 +2365,6 @@ orc_unpack_uyvy_u (orc_uint8 * d1, const orc_uint32 * s1, int n) orc_program_set_backup_function (p, _backup_orc_unpack_uyvy_u); orc_program_add_destination (p, 1, "d1"); orc_program_add_source (p, 4, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_append_2 (p, "select0lw", 0, ORC_VAR_T1, ORC_VAR_S1, @@ -2581,14 +2465,6 @@ orc_unpack_uyvy_v (orc_uint8 * d1, const orc_uint32 * s1, int n) orc_program_set_backup_function (p, _backup_orc_unpack_uyvy_v); orc_program_add_destination (p, 1, "d1"); orc_program_add_source (p, 4, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_append_2 (p, "select1lw", 0, ORC_VAR_T1, ORC_VAR_S1, @@ -2652,13 +2528,14 @@ orc_pack_uyvy (orc_uint32 * d1, const guint8 * s1, const orc_uint8 * s2, /* 4: loadb */ var38 = ptr5[i]; /* 5: mergebw */ - var44.i = ((orc_uint8) var38) | ((orc_uint8) var42 << 8); + var44.i = ((orc_uint8) var38 & 0x00ff) | ((orc_uint8) var42 << 8); /* 6: loadb */ var39 = ptr6[i]; /* 7: mergebw */ - var45.i = ((orc_uint8) var39) | ((orc_uint8) var43 << 8); + var45.i = ((orc_uint8) var39 & 0x00ff) | ((orc_uint8) var43 << 8); /* 8: mergewl */ - var40.i = ((orc_uint16) var44.i) | ((orc_uint16) var45.i << 16); + var40.i = + ((orc_uint16) var44.i & 0x0000ffff) | ((orc_uint16) var45.i << 16); /* 9: storel */ ptr0[i] = var40; } @@ -2703,13 +2580,14 @@ _backup_orc_pack_uyvy (OrcExecutor * ex) /* 4: loadb */ var38 = ptr5[i]; /* 5: mergebw */ - var44.i = ((orc_uint8) var38) | ((orc_uint8) var42 << 8); + var44.i = ((orc_uint8) var38 & 0x00ff) | ((orc_uint8) var42 << 8); /* 6: loadb */ var39 = ptr6[i]; /* 7: mergebw */ - var45.i = ((orc_uint8) var39) | ((orc_uint8) var43 << 8); + var45.i = ((orc_uint8) var39 & 0x00ff) | ((orc_uint8) var43 << 8); /* 8: mergewl */ - var40.i = ((orc_uint16) var44.i) | ((orc_uint16) var45.i << 16); + var40.i = + ((orc_uint16) var44.i & 0x0000ffff) | ((orc_uint16) var45.i << 16); /* 9: storel */ ptr0[i] = var40; } @@ -2737,14 +2615,6 @@ orc_pack_uyvy (orc_uint32 * d1, const guint8 * s1, const orc_uint8 * s2, orc_program_add_source (p, 2, "s1"); orc_program_add_source (p, 1, "s2"); orc_program_add_source (p, 1, "s3"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 1, "t1"); orc_program_add_temporary (p, 1, "t2"); orc_program_add_temporary (p, 2, "t3"); @@ -2866,13 +2736,6 @@ orc_addc_convert_u8_s16 (orc_uint8 * d1, const gint16 * s1, int n) orc_program_add_destination (p, 1, "d1"); orc_program_add_source (p, 2, "s1"); orc_program_add_constant (p, 4, 0x00000080, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_append_2 (p, "addw", 0, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_C1, @@ -2980,13 +2843,6 @@ orc_subc_convert_s16_u8 (gint16 * d1, const orc_uint8 * s1, int n) orc_program_add_destination (p, 2, "d1"); orc_program_add_source (p, 1, "s1"); orc_program_add_constant (p, 4, 0x00000080, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_append_2 (p, "convubw", 0, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_D1, @@ -3076,14 +2932,6 @@ orc_splat_u8_ns (orc_uint8 * d1, int p1, int n) orc_program_set_name (p, "orc_splat_u8_ns"); orc_program_set_backup_function (p, _backup_orc_splat_u8_ns); orc_program_add_destination (p, 1, "d1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_parameter (p, 1, "p1"); orc_program_append_2 (p, "copyb", 0, ORC_VAR_D1, ORC_VAR_P1, ORC_VAR_D1, @@ -3171,14 +3019,6 @@ orc_splat_s16_ns (gint16 * d1, int p1, int n) orc_program_set_name (p, "orc_splat_s16_ns"); orc_program_set_backup_function (p, _backup_orc_splat_s16_ns); orc_program_add_destination (p, 2, "d1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_parameter (p, 2, "p1"); orc_program_append_2 (p, "copyw", 0, ORC_VAR_D1, ORC_VAR_P1, ORC_VAR_D1, @@ -3345,13 +3185,6 @@ orc_matrix2_u8 (guint8 * d1, const guint8 * s1, const guint8 * s2, int p1, orc_program_add_source (p, 1, "s1"); orc_program_add_source (p, 1, "s2"); orc_program_add_constant (p, 4, 0x00000006, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_parameter (p, 2, "p1"); orc_program_add_parameter (p, 2, "p2"); orc_program_add_parameter (p, 2, "p3"); @@ -3578,11 +3411,6 @@ orc_matrix2_11_u8 (guint8 * d1, const guint8 * s1, const guint8 * s2, int p1, orc_program_add_constant (p, 4, 0x00000010, "c1"); orc_program_add_constant (p, 4, 0x00000080, "c2"); orc_program_add_constant (p, 4, 0x00000008, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_parameter (p, 2, "p1"); orc_program_add_parameter (p, 2, "p2"); orc_program_add_temporary (p, 2, "t1"); @@ -3823,11 +3651,6 @@ orc_matrix2_12_u8 (guint8 * d1, const guint8 * s1, const guint8 * s2, int p1, orc_program_add_constant (p, 4, 0x00000010, "c1"); orc_program_add_constant (p, 4, 0x00000080, "c2"); orc_program_add_constant (p, 4, 0x00000008, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_parameter (p, 2, "p1"); orc_program_add_parameter (p, 2, "p2"); orc_program_add_temporary (p, 2, "t1"); @@ -4061,13 +3884,6 @@ orc_matrix3_u8 (guint8 * d1, const guint8 * s1, const guint8 * s2, orc_program_add_source (p, 1, "s2"); orc_program_add_source (p, 1, "s3"); orc_program_add_constant (p, 4, 0x00000006, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_parameter (p, 2, "p1"); orc_program_add_parameter (p, 2, "p2"); orc_program_add_parameter (p, 2, "p3"); @@ -4344,11 +4160,6 @@ orc_matrix3_100_u8 (guint8 * d1, const guint8 * s1, const guint8 * s2, orc_program_add_constant (p, 4, 0x00000010, "c1"); orc_program_add_constant (p, 4, 0x00000080, "c2"); orc_program_add_constant (p, 4, 0x00000008, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_parameter (p, 2, "p1"); orc_program_add_parameter (p, 2, "p2"); orc_program_add_parameter (p, 2, "p3"); @@ -4593,14 +4404,6 @@ orc_matrix3_100_offset_u8 (guint8 * d1, const guint8 * s1, const guint8 * s2, orc_program_add_source (p, 1, "s1"); orc_program_add_source (p, 1, "s2"); orc_program_add_source (p, 1, "s3"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_parameter (p, 2, "p1"); orc_program_add_parameter (p, 2, "p2"); orc_program_add_parameter (p, 2, "p3"); @@ -4837,14 +4640,6 @@ orc_matrix3_000_u8 (guint8 * d1, const guint8 * s1, const guint8 * s2, orc_program_add_source (p, 1, "s1"); orc_program_add_source (p, 1, "s2"); orc_program_add_source (p, 1, "s3"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_parameter (p, 2, "p1"); orc_program_add_parameter (p, 2, "p2"); orc_program_add_parameter (p, 2, "p3"); @@ -4933,13 +4728,14 @@ orc_pack_123x (guint32 * d1, const orc_uint8 * s1, const orc_uint8 * s2, /* 1: loadb */ var35 = ptr5[i]; /* 2: mergebw */ - var39.i = ((orc_uint8) var34) | ((orc_uint8) var35 << 8); + var39.i = ((orc_uint8) var34 & 0x00ff) | ((orc_uint8) var35 << 8); /* 3: loadb */ var36 = ptr6[i]; /* 5: mergebw */ - var40.i = ((orc_uint8) var36) | ((orc_uint8) var37 << 8); + var40.i = ((orc_uint8) var36 & 0x00ff) | ((orc_uint8) var37 << 8); /* 6: mergewl */ - var38.i = ((orc_uint16) var39.i) | ((orc_uint16) var40.i << 16); + var38.i = + ((orc_uint16) var39.i & 0x0000ffff) | ((orc_uint16) var40.i << 16); /* 7: storel */ ptr0[i] = var38; } @@ -4978,13 +4774,14 @@ _backup_orc_pack_123x (OrcExecutor * ex) /* 1: loadb */ var35 = ptr5[i]; /* 2: mergebw */ - var39.i = ((orc_uint8) var34) | ((orc_uint8) var35 << 8); + var39.i = ((orc_uint8) var34 & 0x00ff) | ((orc_uint8) var35 << 8); /* 3: loadb */ var36 = ptr6[i]; /* 5: mergebw */ - var40.i = ((orc_uint8) var36) | ((orc_uint8) var37 << 8); + var40.i = ((orc_uint8) var36 & 0x00ff) | ((orc_uint8) var37 << 8); /* 6: mergewl */ - var38.i = ((orc_uint16) var39.i) | ((orc_uint16) var40.i << 16); + var38.i = + ((orc_uint16) var39.i & 0x0000ffff) | ((orc_uint16) var40.i << 16); /* 7: storel */ ptr0[i] = var38; } @@ -5012,14 +4809,6 @@ orc_pack_123x (guint32 * d1, const orc_uint8 * s1, const orc_uint8 * s2, orc_program_add_source (p, 1, "s1"); orc_program_add_source (p, 1, "s2"); orc_program_add_source (p, 1, "s3"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_parameter (p, 1, "p1"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 2, "t2"); @@ -5082,15 +4871,16 @@ orc_pack_x123 (guint32 * d1, const orc_uint8 * s1, const orc_uint8 * s2, /* 1: loadb */ var35 = ptr4[i]; /* 2: mergebw */ - var39.i = ((orc_uint8) var34) | ((orc_uint8) var35 << 8); + var39.i = ((orc_uint8) var34 & 0x00ff) | ((orc_uint8) var35 << 8); /* 3: loadb */ var36 = ptr5[i]; /* 4: loadb */ var37 = ptr6[i]; /* 5: mergebw */ - var40.i = ((orc_uint8) var36) | ((orc_uint8) var37 << 8); + var40.i = ((orc_uint8) var36 & 0x00ff) | ((orc_uint8) var37 << 8); /* 6: mergewl */ - var38.i = ((orc_uint16) var39.i) | ((orc_uint16) var40.i << 16); + var38.i = + ((orc_uint16) var39.i & 0x0000ffff) | ((orc_uint16) var40.i << 16); /* 7: storel */ ptr0[i] = var38; } @@ -5127,15 +4917,16 @@ _backup_orc_pack_x123 (OrcExecutor * ex) /* 1: loadb */ var35 = ptr4[i]; /* 2: mergebw */ - var39.i = ((orc_uint8) var34) | ((orc_uint8) var35 << 8); + var39.i = ((orc_uint8) var34 & 0x00ff) | ((orc_uint8) var35 << 8); /* 3: loadb */ var36 = ptr5[i]; /* 4: loadb */ var37 = ptr6[i]; /* 5: mergebw */ - var40.i = ((orc_uint8) var36) | ((orc_uint8) var37 << 8); + var40.i = ((orc_uint8) var36 & 0x00ff) | ((orc_uint8) var37 << 8); /* 6: mergewl */ - var38.i = ((orc_uint16) var39.i) | ((orc_uint16) var40.i << 16); + var38.i = + ((orc_uint16) var39.i & 0x0000ffff) | ((orc_uint16) var40.i << 16); /* 7: storel */ ptr0[i] = var38; } @@ -5163,14 +4954,6 @@ orc_pack_x123 (guint32 * d1, const orc_uint8 * s1, const orc_uint8 * s2, orc_program_add_source (p, 1, "s1"); orc_program_add_source (p, 1, "s2"); orc_program_add_source (p, 1, "s3"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_parameter (p, 1, "p1"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 2, "t2"); @@ -5334,13 +5117,6 @@ cogorc_combine2_u8 (orc_uint8 * d1, const orc_uint8 * s1, const orc_uint8 * s2, orc_program_add_source (p, 1, "s1"); orc_program_add_source (p, 1, "s2"); orc_program_add_constant (p, 4, 0x00000008, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_parameter (p, 2, "p1"); orc_program_add_parameter (p, 2, "p2"); orc_program_add_temporary (p, 2, "t1"); @@ -5598,12 +5374,6 @@ cogorc_combine4_u8 (orc_uint8 * d1, const orc_uint8 * s1, const orc_uint8 * s2, orc_program_add_source (p, 1, "s4"); orc_program_add_constant (p, 4, 0x00000020, "c1"); orc_program_add_constant (p, 4, 0x00000006, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_parameter (p, 2, "p1"); orc_program_add_parameter (p, 2, "p2"); orc_program_add_parameter (p, 2, "p3"); @@ -5740,14 +5510,6 @@ cogorc_unpack_axyz_0 (orc_uint8 * d1, const orc_uint32 * s1, int n) orc_program_set_backup_function (p, _backup_cogorc_unpack_axyz_0); orc_program_add_destination (p, 1, "d1"); orc_program_add_source (p, 4, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_append_2 (p, "select0lw", 0, ORC_VAR_T1, ORC_VAR_S1, @@ -5848,14 +5610,6 @@ cogorc_unpack_axyz_1 (orc_uint8 * d1, const orc_uint32 * s1, int n) orc_program_set_backup_function (p, _backup_cogorc_unpack_axyz_1); orc_program_add_destination (p, 1, "d1"); orc_program_add_source (p, 4, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_append_2 (p, "select0lw", 0, ORC_VAR_T1, ORC_VAR_S1, @@ -5956,14 +5710,6 @@ cogorc_unpack_axyz_2 (orc_uint8 * d1, const orc_uint32 * s1, int n) orc_program_set_backup_function (p, _backup_cogorc_unpack_axyz_2); orc_program_add_destination (p, 1, "d1"); orc_program_add_source (p, 4, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_append_2 (p, "select1lw", 0, ORC_VAR_T1, ORC_VAR_S1, @@ -6064,14 +5810,6 @@ cogorc_unpack_axyz_3 (orc_uint8 * d1, const orc_uint32 * s1, int n) orc_program_set_backup_function (p, _backup_cogorc_unpack_axyz_3); orc_program_add_destination (p, 1, "d1"); orc_program_add_source (p, 4, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_append_2 (p, "select1lw", 0, ORC_VAR_T1, ORC_VAR_S1, @@ -6162,14 +5900,6 @@ cogorc_resample_horiz_1tap (orc_uint8 * d1, const orc_uint8 * s1, int p1, orc_program_set_backup_function (p, _backup_cogorc_resample_horiz_1tap); orc_program_add_destination (p, 1, "d1"); orc_program_add_source (p, 1, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_parameter (p, 4, "p1"); orc_program_add_parameter (p, 4, "p2"); @@ -6271,14 +6001,6 @@ cogorc_resample_horiz_2tap (orc_uint8 * d1, const orc_uint8 * s1, int p1, orc_program_set_backup_function (p, _backup_cogorc_resample_horiz_2tap); orc_program_add_destination (p, 1, "d1"); orc_program_add_source (p, 1, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_parameter (p, 4, "p1"); orc_program_add_parameter (p, 4, "p2"); @@ -6340,19 +6062,23 @@ cogorc_convert_I420_UYVY (orc_uint32 * d1, orc_uint32 * d2, /* 1: loadb */ var34 = ptr7[i]; /* 2: mergebw */ - var39.i = ((orc_uint8) var33) | ((orc_uint8) var34 << 8); + var39.i = ((orc_uint8) var33 & 0x00ff) | ((orc_uint8) var34 << 8); /* 3: loadw */ var35 = ptr4[i]; /* 4: mergebw */ - var36.x2[0] = ((orc_uint8) var39.x2[0]) | ((orc_uint8) var35.x2[0] << 8); - var36.x2[1] = ((orc_uint8) var39.x2[1]) | ((orc_uint8) var35.x2[1] << 8); + var36.x2[0] = + ((orc_uint8) var39.x2[0] & 0x00ff) | ((orc_uint8) var35.x2[0] << 8); + var36.x2[1] = + ((orc_uint8) var39.x2[1] & 0x00ff) | ((orc_uint8) var35.x2[1] << 8); /* 5: storel */ ptr0[i] = var36; /* 6: loadw */ var37 = ptr5[i]; /* 7: mergebw */ - var38.x2[0] = ((orc_uint8) var39.x2[0]) | ((orc_uint8) var37.x2[0] << 8); - var38.x2[1] = ((orc_uint8) var39.x2[1]) | ((orc_uint8) var37.x2[1] << 8); + var38.x2[0] = + ((orc_uint8) var39.x2[0] & 0x00ff) | ((orc_uint8) var37.x2[0] << 8); + var38.x2[1] = + ((orc_uint8) var39.x2[1] & 0x00ff) | ((orc_uint8) var37.x2[1] << 8); /* 8: storel */ ptr1[i] = var38; } @@ -6393,19 +6119,23 @@ _backup_cogorc_convert_I420_UYVY (OrcExecutor * ex) /* 1: loadb */ var34 = ptr7[i]; /* 2: mergebw */ - var39.i = ((orc_uint8) var33) | ((orc_uint8) var34 << 8); + var39.i = ((orc_uint8) var33 & 0x00ff) | ((orc_uint8) var34 << 8); /* 3: loadw */ var35 = ptr4[i]; /* 4: mergebw */ - var36.x2[0] = ((orc_uint8) var39.x2[0]) | ((orc_uint8) var35.x2[0] << 8); - var36.x2[1] = ((orc_uint8) var39.x2[1]) | ((orc_uint8) var35.x2[1] << 8); + var36.x2[0] = + ((orc_uint8) var39.x2[0] & 0x00ff) | ((orc_uint8) var35.x2[0] << 8); + var36.x2[1] = + ((orc_uint8) var39.x2[1] & 0x00ff) | ((orc_uint8) var35.x2[1] << 8); /* 5: storel */ ptr0[i] = var36; /* 6: loadw */ var37 = ptr5[i]; /* 7: mergebw */ - var38.x2[0] = ((orc_uint8) var39.x2[0]) | ((orc_uint8) var37.x2[0] << 8); - var38.x2[1] = ((orc_uint8) var39.x2[1]) | ((orc_uint8) var37.x2[1] << 8); + var38.x2[0] = + ((orc_uint8) var39.x2[0] & 0x00ff) | ((orc_uint8) var37.x2[0] << 8); + var38.x2[1] = + ((orc_uint8) var39.x2[1] & 0x00ff) | ((orc_uint8) var37.x2[1] << 8); /* 8: storel */ ptr1[i] = var38; } @@ -6436,14 +6166,6 @@ cogorc_convert_I420_UYVY (orc_uint32 * d1, orc_uint32 * d2, orc_program_add_source (p, 2, "s2"); orc_program_add_source (p, 1, "s3"); orc_program_add_source (p, 1, "s4"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_append_2 (p, "mergebw", 0, ORC_VAR_T1, ORC_VAR_S3, ORC_VAR_S4, @@ -6510,19 +6232,23 @@ cogorc_convert_I420_YUY2 (orc_uint32 * d1, orc_uint32 * d2, /* 1: loadb */ var34 = ptr7[i]; /* 2: mergebw */ - var39.i = ((orc_uint8) var33) | ((orc_uint8) var34 << 8); + var39.i = ((orc_uint8) var33 & 0x00ff) | ((orc_uint8) var34 << 8); /* 3: loadw */ var35 = ptr4[i]; /* 4: mergebw */ - var36.x2[0] = ((orc_uint8) var35.x2[0]) | ((orc_uint8) var39.x2[0] << 8); - var36.x2[1] = ((orc_uint8) var35.x2[1]) | ((orc_uint8) var39.x2[1] << 8); + var36.x2[0] = + ((orc_uint8) var35.x2[0] & 0x00ff) | ((orc_uint8) var39.x2[0] << 8); + var36.x2[1] = + ((orc_uint8) var35.x2[1] & 0x00ff) | ((orc_uint8) var39.x2[1] << 8); /* 5: storel */ ptr0[i] = var36; /* 6: loadw */ var37 = ptr5[i]; /* 7: mergebw */ - var38.x2[0] = ((orc_uint8) var37.x2[0]) | ((orc_uint8) var39.x2[0] << 8); - var38.x2[1] = ((orc_uint8) var37.x2[1]) | ((orc_uint8) var39.x2[1] << 8); + var38.x2[0] = + ((orc_uint8) var37.x2[0] & 0x00ff) | ((orc_uint8) var39.x2[0] << 8); + var38.x2[1] = + ((orc_uint8) var37.x2[1] & 0x00ff) | ((orc_uint8) var39.x2[1] << 8); /* 8: storel */ ptr1[i] = var38; } @@ -6563,19 +6289,23 @@ _backup_cogorc_convert_I420_YUY2 (OrcExecutor * ex) /* 1: loadb */ var34 = ptr7[i]; /* 2: mergebw */ - var39.i = ((orc_uint8) var33) | ((orc_uint8) var34 << 8); + var39.i = ((orc_uint8) var33 & 0x00ff) | ((orc_uint8) var34 << 8); /* 3: loadw */ var35 = ptr4[i]; /* 4: mergebw */ - var36.x2[0] = ((orc_uint8) var35.x2[0]) | ((orc_uint8) var39.x2[0] << 8); - var36.x2[1] = ((orc_uint8) var35.x2[1]) | ((orc_uint8) var39.x2[1] << 8); + var36.x2[0] = + ((orc_uint8) var35.x2[0] & 0x00ff) | ((orc_uint8) var39.x2[0] << 8); + var36.x2[1] = + ((orc_uint8) var35.x2[1] & 0x00ff) | ((orc_uint8) var39.x2[1] << 8); /* 5: storel */ ptr0[i] = var36; /* 6: loadw */ var37 = ptr5[i]; /* 7: mergebw */ - var38.x2[0] = ((orc_uint8) var37.x2[0]) | ((orc_uint8) var39.x2[0] << 8); - var38.x2[1] = ((orc_uint8) var37.x2[1]) | ((orc_uint8) var39.x2[1] << 8); + var38.x2[0] = + ((orc_uint8) var37.x2[0] & 0x00ff) | ((orc_uint8) var39.x2[0] << 8); + var38.x2[1] = + ((orc_uint8) var37.x2[1] & 0x00ff) | ((orc_uint8) var39.x2[1] << 8); /* 8: storel */ ptr1[i] = var38; } @@ -6606,14 +6336,6 @@ cogorc_convert_I420_YUY2 (orc_uint32 * d1, orc_uint32 * d2, orc_program_add_source (p, 2, "s2"); orc_program_add_source (p, 1, "s3"); orc_program_add_source (p, 1, "s4"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_append_2 (p, "mergebw", 0, ORC_VAR_T1, ORC_VAR_S3, ORC_VAR_S4, @@ -6688,21 +6410,23 @@ cogorc_convert_I420_AYUV (orc_uint32 * d1, orc_uint32 * d2, /* 1: loadupdb */ var43 = ptr7[i >> 1]; /* 2: mergebw */ - var44.i = ((orc_uint8) var42) | ((orc_uint8) var43 << 8); + var44.i = ((orc_uint8) var42 & 0x00ff) | ((orc_uint8) var43 << 8); /* 4: loadb */ var37 = ptr4[i]; /* 5: mergebw */ - var45.i = ((orc_uint8) var36) | ((orc_uint8) var37 << 8); + var45.i = ((orc_uint8) var36 & 0x00ff) | ((orc_uint8) var37 << 8); /* 6: mergewl */ - var38.i = ((orc_uint16) var45.i) | ((orc_uint16) var44.i << 16); + var38.i = + ((orc_uint16) var45.i & 0x0000ffff) | ((orc_uint16) var44.i << 16); /* 7: storel */ ptr0[i] = var38; /* 9: loadb */ var40 = ptr5[i]; /* 10: mergebw */ - var46.i = ((orc_uint8) var39) | ((orc_uint8) var40 << 8); + var46.i = ((orc_uint8) var39 & 0x00ff) | ((orc_uint8) var40 << 8); /* 11: mergewl */ - var41.i = ((orc_uint16) var46.i) | ((orc_uint16) var44.i << 16); + var41.i = + ((orc_uint16) var46.i & 0x0000ffff) | ((orc_uint16) var44.i << 16); /* 12: storel */ ptr1[i] = var41; } @@ -6751,21 +6475,23 @@ _backup_cogorc_convert_I420_AYUV (OrcExecutor * ex) /* 1: loadupdb */ var43 = ptr7[i >> 1]; /* 2: mergebw */ - var44.i = ((orc_uint8) var42) | ((orc_uint8) var43 << 8); + var44.i = ((orc_uint8) var42 & 0x00ff) | ((orc_uint8) var43 << 8); /* 4: loadb */ var37 = ptr4[i]; /* 5: mergebw */ - var45.i = ((orc_uint8) var36) | ((orc_uint8) var37 << 8); + var45.i = ((orc_uint8) var36 & 0x00ff) | ((orc_uint8) var37 << 8); /* 6: mergewl */ - var38.i = ((orc_uint16) var45.i) | ((orc_uint16) var44.i << 16); + var38.i = + ((orc_uint16) var45.i & 0x0000ffff) | ((orc_uint16) var44.i << 16); /* 7: storel */ ptr0[i] = var38; /* 9: loadb */ var40 = ptr5[i]; /* 10: mergebw */ - var46.i = ((orc_uint8) var39) | ((orc_uint8) var40 << 8); + var46.i = ((orc_uint8) var39 & 0x00ff) | ((orc_uint8) var40 << 8); /* 11: mergewl */ - var41.i = ((orc_uint16) var46.i) | ((orc_uint16) var44.i << 16); + var41.i = + ((orc_uint16) var46.i & 0x0000ffff) | ((orc_uint16) var44.i << 16); /* 12: storel */ ptr1[i] = var41; } @@ -6797,13 +6523,6 @@ cogorc_convert_I420_AYUV (orc_uint32 * d1, orc_uint32 * d2, orc_program_add_source (p, 1, "s3"); orc_program_add_source (p, 1, "s4"); orc_program_add_constant (p, 1, 0x000000ff, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 2, "t2"); orc_program_add_temporary (p, 1, "t3"); @@ -6995,14 +6714,6 @@ cogorc_convert_YUY2_I420 (orc_uint16 * d1, orc_uint16 * d2, orc_uint8 * d3, orc_program_add_destination (p, 1, "d4"); orc_program_add_source (p, 4, "s1"); orc_program_add_source (p, 4, "s2"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 2, "t2"); orc_program_add_temporary (p, 2, "t3"); @@ -7123,14 +6834,6 @@ cogorc_convert_UYVY_YUY2 (orc_uint32 * d1, int d1_stride, const orc_uint32 * s1, orc_program_set_backup_function (p, _backup_cogorc_convert_UYVY_YUY2); orc_program_add_destination (p, 4, "d1"); orc_program_add_source (p, 4, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_append_2 (p, "swapw", 1, ORC_VAR_D1, ORC_VAR_S1, ORC_VAR_D1, ORC_VAR_D1); @@ -7256,14 +6959,6 @@ cogorc_planar_chroma_420_422 (orc_uint8 * d1, int d1_stride, orc_uint8 * d2, orc_program_add_destination (p, 1, "d1"); orc_program_add_destination (p, 1, "d2"); orc_program_add_source (p, 1, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_append_2 (p, "copyb", 0, ORC_VAR_D1, ORC_VAR_S1, ORC_VAR_D1, ORC_VAR_D1); @@ -7381,14 +7076,6 @@ cogorc_planar_chroma_420_444 (orc_uint16 * d1, int d1_stride, orc_uint16 * d2, orc_program_add_destination (p, 2, "d1"); orc_program_add_destination (p, 2, "d2"); orc_program_add_source (p, 1, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_append_2 (p, "splatbw", 0, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_D1, @@ -7500,14 +7187,6 @@ cogorc_planar_chroma_422_444 (orc_uint16 * d1, int d1_stride, orc_program_set_backup_function (p, _backup_cogorc_planar_chroma_422_444); orc_program_add_destination (p, 2, "d1"); orc_program_add_source (p, 1, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_append_2 (p, "splatbw", 0, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_D1, @@ -7625,14 +7304,6 @@ cogorc_planar_chroma_444_422 (orc_uint8 * d1, int d1_stride, orc_program_set_backup_function (p, _backup_cogorc_planar_chroma_444_422); orc_program_add_destination (p, 1, "d1"); orc_program_add_source (p, 2, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 1, "t1"); orc_program_add_temporary (p, 1, "t2"); @@ -7776,14 +7447,6 @@ cogorc_planar_chroma_444_420 (orc_uint8 * d1, int d1_stride, orc_program_add_destination (p, 1, "d1"); orc_program_add_source (p, 2, "s1"); orc_program_add_source (p, 2, "s2"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 1, "t2"); orc_program_add_temporary (p, 1, "t3"); @@ -7910,14 +7573,6 @@ cogorc_planar_chroma_422_420 (orc_uint8 * d1, int d1_stride, orc_program_add_destination (p, 1, "d1"); orc_program_add_source (p, 1, "s1"); orc_program_add_source (p, 1, "s2"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_append_2 (p, "avgub", 0, ORC_VAR_D1, ORC_VAR_S1, ORC_VAR_S2, ORC_VAR_D1); @@ -7979,15 +7634,20 @@ cogorc_convert_YUY2_AYUV (orc_uint64 * d1, int d1_stride, const orc_uint32 * s1, var39.x2[1] = (var36.x2[1] >> 8) & 0xff; var40.x2[1] = var36.x2[1] & 0xff; /* 3: mergebw */ - var41.x2[0] = ((orc_uint8) var37.x2[0]) | ((orc_uint8) var40.x2[0] << 8); - var41.x2[1] = ((orc_uint8) var37.x2[1]) | ((orc_uint8) var40.x2[1] << 8); + var41.x2[0] = + ((orc_uint8) var37.x2[0] & 0x00ff) | ((orc_uint8) var40.x2[0] << 8); + var41.x2[1] = + ((orc_uint8) var37.x2[1] & 0x00ff) | ((orc_uint8) var40.x2[1] << 8); /* 4: mergewl */ - var42.i = ((orc_uint16) var39.i) | ((orc_uint16) var39.i << 16); + var42.i = + ((orc_uint16) var39.i & 0x0000ffff) | ((orc_uint16) var39.i << 16); /* 5: mergewl */ var38.x2[0] = - ((orc_uint16) var41.x2[0]) | ((orc_uint16) var42.x2[0] << 16); + ((orc_uint16) var41.x2[0] & 0x0000ffff) | ((orc_uint16) var42. + x2[0] << 16); var38.x2[1] = - ((orc_uint16) var41.x2[1]) | ((orc_uint16) var42.x2[1] << 16); + ((orc_uint16) var41.x2[1] & 0x0000ffff) | ((orc_uint16) var42. + x2[1] << 16); /* 6: storeq */ ptr0[i] = var38; } @@ -8030,15 +7690,20 @@ _backup_cogorc_convert_YUY2_AYUV (OrcExecutor * ex) var39.x2[1] = (var36.x2[1] >> 8) & 0xff; var40.x2[1] = var36.x2[1] & 0xff; /* 3: mergebw */ - var41.x2[0] = ((orc_uint8) var37.x2[0]) | ((orc_uint8) var40.x2[0] << 8); - var41.x2[1] = ((orc_uint8) var37.x2[1]) | ((orc_uint8) var40.x2[1] << 8); + var41.x2[0] = + ((orc_uint8) var37.x2[0] & 0x00ff) | ((orc_uint8) var40.x2[0] << 8); + var41.x2[1] = + ((orc_uint8) var37.x2[1] & 0x00ff) | ((orc_uint8) var40.x2[1] << 8); /* 4: mergewl */ - var42.i = ((orc_uint16) var39.i) | ((orc_uint16) var39.i << 16); + var42.i = + ((orc_uint16) var39.i & 0x0000ffff) | ((orc_uint16) var39.i << 16); /* 5: mergewl */ var38.x2[0] = - ((orc_uint16) var41.x2[0]) | ((orc_uint16) var42.x2[0] << 16); + ((orc_uint16) var41.x2[0] & 0x0000ffff) | ((orc_uint16) var42. + x2[0] << 16); var38.x2[1] = - ((orc_uint16) var41.x2[1]) | ((orc_uint16) var42.x2[1] << 16); + ((orc_uint16) var41.x2[1] & 0x0000ffff) | ((orc_uint16) var42. + x2[1] << 16); /* 6: storeq */ ptr0[i] = var38; } @@ -8067,13 +7732,6 @@ cogorc_convert_YUY2_AYUV (orc_uint64 * d1, int d1_stride, const orc_uint32 * s1, orc_program_add_destination (p, 8, "d1"); orc_program_add_source (p, 4, "s1"); orc_program_add_constant (p, 2, 0x000000ff, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 2, "t2"); orc_program_add_temporary (p, 4, "t3"); @@ -8143,15 +7801,20 @@ cogorc_convert_UYVY_AYUV (orc_uint64 * d1, int d1_stride, const orc_uint32 * s1, var39.x2[1] = (var36.x2[1] >> 8) & 0xff; var40.x2[1] = var36.x2[1] & 0xff; /* 3: mergebw */ - var41.x2[0] = ((orc_uint8) var37.x2[0]) | ((orc_uint8) var39.x2[0] << 8); - var41.x2[1] = ((orc_uint8) var37.x2[1]) | ((orc_uint8) var39.x2[1] << 8); + var41.x2[0] = + ((orc_uint8) var37.x2[0] & 0x00ff) | ((orc_uint8) var39.x2[0] << 8); + var41.x2[1] = + ((orc_uint8) var37.x2[1] & 0x00ff) | ((orc_uint8) var39.x2[1] << 8); /* 4: mergewl */ - var42.i = ((orc_uint16) var40.i) | ((orc_uint16) var40.i << 16); + var42.i = + ((orc_uint16) var40.i & 0x0000ffff) | ((orc_uint16) var40.i << 16); /* 5: mergewl */ var38.x2[0] = - ((orc_uint16) var41.x2[0]) | ((orc_uint16) var42.x2[0] << 16); + ((orc_uint16) var41.x2[0] & 0x0000ffff) | ((orc_uint16) var42. + x2[0] << 16); var38.x2[1] = - ((orc_uint16) var41.x2[1]) | ((orc_uint16) var42.x2[1] << 16); + ((orc_uint16) var41.x2[1] & 0x0000ffff) | ((orc_uint16) var42. + x2[1] << 16); /* 6: storeq */ ptr0[i] = var38; } @@ -8194,15 +7857,20 @@ _backup_cogorc_convert_UYVY_AYUV (OrcExecutor * ex) var39.x2[1] = (var36.x2[1] >> 8) & 0xff; var40.x2[1] = var36.x2[1] & 0xff; /* 3: mergebw */ - var41.x2[0] = ((orc_uint8) var37.x2[0]) | ((orc_uint8) var39.x2[0] << 8); - var41.x2[1] = ((orc_uint8) var37.x2[1]) | ((orc_uint8) var39.x2[1] << 8); + var41.x2[0] = + ((orc_uint8) var37.x2[0] & 0x00ff) | ((orc_uint8) var39.x2[0] << 8); + var41.x2[1] = + ((orc_uint8) var37.x2[1] & 0x00ff) | ((orc_uint8) var39.x2[1] << 8); /* 4: mergewl */ - var42.i = ((orc_uint16) var40.i) | ((orc_uint16) var40.i << 16); + var42.i = + ((orc_uint16) var40.i & 0x0000ffff) | ((orc_uint16) var40.i << 16); /* 5: mergewl */ var38.x2[0] = - ((orc_uint16) var41.x2[0]) | ((orc_uint16) var42.x2[0] << 16); + ((orc_uint16) var41.x2[0] & 0x0000ffff) | ((orc_uint16) var42. + x2[0] << 16); var38.x2[1] = - ((orc_uint16) var41.x2[1]) | ((orc_uint16) var42.x2[1] << 16); + ((orc_uint16) var41.x2[1] & 0x0000ffff) | ((orc_uint16) var42. + x2[1] << 16); /* 6: storeq */ ptr0[i] = var38; } @@ -8231,13 +7899,6 @@ cogorc_convert_UYVY_AYUV (orc_uint64 * d1, int d1_stride, const orc_uint32 * s1, orc_program_add_destination (p, 8, "d1"); orc_program_add_source (p, 4, "s1"); orc_program_add_constant (p, 2, 0x000000ff, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 2, "t2"); orc_program_add_temporary (p, 4, "t3"); @@ -8390,14 +8051,6 @@ cogorc_convert_YUY2_Y42B (orc_uint16 * d1, int d1_stride, orc_uint8 * d2, orc_program_add_destination (p, 1, "d2"); orc_program_add_destination (p, 1, "d3"); orc_program_add_source (p, 4, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_append_2 (p, "splitwb", 1, ORC_VAR_T1, ORC_VAR_D1, ORC_VAR_S1, @@ -8547,14 +8200,6 @@ cogorc_convert_UYVY_Y42B (orc_uint16 * d1, int d1_stride, orc_uint8 * d2, orc_program_add_destination (p, 1, "d2"); orc_program_add_destination (p, 1, "d3"); orc_program_add_source (p, 4, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_append_2 (p, "splitwb", 1, ORC_VAR_D1, ORC_VAR_T1, ORC_VAR_S1, @@ -8716,14 +8361,6 @@ cogorc_convert_YUY2_Y444 (orc_uint16 * d1, int d1_stride, orc_uint16 * d2, orc_program_add_destination (p, 2, "d2"); orc_program_add_destination (p, 2, "d3"); orc_program_add_source (p, 4, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 1, "t2"); orc_program_add_temporary (p, 1, "t3"); @@ -8891,14 +8528,6 @@ cogorc_convert_UYVY_Y444 (orc_uint16 * d1, int d1_stride, orc_uint16 * d2, orc_program_add_destination (p, 2, "d2"); orc_program_add_destination (p, 2, "d3"); orc_program_add_source (p, 4, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 1, "t2"); orc_program_add_temporary (p, 1, "t3"); @@ -9086,14 +8715,6 @@ cogorc_convert_UYVY_I420 (orc_uint16 * d1, orc_uint16 * d2, orc_uint8 * d3, orc_program_add_destination (p, 1, "d4"); orc_program_add_source (p, 4, "s1"); orc_program_add_source (p, 4, "s2"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 2, "t2"); orc_program_add_temporary (p, 2, "t3"); @@ -9358,14 +8979,6 @@ cogorc_convert_AYUV_I420 (orc_uint16 * d1, int d1_stride, orc_uint16 * d2, orc_program_add_destination (p, 1, "d4"); orc_program_add_source (p, 8, "s1"); orc_program_add_source (p, 8, "s2"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 4, "t1"); orc_program_add_temporary (p, 4, "t2"); orc_program_add_temporary (p, 4, "t3"); @@ -9468,8 +9081,10 @@ cogorc_convert_AYUV_YUY2 (orc_uint32 * d1, int d1_stride, const orc_uint64 * s1, var44.x2[0] = ((orc_uint16) var40.x2[0] >> 8) & 0xff; var44.x2[1] = ((orc_uint16) var40.x2[1] >> 8) & 0xff; /* 5: mergebw */ - var38.x2[0] = ((orc_uint8) var44.x2[0]) | ((orc_uint8) var43.x2[0] << 8); - var38.x2[1] = ((orc_uint8) var44.x2[1]) | ((orc_uint8) var43.x2[1] << 8); + var38.x2[0] = + ((orc_uint8) var44.x2[0] & 0x00ff) | ((orc_uint8) var43.x2[0] << 8); + var38.x2[1] = + ((orc_uint8) var44.x2[1] & 0x00ff) | ((orc_uint8) var43.x2[1] << 8); /* 6: storel */ ptr0[i] = var38; } @@ -9521,8 +9136,10 @@ _backup_cogorc_convert_AYUV_YUY2 (OrcExecutor * ex) var44.x2[0] = ((orc_uint16) var40.x2[0] >> 8) & 0xff; var44.x2[1] = ((orc_uint16) var40.x2[1] >> 8) & 0xff; /* 5: mergebw */ - var38.x2[0] = ((orc_uint8) var44.x2[0]) | ((orc_uint8) var43.x2[0] << 8); - var38.x2[1] = ((orc_uint8) var44.x2[1]) | ((orc_uint8) var43.x2[1] << 8); + var38.x2[0] = + ((orc_uint8) var44.x2[0] & 0x00ff) | ((orc_uint8) var43.x2[0] << 8); + var38.x2[1] = + ((orc_uint8) var44.x2[1] & 0x00ff) | ((orc_uint8) var43.x2[1] << 8); /* 6: storel */ ptr0[i] = var38; } @@ -9550,14 +9167,6 @@ cogorc_convert_AYUV_YUY2 (orc_uint32 * d1, int d1_stride, const orc_uint64 * s1, orc_program_set_backup_function (p, _backup_cogorc_convert_AYUV_YUY2); orc_program_add_destination (p, 4, "d1"); orc_program_add_source (p, 8, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 2, "t2"); orc_program_add_temporary (p, 2, "t3"); @@ -9639,8 +9248,10 @@ cogorc_convert_AYUV_UYVY (orc_uint32 * d1, int d1_stride, const orc_uint64 * s1, var44.x2[0] = ((orc_uint16) var40.x2[0] >> 8) & 0xff; var44.x2[1] = ((orc_uint16) var40.x2[1] >> 8) & 0xff; /* 5: mergebw */ - var38.x2[0] = ((orc_uint8) var43.x2[0]) | ((orc_uint8) var44.x2[0] << 8); - var38.x2[1] = ((orc_uint8) var43.x2[1]) | ((orc_uint8) var44.x2[1] << 8); + var38.x2[0] = + ((orc_uint8) var43.x2[0] & 0x00ff) | ((orc_uint8) var44.x2[0] << 8); + var38.x2[1] = + ((orc_uint8) var43.x2[1] & 0x00ff) | ((orc_uint8) var44.x2[1] << 8); /* 6: storel */ ptr0[i] = var38; } @@ -9692,8 +9303,10 @@ _backup_cogorc_convert_AYUV_UYVY (OrcExecutor * ex) var44.x2[0] = ((orc_uint16) var40.x2[0] >> 8) & 0xff; var44.x2[1] = ((orc_uint16) var40.x2[1] >> 8) & 0xff; /* 5: mergebw */ - var38.x2[0] = ((orc_uint8) var43.x2[0]) | ((orc_uint8) var44.x2[0] << 8); - var38.x2[1] = ((orc_uint8) var43.x2[1]) | ((orc_uint8) var44.x2[1] << 8); + var38.x2[0] = + ((orc_uint8) var43.x2[0] & 0x00ff) | ((orc_uint8) var44.x2[0] << 8); + var38.x2[1] = + ((orc_uint8) var43.x2[1] & 0x00ff) | ((orc_uint8) var44.x2[1] << 8); /* 6: storel */ ptr0[i] = var38; } @@ -9721,14 +9334,6 @@ cogorc_convert_AYUV_UYVY (orc_uint32 * d1, int d1_stride, const orc_uint64 * s1, orc_program_set_backup_function (p, _backup_cogorc_convert_AYUV_UYVY); orc_program_add_destination (p, 4, "d1"); orc_program_add_source (p, 8, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 2, "t2"); orc_program_add_temporary (p, 2, "t3"); @@ -9914,14 +9519,6 @@ cogorc_convert_AYUV_Y42B (orc_uint16 * d1, int d1_stride, orc_uint8 * d2, orc_program_add_destination (p, 1, "d2"); orc_program_add_destination (p, 1, "d3"); orc_program_add_source (p, 8, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 4, "t1"); orc_program_add_temporary (p, 4, "t2"); orc_program_add_temporary (p, 2, "t3"); @@ -10082,14 +9679,6 @@ cogorc_convert_AYUV_Y444 (orc_uint8 * d1, int d1_stride, orc_uint8 * d2, orc_program_add_destination (p, 1, "d2"); orc_program_add_destination (p, 1, "d3"); orc_program_add_source (p, 4, "s1"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 2, "t2"); @@ -10156,12 +9745,14 @@ cogorc_convert_Y42B_YUY2 (orc_uint32 * d1, int d1_stride, const orc_uint16 * s1, /* 1: loadb */ var34 = ptr6[i]; /* 2: mergebw */ - var37.i = ((orc_uint8) var33) | ((orc_uint8) var34 << 8); + var37.i = ((orc_uint8) var33 & 0x00ff) | ((orc_uint8) var34 << 8); /* 3: loadw */ var35 = ptr4[i]; /* 4: mergebw */ - var36.x2[0] = ((orc_uint8) var35.x2[0]) | ((orc_uint8) var37.x2[0] << 8); - var36.x2[1] = ((orc_uint8) var35.x2[1]) | ((orc_uint8) var37.x2[1] << 8); + var36.x2[0] = + ((orc_uint8) var35.x2[0] & 0x00ff) | ((orc_uint8) var37.x2[0] << 8); + var36.x2[1] = + ((orc_uint8) var35.x2[1] & 0x00ff) | ((orc_uint8) var37.x2[1] << 8); /* 5: storel */ ptr0[i] = var36; } @@ -10200,12 +9791,14 @@ _backup_cogorc_convert_Y42B_YUY2 (OrcExecutor * ex) /* 1: loadb */ var34 = ptr6[i]; /* 2: mergebw */ - var37.i = ((orc_uint8) var33) | ((orc_uint8) var34 << 8); + var37.i = ((orc_uint8) var33 & 0x00ff) | ((orc_uint8) var34 << 8); /* 3: loadw */ var35 = ptr4[i]; /* 4: mergebw */ - var36.x2[0] = ((orc_uint8) var35.x2[0]) | ((orc_uint8) var37.x2[0] << 8); - var36.x2[1] = ((orc_uint8) var35.x2[1]) | ((orc_uint8) var37.x2[1] << 8); + var36.x2[0] = + ((orc_uint8) var35.x2[0] & 0x00ff) | ((orc_uint8) var37.x2[0] << 8); + var36.x2[1] = + ((orc_uint8) var35.x2[1] & 0x00ff) | ((orc_uint8) var37.x2[1] << 8); /* 5: storel */ ptr0[i] = var36; } @@ -10236,14 +9829,6 @@ cogorc_convert_Y42B_YUY2 (orc_uint32 * d1, int d1_stride, const orc_uint16 * s1, orc_program_add_source (p, 2, "s1"); orc_program_add_source (p, 1, "s2"); orc_program_add_source (p, 1, "s3"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_append_2 (p, "mergebw", 0, ORC_VAR_T1, ORC_VAR_S2, ORC_VAR_S3, @@ -10307,12 +9892,14 @@ cogorc_convert_Y42B_UYVY (orc_uint32 * d1, int d1_stride, const orc_uint16 * s1, /* 1: loadb */ var34 = ptr6[i]; /* 2: mergebw */ - var37.i = ((orc_uint8) var33) | ((orc_uint8) var34 << 8); + var37.i = ((orc_uint8) var33 & 0x00ff) | ((orc_uint8) var34 << 8); /* 3: loadw */ var35 = ptr4[i]; /* 4: mergebw */ - var36.x2[0] = ((orc_uint8) var37.x2[0]) | ((orc_uint8) var35.x2[0] << 8); - var36.x2[1] = ((orc_uint8) var37.x2[1]) | ((orc_uint8) var35.x2[1] << 8); + var36.x2[0] = + ((orc_uint8) var37.x2[0] & 0x00ff) | ((orc_uint8) var35.x2[0] << 8); + var36.x2[1] = + ((orc_uint8) var37.x2[1] & 0x00ff) | ((orc_uint8) var35.x2[1] << 8); /* 5: storel */ ptr0[i] = var36; } @@ -10351,12 +9938,14 @@ _backup_cogorc_convert_Y42B_UYVY (OrcExecutor * ex) /* 1: loadb */ var34 = ptr6[i]; /* 2: mergebw */ - var37.i = ((orc_uint8) var33) | ((orc_uint8) var34 << 8); + var37.i = ((orc_uint8) var33 & 0x00ff) | ((orc_uint8) var34 << 8); /* 3: loadw */ var35 = ptr4[i]; /* 4: mergebw */ - var36.x2[0] = ((orc_uint8) var37.x2[0]) | ((orc_uint8) var35.x2[0] << 8); - var36.x2[1] = ((orc_uint8) var37.x2[1]) | ((orc_uint8) var35.x2[1] << 8); + var36.x2[0] = + ((orc_uint8) var37.x2[0] & 0x00ff) | ((orc_uint8) var35.x2[0] << 8); + var36.x2[1] = + ((orc_uint8) var37.x2[1] & 0x00ff) | ((orc_uint8) var35.x2[1] << 8); /* 5: storel */ ptr0[i] = var36; } @@ -10387,14 +9976,6 @@ cogorc_convert_Y42B_UYVY (orc_uint32 * d1, int d1_stride, const orc_uint16 * s1, orc_program_add_source (p, 2, "s1"); orc_program_add_source (p, 1, "s2"); orc_program_add_source (p, 1, "s3"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_append_2 (p, "mergebw", 0, ORC_VAR_T1, ORC_VAR_S2, ORC_VAR_S3, @@ -10464,19 +10045,24 @@ cogorc_convert_Y42B_AYUV (orc_uint64 * d1, int d1_stride, const orc_uint16 * s1, /* 1: loadb */ var37 = ptr6[i]; /* 2: mergebw */ - var41.i = ((orc_uint8) var36) | ((orc_uint8) var37 << 8); + var41.i = ((orc_uint8) var36 & 0x00ff) | ((orc_uint8) var37 << 8); /* 4: loadw */ var39 = ptr4[i]; /* 5: mergebw */ - var42.x2[0] = ((orc_uint8) var38.x2[0]) | ((orc_uint8) var39.x2[0] << 8); - var42.x2[1] = ((orc_uint8) var38.x2[1]) | ((orc_uint8) var39.x2[1] << 8); + var42.x2[0] = + ((orc_uint8) var38.x2[0] & 0x00ff) | ((orc_uint8) var39.x2[0] << 8); + var42.x2[1] = + ((orc_uint8) var38.x2[1] & 0x00ff) | ((orc_uint8) var39.x2[1] << 8); /* 6: mergewl */ - var43.i = ((orc_uint16) var41.i) | ((orc_uint16) var41.i << 16); + var43.i = + ((orc_uint16) var41.i & 0x0000ffff) | ((orc_uint16) var41.i << 16); /* 7: mergewl */ var40.x2[0] = - ((orc_uint16) var42.x2[0]) | ((orc_uint16) var43.x2[0] << 16); + ((orc_uint16) var42.x2[0] & 0x0000ffff) | ((orc_uint16) var43. + x2[0] << 16); var40.x2[1] = - ((orc_uint16) var42.x2[1]) | ((orc_uint16) var43.x2[1] << 16); + ((orc_uint16) var42.x2[1] & 0x0000ffff) | ((orc_uint16) var43. + x2[1] << 16); /* 8: storeq */ ptr0[i] = var40; } @@ -10521,19 +10107,24 @@ _backup_cogorc_convert_Y42B_AYUV (OrcExecutor * ex) /* 1: loadb */ var37 = ptr6[i]; /* 2: mergebw */ - var41.i = ((orc_uint8) var36) | ((orc_uint8) var37 << 8); + var41.i = ((orc_uint8) var36 & 0x00ff) | ((orc_uint8) var37 << 8); /* 4: loadw */ var39 = ptr4[i]; /* 5: mergebw */ - var42.x2[0] = ((orc_uint8) var38.x2[0]) | ((orc_uint8) var39.x2[0] << 8); - var42.x2[1] = ((orc_uint8) var38.x2[1]) | ((orc_uint8) var39.x2[1] << 8); + var42.x2[0] = + ((orc_uint8) var38.x2[0] & 0x00ff) | ((orc_uint8) var39.x2[0] << 8); + var42.x2[1] = + ((orc_uint8) var38.x2[1] & 0x00ff) | ((orc_uint8) var39.x2[1] << 8); /* 6: mergewl */ - var43.i = ((orc_uint16) var41.i) | ((orc_uint16) var41.i << 16); + var43.i = + ((orc_uint16) var41.i & 0x0000ffff) | ((orc_uint16) var41.i << 16); /* 7: mergewl */ var40.x2[0] = - ((orc_uint16) var42.x2[0]) | ((orc_uint16) var43.x2[0] << 16); + ((orc_uint16) var42.x2[0] & 0x0000ffff) | ((orc_uint16) var43. + x2[0] << 16); var40.x2[1] = - ((orc_uint16) var42.x2[1]) | ((orc_uint16) var43.x2[1] << 16); + ((orc_uint16) var42.x2[1] & 0x0000ffff) | ((orc_uint16) var43. + x2[1] << 16); /* 8: storeq */ ptr0[i] = var40; } @@ -10565,13 +10156,6 @@ cogorc_convert_Y42B_AYUV (orc_uint64 * d1, int d1_stride, const orc_uint16 * s1, orc_program_add_source (p, 1, "s2"); orc_program_add_source (p, 1, "s3"); orc_program_add_constant (p, 1, 0x000000ff, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 2, "t2"); orc_program_add_temporary (p, 4, "t3"); @@ -10645,8 +10229,10 @@ cogorc_convert_Y444_YUY2 (orc_uint32 * d1, int d1_stride, const orc_uint16 * s1, /* 1: loadw */ var37 = ptr6[i]; /* 2: mergebw */ - var40.x2[0] = ((orc_uint8) var36.x2[0]) | ((orc_uint8) var37.x2[0] << 8); - var40.x2[1] = ((orc_uint8) var36.x2[1]) | ((orc_uint8) var37.x2[1] << 8); + var40.x2[0] = + ((orc_uint8) var36.x2[0] & 0x00ff) | ((orc_uint8) var37.x2[0] << 8); + var40.x2[1] = + ((orc_uint8) var36.x2[1] & 0x00ff) | ((orc_uint8) var37.x2[1] << 8); /* 3: splitlw */ var41.i = (var40.i >> 16) & 0xffff; var42.i = var40.i & 0xffff; @@ -10658,8 +10244,10 @@ cogorc_convert_Y444_YUY2 (orc_uint32 * d1, int d1_stride, const orc_uint16 * s1, /* 5: loadw */ var38 = ptr4[i]; /* 6: mergebw */ - var39.x2[0] = ((orc_uint8) var38.x2[0]) | ((orc_uint8) var43.x2[0] << 8); - var39.x2[1] = ((orc_uint8) var38.x2[1]) | ((orc_uint8) var43.x2[1] << 8); + var39.x2[0] = + ((orc_uint8) var38.x2[0] & 0x00ff) | ((orc_uint8) var43.x2[0] << 8); + var39.x2[1] = + ((orc_uint8) var38.x2[1] & 0x00ff) | ((orc_uint8) var43.x2[1] << 8); /* 7: storel */ ptr0[i] = var39; } @@ -10701,8 +10289,10 @@ _backup_cogorc_convert_Y444_YUY2 (OrcExecutor * ex) /* 1: loadw */ var37 = ptr6[i]; /* 2: mergebw */ - var40.x2[0] = ((orc_uint8) var36.x2[0]) | ((orc_uint8) var37.x2[0] << 8); - var40.x2[1] = ((orc_uint8) var36.x2[1]) | ((orc_uint8) var37.x2[1] << 8); + var40.x2[0] = + ((orc_uint8) var36.x2[0] & 0x00ff) | ((orc_uint8) var37.x2[0] << 8); + var40.x2[1] = + ((orc_uint8) var36.x2[1] & 0x00ff) | ((orc_uint8) var37.x2[1] << 8); /* 3: splitlw */ var41.i = (var40.i >> 16) & 0xffff; var42.i = var40.i & 0xffff; @@ -10714,8 +10304,10 @@ _backup_cogorc_convert_Y444_YUY2 (OrcExecutor * ex) /* 5: loadw */ var38 = ptr4[i]; /* 6: mergebw */ - var39.x2[0] = ((orc_uint8) var38.x2[0]) | ((orc_uint8) var43.x2[0] << 8); - var39.x2[1] = ((orc_uint8) var38.x2[1]) | ((orc_uint8) var43.x2[1] << 8); + var39.x2[0] = + ((orc_uint8) var38.x2[0] & 0x00ff) | ((orc_uint8) var43.x2[0] << 8); + var39.x2[1] = + ((orc_uint8) var38.x2[1] & 0x00ff) | ((orc_uint8) var43.x2[1] << 8); /* 7: storel */ ptr0[i] = var39; } @@ -10746,14 +10338,6 @@ cogorc_convert_Y444_YUY2 (orc_uint32 * d1, int d1_stride, const orc_uint16 * s1, orc_program_add_source (p, 2, "s1"); orc_program_add_source (p, 2, "s2"); orc_program_add_source (p, 2, "s3"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 4, "t2"); orc_program_add_temporary (p, 2, "t3"); @@ -10827,8 +10411,10 @@ cogorc_convert_Y444_UYVY (orc_uint32 * d1, int d1_stride, const orc_uint16 * s1, /* 1: loadw */ var37 = ptr6[i]; /* 2: mergebw */ - var40.x2[0] = ((orc_uint8) var36.x2[0]) | ((orc_uint8) var37.x2[0] << 8); - var40.x2[1] = ((orc_uint8) var36.x2[1]) | ((orc_uint8) var37.x2[1] << 8); + var40.x2[0] = + ((orc_uint8) var36.x2[0] & 0x00ff) | ((orc_uint8) var37.x2[0] << 8); + var40.x2[1] = + ((orc_uint8) var36.x2[1] & 0x00ff) | ((orc_uint8) var37.x2[1] << 8); /* 3: splitlw */ var41.i = (var40.i >> 16) & 0xffff; var42.i = var40.i & 0xffff; @@ -10840,8 +10426,10 @@ cogorc_convert_Y444_UYVY (orc_uint32 * d1, int d1_stride, const orc_uint16 * s1, /* 5: loadw */ var38 = ptr4[i]; /* 6: mergebw */ - var39.x2[0] = ((orc_uint8) var43.x2[0]) | ((orc_uint8) var38.x2[0] << 8); - var39.x2[1] = ((orc_uint8) var43.x2[1]) | ((orc_uint8) var38.x2[1] << 8); + var39.x2[0] = + ((orc_uint8) var43.x2[0] & 0x00ff) | ((orc_uint8) var38.x2[0] << 8); + var39.x2[1] = + ((orc_uint8) var43.x2[1] & 0x00ff) | ((orc_uint8) var38.x2[1] << 8); /* 7: storel */ ptr0[i] = var39; } @@ -10883,8 +10471,10 @@ _backup_cogorc_convert_Y444_UYVY (OrcExecutor * ex) /* 1: loadw */ var37 = ptr6[i]; /* 2: mergebw */ - var40.x2[0] = ((orc_uint8) var36.x2[0]) | ((orc_uint8) var37.x2[0] << 8); - var40.x2[1] = ((orc_uint8) var36.x2[1]) | ((orc_uint8) var37.x2[1] << 8); + var40.x2[0] = + ((orc_uint8) var36.x2[0] & 0x00ff) | ((orc_uint8) var37.x2[0] << 8); + var40.x2[1] = + ((orc_uint8) var36.x2[1] & 0x00ff) | ((orc_uint8) var37.x2[1] << 8); /* 3: splitlw */ var41.i = (var40.i >> 16) & 0xffff; var42.i = var40.i & 0xffff; @@ -10896,8 +10486,10 @@ _backup_cogorc_convert_Y444_UYVY (OrcExecutor * ex) /* 5: loadw */ var38 = ptr4[i]; /* 6: mergebw */ - var39.x2[0] = ((orc_uint8) var43.x2[0]) | ((orc_uint8) var38.x2[0] << 8); - var39.x2[1] = ((orc_uint8) var43.x2[1]) | ((orc_uint8) var38.x2[1] << 8); + var39.x2[0] = + ((orc_uint8) var43.x2[0] & 0x00ff) | ((orc_uint8) var38.x2[0] << 8); + var39.x2[1] = + ((orc_uint8) var43.x2[1] & 0x00ff) | ((orc_uint8) var38.x2[1] << 8); /* 7: storel */ ptr0[i] = var39; } @@ -10928,14 +10520,6 @@ cogorc_convert_Y444_UYVY (orc_uint32 * d1, int d1_stride, const orc_uint16 * s1, orc_program_add_source (p, 2, "s1"); orc_program_add_source (p, 2, "s2"); orc_program_add_source (p, 2, "s3"); - orc_program_add_constant (p, 0, 0x00000000, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 4, "t2"); orc_program_add_temporary (p, 2, "t3"); @@ -11010,13 +10594,14 @@ cogorc_convert_Y444_AYUV (orc_uint32 * d1, int d1_stride, const orc_uint8 * s1, /* 1: loadb */ var35 = ptr6[i]; /* 2: mergebw */ - var39.i = ((orc_uint8) var34) | ((orc_uint8) var35 << 8); + var39.i = ((orc_uint8) var34 & 0x00ff) | ((orc_uint8) var35 << 8); /* 4: loadb */ var37 = ptr4[i]; /* 5: mergebw */ - var40.i = ((orc_uint8) var36) | ((orc_uint8) var37 << 8); + var40.i = ((orc_uint8) var36 & 0x00ff) | ((orc_uint8) var37 << 8); /* 6: mergewl */ - var38.i = ((orc_uint16) var40.i) | ((orc_uint16) var39.i << 16); + var38.i = + ((orc_uint16) var40.i & 0x0000ffff) | ((orc_uint16) var39.i << 16); /* 7: storel */ ptr0[i] = var38; } @@ -11059,13 +10644,14 @@ _backup_cogorc_convert_Y444_AYUV (OrcExecutor * ex) /* 1: loadb */ var35 = ptr6[i]; /* 2: mergebw */ - var39.i = ((orc_uint8) var34) | ((orc_uint8) var35 << 8); + var39.i = ((orc_uint8) var34 & 0x00ff) | ((orc_uint8) var35 << 8); /* 4: loadb */ var37 = ptr4[i]; /* 5: mergebw */ - var40.i = ((orc_uint8) var36) | ((orc_uint8) var37 << 8); + var40.i = ((orc_uint8) var36 & 0x00ff) | ((orc_uint8) var37 << 8); /* 6: mergewl */ - var38.i = ((orc_uint16) var40.i) | ((orc_uint16) var39.i << 16); + var38.i = + ((orc_uint16) var40.i & 0x0000ffff) | ((orc_uint16) var39.i << 16); /* 7: storel */ ptr0[i] = var38; } @@ -11097,13 +10683,6 @@ cogorc_convert_Y444_AYUV (orc_uint32 * d1, int d1_stride, const orc_uint8 * s1, orc_program_add_source (p, 1, "s2"); orc_program_add_source (p, 1, "s3"); orc_program_add_constant (p, 1, 0x000000ff, "c1"); - orc_program_add_constant (p, 0, 0x00000000, "c2"); - orc_program_add_constant (p, 0, 0x00000000, "c3"); - orc_program_add_constant (p, 0, 0x00000000, "c4"); - orc_program_add_constant (p, 0, 0x00000000, "c5"); - orc_program_add_constant (p, 0, 0x00000000, "c6"); - orc_program_add_constant (p, 0, 0x00000000, "c7"); - orc_program_add_constant (p, 0, 0x00000000, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 2, "t2"); @@ -11289,11 +10868,12 @@ cogorc_convert_AYUV_ARGB (orc_uint32 * d1, int d1_stride, const orc_uint32 * s1, /* 36: convssswb */ var89 = ORC_CLAMP_SB (var79.i); /* 37: mergebw */ - var90.i = ((orc_uint8) var61) | ((orc_uint8) var87 << 8); + var90.i = ((orc_uint8) var61 & 0x00ff) | ((orc_uint8) var87 << 8); /* 38: mergebw */ - var91.i = ((orc_uint8) var88) | ((orc_uint8) var89 << 8); + var91.i = ((orc_uint8) var88 & 0x00ff) | ((orc_uint8) var89 << 8); /* 39: mergewl */ - var92.i = ((orc_uint16) var90.i) | ((orc_uint16) var91.i << 16); + var92.i = + ((orc_uint16) var90.i & 0x0000ffff) | ((orc_uint16) var91.i << 16); /* 41: addb */ var56.x4[0] = var92.x4[0] + var55.x4[0]; var56.x4[1] = var92.x4[1] + var55.x4[1]; @@ -11457,11 +11037,12 @@ _backup_cogorc_convert_AYUV_ARGB (OrcExecutor * ex) /* 36: convssswb */ var89 = ORC_CLAMP_SB (var79.i); /* 37: mergebw */ - var90.i = ((orc_uint8) var61) | ((orc_uint8) var87 << 8); + var90.i = ((orc_uint8) var61 & 0x00ff) | ((orc_uint8) var87 << 8); /* 38: mergebw */ - var91.i = ((orc_uint8) var88) | ((orc_uint8) var89 << 8); + var91.i = ((orc_uint8) var88 & 0x00ff) | ((orc_uint8) var89 << 8); /* 39: mergewl */ - var92.i = ((orc_uint16) var90.i) | ((orc_uint16) var91.i << 16); + var92.i = + ((orc_uint16) var90.i & 0x0000ffff) | ((orc_uint16) var91.i << 16); /* 41: addb */ var56.x4[0] = var92.x4[0] + var55.x4[0]; var56.x4[1] = var92.x4[1] + var55.x4[1]; @@ -11501,7 +11082,6 @@ cogorc_convert_AYUV_ARGB (orc_uint32 * d1, int d1_stride, const orc_uint32 * s1, orc_program_add_constant (p, 4, 0x00000004, "c5"); orc_program_add_constant (p, 4, 0x00000064, "c6"); orc_program_add_constant (p, 4, 0x00000068, "c7"); - orc_program_add_constant (p, 0, 0x00000080, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 2, "t2"); orc_program_add_temporary (p, 1, "t3"); @@ -11759,11 +11339,12 @@ cogorc_convert_AYUV_BGRA (orc_uint32 * d1, int d1_stride, const orc_uint32 * s1, /* 36: convssswb */ var89 = ORC_CLAMP_SB (var79.i); /* 37: mergebw */ - var90.i = ((orc_uint8) var89) | ((orc_uint8) var88 << 8); + var90.i = ((orc_uint8) var89 & 0x00ff) | ((orc_uint8) var88 << 8); /* 38: mergebw */ - var91.i = ((orc_uint8) var87) | ((orc_uint8) var61 << 8); + var91.i = ((orc_uint8) var87 & 0x00ff) | ((orc_uint8) var61 << 8); /* 39: mergewl */ - var92.i = ((orc_uint16) var90.i) | ((orc_uint16) var91.i << 16); + var92.i = + ((orc_uint16) var90.i & 0x0000ffff) | ((orc_uint16) var91.i << 16); /* 41: addb */ var56.x4[0] = var92.x4[0] + var55.x4[0]; var56.x4[1] = var92.x4[1] + var55.x4[1]; @@ -11927,11 +11508,12 @@ _backup_cogorc_convert_AYUV_BGRA (OrcExecutor * ex) /* 36: convssswb */ var89 = ORC_CLAMP_SB (var79.i); /* 37: mergebw */ - var90.i = ((orc_uint8) var89) | ((orc_uint8) var88 << 8); + var90.i = ((orc_uint8) var89 & 0x00ff) | ((orc_uint8) var88 << 8); /* 38: mergebw */ - var91.i = ((orc_uint8) var87) | ((orc_uint8) var61 << 8); + var91.i = ((orc_uint8) var87 & 0x00ff) | ((orc_uint8) var61 << 8); /* 39: mergewl */ - var92.i = ((orc_uint16) var90.i) | ((orc_uint16) var91.i << 16); + var92.i = + ((orc_uint16) var90.i & 0x0000ffff) | ((orc_uint16) var91.i << 16); /* 41: addb */ var56.x4[0] = var92.x4[0] + var55.x4[0]; var56.x4[1] = var92.x4[1] + var55.x4[1]; @@ -11971,7 +11553,6 @@ cogorc_convert_AYUV_BGRA (orc_uint32 * d1, int d1_stride, const orc_uint32 * s1, orc_program_add_constant (p, 4, 0x00000004, "c5"); orc_program_add_constant (p, 4, 0x00000064, "c6"); orc_program_add_constant (p, 4, 0x00000068, "c7"); - orc_program_add_constant (p, 0, 0x00000080, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 2, "t2"); orc_program_add_temporary (p, 1, "t3"); @@ -12229,11 +11810,12 @@ cogorc_convert_AYUV_ABGR (orc_uint32 * d1, int d1_stride, const orc_uint32 * s1, /* 36: convssswb */ var89 = ORC_CLAMP_SB (var79.i); /* 37: mergebw */ - var90.i = ((orc_uint8) var61) | ((orc_uint8) var89 << 8); + var90.i = ((orc_uint8) var61 & 0x00ff) | ((orc_uint8) var89 << 8); /* 38: mergebw */ - var91.i = ((orc_uint8) var88) | ((orc_uint8) var87 << 8); + var91.i = ((orc_uint8) var88 & 0x00ff) | ((orc_uint8) var87 << 8); /* 39: mergewl */ - var92.i = ((orc_uint16) var90.i) | ((orc_uint16) var91.i << 16); + var92.i = + ((orc_uint16) var90.i & 0x0000ffff) | ((orc_uint16) var91.i << 16); /* 41: addb */ var56.x4[0] = var92.x4[0] + var55.x4[0]; var56.x4[1] = var92.x4[1] + var55.x4[1]; @@ -12397,11 +11979,12 @@ _backup_cogorc_convert_AYUV_ABGR (OrcExecutor * ex) /* 36: convssswb */ var89 = ORC_CLAMP_SB (var79.i); /* 37: mergebw */ - var90.i = ((orc_uint8) var61) | ((orc_uint8) var89 << 8); + var90.i = ((orc_uint8) var61 & 0x00ff) | ((orc_uint8) var89 << 8); /* 38: mergebw */ - var91.i = ((orc_uint8) var88) | ((orc_uint8) var87 << 8); + var91.i = ((orc_uint8) var88 & 0x00ff) | ((orc_uint8) var87 << 8); /* 39: mergewl */ - var92.i = ((orc_uint16) var90.i) | ((orc_uint16) var91.i << 16); + var92.i = + ((orc_uint16) var90.i & 0x0000ffff) | ((orc_uint16) var91.i << 16); /* 41: addb */ var56.x4[0] = var92.x4[0] + var55.x4[0]; var56.x4[1] = var92.x4[1] + var55.x4[1]; @@ -12441,7 +12024,6 @@ cogorc_convert_AYUV_ABGR (orc_uint32 * d1, int d1_stride, const orc_uint32 * s1, orc_program_add_constant (p, 4, 0x00000004, "c5"); orc_program_add_constant (p, 4, 0x00000064, "c6"); orc_program_add_constant (p, 4, 0x00000068, "c7"); - orc_program_add_constant (p, 0, 0x00000080, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 2, "t2"); orc_program_add_temporary (p, 1, "t3"); @@ -12699,11 +12281,12 @@ cogorc_convert_AYUV_RGBA (orc_uint32 * d1, int d1_stride, const orc_uint32 * s1, /* 36: convssswb */ var89 = ORC_CLAMP_SB (var79.i); /* 37: mergebw */ - var90.i = ((orc_uint8) var87) | ((orc_uint8) var88 << 8); + var90.i = ((orc_uint8) var87 & 0x00ff) | ((orc_uint8) var88 << 8); /* 38: mergebw */ - var91.i = ((orc_uint8) var89) | ((orc_uint8) var61 << 8); + var91.i = ((orc_uint8) var89 & 0x00ff) | ((orc_uint8) var61 << 8); /* 39: mergewl */ - var92.i = ((orc_uint16) var90.i) | ((orc_uint16) var91.i << 16); + var92.i = + ((orc_uint16) var90.i & 0x0000ffff) | ((orc_uint16) var91.i << 16); /* 41: addb */ var56.x4[0] = var92.x4[0] + var55.x4[0]; var56.x4[1] = var92.x4[1] + var55.x4[1]; @@ -12867,11 +12450,12 @@ _backup_cogorc_convert_AYUV_RGBA (OrcExecutor * ex) /* 36: convssswb */ var89 = ORC_CLAMP_SB (var79.i); /* 37: mergebw */ - var90.i = ((orc_uint8) var87) | ((orc_uint8) var88 << 8); + var90.i = ((orc_uint8) var87 & 0x00ff) | ((orc_uint8) var88 << 8); /* 38: mergebw */ - var91.i = ((orc_uint8) var89) | ((orc_uint8) var61 << 8); + var91.i = ((orc_uint8) var89 & 0x00ff) | ((orc_uint8) var61 << 8); /* 39: mergewl */ - var92.i = ((orc_uint16) var90.i) | ((orc_uint16) var91.i << 16); + var92.i = + ((orc_uint16) var90.i & 0x0000ffff) | ((orc_uint16) var91.i << 16); /* 41: addb */ var56.x4[0] = var92.x4[0] + var55.x4[0]; var56.x4[1] = var92.x4[1] + var55.x4[1]; @@ -12911,7 +12495,6 @@ cogorc_convert_AYUV_RGBA (orc_uint32 * d1, int d1_stride, const orc_uint32 * s1, orc_program_add_constant (p, 4, 0x00000004, "c5"); orc_program_add_constant (p, 4, 0x00000064, "c6"); orc_program_add_constant (p, 4, 0x00000068, "c7"); - orc_program_add_constant (p, 0, 0x00000080, "c8"); orc_program_add_temporary (p, 2, "t1"); orc_program_add_temporary (p, 2, "t2"); orc_program_add_temporary (p, 1, "t3"); @@ -13175,11 +12758,12 @@ cogorc_convert_I420_BGRA (orc_uint32 * d1, const orc_uint8 * s1, /* 39: convssswb */ var87 = ORC_CLAMP_SB (var77.i); /* 40: mergebw */ - var88.i = ((orc_uint8) var87) | ((orc_uint8) var86 << 8); + var88.i = ((orc_uint8) var87 & 0x00ff) | ((orc_uint8) var86 << 8); /* 42: mergebw */ - var89.i = ((orc_uint8) var85) | ((orc_uint8) var54 << 8); + var89.i = ((orc_uint8) var85 & 0x00ff) | ((orc_uint8) var54 << 8); /* 43: mergewl */ - var90.i = ((orc_uint16) var88.i) | ((orc_uint16) var89.i << 16); + var90.i = + ((orc_uint16) var88.i & 0x0000ffff) | ((orc_uint16) var89.i << 16); /* 45: addb */ var56.x4[0] = var90.x4[0] + var55.x4[0]; var56.x4[1] = var90.x4[1] + var55.x4[1]; @@ -13347,11 +12931,12 @@ _backup_cogorc_convert_I420_BGRA (OrcExecutor * ex) /* 39: convssswb */ var87 = ORC_CLAMP_SB (var77.i); /* 40: mergebw */ - var88.i = ((orc_uint8) var87) | ((orc_uint8) var86 << 8); + var88.i = ((orc_uint8) var87 & 0x00ff) | ((orc_uint8) var86 << 8); /* 42: mergebw */ - var89.i = ((orc_uint8) var85) | ((orc_uint8) var54 << 8); + var89.i = ((orc_uint8) var85 & 0x00ff) | ((orc_uint8) var54 << 8); /* 43: mergewl */ - var90.i = ((orc_uint16) var88.i) | ((orc_uint16) var89.i << 16); + var90.i = + ((orc_uint16) var88.i & 0x0000ffff) | ((orc_uint16) var89.i << 16); /* 45: addb */ var56.x4[0] = var90.x4[0] + var55.x4[0]; var56.x4[1] = var90.x4[1] + var55.x4[1]; @@ -13674,11 +13259,12 @@ cogorc_convert_I420_BGRA_avg (orc_uint32 * d1, const orc_uint8 * s1, /* 43: convssswb */ var92 = ORC_CLAMP_SB (var82.i); /* 44: mergebw */ - var93.i = ((orc_uint8) var92) | ((orc_uint8) var91 << 8); + var93.i = ((orc_uint8) var92 & 0x00ff) | ((orc_uint8) var91 << 8); /* 46: mergebw */ - var94.i = ((orc_uint8) var90) | ((orc_uint8) var55 << 8); + var94.i = ((orc_uint8) var90 & 0x00ff) | ((orc_uint8) var55 << 8); /* 47: mergewl */ - var95.i = ((orc_uint16) var93.i) | ((orc_uint16) var94.i << 16); + var95.i = + ((orc_uint16) var93.i & 0x0000ffff) | ((orc_uint16) var94.i << 16); /* 49: addb */ var57.x4[0] = var95.x4[0] + var56.x4[0]; var57.x4[1] = var95.x4[1] + var56.x4[1]; @@ -13866,11 +13452,12 @@ _backup_cogorc_convert_I420_BGRA_avg (OrcExecutor * ex) /* 43: convssswb */ var92 = ORC_CLAMP_SB (var82.i); /* 44: mergebw */ - var93.i = ((orc_uint8) var92) | ((orc_uint8) var91 << 8); + var93.i = ((orc_uint8) var92 & 0x00ff) | ((orc_uint8) var91 << 8); /* 46: mergebw */ - var94.i = ((orc_uint8) var90) | ((orc_uint8) var55 << 8); + var94.i = ((orc_uint8) var90 & 0x00ff) | ((orc_uint8) var55 << 8); /* 47: mergewl */ - var95.i = ((orc_uint16) var93.i) | ((orc_uint16) var94.i << 16); + var95.i = + ((orc_uint16) var93.i & 0x0000ffff) | ((orc_uint16) var94.i << 16); /* 49: addb */ var57.x4[0] = var95.x4[0] + var56.x4[0]; var57.x4[1] = var95.x4[1] + var56.x4[1]; diff --git a/ext/cog/gstcogorc-dist.h b/ext/cog/gstcogorc-dist.h index a33587594..4f1dbd204 100644 --- a/ext/cog/gstcogorc-dist.h +++ b/ext/cog/gstcogorc-dist.h @@ -24,6 +24,7 @@ typedef uint8_t orc_uint8; typedef uint16_t orc_uint16; typedef uint32_t orc_uint32; typedef uint64_t orc_uint64; +#define ORC_UINT64_C(x) UINT64_C(x) #elif defined(_MSC_VER) typedef signed __int8 orc_int8; typedef signed __int16 orc_int16; @@ -33,6 +34,7 @@ typedef unsigned __int8 orc_uint8; typedef unsigned __int16 orc_uint16; typedef unsigned __int32 orc_uint32; typedef unsigned __int64 orc_uint64; +#define ORC_UINT64_C(x) (x##Ui64) #else #include <limits.h> typedef signed char orc_int8; @@ -44,14 +46,16 @@ typedef unsigned int orc_uint32; #if INT_MAX == LONG_MAX typedef long long orc_int64; typedef unsigned long long orc_uint64; +#define ORC_UINT64_C(x) (x##ULL) #else typedef long orc_int64; typedef unsigned long orc_uint64; +#define ORC_UINT64_C(x) (x##UL) #endif #endif typedef union { orc_int16 i; orc_int8 x2[2]; } orc_union16; typedef union { orc_int32 i; float f; orc_int16 x2[2]; orc_int8 x4[4]; } orc_union32; -typedef union { orc_int64 i; double f; orc_int32 x2[2]; orc_int16 x4[4]; } orc_union64; +typedef union { orc_int64 i; double f; orc_int32 x2[2]; float x2f[2]; orc_int16 x4[4]; } orc_union64; #endif void cogorc_memcpy_2d (orc_uint8 * d1, int d1_stride, const orc_uint8 * s1, int s1_stride, int n, int m); void cogorc_downsample_horiz_cosite_1tap (orc_uint8 * d1, const orc_uint16 * s1, int n); diff --git a/ext/cog/gstcogutils.c b/ext/cog/gstcogutils.c index 4d7c8b99f..ff23862f8 100644 --- a/ext/cog/gstcogutils.c +++ b/ext/cog/gstcogutils.c @@ -126,6 +126,7 @@ gst_cog_buffer_wrap (GstBuffer * buf, GstVideoFormat format, int width, break; default: g_assert_not_reached (); + return NULL; } cog_frame_set_free_callback (frame, gst_cog_frame_free, buf); diff --git a/ext/cog/gstcolorconvert.c b/ext/cog/gstcolorconvert.c index 6f5d9c85f..560ca68c9 100644 --- a/ext/cog/gstcolorconvert.c +++ b/ext/cog/gstcolorconvert.c @@ -27,7 +27,7 @@ #include <string.h> #include <cog/cog.h> #include <cog/cogvirtframe.h> -#include <math.h> +#include <gst/math-compat.h> #include "gstcogutils.h" diff --git a/ext/directfb/dfb-example.c b/ext/directfb/dfb-example.c index 17dbce3b1..59bbd4a6f 100644 --- a/ext/directfb/dfb-example.c +++ b/ext/directfb/dfb-example.c @@ -57,7 +57,8 @@ main (int argc, char *argv[]) /* Adding elements to the pipeline */ gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL); - g_assert (gst_element_link (src, sink)); + if (!gst_element_link (src, sink)) + g_error ("Couldn't link videotestsrc and dfbvideosink"); /* Let's play ! */ gst_element_set_state (pipeline, GST_STATE_PLAYING); diff --git a/ext/faac/gstfaac.c b/ext/faac/gstfaac.c index d26da1043..f3086036f 100644 --- a/ext/faac/gstfaac.c +++ b/ext/faac/gstfaac.c @@ -764,7 +764,6 @@ gst_faac_push_buffers (GstFaac * faac, gboolean force) encode_failed: { GST_ELEMENT_ERROR (faac, LIBRARY, ENCODE, (NULL), (NULL)); - gst_buffer_unref (outbuf); return GST_FLOW_ERROR; } } diff --git a/ext/jack/.gitignore b/ext/jack/.gitignore deleted file mode 100644 index 916f265c7..000000000 --- a/ext/jack/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.loT diff --git a/ext/jack/Makefile.am b/ext/jack/Makefile.am deleted file mode 100644 index ede70594b..000000000 --- a/ext/jack/Makefile.am +++ /dev/null @@ -1,12 +0,0 @@ - -plugin_LTLIBRARIES = libgstjack.la - -libgstjack_la_SOURCES = gstjackutil.c gstjack.c gstjackaudiosrc.c gstjackaudiosink.c gstjackaudioclient.c -libgstjack_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(JACK_CFLAGS) -libgstjack_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) $(JACK_LIBS) -libgstjack_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstjack_la_LIBTOOLFLAGS = --tag=disable-static - -noinst_HEADERS = gstjackutil.h gstjackaudiosrc.h gstjackaudiosink.h gstjackaudioclient.h gstjack.h gstjackringbuffer.h - -EXTRA_DIST = README diff --git a/ext/jack/README b/ext/jack/README deleted file mode 100644 index 2bb97beba..000000000 --- a/ext/jack/README +++ /dev/null @@ -1,4 +0,0 @@ -to be written, la dee da - -jackit.sf.net - diff --git a/ext/jack/gstjack.c b/ext/jack/gstjack.c deleted file mode 100644 index 371a9e934..000000000 --- a/ext/jack/gstjack.c +++ /dev/null @@ -1,95 +0,0 @@ -/* GStreamer Jack plugins - * Copyright (C) 2006 Wim Taymans <wim@fluendo.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstjackaudiosrc.h" -#include "gstjackaudiosink.h" - -GType -gst_jack_connect_get_type (void) -{ - static GType jack_connect_type = 0; - static const GEnumValue jack_connect[] = { - {GST_JACK_CONNECT_NONE, - "Don't automatically connect ports to physical ports", "none"}, - {GST_JACK_CONNECT_AUTO, - "Automatically connect ports to physical ports", "auto"}, - {GST_JACK_CONNECT_AUTO_FORCED, - "Automatically connect ports to as many physical ports as possible", - "auto-forced"}, - {0, NULL, NULL}, - }; - - if (!jack_connect_type) { - jack_connect_type = g_enum_register_static ("GstJackConnect", jack_connect); - } - return jack_connect_type; -} - - -static gpointer -gst_jack_client_copy (gpointer jclient) -{ - return jclient; -} - - -static void -gst_jack_client_free (gpointer jclient) -{ - return; -} - - -GType -gst_jack_client_get_type (void) -{ - static GType type; /* 0 */ - - if (type == 0) { - /* hackish, but makes it show up nicely in gst-inspect */ - type = g_boxed_type_register_static ("JackClient", - (GBoxedCopyFunc) gst_jack_client_copy, - (GBoxedFreeFunc) gst_jack_client_free); - } - - return type; -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - if (!gst_element_register (plugin, "jackaudiosrc", GST_RANK_PRIMARY, - GST_TYPE_JACK_AUDIO_SRC)) - return FALSE; - if (!gst_element_register (plugin, "jackaudiosink", GST_RANK_PRIMARY, - GST_TYPE_JACK_AUDIO_SINK)) - return FALSE; - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "jack", - "Jack elements", - plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/ext/jack/gstjack.h b/ext/jack/gstjack.h deleted file mode 100644 index d923866df..000000000 --- a/ext/jack/gstjack.h +++ /dev/null @@ -1,55 +0,0 @@ -/* GStreamer - * Copyright (C) 2006 Wim Taymans <wim@fluendo.com> - * - * gstjack.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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef _GST_JACK_H_ -#define _GST_JACK_H_ - - -/** - * GstJackConnect: - * @GST_JACK_CONNECT_NONE: Don't automatically connect to physical ports. - * In this mode, the element will accept any number of input channels and will - * create (but not connect) an output port for each channel. - * @GST_JACK_CONNECT_AUTO: In this mode, the element will try to connect each - * output port to a random physical jack input pin. The sink will - * expose the number of physical channels on its pad caps. - * @GST_JACK_CONNECT_AUTO_FORCED: In this mode, the element will try to connect each - * output port to a random physical jack input pin. The element will accept any number - * of input channels. - * - * Specify how the output ports will be connected. - */ - -typedef enum { - GST_JACK_CONNECT_NONE, - GST_JACK_CONNECT_AUTO, - GST_JACK_CONNECT_AUTO_FORCED -} GstJackConnect; - -typedef jack_default_audio_sample_t sample_t; - -#define GST_TYPE_JACK_CONNECT (gst_jack_connect_get_type()) -#define GST_TYPE_JACK_CLIENT (gst_jack_client_get_type ()) - -GType gst_jack_client_get_type(void); -GType gst_jack_connect_get_type(void); - -#endif // _GST_JACK_H_ diff --git a/ext/jack/gstjackaudioclient.c b/ext/jack/gstjackaudioclient.c deleted file mode 100644 index 1789edb60..000000000 --- a/ext/jack/gstjackaudioclient.c +++ /dev/null @@ -1,525 +0,0 @@ -/* GStreamer - * Copyright (C) 2006 Wim Taymans <wim@fluendo.com> - * - * gstjackaudioclient.c: jack audio client implementation - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include <string.h> - -#include "gstjackaudioclient.h" - -GST_DEBUG_CATEGORY_STATIC (gst_jack_audio_client_debug); -#define GST_CAT_DEFAULT gst_jack_audio_client_debug - -void -gst_jack_audio_client_init (void) -{ - GST_DEBUG_CATEGORY_INIT (gst_jack_audio_client_debug, "jackclient", 0, - "jackclient helpers"); -} - -/* a list of global connections indexed by id and server. */ -G_LOCK_DEFINE_STATIC (connections_lock); -static GList *connections; - -/* the connection to a server */ -typedef struct -{ - gint refcount; - GMutex *lock; - GCond *flush_cond; - - /* id/server pair and the connection */ - gchar *id; - gchar *server; - jack_client_t *client; - - /* lists of GstJackAudioClients */ - gint n_clients; - GList *src_clients; - GList *sink_clients; -} GstJackAudioConnection; - -/* an object sharing a jack_client_t connection. */ -struct _GstJackAudioClient -{ - GstJackAudioConnection *conn; - - GstJackClientType type; - gboolean active; - gboolean deactivate; - - void (*shutdown) (void *arg); - JackProcessCallback process; - JackBufferSizeCallback buffer_size; - JackSampleRateCallback sample_rate; - gpointer user_data; -}; - -typedef jack_default_audio_sample_t sample_t; - -typedef struct -{ - jack_nframes_t nframes; - gpointer user_data; -} JackCB; - -static int -jack_process_cb (jack_nframes_t nframes, void *arg) -{ - GstJackAudioConnection *conn = (GstJackAudioConnection *) arg; - GList *walk; - int res = 0; - - g_mutex_lock (conn->lock); - /* call sources first, then sinks. Sources will either push data into the - * ringbuffer of the sinks, which will then pull the data out of it, or - * sinks will pull the data from the sources. */ - for (walk = conn->src_clients; walk; walk = g_list_next (walk)) { - GstJackAudioClient *client = (GstJackAudioClient *) walk->data; - - /* only call active clients */ - if ((client->active || client->deactivate) && client->process) { - res = client->process (nframes, client->user_data); - if (client->deactivate) { - client->deactivate = FALSE; - g_cond_signal (conn->flush_cond); - } - } - } - for (walk = conn->sink_clients; walk; walk = g_list_next (walk)) { - GstJackAudioClient *client = (GstJackAudioClient *) walk->data; - - /* only call active clients */ - if ((client->active || client->deactivate) && client->process) { - res = client->process (nframes, client->user_data); - if (client->deactivate) { - client->deactivate = FALSE; - g_cond_signal (conn->flush_cond); - } - } - } - g_mutex_unlock (conn->lock); - - return res; -} - -/* we error out */ -static int -jack_sample_rate_cb (jack_nframes_t nframes, void *arg) -{ - return 0; -} - -/* we error out */ -static int -jack_buffer_size_cb (jack_nframes_t nframes, void *arg) -{ - return 0; -} - -static void -jack_shutdown_cb (void *arg) -{ - GstJackAudioConnection *conn = (GstJackAudioConnection *) arg; - GList *walk; - - GST_DEBUG ("disconnect client %s from server %s", conn->id, - GST_STR_NULL (conn->server)); - - g_mutex_lock (conn->lock); - for (walk = conn->src_clients; walk; walk = g_list_next (walk)) { - GstJackAudioClient *client = (GstJackAudioClient *) walk->data; - - if (client->shutdown) - client->shutdown (client->user_data); - } - for (walk = conn->sink_clients; walk; walk = g_list_next (walk)) { - GstJackAudioClient *client = (GstJackAudioClient *) walk->data; - - if (client->shutdown) - client->shutdown (client->user_data); - } - g_mutex_unlock (conn->lock); -} - -typedef struct -{ - const gchar *id; - const gchar *server; -} FindData; - -static gint -connection_find (GstJackAudioConnection * conn, FindData * data) -{ - /* id's must match */ - if (strcmp (conn->id, data->id)) - return 1; - - /* both the same or NULL */ - if (conn->server == data->server) - return 0; - - /* we cannot compare NULL */ - if (conn->server == NULL || data->server == NULL) - return 1; - - if (strcmp (conn->server, data->server)) - return 1; - - return 0; -} - -/* make a connection with @id and @server. Returns NULL on failure with the - * status set. */ -static GstJackAudioConnection * -gst_jack_audio_make_connection (const gchar * id, const gchar * server, - jack_client_t * jclient, jack_status_t * status) -{ - GstJackAudioConnection *conn; - jack_options_t options; - gint res; - - *status = 0; - - GST_DEBUG ("new client %s, connecting to server %s", id, - GST_STR_NULL (server)); - - /* never start a server */ - options = JackNoStartServer; - /* if we have a servername, use it */ - if (server != NULL) - options |= JackServerName; - /* open the client */ - if (jclient == NULL) - jclient = jack_client_open (id, options, status, server); - if (jclient == NULL) - goto could_not_open; - - /* now create object */ - conn = g_new (GstJackAudioConnection, 1); - conn->refcount = 1; - conn->lock = g_mutex_new (); - conn->flush_cond = g_cond_new (); - conn->id = g_strdup (id); - conn->server = g_strdup (server); - conn->client = jclient; - conn->n_clients = 0; - conn->src_clients = NULL; - conn->sink_clients = NULL; - - /* set our callbacks */ - jack_set_process_callback (jclient, jack_process_cb, conn); - /* these callbacks cause us to error */ - jack_set_buffer_size_callback (jclient, jack_buffer_size_cb, conn); - jack_set_sample_rate_callback (jclient, jack_sample_rate_cb, conn); - jack_on_shutdown (jclient, jack_shutdown_cb, conn); - - /* all callbacks are set, activate the client */ - if ((res = jack_activate (jclient))) - goto could_not_activate; - - GST_DEBUG ("opened connection %p", conn); - - return conn; - - /* ERRORS */ -could_not_open: - { - GST_DEBUG ("failed to open jack client, %d", *status); - return NULL; - } -could_not_activate: - { - GST_ERROR ("Could not activate client (%d)", res); - *status = JackFailure; - g_mutex_free (conn->lock); - g_free (conn->id); - g_free (conn->server); - g_free (conn); - return NULL; - } -} - -static GstJackAudioConnection * -gst_jack_audio_get_connection (const gchar * id, const gchar * server, - jack_client_t * jclient, jack_status_t * status) -{ - GstJackAudioConnection *conn; - GList *found; - FindData data; - - GST_DEBUG ("getting connection for id %s, server %s", id, - GST_STR_NULL (server)); - - data.id = id; - data.server = server; - - G_LOCK (connections_lock); - found = - g_list_find_custom (connections, &data, (GCompareFunc) connection_find); - if (found != NULL && jclient != NULL) { - /* we found it, increase refcount and return it */ - conn = (GstJackAudioConnection *) found->data; - conn->refcount++; - - GST_DEBUG ("found connection %p", conn); - } else { - /* make new connection */ - conn = gst_jack_audio_make_connection (id, server, jclient, status); - if (conn != NULL) { - GST_DEBUG ("created connection %p", conn); - /* add to list on success */ - connections = g_list_prepend (connections, conn); - } else { - GST_WARNING ("could not create connection"); - } - } - G_UNLOCK (connections_lock); - - return conn; -} - -static void -gst_jack_audio_unref_connection (GstJackAudioConnection * conn) -{ - gint res; - gboolean zero; - - GST_DEBUG ("unref connection %p refcnt %d", conn, conn->refcount); - - G_LOCK (connections_lock); - conn->refcount--; - if ((zero = (conn->refcount == 0))) { - GST_DEBUG ("closing connection %p", conn); - /* remove from list, we can release the mutex after removing the connection - * from the list because after that, nobody can access the connection anymore. */ - connections = g_list_remove (connections, conn); - } - G_UNLOCK (connections_lock); - - /* if we are zero, close and cleanup the connection */ - if (zero) { - /* don't use conn->lock here. two reasons: - * - * 1) its not necessary: jack_deactivate() will not return until the JACK thread - * associated with this connection is cleaned up by a thread join, hence - * no more callbacks can occur or be in progress. - * - * 2) it would deadlock anyway, because jack_deactivate() will sleep - * waiting for the JACK thread, and can thus cause deadlock in - * jack_process_cb() - */ - if ((res = jack_deactivate (conn->client))) { - /* we only warn, this means the server is probably shut down and the client - * is gone anyway. */ - GST_WARNING ("Could not deactivate Jack client (%d)", res); - } - /* close connection */ - if ((res = jack_client_close (conn->client))) { - /* we assume the client is gone. */ - GST_WARNING ("close failed (%d)", res); - } - - /* free resources */ - g_mutex_free (conn->lock); - g_cond_free (conn->flush_cond); - g_free (conn->id); - g_free (conn->server); - g_free (conn); - } -} - -static void -gst_jack_audio_connection_add_client (GstJackAudioConnection * conn, - GstJackAudioClient * client) -{ - g_mutex_lock (conn->lock); - switch (client->type) { - case GST_JACK_CLIENT_SOURCE: - conn->src_clients = g_list_append (conn->src_clients, client); - conn->n_clients++; - break; - case GST_JACK_CLIENT_SINK: - conn->sink_clients = g_list_append (conn->sink_clients, client); - conn->n_clients++; - break; - default: - g_warning ("trying to add unknown client type"); - break; - } - g_mutex_unlock (conn->lock); -} - -static void -gst_jack_audio_connection_remove_client (GstJackAudioConnection * conn, - GstJackAudioClient * client) -{ - g_mutex_lock (conn->lock); - switch (client->type) { - case GST_JACK_CLIENT_SOURCE: - conn->src_clients = g_list_remove (conn->src_clients, client); - conn->n_clients--; - break; - case GST_JACK_CLIENT_SINK: - conn->sink_clients = g_list_remove (conn->sink_clients, client); - conn->n_clients--; - break; - default: - g_warning ("trying to remove unknown client type"); - break; - } - g_mutex_unlock (conn->lock); -} - -/** - * gst_jack_audio_client_get: - * @id: the client id - * @server: the server to connect to or NULL for the default server - * @type: the client type - * @shutdown: a callback when the jack server shuts down - * @process: a callback when samples are available - * @buffer_size: a callback when the buffer_size changes - * @sample_rate: a callback when the sample_rate changes - * @user_data: user data passed to the callbacks - * @status: pointer to hold the jack status code in case of errors - * - * Get the jack client connection for @id and @server. Connections to the same - * @id and @server will receive the same physical Jack client connection and - * will therefore be scheduled in the same process callback. - * - * Returns: a #GstJackAudioClient. - */ -GstJackAudioClient * -gst_jack_audio_client_new (const gchar * id, const gchar * server, - jack_client_t * jclient, GstJackClientType type, - void (*shutdown) (void *arg), JackProcessCallback process, - JackBufferSizeCallback buffer_size, JackSampleRateCallback sample_rate, - gpointer user_data, jack_status_t * status) -{ - GstJackAudioClient *client; - GstJackAudioConnection *conn; - - g_return_val_if_fail (id != NULL, NULL); - g_return_val_if_fail (status != NULL, NULL); - - /* first get a connection for the id/server pair */ - conn = gst_jack_audio_get_connection (id, server, jclient, status); - if (conn == NULL) - goto no_connection; - - GST_INFO ("new client %s", id); - - /* make new client using the connection */ - client = g_new (GstJackAudioClient, 1); - client->active = client->deactivate = FALSE; - client->conn = conn; - client->type = type; - client->shutdown = shutdown; - client->process = process; - client->buffer_size = buffer_size; - client->sample_rate = sample_rate; - client->user_data = user_data; - - /* add the client to the connection */ - gst_jack_audio_connection_add_client (conn, client); - - return client; - - /* ERRORS */ -no_connection: - { - GST_DEBUG ("Could not get server connection (%d)", *status); - return NULL; - } -} - -/** - * gst_jack_audio_client_free: - * @client: a #GstJackAudioClient - * - * Free the resources used by @client. - */ -void -gst_jack_audio_client_free (GstJackAudioClient * client) -{ - GstJackAudioConnection *conn; - - g_return_if_fail (client != NULL); - - GST_INFO ("free client"); - - conn = client->conn; - - /* remove from connection first so that it's not scheduled anymore after this - * call */ - gst_jack_audio_connection_remove_client (conn, client); - gst_jack_audio_unref_connection (conn); - - g_free (client); -} - -/** - * gst_jack_audio_client_get_client: - * @client: a #GstJackAudioClient - * - * Get the jack audio client for @client. This function is used to perform - * operations on the jack server from this client. - * - * Returns: The jack audio client. - */ -jack_client_t * -gst_jack_audio_client_get_client (GstJackAudioClient * client) -{ - g_return_val_if_fail (client != NULL, NULL); - - /* no lock needed, the connection and the client does not change - * once the client is created. */ - return client->conn->client; -} - -/** - * gst_jack_audio_client_set_active: - * @client: a #GstJackAudioClient - * @active: new mode for the client - * - * Activate or deactive @client. When a client is activated it will receive - * callbacks when data should be processed. - * - * Returns: 0 if all ok. - */ -gint -gst_jack_audio_client_set_active (GstJackAudioClient * client, gboolean active) -{ - g_return_val_if_fail (client != NULL, -1); - - /* make sure that we are not dispatching the client */ - g_mutex_lock (client->conn->lock); - if (client->active && !active) { - /* we need to process once more to flush the port */ - client->deactivate = TRUE; - - /* need to wait for process_cb run once more */ - while (client->deactivate) - g_cond_wait (client->conn->flush_cond, client->conn->lock); - } - client->active = active; - g_mutex_unlock (client->conn->lock); - - return 0; -} diff --git a/ext/jack/gstjackaudioclient.h b/ext/jack/gstjackaudioclient.h deleted file mode 100644 index 5fb7e3544..000000000 --- a/ext/jack/gstjackaudioclient.h +++ /dev/null @@ -1,59 +0,0 @@ -/* GStreamer - * Copyright (C) 2006 Wim Taymans <wim@fluendo.com> - * - * gstjackaudioclient.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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GST_JACK_AUDIO_CLIENT_H__ -#define __GST_JACK_AUDIO_CLIENT_H__ - -#include <jack/jack.h> - -#include <gst/gst.h> - -G_BEGIN_DECLS - -typedef enum -{ - GST_JACK_CLIENT_SOURCE, - GST_JACK_CLIENT_SINK -} GstJackClientType; - -typedef struct _GstJackAudioClient GstJackAudioClient; - -void gst_jack_audio_client_init (void); - - -GstJackAudioClient * gst_jack_audio_client_new (const gchar *id, const gchar *server, - jack_client_t *jclient, - GstJackClientType type, - void (*shutdown) (void *arg), - JackProcessCallback process, - JackBufferSizeCallback buffer_size, - JackSampleRateCallback sample_rate, - gpointer user_data, - jack_status_t *status); -void gst_jack_audio_client_free (GstJackAudioClient *client); - -jack_client_t * gst_jack_audio_client_get_client (GstJackAudioClient *client); - -gboolean gst_jack_audio_client_set_active (GstJackAudioClient *client, gboolean active); - -G_END_DECLS - -#endif /* __GST_JACK_AUDIO_CLIENT_H__ */ diff --git a/ext/jack/gstjackaudiosink.c b/ext/jack/gstjackaudiosink.c deleted file mode 100644 index 32bf1af3e..000000000 --- a/ext/jack/gstjackaudiosink.c +++ /dev/null @@ -1,852 +0,0 @@ -/* GStreamer - * Copyright (C) 2006 Wim Taymans <wim@fluendo.com> - * - * gstjackaudiosink.c: jack audio sink implementation - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/** - * SECTION:element-jackaudiosink - * @see_also: #GstBaseAudioSink, #GstRingBuffer - * - * A Sink that outputs data to Jack ports. - * - * It will create N Jack ports named out_<name>_<num> where - * <name> is the element name and <num> is starting from 1. - * Each port corresponds to a gstreamer channel. - * - * The samplerate as exposed on the caps is always the same as the samplerate of - * the jack server. - * - * When the #GstJackAudioSink:connect property is set to auto, this element - * will try to connect each output port to a random physical jack input pin. In - * this mode, the sink will expose the number of physical channels on its pad - * caps. - * - * When the #GstJackAudioSink:connect property is set to none, the element will - * accept any number of input channels and will create (but not connect) an - * output port for each channel. - * - * The element will generate an error when the Jack server is shut down when it - * was PAUSED or PLAYING. This element does not support dynamic rate and buffer - * size changes at runtime. - * - * <refsect2> - * <title>Example launch line</title> - * |[ - * gst-launch audiotestsrc ! jackaudiosink - * ]| Play a sine wave to using jack. - * </refsect2> - * - * Last reviewed on 2006-11-30 (0.10.4) - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <gst/gst-i18n-plugin.h> -#include <stdlib.h> -#include <string.h> - -#include "gstjackaudiosink.h" -#include "gstjackringbuffer.h" - -GST_DEBUG_CATEGORY_STATIC (gst_jack_audio_sink_debug); -#define GST_CAT_DEFAULT gst_jack_audio_sink_debug - -static gboolean -gst_jack_audio_sink_allocate_channels (GstJackAudioSink * sink, gint channels) -{ - jack_client_t *client; - - client = gst_jack_audio_client_get_client (sink->client); - - /* remove ports we don't need */ - while (sink->port_count > channels) { - jack_port_unregister (client, sink->ports[--sink->port_count]); - } - - /* alloc enough output ports */ - sink->ports = g_realloc (sink->ports, sizeof (jack_port_t *) * channels); - - /* create an output port for each channel */ - while (sink->port_count < channels) { - gchar *name; - - /* port names start from 1 and are local to the element */ - name = - g_strdup_printf ("out_%s_%d", GST_ELEMENT_NAME (sink), - sink->port_count + 1); - sink->ports[sink->port_count] = - jack_port_register (client, name, JACK_DEFAULT_AUDIO_TYPE, - JackPortIsOutput, 0); - if (sink->ports[sink->port_count] == NULL) - return FALSE; - - sink->port_count++; - - g_free (name); - } - return TRUE; -} - -static void -gst_jack_audio_sink_free_channels (GstJackAudioSink * sink) -{ - gint res, i = 0; - jack_client_t *client; - - client = gst_jack_audio_client_get_client (sink->client); - - /* get rid of all ports */ - while (sink->port_count) { - GST_LOG_OBJECT (sink, "unregister port %d", i); - if ((res = jack_port_unregister (client, sink->ports[i++]))) { - GST_DEBUG_OBJECT (sink, "unregister of port failed (%d)", res); - } - sink->port_count--; - } - g_free (sink->ports); - sink->ports = NULL; -} - -/* ringbuffer abstract base class */ -static GType -gst_jack_ring_buffer_get_type (void) -{ - static GType ringbuffer_type = 0; - - if (!ringbuffer_type) { - static const GTypeInfo ringbuffer_info = { - sizeof (GstJackRingBufferClass), - NULL, - NULL, - (GClassInitFunc) gst_jack_ring_buffer_class_init, - NULL, - NULL, - sizeof (GstJackRingBuffer), - 0, - (GInstanceInitFunc) gst_jack_ring_buffer_init, - NULL - }; - - ringbuffer_type = - g_type_register_static (GST_TYPE_RING_BUFFER, - "GstJackAudioSinkRingBuffer", &ringbuffer_info, 0); - } - return ringbuffer_type; -} - -static void -gst_jack_ring_buffer_class_init (GstJackRingBufferClass * klass) -{ - GObjectClass *gobject_class; - GstObjectClass *gstobject_class; - GstRingBufferClass *gstringbuffer_class; - - gobject_class = (GObjectClass *) klass; - gstobject_class = (GstObjectClass *) klass; - gstringbuffer_class = (GstRingBufferClass *) klass; - - ring_parent_class = g_type_class_peek_parent (klass); - - gstringbuffer_class->open_device = - GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_open_device); - gstringbuffer_class->close_device = - GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_close_device); - gstringbuffer_class->acquire = - GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_acquire); - gstringbuffer_class->release = - GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_release); - gstringbuffer_class->start = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_start); - gstringbuffer_class->pause = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_pause); - gstringbuffer_class->resume = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_start); - gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_stop); - - gstringbuffer_class->delay = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_delay); -} - -/* this is the callback of jack. This should RT-safe. - */ -static int -jack_process_cb (jack_nframes_t nframes, void *arg) -{ - GstJackAudioSink *sink; - GstRingBuffer *buf; - GstJackRingBuffer *abuf; - gint readseg, len; - guint8 *readptr; - gint i, j, flen, channels; - sample_t **buffers, *data; - - buf = GST_RING_BUFFER_CAST (arg); - abuf = GST_JACK_RING_BUFFER_CAST (arg); - sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf)); - - channels = buf->spec.channels; - - /* alloc pointers to samples */ - buffers = g_alloca (sizeof (sample_t *) * channels); - - /* get target buffers */ - for (i = 0; i < channels; i++) { - buffers[i] = (sample_t *) jack_port_get_buffer (sink->ports[i], nframes); - } - - if (gst_ring_buffer_prepare_read (buf, &readseg, &readptr, &len)) { - flen = len / channels; - - /* the number of samples must be exactly the segment size */ - if (nframes * sizeof (sample_t) != flen) - goto wrong_size; - - GST_DEBUG_OBJECT (sink, "copy %d frames: %p, %d bytes, %d channels", - nframes, readptr, flen, channels); - data = (sample_t *) readptr; - - /* the samples in the ringbuffer have the channels interleaved, we need to - * deinterleave into the jack target buffers */ - for (i = 0; i < nframes; i++) { - for (j = 0; j < channels; j++) { - buffers[j][i] = *data++; - } - } - - /* clear written samples in the ringbuffer */ - gst_ring_buffer_clear (buf, readseg); - - /* we wrote one segment */ - gst_ring_buffer_advance (buf, 1); - } else { - GST_DEBUG_OBJECT (sink, "write %d frames silence", nframes); - /* We are not allowed to read from the ringbuffer, write silence to all - * jack output buffers */ - for (i = 0; i < channels; i++) { - memset (buffers[i], 0, nframes * sizeof (sample_t)); - } - } - return 0; - - /* ERRORS */ -wrong_size: - { - GST_ERROR_OBJECT (sink, "nbytes (%d) != flen (%d)", - (gint) (nframes * sizeof (sample_t)), flen); - return 1; - } -} - -/* we error out */ -static int -jack_sample_rate_cb (jack_nframes_t nframes, void *arg) -{ - GstJackAudioSink *sink; - GstJackRingBuffer *abuf; - - abuf = GST_JACK_RING_BUFFER_CAST (arg); - sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (arg)); - - if (abuf->sample_rate != -1 && abuf->sample_rate != nframes) - goto not_supported; - - return 0; - - /* ERRORS */ -not_supported: - { - GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, - (NULL), ("Jack changed the sample rate, which is not supported")); - return 1; - } -} - -/* we error out */ -static int -jack_buffer_size_cb (jack_nframes_t nframes, void *arg) -{ - GstJackAudioSink *sink; - GstJackRingBuffer *abuf; - - abuf = GST_JACK_RING_BUFFER_CAST (arg); - sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (arg)); - - if (abuf->buffer_size != -1 && abuf->buffer_size != nframes) - goto not_supported; - - return 0; - - /* ERRORS */ -not_supported: - { - GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, - (NULL), ("Jack changed the buffer size, which is not supported")); - return 1; - } -} - -static void -jack_shutdown_cb (void *arg) -{ - GstJackAudioSink *sink; - - sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (arg)); - - GST_DEBUG_OBJECT (sink, "shutdown"); - - GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND, - (NULL), ("Jack server shutdown")); -} - -static void -gst_jack_ring_buffer_init (GstJackRingBuffer * buf, - GstJackRingBufferClass * g_class) -{ - buf->channels = -1; - buf->buffer_size = -1; - buf->sample_rate = -1; -} - -/* the _open_device method should make a connection with the server - */ -static gboolean -gst_jack_ring_buffer_open_device (GstRingBuffer * buf) -{ - GstJackAudioSink *sink; - jack_status_t status = 0; - const gchar *name; - - sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf)); - - GST_DEBUG_OBJECT (sink, "open"); - - name = g_get_application_name (); - if (!name) - name = "GStreamer"; - - sink->client = gst_jack_audio_client_new (name, sink->server, - sink->jclient, - GST_JACK_CLIENT_SINK, - jack_shutdown_cb, - jack_process_cb, jack_buffer_size_cb, jack_sample_rate_cb, buf, &status); - if (sink->client == NULL) - goto could_not_open; - - GST_DEBUG_OBJECT (sink, "opened"); - - return TRUE; - - /* ERRORS */ -could_not_open: - { - if (status & JackServerFailed) { - GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND, - (_("Jack server not found")), - ("Cannot connect to the Jack server (status %d)", status)); - } else { - GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, - (NULL), ("Jack client open error (status %d)", status)); - } - return FALSE; - } -} - -/* close the connection with the server - */ -static gboolean -gst_jack_ring_buffer_close_device (GstRingBuffer * buf) -{ - GstJackAudioSink *sink; - - sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf)); - - GST_DEBUG_OBJECT (sink, "close"); - - gst_jack_audio_sink_free_channels (sink); - gst_jack_audio_client_free (sink->client); - sink->client = NULL; - - return TRUE; -} - -/* allocate a buffer and setup resources to process the audio samples of - * the format as specified in @spec. - * - * We allocate N jack ports, one for each channel. If we are asked to - * automatically make a connection with physical ports, we connect as many - * ports as there are physical ports, leaving leftover ports unconnected. - * - * It is assumed that samplerate and number of channels are acceptable since our - * getcaps method will always provide correct values. If unacceptable caps are - * received for some reason, we fail here. - */ -static gboolean -gst_jack_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec) -{ - GstJackAudioSink *sink; - GstJackRingBuffer *abuf; - const char **ports; - gint sample_rate, buffer_size; - gint i, channels, res; - jack_client_t *client; - - sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf)); - abuf = GST_JACK_RING_BUFFER_CAST (buf); - - GST_DEBUG_OBJECT (sink, "acquire"); - - client = gst_jack_audio_client_get_client (sink->client); - - /* sample rate must be that of the server */ - sample_rate = jack_get_sample_rate (client); - if (sample_rate != spec->rate) - goto wrong_samplerate; - - channels = spec->channels; - - if (!gst_jack_audio_sink_allocate_channels (sink, channels)) - goto out_of_ports; - - buffer_size = jack_get_buffer_size (client); - - /* the segment size in bytes, this is large enough to hold a buffer of 32bit floats - * for all channels */ - spec->segsize = buffer_size * sizeof (gfloat) * channels; - spec->latency_time = gst_util_uint64_scale (spec->segsize, - (GST_SECOND / GST_USECOND), spec->rate * spec->bytes_per_sample); - /* segtotal based on buffer-time latency */ - spec->segtotal = spec->buffer_time / spec->latency_time; - if (spec->segtotal < 2) { - spec->segtotal = 2; - spec->buffer_time = spec->latency_time * spec->segtotal; - } - - GST_DEBUG_OBJECT (sink, "buffer time: %" G_GINT64_FORMAT " usec", - spec->buffer_time); - GST_DEBUG_OBJECT (sink, "latency time: %" G_GINT64_FORMAT " usec", - spec->latency_time); - GST_DEBUG_OBJECT (sink, "buffer_size %d, segsize %d, segtotal %d", - buffer_size, spec->segsize, spec->segtotal); - - /* allocate the ringbuffer memory now */ - buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize); - memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data)); - - if ((res = gst_jack_audio_client_set_active (sink->client, TRUE))) - goto could_not_activate; - - /* if we need to automatically connect the ports, do so now. We must do this - * after activating the client. */ - if (sink->connect == GST_JACK_CONNECT_AUTO - || sink->connect == GST_JACK_CONNECT_AUTO_FORCED) { - /* find all the physical input ports. A physical input port is a port - * associated with a hardware device. Someone needs connect to a physical - * port in order to hear something. */ - ports = jack_get_ports (client, NULL, NULL, - JackPortIsPhysical | JackPortIsInput); - if (ports == NULL) { - /* no ports? fine then we don't do anything except for posting a warning - * message. */ - GST_ELEMENT_WARNING (sink, RESOURCE, NOT_FOUND, (NULL), - ("No physical input ports found, leaving ports unconnected")); - goto done; - } - - for (i = 0; i < channels; i++) { - /* stop when all input ports are exhausted */ - if (ports[i] == NULL) { - /* post a warning that we could not connect all ports */ - GST_ELEMENT_WARNING (sink, RESOURCE, NOT_FOUND, (NULL), - ("No more physical ports, leaving some ports unconnected")); - break; - } - GST_DEBUG_OBJECT (sink, "try connecting to %s", - jack_port_name (sink->ports[i])); - /* connect the port to a physical port */ - res = jack_connect (client, jack_port_name (sink->ports[i]), ports[i]); - if (res != 0 && res != EEXIST) - goto cannot_connect; - } - free (ports); - } -done: - - abuf->sample_rate = sample_rate; - abuf->buffer_size = buffer_size; - abuf->channels = spec->channels; - - return TRUE; - - /* ERRORS */ -wrong_samplerate: - { - GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL), - ("Wrong samplerate, server is running at %d and we received %d", - sample_rate, spec->rate)); - return FALSE; - } -out_of_ports: - { - GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL), - ("Cannot allocate more Jack ports")); - return FALSE; - } -could_not_activate: - { - GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL), - ("Could not activate client (%d:%s)", res, g_strerror (res))); - return FALSE; - } -cannot_connect: - { - GST_ELEMENT_ERROR (sink, RESOURCE, SETTINGS, (NULL), - ("Could not connect output ports to physical ports (%d:%s)", - res, g_strerror (res))); - free (ports); - return FALSE; - } -} - -/* function is called with LOCK */ -static gboolean -gst_jack_ring_buffer_release (GstRingBuffer * buf) -{ - GstJackAudioSink *sink; - GstJackRingBuffer *abuf; - gint res; - - abuf = GST_JACK_RING_BUFFER_CAST (buf); - sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf)); - - GST_DEBUG_OBJECT (sink, "release"); - - if ((res = gst_jack_audio_client_set_active (sink->client, FALSE))) { - /* we only warn, this means the server is probably shut down and the client - * is gone anyway. */ - GST_ELEMENT_WARNING (sink, RESOURCE, CLOSE, (NULL), - ("Could not deactivate Jack client (%d)", res)); - } - - abuf->channels = -1; - abuf->buffer_size = -1; - abuf->sample_rate = -1; - - /* free the buffer */ - gst_buffer_unref (buf->data); - buf->data = NULL; - - return TRUE; -} - -static gboolean -gst_jack_ring_buffer_start (GstRingBuffer * buf) -{ - GstJackAudioSink *sink; - - sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf)); - - GST_DEBUG_OBJECT (sink, "start"); - - return TRUE; -} - -static gboolean -gst_jack_ring_buffer_pause (GstRingBuffer * buf) -{ - GstJackAudioSink *sink; - - sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf)); - - GST_DEBUG_OBJECT (sink, "pause"); - - return TRUE; -} - -static gboolean -gst_jack_ring_buffer_stop (GstRingBuffer * buf) -{ - GstJackAudioSink *sink; - - sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf)); - - GST_DEBUG_OBJECT (sink, "stop"); - - return TRUE; -} - -static guint -gst_jack_ring_buffer_delay (GstRingBuffer * buf) -{ - GstJackAudioSink *sink; - guint i, res = 0, latency; - jack_client_t *client; - - sink = GST_JACK_AUDIO_SINK (GST_OBJECT_PARENT (buf)); - client = gst_jack_audio_client_get_client (sink->client); - - for (i = 0; i < sink->port_count; i++) { - latency = jack_port_get_total_latency (client, sink->ports[i]); - if (latency > res) - res = latency; - } - - GST_LOG_OBJECT (sink, "delay %u", res); - - return res; -} - -static GstStaticPadTemplate jackaudiosink_sink_factory = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-float, " - "endianness = (int) { " G_STRINGIFY (G_BYTE_ORDER) " }, " - "width = (int) 32, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]") - ); - -/* AudioSink signals and args */ -enum -{ - /* FILL ME */ - SIGNAL_LAST -}; - -#define DEFAULT_PROP_CONNECT GST_JACK_CONNECT_AUTO -#define DEFAULT_PROP_SERVER NULL - -enum -{ - PROP_0, - PROP_CONNECT, - PROP_SERVER, - PROP_CLIENT, - PROP_LAST -}; - -#define _do_init(bla) \ - GST_DEBUG_CATEGORY_INIT (gst_jack_audio_sink_debug, "jacksink", 0, "jacksink element"); - -GST_BOILERPLATE_FULL (GstJackAudioSink, gst_jack_audio_sink, GstBaseAudioSink, - GST_TYPE_BASE_AUDIO_SINK, _do_init); - -static void gst_jack_audio_sink_dispose (GObject * object); -static void gst_jack_audio_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_jack_audio_sink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -static GstCaps *gst_jack_audio_sink_getcaps (GstBaseSink * bsink); -static GstRingBuffer *gst_jack_audio_sink_create_ringbuffer (GstBaseAudioSink * - sink); - -static void -gst_jack_audio_sink_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details_simple (element_class, "Audio Sink (Jack)", - "Sink/Audio", "Output to Jack", "Wim Taymans <wim@fluendo.com>"); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&jackaudiosink_sink_factory)); -} - -static void -gst_jack_audio_sink_class_init (GstJackAudioSinkClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseSinkClass *gstbasesink_class; - GstBaseAudioSinkClass *gstbaseaudiosink_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - gstbasesink_class = (GstBaseSinkClass *) klass; - gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass; - - gobject_class->dispose = gst_jack_audio_sink_dispose; - gobject_class->get_property = gst_jack_audio_sink_get_property; - gobject_class->set_property = gst_jack_audio_sink_set_property; - - g_object_class_install_property (gobject_class, PROP_CONNECT, - g_param_spec_enum ("connect", "Connect", - "Specify how the output ports will be connected", - GST_TYPE_JACK_CONNECT, DEFAULT_PROP_CONNECT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_SERVER, - g_param_spec_string ("server", "Server", - "The Jack server to connect to (NULL = default)", - DEFAULT_PROP_SERVER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_CLIENT, - g_param_spec_boxed ("client", "JackClient", "Handle for jack client", - GST_TYPE_JACK_CLIENT, - GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_jack_audio_sink_getcaps); - - gstbaseaudiosink_class->create_ringbuffer = - GST_DEBUG_FUNCPTR (gst_jack_audio_sink_create_ringbuffer); - - /* ref class from a thread-safe context to work around missing bit of - * thread-safety in GObject */ - g_type_class_ref (GST_TYPE_JACK_RING_BUFFER); - - gst_jack_audio_client_init (); -} - -static void -gst_jack_audio_sink_init (GstJackAudioSink * sink, - GstJackAudioSinkClass * g_class) -{ - sink->connect = DEFAULT_PROP_CONNECT; - sink->server = g_strdup (DEFAULT_PROP_SERVER); - sink->jclient = NULL; - sink->ports = NULL; - sink->port_count = 0; -} - -static void -gst_jack_audio_sink_dispose (GObject * object) -{ - GstJackAudioSink *sink = GST_JACK_AUDIO_SINK (object); - - gst_caps_replace (&sink->caps, NULL); - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static void -gst_jack_audio_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstJackAudioSink *sink; - - sink = GST_JACK_AUDIO_SINK (object); - - switch (prop_id) { - case PROP_CONNECT: - sink->connect = g_value_get_enum (value); - break; - case PROP_SERVER: - g_free (sink->server); - sink->server = g_value_dup_string (value); - break; - case PROP_CLIENT: - if (GST_STATE (sink) == GST_STATE_NULL || - GST_STATE (sink) == GST_STATE_READY) { - sink->jclient = g_value_get_boxed (value); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_jack_audio_sink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstJackAudioSink *sink; - - sink = GST_JACK_AUDIO_SINK (object); - - switch (prop_id) { - case PROP_CONNECT: - g_value_set_enum (value, sink->connect); - break; - case PROP_SERVER: - g_value_set_string (value, sink->server); - break; - case PROP_CLIENT: - g_value_set_boxed (value, sink->jclient); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static GstCaps * -gst_jack_audio_sink_getcaps (GstBaseSink * bsink) -{ - GstJackAudioSink *sink = GST_JACK_AUDIO_SINK (bsink); - const char **ports; - gint min, max; - gint rate; - jack_client_t *client; - - if (sink->client == NULL) - goto no_client; - - client = gst_jack_audio_client_get_client (sink->client); - - if (sink->connect == GST_JACK_CONNECT_AUTO) { - /* get a port count, this is the number of channels we can automatically - * connect. */ - ports = jack_get_ports (client, NULL, NULL, - JackPortIsPhysical | JackPortIsInput); - max = 0; - if (ports != NULL) { - for (; ports[max]; max++); - free (ports); - } else - max = 0; - } else { - /* we allow any number of pads, something else is going to connect the - * pads. */ - max = G_MAXINT; - } - min = MIN (1, max); - - rate = jack_get_sample_rate (client); - - GST_DEBUG_OBJECT (sink, "got %d-%d ports, samplerate: %d", min, max, rate); - - if (!sink->caps) { - sink->caps = gst_caps_new_simple ("audio/x-raw-float", - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "width", G_TYPE_INT, 32, - "rate", G_TYPE_INT, rate, - "channels", GST_TYPE_INT_RANGE, min, max, NULL); - } - GST_INFO_OBJECT (sink, "returning caps %" GST_PTR_FORMAT, sink->caps); - - return gst_caps_ref (sink->caps); - - /* ERRORS */ -no_client: - { - GST_DEBUG_OBJECT (sink, "device not open, using template caps"); - /* base class will get template caps for us when we return NULL */ - return NULL; - } -} - -static GstRingBuffer * -gst_jack_audio_sink_create_ringbuffer (GstBaseAudioSink * sink) -{ - GstRingBuffer *buffer; - - buffer = g_object_new (GST_TYPE_JACK_RING_BUFFER, NULL); - GST_DEBUG_OBJECT (sink, "created ringbuffer @%p", buffer); - - return buffer; -} diff --git a/ext/jack/gstjackaudiosink.h b/ext/jack/gstjackaudiosink.h deleted file mode 100644 index def423329..000000000 --- a/ext/jack/gstjackaudiosink.h +++ /dev/null @@ -1,78 +0,0 @@ -/* GStreamer - * Copyright (C) 2006 Wim Taymans <wim@fluendo.com> - * - * gstjacksink.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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GST_JACK_AUDIO_SINK_H__ -#define __GST_JACK_AUDIO_SINK_H__ - -#include <jack/jack.h> - -#include <gst/gst.h> -#include <gst/audio/gstbaseaudiosink.h> - -#include "gstjack.h" -#include "gstjackaudioclient.h" - -G_BEGIN_DECLS - -#define GST_TYPE_JACK_AUDIO_SINK (gst_jack_audio_sink_get_type()) -#define GST_JACK_AUDIO_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_JACK_AUDIO_SINK,GstJackAudioSink)) -#define GST_JACK_AUDIO_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_JACK_AUDIO_SINK,GstJackAudioSinkClass)) -#define GST_JACK_AUDIO_SINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_JACK_AUDIO_SINK,GstJackAudioSinkClass)) -#define GST_IS_JACK_AUDIO_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_JACK_AUDIO_SINK)) -#define GST_IS_JACK_AUDIO_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_JACK_AUDIO_SINK)) - -typedef struct _GstJackAudioSink GstJackAudioSink; -typedef struct _GstJackAudioSinkClass GstJackAudioSinkClass; - -/** - * GstJackAudioSink: - * - * Opaque #GstJackAudioSink. - */ -struct _GstJackAudioSink { - GstBaseAudioSink element; - - /*< private >*/ - /* cached caps */ - GstCaps *caps; - - /* properties */ - GstJackConnect connect; - gchar *server; - jack_client_t *jclient; - - /* our client */ - GstJackAudioClient *client; - - /* our ports */ - jack_port_t **ports; - int port_count; -}; - -struct _GstJackAudioSinkClass { - GstBaseAudioSinkClass parent_class; -}; - -GType gst_jack_audio_sink_get_type (void); - -G_END_DECLS - -#endif /* __GST_JACK_AUDIO_SINK_H__ */ diff --git a/ext/jack/gstjackaudiosrc.c b/ext/jack/gstjackaudiosrc.c deleted file mode 100644 index 0ffdb2398..000000000 --- a/ext/jack/gstjackaudiosrc.c +++ /dev/null @@ -1,874 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 Tristan Matthews <tristan@sat.qc.ca> - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/** - * SECTION:element-jackaudiosrc - * @see_also: #GstBaseAudioSrc, #GstRingBuffer - * - * A Src that inputs data from Jack ports. - * - * It will create N Jack ports named in_<name>_<num> where - * <name> is the element name and <num> is starting from 1. - * Each port corresponds to a gstreamer channel. - * - * The samplerate as exposed on the caps is always the same as the samplerate of - * the jack server. - * - * When the #GstJackAudioSrc:connect property is set to auto, this element - * will try to connect each input port to a random physical jack output pin. - * - * When the #GstJackAudioSrc:connect property is set to none, the element will - * accept any number of output channels and will create (but not connect) an - * input port for each channel. - * - * The element will generate an error when the Jack server is shut down when it - * was PAUSED or PLAYING. This element does not support dynamic rate and buffer - * size changes at runtime. - * - * <refsect2> - * <title>Example launch line</title> - * |[ - * gst-launch jackaudiosrc connect=0 ! jackaudiosink connect=0 - * ]| Get audio input into gstreamer from jack. - * </refsect2> - * - * Last reviewed on 2008-07-22 (0.10.4) - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <gst/gst-i18n-plugin.h> -#include <stdlib.h> -#include <string.h> - -#include "gstjackaudiosrc.h" -#include "gstjackringbuffer.h" -#include "gstjackutil.h" - -GST_DEBUG_CATEGORY_STATIC (gst_jack_audio_src_debug); -#define GST_CAT_DEFAULT gst_jack_audio_src_debug - -static gboolean -gst_jack_audio_src_allocate_channels (GstJackAudioSrc * src, gint channels) -{ - jack_client_t *client; - - client = gst_jack_audio_client_get_client (src->client); - - /* remove ports we don't need */ - while (src->port_count > channels) - jack_port_unregister (client, src->ports[--src->port_count]); - - /* alloc enough input ports */ - src->ports = g_realloc (src->ports, sizeof (jack_port_t *) * channels); - src->buffers = g_realloc (src->buffers, sizeof (sample_t *) * channels); - - /* create an input port for each channel */ - while (src->port_count < channels) { - gchar *name; - - /* port names start from 1 and are local to the element */ - name = - g_strdup_printf ("in_%s_%d", GST_ELEMENT_NAME (src), - src->port_count + 1); - src->ports[src->port_count] = - jack_port_register (client, name, JACK_DEFAULT_AUDIO_TYPE, - JackPortIsInput, 0); - if (src->ports[src->port_count] == NULL) - return FALSE; - - src->port_count++; - - g_free (name); - } - return TRUE; -} - -static void -gst_jack_audio_src_free_channels (GstJackAudioSrc * src) -{ - gint res, i = 0; - jack_client_t *client; - - client = gst_jack_audio_client_get_client (src->client); - - /* get rid of all ports */ - while (src->port_count) { - GST_LOG_OBJECT (src, "unregister port %d", i); - if ((res = jack_port_unregister (client, src->ports[i++]))) - GST_DEBUG_OBJECT (src, "unregister of port failed (%d)", res); - - src->port_count--; - } - g_free (src->ports); - src->ports = NULL; - g_free (src->buffers); - src->buffers = NULL; -} - -/* ringbuffer abstract base class */ -static GType -gst_jack_ring_buffer_get_type (void) -{ - static GType ringbuffer_type = 0; - - if (!ringbuffer_type) { - static const GTypeInfo ringbuffer_info = { sizeof (GstJackRingBufferClass), - NULL, - NULL, - (GClassInitFunc) gst_jack_ring_buffer_class_init, - NULL, - NULL, - sizeof (GstJackRingBuffer), - 0, - (GInstanceInitFunc) gst_jack_ring_buffer_init, - NULL - }; - - ringbuffer_type = - g_type_register_static (GST_TYPE_RING_BUFFER, - "GstJackAudioSrcRingBuffer", &ringbuffer_info, 0); - } - return ringbuffer_type; -} - -static void -gst_jack_ring_buffer_class_init (GstJackRingBufferClass * klass) -{ - GObjectClass *gobject_class; - GstObjectClass *gstobject_class; - GstRingBufferClass *gstringbuffer_class; - - gobject_class = (GObjectClass *) klass; - gstobject_class = (GstObjectClass *) klass; - gstringbuffer_class = (GstRingBufferClass *) klass; - - ring_parent_class = g_type_class_peek_parent (klass); - - gstringbuffer_class->open_device = - GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_open_device); - gstringbuffer_class->close_device = - GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_close_device); - gstringbuffer_class->acquire = - GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_acquire); - gstringbuffer_class->release = - GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_release); - gstringbuffer_class->start = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_start); - gstringbuffer_class->pause = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_pause); - gstringbuffer_class->resume = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_start); - gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_stop); - - gstringbuffer_class->delay = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_delay); -} - -/* this is the callback of jack. This should be RT-safe. - * Writes samples from the jack input port's buffer to the gst ring buffer. - */ -static int -jack_process_cb (jack_nframes_t nframes, void *arg) -{ - GstJackAudioSrc *src; - GstRingBuffer *buf; - gint len; - guint8 *writeptr; - gint writeseg; - gint channels, i, j, flen; - sample_t *data; - - buf = GST_RING_BUFFER_CAST (arg); - src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); - - channels = buf->spec.channels; - - /* get input buffers */ - for (i = 0; i < channels; i++) - src->buffers[i] = - (sample_t *) jack_port_get_buffer (src->ports[i], nframes); - - if (gst_ring_buffer_prepare_read (buf, &writeseg, &writeptr, &len)) { - flen = len / channels; - - /* the number of samples must be exactly the segment size */ - if (nframes * sizeof (sample_t) != flen) - goto wrong_size; - - /* the samples in the jack input buffers have to be interleaved into the - * ringbuffer */ - data = (sample_t *) writeptr; - for (i = 0; i < nframes; ++i) - for (j = 0; j < channels; ++j) - *data++ = src->buffers[j][i]; - - GST_DEBUG ("copy %d frames: %p, %d bytes, %d channels", nframes, writeptr, - len / channels, channels); - - /* we wrote one segment */ - gst_ring_buffer_advance (buf, 1); - } - return 0; - - /* ERRORS */ -wrong_size: - { - GST_ERROR_OBJECT (src, "nbytes (%d) != flen (%d)", - (gint) (nframes * sizeof (sample_t)), flen); - return 1; - } -} - -/* we error out */ -static int -jack_sample_rate_cb (jack_nframes_t nframes, void *arg) -{ - GstJackAudioSrc *src; - GstJackRingBuffer *abuf; - - abuf = GST_JACK_RING_BUFFER_CAST (arg); - src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (arg)); - - if (abuf->sample_rate != -1 && abuf->sample_rate != nframes) - goto not_supported; - - return 0; - - /* ERRORS */ -not_supported: - { - GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, - (NULL), ("Jack changed the sample rate, which is not supported")); - return 1; - } -} - -/* we error out */ -static int -jack_buffer_size_cb (jack_nframes_t nframes, void *arg) -{ - GstJackAudioSrc *src; - GstJackRingBuffer *abuf; - - abuf = GST_JACK_RING_BUFFER_CAST (arg); - src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (arg)); - - if (abuf->buffer_size != -1 && abuf->buffer_size != nframes) - goto not_supported; - - return 0; - - /* ERRORS */ -not_supported: - { - GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, - (NULL), ("Jack changed the buffer size, which is not supported")); - return 1; - } -} - -static void -jack_shutdown_cb (void *arg) -{ - GstJackAudioSrc *src; - - src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (arg)); - - GST_DEBUG_OBJECT (src, "shutdown"); - - GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, - (NULL), ("Jack server shutdown")); -} - -static void -gst_jack_ring_buffer_init (GstJackRingBuffer * buf, - GstJackRingBufferClass * g_class) -{ - buf->channels = -1; - buf->buffer_size = -1; - buf->sample_rate = -1; -} - -/* the _open_device method should make a connection with the server -*/ -static gboolean -gst_jack_ring_buffer_open_device (GstRingBuffer * buf) -{ - GstJackAudioSrc *src; - jack_status_t status = 0; - const gchar *name; - - src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); - - GST_DEBUG_OBJECT (src, "open"); - - name = g_get_application_name (); - if (!name) - name = "GStreamer"; - - src->client = gst_jack_audio_client_new (name, src->server, - src->jclient, - GST_JACK_CLIENT_SOURCE, - jack_shutdown_cb, - jack_process_cb, jack_buffer_size_cb, jack_sample_rate_cb, buf, &status); - if (src->client == NULL) - goto could_not_open; - - GST_DEBUG_OBJECT (src, "opened"); - - return TRUE; - - /* ERRORS */ -could_not_open: - { - if (status & JackServerFailed) { - GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, - (_("Jack server not found")), - ("Cannot connect to the Jack server (status %d)", status)); - } else { - GST_ELEMENT_ERROR (src, RESOURCE, OPEN_WRITE, - (NULL), ("Jack client open error (status %d)", status)); - } - return FALSE; - } -} - -/* close the connection with the server -*/ -static gboolean -gst_jack_ring_buffer_close_device (GstRingBuffer * buf) -{ - GstJackAudioSrc *src; - - src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); - - GST_DEBUG_OBJECT (src, "close"); - - gst_jack_audio_src_free_channels (src); - gst_jack_audio_client_free (src->client); - src->client = NULL; - - return TRUE; -} - - -/* allocate a buffer and setup resources to process the audio samples of - * the format as specified in @spec. - * - * We allocate N jack ports, one for each channel. If we are asked to - * automatically make a connection with physical ports, we connect as many - * ports as there are physical ports, leaving leftover ports unconnected. - * - * It is assumed that samplerate and number of channels are acceptable since our - * getcaps method will always provide correct values. If unacceptable caps are - * received for some reason, we fail here. - */ -static gboolean -gst_jack_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec) -{ - GstJackAudioSrc *src; - GstJackRingBuffer *abuf; - const char **ports; - gint sample_rate, buffer_size; - gint i, channels, res; - jack_client_t *client; - - src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); - abuf = GST_JACK_RING_BUFFER_CAST (buf); - - GST_DEBUG_OBJECT (src, "acquire"); - - client = gst_jack_audio_client_get_client (src->client); - - /* sample rate must be that of the server */ - sample_rate = jack_get_sample_rate (client); - if (sample_rate != spec->rate) - goto wrong_samplerate; - - channels = spec->channels; - - if (!gst_jack_audio_src_allocate_channels (src, channels)) - goto out_of_ports; - - gst_jack_set_layout_on_caps (&spec->caps, channels); - - buffer_size = jack_get_buffer_size (client); - - /* the segment size in bytes, this is large enough to hold a buffer of 32bit floats - * for all channels */ - spec->segsize = buffer_size * sizeof (gfloat) * channels; - spec->latency_time = gst_util_uint64_scale (spec->segsize, - (GST_SECOND / GST_USECOND), spec->rate * spec->bytes_per_sample); - /* segtotal based on buffer-time latency */ - spec->segtotal = spec->buffer_time / spec->latency_time; - if (spec->segtotal < 2) { - spec->segtotal = 2; - spec->buffer_time = spec->latency_time * spec->segtotal; - } - - GST_DEBUG_OBJECT (src, "buffer time: %" G_GINT64_FORMAT " usec", - spec->buffer_time); - GST_DEBUG_OBJECT (src, "latency time: %" G_GINT64_FORMAT " usec", - spec->latency_time); - GST_DEBUG_OBJECT (src, "buffer_size %d, segsize %d, segtotal %d", - buffer_size, spec->segsize, spec->segtotal); - - /* allocate the ringbuffer memory now */ - buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize); - memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data)); - - if ((res = gst_jack_audio_client_set_active (src->client, TRUE))) - goto could_not_activate; - - /* if we need to automatically connect the ports, do so now. We must do this - * after activating the client. */ - if (src->connect == GST_JACK_CONNECT_AUTO - || src->connect == GST_JACK_CONNECT_AUTO_FORCED) { - /* find all the physical output ports. A physical output port is a port - * associated with a hardware device. Someone needs connect to a physical - * port in order to capture something. */ - ports = - jack_get_ports (client, NULL, NULL, - JackPortIsPhysical | JackPortIsOutput); - if (ports == NULL) { - /* no ports? fine then we don't do anything except for posting a warning - * message. */ - GST_ELEMENT_WARNING (src, RESOURCE, NOT_FOUND, (NULL), - ("No physical output ports found, leaving ports unconnected")); - goto done; - } - - for (i = 0; i < channels; i++) { - /* stop when all output ports are exhausted */ - if (ports[i] == NULL) { - /* post a warning that we could not connect all ports */ - GST_ELEMENT_WARNING (src, RESOURCE, NOT_FOUND, (NULL), - ("No more physical ports, leaving some ports unconnected")); - break; - } - GST_DEBUG_OBJECT (src, "try connecting to %s", - jack_port_name (src->ports[i])); - - /* connect the physical port to a port */ - res = jack_connect (client, ports[i], jack_port_name (src->ports[i])); - if (res != 0 && res != EEXIST) - goto cannot_connect; - } - free (ports); - } -done: - - abuf->sample_rate = sample_rate; - abuf->buffer_size = buffer_size; - abuf->channels = spec->channels; - - return TRUE; - - /* ERRORS */ -wrong_samplerate: - { - GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), - ("Wrong samplerate, server is running at %d and we received %d", - sample_rate, spec->rate)); - return FALSE; - } -out_of_ports: - { - GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), - ("Cannot allocate more Jack ports")); - return FALSE; - } -could_not_activate: - { - GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), - ("Could not activate client (%d:%s)", res, g_strerror (res))); - return FALSE; - } -cannot_connect: - { - GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), - ("Could not connect input ports to physical ports (%d:%s)", - res, g_strerror (res))); - free (ports); - return FALSE; - } -} - -/* function is called with LOCK */ -static gboolean -gst_jack_ring_buffer_release (GstRingBuffer * buf) -{ - GstJackAudioSrc *src; - GstJackRingBuffer *abuf; - gint res; - - abuf = GST_JACK_RING_BUFFER_CAST (buf); - src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); - - GST_DEBUG_OBJECT (src, "release"); - - if ((res = gst_jack_audio_client_set_active (src->client, FALSE))) { - /* we only warn, this means the server is probably shut down and the client - * is gone anyway. */ - GST_ELEMENT_WARNING (src, RESOURCE, CLOSE, (NULL), - ("Could not deactivate Jack client (%d)", res)); - } - - abuf->channels = -1; - abuf->buffer_size = -1; - abuf->sample_rate = -1; - - /* free the buffer */ - gst_buffer_unref (buf->data); - buf->data = NULL; - - return TRUE; -} - -static gboolean -gst_jack_ring_buffer_start (GstRingBuffer * buf) -{ - GstJackAudioSrc *src; - - src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); - - GST_DEBUG_OBJECT (src, "start"); - - return TRUE; -} - -static gboolean -gst_jack_ring_buffer_pause (GstRingBuffer * buf) -{ - GstJackAudioSrc *src; - - src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); - - GST_DEBUG_OBJECT (src, "pause"); - - return TRUE; -} - -static gboolean -gst_jack_ring_buffer_stop (GstRingBuffer * buf) -{ - GstJackAudioSrc *src; - - src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); - - GST_DEBUG_OBJECT (src, "stop"); - - return TRUE; -} - -static guint -gst_jack_ring_buffer_delay (GstRingBuffer * buf) -{ - GstJackAudioSrc *src; - guint i, res = 0, latency; - jack_client_t *client; - - src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); - client = gst_jack_audio_client_get_client (src->client); - - for (i = 0; i < src->port_count; i++) { - latency = jack_port_get_total_latency (client, src->ports[i]); - if (latency > res) - res = latency; - } - - GST_DEBUG_OBJECT (src, "delay %u", res); - - return res; -} - -/* Audiosrc signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -#define DEFAULT_PROP_CONNECT GST_JACK_CONNECT_AUTO -#define DEFAULT_PROP_SERVER NULL - -enum -{ - PROP_0, - PROP_CONNECT, - PROP_SERVER, - PROP_CLIENT, - PROP_LAST -}; - - -/* the capabilities of the inputs and outputs. - * - * describe the real formats here. - */ - -static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-float, " - "endianness = (int) { " G_STRINGIFY (G_BYTE_ORDER) " }, " - "width = (int) 32, " - "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]") - ); - -#define _do_init(bla) \ - GST_DEBUG_CATEGORY_INIT(gst_jack_audio_src_debug, "jacksrc", 0, "jacksrc element"); - -GST_BOILERPLATE_FULL (GstJackAudioSrc, gst_jack_audio_src, GstBaseAudioSrc, - GST_TYPE_BASE_AUDIO_SRC, _do_init); - -static void gst_jack_audio_src_dispose (GObject * object); -static void gst_jack_audio_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_jack_audio_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -static GstCaps *gst_jack_audio_src_getcaps (GstBaseSrc * bsrc); -static GstRingBuffer *gst_jack_audio_src_create_ringbuffer (GstBaseAudioSrc * - src); - -/* GObject vmethod implementations */ - -static void -gst_jack_audio_src_base_init (gpointer gclass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (gclass); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_factory)); - gst_element_class_set_details_simple (element_class, "Audio Source (Jack)", - "Source/Audio", - "Input from Jack", "Tristan Matthews <tristan@sat.qc.ca>"); -} - -/* initialize the jack_audio_src's class */ -static void -gst_jack_audio_src_class_init (GstJackAudioSrcClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseSrcClass *gstbasesrc_class; - GstBaseAudioSrcClass *gstbaseaudiosrc_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - gstbasesrc_class = (GstBaseSrcClass *) klass; - gstbaseaudiosrc_class = (GstBaseAudioSrcClass *) klass; - - gobject_class->dispose = gst_jack_audio_src_dispose; - gobject_class->set_property = gst_jack_audio_src_set_property; - gobject_class->get_property = gst_jack_audio_src_get_property; - - g_object_class_install_property (gobject_class, PROP_CONNECT, - g_param_spec_enum ("connect", "Connect", - "Specify how the input ports will be connected", - GST_TYPE_JACK_CONNECT, DEFAULT_PROP_CONNECT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_SERVER, - g_param_spec_string ("server", "Server", - "The Jack server to connect to (NULL = default)", - DEFAULT_PROP_SERVER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_CLIENT, - g_param_spec_boxed ("client", "JackClient", "Handle for jack client", - GST_TYPE_JACK_CLIENT, - GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_jack_audio_src_getcaps); - gstbaseaudiosrc_class->create_ringbuffer = - GST_DEBUG_FUNCPTR (gst_jack_audio_src_create_ringbuffer); - - /* ref class from a thread-safe context to work around missing bit of - * thread-safety in GObject */ - g_type_class_ref (GST_TYPE_JACK_RING_BUFFER); - - gst_jack_audio_client_init (); -} - -/* initialize the new element - * instantiate pads and add them to element - * set pad calback functions - * initialize instance structure - */ -static void -gst_jack_audio_src_init (GstJackAudioSrc * src, GstJackAudioSrcClass * gclass) -{ - //gst_base_src_set_live(GST_BASE_SRC (src), TRUE); - src->connect = DEFAULT_PROP_CONNECT; - src->server = g_strdup (DEFAULT_PROP_SERVER); - src->jclient = NULL; - src->ports = NULL; - src->port_count = 0; - src->buffers = NULL; -} - -static void -gst_jack_audio_src_dispose (GObject * object) -{ - GstJackAudioSrc *src = GST_JACK_AUDIO_SRC (object); - - gst_caps_replace (&src->caps, NULL); - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static void -gst_jack_audio_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstJackAudioSrc *src = GST_JACK_AUDIO_SRC (object); - - switch (prop_id) { - case PROP_CONNECT: - src->connect = g_value_get_enum (value); - break; - case PROP_SERVER: - g_free (src->server); - src->server = g_value_dup_string (value); - break; - case PROP_CLIENT: - if (GST_STATE (src) == GST_STATE_NULL || - GST_STATE (src) == GST_STATE_READY) { - src->jclient = g_value_get_boxed (value); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_jack_audio_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstJackAudioSrc *src = GST_JACK_AUDIO_SRC (object); - - switch (prop_id) { - case PROP_CONNECT: - g_value_set_enum (value, src->connect); - break; - case PROP_SERVER: - g_value_set_string (value, src->server); - break; - case PROP_CLIENT: - g_value_set_boxed (value, src->jclient); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static GstCaps * -gst_jack_audio_src_getcaps (GstBaseSrc * bsrc) -{ - GstJackAudioSrc *src = GST_JACK_AUDIO_SRC (bsrc); - const char **ports; - gint min, max; - gint rate; - jack_client_t *client; - - if (src->client == NULL) - goto no_client; - - client = gst_jack_audio_client_get_client (src->client); - - if (src->connect == GST_JACK_CONNECT_AUTO) { - /* get a port count, this is the number of channels we can automatically - * connect. */ - ports = jack_get_ports (client, NULL, NULL, - JackPortIsPhysical | JackPortIsOutput); - max = 0; - if (ports != NULL) { - for (; ports[max]; max++); - - free (ports); - } else - max = 0; - } else { - /* we allow any number of pads, something else is going to connect the - * pads. */ - max = G_MAXINT; - } - min = MIN (1, max); - - rate = jack_get_sample_rate (client); - - GST_DEBUG_OBJECT (src, "got %d-%d ports, samplerate: %d", min, max, rate); - - if (!src->caps) { - src->caps = gst_caps_new_simple ("audio/x-raw-float", - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "width", G_TYPE_INT, 32, - "rate", G_TYPE_INT, rate, - "channels", GST_TYPE_INT_RANGE, min, max, NULL); - } - GST_INFO_OBJECT (src, "returning caps %" GST_PTR_FORMAT, src->caps); - - return gst_caps_ref (src->caps); - - /* ERRORS */ -no_client: - { - GST_DEBUG_OBJECT (src, "device not open, using template caps"); - /* base class will get template caps for us when we return NULL */ - return NULL; - } -} - -static GstRingBuffer * -gst_jack_audio_src_create_ringbuffer (GstBaseAudioSrc * src) -{ - GstRingBuffer *buffer; - - buffer = g_object_new (GST_TYPE_JACK_RING_BUFFER, NULL); - GST_DEBUG_OBJECT (src, "created ringbuffer @%p", buffer); - - return buffer; -} diff --git a/ext/jack/gstjackaudiosrc.h b/ext/jack/gstjackaudiosrc.h deleted file mode 100644 index 7e99b69df..000000000 --- a/ext/jack/gstjackaudiosrc.h +++ /dev/null @@ -1,97 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 Tristan Matthews <tristan@sat.qc.ca> - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GST_JACK_AUDIO_SRC_H__ -#define __GST_JACK_AUDIO_SRC_H__ - -#include <jack/jack.h> - -#include <gst/gst.h> -#include <gst/audio/gstaudiosrc.h> - -#include "gstjackaudioclient.h" -#include "gstjack.h" - -G_BEGIN_DECLS - -#define GST_TYPE_JACK_AUDIO_SRC (gst_jack_audio_src_get_type()) -#define GST_JACK_AUDIO_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_JACK_AUDIO_SRC,GstJackAudioSrc)) -#define GST_JACK_AUDIO_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_JACK_AUDIO_SRC,GstJackAudioSrcClass)) -#define GST_JACK_AUDIO_SRC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_JACK_AUDIO_SRC,GstJackAudioSrcClass)) -#define GST_IS_JACK_AUDIO_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_JACK_AUDIO_SRC)) -#define GST_IS_JACK_AUDIO_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_JACK_AUDIO_SRC)) - -typedef struct _GstJackAudioSrc GstJackAudioSrc; -typedef struct _GstJackAudioSrcClass GstJackAudioSrcClass; - -struct _GstJackAudioSrc -{ - GstBaseAudioSrc src; - - /*< private >*/ - /* cached caps */ - GstCaps *caps; - - /* properties */ - GstJackConnect connect; - gchar *server; - jack_client_t *jclient; - - /* our client */ - GstJackAudioClient *client; - - /* our ports */ - jack_port_t **ports; - int port_count; - sample_t **buffers; -}; - -struct _GstJackAudioSrcClass -{ - GstBaseAudioSrcClass parent_class; -}; - -GType gst_jack_audio_src_get_type (void); - -G_END_DECLS - -#endif /* __GST_JACK_AUDIO_SRC_H__ */ diff --git a/ext/jack/gstjackringbuffer.h b/ext/jack/gstjackringbuffer.h deleted file mode 100644 index 266fdfa31..000000000 --- a/ext/jack/gstjackringbuffer.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2006 Wim Taymans <wim@fluendo.com> - * Copyright (C) 2008 Tristan Matthews <tristan@sat.qc.ca> - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GST_JACK_RING_BUFFER_H__ -#define __GST_JACK_RING_BUFFER_H__ - -#define GST_TYPE_JACK_RING_BUFFER (gst_jack_ring_buffer_get_type()) -#define GST_JACK_RING_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_JACK_RING_BUFFER,GstJackRingBuffer)) -#define GST_JACK_RING_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_JACK_RING_BUFFER,GstJackRingBufferClass)) -#define GST_JACK_RING_BUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_JACK_RING_BUFFER,GstJackRingBufferClass)) -#define GST_JACK_RING_BUFFER_CAST(obj) ((GstJackRingBuffer *)obj) -#define GST_IS_JACK_RING_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_JACK_RING_BUFFER)) -#define GST_IS_JACK_RING_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_JACK_RING_BUFFER)) - -typedef struct _GstJackRingBuffer GstJackRingBuffer; -typedef struct _GstJackRingBufferClass GstJackRingBufferClass; - -struct _GstJackRingBuffer -{ - GstRingBuffer object; - - gint sample_rate; - gint buffer_size; - gint channels; -}; - -struct _GstJackRingBufferClass -{ - GstRingBufferClass parent_class; -}; - -static void gst_jack_ring_buffer_class_init(GstJackRingBufferClass * klass); -static void gst_jack_ring_buffer_init(GstJackRingBuffer * ringbuffer, - GstJackRingBufferClass * klass); - -static GstRingBufferClass *ring_parent_class = NULL; - -static gboolean gst_jack_ring_buffer_open_device(GstRingBuffer * buf); -static gboolean gst_jack_ring_buffer_close_device(GstRingBuffer * buf); -static gboolean gst_jack_ring_buffer_acquire(GstRingBuffer * buf,GstRingBufferSpec * spec); -static gboolean gst_jack_ring_buffer_release(GstRingBuffer * buf); -static gboolean gst_jack_ring_buffer_start(GstRingBuffer * buf); -static gboolean gst_jack_ring_buffer_pause(GstRingBuffer * buf); -static gboolean gst_jack_ring_buffer_stop(GstRingBuffer * buf); -static guint gst_jack_ring_buffer_delay(GstRingBuffer * buf); - -#endif diff --git a/ext/jack/gstjackutil.c b/ext/jack/gstjackutil.c deleted file mode 100644 index cde84d8e8..000000000 --- a/ext/jack/gstjackutil.c +++ /dev/null @@ -1,114 +0,0 @@ -/* GStreamer Jack utility functions - * Copyright (C) 2010 Tristan Matthews <tristan@sat.qc.ca> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "gstjackutil.h" -#include <gst/audio/multichannel.h> - -static const GstAudioChannelPosition default_positions[8][8] = { - /* 1 channel */ - { - GST_AUDIO_CHANNEL_POSITION_FRONT_MONO, - }, - /* 2 channels */ - { - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - }, - /* 3 channels (2.1) */ - { - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_LFE, /* or FRONT_CENTER for 3.0? */ - }, - /* 4 channels (4.0 or 3.1?) */ - { - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, - }, - /* 5 channels */ - { - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, - GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - }, - /* 6 channels */ - { - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, - GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_LFE, - }, - /* 7 channels */ - { - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, - GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_LFE, - GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, - }, - /* 8 channels */ - { - GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, - GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_LFE, - GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, - GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, - } -}; - - -/* if channels are less than or equal to 8, we set a default layout, - * otherwise set layout to an array of GST_AUDIO_CHANNEL_POSITION_NONE */ -void -gst_jack_set_layout_on_caps (GstCaps ** caps, gint channels) -{ - int c; - GValue pos = { 0 }; - GValue chanpos = { 0 }; - gst_caps_unref (*caps); - - if (channels <= 8) { - g_assert (channels >= 1); - gst_audio_set_channel_positions (gst_caps_get_structure (*caps, 0), - default_positions[channels - 1]); - } else { - g_value_init (&chanpos, GST_TYPE_ARRAY); - g_value_init (&pos, GST_TYPE_AUDIO_CHANNEL_POSITION); - for (c = 0; c < channels; c++) { - g_value_set_enum (&pos, GST_AUDIO_CHANNEL_POSITION_NONE); - gst_value_array_append_value (&chanpos, &pos); - } - g_value_unset (&pos); - gst_structure_set_value (gst_caps_get_structure (*caps, 0), - "channel-positions", &chanpos); - g_value_unset (&chanpos); - } - gst_caps_ref (*caps); -} diff --git a/ext/jp2k/gstjasperdec.c b/ext/jp2k/gstjasperdec.c index 05c1963ac..595134c46 100644 --- a/ext/jp2k/gstjasperdec.c +++ b/ext/jp2k/gstjasperdec.c @@ -65,7 +65,7 @@ static GstStaticPadTemplate gst_jasper_dec_src_template = GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB "; " GST_VIDEO_CAPS_BGR "; " GST_VIDEO_CAPS_RGBx "; " GST_VIDEO_CAPS_xRGB "; " GST_VIDEO_CAPS_BGRx "; " GST_VIDEO_CAPS_xBGR "; " - GST_VIDEO_CAPS_YUV ("{ I420, YV12, YUY2, UYVY, Y41B, Y42B }")) + GST_VIDEO_CAPS_YUV ("{ I420, YV12, YUY2, UYVY, Y41B, Y42B, v308 }")) ); static void gst_jasper_dec_set_property (GObject * object, guint prop_id, @@ -535,8 +535,8 @@ fail: if (*outbuf) gst_buffer_unref (*outbuf); *outbuf = NULL; - GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), (NULL)); - ret = GST_FLOW_ERROR; + GST_ELEMENT_WARNING (dec, STREAM, DECODE, (NULL), (NULL)); + ret = GST_FLOW_OK; goto done; } no_buffer: diff --git a/ext/jp2k/gstjasperenc.c b/ext/jp2k/gstjasperenc.c index a372be2ab..27073e22a 100644 --- a/ext/jp2k/gstjasperenc.c +++ b/ext/jp2k/gstjasperenc.c @@ -49,7 +49,7 @@ static GstStaticPadTemplate gst_jasper_enc_sink_template = GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB "; " GST_VIDEO_CAPS_BGR "; " GST_VIDEO_CAPS_RGBx "; " GST_VIDEO_CAPS_xRGB "; " GST_VIDEO_CAPS_BGRx "; " GST_VIDEO_CAPS_xBGR "; " - GST_VIDEO_CAPS_YUV ("{ I420, YV12 }")) + GST_VIDEO_CAPS_YUV ("{ I420, YV12, v308 }")) ); static GstStaticPadTemplate gst_jasper_enc_src_template = diff --git a/ext/kate/Makefile.am b/ext/kate/Makefile.am index 6a2152d13..fd7d6ced4 100644 --- a/ext/kate/Makefile.am +++ b/ext/kate/Makefile.am @@ -10,7 +10,7 @@ endif # flags used to compile this plugin libgstkate_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(TIGER_CFLAGS) $(KATE_CFLAGS) -libgstkate_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_MAJORMINOR) $(GST_LIBS) $(TIGER_LIBS) $(KATE_LIBS) +libgstkate_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) -lgsttag-$(GST_MAJORMINOR) $(GST_LIBS) $(TIGER_LIBS) $(KATE_LIBS) libgstkate_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstkate_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/ext/kate/gstkate.c b/ext/kate/gstkate.c index 08adfea8d..c7858e495 100644 --- a/ext/kate/gstkate.c +++ b/ext/kate/gstkate.c @@ -64,6 +64,7 @@ GST_DEBUG_CATEGORY (gst_katedec_debug); GST_DEBUG_CATEGORY (gst_kateenc_debug); GST_DEBUG_CATEGORY (gst_kateparse_debug); GST_DEBUG_CATEGORY (gst_katetag_debug); +GST_DEBUG_CATEGORY (gst_kateutil_debug); #ifdef HAVE_TIGER GST_DEBUG_CATEGORY (gst_katetiger_debug); #endif @@ -75,6 +76,8 @@ plugin_init (GstPlugin * plugin) GST_DEBUG_CATEGORY_INIT (gst_kateenc_debug, "kateenc", 0, "Kate encoder"); GST_DEBUG_CATEGORY_INIT (gst_kateparse_debug, "kateparse", 0, "Kate parser"); GST_DEBUG_CATEGORY_INIT (gst_katetag_debug, "katetag", 0, "Kate tagger"); + GST_DEBUG_CATEGORY_INIT (gst_kateutil_debug, "kateutil", 0, + "Kate utility functions"); #ifdef HAVE_TIGER GST_DEBUG_CATEGORY_INIT (gst_katetiger_debug, "tiger", 0, "Kate Tiger renderer"); @@ -97,7 +100,7 @@ plugin_init (GstPlugin * plugin) return FALSE; #ifdef HAVE_TIGER - if (!gst_element_register (plugin, "tiger", GST_RANK_NONE, + if (!gst_element_register (plugin, "tiger", GST_RANK_PRIMARY, GST_TYPE_KATE_TIGER)) return FALSE; #endif diff --git a/ext/kate/gstkatedec.c b/ext/kate/gstkatedec.c index 322363d81..df3607024 100644 --- a/ext/kate/gstkatedec.c +++ b/ext/kate/gstkatedec.c @@ -128,6 +128,9 @@ static GstFlowReturn gst_kate_dec_chain (GstPad * pad, GstBuffer * buf); static GstStateChangeReturn gst_kate_dec_change_state (GstElement * element, GstStateChange transition); static gboolean gst_kate_dec_sink_query (GstPad * pad, GstQuery * query); +static gboolean gst_kate_dec_sink_event (GstPad * pad, GstEvent * event); +static gboolean gst_kate_dec_sink_handle_event (GstPad * pad, GstEvent * event); +static GstCaps *gst_kate_dec_src_get_caps (GstPad * pad); static void gst_kate_dec_base_init (gpointer gclass) @@ -155,8 +158,8 @@ gst_kate_dec_class_init (GstKateDecClass * klass) gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; - gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_kate_dec_set_property); - gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_kate_dec_get_property); + gobject_class->set_property = gst_kate_dec_set_property; + gobject_class->get_property = gst_kate_dec_get_property; gst_kate_util_install_decoder_base_properties (gobject_class); @@ -184,16 +187,21 @@ gst_kate_dec_init (GstKateDec * dec, GstKateDecClass * gclass) GST_DEBUG_FUNCPTR (gst_kate_dec_chain)); gst_pad_set_query_function (dec->sinkpad, GST_DEBUG_FUNCPTR (gst_kate_dec_sink_query)); + gst_pad_set_event_function (dec->sinkpad, + GST_DEBUG_FUNCPTR (gst_kate_dec_sink_event)); gst_pad_use_fixed_caps (dec->sinkpad); gst_pad_set_caps (dec->sinkpad, gst_static_pad_template_get_caps (&sink_factory)); gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad); dec->srcpad = gst_pad_new_from_static_template (&src_factory, "src"); + gst_pad_set_getcaps_function (dec->srcpad, + GST_DEBUG_FUNCPTR (gst_kate_dec_src_get_caps)); gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad); - gst_kate_util_decode_base_init (&dec->decoder); + gst_kate_util_decode_base_init (&dec->decoder, TRUE); + dec->src_caps = NULL; dec->remove_markup = FALSE; } @@ -240,9 +248,16 @@ gst_kate_dec_chain (GstPad * pad, GstBuffer * buf) const kate_event *ev = NULL; GstFlowReturn rflow = GST_FLOW_OK; + if (!gst_kate_util_decoder_base_update_segment (&kd->decoder, + GST_ELEMENT_CAST (kd), buf)) { + GST_WARNING_OBJECT (kd, "Out of segment!"); + goto not_in_seg; + } + rflow = gst_kate_util_decoder_base_chain_kate_packet (&kd->decoder, - GST_ELEMENT_CAST (kd), pad, buf, kd->srcpad, &ev); + GST_ELEMENT_CAST (kd), pad, buf, kd->srcpad, kd->srcpad, &kd->src_caps, + &ev); if (G_UNLIKELY (rflow != GST_FLOW_OK)) { gst_object_unref (kd); gst_buffer_unref (buf); @@ -336,6 +351,7 @@ gst_kate_dec_chain (GstPad * pad, GstBuffer * buf) } } +not_in_seg: gst_object_unref (kd); gst_buffer_unref (buf); return rflow; @@ -344,9 +360,17 @@ gst_kate_dec_chain (GstPad * pad, GstBuffer * buf) static GstStateChangeReturn gst_kate_dec_change_state (GstElement * element, GstStateChange transition) { + GstStateChangeReturn ret; GstKateDec *kd = GST_KATE_DEC (element); - return gst_kate_decoder_base_change_state (&kd->decoder, element, + + ret = gst_kate_decoder_base_change_state (&kd->decoder, element, parent_class, transition); + + if (transition == GST_STATE_CHANGE_PAUSED_TO_READY) { + gst_caps_replace (&kd->src_caps, NULL); + } + + return ret; } gboolean @@ -359,3 +383,80 @@ gst_kate_dec_sink_query (GstPad * pad, GstQuery * query) gst_object_unref (kd); return res; } + +static gboolean +gst_kate_dec_sink_event (GstPad * pad, GstEvent * event) +{ + GstKateDec *kd = (GstKateDec *) (gst_object_get_parent (GST_OBJECT (pad))); + gboolean res = TRUE; + + GST_LOG_OBJECT (pad, "Event on sink pad: %s", GST_EVENT_TYPE_NAME (event)); + + /* Delay events till we've set caps */ + if (gst_kate_util_decoder_base_queue_event (&kd->decoder, event, + &gst_kate_dec_sink_handle_event, pad)) { + gst_object_unref (kd); + return TRUE; + } + + res = gst_kate_dec_sink_handle_event (pad, event); + + gst_object_unref (kd); + + return res; +} + +static gboolean +gst_kate_dec_sink_handle_event (GstPad * pad, GstEvent * event) +{ + GstKateDec *kd = (GstKateDec *) (gst_object_get_parent (GST_OBJECT (pad))); + gboolean res = TRUE; + + GST_LOG_OBJECT (pad, "Handling event on sink pad: %s", + GST_EVENT_TYPE_NAME (event)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NEWSEGMENT: + gst_kate_util_decoder_base_new_segment_event (&kd->decoder, event); + res = gst_pad_event_default (pad, event); + break; + + case GST_EVENT_FLUSH_START: + gst_kate_util_decoder_base_set_flushing (&kd->decoder, TRUE); + res = gst_pad_event_default (pad, event); + break; + + case GST_EVENT_FLUSH_STOP: + gst_kate_util_decoder_base_set_flushing (&kd->decoder, FALSE); + res = gst_pad_event_default (pad, event); + break; + + default: + res = gst_pad_event_default (pad, event); + break; + } + + gst_object_unref (kd); + + return res; +} + +static GstCaps * +gst_kate_dec_src_get_caps (GstPad * pad) +{ + GstKateDec *kd = (GstKateDec *) (gst_object_get_parent (GST_OBJECT (pad))); + GstCaps *caps; + + if (kd->src_caps) { + GST_DEBUG_OBJECT (kd, "We have src caps %" GST_PTR_FORMAT, kd->src_caps); + caps = kd->src_caps; + } else { + GST_DEBUG_OBJECT (kd, "We have no src caps, using template caps"); + caps = gst_static_pad_template_get_caps (&src_factory); + } + + caps = gst_caps_copy (caps); + + gst_object_unref (kd); + return caps; +} diff --git a/ext/kate/gstkatedec.h b/ext/kate/gstkatedec.h index a7011ecbc..b4d99059a 100644 --- a/ext/kate/gstkatedec.h +++ b/ext/kate/gstkatedec.h @@ -67,12 +67,12 @@ typedef struct _GstKateDecClass GstKateDecClass; struct _GstKateDec { - GstElement element; + GstKateDecoderBase decoder; GstPad *sinkpad; GstPad *srcpad; - GstKateDecoderBase decoder; + GstCaps *src_caps; gboolean remove_markup; }; diff --git a/ext/kate/gstkateparse.c b/ext/kate/gstkateparse.c index c41066645..6a72edec9 100644 --- a/ext/kate/gstkateparse.c +++ b/ext/kate/gstkateparse.c @@ -255,11 +255,6 @@ gst_kate_parse_push_buffer (GstKateParse * parse, GstBuffer * buf, GST_BUFFER_OFFSET_END (buf) = granulepos; GST_BUFFER_TIMESTAMP (buf) = GST_BUFFER_OFFSET (buf); - /* Hack to flush each packet on its own page - taken off the CMML encoder element */ - /* TODO: this is shite and needs to go once I find a way to tell Ogg to flush - as it messes up Matroska's track duration */ - GST_BUFFER_DURATION (buf) = G_MAXINT64; - gst_buffer_set_caps (buf, GST_PAD_CAPS (parse->srcpad)); return gst_pad_push (parse->srcpad, buf); diff --git a/ext/kate/gstkatespu.c b/ext/kate/gstkatespu.c index 778288ecf..13f561941 100644 --- a/ext/kate/gstkatespu.c +++ b/ext/kate/gstkatespu.c @@ -804,14 +804,6 @@ gst_kate_spu_encode_spu (GstKateDec * kd, const kate_event * ev) bytes[nbytes++] = ((kp->colors[palette[1]].a / 17) << 4) | (kp->colors[palette[0]].a / 17); -#if 0 - // move to top left - avoids a crash in dvdspu when overlaying on a small video :/ - right -= left; - bottom -= top; - left = 0; - top = 0; -#endif - CHKBUFSPC (7 * 2); bytes[nbytes++] = SPU_CMD_SET_DAREA; bytes[nbytes++] = left >> 4; diff --git a/ext/kate/gstkatetiger.c b/ext/kate/gstkatetiger.c index 93d98e73a..81ac6f755 100644 --- a/ext/kate/gstkatetiger.c +++ b/ext/kate/gstkatetiger.c @@ -88,6 +88,19 @@ GST_DEBUG_CATEGORY_EXTERN (gst_katetiger_debug); #define GST_CAT_DEFAULT gst_katetiger_debug +#define GST_KATE_TIGER_MUTEX_LOCK(element) \ + do { \ + /*GST_LOG_OBJECT ((element), "locking from %s:%d\n",__FILE__,__LINE__);*/ \ + g_mutex_lock ((element)->mutex); \ + /*GST_LOG_OBJECT ((element), "ready from %s:%d\n",__FILE__,__LINE__);*/ \ + } while(0) + +#define GST_KATE_TIGER_MUTEX_UNLOCK(element) \ + do { \ + /*GST_LOG_OBJECT ((element), "unlocking from %s:%d\n",__FILE__,__LINE__);*/ \ + g_mutex_unlock ((element)->mutex); \ + } while(0) + /* Filter signals and args */ enum { @@ -118,18 +131,26 @@ static GstStaticPadTemplate kate_sink_factory = GST_STATIC_CAPS ("subtitle/x-kate; application/x-kate") ); +#if G_BYTE_ORDER == G_LITTLE_ENDIAN +#define TIGER_VIDEO_CAPS \ + GST_VIDEO_CAPS_xRGB ", endianness = (int)1234; " \ + GST_VIDEO_CAPS_BGRx ", endianness = (int)4321" +#else +#define TIGER_VIDEO_CAPS \ + GST_VIDEO_CAPS_BGRx ", endianness = (int)4321; " \ + GST_VIDEO_CAPS_xRGB ", endianness = (int)1234" +#endif + static GstStaticPadTemplate video_sink_factory = GST_STATIC_PAD_TEMPLATE ("video_sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-raw-rgb, bpp=(int)32, depth=(int)24") - ); + GST_STATIC_CAPS (TIGER_VIDEO_CAPS)); static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-raw-rgb, bpp=(int)32, depth=(int)24") - ); + GST_STATIC_CAPS (TIGER_VIDEO_CAPS)); GST_BOILERPLATE (GstKateTiger, gst_kate_tiger, GstElement, GST_TYPE_ELEMENT); @@ -163,6 +184,7 @@ static GstStateChangeReturn gst_kate_tiger_change_state (GstElement * element, GstStateChange transition); static gboolean gst_kate_tiger_kate_sink_query (GstPad * pad, GstQuery * query); static gboolean gst_kate_tiger_kate_event (GstPad * pad, GstEvent * event); +static gboolean gst_kate_tiger_video_event (GstPad * pad, GstEvent * event); static gboolean gst_kate_tiger_video_set_caps (GstPad * pad, GstCaps * caps); static gboolean gst_kate_tiger_source_event (GstPad * pad, GstEvent * event); @@ -214,7 +236,7 @@ gst_kate_tiger_class_init (GstKateTigerClass * klass) g_param_spec_enum ("default-font-effect", "Default font effect", "Whether to apply an effect to text by default, for increased readability", gst_kate_tiger_font_effect_get_type (), - tiger_font_plain, + tiger_font_outline, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, @@ -287,6 +309,7 @@ gst_kate_tiger_init (GstKateTiger * tiger, GstKateTigerClass * gclass) GST_DEBUG_OBJECT (tiger, "gst_kate_tiger_init"); tiger->mutex = g_mutex_new (); + tiger->cond = g_cond_new (); tiger->katesinkpad = gst_pad_new_from_static_template (&kate_sink_factory, "subtitle_sink"); @@ -302,25 +325,25 @@ gst_kate_tiger_init (GstKateTiger * tiger, GstKateTigerClass * gclass) gst_pad_new_from_static_template (&video_sink_factory, "video_sink"); gst_pad_set_chain_function (tiger->videosinkpad, GST_DEBUG_FUNCPTR (gst_kate_tiger_video_chain)); - //gst_pad_set_query_function (tiger->videosinkpad, GST_DEBUG_FUNCPTR (gst_kate_tiger_video_sink_query)); gst_pad_use_fixed_caps (tiger->videosinkpad); - gst_pad_set_caps (tiger->videosinkpad, - gst_static_pad_template_get_caps (&video_sink_factory)); gst_pad_set_setcaps_function (tiger->videosinkpad, GST_DEBUG_FUNCPTR (gst_kate_tiger_video_set_caps)); + gst_pad_set_event_function (tiger->videosinkpad, + GST_DEBUG_FUNCPTR (gst_kate_tiger_video_event)); gst_element_add_pad (GST_ELEMENT (tiger), tiger->videosinkpad); tiger->srcpad = gst_pad_new_from_static_template (&src_factory, "src"); gst_pad_set_event_function (tiger->srcpad, gst_kate_tiger_source_event); + gst_pad_use_fixed_caps (tiger->srcpad); gst_element_add_pad (GST_ELEMENT (tiger), tiger->srcpad); - gst_kate_util_decode_base_init (&tiger->decoder); + gst_kate_util_decode_base_init (&tiger->decoder, FALSE); tiger->tr = NULL; tiger->default_font_desc = NULL; tiger->quality = -1.0; - tiger->default_font_effect = tiger_font_plain; + tiger->default_font_effect = tiger_font_outline; tiger->default_font_effect_strength = 0.5; tiger->default_font_r = 255; tiger->default_font_g = 255; @@ -333,6 +356,8 @@ gst_kate_tiger_init (GstKateTiger * tiger, GstKateTigerClass * gclass) tiger->video_width = 0; tiger->video_height = 0; + + tiger->seen_header = FALSE; } static void @@ -347,6 +372,9 @@ gst_kate_tiger_dispose (GObject * object) tiger->default_font_desc = NULL; } + g_cond_free (tiger->cond); + tiger->cond = NULL; + g_mutex_free (tiger->mutex); tiger->mutex = NULL; @@ -400,7 +428,7 @@ gst_kate_tiger_set_property (GObject * object, guint prop_id, GstKateTiger *tiger = GST_KATE_TIGER (object); const char *str; - g_mutex_lock (tiger->mutex); + GST_KATE_TIGER_MUTEX_LOCK (tiger); switch (prop_id) { case ARG_DEFAULT_FONT_DESC: @@ -465,7 +493,7 @@ gst_kate_tiger_set_property (GObject * object, guint prop_id, break; } - g_mutex_unlock (tiger->mutex); + GST_KATE_TIGER_MUTEX_UNLOCK (tiger); } static void @@ -474,7 +502,7 @@ gst_kate_tiger_get_property (GObject * object, guint prop_id, { GstKateTiger *tiger = GST_KATE_TIGER (object); - g_mutex_lock (tiger->mutex); + GST_KATE_TIGER_MUTEX_LOCK (tiger); switch (prop_id) { case ARG_DEFAULT_FONT_DESC: @@ -522,7 +550,7 @@ gst_kate_tiger_get_property (GObject * object, guint prop_id, break; } - g_mutex_unlock (tiger->mutex); + GST_KATE_TIGER_MUTEX_UNLOCK (tiger); } /* GstElement vmethod implementations */ @@ -538,30 +566,108 @@ gst_kate_tiger_kate_chain (GstPad * pad, GstBuffer * buf) const kate_event *ev = NULL; GstFlowReturn rflow = GST_FLOW_OK; - g_mutex_lock (tiger->mutex); + GST_KATE_TIGER_MUTEX_LOCK (tiger); + + GST_LOG_OBJECT (tiger, "Got kate buffer, caps %" GST_PTR_FORMAT, + GST_BUFFER_CAPS (buf)); + + /* Unfortunately, it can happen that the start of the stream is not sent, + for instance if there's a stream selector upstream, which is switched + from another Kate stream. If this happens, then we can fallback on the + headers stored in the caps (if any). */ + if (!tiger->seen_header) { + if (GST_BUFFER_SIZE (buf) == 0 || (GST_BUFFER_DATA (buf)[0] & 0x80) == 0) { + /* Not a header, try to fall back on caps */ + GstStructure *s; + const GValue *streamheader; + + GST_INFO_OBJECT (tiger, "Headers not seen, start of stream is cut off"); + s = gst_caps_get_structure (GST_BUFFER_CAPS (buf), 0); + streamheader = gst_structure_get_value (s, "streamheader"); + if (streamheader && G_VALUE_TYPE (streamheader) == GST_TYPE_ARRAY) { + GstPad *tagpad = gst_pad_get_peer (pad); + GArray *array; + gint i; + + GST_INFO_OBJECT (tiger, "Falling back on caps to initialize decoder"); + array = g_value_peek_pointer (streamheader); + for (i = 0; i < array->len; i++) { + GValue *value = &g_array_index (array, GValue, i); + if (G_VALUE_TYPE (value) == GST_TYPE_BUFFER) { + GstBuffer *hbuf = g_value_peek_pointer (value); + gst_buffer_ref (hbuf); + rflow = + gst_kate_util_decoder_base_chain_kate_packet (&tiger->decoder, + GST_ELEMENT_CAST (tiger), pad, hbuf, tiger->srcpad, tagpad, + NULL, NULL); + } else { + GST_WARNING_OBJECT (tiger, + "Streamheader index %d does not hold a buffer", i); + } + } + gst_object_unref (tagpad); + tiger->seen_header = TRUE; + } else { + GST_WARNING_OBJECT (tiger, "No headers seen, and no headers on caps"); + } + } else { + tiger->seen_header = TRUE; + } + } - GST_LOG_OBJECT (tiger, "Got kate buffer"); + if (gst_kate_util_decoder_base_update_segment (&tiger->decoder, + GST_ELEMENT_CAST (tiger), buf)) { + GstPad *tagpad = gst_pad_get_peer (pad); + rflow = + gst_kate_util_decoder_base_chain_kate_packet (&tiger->decoder, + GST_ELEMENT_CAST (tiger), pad, buf, tiger->srcpad, tagpad, NULL, &ev); + if (G_LIKELY (rflow == GST_FLOW_OK)) { + if (ev) { + int ret = tiger_renderer_add_event (tiger->tr, ev->ki, ev); + GST_INFO_OBJECT (tiger, "adding event for %p from %f to %f: %p, \"%s\"", + ev->ki, ev->start_time, ev->end_time, ev->bitmap, ev->text); + if (G_UNLIKELY (ret < 0)) { + GST_WARNING_OBJECT (tiger, + "failed to add Kate event to Tiger renderer: %d", ret); + } + } + } + gst_object_unref (tagpad); + } - rflow = - gst_kate_util_decoder_base_chain_kate_packet (&tiger->decoder, - GST_ELEMENT_CAST (tiger), pad, buf, tiger->srcpad, &ev); - if (G_LIKELY (rflow == GST_FLOW_OK)) { - if (ev) { - int ret = tiger_renderer_add_event (tiger->tr, ev->ki, ev); - GST_INFO_OBJECT (tiger, "adding event for %p from %f to %f: %p, \"%s\"", - ev->ki, ev->start_time, ev->end_time, ev->bitmap, ev->text); - if (G_UNLIKELY (ret < 0)) { - GST_WARNING_OBJECT (tiger, - "failed to add Kate event to Tiger renderer: %d", ret); + /* we want to avoid shooting ahead of the video stream, or we will + get segment updates which will place us ahead of it, and we won't + be able to convert a video timestamp back into a kate timestamp */ + if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (buf))) { + while (1) { + gint64 kate_time, video_time; + kate_time = + gst_segment_to_running_time (&tiger->decoder.kate_segment, + GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buf)); + video_time = + gst_segment_to_running_time (&tiger->video_segment, GST_FORMAT_TIME, + tiger->video_segment.last_stop); + GST_DEBUG_OBJECT (tiger, "Kate time %.2f, video time %.2f (kts %ld)", + kate_time / (float) GST_SECOND, video_time / (float) GST_SECOND, + (long) GST_BUFFER_TIMESTAMP (buf)); + if (kate_time <= video_time) { + break; + } + GST_LOG_OBJECT (tiger, "Waiting to return from chain function"); + g_cond_wait (tiger->cond, tiger->mutex); + if (tiger->decoder.kate_flushing) { + GST_DEBUG_OBJECT (tiger, "Flushing while waiting"); + break; } + GST_LOG_OBJECT (tiger, "Woken up, checking time again"); } } + GST_KATE_TIGER_MUTEX_UNLOCK (tiger); + gst_object_unref (tiger); gst_buffer_unref (buf); - g_mutex_unlock (tiger->mutex); - return rflow; } @@ -569,28 +675,41 @@ static gboolean gst_kate_tiger_video_set_caps (GstPad * pad, GstCaps * caps) { GstKateTiger *tiger = GST_KATE_TIGER (gst_pad_get_parent (pad)); - GstStructure *s; + GstVideoFormat format; gint w, h; - gboolean res = FALSE; - g_mutex_lock (tiger->mutex); + GST_KATE_TIGER_MUTEX_LOCK (tiger); - s = gst_caps_get_structure (caps, 0); + /* Cairo expects ARGB in native endianness, and that's what we get + as we've forced it in the caps. We might allow swapped red/blue + at some point, and get tiger to swap, to make some cases faster */ + tiger->swap_rgb = FALSE; - if (G_LIKELY (gst_structure_get_int (s, "width", &w)) - && G_LIKELY (gst_structure_get_int (s, "height", &h))) { - GST_INFO_OBJECT (tiger, "video sink: %d %d", w, h); + if (gst_video_format_parse_caps (caps, &format, &w, &h)) { tiger->video_width = w; tiger->video_height = h; - res = TRUE; } - g_mutex_unlock (tiger->mutex); + GST_KATE_TIGER_MUTEX_UNLOCK (tiger); + + gst_pad_set_caps (tiger->srcpad, caps); gst_object_unref (tiger); return TRUE; } +static gdouble +gst_kate_tiger_get_time (GstKateTiger * tiger) +{ + gint64 rt = + gst_segment_to_running_time (&tiger->video_segment, GST_FORMAT_TIME, + tiger->video_segment.last_stop); + gint64 pos = + gst_segment_to_position (&tiger->decoder.kate_segment, GST_FORMAT_TIME, + rt); + return pos / (gdouble) GST_SECOND; +} + static GstFlowReturn gst_kate_tiger_video_chain (GstPad * pad, GstBuffer * buf) { @@ -599,10 +718,23 @@ gst_kate_tiger_video_chain (GstPad * pad, GstBuffer * buf) unsigned char *ptr; int ret; - g_mutex_lock (tiger->mutex); + GST_KATE_TIGER_MUTEX_LOCK (tiger); GST_LOG_OBJECT (tiger, "got video frame, %u bytes", GST_BUFFER_SIZE (buf)); + if (G_UNLIKELY (tiger->video_flushing)) { + GST_KATE_TIGER_MUTEX_UNLOCK (tiger); + gst_object_unref (tiger); + gst_buffer_unref (buf); + return GST_FLOW_WRONG_STATE; + } + + if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (buf))) { + gst_segment_set_last_stop (&tiger->video_segment, GST_FORMAT_TIME, + GST_BUFFER_TIMESTAMP (buf)); + g_cond_broadcast (tiger->cond); + } + /* draw on it */ buf = gst_buffer_make_writable (buf); if (G_UNLIKELY (!buf)) { @@ -613,12 +745,17 @@ gst_kate_tiger_video_chain (GstPad * pad, GstBuffer * buf) GST_WARNING_OBJECT (tiger, "Failed to get a pointer to video buffer data"); } else { - ret = tiger_renderer_set_buffer (tiger->tr, ptr, tiger->video_width, tiger->video_height, tiger->video_width * 4, 0); // TODO: stride ? + ret = + tiger_renderer_set_buffer (tiger->tr, ptr, tiger->video_width, + tiger->video_height, tiger->video_width * 4, tiger->swap_rgb); if (G_UNLIKELY (ret < 0)) { GST_WARNING_OBJECT (tiger, "Tiger renderer failed to set buffer to video frame: %d", ret); } else { - kate_float t = GST_BUFFER_TIMESTAMP (buf) / (gdouble) GST_SECOND; + kate_float t = gst_kate_tiger_get_time (tiger); + GST_LOG_OBJECT (tiger, "Video segment calc: last stop %ld, time %.3f", + (long) tiger->video_segment.last_stop, t); + ret = tiger_renderer_update (tiger->tr, t, 1); if (G_UNLIKELY (ret < 0)) { GST_WARNING_OBJECT (tiger, "Tiger renderer failed to update: %d", @@ -636,12 +773,13 @@ gst_kate_tiger_video_chain (GstPad * pad, GstBuffer * buf) } } } + + GST_KATE_TIGER_MUTEX_UNLOCK (tiger); + rflow = gst_pad_push (tiger->srcpad, buf); gst_object_unref (tiger); - g_mutex_unlock (tiger->mutex); - return rflow; } @@ -654,12 +792,16 @@ gst_kate_tiger_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: GST_DEBUG_OBJECT (tiger, "PAUSED -> READY, clearing kate state"); - g_mutex_lock (tiger->mutex); + GST_KATE_TIGER_MUTEX_LOCK (tiger); + gst_kate_util_decoder_base_set_flushing (&tiger->decoder, TRUE); + g_cond_broadcast (tiger->cond); if (tiger->tr) { tiger_renderer_destroy (tiger->tr); tiger->tr = NULL; } - g_mutex_unlock (tiger->mutex); + gst_segment_init (&tiger->video_segment, GST_FORMAT_UNDEFINED); + tiger->video_flushing = TRUE; + GST_KATE_TIGER_MUTEX_UNLOCK (tiger); break; default: break; @@ -672,7 +814,7 @@ gst_kate_tiger_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_READY_TO_PAUSED: GST_DEBUG_OBJECT (tiger, "READY -> PAUSED, initializing kate state"); - g_mutex_lock (tiger->mutex); + GST_KATE_TIGER_MUTEX_LOCK (tiger); if (tiger->decoder.initialized) { int ret = tiger_renderer_create (&tiger->tr); if (ret < 0) { @@ -692,7 +834,10 @@ gst_kate_tiger_change_state (GstElement * element, GstStateChange transition) gst_kate_tiger_update_quality (tiger); } } - g_mutex_unlock (tiger->mutex); + gst_segment_init (&tiger->video_segment, GST_FORMAT_UNDEFINED); + tiger->video_flushing = FALSE; + tiger->seen_header = FALSE; + GST_KATE_TIGER_MUTEX_UNLOCK (tiger); break; default: break; @@ -713,18 +858,44 @@ gst_kate_tiger_seek (GstKateTiger * tiger, GstPad * pad, GstEvent * event) gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur, &stop_type, &stop); + GST_KATE_TIGER_MUTEX_LOCK (tiger); + tiger->video_flushing = TRUE; + gst_kate_util_decoder_base_set_flushing (&tiger->decoder, TRUE); + GST_KATE_TIGER_MUTEX_UNLOCK (tiger); + + if (format == GST_FORMAT_TIME) { + /* if seeking in time, we can update tiger to remove any appropriate events */ + kate_float target; + switch (cur_type) { + case GST_SEEK_TYPE_SET: + target = cur / (float) GST_SECOND; + break; + case GST_SEEK_TYPE_CUR: + GST_WARNING_OBJECT (tiger, + "Seeking from the current segment, cannot work out target so flushing everything"); + target = (kate_float) 0; + break; + case GST_SEEK_TYPE_END: + GST_WARNING_OBJECT (tiger, + "Seeking from the end, cannot work out target so flushing everything"); + target = (kate_float) 0; + break; + default: + GST_WARNING_OBJECT (tiger, "Unexpected seek type"); + target = (kate_float) 0; + break; + } + GST_INFO_OBJECT (tiger, "Seeking in time to %f", target); + GST_KATE_TIGER_MUTEX_LOCK (tiger); + tiger_renderer_seek (tiger->tr, target); + GST_KATE_TIGER_MUTEX_UNLOCK (tiger); + } + /* forward to both sinks */ gst_event_ref (event); if (gst_pad_push_event (tiger->videosinkpad, event)) { - if (gst_pad_push_event (tiger->katesinkpad, event)) { - if (format == GST_FORMAT_TIME) { - /* if seeking in time, we can update tiger to remove any appropriate events */ - kate_float target = cur / (gdouble) GST_SECOND; - GST_INFO_OBJECT (tiger, "Seeking in time to %f", target); - g_mutex_lock (tiger->mutex); - tiger_renderer_seek (tiger->tr, target); - g_mutex_unlock (tiger->mutex); - } + int ret = gst_pad_push_event (tiger->katesinkpad, event); + if (ret) { return TRUE; } else { return FALSE; @@ -744,6 +915,9 @@ gst_kate_tiger_source_event (GstPad * pad, GstEvent * event) g_return_val_if_fail (tiger != NULL, FALSE); + GST_LOG_OBJECT (tiger, "Event on source pad: %s", + GST_EVENT_TYPE_NAME (event)); + switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: GST_INFO_OBJECT (tiger, "Seek on source pad"); @@ -760,23 +934,41 @@ gst_kate_tiger_source_event (GstPad * pad, GstEvent * event) } static gboolean -gst_kate_tiger_kate_event (GstPad * pad, GstEvent * event) +gst_kate_tiger_handle_kate_event (GstPad * pad, GstEvent * event) { GstKateTiger *tiger = (GstKateTiger *) (gst_object_get_parent (GST_OBJECT (pad))); gboolean res = TRUE; - g_return_val_if_fail (tiger != NULL, FALSE); - switch (GST_EVENT_TYPE (event)) { case GST_EVENT_NEWSEGMENT: GST_INFO_OBJECT (tiger, "New segment on Kate pad"); + GST_KATE_TIGER_MUTEX_LOCK (tiger); + g_cond_broadcast (tiger->cond); + gst_kate_util_decoder_base_new_segment_event (&tiger->decoder, event); + GST_KATE_TIGER_MUTEX_UNLOCK (tiger); + gst_event_unref (event); + break; + case GST_EVENT_FLUSH_START: + GST_KATE_TIGER_MUTEX_LOCK (tiger); + gst_kate_util_decoder_base_set_flushing (&tiger->decoder, TRUE); + GST_KATE_TIGER_MUTEX_UNLOCK (tiger); + g_cond_broadcast (tiger->cond); + gst_event_unref (event); + break; + case GST_EVENT_FLUSH_STOP: + GST_KATE_TIGER_MUTEX_LOCK (tiger); + gst_kate_util_decoder_base_set_flushing (&tiger->decoder, FALSE); + GST_KATE_TIGER_MUTEX_UNLOCK (tiger); gst_event_unref (event); break; case GST_EVENT_EOS: /* we ignore this, it just means we don't have anymore Kate packets, but the Tiger renderer will still draw (if appropriate) on incoming video */ GST_INFO_OBJECT (tiger, "EOS on Kate pad"); + GST_KATE_TIGER_MUTEX_LOCK (tiger); + g_cond_broadcast (tiger->cond); + GST_KATE_TIGER_MUTEX_UNLOCK (tiger); gst_event_unref (event); break; default: @@ -789,12 +981,116 @@ gst_kate_tiger_kate_event (GstPad * pad, GstEvent * event) return res; } +static gboolean +gst_kate_tiger_kate_event (GstPad * pad, GstEvent * event) +{ + GstKateTiger *tiger = + (GstKateTiger *) (gst_object_get_parent (GST_OBJECT (pad))); + gboolean res = TRUE; + + g_return_val_if_fail (tiger != NULL, FALSE); + + GST_LOG_OBJECT (tiger, "Event on Kate pad: %s", GST_EVENT_TYPE_NAME (event)); + + /* Delay events till we've set caps */ + if (gst_kate_util_decoder_base_queue_event (&tiger->decoder, event, + &gst_kate_tiger_handle_kate_event, pad)) { + gst_object_unref (tiger); + return TRUE; + } + + res = gst_kate_tiger_handle_kate_event (pad, event); + + gst_object_unref (tiger); + + return res; +} + +static gboolean +gst_kate_tiger_handle_video_event (GstPad * pad, GstEvent * event) +{ + GstKateTiger *tiger = + (GstKateTiger *) (gst_object_get_parent (GST_OBJECT (pad))); + gboolean res = TRUE; + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NEWSEGMENT: + { + gboolean update; + gdouble rate, arate; + GstFormat format; + gint64 start, stop, time; + + gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, + &start, &stop, &time); + + if (format == GST_FORMAT_TIME) { + GST_DEBUG_OBJECT (tiger, "video pad segment:" + " Update %d, rate %g arate %g format %d start %" GST_TIME_FORMAT + " %" GST_TIME_FORMAT " position %" GST_TIME_FORMAT, + update, rate, arate, format, GST_TIME_ARGS (start), + GST_TIME_ARGS (stop), GST_TIME_ARGS (time)); + + GST_KATE_TIGER_MUTEX_LOCK (tiger); + gst_segment_set_newsegment_full (&tiger->video_segment, update, rate, + arate, format, start, stop, time); + GST_KATE_TIGER_MUTEX_UNLOCK (tiger); + } + + res = gst_pad_event_default (pad, event); + break; + } + case GST_EVENT_FLUSH_START: + GST_KATE_TIGER_MUTEX_LOCK (tiger); + gst_segment_init (&tiger->video_segment, GST_FORMAT_UNDEFINED); + tiger->video_flushing = TRUE; + GST_KATE_TIGER_MUTEX_UNLOCK (tiger); + g_cond_broadcast (tiger->cond); + res = gst_pad_event_default (pad, event); + break; + case GST_EVENT_FLUSH_STOP: + GST_KATE_TIGER_MUTEX_LOCK (tiger); + gst_segment_init (&tiger->video_segment, GST_FORMAT_UNDEFINED); + tiger->video_flushing = FALSE; + GST_KATE_TIGER_MUTEX_UNLOCK (tiger); + res = gst_pad_event_default (pad, event); + break; + default: + res = gst_pad_event_default (pad, event); + break; + } + + gst_object_unref (tiger); + + return res; +} + +static gboolean +gst_kate_tiger_video_event (GstPad * pad, GstEvent * event) +{ + GstKateTiger *tiger = + (GstKateTiger *) (gst_object_get_parent (GST_OBJECT (pad))); + gboolean res = TRUE; + + g_return_val_if_fail (tiger != NULL, FALSE); + + GST_INFO_OBJECT (tiger, "Event on video pad: %s", + GST_EVENT_TYPE_NAME (event)); + + res = gst_kate_tiger_handle_video_event (pad, event); + + gst_object_unref (tiger); + + return res; +} + gboolean gst_kate_tiger_kate_sink_query (GstPad * pad, GstQuery * query) { GstKateTiger *tiger = GST_KATE_TIGER (gst_pad_get_parent (pad)); gboolean res = gst_kate_decoder_base_sink_query (&tiger->decoder, GST_ELEMENT_CAST (tiger), pad, query); + GST_INFO_OBJECT (tiger, "Query on Kate pad"); gst_object_unref (tiger); return res; } diff --git a/ext/kate/gstkatetiger.h b/ext/kate/gstkatetiger.h index 0ab7dc136..d3880b32b 100644 --- a/ext/kate/gstkatetiger.h +++ b/ext/kate/gstkatetiger.h @@ -68,14 +68,12 @@ typedef struct _GstKateTigerClass GstKateTigerClass; struct _GstKateTiger { - GstElement element; + GstKateDecoderBase decoder; GstPad *katesinkpad; GstPad *videosinkpad; GstPad *srcpad; - GstKateDecoderBase decoder; - tiger_renderer *tr; gdouble quality; @@ -93,8 +91,14 @@ struct _GstKateTiger gint video_width; gint video_height; + gboolean swap_rgb; GMutex *mutex; + GCond *cond; + + GstSegment video_segment; + gboolean video_flushing; + gboolean seen_header; }; struct _GstKateTigerClass diff --git a/ext/kate/gstkateutil.c b/ext/kate/gstkateutil.c index 5b71b94a3..46ae19b9d 100644 --- a/ext/kate/gstkateutil.c +++ b/ext/kate/gstkateutil.c @@ -23,10 +23,17 @@ # include "config.h" #endif +#include <string.h> #include <gst/tag/tag.h> #include "gstkate.h" #include "gstkateutil.h" +GST_DEBUG_CATEGORY_EXTERN (gst_kateutil_debug); +#define GST_CAT_DEFAULT gst_kateutil_debug + +static void gst_kate_util_decoder_base_free_event_queue (GstKateDecoderBase * + decoder); + GstCaps * gst_kate_util_set_header_on_caps (GstElement * element, GstCaps * caps, GList * headers) @@ -95,7 +102,8 @@ gst_kate_util_install_decoder_base_properties (GObjectClass * gobject_class) } void -gst_kate_util_decode_base_init (GstKateDecoderBase * decoder) +gst_kate_util_decode_base_init (GstKateDecoderBase * decoder, + gboolean delay_events) { if (G_UNLIKELY (!decoder)) return; @@ -106,6 +114,8 @@ gst_kate_util_decode_base_init (GstKateDecoderBase * decoder) decoder->original_canvas_height = 0; decoder->tags = NULL; decoder->initialized = FALSE; + decoder->delay_events = delay_events; + decoder->event_queue = NULL; } static void @@ -121,10 +131,77 @@ gst_kate_util_decode_base_reset (GstKateDecoderBase * decoder) } decoder->original_canvas_width = 0; decoder->original_canvas_height = 0; + if (decoder->event_queue) { + gst_kate_util_decoder_base_free_event_queue (decoder); + } decoder->initialized = FALSE; } gboolean +gst_kate_util_decoder_base_queue_event (GstKateDecoderBase * decoder, + GstEvent * event, gboolean (*handler) (GstPad *, GstEvent *), GstPad * pad) +{ + gboolean can_be_queued; + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_START: + case GST_EVENT_FLUSH_STOP: + case GST_EVENT_EOS: + can_be_queued = FALSE; + break; + default: + can_be_queued = TRUE; + break; + } + + if (decoder->delay_events && can_be_queued) { + GstKateDecoderBaseQueuedEvent *item; + GST_DEBUG_OBJECT (decoder, "We have to delay the event"); + item = g_slice_new (GstKateDecoderBaseQueuedEvent); + if (item) { + item->event = event; + item->pad = pad; + item->handler = handler; + g_queue_push_tail (decoder->event_queue, item); + return TRUE; + } else { + return FALSE; + } + } else { + return FALSE; + } +} + +static void +gst_kate_util_decoder_base_free_event_queue (GstKateDecoderBase * decoder) +{ + while (decoder->event_queue->length) { + GstKateDecoderBaseQueuedEvent *item = (GstKateDecoderBaseQueuedEvent *) + g_queue_pop_head (decoder->event_queue); + g_slice_free (GstKateDecoderBaseQueuedEvent, item); + } + g_queue_free (decoder->event_queue); + decoder->event_queue = NULL; +} + +static void +gst_kate_util_decoder_base_drain_event_queue (GstKateDecoderBase * decoder) +{ + decoder->delay_events = FALSE; + + if (decoder->event_queue->length == 0) + return; + + GST_DEBUG_OBJECT (decoder, "We can now drain all events!"); + while (decoder->event_queue->length) { + GstKateDecoderBaseQueuedEvent *item = (GstKateDecoderBaseQueuedEvent *) + g_queue_pop_head (decoder->event_queue); + (*item->handler) (item->pad, item->event); + g_slice_free (GstKateDecoderBaseQueuedEvent, item); + } +} + +gboolean gst_kate_util_decoder_base_get_property (GstKateDecoderBase * decoder, GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { @@ -152,38 +229,65 @@ gst_kate_util_decoder_base_get_property (GstKateDecoderBase * decoder, GstFlowReturn gst_kate_util_decoder_base_chain_kate_packet (GstKateDecoderBase * decoder, GstElement * element, GstPad * pad, GstBuffer * buf, GstPad * srcpad, - const kate_event ** ev) + GstPad * tagpad, GstCaps ** src_caps, const kate_event ** ev) { kate_packet kp; int ret; GstFlowReturn rflow = GST_FLOW_OK; + gboolean is_header; GST_DEBUG_OBJECT (element, "got kate packet, %u bytes, type %02x", GST_BUFFER_SIZE (buf), GST_BUFFER_SIZE (buf) == 0 ? -1 : GST_BUFFER_DATA (buf)[0]); + + is_header = GST_BUFFER_SIZE (buf) > 0 && (GST_BUFFER_DATA (buf)[0] & 0x80); + + if (!is_header && decoder->tags) { + /* after we've processed headers, send any tags before processing the data packet */ + GST_DEBUG_OBJECT (element, "Not a header, sending tags for pad %s:%s", + GST_DEBUG_PAD_NAME (tagpad)); + gst_element_found_tags_for_pad (element, tagpad, decoder->tags); + decoder->tags = NULL; + } + kate_packet_wrap (&kp, GST_BUFFER_SIZE (buf), GST_BUFFER_DATA (buf)); ret = kate_high_decode_packetin (&decoder->k, &kp, ev); if (G_UNLIKELY (ret < 0)) { GST_ELEMENT_ERROR (element, STREAM, DECODE, (NULL), ("Failed to decode Kate packet: %d", ret)); return GST_FLOW_ERROR; - } else if (G_UNLIKELY (ret > 0)) { + } + + if (G_UNLIKELY (ret > 0)) { GST_DEBUG_OBJECT (element, "kate_high_decode_packetin has received EOS packet"); - return GST_FLOW_OK; } /* headers may be interesting to retrieve information from */ - if (G_LIKELY (GST_BUFFER_SIZE (buf) > 0)) + if (G_UNLIKELY (is_header)) { switch (GST_BUFFER_DATA (buf)[0]) { - GstCaps *caps; - case 0x80: /* ID header */ GST_INFO_OBJECT (element, "Parsed ID header: language %s, category %s", decoder->k.ki->language, decoder->k.ki->category); - caps = gst_caps_new_simple ("text/x-pango-markup", NULL); - gst_pad_set_caps (srcpad, caps); - gst_caps_unref (caps); + if (src_caps) { + if (*src_caps) { + gst_caps_unref (*src_caps); + *src_caps = NULL; + } + if (strcmp (decoder->k.ki->category, "K-SPU") == 0 || + strcmp (decoder->k.ki->category, "spu-subtitles") == 0) { + *src_caps = gst_caps_new_simple ("video/x-dvd-subpicture", NULL); + } else if (decoder->k.ki->text_markup_type == kate_markup_none) { + *src_caps = gst_caps_new_simple ("text/plain", NULL); + } else { + *src_caps = gst_caps_new_simple ("text/x-pango-markup", NULL); + } + GST_INFO_OBJECT (srcpad, "Setting caps: %" GST_PTR_FORMAT, *src_caps); + if (!gst_pad_set_caps (srcpad, *src_caps)) { + GST_ERROR_OBJECT (srcpad, "Failed to set caps %" GST_PTR_FORMAT, + *src_caps); + } + } if (decoder->k.ki->language && *decoder->k.ki->language) { GstTagList *old = decoder->tags, *tags = gst_tag_list_new (); if (tags) { @@ -214,6 +318,9 @@ gst_kate_util_decoder_base_chain_kate_packet (GstKateDecoderBase * decoder, decoder->original_canvas_width = decoder->k.ki->original_canvas_width; decoder->original_canvas_height = decoder->k.ki->original_canvas_height; + /* we can now send away any event we've delayed, as the src pad now has caps */ + gst_kate_util_decoder_base_drain_event_queue (decoder); + break; case 0x81: /* Vorbis comments header */ @@ -248,7 +355,7 @@ gst_kate_util_decoder_base_chain_kate_packet (GstKateDecoderBase * decoder, gst_tag_list_free (old); if (decoder->initialized) { - gst_element_found_tags_for_pad (element, srcpad, decoder->tags); + gst_element_found_tags_for_pad (element, tagpad, decoder->tags); decoder->tags = NULL; } else { /* Only push them as messages for the time being. * @@ -263,6 +370,7 @@ gst_kate_util_decoder_base_chain_kate_packet (GstKateDecoderBase * decoder, default: break; } + } return rflow; } @@ -285,7 +393,10 @@ gst_kate_decoder_base_change_state (GstKateDecoderBase * decoder, GST_WARNING_OBJECT (element, "failed to initialize kate state: %d", ret); } + gst_segment_init (&decoder->kate_segment, GST_FORMAT_UNDEFINED); + decoder->kate_flushing = FALSE; decoder->initialized = TRUE; + decoder->event_queue = g_queue_new (); break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: break; @@ -304,6 +415,8 @@ gst_kate_decoder_base_change_state (GstKateDecoderBase * decoder, kate_high_decode_clear (&decoder->k); decoder->initialized = FALSE; } + gst_segment_init (&decoder->kate_segment, GST_FORMAT_UNDEFINED); + decoder->kate_flushing = TRUE; gst_kate_util_decode_base_reset (decoder); break; case GST_STATE_CHANGE_READY_TO_NULL: @@ -316,6 +429,79 @@ gst_kate_decoder_base_change_state (GstKateDecoderBase * decoder, return res; } +void +gst_kate_util_decoder_base_set_flushing (GstKateDecoderBase * decoder, + gboolean flushing) +{ + decoder->kate_flushing = flushing; + gst_segment_init (&decoder->kate_segment, GST_FORMAT_UNDEFINED); +} + +void +gst_kate_util_decoder_base_new_segment_event (GstKateDecoderBase * decoder, + GstEvent * event) +{ + gboolean update; + gdouble rate; + GstFormat format; + gint64 start, stop, time; + gdouble arate; + + gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, + &start, &stop, &time); + GST_DEBUG_OBJECT (decoder, "kate pad segment:" + " Update %d, rate %g arate %g format %d start %" GST_TIME_FORMAT + " %" GST_TIME_FORMAT " position %" GST_TIME_FORMAT, + update, rate, arate, format, GST_TIME_ARGS (start), + GST_TIME_ARGS (stop), GST_TIME_ARGS (time)); + if (!update) { + /* Tiger uses this segment is used to remap the video running time to the + Kate running time. The sending of segment updates to keep streams in sync + does kinda rain on our parade though, and since we don't need these, + we just ignore those here */ + gst_segment_set_newsegment_full (&decoder->kate_segment, update, rate, + arate, format, start, stop, time); + } +} + +gboolean +gst_kate_util_decoder_base_update_segment (GstKateDecoderBase * decoder, + GstElement * element, GstBuffer * buf) +{ + gint64 clip_start = 0, clip_stop = 0; + gboolean in_seg; + + if (decoder->kate_flushing) { + GST_LOG_OBJECT (element, "Kate pad flushing, buffer ignored"); + return FALSE; + } + + if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (buf))) { + GstClockTime stop; + + if (G_LIKELY (GST_BUFFER_DURATION_IS_VALID (buf))) + stop = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf); + else + stop = GST_CLOCK_TIME_NONE; + + in_seg = gst_segment_clip (&decoder->kate_segment, GST_FORMAT_TIME, + GST_BUFFER_TIMESTAMP (buf), stop, &clip_start, &clip_stop); + } else { + in_seg = TRUE; + } + + if (in_seg) { + if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { + gst_segment_set_last_stop (&decoder->kate_segment, GST_FORMAT_TIME, + clip_start); + } + } else { + GST_INFO_OBJECT (element, "Kate buffer not in segment, ignored"); + } + + return in_seg; +} + static GstClockTime gst_kate_util_granule_time (kate_state * k, gint64 granulepos) { diff --git a/ext/kate/gstkateutil.h b/ext/kate/gstkateutil.h index 6e8ea2e01..27b6f70f3 100644 --- a/ext/kate/gstkateutil.h +++ b/ext/kate/gstkateutil.h @@ -37,6 +37,15 @@ G_BEGIN_DECLS enum typedef struct { + GstEvent * event; + gboolean (*handler)(GstPad *, GstEvent *); + GstPad *pad; +} GstKateDecoderBaseQueuedEvent; + +typedef struct +{ + GstElement element; + kate_state k; gboolean initialized; @@ -49,11 +58,17 @@ typedef struct gint original_canvas_width; gint original_canvas_height; + GstSegment kate_segment; + gboolean kate_flushing; + + gboolean delay_events; + GQueue *event_queue; } GstKateDecoderBase; extern GstCaps *gst_kate_util_set_header_on_caps (GstElement * element, GstCaps * caps, GList * headers); -extern void gst_kate_util_decode_base_init (GstKateDecoderBase * decoder); +extern void gst_kate_util_decode_base_init (GstKateDecoderBase * decoder, + gboolean delay_events); extern void gst_kate_util_install_decoder_base_properties (GObjectClass * gobject_class); extern gboolean gst_kate_util_decoder_base_get_property (GstKateDecoderBase * @@ -62,7 +77,16 @@ extern gboolean gst_kate_util_decoder_base_get_property (GstKateDecoderBase * extern GstFlowReturn gst_kate_util_decoder_base_chain_kate_packet (GstKateDecoderBase * decoder, GstElement * element, GstPad * pad, GstBuffer * buffer, GstPad * srcpad, - const kate_event ** ev); + GstPad * tagpad, GstCaps **src_caps, const kate_event ** ev); +extern void +gst_kate_util_decoder_base_set_flushing (GstKateDecoderBase * decoder, + gboolean flushing); +extern void +gst_kate_util_decoder_base_new_segment_event (GstKateDecoderBase * decoder, + GstEvent * event); +extern gboolean +gst_kate_util_decoder_base_update_segment (GstKateDecoderBase * decoder, + GstElement * element, GstBuffer * buf); extern GstStateChangeReturn gst_kate_decoder_base_change_state (GstKateDecoderBase * decoder, GstElement * element, GstElementClass * parent_class, @@ -72,6 +96,8 @@ extern gboolean gst_kate_decoder_base_convert (GstKateDecoderBase * decoder, GstFormat * dest_fmt, gint64 * dest_val); extern gboolean gst_kate_decoder_base_sink_query (GstKateDecoderBase * decoder, GstElement * element, GstPad * pad, GstQuery * query); +extern gboolean +gst_kate_util_decoder_base_queue_event (GstKateDecoderBase * decoder, GstEvent * event, gboolean (*handler)(GstPad *, GstEvent *), GstPad * pad); G_END_DECLS #endif /* __GST_KATE_UTIL_H__ */ diff --git a/ext/resindvd/resindvdsrc.c b/ext/resindvd/resindvdsrc.c index 72c8d2544..e4bdd7eec 100644 --- a/ext/resindvd/resindvdsrc.c +++ b/ext/resindvd/resindvdsrc.c @@ -36,6 +36,7 @@ GST_DEBUG_CATEGORY_STATIC (rsndvdsrc_debug); #define DEFAULT_DEVICE "/dev/dvd" #define DEFAULT_FASTSTART TRUE +#define DEFAULT_LANG "en" #define GST_FLOW_WOULD_BLOCK GST_FLOW_CUSTOM_SUCCESS @@ -61,7 +62,7 @@ typedef enum RSN_BTN_LEFT = 0x01, RSN_BTN_RIGHT = 0x02, RSN_BTN_UP = 0x04, - RSN_BTN_DOWN = 0x04 + RSN_BTN_DOWN = 0x08 } RsnBtnMask; enum @@ -354,6 +355,8 @@ static gboolean rsn_dvdsrc_start (GstBaseSrc * bsrc) { resinDvdSrc *src = RESINDVDSRC (bsrc); + const gchar *const *langs, *const *cur; + gchar lang[8]; g_mutex_lock (src->dvd_lock); if (!read_vts_info (src)) { @@ -374,6 +377,21 @@ rsn_dvdsrc_start (GstBaseSrc * bsrc) goto fail; } + /* Attempt to set DVD menu, audio and spu languages */ + langs = g_get_language_names (); + strncpy (lang, DEFAULT_LANG, 8); + for (cur = langs; *cur != NULL; cur++) { + /* Look for a 2 char iso-639 lang */ + if (strlen (*cur) == 2) { + strncpy (lang, *cur, 8); + break; + } + } + /* Set the user's preferred language */ + dvdnav_menu_language_select (src->dvdnav, lang); + dvdnav_audio_language_select (src->dvdnav, lang); + dvdnav_spu_language_select (src->dvdnav, lang); + if (src->faststart) { if (dvdnav_title_play (src->dvdnav, 1) != DVDNAV_STATUS_OK || (dvdnav_menu_call (src->dvdnav, DVD_MENU_Title) != DVDNAV_STATUS_OK && @@ -391,6 +409,7 @@ rsn_dvdsrc_start (GstBaseSrc * bsrc) src->branching = FALSE; src->discont = TRUE; src->need_segment = TRUE; + src->need_tag_update = TRUE; src->cur_position = GST_CLOCK_TIME_NONE; src->pgc_duration = GST_CLOCK_TIME_NONE; @@ -792,8 +811,8 @@ get_current_pgc (resinDvdSrc * src) return pgc; } -static void -update_title_info (resinDvdSrc * src) +static GstTagList * +update_title_info (resinDvdSrc * src, gboolean force) { gint n_angles, cur_agl; gint title_n, part_n; @@ -807,14 +826,14 @@ update_title_info (resinDvdSrc * src) if (dvdnav_current_title_info (src->dvdnav, &title_n, &part_n) != DVDNAV_STATUS_OK) { if (!src->in_menu) - return; /* Can't update now */ + return NULL; /* Can't update now */ /* Must be in the first play sequence */ title_n = -1; part_n = 0; } if (title_n != src->title_n || part_n != src->part_n || - src->n_angles != n_angles || src->cur_angle != cur_agl) { + src->n_angles != n_angles || src->cur_angle != cur_agl || force) { gchar *title_str = NULL; src->title_n = title_n; @@ -852,9 +871,11 @@ update_title_info (resinDvdSrc * src) gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_TITLE, title_str, NULL); g_free (title_str); - gst_element_found_tags (GST_ELEMENT_CAST (src), tags); + return tags; } } + + return NULL; } /* we don't cache the result on purpose */ @@ -1028,8 +1049,7 @@ rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock) GST_TIME_ARGS (src->cur_position)); rsn_dvdsrc_prepare_streamsinfo_event (src); - - update_title_info (src); + src->need_tag_update = TRUE; break; } @@ -1058,11 +1078,11 @@ rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock) dvdnav_audio_stream_change_event_t *event = (dvdnav_audio_stream_change_event_t *) data; + rsn_dvdsrc_prepare_audio_stream_event (src, + event->logical, event->physical); GST_DEBUG_OBJECT (src, " physical: %d", event->physical); GST_DEBUG_OBJECT (src, " logical: %d", event->logical); - rsn_dvdsrc_prepare_audio_stream_event (src, - event->logical, event->physical); break; } case DVDNAV_SPU_STREAM_CHANGE:{ @@ -1276,6 +1296,7 @@ rsn_dvdsrc_create (GstBaseSrc * bsrc, guint64 offset, GstEvent *audio_select_event = NULL; GstEvent *highlight_event = NULL; GstMessage *angles_msg = NULL; + GstTagList *tags = NULL; gboolean cmds_changed = FALSE; *outbuf = NULL; @@ -1313,6 +1334,11 @@ rsn_dvdsrc_create (GstBaseSrc * bsrc, guint64 offset, cmds_changed = src->commands_changed; src->commands_changed = FALSE; + if (src->need_tag_update) { + tags = update_title_info (src, FALSE); + src->need_tag_update = FALSE; + } + g_mutex_unlock (src->dvd_lock); /* Push in-band events now that we've dropped the dvd_lock, before @@ -1359,6 +1385,11 @@ rsn_dvdsrc_create (GstBaseSrc * bsrc, guint64 offset, if (src->cur_end_ts != GST_CLOCK_TIME_NONE) gst_segment_set_last_stop (segment, GST_FORMAT_TIME, src->cur_end_ts); + if (tags) { + gst_element_found_tags_for_pad (GST_ELEMENT_CAST (src), + GST_BASE_SRC_PAD (src), tags); + tags = NULL; + } g_mutex_lock (src->dvd_lock); if (src->next_buf != NULL) { @@ -1766,7 +1797,7 @@ rsn_dvdsrc_handle_navigation_event (resinDvdSrc * src, GstEvent * event) } src->angles_changed = FALSE; - update_title_info (src); + src->need_tag_update = TRUE; } cmds_changed = src->commands_changed; @@ -2369,7 +2400,7 @@ rsn_dvdsrc_src_event (GstBaseSrc * basesrc, GstEvent * event) GST_LOG_OBJECT (src, "handling seek event"); gst_event_parse_seek (event, NULL, NULL, &flags, NULL, NULL, NULL, NULL); - src->flushing_seek = ! !(flags & GST_SEEK_FLAG_FLUSH); + src->flushing_seek = !!(flags & GST_SEEK_FLAG_FLUSH); GST_DEBUG_OBJECT (src, "%s seek event", src->flushing_seek ? "flushing" : "non-flushing"); diff --git a/ext/resindvd/resindvdsrc.h b/ext/resindvd/resindvdsrc.h index c3985b6cf..5e6e3c7a0 100644 --- a/ext/resindvd/resindvdsrc.h +++ b/ext/resindvd/resindvdsrc.h @@ -84,6 +84,7 @@ struct _resinDvdSrc gboolean first_seek; gboolean flushing_seek; gboolean need_segment; + gboolean need_tag_update; gboolean active_highlight; gboolean in_still_state; gboolean in_playing; diff --git a/ext/rsvg/gstrsvgdec.c b/ext/rsvg/gstrsvgdec.c index b885d15b8..c0a636216 100644 --- a/ext/rsvg/gstrsvgdec.c +++ b/ext/rsvg/gstrsvgdec.c @@ -16,6 +16,18 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ +/** + * SECTION:element-rsvgdec + * + * This elements renders SVG graphics. + * + * <refsect2> + * <title>Example launch lines</title> + * |[ + * gst-launch filesrc location=image.svg ! rsvgdec ! imagefreeze ! ffmpegcolorspace ! autovideosink + * ]| render and show a svg image. + * </refsect2> + */ #ifdef HAVE_CONFIG_H #include "config.h" diff --git a/ext/rsvg/gstrsvgoverlay.c b/ext/rsvg/gstrsvgoverlay.c index d5c707824..1cbd0990c 100644 --- a/ext/rsvg/gstrsvgoverlay.c +++ b/ext/rsvg/gstrsvgoverlay.c @@ -24,19 +24,34 @@ * either be specified through properties, or fed through the * data-sink pad. * - * Note: setting the x or y parameter to a non-zero value will implicitly disable the fit-to-frame behaviour. + * Position and dimension of the SVG graphics can be achieved by + * specifying appropriate dimensions in the SVG file itself, but + * shortcuts are provided by the element to specify x/y position and + * width/height dimension, both in absolute form (pixels) and in + * relative form (percentage of video dimension). + * + * For any measure (x/y/width/height), the absolute value (in pixels) + * takes precedence over the relative one if both are + * specified. Absolute values must be set to 0 to disable them. + * + * If all parameters are 0, the image is displayed without rescaling + * at (0, 0) position. + * + * The fit-to-frame property is a shortcut for displaying the SVG + * overlay at (0, 0) position filling the whole screen. It modifies + * the values of the x/y/width/height attributes, by setting + * height-/width-relative to 1.0. and all other attributes to 0. * * <refsect2> - * * <title>Example launch lines</title> * |[ * gst-launch -v videotestsrc ! ffmpegcolorspace ! rsvgoverlay location=foo.svg ! ffmpegcolorspace ! autovideosink - * ]| specifies the SVG location through the filename property. + * ]| specifies the SVG location through the filename property. * |[ * gst-launch -v videotestsrc ! ffmpegcolorspace ! rsvgoverlay name=overlay ! ffmpegcolorspace ! autovideosink filesrc location=foo.svg ! image/svg ! overlay.data_sink * ]| does the same by feeding data through the data_sink pad. You can also specify the SVG data itself as parameter: * |[ - * gst-launch -v videotestsrc ! ffmpegcolorspace ! rsvgoverlay data='<svg viewBox="0 0 800 600"><image x="80%" y="80%" width="10%" height="10%" xlink:href="foo.jpg" /></svg>' ! ffmpegcolorspace ! autovideosink + * gst-launch -v videotestsrc ! ffmpegcolorspace ! rsvgoverlay data='<svg viewBox="0 0 800 600"><image x="80%" y="80%" width="10%" height="10%" xlink:href="foo.jpg" /></svg>' ! ffmpegcolorspace ! autovideosink * ]| * </refsect2> */ @@ -61,6 +76,12 @@ enum PROP_FIT_TO_FRAME, PROP_X, PROP_Y, + PROP_X_RELATIVE, + PROP_Y_RELATIVE, + PROP_WIDTH, + PROP_HEIGHT, + PROP_WIDTH_RELATIVE, + PROP_HEIGHT_RELATIVE }; #define GST_RSVG_LOCK(overlay) G_STMT_START { \ @@ -126,16 +147,20 @@ gst_rsvg_overlay_set_svg_data (GstRsvgOverlay * overlay, const gchar * data, else overlay->handle = rsvg_handle_new_from_data ((guint8 *) data, size, &error); - if (error) { - GST_ERROR_OBJECT (overlay, "Cannot read SVG data: %s\n%s", - error->message, data); - g_error_free (error); + if (error || overlay->handle == NULL) { + if (error) { + GST_ERROR_OBJECT (overlay, "Cannot read SVG data: %s\n%s", + error->message, data); + g_error_free (error); + } else { + GST_ERROR_OBJECT (overlay, "Cannot read SVG data: %s", data); + } } else { /* Get SVG dimension. */ RsvgDimensionData svg_dimension; rsvg_handle_get_dimensions (overlay->handle, &svg_dimension); - overlay->width = svg_dimension.width; - overlay->height = svg_dimension.height; + overlay->svg_width = svg_dimension.width; + overlay->svg_height = svg_dimension.height; gst_base_transform_set_passthrough (btrans, FALSE); } } @@ -164,7 +189,19 @@ gst_rsvg_overlay_set_property (GObject * object, guint prop_id, } case PROP_FIT_TO_FRAME: { - overlay->fit_to_frame = g_value_get_boolean (value); + if (g_value_get_boolean (value)) { + overlay->x_offset = 0; + overlay->y_offset = 0; + overlay->x_relative = 0.0; + overlay->y_relative = 0.0; + overlay->width = 0; + overlay->height = 0; + overlay->width_relative = 1.0; + overlay->height_relative = 1.0; + } else { + overlay->width_relative = 0; + overlay->height_relative = 0; + } break; } case PROP_X: @@ -177,6 +214,37 @@ gst_rsvg_overlay_set_property (GObject * object, guint prop_id, overlay->y_offset = g_value_get_int (value); break; } + case PROP_X_RELATIVE: + { + overlay->x_relative = g_value_get_float (value); + break; + } + case PROP_Y_RELATIVE: + { + overlay->y_relative = g_value_get_float (value); + break; + } + + case PROP_WIDTH: + { + overlay->width = g_value_get_int (value); + break; + } + case PROP_HEIGHT: + { + overlay->height = g_value_get_int (value); + break; + } + case PROP_WIDTH_RELATIVE: + { + overlay->width_relative = g_value_get_float (value); + break; + } + case PROP_HEIGHT_RELATIVE: + { + overlay->height_relative = g_value_get_float (value); + break; + } default: { @@ -196,13 +264,34 @@ gst_rsvg_overlay_get_property (GObject * object, guint prop_id, GValue * value, switch (prop_id) { case PROP_X: - g_value_set_uint (value, overlay->x_offset); + g_value_set_int (value, overlay->x_offset); break; case PROP_Y: - g_value_set_uint (value, overlay->y_offset); + g_value_set_int (value, overlay->y_offset); + break; + case PROP_X_RELATIVE: + g_value_set_float (value, overlay->x_relative); + break; + case PROP_Y_RELATIVE: + g_value_set_float (value, overlay->y_relative); + break; + + case PROP_WIDTH: + g_value_set_int (value, overlay->width); break; + case PROP_HEIGHT: + g_value_set_int (value, overlay->height); + break; + case PROP_WIDTH_RELATIVE: + g_value_set_float (value, overlay->width_relative); + break; + case PROP_HEIGHT_RELATIVE: + g_value_set_float (value, overlay->height_relative); + break; + case PROP_FIT_TO_FRAME: - g_value_set_boolean (value, overlay->fit_to_frame); + g_value_set_boolean (value, (overlay->width_relative == 1.0 + && overlay->height_relative == 1.0)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -274,6 +363,10 @@ gst_rsvg_overlay_transform_ip (GstBaseTransform * btrans, GstBuffer * buf) GstRsvgOverlay *overlay = GST_RSVG_OVERLAY (btrans); cairo_surface_t *surface; cairo_t *cr; + double applied_x_offset = (double) overlay->x_offset; + double applied_y_offset = (double) overlay->y_offset; + int applied_width = overlay->width; + int applied_height = overlay->height; GST_RSVG_LOCK (overlay); if (!overlay->handle) { @@ -294,14 +387,37 @@ gst_rsvg_overlay_transform_ip (GstBaseTransform * btrans, GstBuffer * buf) return GST_FLOW_ERROR; } - /* If x or y offset is specified, do not fit-to-frame. */ - if (overlay->x_offset || overlay->y_offset) - cairo_translate (cr, (double) overlay->x_offset, - (double) overlay->y_offset); - else if (overlay->fit_to_frame && overlay->width && overlay->height) - cairo_scale (cr, (float) overlay->caps_width / overlay->width, - (float) overlay->caps_height / overlay->height); + /* Compute relative dimensions if absolute dimensions are not set */ + if (!applied_x_offset && overlay->x_relative) { + applied_x_offset = overlay->x_relative * overlay->caps_width; + } + if (!applied_y_offset && overlay->y_relative) { + applied_y_offset = overlay->y_relative * overlay->caps_height; + } + if (!applied_width && overlay->width_relative) { + applied_width = (int) (overlay->width_relative * overlay->caps_width); + } + if (!applied_height && overlay->height_relative) { + applied_height = (int) (overlay->height_relative * overlay->caps_height); + } + + if (applied_x_offset || applied_y_offset) { + cairo_translate (cr, applied_x_offset, applied_y_offset); + } + /* Scale when necessary, i.e. an absolute or relative dimension has been specified. */ + if ((applied_width || applied_height) && overlay->svg_width + && overlay->svg_height) { + /* If may happen that only one of the dimension is specified. Use + the original SVG size for the other dimension. */ + if (!applied_width) + applied_width = overlay->svg_width; + if (!applied_height) + applied_height = overlay->svg_height; + + cairo_scale (cr, (double) applied_width / overlay->svg_width, + (double) applied_height / overlay->svg_height); + } rsvg_handle_render_cairo (overlay->handle, cr); GST_RSVG_UNLOCK (overlay); @@ -362,14 +478,40 @@ gst_rsvg_overlay_class_init (GstRsvgOverlayClass * klass) g_param_spec_boolean ("fit-to-frame", "fit to frame", "Fit the SVG to fill the whole frame.", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_X, g_param_spec_int ("x", "x offset", - "Specify an x offset.", 0, G_MAXINT, 0, + "Specify an x offset.", -G_MAXINT, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_Y, g_param_spec_int ("y", "y offset", - "Specify a y offset.", 0, G_MAXINT, 0, + "Specify a y offset.", -G_MAXINT, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_X_RELATIVE, + g_param_spec_float ("x-relative", "x relative offset", + "Specify an x offset relative to the display size.", -G_MAXFLOAT, + G_MAXFLOAT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_Y_RELATIVE, + g_param_spec_float ("y-relative", "y relative offset", + "Specify a y offset relative to the display size.", -G_MAXFLOAT, + G_MAXFLOAT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_WIDTH, + g_param_spec_int ("width", "width", + "Specify a width in pixels.", -G_MAXINT, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HEIGHT, + g_param_spec_int ("height", "height", + "Specify a height in pixels.", -G_MAXINT, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_WIDTH_RELATIVE, + g_param_spec_float ("width-relative", "relative width", + "Specify a width relative to the display size.", -G_MAXFLOAT, + G_MAXFLOAT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HEIGHT_RELATIVE, + g_param_spec_float ("height-relative", "relative height", + "Specify a height relative to the display size.", -G_MAXFLOAT, + G_MAXFLOAT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); basetransform_class->set_caps = gst_rsvg_overlay_set_caps; basetransform_class->transform_ip = gst_rsvg_overlay_transform_ip; @@ -380,7 +522,15 @@ gst_rsvg_overlay_class_init (GstRsvgOverlayClass * klass) static void gst_rsvg_overlay_init (GstRsvgOverlay * overlay, GstRsvgOverlayClass * klass) { - overlay->fit_to_frame = 1; + overlay->x_offset = 0; + overlay->y_offset = 0; + overlay->x_relative = 0.0; + overlay->y_relative = 0.0; + overlay->width = 0; + overlay->height = 0; + overlay->width_relative = 0.0; + overlay->height_relative = 0.0; + overlay->adapter = gst_adapter_new (); /* data sink */ diff --git a/ext/rsvg/gstrsvgoverlay.h b/ext/rsvg/gstrsvgoverlay.h index a0125444c..371bc35be 100644 --- a/ext/rsvg/gstrsvgoverlay.h +++ b/ext/rsvg/gstrsvgoverlay.h @@ -50,13 +50,18 @@ struct _GstRsvgOverlay RsvgHandle *handle; /* width and height of the SVG data */ - int width; - int height; - /* Should we fit the SVG to the dimension ? */ - gboolean fit_to_frame; + int svg_width; + int svg_height; int x_offset; int y_offset; + float x_relative; + float y_relative; + + int width; + int height; + float width_relative; + float height_relative; GstVideoFormat caps_format; int caps_width; diff --git a/ext/schroedinger/Makefile.am b/ext/schroedinger/Makefile.am index fdedd67f0..66b2e1e2f 100644 --- a/ext/schroedinger/Makefile.am +++ b/ext/schroedinger/Makefile.am @@ -8,7 +8,6 @@ libgstschro_la_SOURCES = \ gstschro.c \ gstschrodec.c \ gstschroenc.c \ - gstschroparse.c \ gstschroutils.c libgstschro_la_CFLAGS = \ $(GST_PLUGINS_BAD_CFLAGS) \ diff --git a/ext/schroedinger/gstschro.c b/ext/schroedinger/gstschro.c index 44d9226e6..c486473f9 100644 --- a/ext/schroedinger/gstschro.c +++ b/ext/schroedinger/gstschro.c @@ -26,7 +26,6 @@ GType gst_schro_enc_get_type (void); GType gst_schro_dec_get_type (void); -GType gst_schro_parse_get_type (void); GST_DEBUG_CATEGORY (schro_debug); #define GST_CAT_DEFAULT schro_debug @@ -39,8 +38,6 @@ plugin_init (GstPlugin * plugin) GST_DEBUG_CATEGORY_INIT (schro_debug, "schro", 0, "Schroedinger"); gst_element_register (plugin, "schrodec", GST_RANK_PRIMARY, gst_schro_dec_get_type ()); - gst_element_register (plugin, "schroparse", GST_RANK_NONE, - gst_schro_parse_get_type ()); gst_element_register (plugin, "schroenc", GST_RANK_PRIMARY, gst_schro_enc_get_type ()); diff --git a/ext/schroedinger/gstschroenc.c b/ext/schroedinger/gstschroenc.c index b4e50a922..7af28eac2 100644 --- a/ext/schroedinger/gstschroenc.c +++ b/ext/schroedinger/gstschroenc.c @@ -600,6 +600,7 @@ gst_schro_enc_get_caps (GstBaseVideoEncoder * base_video_encoder) state->par_d, NULL); } else { g_assert_not_reached (); + caps = NULL; } return caps; diff --git a/ext/schroedinger/gstschroparse.c b/ext/schroedinger/gstschroparse.c deleted file mode 100644 index 25711c8d1..000000000 --- a/ext/schroedinger/gstschroparse.c +++ /dev/null @@ -1,585 +0,0 @@ -/* Schrodinger - * Copyright (C) 2006 David Schleef <ds@schleef.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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <gst/gst.h> -#include <gst/base/gstadapter.h> -#include <gst/video/video.h> -#include <gst/video/gstbasevideoparse.h> -#include <string.h> -#include <schroedinger/schro.h> -#include <math.h> - -#include <schroedinger/schroparse.h> - - -GST_DEBUG_CATEGORY_EXTERN (schro_debug); -#define GST_CAT_DEFAULT schro_debug - -#define GST_TYPE_SCHRO_PARSE \ - (gst_schro_parse_get_type()) -#define GST_SCHRO_PARSE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SCHRO_PARSE,GstSchroParse)) -#define GST_SCHRO_PARSE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SCHRO_PARSE,GstSchroParseClass)) -#define GST_IS_SCHRO_PARSE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SCHRO_PARSE)) -#define GST_IS_SCHRO_PARSE_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SCHRO_PARSE)) - -typedef struct _GstSchroParse GstSchroParse; -typedef struct _GstSchroParseClass GstSchroParseClass; - -typedef enum -{ - GST_SCHRO_PARSE_OUTPUT_OGG, - GST_SCHRO_PARSE_OUTPUT_QUICKTIME, - GST_SCHRO_PARSE_OUTPUT_AVI, - GST_SCHRO_PARSE_OUTPUT_MPEG_TS, - GST_SCHRO_PARSE_OUTPUT_MP4 -} GstSchroParseOutputType; - -struct _GstSchroParse -{ - GstBaseVideoParse base_video_parse; - - GstPad *sinkpad, *srcpad; - - GstSchroParseOutputType output_format; - - GstBuffer *seq_header_buffer; - - /* state */ - - - gboolean have_picture; - int buf_picture_number; - int seq_hdr_picture_number; - int picture_number; - - guint64 last_granulepos; - - int bytes_per_picture; -}; - -struct _GstSchroParseClass -{ - GstBaseVideoParseClass base_video_parse_class; -}; - -GType gst_schro_parse_get_type (void); - - -/* GstSchroParse signals and args */ -enum -{ - LAST_SIGNAL -}; - -enum -{ - ARG_0 -}; - -static gboolean gst_schro_parse_start (GstBaseVideoParse * base_video_parse); -static gboolean gst_schro_parse_stop (GstBaseVideoParse * base_video_parse); -static gboolean gst_schro_parse_reset (GstBaseVideoParse * base_video_parse); -static int gst_schro_parse_scan_for_sync (GstAdapter * adapter, - gboolean at_eos, int offset, int n); -static gboolean gst_schro_parse_parse_data (GstBaseVideoParse * - base_video_parse, gboolean at_eos); -static gboolean gst_schro_parse_shape_output (GstBaseVideoParse * - base_video_parse, GstVideoFrame * frame); -static GstCaps *gst_schro_parse_get_caps (GstBaseVideoParse * base_video_parse); - - - -static GstStaticPadTemplate gst_schro_parse_sink_template = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-dirac") - ); - -static GstStaticPadTemplate gst_schro_parse_src_template = - GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS - ("video/x-dirac;video/x-qt-part;video/x-avi-part;video/x-mp4-part") - ); - -GST_BOILERPLATE (GstSchroParse, gst_schro_parse, GstBaseVideoParse, - GST_TYPE_BASE_VIDEO_PARSE); - -static void -gst_schro_parse_base_init (gpointer g_class) -{ - - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_schro_parse_src_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_schro_parse_sink_template)); - - gst_element_class_set_details_simple (element_class, "Dirac Parser", - "Codec/Parser/Video", - "Parse Dirac streams", "David Schleef <ds@schleef.org>"); -} - -static void -gst_schro_parse_class_init (GstSchroParseClass * klass) -{ - GstBaseVideoParseClass *base_video_parse_class; - - base_video_parse_class = GST_BASE_VIDEO_PARSE_CLASS (klass); - - base_video_parse_class->start = GST_DEBUG_FUNCPTR (gst_schro_parse_start); - base_video_parse_class->stop = GST_DEBUG_FUNCPTR (gst_schro_parse_stop); - base_video_parse_class->reset = GST_DEBUG_FUNCPTR (gst_schro_parse_reset); - base_video_parse_class->parse_data = - GST_DEBUG_FUNCPTR (gst_schro_parse_parse_data); - base_video_parse_class->shape_output = - GST_DEBUG_FUNCPTR (gst_schro_parse_shape_output); - base_video_parse_class->scan_for_sync = - GST_DEBUG_FUNCPTR (gst_schro_parse_scan_for_sync); - base_video_parse_class->get_caps = - GST_DEBUG_FUNCPTR (gst_schro_parse_get_caps); - -} - -static void -gst_schro_parse_init (GstSchroParse * schro_parse, GstSchroParseClass * klass) -{ - GstBaseVideoParse *base_video_parse = GST_BASE_VIDEO_PARSE (schro_parse); - - GST_DEBUG ("gst_schro_parse_init"); - - schro_parse->output_format = GST_SCHRO_PARSE_OUTPUT_OGG; - - base_video_parse->reorder_depth = 2; -} - -static gboolean -gst_schro_parse_reset (GstBaseVideoParse * base_video_parse) -{ - GST_DEBUG ("reset"); - - return TRUE; -} - -static gboolean -gst_schro_parse_start (GstBaseVideoParse * base_video_parse) -{ - GstSchroParse *schro_parse = GST_SCHRO_PARSE (base_video_parse); - GstCaps *caps; - GstStructure *structure; - - GST_DEBUG ("start"); - caps = - gst_pad_get_allowed_caps (GST_BASE_VIDEO_CODEC_SRC_PAD - (base_video_parse)); - - if (gst_caps_is_empty (caps)) { - gst_caps_unref (caps); - return FALSE; - } - - structure = gst_caps_get_structure (caps, 0); - - if (gst_structure_has_name (structure, "video/x-dirac")) { - schro_parse->output_format = GST_SCHRO_PARSE_OUTPUT_OGG; - } else if (gst_structure_has_name (structure, "video/x-qt-part")) { - schro_parse->output_format = GST_SCHRO_PARSE_OUTPUT_QUICKTIME; - } else if (gst_structure_has_name (structure, "video/x-avi-part")) { - schro_parse->output_format = GST_SCHRO_PARSE_OUTPUT_AVI; - } else if (gst_structure_has_name (structure, "video/x-mpegts-part")) { - schro_parse->output_format = GST_SCHRO_PARSE_OUTPUT_MPEG_TS; - } else if (gst_structure_has_name (structure, "video/x-mp4-part")) { - schro_parse->output_format = GST_SCHRO_PARSE_OUTPUT_MP4; - } else { - return FALSE; - } - - gst_caps_unref (caps); - return TRUE; -} - -static gboolean -gst_schro_parse_stop (GstBaseVideoParse * base_video_parse) -{ - return TRUE; -} - -static void -parse_sequence_header (GstSchroParse * schro_parse, guint8 * data, int size) -{ - SchroVideoFormat video_format; - int ret; - GstVideoState *state; - - GST_DEBUG ("parse_sequence_header size=%d", size); - - state = gst_base_video_parse_get_state (GST_BASE_VIDEO_PARSE (schro_parse)); - - schro_parse->seq_header_buffer = gst_buffer_new_and_alloc (size); - memcpy (GST_BUFFER_DATA (schro_parse->seq_header_buffer), data, size); - - ret = schro_parse_decode_sequence_header (data + 13, size - 13, - &video_format); - if (ret) { - state->fps_n = video_format.frame_rate_numerator; - state->fps_d = video_format.frame_rate_denominator; - GST_DEBUG ("Frame rate is %d/%d", state->fps_n, state->fps_d); - - state->width = video_format.width; - state->height = video_format.height; - GST_DEBUG ("Frame dimensions are %d x %d\n", state->width, state->height); - - state->clean_width = video_format.clean_width; - state->clean_height = video_format.clean_height; - state->clean_offset_left = video_format.left_offset; - state->clean_offset_top = video_format.top_offset; - - state->par_n = video_format.aspect_ratio_numerator; - state->par_d = video_format.aspect_ratio_denominator; - GST_DEBUG ("Pixel aspect ratio is %d/%d", state->par_n, state->par_d); - - gst_base_video_parse_set_state (GST_BASE_VIDEO_PARSE (schro_parse), state); - } else { - GST_WARNING ("Failed to get frame rate from sequence header"); - } - -} - -static int -gst_schro_parse_scan_for_sync (GstAdapter * adapter, gboolean at_eos, - int offset, int n) -{ - int n_available = gst_adapter_available (adapter) - offset; - - if (n_available < 4) { - if (at_eos) { - return n_available; - } else { - return 0; - } - } - - n_available -= 3; - - return gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x42424344, - offset, MIN (n, n_available - 3)); -} - -static GstFlowReturn -gst_schro_parse_parse_data (GstBaseVideoParse * base_video_parse, - gboolean at_eos) -{ - GstSchroParse *schro_parse; - unsigned char header[SCHRO_PARSE_HEADER_SIZE]; - int next; - int prev; - int parse_code; - - GST_DEBUG ("parse_data"); - - schro_parse = GST_SCHRO_PARSE (base_video_parse); - - if (gst_adapter_available (base_video_parse->input_adapter) < - SCHRO_PARSE_HEADER_SIZE) { - return GST_BASE_VIDEO_PARSE_FLOW_NEED_DATA; - } - - GST_DEBUG ("available %d", - gst_adapter_available (base_video_parse->input_adapter)); - - gst_adapter_copy (base_video_parse->input_adapter, header, 0, - SCHRO_PARSE_HEADER_SIZE); - - parse_code = header[4]; - next = GST_READ_UINT32_BE (header + 5); - prev = GST_READ_UINT32_BE (header + 9); - - GST_DEBUG ("%08x %02x %08x %08x", - GST_READ_UINT32_BE (header), parse_code, next, prev); - - if (memcmp (header, "BBCD", 4) != 0 || - (next & 0xf0000000) || (prev & 0xf0000000)) { - gst_base_video_parse_lost_sync (base_video_parse); - return GST_BASE_VIDEO_PARSE_FLOW_NEED_DATA; - } - - if (SCHRO_PARSE_CODE_IS_END_OF_SEQUENCE (parse_code)) { - GstVideoFrame *frame; - - if (next != 0 && next != SCHRO_PARSE_HEADER_SIZE) { - GST_WARNING ("next is not 0 or 13 in EOS packet (%d)", next); - } - - gst_base_video_parse_add_to_frame (base_video_parse, - SCHRO_PARSE_HEADER_SIZE); - - frame = gst_base_video_parse_get_frame (base_video_parse); - frame->is_eos = TRUE; - - SCHRO_DEBUG ("eos"); - - return gst_base_video_parse_finish_frame (base_video_parse); - } - - if (gst_adapter_available (base_video_parse->input_adapter) < next) { - return GST_BASE_VIDEO_PARSE_FLOW_NEED_DATA; - } - - if (SCHRO_PARSE_CODE_IS_SEQ_HEADER (parse_code)) { - guint8 *data; - - data = g_malloc (next); - - gst_adapter_copy (base_video_parse->input_adapter, data, 0, next); - parse_sequence_header (schro_parse, data, next); - - base_video_parse->current_frame->is_sync_point = TRUE; - - g_free (data); - } - - if (schro_parse->seq_header_buffer == NULL) { - gst_adapter_flush (base_video_parse->input_adapter, next); - return GST_FLOW_OK; - } - - if (SCHRO_PARSE_CODE_IS_PICTURE (parse_code)) { - GstVideoFrame *frame; - guint8 tmp[4]; - - frame = gst_base_video_parse_get_frame (base_video_parse); - -#if 0 - if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buf))) { - frame->presentation_timestamp = GST_BUFFER_TIMESTAMP (buf); - } -#endif - - gst_adapter_copy (base_video_parse->input_adapter, tmp, - SCHRO_PARSE_HEADER_SIZE, 4); - - frame->presentation_frame_number = GST_READ_UINT32_BE (tmp); - - gst_base_video_parse_add_to_frame (base_video_parse, next); - - return gst_base_video_parse_finish_frame (base_video_parse); - } else { - gst_base_video_parse_add_to_frame (base_video_parse, next); - } - - return GST_FLOW_OK; -} - -static GstFlowReturn -gst_schro_parse_shape_output_ogg (GstBaseVideoParse * base_video_parse, - GstVideoFrame * frame) -{ - GstSchroParse *schro_parse; - int dpn; - int delay; - int dist; - int pt; - int dt; - guint64 granulepos_hi; - guint64 granulepos_low; - GstBuffer *buf = frame->src_buffer; - - schro_parse = GST_SCHRO_PARSE (base_video_parse); - - dpn = frame->decode_frame_number; - - pt = frame->presentation_frame_number * 2; - dt = frame->decode_frame_number * 2; - delay = pt - dt; - dist = frame->distance_from_sync; - - GST_DEBUG ("sys %d dpn %d pt %d dt %d delay %d dist %d", - (int) frame->system_frame_number, - (int) frame->decode_frame_number, pt, dt, delay, dist); - - granulepos_hi = (((guint64) pt - delay) << 9) | ((dist >> 8)); - granulepos_low = (delay << 9) | (dist & 0xff); - GST_DEBUG ("granulepos %" G_GINT64_FORMAT ":%" G_GINT64_FORMAT, granulepos_hi, - granulepos_low); - - if (frame->is_eos) { - GST_BUFFER_OFFSET_END (buf) = schro_parse->last_granulepos; - } else { - schro_parse->last_granulepos = (granulepos_hi << 22) | (granulepos_low); - GST_BUFFER_OFFSET_END (buf) = schro_parse->last_granulepos; - } - - return gst_base_video_parse_push (base_video_parse, buf); -} - -static GstFlowReturn -gst_schro_parse_shape_output_quicktime (GstBaseVideoParse * base_video_parse, - GstVideoFrame * frame) -{ - GstBuffer *buf = frame->src_buffer; - const GstVideoState *state; - - state = gst_base_video_parse_get_state (base_video_parse); - - GST_BUFFER_OFFSET_END (buf) = gst_video_state_get_timestamp (state, - &base_video_parse->segment, frame->system_frame_number); - - if (frame->is_sync_point && - frame->presentation_frame_number == frame->system_frame_number) { - GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT); - GST_DEBUG ("sync point"); - } else { - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT); - } - - return gst_base_video_parse_push (base_video_parse, buf); -} - -static GstFlowReturn -gst_schro_parse_shape_output_mpeg_ts (GstBaseVideoParse * base_video_parse, - GstVideoFrame * frame) -{ - GstBuffer *buf = frame->src_buffer; - - return gst_base_video_parse_push (base_video_parse, buf); -} - -static GstFlowReturn -gst_schro_parse_shape_output (GstBaseVideoParse * base_video_parse, - GstVideoFrame * frame) -{ - GstSchroParse *schro_parse; - - schro_parse = GST_SCHRO_PARSE (base_video_parse); - - switch (schro_parse->output_format) { - case GST_SCHRO_PARSE_OUTPUT_OGG: - return gst_schro_parse_shape_output_ogg (base_video_parse, frame); - case GST_SCHRO_PARSE_OUTPUT_QUICKTIME: - return gst_schro_parse_shape_output_quicktime (base_video_parse, frame); - case GST_SCHRO_PARSE_OUTPUT_MPEG_TS: - return gst_schro_parse_shape_output_mpeg_ts (base_video_parse, frame); - default: - break; - } - - return GST_FLOW_ERROR; -} - -static GstCaps * -gst_schro_parse_get_caps (GstBaseVideoParse * base_video_parse) -{ - GstCaps *caps; - GstVideoState *state; - GstSchroParse *schro_parse; - - schro_parse = GST_SCHRO_PARSE (base_video_parse); - - state = gst_base_video_parse_get_state (base_video_parse); - - if (schro_parse->output_format == GST_SCHRO_PARSE_OUTPUT_OGG) { - caps = gst_caps_new_simple ("video/x-dirac", - "width", G_TYPE_INT, state->width, - "height", G_TYPE_INT, state->height, - "framerate", GST_TYPE_FRACTION, state->fps_n, - state->fps_d, - "pixel-aspect-ratio", GST_TYPE_FRACTION, state->par_n, - state->par_d, NULL); - - GST_BUFFER_FLAG_SET (schro_parse->seq_header_buffer, - GST_BUFFER_FLAG_IN_CAPS); - - { - GValue array = { 0 }; - GValue value = { 0 }; - GstBuffer *buf; - int size; - - g_value_init (&array, GST_TYPE_ARRAY); - g_value_init (&value, GST_TYPE_BUFFER); - size = GST_BUFFER_SIZE (schro_parse->seq_header_buffer); - buf = gst_buffer_new_and_alloc (size + SCHRO_PARSE_HEADER_SIZE); - memcpy (GST_BUFFER_DATA (buf), - GST_BUFFER_DATA (schro_parse->seq_header_buffer), size); - GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf) + size + 0, 0x42424344); - GST_WRITE_UINT8 (GST_BUFFER_DATA (buf) + size + 4, - SCHRO_PARSE_CODE_END_OF_SEQUENCE); - GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf) + size + 5, 0); - GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf) + size + 9, size); - gst_value_set_buffer (&value, buf); - gst_buffer_unref (buf); - gst_value_array_append_value (&array, &value); - gst_structure_set_value (gst_caps_get_structure (caps, 0), - "streamheader", &array); - g_value_unset (&value); - g_value_unset (&array); - } - } else if (schro_parse->output_format == GST_SCHRO_PARSE_OUTPUT_QUICKTIME) { - caps = gst_caps_new_simple ("video/x-qt-part", - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('d', 'r', 'a', 'c'), - "width", G_TYPE_INT, state->width, - "height", G_TYPE_INT, state->height, - "framerate", GST_TYPE_FRACTION, state->fps_n, - state->fps_d, - "pixel-aspect-ratio", GST_TYPE_FRACTION, state->par_n, - state->par_d, NULL); - } else if (schro_parse->output_format == GST_SCHRO_PARSE_OUTPUT_AVI) { - caps = gst_caps_new_simple ("video/x-avi-part", - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('d', 'r', 'a', 'c'), - "width", G_TYPE_INT, state->width, - "height", G_TYPE_INT, state->height, - "framerate", GST_TYPE_FRACTION, state->fps_n, - state->fps_d, - "pixel-aspect-ratio", GST_TYPE_FRACTION, state->par_n, - state->par_d, NULL); - } else if (schro_parse->output_format == GST_SCHRO_PARSE_OUTPUT_MPEG_TS) { - caps = gst_caps_new_simple ("video/x-mpegts-part", - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('d', 'r', 'a', 'c'), - "width", G_TYPE_INT, state->width, - "height", G_TYPE_INT, state->height, - "framerate", GST_TYPE_FRACTION, state->fps_n, - state->fps_d, - "pixel-aspect-ratio", GST_TYPE_FRACTION, state->par_n, - state->par_d, NULL); - } else if (schro_parse->output_format == GST_SCHRO_PARSE_OUTPUT_MP4) { - caps = gst_caps_new_simple ("video/x-mp4-part", - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('d', 'r', 'a', 'c'), - "width", G_TYPE_INT, state->width, - "height", G_TYPE_INT, state->height, - "framerate", GST_TYPE_FRACTION, state->fps_n, - state->fps_d, - "pixel-aspect-ratio", GST_TYPE_FRACTION, state->par_n, - state->par_d, NULL); - } else { - g_assert_not_reached (); - } - - return caps; -} diff --git a/ext/schroedinger/gstschroutils.c b/ext/schroedinger/gstschroutils.c index bb1f1bcd6..66514a3d5 100644 --- a/ext/schroedinger/gstschroutils.c +++ b/ext/schroedinger/gstschroutils.c @@ -95,6 +95,7 @@ gst_schro_buffer_wrap (GstBuffer * buf, GstVideoFormat format, int width, #endif default: g_assert_not_reached (); + return NULL; } schro_frame_set_free_callback (frame, gst_schro_frame_free, buf); diff --git a/ext/vp8/gstvp8enc.c b/ext/vp8/gstvp8enc.c index b70510243..17b316a5b 100644 --- a/ext/vp8/gstvp8enc.c +++ b/ext/vp8/gstvp8enc.c @@ -229,7 +229,7 @@ gst_vp8_enc_class_init (GstVP8EncClass * klass) g_object_class_install_property (gobject_class, PROP_BITRATE, g_param_spec_int ("bitrate", "Bit rate", - "Bit rate", + "Bit rate (in bits/sec)", 0, 1000000000, DEFAULT_BITRATE, (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); diff --git a/ext/xvid/gstxviddec.c b/ext/xvid/gstxviddec.c index 84a0eaad9..67e33c03e 100644 --- a/ext/xvid/gstxviddec.c +++ b/ext/xvid/gstxviddec.c @@ -310,7 +310,7 @@ gst_xviddec_chain (GstPad * pad, GstBuffer * buf) xvid_dec_frame_t xframe; xvid_dec_stats_t xstats; gint ret; - guint8 *data; + guint8 *data, *dupe = NULL; guint size; GstFlowReturn fret; @@ -333,6 +333,16 @@ gst_xviddec_chain (GstPad * pad, GstBuffer * buf) 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); @@ -412,6 +422,7 @@ gst_xviddec_chain (GstPad * pad, GstBuffer * buf) } done: + g_free (dupe); gst_buffer_unref (buf); return fret; diff --git a/ext/xvid/gstxvidenc.c b/ext/xvid/gstxvidenc.c index 1194ecbbc..6d16e87bd 100644 --- a/ext/xvid/gstxvidenc.c +++ b/ext/xvid/gstxvidenc.c @@ -714,11 +714,17 @@ gst_xvidenc_setcaps (GstPad * pad, GstCaps * vscaps) structure = gst_caps_get_structure (vscaps, 0); - g_return_val_if_fail (gst_structure_get_int (structure, "width", &w), FALSE); - g_return_val_if_fail (gst_structure_get_int (structure, "height", &h), FALSE); + if (!gst_structure_get_int (structure, "width", &w) || + !gst_structure_get_int (structure, "height", &h)) { + return FALSE; + } + fps = gst_structure_get_value (structure, "framerate"); - g_return_val_if_fail (w > 0 && h > 0 - && fps != NULL && GST_VALUE_HOLDS_FRACTION (fps), FALSE); + if (fps == NULL || !GST_VALUE_HOLDS_FRACTION (fps)) { + GST_WARNING_OBJECT (pad, "no framerate specified, or not a GstFraction"); + return FALSE; + } + /* optional par info */ par = gst_structure_get_value (structure, "pixel-aspect-ratio"); @@ -1039,7 +1045,6 @@ gst_xvidenc_set_property (GObject * object, GstXvidEnc *xvidenc; guint offset; - g_return_if_fail (GST_IS_XVIDENC (object)); xvidenc = GST_XVIDENC (object); if (prop_id > xvidenc_prop_count) { @@ -1050,7 +1055,9 @@ gst_xvidenc_set_property (GObject * object, /* our param specs should have such qdata */ offset = GPOINTER_TO_UINT (g_param_spec_get_qdata (pspec, xvidenc_pspec_quark)); - g_return_if_fail (offset != 0); + + if (offset == 0) + return; switch (G_PARAM_SPEC_VALUE_TYPE (pspec)) { case G_TYPE_BOOLEAN: @@ -1080,7 +1087,6 @@ gst_xvidenc_get_property (GObject * object, GstXvidEnc *xvidenc; guint offset; - g_return_if_fail (GST_IS_XVIDENC (object)); xvidenc = GST_XVIDENC (object); if (prop_id > xvidenc_prop_count) { @@ -1091,7 +1097,9 @@ gst_xvidenc_get_property (GObject * object, /* our param specs should have such qdata */ offset = GPOINTER_TO_UINT (g_param_spec_get_qdata (pspec, xvidenc_pspec_quark)); - g_return_if_fail (offset != 0); + + if (offset == 0) + return; switch (G_PARAM_SPEC_VALUE_TYPE (pspec)) { case G_TYPE_BOOLEAN: diff --git a/gst-libs/gst/Makefile.am b/gst-libs/gst/Makefile.am index e48cdd802..92d951cc8 100644 --- a/gst-libs/gst/Makefile.am +++ b/gst-libs/gst/Makefile.am @@ -1,5 +1,9 @@ +if BUILD_EXPERIMENTAL +EXPERIMENTAL_LIBS=basecamerabinsrc +endif -SUBDIRS = interfaces signalprocessor video +SUBDIRS = baseparse interfaces signalprocessor video $(EXPERIMENTAL_LIBS) noinst_HEADERS = gst-i18n-plugin.h gettext.h -DIST_SUBDIRS = interfaces signalprocessor video +DIST_SUBDIRS = baseparse interfaces signalprocessor video basecamerabinsrc + diff --git a/gst-libs/gst/basecamerabinsrc/Makefile.am b/gst-libs/gst/basecamerabinsrc/Makefile.am new file mode 100644 index 000000000..c5d1ac0af --- /dev/null +++ b/gst-libs/gst/basecamerabinsrc/Makefile.am @@ -0,0 +1,26 @@ + +lib_LTLIBRARIES = libgstbasecamerabinsrc-@GST_MAJORMINOR@.la + +CLEANFILES = $(BUILT_SOURCES) + +libgstbasecamerabinsrc_@GST_MAJORMINOR@_la_SOURCES = \ + gstcamerabin-enum.c \ + gstbasecamerasrc.c + +libgstbasecamerabinsrc_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/basecamerabinsrc +libgstbasecamerabinsrc_@GST_MAJORMINOR@include_HEADERS = \ + gstcamerabin-enum.h \ + gstbasecamerasrc.h + +libgstbasecamerabinsrc_@GST_MAJORMINOR@_la_CFLAGS = \ + $(GST_PLUGINS_BAD_CFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) \ + -DGST_USE_UNSTABLE_API \ + $(GST_CFLAGS) +libgstbasecamerabinsrc_@GST_MAJORMINOR@_la_LIBADD = \ + $(top_builddir)/gst-libs/gst/interfaces/libgstphotography-@GST_MAJORMINOR@.la \ + $(GST_PLUGINS_BASE_LIBS) -lgstinterfaces-$(GST_MAJORMINOR) \ + $(GST_BASE_LIBS) $(GST_LIBS) + +libgstbasecamerabinsrc_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS) + diff --git a/gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.c b/gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.c new file mode 100644 index 000000000..57582cba7 --- /dev/null +++ b/gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.c @@ -0,0 +1,482 @@ +/* + * GStreamer + * Copyright (C) 2010 Texas Instruments, Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + + +/** + * SECTION:element-basecamerasrc + * + * Base class for the camera source bin used by camerabin for capture. + * Sophisticated camera hardware can derive from this baseclass and map the + * features to this interface. + * + * The design mandates that the subclasses implement the following features and + * behaviour: + * <itemizedlist> + * <listitem><para> + * 3 pads: viewfinder, image capture, video capture + * </para></listitem> + * <listitem><para> + * </para></listitem> + * </itemizedlist> + * + * During construct_pipeline() vmethod a subclass can add several elements into + * the bin and expose 3 srcs pads as ghostpads implementing the 3 pad templates. + * + * It is also possible to add regular pads from the subclass and implement the + * dataflow methods on these pads. This way all functionality can be implemneted + * directly in the subclass without extra elements. + * + * The src will receive the capture mode from #GstCameraBin2 on the + * #GstBaseCameraSrc:mode property. Possible capture modes are defined in + * #GstCameraBinMode. + */ + + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "gstbasecamerasrc.h" + +enum +{ + PROP_0, + PROP_MODE, + PROP_ZOOM, + PROP_READY_FOR_CAPTURE +}; + +enum +{ + /* action signals */ + START_CAPTURE_SIGNAL, + STOP_CAPTURE_SIGNAL, + /* emit signals */ + LAST_SIGNAL +}; + +static guint basecamerasrc_signals[LAST_SIGNAL]; + +GST_DEBUG_CATEGORY (base_camera_src_debug); +#define GST_CAT_DEFAULT base_camera_src_debug + +GST_BOILERPLATE (GstBaseCameraSrc, gst_base_camera_src, GstBin, GST_TYPE_BIN); + +static GstStaticPadTemplate vfsrc_template = +GST_STATIC_PAD_TEMPLATE (GST_BASE_CAMERA_SRC_VIEWFINDER_PAD_NAME, + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +static GstStaticPadTemplate imgsrc_template = +GST_STATIC_PAD_TEMPLATE (GST_BASE_CAMERA_SRC_IMAGE_PAD_NAME, + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +static GstStaticPadTemplate vidsrc_template = +GST_STATIC_PAD_TEMPLATE (GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME, + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +/* NOTE: we could provide a vmethod for derived class to overload to provide + * it's own implementation of interface.. but in all cases I can think of at + * moment, either the camerasrc itself, or some element within the bin, will + * be implementing the interface.. + */ + +/** + * gst_base_camera_src_get_photography: + * @self: the camerasrc bin + * + * Get object implementing photography interface, if there is one. Otherwise + * returns NULL. + */ +GstPhotography * +gst_base_camera_src_get_photography (GstBaseCameraSrc * self) +{ + GstElement *elem; + + if (GST_IS_PHOTOGRAPHY (self)) { + elem = GST_ELEMENT (self); + } else { + elem = gst_bin_get_by_interface (GST_BIN (self), GST_TYPE_PHOTOGRAPHY); + } + + if (elem) { + return GST_PHOTOGRAPHY (self); + } + + return NULL; +} + + +/** + * gst_base_camera_src_get_colorbalance: + * @self: the camerasrc bin + * + * Get object implementing colorbalance interface, if there is one. Otherwise + * returns NULL. + */ +GstColorBalance * +gst_base_camera_src_get_color_balance (GstBaseCameraSrc * self) +{ + GstElement *elem; + + if (GST_IS_COLOR_BALANCE (self)) { + elem = GST_ELEMENT (self); + } else { + elem = gst_bin_get_by_interface (GST_BIN (self), GST_TYPE_COLOR_BALANCE); + } + + if (elem) { + return GST_COLOR_BALANCE (self); + } + + return NULL; +} + +/** + * gst_base_camera_src_set_mode: + * @self: the camerasrc bin + * @mode: the mode + * + * Set the chosen #GstCameraBinMode capture mode. + */ +gboolean +gst_base_camera_src_set_mode (GstBaseCameraSrc * self, GstCameraBinMode mode) +{ + GstBaseCameraSrcClass *bclass = GST_BASE_CAMERA_SRC_GET_CLASS (self); + + g_return_val_if_fail (bclass->set_mode, FALSE); + + if (bclass->set_mode (self, mode)) { + self->mode = mode; + return TRUE; + } + return FALSE; +} + +/** + * gst_base_camera_src_setup_zoom: + * @self: camerasrc object + * + * Apply zoom configured to camerabin to capture. + */ +void +gst_base_camera_src_setup_zoom (GstBaseCameraSrc * self) +{ + GstBaseCameraSrcClass *bclass = GST_BASE_CAMERA_SRC_GET_CLASS (self); + gint zoom; + + zoom = g_atomic_int_get (&self->zoom); + + g_return_if_fail (zoom); + g_return_if_fail (bclass->set_zoom); + + bclass->set_zoom (self, zoom); +} + + +/** + * gst_base_camera_src_get_allowed_input_caps: + * @self: the camerasrc bin + * + * Retrieve caps from videosrc describing formats it supports + * + * Returns: caps object from videosrc + */ +GstCaps * +gst_base_camera_src_get_allowed_input_caps (GstBaseCameraSrc * self) +{ + GstBaseCameraSrcClass *bclass = GST_BASE_CAMERA_SRC_GET_CLASS (self); + + g_return_val_if_fail (bclass->get_allowed_input_caps, NULL); + + return bclass->get_allowed_input_caps (self); +} + +static void +gst_base_camera_src_start_capture (GstBaseCameraSrc * src) +{ + GstBaseCameraSrcClass *klass = GST_BASE_CAMERA_SRC_GET_CLASS (src); + + g_return_if_fail (klass->start_capture != NULL); + + GST_DEBUG_OBJECT (src, "Starting capture"); + + g_mutex_lock (src->capturing_mutex); + if (src->capturing) { + GST_WARNING_OBJECT (src, "Capturing already ongoing"); + g_mutex_unlock (src->capturing_mutex); + return; + } + + src->capturing = TRUE; + g_object_notify (G_OBJECT (src), "ready-for-capture"); + if (klass->start_capture (src)) { + GST_DEBUG_OBJECT (src, "Capture started"); + } else { + src->capturing = FALSE; + g_object_notify (G_OBJECT (src), "ready-for-capture"); + GST_WARNING_OBJECT (src, "Failed to start capture"); + } + g_mutex_unlock (src->capturing_mutex); +} + +static void +gst_base_camera_src_stop_capture (GstBaseCameraSrc * src) +{ + GstBaseCameraSrcClass *klass = GST_BASE_CAMERA_SRC_GET_CLASS (src); + + g_return_if_fail (klass->stop_capture != NULL); + + g_mutex_lock (src->capturing_mutex); + if (!src->capturing) { + GST_DEBUG_OBJECT (src, "No ongoing capture"); + g_mutex_unlock (src->capturing_mutex); + return; + } + klass->stop_capture (src); + g_mutex_unlock (src->capturing_mutex); +} + +void +gst_base_camera_src_finish_capture (GstBaseCameraSrc * self) +{ + GST_DEBUG_OBJECT (self, "Finishing capture"); + g_return_if_fail (self->capturing); + self->capturing = FALSE; + g_object_notify (G_OBJECT (self), "ready-for-capture"); +} + +static void +gst_base_camera_src_dispose (GObject * object) +{ + GstBaseCameraSrc *src = GST_BASE_CAMERA_SRC_CAST (object); + + g_mutex_free (src->capturing_mutex); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_base_camera_src_finalize (GstBaseCameraSrc * self) +{ + G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (self)); +} + +static void +gst_base_camera_src_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstBaseCameraSrc *self = GST_BASE_CAMERA_SRC (object); + + switch (prop_id) { + case PROP_MODE: + gst_base_camera_src_set_mode (GST_BASE_CAMERA_SRC (self), + g_value_get_enum (value)); + break; + case PROP_ZOOM:{ + g_atomic_int_set (&self->zoom, g_value_get_int (value)); + /* does not set it if in NULL, the src is not created yet */ + if (GST_STATE (self) != GST_STATE_NULL) + gst_base_camera_src_setup_zoom (self); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec); + break; + } +} + +static void +gst_base_camera_src_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstBaseCameraSrc *self = GST_BASE_CAMERA_SRC (object); + + switch (prop_id) { + case PROP_MODE: + g_value_set_enum (value, self->mode); + break; + case PROP_READY_FOR_CAPTURE: + g_value_set_boolean (value, !self->capturing); + break; + case PROP_ZOOM: + g_value_set_int (value, g_atomic_int_get (&self->zoom)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec); + break; + } +} + +static gboolean +construct_pipeline (GstBaseCameraSrc * self) +{ + GstBaseCameraSrcClass *bclass = GST_BASE_CAMERA_SRC_GET_CLASS (self); + + if (bclass->construct_pipeline) { + if (!bclass->construct_pipeline (self)) { + GST_ERROR_OBJECT (self, "pipeline construction failed"); + return FALSE; + } + } + + return TRUE; +} + +static gboolean +setup_pipeline (GstBaseCameraSrc * self) +{ + GstBaseCameraSrcClass *bclass = GST_BASE_CAMERA_SRC_GET_CLASS (self); + if (bclass->setup_pipeline) + return bclass->setup_pipeline (self); + return TRUE; +} + +static GstStateChangeReturn +gst_base_camera_src_change_state (GstElement * element, + GstStateChange transition) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + GstBaseCameraSrc *self = GST_BASE_CAMERA_SRC (element); + + GST_DEBUG_OBJECT (self, "%d -> %d", + GST_STATE_TRANSITION_CURRENT (transition), + GST_STATE_TRANSITION_NEXT (transition)); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + if (!construct_pipeline (self)) + return GST_STATE_CHANGE_FAILURE; + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + if (!setup_pipeline (self)) + return GST_STATE_CHANGE_FAILURE; + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + return ret; +} + +static void +gst_base_camera_src_base_init (gpointer g_class) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); + + GST_DEBUG_CATEGORY_INIT (base_camera_src_debug, "base_camera_src", 0, + "Base camera src"); + + gst_element_class_set_details_simple (gstelement_class, + "Base class for camerabin src bin", "Source/Video", + "Abstracts capture device for camerabin2", "Rob Clark <rob@ti.com>"); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&vfsrc_template)); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&imgsrc_template)); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&vidsrc_template)); +} + +static void +gst_base_camera_src_class_init (GstBaseCameraSrcClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = G_OBJECT_CLASS (klass); + gstelement_class = GST_ELEMENT_CLASS (klass); + + gobject_class->dispose = gst_base_camera_src_dispose; + gobject_class->finalize = (GObjectFinalizeFunc) gst_base_camera_src_finalize; + gobject_class->set_property = gst_base_camera_src_set_property; + gobject_class->get_property = gst_base_camera_src_get_property; + + g_object_class_install_property (gobject_class, PROP_MODE, + g_param_spec_enum ("mode", "Mode", + "The capture mode (still image capture or video recording)", + GST_TYPE_CAMERABIN_MODE, MODE_IMAGE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstBaseCameraSrc:ready-for-capture: + * + * When TRUE new capture can be prepared. If FALSE capturing is ongoing + * and starting a new capture immediately is not possible. + * + * Note that calling start-capture from the notify callback of this property + * will cause a deadlock. If you need to react like this on the notify + * function, please schedule a new thread to do it. If you're using glib's + * mainloop you can use g_idle_add() for example. + */ + g_object_class_install_property (gobject_class, PROP_READY_FOR_CAPTURE, + g_param_spec_boolean ("ready-for-capture", "Ready for capture", + "Informs this element is ready for starting another capture", + TRUE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + + /* Signals */ + basecamerasrc_signals[START_CAPTURE_SIGNAL] = + g_signal_new ("start-capture", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GstBaseCameraSrcClass, private_start_capture), + NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + + basecamerasrc_signals[STOP_CAPTURE_SIGNAL] = + g_signal_new ("stop-capture", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GstBaseCameraSrcClass, private_stop_capture), + NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + + /* TODO these should be moved to a private struct + * that is allocated sequentially to the main struct as said at: + * http://library.gnome.org/devel/gobject/unstable/gobject-Type-Information.html#g-type-add-class-private + */ + klass->private_start_capture = gst_base_camera_src_start_capture; + klass->private_stop_capture = gst_base_camera_src_stop_capture; + + gstelement_class->change_state = gst_base_camera_src_change_state; +} + +static void +gst_base_camera_src_init (GstBaseCameraSrc * self, + GstBaseCameraSrcClass * klass) +{ + self->width = DEFAULT_WIDTH; + self->height = DEFAULT_HEIGHT; + self->zoom = DEFAULT_ZOOM; + self->mode = MODE_IMAGE; + + self->capturing = FALSE; + self->capturing_mutex = g_mutex_new (); +} diff --git a/gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.h b/gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.h new file mode 100644 index 000000000..70535bccf --- /dev/null +++ b/gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.h @@ -0,0 +1,131 @@ +/* + * GStreamer + * Copyright (C) 2010 Texas Instruments, Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_BASE_CAMERA_SRC_H__ +#define __GST_BASE_CAMERA_SRC_H__ + +#include <gst/gst.h> +#include <gst/gstbin.h> +#include <gst/interfaces/photography.h> +#include <gst/interfaces/colorbalance.h> +#include "gstcamerabin-enum.h" + +G_BEGIN_DECLS +#define GST_TYPE_BASE_CAMERA_SRC \ + (gst_base_camera_src_get_type()) +#define GST_BASE_CAMERA_SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASE_CAMERA_SRC,GstBaseCameraSrc)) +#define GST_BASE_CAMERA_SRC_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_BASE_CAMERA_SRC, GstBaseCameraSrcClass)) +#define GST_BASE_CAMERA_SRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASE_CAMERA_SRC,GstBaseCameraSrcClass)) +#define GST_IS_BASE_CAMERA_SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASE_CAMERA_SRC)) +#define GST_IS_BASE_CAMERA_SRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASE_CAMERA_SRC)) +#define GST_BASE_CAMERA_SRC_CAST(obj) \ + ((GstBaseCameraSrc *) (obj)) +GType gst_base_camera_src_get_type (void); + +typedef struct _GstBaseCameraSrc GstBaseCameraSrc; +typedef struct _GstBaseCameraSrcClass GstBaseCameraSrcClass; + +#define GST_BASE_CAMERA_SRC_VIEWFINDER_PAD_NAME "vfsrc" +#define GST_BASE_CAMERA_SRC_IMAGE_PAD_NAME "imgsrc" +#define GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME "vidsrc" + +#define GST_BASE_CAMERA_SRC_PREVIEW_MESSAGE_NAME "preview-image" + +/** + * GstBaseCameraSrc: + */ +struct _GstBaseCameraSrc +{ + GstBin parent; + + GstCameraBinMode mode; + + gboolean capturing; + GMutex *capturing_mutex; + + /* Resolution of the buffers configured to camerabin */ + gint width; + gint height; + + /* The digital zoom (from 100% to 1000%) */ + gint zoom; + + gpointer _gst_reserved[GST_PADDING_LARGE]; +}; + + +/** + * GstBaseCameraSrcClass: + * @construct_pipeline: construct pipeline must be implemented by derived class + * @setup_pipeline: configure pipeline for the chosen settings + * @set_zoom: set the zoom + * @set_mode: set the mode + */ +struct _GstBaseCameraSrcClass +{ + GstBinClass parent; + + /* construct pipeline must be implemented by derived class */ + gboolean (*construct_pipeline) (GstBaseCameraSrc *self); + + /* optional */ + gboolean (*setup_pipeline) (GstBaseCameraSrc *self); + + /* set the zoom */ + void (*set_zoom) (GstBaseCameraSrc *self, gint zoom); + + /* set the mode */ + gboolean (*set_mode) (GstBaseCameraSrc *self, + GstCameraBinMode mode); + + /* */ + GstCaps * (*get_allowed_input_caps) (GstBaseCameraSrc * self); + + void (*private_start_capture) (GstBaseCameraSrc * src); + void (*private_stop_capture) (GstBaseCameraSrc * src); + gboolean (*start_capture) (GstBaseCameraSrc * src); + void (*stop_capture) (GstBaseCameraSrc * src); + + gpointer _gst_reserved[GST_PADDING_LARGE]; +}; + + +#define MIN_ZOOM 100 +#define MAX_ZOOM 1000 +#define ZOOM_1X MIN_ZOOM + +GstPhotography * gst_base_camera_src_get_photography (GstBaseCameraSrc *self); +GstColorBalance * gst_base_camera_src_get_color_balance (GstBaseCameraSrc *self); + +gboolean gst_base_camera_src_set_mode (GstBaseCameraSrc *self, GstCameraBinMode mode); +void gst_base_camera_src_setup_zoom (GstBaseCameraSrc * self); +GstCaps * gst_base_camera_src_get_allowed_input_caps (GstBaseCameraSrc * self); +void gst_base_camera_src_finish_capture (GstBaseCameraSrc *self); + + +// XXX add methods to get/set img capture and vid capture caps.. + +#endif /* __GST_BASE_CAMERA_SRC_H__ */ diff --git a/ext/jack/gstjackutil.h b/gst-libs/gst/basecamerabinsrc/gstcamerabin-enum.c index e330afd5e..ba09dcf3e 100644 --- a/ext/jack/gstjackutil.h +++ b/gst-libs/gst/basecamerabinsrc/gstcamerabin-enum.c @@ -1,7 +1,6 @@ -/* GStreamer - * Copyright (C) 2010 Tristan Matthews <tristan@sat.qc.ca> - * - * gstjackutil.h: +/* + * GStreamer + * Copyright (C) 2009 Nokia Corporation <multimedia@maemo.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -19,12 +18,22 @@ * Boston, MA 02111-1307, USA. */ -#ifndef _GST_JACK_UTIL_H_ -#define _GST_JACK_UTIL_H_ +#include "gstcamerabin-enum.h" -#include <gst/gst.h> +GType +gst_camerabin_mode_get_type (void) +{ + static GType gtype = 0; -void -gst_jack_set_layout_on_caps (GstCaps **caps, gint channels); + if (gtype == 0) { + static const GEnumValue values[] = { + /* {MODE_PREVIEW, "Preview mode (should be default?)", "mode-preview"}, */ + {MODE_IMAGE, "Still image capture (default)", "mode-image"}, + {MODE_VIDEO, "Video recording", "mode-video"}, + {0, NULL, NULL} + }; -#endif // _GST_JACK_UTIL_H_ + gtype = g_enum_register_static ("GstCameraBin2Mode", values); + } + return gtype; +} diff --git a/gst-libs/gst/basecamerabinsrc/gstcamerabin-enum.h b/gst-libs/gst/basecamerabinsrc/gstcamerabin-enum.h new file mode 100644 index 000000000..590cb6882 --- /dev/null +++ b/gst-libs/gst/basecamerabinsrc/gstcamerabin-enum.h @@ -0,0 +1,57 @@ +/* + * GStreamer + * Copyright (C) 2009 Nokia Corporation <multimedia@maemo.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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_CAMERABIN_ENUM_H__ +#define __GST_CAMERABIN_ENUM_H__ + +#include <gst/gst.h> + +G_BEGIN_DECLS + +#define DEFAULT_WIDTH 640 +#define DEFAULT_HEIGHT 480 +#define DEFAULT_CAPTURE_WIDTH 800 +#define DEFAULT_CAPTURE_HEIGHT 600 +#define DEFAULT_FPS_N 0 /* makes it use the default */ +#define DEFAULT_FPS_D 1 +#define DEFAULT_ZOOM MIN_ZOOM + + +/** + * GstCameraBinMode: + * @MODE_IMAGE: image capture + * @MODE_VIDEO: video capture + * + * Capture mode to use. + */ +typedef enum +{ + /* MODE_PREVIEW = 0, No use for this */ + MODE_IMAGE = 1, + MODE_VIDEO = 2, +} GstCameraBinMode; + + +#define GST_TYPE_CAMERABIN_MODE (gst_camerabin_mode_get_type ()) +GType gst_camerabin_mode_get_type (void); + +G_END_DECLS + +#endif /* #ifndef __GST_CAMERABIN_ENUM_H__ */ diff --git a/gst-libs/gst/baseparse/Makefile.am b/gst-libs/gst/baseparse/Makefile.am new file mode 100644 index 000000000..e44a78b0a --- /dev/null +++ b/gst-libs/gst/baseparse/Makefile.am @@ -0,0 +1,20 @@ + +lib_LTLIBRARIES = libgstbaseparse-@GST_MAJORMINOR@.la + +CLEANFILES = $(BUILT_SOURCES) + +libgstbaseparse_@GST_MAJORMINOR@_la_SOURCES = \ + gstbaseparse.c + +libgstbaseparse_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/baseparse +libgstbaseparse_@GST_MAJORMINOR@include_HEADERS = \ + gstbaseparse.h + +libgstbaseparse_@GST_MAJORMINOR@_la_CFLAGS = \ + $(GST_PLUGINS_BAD_CFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) \ + -DGST_USE_UNSTABLE_API \ + $(GST_CFLAGS) +libgstbaseparse_@GST_MAJORMINOR@_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_LIBS) +libgstbaseparse_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS) + diff --git a/gst/audioparsers/gstbaseparse.c b/gst-libs/gst/baseparse/gstbaseparse.c index 4cd759aac..e465529db 100644 --- a/gst/audioparsers/gstbaseparse.c +++ b/gst-libs/gst/baseparse/gstbaseparse.c @@ -24,7 +24,7 @@ * @short_description: Base class for stream parsers * @see_also: #GstBaseTransform * - * This base class is for parser elements that process data and splits it + * This base class is for parser elements that process data and splits it * into separate audio/video/whatever frames. * * It provides for: @@ -58,7 +58,7 @@ * </para></listitem> * <listitem><para> * At least in this point subclass needs to tell the GstBaseParse class - * how big data chunks it wants to receive (min_frame_size). It can do + * how big data chunks it wants to receive (min_frame_size). It can do * this with @gst_base_parse_set_min_frame_size. * </para></listitem> * <listitem><para> @@ -71,27 +71,32 @@ * <itemizedlist> * <title>Parsing phase</title> * <listitem><para> - * GstBaseParse gathers at least min_frame_size bytes of data either + * GstBaseParse gathers at least min_frame_size bytes of data either * by pulling it from upstream or collecting buffers into internal * #GstAdapter. * </para></listitem> * <listitem><para> - * A buffer of min_frame_size bytes is passed to subclass with + * A buffer of (at least) min_frame_size bytes is passed to subclass with * @check_valid_frame. Subclass checks the contents and returns TRUE * if the buffer contains a valid frame. It also needs to set the * @framesize according to the detected frame size. If buffer didn't * contain a valid frame, this call must return FALSE and optionally * set the @skipsize value to inform base class that how many bytes - * it needs to skip in order to find a valid frame. The passed buffer + * it needs to skip in order to find a valid frame. @framesize can always + * indicate a new minimum for current frame parsing. The passed buffer * is read-only. Note that @check_valid_frame might receive any small * amount of input data when leftover data is being drained (e.g. at EOS). * </para></listitem> * <listitem><para> * After valid frame is found, it will be passed again to subclass with * @parse_frame call. Now subclass is responsible for parsing the - * frame contents and setting the caps, buffer timestamp and duration + * frame contents and setting the caps, and buffer metadata (e.g. + * buffer timestamp and duration, or keyframe if applicable). * (although the latter can also be done by GstBaseParse if it is - * appropriately configured, see below). + * appropriately configured, see below). Frame is provided with + * timestamp derived from upstream (as much as generally possible), + * duration obtained form configuration (see below), and offset + * if meaningful (in pull mode). * </para></listitem> * <listitem><para> * Finally the buffer can be pushed downstream and parsing loop starts @@ -118,8 +123,8 @@ * </orderedlist> * * Subclass is responsible for providing pad template caps for - * source and sink pads. The pads need to be named "sink" and "src". It also - * needs to set the fixed caps on srcpad, when the format is ensured (e.g. + * source and sink pads. The pads need to be named "sink" and "src". It also + * needs to set the fixed caps on srcpad, when the format is ensured (e.g. * when base class calls subclass' @set_sink_caps function). * * This base class uses GST_FORMAT_DEFAULT as a meaning of frames. So, @@ -156,7 +161,7 @@ * Update the duration information with @gst_base_parse_set_duration * </para></listitem> * <listitem><para> - * Optionally passthrough using @gst_base_parse_set_passthrough + * Optionally passthrough using @gst_base_parse_set_format * </para></listitem> * <listitem><para> * Configure various baseparse parameters using @gst_base_parse_set_seek and @@ -218,9 +223,9 @@ struct _GstBaseParsePrivate gint64 estimated_duration; guint min_frame_size; - gboolean passthrough; + guint format; guint fps_num, fps_den; - guint update_interval; + gint update_interval; guint bitrate; guint lead_in, lead_out; GstClockTime lead_in_ts, lead_out_ts; @@ -269,7 +274,7 @@ struct _GstBaseParsePrivate GstClockTimeDiff idx_interval; /* ts and offset of last entry added */ GstClockTime index_last_ts; - guint64 index_last_offset; + gint64 index_last_offset; gboolean index_last_valid; /* timestamps currently produced are accurate, e.g. started from 0 onwards */ @@ -280,6 +285,7 @@ struct _GstBaseParsePrivate /* reverse playback */ GSList *buffers_pending; GSList *buffers_queued; + GSList *buffers_send; GstClockTime last_ts; gint64 last_offset; }; @@ -292,6 +298,12 @@ typedef struct _GstBaseParseSeek GstClockTime start_ts; } GstBaseParseSeek; +#define GST_BASE_PARSE_PASSTHROUGH(parse) \ + (parse->priv->format & GST_BASE_PARSE_FORMAT_PASSTHROUGH) +#define GST_BASE_PARSE_HAS_TIME(parse) \ + (parse->priv->format & GST_BASE_PARSE_FORMAT_HAS_TIME) + + static GstElementClass *parent_class = NULL; static void gst_base_parse_class_init (GstBaseParseClass * klass); @@ -317,7 +329,7 @@ gst_base_parse_get_type (void) }; base_parse_type = g_type_register_static (GST_TYPE_ELEMENT, - "GstAudioBaseParseBad", &base_parse_info, G_TYPE_FLAG_ABSTRACT); + "GstBaseParseBad", &base_parse_info, G_TYPE_FLAG_ABSTRACT); } return base_parse_type; } @@ -350,10 +362,9 @@ static GstFlowReturn gst_base_parse_chain (GstPad * pad, GstBuffer * buffer); static void gst_base_parse_loop (GstPad * pad); static gboolean gst_base_parse_check_frame (GstBaseParse * parse, - GstBuffer * buffer, guint * framesize, gint * skipsize); - + GstBaseParseFrame * frame, guint * framesize, gint * skipsize); static GstFlowReturn gst_base_parse_parse_frame (GstBaseParse * parse, - GstBuffer * buffer); + GstBaseParseFrame * frame); static gboolean gst_base_parse_sink_eventfunc (GstBaseParse * parse, GstEvent * event); @@ -384,6 +395,9 @@ gst_base_parse_clear_queues (GstBaseParse * parse) NULL); g_slist_free (parse->priv->buffers_pending); parse->priv->buffers_pending = NULL; + g_slist_foreach (parse->priv->buffers_send, (GFunc) gst_buffer_unref, NULL); + g_slist_free (parse->priv->buffers_send); + parse->priv->buffers_send = NULL; } static void @@ -392,7 +406,6 @@ gst_base_parse_finalize (GObject * object) GstBaseParse *parse = GST_BASE_PARSE (object); GstEvent **p_ev; - g_mutex_free (parse->parse_lock); g_object_unref (parse->adapter); if (parse->pending_segment) { @@ -494,7 +507,6 @@ gst_base_parse_init (GstBaseParse * parse, GstBaseParseClass * bclass) gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad); GST_DEBUG_OBJECT (parse, "src created"); - parse->parse_lock = g_mutex_new (); parse->adapter = gst_adapter_new (); parse->priv->pad_mode = GST_ACTIVATE_NONE; @@ -504,6 +516,49 @@ gst_base_parse_init (GstBaseParse * parse, GstBaseParseClass * bclass) GST_DEBUG_OBJECT (parse, "init ok"); } +/** + * gst_base_parse_frame_init: + * @parse: #GstBaseParse. + * @fmt: #GstBaseParseFrame. + * + * Sets a #GstBaseParseFrame to initial state. Currently this means + * all fields are zero-ed. + */ +void +gst_base_parse_frame_init (GstBaseParse * parse, GstBaseParseFrame * frame) +{ + memset (frame, 0, sizeof (*frame)); +} + +/* clear == frame no longer to be used following this */ +static void +gst_base_parse_frame_clear (GstBaseParse * parse, GstBaseParseFrame * frame) +{ + /* limited for now */ + if (frame->buffer) { + gst_buffer_unref (frame->buffer); + frame->buffer = NULL; + } +} + +static inline void +gst_base_parse_frame_update (GstBaseParse * parse, GstBaseParseFrame * frame, + GstBuffer * buf) +{ + gst_buffer_replace (&frame->buffer, buf); + if (parse->priv->drain) { + frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DRAIN; + } else { + frame->flags &= ~(GST_BASE_PARSE_FRAME_FLAG_DRAIN); + } + /* losing sync is pretty much a discont (and vice versa), no ? */ + if (!parse->priv->discont) { + frame->flags |= GST_BASE_PARSE_FRAME_FLAG_SYNC; + } else { + frame->flags &= ~(GST_BASE_PARSE_FRAME_FLAG_SYNC); + } +} + static void gst_base_parse_reset (GstBaseParse * parse) { @@ -515,7 +570,7 @@ gst_base_parse_reset (GstBaseParse * parse) parse->priv->flushing = FALSE; parse->priv->offset = 0; parse->priv->sync_offset = 0; - parse->priv->update_interval = 50; + parse->priv->update_interval = -1; parse->priv->fps_num = parse->priv->fps_den = 0; parse->priv->frame_duration = GST_CLOCK_TIME_NONE; parse->priv->lead_in = parse->priv->lead_out = 0; @@ -529,7 +584,7 @@ gst_base_parse_reset (GstBaseParse * parse) parse->priv->first_frame_offset = -1; parse->priv->estimated_duration = -1; parse->priv->next_ts = 0; - parse->priv->passthrough = FALSE; + parse->priv->format = 0; parse->priv->post_min_bitrate = TRUE; parse->priv->post_avg_bitrate = TRUE; parse->priv->post_max_bitrate = TRUE; @@ -538,8 +593,8 @@ gst_base_parse_reset (GstBaseParse * parse) parse->priv->avg_bitrate = 0; parse->priv->posted_avg_bitrate = 0; - parse->priv->index_last_ts = 0; - parse->priv->index_last_offset = 0; + parse->priv->index_last_ts = GST_CLOCK_TIME_NONE; + parse->priv->index_last_offset = -1; parse->priv->index_last_valid = TRUE; parse->priv->upstream_seekable = FALSE; parse->priv->upstream_size = 0; @@ -582,14 +637,14 @@ gst_base_parse_reset (GstBaseParse * parse) * in order to find the following frame header. * * Default callback for check_valid_frame. - * + * * Returns: Always TRUE. */ static gboolean gst_base_parse_check_frame (GstBaseParse * parse, - GstBuffer * buffer, guint * framesize, gint * skipsize) + GstBaseParseFrame * frame, guint * framesize, gint * skipsize) { - *framesize = GST_BUFFER_SIZE (buffer); + *framesize = GST_BUFFER_SIZE (frame->buffer); *skipsize = 0; return TRUE; } @@ -603,8 +658,10 @@ gst_base_parse_check_frame (GstBaseParse * parse, * Default callback for parse_frame. */ static GstFlowReturn -gst_base_parse_parse_frame (GstBaseParse * parse, GstBuffer * buffer) +gst_base_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) { + GstBuffer *buffer = frame->buffer; + if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer) && GST_CLOCK_TIME_IS_VALID (parse->priv->next_ts)) { GST_BUFFER_TIMESTAMP (buffer) = parse->priv->next_ts; @@ -688,11 +745,11 @@ gst_base_parse_sink_event (GstPad * pad, GstEvent * event) gboolean handled = FALSE; gboolean ret = TRUE; - parse = GST_BASE_PARSE (gst_pad_get_parent (pad)); bclass = GST_BASE_PARSE_GET_CLASS (parse); - GST_DEBUG_OBJECT (parse, "handling event %d", GST_EVENT_TYPE (event)); + GST_DEBUG_OBJECT (parse, "handling event %d, %s", GST_EVENT_TYPE (event), + GST_EVENT_TYPE_NAME (event)); /* Cache all events except EOS, NEWSEGMENT and FLUSH_STOP if we have a * pending segment */ @@ -738,7 +795,10 @@ gst_base_parse_sink_event (GstPad * pad, GstEvent * event) * * Element-level event handler function. * - * Returns: TRUE if the event was handled and not need forwarding. + * The event will be unreffed only if it has been handled and this + * function returns %TRUE + * + * Returns: %TRUE if the event was handled and not need forwarding. */ static gboolean gst_base_parse_sink_eventfunc (GstBaseParse * parse, GstEvent * event) @@ -814,7 +874,7 @@ gst_base_parse_sink_eventfunc (GstBaseParse * parse, GstEvent * event) "start = %" GST_TIME_FORMAT ", stop = %" GST_TIME_FORMAT, GST_TIME_ARGS (seg_start), GST_TIME_ARGS (seg_stop)); } else if (format != GST_FORMAT_TIME) { - /* Unknown incoming segment format. Output a default open-ended + /* Unknown incoming segment format. Output a default open-ended * TIME segment */ gst_event_unref (event); event = gst_event_new_new_segment_full (update, rate, applied_rate, @@ -858,7 +918,9 @@ gst_base_parse_sink_eventfunc (GstBaseParse * parse, GstEvent * event) case GST_EVENT_FLUSH_START: parse->priv->flushing = TRUE; - handled = gst_pad_push_event (parse->srcpad, event); + handled = gst_pad_push_event (parse->srcpad, gst_event_ref (event)); + if (handled) + gst_event_unref (event); /* Wait for _chain() to exit by taking the srcpad STREAM_LOCK */ GST_PAD_STREAM_LOCK (parse->srcpad); GST_PAD_STREAM_UNLOCK (parse->srcpad); @@ -927,8 +989,6 @@ gst_base_parse_src_event (GstPad * pad, GstEvent * event) if (!handled) ret = gst_pad_event_default (pad, event); - else - gst_event_unref (event); gst_object_unref (parse); return ret; @@ -1067,8 +1127,12 @@ gst_base_parse_update_duration (GstBaseParse * aacparse) gst_object_unref (GST_OBJECT (peer)); if (qres) { if (gst_base_parse_convert (parse, pformat, ptot, - GST_FORMAT_TIME, &dest_value)) + GST_FORMAT_TIME, &dest_value)) { parse->priv->estimated_duration = dest_value; + GST_LOG_OBJECT (parse, + "updated estimated duration to %" GST_TIME_FORMAT, + GST_TIME_ARGS (dest_value)); + } } } } @@ -1109,23 +1173,22 @@ gst_base_parse_post_bitrates (GstBaseParse * parse, gboolean post_min, * running average bitrate of the stream so far. */ static void -gst_base_parse_update_bitrates (GstBaseParse * parse, GstBuffer * buffer) +gst_base_parse_update_bitrates (GstBaseParse * parse, GstBaseParseFrame * frame) { /* Only update the tag on a 10 kbps delta */ static const gint update_threshold = 10000; GstBaseParseClass *klass; guint64 data_len, frame_dur; - gint overhead = 0, frame_bitrate, old_avg_bitrate; + gint overhead, frame_bitrate, old_avg_bitrate; gboolean update_min = FALSE, update_avg = FALSE, update_max = FALSE; + GstBuffer *buffer = frame->buffer; klass = GST_BASE_PARSE_GET_CLASS (parse); - if (klass->get_frame_overhead) { - overhead = klass->get_frame_overhead (parse, buffer); - if (overhead == -1) - return; - } + overhead = frame->overhead; + if (overhead == -1) + return; data_len = GST_BUFFER_SIZE (buffer) - overhead; parse->priv->data_bytecount += data_len; @@ -1151,7 +1214,10 @@ gst_base_parse_update_bitrates (GstBaseParse * parse, GstBuffer * buffer) gst_base_parse_post_bitrates (parse, FALSE, TRUE, FALSE); } - frame_bitrate = (8 * data_len * GST_SECOND) / frame_dur; + if (frame_dur) + frame_bitrate = (8 * data_len * GST_SECOND) / frame_dur; + else + return; GST_LOG_OBJECT (parse, "frame bitrate %u, avg bitrate %u", frame_bitrate, parse->priv->avg_bitrate); @@ -1161,7 +1227,9 @@ gst_base_parse_update_bitrates (GstBaseParse * parse, GstBuffer * buffer) } else if (parse->priv->framecount == MIN_FRAMES_TO_POST_BITRATE) { /* always post all at threshold time */ update_min = update_max = update_avg = TRUE; - } else { + } + + if (G_LIKELY (parse->priv->framecount >= MIN_FRAMES_TO_POST_BITRATE)) { if (frame_bitrate < parse->priv->min_bitrate) { parse->priv->min_bitrate = frame_bitrate; update_min = TRUE; @@ -1228,13 +1296,14 @@ gst_base_parse_add_index_entry (GstBaseParse * parse, guint64 offset, /* FIXME need better helper data structure that handles these issues * related to ongoing collecting of index entries */ - if (parse->priv->index_last_offset >= offset) { + if (parse->priv->index_last_offset >= (gint64) offset) { GST_DEBUG_OBJECT (parse, "already have entries up to offset " "0x%08" G_GINT64_MODIFIER "x", parse->priv->index_last_offset); goto exit; } - if (GST_CLOCK_DIFF (parse->priv->index_last_ts, ts) < + if (GST_CLOCK_TIME_IS_VALID (parse->priv->index_last_ts) && + GST_CLOCK_DIFF (parse->priv->index_last_ts, ts) < parse->priv->idx_interval) { GST_DEBUG_OBJECT (parse, "entry too close to last time %" GST_TIME_FORMAT, GST_TIME_ARGS (parse->priv->index_last_ts)); @@ -1265,7 +1334,7 @@ gst_base_parse_add_index_entry (GstBaseParse * parse, guint64 offset, /* index might change on-the-fly, although that would be nutty app ... */ GST_OBJECT_LOCK (parse); gst_index_add_associationv (parse->priv->index, parse->priv->index_id, - (key) ? GST_ASSOCIATION_FLAG_KEY_UNIT : GST_ASSOCIATION_FLAG_NONE, + (key) ? GST_ASSOCIATION_FLAG_KEY_UNIT : GST_ASSOCIATION_FLAG_DELTA_UNIT, 2, (const GstIndexAssociation *) &associations); GST_OBJECT_UNLOCK (parse); @@ -1386,11 +1455,16 @@ gst_base_parse_check_media (GstBaseParse * parse) * Returns: #GstFlowReturn */ static GstFlowReturn -gst_base_parse_handle_and_push_buffer (GstBaseParse * parse, - GstBaseParseClass * klass, GstBuffer * buffer) +gst_base_parse_handle_and_push_frame (GstBaseParse * parse, + GstBaseParseClass * klass, GstBaseParseFrame * frame) { GstFlowReturn ret; gint64 offset; + GstBuffer *buffer; + + g_return_val_if_fail (frame != NULL, GST_FLOW_ERROR); + + buffer = frame->buffer; if (parse->priv->discont) { GST_DEBUG_OBJECT (parse, "marking DISCONT"); @@ -1410,14 +1484,23 @@ gst_base_parse_handle_and_push_buffer (GstBaseParse * parse, GST_BUFFER_OFFSET (buffer), GST_BUFFER_OFFSET (buffer), GST_BUFFER_SIZE (buffer)); + /* use default handler to provide initial (upstream) metadata */ + gst_base_parse_parse_frame (parse, frame); + /* store offset as it might get overwritten */ offset = GST_BUFFER_OFFSET (buffer); - ret = klass->parse_frame (parse, buffer); + ret = klass->parse_frame (parse, frame); + /* sync */ + buffer = frame->buffer; + /* subclass must play nice */ + g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR); - /* check initial frame to determine if subclass/format can provide ts. + /* check if subclass/format can provide ts. * If so, that allows and enables extra seek and duration determining options */ if (G_UNLIKELY (parse->priv->first_frame_offset < 0 && ret == GST_FLOW_OK)) { - if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) { + if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) && + GST_BASE_PARSE_HAS_TIME (parse) && + parse->priv->pad_mode == GST_ACTIVATE_PULL) { parse->priv->first_frame_offset = offset; parse->priv->first_frame_ts = GST_BUFFER_TIMESTAMP (buffer); GST_DEBUG_OBJECT (parse, "subclass provided ts %" GST_TIME_FORMAT @@ -1439,8 +1522,9 @@ gst_base_parse_handle_and_push_buffer (GstBaseParse * parse, } } - /* re-use default handler to add missing metadata as-much-as-possible */ - gst_base_parse_parse_frame (parse, buffer); + /* again use default handler to add missing metadata; + * we may have new information on frame properties */ + gst_base_parse_parse_frame (parse, frame); if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) && GST_BUFFER_DURATION_IS_VALID (buffer)) { parse->priv->next_ts = @@ -1462,34 +1546,40 @@ gst_base_parse_handle_and_push_buffer (GstBaseParse * parse, * frames to decide on the format and queues them internally */ /* convert internal flow to OK and mark discont for the next buffer. */ if (ret == GST_BASE_PARSE_FLOW_DROPPED) { - gst_buffer_unref (buffer); + gst_base_parse_frame_clear (parse, frame); return GST_FLOW_OK; } else if (ret != GST_FLOW_OK) { return ret; } - return gst_base_parse_push_buffer (parse, buffer); + return gst_base_parse_push_frame (parse, frame); } /** - * gst_base_parse_push_buffer: + * gst_base_parse_push_frame: * @parse: #GstBaseParse. - * @buffer: #GstBuffer. + * @frame: #GstBaseParseFrame. * - * Pushes the buffer downstream, sends any pending events and + * Pushes the frame downstream, sends any pending events and * does some timestamp and segment handling. * - * This must be called with srcpad STREAM_LOCK held. + * This must be called with sinkpad STREAM_LOCK held. * * Returns: #GstFlowReturn */ GstFlowReturn -gst_base_parse_push_buffer (GstBaseParse * parse, GstBuffer * buffer) +gst_base_parse_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame) { GstFlowReturn ret = GST_FLOW_OK; GstClockTime last_start = GST_CLOCK_TIME_NONE; GstClockTime last_stop = GST_CLOCK_TIME_NONE; GstBaseParseClass *klass = GST_BASE_PARSE_GET_CLASS (parse); + GstBuffer *buffer; + + g_return_val_if_fail (frame != NULL, GST_FLOW_ERROR); + g_return_val_if_fail (frame->buffer != NULL, GST_FLOW_ERROR); + + buffer = frame->buffer; GST_LOG_OBJECT (parse, "processing buffer of size %d with ts %" GST_TIME_FORMAT @@ -1499,14 +1589,16 @@ gst_base_parse_push_buffer (GstBaseParse * parse, GstBuffer * buffer) /* update stats */ parse->priv->bytecount += GST_BUFFER_SIZE (buffer); - if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BASE_PARSE_BUFFER_FLAG_NO_FRAME)) { + if (G_LIKELY (!(frame->flags & GST_BASE_PARSE_FRAME_FLAG_NO_FRAME))) { parse->priv->framecount++; if (GST_BUFFER_DURATION_IS_VALID (buffer)) { parse->priv->acc_duration += GST_BUFFER_DURATION (buffer); } } - GST_BUFFER_FLAG_UNSET (buffer, GST_BASE_PARSE_BUFFER_FLAG_NO_FRAME); - if (parse->priv->update_interval && + /* 0 means disabled */ + if (parse->priv->update_interval < 0) + parse->priv->update_interval = 50; + else if (parse->priv->update_interval > 0 && (parse->priv->framecount % parse->priv->update_interval) == 0) gst_base_parse_update_duration (parse); @@ -1519,10 +1611,8 @@ gst_base_parse_push_buffer (GstBaseParse * parse, GstBuffer * buffer) /* should have caps by now */ g_return_val_if_fail (GST_PAD_CAPS (parse->srcpad), GST_FLOW_ERROR); - gst_buffer_set_caps (buffer, GST_PAD_CAPS (parse->srcpad)); - /* segment adjustment magic; only if we are running the whole show */ - if (!parse->priv->passthrough && parse->segment.rate > 0.0 && + if (!GST_BASE_PARSE_PASSTHROUGH (parse) && parse->segment.rate > 0.0 && (parse->priv->pad_mode == GST_ACTIVATE_PULL || parse->priv->upstream_seekable)) { /* segment times are typically estimates, @@ -1609,7 +1699,7 @@ gst_base_parse_push_buffer (GstBaseParse * parse, GstBuffer * buffer) /* update bitrates and optionally post corresponding tags * (following newsegment) */ - gst_base_parse_update_bitrates (parse, buffer); + gst_base_parse_update_bitrates (parse, frame); if (G_UNLIKELY (parse->priv->pending_events)) { GList *l; @@ -1621,15 +1711,27 @@ gst_base_parse_push_buffer (GstBaseParse * parse, GstBuffer * buffer) parse->priv->pending_events = NULL; } - if (klass->pre_push_buffer) - ret = klass->pre_push_buffer (parse, buffer); - else - ret = GST_BASE_PARSE_FLOW_CLIP; + if (klass->pre_push_frame) { + ret = klass->pre_push_frame (parse, frame); + } else { + frame->flags |= GST_BASE_PARSE_FRAME_FLAG_CLIP; + } + + /* take final ownership of frame buffer */ + buffer = frame->buffer; + frame->buffer = NULL; + + /* subclass must play nice */ + g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR); + + /* decorate */ + buffer = gst_buffer_make_metadata_writable (buffer); + gst_buffer_set_caps (buffer, GST_PAD_CAPS (parse->srcpad)); parse->priv->seen_keyframe |= parse->priv->is_video && !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT); - if (ret == GST_BASE_PARSE_FLOW_CLIP) { + if (frame->flags & GST_BASE_PARSE_FRAME_FLAG_CLIP) { if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) && GST_CLOCK_TIME_IS_VALID (parse->segment.stop) && GST_BUFFER_TIMESTAMP (buffer) > @@ -1676,7 +1778,7 @@ gst_base_parse_push_buffer (GstBaseParse * parse, GstBuffer * buffer) GST_BUFFER_SIZE (buffer), gst_flow_get_name (ret)); /* if we are not sufficiently in control, let upstream decide on EOS */ if (ret == GST_FLOW_UNEXPECTED && - (parse->priv->passthrough || + (GST_BASE_PARSE_PASSTHROUGH (parse) || (parse->priv->pad_mode == GST_ACTIVATE_PUSH && !parse->priv->upstream_seekable))) ret = GST_FLOW_OK; @@ -1687,6 +1789,8 @@ gst_base_parse_push_buffer (GstBaseParse * parse, GstBuffer * buffer) parse->segment.last_stop < last_stop) gst_segment_set_last_stop (&parse->segment, GST_FORMAT_TIME, last_stop); + gst_base_parse_frame_clear (parse, frame); + return ret; } @@ -1730,6 +1834,50 @@ gst_base_parse_drain (GstBaseParse * parse) * gst_base_parse_process_fragment: * @parse: #GstBaseParse. * + * Sends buffers collected in send_buffers downstream, and ensures that list + * is empty at the end (errors or not). + */ +static GstFlowReturn +gst_base_parse_send_buffers (GstBaseParse * parse) +{ + GSList *send = NULL; + GstBuffer *buf; + GstFlowReturn ret = GST_FLOW_OK; + + send = parse->priv->buffers_send; + + /* send buffers */ + while (send) { + buf = GST_BUFFER_CAST (send->data); + GST_LOG_OBJECT (parse, "pushing buffer %p, timestamp %" + GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT + ", offset %" G_GINT64_FORMAT, buf, + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf)); + + /* iterate output queue an push downstream */ + ret = gst_pad_push (parse->srcpad, buf); + send = g_slist_delete_link (send, send); + + /* clear any leftover if error */ + if (G_UNLIKELY (ret != GST_FLOW_OK)) { + while (send) { + buf = GST_BUFFER_CAST (send->data); + gst_buffer_unref (buf); + send = g_slist_delete_link (send, send); + } + } + } + + parse->priv->buffers_send = send; + + return ret; +} + +/** + * gst_base_parse_process_fragment: + * @parse: #GstBaseParse. + * * Processes a reverse playback (forward) fragment: * - append head of last fragment that was skipped to current fragment data * - drain the resulting current fragment data (i.e. repeated chain) @@ -1741,7 +1889,7 @@ gst_base_parse_process_fragment (GstBaseParse * parse, gboolean push_only) { GstBuffer *buf; GstFlowReturn ret = GST_FLOW_OK; - GSList *send = NULL; + gboolean seen_key = FALSE, seen_delta = FALSE; if (push_only) goto push; @@ -1771,6 +1919,11 @@ gst_base_parse_process_fragment (GstBaseParse * parse, gboolean push_only) gst_base_parse_drain (parse); push: + if (parse->priv->buffers_send) { + buf = GST_BUFFER_CAST (parse->priv->buffers_send->data); + seen_key |= !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT); + } + /* add metadata (if needed to queued buffers */ GST_LOG_OBJECT (parse, "last timestamp: %" GST_TIME_FORMAT, GST_TIME_ARGS (parse->priv->last_ts)); @@ -1795,38 +1948,39 @@ push: GST_WARNING_OBJECT (parse, "could not determine time for buffer"); } + parse->priv->last_ts = GST_BUFFER_TIMESTAMP (buf); + /* reverse order for ascending sending */ - send = g_slist_prepend (send, buf); + /* send downstream at keyframe not preceded by a keyframe + * (e.g. that should identify start of collection of IDR nals) */ + if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) { + if (seen_key) { + ret = gst_base_parse_send_buffers (parse); + /* if a problem, throw all to sending */ + if (ret != GST_FLOW_OK) { + parse->priv->buffers_send = + g_slist_reverse (parse->priv->buffers_queued); + parse->priv->buffers_queued = NULL; + break; + } + seen_key = FALSE; + } + } else { + seen_delta = TRUE; + } + + seen_key |= !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT); + + parse->priv->buffers_send = + g_slist_prepend (parse->priv->buffers_send, buf); parse->priv->buffers_queued = g_slist_delete_link (parse->priv->buffers_queued, parse->priv->buffers_queued); } - /* send buffers */ - while (send) { - buf = GST_BUFFER_CAST (send->data); - GST_LOG_OBJECT (parse, "pushing buffer %p, timestamp %" - GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT - ", offset %" G_GINT64_FORMAT, buf, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf)); - - if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (parse->priv->last_ts))) - parse->priv->last_ts = GST_BUFFER_TIMESTAMP (buf); - - /* iterate output queue an push downstream */ - ret = gst_pad_push (parse->srcpad, buf); - send = g_slist_delete_link (send, send); - - /* clear any leftover if error */ - if (G_UNLIKELY (ret != GST_FLOW_OK)) { - while (send) { - buf = GST_BUFFER_CAST (send->data); - gst_buffer_unref (buf); - send = g_slist_delete_link (send, send); - } - } - } + /* audio may have all marked as keyframe, so arrange to send here */ + if (!seen_delta) + ret = gst_base_parse_send_buffers (parse); /* any trailing unused no longer usable (ideally none) */ if (G_UNLIKELY (gst_adapter_available (parse->adapter))) { @@ -1868,21 +2022,24 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer) GstFlowReturn ret = GST_FLOW_OK; GstBuffer *outbuf = NULL; GstBuffer *tmpbuf = NULL; - guint fsize = 0; + guint fsize = 1; gint skip = -1; const guint8 *data; - guint min_size; + guint old_min_size = 0, min_size, av; GstClockTime timestamp; + GstBaseParseFrame _frame = { 0, }; + GstBaseParseFrame *frame; parse = GST_BASE_PARSE (GST_OBJECT_PARENT (pad)); bclass = GST_BASE_PARSE_GET_CLASS (parse); + frame = &_frame; if (G_LIKELY (buffer)) { GST_LOG_OBJECT (parse, "buffer size: %d, offset = %" G_GINT64_FORMAT, GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer)); - if (G_UNLIKELY (parse->priv->passthrough)) { - buffer = gst_buffer_make_metadata_writable (buffer); - return gst_base_parse_push_buffer (parse, buffer); + if (G_UNLIKELY (GST_BASE_PARSE_PASSTHROUGH (parse))) { + frame->buffer = gst_buffer_make_metadata_writable (buffer); + return gst_base_parse_push_frame (parse, frame); } /* upstream feeding us in reverse playback; * gather each fragment, then process it in single run */ @@ -1900,16 +2057,23 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer) /* Parse and push as many frames as possible */ /* Stop either when adapter is empty or we are flushing */ while (!parse->priv->flushing) { + gboolean res; + tmpbuf = gst_buffer_new (); + old_min_size = 0; /* Synchronization loop */ for (;;) { - GST_BASE_PARSE_LOCK (parse); - min_size = parse->priv->min_frame_size; - GST_BASE_PARSE_UNLOCK (parse); + min_size = MAX (parse->priv->min_frame_size, fsize); + av = gst_adapter_available (parse->adapter); + + /* loop safety check */ + if (G_UNLIKELY (old_min_size >= min_size)) + goto invalid_min; + old_min_size = min_size; if (G_UNLIKELY (parse->priv->drain)) { - min_size = gst_adapter_available (parse->adapter); + min_size = av; GST_DEBUG_OBJECT (parse, "draining, data left: %d", min_size); if (G_UNLIKELY (!min_size)) { gst_buffer_unref (tmpbuf); @@ -1918,14 +2082,15 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer) } /* Collect at least min_frame_size bytes */ - if (gst_adapter_available (parse->adapter) < min_size) { + if (av < min_size) { GST_DEBUG_OBJECT (parse, "not enough data available (only %d bytes)", - gst_adapter_available (parse->adapter)); + av); gst_buffer_unref (tmpbuf); goto done; } - data = gst_adapter_peek (parse->adapter, min_size); + /* always pass all available data */ + data = gst_adapter_peek (parse->adapter, av); GST_BUFFER_DATA (tmpbuf) = (guint8 *) data; GST_BUFFER_SIZE (tmpbuf) = min_size; GST_BUFFER_OFFSET (tmpbuf) = parse->priv->offset; @@ -1937,7 +2102,10 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer) } skip = -1; - if (bclass->check_valid_frame (parse, tmpbuf, &fsize, &skip)) { + gst_base_parse_frame_update (parse, frame, tmpbuf); + res = bclass->check_valid_frame (parse, frame, &fsize, &skip); + gst_buffer_replace (&frame->buffer, NULL); + if (res) { if (gst_adapter_available (parse->adapter) < fsize) { GST_DEBUG_OBJECT (parse, "found valid frame but not enough data available (only %d bytes)", @@ -1945,6 +2113,7 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer) gst_buffer_unref (tmpbuf); goto done; } + GST_LOG_OBJECT (parse, "valid frame of size %d at pos %d", fsize, skip); break; } if (skip == -1) { @@ -1971,10 +2140,11 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer) if (!parse->priv->discont) parse->priv->sync_offset = parse->priv->offset; parse->priv->discont = TRUE; + /* something changed least; nullify loop check */ + old_min_size = 0; } - /* There is a possibility that subclass set the skip value to zero. - This means that it has probably found a frame but wants to ask - more data (by increasing the min_size) to be sure of this. */ + /* skip == 0 should imply subclass set min_size to need more data; + * we check this shortly */ if ((ret = gst_base_parse_check_sync (parse)) != GST_FLOW_OK) { gst_buffer_unref (tmpbuf); goto done; @@ -2000,6 +2170,14 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer) break; } + /* move along with upstream timestamp (if any), + * but interpolate in between */ + timestamp = gst_adapter_prev_timestamp (parse->adapter, NULL); + if (GST_CLOCK_TIME_IS_VALID (timestamp) && + (parse->priv->prev_ts != timestamp)) { + parse->priv->prev_ts = parse->priv->next_ts = timestamp; + } + /* FIXME: Would it be more efficient to make a subbuffer instead? */ outbuf = gst_adapter_take_buffer (parse->adapter, fsize); outbuf = gst_buffer_make_metadata_writable (outbuf); @@ -2008,16 +2186,10 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer) GST_BUFFER_OFFSET (outbuf) = parse->priv->offset; parse->priv->offset += fsize; GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE; + GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE; - /* move along with upstream timestamp (if any), - * but interpolate in between */ - timestamp = gst_adapter_prev_timestamp (parse->adapter, NULL); - if (GST_CLOCK_TIME_IS_VALID (timestamp) && - (parse->priv->prev_ts != timestamp)) { - parse->priv->prev_ts = parse->priv->next_ts = timestamp; - } - - ret = gst_base_parse_handle_and_push_buffer (parse, bclass, outbuf); + frame->buffer = outbuf; + ret = gst_base_parse_handle_and_push_frame (parse, bclass, frame); GST_PAD_STREAM_UNLOCK (parse->srcpad); if (ret != GST_FLOW_OK) { @@ -2029,6 +2201,15 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer) done: GST_LOG_OBJECT (parse, "chain leaving"); return ret; + + /* ERRORS */ +invalid_min: + { + GST_ELEMENT_ERROR (parse, STREAM, FAILED, (NULL), + ("min_size evolution %d -> %d; breaking to avoid looping", + old_min_size, min_size)); + return GST_FLOW_ERROR; + } } /* pull @size bytes at current offset, @@ -2152,11 +2333,17 @@ gst_base_parse_handle_previous_fragment (GstBaseParse * parse) if (ret != GST_FLOW_OK) goto exit; + /* offset will increase again as fragment is processed/parsed */ + parse->priv->last_offset = offset; + gst_adapter_push (parse->adapter, buffer); ret = gst_base_parse_process_fragment (parse, FALSE); if (ret != GST_FLOW_OK) goto exit; + /* force previous fragment */ + parse->priv->offset = -1; + exit: return ret; } @@ -2166,20 +2353,26 @@ exit: * ajusts sync, drain and offset going along */ static GstFlowReturn gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass, - GstBuffer ** buf, gboolean full) + GstBaseParseFrame * frame, gboolean full) { GstBuffer *buffer, *outbuf; GstFlowReturn ret = GST_FLOW_OK; - guint fsize = 0, min_size; + guint fsize = 1, min_size, old_min_size = 0; gint skip = 0; - g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR); + g_return_val_if_fail (frame != NULL, GST_FLOW_ERROR); + + GST_LOG_OBJECT (parse, "scanning for frame at offset %" G_GUINT64_FORMAT + " (%#" G_GINT64_MODIFIER "x)", parse->priv->offset, parse->priv->offset); while (TRUE) { + gboolean res; - GST_BASE_PARSE_LOCK (parse); - min_size = parse->priv->min_frame_size; - GST_BASE_PARSE_UNLOCK (parse); + min_size = MAX (parse->priv->min_frame_size, fsize); + /* loop safety check */ + if (G_UNLIKELY (old_min_size >= min_size)) + goto invalid_min; + old_min_size = min_size; ret = gst_base_parse_pull_range (parse, min_size, &buffer); if (ret != GST_FLOW_OK) @@ -2196,8 +2389,12 @@ gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass, parse->priv->drain = TRUE; skip = -1; - if (klass->check_valid_frame (parse, buffer, &fsize, &skip)) { + gst_base_parse_frame_update (parse, frame, buffer); + res = klass->check_valid_frame (parse, frame, &fsize, &skip); + gst_buffer_replace (&frame->buffer, NULL); + if (res) { parse->priv->drain = FALSE; + GST_LOG_OBJECT (parse, "valid frame of size %d at pos %d", fsize, skip); break; } parse->priv->drain = FALSE; @@ -2218,8 +2415,11 @@ gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass, if (!parse->priv->discont) parse->priv->sync_offset = parse->priv->offset; parse->priv->discont = TRUE; + /* something changed least; nullify loop check */ + old_min_size = 0; } - /* skip == 0 should imply subclass set min_size to need more data ... */ + /* skip == 0 should imply subclass set min_size to need more data; + * we check this shortly */ GST_DEBUG_OBJECT (parse, "finding sync..."); gst_buffer_unref (buffer); if ((ret = gst_base_parse_check_sync (parse)) != GST_FLOW_OK) { @@ -2227,9 +2427,15 @@ gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass, } } - if (fsize <= GST_BUFFER_SIZE (buffer)) { - outbuf = gst_buffer_create_sub (buffer, 0, fsize); - GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buffer); + /* Does the subclass want to skip too? */ + if (skip > 0) + parse->priv->offset += skip; + else if (skip < 0) + skip = 0; + + if (fsize + skip <= GST_BUFFER_SIZE (buffer)) { + outbuf = gst_buffer_create_sub (buffer, skip, fsize); + GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buffer) + skip; GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE; gst_buffer_unref (buffer); } else { @@ -2245,14 +2451,19 @@ gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass, parse->priv->offset += fsize; - /* Does the subclass want to skip too? */ - if (skip > 0) - parse->priv->offset += skip; - - *buf = outbuf; + frame->buffer = outbuf; done: return ret; + + /* ERRORS */ +invalid_min: + { + GST_ELEMENT_ERROR (parse, STREAM, FAILED, (NULL), + ("min_size evolution %d -> %d; breaking to avoid looping", + old_min_size, min_size)); + return GST_FLOW_ERROR; + } } /** @@ -2266,8 +2477,8 @@ gst_base_parse_loop (GstPad * pad) { GstBaseParse *parse; GstBaseParseClass *klass; - GstBuffer *outbuf; GstFlowReturn ret = GST_FLOW_OK; + GstBaseParseFrame frame = { 0, }; parse = GST_BASE_PARSE (gst_pad_get_parent (pad)); klass = GST_BASE_PARSE_GET_CLASS (parse); @@ -2276,18 +2487,20 @@ gst_base_parse_loop (GstPad * pad) * first fragment (closest to stop time) is handled normally below, * then we pull in fragments going backwards */ if (parse->segment.rate < 0.0) { - if (GST_CLOCK_TIME_IS_VALID (parse->priv->last_ts)) { + /* check if we jumped back to a previous fragment, + * which is a post-first fragment */ + if (parse->priv->offset < 0) { ret = gst_base_parse_handle_previous_fragment (parse); goto done; } } - ret = gst_base_parse_scan_frame (parse, klass, &outbuf, TRUE); + ret = gst_base_parse_scan_frame (parse, klass, &frame, TRUE); if (ret != GST_FLOW_OK) goto done; - /* This always unrefs the outbuf, even if error occurs */ - ret = gst_base_parse_handle_and_push_buffer (parse, klass, outbuf); + /* This always cleans up frame, even if error occurs */ + ret = gst_base_parse_handle_and_push_frame (parse, klass, &frame); /* eat expected eos signalling past segment in reverse playback */ if (parse->segment.rate < 0.0 && ret == GST_FLOW_UNEXPECTED && @@ -2295,6 +2508,8 @@ gst_base_parse_loop (GstPad * pad) GST_DEBUG_OBJECT (parse, "downstream has reached end of segment"); /* push what was accumulated during loop run */ gst_base_parse_process_fragment (parse, TRUE); + /* force previous fragment */ + parse->priv->offset = -1; ret = GST_FLOW_OK; } @@ -2398,7 +2613,7 @@ gst_base_parse_sink_activate (GstPad * sinkpad) /** * gst_base_parse_activate: * @parse: #GstBaseParse. - * @active: TRUE if element will be activated, FALSE if disactivated. + * @active: TRUE if element will be activated, FALSE if deactivated. * * Returns: TRUE if the operation succeeded. */ @@ -2408,7 +2623,7 @@ gst_base_parse_activate (GstBaseParse * parse, gboolean active) GstBaseParseClass *klass; gboolean result = FALSE; - GST_DEBUG_OBJECT (parse, "activate"); + GST_DEBUG_OBJECT (parse, "activate %d", active); klass = GST_BASE_PARSE_GET_CLASS (parse); @@ -2426,7 +2641,7 @@ gst_base_parse_activate (GstBaseParse * parse, gboolean active) parse->priv->pad_mode = GST_ACTIVATE_NONE; } - GST_DEBUG_OBJECT (parse, "activate: %d", result); + GST_DEBUG_OBJECT (parse, "activate return: %d", result); return result; } @@ -2446,14 +2661,14 @@ gst_base_parse_sink_activate_push (GstPad * pad, gboolean active) parse = GST_BASE_PARSE (gst_pad_get_parent (pad)); - GST_DEBUG_OBJECT (parse, "sink activate push"); + GST_DEBUG_OBJECT (parse, "sink activate push %d", active); result = gst_base_parse_activate (parse, active); if (result) parse->priv->pad_mode = active ? GST_ACTIVATE_PUSH : GST_ACTIVATE_NONE; - GST_DEBUG_OBJECT (parse, "sink activate push: %d", result); + GST_DEBUG_OBJECT (parse, "sink activate push return: %d", result); gst_object_unref (parse); return result; @@ -2475,7 +2690,7 @@ gst_base_parse_sink_activate_pull (GstPad * sinkpad, gboolean active) parse = GST_BASE_PARSE (gst_pad_get_parent (sinkpad)); - GST_DEBUG_OBJECT (parse, "activate pull"); + GST_DEBUG_OBJECT (parse, "activate pull %d", active); result = gst_base_parse_activate (parse, active); @@ -2494,7 +2709,7 @@ gst_base_parse_sink_activate_pull (GstPad * sinkpad, gboolean active) if (result) parse->priv->pad_mode = active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE; - GST_DEBUG_OBJECT (parse, "sink activate pull: %d", result); + GST_DEBUG_OBJECT (parse, "sink activate pull return: %d", result); gst_object_unref (parse); return result; @@ -2518,7 +2733,6 @@ gst_base_parse_set_duration (GstBaseParse * parse, { g_return_if_fail (parse != NULL); - GST_BASE_PARSE_LOCK (parse); if (parse->priv->upstream_has_duration) { GST_DEBUG_OBJECT (parse, "using upstream duration; discarding update"); goto exit; @@ -2544,7 +2758,7 @@ gst_base_parse_set_duration (GstBaseParse * parse, GST_DEBUG_OBJECT (parse, "set update interval: %d", interval); parse->priv->update_interval = interval; exit: - GST_BASE_PARSE_UNLOCK (parse); + return; } /** @@ -2566,6 +2780,7 @@ gst_base_parse_set_seek (GstBaseParse * parse, { parse->priv->seekable = seek; parse->priv->bitrate = bitrate; + GST_DEBUG_OBJECT (parse, "seek %d, bitrate %d", seek, bitrate); } @@ -2583,33 +2798,33 @@ gst_base_parse_set_min_frame_size (GstBaseParse * parse, guint min_size) { g_return_if_fail (parse != NULL); - GST_BASE_PARSE_LOCK (parse); parse->priv->min_frame_size = min_size; GST_LOG_OBJECT (parse, "set frame_min_size: %d", min_size); - GST_BASE_PARSE_UNLOCK (parse); } /** - * gst_base_transform_set_passthrough: - * @trans: the #GstBaseParse to set - * @passthrough: boolean indicating passthrough mode. + * gst_base_parse_set_format: + * @parse: the #GstBaseParseFormat to set or unset + * @flags: format flag to enable or disable + * @on: whether or not to enable * - * Set passthrough mode for this parser. If operating in passthrough, - * incoming buffers are pushed through unmodified. + * Set flags describing characteristics of parsed format. */ void -gst_base_parse_set_passthrough (GstBaseParse * parse, gboolean passthrough) +gst_base_parse_set_format (GstBaseParse * parse, GstBaseParseFormat flag, + gboolean on) { g_return_if_fail (parse != NULL); - GST_BASE_PARSE_LOCK (parse); - parse->priv->passthrough = passthrough; - GST_LOG_OBJECT (parse, "set passthrough: %d", passthrough); - GST_BASE_PARSE_UNLOCK (parse); + GST_LOG_OBJECT (parse, "set flag %d to %d", flag, on); + if (on) + parse->priv->format |= flag; + else + parse->priv->format &= ~flag; } /** - * gst_base_transform_set_frame_props: + * gst_base_parse_set_frame_props: * @parse: the #GstBaseParse to set * @fps_num: frames per second (numerator). * @fps_den: frames per second (denominator). @@ -2628,7 +2843,6 @@ gst_base_parse_set_frame_props (GstBaseParse * parse, guint fps_num, { g_return_if_fail (parse != NULL); - GST_BASE_PARSE_LOCK (parse); parse->priv->fps_num = fps_num; parse->priv->fps_den = fps_den; if (!fps_num || !fps_den) { @@ -2647,6 +2861,12 @@ gst_base_parse_set_frame_props (GstBaseParse * parse, guint fps_num, gst_util_uint64_scale (GST_SECOND, fps_den * lead_in, fps_num); parse->priv->lead_out_ts = gst_util_uint64_scale (GST_SECOND, fps_den * lead_out, fps_num); + /* aim for about 1.5s to estimate duration */ + if (parse->priv->update_interval < 0) { + parse->priv->update_interval = fps_num * 3 / (fps_den * 2); + GST_LOG_OBJECT (parse, "estimated update interval to %d frames", + parse->priv->update_interval); + } } GST_LOG_OBJECT (parse, "set fps: %d/%d => duration: %" G_GINT64_FORMAT " ms", fps_num, fps_den, parse->priv->frame_duration / GST_MSECOND); @@ -2654,53 +2874,6 @@ gst_base_parse_set_frame_props (GstBaseParse * parse, guint fps_num, "lead out: %d frames = %" G_GUINT64_FORMAT " ms", lead_in, parse->priv->lead_in_ts / GST_MSECOND, lead_out, parse->priv->lead_out_ts / GST_MSECOND); - GST_BASE_PARSE_UNLOCK (parse); -} - -/** - * gst_base_transform_get_sync: - * @parse: the #GstBaseParse to query - * - * Returns: TRUE if parser is considered 'in sync'. That is, frames have been - * continuously successfully parsed and pushed. - */ -gboolean -gst_base_parse_get_sync (GstBaseParse * parse) -{ - gboolean ret; - - g_return_val_if_fail (parse != NULL, FALSE); - - GST_BASE_PARSE_LOCK (parse); - /* losing sync is pretty much a discont (and vice versa), no ? */ - ret = !parse->priv->discont; - GST_BASE_PARSE_UNLOCK (parse); - - GST_DEBUG_OBJECT (parse, "sync: %d", ret); - return ret; -} - -/** - * gst_base_transform_get_drain: - * @parse: the #GstBaseParse to query - * - * Returns: TRUE if parser is currently 'draining'. That is, leftover data - * (e.g. in FLUSH or EOS situation) is being parsed. - */ -gboolean -gst_base_parse_get_drain (GstBaseParse * parse) -{ - gboolean ret; - - g_return_val_if_fail (parse != NULL, FALSE); - - GST_BASE_PARSE_LOCK (parse); - /* losing sync is pretty much a discont (and vice versa), no ? */ - ret = parse->priv->drain; - GST_BASE_PARSE_UNLOCK (parse); - - GST_DEBUG_OBJECT (parse, "drain: %d", ret); - return ret; } static gboolean @@ -2779,7 +2952,7 @@ gst_base_parse_query (GstPad * pad, GstQuery * query) GST_DEBUG_OBJECT (parse, "position query"); gst_query_parse_position (query, &format, NULL); - g_mutex_lock (parse->parse_lock); + GST_OBJECT_LOCK (parse); if (format == GST_FORMAT_BYTES) { dest_value = parse->priv->offset; res = TRUE; @@ -2788,7 +2961,7 @@ gst_base_parse_query (GstPad * pad, GstQuery * query) dest_value = parse->segment.last_stop; res = TRUE; } - g_mutex_unlock (parse->parse_lock); + GST_OBJECT_UNLOCK (parse); if (res) gst_query_set_position (query, format, dest_value); @@ -2797,10 +2970,8 @@ gst_base_parse_query (GstPad * pad, GstQuery * query) if (!res) { /* no precise result, upstream no idea either, then best estimate */ /* priv->offset is updated in both PUSH/PULL modes */ - g_mutex_lock (parse->parse_lock); res = gst_base_parse_convert (parse, GST_FORMAT_BYTES, parse->priv->offset, format, &dest_value); - g_mutex_unlock (parse->parse_lock); } } break; @@ -2818,9 +2989,7 @@ gst_base_parse_query (GstPad * pad, GstQuery * query) /* otherwise best estimate from us */ if (!res) { - g_mutex_lock (parse->parse_lock); res = gst_base_parse_get_duration (parse, format, &duration); - g_mutex_unlock (parse->parse_lock); if (res) gst_query_set_duration (query, format, duration); } @@ -2848,7 +3017,9 @@ gst_base_parse_query (GstPad * pad, GstQuery * query) if (!(res && seekable)) { if (!gst_base_parse_get_duration (parse, GST_FORMAT_TIME, &duration) || duration == -1) { - seekable = FALSE; + /* seekable if we still have a chance to get duration later on */ + seekable = + parse->priv->upstream_seekable && parse->priv->update_interval; } else { seekable = parse->priv->upstream_seekable; GST_LOG_OBJECT (parse, "already determine upstream seekabled: %d", @@ -2898,6 +3069,7 @@ gst_base_parse_find_frame (GstBaseParse * parse, gint64 * pos, gboolean orig_drain, orig_discont; GstFlowReturn ret = GST_FLOW_OK; GstBuffer *buf = NULL; + GstBaseParseFrame frame = { 0, }; g_return_val_if_fail (GST_FLOW_ERROR, pos != NULL); g_return_val_if_fail (GST_FLOW_ERROR, time != NULL); @@ -2918,10 +3090,11 @@ gst_base_parse_find_frame (GstBaseParse * parse, gint64 * pos, /* jump elsewhere and locate next frame */ parse->priv->offset = *pos; - ret = gst_base_parse_scan_frame (parse, klass, &buf, FALSE); + ret = gst_base_parse_scan_frame (parse, klass, &frame, FALSE); if (ret != GST_FLOW_OK) goto done; + buf = frame.buffer; GST_LOG_OBJECT (parse, "peek parsing frame at offset %" G_GUINT64_FORMAT " (%#" G_GINT64_MODIFIER "x) of size %d", @@ -2929,12 +3102,13 @@ gst_base_parse_find_frame (GstBaseParse * parse, gint64 * pos, /* get offset first, subclass parsing might dump other stuff in there */ *pos = GST_BUFFER_OFFSET (buf); - ret = klass->parse_frame (parse, buf); + ret = klass->parse_frame (parse, &frame); + buf = frame.buffer; /* but it should provide proper time */ *time = GST_BUFFER_TIMESTAMP (buf); *duration = GST_BUFFER_DURATION (buf); - gst_buffer_unref (buf); + gst_base_parse_frame_clear (parse, &frame); GST_LOG_OBJECT (parse, "frame with time %" GST_TIME_FORMAT " at offset %" G_GINT64_FORMAT, @@ -3027,6 +3201,7 @@ gst_base_parse_locate_time (GstBaseParse * parse, GstClockTime * _time, gst_util_uint64_scale (hpos - lpos, time - ltime, htime - ltime) + lpos - chunk; } else { + /* should mean lpos == hpos, since lpos <= hpos is invariant */ newpos = lpos; /* we check this case once, but not forever, so break loop */ cont = FALSE; @@ -3060,8 +3235,7 @@ gst_base_parse_locate_time (GstBaseParse * parse, GstClockTime * _time, break; } else if (newtime > time) { /* overshoot */ - newpos -= newpos == hpos ? chunk : 0; - hpos = CLAMP (newpos, lpos, hpos); + hpos = (newpos >= hpos) ? MAX (lpos, hpos - chunk) : MAX (lpos, newpos); htime = newtime; } else if (newtime + tolerance > time) { /* close enough undershoot */ @@ -3071,9 +3245,10 @@ gst_base_parse_locate_time (GstBaseParse * parse, GstClockTime * _time, } else if (newtime < ltime) { /* so a position beyond lpos resulted in earlier time than ltime ... */ GST_DEBUG_OBJECT (parse, "non-ascending time; aborting"); + break; } else { /* undershoot too far */ - newpos += newpos == hpos ? chunk : 0; + newpos += newpos == lpos ? chunk : 0; lpos = CLAMP (newpos, lpos, hpos); ltime = newtime; } @@ -3173,11 +3348,12 @@ gst_base_parse_handle_seek (GstBaseParse * parse, GstEvent * event) * it fails upstream */ if (format != GST_FORMAT_TIME) { /* default action delegates to upstream */ - return FALSE; + res = FALSE; + goto done; } else { gst_event_ref (event); - if (gst_pad_push_event (parse->sinkpad, event)) { - return TRUE; + if ((res = gst_pad_push_event (parse->sinkpad, event))) { + goto done; } } @@ -3339,6 +3515,9 @@ gst_base_parse_handle_seek (GstBaseParse * parse, GstEvent * event) (GstTaskFunction) gst_base_parse_loop, parse->sinkpad); GST_PAD_STREAM_UNLOCK (parse->sinkpad); + + /* handled seek */ + res = TRUE; } else { GstEvent *new_event; GstBaseParseSeek *seek; @@ -3379,12 +3558,15 @@ gst_base_parse_handle_seek (GstBaseParse * parse, GstEvent * event) } done: + /* handled event is ours to free */ + if (res) + gst_event_unref (event); return res; /* ERRORS */ negative_rate: { - GST_DEBUG_OBJECT (parse, "negative playback rates are not supported yet."); + GST_DEBUG_OBJECT (parse, "negative playback rates delegated upstream."); res = FALSE; goto done; } @@ -3454,7 +3636,7 @@ gst_base_parse_sink_setcaps (GstPad * pad, GstCaps * caps) if (klass->set_sink_caps) res = klass->set_sink_caps (parse, caps); - return res && gst_pad_set_caps (pad, caps); + return res; } static void diff --git a/gst/audioparsers/gstbaseparse.h b/gst-libs/gst/baseparse/gstbaseparse.h index 27547a992..d0f43ee7c 100644 --- a/gst/audioparsers/gstbaseparse.h +++ b/gst-libs/gst/baseparse/gstbaseparse.h @@ -46,7 +46,7 @@ G_BEGIN_DECLS * * the name of the templates for the source pad */ -#define GST_BASE_PARSE_SRC_NAME "src" +#define GST_BASE_PARSE_SRC_NAME "src" /** * GST_BASE_PARSE_SRC_PAD: @@ -56,7 +56,7 @@ G_BEGIN_DECLS * * Since: 0.10.x */ -#define GST_BASE_PARSE_SRC_PAD(obj) (GST_BASE_PARSE_CAST (obj)->srcpad) +#define GST_BASE_PARSE_SRC_PAD(obj) (GST_BASE_PARSE_CAST (obj)->srcpad) /** * GST_BASE_PARSE_SINK_PAD: @@ -87,57 +87,113 @@ G_BEGIN_DECLS * * Since: 0.10.x */ -#define GST_BASE_PARSE_FLOW_DROPPED GST_FLOW_CUSTOM_SUCCESS +#define GST_BASE_PARSE_FLOW_DROPPED GST_FLOW_CUSTOM_SUCCESS /** - * GST_BASE_PARSE_FLOW_CLIP: + * GstBaseParseFrameFlags: + * @GST_BASE_PARSE_FRAME_FLAG_NONE: no flag + * @GST_BASE_PARSE_FRAME_FLAG_SYNC: indicates if parsing is 'in sync' + * @GST_BASE_PARSE_FRAME_FLAG_DRAIN: indicates if parser is 'draining'. + * That is, leftover data (e.g. in FLUSH or EOS situation) is being parsed. + * @GST_BASE_PARSE_FRAME_FLAG_NO_FRAME: set to indicate this buffer should not be + * counted as frame, e.g. if this frame is dependent on a previous one. + * As it is not counted as a frame, bitrate increases but frame to time + * conversions are maintained. + * @GST_BASE_PARSE_FRAME_FLAG_CLIP: @pre_push_buffer can set this to indicate + * that regular segment clipping can still be performed (as opposed to + * any custom one having been done). * - * A #GstFlowReturn that can be returned from pre_push_buffer to - * indicate that regular segment clipping should be performed. + * Flags to be used in a #GstBaseParseFrame. * * Since: 0.10.x */ -#define GST_BASE_PARSE_FLOW_CLIP GST_FLOW_CUSTOM_SUCCESS_1 +typedef enum { + GST_BASE_PARSE_FRAME_FLAG_NONE = 0, + GST_BASE_PARSE_FRAME_FLAG_SYNC = (1 << 0), + GST_BASE_PARSE_FRAME_FLAG_DRAIN = (1 << 1), + GST_BASE_PARSE_FRAME_FLAG_NO_FRAME = (1 << 2), + GST_BASE_PARSE_FRAME_FLAG_CLIP = (1 << 3) +} GstBaseParseFrameFlags; /** - * GST_BASE_PARSE_BUFFER_FLAG_NO_FRAME: + * GstBaseParseFrame: + * @buffer: data to check for valid frame or parsed frame. + * Subclass is allowed to replace this buffer. + * @overhead: subclass can set this to indicates the metadata overhead + * for the given frame, which is then used to enable more accurate bitrate + * computations. If this is -1, it is assumed that this frame should be + * skipped in bitrate calculation. + * @flags: a combination of input and output #GstBaseParseFrameFlags that + * convey additional context to subclass or allow subclass to tune + * subsequent #GstBaseParse actions. * - * A #GstBufferFlag that can be set to have this buffer not counted as frame, - * e.g. if this frame is dependent on a previous one. As it is not counted as - * a frame, bitrate increases but frame to time conversions are maintained. + * Frame (context) data passed to each frame parsing virtual methods. In + * addition to providing the data to be checked for a valid frame or an already + * identified frame, it conveys additional metadata or control information + * from and to the subclass w.r.t. the particular frame in question (rather + * than global parameters). Some of these may apply to each parsing stage, others + * only to some a particular one. These parameters are effectively zeroed at start + * of each frame's processing, i.e. parsing virtual method invocation sequence. * * Since: 0.10.x */ -#define GST_BASE_PARSE_BUFFER_FLAG_NO_FRAME GST_BUFFER_FLAG_LAST +typedef struct { + GstBuffer *buffer; + guint flags; + gint overhead; +} GstBaseParseFrame; /** - * GST_BASE_PARSE_LOCK: - * @obj: base parse instance + * GST_BASE_PARSE_FRAME_SYNC: + * @frame: base parse frame instance * - * Obtain a lock to protect the parse function from concurrent access. + * Obtains current sync status indicated in frame. * * Since: 0.10.x */ -#define GST_BASE_PARSE_LOCK(obj) g_mutex_lock (GST_BASE_PARSE_CAST (obj)->parse_lock) +#define GST_BASE_PARSE_FRAME_SYNC(frame) (!!(frame->flags & GST_BASE_PARSE_FRAME_FLAG_SYNC)) /** - * GST_BASE_PARSE_UNLOCK: - * @obj: base parse instance + * GST_BASE_PARSE_FRAME_DRAIN: + * @frame: base parse frame instance * - * Release the lock that protects the parse function from concurrent access. + * Obtains current drain status indicated in frame. * * Since: 0.10.x */ -#define GST_BASE_PARSE_UNLOCK(obj) g_mutex_unlock (GST_BASE_PARSE_CAST (obj)->parse_lock) +#define GST_BASE_PARSE_FRAME_DRAIN(frame) (!!(frame->flags & GST_BASE_PARSE_FRAME_FLAG_DRAIN)) +/** + * GstBaseParseFormat: + * @GST_BASE_PARSE_FORMAT_NONE: default setting + * @GST_BASE_PARSE_FORMAT_PASSTHROUGH: nature of format or configuration + * does not allow (much) parsing, so parser should operate in passthrough mode + * (which only applies operating in pull mode). That is, incoming buffers + * are pushed through unmodified, i.e. no @check_valid_frame or @parse_frame + * callbacks will be invoked. On the other hand, @pre_push_buffer is still invoked, + * where subclass can perform as much or as little is appropriate for + * "passthrough" semantics. + * @GST_BASE_PARSE_FORMAT_HAS_TIME: frames carry timing info which subclass + * can (generally) parse and provide. In particular, intrinsic time + * (rather than estimated) can be obtained following seek. + * + * Since: 0.10.x + */ +typedef enum _GstBaseParseFormat { + GST_BASE_PARSE_FORMAT_NONE = 0, + GST_BASE_PARSE_FORMAT_PASSTHROUGH = (1 << 0), + GST_BASE_PARSE_FORMAT_HAS_TIME = (1 << 1), +} GstBaseParseFormat; /** * GstBaseParseSeekable: * @GST_BASE_PARSE_SEEK_NONE: No seeking possible. - * GST_BASE_PARSE_SEEK_DEFAULT: Default seeking possible using estimated bitrate. - * GST_BASE_PARSE_SEEK_TABLE: Additional metadata provides more accurate seeking. + * @GST_BASE_PARSE_SEEK_DEFAULT: Default seeking possible using estimated bitrate. + * @GST_BASE_PARSE_SEEK_TABLE: Additional metadata provides more accurate seeking. * * Indicates what level (of quality) of seeking is possible. + * + * Since: 0.10.x */ typedef enum _GstBaseParseSeekable { GST_BASE_PARSE_SEEK_NONE, @@ -173,8 +229,6 @@ struct _GstBaseParse { /* Segment event that closes the running segment prior to SEEK */ GstEvent *close_segment; - GMutex *parse_lock; - /*< private >*/ gpointer _gst_reserved[GST_PADDING_LARGE]; GstBaseParsePrivate *priv; @@ -197,14 +251,6 @@ struct _GstBaseParse { * STREAM_LOCK held. * @convert: Optional. * Convert between formats. - * @find_frame: Optional. - * Finds a frame. Gets a position passed and should return - * TRUE and the offset in bytes where this position is. - * Will only be called in pull mode and the subclass can pull - * whatever it wants from upstream. If not implemented, - * the base class will implement it by calling - * @check_valid_frame and @parse_frame to find the wanted - * frame and build a seek table. * @event: Optional. * Event handler on the sink pad. This function should return * TRUE if the event was handled and can be dropped. @@ -212,17 +258,11 @@ struct _GstBaseParse { * Event handler on the source pad. Should return TRUE * if the event was handled and can be dropped. * - * @get_frame_overhead: Finds the metadata overhead for the given frame. This - * is used to enable more accurate bitrate computations. - * If NULL, the per-frame overhead is assumed to be 0. If - * this returns -1, it is assumed that this frame should - * be skipped in bitrate calculation. - * - * @pre_push_buffer: Optional. + * @pre_push_frame: Optional. * Called just prior to pushing a frame (after any pending * events have been sent) to give subclass a chance to perform * additional actions at this time (e.g. tag sending) or to - * decide whether this buffer should be dropped or no + * decide whether this buffer should be dropped or not * (e.g. custom segment clipping). * * Subclasses can override any of the available virtual methods or not, as @@ -243,12 +283,15 @@ struct _GstBaseParseClass { GstCaps *caps); gboolean (*check_valid_frame) (GstBaseParse *parse, - GstBuffer *buffer, + GstBaseParseFrame *frame, guint *framesize, gint *skipsize); GstFlowReturn (*parse_frame) (GstBaseParse *parse, - GstBuffer *buffer); + GstBaseParseFrame *frame); + + GstFlowReturn (*pre_push_frame) (GstBaseParse *parse, + GstBaseParseFrame *frame); gboolean (*convert) (GstBaseParse * parse, GstFormat src_format, @@ -256,56 +299,45 @@ struct _GstBaseParseClass { GstFormat dest_format, gint64 * dest_value); - gboolean (*find_frame) (GstBaseParse *parse, - GstFormat src_format, - gint64 src_value, - gint64 * dest_value); - gboolean (*event) (GstBaseParse *parse, GstEvent *event); gboolean (*src_event) (GstBaseParse *parse, GstEvent *event); - gint (*get_frame_overhead) (GstBaseParse *parse, - GstBuffer *buf); - - GstFlowReturn (*pre_push_buffer) (GstBaseParse *parse, - GstBuffer *buf); - /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE]; + gpointer _gst_reserved[GST_PADDING_LARGE]; }; GType gst_base_parse_get_type (void); - -GstFlowReturn gst_base_parse_push_buffer (GstBaseParse *parse, - GstBuffer *buffer); - -void gst_base_parse_set_duration (GstBaseParse *parse, - GstFormat fmt, gint64 duration, gint interval); - -void gst_base_parse_set_seek (GstBaseParse * parse, - GstBaseParseSeekable seek, guint bitrate); - -void gst_base_parse_set_min_frame_size (GstBaseParse *parse, - guint min_size); -void gst_base_parse_set_passthrough (GstBaseParse * parse, gboolean passthrough); - -void gst_base_parse_set_frame_props (GstBaseParse * parse, guint fps_num, - guint fps_den, guint lead_in, guint lead_out); - -gboolean gst_base_parse_get_sync (GstBaseParse * parse); - -gboolean gst_base_parse_get_drain (GstBaseParse * parse); - -gboolean gst_base_parse_convert_default (GstBaseParse * parse, - GstFormat src_format, gint64 src_value, - GstFormat dest_format, gint64 * dest_value); - -gboolean gst_base_parse_add_index_entry (GstBaseParse * parse, guint64 offset, - GstClockTime ts, gboolean key, gboolean force); +void gst_base_parse_frame_init (GstBaseParse * parse, + GstBaseParseFrame * frame); +GstFlowReturn gst_base_parse_push_frame (GstBaseParse *parse, + GstBaseParseFrame *frame); + +void gst_base_parse_set_duration (GstBaseParse *parse, + GstFormat fmt, gint64 duration, + gint interval); +void gst_base_parse_set_seek (GstBaseParse * parse, + GstBaseParseSeekable seek, + guint bitrate); +void gst_base_parse_set_min_frame_size (GstBaseParse *parse, + guint min_size); +void gst_base_parse_set_format (GstBaseParse * parse, + GstBaseParseFormat flag, + gboolean on); +void gst_base_parse_set_frame_props (GstBaseParse * parse, + guint fps_num, guint fps_den, + guint lead_in, guint lead_out); + +gboolean gst_base_parse_convert_default (GstBaseParse * parse, + GstFormat src_format, gint64 src_value, + GstFormat dest_format, gint64 * dest_value); + +gboolean gst_base_parse_add_index_entry (GstBaseParse * parse, + guint64 offset, GstClockTime ts, + gboolean key, gboolean force); G_END_DECLS diff --git a/gst-libs/gst/interfaces/photography.c b/gst-libs/gst/interfaces/photography.c index 6fcf0d9c6..878b185eb 100644 --- a/gst-libs/gst/interfaces/photography.c +++ b/gst-libs/gst/interfaces/photography.c @@ -313,7 +313,7 @@ GST_PHOTOGRAPHY_FUNC_TEMPLATE (flash_mode, GstFlashMode); * * Since: 0.10.21 */ -GST_PHOTOGRAPHY_FUNC_TEMPLATE (noise_reduction, guint); +GST_PHOTOGRAPHY_FUNC_TEMPLATE (noise_reduction, GstPhotographyNoiseReduction); /** * gst_photography_set_zoom: @@ -613,4 +613,12 @@ gst_photography_iface_class_init (gpointer g_class) "Zoom property", "How much the resulted image will be zoomed", 1.0f, 10.0f, 1.0f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /* Noise Reduction, Bayer an YCC noise reduction are enabled by default */ + g_object_interface_install_property (g_class, + g_param_spec_flags (GST_PHOTOGRAPHY_PROP_NOISE_REDUCTION, + "Noise Reduction settings", + "Which noise reduction modes are enabled (0 = disabled)", + GST_TYPE_PHOTOGRAPHY_NOISE_REDUCTION, + 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } diff --git a/gst-libs/gst/interfaces/photography.h b/gst-libs/gst/interfaces/photography.h index 0198788fd..ce8fea923 100644 --- a/gst-libs/gst/interfaces/photography.h +++ b/gst-libs/gst/interfaces/photography.h @@ -174,7 +174,8 @@ typedef enum GST_PHOTOGRAPHY_CAPS_FOCUS = (1 << 7), GST_PHOTOGRAPHY_CAPS_APERTURE = (1 << 8), GST_PHOTOGRAPHY_CAPS_EXPOSURE = (1 << 9), - GST_PHOTOGRAPHY_CAPS_SHAKE = (1 << 10) + GST_PHOTOGRAPHY_CAPS_SHAKE = (1 << 10), + GST_PHOTOGRAPHY_CAPS_NOISE_REDUCTION = (1 << 11) } GstPhotoCaps; typedef enum @@ -216,7 +217,7 @@ typedef struct gfloat zoom; GstFlickerReductionMode flicker_mode; GstFocusMode focus_mode; - guint noise_reduction; + GstPhotographyNoiseReduction noise_reduction; } GstPhotoSettings; /** @@ -340,7 +341,7 @@ gboolean gst_photography_get_scene_mode (GstPhotography * photo, gboolean gst_photography_get_flash_mode (GstPhotography * photo, GstFlashMode * flash_mode); gboolean gst_photography_get_noise_reduction (GstPhotography * photo, - guint * noise_reduction); + GstPhotographyNoiseReduction * noise_reduction); gboolean gst_photography_get_zoom (GstPhotography * photo, gfloat * zoom); gboolean gst_photography_get_flicker_mode (GstPhotography * photo, GstFlickerReductionMode *mode); @@ -362,7 +363,7 @@ gboolean gst_photography_set_scene_mode (GstPhotography * photo, gboolean gst_photography_set_flash_mode (GstPhotography * photo, GstFlashMode flash_mode); gboolean gst_photography_set_noise_reduction (GstPhotography * photo, - guint noise_reduction); + GstPhotographyNoiseReduction noise_reduction); gboolean gst_photography_set_zoom (GstPhotography * photo, gfloat zoom); gboolean gst_photography_set_flicker_mode (GstPhotography * photo, GstFlickerReductionMode mode); diff --git a/gst-libs/gst/signalprocessor/gstsignalprocessor.c b/gst-libs/gst/signalprocessor/gstsignalprocessor.c index 45a4dd21a..2cd33a42e 100644 --- a/gst-libs/gst/signalprocessor/gstsignalprocessor.c +++ b/gst-libs/gst/signalprocessor/gstsignalprocessor.c @@ -115,6 +115,8 @@ gst_signal_processor_class_add_pad_template (GstSignalProcessorClass * klass, "name", name, "name-template", name, "direction", direction, "presence", GST_PAD_ALWAYS, "caps", caps, NULL); + gst_caps_unref (caps); + GST_SIGNAL_PROCESSOR_PAD_TEMPLATE (new)->index = index; GST_SIGNAL_PROCESSOR_PAD_TEMPLATE (new)->channels = channels; diff --git a/gst-libs/gst/video/Makefile.am b/gst-libs/gst/video/Makefile.am index 5072f1df6..a0c4026ec 100644 --- a/gst-libs/gst/video/Makefile.am +++ b/gst-libs/gst/video/Makefile.am @@ -7,16 +7,14 @@ libgstbasevideo_@GST_MAJORMINOR@_la_SOURCES = \ gstbasevideoutils.c \ gstbasevideocodec.c \ gstbasevideodecoder.c \ - gstbasevideoencoder.c \ - gstbasevideoparse.c + gstbasevideoencoder.c libgstbasevideo_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/video libgstbasevideo_@GST_MAJORMINOR@include_HEADERS = \ gstbasevideoutils.h \ gstbasevideocodec.h \ gstbasevideodecoder.h \ - gstbasevideoencoder.h \ - gstbasevideoparse.h + gstbasevideoencoder.h libgstbasevideo_@GST_MAJORMINOR@_la_CFLAGS = \ $(GST_PLUGINS_BAD_CFLAGS) \ diff --git a/gst-libs/gst/video/gstbasevideodecoder.c b/gst-libs/gst/video/gstbasevideodecoder.c index bcad36717..eba17a4ca 100644 --- a/gst-libs/gst/video/gstbasevideodecoder.c +++ b/gst-libs/gst/video/gstbasevideodecoder.c @@ -319,7 +319,7 @@ gst_base_video_decoder_src_event (GstPad * pad, GstEvent * event) GstSeekFlags flags; GstSeekType cur_type, stop_type; gint64 cur, stop; - gint64 tcur, tstop; + gint64 tcur = -1, tstop = -1; GST_DEBUG ("seek event"); diff --git a/gst-libs/gst/video/gstbasevideoparse.c b/gst-libs/gst/video/gstbasevideoparse.c deleted file mode 100644 index e200838a0..000000000 --- a/gst-libs/gst/video/gstbasevideoparse.c +++ /dev/null @@ -1,862 +0,0 @@ -/* Schrodinger - * Copyright (C) 2006 David Schleef <ds@schleef.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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstbasevideoparse.h" - -#include <string.h> -#include <math.h> - -GST_DEBUG_CATEGORY (basevideoparse_debug); -#define GST_CAT_DEFAULT basevideoparse_debug - - - -/* GstBaseVideoParse signals and args */ -enum -{ - LAST_SIGNAL -}; - -enum -{ - ARG_0 -}; - -static void gst_base_video_parse_finalize (GObject * object); - -static const GstQueryType *gst_base_video_parse_get_query_types (GstPad * pad); -static gboolean gst_base_video_parse_src_query (GstPad * pad, GstQuery * query); -static gboolean gst_base_video_parse_sink_query (GstPad * pad, - GstQuery * query); -static gboolean gst_base_video_parse_src_event (GstPad * pad, GstEvent * event); -static gboolean gst_base_video_parse_sink_event (GstPad * pad, - GstEvent * event); -static GstStateChangeReturn gst_base_video_parse_change_state (GstElement * - element, GstStateChange transition); -static GstFlowReturn gst_base_video_parse_push_all (GstBaseVideoParse * - base_video_parse, gboolean at_eos); -static GstFlowReturn gst_base_video_parse_chain (GstPad * pad, GstBuffer * buf); -static void gst_base_video_parse_free_frame (GstVideoFrame * frame); -static GstVideoFrame *gst_base_video_parse_new_frame (GstBaseVideoParse * - base_video_parse); - - -GST_BOILERPLATE (GstBaseVideoParse, gst_base_video_parse, - GstBaseVideoCodec, GST_TYPE_BASE_VIDEO_CODEC); - -static void -gst_base_video_parse_base_init (gpointer g_class) -{ - GST_DEBUG_CATEGORY_INIT (basevideoparse_debug, "basevideoparse", 0, - "Base Video Parse"); - - -} - -static void -gst_base_video_parse_class_init (GstBaseVideoParseClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *element_class; - - gobject_class = G_OBJECT_CLASS (klass); - element_class = GST_ELEMENT_CLASS (klass); - - gobject_class->finalize = gst_base_video_parse_finalize; - - element_class->change_state = gst_base_video_parse_change_state; -} - -static void -gst_base_video_parse_init (GstBaseVideoParse * base_video_parse, - GstBaseVideoParseClass * klass) -{ - GstPad *pad; - - GST_DEBUG ("gst_base_video_parse_init"); - - pad = GST_BASE_VIDEO_CODEC_SINK_PAD (base_video_parse); - - gst_pad_set_chain_function (pad, gst_base_video_parse_chain); - gst_pad_set_query_function (pad, gst_base_video_parse_sink_query); - gst_pad_set_event_function (pad, gst_base_video_parse_sink_event); - - pad = GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_parse); - - gst_pad_set_query_type_function (pad, gst_base_video_parse_get_query_types); - gst_pad_set_query_function (pad, gst_base_video_parse_src_query); - gst_pad_set_event_function (pad, gst_base_video_parse_src_event); - - base_video_parse->input_adapter = gst_adapter_new (); - base_video_parse->output_adapter = gst_adapter_new (); - - base_video_parse->reorder_depth = 1; - - base_video_parse->current_frame = - gst_base_video_parse_new_frame (base_video_parse); -} - -static void -gst_base_video_parse_reset (GstBaseVideoParse * base_video_parse) -{ - GST_DEBUG ("reset"); - - base_video_parse->discont = TRUE; - base_video_parse->have_sync = FALSE; - - base_video_parse->system_frame_number = 0; - base_video_parse->presentation_frame_number = 0; - - if (base_video_parse->caps) { - gst_caps_unref (base_video_parse->caps); - base_video_parse->caps = NULL; - } - - gst_segment_init (&base_video_parse->segment, GST_FORMAT_TIME); - gst_adapter_clear (base_video_parse->input_adapter); - gst_adapter_clear (base_video_parse->output_adapter); - - if (base_video_parse->current_frame) { - gst_base_video_parse_free_frame (base_video_parse->current_frame); - } - base_video_parse->current_frame = - gst_base_video_parse_new_frame (base_video_parse); - -} - -static void -gst_base_video_parse_finalize (GObject * object) -{ - GstBaseVideoParse *base_video_parse; - - g_return_if_fail (GST_IS_BASE_VIDEO_PARSE (object)); - base_video_parse = GST_BASE_VIDEO_PARSE (object); - - if (base_video_parse->input_adapter) { - g_object_unref (base_video_parse->input_adapter); - } - if (base_video_parse->output_adapter) { - g_object_unref (base_video_parse->output_adapter); - } - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static const GstQueryType * -gst_base_video_parse_get_query_types (GstPad * pad) -{ - static const GstQueryType query_types[] = { - GST_QUERY_POSITION, - GST_QUERY_DURATION, - GST_QUERY_CONVERT, - 0 - }; - - return query_types; -} - -#if 0 -static gboolean -gst_base_video_parse_src_convert (GstPad * pad, - GstFormat src_format, gint64 src_value, - GstFormat * dest_format, gint64 * dest_value) -{ - gboolean res; - GstBaseVideoParse *dec; - - if (src_format == *dest_format) { - *dest_value = src_value; - return TRUE; - } - - dec = GST_BASE_VIDEO_PARSE (gst_pad_get_parent (pad)); - - if (src_format == GST_FORMAT_DEFAULT && *dest_format == GST_FORMAT_TIME) { - if (dec->fps_d != 0) { - *dest_value = gst_util_uint64_scale (granulepos_to_frame (src_value), - dec->fps_d * GST_SECOND, dec->fps_n); - res = TRUE; - } else { - res = FALSE; - } - } else { - GST_WARNING ("unhandled conversion from %d to %d", src_format, - *dest_format); - res = FALSE; - } - - gst_object_unref (dec); - - return res; -} - -static gboolean -gst_base_video_parse_sink_convert (GstPad * pad, - GstFormat src_format, gint64 src_value, - GstFormat * dest_format, gint64 * dest_value) -{ - gboolean res = TRUE; - GstBaseVideoParse *dec; - - if (src_format == *dest_format) { - *dest_value = src_value; - return TRUE; - } - - dec = GST_BASE_VIDEO_PARSE (gst_pad_get_parent (pad)); - - /* FIXME: check if we are in a decoding state */ - - switch (src_format) { - case GST_FORMAT_DEFAULT: - switch (*dest_format) { - case GST_FORMAT_TIME: - *dest_value = gst_util_uint64_scale (src_value, - dec->fps_d * GST_SECOND, dec->fps_n); - break; - default: - res = FALSE; - } - break; - case GST_FORMAT_TIME: - switch (*dest_format) { - case GST_FORMAT_DEFAULT: - { - *dest_value = gst_util_uint64_scale (src_value, - dec->fps_n, dec->fps_d * GST_SECOND); - break; - } - default: - res = FALSE; - break; - } - break; - default: - res = FALSE; - break; - } - - gst_object_unref (dec); - - return res; -} -#endif - -static gboolean -gst_base_video_parse_src_query (GstPad * pad, GstQuery * query) -{ - GstBaseVideoParse *base_parse; - gboolean res = FALSE; - - base_parse = GST_BASE_VIDEO_PARSE (gst_pad_get_parent (pad)); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_POSITION: - { - GstFormat format; - gint64 time; - gint64 value; - - gst_query_parse_position (query, &format, NULL); - - time = gst_util_uint64_scale (base_parse->presentation_frame_number, - base_parse->state.fps_n, base_parse->state.fps_d); - time += base_parse->segment.time; - GST_DEBUG ("query position %" GST_TIME_FORMAT, GST_TIME_ARGS (time)); - res = gst_base_video_encoded_video_convert (&base_parse->state, - GST_FORMAT_TIME, time, &format, &value); - if (!res) - goto error; - - gst_query_set_position (query, format, value); - break; - } - case GST_QUERY_DURATION: - res = - gst_pad_query (GST_PAD_PEER (GST_BASE_VIDEO_CODEC_SINK_PAD - (base_parse)), query); - if (!res) - goto error; - break; - case GST_QUERY_CONVERT: - { - GstFormat src_fmt, dest_fmt; - gint64 src_val, dest_val; - - GST_WARNING ("query convert"); - - gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); - res = gst_base_video_encoded_video_convert (&base_parse->state, - src_fmt, src_val, &dest_fmt, &dest_val); - if (!res) - goto error; - gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); - break; - } - default: - res = gst_pad_query_default (pad, query); - break; - } -done: - gst_object_unref (base_parse); - - return res; -error: - GST_DEBUG_OBJECT (base_parse, "query failed"); - goto done; -} - -static gboolean -gst_base_video_parse_sink_query (GstPad * pad, GstQuery * query) -{ - GstBaseVideoParse *base_video_parse; - gboolean res = FALSE; - - base_video_parse = GST_BASE_VIDEO_PARSE (gst_pad_get_parent (pad)); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_CONVERT: - { - GstFormat src_fmt, dest_fmt; - gint64 src_val, dest_val; - - gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); - res = gst_base_video_encoded_video_convert (&base_video_parse->state, - src_fmt, src_val, &dest_fmt, &dest_val); - if (!res) - goto error; - gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); - break; - } - default: - res = gst_pad_query_default (pad, query); - break; - } -done: - gst_object_unref (base_video_parse); - - return res; -error: - GST_DEBUG_OBJECT (base_video_parse, "query failed"); - goto done; -} - -static gboolean -gst_base_video_parse_src_event (GstPad * pad, GstEvent * event) -{ - GstBaseVideoParse *base_video_parse; - gboolean res = FALSE; - - base_video_parse = GST_BASE_VIDEO_PARSE (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_SEEK: - { - GstFormat format, tformat; - gdouble rate; - GstEvent *real_seek; - GstSeekFlags flags; - GstSeekType cur_type, stop_type; - gint64 cur, stop; - gint64 tcur, tstop; - - gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, - &cur, &stop_type, &stop); - gst_event_unref (event); - - tformat = GST_FORMAT_TIME; - res = gst_base_video_encoded_video_convert (&base_video_parse->state, - format, cur, &tformat, &tcur); - if (!res) - goto convert_error; - res = gst_base_video_encoded_video_convert (&base_video_parse->state, - format, stop, &tformat, &tstop); - if (!res) - goto convert_error; - - real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME, - flags, cur_type, tcur, stop_type, tstop); - - res = - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SINK_PAD (base_video_parse), - real_seek); - - break; - } -#if 0 - case GST_EVENT_QOS: - { - gdouble proportion; - GstClockTimeDiff diff; - GstClockTime timestamp; - - gst_event_parse_qos (event, &proportion, &diff, ×tamp); - - GST_OBJECT_LOCK (base_video_parse); - base_video_parse->proportion = proportion; - base_video_parse->earliest_time = timestamp + diff; - GST_OBJECT_UNLOCK (base_video_parse); - - GST_DEBUG_OBJECT (base_video_parse, - "got QoS %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT, - GST_TIME_ARGS (timestamp), diff); - - res = gst_pad_push_event (base_video_parse->sinkpad, event); - break; - } -#endif - default: - res = - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SINK_PAD (base_video_parse), - event); - break; - } -done: - gst_object_unref (base_video_parse); - return res; - -convert_error: - GST_DEBUG_OBJECT (base_video_parse, "could not convert format"); - goto done; -} - -static gboolean -gst_base_video_parse_sink_event (GstPad * pad, GstEvent * event) -{ - GstBaseVideoParse *base_video_parse; - gboolean ret = FALSE; - - base_video_parse = GST_BASE_VIDEO_PARSE (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_START: - ret = - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_parse), - event); - break; - case GST_EVENT_FLUSH_STOP: - gst_base_video_parse_reset (base_video_parse); - ret = - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_parse), - event); - break; - case GST_EVENT_EOS: - if (gst_base_video_parse_push_all (base_video_parse, - FALSE) == GST_FLOW_ERROR) { - gst_event_unref (event); - return FALSE; - } - - ret = - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_parse), - event); - break; - case GST_EVENT_NEWSEGMENT: - { - gboolean update; - GstFormat format; - gdouble rate; - gint64 start, stop, time; - - gst_event_parse_new_segment (event, &update, &rate, &format, &start, - &stop, &time); - - if (format != GST_FORMAT_TIME) - goto newseg_wrong_format; - - if (rate <= 0.0) - goto newseg_wrong_rate; - - GST_DEBUG ("newsegment %" GST_TIME_FORMAT " %" GST_TIME_FORMAT, - GST_TIME_ARGS (start), GST_TIME_ARGS (time)); - gst_segment_set_newsegment (&base_video_parse->segment, update, - rate, format, start, stop, time); - - ret = - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_parse), - event); - break; - } - default: - ret = - gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_parse), - event); - break; - } -done: - gst_object_unref (base_video_parse); - return ret; - -newseg_wrong_format: - GST_DEBUG_OBJECT (base_video_parse, "received non TIME newsegment"); - gst_event_unref (event); - goto done; - -newseg_wrong_rate: - GST_DEBUG_OBJECT (base_video_parse, "negative rates not supported"); - gst_event_unref (event); - goto done; -} - - -static GstStateChangeReturn -gst_base_video_parse_change_state (GstElement * element, - GstStateChange transition) -{ - GstBaseVideoParse *base_parse = GST_BASE_VIDEO_PARSE (element); - GstStateChangeReturn ret; - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - gst_base_video_parse_reset (base_parse); - 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: - gst_base_video_parse_reset (base_parse); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - break; - default: - break; - } - - return ret; -} - -static guint64 -gst_base_video_parse_get_timestamp (GstBaseVideoParse * base_video_parse, - int picture_number) -{ - if (picture_number < 0) { - return base_video_parse->timestamp_offset - - (gint64) gst_util_uint64_scale (-picture_number, - base_video_parse->state.fps_d * GST_SECOND, - base_video_parse->state.fps_n); - } else { - return base_video_parse->timestamp_offset + - gst_util_uint64_scale (picture_number, - base_video_parse->state.fps_d * GST_SECOND, - base_video_parse->state.fps_n); - } -} - -static GstFlowReturn -gst_base_video_parse_push_all (GstBaseVideoParse * base_video_parse, - gboolean at_eos) -{ - GstFlowReturn ret = GST_FLOW_OK; - - /* FIXME do stuff */ - - return ret; -} - -static GstFlowReturn -gst_base_video_parse_chain (GstPad * pad, GstBuffer * buf) -{ - GstBaseVideoParse *base_video_parse; - GstBaseVideoParseClass *klass; - GstFlowReturn ret; - - GST_DEBUG ("chain with %d bytes", GST_BUFFER_SIZE (buf)); - - base_video_parse = GST_BASE_VIDEO_PARSE (GST_PAD_PARENT (pad)); - klass = GST_BASE_VIDEO_PARSE_GET_CLASS (base_video_parse); - - if (!base_video_parse->started) { - klass->start (base_video_parse); - base_video_parse->started = TRUE; - } - - if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT))) { - GST_DEBUG_OBJECT (base_video_parse, "received DISCONT buffer"); - gst_base_video_parse_reset (base_video_parse); - base_video_parse->discont = TRUE; - base_video_parse->have_sync = FALSE; - } - - if (GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) { - base_video_parse->last_timestamp = GST_BUFFER_TIMESTAMP (buf); - } - gst_adapter_push (base_video_parse->input_adapter, buf); - - if (!base_video_parse->have_sync) { - int n, m; - - GST_DEBUG ("no sync, scanning"); - - n = gst_adapter_available (base_video_parse->input_adapter); - m = klass->scan_for_sync (base_video_parse->input_adapter, FALSE, 0, n); - - gst_adapter_flush (base_video_parse->input_adapter, m); - - if (m < n) { - GST_DEBUG ("found possible sync after %d bytes (of %d)", m, n); - - /* this is only "maybe" sync */ - base_video_parse->have_sync = TRUE; - } - - if (!base_video_parse->have_sync) { - return GST_FLOW_OK; - } - } - - /* FIXME check klass->parse_data */ - - do { - ret = klass->parse_data (base_video_parse, FALSE); - } while (ret == GST_FLOW_OK); - - if (ret == GST_BASE_VIDEO_PARSE_FLOW_NEED_DATA) { - return GST_FLOW_OK; - } - return ret; -} - -GstVideoState * -gst_base_video_parse_get_state (GstBaseVideoParse * base_video_parse) -{ - return &base_video_parse->state; -} - -void -gst_base_video_parse_set_state (GstBaseVideoParse * base_video_parse, - GstVideoState * state) -{ - GST_DEBUG ("set_state"); - - memcpy (&base_video_parse->state, state, sizeof (GstVideoState)); - - /* FIXME set caps */ - -} - - -gboolean -gst_base_video_parse_set_src_caps (GstBaseVideoParse * base_video_parse, - GstCaps * caps) -{ - g_return_val_if_fail (GST_IS_BASE_VIDEO_PARSE (base_video_parse), FALSE); - - GST_DEBUG ("set_src_caps"); - - return gst_pad_set_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_parse), - caps); -} - -void -gst_base_video_parse_lost_sync (GstBaseVideoParse * base_video_parse) -{ - g_return_if_fail (GST_IS_BASE_VIDEO_PARSE (base_video_parse)); - - GST_DEBUG ("lost_sync"); - - if (gst_adapter_available (base_video_parse->input_adapter) >= 1) { - gst_adapter_flush (base_video_parse->input_adapter, 1); - } - - base_video_parse->have_sync = FALSE; -} - -GstVideoFrame * -gst_base_video_parse_get_frame (GstBaseVideoParse * base_video_parse) -{ - g_return_val_if_fail (GST_IS_BASE_VIDEO_PARSE (base_video_parse), NULL); - - return base_video_parse->current_frame; -} - -void -gst_base_video_parse_add_to_frame (GstBaseVideoParse * base_video_parse, - int n_bytes) -{ - GstBuffer *buf; - - GST_DEBUG ("add_to_frame"); - - buf = gst_adapter_take_buffer (base_video_parse->input_adapter, n_bytes); - - gst_adapter_push (base_video_parse->output_adapter, buf); -} - -GstFlowReturn -gst_base_video_parse_finish_frame (GstBaseVideoParse * base_video_parse) -{ - GstVideoFrame *frame = base_video_parse->current_frame; - GstBuffer *buffer; - GstBaseVideoParseClass *base_video_parse_class; - GstFlowReturn ret; - - GST_DEBUG ("finish_frame"); - - base_video_parse_class = GST_BASE_VIDEO_PARSE_GET_CLASS (base_video_parse); - - buffer = gst_adapter_take_buffer (base_video_parse->output_adapter, - gst_adapter_available (base_video_parse->output_adapter)); - - if (frame->is_sync_point) { - base_video_parse->timestamp_offset = base_video_parse->last_timestamp - - gst_util_uint64_scale (frame->presentation_frame_number, - base_video_parse->state.fps_d * GST_SECOND, - base_video_parse->state.fps_n); - base_video_parse->distance_from_sync = 0; - } - - frame->distance_from_sync = base_video_parse->distance_from_sync; - base_video_parse->distance_from_sync++; - - frame->presentation_timestamp = - gst_base_video_parse_get_timestamp (base_video_parse, - frame->presentation_frame_number); - frame->presentation_duration = - gst_base_video_parse_get_timestamp (base_video_parse, - frame->presentation_frame_number + 1) - frame->presentation_timestamp; - frame->decode_timestamp = - gst_base_video_parse_get_timestamp (base_video_parse, - frame->decode_frame_number); - - GST_BUFFER_TIMESTAMP (buffer) = frame->presentation_timestamp; - GST_BUFFER_DURATION (buffer) = frame->presentation_duration; - if (frame->decode_frame_number < 0) { - GST_BUFFER_OFFSET (buffer) = 0; - } else { - GST_BUFFER_OFFSET (buffer) = frame->decode_timestamp; - } - GST_BUFFER_OFFSET_END (buffer) = GST_CLOCK_TIME_NONE; - - GST_DEBUG ("pts %" GST_TIME_FORMAT, - GST_TIME_ARGS (frame->presentation_timestamp)); - GST_DEBUG ("dts %" GST_TIME_FORMAT, GST_TIME_ARGS (frame->decode_timestamp)); - GST_DEBUG ("dist %d", frame->distance_from_sync); - - if (frame->is_sync_point) { - GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT); - } else { - GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT); - } - - frame->src_buffer = buffer; - ret = base_video_parse_class->shape_output (base_video_parse, frame); - - gst_base_video_parse_free_frame (base_video_parse->current_frame); - - /* create new frame */ - base_video_parse->current_frame = - gst_base_video_parse_new_frame (base_video_parse); - - return ret; -} - -static void -gst_base_video_parse_free_frame (GstVideoFrame * frame) -{ - if (frame->sink_buffer) { - gst_buffer_unref (frame->sink_buffer); - } -#if 0 - if (frame->src_buffer) { - gst_buffer_unref (frame->src_buffer); - } -#endif - - g_free (frame); -} - -static GstVideoFrame * -gst_base_video_parse_new_frame (GstBaseVideoParse * base_video_parse) -{ - GstVideoFrame *frame; - - frame = g_malloc0 (sizeof (GstVideoFrame)); - - frame->system_frame_number = base_video_parse->system_frame_number; - base_video_parse->system_frame_number++; - - frame->decode_frame_number = frame->system_frame_number - - base_video_parse->reorder_depth; - - return frame; -} - -void -gst_base_video_parse_set_sync_point (GstBaseVideoParse * base_video_parse) -{ - GST_DEBUG ("set_sync_point"); - - base_video_parse->current_frame->is_sync_point = TRUE; - - base_video_parse->distance_from_sync = 0; -} - -GstFlowReturn -gst_base_video_parse_push (GstBaseVideoParse * base_video_parse, - GstBuffer * buffer) -{ - GstBaseVideoParseClass *base_video_parse_class; - - base_video_parse_class = GST_BASE_VIDEO_PARSE_GET_CLASS (base_video_parse); - - if (base_video_parse->caps == NULL) { - gboolean ret; - - base_video_parse->caps = - base_video_parse_class->get_caps (base_video_parse); - - ret = gst_pad_set_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_parse), - base_video_parse->caps); - - if (!ret) { - GST_WARNING ("pad didn't accept caps"); - return GST_FLOW_ERROR; - } - } - gst_buffer_set_caps (buffer, base_video_parse->caps); - - GST_DEBUG ("pushing ts=%" GST_TIME_FORMAT " dur=%" GST_TIME_FORMAT - " off=%" G_GUINT64_FORMAT " off_end=%" G_GUINT64_FORMAT, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), - GST_BUFFER_OFFSET (buffer), GST_BUFFER_OFFSET_END (buffer)); - - if (base_video_parse->discont) { - GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); - base_video_parse->discont = FALSE; - } else { - GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT); - } - - return gst_pad_push (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_parse), buffer); -} diff --git a/gst-libs/gst/video/gstbasevideoparse.h b/gst-libs/gst/video/gstbasevideoparse.h deleted file mode 100644 index 252685acd..000000000 --- a/gst-libs/gst/video/gstbasevideoparse.h +++ /dev/null @@ -1,142 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 David Schleef <ds@schleef.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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef _GST_BASE_VIDEO_PARSE_H_ -#define _GST_BASE_VIDEO_PARSE_H_ - -#ifndef GST_USE_UNSTABLE_API -#warning "GstBaseVideoParse is unstable API and may change in future." -#warning "You can define GST_USE_UNSTABLE_API to avoid this warning." -#endif - -#include <gst/video/gstbasevideocodec.h> -#include <gst/video/gstbasevideoutils.h> - -G_BEGIN_DECLS - -#define GST_TYPE_BASE_VIDEO_PARSE \ - (gst_base_video_parse_get_type()) -#define GST_BASE_VIDEO_PARSE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASE_VIDEO_PARSE,GstBaseVideoParse)) -#define GST_BASE_VIDEO_PARSE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASE_VIDEO_PARSE,GstBaseVideoParseClass)) -#define GST_BASE_VIDEO_PARSE_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_BASE_VIDEO_PARSE,GstBaseVideoParseClass)) -#define GST_IS_BASE_VIDEO_PARSE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASE_VIDEO_PARSE)) -#define GST_IS_BASE_VIDEO_PARSE_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASE_VIDEO_PARSE)) - -/** - * GST_BASE_VIDEO_PARSE_SINK_NAME: - * - * The name of the templates for the sink pad. - */ -#define GST_BASE_VIDEO_PARSE_SINK_NAME "sink" -/** - * GST_BASE_VIDEO_PARSE_SRC_NAME: - * - * The name of the templates for the source pad. - */ -#define GST_BASE_VIDEO_PARSE_SRC_NAME "src" - -/** - * GST_BASE_VIDEO_PARSE_FLOW_NEED_DATA: - * - */ -#define GST_BASE_VIDEO_PARSE_FLOW_NEED_DATA GST_FLOW_CUSTOM_SUCCESS - -typedef struct _GstBaseVideoParse GstBaseVideoParse; -typedef struct _GstBaseVideoParseClass GstBaseVideoParseClass; - -struct _GstBaseVideoParse -{ - GstBaseVideoCodec base_video_codec; - - /*< private >*/ - GstAdapter *input_adapter; - GstAdapter *output_adapter; - - int reorder_depth; - - gboolean have_sync; - gboolean discont; - gboolean started; - - GstVideoFrame *current_frame; - GstVideoState state; - GstSegment segment; - int distance_from_sync; - - gboolean sink_clipping; - - guint64 presentation_frame_number; - guint64 system_frame_number; - - GstCaps *caps; - gboolean set_output_caps; - - GstClockTime last_timestamp; - - gint64 timestamp_offset; -}; - -struct _GstBaseVideoParseClass -{ - GstBaseVideoCodecClass base_video_codec_class; - - gboolean (*start) (GstBaseVideoParse *parse); - gboolean (*stop) (GstBaseVideoParse *parse); - gboolean (*reset) (GstBaseVideoParse *parse); - GstFlowReturn (*parse_data) (GstBaseVideoParse *parse, gboolean at_eos); - int (*scan_for_sync) (GstAdapter *adapter, gboolean at_eos, - int offset, int n); - GstFlowReturn (*shape_output) (GstBaseVideoParse *parse, GstVideoFrame *frame); - GstCaps *(*get_caps) (GstBaseVideoParse *parse); - -}; - -GType gst_base_video_parse_get_type (void); - -int gst_base_video_parse_get_width (GstBaseVideoParse *parse); -int gst_base_video_parse_get_height (GstBaseVideoParse *parse); -GstVideoState *gst_base_video_parse_get_state (GstBaseVideoParse *parse); -void gst_base_video_parse_set_state (GstBaseVideoParse *parse, - GstVideoState *state); - -guint64 gst_base_video_parse_get_timestamp_offset (GstBaseVideoParse *parse); - -gboolean gst_base_video_parse_set_src_caps (GstBaseVideoParse *base_video_parse, GstCaps *caps); - -GstFlowReturn gst_base_video_parse_end_of_stream (GstBaseVideoParse *base_video_parse, - GstBuffer *buffer); - -void gst_base_video_parse_lost_sync (GstBaseVideoParse *base_video_parse); - -GstVideoFrame * gst_base_video_parse_get_frame (GstBaseVideoParse *base_video_parse); -void gst_base_video_parse_add_to_frame (GstBaseVideoParse *base_video_parse, int n_bytes); -GstFlowReturn gst_base_video_parse_finish_frame (GstBaseVideoParse *base_video_parse); -void gst_base_video_parse_set_sync_point (GstBaseVideoParse *base_video_parse); -GstFlowReturn gst_base_video_parse_push (GstBaseVideoParse *base_video_parse, - GstBuffer *buffer); - -G_END_DECLS - -#endif - diff --git a/gst-plugins-bad.doap b/gst-plugins-bad.doap index d86079c14..2ec1153d8 100644 --- a/gst-plugins-bad.doap +++ b/gst-plugins-bad.doap @@ -35,6 +35,17 @@ real live maintainer, or some actual wide use. <release> <Version> + <revision>0.10.21</revision> + <branch>0.10</branch> + <name>Pink Noise</name> + <created>2011-01-21</created> + <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-bad/gst-plugins-bad-0.10.21.tar.bz2" /> + <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-plugins-bad/gst-plugins-bad-0.10.21.tar.gz" /> + </Version> + </release> + + <release> + <Version> <revision>0.10.20</revision> <branch>0.10</branch> <name>For it is a Human Number</name> diff --git a/gst-plugins-bad.spec.in b/gst-plugins-bad.spec.in index 8da39aae5..3b4fa9e27 100644 --- a/gst-plugins-bad.spec.in +++ b/gst-plugins-bad.spec.in @@ -95,7 +95,6 @@ rm -rf $RPM_BUILD_ROOT %{_libdir}/gstreamer-%{majorminor}/libgstmpeg4videoparse.so %{_libdir}/gstreamer-%{majorminor}/libgstfbdevsink.so %{_libdir}/gstreamer-%{majorminor}/libgstrawparse.so -%{_libdir}/gstreamer-%{majorminor}/libgstselector.so %{_libdir}/gstreamer-%{majorminor}/libgstsubenc.so %{_libdir}/gstreamer-%{majorminor}/libresindvd.so %{_libdir}/gstreamer-%{majorminor}/libgstaiff.so @@ -104,6 +103,7 @@ rm -rf $RPM_BUILD_ROOT %{_libdir}/gstreamer-%{majorminor}/libgstmpegtsmux.so %{_libdir}/gstreamer-%{majorminor}/libgstscaletempoplugin.so %{_libdir}/gstreamer-%{majorminor}/libgstmpegdemux.so +%{_libdir}/gstreamer-%{majorminor}/libgstmpegtsdemux.so %{_libdir}/gstreamer-%{majorminor}/libgstjp2k.so %{_libdir}/gstreamer-%{majorminor}/libgstapexsink.so %{_libdir}/gstreamer-%{majorminor}/libgstqtmux.so @@ -111,7 +111,6 @@ rm -rf $RPM_BUILD_ROOT %{_libdir}/gstreamer-%{majorminor}/libgstmxf.so %{_libdir}/gstreamer-%{majorminor}/libgstvmnc.so %{_libdir}/gstreamer-%{majorminor}/libgstvideosignal.so -%{_libdir}/gstreamer-%{majorminor}/libgstvalve.so %{_libdir}/gstreamer-%{majorminor}/libgstautoconvert.so %{_libdir}/gstreamer-%{majorminor}/libgstdtmf.so %{_libdir}/gstreamer-%{majorminor}/libgstliveadder.so @@ -167,7 +166,6 @@ rm -rf $RPM_BUILD_ROOT @USE_DC1394_TRUE@%{_libdir}/gstreamer-%{majorminor}/libgstdc1394.so @USE_TIMIDITY_TRUE@%{_libdir}/gstreamer-%{majorminor}/libgsttimidity.so @USE_WILDMIDI_TRUE@%{_libdir}/gstreamer-%{majorminor}/libgstwildmidi.so -@USE_JACK_TRUE@%{_libdir}/gstreamer-%{majorminor}/libgstjack.so @USE_SNDFILE_TRUE@%{_libdir}/gstreamer-%{majorminor}/libgstsndfile.so @USE_CELT_TRUE@%{_libdir}/gstreamer-%{majorminor}/libgstcelt.so @USE_MPEG2ENC_TRUE@%{_libdir}/gstreamer-%{majorminor}/libgstmpeg2enc.so diff --git a/gst/asfmux/gstasf.c b/gst/asfmux/gstasf.c index fb9351721..0cf3b32e5 100644 --- a/gst/asfmux/gstasf.c +++ b/gst/asfmux/gstasf.c @@ -48,4 +48,4 @@ GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, "asfmux", "ASF Muxer Plugin", - plugin_init, VERSION, "LGPL", "gsoc2009 package", "embedded.ufcg.edu.br") + plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/gst/asfmux/gstasfmux.c b/gst/asfmux/gstasfmux.c index 3c8921f4c..2e85e1ae2 100644 --- a/gst/asfmux/gstasfmux.c +++ b/gst/asfmux/gstasfmux.c @@ -919,7 +919,7 @@ gst_asf_mux_write_string_with_size (GstAsfMux * asfmux, if (error) { GST_WARNING_OBJECT (asfmux, "Error converting string " "to UTF-16: %s - %s", str, error->message); - g_free (error); + g_error_free (error); memset (str_buf, 0, str_size); } else { /* HACK: g_convert seems to add only a single byte null char to diff --git a/gst/audioparsers/Makefile.am b/gst/audioparsers/Makefile.am index 8aca6d98c..77039c715 100644 --- a/gst/audioparsers/Makefile.am +++ b/gst/audioparsers/Makefile.am @@ -3,10 +3,13 @@ plugin_LTLIBRARIES = libgstaudioparsersbad.la libgstaudioparsersbad_la_SOURCES = \ gstaacparse.c gstamrparse.c gstac3parse.c \ gstdcaparse.c gstflacparse.c gstmpegaudioparse.c \ - gstbaseparse.c plugin.c + plugin.c -libgstaudioparsersbad_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) +libgstaudioparsersbad_la_CFLAGS = \ + -I$(top_srcdir)/gst-libs \ + $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) libgstaudioparsersbad_la_LIBADD = \ + $(top_builddir)/gst-libs/gst/baseparse/libgstbaseparse-$(GST_MAJORMINOR).la \ $(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_MAJORMINOR) \ -lgstaudio-$(GST_MAJORMINOR) \ $(GST_BASE_LIBS) $(GST_LIBS) @@ -14,5 +17,4 @@ libgstaudioparsersbad_la_LDFLAGS = $(PACKAGE_LIBS) $(GST_PLUGIN_LDFLAGS) libgstaudioparsersbad_la_LIBTOOLFLAGS = --tag=disable-static noinst_HEADERS = gstaacparse.h gstamrparse.h gstac3parse.h \ - gstdcaparse.h gstflacparse.h gstmpegaudioparse.h \ - gstbaseparse.h + gstdcaparse.h gstflacparse.h gstmpegaudioparse.h diff --git a/gst/audioparsers/gstaacparse.c b/gst/audioparsers/gstaacparse.c index 4dd2dc761..09e3e71f2 100644 --- a/gst/audioparsers/gstaacparse.c +++ b/gst/audioparsers/gstaacparse.c @@ -77,10 +77,10 @@ static gboolean gst_aacparse_sink_setcaps (GstBaseParse * parse, GstCaps * caps); gboolean gst_aacparse_check_valid_frame (GstBaseParse * parse, - GstBuffer * buffer, guint * size, gint * skipsize); + GstBaseParseFrame * frame, guint * size, gint * skipsize); GstFlowReturn gst_aacparse_parse_frame (GstBaseParse * parse, - GstBuffer * buffer); + GstBaseParseFrame * frame); gboolean gst_aacparse_convert (GstBaseParse * parse, GstFormat src_format, @@ -147,8 +147,6 @@ gst_aacparse_class_init (GstAacParseClass * klass) parse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_aacparse_parse_frame); parse_class->check_valid_frame = GST_DEBUG_FUNCPTR (gst_aacparse_check_valid_frame); - parse_class->get_frame_overhead = - GST_DEBUG_FUNCPTR (gst_aacparse_get_frame_overhead); } @@ -269,7 +267,8 @@ gst_aacparse_sink_setcaps (GstBaseParse * parse, GstCaps * caps) /* arrange for metadata and get out of the way */ gst_aacparse_set_src_caps (aacparse, caps); - gst_base_parse_set_passthrough (parse, TRUE); + gst_base_parse_set_format (parse, + GST_BASE_PARSE_FORMAT_PASSTHROUGH, TRUE); } else return FALSE; @@ -330,8 +329,8 @@ gst_aacparse_adts_get_frame_len (const guint8 * data) */ static gboolean gst_aacparse_check_adts_frame (GstAacParse * aacparse, - const guint8 * data, - const guint avail, guint * framesize, guint * needed_data) + const guint8 * data, const guint avail, gboolean drain, + guint * framesize, guint * needed_data) { if (G_UNLIKELY (avail < 2)) return FALSE; @@ -340,7 +339,7 @@ gst_aacparse_check_adts_frame (GstAacParse * aacparse, *framesize = gst_aacparse_adts_get_frame_len (data); /* In EOS mode this is enough. No need to examine the data further */ - if (gst_base_parse_get_drain (GST_BASE_PARSE (aacparse))) { + if (drain) { return TRUE; } @@ -408,7 +407,8 @@ gst_aacparse_parse_adts_header (GstAacParse * aacparse, const guint8 * data, */ static gboolean gst_aacparse_detect_stream (GstAacParse * aacparse, - const guint8 * data, const guint avail, guint * framesize, gint * skipsize) + const guint8 * data, const guint avail, gboolean drain, + guint * framesize, gint * skipsize) { gboolean found = FALSE; guint need_data = 0; @@ -444,7 +444,7 @@ gst_aacparse_detect_stream (GstAacParse * aacparse, return FALSE; } - if (gst_aacparse_check_adts_frame (aacparse, data, avail, + if (gst_aacparse_check_adts_frame (aacparse, data, avail, drain, framesize, &need_data)) { gint rate, channels; @@ -543,7 +543,8 @@ gst_aacparse_detect_stream (GstAacParse * aacparse, /* arrange for metadata and get out of the way */ gst_aacparse_set_src_caps (aacparse, GST_PAD_CAPS (GST_BASE_PARSE_SINK_PAD (aacparse))); - gst_base_parse_set_passthrough (GST_BASE_PARSE (aacparse), TRUE); + gst_base_parse_set_format (GST_BASE_PARSE (aacparse), + GST_BASE_PARSE_FORMAT_PASSTHROUGH, TRUE); *framesize = avail; return TRUE; @@ -568,17 +569,19 @@ gst_aacparse_detect_stream (GstAacParse * aacparse, */ gboolean gst_aacparse_check_valid_frame (GstBaseParse * parse, - GstBuffer * buffer, guint * framesize, gint * skipsize) + GstBaseParseFrame * frame, guint * framesize, gint * skipsize) { const guint8 *data; GstAacParse *aacparse; gboolean ret = FALSE; gboolean sync; + GstBuffer *buffer; aacparse = GST_AACPARSE (parse); + buffer = frame->buffer; data = GST_BUFFER_DATA (buffer); - sync = gst_base_parse_get_sync (parse); + sync = GST_BASE_PARSE_FRAME_SYNC (frame); if (aacparse->header_type == DSPAAC_HEADER_ADIF || aacparse->header_type == DSPAAC_HEADER_NONE) { @@ -589,13 +592,14 @@ gst_aacparse_check_valid_frame (GstBaseParse * parse, } else if (aacparse->header_type == DSPAAC_HEADER_NOT_PARSED || sync == FALSE) { ret = gst_aacparse_detect_stream (aacparse, data, GST_BUFFER_SIZE (buffer), - framesize, skipsize); + GST_BASE_PARSE_FRAME_DRAIN (frame), framesize, skipsize); } else if (aacparse->header_type == DSPAAC_HEADER_ADTS) { guint needed_data = 1024; ret = gst_aacparse_check_adts_frame (aacparse, data, - GST_BUFFER_SIZE (buffer), framesize, &needed_data); + GST_BUFFER_SIZE (buffer), GST_BASE_PARSE_FRAME_DRAIN (frame), + framesize, &needed_data); if (!ret) { GST_DEBUG ("buffer didn't contain valid frame"); @@ -619,21 +623,39 @@ gst_aacparse_check_valid_frame (GstBaseParse * parse, * * Implementation of "parse_frame" vmethod in #GstBaseParse class. * + * Also determines frame overhead. + * ADTS streams have a 7 byte header in each frame. MP4 and ADIF streams don't have + * a per-frame header. + * + * We're making a couple of simplifying assumptions: + * + * 1. We count Program Configuration Elements rather than searching for them + * in the streams to discount them - the overhead is negligible. + * + * 2. We ignore CRC. This has a worst-case impact of (num_raw_blocks + 1)*16 + * bits, which should still not be significant enough to warrant the + * additional parsing through the headers + * * Returns: GST_FLOW_OK if frame was successfully parsed and can be pushed * forward. Otherwise appropriate error is returned. */ GstFlowReturn -gst_aacparse_parse_frame (GstBaseParse * parse, GstBuffer * buffer) +gst_aacparse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) { GstAacParse *aacparse; + GstBuffer *buffer; GstFlowReturn ret = GST_FLOW_OK; gint rate, channels; aacparse = GST_AACPARSE (parse); + buffer = frame->buffer; if (G_UNLIKELY (aacparse->header_type != DSPAAC_HEADER_ADTS)) return ret; + /* see above */ + frame->overhead = 7; + gst_aacparse_parse_adts_header (aacparse, GST_BUFFER_DATA (buffer), &rate, &channels, NULL, NULL); GST_LOG_OBJECT (aacparse, "rate: %d, chans: %d", rate, channels); @@ -673,7 +695,6 @@ gst_aacparse_start (GstBaseParse * parse) aacparse = GST_AACPARSE (parse); GST_DEBUG ("start"); gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse), 1024); - gst_base_parse_set_passthrough (parse, FALSE); return TRUE; } @@ -692,33 +713,3 @@ gst_aacparse_stop (GstBaseParse * parse) GST_DEBUG ("stop"); return TRUE; } - - -/** - * gst_aacparse_get_frame_overhead: - * @parse: #GstBaseParse. - * @buffer: #GstBuffer. - * - * Implementation of "get_frame_overhead" vmethod in #GstBaseParse class. ADTS - * streams have a 7 byte header in each frame. MP4 and ADIF streams don't have - * a per-frame header. - * - * We're making a couple of simplifying assumptions: - * - * 1. We count Program Configuration Elements rather than searching for them - * in the streams to discount them - the overhead is negligible. - * - * 2. We ignore CRC. This has a worst-case impact of (num_raw_blocks + 1)*16 - * bits, which should still not be significant enough to warrant the - * additional parsing through the headers - */ -gint -gst_aacparse_get_frame_overhead (GstBaseParse * parse, GstBuffer * buffer) -{ - GstAacParse *aacparse = GST_AACPARSE (parse); - - if (aacparse->header_type == DSPAAC_HEADER_ADTS) - return 7; - else - return 0; -} diff --git a/gst/audioparsers/gstaacparse.h b/gst/audioparsers/gstaacparse.h index 7d71ef0dc..e62bf651f 100644 --- a/gst/audioparsers/gstaacparse.h +++ b/gst/audioparsers/gstaacparse.h @@ -23,7 +23,7 @@ #define __GST_AACPARSE_H__ #include <gst/gst.h> -#include "gstbaseparse.h" +#include <gst/baseparse/gstbaseparse.h> G_BEGIN_DECLS diff --git a/gst/audioparsers/gstac3parse.c b/gst/audioparsers/gstac3parse.c index 96e9a911e..e001bc37e 100644 --- a/gst/audioparsers/gstac3parse.c +++ b/gst/audioparsers/gstac3parse.c @@ -160,9 +160,9 @@ static void gst_ac3_parse_finalize (GObject * object); static gboolean gst_ac3_parse_start (GstBaseParse * parse); static gboolean gst_ac3_parse_stop (GstBaseParse * parse); static gboolean gst_ac3_parse_check_valid_frame (GstBaseParse * parse, - GstBuffer * buffer, guint * size, gint * skipsize); + GstBaseParseFrame * frame, guint * size, gint * skipsize); static GstFlowReturn gst_ac3_parse_parse_frame (GstBaseParse * parse, - GstBuffer * buf); + GstBaseParseFrame * frame); GST_BOILERPLATE (GstAc3Parse, gst_ac3_parse, GstBaseParse, GST_TYPE_BASE_PARSE); @@ -262,10 +262,13 @@ gst_ac3_parse_frame_header_ac3 (GstAc3Parse * ac3parse, GstBuffer * buf, bsmod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 3); acmod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 3); - /* FIXME: are other bsids ok as well? check spec */ - if (bsid != 8 && bsid != 6) { + /* spec not quite clear here: decoder should decode if less than 8, + * but seemingly only defines 6 and 8 cases */ + if (bsid > 8) { GST_DEBUG_OBJECT (ac3parse, "unexpected bsid=%d", bsid); return FALSE; + } else if (bsid != 8 && bsid != 6) { + GST_DEBUG_OBJECT (ac3parse, "undefined bsid=%d", bsid); } if ((acmod & 0x1) && (acmod != 0x1)) /* 3 front channels */ @@ -381,11 +384,12 @@ gst_ac3_parse_frame_header (GstAc3Parse * parse, GstBuffer * buf, } static gboolean -gst_ac3_parse_check_valid_frame (GstBaseParse * parse, GstBuffer * buf, - guint * framesize, gint * skipsize) +gst_ac3_parse_check_valid_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, guint * framesize, gint * skipsize) { - GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buf); GstAc3Parse *ac3parse = GST_AC3_PARSE (parse); + GstBuffer *buf = frame->buffer; + GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buf); gint off; gboolean sync, drain; @@ -418,8 +422,8 @@ gst_ac3_parse_check_valid_frame (GstBaseParse * parse, GstBuffer * buf, GST_LOG_OBJECT (parse, "got frame"); - sync = gst_base_parse_get_sync (parse); - drain = gst_base_parse_get_drain (parse); + sync = GST_BASE_PARSE_FRAME_SYNC (frame); + drain = GST_BASE_PARSE_FRAME_DRAIN (frame); if (!sync && !drain) { guint16 word = 0; @@ -448,9 +452,10 @@ gst_ac3_parse_check_valid_frame (GstBaseParse * parse, GstBuffer * buf, } static GstFlowReturn -gst_ac3_parse_parse_frame (GstBaseParse * parse, GstBuffer * buf) +gst_ac3_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) { GstAc3Parse *ac3parse = GST_AC3_PARSE (parse); + GstBuffer *buf = frame->buffer; guint fsize, rate, chans, blocks, sid; gboolean eac; @@ -461,8 +466,17 @@ gst_ac3_parse_parse_frame (GstBaseParse * parse, GstBuffer * buf) GST_LOG_OBJECT (parse, "size: %u, rate: %u, chans: %u", fsize, rate, chans); if (G_UNLIKELY (sid)) { + /* dependent frame, no need to (ac)count for or consider further */ GST_LOG_OBJECT (parse, "sid: %d", sid); - GST_BUFFER_FLAG_SET (buf, GST_BASE_PARSE_BUFFER_FLAG_NO_FRAME); + frame->flags |= GST_BASE_PARSE_FRAME_FLAG_NO_FRAME; + /* TODO maybe also mark as DELTA_UNIT, + * if that does not surprise baseparse elsewhere */ + /* occupies same time space as previous base frame */ + if (G_LIKELY (GST_BUFFER_TIMESTAMP (buf) >= GST_BUFFER_DURATION (buf))) + GST_BUFFER_TIMESTAMP (buf) -= GST_BUFFER_DURATION (buf); + /* only return if we already arranged for caps */ + if (G_LIKELY (ac3parse->sample_rate > 0)) + return GST_FLOW_OK; } if (G_UNLIKELY (ac3parse->sample_rate != rate || ac3parse->channels != chans diff --git a/gst/audioparsers/gstac3parse.h b/gst/audioparsers/gstac3parse.h index 724b56f59..781554be5 100644 --- a/gst/audioparsers/gstac3parse.h +++ b/gst/audioparsers/gstac3parse.h @@ -24,7 +24,7 @@ #define __GST_AC3_PARSE_H__ #include <gst/gst.h> -#include "gstbaseparse.h" +#include <gst/baseparse/gstbaseparse.h> G_BEGIN_DECLS diff --git a/gst/audioparsers/gstamrparse.c b/gst/audioparsers/gstamrparse.c index a182e765b..42481a2b2 100644 --- a/gst/audioparsers/gstamrparse.c +++ b/gst/audioparsers/gstamrparse.c @@ -64,7 +64,7 @@ static const gint block_size_nb[16] = { 12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0 }; static const gint block_size_wb[16] = - { 17, 23, 32, 36, 40, 46, 50, 58, 60, 5, 5, 0, 0, 0, 0, 0 }; + { 17, 23, 32, 36, 40, 46, 50, 58, 60, 5, -1, -1, -1, -1, 0, 0 }; /* AMR has a "hardcoded" framerate of 50fps */ #define AMR_FRAMES_PER_SECOND 50 @@ -78,10 +78,10 @@ static gboolean gst_amrparse_sink_setcaps (GstBaseParse * parse, GstCaps * caps); gboolean gst_amrparse_check_valid_frame (GstBaseParse * parse, - GstBuffer * buffer, guint * framesize, gint * skipsize); + GstBaseParseFrame * frame, guint * framesize, gint * skipsize); GstFlowReturn gst_amrparse_parse_frame (GstBaseParse * parse, - GstBuffer * buffer); + GstBaseParseFrame * frame); #define _do_init(bla) \ GST_DEBUG_CATEGORY_INIT (gst_amrparse_debug, "amrparse", 0, \ @@ -267,13 +267,15 @@ gst_amrparse_parse_header (GstAmrParse * amrparse, */ gboolean gst_amrparse_check_valid_frame (GstBaseParse * parse, - GstBuffer * buffer, guint * framesize, gint * skipsize) + GstBaseParseFrame * frame, guint * framesize, gint * skipsize) { + GstBuffer *buffer; const guint8 *data; gint fsize, mode, dsize; GstAmrParse *amrparse; amrparse = GST_AMRPARSE (parse); + buffer = frame->buffer; data = GST_BUFFER_DATA (buffer); dsize = GST_BUFFER_SIZE (buffer); @@ -305,8 +307,9 @@ gst_amrparse_check_valid_frame (GstBaseParse * parse, * to contain a valid header as well (and there is enough data to * perform this check) */ - if (gst_base_parse_get_sync (parse) || gst_base_parse_get_drain (parse) || - (dsize >= fsize && (data[fsize] & 0x83) == 0)) { + if (fsize && + (GST_BASE_PARSE_FRAME_SYNC (frame) || GST_BASE_PARSE_FRAME_DRAIN (frame) + || (dsize > fsize && (data[fsize] & 0x83) == 0))) { *framesize = fsize; return TRUE; } @@ -327,9 +330,8 @@ gst_amrparse_check_valid_frame (GstBaseParse * parse, * Returns: #GstFlowReturn defining the parsing status. */ GstFlowReturn -gst_amrparse_parse_frame (GstBaseParse * parse, GstBuffer * buffer) +gst_amrparse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) { - gst_buffer_set_caps (buffer, GST_PAD_CAPS (parse->srcpad)); return GST_FLOW_OK; } diff --git a/gst/audioparsers/gstamrparse.h b/gst/audioparsers/gstamrparse.h index e3fc191b8..04cd6e763 100644 --- a/gst/audioparsers/gstamrparse.h +++ b/gst/audioparsers/gstamrparse.h @@ -24,7 +24,7 @@ #define __GST_AMRPARSE_H__ #include <gst/gst.h> -#include "gstbaseparse.h" +#include <gst/baseparse/gstbaseparse.h> G_BEGIN_DECLS diff --git a/gst/audioparsers/gstdcaparse.c b/gst/audioparsers/gstdcaparse.c index 3b074ccc0..8ef6acd0f 100644 --- a/gst/audioparsers/gstdcaparse.c +++ b/gst/audioparsers/gstdcaparse.c @@ -70,9 +70,9 @@ static void gst_dca_parse_finalize (GObject * object); static gboolean gst_dca_parse_start (GstBaseParse * parse); static gboolean gst_dca_parse_stop (GstBaseParse * parse); static gboolean gst_dca_parse_check_valid_frame (GstBaseParse * parse, - GstBuffer * buffer, guint * size, gint * skipsize); + GstBaseParseFrame * frame, guint * size, gint * skipsize); static GstFlowReturn gst_dca_parse_parse_frame (GstBaseParse * parse, - GstBuffer * buf); + GstBaseParseFrame * frame); GST_BOILERPLATE (GstDcaParse, gst_dca_parse, GstBaseParse, GST_TYPE_BASE_PARSE); @@ -246,7 +246,7 @@ gst_dca_parse_find_sync (GstDcaParse * dcaparse, GstByteReader * reader, /* FIXME: verify syncs via _parse_header() here already */ - /* Raw big endian */ + /* Raw little endian */ off = gst_byte_reader_masked_scan_uint32 (reader, 0xffffffff, 0xfe7f0180, 0, GST_BUFFER_SIZE (buf)); if (off >= 0 && off < best_offset) { @@ -254,7 +254,7 @@ gst_dca_parse_find_sync (GstDcaParse * dcaparse, GstByteReader * reader, best_sync = 0xfe7f0180; } - /* Raw little endian */ + /* Raw big endian */ off = gst_byte_reader_masked_scan_uint32 (reader, 0xffffffff, 0x7ffe8001, 0, GST_BUFFER_SIZE (buf)); if (off >= 0 && off < best_offset) { @@ -265,15 +265,15 @@ gst_dca_parse_find_sync (GstDcaParse * dcaparse, GstByteReader * reader, /* FIXME: check next 2 bytes as well for 14-bit formats (but then don't * forget to adjust the *skipsize= in _check_valid_frame() */ - /* 14-bit big endian */ - off = gst_byte_reader_masked_scan_uint32 (reader, 0xffffffff, 0xfe7f0180, + /* 14-bit little endian */ + off = gst_byte_reader_masked_scan_uint32 (reader, 0xffffffff, 0xff1f00e8, 0, GST_BUFFER_SIZE (buf)); if (off >= 0 && off < best_offset) { best_offset = off; - best_sync = 0xfe7f0180; + best_sync = 0xff1f00e8; } - /* 14-bit little endian */ + /* 14-bit big endian */ off = gst_byte_reader_masked_scan_uint32 (reader, 0xffffffff, 0x1fffe800, 0, GST_BUFFER_SIZE (buf)); if (off >= 0 && off < best_offset) { @@ -289,11 +289,12 @@ gst_dca_parse_find_sync (GstDcaParse * dcaparse, GstByteReader * reader, } static gboolean -gst_dca_parse_check_valid_frame (GstBaseParse * parse, GstBuffer * buf, - guint * framesize, gint * skipsize) +gst_dca_parse_check_valid_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, guint * framesize, gint * skipsize) { - GstByteReader r = GST_BYTE_READER_INIT_FROM_BUFFER (buf); GstDcaParse *dcaparse = GST_DCA_PARSE (parse); + GstBuffer *buf = frame->buffer; + GstByteReader r = GST_BYTE_READER_INIT_FROM_BUFFER (buf); gboolean parser_draining; gboolean parser_in_sync; guint32 sync = 0; @@ -303,7 +304,7 @@ gst_dca_parse_check_valid_frame (GstBaseParse * parse, GstBuffer * buf, if (G_UNLIKELY (GST_BUFFER_SIZE (buf) < 16)) return FALSE; - parser_in_sync = gst_base_parse_get_sync (parse); + parser_in_sync = GST_BASE_PARSE_FRAME_SYNC (frame); if (G_LIKELY (parser_in_sync && dcaparse->last_sync != 0)) { off = gst_byte_reader_masked_scan_uint32 (&r, 0xffffffff, @@ -317,6 +318,7 @@ gst_dca_parse_check_valid_frame (GstBaseParse * parse, GstBuffer * buf, /* didn't find anything that looks like a sync word, skip */ if (off < 0) { *skipsize = GST_BUFFER_SIZE (buf) - 3; + GST_DEBUG_OBJECT (dcaparse, "no sync, skipping %d bytes", *skipsize); return FALSE; } @@ -342,7 +344,7 @@ gst_dca_parse_check_valid_frame (GstBaseParse * parse, GstBuffer * buf, dcaparse->last_sync = sync; - parser_draining = gst_base_parse_get_drain (parse); + parser_draining = GST_BASE_PARSE_FRAME_DRAIN (frame); if (!parser_in_sync && !parser_draining) { /* check for second frame to be sure */ @@ -376,10 +378,11 @@ gst_dca_parse_check_valid_frame (GstBaseParse * parse, GstBuffer * buf, } static GstFlowReturn -gst_dca_parse_parse_frame (GstBaseParse * parse, GstBuffer * buf) +gst_dca_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) { - GstByteReader r = GST_BYTE_READER_INIT_FROM_BUFFER (buf); GstDcaParse *dcaparse = GST_DCA_PARSE (parse); + GstBuffer *buf = frame->buffer; + GstByteReader r = GST_BYTE_READER_INIT_FROM_BUFFER (buf); guint size, rate, chans, samples; if (!gst_dca_parse_parse_header (dcaparse, &r, &size, &rate, &chans, diff --git a/gst/audioparsers/gstdcaparse.h b/gst/audioparsers/gstdcaparse.h index 150a19181..b0d754641 100644 --- a/gst/audioparsers/gstdcaparse.h +++ b/gst/audioparsers/gstdcaparse.h @@ -21,7 +21,7 @@ #define __GST_DCA_PARSE_H__ #include <gst/gst.h> -#include "gstbaseparse.h" +#include <gst/baseparse/gstbaseparse.h> G_BEGIN_DECLS diff --git a/gst/audioparsers/gstflacparse.c b/gst/audioparsers/gstflacparse.c index 0d21c4c0e..8306e8e8b 100644 --- a/gst/audioparsers/gstflacparse.c +++ b/gst/audioparsers/gstflacparse.c @@ -193,13 +193,11 @@ static void gst_flac_parse_get_property (GObject * object, guint prop_id, static gboolean gst_flac_parse_start (GstBaseParse * parse); static gboolean gst_flac_parse_stop (GstBaseParse * parse); static gboolean gst_flac_parse_check_valid_frame (GstBaseParse * parse, - GstBuffer * buffer, guint * framesize, gint * skipsize); + GstBaseParseFrame * frame, guint * framesize, gint * skipsize); static GstFlowReturn gst_flac_parse_parse_frame (GstBaseParse * parse, - GstBuffer * buffer); -static gint gst_flac_parse_get_frame_overhead (GstBaseParse * parse, - GstBuffer * buffer); -static GstFlowReturn gst_flac_parse_pre_push_buffer (GstBaseParse * parse, - GstBuffer * buf); + GstBaseParseFrame * frame); +static GstFlowReturn gst_flac_parse_pre_push_frame (GstBaseParse * parse, + GstBaseParseFrame * frame); GST_BOILERPLATE (GstFlacParse, gst_flac_parse, GstBaseParse, GST_TYPE_BASE_PARSE); @@ -244,10 +242,8 @@ gst_flac_parse_class_init (GstFlacParseClass * klass) baseparse_class->check_valid_frame = GST_DEBUG_FUNCPTR (gst_flac_parse_check_valid_frame); baseparse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_flac_parse_parse_frame); - baseparse_class->get_frame_overhead = - GST_DEBUG_FUNCPTR (gst_flac_parse_get_frame_overhead); - baseparse_class->pre_push_buffer = - GST_DEBUG_FUNCPTR (gst_flac_parse_pre_push_buffer); + baseparse_class->pre_push_frame = + GST_DEBUG_FUNCPTR (gst_flac_parse_pre_push_frame); } static void @@ -330,6 +326,9 @@ gst_flac_parse_start (GstBaseParse * parse) /* "fLaC" marker */ gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), 4); + /* inform baseclass we can come up with ts, based on counters in packets */ + gst_base_parse_set_format (GST_BASE_PARSE (flacparse), + GST_BASE_PARSE_FORMAT_HAS_TIME, TRUE); return TRUE; } @@ -563,15 +562,17 @@ need_more_data: } static gboolean -gst_flac_parse_frame_is_valid (GstFlacParse * flacparse, GstBuffer * buffer, - guint * ret) +gst_flac_parse_frame_is_valid (GstFlacParse * flacparse, + GstBaseParseFrame * frame, guint * ret) { + GstBuffer *buffer; const guint8 *data; guint max, size, remaining; guint i, search_start, search_end; FrameHeaderCheckReturn header_ret; guint16 block_size; + buffer = frame->buffer; data = GST_BUFFER_DATA (buffer); size = GST_BUFFER_SIZE (buffer); @@ -621,7 +622,7 @@ gst_flac_parse_frame_is_valid (GstFlacParse * flacparse, GstBuffer * buffer, } /* For the last frame output everything to the end */ - if (G_UNLIKELY (gst_base_parse_get_drain (GST_BASE_PARSE (flacparse)))) { + if (G_UNLIKELY (GST_BASE_PARSE_FRAME_DRAIN (frame))) { if (flacparse->check_frame_checksums) { guint16 actual_crc = gst_flac_calculate_crc16 (data, size - 2); guint16 expected_crc = GST_READ_UINT16_BE (data + size - 2); @@ -648,9 +649,10 @@ need_more: static gboolean gst_flac_parse_check_valid_frame (GstBaseParse * parse, - GstBuffer * buffer, guint * framesize, gint * skipsize) + GstBaseParseFrame * frame, guint * framesize, gint * skipsize) { GstFlacParse *flacparse = GST_FLAC_PARSE (parse); + GstBuffer *buffer = frame->buffer; const guint8 *data = GST_BUFFER_DATA (buffer); if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < 4)) @@ -689,13 +691,13 @@ gst_flac_parse_check_valid_frame (GstBaseParse * parse, flacparse->sample_number = 0; GST_DEBUG_OBJECT (flacparse, "Found sync code"); - ret = gst_flac_parse_frame_is_valid (flacparse, buffer, &next); + ret = gst_flac_parse_frame_is_valid (flacparse, frame, &next); if (ret) { *framesize = next; return TRUE; } else { /* If we're at EOS and the frame was not valid, drop it! */ - if (G_UNLIKELY (gst_base_parse_get_drain (parse))) { + if (G_UNLIKELY (GST_BASE_PARSE_FRAME_DRAIN (frame))) { GST_WARNING_OBJECT (flacparse, "EOS"); return FALSE; } @@ -898,7 +900,7 @@ static void gst_flac_parse_process_seektable (GstFlacParse * flacparse, gint64 boffset) { GstByteReader br; - gint64 offset, samples; + gint64 offset = 0, samples = 0; GST_DEBUG_OBJECT (flacparse, "parsing seektable; base offset %" G_GINT64_FORMAT, boffset); @@ -961,6 +963,7 @@ gst_flac_parse_handle_headers (GstFlacParse * flacparse) GValue array = { 0, }; GstCaps *caps; GList *l; + gboolean res = TRUE; caps = gst_caps_new_simple ("audio/x-flac", "channels", G_TYPE_INT, flacparse->channels, @@ -1040,23 +1043,32 @@ push_headers: /* push header buffers; update caps, so when we push the first buffer the * negotiated caps will change to caps that include the streamheader field */ - for (l = flacparse->headers; l != NULL; l = l->next) { - GstBuffer *buf = GST_BUFFER (l->data); + while (flacparse->headers) { + GstBuffer *buf = GST_BUFFER (flacparse->headers->data); GstFlowReturn ret; + GstBaseParseFrame frame; - l->data = NULL; + flacparse->headers = + g_list_delete_link (flacparse->headers, flacparse->headers); buf = gst_buffer_make_metadata_writable (buf); gst_buffer_set_caps (buf, GST_PAD_CAPS (GST_BASE_PARSE_SRC_PAD (GST_BASE_PARSE (flacparse)))); - ret = gst_base_parse_push_buffer (GST_BASE_PARSE (flacparse), buf); - if (ret != GST_FLOW_OK) - return FALSE; + /* init, set and give away frame */ + gst_base_parse_frame_init (GST_BASE_PARSE (flacparse), &frame); + frame.buffer = buf; + frame.overhead = -1; + ret = gst_base_parse_push_frame (GST_BASE_PARSE (flacparse), &frame); + if (ret != GST_FLOW_OK) { + res = FALSE; + break; + } } + g_list_foreach (flacparse->headers, (GFunc) gst_mini_object_unref, NULL); g_list_free (flacparse->headers); flacparse->headers = NULL; - return TRUE; + return res; } static gboolean @@ -1170,9 +1182,10 @@ gst_flac_parse_generate_headers (GstFlacParse * flacparse) } static GstFlowReturn -gst_flac_parse_parse_frame (GstBaseParse * parse, GstBuffer * buffer) +gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) { GstFlacParse *flacparse = GST_FLAC_PARSE (parse); + GstBuffer *buffer = frame->buffer; const guint8 *data = GST_BUFFER_DATA (buffer); if (flacparse->state == GST_FLAC_PARSE_STATE_INIT) { @@ -1307,6 +1320,11 @@ gst_flac_parse_parse_frame (GstBaseParse * parse, GstBuffer * buffer) GST_BUFFER_DURATION (buffer) = GST_BUFFER_OFFSET (buffer) - GST_BUFFER_TIMESTAMP (buffer); + /* To simplify, we just assume that it's a fixed size header and ignore + * subframe headers. The first could lead us to being off by 88 bits and + * the second even less, so the total inaccuracy is negligible. */ + frame->overhead = 7; + /* Minimal size of a frame header */ gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), MAX (9, flacparse->min_framesize)); @@ -1319,22 +1337,8 @@ gst_flac_parse_parse_frame (GstBaseParse * parse, GstBuffer * buffer) } } -static gint -gst_flac_parse_get_frame_overhead (GstBaseParse * parse, GstBuffer * buffer) -{ - GstFlacParse *flacparse = GST_FLAC_PARSE (parse); - - if (flacparse->state != GST_FLAC_PARSE_STATE_DATA) - return -1; - else - /* To simplify, we just assume that it's a fixed size header and ignore - * subframe headers. The first could lead us to being off by 88 bits and - * the second even less, so the total inaccuracy is negligible. */ - return 7; -} - static GstFlowReturn -gst_flac_parse_pre_push_buffer (GstBaseParse * parse, GstBuffer * buf) +gst_flac_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame) { GstFlacParse *flacparse = GST_FLAC_PARSE (parse); @@ -1344,5 +1348,7 @@ gst_flac_parse_pre_push_buffer (GstBaseParse * parse, GstBuffer * buf) flacparse->tags = NULL; } - return GST_BASE_PARSE_FLOW_CLIP; + frame->flags |= GST_BASE_PARSE_FRAME_FLAG_CLIP; + + return GST_FLOW_OK; } diff --git a/gst/audioparsers/gstflacparse.h b/gst/audioparsers/gstflacparse.h index 3394115f9..664b2a6bc 100644 --- a/gst/audioparsers/gstflacparse.h +++ b/gst/audioparsers/gstflacparse.h @@ -25,7 +25,7 @@ #define __GST_FLAC_PARSE_H__ #include <gst/gst.h> -#include "gstbaseparse.h" +#include <gst/baseparse/gstbaseparse.h> G_BEGIN_DECLS diff --git a/gst/audioparsers/gstmpegaudioparse.c b/gst/audioparsers/gstmpegaudioparse.c index 889efec1f..b9ad66a43 100644 --- a/gst/audioparsers/gstmpegaudioparse.c +++ b/gst/audioparsers/gstmpegaudioparse.c @@ -82,11 +82,11 @@ static void gst_mpeg_audio_parse_finalize (GObject * object); static gboolean gst_mpeg_audio_parse_start (GstBaseParse * parse); static gboolean gst_mpeg_audio_parse_stop (GstBaseParse * parse); static gboolean gst_mpeg_audio_parse_check_valid_frame (GstBaseParse * parse, - GstBuffer * buffer, guint * size, gint * skipsize); + GstBaseParseFrame * frame, guint * size, gint * skipsize); static GstFlowReturn gst_mpeg_audio_parse_parse_frame (GstBaseParse * parse, - GstBuffer * buf); -static GstFlowReturn gst_mpeg_audio_parse_pre_push_buffer (GstBaseParse * parse, - GstBuffer * buf); + GstBaseParseFrame * frame); +static GstFlowReturn gst_mpeg_audio_parse_pre_push_frame (GstBaseParse * parse, + GstBaseParseFrame * frame); static gboolean gst_mpeg_audio_parse_convert (GstBaseParse * parse, GstFormat src_format, gint64 src_value, GstFormat dest_format, gint64 * dest_value); @@ -164,8 +164,8 @@ gst_mpeg_audio_parse_class_init (GstMpegAudioParseClass * klass) GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_check_valid_frame); parse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_parse_frame); - parse_class->pre_push_buffer = - GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_pre_push_buffer); + parse_class->pre_push_frame = + GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_pre_push_frame); parse_class->convert = GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_convert); /* register tags */ @@ -189,6 +189,8 @@ gst_mpeg_audio_parse_reset (GstMpegAudioParse * mp3parse) mp3parse->last_posted_crc = CRC_UNKNOWN; mp3parse->last_posted_channel_mode = MPEG_AUDIO_CHANNEL_MODE_UNKNOWN; + mp3parse->hdr_bitrate = 0; + mp3parse->xing_flags = 0; mp3parse->xing_bitrate = 0; mp3parse->xing_frames = 0; @@ -470,11 +472,12 @@ gst_mpeg_audio_parse_head_check (GstMpegAudioParse * mp3parse, } static gboolean -gst_mpeg_audio_parse_check_valid_frame (GstBaseParse * parse, GstBuffer * buf, - guint * framesize, gint * skipsize) +gst_mpeg_audio_parse_check_valid_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, guint * framesize, gint * skipsize) { - GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buf); GstMpegAudioParse *mp3parse = GST_MPEG_AUDIO_PARSE (parse); + GstBuffer *buf = frame->buffer; + GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buf); gint off, bpf; gboolean sync, drain, valid, caps_change; guint32 header; @@ -519,8 +522,8 @@ gst_mpeg_audio_parse_check_valid_frame (GstBaseParse * parse, GstBuffer * buf, else caps_change = FALSE; - sync = gst_base_parse_get_sync (parse); - drain = gst_base_parse_get_drain (parse); + sync = GST_BASE_PARSE_FRAME_SYNC (frame); + drain = GST_BASE_PARSE_FRAME_DRAIN (frame); if (!drain && (!sync || caps_change)) { if (!gst_mp3parse_validate_extended (mp3parse, buf, header, bpf, drain, @@ -900,9 +903,11 @@ gst_mpeg_audio_parse_handle_first_frame (GstMpegAudioParse * mp3parse, } static GstFlowReturn -gst_mpeg_audio_parse_parse_frame (GstBaseParse * parse, GstBuffer * buf) +gst_mpeg_audio_parse_parse_frame (GstBaseParse * parse, + GstBaseParseFrame * frame) { GstMpegAudioParse *mp3parse = GST_MPEG_AUDIO_PARSE (parse); + GstBuffer *buf = frame->buffer; guint bitrate, layer, rate, channels, version, mode, crc; g_return_val_if_fail (GST_BUFFER_SIZE (buf) >= 4, GST_FLOW_ERROR); @@ -955,6 +960,8 @@ gst_mpeg_audio_parse_parse_frame (GstBaseParse * parse, GstBuffer * buf) (version == 1) ? 10 : 30, 2); } + mp3parse->hdr_bitrate = bitrate; + /* For first frame; check for seek tables and output a codec tag */ gst_mpeg_audio_parse_handle_first_frame (mp3parse, buf); @@ -1122,7 +1129,8 @@ gst_mpeg_audio_parse_convert (GstBaseParse * parse, GstFormat src_format, } static GstFlowReturn -gst_mpeg_audio_parse_pre_push_buffer (GstBaseParse * parse, GstBuffer * buf) +gst_mpeg_audio_parse_pre_push_frame (GstBaseParse * parse, + GstBaseParseFrame * frame) { GstMpegAudioParse *mp3parse = GST_MPEG_AUDIO_PARSE (parse); GstTagList *taglist; @@ -1144,6 +1152,13 @@ gst_mpeg_audio_parse_pre_push_buffer (GstBaseParse * parse, GstBuffer * buf) taglist = gst_tag_list_new (); gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_AUDIO_CODEC, codec, NULL); + if (mp3parse->hdr_bitrate > 0 && mp3parse->xing_bitrate == 0 && + mp3parse->vbri_bitrate == 0) { + /* We don't have a VBR bitrate, so post the available bitrate as + * nominal and let baseparse calculate the real bitrate */ + gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, + GST_TAG_NOMINAL_BITRATE, mp3parse->hdr_bitrate, NULL); + } gst_element_found_tags_for_pad (GST_ELEMENT (mp3parse), GST_BASE_PARSE_SRC_PAD (mp3parse), taglist); g_free (codec); @@ -1188,5 +1203,7 @@ gst_mpeg_audio_parse_pre_push_buffer (GstBaseParse * parse, GstBuffer * buf) } /* usual clipping applies */ - return GST_BASE_PARSE_FLOW_CLIP; + frame->flags |= GST_BASE_PARSE_FRAME_FLAG_CLIP; + + return GST_FLOW_OK; } diff --git a/gst/audioparsers/gstmpegaudioparse.h b/gst/audioparsers/gstmpegaudioparse.h index 0b4dad775..3f680d1e5 100644 --- a/gst/audioparsers/gstmpegaudioparse.h +++ b/gst/audioparsers/gstmpegaudioparse.h @@ -24,7 +24,7 @@ #define __GST_MPEG_AUDIO_PARSE_H__ #include <gst/gst.h> -#include "gstbaseparse.h" +#include <gst/baseparse/gstbaseparse.h> G_BEGIN_DECLS @@ -65,6 +65,9 @@ struct _GstMpegAudioParse { gint last_posted_crc, last_crc; guint last_posted_channel_mode, last_mode; + /* Bitrate from non-vbr headers */ + guint32 hdr_bitrate; + /* Xing info */ guint32 xing_flags; guint32 xing_frames; diff --git a/gst/autoconvert/Makefile.am b/gst/autoconvert/Makefile.am index 28fc01557..e57b9bc6c 100644 --- a/gst/autoconvert/Makefile.am +++ b/gst/autoconvert/Makefile.am @@ -1,9 +1,10 @@ plugin_LTLIBRARIES = libgstautoconvert.la -libgstautoconvert_la_SOURCES = gstautoconvert.c gstautoconvert.h +libgstautoconvert_la_SOURCES = gstautoconvert.c gstautovideoconvert.c plugin.c libgstautoconvert_la_CFLAGS = $(GST_CFLAGS) libgstautoconvert_la_LIBADD = $(GST_LIBS) libgstautoconvert_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstautoconvert_la_LIBTOOLFLAGS = --tag=disable-static +noinst_HEADERS = gstautoconvert.h gstautovideoconvert.h diff --git a/gst/autoconvert/gstautoconvert.c b/gst/autoconvert/gstautoconvert.c index 3c254f6de..0cf7e0874 100644 --- a/gst/autoconvert/gstautoconvert.c +++ b/gst/autoconvert/gstautoconvert.c @@ -547,8 +547,8 @@ gst_auto_convert_add_element (GstAutoConvert * autoconvert, GstElement *element = NULL; GstPad *internal_sinkpad = NULL; GstPad *internal_srcpad = NULL; - GstPad *sinkpad; - GstPad *srcpad; + GstPad *sinkpad = NULL; + GstPad *srcpad = NULL; GstPadLinkReturn padlinkret; GST_DEBUG_OBJECT (autoconvert, "Adding element %s to the autoconvert bin", @@ -587,6 +587,10 @@ gst_auto_convert_add_element (GstAutoConvert * autoconvert, if (!internal_sinkpad || !internal_srcpad) { GST_ERROR_OBJECT (autoconvert, "Could not create internal pads"); + if (internal_srcpad) + gst_object_unref (internal_srcpad); + if (internal_sinkpad) + gst_object_unref (internal_sinkpad); goto error; } @@ -652,11 +656,19 @@ gst_auto_convert_add_element (GstAutoConvert * autoconvert, /* Increment the reference count we will return to the caller */ gst_object_ref (element); + /* unref sink and src pad */ + gst_object_unref (srcpad); + gst_object_unref (sinkpad); return element; error: gst_bin_remove (GST_BIN (autoconvert), element); + if (srcpad) + gst_object_unref (srcpad); + if (sinkpad) + gst_object_unref (sinkpad); + return NULL; } @@ -707,8 +719,8 @@ factory_can_intersect (GstAutoConvert * autoconvert, GstStaticPadTemplate *template = (GstStaticPadTemplate *) templates->data; if (template->direction == direction) { - GstCaps *intersect = NULL; GstCaps *tmpl_caps = NULL; + gboolean intersect; /* If there is more than one pad in this direction, we return FALSE * Only transform elements (with one sink and one source pad) @@ -723,18 +735,14 @@ factory_can_intersect (GstAutoConvert * autoconvert, has_direction = TRUE; tmpl_caps = gst_static_caps_get (&template->static_caps); - intersect = gst_caps_intersect (tmpl_caps, caps); - GST_DEBUG_OBJECT (autoconvert, "Intersection of factory %" GST_PTR_FORMAT + intersect = gst_caps_can_intersect (tmpl_caps, caps); + GST_DEBUG_OBJECT (autoconvert, "Factories %" GST_PTR_FORMAT " static caps %" GST_PTR_FORMAT " and caps %" GST_PTR_FORMAT - " is %" GST_PTR_FORMAT, factory, tmpl_caps, caps, intersect); + " can%s intersect", factory, tmpl_caps, caps, + intersect ? "" : " not"); gst_caps_unref (tmpl_caps); - if (intersect) { - if (!gst_caps_is_empty (intersect)) - ret = TRUE; - - gst_caps_unref (intersect); - } + ret |= intersect; } templates = g_list_next (templates); } @@ -883,6 +891,8 @@ gst_auto_convert_sink_setcaps (GstPad * pad, GstCaps * caps) /* And make it the current child */ if (gst_auto_convert_activate_element (autoconvert, element, caps)) break; + else + gst_object_unref (element); } get_out: @@ -1552,6 +1562,7 @@ gst_auto_convert_internal_src_query_type (GstPad * pad) return ret; } +/* static gboolean gst_auto_convert_plugin_init (GstPlugin * plugin) { @@ -1565,3 +1576,4 @@ GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, "Selects convertor element based on caps", gst_auto_convert_plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) +*/ diff --git a/gst/autoconvert/gstautovideoconvert.c b/gst/autoconvert/gstautovideoconvert.c new file mode 100644 index 000000000..00ee6db47 --- /dev/null +++ b/gst/autoconvert/gstautovideoconvert.c @@ -0,0 +1,289 @@ +/* GStreamer + * Copyright 2010 ST-Ericsson SA + * @author: Benjamin Gaignard <benjamin.gaignard@stericsson.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/* + * test autovideoconvert: + * if rgb2bayer is present + * gst-launch videotestsrc num-buffers=2 ! "video/x-raw-rgb,width=100,height=100,framerate=10/1" ! autovideoconvert ! "video/x-raw-bayer,width=100,height=100,format=bggr,framerate=10/1" ! fakesink -v + * if bayer2rgb is present + * gst-launch videotestsrc num-buffers=2 ! "video/x-raw-bayer,width=100,height=100,format=bggr,framerate=10/1" ! autovideoconvert ! "video/x-raw-rgb,width=100,height=100,framerate=10/1" ! fakesink -v + * test with ffmpegvideoconvert + * gst-launch videotestsrc num-buffers=2 ! "video/x-raw-rgb,bpp=32,width=100,height=100,framerate=10/1" ! autovideoconvert ! "video/x-raw-rgb,bpp=16,width=100,height=100,framerate=10/1" ! fakesink -v + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> + +#include "gstautovideoconvert.h" + +GST_DEBUG_CATEGORY (autovideoconvert_debug); +#define GST_CAT_DEFAULT (autovideoconvert_debug) + +GStaticMutex factories_mutex = G_STATIC_MUTEX_INIT; +guint32 factories_cookie = 0; /* Cookie from last time when factories was updated */ +GList *factories = NULL; /* factories we can use for selecting elements */ + +/* element factory information */ +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + + +static GstStateChangeReturn gst_auto_video_convert_change_state (GstElement * + element, GstStateChange transition); + +void gst_auto_video_convert_update_factory_list (GstAutoVideoConvert * + autovideoconvert); + +static gboolean +gst_auto_video_convert_element_filter (GstPluginFeature * feature, + GstAutoVideoConvert * autovideoconvert) +{ + const gchar *klass; + + /* we only care about element factories */ + if (G_UNLIKELY (!GST_IS_ELEMENT_FACTORY (feature))) + return FALSE; + + klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY_CAST (feature)); + /* only select color space converter */ + if (strstr (klass, "Filter") && + strstr (klass, "Converter") && strstr (klass, "Video")) { + GST_DEBUG_OBJECT (autovideoconvert, + "gst_auto_video_convert_element_filter found %s\n", + gst_plugin_feature_get_name (GST_PLUGIN_FEATURE_CAST (feature))); + return TRUE; + } + return FALSE; +} + + +static GList * +gst_auto_video_convert_create_factory_list (GstAutoVideoConvert * + autovideoconvert) +{ + GList *result = NULL; + + /* get the feature list using the filter */ + result = gst_default_registry_feature_filter ((GstPluginFeatureFilter) + gst_auto_video_convert_element_filter, FALSE, autovideoconvert); + + /* sort on rank and name */ + result = g_list_sort (result, gst_plugin_feature_rank_compare_func); + + return result; +} + +void +gst_auto_video_convert_update_factory_list (GstAutoVideoConvert * + autovideoconvert) +{ + /* use a static mutex to protect factories list and factories cookie */ + g_static_mutex_lock (&factories_mutex); + + /* test if a factories list already exist or not */ + if (!factories) { + /* no factories list create it */ + factories_cookie = gst_default_registry_get_feature_list_cookie (); + factories = gst_auto_video_convert_create_factory_list (autovideoconvert); + } else { + /* a factories list exist but is it up to date? */ + if (factories_cookie != gst_default_registry_get_feature_list_cookie ()) { + /* we need to update the factories list */ + /* first free the old one */ + gst_plugin_feature_list_free (factories); + /* then create an updated one */ + factories_cookie = gst_default_registry_get_feature_list_cookie (); + factories = gst_auto_video_convert_create_factory_list (autovideoconvert); + } + } + + g_static_mutex_unlock (&factories_mutex); +} + +GST_BOILERPLATE (GstAutoVideoConvert, gst_auto_video_convert, GstBin, + GST_TYPE_BIN); + +static void +gst_auto_video_convert_base_init (gpointer klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&srctemplate)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sinktemplate)); + + gst_element_class_set_details_simple (element_class, + "Select color space convertor based on caps", "Generic/Bin", + "Selects the right color space convertor based on the caps", + "Benjamin Gaignard <benjamin.gaignard@stericsson.com>"); +} + +static void +gst_auto_video_convert_dispose (GObject * object) +{ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_auto_video_convert_class_init (GstAutoVideoConvertClass * klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + GstElementClass *gstelement_class = (GstElementClass *) klass; + + gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_auto_video_convert_dispose); + + GST_DEBUG_CATEGORY_INIT (autovideoconvert_debug, "autovideoconvert", 0, + "Auto color space converter"); + + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_auto_video_convert_change_state); + +} + +static gboolean +gst_auto_video_convert_add_autoconvert (GstAutoVideoConvert * autovideoconvert) +{ + GstPad *pad; + + if (autovideoconvert->autoconvert) + return TRUE; + + autovideoconvert->autoconvert = + gst_element_factory_make ("autoconvert", "autoconvertchild"); + if (!autovideoconvert->autoconvert) { + GST_ERROR_OBJECT (autovideoconvert, + "Could not create autoconvert instance"); + return FALSE; + } + + /* first add autoconvert in bin */ + gst_bin_add (GST_BIN (autovideoconvert), + gst_object_ref (autovideoconvert->autoconvert)); + + /* get sinkpad and link it to ghost sink pad */ + pad = gst_element_get_static_pad (autovideoconvert->autoconvert, "sink"); + gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (autovideoconvert->sinkpad), + pad); + gst_object_unref (pad); + + /* get srcpad and link it to ghost src pad */ + pad = gst_element_get_static_pad (autovideoconvert->autoconvert, "src"); + gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (autovideoconvert->srcpad), pad); + gst_object_unref (pad); + + return TRUE; +} + +static void +gst_auto_video_convert_remove_autoconvert (GstAutoVideoConvert * + autovideoconvert) +{ + if (!autovideoconvert->autoconvert) + return; + + gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (autovideoconvert->srcpad), + NULL); + gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (autovideoconvert->sinkpad), + NULL); + + gst_bin_remove (GST_BIN (autovideoconvert), autovideoconvert->autoconvert); + gst_object_unref (autovideoconvert->autoconvert); + autovideoconvert->autoconvert = NULL; +} + +static void +gst_auto_video_convert_init (GstAutoVideoConvert * autovideoconvert, + GstAutoVideoConvertClass * klass) +{ + GstPadTemplate *pad_tmpl; + + /* get sink pad template */ + pad_tmpl = gst_static_pad_template_get (&sinktemplate); + autovideoconvert->sinkpad = + gst_ghost_pad_new_no_target_from_template ("sink", pad_tmpl); + /* add sink ghost pad */ + gst_element_add_pad (GST_ELEMENT (autovideoconvert), + autovideoconvert->sinkpad); + gst_object_unref (pad_tmpl); + + /* get src pad template */ + pad_tmpl = gst_static_pad_template_get (&srctemplate); + autovideoconvert->srcpad = + gst_ghost_pad_new_no_target_from_template ("src", pad_tmpl); + /* add src ghost pad */ + gst_element_add_pad (GST_ELEMENT (autovideoconvert), + autovideoconvert->srcpad); + gst_object_unref (pad_tmpl); + + return; +} + +static GstStateChangeReturn +gst_auto_video_convert_change_state (GstElement * element, + GstStateChange transition) +{ + GstAutoVideoConvert *autovideoconvert = GST_AUTO_VIDEO_CONVERT (element); + GstStateChangeReturn ret; + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + { + /* create and add autoconvert in bin */ + if (!gst_auto_video_convert_add_autoconvert (autovideoconvert)) { + ret = GST_STATE_CHANGE_FAILURE; + return ret; + } + /* get an updated list of factories */ + gst_auto_video_convert_update_factory_list (autovideoconvert); + GST_DEBUG_OBJECT (autovideoconvert, "set factories list"); + /* give factory list to autoconvert */ + g_object_set (GST_ELEMENT (autovideoconvert->autoconvert), "factories", + factories, NULL); + break; + } + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + if (ret == GST_STATE_CHANGE_FAILURE) + return ret; + + switch (transition) { + case GST_STATE_CHANGE_READY_TO_NULL: + { + gst_auto_video_convert_remove_autoconvert (autovideoconvert); + break; + } + default: + break; + } + + return ret; +} diff --git a/gst/autoconvert/gstautovideoconvert.h b/gst/autoconvert/gstautovideoconvert.h new file mode 100644 index 000000000..9136efaed --- /dev/null +++ b/gst/autoconvert/gstautovideoconvert.h @@ -0,0 +1,55 @@ +/* GStreamer + * Copyright 2010 ST-Ericsson SA + * @author: Benjamin Gaignard <benjamin.gaignard@stericsson.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_AUTO_VIDEO_CONVERT_H__ +#define __GST_AUTO_VIDEO_CONVERT_H__ + +#include <gst/gst.h> +#include <gst/gstbin.h> +#include "gstautoconvert.h" + +G_BEGIN_DECLS +#define GST_TYPE_AUTO_VIDEO_CONVERT (gst_auto_video_convert_get_type()) +#define GST_AUTO_VIDEO_CONVERT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_AUTO_VIDEO_CONVERT,GstAutoVideoConvert)) +#define GST_AUTO_VIDEO_CONVERT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_AUTO_VIDEO_CONVERT,GstAutoVideoConvertClass)) +#define GST_IS_AUTO_VIDEO_CONVERT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_AUTO_VIDEO_CONVERT)) +#define GST_IS_AUTO_VIDEO_CONVERT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_AUTO_VIDEO_CONVERT)) +typedef struct _GstAutoVideoConvert GstAutoVideoConvert; +typedef struct _GstAutoVideoConvertClass GstAutoVideoConvertClass; + +struct _GstAutoVideoConvert +{ + /*< private > */ + GstBin bin; /* we extend GstBin */ + + GstElement *autoconvert; + GstPad *sinkpad; + GstPad *srcpad; +}; + +struct _GstAutoVideoConvertClass +{ + GstBinClass parent_class; +}; + +GType gst_auto_video_convert_get_type (void); + +G_END_DECLS +#endif /* __GST_AUTO_VIDEO_CONVERT_H__ */ diff --git a/gst/selector/gstselector.c b/gst/autoconvert/plugin.c index 008e45756..0de71d3bb 100644 --- a/gst/selector/gstselector.c +++ b/gst/autoconvert/plugin.c @@ -1,6 +1,7 @@ /* GStreamer - * Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.com>) - * + * Copyright 2010 ST-Ericsson SA + * @author: Benjamin Gaignard <benjamin.gaignard@stericsson.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 @@ -21,24 +22,25 @@ #include "config.h" #endif -#include <gst/gst.h> - -#include "gstinputselector.h" -#include "gstoutputselector.h" - +#include "gstautoconvert.h" +#include "gstautovideoconvert.h" static gboolean plugin_init (GstPlugin * plugin) { + gboolean ret; + + ret = gst_element_register (plugin, "autoconvert", + GST_RANK_NONE, GST_TYPE_AUTO_CONVERT); + + ret &= gst_element_register (plugin, "autovideoconvert", + GST_RANK_NONE, GST_TYPE_AUTO_VIDEO_CONVERT); - return gst_element_register (plugin, "input-selector", - GST_RANK_NONE, GST_TYPE_INPUT_SELECTOR) && - gst_element_register (plugin, "output-selector", - GST_RANK_NONE, GST_TYPE_OUTPUT_SELECTOR); + return ret; } GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, - "selector", - "input/output stream selector elements", + "autoconvert", + "Selects convertor element based on caps", plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/gst/bayer/gstbayer2rgb.c b/gst/bayer/gstbayer2rgb.c index c8c0640f4..67aaa4229 100644 --- a/gst/bayer/gstbayer2rgb.c +++ b/gst/bayer/gstbayer2rgb.c @@ -139,7 +139,7 @@ struct _GstBayer2RGBClass GST_VIDEO_CAPS_BGR #define SINK_CAPS "video/x-raw-bayer,format=(string){bggr,grbg,gbrg,rggb}," \ - "width=(int)[1,MAX],height=(int)[1,MAX]" + "width=(int)[1,MAX],height=(int)[1,MAX],framerate=(fraction)[0/1,MAX]" enum { diff --git a/gst/camerabin/Makefile.am b/gst/camerabin/Makefile.am index d77dae464..7d7e55576 100644 --- a/gst/camerabin/Makefile.am +++ b/gst/camerabin/Makefile.am @@ -16,6 +16,7 @@ plugin_LTLIBRARIES = libgstcamerabin.la libgstcamerabin_la_SOURCES = gstcamerabin.c \ gstcamerabincolorbalance.c \ + gstinputselector.c \ camerabinimage.c \ camerabinvideo.c \ camerabingeneral.c \ @@ -37,6 +38,7 @@ libgstcamerabin_la_LIBTOOLFLAGS = --tag=disable-static noinst_HEADERS = gstcamerabin.h \ gstcamerabincolorbalance.h \ + gstinputselector.h \ camerabinimage.h \ camerabinvideo.h \ camerabindebug.h \ diff --git a/gst/camerabin/camerabingeneral.c b/gst/camerabin/camerabingeneral.c index f1cf35da0..f47b9d23b 100644 --- a/gst/camerabin/camerabingeneral.c +++ b/gst/camerabin/camerabingeneral.c @@ -27,9 +27,10 @@ * */ #include <string.h> +#include <glib.h> #include "camerabingeneral.h" -#include <glib.h> +#include "gstinputselector.h" GST_DEBUG_CATEGORY (gst_camerabin_debug); @@ -113,6 +114,7 @@ gst_camerabin_try_add_element (GstBin * bin, GstElement * new_elem) * gst_camerabin_create_and_add_element: * @bin: tries adding an element to this bin * @elem_name: name of the element to be created + * @instance_name: name of the instance of the element to be created * * Creates an element according to given name and * adds it to given @bin. Looks for an unconnected src pad @@ -121,14 +123,23 @@ gst_camerabin_try_add_element (GstBin * bin, GstElement * new_elem) * Returns: pointer to the new element if successful, NULL otherwise. */ GstElement * -gst_camerabin_create_and_add_element (GstBin * bin, const gchar * elem_name) +gst_camerabin_create_and_add_element (GstBin * bin, const gchar * elem_name, + const gchar * instance_name) { GstElement *new_elem; g_return_val_if_fail (bin, FALSE); g_return_val_if_fail (elem_name, FALSE); - new_elem = gst_element_factory_make (elem_name, NULL); + if (strcmp (elem_name, "input-selector") == 0) { + /* we ship our own copy of input-selector because we still use the + * "select-all" property which was removed when input-selector was + * moved to core */ + new_elem = g_object_new (GST_TYPE_INPUT_SELECTOR, NULL); + } else { + new_elem = gst_element_factory_make (elem_name, NULL); + } + if (!new_elem) { GST_ELEMENT_ERROR (bin, CORE, MISSING_PLUGIN, (NULL), ("could not create \"%s\" element.", elem_name)); diff --git a/gst/camerabin/camerabingeneral.h b/gst/camerabin/camerabingeneral.h index 0e84e4ad2..12a4d4693 100644 --- a/gst/camerabin/camerabingeneral.h +++ b/gst/camerabin/camerabingeneral.h @@ -25,7 +25,7 @@ gboolean gst_camerabin_try_add_element (GstBin * bin, GstElement * new_elem); gboolean gst_camerabin_add_element (GstBin * bin, GstElement * new_elem); -GstElement *gst_camerabin_create_and_add_element (GstBin * bin, const gchar * elem_name); +GstElement *gst_camerabin_create_and_add_element (GstBin * bin, const gchar * elem_name, const gchar * instance_name); GstElement * gst_camerabin_setup_default_element (GstBin * bin, GstElement *user_elem, const gchar *auto_elem_name, const gchar *default_elem_name); diff --git a/gst/camerabin/camerabinimage.c b/gst/camerabin/camerabinimage.c index 8b94d7d22..2aa858d88 100644 --- a/gst/camerabin/camerabinimage.c +++ b/gst/camerabin/camerabinimage.c @@ -196,7 +196,14 @@ gst_camerabin_image_dispose (GstCameraBinImage * img) } + /* Note: if imagebin was never set to READY state the + ownership of elements created by application were never + taken by bin and therefore gst_object_sink is called for + these elements (they may still be in floating state + and not unreffed properly without sinking first) + */ if (img->app_enc) { + gst_object_sink (img->app_enc); GST_LOG_OBJECT (img, "disposing %s with refcount %d", GST_ELEMENT_NAME (img->app_enc), GST_OBJECT_REFCOUNT_VALUE (img->app_enc)); @@ -205,6 +212,7 @@ gst_camerabin_image_dispose (GstCameraBinImage * img) } if (img->post) { + gst_object_sink (img->post); GST_LOG_OBJECT (img, "disposing %s with refcount %d", GST_ELEMENT_NAME (img->post), GST_OBJECT_REFCOUNT_VALUE (img->post)); gst_object_unref (img->post); diff --git a/gst/camerabin/camerabinpreview.c b/gst/camerabin/camerabinpreview.c index 028297eaf..5f46d0628 100644 --- a/gst/camerabin/camerabinpreview.c +++ b/gst/camerabin/camerabinpreview.c @@ -60,124 +60,133 @@ create_element (const gchar * factory_name, const gchar * elem_name, /** * gst_camerabin_preview_create_pipeline: + * @element: #GstCameraBin element * @caps: pointer to the caps used in pipeline + * @src_filter: source filter element * * Create a preview converter pipeline that outputs the format defined in * @caps parameter. * - * Returns: New pipeline, or NULL if error occured. + * Returns: New pipeline data structure, or NULL if error occured. */ -GstElement * -gst_camerabin_preview_create_pipeline (GstCameraBin * camera, GstCaps * caps, +GstCameraBinPreviewPipelineData * +gst_camerabin_preview_create_pipeline (GstElement * element, GstCaps * caps, GstElement * src_filter) { - GstElement *pipe, *src, *csp, *filter, *vscale, *sink; + GstElement *csp = NULL, *vscale = NULL; GError *error = NULL; + GstCameraBinPreviewPipelineData *data; - g_return_val_if_fail (caps != NULL, FALSE); + g_return_val_if_fail (caps != NULL, NULL); GST_DEBUG ("creating elements"); - if (!create_element ("appsrc", "prev_src", &src, &error) || - !create_element ("videoscale", NULL, &vscale, &error) || - !create_element ("ffmpegcolorspace", NULL, &csp, &error) || - !create_element ("capsfilter", NULL, &filter, &error) || - !create_element ("fakesink", "prev_sink", &sink, &error)) - goto no_elements; + data = g_new (GstCameraBinPreviewPipelineData, 1); /* We have multiple pipelines created by using this function, so we can't * give a name to them. Another way would to ensure the uniqueness of the * name here*/ - pipe = gst_pipeline_new (NULL); - if (pipe == NULL) - goto no_pipeline; + data->pipeline = gst_pipeline_new (NULL); + if (!data->pipeline) + goto create_error; + + if (!create_element ("appsrc", "prev_src", &data->appsrc, &error) || + !create_element ("videoscale", NULL, &vscale, &error) || + !create_element ("ffmpegcolorspace", NULL, &csp, &error) || + !create_element ("capsfilter", NULL, &data->capsfilter, &error) || + !create_element ("fakesink", "prev_sink", &data->appsink, &error)) + goto create_error; GST_DEBUG ("adding elements"); - gst_bin_add_many (GST_BIN (pipe), src, csp, filter, vscale, sink, NULL); + gst_bin_add_many (GST_BIN (data->pipeline), data->appsrc, csp, + data->capsfilter, vscale, data->appsink, NULL); if (src_filter) { - gst_bin_add (GST_BIN (pipe), src_filter); + gst_bin_add (GST_BIN (data->pipeline), src_filter); } + data->element = element; + GST_DEBUG ("preview format is: %" GST_PTR_FORMAT, caps); - g_object_set (filter, "caps", caps, NULL); - g_object_set (sink, "preroll-queue-len", 1, "signal-handoffs", TRUE, NULL); + g_object_set (data->capsfilter, "caps", caps, NULL); + g_object_set (data->appsink, "preroll-queue-len", 1, "signal-handoffs", TRUE, + NULL); g_object_set (vscale, "method", 0, NULL); - /* FIXME: linking is still way too expensive, profile this properly */ GST_DEBUG ("linking src->vscale"); - if (!gst_element_link_pads_full (src, "src", vscale, "sink", - GST_PAD_LINK_CHECK_CAPS)) - return FALSE; + if (!gst_element_link_pads (data->appsrc, "src", vscale, "sink")) + goto link_error; if (src_filter) { - GST_DEBUG ("linking vscale->filter"); - if (!gst_element_link_pads_full (vscale, "src", src_filter, "sink", - GST_PAD_LINK_CHECK_CAPS)) { - return FALSE; + GST_DEBUG ("linking vscale->src_filter"); + if (!gst_element_link_pads (vscale, "src", src_filter, "sink")) { + goto link_error; } GST_DEBUG ("linking filter->csp"); - if (!gst_element_link_pads_full (src_filter, "src", csp, "sink", - GST_PAD_LINK_CHECK_CAPS)) { - return FALSE; + if (!gst_element_link_pads (src_filter, "src", csp, "sink")) { + goto link_error; } } else { GST_DEBUG ("linking vscale->csp"); - if (!gst_element_link_pads_full (vscale, "src", csp, "sink", - GST_PAD_LINK_CHECK_CAPS)) - return FALSE; + if (!gst_element_link_pads (vscale, "src", csp, "sink")) + goto link_error; } GST_DEBUG ("linking csp->capsfilter"); - if (!gst_element_link_pads_full (csp, "src", filter, "sink", - GST_PAD_LINK_CHECK_CAPS)) - return FALSE; + if (!gst_element_link_pads (csp, "src", data->capsfilter, "sink")) + goto link_error; GST_DEBUG ("linking capsfilter->sink"); - if (!gst_element_link_pads_full (filter, "src", sink, "sink", - GST_PAD_LINK_CHECK_CAPS)) - return FALSE; + if (!gst_element_link_pads (data->capsfilter, "src", data->appsink, "sink")) + goto link_error; - return pipe; + return data; - /* ERRORS */ -no_elements: - { - g_warning ("Could not make preview pipeline: %s", error->message); +create_error: + if (error) { + GST_WARNING ("Preview pipeline element creation failed: %s", + error->message); g_error_free (error); - return NULL; - } -no_pipeline: - { - g_warning ("Could not make preview pipeline: %s", - "no pipeline (unknown error)"); - return NULL; } + if (csp) + gst_object_unref (csp); + if (vscale) + gst_object_unref (vscale); + if (data->appsrc) + gst_object_unref (data->appsrc); + if (data->capsfilter) + gst_object_unref (data->capsfilter); + if (data->appsink) + gst_object_unref (data->appsink); + +link_error: + GST_WARNING ("Could not create preview pipeline"); + gst_camerabin_preview_destroy_pipeline (data); + + return NULL; } /** * gst_camerabin_preview_destroy_pipeline: - * @camera: camerabin object - * @pipeline: the pipeline to be destroyed + * @data: the pipeline data to be destroyed * * Destroy preview converter pipeline. */ void -gst_camerabin_preview_destroy_pipeline (GstCameraBin * camera, - GstElement * pipeline) +gst_camerabin_preview_destroy_pipeline (GstCameraBinPreviewPipelineData * data) { - g_return_if_fail (pipeline != NULL); - - gst_element_set_state (pipeline, GST_STATE_NULL); - gst_object_unref (pipeline); + if (data->pipeline) { + gst_element_set_state (data->pipeline, GST_STATE_NULL); + gst_object_unref (data->pipeline); + } + g_free (data); } /** * gst_camerabin_preview_convert: - * @camera: camerabin object - * @pipeline: preview pipeline to use + * @data: preview pipeline data to use * @buf: #GstBuffer that contains the frame to be converted * * Create a preview image of the given frame. @@ -185,8 +194,8 @@ gst_camerabin_preview_destroy_pipeline (GstCameraBin * camera, * Returns: converted preview image, or NULL if operation failed. */ GstBuffer * -gst_camerabin_preview_convert (GstCameraBin * camera, - GstElement * pipeline, GstBuffer * buf) +gst_camerabin_preview_convert (GstCameraBinPreviewPipelineData * data, + GstBuffer * buf) { GstMessage *msg; GstBuffer *result = NULL; @@ -198,13 +207,13 @@ gst_camerabin_preview_convert (GstCameraBin * camera, g_return_val_if_fail (GST_BUFFER_CAPS (buf) != NULL, NULL); - if (pipeline == NULL) { + if (data->pipeline == NULL) { GST_WARNING ("pipeline is NULL"); goto no_pipeline; } - src = gst_bin_get_by_name (GST_BIN (pipeline), "prev_src"); - sink = gst_bin_get_by_name (GST_BIN (pipeline), "prev_sink"); + src = gst_bin_get_by_name (GST_BIN (data->pipeline), "prev_src"); + sink = gst_bin_get_by_name (GST_BIN (data->pipeline), "prev_sink"); if (!src || !sink) { GST_WARNING ("pipeline doesn't have src / sink elements"); @@ -222,11 +231,11 @@ gst_camerabin_preview_convert (GstCameraBin * camera, GST_DEBUG ("running conversion pipeline, source is: %" GST_PTR_FORMAT, GST_BUFFER_CAPS (buf)); - gst_element_set_state (pipeline, GST_STATE_PLAYING); + gst_element_set_state (data->pipeline, GST_STATE_PLAYING); g_signal_emit_by_name (src, "push-buffer", buf, &fret); - bus = gst_element_get_bus (pipeline); + bus = gst_element_get_bus (data->pipeline); msg = gst_bus_timed_pop_filtered (bus, (25 * GST_SECOND), GST_MESSAGE_ERROR | GST_MESSAGE_EOS); gst_object_unref (bus); @@ -268,7 +277,7 @@ gst_camerabin_preview_convert (GstCameraBin * camera, g_signal_handlers_disconnect_by_func (sink, G_CALLBACK (save_result), &result); - gst_element_set_state (pipeline, GST_STATE_READY); + gst_element_set_state (data->pipeline, GST_STATE_READY); GST_BUFFER_FLAGS (buf) = bflags; @@ -297,7 +306,7 @@ no_pipeline: /** * gst_camerabin_preview_send_event: - * @camera: the #GstCameraBin + * @data: preview pipeline data to use * @evt: The #GstEvent to be pushed, takes ownership * * Pushes an event to the preview pipeline. @@ -305,21 +314,50 @@ no_pipeline: * Returns: True if the event was handled */ gboolean -gst_camerabin_preview_send_event (GstCameraBin * camera, GstElement * pipeline, +gst_camerabin_preview_send_event (GstCameraBinPreviewPipelineData * data, GstEvent * evt) { GstElement *src; - gboolean ret = FALSE; - src = gst_bin_get_by_name (GST_BIN (pipeline), "prev_src"); + src = gst_bin_get_by_name (GST_BIN (data->pipeline), "prev_src"); if (!src) { GST_WARNING ("Preview pipeline doesn't have src element, can't push event"); gst_event_unref (evt); - } else { - GST_DEBUG_OBJECT (camera, "Pushing event %p to preview pipeline", evt); - ret = gst_element_send_event (src, evt); - gst_object_unref (src); + return FALSE; + } + + GST_DEBUG_OBJECT (data->element, "Pushing event %p to preview pipeline", evt); + + return gst_element_send_event (src, evt); +} + +/** + * gst_camerabin_preview_set_caps: + * @data: preview pipeline data to use + * @caps: New #GstCaps to be set for the pipeline + * + * Sets new caps for the preview pipeline + */ +void +gst_camerabin_preview_set_caps (GstCameraBinPreviewPipelineData * data, + GstCaps * caps) +{ + GstState state, pending; + GstStateChangeReturn ret; + + g_return_if_fail (data->pipeline != NULL); + g_return_if_fail (caps != NULL); + + ret = gst_element_get_state (data->pipeline, &state, &pending, 0); + if (ret == GST_STATE_CHANGE_FAILURE) { + /* make it try again */ + state = GST_STATE_PLAYING; + pending = GST_STATE_VOID_PENDING; } - return ret; + gst_element_set_state (data->pipeline, GST_STATE_NULL); + g_object_set (data->capsfilter, "caps", caps, NULL); + if (pending != GST_STATE_VOID_PENDING) + state = pending; + gst_element_set_state (data->pipeline, state); } diff --git a/gst/camerabin/camerabinpreview.h b/gst/camerabin/camerabinpreview.h index cde9f7b88..3da9a05b3 100644 --- a/gst/camerabin/camerabinpreview.h +++ b/gst/camerabin/camerabinpreview.h @@ -23,20 +23,35 @@ #include <gst/gst.h> -#include "gstcamerabin.h" - G_BEGIN_DECLS - GstElement * gst_camerabin_preview_create_pipeline (GstCameraBin * camera, - GstCaps * caps, GstElement * src_filter); -void gst_camerabin_preview_destroy_pipeline (GstCameraBin * camera, - GstElement * pipeline); +typedef struct +{ + GstElement *pipeline; + + GstElement *appsrc; + GstElement *capsfilter; + GstElement *appsink; + + GstElement *element; +} GstCameraBinPreviewPipelineData; + -GstBuffer *gst_camerabin_preview_convert (GstCameraBin * camera, - GstElement * pipeline, GstBuffer * buf); +GstCameraBinPreviewPipelineData * gst_camerabin_preview_create_pipeline ( + GstElement *element, GstCaps *caps, GstElement *src_filter); -gboolean gst_camerabin_preview_send_event (GstCameraBin * camera, - GstElement * pipeline, GstEvent * event); +void gst_camerabin_preview_destroy_pipeline ( + GstCameraBinPreviewPipelineData *data); + +GstBuffer *gst_camerabin_preview_convert ( + GstCameraBinPreviewPipelineData *data, GstBuffer *buf); + +gboolean gst_camerabin_preview_send_event ( + GstCameraBinPreviewPipelineData *pipeline, GstEvent *event); + +void gst_camerabin_preview_set_caps ( + GstCameraBinPreviewPipelineData *pipeline, GstCaps *caps); G_END_DECLS + #endif /* __CAMERABINPREVIEW_H__ */ diff --git a/gst/camerabin/camerabinvideo.c b/gst/camerabin/camerabinvideo.c index 6b0ed107b..257eed31f 100644 --- a/gst/camerabin/camerabinvideo.c +++ b/gst/camerabin/camerabinvideo.c @@ -215,27 +215,38 @@ gst_camerabin_video_dispose (GstCameraBinVideo * vid) vid->vid_sink_probe_id = 0; } + /* Note: if videobin was never set to READY state the + ownership of elements created by application were never + taken by bin and therefore gst_object_sink is called for + these elements (they may still be in floating state + and not unreffed properly without sinking first) + */ if (vid->app_post) { + gst_object_sink (vid->app_post); gst_object_unref (vid->app_post); vid->app_post = NULL; } if (vid->app_vid_enc) { + gst_object_sink (vid->app_vid_enc); gst_object_unref (vid->app_vid_enc); vid->app_vid_enc = NULL; } if (vid->app_aud_enc) { + gst_object_sink (vid->app_aud_enc); gst_object_unref (vid->app_aud_enc); vid->app_aud_enc = NULL; } if (vid->app_aud_src) { + gst_object_sink (vid->app_aud_src); gst_object_unref (vid->app_aud_src); vid->app_aud_src = NULL; } if (vid->app_mux) { + gst_object_sink (vid->app_mux); gst_object_unref (vid->app_mux); vid->app_mux = NULL; } @@ -542,7 +553,8 @@ gst_camerabin_video_create_elements (GstCameraBinVideo * vid) } /* Add tee element */ - if (!(vid->tee = gst_camerabin_create_and_add_element (vidbin, "tee"))) { + if (!(vid->tee = + gst_camerabin_create_and_add_element (vidbin, "tee", "video-tee"))) { goto error; } @@ -569,7 +581,7 @@ gst_camerabin_video_create_elements (GstCameraBinVideo * vid) if (vid->flags & GST_CAMERABIN_FLAG_VIDEO_COLOR_CONVERSION) { /* Add colorspace converter */ if (gst_camerabin_create_and_add_element (vidbin, - "ffmpegcolorspace") == NULL) { + "ffmpegcolorspace", "video-ffmpegcolorspace") == NULL) { goto error; } } @@ -581,7 +593,8 @@ gst_camerabin_video_create_elements (GstCameraBinVideo * vid) goto error; } } else if (!(vid->vid_enc = - gst_camerabin_create_and_add_element (vidbin, DEFAULT_VID_ENC))) { + gst_camerabin_create_and_add_element (vidbin, DEFAULT_VID_ENC, + "video-encoder"))) { goto error; } @@ -592,13 +605,15 @@ gst_camerabin_video_create_elements (GstCameraBinVideo * vid) goto error; } } else if (!(vid->muxer = - gst_camerabin_create_and_add_element (vidbin, DEFAULT_MUX))) { + gst_camerabin_create_and_add_element (vidbin, DEFAULT_MUX, + "video-muxer"))) { goto error; } /* Add sink element for storing the video */ if (!(vid->sink = - gst_camerabin_create_and_add_element (vidbin, DEFAULT_SINK))) { + gst_camerabin_create_and_add_element (vidbin, DEFAULT_SINK, + "video-sink"))) { goto error; } g_object_set (G_OBJECT (vid->sink), "location", vid->filename->str, "buffer-mode", 2, /* non buffered io */ @@ -648,7 +663,8 @@ gst_camerabin_video_create_elements (GstCameraBinVideo * vid) goto error; } } else if (!(vid->aud_enc = - gst_camerabin_create_and_add_element (vidbin, DEFAULT_AUD_ENC))) { + gst_camerabin_create_and_add_element (vidbin, DEFAULT_AUD_ENC, + "audio-encoder"))) { goto error; } diff --git a/gst/camerabin/gstcamerabin-marshal.list b/gst/camerabin/gstcamerabin-marshal.list index 40829e545..6bc959adb 100644 --- a/gst/camerabin/gstcamerabin-marshal.list +++ b/gst/camerabin/gstcamerabin-marshal.list @@ -4,3 +4,5 @@ VOID:INT,INT,INT,INT VOID:INT,INT BOOLEAN:STRING +INT64:VOID +VOID:OBJECT,INT64,INT64 diff --git a/gst/camerabin/gstcamerabin.c b/gst/camerabin/gstcamerabin.c index 0f43020c7..5704513c6 100644 --- a/gst/camerabin/gstcamerabin.c +++ b/gst/camerabin/gstcamerabin.c @@ -208,7 +208,9 @@ static guint camerabin_signals[LAST_SIGNAL]; #define DEFAULT_FLAGS GST_CAMERABIN_FLAG_SOURCE_RESIZE | \ GST_CAMERABIN_FLAG_VIEWFINDER_SCALE | \ - GST_CAMERABIN_FLAG_IMAGE_COLOR_CONVERSION + GST_CAMERABIN_FLAG_AUDIO_CONVERSION | \ + GST_CAMERABIN_FLAG_IMAGE_COLOR_CONVERSION | \ + GST_CAMERABIN_FLAG_VIDEO_COLOR_CONVERSION /* Using "bilinear" as default zoom method */ #define CAMERABIN_DEFAULT_ZOOM_METHOD 1 @@ -589,21 +591,26 @@ camerabin_create_src_elements (GstCameraBin * camera) goto done; } if (camera->flags & GST_CAMERABIN_FLAG_SOURCE_COLOR_CONVERSION) { - if (!gst_camerabin_create_and_add_element (cbin, "ffmpegcolorspace")) + if (!gst_camerabin_create_and_add_element (cbin, "ffmpegcolorspace", + "src-ffmpegcolorspace")) goto done; } if (!(camera->src_filter = - gst_camerabin_create_and_add_element (cbin, "capsfilter"))) + gst_camerabin_create_and_add_element (cbin, "capsfilter", + "src-capsfilter"))) goto done; if (camera->flags & GST_CAMERABIN_FLAG_SOURCE_RESIZE) { if (!(camera->src_zoom_crop = - gst_camerabin_create_and_add_element (cbin, "videocrop"))) + gst_camerabin_create_and_add_element (cbin, "videocrop", + "src-videocrop"))) goto done; if (!(camera->src_zoom_scale = - gst_camerabin_create_and_add_element (cbin, "videoscale"))) + gst_camerabin_create_and_add_element (cbin, "videoscale", + "src-videoscale"))) goto done; if (!(camera->src_zoom_filter = - gst_camerabin_create_and_add_element (cbin, "capsfilter"))) + gst_camerabin_create_and_add_element (cbin, "capsfilter", + "src-resize-capsfilter"))) goto done; } if (camera->app_video_filter) { @@ -612,9 +619,12 @@ camerabin_create_src_elements (GstCameraBin * camera) } } if (!(camera->src_out_sel = - gst_camerabin_create_and_add_element (cbin, "output-selector"))) + gst_camerabin_create_and_add_element (cbin, "output-selector", NULL))) goto done; + /* Set pad-negotiation-mode to active */ + g_object_set (camera->src_out_sel, "pad-negotiation-mode", 2, NULL); + /* Set default "driver-name" for v4l2camsrc if not set */ /* FIXME: v4l2camsrc specific */ if (g_object_class_find_property (G_OBJECT_GET_CLASS (camera->src_vid_src), @@ -676,7 +686,8 @@ camerabin_create_view_elements (GstCameraBin * camera) GstBin *cbin = GST_BIN (camera); if (!(camera->view_in_sel = - gst_camerabin_create_and_add_element (cbin, "input-selector"))) { + gst_camerabin_create_and_add_element (cbin, "input-selector", + NULL))) { goto error; } @@ -691,18 +702,21 @@ camerabin_create_view_elements (GstCameraBin * camera) /* Add videoscale in case we need to downscale frame for view finder */ if (camera->flags & GST_CAMERABIN_FLAG_VIEWFINDER_SCALE) { if (!(camera->view_scale = - gst_camerabin_create_and_add_element (cbin, "videoscale"))) { + gst_camerabin_create_and_add_element (cbin, "videoscale", + "vf-videoscale"))) { goto error; } /* Add capsfilter to maintain aspect ratio while scaling */ if (!(camera->aspect_filter = - gst_camerabin_create_and_add_element (cbin, "capsfilter"))) { + gst_camerabin_create_and_add_element (cbin, "capsfilter", + "vf-scale-capsfilter"))) { goto error; } } if (camera->flags & GST_CAMERABIN_FLAG_VIEWFINDER_COLOR_CONVERSION) { - if (!gst_camerabin_create_and_add_element (cbin, "ffmpegcolorspace")) { + if (!gst_camerabin_create_and_add_element (cbin, "ffmpegcolorspace", + "vf-ffmpegcolorspace")) { goto error; } } @@ -1312,7 +1326,6 @@ static void gst_camerabin_rewrite_tags_to_bin (GstBin * bin, const GstTagList * list) { GstElement *setter; - GstElementFactory *setter_factory; GstIterator *iter; GstIteratorResult res = GST_ITERATOR_OK; gpointer data; @@ -1333,7 +1346,6 @@ gst_camerabin_rewrite_tags_to_bin (GstBin * bin, const GstTagList * list) case GST_ITERATOR_OK: setter = GST_ELEMENT (data); GST_LOG ("iterating tag setters: %" GST_PTR_FORMAT, setter); - setter_factory = gst_element_get_factory (setter); GST_DEBUG ("replacement tags %" GST_PTR_FORMAT, list); gst_tag_setter_merge_tags (GST_TAG_SETTER (setter), list, GST_TAG_MERGE_REPLACE_ALL); @@ -1748,7 +1760,7 @@ camerabin_pad_blocked (GstPad * pad, gboolean blocked, gpointer user_data) static gboolean gst_camerabin_send_preview (GstCameraBin * camera, GstBuffer * buffer) { - GstElement *pipeline; + GstCameraBinPreviewPipelineData *data; GstBuffer *prev = NULL; GstStructure *s; GstMessage *msg; @@ -1756,9 +1768,9 @@ gst_camerabin_send_preview (GstCameraBin * camera, GstBuffer * buffer) GST_DEBUG_OBJECT (camera, "creating preview"); - pipeline = (camera->mode == MODE_IMAGE) ? + data = (camera->mode == MODE_IMAGE) ? camera->preview_pipeline : camera->video_preview_pipeline; - prev = gst_camerabin_preview_convert (camera, pipeline, buffer); + prev = gst_camerabin_preview_convert (data, buffer); GST_DEBUG_OBJECT (camera, "preview created: %p", prev); @@ -1804,6 +1816,10 @@ gst_camerabin_have_img_buffer (GstPad * pad, GstMiniObject * obj, GST_LOG ("got buffer %p with size %d", buffer, GST_BUFFER_SIZE (buffer)); + if (camera->preview_caps) { + gst_camerabin_send_preview (camera, buffer); + } + /* Image filename should be set by now */ if (g_str_equal (camera->filename->str, "")) { GST_DEBUG_OBJECT (camera, "filename not set, dropping buffer"); @@ -1812,10 +1828,6 @@ gst_camerabin_have_img_buffer (GstPad * pad, GstMiniObject * obj, goto done; } - if (camera->preview_caps) { - gst_camerabin_send_preview (camera, buffer); - } - gst_camerabin_rewrite_tags (camera); /* Send a custom event which tells the filename to image queue */ @@ -1853,12 +1865,11 @@ gst_camerabin_have_img_buffer (GstPad * pad, GstMiniObject * obj, /* forward tag events to preview pipeline */ if (camera->preview_caps && GST_EVENT_TYPE (event) == GST_EVENT_TAG) { - GstElement *pipeline; + GstCameraBinPreviewPipelineData *data; - pipeline = (camera->mode == MODE_IMAGE) ? + data = (camera->mode == MODE_IMAGE) ? camera->preview_pipeline : camera->video_preview_pipeline; - gst_camerabin_preview_send_event (camera, pipeline, - gst_event_ref (event)); + gst_camerabin_preview_send_event (data, gst_event_ref (event)); } } @@ -3361,12 +3372,11 @@ gst_camerabin_dispose (GObject * object) gst_object_unref (camera->vidbin); if (camera->preview_pipeline) { - gst_camerabin_preview_destroy_pipeline (camera, camera->preview_pipeline); + gst_camerabin_preview_destroy_pipeline (camera->preview_pipeline); camera->preview_pipeline = NULL; } if (camera->video_preview_pipeline) { - gst_camerabin_preview_destroy_pipeline (camera, - camera->video_preview_pipeline); + gst_camerabin_preview_destroy_pipeline (camera->video_preview_pipeline); camera->video_preview_pipeline = NULL; } @@ -3513,7 +3523,7 @@ gst_camerabin_set_property (GObject * object, guint prop_id, break; case ARG_PREVIEW_CAPS: { - GstElement **prev_pipe = NULL; + GstCameraBinPreviewPipelineData **prev_pipe = NULL; GstElement **preview_source_filter = NULL; GstCaps **prev_caps = NULL; GstCaps *new_caps = NULL; @@ -3522,7 +3532,7 @@ gst_camerabin_set_property (GObject * object, guint prop_id, prev_pipe = &camera->preview_pipeline; preview_source_filter = &camera->app_preview_source_filter; prev_caps = &camera->preview_caps; - } else if (camera->mode == MODE_VIDEO) { + } else { /* MODE VIDEO */ prev_pipe = &camera->video_preview_pipeline; preview_source_filter = &camera->app_video_preview_source_filter; prev_caps = &camera->video_preview_caps; @@ -3533,19 +3543,20 @@ gst_camerabin_set_property (GObject * object, guint prop_id, if (prev_caps && !gst_caps_is_equal (*prev_caps, new_caps)) { GST_DEBUG_OBJECT (camera, "setting preview caps: %" GST_PTR_FORMAT, new_caps); - if (*prev_pipe) { - gst_camerabin_preview_destroy_pipeline (camera, *prev_pipe); - *prev_pipe = NULL; - } + GST_OBJECT_LOCK (camera); gst_caps_replace (prev_caps, new_caps); GST_OBJECT_UNLOCK (camera); if (new_caps && !gst_caps_is_any (new_caps) && !gst_caps_is_empty (new_caps)) { - *prev_pipe = - gst_camerabin_preview_create_pipeline (camera, new_caps, - *preview_source_filter); + if (!*prev_pipe) { + *prev_pipe = + gst_camerabin_preview_create_pipeline (GST_ELEMENT (camera), + new_caps, *preview_source_filter); + } else { + gst_camerabin_preview_set_caps (*prev_pipe, new_caps); + } } } break; @@ -3556,7 +3567,7 @@ gst_camerabin_set_property (GObject * object, guint prop_id, ("camerabin must be in NULL state when setting the preview source filter element"), (NULL)); } else { - GstElement **preview_pipe = NULL; + GstCameraBinPreviewPipelineData **preview_pipe = NULL; GstElement **preview_source_filter = NULL; GstCaps *preview_caps = NULL; @@ -3564,7 +3575,7 @@ gst_camerabin_set_property (GObject * object, guint prop_id, preview_pipe = &camera->preview_pipeline; preview_source_filter = &camera->app_preview_source_filter; preview_caps = camera->preview_caps; - } else if (camera->mode == MODE_VIDEO) { + } else { /* MODE VIDEO */ preview_pipe = &camera->video_preview_pipeline; preview_source_filter = &camera->app_video_preview_source_filter; preview_caps = camera->video_preview_caps; @@ -3575,10 +3586,10 @@ gst_camerabin_set_property (GObject * object, guint prop_id, *preview_source_filter = g_value_dup_object (value); if (*preview_pipe) { - gst_camerabin_preview_destroy_pipeline (camera, *preview_pipe); + gst_camerabin_preview_destroy_pipeline (*preview_pipe); *preview_pipe = - gst_camerabin_preview_create_pipeline (camera, preview_caps, - *preview_source_filter); + gst_camerabin_preview_create_pipeline (GST_ELEMENT (camera), + preview_caps, *preview_source_filter); } } break; @@ -4034,11 +4045,14 @@ gst_camerabin_capture_start (GstCameraBin * camera) } } - if (g_str_equal (camera->filename->str, "")) { - GST_ELEMENT_ERROR (camera, CORE, FAILED, - ("set filename before starting capture"), (NULL)); - return; - } + /* We need a filename unless it's a photo and preview_caps is set */ + + if (g_str_equal (camera->filename->str, "")) + if (camera->active_bin == camera->vidbin || !camera->preview_caps) { + GST_ELEMENT_ERROR (camera, CORE, FAILED, + ("set filename before starting capture"), (NULL)); + return; + } g_mutex_lock (camera->capture_mutex); if (camera->capturing) { diff --git a/gst/camerabin/gstcamerabin.h b/gst/camerabin/gstcamerabin.h index d53af1e1b..066545c94 100644 --- a/gst/camerabin/gstcamerabin.h +++ b/gst/camerabin/gstcamerabin.h @@ -31,6 +31,7 @@ #include "gstcamerabin-enum.h" #include "camerabinimage.h" #include "camerabinvideo.h" +#include "camerabinpreview.h" G_BEGIN_DECLS /* #defines don't like whitespacey bits */ @@ -147,8 +148,10 @@ struct _GstCameraBin GstElement *imgbin; /* bin that holds image capturing elements */ GstElement *vidbin; /* bin that holds video capturing elements */ GstElement *active_bin; /* image or video bin that is currently in use */ - GstElement *preview_pipeline; /* pipeline for creating preview images */ - GstElement *video_preview_pipeline; /* pipeline for creating video preview image */ + /* pipeline for creating preview images */ + GstCameraBinPreviewPipelineData *preview_pipeline; + /* pipeline for creating video preview image */ + GstCameraBinPreviewPipelineData *video_preview_pipeline; GstBuffer *video_preview_buffer; /* buffer for storing video preview */ diff --git a/gst/selector/gstinputselector.c b/gst/camerabin/gstinputselector.c index ee7643f26..ef4e23637 100644 --- a/gst/selector/gstinputselector.c +++ b/gst/camerabin/gstinputselector.c @@ -36,7 +36,7 @@ #include <string.h> #include "gstinputselector.h" -#include "gstselector-marshal.h" +#include "gstcamerabin-marshal.h" GST_DEBUG_CATEGORY_STATIC (input_selector_debug); #define GST_CAT_DEFAULT input_selector_debug @@ -165,7 +165,7 @@ gst_selector_pad_get_type (void) }; selector_pad_type = - g_type_register_static (GST_TYPE_PAD, "GstSelectorPad", + g_type_register_static (GST_TYPE_PAD, "GstCamerabinSelectorPad", &selector_pad_info, 0); } return selector_pad_type; @@ -680,6 +680,10 @@ flushing: } } +static void gst_input_selector_init (GstInputSelector * sel); +static void gst_input_selector_base_init (GstInputSelectorClass * klass); +static void gst_input_selector_class_init (GstInputSelectorClass * klass); + static void gst_input_selector_dispose (GObject * object); static void gst_input_selector_set_property (GObject * object, @@ -701,20 +705,43 @@ static gint64 gst_input_selector_block (GstInputSelector * self); static void gst_input_selector_switch (GstInputSelector * self, GstPad * pad, gint64 stop_time, gint64 start_time); -#define _do_init(bla) \ - GST_DEBUG_CATEGORY_INIT (input_selector_debug, \ - "input-selector", 0, "An input stream selector element"); +static GstElementClass *parent_class = NULL; + +GType +gst_input_selector_get_type (void) +{ + static GType input_selector_type = 0; + + if (!input_selector_type) { + static const GTypeInfo input_selector_info = { + sizeof (GstInputSelectorClass), + (GBaseInitFunc) gst_input_selector_base_init, + NULL, + (GClassInitFunc) gst_input_selector_class_init, + NULL, + NULL, + sizeof (GstInputSelector), + 0, + (GInstanceInitFunc) gst_input_selector_init, + }; + input_selector_type = + g_type_register_static (GST_TYPE_ELEMENT, + "GstCamerabinInputSelector", &input_selector_info, 0); + GST_DEBUG_CATEGORY_INIT (input_selector_debug, + "camerabin-input-selector", 0, "Camerabin input selector element"); + } -GST_BOILERPLATE_FULL (GstInputSelector, gst_input_selector, GstElement, - GST_TYPE_ELEMENT, _do_init); + return input_selector_type; +} static void -gst_input_selector_base_init (gpointer g_class) +gst_input_selector_base_init (GstInputSelectorClass * klass) { - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - gst_element_class_set_details_simple (element_class, "Input selector", - "Generic", "N-to-1 input stream selectoring", + gst_element_class_set_details_simple (element_class, + "Input selector", "Generic", + "N-to-1 input stream selectoring", "Julien Moutte <julien@moutte.net>, " "Jan Schmidt <thaytan@mad.scientist.com>, " "Wim Taymans <wim.taymans@gmail.com>"); @@ -732,6 +759,9 @@ gst_input_selector_class_init (GstInputSelectorClass * klass) parent_class = g_type_class_peek_parent (klass); + /* FIXME: remove after confirming it is safe now */ + g_type_class_ref (gst_selector_pad_get_type ()); + gobject_class->dispose = gst_input_selector_dispose; gobject_class->set_property = gst_input_selector_set_property; @@ -764,7 +794,7 @@ gst_input_selector_class_init (GstInputSelectorClass * klass) g_signal_new ("block", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstInputSelectorClass, block), NULL, NULL, - gst_selector_marshal_INT64__VOID, G_TYPE_INT64, 0); + __gst_camerabin_marshal_INT64__VOID, G_TYPE_INT64, 0); /** * GstInputSelector::switch: * @inputselector: the #GstInputSelector @@ -814,7 +844,7 @@ gst_input_selector_class_init (GstInputSelectorClass * klass) gst_input_selector_signals[SIGNAL_SWITCH] = g_signal_new ("switch", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstInputSelectorClass, switch_), - NULL, NULL, gst_selector_marshal_VOID__OBJECT_INT64_INT64, + NULL, NULL, __gst_camerabin_marshal_VOID__OBJECT_INT64_INT64, G_TYPE_NONE, 3, GST_TYPE_PAD, G_TYPE_INT64, G_TYPE_INT64); gstelement_class->request_new_pad = gst_input_selector_request_new_pad; @@ -827,8 +857,7 @@ gst_input_selector_class_init (GstInputSelectorClass * klass) } static void -gst_input_selector_init (GstInputSelector * sel, - GstInputSelectorClass * g_class) +gst_input_selector_init (GstInputSelector * sel) { sel->srcpad = gst_pad_new ("src", GST_PAD_SRC); gst_pad_set_iterate_internal_links_function (sel->srcpad, @@ -1047,15 +1076,54 @@ gst_input_selector_event (GstPad * pad, GstEvent * event) { gboolean res = FALSE; GstPad *otherpad; + GstInputSelector *sel; + GstIterator *iter; + gboolean done; + gpointer nextpad; + sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad)); otherpad = gst_input_selector_get_linked_pad (pad, TRUE); if (otherpad) { res = gst_pad_push_event (otherpad, event); gst_object_unref (otherpad); + } else if (sel->select_all) { + + /* If select-all is set, we should push the event to all pads. + * The result will be TRUE if the push works for any of the pads, even if a + * push fails. This is coherent with the way camerabin uses input-selector, + * but might not be for other uses of it. */ + + iter = gst_element_iterate_sink_pads (GST_ELEMENT (sel)); + + done = FALSE; + while (!done) { + switch (gst_iterator_next (iter, &nextpad)) { + case GST_ITERATOR_OK: + res |= gst_pad_push_event (nextpad, gst_event_ref (event)); + gst_object_unref (nextpad); + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iter); + break; + case GST_ITERATOR_ERROR: + GST_WARNING_OBJECT (sel, + "Wrong parameters when retrieving sink pads"); + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_event_unref (event); + gst_iterator_free (iter); } else gst_event_unref (event); + + gst_object_unref (sel); + return res; } @@ -1180,7 +1248,7 @@ gst_input_selector_getcaps (GstPad * pad) } /* check if the pad is the active sinkpad */ -static inline gboolean +static gboolean gst_input_selector_is_active_sinkpad (GstInputSelector * sel, GstPad * pad) { gboolean res; diff --git a/gst/selector/gstinputselector.h b/gst/camerabin/gstinputselector.h index 58a671d50..58a671d50 100644 --- a/gst/selector/gstinputselector.h +++ b/gst/camerabin/gstinputselector.h diff --git a/gst/camerabin2/Makefile.am b/gst/camerabin2/Makefile.am new file mode 100644 index 000000000..24f497ed5 --- /dev/null +++ b/gst/camerabin2/Makefile.am @@ -0,0 +1,29 @@ +plugin_LTLIBRARIES = libgstcamerabin2.la + +libgstcamerabin2_la_SOURCES = gstviewfinderbin.c \ + gstimagecapturebin.c \ + camerabingeneral.c \ + gstwrappercamerabinsrc.c \ + gstcamerabin2.c \ + gstplugin.c + +libgstcamerabin2_la_CFLAGS = \ + $(GST_PLUGINS_BAD_CFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) $(GST_CFLAGS) \ + -DGST_USE_UNSTABLE_API + +libgstcamerabin2_la_LIBADD = \ + $(top_builddir)/gst-libs/gst/interfaces/libgstphotography-$(GST_MAJORMINOR).la \ + $(top_builddir)/gst-libs/gst/basecamerabinsrc/libgstbasecamerabinsrc-$(GST_MAJORMINOR).la \ + $(GST_PLUGINS_BASE_LIBS) -lgstinterfaces-$(GST_MAJORMINOR) -lgsttag-$(GST_MAJORMINOR) -lgstapp-$(GST_MAJORMINOR) -lgstpbutils-$(GST_MAJORMINOR) \ + $(GST_BASE_LIBS) $(GST_LIBS) + +libgstcamerabin2_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstcamerabin2_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = gstviewfinderbin.h \ + gstimagecapturebin.h \ + camerabingeneral.h \ + gstwrappercamerabinsrc.h \ + gstcamerabin2.h diff --git a/gst/camerabin2/PORTING b/gst/camerabin2/PORTING new file mode 100644 index 000000000..c9b6dd825 --- /dev/null +++ b/gst/camerabin2/PORTING @@ -0,0 +1,22 @@ +This document lists the differenced between camerabin and camerabin2 from +the API point of view and should be used to help on porting applications +from camerabin to camerabin2. + +* Setting the location for the captures: +camerabin requires that the path of the file to save the captures is set before +each capture. Camerabin2 allows the application to use a multifilesink-like +approach, the application can set a file with a '%d' marker, this marker +will be automatically replaced by a number and be autoincremented after each +capture. + +* Capture signals +The signals were renamed from capture-start/stop to start/stop-capture as +this is the usual naming on actions. + +* image-done +In camerabin, image-done is a signal, in camerabin2, it is a bus message + +* video recording encoder/muxer +In camerabin, video/audio encoder/muxer are selected by passing GstElements to +camerabin properties. In camerabin2, a GstEncodingProfile is passed as a +property and encodebin manages to instantiate the elements for the format. diff --git a/gst/camerabin2/camerabingeneral.c b/gst/camerabin2/camerabingeneral.c new file mode 100644 index 000000000..2f5bd05b1 --- /dev/null +++ b/gst/camerabin2/camerabingeneral.c @@ -0,0 +1,474 @@ +/* + * GStreamer + * Copyright (C) 2008 Nokia Corporation <multimedia@maemo.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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * SECTION:camerabingeneral + * @short_description: helper functions for #GstCameraBin and it's modules + * + * Common helper functions for #GstCameraBin, #GstCameraBinImage and + * #GstCameraBinVideo. + * + */ +#include <string.h> + +#include <glib.h> +#include <gst/app/gstappsrc.h> +#include <gst/app/gstappsink.h> +#include <gst/basecamerabinsrc/gstbasecamerasrc.h> +#include "camerabingeneral.h" + +/** + * gst_camerabin_add_element: + * @bin: add an element to this bin + * @new_elem: new element to be added + * + * Adds given element to given @bin. Looks for an unconnected src pad + * from the @bin and links the element to it. Raises an error if adding + * or linking failed. Unrefs the element in the case of an error. + * + * Returns: %TRUE if adding and linking succeeded, %FALSE otherwise. + */ +gboolean +gst_camerabin_add_element (GstBin * bin, GstElement * new_elem) +{ + return gst_camerabin_add_element_full (bin, NULL, new_elem, NULL); +} + +/** + * gst_camerabin_add_element_full: + * @bin: add an element to this bin + * @srcpad: src pad name, or NULL for any + * @new_elem: new element to be added + * @dstpad: dst pad name, or NULL for any + * + * Adds given element to given @bin. Looks for an unconnected src pad + * (with name @srcpad, if specified) from the @bin and links the element + * to it. Raises an error if adding or linking failed. Unrefs the element + * in the case of an error. + * + * Returns: %TRUE if adding and linking succeeded, %FALSE otherwise. + */ +gboolean +gst_camerabin_add_element_full (GstBin * bin, const gchar * srcpad, + GstElement * new_elem, const gchar * dstpad) +{ + gboolean ret; + + g_return_val_if_fail (bin, FALSE); + g_return_val_if_fail (new_elem, FALSE); + + ret = gst_camerabin_try_add_element (bin, srcpad, new_elem, dstpad); + + if (!ret) { + gchar *elem_name = gst_element_get_name (new_elem); + GST_ELEMENT_ERROR (bin, CORE, NEGOTIATION, (NULL), + ("linking %s failed", elem_name)); + g_free (elem_name); + gst_object_unref (new_elem); + } + + return ret; +} + +/** + * gst_camerabin_try_add_element: + * @bin: tries adding an element to this bin + * @srcpad: src pad name, or NULL for any + * @new_elem: new element to be added + * @dstpad: dst pad name, or NULL for any + * + * Adds given element to given @bin. Looks for an unconnected src pad + * (with name @srcpad, if specified) from the @bin and links the element to + * it. + * + * Returns: %TRUE if adding and linking succeeded, %FALSE otherwise. + */ +gboolean +gst_camerabin_try_add_element (GstBin * bin, const gchar * srcpad, + GstElement * new_elem, const gchar * dstpad) +{ + GstPad *bin_pad; + GstElement *bin_elem; + gboolean ret = TRUE; + + g_return_val_if_fail (bin, FALSE); + g_return_val_if_fail (new_elem, FALSE); + + /* Get pads for linking */ + bin_pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SRC); + /* Add to bin */ + gst_bin_add (GST_BIN (bin), new_elem); + /* Link, if unconnected pad was found, otherwise just add it to bin */ + if (bin_pad) { + GST_DEBUG_OBJECT (bin, "linking %s to %s:%s", GST_OBJECT_NAME (new_elem), + GST_DEBUG_PAD_NAME (bin_pad)); + bin_elem = gst_pad_get_parent_element (bin_pad); + gst_object_unref (bin_pad); + if (!gst_element_link_pads (bin_elem, srcpad, new_elem, dstpad)) { + gst_object_ref (new_elem); + gst_bin_remove (bin, new_elem); + ret = FALSE; + } + gst_object_unref (bin_elem); + } else { + GST_INFO_OBJECT (bin, "no unlinked source pad in bin"); + } + + return ret; +} + +/** + * gst_camerabin_create_and_add_element: + * @bin: tries adding an element to this bin + * @elem_name: name of the element to be created + * @instance_name: name of the instance of the element to be created + * + * Creates an element according to given name and + * adds it to given @bin. Looks for an unconnected src pad + * from the @bin and links the element to it. + * + * Returns: pointer to the new element if successful, NULL otherwise. + */ +GstElement * +gst_camerabin_create_and_add_element (GstBin * bin, const gchar * elem_name, + const gchar * instance_name) +{ + GstElement *new_elem; + + g_return_val_if_fail (bin, FALSE); + g_return_val_if_fail (elem_name, FALSE); + + new_elem = gst_element_factory_make (elem_name, instance_name); + if (!new_elem) { + GST_ELEMENT_ERROR (bin, CORE, MISSING_PLUGIN, (NULL), + ("could not create \"%s\" element.", elem_name)); + } else if (!gst_camerabin_add_element (bin, new_elem)) { + new_elem = NULL; + } + + return new_elem; +} + +/* try to change the state of an element. This function returns the element when + * the state change could be performed. When this function returns NULL an error + * occured and the element is unreffed if @unref is TRUE. */ +static GstElement * +try_element (GstElement * bin, GstElement * element, gboolean unref) +{ + GstStateChangeReturn ret; + + if (element) { + ret = gst_element_set_state (element, GST_STATE_READY); + if (ret == GST_STATE_CHANGE_FAILURE) { + GST_DEBUG_OBJECT (bin, "failed state change.."); + gst_element_set_state (element, GST_STATE_NULL); + if (unref) + gst_object_unref (element); + element = NULL; + } + } + return element; +} + +GstElement * +gst_camerabin_setup_default_element (GstBin * bin, GstElement * user_elem, + const gchar * auto_elem_name, const gchar * default_elem_name, + const gchar * instance_name) +{ + GstElement *elem; + + if (user_elem) { + GST_DEBUG_OBJECT (bin, "trying configured element"); + elem = try_element (GST_ELEMENT_CAST (bin), user_elem, FALSE); + } else { + /* only try fallback if no specific sink was chosen */ + GST_DEBUG_OBJECT (bin, "trying %s", auto_elem_name); + elem = gst_element_factory_make (auto_elem_name, instance_name); + elem = try_element (GST_ELEMENT_CAST (bin), elem, TRUE); + if (elem == NULL) { + /* if default sink from config.h is different then try it too */ + if (strcmp (default_elem_name, auto_elem_name)) { + GST_DEBUG_OBJECT (bin, "trying %s", default_elem_name); + elem = gst_element_factory_make (default_elem_name, instance_name); + elem = try_element (GST_ELEMENT_CAST (bin), elem, TRUE); + } + } + } + return elem; +} + +/** + * gst_camerabin_remove_elements_from_bin: + * @bin: removes all elements from this bin + * + * Removes all elements from this @bin. + */ +void +gst_camerabin_remove_elements_from_bin (GstBin * bin) +{ + GstIterator *iter = NULL; + gpointer data = NULL; + GstElement *elem = NULL; + gboolean done = FALSE; + + iter = gst_bin_iterate_elements (bin); + while (!done) { + switch (gst_iterator_next (iter, &data)) { + case GST_ITERATOR_OK: + elem = GST_ELEMENT (data); + gst_bin_remove (bin, elem); + gst_element_set_state (GST_ELEMENT (elem), GST_STATE_NULL); + /* Iterator increased the element refcount, so unref */ + gst_object_unref (elem); + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iter); + break; + case GST_ITERATOR_ERROR: + GST_WARNING_OBJECT (bin, "error in iterating elements"); + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iter); +} + +/** + * gst_camerabin_drop_eos_probe: + * @pad: pad receiving the event + * @event: received event + * @u_data: not used + * + * Event probe that drop all eos events. + * + * Returns: FALSE to drop the event, TRUE otherwise + */ +gboolean +gst_camerabin_drop_eos_probe (GstPad * pad, GstEvent * event, gpointer u_data) +{ + gboolean ret = TRUE; + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_EOS: + GST_DEBUG ("dropping eos in %s:%s", GST_DEBUG_PAD_NAME (pad)); + ret = FALSE; + break; + default: + break; + } + return ret; +} + +static GstFlowReturn +gst_camerabin_preview_pipeline_new_preroll (GstAppSink * appsink, + gpointer user_data) +{ + GstBuffer *buffer; + + buffer = gst_app_sink_pull_preroll (appsink); + gst_buffer_unref (buffer); + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_camerabin_preview_pipeline_new_buffer (GstAppSink * appsink, + gpointer user_data) +{ + GstBuffer *buffer; + GstStructure *s; + GstMessage *msg; + GstCameraBinPreviewPipelineData *data; + + data = user_data; + + buffer = gst_app_sink_pull_buffer (appsink); + s = gst_structure_new (GST_BASE_CAMERA_SRC_PREVIEW_MESSAGE_NAME, + "buffer", GST_TYPE_BUFFER, buffer, NULL); + gst_buffer_unref (buffer); + msg = gst_message_new_element (GST_OBJECT (data->element), s); + + GST_DEBUG_OBJECT (data->element, "sending message with preview image"); + if (gst_element_post_message (data->element, msg) == FALSE) { + GST_WARNING_OBJECT (data->element, + "This element has no bus, therefore no message sent!"); + } + + return GST_FLOW_OK; +} + +/** + * gst_camerabin_create_preview_pipeline: + * @element: Owner of this pipeline + * @filter: Custom filter to process preview data (an extra ref is taken) + * + * Creates a new previewing pipeline that can receive buffers + * to be posted as camerabin preview messages for @element + * + * Returns: The newly created #GstCameraBinPreviewPipelineData + */ +GstCameraBinPreviewPipelineData * +gst_camerabin_create_preview_pipeline (GstElement * element, + GstElement * filter) +{ + GstCameraBinPreviewPipelineData *data; + GstElement *csp; + GstElement *csp2; + GstElement *vscale; + gboolean added = FALSE; + GstAppSinkCallbacks callbacks = { 0, }; + + data = g_new (GstCameraBinPreviewPipelineData, 1); + + data->pipeline = gst_pipeline_new ("preview-pipeline"); + data->appsrc = gst_element_factory_make ("appsrc", "preview-appsrc"); + data->capsfilter = gst_element_factory_make ("capsfilter", + "preview-capsfilter"); + data->appsink = gst_element_factory_make ("appsink", "preview-appsink"); + csp = gst_element_factory_make ("ffmpegcolorspace", "preview-csp0"); + csp2 = gst_element_factory_make ("ffmpegcolorspace", "preview-csp1"); + vscale = gst_element_factory_make ("videoscale", "preview-vscale"); + + if (!data->appsrc || !data->capsfilter || !data->appsink || !csp || + !csp2 || !vscale) { + goto error; + } + + gst_bin_add_many (GST_BIN (data->pipeline), data->appsrc, data->capsfilter, + data->appsink, csp, csp2, vscale, NULL); + if (filter) + gst_bin_add (GST_BIN (data->pipeline), gst_object_ref (filter)); + added = TRUE; + + if (filter) { + if (!gst_element_link_many (data->appsrc, filter, csp, vscale, csp2, + data->capsfilter, data->appsink, NULL)) + goto error; + } else { + if (!gst_element_link_many (data->appsrc, csp, vscale, csp2, + data->capsfilter, data->appsink, NULL)) + goto error; + } + + callbacks.new_preroll = gst_camerabin_preview_pipeline_new_preroll; + callbacks.new_buffer = gst_camerabin_preview_pipeline_new_buffer; + gst_app_sink_set_callbacks ((GstAppSink *) data->appsink, &callbacks, data, + NULL); + + g_object_set (data->appsink, "sync", FALSE, NULL); + + data->element = element; + data->filter = filter; + + return data; +error: + GST_WARNING ("Failed to create camerabin's preview pipeline"); + if (!added) { + if (csp) + gst_object_unref (csp); + if (csp2) + gst_object_unref (csp2); + if (vscale) + gst_object_unref (vscale); + if (data->appsrc) + gst_object_unref (data->appsrc); + if (data->capsfilter) + gst_object_unref (data->capsfilter); + if (data->appsink) + gst_object_unref (data->appsink); + } + gst_camerabin_destroy_preview_pipeline (data); + return NULL; +} + +/** + * gst_camerabin_destroy_preview_pipeline: + * @preview: the #GstCameraBinPreviewPipelineData + * + * Frees a #GstCameraBinPreviewPipelineData + */ +void +gst_camerabin_destroy_preview_pipeline (GstCameraBinPreviewPipelineData * + preview) +{ + if (preview->pipeline) { + gst_element_set_state (preview->pipeline, GST_STATE_NULL); + gst_object_unref (preview->pipeline); + } + g_free (preview); +} + +/** + * gst_camerabin_preview_pipeline_post: + * @preview: the #GstCameraBinPreviewPipelineData + * @buffer: the buffer to be posted as a preview + * + * Converts the @buffer to the desired format and posts the preview + * message to the bus. + * + * Returns: %TRUE on success + */ +gboolean +gst_camerabin_preview_pipeline_post (GstCameraBinPreviewPipelineData * preview, + GstBuffer * buffer) +{ + g_return_val_if_fail (preview != NULL, FALSE); + g_return_val_if_fail (preview->pipeline != NULL, FALSE); + g_return_val_if_fail (buffer, FALSE); + + gst_app_src_push_buffer ((GstAppSrc *) preview->appsrc, + gst_buffer_ref (buffer)); + + return TRUE; +} + +/** + * gst_camerabin_preview_set_caps: + * @preview: the #GstCameraBinPreviewPipelineData + * @caps: the #GstCaps to be set + * + * The caps that preview buffers should have when posted + * on the bus + */ +void +gst_camerabin_preview_set_caps (GstCameraBinPreviewPipelineData * preview, + GstCaps * caps) +{ + GstState state, pending; + GstStateChangeReturn ret; + + g_return_if_fail (preview != NULL); + + ret = gst_element_get_state (preview->pipeline, &state, &pending, 0); + if (ret == GST_STATE_CHANGE_FAILURE) { + /* make it try again */ + state = GST_STATE_PLAYING; + pending = GST_STATE_VOID_PENDING; + } + + gst_element_set_state (preview->pipeline, GST_STATE_NULL); + g_object_set (preview->capsfilter, "caps", caps, NULL); + if (pending != GST_STATE_VOID_PENDING) + state = pending; + gst_element_set_state (preview->pipeline, state); +} diff --git a/gst/camerabin2/camerabingeneral.h b/gst/camerabin2/camerabingeneral.h new file mode 100644 index 000000000..f39cbd77e --- /dev/null +++ b/gst/camerabin2/camerabingeneral.h @@ -0,0 +1,56 @@ +/* + * GStreamer + * Copyright (C) 2008 Nokia Corporation <multimedia@maemo.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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __CAMERABIN_GENERAL_H_ +#define __CAMERABIN_GENERAL_H_ + +#include <gst/gst.h> + +typedef struct +{ + GstElement *pipeline; + + GstElement *appsrc; + GstElement *filter; + GstElement *capsfilter; + GstElement *appsink; + + GstElement *element; +} GstCameraBinPreviewPipelineData; + +GstCameraBinPreviewPipelineData *gst_camerabin_create_preview_pipeline (GstElement * element, GstElement * filter); +void gst_camerabin_destroy_preview_pipeline (GstCameraBinPreviewPipelineData * preview); +gboolean gst_camerabin_preview_pipeline_post (GstCameraBinPreviewPipelineData * preview, GstBuffer * buffer); +void gst_camerabin_preview_set_caps (GstCameraBinPreviewPipelineData * preview, GstCaps * caps); + +gboolean gst_camerabin_try_add_element (GstBin * bin, const gchar * srcpad, GstElement * new_elem, const gchar * dstpad); +gboolean gst_camerabin_add_element (GstBin * bin, GstElement * new_elem); +gboolean gst_camerabin_add_element_full (GstBin * bin, const gchar * srcpad, GstElement * new_elem, const gchar * dstpad); + +GstElement *gst_camerabin_create_and_add_element (GstBin * bin, const gchar * elem_name, const gchar * instance_name); + +GstElement * gst_camerabin_setup_default_element (GstBin * bin, GstElement *user_elem, const gchar *auto_elem_name, const gchar *default_elem_name, + const gchar * instance_elem_name); + +void gst_camerabin_remove_elements_from_bin (GstBin * bin); + +gboolean gst_camerabin_drop_eos_probe (GstPad * pad, GstEvent * event, gpointer u_data); + +#endif /* #ifndef __CAMERABIN_GENERAL_H_ */ diff --git a/gst/camerabin2/gstcamerabin2.c b/gst/camerabin2/gstcamerabin2.c new file mode 100644 index 000000000..d7139a4ab --- /dev/null +++ b/gst/camerabin2/gstcamerabin2.c @@ -0,0 +1,1015 @@ +/* GStreamer + * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/** + * SECTION:element-gstcamerabin2 + * + * The gstcamerabin2 element does FIXME stuff. + * + * Note that camerabin2 is still UNSTABLE, EXPERIMENTAL and under heavy + * development. + */ + +/* + * Detail Topics: + * + * videorecordingbin state management (for now on called 'videobin') + * - The problem: keeping videobin state in sync with camerabin will make it + * go to playing when it might not be used, causing its internal + * filesink to open a file that might be left blank. + * - The solution: videobin state is set to locked upon its creation and camerabin + * registers itself on the notify::ready-for-capture of the src. + * Whenever the src readyness goes to FALSE it means a new + * capture is starting. If we are on video mode, the videobin's + * state is set to NULL and then PLAYING (in between this we + * have room to set the destination filename). + * There is no problem to leave it on playing after an EOS, so + * no action is taken on stop-capture. + * + * - TODO: What happens when an error pops? + * - TODO: Should we split properties in image/video variants? We already do so + * for some of them + * + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gst/basecamerabinsrc/gstbasecamerasrc.h> +#include "gstcamerabin2.h" + +GST_DEBUG_CATEGORY_STATIC (gst_camera_bin_debug); +#define GST_CAT_DEFAULT gst_camera_bin_debug + +/* prototypes */ + +enum +{ + PROP_0, + PROP_MODE, + PROP_LOCATION, + PROP_CAMERA_SRC, + PROP_IMAGE_CAPTURE_SUPPORTED_CAPS, + PROP_VIDEO_CAPTURE_SUPPORTED_CAPS, + PROP_IMAGE_CAPTURE_CAPS, + PROP_VIDEO_CAPTURE_CAPS, + PROP_POST_PREVIEWS, + PROP_PREVIEW_CAPS, + PROP_VIDEO_ENCODING_PROFILE, + PROP_IMAGE_FILTER, + PROP_VIDEO_FILTER, + PROP_VIEWFINDER_FILTER, + PROP_PREVIEW_FILTER +}; + +enum +{ + /* action signals */ + START_CAPTURE_SIGNAL, + STOP_CAPTURE_SIGNAL, + /* emit signals */ + LAST_SIGNAL +}; +static guint camerabin_signals[LAST_SIGNAL]; + +#define DEFAULT_MODE MODE_IMAGE +#define DEFAULT_VID_LOCATION "vid_%d" +#define DEFAULT_IMG_LOCATION "img_%d" +#define DEFAULT_POST_PREVIEWS TRUE + +/******************************** + * Standard GObject boilerplate * + * and GObject types * + ********************************/ + +static GstPipelineClass *parent_class; +static void gst_camera_bin_class_init (GstCameraBinClass * klass); +static void gst_camera_bin_base_init (gpointer klass); +static void gst_camera_bin_init (GstCameraBin * camera); +static void gst_camera_bin_dispose (GObject * object); +static void gst_camera_bin_finalize (GObject * object); + +static void gst_camera_bin_handle_message (GstBin * bin, GstMessage * message); + +GType +gst_camera_bin_get_type (void) +{ + static GType gst_camera_bin_type = 0; + static const GInterfaceInfo camerabin_tagsetter_info = { + NULL, + NULL, + NULL, + }; + + if (!gst_camera_bin_type) { + static const GTypeInfo gst_camera_bin_info = { + sizeof (GstCameraBinClass), + (GBaseInitFunc) gst_camera_bin_base_init, + NULL, + (GClassInitFunc) gst_camera_bin_class_init, + NULL, + NULL, + sizeof (GstCameraBin), + 0, + (GInstanceInitFunc) gst_camera_bin_init, + NULL + }; + + gst_camera_bin_type = + g_type_register_static (GST_TYPE_PIPELINE, "GstCameraBin2", + &gst_camera_bin_info, 0); + + g_type_add_interface_static (gst_camera_bin_type, GST_TYPE_TAG_SETTER, + &camerabin_tagsetter_info); + } + + return gst_camera_bin_type; +} + +/* GObject class functions */ +static void gst_camera_bin_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_camera_bin_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +/* Element class functions */ +static GstStateChangeReturn +gst_camera_bin_change_state (GstElement * element, GstStateChange trans); + + +/* Camerabin functions */ + +static GstEvent * +gst_camera_bin_new_event_renegotiate (void) +{ + return gst_event_new_custom (GST_EVENT_CUSTOM_BOTH, + gst_structure_new ("renegotiate", NULL)); +} + +static void +gst_camera_bin_start_capture (GstCameraBin * camerabin) +{ + const GstTagList *taglist; + + GST_DEBUG_OBJECT (camerabin, "Received start-capture"); + + taglist = gst_tag_setter_get_tag_list (GST_TAG_SETTER (camerabin)); + if (taglist) { + GstPad *active_pad; + + GST_DEBUG_OBJECT (camerabin, "Pushing tags from application: %" + GST_PTR_FORMAT, taglist); + + if (camerabin->mode == MODE_IMAGE) { + active_pad = gst_element_get_static_pad (camerabin->src, + GST_BASE_CAMERA_SRC_IMAGE_PAD_NAME); + } else { + active_pad = gst_element_get_static_pad (camerabin->src, + GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME); + } + + gst_pad_push_event (active_pad, + gst_event_new_tag (gst_tag_list_copy (taglist))); + gst_object_unref (active_pad); + } + + g_signal_emit_by_name (camerabin->src, "start-capture", NULL); +} + +static void +gst_camera_bin_stop_capture (GstCameraBin * camerabin) +{ + if (camerabin->src) + g_signal_emit_by_name (camerabin->src, "stop-capture", NULL); +} + +static void +gst_camera_bin_change_mode (GstCameraBin * camerabin, gint mode) +{ + if (mode == camerabin->mode) + return; + + GST_DEBUG_OBJECT (camerabin, "Changing mode to %d", mode); + + /* stop any ongoing capture */ + gst_camera_bin_stop_capture (camerabin); + camerabin->mode = mode; + if (camerabin->src) + g_object_set (camerabin->src, "mode", mode, NULL); +} + +static void +gst_camera_bin_src_notify_readyforcapture (GObject * obj, GParamSpec * pspec, + gpointer user_data) +{ + GstCameraBin *camera = GST_CAMERA_BIN_CAST (user_data); + gboolean ready; + + if (camera->mode == MODE_VIDEO) { + g_object_get (camera->src, "ready-for-capture", &ready, NULL); + if (!ready) { + gchar *location; + + /* a video recording is about to start, we reset the videobin to clear eos/flushing state + * also need to clean the queue ! capsfilter before it */ + gst_element_set_state (camera->encodebin, GST_STATE_NULL); + gst_element_set_state (camera->videosink, GST_STATE_NULL); + gst_element_set_state (camera->videobin_queue, GST_STATE_NULL); + gst_element_set_state (camera->videobin_capsfilter, GST_STATE_NULL); + location = + g_strdup_printf (camera->video_location, camera->video_index++); + GST_DEBUG_OBJECT (camera, "Switching videobin location to %s", location); + g_object_set (camera->videosink, "location", location, NULL); + g_free (location); + gst_element_set_state (camera->encodebin, GST_STATE_PLAYING); + gst_element_set_state (camera->videosink, GST_STATE_PLAYING); + gst_element_set_state (camera->videobin_capsfilter, GST_STATE_PLAYING); + gst_element_set_state (camera->videobin_queue, GST_STATE_PLAYING); + } + } +} + +static void +gst_camera_bin_dispose (GObject * object) +{ + GstCameraBin *camerabin = GST_CAMERA_BIN_CAST (object); + + g_free (camerabin->image_location); + g_free (camerabin->video_location); + + if (camerabin->src_capture_notify_id) + g_signal_handler_disconnect (camerabin->src, + camerabin->src_capture_notify_id); + if (camerabin->src) + gst_object_unref (camerabin->src); + if (camerabin->user_src) + gst_object_unref (camerabin->user_src); + + if (camerabin->viewfinderbin) + gst_object_unref (camerabin->viewfinderbin); + if (camerabin->viewfinderbin_queue) + gst_object_unref (camerabin->viewfinderbin_queue); + if (camerabin->viewfinderbin_capsfilter) + gst_object_unref (camerabin->viewfinderbin_capsfilter); + + if (camerabin->videosink) + gst_object_unref (camerabin->videosink); + if (camerabin->encodebin) + gst_object_unref (camerabin->encodebin); + if (camerabin->videobin_queue) + gst_object_unref (camerabin->videobin_queue); + if (camerabin->videobin_capsfilter) + gst_object_unref (camerabin->videobin_capsfilter); + + if (camerabin->imagebin) + gst_object_unref (camerabin->imagebin); + if (camerabin->imagebin_queue) + gst_object_unref (camerabin->imagebin_queue); + if (camerabin->imagebin_capsfilter) + gst_object_unref (camerabin->imagebin_capsfilter); + + if (camerabin->video_filter) + gst_object_unref (camerabin->video_filter); + if (camerabin->image_filter) + gst_object_unref (camerabin->image_filter); + if (camerabin->viewfinder_filter) + gst_object_unref (camerabin->viewfinder_filter); + + if (camerabin->user_video_filter) + gst_object_unref (camerabin->user_video_filter); + if (camerabin->user_image_filter) + gst_object_unref (camerabin->user_image_filter); + if (camerabin->user_viewfinder_filter) + gst_object_unref (camerabin->user_viewfinder_filter); + + if (camerabin->video_profile) + gst_encoding_profile_unref (camerabin->video_profile); + + if (camerabin->preview_caps) + gst_caps_replace (&camerabin->preview_caps, NULL); + if (camerabin->preview_filter) { + gst_object_unref (camerabin->preview_filter); + camerabin->preview_filter = NULL; + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_camera_bin_finalize (GObject * object) +{ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_camera_bin_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_set_details_simple (element_class, "CameraBin2", + "Generic/Bin/Camera", "CameraBin2", + "Thiago Santos <thiago.sousa.santos@collabora.co.uk>"); +} + +static void +gst_camera_bin_class_init (GstCameraBinClass * klass) +{ + GObjectClass *object_class; + GstElementClass *element_class; + GstBinClass *bin_class; + + parent_class = g_type_class_peek_parent (klass); + object_class = G_OBJECT_CLASS (klass); + element_class = GST_ELEMENT_CLASS (klass); + bin_class = GST_BIN_CLASS (klass); + + object_class->dispose = gst_camera_bin_dispose; + object_class->finalize = gst_camera_bin_finalize; + object_class->set_property = gst_camera_bin_set_property; + object_class->get_property = gst_camera_bin_get_property; + + element_class->change_state = GST_DEBUG_FUNCPTR (gst_camera_bin_change_state); + + bin_class->handle_message = gst_camera_bin_handle_message; + + klass->start_capture = gst_camera_bin_start_capture; + klass->stop_capture = gst_camera_bin_stop_capture; + + /** + * GstCameraBin:mode: + * + * Set the mode of operation: still image capturing or video recording. + */ + g_object_class_install_property (object_class, PROP_MODE, + g_param_spec_enum ("mode", "Mode", + "The capture mode (still image capture or video recording)", + GST_TYPE_CAMERABIN_MODE, DEFAULT_MODE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_LOCATION, + g_param_spec_string ("location", "Location", + "Location to save the captured files. A %d might be used on the" + "filename as a placeholder for a numeric index of the capture." + "Default for images is img_%d and vid_%d for videos", + DEFAULT_IMG_LOCATION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_CAMERA_SRC, + g_param_spec_object ("camera-src", "Camera source", + "The camera source element to be used", + GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, + PROP_IMAGE_CAPTURE_SUPPORTED_CAPS, + g_param_spec_boxed ("image-capture-supported-caps", + "Image capture supported caps", + "Formats supported for capturing images represented as GstCaps", + GST_TYPE_CAPS, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, + PROP_VIDEO_CAPTURE_SUPPORTED_CAPS, + g_param_spec_boxed ("video-capture-supported-caps", + "Video capture supported caps", + "Formats supported for capturing videos represented as GstCaps", + GST_TYPE_CAPS, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, + PROP_IMAGE_CAPTURE_CAPS, + g_param_spec_boxed ("image-capture-caps", + "Image capture caps", + "Caps for image capture", + GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, + PROP_VIDEO_CAPTURE_CAPS, + g_param_spec_boxed ("video-capture-caps", + "Video capture caps", + "Caps for video capture", + GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_POST_PREVIEWS, + g_param_spec_boolean ("post-previews", "Post Previews", + "If capture preview images should be posted to the bus", + DEFAULT_POST_PREVIEWS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_PREVIEW_CAPS, + g_param_spec_boxed ("preview-caps", "Preview caps", + "The caps of the preview image to be posted", + GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_VIDEO_ENCODING_PROFILE, + gst_param_spec_mini_object ("video-profile", "Video Profile", + "The GstEncodingProfile to use for video recording", + GST_TYPE_ENCODING_PROFILE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_IMAGE_FILTER, + g_param_spec_object ("image-filter", "Image filter", + "The element that will process captured image frames. (Should be" + " set on NULL state)", + GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_VIDEO_FILTER, + g_param_spec_object ("video-filter", "Video filter", + "The element that will process captured video frames. (Should be" + " set on NULL state)", + GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_VIEWFINDER_FILTER, + g_param_spec_object ("viewfinder-filter", "Viewfinder filter", + "The element that will process frames going to the viewfinder." + " (Should be set on NULL state)", + GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_PREVIEW_FILTER, + g_param_spec_object ("preview-filter", "Preview filter", + "The element that will process preview buffers." + " (Should be set on NULL state)", + GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + + /** + * GstCameraBin::capture-start: + * @camera: the camera bin element + * + * Starts image capture or video recording depending on the Mode. + */ + camerabin_signals[START_CAPTURE_SIGNAL] = + g_signal_new ("start-capture", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GstCameraBinClass, start_capture), + NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + + /** + * GstCameraBin::capture-stop: + * @camera: the camera bin element + */ + camerabin_signals[STOP_CAPTURE_SIGNAL] = + g_signal_new ("stop-capture", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GstCameraBinClass, stop_capture), + NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); +} + +static void +gst_camera_bin_init (GstCameraBin * camera) +{ + camera->post_previews = DEFAULT_POST_PREVIEWS; + camera->mode = DEFAULT_MODE; + camera->video_location = g_strdup (DEFAULT_VID_LOCATION); + camera->image_location = g_strdup (DEFAULT_IMG_LOCATION); + camera->viewfinderbin = gst_element_factory_make ("viewfinderbin", "vf-bin"); + + /* capsfilters are created here as we proxy their caps properties and + * this way we avoid having to store the caps while on NULL state to + * set them later */ + camera->videobin_capsfilter = gst_element_factory_make ("capsfilter", + "videobin-capsfilter"); + camera->imagebin_capsfilter = gst_element_factory_make ("capsfilter", + "imagebin-capsfilter"); + camera->viewfinderbin_capsfilter = gst_element_factory_make ("capsfilter", + "viewfinderbin-capsfilter"); + + gst_bin_add_many (GST_BIN (camera), + gst_object_ref (camera->viewfinderbin), + gst_object_ref (camera->videobin_capsfilter), + gst_object_ref (camera->imagebin_capsfilter), + gst_object_ref (camera->viewfinderbin_capsfilter), NULL); +} + +static void +gst_image_capture_bin_post_image_done (GstCameraBin * camera, + const gchar * filename) +{ + GstMessage *msg; + + g_return_if_fail (filename != NULL); + + msg = gst_message_new_element (GST_OBJECT_CAST (camera), + gst_structure_new ("image-done", "filename", G_TYPE_STRING, + filename, NULL)); + + if (!gst_element_post_message (GST_ELEMENT_CAST (camera), msg)) + GST_WARNING_OBJECT (camera, "Failed to post image-done message"); +} + +static void +gst_camera_bin_handle_message (GstBin * bin, GstMessage * message) +{ + if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT) { + const GstStructure *structure = gst_message_get_structure (message); + const gchar *filename; + + if (gst_structure_has_name (structure, "GstMultiFileSink")) { + filename = gst_structure_get_string (structure, "filename"); + if (filename) { + gst_image_capture_bin_post_image_done (GST_CAMERA_BIN_CAST (bin), + filename); + } + } + } + GST_BIN_CLASS (parent_class)->handle_message (bin, message); +} + +/* + * Transforms: + * ... ! previous_element [ ! current_filter ] ! next_element ! ... + * + * into: + * ... ! previous_element [ ! new_filter ] ! next_element ! ... + * + * Where current_filter and new_filter might or might not be NULL + */ +static void +gst_camera_bin_check_and_replace_filter (GstCameraBin * camera, + GstElement ** current_filter, GstElement * new_filter, + GstElement * previous_element, GstElement * next_element) +{ + if (*current_filter == new_filter) { + GST_DEBUG_OBJECT (camera, "Current filter is the same as the previous, " + "no switch needed."); + return; + } + + GST_DEBUG_OBJECT (camera, "Replacing current filter (%s) with new filter " + "(%s)", *current_filter ? GST_ELEMENT_NAME (*current_filter) : "null", + new_filter ? GST_ELEMENT_NAME (new_filter) : "null"); + + if (*current_filter) { + gst_bin_remove (GST_BIN_CAST (camera), *current_filter); + gst_object_unref (*current_filter); + *current_filter = NULL; + } else { + /* unlink the pads */ + gst_element_unlink (previous_element, next_element); + } + + if (new_filter) { + *current_filter = gst_object_ref (new_filter); + gst_bin_add (GST_BIN_CAST (camera), gst_object_ref (new_filter)); + gst_element_link_many (previous_element, new_filter, next_element, NULL); + } else { + gst_element_link (previous_element, next_element); + } +} + +/** + * gst_camera_bin_create_elements: + * @param camera: the #GstCameraBin + * + * Creates all elements inside #GstCameraBin + * + * Each of the pads on the camera source is linked as follows: + * .pad ! queue ! capsfilter ! correspondingbin + * + * Where 'correspondingbin' is the bin appropriate for + * the camera source pad. + */ +static gboolean +gst_camera_bin_create_elements (GstCameraBin * camera) +{ + gboolean new_src = FALSE; + + if (!camera->elements_created) { + + camera->encodebin = gst_element_factory_make ("encodebin", NULL); + camera->videosink = + gst_element_factory_make ("filesink", "videobin-filesink"); + camera->imagebin = gst_element_factory_make ("imagecapturebin", "imagebin"); + g_object_set (camera->videosink, "async", FALSE, NULL); + + if (camera->video_profile == NULL) { + GstEncodingContainerProfile *prof; + GstCaps *caps; + + caps = gst_caps_new_simple ("application/ogg", NULL); + prof = gst_encoding_container_profile_new ("ogg", "theora+ogg", caps, + NULL); + gst_caps_unref (caps); + + caps = gst_caps_new_simple ("video/x-theora", NULL); + if (!gst_encoding_container_profile_add_profile (prof, + (GstEncodingProfile *) gst_encoding_video_profile_new (caps, + NULL, NULL, 1))) { + GST_WARNING_OBJECT (camera, "Failed to create encoding profiles"); + } + gst_caps_unref (caps); + + camera->video_profile = (GstEncodingProfile *) prof; + } + g_object_set (camera->encodebin, "profile", camera->video_profile, NULL); + + camera->videobin_queue = + gst_element_factory_make ("queue", "videobin-queue"); + camera->imagebin_queue = + gst_element_factory_make ("queue", "imagebin-queue"); + camera->viewfinderbin_queue = + gst_element_factory_make ("queue", "viewfinderbin-queue"); + + gst_bin_add_many (GST_BIN_CAST (camera), + gst_object_ref (camera->encodebin), + gst_object_ref (camera->videosink), + gst_object_ref (camera->imagebin), + gst_object_ref (camera->videobin_queue), + gst_object_ref (camera->imagebin_queue), + gst_object_ref (camera->viewfinderbin_queue), NULL); + + /* Linking can be optimized TODO */ + gst_element_link_many (camera->videobin_queue, camera->videobin_capsfilter, + NULL); + gst_element_link (camera->encodebin, camera->videosink); + gst_element_link (camera->videobin_capsfilter, camera->encodebin); + + gst_element_link_many (camera->imagebin_queue, camera->imagebin_capsfilter, + camera->imagebin, NULL); + gst_element_link_many (camera->viewfinderbin_queue, + camera->viewfinderbin_capsfilter, camera->viewfinderbin, NULL); + /* + * Video can't get into playing as its internal filesink will open + * a file for writing and leave it empty if unused. + * + * Its state is managed using the current mode and the source's + * ready-for-capture notify callback. When we are at video mode and + * the source's ready-for-capture goes to FALSE it means it is + * starting recording, so we should prepare the video bin. + */ + gst_element_set_locked_state (camera->videosink, TRUE); + + g_object_set (camera->videosink, "location", camera->video_location, NULL); + g_object_set (camera->imagebin, "location", camera->image_location, NULL); + } + + /* check if we need to replace the camera src */ + + if (camera->src) { + if (camera->user_src && camera->user_src != camera->src) { + + if (camera->src_capture_notify_id) + g_signal_handler_disconnect (camera->src, + camera->src_capture_notify_id); + + gst_bin_remove (GST_BIN_CAST (camera), camera->src); + gst_object_unref (camera->src); + camera->src = NULL; + } + } + + if (!camera->src) { + if (camera->user_src) { + camera->src = gst_object_ref (camera->user_src); + } else { + camera->src = + gst_element_factory_make ("wrappercamerabinsrc", "camerasrc"); + } + + new_src = TRUE; + } + + g_assert (camera->src != NULL); + g_object_set (camera->src, "mode", camera->mode, NULL); + if (camera->src + && g_object_class_find_property (G_OBJECT_GET_CLASS (camera->src), + "preview-caps")) { + g_object_set (camera->src, "post-previews", camera->post_previews, + "preview-caps", camera->preview_caps, "preview-filter", + camera->preview_filter, NULL); + } + if (new_src) { + gst_bin_add (GST_BIN_CAST (camera), gst_object_ref (camera->src)); + camera->src_capture_notify_id = g_signal_connect (G_OBJECT (camera->src), + "notify::ready-for-capture", + G_CALLBACK (gst_camera_bin_src_notify_readyforcapture), camera); + gst_element_link_pads (camera->src, "vfsrc", camera->viewfinderbin_queue, + "sink"); + gst_element_link_pads (camera->src, "imgsrc", camera->imagebin_queue, + "sink"); + gst_element_link_pads (camera->src, "vidsrc", camera->videobin_queue, + "sink"); + } + + gst_camera_bin_check_and_replace_filter (camera, &camera->image_filter, + camera->user_image_filter, camera->imagebin_queue, + camera->imagebin_capsfilter); + gst_camera_bin_check_and_replace_filter (camera, &camera->video_filter, + camera->user_video_filter, camera->videobin_queue, + camera->videobin_capsfilter); + gst_camera_bin_check_and_replace_filter (camera, &camera->viewfinder_filter, + camera->user_viewfinder_filter, camera->viewfinderbin_queue, + camera->viewfinderbin_capsfilter); + + camera->elements_created = TRUE; + return TRUE; +} + +static GstStateChangeReturn +gst_camera_bin_change_state (GstElement * element, GstStateChange trans) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + GstCameraBin *camera = GST_CAMERA_BIN_CAST (element); + + switch (trans) { + case GST_STATE_CHANGE_NULL_TO_READY: + if (!gst_camera_bin_create_elements (camera)) { + return GST_STATE_CHANGE_FAILURE; + } + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, trans); + + switch (trans) { + case GST_STATE_CHANGE_PAUSED_TO_READY: + if (GST_STATE (camera->videosink) >= GST_STATE_PAUSED) + gst_element_set_state (camera->videosink, GST_STATE_READY); + + gst_tag_setter_reset_tags (GST_TAG_SETTER (camera)); + break; + case GST_STATE_CHANGE_READY_TO_NULL: + gst_element_set_state (camera->videosink, GST_STATE_NULL); + break; + default: + break; + } + + return ret; +} + +static void +gst_camera_bin_set_location (GstCameraBin * camera, const gchar * location) +{ + GST_DEBUG_OBJECT (camera, "Setting mode %d location to %s", camera->mode, + location); + if (camera->mode == MODE_IMAGE) { + if (camera->imagebin) + g_object_set (camera->imagebin, "location", location, NULL); + g_free (camera->image_location); + camera->image_location = g_strdup (location); + } else { + g_free (camera->video_location); + camera->video_location = g_strdup (location); + } +} + +static void +gst_camera_bin_set_camera_src (GstCameraBin * camera, GstElement * src) +{ + GST_DEBUG_OBJECT (GST_OBJECT (camera), + "Setting camera source %" GST_PTR_FORMAT, src); + + if (camera->user_src) + g_object_unref (camera->user_src); + + if (src) + g_object_ref (src); + camera->user_src = src; +} + +static void +gst_camera_bin_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstCameraBin *camera = GST_CAMERA_BIN_CAST (object); + + switch (prop_id) { + case PROP_MODE: + gst_camera_bin_change_mode (camera, g_value_get_enum (value)); + break; + case PROP_LOCATION: + gst_camera_bin_set_location (camera, g_value_get_string (value)); + break; + case PROP_CAMERA_SRC: + gst_camera_bin_set_camera_src (camera, g_value_get_object (value)); + break; + case PROP_IMAGE_CAPTURE_CAPS:{ + GstPad *pad = NULL; + + if (camera->src) + pad = + gst_element_get_static_pad (camera->src, + GST_BASE_CAMERA_SRC_IMAGE_PAD_NAME); + + GST_DEBUG_OBJECT (camera, + "Setting image capture caps to %" GST_PTR_FORMAT, + gst_value_get_caps (value)); + + /* set the capsfilter caps and notify the src to renegotiate */ + g_object_set (camera->imagebin_capsfilter, "caps", + gst_value_get_caps (value), NULL); + if (pad) { + GST_DEBUG_OBJECT (camera, "Pushing renegotiate on %s", + GST_PAD_NAME (pad)); + GST_PAD_EVENTFUNC (pad) (pad, gst_camera_bin_new_event_renegotiate ()); + gst_object_unref (pad); + } + } + break; + case PROP_VIDEO_CAPTURE_CAPS:{ + GstPad *pad = NULL; + + if (camera->src) + pad = + gst_element_get_static_pad (camera->src, + GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME); + + GST_DEBUG_OBJECT (camera, + "Setting video capture caps to %" GST_PTR_FORMAT, + gst_value_get_caps (value)); + + /* set the capsfilter caps and notify the src to renegotiate */ + g_object_set (camera->videobin_capsfilter, "caps", + gst_value_get_caps (value), NULL); + if (pad) { + GST_DEBUG_OBJECT (camera, "Pushing renegotiate on %s", + GST_PAD_NAME (pad)); + GST_PAD_EVENTFUNC (pad) (pad, gst_camera_bin_new_event_renegotiate ()); + gst_object_unref (pad); + } + } + break; + case PROP_POST_PREVIEWS: + camera->post_previews = g_value_get_boolean (value); + if (camera->src + && g_object_class_find_property (G_OBJECT_GET_CLASS (camera->src), + "post-previews")) + g_object_set (camera->src, "post-previews", camera->post_previews, + NULL); + break; + case PROP_PREVIEW_CAPS: + gst_caps_replace (&camera->preview_caps, + (GstCaps *) gst_value_get_caps (value)); + if (camera->src + && g_object_class_find_property (G_OBJECT_GET_CLASS (camera->src), + "preview-caps")) + g_object_set (camera->src, "preview-caps", camera->preview_caps, NULL); + break; + case PROP_VIDEO_ENCODING_PROFILE: + camera->video_profile = + (GstEncodingProfile *) gst_value_dup_mini_object (value); + break; + case PROP_IMAGE_FILTER: + if (camera->user_image_filter) + g_object_unref (camera->user_image_filter); + + camera->user_image_filter = g_value_dup_object (value); + break; + case PROP_VIDEO_FILTER: + if (camera->user_video_filter) + g_object_unref (camera->user_video_filter); + + camera->user_video_filter = g_value_dup_object (value); + break; + case PROP_VIEWFINDER_FILTER: + if (camera->user_viewfinder_filter) + g_object_unref (camera->user_viewfinder_filter); + + camera->user_viewfinder_filter = g_value_dup_object (value); + break; + case PROP_PREVIEW_FILTER: + if (camera->preview_filter) + g_object_unref (camera->preview_filter); + + camera->preview_filter = g_value_dup_object (value); + if (camera->src + && g_object_class_find_property (G_OBJECT_GET_CLASS (camera->src), + "preview-filter")) + g_object_set (camera->src, "preview-filter", camera->preview_filter, + NULL); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_camera_bin_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstCameraBin *camera = GST_CAMERA_BIN_CAST (object); + + switch (prop_id) { + case PROP_MODE: + g_value_set_enum (value, camera->mode); + break; + case PROP_LOCATION: + if (camera->mode == MODE_VIDEO) { + g_value_set_string (value, camera->video_location); + } else { + g_value_set_string (value, camera->image_location); + } + break; + case PROP_CAMERA_SRC: + g_value_set_object (value, camera->src); + break; + case PROP_VIDEO_CAPTURE_SUPPORTED_CAPS: + case PROP_IMAGE_CAPTURE_SUPPORTED_CAPS:{ + GstPad *pad; + GstCaps *caps; + const gchar *padname; + + if (prop_id == PROP_VIDEO_CAPTURE_SUPPORTED_CAPS) { + padname = GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME; + } else { + padname = GST_BASE_CAMERA_SRC_IMAGE_PAD_NAME; + } + + if (camera->src) { + pad = gst_element_get_static_pad (camera->src, padname); + + g_assert (pad != NULL); + + /* TODO not sure if we want get_caps or get_allowed_caps to already + * consider the full pipeline scenario and avoid picking a caps that + * won't negotiate. Need to take care on the special case of the + * pad being unlinked. + */ + caps = gst_pad_get_caps_reffed (pad); + if (caps) { + gst_value_set_caps (value, caps); + gst_caps_unref (caps); + } + + gst_object_unref (pad); + } else { + GST_DEBUG_OBJECT (camera, "Camera source not created, can't get " + "supported caps"); + } + } + break; + case PROP_IMAGE_CAPTURE_CAPS:{ + GstCaps *caps = NULL; + g_object_get (camera->imagebin_capsfilter, "caps", &caps, NULL); + gst_value_set_caps (value, caps); + gst_caps_unref (caps); + } + break; + case PROP_VIDEO_CAPTURE_CAPS:{ + GstCaps *caps = NULL; + g_object_get (camera->videobin_capsfilter, "caps", &caps, NULL); + gst_value_set_caps (value, caps); + gst_caps_unref (caps); + } + break; + case PROP_POST_PREVIEWS: + g_value_set_boolean (value, camera->post_previews); + break; + case PROP_PREVIEW_CAPS: + if (camera->preview_caps) + gst_value_set_caps (value, camera->preview_caps); + break; + case PROP_VIDEO_ENCODING_PROFILE: + if (camera->video_profile) { + gst_value_set_mini_object (value, + (GstMiniObject *) camera->video_profile); + } + break; + case PROP_VIDEO_FILTER: + if (camera->video_filter) + g_value_set_object (value, camera->video_filter); + break; + case PROP_IMAGE_FILTER: + if (camera->image_filter) + g_value_set_object (value, camera->image_filter); + break; + case PROP_VIEWFINDER_FILTER: + if (camera->viewfinder_filter) + g_value_set_object (value, camera->viewfinder_filter); + break; + case PROP_PREVIEW_FILTER: + if (camera->preview_filter) + g_value_set_object (value, camera->preview_filter); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +gboolean +gst_camera_bin_plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (gst_camera_bin_debug, "camerabin2", 0, "CameraBin2"); + + return gst_element_register (plugin, "camerabin2", GST_RANK_NONE, + gst_camera_bin_get_type ()); +} diff --git a/gst/camerabin2/gstcamerabin2.h b/gst/camerabin2/gstcamerabin2.h new file mode 100644 index 000000000..64828b49e --- /dev/null +++ b/gst/camerabin2/gstcamerabin2.h @@ -0,0 +1,94 @@ +/* GStreamer + * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef _GST_CAMERA_BIN_H_ +#define _GST_CAMERA_BIN_H_ + +#include <gst/gst.h> +#include <gst/pbutils/encoding-profile.h> + +G_BEGIN_DECLS + +#define GST_TYPE_CAMERA_BIN (gst_camera_bin_get_type()) +#define GST_CAMERA_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CAMERA_BIN,GstCameraBin)) +#define GST_CAMERA_BIN_CAST(obj) ((GstCameraBin *) obj) +#define GST_CAMERA_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CAMERA_BIN,GstCameraBinClass)) +#define GST_IS_CAMERA_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CAMERA_BIN)) +#define GST_IS_CAMERA_BIN_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CAMERA_BIN)) + +typedef struct _GstCameraBin GstCameraBin; +typedef struct _GstCameraBinClass GstCameraBinClass; + +struct _GstCameraBin +{ + GstPipeline pipeline; + + GstElement *src; + GstElement *user_src; + gulong src_capture_notify_id; + + GstElement *encodebin; + GstElement *videosink; + GstElement *videobin_queue; + GstElement *videobin_capsfilter; + + GstElement *viewfinderbin; + GstElement *viewfinderbin_queue; + GstElement *viewfinderbin_capsfilter; + + GstElement *imagebin; + GstElement *imagebin_queue; + GstElement *imagebin_capsfilter; + + GstElement *video_filter; + GstElement *image_filter; + GstElement *viewfinder_filter; + GstElement *user_video_filter; + GstElement *user_image_filter; + GstElement *user_viewfinder_filter; + + /* Index of the auto incrementing file index for video recordings */ + gint video_index; + + /* properties */ + gint mode; + gchar *video_location; + gchar *image_location; + gboolean post_previews; + GstCaps *preview_caps; + GstElement *preview_filter; + GstEncodingProfile *video_profile; + + gboolean elements_created; +}; + +struct _GstCameraBinClass +{ + GstPipelineClass pipeline_class; + + /* Action signals */ + void (*start_capture) (GstCameraBin * camera); + void (*stop_capture) (GstCameraBin * camera); +}; + +GType gst_camera_bin_get_type (void); +gboolean gst_camera_bin_plugin_init (GstPlugin * plugin); + +G_END_DECLS + +#endif diff --git a/gst/camerabin2/gstimagecapturebin.c b/gst/camerabin2/gstimagecapturebin.c new file mode 100644 index 000000000..b4aba2aa0 --- /dev/null +++ b/gst/camerabin2/gstimagecapturebin.c @@ -0,0 +1,352 @@ +/* GStreamer + * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/** + * SECTION:element-gstimagecapturebin + * + * The gstimagecapturebin element does FIXME stuff. + * + * <refsect2> + * <title>Example launch line</title> + * |[ + * gst-launch -v videotestsrc num-buffers=3 ! imagecapturebin + * ]| + * FIXME Describe what the pipeline does. + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstimagecapturebin.h" +#include "camerabingeneral.h" + +/* prototypes */ + + +enum +{ + PROP_0, + PROP_LOCATION, + PROP_ENCODER, + PROP_MUXER +}; + +#define DEFAULT_LOCATION "img_%d" +#define DEFAULT_COLORSPACE "ffmpegcolorspace" +#define DEFAULT_ENCODER "jpegenc" +#define DEFAULT_MUXER "jifmux" +#define DEFAULT_SINK "multifilesink" + +/* pad templates */ + +static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-raw-yuv; video/x-raw-rgb") + ); + +/* class initialization */ + +GST_BOILERPLATE (GstImageCaptureBin, gst_image_capture_bin, GstBin, + GST_TYPE_BIN); + +/* GObject callbacks */ +static void gst_image_capture_bin_dispose (GObject * object); +static void gst_image_capture_bin_finalize (GObject * object); + +/* Element class functions */ +static GstStateChangeReturn +gst_image_capture_bin_change_state (GstElement * element, GstStateChange trans); + +static void +gst_image_capture_bin_set_encoder (GstImageCaptureBin * imagebin, + GstElement * encoder) +{ + GST_DEBUG_OBJECT (GST_OBJECT (imagebin), + "Setting image encoder %" GST_PTR_FORMAT, encoder); + + if (imagebin->user_encoder) + g_object_unref (imagebin->user_encoder); + + if (encoder) + g_object_ref (encoder); + + imagebin->user_encoder = encoder; +} + +static void +gst_image_capture_bin_set_muxer (GstImageCaptureBin * imagebin, + GstElement * muxer) +{ + GST_DEBUG_OBJECT (GST_OBJECT (imagebin), + "Setting image muxer %" GST_PTR_FORMAT, muxer); + + if (imagebin->user_muxer) + g_object_unref (imagebin->user_muxer); + + if (muxer) + g_object_ref (muxer); + + imagebin->user_muxer = muxer; +} + +static void +gst_image_capture_bin_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstImageCaptureBin *imagebin = GST_IMAGE_CAPTURE_BIN_CAST (object); + + switch (prop_id) { + case PROP_LOCATION: + g_free (imagebin->location); + imagebin->location = g_value_dup_string (value); + GST_DEBUG_OBJECT (imagebin, "setting location to %s", imagebin->location); + if (imagebin->sink) { + g_object_set (imagebin->sink, "location", imagebin->location, NULL); + } + break; + case PROP_ENCODER: + gst_image_capture_bin_set_encoder (imagebin, g_value_get_object (value)); + break; + case PROP_MUXER: + gst_image_capture_bin_set_muxer (imagebin, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_image_capture_bin_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstImageCaptureBin *imagebin = GST_IMAGE_CAPTURE_BIN_CAST (object); + + switch (prop_id) { + case PROP_LOCATION: + g_value_set_string (value, imagebin->location); + break; + case PROP_ENCODER: + g_value_set_object (value, imagebin->encoder); + break; + case PROP_MUXER: + g_value_set_object (value, imagebin->muxer); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_image_capture_bin_finalize (GObject * object) +{ + GstImageCaptureBin *imgbin = GST_IMAGE_CAPTURE_BIN_CAST (object); + + g_free (imgbin->location); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_image_capture_bin_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_template)); + + gst_element_class_set_details_simple (element_class, "Image Capture Bin", + "Sink/Video", "Image Capture Bin used in camerabin2", + "Thiago Santos <thiago.sousa.santos@collabora.co.uk>"); +} + +static void +gst_image_capture_bin_class_init (GstImageCaptureBinClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *element_class; + + gobject_class = G_OBJECT_CLASS (klass); + element_class = GST_ELEMENT_CLASS (klass); + + gobject_class->dispose = gst_image_capture_bin_dispose; + gobject_class->finalize = gst_image_capture_bin_finalize; + gobject_class->set_property = gst_image_capture_bin_set_property; + gobject_class->get_property = gst_image_capture_bin_get_property; + + element_class->change_state = + GST_DEBUG_FUNCPTR (gst_image_capture_bin_change_state); + + g_object_class_install_property (gobject_class, PROP_LOCATION, + g_param_spec_string ("location", "Location", + "Location to save the captured files. A %%d can be used as a " + "placeholder for a capture count", + DEFAULT_LOCATION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_ENCODER, + g_param_spec_object ("image-encoder", "Image encoder", + "Image encoder GStreamer element (default is jpegenc)", + GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_MUXER, + g_param_spec_object ("image-muxer", "Image muxer", + "Image muxer GStreamer element (default is jifmux)", + GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +} + +static void +gst_image_capture_bin_init (GstImageCaptureBin * imagebin, + GstImageCaptureBinClass * imagebin_class) +{ + GstPadTemplate *tmpl; + + tmpl = gst_static_pad_template_get (&sink_template); + imagebin->ghostpad = gst_ghost_pad_new_no_target_from_template ("sink", tmpl); + gst_object_unref (tmpl); + gst_element_add_pad (GST_ELEMENT_CAST (imagebin), imagebin->ghostpad); + + imagebin->sink = NULL; + + imagebin->location = g_strdup (DEFAULT_LOCATION); + imagebin->encoder = NULL; + imagebin->user_encoder = NULL; + imagebin->muxer = NULL; + imagebin->user_muxer = NULL; +} + +static void +gst_image_capture_bin_dispose (GObject * object) +{ + GstImageCaptureBin *imagebin = GST_IMAGE_CAPTURE_BIN_CAST (object); + + if (imagebin->user_encoder) { + gst_object_unref (imagebin->user_encoder); + imagebin->user_encoder = NULL; + } + + if (imagebin->user_muxer) { + gst_object_unref (imagebin->user_muxer); + imagebin->user_muxer = NULL; + } + G_OBJECT_CLASS (parent_class)->dispose ((GObject *) imagebin); +} + +static gboolean +gst_image_capture_bin_create_elements (GstImageCaptureBin * imagebin) +{ + GstElement *colorspace; + GstPad *pad = NULL; + + if (imagebin->elements_created) + return TRUE; + + /* create elements */ + colorspace = + gst_camerabin_create_and_add_element (GST_BIN (imagebin), + DEFAULT_COLORSPACE, "imagebin-colorspace"); + if (!colorspace) + goto error; + + if (imagebin->user_encoder) { + imagebin->encoder = imagebin->user_encoder; + if (!gst_camerabin_add_element (GST_BIN (imagebin), imagebin->encoder)) { + goto error; + } + } else { + imagebin->encoder = + gst_camerabin_create_and_add_element (GST_BIN (imagebin), + DEFAULT_ENCODER, "imagebin-encoder"); + if (!imagebin->encoder) + goto error; + } + + if (imagebin->user_muxer) { + imagebin->muxer = imagebin->user_muxer; + if (!gst_camerabin_add_element (GST_BIN (imagebin), imagebin->muxer)) { + goto error; + } + } else { + imagebin->muxer = + gst_camerabin_create_and_add_element (GST_BIN (imagebin), + DEFAULT_MUXER, "imagebin-muxer"); + if (!imagebin->muxer) + goto error; + } + + imagebin->sink = + gst_camerabin_create_and_add_element (GST_BIN (imagebin), DEFAULT_SINK, + "imagebin-sink"); + if (!imagebin->sink) + goto error; + + g_object_set (imagebin->sink, "location", imagebin->location, "async", FALSE, + "post-messages", TRUE, NULL); + + /* add ghostpad */ + pad = gst_element_get_static_pad (colorspace, "sink"); + if (!gst_ghost_pad_set_target (GST_GHOST_PAD (imagebin->ghostpad), pad)) + goto error; + gst_object_unref (pad); + + imagebin->elements_created = TRUE; + return TRUE; + +error: + if (pad) + gst_object_unref (pad); + return FALSE; +} + +static GstStateChangeReturn +gst_image_capture_bin_change_state (GstElement * element, GstStateChange trans) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + GstImageCaptureBin *imagebin = GST_IMAGE_CAPTURE_BIN_CAST (element); + + switch (trans) { + case GST_STATE_CHANGE_NULL_TO_READY: + if (!gst_image_capture_bin_create_elements (imagebin)) { + return GST_STATE_CHANGE_FAILURE; + } + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, trans); + + switch (trans) { + case GST_STATE_CHANGE_READY_TO_NULL: + break; + default: + break; + } + + return ret; +} + +gboolean +gst_image_capture_bin_plugin_init (GstPlugin * plugin) +{ + return gst_element_register (plugin, "imagecapturebin", GST_RANK_NONE, + gst_image_capture_bin_get_type ()); +} diff --git a/gst/camerabin2/gstimagecapturebin.h b/gst/camerabin2/gstimagecapturebin.h new file mode 100644 index 000000000..98a28e983 --- /dev/null +++ b/gst/camerabin2/gstimagecapturebin.h @@ -0,0 +1,63 @@ +/* GStreamer + * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef _GST_IMAGE_CAPTURE_BIN_H_ +#define _GST_IMAGE_CAPTURE_BIN_H_ + +#include <gst/gst.h> + +G_BEGIN_DECLS + +#define GST_TYPE_IMAGE_CAPTURE_BIN (gst_image_capture_bin_get_type()) +#define GST_IMAGE_CAPTURE_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_IMAGE_CAPTURE_BIN,GstImageCaptureBin)) +#define GST_IMAGE_CAPTURE_BIN_CAST(obj) ((GstImageCaptureBin *) obj) +#define GST_IMAGE_CAPTURE_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_IMAGE_CAPTURE_BIN,GstImageCaptureBinClass)) +#define GST_IS_IMAGE_CAPTURE_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_IMAGE_CAPTURE_BIN)) +#define GST_IS_IMAGE_CAPTURE_BIN_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_IMAGE_CAPTURE_BIN)) + +typedef struct _GstImageCaptureBin GstImageCaptureBin; +typedef struct _GstImageCaptureBinClass GstImageCaptureBinClass; + +struct _GstImageCaptureBin +{ + GstBin bin; + + GstPad *ghostpad; + GstElement *sink; + + /* props */ + gchar *location; + GstElement *encoder; + GstElement *user_encoder; + GstElement *muxer; + GstElement *user_muxer; + + gboolean elements_created; +}; + +struct _GstImageCaptureBinClass +{ + GstBinClass bin_class; +}; + +GType gst_image_capture_bin_get_type (void); +gboolean gst_image_capture_bin_plugin_init (GstPlugin * plugin); + +G_END_DECLS + +#endif diff --git a/gst/camerabin2/gstplugin.c b/gst/camerabin2/gstplugin.c new file mode 100644 index 000000000..56fa78f80 --- /dev/null +++ b/gst/camerabin2/gstplugin.c @@ -0,0 +1,49 @@ +/* GStreamer + * Copyright (C) <2010> Thiago Santos <thiago.sousa.santos@collabora.co.uk> + * + * gstplugin.c: camerabin2 plugin registering + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstviewfinderbin.h" +#include "gstimagecapturebin.h" +#include "gstwrappercamerabinsrc.h" +#include "gstcamerabin2.h" + +static gboolean +plugin_init (GstPlugin * plugin) +{ + if (!gst_viewfinder_bin_plugin_init (plugin)) + return FALSE; + if (!gst_image_capture_bin_plugin_init (plugin)) + return FALSE; + if (!gst_wrapper_camera_bin_src_plugin_init (plugin)) + return FALSE; + if (!gst_camera_bin_plugin_init (plugin)) + return FALSE; + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "camerabin2", "camerabin2", + plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/gst/camerabin2/gstviewfinderbin.c b/gst/camerabin2/gstviewfinderbin.c new file mode 100644 index 000000000..e03631e32 --- /dev/null +++ b/gst/camerabin2/gstviewfinderbin.c @@ -0,0 +1,305 @@ +/* GStreamer + * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/** + * SECTION:element-gstviewfinderbin + * + * The gstviewfinderbin element is a displaying element for camerabin2. + * + * <refsect2> + * <title>Example launch line</title> + * |[ + * gst-launch -v videotestsrc ! viewfinderbin + * ]| + * Feeds the viewfinderbin with video test data. + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstviewfinderbin.h" + +GST_DEBUG_CATEGORY_STATIC (gst_viewfinder_bin_debug); +#define GST_CAT_DEFAULT gst_viewfinder_bin_debug + +/* prototypes */ + + +enum +{ + PROP_0, + PROP_VIDEO_SINK, +}; + +/* pad templates */ + +static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-raw-yuv; video/x-raw-rgb") + ); + +/* class initialization */ + +GST_BOILERPLATE (GstViewfinderBin, gst_viewfinder_bin, GstBin, GST_TYPE_BIN); + +static void gst_viewfinder_bin_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * spec); +static void gst_viewfinder_bin_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * spec); + +static void +gst_viewfinder_bin_set_video_sink (GstViewfinderBin * vfbin, GstElement * sink); + + +/* Element class functions */ +static GstStateChangeReturn +gst_viewfinder_bin_change_state (GstElement * element, GstStateChange trans); + +static void +gst_viewfinder_bin_dispose (GObject * object) +{ + GstViewfinderBin *viewfinderbin = GST_VIEWFINDER_BIN_CAST (object); + + if (viewfinderbin->user_video_sink) { + gst_object_unref (viewfinderbin->user_video_sink); + viewfinderbin->user_video_sink = NULL; + } + + if (viewfinderbin->video_sink) { + gst_object_unref (viewfinderbin->video_sink); + viewfinderbin->video_sink = NULL; + } + + G_OBJECT_CLASS (parent_class)->dispose ((GObject *) viewfinderbin); +} + +static void +gst_viewfinder_bin_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_template)); + + gst_element_class_set_details_simple (element_class, "Viewfinder Bin", + "Sink/Video", "Viewfinder Bin used in camerabin2", + "Thiago Santos <thiago.sousa.santos@collabora.co.uk>"); +} + +static void +gst_viewfinder_bin_class_init (GstViewfinderBinClass * klass) +{ + GObjectClass *gobject_klass; + GstElementClass *element_class; + + gobject_klass = (GObjectClass *) klass; + element_class = GST_ELEMENT_CLASS (klass); + + element_class->change_state = + GST_DEBUG_FUNCPTR (gst_viewfinder_bin_change_state); + + gobject_klass->dispose = gst_viewfinder_bin_dispose; + gobject_klass->set_property = gst_viewfinder_bin_set_property; + gobject_klass->get_property = gst_viewfinder_bin_get_property; + + g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK, + g_param_spec_object ("video-sink", "Video Sink", + "the video output element to use (NULL = default)", + GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +} + +static void +gst_viewfinder_bin_init (GstViewfinderBin * viewfinderbin, + GstViewfinderBinClass * viewfinderbin_class) +{ + GstPadTemplate *templ = gst_static_pad_template_get (&sink_template); + viewfinderbin->ghostpad = gst_ghost_pad_new_no_target_from_template ("sink", + templ); + gst_object_unref (templ); + gst_element_add_pad (GST_ELEMENT_CAST (viewfinderbin), + viewfinderbin->ghostpad); +} + +static gboolean +gst_viewfinder_bin_create_elements (GstViewfinderBin * vfbin) +{ + GstElement *csp = NULL; + GstElement *videoscale = NULL; + GstPad *pad = NULL; + gboolean added = FALSE; + + GST_DEBUG_OBJECT (vfbin, "Creating internal elements"); + + if (!vfbin->elements_created) { + /* create elements */ + csp = gst_element_factory_make ("ffmpegcolorspace", "vfbin-csp"); + if (!csp) + goto error; + + videoscale = gst_element_factory_make ("videoscale", "vfbin-videoscale"); + if (!videoscale) + goto error; + + GST_DEBUG_OBJECT (vfbin, "Internal elements created, proceding to linking"); + + /* add and link */ + gst_bin_add_many (GST_BIN_CAST (vfbin), csp, videoscale, NULL); + added = TRUE; + if (!gst_element_link (csp, videoscale)) + goto error; + + /* add ghostpad */ + pad = gst_element_get_static_pad (csp, "sink"); + if (!gst_ghost_pad_set_target (GST_GHOST_PAD (vfbin->ghostpad), pad)) + goto error; + gst_object_unref (pad); + + vfbin->elements_created = TRUE; + GST_DEBUG_OBJECT (vfbin, "Elements succesfully created and linked"); + } + + if (vfbin->video_sink) { + /* check if we need to replace the current one */ + if (vfbin->user_video_sink && vfbin->video_sink != vfbin->user_video_sink) { + gst_bin_remove (GST_BIN_CAST (vfbin), vfbin->video_sink); + gst_object_unref (vfbin->video_sink); + vfbin->video_sink = NULL; + } + } + + if (!vfbin->video_sink) { + if (vfbin->user_video_sink) + vfbin->video_sink = gst_object_ref (vfbin->user_video_sink); + else + vfbin->video_sink = gst_element_factory_make ("autovideosink", + "vfbin-sink"); + + gst_bin_add (GST_BIN_CAST (vfbin), gst_object_ref (vfbin->video_sink)); + + if (!videoscale) + videoscale = gst_bin_get_by_name (GST_BIN_CAST (vfbin), + "vfbin-videoscale"); + + if (!gst_element_link_pads (videoscale, "src", vfbin->video_sink, "sink")) { + GST_WARNING_OBJECT (vfbin, "Failed to link the new sink"); + } + } + + return TRUE; + +error: + GST_WARNING_OBJECT (vfbin, "Creating internal elements failed"); + if (pad) + gst_object_unref (pad); + if (!added) { + if (csp) + gst_object_unref (csp); + if (videoscale) + gst_object_unref (videoscale); + } else { + gst_bin_remove_many (GST_BIN_CAST (vfbin), csp, videoscale, NULL); + } + return FALSE; +} + +static GstStateChangeReturn +gst_viewfinder_bin_change_state (GstElement * element, GstStateChange trans) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + GstViewfinderBin *vfbin = GST_VIEWFINDER_BIN_CAST (element); + + switch (trans) { + case GST_STATE_CHANGE_NULL_TO_READY: + if (!gst_viewfinder_bin_create_elements (vfbin)) { + return GST_STATE_CHANGE_FAILURE; + } + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, trans); + + switch (trans) { + case GST_STATE_CHANGE_READY_TO_NULL: + break; + default: + break; + } + + return ret; +} + +static void +gst_viewfinder_bin_set_video_sink (GstViewfinderBin * vfbin, GstElement * sink) +{ + GST_INFO_OBJECT (vfbin, "Setting video sink to %" GST_PTR_FORMAT, sink); + + if (vfbin->user_video_sink != sink) { + if (vfbin->user_video_sink) { + gst_object_unref (vfbin->user_video_sink); + } + vfbin->user_video_sink = sink; + if (sink) + gst_object_ref (sink); + } +} + +static void +gst_viewfinder_bin_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstViewfinderBin *vfbin = GST_VIEWFINDER_BIN_CAST (object); + + switch (prop_id) { + case PROP_VIDEO_SINK: + gst_viewfinder_bin_set_video_sink (vfbin, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_viewfinder_bin_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstViewfinderBin *vfbin = GST_VIEWFINDER_BIN_CAST (object); + + switch (prop_id) { + case PROP_VIDEO_SINK: + g_value_set_object (value, vfbin->video_sink); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +gboolean +gst_viewfinder_bin_plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (gst_viewfinder_bin_debug, "viewfinderbin", 0, + "ViewFinderBin"); + return gst_element_register (plugin, "viewfinderbin", GST_RANK_NONE, + gst_viewfinder_bin_get_type ()); +} diff --git a/gst/camerabin2/gstviewfinderbin.h b/gst/camerabin2/gstviewfinderbin.h new file mode 100644 index 000000000..636921957 --- /dev/null +++ b/gst/camerabin2/gstviewfinderbin.h @@ -0,0 +1,58 @@ +/* GStreamer + * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef _GST_VIEWFINDER_BIN_H_ +#define _GST_VIEWFINDER_BIN_H_ + +#include <gst/gst.h> + +G_BEGIN_DECLS + +#define GST_TYPE_VIEWFINDER_BIN (gst_viewfinder_bin_get_type()) +#define GST_VIEWFINDER_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIEWFINDER_BIN,GstViewfinderBin)) +#define GST_VIEWFINDER_BIN_CAST(obj) ((GstViewfinderBin *) obj) +#define GST_VIEWFINDER_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIEWFINDER_BIN,GstViewfinderBinClass)) +#define GST_IS_VIEWFINDER_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIEWFINDER_BIN)) +#define GST_IS_VIEWFINDER_BIN_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIEWFINDER_BIN)) + +typedef struct _GstViewfinderBin GstViewfinderBin; +typedef struct _GstViewfinderBinClass GstViewfinderBinClass; + +struct _GstViewfinderBin +{ + GstBin bin; + + GstPad *ghostpad; + + GstElement *video_sink; + GstElement *user_video_sink; + + gboolean elements_created; +}; + +struct _GstViewfinderBinClass +{ + GstBinClass bin_class; +}; + +GType gst_viewfinder_bin_get_type (void); +gboolean gst_viewfinder_bin_plugin_init (GstPlugin * plugin); + +G_END_DECLS + +#endif diff --git a/gst/camerabin2/gstwrappercamerabinsrc.c b/gst/camerabin2/gstwrappercamerabinsrc.c new file mode 100644 index 000000000..811479493 --- /dev/null +++ b/gst/camerabin2/gstwrappercamerabinsrc.c @@ -0,0 +1,1192 @@ +/* + * GStreamer + * Copyright (C) 2010 Texas Instruments, Inc + * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +/** + * SECTION:element-wrappercamerabinsrc + * + * A camera bin src element that wraps a default video source with a single + * pad into the 3pad model that camerabin2 expects. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "gstwrappercamerabinsrc.h" +#include "camerabingeneral.h" + +enum +{ + PROP_0, + PROP_VIDEO_SRC, + PROP_POST_PREVIEWS, + PROP_PREVIEW_CAPS, + PROP_PREVIEW_FILTER +}; + +#define DEFAULT_POST_PREVIEWS TRUE + +/* Using "bilinear" as default zoom method */ +#define CAMERABIN_DEFAULT_ZOOM_METHOD 1 + +GST_DEBUG_CATEGORY (wrapper_camera_bin_src_debug); +#define GST_CAT_DEFAULT wrapper_camera_bin_src_debug + +GST_BOILERPLATE (GstWrapperCameraBinSrc, gst_wrapper_camera_bin_src, + GstBaseCameraSrc, GST_TYPE_BASE_CAMERA_SRC); + +static void set_capsfilter_caps (GstWrapperCameraBinSrc * self, + GstCaps * new_caps); + +static void +gst_wrapper_camera_bin_src_dispose (GObject * object) +{ + GstWrapperCameraBinSrc *self = GST_WRAPPER_CAMERA_BIN_SRC (object); + + if (self->app_vid_src) { + gst_object_unref (self->app_vid_src); + self->app_vid_src = NULL; + } + + if (self->preview_pipeline) { + gst_camerabin_destroy_preview_pipeline (self->preview_pipeline); + self->preview_pipeline = NULL; + } + + if (self->preview_caps) + gst_caps_replace (&self->preview_caps, NULL); + + if (self->preview_filter) { + gst_object_unref (self->preview_filter); + self->preview_filter = NULL; + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_wrapper_camera_bin_src_finalize (GstWrapperCameraBinSrc * self) +{ + G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (self)); +} + +static void +gst_wrapper_camera_bin_src_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstWrapperCameraBinSrc *self = GST_WRAPPER_CAMERA_BIN_SRC (object); + + switch (prop_id) { + case PROP_VIDEO_SRC: + if (GST_STATE (self) != GST_STATE_NULL) { + GST_ELEMENT_ERROR (self, CORE, FAILED, + ("camerasrc must be in NULL state when setting the video source element"), + (NULL)); + } else { + if (self->app_vid_src) + gst_object_unref (self->app_vid_src); + self->app_vid_src = g_value_get_object (value); + if (self->app_vid_src) + gst_object_ref (self->app_vid_src); + } + break; + case PROP_POST_PREVIEWS: + self->post_previews = g_value_get_boolean (value); + break; + case PROP_PREVIEW_CAPS: + gst_caps_replace (&self->preview_caps, + (GstCaps *) gst_value_get_caps (value)); + if (self->preview_pipeline) { + GST_DEBUG_OBJECT (self, + "Setting preview pipeline caps %" GST_PTR_FORMAT, + self->preview_caps); + gst_camerabin_preview_set_caps (self->preview_pipeline, + (GstCaps *) gst_value_get_caps (value)); + } + break; + case PROP_PREVIEW_FILTER: + if (self->preview_filter) + gst_object_unref (self->preview_filter); + self->preview_filter = g_value_dup_object (value); + self->preview_filter_changed = TRUE; + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec); + break; + } +} + +static void +gst_wrapper_camera_bin_src_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstWrapperCameraBinSrc *self = GST_WRAPPER_CAMERA_BIN_SRC (object); + + switch (prop_id) { + case PROP_VIDEO_SRC: + if (self->src_vid_src) + g_value_set_object (value, self->src_vid_src); + else + g_value_set_object (value, self->app_vid_src); + break; + case PROP_POST_PREVIEWS: + g_value_set_boolean (value, self->post_previews); + break; + case PROP_PREVIEW_CAPS: + if (self->preview_caps) + gst_value_set_caps (value, self->preview_caps); + break; + case PROP_PREVIEW_FILTER: + if (self->preview_filter) + g_value_set_object (value, self->preview_filter); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec); + break; + } +} + +static void +gst_wrapper_camera_bin_reset_video_src_caps (GstWrapperCameraBinSrc * self, + GstCaps * caps) +{ + GstClock *clock; + gint64 base_time; + + GST_DEBUG_OBJECT (self, "Resetting src caps to %" GST_PTR_FORMAT, caps); + if (self->src_vid_src) { + clock = gst_element_get_clock (self->src_vid_src); + base_time = gst_element_get_base_time (self->src_vid_src); + + gst_element_set_state (self->src_vid_src, GST_STATE_NULL); + set_capsfilter_caps (self, caps); + + self->drop_newseg = TRUE; + + GST_DEBUG_OBJECT (self, "Bringing source up"); + gst_element_sync_state_with_parent (self->src_vid_src); + + if (clock) { + gst_element_set_clock (self->src_vid_src, clock); + gst_element_set_base_time (self->src_vid_src, base_time); + + if (GST_IS_BIN (self->src_vid_src)) { + GstIterator *it = + gst_bin_iterate_elements (GST_BIN (self->src_vid_src)); + gpointer item = NULL; + gboolean done = FALSE; + while (!done) { + switch (gst_iterator_next (it, &item)) { + case GST_ITERATOR_OK: + gst_element_set_base_time (GST_ELEMENT (item), base_time); + gst_object_unref (item); + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (it); + break; + case GST_ITERATOR_ERROR: + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (it); + } + + gst_object_unref (clock); + } + } +} + +/** + * gst_wrapper_camera_bin_src_imgsrc_probe: + * + * Buffer probe called before sending each buffer to image queue. + */ +static gboolean +gst_wrapper_camera_bin_src_imgsrc_probe (GstPad * pad, GstBuffer * buffer, + gpointer data) +{ + GstWrapperCameraBinSrc *self = GST_WRAPPER_CAMERA_BIN_SRC (data); + GstBaseCameraSrc *camerasrc = GST_BASE_CAMERA_SRC (data); + gboolean ret = FALSE; + + GST_LOG_OBJECT (self, "Image probe, mode %d, capture count %d", + camerasrc->mode, self->image_capture_count); + + g_mutex_lock (camerasrc->capturing_mutex); + if (self->image_capture_count > 0) { + ret = TRUE; + self->image_capture_count--; + + /* post preview */ + /* TODO This can likely be optimized if the viewfinder caps is the same as + * the preview caps, avoiding another scaling of the same buffer. */ + if (self->post_previews) { + GST_DEBUG_OBJECT (self, "Posting preview for image"); + gst_camerabin_preview_pipeline_post (self->preview_pipeline, buffer); + } + + if (self->image_capture_count == 0) { + gst_base_camera_src_finish_capture (camerasrc); + } + } + g_mutex_unlock (camerasrc->capturing_mutex); + return ret; +} + +/** + * gst_wrapper_camera_bin_src_vidsrc_probe: + * + * Buffer probe called before sending each buffer to image queue. + */ +static gboolean +gst_wrapper_camera_bin_src_vidsrc_probe (GstPad * pad, GstBuffer * buffer, + gpointer data) +{ + GstWrapperCameraBinSrc *self = GST_WRAPPER_CAMERA_BIN_SRC (data); + GstBaseCameraSrc *camerasrc = GST_BASE_CAMERA_SRC_CAST (self); + gboolean ret = FALSE; + + GST_LOG_OBJECT (self, "Video probe, mode %d, capture status %d", + camerasrc->mode, self->video_rec_status); + + /* TODO do we want to lock for every buffer? */ + /* + * Note that we can use gst_pad_push_event here because we are a buffer + * probe. + */ + /* TODO shouldn't access this directly */ + g_mutex_lock (camerasrc->capturing_mutex); + if (self->video_rec_status == GST_VIDEO_RECORDING_STATUS_DONE) { + /* NOP */ + } else if (self->video_rec_status == GST_VIDEO_RECORDING_STATUS_STARTING) { + gint64 start = 0; + + if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) + start = GST_BUFFER_TIMESTAMP (buffer); + + /* send the newseg */ + GST_DEBUG_OBJECT (self, "Starting video recording, pushing newsegment"); + gst_pad_push_event (pad, gst_event_new_new_segment (FALSE, 1.0, + GST_FORMAT_TIME, start, -1, 0)); + self->video_rec_status = GST_VIDEO_RECORDING_STATUS_RUNNING; + + /* post preview */ + if (self->post_previews) { + GST_DEBUG_OBJECT (self, "Posting preview for video"); + gst_camerabin_preview_pipeline_post (self->preview_pipeline, buffer); + } + + ret = TRUE; + } else if (self->video_rec_status == GST_VIDEO_RECORDING_STATUS_FINISHING) { + /* send eos */ + GST_DEBUG_OBJECT (self, "Finishing video recording, pushing eos"); + gst_pad_push_event (pad, gst_event_new_eos ()); + self->video_rec_status = GST_VIDEO_RECORDING_STATUS_DONE; + gst_base_camera_src_finish_capture (camerasrc); + } else { + ret = TRUE; + } + g_mutex_unlock (camerasrc->capturing_mutex); + return ret; +} + +static gboolean +gst_wrapper_camera_bin_src_event (GstPad * pad, GstEvent * event) +{ + GstWrapperCameraBinSrc *src = + GST_WRAPPER_CAMERA_BIN_SRC (GST_PAD_PARENT (pad)); + const GstStructure *structure; + + structure = gst_event_get_structure (event); + if (structure && gst_structure_has_name (structure, "renegotiate")) { + GST_DEBUG_OBJECT (src, "Received renegotiate on pad %s", + GST_PAD_NAME (pad)); + + if (pad == src->imgsrc) { + src->image_renegotiate = TRUE; + } else if (pad == src->vidsrc) { + src->video_renegotiate = TRUE; + } + } + + return src->srcpad_event_func (pad, event); +} + +static gboolean +gst_wrapper_camera_src_src_event_probe (GstPad * pad, GstEvent * evt, + gpointer udata) +{ + gboolean ret = TRUE; + GstWrapperCameraBinSrc *self = udata; + + switch (GST_EVENT_TYPE (evt)) { + case GST_EVENT_EOS: + /* drop */ + ret = FALSE; + break; + case GST_EVENT_NEWSEGMENT: + if (self->drop_newseg) { + ret = FALSE; + self->drop_newseg = FALSE; + } + break; + default: + break; + } + return ret; +} + +/** + * gst_wrapper_camera_bin_src_construct_pipeline: + * @bcamsrc: camerasrc object + * + * This function creates and links the elements of the camerasrc bin + * videosrc ! cspconv ! capsfilter ! crop ! scale ! capsfilter ! tee name=t ! + * t. ! ... (viewfinder pad) + * t. ! output-selector name=outsel + * outsel. ! (image pad) + * outsel. ! (video pad) + * + * Returns: TRUE, if elements were successfully created, FALSE otherwise + */ +static gboolean +gst_wrapper_camera_bin_src_construct_pipeline (GstBaseCameraSrc * bcamsrc) +{ + GstWrapperCameraBinSrc *self = GST_WRAPPER_CAMERA_BIN_SRC (bcamsrc); + GstBin *cbin = GST_BIN (bcamsrc); + GstElement *tee; + gboolean ret = FALSE; + GstElement *videoscale; + GstPad *vf_pad; + GstPad *tee_capture_pad; + + if (!self->elements_created) { + + GST_DEBUG_OBJECT (self, "constructing pipeline"); + + /* Add application set or default video src element */ + if (!(self->src_vid_src = gst_camerabin_setup_default_element (cbin, + self->app_vid_src, "autovideosrc", DEFAULT_VIDEOSRC, + "camerasrc-real-src"))) { + self->src_vid_src = NULL; + goto done; + } else { + if (!gst_camerabin_add_element (cbin, self->src_vid_src)) { + goto done; + } + } + /* we lost the reference */ + self->app_vid_src = NULL; + + /* add a buffer probe to the src elemento to drop EOS from READY->NULL */ + { + GstPad *pad; + pad = gst_element_get_static_pad (self->src_vid_src, "src"); + + self->src_event_probe_id = gst_pad_add_event_probe (pad, + (GCallback) gst_wrapper_camera_src_src_event_probe, self); + gst_object_unref (pad); + } + + if (!gst_camerabin_create_and_add_element (cbin, "ffmpegcolorspace", + "src-colorspace")) + goto done; + + if (!(self->src_filter = + gst_camerabin_create_and_add_element (cbin, "capsfilter", + "src-capsfilter"))) + goto done; + + if (!(self->src_zoom_crop = + gst_camerabin_create_and_add_element (cbin, "videocrop", + "zoom-crop"))) + goto done; + if (!(self->src_zoom_scale = + gst_camerabin_create_and_add_element (cbin, "videoscale", + "zoom-scale"))) + goto done; + if (!(self->src_zoom_filter = + gst_camerabin_create_and_add_element (cbin, "capsfilter", + "zoom-capsfilter"))) + goto done; + + if (!(tee = + gst_camerabin_create_and_add_element (cbin, "tee", + "camerasrc-tee"))) + goto done; + + /* viewfinder pad */ + vf_pad = gst_element_get_request_pad (tee, "src%d"); + g_object_set (tee, "alloc-pad", vf_pad, NULL); + gst_object_unref (vf_pad); + + /* the viewfinder should always work, so we add some converters to it */ + if (!gst_camerabin_create_and_add_element (cbin, "ffmpegcolorspace", + "viewfinder-colorspace")) + goto done; + if (!(videoscale = + gst_camerabin_create_and_add_element (cbin, "videoscale", + "viewfinder-scale"))) + goto done; + + /* image/video pad from tee */ + tee_capture_pad = gst_element_get_request_pad (tee, "src%d"); + + self->output_selector = + gst_element_factory_make ("output-selector", "outsel"); + g_object_set (self->output_selector, "pad-negotiation-mode", 0, NULL); + gst_bin_add (GST_BIN (self), self->output_selector); + { + GstPad *pad = gst_element_get_static_pad (self->output_selector, "sink"); + + /* check return TODO */ + gst_pad_link (tee_capture_pad, pad); + gst_object_unref (pad); + } + gst_object_unref (tee_capture_pad); + + /* Create the 2 output pads for video and image */ + self->outsel_vidpad = + gst_element_get_request_pad (self->output_selector, "src%d"); + self->outsel_imgpad = + gst_element_get_request_pad (self->output_selector, "src%d"); + + g_assert (self->outsel_vidpad != NULL); + g_assert (self->outsel_imgpad != NULL); + + gst_pad_add_buffer_probe (self->outsel_imgpad, + G_CALLBACK (gst_wrapper_camera_bin_src_imgsrc_probe), self); + gst_pad_add_buffer_probe (self->outsel_vidpad, + G_CALLBACK (gst_wrapper_camera_bin_src_vidsrc_probe), self); + gst_ghost_pad_set_target (GST_GHOST_PAD (self->imgsrc), + self->outsel_imgpad); + gst_ghost_pad_set_target (GST_GHOST_PAD (self->vidsrc), + self->outsel_vidpad); + + if (bcamsrc->mode == MODE_IMAGE) { + g_object_set (self->output_selector, "active-pad", self->outsel_imgpad, + NULL); + } else { + g_object_set (self->output_selector, "active-pad", self->outsel_vidpad, + NULL); + } + + /* hook-up the vf ghostpad */ + vf_pad = gst_element_get_static_pad (videoscale, "src"); + gst_ghost_pad_set_target (GST_GHOST_PAD (self->vfsrc), vf_pad); + gst_object_unref (vf_pad); + + gst_pad_set_active (self->vfsrc, TRUE); + gst_pad_set_active (self->imgsrc, TRUE); /* XXX ??? */ + gst_pad_set_active (self->vidsrc, TRUE); /* XXX ??? */ + } + /* recreate the preview pipeline */ + if (self->preview_pipeline && self->preview_filter_changed) { + gst_camerabin_destroy_preview_pipeline (self->preview_pipeline); + } + + if (self->preview_pipeline == NULL) + self->preview_pipeline = + gst_camerabin_create_preview_pipeline (GST_ELEMENT_CAST (self), + self->preview_filter); + + g_assert (self->preview_pipeline != NULL); + self->preview_filter_changed = FALSE; + if (self->preview_caps) { + GST_DEBUG_OBJECT (self, "Setting preview pipeline caps %" GST_PTR_FORMAT, + self->preview_caps); + gst_camerabin_preview_set_caps (self->preview_pipeline, self->preview_caps); + } + + ret = TRUE; + self->elements_created = TRUE; +done: + return ret; +} + +static gboolean +copy_missing_fields (GQuark field_id, const GValue * value, gpointer user_data) +{ + GstStructure *st = (GstStructure *) user_data; + const GValue *val = gst_structure_id_get_value (st, field_id); + + if (G_UNLIKELY (val == NULL)) { + gst_structure_id_set_value (st, field_id, value); + } + + return TRUE; +} + +/** + * adapt_image_capture: + * @self: camerasrc object + * @in_caps: caps object that describes incoming image format + * + * Adjust capsfilters and crop according image capture caps if necessary. + * The captured image format from video source might be different from + * what application requested, so we can try to fix that in camerabin. + * + */ +static void +adapt_image_capture (GstWrapperCameraBinSrc * self, GstCaps * in_caps) +{ + GstBaseCameraSrc *bcamsrc = GST_BASE_CAMERA_SRC (self); + GstStructure *in_st, *new_st, *req_st; + gint in_width = 0, in_height = 0, req_width = 0, req_height = 0, crop = 0; + gdouble ratio_w, ratio_h; + GstCaps *filter_caps = NULL; + + GST_LOG_OBJECT (self, "in caps: %" GST_PTR_FORMAT, in_caps); + GST_LOG_OBJECT (self, "requested caps: %" GST_PTR_FORMAT, + self->image_capture_caps); + + in_st = gst_caps_get_structure (in_caps, 0); + gst_structure_get_int (in_st, "width", &in_width); + gst_structure_get_int (in_st, "height", &in_height); + + req_st = gst_caps_get_structure (self->image_capture_caps, 0); + gst_structure_get_int (req_st, "width", &req_width); + gst_structure_get_int (req_st, "height", &req_height); + + GST_INFO_OBJECT (self, "we requested %dx%d, and got %dx%d", req_width, + req_height, in_width, in_height); + + new_st = gst_structure_copy (req_st); + /* If new fields have been added, we need to copy them */ + gst_structure_foreach (in_st, copy_missing_fields, new_st); + + gst_structure_set (new_st, "width", G_TYPE_INT, in_width, "height", + G_TYPE_INT, in_height, NULL); + + GST_LOG_OBJECT (self, "new image capture caps: %" GST_PTR_FORMAT, new_st); + + /* Crop if requested aspect ratio differs from incoming frame aspect ratio */ + if (self->src_zoom_crop) { + + ratio_w = (gdouble) in_width / req_width; + ratio_h = (gdouble) in_height / req_height; + + if (ratio_w < ratio_h) { + crop = in_height - (req_height * ratio_w); + self->base_crop_top = crop / 2; + self->base_crop_bottom = crop / 2; + } else { + crop = in_width - (req_width * ratio_h); + self->base_crop_left = crop / 2; + self->base_crop_right += crop / 2; + } + + GST_INFO_OBJECT (self, + "setting base crop: left:%d, right:%d, top:%d, bottom:%d", + self->base_crop_left, self->base_crop_right, self->base_crop_top, + self->base_crop_bottom); + g_object_set (G_OBJECT (self->src_zoom_crop), + "top", self->base_crop_top, + "bottom", self->base_crop_bottom, + "left", self->base_crop_left, "right", self->base_crop_right, NULL); + } + + /* Update capsfilters */ + if (self->image_capture_caps) { + gst_caps_unref (self->image_capture_caps); + } + self->image_capture_caps = gst_caps_new_full (new_st, NULL); + set_capsfilter_caps (self, self->image_capture_caps); + + /* Adjust the capsfilter before crop and videoscale elements if necessary */ + if (in_width == bcamsrc->width && in_height == bcamsrc->height) { + GST_DEBUG_OBJECT (self, "no adaptation with resolution needed"); + } else { + GST_DEBUG_OBJECT (self, + "changing %" GST_PTR_FORMAT " from %dx%d to %dx%d", self->src_filter, + bcamsrc->width, bcamsrc->height, in_width, in_height); + /* Apply the width and height to filter caps */ + g_object_get (G_OBJECT (self->src_filter), "caps", &filter_caps, NULL); + filter_caps = gst_caps_make_writable (filter_caps); + gst_caps_set_simple (filter_caps, "width", G_TYPE_INT, in_width, "height", + G_TYPE_INT, in_height, NULL); + g_object_set (G_OBJECT (self->src_filter), "caps", filter_caps, NULL); + gst_caps_unref (filter_caps); + } +} + +/** + * img_capture_prepared: + * @data: camerasrc object + * @caps: caps describing the prepared image format + * + * Callback which is called after image capture has been prepared. + */ +static void +img_capture_prepared (gpointer data, GstCaps * caps) +{ + GstWrapperCameraBinSrc *self = GST_WRAPPER_CAMERA_BIN_SRC (data); + + GST_INFO_OBJECT (self, "image capture prepared"); + + /* It is possible we are about to get something else that we requested */ + if (!gst_caps_is_equal (self->image_capture_caps, caps)) { + adapt_image_capture (self, caps); + } else { + set_capsfilter_caps (self, self->image_capture_caps); + } +} + +/** + * + */ +static gboolean +start_image_capture (GstWrapperCameraBinSrc * self) +{ + GstBaseCameraSrc *bcamsrc = GST_BASE_CAMERA_SRC (self); + GstPhotography *photography = gst_base_camera_src_get_photography (bcamsrc); + gboolean ret = FALSE; + GstCaps *caps; + + GST_DEBUG_OBJECT (self, "Starting image capture"); + + if (self->image_renegotiate) { + /* clean capsfilter caps so they don't interfere here */ + g_object_set (self->src_filter, "caps", NULL, NULL); + if (self->src_zoom_filter) + g_object_set (self->src_zoom_filter, "caps", NULL, NULL); + + caps = gst_pad_get_allowed_caps (self->imgsrc); + + caps = gst_caps_make_writable (caps); + gst_pad_fixate_caps (self->imgsrc, caps); + + gst_caps_replace (&self->image_capture_caps, caps); + gst_caps_unref (caps); + + self->image_renegotiate = FALSE; + } + + if (photography) { + GST_DEBUG_OBJECT (self, "prepare image capture caps %" GST_PTR_FORMAT, + self->image_capture_caps); + ret = gst_photography_prepare_for_capture (photography, + (GstPhotoCapturePrepared) img_capture_prepared, + self->image_capture_caps, self); + } else { + g_mutex_unlock (bcamsrc->capturing_mutex); + gst_wrapper_camera_bin_reset_video_src_caps (self, + self->image_capture_caps); + g_mutex_lock (bcamsrc->capturing_mutex); + ret = TRUE; + } + + return ret; +} + +static gboolean +gst_wrapper_camera_bin_src_set_mode (GstBaseCameraSrc * bcamsrc, + GstCameraBinMode mode) +{ + GstPhotography *photography = gst_base_camera_src_get_photography (bcamsrc); + GstWrapperCameraBinSrc *self = GST_WRAPPER_CAMERA_BIN_SRC (bcamsrc); + + self->mode = mode; + + if (self->output_selector) { + if (mode == MODE_IMAGE) { + g_object_set (self->output_selector, "active-pad", self->outsel_imgpad, + NULL); + } else { + g_object_set (self->output_selector, "active-pad", self->outsel_vidpad, + NULL); + } + } + + if (photography) { + if (g_object_class_find_property (G_OBJECT_GET_CLASS (photography), + "capture-mode")) { + g_object_set (G_OBJECT (photography), "capture-mode", mode, NULL); + } + } else { + gst_wrapper_camera_bin_reset_video_src_caps (self, NULL); + } + + return TRUE; +} + +static gboolean +set_videosrc_zoom (GstWrapperCameraBinSrc * self, gint zoom) +{ + gboolean ret = FALSE; + + if (g_object_class_find_property (G_OBJECT_GET_CLASS (self->src_vid_src), + "zoom")) { + g_object_set (G_OBJECT (self->src_vid_src), "zoom", + (gfloat) zoom / 100, NULL); + ret = TRUE; + } + return ret; +} + +static gboolean +set_element_zoom (GstWrapperCameraBinSrc * self, gint zoom) +{ + gboolean ret = FALSE; + GstBaseCameraSrc *bcamsrc = GST_BASE_CAMERA_SRC (self); + gint w2_crop = 0, h2_crop = 0; + GstPad *pad_zoom_sink = NULL; + gint left = self->base_crop_left; + gint right = self->base_crop_right; + gint top = self->base_crop_top; + gint bottom = self->base_crop_bottom; + + if (self->src_zoom_crop) { + /* Update capsfilters to apply the zoom */ + GST_INFO_OBJECT (self, "zoom: %d, orig size: %dx%d", zoom, + bcamsrc->width, bcamsrc->height); + + if (zoom != ZOOM_1X) { + w2_crop = (bcamsrc->width - (bcamsrc->width * ZOOM_1X / zoom)) / 2; + h2_crop = (bcamsrc->height - (bcamsrc->height * ZOOM_1X / zoom)) / 2; + + left += w2_crop; + right += w2_crop; + top += h2_crop; + bottom += h2_crop; + + /* force number of pixels cropped from left to be even, to avoid slow code + * path on videoscale */ + left &= 0xFFFE; + } + + pad_zoom_sink = gst_element_get_static_pad (self->src_zoom_crop, "sink"); + + GST_INFO_OBJECT (self, + "sw cropping: left:%d, right:%d, top:%d, bottom:%d", left, right, top, + bottom); + + GST_PAD_STREAM_LOCK (pad_zoom_sink); + g_object_set (self->src_zoom_crop, "left", left, "right", right, "top", + top, "bottom", bottom, NULL); + GST_PAD_STREAM_UNLOCK (pad_zoom_sink); + gst_object_unref (pad_zoom_sink); + ret = TRUE; + } + return ret; +} + +static void +gst_wrapper_camera_bin_src_set_zoom (GstBaseCameraSrc * bcamsrc, gint zoom) +{ + GstWrapperCameraBinSrc *self = GST_WRAPPER_CAMERA_BIN_SRC (bcamsrc); + + GST_INFO_OBJECT (self, "setting zoom %d", zoom); + + if (set_videosrc_zoom (self, zoom)) { + set_element_zoom (self, ZOOM_1X); + GST_INFO_OBJECT (self, "zoom set using videosrc"); + } else if (set_element_zoom (self, zoom)) { + GST_INFO_OBJECT (self, "zoom set using gst elements"); + } else { + GST_INFO_OBJECT (self, "setting zoom failed"); + } +} + +static GstCaps * +gst_wrapper_camera_bin_src_get_allowed_input_caps (GstBaseCameraSrc * bcamsrc) +{ + GstWrapperCameraBinSrc *self = GST_WRAPPER_CAMERA_BIN_SRC (bcamsrc); + GstCaps *caps = NULL; + GstPad *pad = NULL, *peer_pad = NULL; + GstState state; + GstElement *videosrc; + + videosrc = self->src_vid_src ? self->src_vid_src : self->app_vid_src; + + if (!videosrc) { + GST_WARNING_OBJECT (self, "no videosrc, can't get allowed caps"); + goto failed; + } + + if (self->allowed_caps) { + GST_DEBUG_OBJECT (self, "returning cached caps"); + goto done; + } + + pad = gst_element_get_static_pad (videosrc, "src"); + + if (!pad) { + GST_WARNING_OBJECT (self, "no srcpad in videosrc"); + goto failed; + } + + state = GST_STATE (videosrc); + + /* Make this function work also in NULL state */ + if (state == GST_STATE_NULL) { + GST_DEBUG_OBJECT (self, "setting videosrc to ready temporarily"); + peer_pad = gst_pad_get_peer (pad); + if (peer_pad) { + gst_pad_unlink (pad, peer_pad); + } + /* Set videosrc to READY to open video device */ + gst_element_set_locked_state (videosrc, TRUE); + gst_element_set_state (videosrc, GST_STATE_READY); + } + + self->allowed_caps = gst_pad_get_caps (pad); + + /* Restore state and re-link if necessary */ + if (state == GST_STATE_NULL) { + GST_DEBUG_OBJECT (self, "restoring videosrc state %d", state); + /* Reset videosrc to NULL state, some drivers seem to need this */ + gst_element_set_state (videosrc, GST_STATE_NULL); + if (peer_pad) { + gst_pad_link (pad, peer_pad); + gst_object_unref (peer_pad); + } + gst_element_set_locked_state (videosrc, FALSE); + } + + gst_object_unref (pad); + +done: + if (self->allowed_caps) { + caps = gst_caps_copy (self->allowed_caps); + } + GST_DEBUG_OBJECT (self, "allowed caps:%" GST_PTR_FORMAT, caps); +failed: + return caps; +} + +/** + * update_aspect_filter: + * @self: camerasrc object + * @new_caps: new caps of next buffers arriving to view finder sink element + * + * Updates aspect ratio capsfilter to maintain aspect ratio, if we need to + * scale frames for showing them in view finder. + */ +static void +update_aspect_filter (GstWrapperCameraBinSrc * self, GstCaps * new_caps) +{ + // XXX why not instead add a preserve-aspect-ratio property to videoscale? +#if 0 + if (camera->flags & GST_CAMERABIN_FLAG_VIEWFINDER_SCALE) { + GstCaps *sink_caps, *ar_caps; + GstStructure *st; + gint in_w = 0, in_h = 0, sink_w = 0, sink_h = 0, target_w = 0, target_h = 0; + gdouble ratio_w, ratio_h; + GstPad *sink_pad; + const GValue *range; + + sink_pad = gst_element_get_static_pad (camera->view_sink, "sink"); + + if (sink_pad) { + sink_caps = gst_pad_get_caps (sink_pad); + gst_object_unref (sink_pad); + if (sink_caps) { + if (!gst_caps_is_any (sink_caps)) { + GST_DEBUG_OBJECT (camera, "sink element caps %" GST_PTR_FORMAT, + sink_caps); + /* Get maximum resolution that view finder sink accepts */ + st = gst_caps_get_structure (sink_caps, 0); + if (gst_structure_has_field_typed (st, "width", GST_TYPE_INT_RANGE)) { + range = gst_structure_get_value (st, "width"); + sink_w = gst_value_get_int_range_max (range); + } + if (gst_structure_has_field_typed (st, "height", GST_TYPE_INT_RANGE)) { + range = gst_structure_get_value (st, "height"); + sink_h = gst_value_get_int_range_max (range); + } + GST_DEBUG_OBJECT (camera, "sink element accepts max %dx%d", sink_w, + sink_h); + + /* Get incoming frames' resolution */ + if (sink_h && sink_w) { + st = gst_caps_get_structure (new_caps, 0); + gst_structure_get_int (st, "width", &in_w); + gst_structure_get_int (st, "height", &in_h); + GST_DEBUG_OBJECT (camera, "new caps with %dx%d", in_w, in_h); + } + } + gst_caps_unref (sink_caps); + } + } + + /* If we get bigger frames than view finder sink accepts, then we scale. + If we scale we need to adjust aspect ratio capsfilter caps in order + to maintain aspect ratio while scaling. */ + if (in_w && in_h && (in_w > sink_w || in_h > sink_h)) { + ratio_w = (gdouble) sink_w / in_w; + ratio_h = (gdouble) sink_h / in_h; + + if (ratio_w < ratio_h) { + target_w = sink_w; + target_h = (gint) (ratio_w * in_h); + } else { + target_w = (gint) (ratio_h * in_w); + target_h = sink_h; + } + + GST_DEBUG_OBJECT (camera, "setting %dx%d filter to maintain aspect ratio", + target_w, target_h); + ar_caps = gst_caps_copy (new_caps); + gst_caps_set_simple (ar_caps, "width", G_TYPE_INT, target_w, "height", + G_TYPE_INT, target_h, NULL); + } else { + GST_DEBUG_OBJECT (camera, "no scaling"); + ar_caps = new_caps; + } + + GST_DEBUG_OBJECT (camera, "aspect ratio filter caps %" GST_PTR_FORMAT, + ar_caps); + g_object_set (G_OBJECT (camera->aspect_filter), "caps", ar_caps, NULL); + if (ar_caps != new_caps) + gst_caps_unref (ar_caps); + } +#endif +} + + +/** + * set_capsfilter_caps: + * @self: camerasrc object + * @new_caps: pointer to caps object to set + * + * Set given caps to camerabin capsfilters. + */ +static void +set_capsfilter_caps (GstWrapperCameraBinSrc * self, GstCaps * new_caps) +{ + GST_INFO_OBJECT (self, "new_caps:%" GST_PTR_FORMAT, new_caps); + + /* Update zoom */ + gst_base_camera_src_setup_zoom (GST_BASE_CAMERA_SRC (self)); + + /* Update capsfilters */ + g_object_set (G_OBJECT (self->src_filter), "caps", new_caps, NULL); + if (self->src_zoom_filter) + g_object_set (G_OBJECT (self->src_zoom_filter), "caps", new_caps, NULL); + update_aspect_filter (self, new_caps); + GST_INFO_OBJECT (self, "udpated"); +} + +static gboolean +gst_wrapper_camera_bin_src_start_capture (GstBaseCameraSrc * camerasrc) +{ + GstWrapperCameraBinSrc *src = GST_WRAPPER_CAMERA_BIN_SRC (camerasrc); + + /* TODO should we access this directly? Maybe a macro is better? */ + if (src->mode == MODE_IMAGE) { + start_image_capture (src); + src->image_capture_count = 1; + } else if (src->mode == MODE_VIDEO) { + GstCaps *caps = NULL; + + g_mutex_unlock (camerasrc->capturing_mutex); + gst_wrapper_camera_bin_reset_video_src_caps (src, NULL); + g_mutex_lock (camerasrc->capturing_mutex); + + if (src->video_renegotiate) { + /* clean capsfilter caps so they don't interfere here */ + g_object_set (src->src_filter, "caps", NULL, NULL); + if (src->src_zoom_filter) + g_object_set (src->src_zoom_filter, "caps", NULL, NULL); + + caps = gst_pad_get_allowed_caps (src->vidsrc); + caps = gst_caps_make_writable (caps); + gst_pad_fixate_caps (src->vidsrc, caps); + GST_DEBUG_OBJECT (src, "Vidsrc caps fixated to %" GST_PTR_FORMAT, caps); + + src->video_renegotiate = FALSE; + g_mutex_unlock (camerasrc->capturing_mutex); + gst_wrapper_camera_bin_reset_video_src_caps (src, caps); + g_mutex_lock (camerasrc->capturing_mutex); + gst_caps_unref (caps); + } + if (src->video_rec_status == GST_VIDEO_RECORDING_STATUS_DONE) { + src->video_rec_status = GST_VIDEO_RECORDING_STATUS_STARTING; + } + } else { + g_assert_not_reached (); + return FALSE; + } + return TRUE; +} + +static void +gst_wrapper_camera_bin_src_stop_capture (GstBaseCameraSrc * camerasrc) +{ + GstWrapperCameraBinSrc *src = GST_WRAPPER_CAMERA_BIN_SRC (camerasrc); + + /* TODO shoud we access this directly? Maybe a macro is better? */ + if (src->mode == MODE_VIDEO) { + if (src->video_rec_status == GST_VIDEO_RECORDING_STATUS_STARTING) { + GST_DEBUG_OBJECT (src, "Aborting, had not started recording"); + src->video_rec_status = GST_VIDEO_RECORDING_STATUS_DONE; + + } else if (src->video_rec_status == GST_VIDEO_RECORDING_STATUS_RUNNING) { + GST_DEBUG_OBJECT (src, "Marking video recording as finishing"); + src->video_rec_status = GST_VIDEO_RECORDING_STATUS_FINISHING; + } + } else { + src->image_capture_count = 0; + } +} + +static GstStateChangeReturn +gst_wrapper_camera_bin_src_change_state (GstElement * element, + GstStateChange trans) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + GstWrapperCameraBinSrc *self = GST_WRAPPER_CAMERA_BIN_SRC (element); + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, trans); + + if (ret == GST_STATE_CHANGE_FAILURE) + goto end; + + switch (trans) { + case GST_STATE_CHANGE_PAUSED_TO_READY: + self->drop_newseg = FALSE; + break; + case GST_STATE_CHANGE_READY_TO_NULL: + gst_element_set_state (self->preview_pipeline->pipeline, GST_STATE_NULL); + break; + case GST_STATE_CHANGE_NULL_TO_READY: + gst_element_set_state (self->preview_pipeline->pipeline, + GST_STATE_PLAYING); + break; + default: + break; + } + +end: + return ret; +} + +static void +gst_wrapper_camera_bin_src_base_init (gpointer g_class) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); + + GST_DEBUG_CATEGORY_INIT (wrapper_camera_bin_src_debug, "wrappercamerabinsrc", + 0, "V4l2 camera src"); + + gst_element_class_set_details_simple (gstelement_class, + "V4l2 camera src element for camerabin", "Source/Video", + "V4l2 camera src element for camerabin", "Rob Clark <rob@ti.com>"); +} + +static void +gst_wrapper_camera_bin_src_class_init (GstWrapperCameraBinSrcClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseCameraSrcClass *gstbasecamerasrc_class; + + gobject_class = G_OBJECT_CLASS (klass); + gstelement_class = GST_ELEMENT_CLASS (klass); + gstbasecamerasrc_class = GST_BASE_CAMERA_SRC_CLASS (klass); + + gobject_class->dispose = gst_wrapper_camera_bin_src_dispose; + gobject_class->finalize = + (GObjectFinalizeFunc) gst_wrapper_camera_bin_src_finalize; + gobject_class->set_property = gst_wrapper_camera_bin_src_set_property; + gobject_class->get_property = gst_wrapper_camera_bin_src_get_property; + + /* g_object_class_install_property .... */ + g_object_class_install_property (gobject_class, PROP_VIDEO_SRC, + g_param_spec_object ("video-src", "Video source", + "The video source element to be used", + GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_POST_PREVIEWS, + g_param_spec_boolean ("post-previews", "Post Previews", + "If capture preview images should be posted to the bus", + DEFAULT_POST_PREVIEWS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_PREVIEW_CAPS, + g_param_spec_boxed ("preview-caps", "Preview caps", + "The caps of the preview image to be posted", + GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_PREVIEW_FILTER, + g_param_spec_object ("preview-filter", "Preview filter", + "A custom preview filter to process preview image data", + GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gstelement_class->change_state = gst_wrapper_camera_bin_src_change_state; + + gstbasecamerasrc_class->construct_pipeline = + gst_wrapper_camera_bin_src_construct_pipeline; + gstbasecamerasrc_class->set_zoom = gst_wrapper_camera_bin_src_set_zoom; + gstbasecamerasrc_class->set_mode = gst_wrapper_camera_bin_src_set_mode; + gstbasecamerasrc_class->get_allowed_input_caps = + gst_wrapper_camera_bin_src_get_allowed_input_caps; + gstbasecamerasrc_class->start_capture = + gst_wrapper_camera_bin_src_start_capture; + gstbasecamerasrc_class->stop_capture = + gst_wrapper_camera_bin_src_stop_capture; +} + +static void +gst_wrapper_camera_bin_src_init (GstWrapperCameraBinSrc * self, + GstWrapperCameraBinSrcClass * klass) +{ + self->vfsrc = + gst_ghost_pad_new_no_target (GST_BASE_CAMERA_SRC_VIEWFINDER_PAD_NAME, + GST_PAD_SRC); + gst_element_add_pad (GST_ELEMENT (self), self->vfsrc); + + self->imgsrc = + gst_ghost_pad_new_no_target (GST_BASE_CAMERA_SRC_IMAGE_PAD_NAME, + GST_PAD_SRC); + gst_element_add_pad (GST_ELEMENT (self), self->imgsrc); + + self->vidsrc = + gst_ghost_pad_new_no_target (GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME, + GST_PAD_SRC); + gst_element_add_pad (GST_ELEMENT (self), self->vidsrc); + + self->srcpad_event_func = GST_PAD_EVENTFUNC (self->vfsrc); + + gst_pad_set_event_function (self->imgsrc, gst_wrapper_camera_bin_src_event); + gst_pad_set_event_function (self->vidsrc, gst_wrapper_camera_bin_src_event); + gst_pad_set_event_function (self->vfsrc, gst_wrapper_camera_bin_src_event); + + /* TODO where are variables reset? */ + self->image_capture_count = 0; + self->video_rec_status = GST_VIDEO_RECORDING_STATUS_DONE; + self->video_renegotiate = FALSE; + self->image_renegotiate = FALSE; + self->mode = GST_BASE_CAMERA_SRC_CAST (self)->mode; + self->post_previews = DEFAULT_POST_PREVIEWS; +} + +gboolean +gst_wrapper_camera_bin_src_plugin_init (GstPlugin * plugin) +{ + return gst_element_register (plugin, "wrappercamerabinsrc", GST_RANK_NONE, + gst_wrapper_camera_bin_src_get_type ()); +} diff --git a/gst/camerabin2/gstwrappercamerabinsrc.h b/gst/camerabin2/gstwrappercamerabinsrc.h new file mode 100644 index 000000000..d937321a8 --- /dev/null +++ b/gst/camerabin2/gstwrappercamerabinsrc.h @@ -0,0 +1,135 @@ +/* + * GStreamer + * Copyright (C) 2010 Texas Instruments, Inc + * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_WRAPPER_CAMERA_BIN_SRC_H__ +#define __GST_WRAPPER_CAMERA_BIN_SRC_H__ + +#include <gst/gst.h> +#include <gst/basecamerabinsrc/gstbasecamerasrc.h> +#include "camerabingeneral.h" + +G_BEGIN_DECLS +#define GST_TYPE_WRAPPER_CAMERA_BIN_SRC \ + (gst_wrapper_camera_bin_src_get_type()) +#define GST_WRAPPER_CAMERA_BIN_SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WRAPPER_CAMERA_BIN_SRC,GstWrapperCameraBinSrc)) +#define GST_WRAPPER_CAMERA_BIN_SRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WRAPPER_CAMERA_BIN_SRC,GstWrapperCameraBinSrcClass)) +#define GST_IS_WRAPPER_CAMERA_BIN_SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WRAPPER_CAMERA_BIN_SRC)) +#define GST_IS_WRAPPER_CAMERA_BIN_SRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WRAPPER_CAMERA_BIN_SRC)) + GType gst_wrapper_camera_bin_src_get_type (void); + +typedef struct _GstWrapperCameraBinSrc GstWrapperCameraBinSrc; +typedef struct _GstWrapperCameraBinSrcClass GstWrapperCameraBinSrcClass; + +enum GstVideoRecordingStatus { + GST_VIDEO_RECORDING_STATUS_DONE, + GST_VIDEO_RECORDING_STATUS_STARTING, + GST_VIDEO_RECORDING_STATUS_RUNNING, + GST_VIDEO_RECORDING_STATUS_FINISHING +}; + + +/** + * GstWrapperCameraBinSrc: + * + */ +struct _GstWrapperCameraBinSrc +{ + GstBaseCameraSrc parent; + + GstCameraBinMode mode; + + GstPad *vfsrc; + GstPad *imgsrc; + GstPad *vidsrc; + + /* video recording controls */ + gint video_rec_status; + + /* image capture controls */ + gint image_capture_count; + + /* source elements */ + GstElement *src_vid_src; + GstElement *src_filter; + GstElement *src_zoom_crop; + GstElement *src_zoom_scale; + GstElement *src_zoom_filter; + GstElement *output_selector; + + gboolean elements_created; + + guint src_event_probe_id; + + GstPad *outsel_imgpad; + GstPad *outsel_vidpad; + + GstPadEventFunction srcpad_event_func; + + /* For changing caps without losing timestamps */ + gboolean drop_newseg; + + /* Application configurable elements */ + GstElement *app_vid_src; + + /* Caps that videosrc supports */ + GstCaps *allowed_caps; + + /* Optional base crop for frames. Used to crop frames e.g. + due to wrong aspect ratio, before the crop related to zooming. */ + gint base_crop_top; + gint base_crop_bottom; + gint base_crop_left; + gint base_crop_right; + + /* Caps applied to capsfilters when in view finder mode */ + GstCaps *view_finder_caps; + + /* Caps applied to capsfilters when taking still image */ + GstCaps *image_capture_caps; + gboolean image_renegotiate; + gboolean video_renegotiate; + + /* Preview convert pipeline */ + GstCameraBinPreviewPipelineData *preview_pipeline; + gboolean post_previews; + GstCaps *preview_caps; + GstElement *preview_filter; + gboolean preview_filter_changed; +}; + + +/** + * GstWrapperCameraBinSrcClass: + * + */ +struct _GstWrapperCameraBinSrcClass +{ + GstBaseCameraSrcClass parent; +}; + +gboolean gst_wrapper_camera_bin_src_plugin_init (GstPlugin * plugin); + +#endif /* __GST_WRAPPER_CAMERA_BIN_SRC_H__ */ diff --git a/gst/colorspace/colorspace.c b/gst/colorspace/colorspace.c index 334362ec6..8bcd2c429 100644 --- a/gst/colorspace/colorspace.c +++ b/gst/colorspace/colorspace.c @@ -27,13 +27,14 @@ #include <string.h> #include "gstcolorspaceorc.h" -/* For GST_CHECK_PLUGINS_BASE_VERSION() */ -#include <gst/pbutils/pbutils.h> static void colorspace_convert_generic (ColorspaceConvert * convert, guint8 * dest, const guint8 * src); static void colorspace_convert_lookup_fastpath (ColorspaceConvert * convert); static void colorspace_convert_lookup_getput (ColorspaceConvert * convert); +static void colorspace_dither_none (ColorspaceConvert * convert, int j); +static void colorspace_dither_verterr (ColorspaceConvert * convert, int j); +static void colorspace_dither_halftone (ColorspaceConvert * convert, int j); ColorspaceConvert * @@ -74,6 +75,14 @@ colorspace_convert_new (GstVideoFormat to_format, ColorSpaceColorSpec to_spec, convert->height = height; convert->width = width; convert->convert = colorspace_convert_generic; + convert->dither16 = colorspace_dither_none; + + if (gst_video_format_get_component_depth (to_format, 0) > 8 || + gst_video_format_get_component_depth (from_format, 0) > 8) { + convert->use_16bit = TRUE; + } else { + convert->use_16bit = FALSE; + } for (i = 0; i < 4; i++) { convert->dest_stride[i] = gst_video_format_get_row_stride (to_format, i, @@ -98,9 +107,10 @@ colorspace_convert_new (GstVideoFormat to_format, ColorSpaceColorSpec to_spec, colorspace_convert_lookup_fastpath (convert); colorspace_convert_lookup_getput (convert); - convert->tmpline = g_malloc (sizeof (guint32) * width * 2); + convert->tmpline = g_malloc (sizeof (guint8) * (width + 8) * 4); + convert->tmpline16 = g_malloc (sizeof (guint16) * (width + 8) * 4); + convert->errline = g_malloc (sizeof (guint16) * width * 4); -#if GST_CHECK_PLUGINS_BASE_VERSION(0, 10, 32) if (to_format == GST_VIDEO_FORMAT_RGB8_PALETTED) { /* build poor man's palette, taken from ffmpegcolorspace */ static const guint8 pal_value[6] = { 0x00, 0x33, 0x66, 0x99, 0xcc, 0xff }; @@ -122,7 +132,6 @@ colorspace_convert_new (GstVideoFormat to_format, ColorSpaceColorSpec to_spec, while (i < 256) palette[i++] = 0xff000000; } -#endif return convert; } @@ -130,10 +139,10 @@ colorspace_convert_new (GstVideoFormat to_format, ColorSpaceColorSpec to_spec, void colorspace_convert_free (ColorspaceConvert * convert) { - if (convert->palette) - g_free (convert->palette); - if (convert->tmpline) - g_free (convert->tmpline); + g_free (convert->palette); + g_free (convert->tmpline); + g_free (convert->tmpline16); + g_free (convert->errline); g_free (convert); } @@ -146,6 +155,23 @@ colorspace_convert_set_interlaced (ColorspaceConvert * convert, } void +colorspace_convert_set_dither (ColorspaceConvert * convert, int type) +{ + switch (type) { + case 0: + default: + convert->dither16 = colorspace_dither_none; + break; + case 1: + convert->dither16 = colorspace_dither_verterr; + break; + case 2: + convert->dither16 = colorspace_dither_halftone; + break; + } +} + +void colorspace_convert_set_palette (ColorspaceConvert * convert, const guint32 * palette) { @@ -390,25 +416,131 @@ putline_v210 (ColorspaceConvert * convert, guint8 * dest, const guint8 * src, guint16 u0, u1, u2; guint16 v0, v1, v2; - y0 = src[4 * (i + 0) + 1]; - y1 = src[4 * (i + 1) + 1]; - y2 = src[4 * (i + 2) + 1]; - y3 = src[4 * (i + 3) + 1]; - y4 = src[4 * (i + 4) + 1]; - y5 = src[4 * (i + 5) + 1]; + y0 = src[4 * (i + 0) + 1] << 2; + y1 = src[4 * (i + 1) + 1] << 2; + y2 = src[4 * (i + 2) + 1] << 2; + y3 = src[4 * (i + 3) + 1] << 2; + y4 = src[4 * (i + 4) + 1] << 2; + y5 = src[4 * (i + 5) + 1] << 2; - u0 = (src[4 * (i + 0) + 2] + src[4 * (i + 1) + 2] + 1) >> 1; - u1 = (src[4 * (i + 2) + 2] + src[4 * (i + 3) + 2] + 1) >> 1; - u2 = (src[4 * (i + 4) + 2] + src[4 * (i + 5) + 2] + 1) >> 1; + u0 = (src[4 * (i + 0) + 2] + src[4 * (i + 1) + 2]) << 1; + u1 = (src[4 * (i + 2) + 2] + src[4 * (i + 3) + 2]) << 1; + u2 = (src[4 * (i + 4) + 2] + src[4 * (i + 5) + 2]) << 1; - v0 = (src[4 * (i + 0) + 3] + src[4 * (i + 1) + 3] + 1) >> 1; - v1 = (src[4 * (i + 2) + 3] + src[4 * (i + 3) + 3] + 1) >> 1; - v2 = (src[4 * (i + 4) + 3] + src[4 * (i + 5) + 3] + 1) >> 1; + v0 = (src[4 * (i + 0) + 3] + src[4 * (i + 1) + 3]) << 1; + v1 = (src[4 * (i + 2) + 3] + src[4 * (i + 3) + 3]) << 1; + v2 = (src[4 * (i + 4) + 3] + src[4 * (i + 5) + 3]) << 1; - a0 = (u0 << 2) | ((y0 << 2) << 10) | ((v0 << 2) << 20); - a1 = (y1 << 2) | ((u1 << 2) << 10) | ((y2 << 2) << 20); - a2 = (v1 << 2) | ((y3 << 2) << 10) | ((u2 << 2) << 20); - a3 = (y4 << 2) | ((v2 << 2) << 10) | ((y5 << 2) << 20); + a0 = u0 | (y0 << 10) | (v0 << 20); + a1 = y1 | (u1 << 10) | (y2 << 20); + a2 = v1 | (y3 << 10) | (u2 << 20); + a3 = y4 | (v2 << 10) | (y5 << 20); + + GST_WRITE_UINT32_LE (destline + (i / 6) * 16 + 0, a0); + GST_WRITE_UINT32_LE (destline + (i / 6) * 16 + 4, a1); + GST_WRITE_UINT32_LE (destline + (i / 6) * 16 + 8, a2); + GST_WRITE_UINT32_LE (destline + (i / 6) * 16 + 12, a3); + } +} + +static void +getline16_v210 (ColorspaceConvert * convert, guint16 * dest, const guint8 * src, + int j) +{ + int i; + const guint8 *srcline = FRAME_GET_LINE (src, 0, j); + + for (i = 0; i < convert->width; i += 6) { + guint32 a0, a1, a2, a3; + guint16 y0, y1, y2, y3, y4, y5; + guint16 u0, u2, u4; + guint16 v0, v2, v4; + + a0 = GST_READ_UINT32_LE (srcline + (i / 6) * 16 + 0); + a1 = GST_READ_UINT32_LE (srcline + (i / 6) * 16 + 4); + a2 = GST_READ_UINT32_LE (srcline + (i / 6) * 16 + 8); + a3 = GST_READ_UINT32_LE (srcline + (i / 6) * 16 + 12); + + u0 = ((a0 >> 0) & 0x3ff) << 6; + y0 = ((a0 >> 10) & 0x3ff) << 6; + v0 = ((a0 >> 20) & 0x3ff) << 6; + y1 = ((a1 >> 0) & 0x3ff) << 6; + + u2 = ((a1 >> 10) & 0x3ff) << 6; + y2 = ((a1 >> 20) & 0x3ff) << 6; + v2 = ((a2 >> 0) & 0x3ff) << 6; + y3 = ((a2 >> 10) & 0x3ff) << 6; + + u4 = ((a2 >> 20) & 0x3ff) << 6; + y4 = ((a3 >> 0) & 0x3ff) << 6; + v4 = ((a3 >> 10) & 0x3ff) << 6; + y5 = ((a3 >> 20) & 0x3ff) << 6; + + dest[4 * (i + 0) + 0] = 0xffff; + dest[4 * (i + 0) + 1] = y0; + dest[4 * (i + 0) + 2] = u0; + dest[4 * (i + 0) + 3] = v0; + + dest[4 * (i + 1) + 0] = 0xffff; + dest[4 * (i + 1) + 1] = y1; + dest[4 * (i + 1) + 2] = u0; + dest[4 * (i + 1) + 3] = v0; + + dest[4 * (i + 2) + 0] = 0xffff; + dest[4 * (i + 2) + 1] = y2; + dest[4 * (i + 2) + 2] = u2; + dest[4 * (i + 2) + 3] = v2; + + dest[4 * (i + 3) + 0] = 0xffff; + dest[4 * (i + 3) + 1] = y3; + dest[4 * (i + 3) + 2] = u2; + dest[4 * (i + 3) + 3] = v2; + + dest[4 * (i + 4) + 0] = 0xffff; + dest[4 * (i + 4) + 1] = y4; + dest[4 * (i + 4) + 2] = u4; + dest[4 * (i + 4) + 3] = v4; + + dest[4 * (i + 5) + 0] = 0xffff; + dest[4 * (i + 5) + 1] = y5; + dest[4 * (i + 5) + 2] = u4; + dest[4 * (i + 5) + 3] = v4; + + } +} + +static void +putline16_v210 (ColorspaceConvert * convert, guint8 * dest, const guint16 * src, + int j) +{ + int i; + guint8 *destline = FRAME_GET_LINE (dest, 0, j); + + for (i = 0; i < convert->width + 5; i += 6) { + guint32 a0, a1, a2, a3; + guint16 y0, y1, y2, y3, y4, y5; + guint16 u0, u1, u2; + guint16 v0, v1, v2; + + y0 = src[4 * (i + 0) + 1] >> 6; + y1 = src[4 * (i + 1) + 1] >> 6; + y2 = src[4 * (i + 2) + 1] >> 6; + y3 = src[4 * (i + 3) + 1] >> 6; + y4 = src[4 * (i + 4) + 1] >> 6; + y5 = src[4 * (i + 5) + 1] >> 6; + + u0 = (src[4 * (i + 0) + 2] + src[4 * (i + 1) + 2] + 1) >> 7; + u1 = (src[4 * (i + 2) + 2] + src[4 * (i + 3) + 2] + 1) >> 7; + u2 = (src[4 * (i + 4) + 2] + src[4 * (i + 5) + 2] + 1) >> 7; + + v0 = (src[4 * (i + 0) + 3] + src[4 * (i + 1) + 3] + 1) >> 7; + v1 = (src[4 * (i + 2) + 3] + src[4 * (i + 3) + 3] + 1) >> 7; + v2 = (src[4 * (i + 4) + 3] + src[4 * (i + 5) + 3] + 1) >> 7; + + a0 = u0 | (y0 << 10) | (v0 << 20); + a1 = y1 | (u1 << 10) | (y2 << 20); + a2 = v1 | (y3 << 10) | (u2 << 20); + a3 = y4 | (v2 << 10) | (y5 << 20); GST_WRITE_UINT32_LE (destline + (i / 6) * 16 + 0, a0); GST_WRITE_UINT32_LE (destline + (i / 6) * 16 + 4, a1); @@ -425,9 +557,9 @@ getline_v216 (ColorspaceConvert * convert, guint8 * dest, const guint8 * src, const guint8 *srcline = FRAME_GET_LINE (src, 0, j); for (i = 0; i < convert->width; i++) { dest[i * 4 + 0] = 0xff; - dest[i * 4 + 1] = GST_READ_UINT16_LE (srcline + i * 4 + 2); - dest[i * 4 + 2] = GST_READ_UINT16_LE (srcline + (i >> 1) * 8 + 0); - dest[i * 4 + 3] = GST_READ_UINT16_LE (srcline + (i >> 1) * 8 + 4); + dest[i * 4 + 1] = GST_READ_UINT16_LE (srcline + i * 4 + 2) >> 8; + dest[i * 4 + 2] = GST_READ_UINT16_LE (srcline + (i >> 1) * 8 + 0) >> 8; + dest[i * 4 + 3] = GST_READ_UINT16_LE (srcline + (i >> 1) * 8 + 4) >> 8; } } @@ -446,12 +578,41 @@ putline_v216 (ColorspaceConvert * convert, guint8 * dest, const guint8 * src, } static void +getline16_v216 (ColorspaceConvert * convert, guint16 * dest, const guint8 * src, + int j) +{ + int i; + const guint8 *srcline = FRAME_GET_LINE (src, 0, j); + for (i = 0; i < convert->width; i++) { + dest[i * 4 + 0] = 0xffff; + dest[i * 4 + 1] = GST_READ_UINT16_LE (srcline + i * 4 + 2); + dest[i * 4 + 2] = GST_READ_UINT16_LE (srcline + (i >> 1) * 8 + 0); + dest[i * 4 + 3] = GST_READ_UINT16_LE (srcline + (i >> 1) * 8 + 4); + } +} + +static void +putline16_v216 (ColorspaceConvert * convert, guint8 * dest, const guint16 * src, + int j) +{ + int i; + guint8 *destline = FRAME_GET_LINE (dest, 0, j); + for (i = 0; i < convert->width / 2; i++) { + GST_WRITE_UINT16_LE (destline + i * 8 + 0, src[(i * 2 + 0) * 4 + 2]); + GST_WRITE_UINT16_LE (destline + i * 8 + 2, src[(i * 2 + 0) * 4 + 1]); + GST_WRITE_UINT16_LE (destline + i * 8 + 4, src[(i * 2 + 1) * 4 + 3]); + GST_WRITE_UINT16_LE (destline + i * 8 + 8, src[(i * 2 + 0) * 4 + 1]); + } +} + +static void getline_Y41B (ColorspaceConvert * convert, guint8 * dest, const guint8 * src, int j) { cogorc_getline_YUV9 (dest, FRAME_GET_LINE (src, 0, j), - FRAME_GET_LINE (src, 1, j), FRAME_GET_LINE (src, 2, j), convert->width); + FRAME_GET_LINE (src, 1, j), FRAME_GET_LINE (src, 2, j), + convert->width / 2); } static void @@ -875,7 +1036,6 @@ putline_A420 (ColorspaceConvert * convert, guint8 * dest, const guint8 * src, FRAME_GET_LINE (dest, 3, j), src, convert->width / 2); } -#if GST_CHECK_PLUGINS_BASE_VERSION(0, 10, 32) static void getline_RGB8P (ColorspaceConvert * convert, guint8 * dest, const guint8 * src, int j) @@ -917,7 +1077,7 @@ getline_YUV9 (ColorspaceConvert * convert, guint8 * dest, const guint8 * src, cogorc_getline_YUV9 (dest, FRAME_GET_LINE (src, 0, j), FRAME_GET_LINE (src, 1, j >> 2), - FRAME_GET_LINE (src, 2, j >> 2), convert->width); + FRAME_GET_LINE (src, 2, j >> 2), convert->width / 2); } static void @@ -1053,7 +1213,129 @@ putline_IYU1 (ColorspaceConvert * convert, guint8 * dest, const guint8 * src, destline[(i >> 2) * 6 + 3] = src[i * 4 + 3]; } } -#endif + +static void +getline_AY64 (ColorspaceConvert * convert, guint8 * dest, const guint8 * src, + int j) +{ + int i; + const guint16 *srcline = (const guint16 *) FRAME_GET_LINE (src, 0, j); + for (i = 0; i < convert->width * 4; i++) { + dest[i] = srcline[i] >> 8; + } +} + +static void +putline_AY64 (ColorspaceConvert * convert, guint8 * dest, const guint8 * src, + int j) +{ + int i; + guint16 *destline = (guint16 *) FRAME_GET_LINE (dest, 0, j); + for (i = 0; i < convert->width * 4; i++) { + destline[i] = src[i] << 8; + } +} + +static void +getline16_AY64 (ColorspaceConvert * convert, guint16 * dest, const guint8 * src, + int j) +{ + memcpy (dest, FRAME_GET_LINE (src, 0, j), convert->width * 8); +} + +static void +putline16_AY64 (ColorspaceConvert * convert, guint8 * dest, const guint16 * src, + int j) +{ + memcpy (FRAME_GET_LINE (dest, 0, j), src, convert->width * 8); +} + +static void +getline_r210 (ColorspaceConvert * convert, guint8 * dest, const guint8 * src, + int j) +{ + int i; + const guint8 *srcline = FRAME_GET_LINE (src, 0, j); + for (i = 0; i < convert->width; i++) { + guint8 x; + dest[i * 4 + 0] = 0xff; + x = GST_READ_UINT32_BE (srcline + i * 4); + dest[i * 4 + 1] = (x >> 22) & 0xff; + dest[i * 4 + 2] = (x >> 12) & 0xff; + dest[i * 4 + 3] = (x >> 2) & 0xff; + } +} + +static void +putline_r210 (ColorspaceConvert * convert, guint8 * dest, const guint8 * src, + int j) +{ + int i; + guint8 *destline = FRAME_GET_LINE (dest, 0, j); + for (i = 0; i < convert->width / 2; i++) { + guint32 x = 0; + x |= src[i * 4 + 1] << 22; + x |= (src[i * 4 + 1] & 0xc0) << 14; + x |= src[i * 4 + 2] << 12; + x |= (src[i * 4 + 2] & 0xc0) << 10; + x |= src[i * 4 + 3] << 2; + x |= (src[i * 4 + 3] & 0xc0) >> 6; + GST_WRITE_UINT32_BE (destline + i * 4, x); + } +} + +static void +getline16_r210 (ColorspaceConvert * convert, guint16 * dest, const guint8 * src, + int j) +{ + int i; + const guint8 *srcline = FRAME_GET_LINE (src, 0, j); + for (i = 0; i < convert->width; i++) { + guint32 x; + dest[i * 4 + 0] = 0xffff; + x = GST_READ_UINT32_BE (srcline + i * 4); + dest[i * 4 + 1] = ((x >> 14) & 0xffc0) | (x >> 24); + dest[i * 4 + 2] = ((x >> 4) & 0xffc0) | ((x >> 14) & 0x3f); + dest[i * 4 + 3] = ((x << 6) & 0xffc0) | ((x >> 4) & 0x3f); + } +} + +static void +putline16_r210 (ColorspaceConvert * convert, guint8 * dest, const guint16 * src, + int j) +{ + int i; + guint8 *destline = FRAME_GET_LINE (dest, 0, j); + for (i = 0; i < convert->width / 2; i++) { + guint32 x = 0; + x |= (src[i * 4 + 1] & 0xffc0) << 14; + x |= (src[i * 4 + 2] & 0xffc0) << 4; + x |= (src[i * 4 + 3] & 0xffc0) >> 6; + GST_WRITE_UINT32_BE (destline + i * 4, x); + } +} + +static void +getline16_convert (ColorspaceConvert * convert, guint16 * dest, + const guint8 * src, int j) +{ + int i; + convert->getline (convert, convert->tmpline, src, j); + for (i = 0; i < convert->width * 4; i++) { + dest[i] = convert->tmpline[i] << 8; + } +} + +static void +putline16_convert (ColorspaceConvert * convert, guint8 * dest, + const guint16 * src, int j) +{ + int i; + for (i = 0; i < convert->width * 4; i++) { + convert->tmpline[i] = src[i] >> 8; + } + convert->putline (convert, dest, convert->tmpline, j); +} typedef struct { @@ -1062,6 +1344,10 @@ typedef struct const guint8 * src, int j); void (*putline) (ColorspaceConvert * convert, guint8 * dest, const guint8 * src, int j); + void (*getline16) (ColorspaceConvert * convert, guint16 * dest, + const guint8 * src, int j); + void (*putline16) (ColorspaceConvert * convert, guint8 * dest, + const guint16 * src, int j); } ColorspaceLine; static const ColorspaceLine lines[] = { {GST_VIDEO_FORMAT_I420, getline_I420, putline_I420}, @@ -1083,8 +1369,10 @@ static const ColorspaceLine lines[] = { {GST_VIDEO_FORMAT_Y42B, getline_Y42B, putline_Y42B}, {GST_VIDEO_FORMAT_YVYU, getline_YVYU, putline_YVYU}, {GST_VIDEO_FORMAT_Y444, getline_Y444, putline_Y444}, - {GST_VIDEO_FORMAT_v210, getline_v210, putline_v210}, - {GST_VIDEO_FORMAT_v216, getline_v216, putline_v216}, + {GST_VIDEO_FORMAT_v210, getline_v210, putline_v210, + getline16_v210, putline16_v210}, + {GST_VIDEO_FORMAT_v216, getline_v216, putline_v216, + getline16_v216, putline16_v216}, {GST_VIDEO_FORMAT_NV12, getline_NV12, putline_NV12}, {GST_VIDEO_FORMAT_NV21, getline_NV21, putline_NV21}, //{GST_VIDEO_FORMAT_GRAY8, getline_GRAY8, putline_GRAY8}, @@ -1099,12 +1387,16 @@ static const ColorspaceLine lines[] = { {GST_VIDEO_FORMAT_BGR15, getline_BGR15, putline_BGR15}, {GST_VIDEO_FORMAT_UYVP, getline_UYVP, putline_UYVP}, {GST_VIDEO_FORMAT_A420, getline_A420, putline_A420} -#if GST_CHECK_PLUGINS_BASE_VERSION(0, 10, 32) , {GST_VIDEO_FORMAT_RGB8_PALETTED, getline_RGB8P, putline_RGB8P}, {GST_VIDEO_FORMAT_YUV9, getline_YUV9, putline_YUV9}, {GST_VIDEO_FORMAT_YVU9, getline_YUV9, putline_YUV9}, /* alias */ - {GST_VIDEO_FORMAT_IYU1, getline_IYU1, putline_IYU1} -#endif + {GST_VIDEO_FORMAT_IYU1, getline_IYU1, putline_IYU1}, + {GST_VIDEO_FORMAT_ARGB64, getline_AY64, putline_AY64, getline16_AY64, + putline16_AY64}, + {GST_VIDEO_FORMAT_AYUV64, getline_AY64, putline_AY64, getline16_AY64, + putline16_AY64}, + {GST_VIDEO_FORMAT_r210, getline_r210, putline_r210, getline16_r210, + putline16_r210} }; static void @@ -1251,6 +1543,151 @@ matrix_identity (ColorspaceConvert * convert) /* do nothing */ } +static void +matrix16_rgb_to_yuv_bt470_6 (ColorspaceConvert * convert) +{ + int i; + int r, g, b; + int y, u, v; + guint16 *tmpline = convert->tmpline16; + + for (i = 0; i < convert->width; i++) { + r = tmpline[i * 4 + 1]; + g = tmpline[i * 4 + 2]; + b = tmpline[i * 4 + 3]; + + y = (66 * r + 129 * g + 25 * b + 4096 * 256) >> 8; + u = (-38 * r - 74 * g + 112 * b + 32768 * 256) >> 8; + v = (112 * r - 94 * g - 18 * b + 32768 * 256) >> 8; + + tmpline[i * 4 + 1] = CLAMP (y, 0, 65535); + tmpline[i * 4 + 2] = CLAMP (u, 0, 65535); + tmpline[i * 4 + 3] = CLAMP (v, 0, 65535); + } +} + +static void +matrix16_rgb_to_yuv_bt709 (ColorspaceConvert * convert) +{ + int i; + int r, g, b; + int y, u, v; + guint16 *tmpline = convert->tmpline16; + + for (i = 0; i < convert->width; i++) { + r = tmpline[i * 4 + 1]; + g = tmpline[i * 4 + 2]; + b = tmpline[i * 4 + 3]; + + y = (47 * r + 157 * g + 16 * b + 4096 * 256) >> 8; + u = (-26 * r - 87 * g + 112 * b + 32768 * 256) >> 8; + v = (112 * r - 102 * g - 10 * b + 32768 * 256) >> 8; + + tmpline[i * 4 + 1] = CLAMP (y, 0, 65535); + tmpline[i * 4 + 2] = CLAMP (u, 0, 65535); + tmpline[i * 4 + 3] = CLAMP (v, 0, 65535); + } +} + +static void +matrix16_yuv_bt470_6_to_rgb (ColorspaceConvert * convert) +{ + int i; + int r, g, b; + int y, u, v; + guint16 *tmpline = convert->tmpline16; + + for (i = 0; i < convert->width; i++) { + y = tmpline[i * 4 + 1]; + u = tmpline[i * 4 + 2]; + v = tmpline[i * 4 + 3]; + + r = (298 * y + 409 * v - 57068 * 256) >> 8; + g = (298 * y - 100 * u - 208 * v + 34707 * 256) >> 8; + b = (298 * y + 516 * u - 70870 * 256) >> 8; + + tmpline[i * 4 + 1] = CLAMP (r, 0, 65535); + tmpline[i * 4 + 2] = CLAMP (g, 0, 65535); + tmpline[i * 4 + 3] = CLAMP (b, 0, 65535); + } +} + +static void +matrix16_yuv_bt709_to_rgb (ColorspaceConvert * convert) +{ + int i; + int r, g, b; + int y, u, v; + guint16 *tmpline = convert->tmpline16; + + for (i = 0; i < convert->width; i++) { + y = tmpline[i * 4 + 1]; + u = tmpline[i * 4 + 2]; + v = tmpline[i * 4 + 3]; + + r = (298 * y + 459 * v - 63514 * 256) >> 8; + g = (298 * y - 55 * u - 136 * v + 19681 * 256) >> 8; + b = (298 * y + 541 * u - 73988 * 256) >> 8; + + tmpline[i * 4 + 1] = CLAMP (r, 0, 65535); + tmpline[i * 4 + 2] = CLAMP (g, 0, 65535); + tmpline[i * 4 + 3] = CLAMP (b, 0, 65535); + } +} + +static void +matrix16_yuv_bt709_to_yuv_bt470_6 (ColorspaceConvert * convert) +{ + int i; + int r, g, b; + int y, u, v; + guint16 *tmpline = convert->tmpline16; + + for (i = 0; i < convert->width; i++) { + y = tmpline[i * 4 + 1]; + u = tmpline[i * 4 + 2]; + v = tmpline[i * 4 + 3]; + + r = (256 * y + 25 * u + 49 * v - 9536 * 256) >> 8; + g = (253 * u - 28 * v + 3958 * 256) >> 8; + b = (-19 * u + 252 * v + 2918 * 256) >> 8; + + tmpline[i * 4 + 1] = CLAMP (r, 0, 65535); + tmpline[i * 4 + 2] = CLAMP (g, 0, 65535); + tmpline[i * 4 + 3] = CLAMP (b, 0, 65535); + } +} + +static void +matrix16_yuv_bt470_6_to_yuv_bt709 (ColorspaceConvert * convert) +{ + int i; + int r, g, b; + int y, u, v; + guint16 *tmpline = convert->tmpline16; + + for (i = 0; i < convert->width; i++) { + y = tmpline[i * 4 + 1]; + u = tmpline[i * 4 + 2]; + v = tmpline[i * 4 + 3]; + + r = (256 * y - 30 * u - 53 * v + 10600 * 256) >> 8; + g = (261 * u + 29 * v - 4367 * 256) >> 8; + b = (19 * u + 262 * v - 3289 * 256) >> 8; + + tmpline[i * 4 + 1] = CLAMP (r, 0, 65535); + tmpline[i * 4 + 2] = CLAMP (g, 0, 65535); + tmpline[i * 4 + 3] = CLAMP (b, 0, 65535); + } +} + +static void +matrix16_identity (ColorspaceConvert * convert) +{ + /* do nothing */ +} + + static void colorspace_convert_lookup_getput (ColorspaceConvert * convert) @@ -1258,41 +1695,60 @@ colorspace_convert_lookup_getput (ColorspaceConvert * convert) int i; convert->getline = NULL; + convert->getline16 = NULL; for (i = 0; i < sizeof (lines) / sizeof (lines[0]); i++) { if (lines[i].format == convert->from_format) { convert->getline = lines[i].getline; + convert->getline16 = lines[i].getline16; break; } } convert->putline = NULL; + convert->putline16 = NULL; for (i = 0; i < sizeof (lines) / sizeof (lines[0]); i++) { if (lines[i].format == convert->to_format) { convert->putline = lines[i].putline; + convert->putline16 = lines[i].putline16; break; } } GST_DEBUG ("get %p put %p", convert->getline, convert->putline); - if (convert->from_spec == convert->to_spec) + if (convert->getline16 == NULL) { + convert->getline16 = getline16_convert; + } + if (convert->putline16 == NULL) { + convert->putline16 = putline16_convert; + } + + if (convert->from_spec == convert->to_spec) { convert->matrix = matrix_identity; - else if (convert->from_spec == COLOR_SPEC_RGB - && convert->to_spec == COLOR_SPEC_YUV_BT470_6) + convert->matrix16 = matrix16_identity; + } else if (convert->from_spec == COLOR_SPEC_RGB + && convert->to_spec == COLOR_SPEC_YUV_BT470_6) { convert->matrix = matrix_rgb_to_yuv_bt470_6; - else if (convert->from_spec == COLOR_SPEC_RGB - && convert->to_spec == COLOR_SPEC_YUV_BT709) + convert->matrix16 = matrix16_rgb_to_yuv_bt470_6; + } else if (convert->from_spec == COLOR_SPEC_RGB + && convert->to_spec == COLOR_SPEC_YUV_BT709) { convert->matrix = matrix_rgb_to_yuv_bt709; - else if (convert->from_spec == COLOR_SPEC_YUV_BT470_6 - && convert->to_spec == COLOR_SPEC_RGB) + convert->matrix16 = matrix16_rgb_to_yuv_bt709; + } else if (convert->from_spec == COLOR_SPEC_YUV_BT470_6 + && convert->to_spec == COLOR_SPEC_RGB) { convert->matrix = matrix_yuv_bt470_6_to_rgb; - else if (convert->from_spec == COLOR_SPEC_YUV_BT709 - && convert->to_spec == COLOR_SPEC_RGB) + convert->matrix16 = matrix16_yuv_bt470_6_to_rgb; + } else if (convert->from_spec == COLOR_SPEC_YUV_BT709 + && convert->to_spec == COLOR_SPEC_RGB) { convert->matrix = matrix_yuv_bt709_to_rgb; - else if (convert->from_spec == COLOR_SPEC_YUV_BT709 - && convert->to_spec == COLOR_SPEC_YUV_BT470_6) + convert->matrix16 = matrix16_yuv_bt709_to_rgb; + } else if (convert->from_spec == COLOR_SPEC_YUV_BT709 + && convert->to_spec == COLOR_SPEC_YUV_BT470_6) { convert->matrix = matrix_yuv_bt709_to_yuv_bt470_6; - else if (convert->from_spec == COLOR_SPEC_YUV_BT470_6 - && convert->to_spec == COLOR_SPEC_YUV_BT709) + convert->matrix16 = matrix16_yuv_bt709_to_yuv_bt470_6; + } else if (convert->from_spec == COLOR_SPEC_YUV_BT470_6 + && convert->to_spec == COLOR_SPEC_YUV_BT709) { convert->matrix = matrix_yuv_bt470_6_to_yuv_bt709; + convert->matrix16 = matrix16_yuv_bt470_6_to_yuv_bt709; + } } static void @@ -1311,13 +1767,60 @@ colorspace_convert_generic (ColorspaceConvert * convert, guint8 * dest, return; } - for (j = 0; j < convert->height; j++) { - convert->getline (convert, convert->tmpline, src, j); - convert->matrix (convert); - convert->putline (convert, dest, convert->tmpline, j); + if (convert->use_16bit) { + for (j = 0; j < convert->height; j++) { + convert->getline16 (convert, convert->tmpline16, src, j); + convert->matrix16 (convert); + convert->dither16 (convert, j); + convert->putline16 (convert, dest, convert->tmpline16, j); + } + } else { + for (j = 0; j < convert->height; j++) { + convert->getline (convert, convert->tmpline, src, j); + convert->matrix (convert); + convert->putline (convert, dest, convert->tmpline, j); + } + } +} + +static void +colorspace_dither_none (ColorspaceConvert * convert, int j) +{ +} + +static void +colorspace_dither_verterr (ColorspaceConvert * convert, int j) +{ + int i; + guint16 *tmpline = convert->tmpline16; + guint16 *errline = convert->errline; + + for (i = 0; i < 4 * convert->width; i++) { + tmpline[i] += errline[i]; + errline[i] = tmpline[i] & 0xff; } } +static void +colorspace_dither_halftone (ColorspaceConvert * convert, int j) +{ + int i; + guint16 *tmpline = convert->tmpline16; + static guint16 halftone[8][8] = { + {0, 128, 32, 160, 8, 136, 40, 168}, + {192, 64, 224, 96, 200, 72, 232, 104}, + {48, 176, 16, 144, 56, 184, 24, 152}, + {240, 112, 208, 80, 248, 120, 216, 88}, + {12, 240, 44, 172, 4, 132, 36, 164}, + {204, 76, 236, 108, 196, 68, 228, 100}, + {60, 188, 28, 156, 52, 180, 20, 148}, + {252, 142, 220, 92, 244, 116, 212, 84} + }; + + for (i = 0; i < convert->width * 4; i++) { + tmpline[i] += halftone[(i >> 2) & 7][j & 7]; + } +} /* Fast paths */ @@ -1708,6 +2211,7 @@ convert_Y444_AYUV (ColorspaceConvert * convert, guint8 * dest, convert->src_stride[2], convert->width, convert->height); } +#if G_BYTE_ORDER == G_LITTLE_ENDIAN static void convert_AYUV_ARGB (ColorspaceConvert * convert, guint8 * dest, const guint8 * src) @@ -1776,6 +2280,7 @@ convert_I420_BGRA (ColorspaceConvert * convert, guint8 * dest, } } } +#endif @@ -1857,6 +2362,7 @@ static const ColorspaceTransform transforms[] = { {GST_VIDEO_FORMAT_Y444, COLOR_SPEC_NONE, GST_VIDEO_FORMAT_Y42B, COLOR_SPEC_NONE, TRUE, convert_Y444_Y42B}, +#if G_BYTE_ORDER == G_LITTLE_ENDIAN {GST_VIDEO_FORMAT_AYUV, COLOR_SPEC_YUV_BT470_6, GST_VIDEO_FORMAT_ARGB, COLOR_SPEC_RGB, FALSE, convert_AYUV_ARGB}, {GST_VIDEO_FORMAT_AYUV, COLOR_SPEC_YUV_BT470_6, GST_VIDEO_FORMAT_BGRA, @@ -1872,6 +2378,7 @@ static const ColorspaceTransform transforms[] = { {GST_VIDEO_FORMAT_I420, COLOR_SPEC_YUV_BT470_6, GST_VIDEO_FORMAT_BGRA, COLOR_SPEC_RGB, FALSE, convert_I420_BGRA}, +#endif }; static void diff --git a/gst/colorspace/colorspace.h b/gst/colorspace/colorspace.h index b12b032df..05bcc1867 100644 --- a/gst/colorspace/colorspace.h +++ b/gst/colorspace/colorspace.h @@ -35,6 +35,12 @@ typedef enum { COLOR_SPEC_YUV_BT709 } ColorSpaceColorSpec; +typedef enum { + DITHER_NONE, + DITHER_VERTERR, + DITHER_HALFTONE +} ColorSpaceDitherMethod; + struct _ColorspaceComponent { int offset; int stride; @@ -43,6 +49,8 @@ struct _ColorspaceComponent { struct _ColorspaceConvert { gint width, height; gboolean interlaced; + gboolean use_16bit; + gboolean dither; GstVideoFormat from_format; ColorSpaceColorSpec from_spec; @@ -51,6 +59,8 @@ struct _ColorspaceConvert { guint32 *palette; guint8 *tmpline; + guint16 *tmpline16; + guint16 *errline; int dest_offset[4]; int dest_stride[4]; @@ -61,11 +71,17 @@ struct _ColorspaceConvert { void (*getline) (ColorspaceConvert *convert, guint8 *dest, const guint8 *src, int j); void (*putline) (ColorspaceConvert *convert, guint8 *dest, const guint8 *src, int j); void (*matrix) (ColorspaceConvert *convert); + + void (*getline16) (ColorspaceConvert *convert, guint16 *dest, const guint8 *src, int j); + void (*putline16) (ColorspaceConvert *convert, guint8 *dest, const guint16 *src, int j); + void (*matrix16) (ColorspaceConvert *convert); + void (*dither16) (ColorspaceConvert *convert, int j); }; ColorspaceConvert * colorspace_convert_new (GstVideoFormat to_format, ColorSpaceColorSpec from_spec, GstVideoFormat from_format, ColorSpaceColorSpec to_spec, int width, int height); +void colorspace_convert_set_dither (ColorspaceConvert * convert, int type); void colorspace_convert_set_interlaced (ColorspaceConvert *convert, gboolean interlaced); void colorspace_convert_set_palette (ColorspaceConvert *convert, diff --git a/gst/colorspace/gstcolorspace.c b/gst/colorspace/gstcolorspace.c index 2de57732d..3d934a5ed 100644 --- a/gst/colorspace/gstcolorspace.c +++ b/gst/colorspace/gstcolorspace.c @@ -40,26 +40,22 @@ #include "gstcolorspace.h" #include <gst/video/video.h> -/* For GST_CHECK_PLUGINS_BASE_VERSION() */ -#include <gst/pbutils/pbutils.h> - #include <string.h> GST_DEBUG_CATEGORY (colorspace_debug); #define GST_CAT_DEFAULT colorspace_debug GST_DEBUG_CATEGORY (colorspace_performance); -#if GST_CHECK_PLUGINS_BASE_VERSION(0, 10, 32) -#define VIDEO_CAPS_RGB8_PALETTED \ - GST_VIDEO_CAPS_RGB8_PALETTED "; " -#else -#define VIDEO_CAPS_RGB8_PALETTED /* no-op */ -#endif +enum +{ + PROP_0, + PROP_DITHER +}; #define CSP_VIDEO_CAPS \ "video/x-raw-yuv, width = "GST_VIDEO_SIZE_RANGE" , " \ "height="GST_VIDEO_SIZE_RANGE",framerate="GST_VIDEO_FPS_RANGE"," \ - "format= (fourcc) { I420 , NV12 , NV21 , YV12 , YUY2 , Y42B , Y444 , YUV9 , YVU9 , Y41B , Y800 , Y8 , GREY , Y16 , UYVY , YVYU , IYU1 , v308 , AYUV, v210, A420 } ;" \ + "format= (fourcc) { I420 , NV12 , NV21 , YV12 , YUY2 , Y42B , Y444 , YUV9 , YVU9 , Y41B , Y800 , Y8 , GREY , Y16 , UYVY , YVYU , IYU1 , v308 , AYUV, v210, v216, A420, AY64 } ;" \ GST_VIDEO_CAPS_RGB";" \ GST_VIDEO_CAPS_BGR";" \ GST_VIDEO_CAPS_RGBx";" \ @@ -74,10 +70,12 @@ GST_DEBUG_CATEGORY (colorspace_performance); GST_VIDEO_CAPS_BGR_16";" \ GST_VIDEO_CAPS_RGB_15";" \ GST_VIDEO_CAPS_BGR_15";" \ - VIDEO_CAPS_RGB8_PALETTED \ + GST_VIDEO_CAPS_RGB8_PALETTED "; " \ GST_VIDEO_CAPS_GRAY8";" \ GST_VIDEO_CAPS_GRAY16("BIG_ENDIAN")";" \ - GST_VIDEO_CAPS_GRAY16("LITTLE_ENDIAN")";" + GST_VIDEO_CAPS_GRAY16("LITTLE_ENDIAN")";" \ + GST_VIDEO_CAPS_r210";" \ + GST_VIDEO_CAPS_ARGB_64 static GstStaticPadTemplate gst_csp_src_template = GST_STATIC_PAD_TEMPLATE ("src", @@ -95,6 +93,12 @@ GST_STATIC_PAD_TEMPLATE ("sink", GType gst_csp_get_type (void); +static void gst_csp_set_property (GObject * object, + guint property_id, const GValue * value, GParamSpec * pspec); +static void gst_csp_get_property (GObject * object, + guint property_id, GValue * value, GParamSpec * pspec); +static void gst_csp_dispose (GObject * object); + static gboolean gst_csp_set_caps (GstBaseTransform * btrans, GstCaps * incaps, GstCaps * outcaps); static gboolean gst_csp_get_unit_size (GstBaseTransform * btrans, @@ -106,6 +110,25 @@ static GQuark _QRAWRGB; /* "video/x-raw-rgb" */ static GQuark _QRAWYUV; /* "video/x-raw-yuv" */ static GQuark _QALPHAMASK; /* "alpha_mask" */ + +static GType +dither_method_get_type (void) +{ + static GType gtype = 0; + + if (gtype == 0) { + static const GEnumValue values[] = { + {DITHER_NONE, "No dithering (default)", "none"}, + {DITHER_VERTERR, "Vertical error propogation", "verterr"}, + {DITHER_HALFTONE, "Half-tone", "halftone"}, + {0, NULL, NULL} + }; + + gtype = g_enum_register_static ("GstColorspaceDitherMethod", values); + } + return gtype; +} + /* copies the given caps */ static GstCaps * gst_csp_caps_remove_format_info (GstCaps * caps) @@ -229,6 +252,10 @@ gst_csp_set_caps (GstBaseTransform * btrans, GstCaps * incaps, space = GST_CSP (btrans); + if (space->convert) { + colorspace_convert_free (space->convert); + } + /* input caps */ ret = gst_video_format_parse_caps (incaps, &in_format, &in_width, &in_height); @@ -315,7 +342,6 @@ gst_csp_set_caps (GstBaseTransform * btrans, GstCaps * incaps, if (space->convert) { colorspace_convert_set_interlaced (space->convert, in_interlaced); } -#if GST_CHECK_PLUGINS_BASE_VERSION(0, 10, 32) /* palette, only for from data */ if (space->from_format == GST_VIDEO_FORMAT_RGB8_PALETTED && space->to_format == GST_VIDEO_FORMAT_RGB8_PALETTED) { @@ -343,7 +369,6 @@ gst_csp_set_caps (GstBaseTransform * btrans, GstCaps * incaps, gst_caps_set_simple (outcaps, "palette_data", GST_TYPE_BUFFER, p_buf, NULL); gst_buffer_unref (p_buf); } -#endif GST_DEBUG ("reconfigured %d %d", space->from_format, space->to_format); @@ -371,7 +396,6 @@ format_mismatch: space->to_format = GST_VIDEO_FORMAT_UNKNOWN; return FALSE; } -#if GST_CHECK_PLUGINS_BASE_VERSION(0, 10, 32) invalid_palette: { GST_ERROR_OBJECT (space, "invalid palette"); @@ -379,7 +403,6 @@ invalid_palette: space->to_format = GST_VIDEO_FORMAT_UNKNOWN; return FALSE; } -#endif } GST_BOILERPLATE (GstCsp, gst_csp, GstVideoFilter, GST_TYPE_VIDEO_FILTER); @@ -404,10 +427,30 @@ gst_csp_base_init (gpointer klass) _QALPHAMASK = g_quark_from_string ("alpha_mask"); } +void +gst_csp_dispose (GObject * object) +{ + GstCsp *csp; + + g_return_if_fail (GST_IS_CSP (object)); + csp = GST_CSP (object); + + /* clean up as possible. may be called multiple times */ + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + static void gst_csp_finalize (GObject * obj) { + GstCsp *space = GST_CSP (obj); + + if (space->convert) { + colorspace_convert_free (space->convert); + } + G_OBJECT_CLASS (parent_class)->finalize (obj); + } static void @@ -417,6 +460,9 @@ gst_csp_class_init (GstCspClass * klass) GstBaseTransformClass *gstbasetransform_class = (GstBaseTransformClass *) klass; + gobject_class->set_property = gst_csp_set_property; + gobject_class->get_property = gst_csp_get_property; + gobject_class->dispose = gst_csp_dispose; gobject_class->finalize = gst_csp_finalize; gstbasetransform_class->transform_caps = @@ -427,6 +473,12 @@ gst_csp_class_init (GstCspClass * klass) gstbasetransform_class->transform = GST_DEBUG_FUNCPTR (gst_csp_transform); gstbasetransform_class->passthrough_on_same_caps = TRUE; + + g_object_class_install_property (gobject_class, PROP_DITHER, + g_param_spec_enum ("dither", "Dither", "Apply dithering while converting", + dither_method_get_type (), DITHER_NONE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + } static void @@ -436,6 +488,44 @@ gst_csp_init (GstCsp * space, GstCspClass * klass) space->to_format = GST_VIDEO_FORMAT_UNKNOWN; } +void +gst_csp_set_property (GObject * object, guint property_id, + const GValue * value, GParamSpec * pspec) +{ + GstCsp *csp; + + g_return_if_fail (GST_IS_CSP (object)); + csp = GST_CSP (object); + + switch (property_id) { + case PROP_DITHER: + csp->dither = g_value_get_enum (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +void +gst_csp_get_property (GObject * object, guint property_id, + GValue * value, GParamSpec * pspec) +{ + GstCsp *csp; + + g_return_if_fail (GST_IS_CSP (object)); + csp = GST_CSP (object); + + switch (property_id) { + case PROP_DITHER: + g_value_set_enum (value, csp->dither); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + static gboolean gst_csp_get_unit_size (GstBaseTransform * btrans, GstCaps * caps, guint * size) { @@ -467,6 +557,8 @@ gst_csp_transform (GstBaseTransform * btrans, GstBuffer * inbuf, space->to_format == GST_VIDEO_FORMAT_UNKNOWN)) goto unknown_format; + colorspace_convert_set_dither (space->convert, space->dither); + colorspace_convert_convert (space->convert, GST_BUFFER_DATA (outbuf), GST_BUFFER_DATA (inbuf)); diff --git a/gst/colorspace/gstcolorspace.h b/gst/colorspace/gstcolorspace.h index c97705cea..71245b831 100644 --- a/gst/colorspace/gstcolorspace.h +++ b/gst/colorspace/gstcolorspace.h @@ -56,6 +56,7 @@ struct _GstCsp { ColorSpaceColorSpec to_spec; ColorspaceConvert *convert; + gboolean dither; }; struct _GstCspClass diff --git a/gst/colorspace/gstcolorspaceorc.orc b/gst/colorspace/gstcolorspaceorc.orc index 263992dd4..086990e15 100644 --- a/gst/colorspace/gstcolorspaceorc.orc +++ b/gst/colorspace/gstcolorspaceorc.orc @@ -1384,7 +1384,8 @@ x2 mergewl ayuv, ayay, uvuv .temp 4 ayay .temp 4 uvuv -x2 splitwb yy, uv, uyvy +x2 splitwb uv, yy, uyvy +swapw uv, uv x2 mergebw ayay, c255, yy mergewl uvuv, uv, uv x2 mergewl ayuv, ayay, uvuv diff --git a/gst/dataurisrc/gstdataurisrc.c b/gst/dataurisrc/gstdataurisrc.c index 17ebf4b10..446ca8407 100644 --- a/gst/dataurisrc/gstdataurisrc.c +++ b/gst/dataurisrc/gstdataurisrc.c @@ -415,8 +415,8 @@ gst_data_uri_src_set_uri (GstURIHandler * handler, const gchar * uri) /* Convert to UTF8 */ if (strcmp ("text/plain", mimetype) == 0 && - charset && strcasecmp ("US-ASCII", charset) != 0 - && strcasecmp ("UTF-8", charset) != 0) { + charset && g_ascii_strcasecmp ("US-ASCII", charset) != 0 + && g_ascii_strcasecmp ("UTF-8", charset) != 0) { gsize read; gsize written; gchar *old_data = (gchar *) GST_BUFFER_DATA (src->buffer); diff --git a/gst/dccp/gstdccp.c b/gst/dccp/gstdccp.c index 470c217ac..af652f2de 100644 --- a/gst/dccp/gstdccp.c +++ b/gst/dccp/gstdccp.c @@ -241,18 +241,14 @@ gst_dccp_server_wait_connections (GstElement * element, int server_sock_fd) /* new client */ int client_sock_fd; struct sockaddr_in client_address; - unsigned int client_address_len; + 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, -#ifndef G_OS_WIN32 &client_address_len)) == -1) { -#else - (int *) &client_address_len)) == -1) { -#endif 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)); diff --git a/gst/dccp/gstdccp_common.h b/gst/dccp/gstdccp_common.h index 965780618..a2c2ca2a3 100644 --- a/gst/dccp/gstdccp_common.h +++ b/gst/dccp/gstdccp_common.h @@ -32,6 +32,9 @@ # define WINVER 0x0501
# include <winsock2.h>
# include <ws2tcpip.h>
+#ifndef socklen_t
+#define socklen_t int
+#endif
#endif
#include <sys/types.h>
#include <unistd.h>
diff --git a/gst/dtmf/gstdtmfdetect.c b/gst/dtmf/gstdtmfdetect.c index 6fa17b5e4..0bb924264 100644 --- a/gst/dtmf/gstdtmfdetect.c +++ b/gst/dtmf/gstdtmfdetect.c @@ -175,7 +175,7 @@ gst_dtmf_detect_transform_ip (GstBaseTransform * trans, GstBuffer * buf) if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP)) return GST_FLOW_OK; - zap_dtmf_detect (&self->dtmf_state, (int16_t *) GST_BUFFER_DATA (buf), + zap_dtmf_detect (&self->dtmf_state, (gint16 *) GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf) / 2, FALSE); dtmf_count = zap_dtmf_get (&self->dtmf_state, dtmfbuf, MAX_DTMF_DIGITS); diff --git a/gst/dtmf/tone_detect.c b/gst/dtmf/tone_detect.c index c3b92ba7d..73a73ee98 100644 --- a/gst/dtmf/tone_detect.c +++ b/gst/dtmf/tone_detect.c @@ -38,8 +38,12 @@ #include <fcntl.h> #include "tone_detect.h" +#ifndef FALSE #define FALSE 0 +#endif +#ifndef TRUE #define TRUE (!FALSE) +#endif //#define USE_3DNOW @@ -60,12 +64,12 @@ #define DTMF_THRESHOLD 8.0e7 #define FAX_THRESHOLD 8.0e7 #define FAX_2ND_HARMONIC 2.0 /* 4dB */ -#define DTMF_NORMAL_TWIST 6.3 /* 8dB */ +#define DTMF_NORMAL_TWIST 6.3 /* 8dB */ #define DTMF_REVERSE_TWIST ((isradio) ? 4.0 : 2.5) /* 4dB normal */ -#define DTMF_RELATIVE_PEAK_ROW 6.3 /* 8dB */ -#define DTMF_RELATIVE_PEAK_COL 6.3 /* 8dB */ +#define DTMF_RELATIVE_PEAK_ROW 6.3 /* 8dB */ +#define DTMF_RELATIVE_PEAK_COL 6.3 /* 8dB */ #define DTMF_2ND_HARMONIC_ROW ((isradio) ? 1.7 : 2.5) /* 4dB normal */ -#define DTMF_2ND_HARMONIC_COL 63.1 /* 18dB */ +#define DTMF_2ND_HARMONIC_COL 63.1 /* 18dB */ static tone_detection_descriptor_t dtmf_detect_row[4]; static tone_detection_descriptor_t dtmf_detect_col[4]; @@ -74,443 +78,426 @@ static tone_detection_descriptor_t dtmf_detect_col_2nd[4]; static tone_detection_descriptor_t fax_detect; static tone_detection_descriptor_t fax_detect_2nd; -static float dtmf_row[] = -{ - 697.0, 770.0, 852.0, 941.0 +static float dtmf_row[] = { + 697.0, 770.0, 852.0, 941.0 }; -static float dtmf_col[] = -{ - 1209.0, 1336.0, 1477.0, 1633.0 + +static float dtmf_col[] = { + 1209.0, 1336.0, 1477.0, 1633.0 }; static float fax_freq = 1100.0; static char dtmf_positions[] = "123A" "456B" "789C" "*0#D"; -static void goertzel_init(goertzel_state_t *s, - tone_detection_descriptor_t *t) +static void +goertzel_init (goertzel_state_t * s, tone_detection_descriptor_t * t) { - s->v2 = - s->v3 = 0.0; - s->fac = t->fac; + s->v2 = s->v3 = 0.0; + s->fac = t->fac; } + /*- End of function --------------------------------------------------------*/ #if defined(USE_3DNOW) -static inline void _dtmf_goertzel_update(goertzel_state_t *s, - float x[], - int samples) +static inline void +_dtmf_goertzel_update (goertzel_state_t * s, float x[], int samples) { - int n; - float v; - int i; - float vv[16]; - - vv[4] = s[0].v2; - vv[5] = s[1].v2; - vv[6] = s[2].v2; - vv[7] = s[3].v2; - vv[8] = s[0].v3; - vv[9] = s[1].v3; - vv[10] = s[2].v3; - vv[11] = s[3].v3; - vv[12] = s[0].fac; - vv[13] = s[1].fac; - vv[14] = s[2].fac; - vv[15] = s[3].fac; - - //v1 = s->v2; - //s->v2 = s->v3; - //s->v3 = s->fac*s->v2 - v1 + x[0]; - - __asm__ __volatile__ ( - " femms;\n" - - " movq 16(%%edx),%%mm2;\n" - " movq 24(%%edx),%%mm3;\n" - " movq 32(%%edx),%%mm4;\n" - " movq 40(%%edx),%%mm5;\n" - " movq 48(%%edx),%%mm6;\n" - " movq 56(%%edx),%%mm7;\n" - - " jmp 1f;\n" - " .align 32;\n" - - " 1: ;\n" - " prefetch (%%eax);\n" - " movq %%mm3,%%mm1;\n" - " movq %%mm2,%%mm0;\n" - " movq %%mm5,%%mm3;\n" - " movq %%mm4,%%mm2;\n" - - " pfmul %%mm7,%%mm5;\n" - " pfmul %%mm6,%%mm4;\n" - " pfsub %%mm1,%%mm5;\n" - " pfsub %%mm0,%%mm4;\n" - - " movq (%%eax),%%mm0;\n" - " movq %%mm0,%%mm1;\n" - " punpckldq %%mm0,%%mm1;\n" - " add $4,%%eax;\n" - " pfadd %%mm1,%%mm5;\n" - " pfadd %%mm1,%%mm4;\n" - - " dec %%ecx;\n" - - " jnz 1b;\n" - - " movq %%mm2,16(%%edx);\n" - " movq %%mm3,24(%%edx);\n" - " movq %%mm4,32(%%edx);\n" - " movq %%mm5,40(%%edx);\n" - - " femms;\n" - : - : "c" (samples), "a" (x), "d" (vv) - : "memory", "eax", "ecx"); - - s[0].v2 = vv[4]; - s[1].v2 = vv[5]; - s[2].v2 = vv[6]; - s[3].v2 = vv[7]; - s[0].v3 = vv[8]; - s[1].v3 = vv[9]; - s[2].v3 = vv[10]; - s[3].v3 = vv[11]; + int n; + float v; + int i; + float vv[16]; + + vv[4] = s[0].v2; + vv[5] = s[1].v2; + vv[6] = s[2].v2; + vv[7] = s[3].v2; + vv[8] = s[0].v3; + vv[9] = s[1].v3; + vv[10] = s[2].v3; + vv[11] = s[3].v3; + vv[12] = s[0].fac; + vv[13] = s[1].fac; + vv[14] = s[2].fac; + vv[15] = s[3].fac; + + //v1 = s->v2; + //s->v2 = s->v3; + //s->v3 = s->fac*s->v2 - v1 + x[0]; + + __asm__ __volatile__ (" femms;\n" + " movq 16(%%edx),%%mm2;\n" + " movq 24(%%edx),%%mm3;\n" + " movq 32(%%edx),%%mm4;\n" + " movq 40(%%edx),%%mm5;\n" + " movq 48(%%edx),%%mm6;\n" + " movq 56(%%edx),%%mm7;\n" + " jmp 1f;\n" + " .align 32;\n" + " 1: ;\n" + " prefetch (%%eax);\n" + " movq %%mm3,%%mm1;\n" + " movq %%mm2,%%mm0;\n" + " movq %%mm5,%%mm3;\n" + " movq %%mm4,%%mm2;\n" + " pfmul %%mm7,%%mm5;\n" + " pfmul %%mm6,%%mm4;\n" + " pfsub %%mm1,%%mm5;\n" + " pfsub %%mm0,%%mm4;\n" + " movq (%%eax),%%mm0;\n" + " movq %%mm0,%%mm1;\n" + " punpckldq %%mm0,%%mm1;\n" + " add $4,%%eax;\n" + " pfadd %%mm1,%%mm5;\n" + " pfadd %%mm1,%%mm4;\n" + " dec %%ecx;\n" + " jnz 1b;\n" + " movq %%mm2,16(%%edx);\n" + " movq %%mm3,24(%%edx);\n" + " movq %%mm4,32(%%edx);\n" + " movq %%mm5,40(%%edx);\n" + " femms;\n"::"c" (samples), "a" (x), "d" (vv) + :"memory", "eax", "ecx"); + + s[0].v2 = vv[4]; + s[1].v2 = vv[5]; + s[2].v2 = vv[6]; + s[3].v2 = vv[7]; + s[0].v3 = vv[8]; + s[1].v3 = vv[9]; + s[2].v3 = vv[10]; + s[3].v3 = vv[11]; } #endif /*- End of function --------------------------------------------------------*/ -void zap_goertzel_update(goertzel_state_t *s, - int16_t x[], - int samples) +void +zap_goertzel_update (goertzel_state_t * s, int16_t x[], int samples) { - int i; - float v1; - - for (i = 0; i < samples; i++) - { - v1 = s->v2; - s->v2 = s->v3; - s->v3 = s->fac*s->v2 - v1 + x[i]; - } + int i; + float v1; + + for (i = 0; i < samples; i++) { + v1 = s->v2; + s->v2 = s->v3; + s->v3 = s->fac * s->v2 - v1 + x[i]; + } } + /*- End of function --------------------------------------------------------*/ -float zap_goertzel_result (goertzel_state_t *s) +float +zap_goertzel_result (goertzel_state_t * s) { - return s->v3*s->v3 + s->v2*s->v2 - s->v2*s->v3*s->fac; + return s->v3 * s->v3 + s->v2 * s->v2 - s->v2 * s->v3 * s->fac; } + /*- End of function --------------------------------------------------------*/ -void zap_dtmf_detect_init (dtmf_detect_state_t *s) +void +zap_dtmf_detect_init (dtmf_detect_state_t * s) { - int i; - float theta; - - s->hit1 = - s->hit2 = 0; - - for (i = 0; i < 4; i++) - { - theta = 2.0*M_PI*(dtmf_row[i]/SAMPLE_RATE); - dtmf_detect_row[i].fac = 2.0*cos(theta); - - theta = 2.0*M_PI*(dtmf_col[i]/SAMPLE_RATE); - dtmf_detect_col[i].fac = 2.0*cos(theta); - - theta = 2.0*M_PI*(dtmf_row[i]*2.0/SAMPLE_RATE); - dtmf_detect_row_2nd[i].fac = 2.0*cos(theta); - - theta = 2.0*M_PI*(dtmf_col[i]*2.0/SAMPLE_RATE); - dtmf_detect_col_2nd[i].fac = 2.0*cos(theta); - - goertzel_init (&s->row_out[i], &dtmf_detect_row[i]); - goertzel_init (&s->col_out[i], &dtmf_detect_col[i]); - goertzel_init (&s->row_out2nd[i], &dtmf_detect_row_2nd[i]); - goertzel_init (&s->col_out2nd[i], &dtmf_detect_col_2nd[i]); - - s->energy = 0.0; - } + int i; + float theta; - /* Same for the fax dector */ - theta = 2.0*M_PI*(fax_freq/SAMPLE_RATE); - fax_detect.fac = 2.0 * cos(theta); - goertzel_init (&s->fax_tone, &fax_detect); + s->hit1 = s->hit2 = 0; - /* Same for the fax dector 2nd harmonic */ - theta = 2.0*M_PI*(fax_freq * 2.0/SAMPLE_RATE); - fax_detect_2nd.fac = 2.0 * cos(theta); - goertzel_init (&s->fax_tone2nd, &fax_detect_2nd); - - s->current_sample = 0; - s->detected_digits = 0; - s->lost_digits = 0; - s->digits[0] = '\0'; - s->mhit = 0; + for (i = 0; i < 4; i++) { + theta = 2.0 * G_PI * (dtmf_row[i] / SAMPLE_RATE); + dtmf_detect_row[i].fac = 2.0 * cos (theta); + + theta = 2.0 * G_PI * (dtmf_col[i] / SAMPLE_RATE); + dtmf_detect_col[i].fac = 2.0 * cos (theta); + + theta = 2.0 * G_PI * (dtmf_row[i] * 2.0 / SAMPLE_RATE); + dtmf_detect_row_2nd[i].fac = 2.0 * cos (theta); + + theta = 2.0 * G_PI * (dtmf_col[i] * 2.0 / SAMPLE_RATE); + dtmf_detect_col_2nd[i].fac = 2.0 * cos (theta); + + goertzel_init (&s->row_out[i], &dtmf_detect_row[i]); + goertzel_init (&s->col_out[i], &dtmf_detect_col[i]); + goertzel_init (&s->row_out2nd[i], &dtmf_detect_row_2nd[i]); + goertzel_init (&s->col_out2nd[i], &dtmf_detect_col_2nd[i]); + + s->energy = 0.0; + } + + /* Same for the fax dector */ + theta = 2.0 * G_PI * (fax_freq / SAMPLE_RATE); + fax_detect.fac = 2.0 * cos (theta); + goertzel_init (&s->fax_tone, &fax_detect); + + /* Same for the fax dector 2nd harmonic */ + theta = 2.0 * G_PI * (fax_freq * 2.0 / SAMPLE_RATE); + fax_detect_2nd.fac = 2.0 * cos (theta); + goertzel_init (&s->fax_tone2nd, &fax_detect_2nd); + + s->current_sample = 0; + s->detected_digits = 0; + s->lost_digits = 0; + s->digits[0] = '\0'; + s->mhit = 0; } + /*- End of function --------------------------------------------------------*/ -int zap_dtmf_detect (dtmf_detect_state_t *s, - int16_t amp[], - int samples, - int isradio) +int +zap_dtmf_detect (dtmf_detect_state_t * s, + int16_t amp[], int samples, int isradio) { - float row_energy[4]; - float col_energy[4]; - float fax_energy; - float fax_energy_2nd; - float famp; - float v1; - int i; - int j; - int sample; - int best_row; - int best_col; - int hit; - int limit; - - hit = 0; - for (sample = 0; sample < samples; sample = limit) - { - /* 102 is optimised to meet the DTMF specs. */ - if ((samples - sample) >= (102 - s->current_sample)) - limit = sample + (102 - s->current_sample); - else - limit = samples; + float row_energy[4]; + float col_energy[4]; + float fax_energy; + float fax_energy_2nd; + float famp; + float v1; + int i; + int j; + int sample; + int best_row; + int best_col; + int hit; + int limit; + + hit = 0; + for (sample = 0; sample < samples; sample = limit) { + /* 102 is optimised to meet the DTMF specs. */ + if ((samples - sample) >= (102 - s->current_sample)) + limit = sample + (102 - s->current_sample); + else + limit = samples; #if defined(USE_3DNOW) - _dtmf_goertzel_update (s->row_out, amp + sample, limit - sample); - _dtmf_goertzel_update (s->col_out, amp + sample, limit - sample); - _dtmf_goertzel_update (s->row_out2nd, amp + sample, limit2 - sample); - _dtmf_goertzel_update (s->col_out2nd, amp + sample, limit2 - sample); - /* XXX Need to fax detect for 3dnow too XXX */ - #warning "Fax Support Broken" + _dtmf_goertzel_update (s->row_out, amp + sample, limit - sample); + _dtmf_goertzel_update (s->col_out, amp + sample, limit - sample); + _dtmf_goertzel_update (s->row_out2nd, amp + sample, limit2 - sample); + _dtmf_goertzel_update (s->col_out2nd, amp + sample, limit2 - sample); + /* XXX Need to fax detect for 3dnow too XXX */ +#warning "Fax Support Broken" #else - /* The following unrolled loop takes only 35% (rough estimate) of the - time of a rolled loop on the machine on which it was developed */ - for (j = sample; j < limit; j++) - { - famp = amp[j]; - - s->energy += famp*famp; - - /* With GCC 2.95, the following unrolled code seems to take about 35% - (rough estimate) as long as a neat little 0-3 loop */ - v1 = s->row_out[0].v2; - s->row_out[0].v2 = s->row_out[0].v3; - s->row_out[0].v3 = s->row_out[0].fac*s->row_out[0].v2 - v1 + famp; - - v1 = s->col_out[0].v2; - s->col_out[0].v2 = s->col_out[0].v3; - s->col_out[0].v3 = s->col_out[0].fac*s->col_out[0].v2 - v1 + famp; - - v1 = s->row_out[1].v2; - s->row_out[1].v2 = s->row_out[1].v3; - s->row_out[1].v3 = s->row_out[1].fac*s->row_out[1].v2 - v1 + famp; - - v1 = s->col_out[1].v2; - s->col_out[1].v2 = s->col_out[1].v3; - s->col_out[1].v3 = s->col_out[1].fac*s->col_out[1].v2 - v1 + famp; - - v1 = s->row_out[2].v2; - s->row_out[2].v2 = s->row_out[2].v3; - s->row_out[2].v3 = s->row_out[2].fac*s->row_out[2].v2 - v1 + famp; - - v1 = s->col_out[2].v2; - s->col_out[2].v2 = s->col_out[2].v3; - s->col_out[2].v3 = s->col_out[2].fac*s->col_out[2].v2 - v1 + famp; - - v1 = s->row_out[3].v2; - s->row_out[3].v2 = s->row_out[3].v3; - s->row_out[3].v3 = s->row_out[3].fac*s->row_out[3].v2 - v1 + famp; - - v1 = s->col_out[3].v2; - s->col_out[3].v2 = s->col_out[3].v3; - s->col_out[3].v3 = s->col_out[3].fac*s->col_out[3].v2 - v1 + famp; - - v1 = s->col_out2nd[0].v2; - s->col_out2nd[0].v2 = s->col_out2nd[0].v3; - s->col_out2nd[0].v3 = s->col_out2nd[0].fac*s->col_out2nd[0].v2 - v1 + famp; - - v1 = s->row_out2nd[0].v2; - s->row_out2nd[0].v2 = s->row_out2nd[0].v3; - s->row_out2nd[0].v3 = s->row_out2nd[0].fac*s->row_out2nd[0].v2 - v1 + famp; - - v1 = s->col_out2nd[1].v2; - s->col_out2nd[1].v2 = s->col_out2nd[1].v3; - s->col_out2nd[1].v3 = s->col_out2nd[1].fac*s->col_out2nd[1].v2 - v1 + famp; - - v1 = s->row_out2nd[1].v2; - s->row_out2nd[1].v2 = s->row_out2nd[1].v3; - s->row_out2nd[1].v3 = s->row_out2nd[1].fac*s->row_out2nd[1].v2 - v1 + famp; - - v1 = s->col_out2nd[2].v2; - s->col_out2nd[2].v2 = s->col_out2nd[2].v3; - s->col_out2nd[2].v3 = s->col_out2nd[2].fac*s->col_out2nd[2].v2 - v1 + famp; - - v1 = s->row_out2nd[2].v2; - s->row_out2nd[2].v2 = s->row_out2nd[2].v3; - s->row_out2nd[2].v3 = s->row_out2nd[2].fac*s->row_out2nd[2].v2 - v1 + famp; - - v1 = s->col_out2nd[3].v2; - s->col_out2nd[3].v2 = s->col_out2nd[3].v3; - s->col_out2nd[3].v3 = s->col_out2nd[3].fac*s->col_out2nd[3].v2 - v1 + famp; - - v1 = s->row_out2nd[3].v2; - s->row_out2nd[3].v2 = s->row_out2nd[3].v3; - s->row_out2nd[3].v3 = s->row_out2nd[3].fac*s->row_out2nd[3].v2 - v1 + famp; - - /* Update fax tone */ - v1 = s->fax_tone.v2; - s->fax_tone.v2 = s->fax_tone.v3; - s->fax_tone.v3 = s->fax_tone.fac*s->fax_tone.v2 - v1 + famp; - - v1 = s->fax_tone.v2; - s->fax_tone2nd.v2 = s->fax_tone2nd.v3; - s->fax_tone2nd.v3 = s->fax_tone2nd.fac*s->fax_tone2nd.v2 - v1 + famp; - } + /* The following unrolled loop takes only 35% (rough estimate) of the + time of a rolled loop on the machine on which it was developed */ + for (j = sample; j < limit; j++) { + famp = amp[j]; + + s->energy += famp * famp; + + /* With GCC 2.95, the following unrolled code seems to take about 35% + (rough estimate) as long as a neat little 0-3 loop */ + v1 = s->row_out[0].v2; + s->row_out[0].v2 = s->row_out[0].v3; + s->row_out[0].v3 = s->row_out[0].fac * s->row_out[0].v2 - v1 + famp; + + v1 = s->col_out[0].v2; + s->col_out[0].v2 = s->col_out[0].v3; + s->col_out[0].v3 = s->col_out[0].fac * s->col_out[0].v2 - v1 + famp; + + v1 = s->row_out[1].v2; + s->row_out[1].v2 = s->row_out[1].v3; + s->row_out[1].v3 = s->row_out[1].fac * s->row_out[1].v2 - v1 + famp; + + v1 = s->col_out[1].v2; + s->col_out[1].v2 = s->col_out[1].v3; + s->col_out[1].v3 = s->col_out[1].fac * s->col_out[1].v2 - v1 + famp; + + v1 = s->row_out[2].v2; + s->row_out[2].v2 = s->row_out[2].v3; + s->row_out[2].v3 = s->row_out[2].fac * s->row_out[2].v2 - v1 + famp; + + v1 = s->col_out[2].v2; + s->col_out[2].v2 = s->col_out[2].v3; + s->col_out[2].v3 = s->col_out[2].fac * s->col_out[2].v2 - v1 + famp; + + v1 = s->row_out[3].v2; + s->row_out[3].v2 = s->row_out[3].v3; + s->row_out[3].v3 = s->row_out[3].fac * s->row_out[3].v2 - v1 + famp; + + v1 = s->col_out[3].v2; + s->col_out[3].v2 = s->col_out[3].v3; + s->col_out[3].v3 = s->col_out[3].fac * s->col_out[3].v2 - v1 + famp; + + v1 = s->col_out2nd[0].v2; + s->col_out2nd[0].v2 = s->col_out2nd[0].v3; + s->col_out2nd[0].v3 = + s->col_out2nd[0].fac * s->col_out2nd[0].v2 - v1 + famp; + + v1 = s->row_out2nd[0].v2; + s->row_out2nd[0].v2 = s->row_out2nd[0].v3; + s->row_out2nd[0].v3 = + s->row_out2nd[0].fac * s->row_out2nd[0].v2 - v1 + famp; + + v1 = s->col_out2nd[1].v2; + s->col_out2nd[1].v2 = s->col_out2nd[1].v3; + s->col_out2nd[1].v3 = + s->col_out2nd[1].fac * s->col_out2nd[1].v2 - v1 + famp; + + v1 = s->row_out2nd[1].v2; + s->row_out2nd[1].v2 = s->row_out2nd[1].v3; + s->row_out2nd[1].v3 = + s->row_out2nd[1].fac * s->row_out2nd[1].v2 - v1 + famp; + + v1 = s->col_out2nd[2].v2; + s->col_out2nd[2].v2 = s->col_out2nd[2].v3; + s->col_out2nd[2].v3 = + s->col_out2nd[2].fac * s->col_out2nd[2].v2 - v1 + famp; + + v1 = s->row_out2nd[2].v2; + s->row_out2nd[2].v2 = s->row_out2nd[2].v3; + s->row_out2nd[2].v3 = + s->row_out2nd[2].fac * s->row_out2nd[2].v2 - v1 + famp; + + v1 = s->col_out2nd[3].v2; + s->col_out2nd[3].v2 = s->col_out2nd[3].v3; + s->col_out2nd[3].v3 = + s->col_out2nd[3].fac * s->col_out2nd[3].v2 - v1 + famp; + + v1 = s->row_out2nd[3].v2; + s->row_out2nd[3].v2 = s->row_out2nd[3].v3; + s->row_out2nd[3].v3 = + s->row_out2nd[3].fac * s->row_out2nd[3].v2 - v1 + famp; + + /* Update fax tone */ + v1 = s->fax_tone.v2; + s->fax_tone.v2 = s->fax_tone.v3; + s->fax_tone.v3 = s->fax_tone.fac * s->fax_tone.v2 - v1 + famp; + + v1 = s->fax_tone.v2; + s->fax_tone2nd.v2 = s->fax_tone2nd.v3; + s->fax_tone2nd.v3 = s->fax_tone2nd.fac * s->fax_tone2nd.v2 - v1 + famp; + } #endif - s->current_sample += (limit - sample); - if (s->current_sample < 102) - continue; - - /* Detect the fax energy, too */ - fax_energy = zap_goertzel_result(&s->fax_tone); - - /* We are at the end of a DTMF detection block */ - /* Find the peak row and the peak column */ - row_energy[0] = zap_goertzel_result (&s->row_out[0]); - col_energy[0] = zap_goertzel_result (&s->col_out[0]); - - for (best_row = best_col = 0, i = 1; i < 4; i++) - { - row_energy[i] = zap_goertzel_result (&s->row_out[i]); - if (row_energy[i] > row_energy[best_row]) - best_row = i; - col_energy[i] = zap_goertzel_result (&s->col_out[i]); - if (col_energy[i] > col_energy[best_col]) - best_col = i; - } - hit = 0; - /* Basic signal level test and the twist test */ - if (row_energy[best_row] >= DTMF_THRESHOLD - && - col_energy[best_col] >= DTMF_THRESHOLD - && - col_energy[best_col] < row_energy[best_row]*DTMF_REVERSE_TWIST - && - col_energy[best_col]*DTMF_NORMAL_TWIST > row_energy[best_row]) - { - /* Relative peak test */ - for (i = 0; i < 4; i++) - { - if ((i != best_col && col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) - || - (i != best_row && row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) - { - break; - } - } - /* ... and second harmonic test */ - if (i >= 4 - && - (row_energy[best_row] + col_energy[best_col]) > 42.0*s->energy - && - zap_goertzel_result (&s->col_out2nd[best_col])*DTMF_2ND_HARMONIC_COL < col_energy[best_col] - && - zap_goertzel_result (&s->row_out2nd[best_row])*DTMF_2ND_HARMONIC_ROW < row_energy[best_row]) - { - hit = dtmf_positions[(best_row << 2) + best_col]; - /* Look for two successive similar results */ - /* The logic in the next test is: - We need two successive identical clean detects, with - something different preceeding it. This can work with - back to back differing digits. More importantly, it - can work with nasty phones that give a very wobbly start - to a digit. */ - if (hit == s->hit3 && s->hit3 != s->hit2) - { - s->mhit = hit; - s->digit_hits[(best_row << 2) + best_col]++; - s->detected_digits++; - if (s->current_digits < MAX_DTMF_DIGITS) - { - s->digits[s->current_digits++] = hit; - s->digits[s->current_digits] = '\0'; - } - else - { - s->lost_digits++; - } - } - } - } - if (!hit && (fax_energy >= FAX_THRESHOLD) && (fax_energy > s->energy * 21.0)) { - fax_energy_2nd = zap_goertzel_result(&s->fax_tone2nd); - if (fax_energy_2nd * FAX_2ND_HARMONIC < fax_energy) { + s->current_sample += (limit - sample); + if (s->current_sample < 102) + continue; + + /* Detect the fax energy, too */ + fax_energy = zap_goertzel_result (&s->fax_tone); + + /* We are at the end of a DTMF detection block */ + /* Find the peak row and the peak column */ + row_energy[0] = zap_goertzel_result (&s->row_out[0]); + col_energy[0] = zap_goertzel_result (&s->col_out[0]); + + for (best_row = best_col = 0, i = 1; i < 4; i++) { + row_energy[i] = zap_goertzel_result (&s->row_out[i]); + if (row_energy[i] > row_energy[best_row]) + best_row = i; + col_energy[i] = zap_goertzel_result (&s->col_out[i]); + if (col_energy[i] > col_energy[best_col]) + best_col = i; + } + hit = 0; + /* Basic signal level test and the twist test */ + if (row_energy[best_row] >= DTMF_THRESHOLD + && + col_energy[best_col] >= DTMF_THRESHOLD + && + col_energy[best_col] < row_energy[best_row] * DTMF_REVERSE_TWIST + && col_energy[best_col] * DTMF_NORMAL_TWIST > row_energy[best_row]) { + /* Relative peak test */ + for (i = 0; i < 4; i++) { + if ((i != best_col + && col_energy[i] * DTMF_RELATIVE_PEAK_COL > + col_energy[best_col]) + || (i != best_row + && row_energy[i] * DTMF_RELATIVE_PEAK_ROW > + row_energy[best_row])) { + break; + } + } + /* ... and second harmonic test */ + if (i >= 4 + && + (row_energy[best_row] + col_energy[best_col]) > 42.0 * s->energy + && + zap_goertzel_result (&s->col_out2nd[best_col]) * + DTMF_2ND_HARMONIC_COL < col_energy[best_col] + && zap_goertzel_result (&s->row_out2nd[best_row]) * + DTMF_2ND_HARMONIC_ROW < row_energy[best_row]) { + hit = dtmf_positions[(best_row << 2) + best_col]; + /* Look for two successive similar results */ + /* The logic in the next test is: + We need two successive identical clean detects, with + something different preceeding it. This can work with + back to back differing digits. More importantly, it + can work with nasty phones that give a very wobbly start + to a digit. */ + if (hit == s->hit3 && s->hit3 != s->hit2) { + s->mhit = hit; + s->digit_hits[(best_row << 2) + best_col]++; + s->detected_digits++; + if (s->current_digits < MAX_DTMF_DIGITS) { + s->digits[s->current_digits++] = hit; + s->digits[s->current_digits] = '\0'; + } else { + s->lost_digits++; + } + } + } + } + if (!hit && (fax_energy >= FAX_THRESHOLD) + && (fax_energy > s->energy * 21.0)) { + fax_energy_2nd = zap_goertzel_result (&s->fax_tone2nd); + if (fax_energy_2nd * FAX_2ND_HARMONIC < fax_energy) { #if 0 - printf("Fax energy/Second Harmonic: %f/%f\n", fax_energy, fax_energy_2nd); -#endif - /* XXX Probably need better checking than just this the energy XXX */ - hit = 'f'; - s->fax_hits++; - } /* Don't reset fax hits counter */ - } else { - if (s->fax_hits > 5) { - s->mhit = 'f'; - s->detected_digits++; - if (s->current_digits < MAX_DTMF_DIGITS) - { - s->digits[s->current_digits++] = hit; - s->digits[s->current_digits] = '\0'; - } - else - { - s->lost_digits++; - } - } - s->fax_hits = 0; - } - s->hit1 = s->hit2; - s->hit2 = s->hit3; - s->hit3 = hit; - /* Reinitialise the detector for the next block */ - for (i = 0; i < 4; i++) - { - goertzel_init (&s->row_out[i], &dtmf_detect_row[i]); - goertzel_init (&s->col_out[i], &dtmf_detect_col[i]); - goertzel_init (&s->row_out2nd[i], &dtmf_detect_row_2nd[i]); - goertzel_init (&s->col_out2nd[i], &dtmf_detect_col_2nd[i]); + printf ("Fax energy/Second Harmonic: %f/%f\n", fax_energy, + fax_energy_2nd); +#endif + /* XXX Probably need better checking than just this the energy XXX */ + hit = 'f'; + s->fax_hits++; + } /* Don't reset fax hits counter */ + } else { + if (s->fax_hits > 5) { + s->mhit = 'f'; + s->detected_digits++; + if (s->current_digits < MAX_DTMF_DIGITS) { + s->digits[s->current_digits++] = hit; + s->digits[s->current_digits] = '\0'; + } else { + s->lost_digits++; } - goertzel_init (&s->fax_tone, &fax_detect); - goertzel_init (&s->fax_tone2nd, &fax_detect_2nd); - s->energy = 0.0; - s->current_sample = 0; + } + s->fax_hits = 0; } - if ((!s->mhit) || (s->mhit != hit)) - { - s->mhit = 0; - return(0); + s->hit1 = s->hit2; + s->hit2 = s->hit3; + s->hit3 = hit; + /* Reinitialise the detector for the next block */ + for (i = 0; i < 4; i++) { + goertzel_init (&s->row_out[i], &dtmf_detect_row[i]); + goertzel_init (&s->col_out[i], &dtmf_detect_col[i]); + goertzel_init (&s->row_out2nd[i], &dtmf_detect_row_2nd[i]); + goertzel_init (&s->col_out2nd[i], &dtmf_detect_col_2nd[i]); } - return (hit); + goertzel_init (&s->fax_tone, &fax_detect); + goertzel_init (&s->fax_tone2nd, &fax_detect_2nd); + s->energy = 0.0; + s->current_sample = 0; + } + if ((!s->mhit) || (s->mhit != hit)) { + s->mhit = 0; + return (0); + } + return (hit); } + /*- End of function --------------------------------------------------------*/ -int zap_dtmf_get (dtmf_detect_state_t *s, - char *buf, - int max) +int +zap_dtmf_get (dtmf_detect_state_t * s, char *buf, int max) { - if (max > s->current_digits) - max = s->current_digits; - if (max > 0) - { - memcpy (buf, s->digits, max); - memmove (s->digits, s->digits + max, s->current_digits - max); - s->current_digits -= max; - } - buf[max] = '\0'; - return max; + if (max > s->current_digits) + max = s->current_digits; + if (max > 0) { + memcpy (buf, s->digits, max); + memmove (s->digits, s->digits + max, s->current_digits - max); + s->current_digits -= max; + } + buf[max] = '\0'; + return max; } + /*- End of function --------------------------------------------------------*/ /*- End of file ------------------------------------------------------------*/ diff --git a/gst/dtmf/tone_detect.h b/gst/dtmf/tone_detect.h index 909c5ef60..ce6dddd2c 100644 --- a/gst/dtmf/tone_detect.h +++ b/gst/dtmf/tone_detect.h @@ -35,6 +35,8 @@ #include "_stdint.h" +#include <glib.h> + typedef struct { float v2; @@ -75,13 +77,13 @@ typedef struct } tone_detection_descriptor_t; void zap_goertzel_update(goertzel_state_t *s, - int16_t x[], + gint16 x[], int samples); float zap_goertzel_result (goertzel_state_t *s); void zap_dtmf_detect_init (dtmf_detect_state_t *s); int zap_dtmf_detect (dtmf_detect_state_t *s, - int16_t amp[], + gint16 amp[], int samples, int isradio); int zap_dtmf_get (dtmf_detect_state_t *s, diff --git a/gst/dvbsuboverlay/Makefile.am b/gst/dvbsuboverlay/Makefile.am new file mode 100644 index 000000000..531685e04 --- /dev/null +++ b/gst/dvbsuboverlay/Makefile.am @@ -0,0 +1,10 @@ +plugin_LTLIBRARIES = libgstdvbsuboverlay.la + +libgstdvbsuboverlay_la_SOURCES = dvb-sub.c gstdvbsuboverlay.c + +libgstdvbsuboverlay_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) +libgstdvbsuboverlay_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-@GST_MAJORMINOR@ $(GST_LIBS) +libgstdvbsuboverlay_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstdvbsuboverlay_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = gstdvbsuboverlay.h dvb-sub.h diff --git a/gst/dvbsuboverlay/TODO b/gst/dvbsuboverlay/TODO new file mode 100644 index 000000000..cf1c45cca --- /dev/null +++ b/gst/dvbsuboverlay/TODO @@ -0,0 +1,10 @@ +Check about GST_PAD_PARENT vs gst_pad_get_parent - do we need a reference - is there any danger of losing the parent in the middle or not: +<thaytan> one uses GST_PAD_PARENT in situations where you can be sure the parent exists and will exist for the entire time you need it +<thaytan> and gst_pad_get_parent when you need a ref because the pad might get unparented while you're using it + +Ask about individual segment handling on separate sink pads. Is it possible that the separate NEWSEGMENT events on the text and video pad have different start and/or stop values, as to require some code complexity present? + +- parse incoming buffers into complete packets (first buffer of a packet should + have a timestamp set), and get rid of the gstmpegtsdemux hack + +- implement blitting/overlay for at least I420 diff --git a/gst/dvbsuboverlay/dvb-sub.c b/gst/dvbsuboverlay/dvb-sub.c new file mode 100644 index 000000000..a0ef3e151 --- /dev/null +++ b/gst/dvbsuboverlay/dvb-sub.c @@ -0,0 +1,1491 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ +/* + * libdvbsub - DVB subtitle decoding + * Copyright (C) Mart Raudsepp 2009 <mart.raudsepp@artecdesign.ee> + * + * Heavily uses code algorithms ported from ffmpeg's libavcodec/dvbsubdec.c, + * especially the segment parsers. The original license applies to this + * ported code and the whole code in this file as well. + * + * Original copyright information follows: + */ +/* + * DVB subtitle decoding for ffmpeg + * Copyright (c) 2005 Ian Caulfield + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <string.h> /* memset */ +#include <gst/gstutils.h> /* GST_READ_UINT16_BE */ +#include <gst/base/gstbitreader.h> /* GstBitReader */ + +#include "dvb-sub.h" + +GST_DEBUG_CATEGORY_STATIC (dvbsub_debug); +#define GST_CAT_DEFAULT dvbsub_debug + +static void dvb_sub_init (void); + +/* FIXME: Are we waiting for an acquisition point before trying to do things? */ +/* FIXME: In the end convert some of the guint8/16 (especially stack variables) back to gint for access efficiency */ + +/** + * SECTION:dvb-sub + * @short_description: a DVB subtitle parsing class + * @stability: Unstable + * + * The #DvbSub represents an object used for parsing a DVB subpicture, + * and signalling the API user for new bitmaps to show on screen. + */ + +#define AYUV(y,u,v,a) (((a) << 24) | ((y) << 16) | ((u) << 8) | (v)) +#define RGBA_TO_AYUV(r,g,b,a) (((a) << 24) | ((rgb_to_y(r,g,b)) << 16) | ((rgb_to_u(r,g,b)) << 8) | (rgb_to_v(r,g,b))) + + +typedef struct DVBSubCLUT +{ + int id; /* default_clut uses -1 for this, so guint8 isn't fine without adaptations first */ + + guint32 clut4[4]; + guint32 clut16[16]; + guint32 clut256[256]; + + struct DVBSubCLUT *next; +} DVBSubCLUT; + +static DVBSubCLUT default_clut; + +typedef struct DVBSubObjectDisplay +{ + /* FIXME: Use more correct sizes */ + int object_id; + int region_id; + + int x_pos; + int y_pos; + + int fgcolor; + int bgcolor; + + /* FIXME: Should we use GSList? The relating interaction and pointer assigment is quite complex and perhaps unsuited for a plain GSList anyway */ + struct DVBSubObjectDisplay *region_list_next; + struct DVBSubObjectDisplay *object_list_next; +} DVBSubObjectDisplay; + +typedef struct DVBSubObject +{ + /* FIXME: Use more correct sizes */ + int id; /* FIXME: Use guint8 after checking it's fine in all code using it */ + + int type; + + /* FIXME: Should we use GSList? */ + DVBSubObjectDisplay *display_list; + struct DVBSubObject *next; +} DVBSubObject; + +typedef struct DVBSubRegionDisplay +{ /* FIXME: Figure out if this structure is only used temporarily in page_segment parser, or also more */ + int region_id; + + int x_pos; + int y_pos; + + struct DVBSubRegionDisplay *next; +} DVBSubRegionDisplay; + +typedef struct DVBSubRegion +{ + guint8 id; + guint16 width; + guint16 height; + guint8 depth; /* If we want to make this a guint8, then need to ensure it isn't wrap around with reserved values in region handling code */ + + guint8 clut; + guint8 bgcolor; + + /* FIXME: Validate these fields existence and exact types */ + guint8 *pbuf; + int buf_size; + + DVBSubObjectDisplay *display_list; + + struct DVBSubRegion *next; +} DVBSubRegion; + +struct _DvbSub +{ + DvbSubCallbacks callbacks; + gpointer user_data; + + guint8 page_time_out; + DVBSubRegion *region_list; + DVBSubCLUT *clut_list; + DVBSubObject *object_list; + /* FIXME... */ + int display_list_size; + DVBSubRegionDisplay *display_list; + GString *pes_buffer; + DVBSubtitleWindow display_def; +}; + +typedef enum +{ + TOP_FIELD = 0, + BOTTOM_FIELD = 1 +} DvbSubPixelDataSubBlockFieldType; + +static inline gint +rgb_to_y (gint r, gint g, gint b) +{ + gint ret; + + ret = (gint) (((19595 * r) >> 16) + ((38470 * g) >> 16) + ((7471 * b) >> 16)); + ret = CLAMP (ret, 0, 255); + return ret; +} + +static inline gint +rgb_to_u (gint r, gint g, gint b) +{ + gint ret; + + ret = + (gint) (-((11059 * r) >> 16) - ((21709 * g) >> 16) + ((32768 * b) >> 16) + + 128); + ret = CLAMP (ret, 0, 255); + return ret; +} + +static inline gint +rgb_to_v (gint r, gint g, gint b) +{ + gint ret; + + ret = + (gint) (((32768 * r) >> 16) - ((27439 * g) >> 16) - ((5329 * b) >> 16) + + 128); + ret = CLAMP (ret, 0, 255); + return ret; +} + +static DVBSubObject * +get_object (DvbSub * dvb_sub, guint16 object_id) +{ + DVBSubObject *ptr = dvb_sub->object_list; + + while (ptr && ptr->id != object_id) { + ptr = ptr->next; + } + + return ptr; +} + +static DVBSubCLUT * +get_clut (DvbSub * dvb_sub, gint clut_id) +{ + DVBSubCLUT *ptr = dvb_sub->clut_list; + + while (ptr && ptr->id != clut_id) { + ptr = ptr->next; + } + + return ptr; +} + +static DVBSubRegion * +get_region (DvbSub * dvb_sub, guint8 region_id) +{ + DVBSubRegion *ptr = dvb_sub->region_list; + + while (ptr && ptr->id != region_id) { + ptr = ptr->next; + } + + return ptr; +} + +static void +delete_region_display_list (DvbSub * dvb_sub, DVBSubRegion * region) +{ + DVBSubObject *object, *obj2; + DVBSubObject **obj2_ptr; + DVBSubObjectDisplay *display, *obj_disp, **obj_disp_ptr; + + while (region->display_list) { + display = region->display_list; + + object = get_object (dvb_sub, display->object_id); + + if (object) { + obj_disp_ptr = &object->display_list; + obj_disp = *obj_disp_ptr; + + while (obj_disp && obj_disp != display) { + obj_disp_ptr = &obj_disp->object_list_next; + obj_disp = *obj_disp_ptr; + } + + if (obj_disp) { + *obj_disp_ptr = obj_disp->object_list_next; + + if (!object->display_list) { + obj2_ptr = (DVBSubObject **) & dvb_sub->object_list; /* FIXME: Evil casting */ + obj2 = *obj2_ptr; + + while (obj2 != object) { + g_assert (obj2); + obj2_ptr = &obj2->next; + obj2 = *obj2_ptr; + } + + *obj2_ptr = obj2->next; + + g_slice_free (DVBSubObject, obj2); + } + } + } + + region->display_list = display->region_list_next; + + g_slice_free (DVBSubObjectDisplay, display); + } +} + +static void +delete_state (DvbSub * dvb_sub) +{ + DVBSubRegion *region; + + while (dvb_sub->region_list) { + region = dvb_sub->region_list; + + dvb_sub->region_list = region->next; + + delete_region_display_list (dvb_sub, region); + if (region->pbuf) + g_free (region->pbuf); + + g_slice_free (DVBSubRegion, region); + } + + g_slice_free_chain (DVBSubCLUT, dvb_sub->clut_list, next); + dvb_sub->clut_list = NULL; + + /* Should already be NULL */ + g_warn_if_fail (dvb_sub->object_list == NULL); +} + +static void +dvb_sub_init (void) +{ + int i, r, g, b, a = 0; + + GST_DEBUG_CATEGORY_INIT (dvbsub_debug, "dvbsub", 0, "dvbsuboverlay parser"); + + /* Initialize the static default_clut structure, from which other clut + * structures are initialized from (to start off with default CLUTs + * as defined in the specification). */ + default_clut.id = -1; + + default_clut.clut4[0] = RGBA_TO_AYUV (0, 0, 0, 0); + default_clut.clut4[1] = RGBA_TO_AYUV (255, 255, 255, 255); + default_clut.clut4[2] = RGBA_TO_AYUV (0, 0, 0, 255); + default_clut.clut4[3] = RGBA_TO_AYUV (127, 127, 127, 255); + + default_clut.clut16[0] = RGBA_TO_AYUV (0, 0, 0, 0); + for (i = 1; i < 16; i++) { + if (i < 8) { + r = (i & 1) ? 255 : 0; + g = (i & 2) ? 255 : 0; + b = (i & 4) ? 255 : 0; + } else { + r = (i & 1) ? 127 : 0; + g = (i & 2) ? 127 : 0; + b = (i & 4) ? 127 : 0; + } + default_clut.clut16[i] = RGBA_TO_AYUV (r, g, b, 255); + } + + default_clut.clut256[0] = RGBA_TO_AYUV (0, 0, 0, 0); + for (i = 1; i < 256; i++) { + if (i < 8) { + r = (i & 1) ? 255 : 0; + g = (i & 2) ? 255 : 0; + b = (i & 4) ? 255 : 0; + a = 63; + } else { + switch (i & 0x88) { + case 0x00: + r = ((i & 1) ? 85 : 0) + ((i & 0x10) ? 170 : 0); + g = ((i & 2) ? 85 : 0) + ((i & 0x20) ? 170 : 0); + b = ((i & 4) ? 85 : 0) + ((i & 0x40) ? 170 : 0); + a = 255; + break; + case 0x08: + r = ((i & 1) ? 85 : 0) + ((i & 0x10) ? 170 : 0); + g = ((i & 2) ? 85 : 0) + ((i & 0x20) ? 170 : 0); + b = ((i & 4) ? 85 : 0) + ((i & 0x40) ? 170 : 0); + a = 127; + break; + case 0x80: + r = 127 + ((i & 1) ? 43 : 0) + ((i & 0x10) ? 85 : 0); + g = 127 + ((i & 2) ? 43 : 0) + ((i & 0x20) ? 85 : 0); + b = 127 + ((i & 4) ? 43 : 0) + ((i & 0x40) ? 85 : 0); + a = 255; + break; + case 0x88: + r = ((i & 1) ? 43 : 0) + ((i & 0x10) ? 85 : 0); + g = ((i & 2) ? 43 : 0) + ((i & 0x20) ? 85 : 0); + b = ((i & 4) ? 43 : 0) + ((i & 0x40) ? 85 : 0); + a = 255; + break; + } + } + default_clut.clut256[i] = RGBA_TO_AYUV (r, g, b, a); + } +} + +static void +_dvb_sub_parse_page_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf, + gint buf_size) +{ /* FIXME: Use guint for buf_size here and in many other places? */ + DVBSubRegionDisplay *display; + DVBSubRegionDisplay *tmp_display_list, **tmp_ptr; + + const guint8 *buf_end = buf + buf_size; + guint8 region_id; + guint8 page_state; + + if (buf_size < 1) + return; + + dvb_sub->page_time_out = *buf++; + page_state = ((*buf++) >> 2) & 3; + +#ifndef GST_DISABLE_GST_DEBUG + { + static const gchar *page_state_str[4] = { + "Normal case", "ACQUISITION POINT", "Mode Change", "RESERVED" + }; + + GST_DEBUG ("PAGE: page_id = %u, length = %d, page_time_out = %u secs, " + "page_state = %s", page_id, buf_size, dvb_sub->page_time_out, + page_state_str[page_state]); + } +#endif + + if (page_state == 2) { /* Mode change */ + delete_state (dvb_sub); + } + + tmp_display_list = dvb_sub->display_list; + dvb_sub->display_list = NULL; + dvb_sub->display_list_size = 0; + + while (buf + 5 < buf_end) { + region_id = *buf++; + buf += 1; + + display = tmp_display_list; + tmp_ptr = &tmp_display_list; + + while (display && display->region_id != region_id) { + tmp_ptr = &display->next; + display = display->next; + } + + if (!display) + display = g_slice_new0 (DVBSubRegionDisplay); + + display->region_id = region_id; + + display->x_pos = GST_READ_UINT16_BE (buf); + buf += 2; + display->y_pos = GST_READ_UINT16_BE (buf); + buf += 2; + + *tmp_ptr = display->next; + + display->next = dvb_sub->display_list; + dvb_sub->display_list = display; + dvb_sub->display_list_size++; + + GST_LOG ("PAGE: REGION information: ID = %u, address = %ux%u", region_id, + display->x_pos, display->y_pos); + } + + while (tmp_display_list) { + display = tmp_display_list; + + tmp_display_list = display->next; + + g_slice_free (DVBSubRegionDisplay, display); + } +} + +static void +_dvb_sub_parse_region_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf, + gint buf_size) +{ + const guint8 *buf_end = buf + buf_size; + guint8 region_id; + guint16 object_id; + DVBSubRegion *region; + DVBSubObject *object; + DVBSubObjectDisplay *object_display; + gboolean fill; + + if (buf_size < 10) + return; + + region_id = *buf++; + + region = get_region (dvb_sub, region_id); + + if (!region) { /* Create a new region */ + region = g_slice_new0 (DVBSubRegion); + region->id = region_id; + region->next = dvb_sub->region_list; + dvb_sub->region_list = region; + } + + fill = ((*buf++) >> 3) & 1; + + region->width = GST_READ_UINT16_BE (buf); + buf += 2; + region->height = GST_READ_UINT16_BE (buf); + buf += 2; + + if (region->width * region->height != region->buf_size) { /* FIXME: Read closer from spec what happens when dimensions change */ + if (region->pbuf) + g_free (region->pbuf); + + region->buf_size = region->width * region->height; + + region->pbuf = g_malloc (region->buf_size); /* TODO: We can probably use GSlice here if careful about freeing while buf_size still records the correct size */ + + fill = 1; /* FIXME: Validate from spec that fill is forced on (in the following codes context) when dimensions change */ + } + + region->depth = 1 << (((*buf++) >> 2) & 7); + if (region->depth < 2 || region->depth > 8) { + GST_WARNING ("region depth %d is invalid", region->depth); + region->depth = 4; /* FIXME: Check from spec this is the default? */ + } + + region->clut = *buf++; + + if (region->depth == 8) + region->bgcolor = *buf++; + else { + buf += 1; + + if (region->depth == 4) + region->bgcolor = (((*buf++) >> 4) & 15); + else + region->bgcolor = (((*buf++) >> 2) & 3); + } + + GST_DEBUG ("REGION: id = %u, (%ux%u)@%u-bit", region_id, region->width, + region->height, region->depth); + + if (fill) { + memset (region->pbuf, region->bgcolor, region->buf_size); + GST_DEBUG ("REGION: filling region (%u) with bgcolor = %u", region->id, + region->bgcolor); + } + + delete_region_display_list (dvb_sub, region); /* Delete the region display list for current region - FIXME: why? */ + + while (buf + 6 <= buf_end) { + object_id = GST_READ_UINT16_BE (buf); + buf += 2; + + object = get_object (dvb_sub, object_id); + + if (!object) { + object = g_slice_new0 (DVBSubObject); + + object->id = object_id; + + object->next = dvb_sub->object_list; + dvb_sub->object_list = object; + } + + object->type = (*buf) >> 6; + + object_display = g_slice_new0 (DVBSubObjectDisplay); + + object_display->object_id = object_id; + object_display->region_id = region_id; + + object_display->x_pos = GST_READ_UINT16_BE (buf) & 0xfff; + buf += 2; + object_display->y_pos = GST_READ_UINT16_BE (buf) & 0xfff; + buf += 2; + + if ((object->type == 1 || object->type == 2) && buf + 2 <= buf_end) { + object_display->fgcolor = *buf++; + object_display->bgcolor = *buf++; + } + + object_display->region_list_next = region->display_list; + region->display_list = object_display; + + object_display->object_list_next = object->display_list; + object->display_list = object_display; + + GST_DEBUG ("REGION DATA: object_id = %u, region_id = %u, pos = %ux%u, " + "obj_type = %u", object->id, region->id, object_display->x_pos, + object_display->y_pos, object->type); + + if (object->type == 1 || object->type == 2) { + GST_DEBUG ("REGION DATA: fgcolor = %u, bgcolor = %u", + object_display->fgcolor, object_display->bgcolor); + } + } +} + +static void +_dvb_sub_parse_clut_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf, + gint buf_size) +{ + const guint8 *buf_end = buf + buf_size; + guint8 clut_id; + DVBSubCLUT *clut; + int entry_id, depth, full_range; + int y, cr, cb, alpha; + + GST_MEMDUMP ("DVB clut packet", buf, buf_size); + + clut_id = *buf++; + buf += 1; + + clut = get_clut (dvb_sub, clut_id); + + if (!clut) { + clut = g_slice_new (DVBSubCLUT); + + memcpy (clut, &default_clut, sizeof (DVBSubCLUT)); + + clut->id = clut_id; + + clut->next = dvb_sub->clut_list; + dvb_sub->clut_list = clut; + } + + while (buf + 4 < buf_end) { + entry_id = *buf++; + + depth = (*buf) & 0xe0; + + if (depth == 0) { + GST_WARNING ("Invalid clut depth 0x%x!", *buf); + return; + } + + full_range = (*buf++) & 1; + + if (full_range) { + y = *buf++; + cr = *buf++; + cb = *buf++; + alpha = *buf++; + } else { + y = buf[0] & 0xfc; + cr = (((buf[0] & 3) << 2) | ((buf[1] >> 6) & 3)) << 4; + cb = (buf[1] << 2) & 0xf0; + alpha = (buf[1] << 6) & 0xc0; + + buf += 2; + } + + if (y == 0) + alpha = 0xff; + + GST_DEBUG ("CLUT DEFINITION: clut %d := (%d,%d,%d,%d)", entry_id, y, cb, cr, + alpha); + + if (depth & 0x80) + clut->clut4[entry_id] = AYUV (y, cb, cr, 255 - alpha); + if (depth & 0x40) + clut->clut16[entry_id] = AYUV (y, cb, cr, 255 - alpha); + if (depth & 0x20) + clut->clut256[entry_id] = AYUV (y, cb, cr, 255 - alpha); + } +} + +// FFMPEG-FIXME: The same code in ffmpeg is much more complex, it could use the same +// FFMPEG-FIXME: refactoring as done here +static int +_dvb_sub_read_2bit_string (guint8 * destbuf, gint dbuf_len, + const guint8 ** srcbuf, gint buf_size, guint8 non_mod, guint8 * map_table) +{ + GstBitReader gb = GST_BIT_READER_INIT (*srcbuf, buf_size); + /* FIXME: Handle FALSE returns from gst_bit_reader_get_* calls? */ + + gboolean stop_parsing = FALSE; + guint32 bits = 0; + guint32 pixels_read = 0; + + static gboolean warning_shown = FALSE; + if (!warning_shown) { + g_warning ("Parsing 2bit color DVB sub-picture. This is not tested at all. " + "If you see this message, please provide the developers with sample " + "media with these subtitles, if possible."); + warning_shown = TRUE; + } + + GST_TRACE ("dbuf_len = %d", dbuf_len); + + while (!stop_parsing && (gst_bit_reader_get_remaining (&gb) > 0)) { + guint run_length = 0, clut_index = 0; + gst_bit_reader_get_bits_uint32 (&gb, &bits, 2); + + if (bits) { /* 2-bit_pixel-code */ + run_length = 1; + clut_index = bits; + } else { /* 2-bit_zero */ + gst_bit_reader_get_bits_uint32 (&gb, &bits, 1); + if (bits == 1) { /* switch_1 == '1' */ + gst_bit_reader_get_bits_uint32 (&gb, &run_length, 3); + run_length += 3; + gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 2); + } else { /* switch_1 == '0' */ + gst_bit_reader_get_bits_uint32 (&gb, &bits, 1); + if (bits == 1) { /* switch_2 == '1' */ + run_length = 1; /* 1x pseudo-colour '00' */ + } else { /* switch_2 == '0' */ + gst_bit_reader_get_bits_uint32 (&gb, &bits, 2); + switch (bits) { /* switch_3 */ + case 0x0: /* end of 2-bit/pixel_code_string */ + stop_parsing = TRUE; + break; + case 0x1: /* two pixels shall be set to pseudo colour (entry) '00' */ + run_length = 2; + break; + case 0x2: /* the following 6 bits contain run length coded pixel data */ + gst_bit_reader_get_bits_uint32 (&gb, &run_length, 4); + run_length += 12; + gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 2); + break; + case 0x3: /* the following 10 bits contain run length coded pixel data */ + gst_bit_reader_get_bits_uint32 (&gb, &run_length, 8); + run_length += 29; + gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 2); + break; + } + } + } + } + + /* If run_length is zero, continue. Only case happening is when + * stop_parsing is TRUE too, so next cycle shouldn't run */ + if (run_length == 0) + continue; + + /* Trim the run_length to not go beyond the line end and consume + * it from remaining length of dest line */ + run_length = MIN (run_length, dbuf_len); + dbuf_len -= run_length; + + /* Make clut_index refer to the index into the desired bit depths + * CLUT definition table */ + if (map_table) + clut_index = map_table[clut_index]; /* now clut_index signifies the index into map_table dest */ + + /* Now we can simply memset run_length count of destination bytes + * to clut_index, but only if not non_modifying */ + GST_TRACE ("RUNLEN: setting %u pixels to color 0x%x in destination buffer, " + "dbuf_len left is %d pixels", run_length, clut_index, dbuf_len); + + if (!(non_mod == 1 && bits == 1)) + memset (destbuf, clut_index, run_length); + + destbuf += run_length; + pixels_read += run_length; + } + + // FIXME: Test skip_to_byte instead of adding 7 bits, once everything else is working good + //gst_bit_reader_skip_to_byte (&gb); + *srcbuf += (gst_bit_reader_get_pos (&gb) + 7) >> 3; + + GST_TRACE ("PIXEL: returning, read %u pixels", pixels_read); + // FIXME: Shouldn't need this variable if tracking things in the loop better + return pixels_read; +} + +// FFMPEG-FIXME: The same code in ffmpeg is much more complex, it could use the same +// FFMPEG-FIXME: refactoring as done here, explained in commit 895296c3 +static int +_dvb_sub_read_4bit_string (guint8 * destbuf, gint dbuf_len, + const guint8 ** srcbuf, gint buf_size, guint8 non_mod, guint8 * map_table) +{ + GstBitReader gb = GST_BIT_READER_INIT (*srcbuf, buf_size); + /* FIXME: Handle FALSE returns from gst_bit_reader_get_* calls? */ + gboolean stop_parsing = FALSE; + guint32 bits = 0; + guint32 pixels_read = 0; + + GST_TRACE ("RUNLEN: srcbuf position %p, buf_size = %d; destination buffer " + "size is %d @ %p", *srcbuf, buf_size, dbuf_len, destbuf); + + while (!stop_parsing && (gst_bit_reader_get_remaining (&gb) > 0)) { + guint run_length = 0, clut_index = 0; + gst_bit_reader_get_bits_uint32 (&gb, &bits, 4); + + if (bits) { + run_length = 1; + clut_index = bits; + } else { + gst_bit_reader_get_bits_uint32 (&gb, &bits, 1); + if (bits == 0) { /* switch_1 == '0' */ + gst_bit_reader_get_bits_uint32 (&gb, &run_length, 3); + if (!run_length) { + stop_parsing = TRUE; + } else { + run_length += 2; + } + } else { /* switch_1 == '1' */ + gst_bit_reader_get_bits_uint32 (&gb, &bits, 1); + if (bits == 0) { /* switch_2 == '0' */ + gst_bit_reader_get_bits_uint32 (&gb, &run_length, 2); + run_length += 4; + gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 4); + } else { /* switch_2 == '1' */ + gst_bit_reader_get_bits_uint32 (&gb, &bits, 2); + switch (bits) { + case 0x0: /* switch_3 == '00' */ + run_length = 1; /* 1 pixel of pseudo-color 0 */ + break; + case 0x1: /* switch_3 == '01' */ + run_length = 2; /* 2 pixels of pseudo-color 0 */ + break; + case 0x2: /* switch_3 == '10' */ + gst_bit_reader_get_bits_uint32 (&gb, &run_length, 4); + run_length += 9; + gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 4); + break; + case 0x3: /* switch_3 == '11' */ + gst_bit_reader_get_bits_uint32 (&gb, &run_length, 8); + run_length += 25; + gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 4); + break; + } + } + } + } + + /* If run_length is zero, continue. Only case happening is when + * stop_parsing is TRUE too, so next cycle shouldn't run */ + if (run_length == 0) + continue; + + /* Trim the run_length to not go beyond the line end and consume + * it from remaining length of dest line */ + run_length = MIN (run_length, dbuf_len); + dbuf_len -= run_length; + + /* Make clut_index refer to the index into the desired bit depths + * CLUT definition table */ + if (map_table) + clut_index = map_table[clut_index]; /* now clut_index signifies the index into map_table dest */ + + /* Now we can simply memset run_length count of destination bytes + * to clut_index, but only if not non_modifying */ + GST_TRACE ("RUNLEN: setting %u pixels to color 0x%x in destination buffer; " + "dbuf_len left is %d pixels", run_length, clut_index, dbuf_len); + + if (!(non_mod == 1 && bits == 1)) + memset (destbuf, clut_index, run_length); + + destbuf += run_length; + pixels_read += run_length; + } + + // FIXME: Test skip_to_byte instead of adding 7 bits, once everything else is working good + //gst_bit_reader_skip_to_byte (&gb); + *srcbuf += (gst_bit_reader_get_pos (&gb) + 7) >> 3; + + GST_LOG ("Returning with %u pixels read", pixels_read); + + // FIXME: Shouldn't need this variable if tracking things in the loop better + return pixels_read; +} + +static int +_dvb_sub_read_8bit_string (guint8 * destbuf, gint dbuf_len, + const guint8 ** srcbuf, gint buf_size, guint8 non_mod, guint8 * map_table) +{ + GstBitReader gb = GST_BIT_READER_INIT (*srcbuf, buf_size); + /* FIXME: Handle FALSE returns from gst_bit_reader_get_* calls? */ + + gboolean stop_parsing = FALSE; + guint32 bits = 0; + guint32 pixels_read = 0; + + static gboolean warning_shown = FALSE; + if (!warning_shown) { + g_warning + ("Parsing 8bit color DVB sub-picture. This is not tested at all. If you see this message, " + "please provide the developers with sample media with these subtitles, if possible."); + warning_shown = TRUE; + } + + GST_LOG ("dbuf_len = %d", dbuf_len); + + /* FFMPEG-FIXME: ffmpeg uses a manual byte walking algorithm, which might be more performant, + * FFMPEG-FIXME: but it does almost absolutely no buffer length checking, so could walk over + * FFMPEG-FIXME: memory boundaries. While we don't check gst_bit_reader_get_bits_uint32 + * FFMPEG-FIXME: return values either and therefore might get some pixels corrupted, we at + * FFMPEG-FIXME: lest have no chance of reading memory we don't own and visual corruption + * FFMPEG-FIXME: is guaranteed anyway when not all bytes are present */ + /* Rephrased - it's better to work with bytes with default value '0' instead of reading from memory we don't own. */ + while (!stop_parsing && (gst_bit_reader_get_remaining (&gb) > 0)) { + guint run_length = 0, clut_index = 0; + gst_bit_reader_get_bits_uint32 (&gb, &bits, 8); + + if (bits) { /* 8-bit_pixel-code */ + run_length = 1; + clut_index = bits; + } else { /* 8-bit_zero */ + gst_bit_reader_get_bits_uint32 (&gb, &bits, 1); + if (bits == 0) { /* switch_1 == '0' */ + /* run_length_1-127 for pseudo-colour _entry) '0x00' */ + gst_bit_reader_get_bits_uint32 (&gb, &run_length, 7); + if (run_length == 0) { /* end_of_string_signal */ + stop_parsing = TRUE; + } + } else { /* switch_1 == '1' */ + /* run_length_3-127 */ + gst_bit_reader_get_bits_uint32 (&gb, &run_length, 7); + gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 8); + + if (run_length < 3) { + GST_WARNING ("runlength value was %u, but the spec requires it " + "must be >=3", run_length); + } + } + } + + /* If run_length is zero, continue. Only case happening is when + * stop_parsing is TRUE too, so next cycle shouldn't run */ + if (run_length == 0) + continue; + + /* Trim the run_length to not go beyond the line end and consume + * it from remaining length of dest line */ + run_length = MIN (run_length, dbuf_len); + dbuf_len -= run_length; + + /* Make clut_index refer to the index into the desired bit depths + * CLUT definition table */ + if (map_table) + clut_index = map_table[clut_index]; /* now clut_index signifies the index into map_table dest */ + + /* Now we can simply memset run_length count of destination bytes + * to clut_index, but only if not non_modifying */ + GST_TRACE ("RUNLEN: setting %u pixels to color 0x%x in destination buffer; " + "dbuf_len left is %d pixels", run_length, clut_index, dbuf_len); + + if (!(non_mod == 1 && bits == 1)) + memset (destbuf, clut_index, run_length); + + destbuf += run_length; + pixels_read += run_length; + } + + GST_LOG ("Returning with %u pixels read", pixels_read); + + // FIXME: Shouldn't need this variable if tracking things in the loop better + return pixels_read; +} + +static void +_dvb_sub_parse_pixel_data_block (DvbSub * dvb_sub, + DVBSubObjectDisplay * display, const guint8 * buf, gint buf_size, + DvbSubPixelDataSubBlockFieldType top_bottom, guint8 non_mod) +{ + DVBSubRegion *region = get_region (dvb_sub, display->region_id); + const guint8 *buf_end = buf + buf_size; + guint8 *pbuf; + int x_pos, y_pos; + int i; + gboolean dest_buf_filled = FALSE; + + guint8 map2to4[] = { 0x0, 0x7, 0x8, 0xf }; + guint8 map2to8[] = { 0x00, 0x77, 0x88, 0xff }; + guint8 map4to8[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff + }; + guint8 *map_table; + + GST_LOG ("DVB pixel block size %d, %s field:", buf_size, + top_bottom ? "bottom" : "top"); + + GST_MEMDUMP ("packet", buf, buf_size); + + if (region == NULL) { + GST_LOG ("Region is NULL, returning"); + return; + } + + pbuf = region->pbuf; + + x_pos = display->x_pos; + y_pos = display->y_pos; + + if ((y_pos & 1) != top_bottom) + y_pos++; + + while (buf < buf_end) { + GST_LOG ("Iteration start, %u bytes missing from end; buf = %p, " + "buf_end = %p; Region is number %u, with a dimension of %dx%d; " + "We are at position %dx%d", (guint) (buf_end - buf), buf, buf_end, + region->id, region->width, region->height, x_pos, y_pos); + + // FFMPEG-FIXME: ffmpeg doesn't check for equality and so can overflow destination buffer later on with bad input data + // FFMPEG-FIXME: However that makes it warn on end_of_object_line and map tables as well, so we add the dest_buf_filled tracking + // FIXME: Removed x_pos checking here, because we don't want to turn dest_buf_filled to TRUE permanently in that case + // FIXME: We assume that region->width - x_pos as dbuf_len to read_nbit_string will take care of that case nicely; + // FIXME: That is, that read_nbit_string never scribbles anything if dbuf_len passed to it is zero due to this. + if (y_pos >= region->height) { + dest_buf_filled = TRUE; + } + + switch (*buf++) { + case 0x10: + if (dest_buf_filled) { + /* FIXME: Be more verbose */ + GST_WARNING ("Invalid object location for data_type 0x%x!", + *(buf - 1)); + GST_MEMDUMP ("Remaining data after invalid object location:", buf, + (guint) (buf_end - buf)); + return; + } + + if (region->depth == 8) + map_table = map2to8; + else if (region->depth == 4) + map_table = map2to4; + else + map_table = NULL; + + // FFMPEG-FIXME: ffmpeg code passes buf_size instead of buf_end - buf, and could + // FFMPEG-FIXME: therefore potentially walk over the memory area we own + x_pos += + _dvb_sub_read_2bit_string (pbuf + (y_pos * region->width) + x_pos, + region->width - x_pos, &buf, buf_end - buf, non_mod, map_table); + break; + case 0x11: + if (dest_buf_filled) { + /* FIXME: Be more verbose */ + GST_WARNING ("Invalid object location for data_type 0x%x!", + *(buf - 1)); + GST_MEMDUMP ("Remaining data after invalid object location:", buf, + buf_end - buf); + return; // FIXME: Perhaps tell read_nbit_string that dbuf_len is zero and let it walk the bytes regardless? (Same FIXME for 2bit and 8bit) + } + + if (region->depth < 4) { + GST_WARNING ("4-bit pixel string in %d-bit region!", region->depth); + return; + } + + if (region->depth == 8) + map_table = map4to8; + else + map_table = NULL; + + GST_LOG ("READ_4BIT_STRING: String data into position %dx%d; " + "buf before is %p", x_pos, y_pos, buf); + // FFMPEG-FIXME: ffmpeg code passes buf_size instead of buf_end - buf, and could + // FFMPEG-FIXME: therefore potentially walk over the memory area we own + x_pos += + _dvb_sub_read_4bit_string (pbuf + (y_pos * region->width) + x_pos, + region->width - x_pos, &buf, buf_end - buf, non_mod, map_table); + GST_DEBUG ("READ_4BIT_STRING finished: buf pointer now %p", buf); + break; + case 0x12: + if (dest_buf_filled) { + /* FIXME: Be more verbose */ + GST_WARNING ("Invalid object location for data_type 0x%x!", + *(buf - 1)); + GST_MEMDUMP ("Remaining data after invalid object location:", + buf, (guint) (buf_end - buf)); + return; + } + + if (region->depth < 8) { + GST_WARNING ("8-bit pixel string in %d-bit region!", region->depth); + return; + } + // FFMPEG-FIXME: ffmpeg code passes buf_size instead of buf_end - buf, and could + // FFMPEG-FIXME: therefore potentially walk over the memory area we own + x_pos += + _dvb_sub_read_8bit_string (pbuf + (y_pos * region->width) + x_pos, + region->width - x_pos, &buf, buf_end - buf, non_mod, NULL); + break; + + case 0x20: + GST_DEBUG ("handling map2to4 table data"); + /* FIXME: I don't see any guards about buffer size here - buf++ happens with the switch, but + * FIXME: buffer is walked without length checks? Same deal in other map table cases */ + map2to4[0] = (*buf) >> 4; + map2to4[1] = (*buf++) & 0xf; + map2to4[2] = (*buf) >> 4; + map2to4[3] = (*buf++) & 0xf; + break; + case 0x21: + GST_DEBUG ("handling map2to8 table data"); + for (i = 0; i < 4; i++) + map2to8[i] = *buf++; + break; + case 0x22: + GST_DEBUG ("handling map4to8 table data"); + for (i = 0; i < 16; i++) + map4to8[i] = *buf++; + break; + case 0xf0: + GST_DEBUG ("end of object line code encountered"); + x_pos = display->x_pos; + y_pos += 2; + break; + default: + /* FIXME: Do we consume word align stuffing byte that could follow top/bottom data? */ + GST_WARNING ("Unknown/unsupported pixel block 0x%x", *(buf - 1)); + } + } +} + +static void +_dvb_sub_parse_object_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf, + gint buf_size) +{ + const guint8 *buf_end = buf + buf_size; + guint object_id; + DVBSubObject *object; + + guint8 coding_method, non_modifying_color; + + object_id = GST_READ_UINT16_BE (buf); + buf += 2; + + object = get_object (dvb_sub, object_id); + + GST_DEBUG ("OBJECT: a new object segment has occurred for object_id = %u", + object_id); + + if (!object) { + GST_WARNING ("Nothing known about object with ID %u yet, bailing out", + object_id); + return; + } + + coding_method = ((*buf) >> 2) & 3; + non_modifying_color = ((*buf++) >> 1) & 1; + + if (coding_method == 0) { + const guint8 *block; + DVBSubObjectDisplay *display; + guint16 top_field_len, bottom_field_len; + + top_field_len = GST_READ_UINT16_BE (buf); + buf += 2; + bottom_field_len = GST_READ_UINT16_BE (buf); + buf += 2; + + if (buf + top_field_len + bottom_field_len > buf_end) { + GST_WARNING ("Field data size too large"); + return; + } + + /* FIXME: Potential optimization opportunity here - parse the object pixmap only once, and copy it to all the + * FIXME: regions that need it. One object being in multiple regions is a rare occurrence in real life, however */ + for (display = object->display_list; display; + display = display->object_list_next) { + block = buf; + + GST_DEBUG ("OBJECT: parsing top and bottom part of object id %d; " + "top_field_len = %u, bottom_field_len = %u", + display->object_id, top_field_len, bottom_field_len); + + _dvb_sub_parse_pixel_data_block (dvb_sub, display, block, top_field_len, + TOP_FIELD, non_modifying_color); + + if (bottom_field_len > 0) + block = buf + top_field_len; + else + bottom_field_len = top_field_len; + + _dvb_sub_parse_pixel_data_block (dvb_sub, display, block, + bottom_field_len, BOTTOM_FIELD, non_modifying_color); + } + + } else if (coding_method == 1) { + GST_FIXME ("'a string of characters' coding method not supported yet!"); + } else { + GST_WARNING ("Unknown object coding 0x%x", coding_method); + } +} + +static gint +_dvb_sub_parse_display_definition_segment (DvbSub * dvb_sub, guint8 * buf, + gint buf_size) +{ + int dds_version, info_byte; + + if (buf_size < 5) + return -1; + + info_byte = *buf++; + dds_version = info_byte >> 4; + + if (dvb_sub->display_def.version == dds_version) + return 0; /* already have this display definition version */ + + dvb_sub->display_def.version = dds_version; + dvb_sub->display_def.display_width = GST_READ_UINT16_BE (buf) + 1; + buf += 2; + dvb_sub->display_def.display_height = GST_READ_UINT16_BE (buf) + 1; + buf += 2; + + dvb_sub->display_def.window_flag = info_byte & 1 << 3; + + if (buf_size >= 13 && dvb_sub->display_def.window_flag) { + dvb_sub->display_def.window_x = GST_READ_UINT16_BE (buf); + buf += 2; + dvb_sub->display_def.window_y = GST_READ_UINT16_BE (buf); + buf += 2; + dvb_sub->display_def.window_width = + GST_READ_UINT16_BE (buf) - dvb_sub->display_def.window_x + 1; + buf += 2; + dvb_sub->display_def.window_height = + GST_READ_UINT16_BE (buf) - dvb_sub->display_def.window_y + 1; + buf += 2; + } + + return 0; +} + +static gint +_dvb_sub_parse_end_of_display_set (DvbSub * dvb_sub, guint16 page_id, + guint8 * buf, gint buf_size, guint64 pts) +{ + DVBSubRegionDisplay *display; + DVBSubtitles *sub; + DVBSubCLUT *clut; + guint32 *clut_table; + int i; + + GST_DEBUG ("DISPLAY SET END: page_id = %u, length = %d", page_id, buf_size); + + sub = g_slice_new0 (DVBSubtitles); + +#if 0 /* FIXME: PTS stuff not figured out yet */ + sub->start_display_time = 0; + sub->end_display_time = priv->page_time_out * 1000; + sub->format = 0; /* 0 = graphics */ +#endif + + /* N.B. g_new0() will return NULL if num_rects is 0 */ + sub->num_rects = dvb_sub->display_list_size; + sub->rects = g_new0 (DVBSubtitleRect, sub->num_rects); + + i = 0; + + /* copy subtitle display and window information */ + sub->display_def = dvb_sub->display_def; + + for (display = dvb_sub->display_list; display; display = display->next) { + DVBSubtitleRect *rect; + DVBSubRegion *region; + + region = get_region (dvb_sub, display->region_id); + + if (!region) + continue; + + rect = &sub->rects[i]; + rect->x = display->x_pos; + rect->y = display->y_pos; + rect->w = region->width; + rect->h = region->height; +#if 0 /* FIXME: Don't think we need to save the number of colors in the palette when we are saving as RGBA? */ + rect->nb_colors = 16; +#endif +#if 0 /* FIXME: Needed to be specified once we support strings of characters based subtitles */ + rect->type = SUBTITLE_BITMAP; +#endif + rect->pict.rowstride = region->width; + rect->pict.palette_bits_count = region->depth; + + clut = get_clut (dvb_sub, region->clut); + + if (!clut) + clut = &default_clut; + + switch (region->depth) { + case 2: + clut_table = clut->clut4; + break; + case 8: + clut_table = clut->clut256; + break; + case 4: + default: + clut_table = clut->clut16; + break; + } + + /* FIXME: Tweak this to be saved in a format most suitable for Qt and GStreamer instead. + * Currently kept in AVPicture for quick save_display_set testing */ + rect->pict.palette = g_malloc ((1 << region->depth) * sizeof (guint32)); /* FIXME: Can we use GSlice here? */ + memcpy (rect->pict.palette, clut_table, + (1 << region->depth) * sizeof (guint32)); + + GST_MEMDUMP ("rect->pict.data.palette content", + (guint8 *) rect->pict.palette, (1 << region->depth) * sizeof (guint32)); + + rect->pict.data = g_malloc (region->buf_size); /* FIXME: Can we use GSlice here? */ + memcpy (rect->pict.data, region->pbuf, region->buf_size); + + GST_DEBUG ("DISPLAY: an object rect created: iteration %u, " + "pos: %d:%d, size: %dx%d", i, rect->x, rect->y, rect->w, rect->h); + + GST_MEMDUMP ("rect->pict.data content", rect->pict.data, region->buf_size); + + ++i; + } + + sub->pts = pts; + sub->page_time_out = dvb_sub->page_time_out; + sub->num_rects = i; + + if (dvb_sub->callbacks.new_data) { + dvb_sub->callbacks.new_data (dvb_sub, sub, dvb_sub->user_data); + } else { + /* No-one responsible to clean up memory, so do it ourselves */ + /* FIXME: Just don't bother with all this palette image creation in the first place then... */ + dvb_subtitles_free (sub); + } + + return 1; /* FIXME: The caller of this function is probably supposed to do something with the return value */ +} + +void +dvb_subtitles_free (DVBSubtitles * sub) +{ + int i; + + if (sub == NULL) + return; + + /* Now free up all the temporary memory we allocated */ + for (i = 0; i < sub->num_rects; ++i) { + g_free (sub->rects[i].pict.palette); + g_free (sub->rects[i].pict.data); + } + g_free (sub->rects); + g_slice_free (DVBSubtitles, sub); +} + +DvbSub * +dvb_sub_new (void) +{ + static gsize inited = 0; + DvbSub *sub; + + if (g_once_init_enter (&inited)) { + dvb_sub_init (); + g_once_init_leave (&inited, TRUE); + } + + sub = g_slice_new0 (DvbSub); + + /* TODO: Add initialization code here */ + /* FIXME: Do we have a reason to initiate the members to zero, or are we guaranteed that anyway? */ + sub->region_list = NULL; + sub->object_list = NULL; + sub->page_time_out = 0; /* FIXME: Maybe 255 instead? */ + sub->pes_buffer = g_string_new (NULL); + + /* display/window information */ + sub->display_def.version = -1; + sub->display_def.window_flag = 0; + sub->display_def.display_width = 720; + sub->display_def.display_height = 576; + + return sub; +} + +void +dvb_sub_free (DvbSub * sub) +{ + /* TODO: Add deinitalization code here */ + /* FIXME: Clear up region_list contents */ + delete_state (sub); + while (sub->display_list) { + DVBSubRegionDisplay *tmp = sub->display_list->next; + g_slice_free (DVBSubRegionDisplay, sub->display_list); + sub->display_list = tmp; + } + g_string_free (sub->pes_buffer, TRUE); + g_slice_free (DvbSub, sub); +} + +#define DVB_SUB_SEGMENT_PAGE_COMPOSITION 0x10 +#define DVB_SUB_SEGMENT_REGION_COMPOSITION 0x11 +#define DVB_SUB_SEGMENT_CLUT_DEFINITION 0x12 +#define DVB_SUB_SEGMENT_OBJECT_DATA 0x13 +#define DVB_SUB_SEGMENT_DISPLAY_DEFINITION 0x14 +#define DVB_SUB_SEGMENT_END_OF_DISPLAY_SET 0x80 +#define DVB_SUB_SEGMENT_STUFFING 0xFF + +#define DVB_SUB_SYNC_BYTE 0x0f +/** + * dvb_sub_feed_with_pts: + * @dvb_sub: a #DvbSub + * @pts: The PTS of the data + * @data: The data to feed to the parser + * @len: Length of the data + * + * Feeds the DvbSub parser with new binary data to parse, + * with an associated PTS value. E.g, data left after PES + * packet header has been already parsed, which contains + * the PTS information). + * + * Return value: -1 if data was unhandled (e.g, not a subtitle packet), + * -2 if data parsing was unsuccesful (e.g, length was invalid), + * 0 or positive if data was handled. If positive, then amount of data consumed on success. FIXME: List the positive return values. + */ +gint +dvb_sub_feed_with_pts (DvbSub * dvb_sub, guint64 pts, guint8 * data, gint len) +{ + unsigned int pos = 0; + guint8 segment_type; + guint16 segment_len; + guint16 page_id; + + GST_DEBUG ("pts=%" G_GUINT64_FORMAT " and length %d", pts, len); + + g_return_val_if_fail (data != NULL, -1); + + if (len <= 3) { /* len(0x20 0x00 end_of_PES_data_field_marker) */ + GST_WARNING ("Data length too short"); + return -1; + } + + if (data[pos++] != 0x20) { + GST_WARNING ("Tried to handle a PES packet private data that isn't a " + "subtitle packet (does not start with 0x20)"); + return -1; + } + + if (data[pos++] != 0x00) { + GST_WARNING ("'Subtitle stream in this PES packet' was not 0x00, so this " + "is in theory not a DVB subtitle stream (but some other subtitle " + "standard?); bailing out"); + return -1; + } + + while (data[pos++] == DVB_SUB_SYNC_BYTE) { + if ((len - pos) < (2 * 2 + 1)) { + GST_WARNING ("Data after SYNC BYTE too short, less than needed to " + "even get to segment_length"); + return -2; + } + segment_type = data[pos++]; + GST_DEBUG ("=== Segment type is 0x%x", segment_type); + page_id = (data[pos] << 8) | data[pos + 1]; + GST_DEBUG ("page_id is 0x%x", page_id); + pos += 2; + segment_len = (data[pos] << 8) | data[pos + 1]; + GST_DEBUG ("segment_length is %d (0x%x 0x%x)", segment_len, data[pos], + data[pos + 1]); + pos += 2; + if ((len - pos) < segment_len) { + GST_WARNING ("segment_length was told to be %u, but we only have " + "%d bytes left", segment_len, len - pos); + return -2; + } + // TODO: Parse the segment per type (this is probably a leftover TODO that is now done?) + /* FIXME: Handle differing PTS values - all segments of a given display set must be with the same PTS, + * FIXME: but we let it slip and just take it for granted in end_of_display_set */ + switch (segment_type) { + case DVB_SUB_SEGMENT_PAGE_COMPOSITION: + GST_DEBUG ("Page composition segment at buffer pos %u", pos); + _dvb_sub_parse_page_segment (dvb_sub, page_id, data + pos, segment_len); /* FIXME: Not sure about args */ + break; + case DVB_SUB_SEGMENT_REGION_COMPOSITION: + GST_DEBUG ("Region composition segment at buffer pos %u", pos); + _dvb_sub_parse_region_segment (dvb_sub, page_id, data + pos, segment_len); /* FIXME: Not sure about args */ + break; + case DVB_SUB_SEGMENT_CLUT_DEFINITION: + GST_DEBUG ("CLUT definition segment at buffer pos %u", pos); + _dvb_sub_parse_clut_segment (dvb_sub, page_id, data + pos, segment_len); /* FIXME: Not sure about args */ + break; + case DVB_SUB_SEGMENT_OBJECT_DATA: + GST_DEBUG ("Object data segment at buffer pos %u", pos); + _dvb_sub_parse_object_segment (dvb_sub, page_id, data + pos, segment_len); /* FIXME: Not sure about args */ + break; + case DVB_SUB_SEGMENT_DISPLAY_DEFINITION: + GST_DEBUG ("display definition segment at buffer pos %u", pos); + _dvb_sub_parse_display_definition_segment (dvb_sub, data + pos, + segment_len); + break; + case DVB_SUB_SEGMENT_END_OF_DISPLAY_SET: + GST_DEBUG ("End of display set at buffer pos %u", pos); + _dvb_sub_parse_end_of_display_set (dvb_sub, page_id, data + pos, segment_len, pts); /* FIXME: Not sure about args */ + break; + default: + GST_FIXME ("Unhandled segment type 0x%x", segment_type); + break; + } + + pos += segment_len; + + if (pos == len) { + GST_WARNING ("Data ended without a PES data end marker"); + return 1; + } + } + + GST_LOG ("Processed %d bytes out of %d", pos, len); + return pos; +} + +/** + * dvb_sub_set_callbacks: + * @dvb_sub: a #DvbSub + * @callbacks: the callbacks to install + * @user_data: a user_data argument for the callback + * + * Set callback which will be executed when new subpictures are available. + */ +void +dvb_sub_set_callbacks (DvbSub * dvb_sub, DvbSubCallbacks * callbacks, + gpointer user_data) +{ + g_return_if_fail (dvb_sub != NULL); + g_return_if_fail (callbacks != NULL); + + dvb_sub->callbacks = *callbacks; + dvb_sub->user_data = user_data; +} diff --git a/gst/dvbsuboverlay/dvb-sub.h b/gst/dvbsuboverlay/dvb-sub.h new file mode 100644 index 000000000..7faa31f45 --- /dev/null +++ b/gst/dvbsuboverlay/dvb-sub.h @@ -0,0 +1,138 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ +/* + * libdvbsub - DVB subtitle decoding + * Copyright (C) Mart Raudsepp 2009 <mart.raudsepp@artecdesign.ee> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _DVB_SUB_H_ +#define _DVB_SUB_H_ + +#include <glib.h> + +G_BEGIN_DECLS + +typedef struct _DvbSub DvbSub; + +/** + * DVBSubtitlePicture: + * @data: the data in the form of palette indices, each byte represents one pixel + * as an index into the @palette. + * @palette: the palette used for this subtitle rectangle, up to 256 items depending + * on the depth of the subpicture; each palette item is in ARGB form, 8-bits per channel. + * @palette_bits_count: the amount of bits used in indeces into @palette in @data. + * @rowstride: the number of bytes between the start of a row and the start of the next row. + * + * A structure representing the contents of a subtitle rectangle. + * + * FIXME: Expose the depth of the palette, and perhaps also the height in this struct. + */ +typedef struct DVBSubtitlePicture { + guint8 *data; + guint32 *palette; + guint8 palette_bits_count; + int rowstride; +} DVBSubtitlePicture; + +/** + * DVBSubtitleRect: + * @x: x coordinate of top left corner + * @y: y coordinate of top left corner + * @w: the width of this subpicture rectangle + * @h: the height of this subpicture rectangle + * @pict: the content of this subpicture rectangle + * + * A structure representing one subtitle objects position, dimension and content. + */ +typedef struct DVBSubtitleRect { + int x; + int y; + int w; + int h; + + DVBSubtitlePicture pict; +} DVBSubtitleRect; + +/** + * DVBSubtitleWindow + * @version: version + * @display_window_flag: window_* are valid + * @display_width: assumed width of display + * @display_height: assumed height of display + * @window_x: x coordinate of top left corner of the subtitle window + * @window_y: y coordinate of top left corner of the subtitle window + * @window_width: width of the subtitle window + * @window_height: height of the subtitle window + * + * A structure presenting display and window information + * display definition segment from ETSI EN 300 743 V1.3.1 + */ +typedef struct DVBSubtitleWindow { + gint version; + gint window_flag; + + gint display_width; + gint display_height; + + gint window_x; + gint window_y; + gint window_width; + gint window_height; +} DVBSubtitleWindow; + +/** + * DVBSubtitles: + * @num_rects: the number of #DVBSubtitleRect in @rects + * @rects: dynamic array of #DVBSubtitleRect + * + * A structure representing a set of subtitle objects. + */ +typedef struct DVBSubtitles { + guint64 pts; + guint8 page_time_out; + guint num_rects; + DVBSubtitleRect *rects; + DVBSubtitleWindow display_def; +} DVBSubtitles; + +/** + * DvbSubCallbacks: + * @new_data: called when new subpicture data is available for display. @dvb_sub + * is the #DvbSub instance this callback originates from; @subs is the set of + * subtitle objects that should be display for no more than @page_time_out + * seconds at @pts; @user_data is the same user_data as was passed through + * dvb_sub_set_callbacks(); The callback handler is responsible for eventually + * cleaning up the subpicture data @subs with a call to dvb_subtitles_free() + * + * A set of callbacks that can be installed on the #DvbSub with + * dvb_sub_set_callbacks(). + */ +typedef struct { + void (*new_data) (DvbSub *dvb_sub, DVBSubtitles * subs, gpointer user_data); + /*< private >*/ + gpointer _dvb_sub_reserved[3]; +} DvbSubCallbacks; + +DvbSub *dvb_sub_new (void); +void dvb_sub_free (DvbSub * sub); + +gint dvb_sub_feed_with_pts (DvbSub *dvb_sub, guint64 pts, guint8 *data, gint len); +void dvb_sub_set_callbacks (DvbSub *dvb_sub, DvbSubCallbacks *callbacks, gpointer user_data); +void dvb_subtitles_free (DVBSubtitles *sub); + +G_END_DECLS + +#endif /* _DVB_SUB_H_ */ diff --git a/gst/dvbsuboverlay/gstdvbsuboverlay.c b/gst/dvbsuboverlay/gstdvbsuboverlay.c new file mode 100644 index 000000000..9962ff023 --- /dev/null +++ b/gst/dvbsuboverlay/gstdvbsuboverlay.c @@ -0,0 +1,1102 @@ +/* GStreamer DVB subtitles overlay + * Copyright (c) 2010 Mart Raudsepp <mart.raudsepp@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * SECTION:element-dvbsuboverlay + * + * Renders DVB subtitles on top of a video stream. + * + * <refsect2> + * <title>Example launch line</title> + * |[ FIXME + * gst-launch -v filesrc location=/path/to/ts ! mpegtsdemux name=d ! queue ! mp3parse ! mad ! audioconvert ! autoaudiosink \ + * d. ! queue ! mpeg2dec ! ffmpegcolorspace ! r. \ + * d. ! queue ! "subpicture/x-dvb" ! dvbsuboverlay name=r ! ffmpegcolorspace ! autovideosink + * ]| This pipeline demuxes a MPEG-TS file with MPEG2 video, MP3 audio and embedded DVB subtitles and renders the subtitles on top of the video. + * </refsect2> + */ + + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "gstdvbsuboverlay.h" + +#include <string.h> + +GST_DEBUG_CATEGORY_STATIC (gst_dvbsub_overlay_debug); +#define GST_CAT_DEFAULT gst_dvbsub_overlay_debug + +/* Filter signals and props */ +enum +{ + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_ENABLE, + PROP_MAX_PAGE_TIMEOUT, +}; + +#define DEFAULT_ENABLE (TRUE) +#define DEFAULT_MAX_PAGE_TIMEOUT (0) + +static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420")) + ); + +static GstStaticPadTemplate video_sink_factory = +GST_STATIC_PAD_TEMPLATE ("video_sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420")) + ); + +static GstStaticPadTemplate text_sink_factory = +GST_STATIC_PAD_TEMPLATE ("text_sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("subpicture/x-dvb") + ); + +static void gst_dvbsub_overlay_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_dvbsub_overlay_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static void gst_dvbsub_overlay_finalize (GObject * object); + +static GstStateChangeReturn gst_dvbsub_overlay_change_state (GstElement * + element, GstStateChange transition); + +GST_BOILERPLATE (GstDVBSubOverlay, gst_dvbsub_overlay, GstElement, + GST_TYPE_ELEMENT); + +static GstCaps *gst_dvbsub_overlay_getcaps (GstPad * pad); + +static gboolean gst_dvbsub_overlay_setcaps_video (GstPad * pad, GstCaps * caps); + +static GstFlowReturn gst_dvbsub_overlay_chain_video (GstPad * pad, + GstBuffer * buf); +static GstFlowReturn gst_dvbsub_overlay_chain_text (GstPad * pad, + GstBuffer * buf); + +static gboolean gst_dvbsub_overlay_event_video (GstPad * pad, GstEvent * event); +static gboolean gst_dvbsub_overlay_event_text (GstPad * pad, GstEvent * event); +static gboolean gst_dvbsub_overlay_event_src (GstPad * pad, GstEvent * event); + +static void new_dvb_subtitles_cb (DvbSub * dvb_sub, DVBSubtitles * subs, + gpointer user_data); + +static GstFlowReturn gst_dvbsub_overlay_bufferalloc_video (GstPad * pad, + guint64 offset, guint size, GstCaps * caps, GstBuffer ** buffer); + +static gboolean gst_dvbsub_overlay_query_src (GstPad * pad, GstQuery * query); + +static void +gst_dvbsub_overlay_base_init (gpointer gclass) +{ + GstElementClass *element_class = (GstElementClass *) gclass; + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_factory)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&video_sink_factory)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&text_sink_factory)); + + gst_element_class_set_details_simple (element_class, + "DVB Subtitles Overlay", + "Mixer/Video/Overlay/Subtitle", + "Renders DVB subtitles", "Mart Raudsepp <mart.raudsepp@collabora.co.uk>"); +} + +/* initialize the plugin's class */ +static void +gst_dvbsub_overlay_class_init (GstDVBSubOverlayClass * klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + GstElementClass *gstelement_class = (GstElementClass *) klass; + + gobject_class->set_property = gst_dvbsub_overlay_set_property; + gobject_class->get_property = gst_dvbsub_overlay_get_property; + gobject_class->finalize = gst_dvbsub_overlay_finalize; + + g_object_class_install_property (gobject_class, PROP_ENABLE, g_param_spec_boolean ("enable", "Enable", /* FIXME: "enable" vs "silent"? */ + "Enable rendering of subtitles", DEFAULT_ENABLE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_MAX_PAGE_TIMEOUT, + g_param_spec_int ("max-page-timeout", "max-page-timeout", + "Limit maximum display time of a subtitle page (0 - disabled, value in seconds)", + 0, G_MAXINT, DEFAULT_MAX_PAGE_TIMEOUT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_dvbsub_overlay_change_state); +} + +static void +gst_dvbsub_overlay_flush_subtitles (GstDVBSubOverlay * render) +{ + DVBSubtitles *subs; + + g_mutex_lock (render->dvbsub_mutex); + while ((subs = g_queue_pop_head (render->pending_subtitles))) { + dvb_subtitles_free (subs); + } + + if (render->current_subtitle) + dvb_subtitles_free (render->current_subtitle); + render->current_subtitle = NULL; + + if (render->dvb_sub) + dvb_sub_free (render->dvb_sub); + + render->dvb_sub = dvb_sub_new (); + + { + DvbSubCallbacks dvbsub_callbacks = { &new_dvb_subtitles_cb, }; + dvb_sub_set_callbacks (render->dvb_sub, &dvbsub_callbacks, render); + } + + g_mutex_unlock (render->dvbsub_mutex); +} + +static void +gst_dvbsub_overlay_init (GstDVBSubOverlay * render, + GstDVBSubOverlayClass * gclass) +{ + GST_DEBUG_OBJECT (render, "init"); + + render->srcpad = gst_pad_new_from_static_template (&src_factory, "src"); + render->video_sinkpad = + gst_pad_new_from_static_template (&video_sink_factory, "video_sink"); + render->text_sinkpad = + gst_pad_new_from_static_template (&text_sink_factory, "text_sink"); + + gst_pad_set_setcaps_function (render->video_sinkpad, + GST_DEBUG_FUNCPTR (gst_dvbsub_overlay_setcaps_video)); + + gst_pad_set_getcaps_function (render->srcpad, + GST_DEBUG_FUNCPTR (gst_dvbsub_overlay_getcaps)); + gst_pad_set_getcaps_function (render->video_sinkpad, + GST_DEBUG_FUNCPTR (gst_dvbsub_overlay_getcaps)); + + gst_pad_set_chain_function (render->video_sinkpad, + GST_DEBUG_FUNCPTR (gst_dvbsub_overlay_chain_video)); + gst_pad_set_chain_function (render->text_sinkpad, + GST_DEBUG_FUNCPTR (gst_dvbsub_overlay_chain_text)); + + gst_pad_set_event_function (render->video_sinkpad, + GST_DEBUG_FUNCPTR (gst_dvbsub_overlay_event_video)); + gst_pad_set_event_function (render->text_sinkpad, + GST_DEBUG_FUNCPTR (gst_dvbsub_overlay_event_text)); + gst_pad_set_event_function (render->srcpad, + GST_DEBUG_FUNCPTR (gst_dvbsub_overlay_event_src)); + + gst_pad_set_bufferalloc_function (render->video_sinkpad, + GST_DEBUG_FUNCPTR (gst_dvbsub_overlay_bufferalloc_video)); + + gst_pad_set_query_function (render->srcpad, + GST_DEBUG_FUNCPTR (gst_dvbsub_overlay_query_src)); + + gst_element_add_pad (GST_ELEMENT (render), render->srcpad); + gst_element_add_pad (GST_ELEMENT (render), render->video_sinkpad); + gst_element_add_pad (GST_ELEMENT (render), render->text_sinkpad); + + render->width = 0; + render->height = 0; + + render->current_subtitle = NULL; + render->pending_subtitles = g_queue_new (); + + render->enable = DEFAULT_ENABLE; + render->max_page_timeout = DEFAULT_MAX_PAGE_TIMEOUT; + + render->dvbsub_mutex = g_mutex_new (); + gst_dvbsub_overlay_flush_subtitles (render); + + gst_segment_init (&render->video_segment, GST_FORMAT_TIME); + gst_segment_init (&render->subtitle_segment, GST_FORMAT_TIME); + + GST_DEBUG_OBJECT (render, "init complete"); +} + +static void +gst_dvbsub_overlay_finalize (GObject * object) +{ + GstDVBSubOverlay *overlay = GST_DVBSUB_OVERLAY (object); + DVBSubtitles *subs; + + while ((subs = g_queue_pop_head (overlay->pending_subtitles))) { + dvb_subtitles_free (subs); + } + g_queue_free (overlay->pending_subtitles); + + if (overlay->current_subtitle) + dvb_subtitles_free (overlay->current_subtitle); + overlay->current_subtitle = NULL; + + if (overlay->dvb_sub) + dvb_sub_free (overlay->dvb_sub); + + if (overlay->dvbsub_mutex) + g_mutex_free (overlay->dvbsub_mutex); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_dvbsub_overlay_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstDVBSubOverlay *overlay = GST_DVBSUB_OVERLAY (object); + + switch (prop_id) { + case PROP_ENABLE: + g_atomic_int_set (&overlay->enable, g_value_get_boolean (value)); + break; + case PROP_MAX_PAGE_TIMEOUT: + g_atomic_int_set (&overlay->max_page_timeout, g_value_get_int (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_dvbsub_overlay_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstDVBSubOverlay *overlay = GST_DVBSUB_OVERLAY (object); + + switch (prop_id) { + case PROP_ENABLE: + g_value_set_boolean (value, g_atomic_int_get (&overlay->enable)); + break; + case PROP_MAX_PAGE_TIMEOUT: + g_value_set_int (value, g_atomic_int_get (&overlay->max_page_timeout)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstStateChangeReturn +gst_dvbsub_overlay_change_state (GstElement * element, + GstStateChange transition) +{ + GstDVBSubOverlay *render = GST_DVBSUB_OVERLAY (element); + GstStateChangeReturn ret; + + switch (transition) { + case GST_STATE_CHANGE_READY_TO_PAUSED: + gst_segment_init (&render->video_segment, GST_FORMAT_TIME); + gst_segment_init (&render->subtitle_segment, GST_FORMAT_TIME); + break; + case GST_STATE_CHANGE_NULL_TO_READY: + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + switch (transition) { + case GST_STATE_CHANGE_PAUSED_TO_READY: + gst_dvbsub_overlay_flush_subtitles (render); + gst_segment_init (&render->video_segment, GST_FORMAT_TIME); + gst_segment_init (&render->subtitle_segment, GST_FORMAT_TIME); + render->format = GST_VIDEO_FORMAT_UNKNOWN; + break; + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + case GST_STATE_CHANGE_READY_TO_NULL: + default: + break; + } + + + return ret; +} + +static gboolean +gst_dvbsub_overlay_query_src (GstPad * pad, GstQuery * query) +{ + GstDVBSubOverlay *render = GST_DVBSUB_OVERLAY (gst_pad_get_parent (pad)); + gboolean ret; + + ret = gst_pad_peer_query (render->video_sinkpad, query); + + gst_object_unref (render); + return ret; +} + +static gboolean +gst_dvbsub_overlay_event_src (GstPad * pad, GstEvent * event) +{ + GstDVBSubOverlay *render = GST_DVBSUB_OVERLAY (gst_pad_get_parent (pad)); + gboolean ret = FALSE; + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_SEEK:{ + GstSeekFlags flags; + + GST_DEBUG_OBJECT (render, "seek received, driving from here"); + + gst_event_parse_seek (event, NULL, NULL, &flags, NULL, NULL, NULL, NULL); + + /* Flush downstream, only for flushing seek */ + if (flags & GST_SEEK_FLAG_FLUSH) + gst_pad_push_event (render->srcpad, gst_event_new_flush_start ()); + + gst_dvbsub_overlay_flush_subtitles (render); + + /* Seek on each sink pad */ + gst_event_ref (event); + ret = gst_pad_push_event (render->video_sinkpad, event); + if (ret) { + ret = gst_pad_push_event (render->text_sinkpad, event); + } else { + gst_event_unref (event); + } + break; + } + default: + gst_event_ref (event); + ret = gst_pad_push_event (render->video_sinkpad, event); + gst_pad_push_event (render->text_sinkpad, event); + break; + } + + gst_object_unref (render); + + return ret; +} + +static GstCaps * +gst_dvbsub_overlay_getcaps (GstPad * pad) +{ + GstDVBSubOverlay *render = GST_DVBSUB_OVERLAY (gst_pad_get_parent (pad)); + GstPad *otherpad; + GstCaps *caps; + + if (pad == render->srcpad) + otherpad = render->video_sinkpad; + else + otherpad = render->srcpad; + + /* we can do what the peer can */ + caps = gst_pad_peer_get_caps (otherpad); + if (caps) { + GstCaps *temp; + const GstCaps *templ; + + /* filtered against our padtemplate */ + templ = gst_pad_get_pad_template_caps (otherpad); + temp = gst_caps_intersect (caps, templ); + gst_caps_unref (caps); + /* this is what we can do */ + caps = temp; + } else { + /* no peer, our padtemplate is enough then */ + caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); + } + + gst_object_unref (render); + + return caps; +} + +static void +blit_i420 (GstDVBSubOverlay * overlay, DVBSubtitles * subs, GstBuffer * buffer) +{ + guint counter; + DVBSubtitleRect *sub_region; + gint a1, a2, a3, a4; + gint y1, y2, y3, y4; + gint u1, u2, u3, u4; + gint v1, v2, v3, v4; + guint32 color; + const guint8 *src; + guint8 *dst_y, *dst_y2, *dst_u, *dst_v; + gint x, y; + gint w2, h2; + gint width = overlay->width; + gint height = overlay->height; + gint src_stride; + gint y_offset, y_height, y_width, y_stride; + gint u_offset, u_height, u_width, u_stride; + gint v_offset, v_height, v_width, v_stride; + gint scale = 0; + gint scale_x = 0, scale_y = 0; /* 16.16 fixed point */ + + y_offset = + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 0, width, + height); + u_offset = + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 1, width, + height); + v_offset = + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 2, width, + height); + + y_height = + gst_video_format_get_component_height (GST_VIDEO_FORMAT_I420, 0, height); + u_height = + gst_video_format_get_component_height (GST_VIDEO_FORMAT_I420, 1, height); + v_height = + gst_video_format_get_component_height (GST_VIDEO_FORMAT_I420, 2, height); + + y_width = + gst_video_format_get_component_width (GST_VIDEO_FORMAT_I420, 0, width); + u_width = + gst_video_format_get_component_width (GST_VIDEO_FORMAT_I420, 1, width); + v_width = + gst_video_format_get_component_width (GST_VIDEO_FORMAT_I420, 2, width); + + y_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, width); + u_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, width); + v_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 2, width); + + if (width != subs->display_def.display_width && + height != subs->display_def.display_height) { + scale = 1; + if (subs->display_def.window_flag) { + scale_x = (width << 16) / subs->display_def.window_width; + scale_y = (height << 16) / subs->display_def.window_height; + } else { + scale_x = (width << 16) / subs->display_def.display_width; + scale_y = (height << 16) / subs->display_def.display_height; + } + } + + for (counter = 0; counter < subs->num_rects; counter++) { + gint dw, dh, dx, dy; + gint32 sx = 0, sy; /* 16.16 fixed point */ + gint32 xstep, ystep; /* 16.16 fixed point */ + + sub_region = &subs->rects[counter]; + if (sub_region->y > height || sub_region->x > width) + continue; + + /* blend subtitles onto the video frame */ + dx = sub_region->x; + dy = sub_region->y; + dw = sub_region->w; + dh = sub_region->h; + + if (scale) { + dx = (dx * scale_x) >> 16; + dy = (dy * scale_y) >> 16; + dw = (dw * scale_x) >> 16; + dh = (dh * scale_y) >> 16; + /* apply subtitle window offsets after scaling */ + if (subs->display_def.window_flag) { + dx += subs->display_def.window_x; + dy += subs->display_def.window_y; + } + } + + dw = MIN (dw, width - dx); + dh = MIN (dh, height - dx); + + xstep = (sub_region->w << 16) / dw; + ystep = (sub_region->h << 16) / dh; + + w2 = (dw + 1) / 2; + h2 = (dh + 1) / 2; + + src_stride = sub_region->pict.rowstride; + + src = sub_region->pict.data; + dst_y = buffer->data + y_offset + dy * y_stride + dx; + dst_y2 = buffer->data + y_offset + (dy + 1) * y_stride + dx; + dst_u = buffer->data + u_offset + ((dy + 1) / 2) * u_stride + (dx + 1) / 2; + dst_v = buffer->data + v_offset + ((dy + 1) / 2) * v_stride + (dx + 1) / 2; + + sy = 0; + for (y = 0; y < dh - 1; y += 2) { + sx = 0; + for (x = 0; x < dw - 1; x += 2) { + + color = + sub_region->pict.palette[src[(sy >> 16) * src_stride + (sx >> 16)]]; + a1 = (color >> 24) & 0xff; + y1 = (color >> 16) & 0xff; + u1 = (color >> 8) & 0xff; + v1 = color & 0xff; + + color = + sub_region->pict.palette[src[(sy >> 16) * src_stride + ((sx + + xstep) >> 16)]]; + a2 = (color >> 24) & 0xff; + y2 = (color >> 16) & 0xff; + u2 = (color >> 8) & 0xff; + v2 = color & 0xff; + + color = + sub_region->pict.palette[src[((sy + ystep) >> 16) * src_stride + + (sx >> 16)]]; + a3 = (color >> 24) & 0xff; + y3 = (color >> 16) & 0xff; + u3 = (color >> 8) & 0xff; + v3 = color & 0xff; + + color = + sub_region->pict.palette[src[((sy + ystep) >> 16) * src_stride + + ((sx + xstep) >> 16)]]; + a4 = (color >> 24) & 0xff; + y4 = (color >> 16) & 0xff; + u4 = (color >> 8) & 0xff; + v4 = color & 0xff; + + dst_y[0] = (a1 * y1 + (255 - a1) * dst_y[0]) / 255; + dst_y[1] = (a2 * y2 + (255 - a2) * dst_y[1]) / 255; + dst_y2[0] = (a3 * y3 + (255 - a3) * dst_y2[0]) / 255; + dst_y2[1] = (a4 * y4 + (255 - a4) * dst_y2[1]) / 255; + + a1 = (a1 + a2 + a3 + a4) / 4; + dst_u[0] = + (a1 * ((u1 + u2 + u3 + u4) / 4) + (255 - a1) * dst_u[0]) / 255; + dst_v[0] = + (a1 * ((v1 + v2 + v3 + v4) / 4) + (255 - a1) * dst_v[0]) / 255; + + dst_y += 2; + dst_y2 += 2; + dst_u += 1; + dst_v += 1; + sx += 2 * xstep; + } + + /* Odd width */ + if (x < dw) { + color = + sub_region->pict.palette[src[(sy >> 16) * src_stride + (sx >> 16)]]; + a1 = (color >> 24) & 0xff; + y1 = (color >> 16) & 0xff; + u1 = (color >> 8) & 0xff; + v1 = color & 0xff; + + color = + sub_region->pict.palette[src[((sy + ystep) >> 16) * src_stride + + (sx >> 16)]]; + a3 = (color >> 24) & 0xff; + y3 = (color >> 16) & 0xff; + u3 = (color >> 8) & 0xff; + v3 = color & 0xff; + + dst_y[0] = (a1 * y1 + (255 - a1) * dst_y[0]) / 255; + dst_y2[0] = (a3 * y3 + (255 - a3) * dst_y2[0]) / 255; + + a1 = (a1 + a3) / 2; + dst_u[0] = (a1 * ((u1 + u3) / 2) + (255 - a1) * dst_u[0]) / 255; + dst_v[0] = (a1 * ((v1 + v3) / 2) + (255 - a1) * dst_v[0]) / 255; + + dst_y += 1; + dst_y2 += 1; + dst_u += 1; + dst_v += 1; + sx += xstep; + } + + sy += 2 * ystep; + + dst_y += y_stride + (y_stride - dw); + dst_y2 += y_stride + (y_stride - dw); + dst_u += u_stride - w2; + dst_v += v_stride - w2; + } + + /* Odd height */ + if (y < dh) { + sx = 0; + for (x = 0; x < dw - 1; x += 2) { + color = + sub_region->pict.palette[src[(sy >> 16) * src_stride + (sx >> 16)]]; + a1 = (color >> 24) & 0xff; + y1 = (color >> 16) & 0xff; + u1 = (color >> 8) & 0xff; + v1 = color & 0xff; + + color = + sub_region->pict.palette[src[(sy >> 16) * src_stride + ((sx + + xstep) >> 16)]]; + a2 = (color >> 24) & 0xff; + y2 = (color >> 16) & 0xff; + u2 = (color >> 8) & 0xff; + v2 = color & 0xff; + + dst_y[0] = (a1 * y1 + (255 - a1) * dst_y[0]) / 255; + dst_y[1] = (a2 * y2 + (255 - a2) * dst_y[1]) / 255; + + a1 = (a1 + a2) / 2; + dst_u[0] = (a1 * ((u1 + u2) / 2) + (255 - a1) * dst_u[0]) / 255; + dst_v[0] = (a1 * ((v1 + v2) / 2) + (255 - a1) * dst_v[0]) / 255; + + dst_y += 2; + dst_u += 1; + dst_v += 1; + sx += 2 * xstep; + } + + /* Odd height and width */ + if (x < dw) { + color = + sub_region->pict.palette[src[(sy >> 16) * src_stride + (sx >> 16)]]; + a1 = (color >> 24) & 0xff; + y1 = (color >> 16) & 0xff; + u1 = (color >> 8) & 0xff; + v1 = color & 0xff; + + dst_y[0] = (a1 * y1 + (255 - a1) * dst_y[0]) / 255; + + dst_u[0] = (a1 * u1 + (255 - a1) * dst_u[0]) / 255; + dst_v[0] = (a1 * v1 + (255 - a1) * dst_v[0]) / 255; + + dst_y += 1; + dst_u += 1; + dst_v += 1; + sx += xstep; + } + } + } + + GST_LOG_OBJECT (overlay, "amount of rendered DVBSubtitleRect: %u", counter); +} + +static gboolean +gst_dvbsub_overlay_setcaps_video (GstPad * pad, GstCaps * caps) +{ + GstDVBSubOverlay *render = GST_DVBSUB_OVERLAY (gst_pad_get_parent (pad)); + gboolean ret = FALSE; + + render->width = 0; + render->height = 0; + + if (!gst_video_format_parse_caps (caps, &render->format, &render->width, + &render->height) || + !gst_video_parse_caps_framerate (caps, &render->fps_n, &render->fps_d)) { + GST_ERROR_OBJECT (render, "Can't parse caps: %" GST_PTR_FORMAT, caps); + ret = FALSE; + goto out; + } + + gst_video_parse_caps_pixel_aspect_ratio (caps, &render->par_n, + &render->par_d); + + ret = gst_pad_set_caps (render->srcpad, caps); + if (!ret) + goto out; + + GST_DEBUG_OBJECT (render, "ass renderer setup complete"); + +out: + gst_object_unref (render); + + return ret; +} + +static void +gst_dvbsub_overlay_process_text (GstDVBSubOverlay * overlay, GstBuffer * buffer, + guint64 pts) +{ + guint8 *data = (guint8 *) GST_BUFFER_DATA (buffer); + guint size = GST_BUFFER_SIZE (buffer); + + GST_DEBUG_OBJECT (overlay, + "Processing subtitles with fake PTS=%" G_GUINT64_FORMAT + " which is a running time of %" GST_TIME_FORMAT, + pts, GST_TIME_ARGS (pts)); + GST_DEBUG_OBJECT (overlay, "Feeding %u bytes to libdvbsub", size); + g_mutex_lock (overlay->dvbsub_mutex); + dvb_sub_feed_with_pts (overlay->dvb_sub, pts, data, size); + g_mutex_unlock (overlay->dvbsub_mutex); + gst_buffer_unref (buffer); +} + +static void +new_dvb_subtitles_cb (DvbSub * dvb_sub, DVBSubtitles * subs, gpointer user_data) +{ + GstDVBSubOverlay *overlay = GST_DVBSUB_OVERLAY (user_data); + int max_page_timeout; + + max_page_timeout = g_atomic_int_get (&overlay->max_page_timeout); + if (max_page_timeout > 0) + subs->page_time_out = MIN (subs->page_time_out, max_page_timeout); + + GST_INFO_OBJECT (overlay, + "New DVB subtitles arrived with a page_time_out of %d and %d regions for PTS=%" + G_GUINT64_FORMAT ", which should be at running time %" GST_TIME_FORMAT, + subs->page_time_out, subs->num_rects, subs->pts, + GST_TIME_ARGS (subs->pts)); + + g_queue_push_tail (overlay->pending_subtitles, subs); +} + +static GstFlowReturn +gst_dvbsub_overlay_bufferalloc_video (GstPad * pad, guint64 offset, guint size, + GstCaps * caps, GstBuffer ** buffer) +{ + GstDVBSubOverlay *render = GST_DVBSUB_OVERLAY (gst_pad_get_parent (pad)); + GstFlowReturn ret = GST_FLOW_WRONG_STATE; + GstPad *allocpad; + + GST_OBJECT_LOCK (render); + allocpad = render->srcpad ? gst_object_ref (render->srcpad) : NULL; + GST_OBJECT_UNLOCK (render); + + if (allocpad) { + ret = gst_pad_alloc_buffer (allocpad, offset, size, caps, buffer); + gst_object_unref (allocpad); + } + + gst_object_unref (render); + + return ret; +} + +static GstFlowReturn +gst_dvbsub_overlay_chain_text (GstPad * pad, GstBuffer * buffer) +{ + GstDVBSubOverlay *overlay = GST_DVBSUB_OVERLAY (GST_PAD_PARENT (pad)); + GstClockTime sub_running_time; + + GST_INFO_OBJECT (overlay, "subpicture/x-dvb buffer with size %u", + GST_BUFFER_SIZE (buffer)); + + GST_LOG_OBJECT (overlay, + "Video segment: %" GST_SEGMENT_FORMAT " --- Subtitle segment: %" + GST_SEGMENT_FORMAT " --- BUFFER: ts=%" GST_TIME_FORMAT, + &overlay->video_segment, &overlay->subtitle_segment, + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer))); + + /* DVB subtitle packets are required to carry the PTS */ + if (G_UNLIKELY (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer))) { + GST_WARNING_OBJECT (overlay, + "Text buffer without valid timestamp, dropping"); + gst_buffer_unref (buffer); + return GST_FLOW_OK; + } + + /* As the passed start and stop is equal, we shouldn't need to care about out of segment at all, + * the subtitle data for the PTS is completely out of interest to us. A given display set must + * carry the same PTS value. */ + /* FIXME: Consider with larger than 64kB display sets, which would be cut into multiple packets, + * FIXME: does our waiting + render code work when there are more than one packets before + * FIXME: rendering callback will get called? */ + + gst_segment_set_last_stop (&overlay->subtitle_segment, GST_FORMAT_TIME, + GST_BUFFER_TIMESTAMP (buffer)); + + sub_running_time = + gst_segment_to_running_time (&overlay->subtitle_segment, GST_FORMAT_TIME, + GST_BUFFER_TIMESTAMP (buffer)); + + GST_DEBUG_OBJECT (overlay, "SUBTITLE real running time: %" GST_TIME_FORMAT, + GST_TIME_ARGS (sub_running_time)); + + /* FIXME: We are abusing libdvbsub pts value for tracking our gstreamer running time instead of real PTS. Should be mostly fine though... */ + gst_dvbsub_overlay_process_text (overlay, buffer, sub_running_time); + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_dvbsub_overlay_chain_video (GstPad * pad, GstBuffer * buffer) +{ + GstDVBSubOverlay *overlay = GST_DVBSUB_OVERLAY (GST_PAD_PARENT (pad)); + GstFlowReturn ret = GST_FLOW_OK; + gint64 start, stop; + gint64 cstart, cstop; + gboolean in_seg; + GstClockTime vid_running_time, vid_running_time_end; + + if (overlay->format == GST_VIDEO_FORMAT_UNKNOWN) + return GST_FLOW_NOT_NEGOTIATED; + + if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) + goto missing_timestamp; + + start = GST_BUFFER_TIMESTAMP (buffer); + + GST_LOG_OBJECT (overlay, + "Video segment: %" GST_SEGMENT_FORMAT " --- Subtitle last_stop: %" + GST_TIME_FORMAT " --- BUFFER: ts=%" GST_TIME_FORMAT, + &overlay->video_segment, + GST_TIME_ARGS (overlay->subtitle_segment.last_stop), + GST_TIME_ARGS (start)); + + /* ignore buffers that are outside of the current segment */ + if (!GST_BUFFER_DURATION_IS_VALID (buffer)) { + stop = GST_CLOCK_TIME_NONE; + } else { + stop = start + GST_BUFFER_DURATION (buffer); + } + + in_seg = gst_segment_clip (&overlay->video_segment, GST_FORMAT_TIME, + start, stop, &cstart, &cstop); + if (!in_seg) { + GST_DEBUG_OBJECT (overlay, "Buffer outside configured segment -- dropping"); + gst_buffer_unref (buffer); + return GST_FLOW_OK; + } + + buffer = gst_buffer_make_metadata_writable (buffer); + GST_BUFFER_TIMESTAMP (buffer) = cstart; + if (GST_BUFFER_DURATION_IS_VALID (buffer)) + GST_BUFFER_DURATION (buffer) = cstop - cstart; + + vid_running_time = + gst_segment_to_running_time (&overlay->video_segment, GST_FORMAT_TIME, + cstart); + if (GST_BUFFER_DURATION_IS_VALID (buffer)) + vid_running_time_end = + gst_segment_to_running_time (&overlay->video_segment, GST_FORMAT_TIME, + cstop); + else + vid_running_time_end = vid_running_time; + + GST_DEBUG_OBJECT (overlay, "Video running time: %" GST_TIME_FORMAT, + GST_TIME_ARGS (vid_running_time)); + + gst_segment_set_last_stop (&overlay->video_segment, GST_FORMAT_TIME, + GST_BUFFER_TIMESTAMP (buffer)); + + g_mutex_lock (overlay->dvbsub_mutex); + if (!g_queue_is_empty (overlay->pending_subtitles)) { + DVBSubtitles *tmp, *candidate = NULL; + + while (!g_queue_is_empty (overlay->pending_subtitles)) { + tmp = g_queue_peek_head (overlay->pending_subtitles); + + if (tmp->pts > vid_running_time_end) { + /* For a future video frame */ + break; + } else if (tmp->num_rects == 0) { + /* Clear screen */ + if (overlay->current_subtitle) + dvb_subtitles_free (overlay->current_subtitle); + overlay->current_subtitle = NULL; + if (candidate) + dvb_subtitles_free (candidate); + candidate = NULL; + g_queue_pop_head (overlay->pending_subtitles); + dvb_subtitles_free (tmp); + tmp = NULL; + } else if (tmp->pts + tmp->page_time_out * GST_SECOND * + overlay->subtitle_segment.abs_rate >= vid_running_time) { + if (candidate) + dvb_subtitles_free (candidate); + candidate = tmp; + g_queue_pop_head (overlay->pending_subtitles); + } else { + /* Too late */ + dvb_subtitles_free (tmp); + tmp = NULL; + g_queue_pop_head (overlay->pending_subtitles); + } + } + + if (candidate) { + GST_DEBUG_OBJECT (overlay, + "Time to show the next subtitle page (%" GST_TIME_FORMAT " >= %" + GST_TIME_FORMAT ") - it has %u regions", + GST_TIME_ARGS (vid_running_time), GST_TIME_ARGS (candidate->pts), + candidate->num_rects); + dvb_subtitles_free (overlay->current_subtitle); + overlay->current_subtitle = candidate; + /* FIXME: Pre-convert current_subtitle to a quick-blend format, num_rects=0 means that there are no regions, e.g, a subtitle "clear" happened */ + } + } + + /* Check that we haven't hit the fallback timeout for current subtitle page */ + if (overlay->current_subtitle + && vid_running_time > + (overlay->current_subtitle->pts + + overlay->current_subtitle->page_time_out * GST_SECOND * + overlay->subtitle_segment.abs_rate)) { + GST_INFO_OBJECT (overlay, + "Subtitle page not redefined before fallback page_time_out of %u seconds (missed data?) - deleting current page", + overlay->current_subtitle->page_time_out); + dvb_subtitles_free (overlay->current_subtitle); + overlay->current_subtitle = NULL; + } + + /* Now render it */ + if (g_atomic_int_get (&overlay->enable) && overlay->current_subtitle) { + buffer = gst_buffer_make_writable (buffer); + blit_i420 (overlay, overlay->current_subtitle, buffer); + } + g_mutex_unlock (overlay->dvbsub_mutex); + + ret = gst_pad_push (overlay->srcpad, buffer); + + return ret; + +missing_timestamp: + { + GST_WARNING_OBJECT (overlay, "video buffer without timestamp, discarding"); + gst_buffer_unref (buffer); + return GST_FLOW_OK; + } +} + +static gboolean +gst_dvbsub_overlay_event_video (GstPad * pad, GstEvent * event) +{ + gboolean ret = FALSE; + GstDVBSubOverlay *render = GST_DVBSUB_OVERLAY (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT (pad, "received video event %s", + GST_EVENT_TYPE_NAME (event)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NEWSEGMENT: + { + GstFormat format; + gdouble rate; + gint64 start, stop, time; + gboolean update; + + GST_DEBUG_OBJECT (render, "received new segment"); + + gst_event_parse_new_segment (event, &update, &rate, &format, &start, + &stop, &time); + + if (format == GST_FORMAT_TIME) { + GST_DEBUG_OBJECT (render, "VIDEO SEGMENT now: %" GST_SEGMENT_FORMAT, + &render->video_segment); + + gst_segment_set_newsegment (&render->video_segment, update, rate, + format, start, stop, time); + + GST_DEBUG_OBJECT (render, "VIDEO SEGMENT after: %" GST_SEGMENT_FORMAT, + &render->video_segment); + ret = gst_pad_push_event (render->srcpad, event); + } else { + GST_ELEMENT_WARNING (render, STREAM, MUX, (NULL), + ("received non-TIME newsegment event on video input")); + ret = FALSE; + gst_event_unref (event); + } + break; + } + case GST_EVENT_FLUSH_STOP: + gst_segment_init (&render->video_segment, GST_FORMAT_TIME); + default: + ret = gst_pad_push_event (render->srcpad, event); + break; + } + + gst_object_unref (render); + + return ret; +} + +static gboolean +gst_dvbsub_overlay_event_text (GstPad * pad, GstEvent * event) +{ + gboolean ret = FALSE; + GstDVBSubOverlay *render = GST_DVBSUB_OVERLAY (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT (pad, "received text event %s", GST_EVENT_TYPE_NAME (event)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NEWSEGMENT: + { + GstFormat format; + gdouble rate; + gint64 start, stop, time; + gboolean update; + + GST_DEBUG_OBJECT (render, "received new segment"); + + gst_event_parse_new_segment (event, &update, &rate, &format, &start, + &stop, &time); + + if (format == GST_FORMAT_TIME) { + GST_DEBUG_OBJECT (render, "SUBTITLE SEGMENT now: %" GST_SEGMENT_FORMAT, + &render->subtitle_segment); + + gst_segment_set_newsegment (&render->subtitle_segment, update, rate, + format, start, stop, time); + + GST_DEBUG_OBJECT (render, + "SUBTITLE SEGMENT after: %" GST_SEGMENT_FORMAT, + &render->subtitle_segment); + ret = TRUE; + gst_event_unref (event); + } else { + GST_ELEMENT_WARNING (render, STREAM, MUX, (NULL), + ("received non-TIME newsegment event on subtitle sinkpad")); + ret = FALSE; + gst_event_unref (event); + } + break; + } + case GST_EVENT_FLUSH_STOP: + GST_DEBUG_OBJECT (render, "stop flushing"); + gst_dvbsub_overlay_flush_subtitles (render); + gst_segment_init (&render->subtitle_segment, GST_FORMAT_TIME); + gst_event_unref (event); + ret = TRUE; + break; + case GST_EVENT_FLUSH_START: + GST_DEBUG_OBJECT (render, "begin flushing"); + gst_event_unref (event); + ret = TRUE; + break; + case GST_EVENT_EOS: + GST_INFO_OBJECT (render, "text EOS"); + gst_event_unref (event); + ret = TRUE; + break; + default: + ret = gst_pad_push_event (render->srcpad, event); + break; + } + + gst_object_unref (render); + + return ret; +} + +static gboolean +plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (gst_dvbsub_overlay_debug, "dvbsuboverlay", + 0, "DVB subtitle overlay"); + + return gst_element_register (plugin, "dvbsuboverlay", + GST_RANK_PRIMARY, GST_TYPE_DVBSUB_OVERLAY); +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "dvbsuboverlay", + "DVB subtitle renderer", + plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/gst/dvbsuboverlay/gstdvbsuboverlay.h b/gst/dvbsuboverlay/gstdvbsuboverlay.h new file mode 100644 index 000000000..19835c6c6 --- /dev/null +++ b/gst/dvbsuboverlay/gstdvbsuboverlay.h @@ -0,0 +1,74 @@ +/* GStreamer DVB subtitles overlay + * Copyright (c) 2010 Mart Raudsepp <mart.raudsepp@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_DVBSUB_OVERLAY_H__ +#define __GST_DVBSUB_OVERLAY_H__ + +#include <gst/gst.h> +#include <gst/video/video.h> + +#include "dvb-sub.h" + +G_BEGIN_DECLS + +#define GST_TYPE_DVBSUB_OVERLAY (gst_dvbsub_overlay_get_type()) +#define GST_DVBSUB_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DVBSUB_OVERLAY,GstDVBSubOverlay)) +#define GST_DVBSUB_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DVBSUB_OVERLAY,GstDVBSubOverlayClass)) +#define GST_IS_DVBSUB_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DVBSUB_OVERLAY)) +#define GST_IS_DVBSUB_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DVBSUB_OVERLAY)) + +typedef struct _GstDVBSubOverlay GstDVBSubOverlay; +typedef struct _GstDVBSubOverlayClass GstDVBSubOverlayClass; + +struct _GstDVBSubOverlay +{ + GstElement element; + + GstPad *video_sinkpad, *text_sinkpad, *srcpad; + + /* properties */ + gboolean enable; + gint max_page_timeout; + + /* <private> */ + GstSegment video_segment; + GstSegment subtitle_segment; + + GstVideoFormat format; + gint width, height; + gint fps_n, fps_d; + gint par_n, par_d; + + DVBSubtitles *current_subtitle; /* The currently active set of subtitle regions, if any */ + GQueue *pending_subtitles; /* A queue of raw subtitle region sets with + * metadata that are waiting their running time */ + + GMutex *dvbsub_mutex; /* protects the queue and the DvbSub instance */ + DvbSub *dvb_sub; +}; + +struct _GstDVBSubOverlayClass +{ + GstElementClass parent_class; +}; + +GType gst_dvbsub_overlay_get_type (void); + +G_END_DECLS + +#endif diff --git a/gst/dvdspu/gstspu-vobsub-render.c b/gst/dvdspu/gstspu-vobsub-render.c index 30de0eb80..830017d33 100644 --- a/gst/dvdspu/gstspu-vobsub-render.c +++ b/gst/dvdspu/gstspu-vobsub-render.c @@ -37,15 +37,33 @@ gstspu_vobsub_recalc_palette (GstDVDSpu * dvdspu, SpuState *state = &dvdspu->spu_state; gint i; - for (i = 0; i < 4; i++, dest++) { - guint32 col = state->vobsub.current_clut[idx[i]]; - - /* Convert incoming 4-bit alpha to 8 bit for blending */ - dest->A = (alpha[i] << 4) | alpha[i]; - dest->Y = ((guint16) ((col >> 16) & 0xff)) * dest->A; - /* U/V are stored as V/U in the clut words, so switch them */ - dest->V = ((guint16) ((col >> 8) & 0xff)) * dest->A; - dest->U = ((guint16) (col & 0xff)) * dest->A; + if (state->vobsub.current_clut[idx[0]] != 0) { + for (i = 0; i < 4; i++, dest++) { + guint32 col = state->vobsub.current_clut[idx[i]]; + + /* Convert incoming 4-bit alpha to 8 bit for blending */ + dest->A = (alpha[i] << 4) | alpha[i]; + dest->Y = ((guint16) ((col >> 16) & 0xff)) * dest->A; + /* U/V are stored as V/U in the clut words, so switch them */ + dest->V = ((guint16) ((col >> 8) & 0xff)) * dest->A; + dest->U = ((guint16) (col & 0xff)) * dest->A; + } + } else { + int y = 240; + + /* The CLUT presumably hasn't been set, so we'll just guess some + * values for the non-transparent colors (white, grey, black) */ + for (i = 0; i < 4; i++, dest++) { + dest->A = (alpha[i] << 4) | alpha[i]; + if (alpha[i] != 0) { + dest[0].Y = y * dest[0].A; + y -= 112; + if (y < 0) + y = 0; + } + dest[0].U = 128 * dest[0].A; + dest[0].V = 128 * dest[0].A; + } } } @@ -515,10 +533,11 @@ gstspu_vobsub_render (GstDVDSpu * dvdspu, GstBuffer * buf) /* Render odd line */ state->vobsub.comp_last_x_ptr = state->vobsub.comp_last_x + 1; gstspu_vobsub_render_line (state, planes, &state->vobsub.cur_offsets[1]); - /* Blend the accumulated UV compositing buffers onto the output */ - gstspu_vobsub_blend_comp_buffers (state, planes); if (!clip) { + /* Blend the accumulated UV compositing buffers onto the output */ + gstspu_vobsub_blend_comp_buffers (state, planes); + /* Update all the output pointers */ planes[0] += state->Y_stride; planes[1] += state->UV_stride; diff --git a/gst/frei0r/frei0r.h b/gst/frei0r/frei0r.h index 48c942dd4..9aed4453b 100644 --- a/gst/frei0r/frei0r.h +++ b/gst/frei0r/frei0r.h @@ -200,7 +200,7 @@ #ifndef INCLUDED_FREI0R_H #define INCLUDED_FREI0R_H -#include <inttypes.h> +#include <glib.h> /** * The frei0r API major version @@ -554,7 +554,7 @@ void f0r_get_param_value(f0r_instance_t instance, * \see f0r_update2 */ void f0r_update(f0r_instance_t instance, - double time, const uint32_t* inframe, uint32_t* outframe); + double time, const guint32* inframe, guint32* outframe); //--------------------------------------------------------------------------- @@ -581,10 +581,10 @@ void f0r_update(f0r_instance_t instance, */ void f0r_update2(f0r_instance_t instance, double time, - const uint32_t* inframe1, - const uint32_t* inframe2, - const uint32_t* inframe3, - uint32_t* outframe); + const guint32* inframe1, + const guint32* inframe2, + const guint32* inframe3, + guint32* outframe); //--------------------------------------------------------------------------- #endif diff --git a/gst/frei0r/gstfrei0r.h b/gst/frei0r/gstfrei0r.h index af2126542..490d6aae9 100644 --- a/gst/frei0r/gstfrei0r.h +++ b/gst/frei0r/gstfrei0r.h @@ -66,13 +66,13 @@ struct _GstFrei0rFuncTable { f0r_param_t param, int param_index); void (*update) (f0r_instance_t instance, - double time, const uint32_t* inframe, uint32_t* outframe); + double time, const guint32* inframe, guint32* outframe); void (*update2) (f0r_instance_t instance, double time, - const uint32_t* inframe1, - const uint32_t* inframe2, - const uint32_t* inframe3, - uint32_t* outframe); + const guint32* inframe1, + const guint32* inframe2, + const guint32* inframe3, + guint32* outframe); }; typedef enum { diff --git a/gst/gaudieffects/Makefile.am b/gst/gaudieffects/Makefile.am index 92b8ce5f9..e34e71c50 100644 --- a/gst/gaudieffects/Makefile.am +++ b/gst/gaudieffects/Makefile.am @@ -11,3 +11,5 @@ libgstgaudieffects_la_LIBTOOLFLAGS = --tag=disable-static noinst_HEADERS = \ gstburn.h gstchromium.h gstdilate.h gstdodge.h \ gstexclusion.h gstgaussblur.h gstplugin.h gstsolarize.h + +EXTRA_DIST = blur-example.py burn-example.py diff --git a/gst/gaudieffects/burn-example.py b/gst/gaudieffects/burn-example.py new file mode 100644 index 000000000..01080b909 --- /dev/null +++ b/gst/gaudieffects/burn-example.py @@ -0,0 +1,23 @@ +#!/usr/bin/python +import gobject; gobject.threads_init() +import pygst; pygst.require("0.10") +import gst + +p = gst.parse_launch (""" + v4l2src ! + ffmpegcolorspace ! queue ! video/x-raw-rgb,width=320,height=240,framerate=30/1 ! burn qos=true name=vf ! ffmpegcolorspace ! + timeoverlay ! xvimagesink + """) + +m = p.get_by_name ("vf") +m.set_property ("adjustment", 128) + +control = gst.Controller(m, "adjustment") +control.set_interpolation_mode("adjustment", gst.INTERPOLATE_LINEAR) +control.set("adjustment", 0 * gst.SECOND, 128) +control.set("adjustment", 5 * gst.SECOND, 256) +control.set("adjustment", 25 * gst.SECOND, 0) + +p.set_state (gst.STATE_PLAYING) + +gobject.MainLoop().run() diff --git a/gst/gaudieffects/gstburn.c b/gst/gaudieffects/gstburn.c index 582d5e85b..3d769356a 100644 --- a/gst/gaudieffects/gstburn.c +++ b/gst/gaudieffects/gstburn.c @@ -96,7 +96,6 @@ enum #define DEFAULT_ADJUSTMENT 175 -static gint gate_int (gint value, gint min, gint max); static void transform (guint32 * src, guint32 * dest, gint video_area, gint adjustment); @@ -289,24 +288,13 @@ gst_burn_plugin_init (GstPlugin * burn) } /*** Now the image processing work.... ***/ -/* Keep the values inbounds. */ -static gint -gate_int (gint value, gint min, gint max) -{ - if (value < min) { - return min; - } else if (value > max) { - return max; - } else { - return value; - } -} /* Transform processes each frame. */ static void transform (guint32 * src, guint32 * dest, gint video_area, gint adjustment) { - guint32 in, red, green, blue; + guint32 in; + gint red, green, blue, c; gint x; for (x = 0; x < video_area; x++) { @@ -316,13 +304,16 @@ transform (guint32 * src, guint32 * dest, gint video_area, gint adjustment) green = (in >> 8) & 0xff; blue = (in) & 0xff; - red = 256 - ((256 * (255 - red)) / (red + adjustment)); - green = 256 - ((256 * (255 - green)) / (green + adjustment)); - blue = 256 - ((256 * (255 - blue)) / (blue + adjustment)); + c = (red + adjustment); + red = c ? (256 - (256 * (255 - red) / c)) : 0; + c = (green + adjustment); + green = c ? (256 - (256 * (255 - green) / c)) : 0; + c = (blue + adjustment); + blue = c ? (256 - (256 * (255 - blue) / c)) : 0; - red = gate_int (red, 0, 255); - green = gate_int (green, 0, 255); - blue = gate_int (blue, 0, 255); + red = CLAMP (red, 0, 255); + green = CLAMP (green, 0, 255); + blue = CLAMP (blue, 0, 255); *dest++ = (red << 16) | (green << 8) | blue; } diff --git a/gst/gaudieffects/gstgaussblur.c b/gst/gaudieffects/gstgaussblur.c index 6691c4c36..6b1223e1d 100644 --- a/gst/gaudieffects/gstgaussblur.c +++ b/gst/gaudieffects/gstgaussblur.c @@ -307,7 +307,7 @@ make_gaussian_kernel (GaussBlur * gb, float sigma) int i, center, left, right; float sum, sum2; const float fe = -0.5 / (sigma * sigma); - const float dx = 1.0 / (sigma * sqrt (2 * M_PI)); + const float dx = 1.0 / (sigma * sqrt (2 * G_PI)); center = ceil (2.5 * fabs (sigma)); gb->windowsize = (int) (1 + 2 * center); @@ -330,7 +330,7 @@ make_gaussian_kernel (GaussBlur * gb, float sigma) left = center - 1; right = center + 1; for (i = 1; i <= center; i++, left--, right++) { - float fx = dx * pow (M_E, fe * i * i); + float fx = dx * pow (G_E, fe * i * i); gb->kernel[right] = gb->kernel[left] = fx; sum += 2 * fx; } diff --git a/gst/geometrictransform/gstrotate.c b/gst/geometrictransform/gstrotate.c index a7433cce0..6c5ba62cb 100644 --- a/gst/geometrictransform/gstrotate.c +++ b/gst/geometrictransform/gstrotate.c @@ -154,7 +154,7 @@ rotate_map (GstGeometricTransform * gt, gint x, gint y, gdouble * in_x, h = gt->height; /* our parameters */ - ar = rotate->angle * M_PI / 180.0; /* angle of rotation, degrees to radians */ + ar = rotate->angle * G_PI / 180.0; /* angle of rotation, degrees to radians */ /* get in and out centers */ cox = 0.5 * w; diff --git a/gst/h264parse/gsth264parse.c b/gst/h264parse/gsth264parse.c index 2a5d9a6bb..5ad43f2fc 100644 --- a/gst/h264parse/gsth264parse.c +++ b/gst/h264parse/gsth264parse.c @@ -869,7 +869,10 @@ gst_nal_decode_slice_header (GstH264Parse * h, GstNalBs * bs) return TRUE; } -GST_BOILERPLATE (GstH264Parse, gst_h264_parse, GstElement, GST_TYPE_ELEMENT); +typedef GstH264Parse GstLegacyH264Parse; +typedef GstH264ParseClass GstLegacyH264ParseClass; +GST_BOILERPLATE (GstLegacyH264Parse, gst_h264_parse, GstElement, + GST_TYPE_ELEMENT); static void gst_h264_parse_reset (GstH264Parse * h264parse); static void gst_h264_parse_finalize (GObject * object); @@ -900,7 +903,8 @@ gst_h264_parse_base_init (gpointer g_class) "Michal Benes <michal.benes@itonis.tv>," "Wim Taymans <wim.taymans@gmail.com>"); - GST_DEBUG_CATEGORY_INIT (h264_parse_debug, "h264parse", 0, "h264 parser"); + GST_DEBUG_CATEGORY_INIT (h264_parse_debug, "legacy h264parse", 0, + "legacy h264 parser"); } static void @@ -1016,6 +1020,14 @@ gst_h264_parse_reset (GstH264Parse * h264parse) h264parse->picture_start = FALSE; h264parse->idr_offset = -1; + if (h264parse->pending_segment) + gst_event_unref (h264parse->pending_segment); + h264parse->pending_segment = NULL; + + g_list_foreach (h264parse->pending_events, (GFunc) gst_event_unref, NULL); + g_list_free (h264parse->pending_events); + h264parse->pending_events = NULL; + gst_caps_replace (&h264parse->src_caps, NULL); } @@ -1023,23 +1035,14 @@ static void gst_h264_parse_finalize (GObject * object) { GstH264Parse *h264parse; - gint i; h264parse = GST_H264PARSE (object); + gst_h264_parse_reset (h264parse); + g_object_unref (h264parse->adapter); g_object_unref (h264parse->picture_adapter); - for (i = 0; i < MAX_SPS_COUNT; i++) { - if (h264parse->sps_buffers[i] != NULL) - g_slice_free (GstH264Sps, h264parse->sps_buffers[i]); - } - - for (i = 0; i < MAX_PPS_COUNT; i++) { - if (h264parse->pps_buffers[i] != NULL) - g_slice_free (GstH264Pps, h264parse->pps_buffers[i]); - } - G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -1599,6 +1602,23 @@ gst_h264_parse_push_buffer (GstH264Parse * h264parse, GstBuffer * buf) { GstFlowReturn ret = GST_FLOW_OK; + /* We can send pending events if this is the first call, since we now have + * caps for the srcpad */ + if (G_UNLIKELY (h264parse->pending_segment != NULL)) { + gst_pad_push_event (h264parse->srcpad, h264parse->pending_segment); + h264parse->pending_segment = NULL; + + if (G_UNLIKELY (h264parse->pending_events != NULL)) { + GList *l; + + for (l = h264parse->pending_events; l != NULL; l = l->next) + gst_pad_push_event (h264parse->srcpad, GST_EVENT (l->data)); + + g_list_free (h264parse->pending_events); + h264parse->pending_events = NULL; + } + } + /* start of picture is good time to slip in codec_data NALUs * (when outputting NALS and transforming to bytestream) */ if (G_UNLIKELY (h264parse->codec_nals && h264parse->picture_start)) { @@ -2583,6 +2603,11 @@ gst_h264_parse_sink_event (GstPad * pad, GstEvent * event) break; case GST_EVENT_EOS: GST_DEBUG_OBJECT (h264parse, "received EOS"); + if (h264parse->pending_segment) { + /* Send pending newsegment before EOS */ + gst_pad_push_event (h264parse->srcpad, h264parse->pending_segment); + h264parse->pending_segment = NULL; + } if (h264parse->segment.rate < 0.0) { gst_h264_parse_chain_reverse (h264parse, TRUE, NULL); gst_h264_parse_flush_decode (h264parse); @@ -2595,6 +2620,7 @@ gst_h264_parse_sink_event (GstPad * pad, GstEvent * event) GstFormat format; gint64 start, stop, pos; gboolean update; + GstEvent **ev; gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate, &format, &start, &stop, &pos); @@ -2604,17 +2630,35 @@ gst_h264_parse_sink_event (GstPad * pad, GstEvent * event) rate, applied_rate, format, start, stop, pos); GST_DEBUG_OBJECT (h264parse, - "Pushing newseg rate %g, applied rate %g, format %d, start %" + "Keeping newseg rate %g, applied rate %g, format %d, start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT ", pos %" G_GINT64_FORMAT, rate, applied_rate, format, start, stop, pos); - res = gst_pad_push_event (h264parse->srcpad, event); + ev = &h264parse->pending_segment; + gst_event_replace (ev, event); + gst_event_unref (event); + res = TRUE; break; } - default: + case GST_EVENT_FLUSH_START: + { res = gst_pad_push_event (h264parse->srcpad, event); break; + } + default: + { + if (G_UNLIKELY (h264parse->src_caps == NULL || + h264parse->pending_segment)) { + /* We don't yet have enough data to set caps on the srcpad, so collect + * non-critical events till we do */ + h264parse->pending_events = g_list_append (h264parse->pending_events, + event); + res = TRUE; + } else + res = gst_pad_push_event (h264parse->srcpad, event); + break; + } } gst_object_unref (h264parse); @@ -2655,7 +2699,7 @@ gst_h264_parse_change_state (GstElement * element, GstStateChange transition) static gboolean plugin_init (GstPlugin * plugin) { - return gst_element_register (plugin, "h264parse", + return gst_element_register (plugin, "legacyh264parse", GST_RANK_NONE, GST_TYPE_H264PARSE); } diff --git a/gst/h264parse/gsth264parse.h b/gst/h264parse/gsth264parse.h index 051353f06..e245ea001 100644 --- a/gst/h264parse/gsth264parse.h +++ b/gst/h264parse/gsth264parse.h @@ -137,6 +137,9 @@ struct _GstH264Parse GstBuffer *pps_nals[MAX_PPS_COUNT]; GstCaps *src_caps; + + GstEvent *pending_segment; + GList *pending_events; }; struct _GstH264ParseClass diff --git a/gst/id3tag/gstid3mux.c b/gst/id3tag/gstid3mux.c index 30995884c..43ab1a08b 100644 --- a/gst/id3tag/gstid3mux.c +++ b/gst/id3tag/gstid3mux.c @@ -214,7 +214,8 @@ plugin_init (GstPlugin * plugin) GST_DEBUG_CATEGORY_INIT (gst_id3_mux_debug, "id3mux", 0, "ID3 v1 and v2 tag muxer"); - if (!gst_element_register (plugin, "id3mux", GST_RANK_NONE, GST_TYPE_ID3_MUX)) + if (!gst_element_register (plugin, "id3mux", GST_RANK_PRIMARY, + GST_TYPE_ID3_MUX)) return FALSE; gst_tag_register_musicbrainz_tags (); diff --git a/gst/id3tag/id3tag.c b/gst/id3tag/id3tag.c index 272301bd1..2f3bebf84 100644 --- a/gst/id3tag/id3tag.c +++ b/gst/id3tag/id3tag.c @@ -1047,6 +1047,7 @@ static const struct GST_TAG_COPYRIGHT, add_text_tag, "TCOP"}, { GST_TAG_COMPOSER, add_text_tag, "TCOM"}, { GST_TAG_GENRE, add_text_tag, "TCON"}, { + GST_TAG_ENCODED_BY, add_text_tag, "TENC"}, { /* Private frames */ GST_ID3_DEMUX_TAG_ID3V2_FRAME, add_id3v2frame_tag, NULL}, { diff --git a/gst/jp2kdecimator/jp2kcodestream.c b/gst/jp2kdecimator/jp2kcodestream.c index e5c67e0d8..cbff65414 100644 --- a/gst/jp2kdecimator/jp2kcodestream.c +++ b/gst/jp2kdecimator/jp2kcodestream.c @@ -413,8 +413,8 @@ init_packet_iterator (GstJP2kDecimator * self, PacketIterator * it, it->n_layers = (tile->cod) ? tile->cod->n_layers : header->cod.n_layers; it->n_resolutions = 1 + - ((tile->cod) ? tile->cod->n_decompositions : header-> - cod.n_decompositions); + ((tile->cod) ? tile->cod->n_decompositions : header->cod. + n_decompositions); it->n_components = header->siz.n_components; it->tx0 = tile->tx0; @@ -457,8 +457,8 @@ init_packet_iterator (GstJP2kDecimator * self, PacketIterator * it, } order = - (tile->cod) ? tile->cod->progression_order : header-> - cod.progression_order; + (tile->cod) ? tile->cod->progression_order : header->cod. + progression_order; if (order == PROGRESSION_ORDER_LRCP) { it->next = packet_iterator_next_lrcp; } else if (order == PROGRESSION_ORDER_RLCP) { @@ -574,8 +574,8 @@ parse_cod (GstJP2kDecimator * self, GstByteReader * reader, } Scod = gst_byte_reader_get_uint8_unchecked (reader); - cod->sop = ! !(Scod & 0x02); - cod->eph = ! !(Scod & 0x04); + cod->sop = !!(Scod & 0x02); + cod->eph = !!(Scod & 0x04); /* SGcod */ cod->progression_order = gst_byte_reader_get_uint8_unchecked (reader); @@ -642,8 +642,8 @@ write_cod (GstJP2kDecimator * self, GstByteWriter * writer, /* Scod */ tmp = - (cod->PPx ? 0x01 : 0x00) | (cod-> - sop ? 0x02 : 0x00) | (cod->eph ? 0x04 : 0x00); + (cod->PPx ? 0x01 : 0x00) | (cod->sop ? 0x02 : 0x00) | (cod-> + eph ? 0x04 : 0x00); gst_byte_writer_put_uint8_unchecked (writer, tmp); /* SGcod */ @@ -839,8 +839,8 @@ parse_packet (GstJP2kDecimator * self, GstByteReader * reader, const MainHeader * header, Tile * tile, const PacketIterator * it) { GstFlowReturn ret = GST_FLOW_OK; - guint16 marker, length; - guint16 seqno; + guint16 marker = 0, length; + guint16 seqno = 0; guint packet_start_pos; const guint8 *packet_start_data; gboolean sop, eph; @@ -1031,7 +1031,7 @@ parse_tile (GstJP2kDecimator * self, GstByteReader * reader, const MainHeader * header, Tile * tile) { GstFlowReturn ret = GST_FLOW_OK; - guint16 marker, length; + guint16 marker = 0, length; if (!gst_byte_reader_peek_uint16_be (reader, &marker)) { GST_ERROR_OBJECT (self, "Could not read marker"); @@ -1425,7 +1425,7 @@ parse_main_header (GstJP2kDecimator * self, GstByteReader * reader, MainHeader * header) { GstFlowReturn ret = GST_FLOW_OK; - guint16 marker, length; + guint16 marker = 0, length = 0; /* First SOC */ if (!gst_byte_reader_get_uint16_be (reader, &marker) diff --git a/gst/jpegformat/gstjifmux.c b/gst/jpegformat/gstjifmux.c index 8e1bc267e..5308969bd 100644 --- a/gst/jpegformat/gstjifmux.c +++ b/gst/jpegformat/gstjifmux.c @@ -513,6 +513,7 @@ gst_jif_mux_mangle_markers (GstJifMux * self) } if (!tags) { tags = gst_tag_list_new (); + cleanup_tags = TRUE; } GST_DEBUG_OBJECT (self, "Tags to be serialized %" GST_PTR_FORMAT, tags); diff --git a/gst/jpegformat/gstjpegparse.c b/gst/jpegformat/gstjpegparse.c index d22dd46ab..ca9ac1f2f 100644 --- a/gst/jpegformat/gstjpegparse.c +++ b/gst/jpegformat/gstjpegparse.c @@ -289,9 +289,10 @@ gst_jpeg_parse_parse_tag_has_entropy_segment (guint8 tag) return FALSE; } -/* returns image length in bytes if parsed - * successfully, otherwise 0 if not enough data */ -static guint +/* returns image length in bytes if parsed successfully, + * otherwise 0 if more data needed, + * if < 0 the absolute value needs to be flushed */ +static gint gst_jpeg_parse_get_image_length (GstJpegParse * parse) { guint size; @@ -353,6 +354,13 @@ gst_jpeg_parse_get_image_length (GstJpegParse * parse) parse->priv->last_resync = FALSE; parse->priv->last_offset = 0; return (offset + 4); + } else if (value == 0xd8) { + /* Skip this frame if we found another SOI marker */ + GST_DEBUG ("0x%08x: SOI marker before EOI, skipping", offset + 2); + /* clear parse state */ + parse->priv->last_resync = FALSE; + parse->priv->last_offset = 0; + return -(offset + 2); } if (value >= 0xd0 && value <= 0xd7) @@ -406,6 +414,7 @@ gst_jpeg_parse_get_image_length (GstJpegParse * parse) if (noffset < 0) { /* ignore and continue resyncing until we hit the end * of our data or find a sync point that looks okay */ + offset++; continue; } GST_DEBUG ("found sync at 0x%x", offset + 2); @@ -506,7 +515,7 @@ static inline gboolean gst_jpeg_parse_skip_marker (GstJpegParse * parse, GstByteReader * reader, guint8 marker) { - guint16 size; + guint16 size = 0; if (!gst_byte_reader_get_uint16_be (reader, &size)) return FALSE; @@ -553,16 +562,26 @@ gst_jpeg_parse_read_header (GstJpegParse * parse, GstBuffer * buffer) case COM:{ /* read comment and post as tag */ const guint8 *comment = NULL; + gchar *comm; + const gchar *env_vars[] = { "GST_JPEG_TAG_ENCODING", + "GST_TAG_ENCODING", NULL + }; if (!gst_byte_reader_get_uint16_be (&reader, &size)) goto error; if (!gst_byte_reader_get_data (&reader, size - 2, &comment)) goto error; - if (!parse->priv->tags) - parse->priv->tags = gst_tag_list_new (); - gst_tag_list_add (parse->priv->tags, GST_TAG_MERGE_REPLACE, - GST_TAG_COMMENT, comment, NULL); + comm = (gchar *) comment; + comm = gst_tag_freeform_string_to_utf8 (comm, size - 2, env_vars); + + if (comm) { + if (!parse->priv->tags) + parse->priv->tags = gst_tag_list_new (); + gst_tag_list_add (parse->priv->tags, GST_TAG_MERGE_REPLACE, + GST_TAG_COMMENT, comm, NULL); + g_free (comm); + } break; } @@ -845,7 +864,7 @@ static GstFlowReturn gst_jpeg_parse_chain (GstPad * pad, GstBuffer * buf) { GstJpegParse *parse; - guint len; + gint len; GstClockTime timestamp, duration; GstFlowReturn ret = GST_FLOW_OK; @@ -864,8 +883,12 @@ gst_jpeg_parse_chain (GstPad * pad, GstBuffer * buf) /* check if we already have a EOI */ len = gst_jpeg_parse_get_image_length (parse); - if (len == 0) + if (len == 0) { return GST_FLOW_OK; + } else if (len < 0) { + gst_adapter_flush (parse->priv->adapter, -len); + continue; + } GST_LOG_OBJECT (parse, "parsed image of size %d", len); @@ -911,15 +934,17 @@ gst_jpeg_parse_sink_event (GstPad * pad, GstEvent * event) parse->priv->new_segment = TRUE; break; case GST_EVENT_TAG:{ - GstTagList *taglist = NULL; - gst_event_parse_tag (event, &taglist); if (!parse->priv->new_segment) res = gst_pad_event_default (pad, event); else { + GstTagList *taglist = NULL; + + gst_event_parse_tag (event, &taglist); /* Hold on to the tags till the srcpad caps are definitely set */ if (!parse->priv->tags) parse->priv->tags = gst_tag_list_new (); gst_tag_list_insert (parse->priv->tags, taglist, GST_TAG_MERGE_REPLACE); + gst_event_unref (event); } break; } diff --git a/gst/legacyresample/resample_functable.c b/gst/legacyresample/resample_functable.c index 6d6e26c0c..fc3e38a8b 100644 --- a/gst/legacyresample/resample_functable.c +++ b/gst/legacyresample/resample_functable.c @@ -28,6 +28,8 @@ #include <stdlib.h> #include <limits.h> +#include <gst/math-compat.h> + #include "_stdint.h" #include "resample.h" diff --git a/gst/legacyresample/resample_ref.c b/gst/legacyresample/resample_ref.c index 383e069e9..546e7cc9c 100644 --- a/gst/legacyresample/resample_ref.c +++ b/gst/legacyresample/resample_ref.c @@ -28,6 +28,7 @@ #include <stdlib.h> #include <limits.h> +#include <gst/math-compat.h> #include "_stdint.h" #include "resample.h" diff --git a/gst/librfb/rfbdecoder.c b/gst/librfb/rfbdecoder.c index 36e47aa41..53de8d14a 100644 --- a/gst/librfb/rfbdecoder.c +++ b/gst/librfb/rfbdecoder.c @@ -79,6 +79,7 @@ rfb_decoder_new (void) decoder->rect_width = 0; decoder->rect_height = 0; decoder->shared_flag = TRUE; + decoder->disconnected = FALSE; decoder->data = NULL; decoder->data_len = 0; @@ -129,6 +130,9 @@ rfb_decoder_connect_tcp (RfbDecoder * decoder, gchar * addr, guint port) return FALSE; } //rfb_decoder_use_file_descriptor (decoder, fd); + + decoder->disconnected = FALSE; + return TRUE; } @@ -178,6 +182,7 @@ rfb_decoder_read (RfbDecoder * decoder, guint32 len) now = recv (decoder->fd, (char *) decoder->data + total, len - total, 0); #endif if (now <= 0) { + decoder->disconnected = TRUE; GST_WARNING ("rfb read error on socket"); return NULL; } @@ -620,6 +625,13 @@ rfb_decoder_state_framebuffer_update_rectangle (RfbDecoder * decoder) GST_DEBUG ("w:%d h:%d", w, h); GST_DEBUG ("encoding: %d", encoding); + if (((w * h) + (x * y)) > (decoder->width * decoder->height)) { + GST_ERROR ("Desktop resize is unsupported."); + decoder->state = NULL; + decoder->disconnected = TRUE; + return TRUE; + } + switch (encoding) { case ENCODING_TYPE_RAW: rfb_decoder_raw_encoding (decoder, x, y, w, h); @@ -641,7 +653,7 @@ rfb_decoder_state_framebuffer_update_rectangle (RfbDecoder * decoder) break; } decoder->n_rects--; - if (decoder->n_rects == 0) { + if (decoder->n_rects == 0 || decoder->disconnected == TRUE) { decoder->state = NULL; } else { decoder->state = rfb_decoder_state_framebuffer_update_rectangle; diff --git a/gst/librfb/rfbdecoder.h b/gst/librfb/rfbdecoder.h index c9fb5f55d..33323ac26 100644 --- a/gst/librfb/rfbdecoder.h +++ b/gst/librfb/rfbdecoder.h @@ -48,6 +48,7 @@ struct _RfbDecoder /* settable properties */ gboolean shared_flag; + gboolean disconnected; /* readable properties */ gboolean inited; diff --git a/gst/mpeg4videoparse/mpeg4videoparse.c b/gst/mpeg4videoparse/mpeg4videoparse.c index 09f35212e..254db9fb7 100644 --- a/gst/mpeg4videoparse/mpeg4videoparse.c +++ b/gst/mpeg4videoparse/mpeg4videoparse.c @@ -65,9 +65,15 @@ gst_mpeg4vparse_set_new_caps (GstMpeg4VParse * parse, gint aspect_ratio_width, gint aspect_ratio_height, gint width, gint height) { gboolean res; - GstCaps *out_caps = gst_caps_new_simple ("video/mpeg", - "mpegversion", G_TYPE_INT, 4, - "systemstream", G_TYPE_BOOLEAN, FALSE, + GstCaps *out_caps; + + if (parse->sink_caps) { + out_caps = gst_caps_copy (parse->sink_caps); + } else { + out_caps = gst_caps_new_simple ("video/mpeg", + "mpegversion", G_TYPE_INT, 4, NULL); + } + gst_caps_set_simple (out_caps, "systemstream", G_TYPE_BOOLEAN, FALSE, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); if (parse->profile != 0) { @@ -112,6 +118,22 @@ gst_mpeg4vparse_set_new_caps (GstMpeg4VParse * parse, res = gst_pad_set_caps (parse->srcpad, out_caps); gst_caps_unref (out_caps); + parse->have_src_caps = TRUE; + if (parse->pending_segment != NULL) { + /* We can send pending events since we now have caps for the srcpad */ + gst_pad_push_event (parse->srcpad, parse->pending_segment); + parse->pending_segment = NULL; + + if (G_UNLIKELY (parse->pending_events != NULL)) { + GList *l; + + for (l = parse->pending_events; l != NULL; l = l->next) + gst_pad_push_event (parse->srcpad, GST_EVENT (l->data)); + + g_list_free (parse->pending_events); + parse->pending_events = NULL; + } + } return res; } @@ -480,9 +502,11 @@ gst_mpeg4vparse_push (GstMpeg4VParse * parse, gsize size) GstBuffer *out_buf; out_buf = gst_adapter_take_buffer (parse->adapter, parse->offset); - GST_BUFFER_TIMESTAMP (out_buf) = parse->timestamp; if (G_LIKELY (out_buf)) { + out_buf = gst_buffer_make_metadata_writable (out_buf); + GST_BUFFER_TIMESTAMP (out_buf) = parse->timestamp; + /* Set GST_BUFFER_FLAG_DELTA_UNIT if it's not an intra frame */ if (!parse->intra_frame) { GST_BUFFER_FLAG_SET (out_buf, GST_BUFFER_FLAG_DELTA_UNIT); @@ -517,10 +541,10 @@ gst_mpeg4vparse_push (GstMpeg4VParse * parse, gsize size) /* insert header */ superbuf = gst_buffer_merge (parse->config, out_buf); - - GST_BUFFER_TIMESTAMP (superbuf) = timestamp; gst_buffer_unref (out_buf); - out_buf = superbuf; + + out_buf = gst_buffer_make_metadata_writable (superbuf); + GST_BUFFER_TIMESTAMP (out_buf) = timestamp; if (G_UNLIKELY (timestamp != -1)) { parse->last_report = timestamp; @@ -710,6 +734,7 @@ gst_mpeg4vparse_sink_setcaps (GstPad * pad, GstCaps * caps) const GValue *value; GST_DEBUG_OBJECT (parse, "setcaps called with %" GST_PTR_FORMAT, caps); + parse->sink_caps = gst_caps_ref (caps); s = gst_caps_get_structure (caps, 0); @@ -731,6 +756,7 @@ gst_mpeg4vparse_sink_setcaps (GstPad * pad, GstCaps * caps) } else { const guint8 *data = GST_BUFFER_DATA (buf); + res = FALSE; if (data[0] == 0 && data[1] == 0 && data[2] == 1) { if (data[3] == VOS_STARTCODE) { /* Usually the codec data will be a visual object sequence, containing @@ -745,6 +771,8 @@ gst_mpeg4vparse_sink_setcaps (GstPad * pad, GstCaps * caps) res = gst_mpeg4vparse_handle_vo (parse, data, GST_BUFFER_SIZE (buf), FALSE); } + if (!res) + goto failed_parse; } else { GST_WARNING_OBJECT (parse, "codec_data does not begin with start code, invalid"); @@ -784,6 +812,11 @@ gst_mpeg4vparse_sink_event (GstPad * pad, GstEvent * event) parse->offset = 0; break; case GST_EVENT_EOS: + if (parse->pending_segment != NULL) { + /* Send pending newsegment before EOS */ + gst_pad_push_event (parse->srcpad, parse->pending_segment); + parse->pending_segment = NULL; + } if (parse->state == PARSE_VOP_FOUND) { /* If we've found the start of the VOP assume what's left in the * adapter is the complete VOP. This might cause us to send an @@ -792,11 +825,25 @@ gst_mpeg4vparse_sink_event (GstPad * pad, GstEvent * event) gst_mpeg4vparse_push (parse, gst_adapter_available (parse->adapter)); } /* fallthrough */ + case GST_EVENT_FLUSH_START: + res = gst_pad_event_default (pad, event); + break; + case GST_EVENT_NEWSEGMENT: + gst_event_replace (&parse->pending_segment, event); + gst_event_unref (event); + res = TRUE; + break; default: + if (G_UNLIKELY (!parse->have_src_caps || parse->pending_segment)) { + /* We don't yet have enough data to set caps on the srcpad, so collect + * non-critical events till we do */ + parse->pending_events = g_list_append (parse->pending_events, event); + res = TRUE; + } else + res = gst_pad_event_default (pad, event); break; } - res = gst_pad_event_default (pad, event); gst_object_unref (parse); return res; @@ -857,6 +904,10 @@ gst_mpeg4vparse_src_query (GstPad * pad, GstQuery * query) static void gst_mpeg4vparse_cleanup (GstMpeg4VParse * parse) { + if (parse->sink_caps) { + gst_caps_unref (parse->sink_caps); + parse->sink_caps = NULL; + } if (parse->adapter) { gst_adapter_clear (parse->adapter); } @@ -865,6 +916,16 @@ gst_mpeg4vparse_cleanup (GstMpeg4VParse * parse) parse->config = NULL; } + if (parse->pending_segment) + gst_event_unref (parse->pending_segment); + parse->pending_segment = NULL; + + g_list_foreach (parse->pending_events, (GFunc) gst_event_unref, NULL); + g_list_free (parse->pending_events); + parse->pending_events = NULL; + + parse->have_src_caps = FALSE; + parse->state = PARSE_NEED_START; parse->have_config = FALSE; parse->offset = 0; @@ -891,20 +952,18 @@ gst_mpeg4vparse_change_state (GstElement * element, GstStateChange transition) } static void -gst_mpeg4vparse_dispose (GObject * object) +gst_mpeg4vparse_finalize (GObject * object) { GstMpeg4VParse *parse = GST_MPEG4VIDEOPARSE (object); + gst_mpeg4vparse_cleanup (parse); + if (parse->adapter) { g_object_unref (parse->adapter); parse->adapter = NULL; } - if (parse->config != NULL) { - gst_buffer_unref (parse->config); - parse->config = NULL; - } - GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object)); + GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); } static void @@ -969,7 +1028,7 @@ gst_mpeg4vparse_class_init (GstMpeg4VParseClass * klass) parent_class = g_type_class_peek_parent (klass); - gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_mpeg4vparse_dispose); + gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_mpeg4vparse_finalize); gobject_class->set_property = gst_mpeg4vparse_set_property; gobject_class->get_property = gst_mpeg4vparse_get_property; diff --git a/gst/mpeg4videoparse/mpeg4videoparse.h b/gst/mpeg4videoparse/mpeg4videoparse.h index f5ce3f3c8..29f7fa183 100644 --- a/gst/mpeg4videoparse/mpeg4videoparse.h +++ b/gst/mpeg4videoparse/mpeg4videoparse.h @@ -54,6 +54,8 @@ struct _GstMpeg4VParse { GstPad * sinkpad; GstPad * srcpad; + GstCaps *sink_caps; + guint interval; GstClockTime last_report; @@ -71,6 +73,10 @@ struct _GstMpeg4VParse { GstClockTime frame_duration; gboolean drop; + + gboolean have_src_caps; + GstEvent *pending_segment; + GList *pending_events; }; struct _GstMpeg4VParseClass { diff --git a/gst/mpegdemux/flutspmtinfo.c b/gst/mpegdemux/flutspmtinfo.c index 4c6412eaa..65402e738 100644 --- a/gst/mpegdemux/flutspmtinfo.c +++ b/gst/mpegdemux/flutspmtinfo.c @@ -219,4 +219,5 @@ mpegts_pmt_info_add_stream (MpegTsPmtInfo * pmt_info, g_value_init (&v, G_TYPE_OBJECT); g_value_take_object (&v, stream); g_value_array_append (pmt_info->streams, &v); + g_value_unset (&v); } diff --git a/gst/mpegdemux/gstmpegtsdemux.c b/gst/mpegdemux/gstmpegtsdemux.c index 865dce288..cb0d89c91 100644 --- a/gst/mpegdemux/gstmpegtsdemux.c +++ b/gst/mpegdemux/gstmpegtsdemux.c @@ -671,7 +671,7 @@ gst_mpegts_demux_fill_stream (GstMpegTSStream * stream, guint8 id, DESC_DVB_SUBTITLING)) { template = klass->private_template; name = g_strdup_printf ("private_%04x", stream->PID); - caps = gst_caps_new_simple ("private/x-dvbsub", NULL); + caps = gst_caps_new_simple ("subpicture/x-dvb", NULL); } break; case ST_HDV_AUX_V: @@ -946,31 +946,36 @@ gst_mpegts_demux_send_tags_for_stream (GstMpegTSDemux * demux, GstMpegTSStream * stream) { GstTagList *list = NULL; + gint i; if (stream->ES_info) { - guint8 *iso639_languages = - gst_mpeg_descriptor_find (stream->ES_info, DESC_ISO_639_LANGUAGE); - if (iso639_languages) { - if (DESC_ISO_639_LANGUAGE_codes_n (iso639_languages)) { - const gchar *lc; - gchar lang_code[4]; - gchar *language_n; - - language_n = (gchar *) - DESC_ISO_639_LANGUAGE_language_code_nth (iso639_languages, 0); - - lang_code[0] = language_n[0]; - lang_code[1] = language_n[1]; - lang_code[2] = language_n[2]; - lang_code[3] = 0; - - if (!list) - list = gst_tag_list_new (); - - /* descriptor contains ISO 639-2 code, we want the ISO 639-1 code */ - lc = gst_tag_get_language_code (lang_code); - gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, - GST_TAG_LANGUAGE_CODE, (lc) ? lc : lang_code, NULL); + static const guint8 lang_descs[] = + { DESC_ISO_639_LANGUAGE, DESC_DVB_SUBTITLING }; + for (i = 0; i < G_N_ELEMENTS (lang_descs); i++) { + guint8 *iso639_languages = + gst_mpeg_descriptor_find (stream->ES_info, lang_descs[i]); + if (iso639_languages) { + if (DESC_ISO_639_LANGUAGE_codes_n (iso639_languages)) { + const gchar *lc; + gchar lang_code[4]; + gchar *language_n; + + language_n = (gchar *) + DESC_ISO_639_LANGUAGE_language_code_nth (iso639_languages, 0); + + lang_code[0] = language_n[0]; + lang_code[1] = language_n[1]; + lang_code[2] = language_n[2]; + lang_code[3] = 0; + + if (!list) + list = gst_tag_list_new (); + + /* descriptor contains ISO 639-2 code, we want the ISO 639-1 code */ + lc = gst_tag_get_language_code (lang_code); + gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, + GST_TAG_LANGUAGE_CODE, (lc) ? lc : lang_code, NULL); + } } } } @@ -1469,7 +1474,21 @@ gst_mpegts_stream_parse_pmt (GstMpegTSStream * stream, ES_stream->flags |= MPEGTS_STREAM_FLAG_IS_VIDEO; /* set adaptor */ + GST_LOG ("Initializing PES filter for PID %u", ES_stream->PID); gst_pes_filter_init (&ES_stream->filter, NULL, NULL); + + if (ES_stream->stream_type == ST_PRIVATE_DATA) { + guint8 *dvb_sub_desc = gst_mpeg_descriptor_find (ES_stream->ES_info, + DESC_DVB_SUBTITLING); + + /* enable gather PES for DVB subtitles since the dvbsuboverlay + * expects complete PES packets */ + if (dvb_sub_desc) { + /* FIXME: There's another place where pes filters could get + * initialized. Might need similar temporary hack there as well */ + ES_stream->filter.gather_pes = TRUE; + } + } gst_pes_filter_set_callbacks (&ES_stream->filter, (GstPESFilterData) gst_mpegts_demux_data_cb, (GstPESFilterResync) gst_mpegts_demux_resync_cb, ES_stream); @@ -1598,11 +1617,9 @@ gst_mpegts_stream_parse_private_section (GstMpegTSStream * stream, goto wrong_crc; /* just dump this down the pad */ - if (gst_pad_alloc_buffer (stream->pad, 0, datalen, NULL, &buffer) == - GST_FLOW_OK) { - memcpy (buffer->data, data, datalen); - gst_pad_push (stream->pad, buffer); - } + buffer = gst_buffer_new_and_alloc (datalen); + memcpy (buffer->data, data, datalen); + gst_pad_push (stream->pad, buffer); GST_DEBUG_OBJECT (demux, "parsing private section"); return TRUE; @@ -2298,6 +2315,7 @@ gst_mpegts_demux_parse_stream (GstMpegTSDemux * demux, GstMpegTSStream * stream, } /* Initialise our PES filter */ + GST_LOG ("Initializing PES filter for PID %u", stream->PID); gst_pes_filter_init (&stream->filter, NULL, NULL); gst_pes_filter_set_callbacks (&stream->filter, (GstPESFilterData) gst_mpegts_demux_data_cb, @@ -3119,6 +3137,7 @@ mpegts_demux_build_pat_info (GstMpegTSDemux * demux) g_value_init (&v, G_TYPE_OBJECT); g_value_take_object (&v, info_obj); g_value_array_append (vals, &v); + g_value_unset (&v); } return vals; } diff --git a/gst/mpegdemux/mpegtspacketizer.c b/gst/mpegdemux/mpegtspacketizer.c index 70cf3d710..a86ef0e81 100644 --- a/gst/mpegdemux/mpegtspacketizer.c +++ b/gst/mpegdemux/mpegtspacketizer.c @@ -2089,15 +2089,11 @@ mpegts_try_discover_packet_size (MpegTSPacketizer * packetizer) if (dest[i] == 0x47 && dest[i + packetsize] == 0x47 && dest[i + packetsize * 2] == 0x47 && dest[i + packetsize * 3] == 0x47) { - gchar *str; packetizer->know_packet_size = TRUE; packetizer->packet_size = packetsize; - str = - g_strdup_printf - ("video/mpegts, systemstream=(boolean)true, packetsize=%d", - packetsize); - packetizer->caps = gst_caps_from_string ((const gchar *) str); - g_free (str); + packetizer->caps = gst_caps_new_simple ("video/mpegts", + "systemstream", G_TYPE_BOOLEAN, TRUE, + "packetsize", G_TYPE_INT, packetsize, NULL); pos = i; break; } @@ -2107,9 +2103,13 @@ mpegts_try_discover_packet_size (MpegTSPacketizer * packetizer) } GST_DEBUG ("have packetsize detected: %d of %u bytes", packetizer->know_packet_size, packetizer->packet_size); - /* flush to sync byte */ - if (pos > 0) + if (pos > 0) { + /* flush to sync byte */ gst_adapter_flush (packetizer->adapter, pos); + } else if (!packetizer->know_packet_size) { + /* drop invalid data and move to the next possible packets */ + gst_adapter_flush (packetizer->adapter, MPEGTS_MAX_PACKETSIZE); + } g_free (dest); } diff --git a/gst/mpegtsdemux/Makefile.am b/gst/mpegtsdemux/Makefile.am new file mode 100644 index 000000000..d3d2c3ed5 --- /dev/null +++ b/gst/mpegtsdemux/Makefile.am @@ -0,0 +1,27 @@ +plugin_LTLIBRARIES = libgstmpegtsdemux.la + +libgstmpegtsdemux_la_SOURCES = \ + gsttsdemux.c \ + gstmpegdesc.c \ + mpegtsbase.c \ + mpegtspacketizer.c \ + mpegtsparse.c \ + tsdemux.c + +libgstmpegtsdemux_la_CFLAGS = \ + $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) $(GST_CFLAGS) +libgstmpegtsdemux_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_MAJORMINOR) \ + $(GST_BASE_LIBS) $(GST_LIBS) +libgstmpegtsdemux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstmpegtsdemux_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = \ + gstmpegdefs.h \ + gstmpegdesc.h \ + mpegtsbase.h \ + mpegtspacketizer.h \ + mpegtsparse.h \ + tsdemux.h + diff --git a/gst/mpegtsdemux/TODO b/gst/mpegtsdemux/TODO new file mode 100644 index 000000000..b8f636687 --- /dev/null +++ b/gst/mpegtsdemux/TODO @@ -0,0 +1,117 @@ +mpegtsparse rebasing +-------------------- + +Rationale : +----------- + + mpegtsparse code is more sane to handle and work with. + + We need a modular demuxer + + We need to avoid duplicating code regarding mpeg-ts in a gazillion + elements and allow easy creatiof new elements. + + +Battleplan : +------------ +* Figure out code from mpegtsparse which would be also needed for a +mpeg-ts demuxer (ex: packet/psi/pcr parsing). +* Extract common code into a base mpegtsbase class. +* Refactor mpegtsparse to subclass that base class. +* Create a minimalistic demuxer that creates pads (based on PSI info) +and outputs ES packets (let's say mpeg audio and video to start with) + +Potential subclasses : +---------------------- +* MpegTSParse : Program splitter. Given an incoming multi-program + mpeg-ts stream, it can provide request pads for each program. Each + of those pads will contain the ts packets specific to that program. + +* TSDemux : Program demuxer. Given an incoming single or multi-program + mpeg-ts stream, it will reconstruct the original Program Streams of + the selected program and output them on dynamically created pads. + +* HDVSplitter : Given an incoming HDV mpeg-ts stream, it will locate + the beginning of new scenes and output a mpeg-ts stream with the + PAT/PMT/AUX packets properly ordered and marked with DISCONT, so + that the following pipeline will automatically cut up a tape dump + into individual scenes: + filesrc ! hdvsplit ! multifilesink next-file=discont + +Code/Design common to a program-spliter and a demuxer : +------------------------------------------------------- +* Parsing TS packets +* Establishing PAT/PMT mapping +* Handling the notions of Programs/Streams +* Seeking ? + + One proposal... would be to have the base class automatically create + all the structures (and relationships) for the following objects: + + * Programs (from PAT/PMT, dunno if it could come from something + else) + * Program id + * Streams contained in that program (with links to them) + * Which stream contains the PCR + * Metadata ? + * Streams (ideally... in a table for fast access) + * We want to be able to have stream-type specific information + easily accessible also (like mpeg video specific data) + * Maybe some other info ??? + + The subclasses would then be able to make their own decision based + on those objects. + Maybe we could have some virtual methods that will be called when a + new program is detected, a new stream is added, etc... + + It is the subclass who decides what's to do with a given packet once + it's been parsed. + tsparse : forward it as-is to the pad corresponding to the program + tsdemux : forward it to the proper PS parser + hdvsplit : ? + + +Ideas to be taken into account for a proper demuxer : +----------------------------------------------------- +* Push-based (with inacurrate seeking) +* Pull-based (with fast *AND* accurate seeking) +* Modular system to add stream-type specific helper parsing + * Doesn't have to be fully fledged, just enough to help any kind of + seeking and scanning code. +* ... + +Problems to figure out : +------------------------ +* clock + Needed for proper dvb playback. mpegtsdemux currently does internal + clock estimation... to provide a clock with PCR estimations. + A proper way to solve that would be to timestamp the buffers at the + source element using the system clock, and then adjusting the PCR + against those values. (i.e. doing the opposite of what's done in + mpegtsdemux, but it will be more accurate since the timestamping is + done at the source). + + +Bugs that need fixing : +----------------------- +* Perfomance : Creation/Destruction of buffers is slow + * => This is due to g_type_instance_create using a dogslow rwlock + which take up to 50% of gst_adapter_take_buffer() + => Bugzilla #585375 (performance and contention problems) + +Code structure: + + MpegTSBase + +--- MpegTSParse + +--- TSDemux + + +Known limitations and problems : +-------------------------------- +* mpegtspacketizer + * Assumes 188 bytes packets. It should support all modes. + * offset/timestamp of incoming buffers need to be carried on to the + sub-buffers in order for several demuxer features to work correctly. +* mpegtsparser + * SERIOUS room for improvement performance-wise (see callgrind) + diff --git a/gst/mpegtsdemux/gstmpegdefs.h b/gst/mpegtsdemux/gstmpegdefs.h new file mode 100644 index 000000000..268234f25 --- /dev/null +++ b/gst/mpegtsdemux/gstmpegdefs.h @@ -0,0 +1,217 @@ +/* + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * The Original Code is Fluendo MPEG Demuxer plugin. + * + * The Initial Developer of the Original Code is Fluendo, S.L. + * Portions created by Fluendo, S.L. are Copyright (C) 2005 + * Fluendo, S.L. All Rights Reserved. + * + * Contributor(s): Wim Taymans <wim@fluendo.com> + */ + +#ifndef __GST_MPEG_DEFS_H__ +#define __GST_MPEG_DEFS_H__ + +/* + * 1011 1100 program_stream_map + * 1011 1101 private_stream_1 + * 1011 1110 padding_stream + * 1011 1111 private_stream_2 + * 110x xxxx ISO/IEC 13818-3 or ISO/IEC 11172-3 audio stream number x xxxx + * 1110 xxxx ITU-T Rec. H.262 | ISO/IEC 13818-2 or ISO/IEC 11172-2 video stream number xxxx + * 1111 0000 ECM_stream + * 1111 0001 EMM_stream + * 1111 0010 ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Annex A or ISO/IEC 13818-6_DSMCC_stream + * 1111 0011 ISO/IEC_13522_stream + * 1111 0100 ITU-T Rec. H.222.1 type A + * 1111 0101 ITU-T Rec. H.222.1 type B + * 1111 0110 ITU-T Rec. H.222.1 type C + * 1111 0111 ITU-T Rec. H.222.1 type D + * 1111 1000 ITU-T Rec. H.222.1 type E + * 1111 1001 ancillary_stream + * 1111 1010 E 1111 1110 reserved data stream + * 1111 1111 program_stream_directory + */ + +#define ID_PS_END_CODE 0x000001B9 +#define ID_PS_PACK_START_CODE 0x000001BA +#define ID_PS_SYSTEM_HEADER_START_CODE 0x000001BB +#define ID_PS_PROGRAM_STREAM_MAP 0x000001BC +#define ID_PRIVATE_STREAM_1 0x000001BD +#define ID_PADDING_STREAM 0x000001BE +#define ID_PRIVATE_STREAM_2 0x000001BF +#define ID_ISO_IEC_MPEG12_AUDIO_STREAM_0 0x000001C0 +#define ID_ISO_IEC_MPEG12_AUDIO_STREAM_32 0x000001DF +#define ID_ISO_IEC_MPEG12_VIDEO_STREAM_0 0x000001E0 +#define ID_ISO_IEC_MPEG12_VIDEO_STREAM_16 0x000001EF +#define ID_ECM_STREAM 0x000001F0 +#define ID_EMM_STREAM 0x000001F1 +#define ID_DSMCC_STREAM 0x000001F2 +#define ID_ISO_IEC_13522_STREAM 0x000001F3 +#define ID_ITU_TREC_H222_TYPE_A_STREAM 0x000001F4 +#define ID_ITU_TREC_H222_TYPE_B_STREAM 0x000001F5 +#define ID_ITU_TREC_H222_TYPE_C_STREAM 0x000001F6 +#define ID_ITU_TREC_H222_TYPE_D_STREAM 0x000001F7 +#define ID_ITU_TREC_H222_TYPE_E_STREAM 0x000001F8 +#define ID_ANCILLARY_STREAM 0x000001F9 +#define ID_RESERVED_STREAM_1 0x000001FA +#define ID_RESERVED_STREAM_2 0x000001FB +#define ID_EXTENDED_METADATA 0x000001FC +#define ID_EXTENDED_STREAM_ID 0x000001FD +#define ID_RESERVED_STREAM_3 0x000001FE +#define ID_PROGRAM_STREAM_DIRECTORY 0x000001FF + +#define PACKET_VIDEO_START_CODE 0x000001E0 +#define PACKET_AUDIO_START_CODE 0x000001C0 +#define PICTURE_START_CODE 0x00000100 +#define USER_DATA_START_CODE 0x000001B2 +#define SEQUENCE_HEADER_CODE 0x000001B3 +#define SEQUENCE_ERROR_CODE 0x000001B4 +#define EXTENSION_START_CODE 0x000001B5 +#define SEQUENCE_END_CODE 0x000001B7 +#define GROUP_START_CODE 0x000001B8 + +#define AC3_SYNC_WORD 0x0b770000 + +#define MPEG_TS_SYNC_BYTE 0x00000047 + +#define PID_PROGRAM_ASSOCIATION_TABLE 0x0000 +#define PID_CONDITIONAL_ACCESS_TABLE 0x0001 +#define PID_RESERVED_FIRST 0x0002 +#define PID_RESERVED_LAST 0x0010 +#define PID_NULL_PACKET 0x1FFF + +#define PID_TYPE_UNKNOWN 0 +#define PID_TYPE_RESERVED 1 +#define PID_TYPE_PROGRAM_ASSOCIATION 2 +#define PID_TYPE_CONDITIONAL_ACCESS 3 +#define PID_TYPE_PROGRAM_MAP 4 +#define PID_TYPE_ELEMENTARY 5 +#define PID_TYPE_NULL_PACKET 6 +#define PID_TYPE_PRIVATE_SECTION 7 + +/* Stream type assignments + * + * 0x00 ITU-T | ISO/IEC Reserved + * 0x01 ISO/IEC 11172 Video + * 0x02 ITU-T Rec. H.262 | ISO/IEC 13818-2 Video or + * ISO/IEC 11172-2 constrained parameter video + * stream + * 0x03 ISO/IEC 11172 Audio + * 0x04 ISO/IEC 13818-3 Audio + * 0x05 ITU-T Rec. H.222.0 | ISO/IEC 13818-1 + * private_sections + * 0x06 ITU-T Rec. H.222.0 | ISO/IEC 13818-1 PES + * packets containing private data + * 0x07 ISO/IEC 13522 MHEG + * 0x08 ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Annex A + * DSM CC + * 0x09 ITU-T Rec. H.222.1 + * 0x0A ISO/IEC 13818-6 type A + * 0x0B ISO/IEC 13818-6 type B + * 0x0C ISO/IEC 13818-6 type C + * 0x0D ISO/IEC 13818-6 type D + * 0x0E ISO/IEC 13818-1 auxiliary + * 0x0F-0x7F ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Reserved + * 0x80-0xFF User Private + */ +#define ST_RESERVED 0x00 +#define ST_VIDEO_MPEG1 0x01 +#define ST_VIDEO_MPEG2 0x02 +#define ST_AUDIO_MPEG1 0x03 +#define ST_AUDIO_MPEG2 0x04 +#define ST_PRIVATE_SECTIONS 0x05 +#define ST_PRIVATE_DATA 0x06 +#define ST_MHEG 0x07 +#define ST_DSMCC 0x08 +#define ST_H222_1 0x09 + +/* later extensions */ +#define ST_AUDIO_AAC 0x0f +#define ST_VIDEO_MPEG4 0x10 +#define ST_VIDEO_H264 0x1b + +/* Un-official Dirac extension */ +#define ST_VIDEO_DIRAC 0xd1 + +/* private stream types */ +#define ST_PS_AUDIO_AC3 0x81 +#define ST_PS_AUDIO_DTS 0x8a +#define ST_PS_AUDIO_LPCM 0x8b +#define ST_PS_DVD_SUBPICTURE 0xff +/* Blu-ray related */ +#define ST_BD_AUDIO_LPCM 0x80 +#define ST_BD_AUDIO_AC3 0x81 +#define ST_BD_AUDIO_DTS 0x82 +#define ST_BD_AUDIO_AC3_TRUE_HD 0x83 +#define ST_BD_AUDIO_AC3_PLUS 0x84 +#define ST_BD_AUDIO_DTS_HD 0x85 +#define ST_BD_AUDIO_DTS_HD_MASTER_AUDIO 0x86 +#define ST_BD_AUDIO_EAC3 0x87 +#define ST_BD_PGS_SUBPICTURE 0x90 +#define ST_BD_IGS 0x91 +#define ST_BD_SUBTITLE 0x92 +#define ST_BD_SECONDARY_AC3_PLUS 0xa1 +#define ST_BD_SECONDARY_DTS_HD 0xa2 + +/* defined for VC1 extension in RP227 */ +#define ST_PRIVATE_EA 0xea + +/* HDV AUX stream mapping + * 0xA0 ISO/IEC 61834-11 + * 0xA1 ISO/IEC 61834-11 + */ +#define ST_HDV_AUX_A 0xa0 +#define ST_HDV_AUX_V 0xa1 + +/* Un-official time-code stream */ +#define ST_PS_TIMECODE 0xd2 + +/* Internal stream types >= 0x100 */ +#define ST_GST_AUDIO_RAWA52 0x181 + /* Used when we don't yet know which stream type it will be in a PS stream */ +#define ST_GST_VIDEO_MPEG1_OR_2 0x102 + +#define CLOCK_BASE 9LL +#define CLOCK_FREQ (CLOCK_BASE * 10000) + +#define PCRTIME_TO_GSTTIME(time) (gst_util_uint64_scale ((time), \ + GST_MSECOND/10, 300 * CLOCK_BASE)) +#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)) + +#define MPEG_MUX_RATE_MULT 50 + +/* sync:4 == 00xx ! pts:3 ! 1 ! pts:15 ! 1 | pts:15 ! 1 */ +#define READ_TS(data, target, lost_sync_label) \ + if ((*data & 0x01) != 0x01) goto lost_sync_label; \ + target = ((guint64) (*data++ & 0x0E)) << 29; \ + target |= ((guint64) (*data++ )) << 22; \ + if ((*data & 0x01) != 0x01) goto lost_sync_label; \ + target |= ((guint64) (*data++ & 0xFE)) << 14; \ + target |= ((guint64) (*data++ )) << 7; \ + if ((*data & 0x01) != 0x01) goto lost_sync_label; \ + target |= ((guint64) (*data++ & 0xFE)) >> 1; + +/* some extra GstFlowReturn values used internally */ +#define GST_FLOW_NEED_MORE_DATA GST_FLOW_CUSTOM_SUCCESS +#define GST_FLOW_LOST_SYNC GST_FLOW_CUSTOM_SUCCESS_1 + +#endif /* __GST_MPEG_DEFS_H__ */ diff --git a/gst/mpegtsdemux/gstmpegdesc.c b/gst/mpegtsdemux/gstmpegdesc.c new file mode 100644 index 000000000..4abf5eb36 --- /dev/null +++ b/gst/mpegtsdemux/gstmpegdesc.c @@ -0,0 +1,205 @@ +/* + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * The Original Code is Fluendo MPEG Demuxer plugin. + * + * The Initial Developer of the Original Code is Fluendo, S.L. + * Portions created by Fluendo, S.L. are Copyright (C) 2005 + * Fluendo, S.L. All Rights Reserved. + * + * Contributor(s): Wim Taymans <wim@fluendo.com> + * + */ + +#include <string.h> + +#include <gst/gst.h> + +#include "gstmpegdesc.h" + +GST_DEBUG_CATEGORY (gstmpegtsdesc_debug); +#define GST_CAT_DEFAULT (gstmpegtsdesc_debug) + +void +gst_mpeg_descriptor_free (GstMPEGDescriptor * desc) +{ + g_return_if_fail (desc != NULL); + + g_free (desc); +} + +static guint +gst_mpeg_descriptor_parse_1 (guint8 * data, guint size) +{ + guint8 tag; + guint8 length; + + /* need at least 2 bytes for tag and length */ + if (size < 2) + return 0; + + tag = *data++; + length = *data++; + size -= 2; + + GST_DEBUG ("tag: 0x%02x, length: %d", tag, length); + + if (length > size) + return 0; + + GST_MEMDUMP ("tag contents:", data, length); + + return length + 2; +} + +GstMPEGDescriptor * +gst_mpeg_descriptor_parse (guint8 * data, guint size) +{ + guint8 *current; + guint consumed, total, n_desc; + GstMPEGDescriptor *result; + + g_return_val_if_fail (data != NULL, NULL); + + current = data; + total = 0; + n_desc = 0; + + do { + consumed = gst_mpeg_descriptor_parse_1 (current, size); + + if (consumed > 0) { + current += consumed; + total += consumed; + size -= consumed; + n_desc++; + } + } + while (consumed > 0); + + GST_DEBUG ("parsed %d descriptors", n_desc); + + if (total == 0) + return NULL; + + result = g_malloc (sizeof (GstMPEGDescriptor) + total); + result->n_desc = n_desc; + result->data_length = total; + result->data = ((guint8 *) result) + sizeof (GstMPEGDescriptor); + + memcpy (result->data, data, total); + + return result; +} + +guint +gst_mpeg_descriptor_n_desc (GstMPEGDescriptor * desc) +{ + g_return_val_if_fail (desc != NULL, 0); + + return desc->n_desc; +} + +guint8 * +gst_mpeg_descriptor_find (GstMPEGDescriptor * desc, gint tag) +{ + guint8 length; + guint8 *current; + guint size; + + g_return_val_if_fail (desc != NULL, NULL); + + current = desc->data; + length = desc->data_length; + + while (length > 0) { + if (DESC_TAG (current) == tag) + return current; + + size = DESC_LENGTH (current) + 2; + + current += size; + length -= size; + } + return NULL; +} + +/* array needs freeing afterwards */ +GArray * +gst_mpeg_descriptor_find_all (GstMPEGDescriptor * desc, gint tag) +{ + GArray *all; + + guint8 length; + guint8 *current; + guint size; + + g_return_val_if_fail (desc != NULL, NULL); + all = g_array_new (TRUE, TRUE, sizeof (guint8 *)); + + current = desc->data; + length = desc->data_length; + + while (length > 0) { + if (DESC_TAG (current) == tag) + g_array_append_val (all, current); + size = DESC_LENGTH (current) + 2; + + current += size; + length -= size; + } + + GST_DEBUG ("found tag 0x%02x %d times", tag, all->len); + + return all; +} + +guint8 * +gst_mpeg_descriptor_nth (GstMPEGDescriptor * desc, guint i) +{ + guint8 length; + guint8 *current; + guint size; + + g_return_val_if_fail (desc != NULL, NULL); + + if (i > desc->n_desc) + return NULL; + + current = desc->data; + length = desc->data_length; + + while (length > 0) { + if (i == 0) + return current; + + size = DESC_LENGTH (current) + 2; + + current += size; + length -= size; + i--; + + } + return NULL; +} + +void +gst_mpegtsdesc_init_debug (void) +{ + GST_DEBUG_CATEGORY_INIT (gstmpegtsdesc_debug, "mpegtsdesc", 0, + "MPEG transport stream parser (descriptor)"); +} diff --git a/gst/mpegtsdemux/gstmpegdesc.h b/gst/mpegtsdemux/gstmpegdesc.h new file mode 100644 index 000000000..06aa17b95 --- /dev/null +++ b/gst/mpegtsdemux/gstmpegdesc.h @@ -0,0 +1,338 @@ +/* + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * The Original Code is Fluendo MPEG Demuxer plugin. + * + * The Initial Developer of the Original Code is Fluendo, S.L. + * Portions created by Fluendo, S.L. are Copyright (C) 2005 + * Fluendo, S.L. All Rights Reserved. + * + * Contributor(s): Wim Taymans <wim@fluendo.com> + * + */ + +#ifndef __GST_MPEG_DESC_H__ +#define __GST_MPEG_DESC_H__ + +#include <glib.h> +/* + * descriptor_tag TS PS Identification + * 0 n/a n/a Reserved + * 1 n/a n/a Reserved + * 2 X X video_stream_descriptor + * 3 X X audio_stream_descriptor + * 4 X X hierarchy_descriptor + * 5 X X registration_descriptor + * 6 X X data_stream_alignment_descriptor + * 7 X X target_background_grid_descriptor + * 8 X X video_window_descriptor + * 9 X X CA_descriptor + * 10 X X ISO_639_language_descriptor + * 11 X X system_clock_descriptor + * 12 X X multiplex_buffer_utilization_descriptor + * 13 X X copyright_descriptor + * 14 X maximum bitrate descriptor + * 15 X X private data indicator descriptor + * 16 X X smoothing buffer descriptor + * 17 X STD_descriptor + * 18 X X IBP descriptor + * 19-63 n/a n/a ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Reserved + * 64-255 n/a n/a User Private + */ +#define DESC_VIDEO_STREAM 2 +#define DESC_AUDIO_STREAM 3 +#define DESC_HIERARCHY 4 +#define DESC_REGISTRATION 5 +#define DESC_DATA_STREAM_ALIGNMENT 6 +#define DESC_TARGET_BACKGROUND_GRID 7 +#define DESC_VIDEO_WINDOW 8 +#define DESC_CA 9 +#define DESC_ISO_639_LANGUAGE 10 +#define DESC_SYSTEM_CLOCK 11 +#define DESC_MULTIPLEX_BUFFER_UTILISATION 12 +#define DESC_COPYRIGHT 13 +#define DESC_MAXIMUM_BITRATE 14 +#define DESC_PRIVATE_DATA_INDICATOR 15 +#define DESC_SMOOTHING_BUFFER 16 +#define DESC_STD 17 +#define DESC_IBP 18 + +#define DESC_DIRAC_TC_PRIVATE 0xAC + +/* DVB tags */ +#define DESC_DVB_CAROUSEL_IDENTIFIER 0x13 +#define DESC_DVB_NETWORK_NAME 0x40 +#define DESC_DVB_SERVICE_LIST 0x41 +#define DESC_DVB_STUFFING 0x42 +#define DESC_DVB_SATELLITE_DELIVERY_SYSTEM 0x43 +#define DESC_DVB_CABLE_DELIVERY_SYSTEM 0x44 +#define DESC_DVB_VBI_DATA 0x45 +#define DESC_DVB_VBI_TELETEXT 0x46 +#define DESC_DVB_BOUQUET_NAME 0x47 +#define DESC_DVB_SERVICE 0x48 +#define DESC_DVB_COUNTRY_AVAILABILITY 0x49 +#define DESC_DVB_LINKAGE 0x4A +#define DESC_DVB_NVOD_REFERENCE 0x4B +#define DESC_DVB_TIME_SHIFTED_SERVICE 0x4C +#define DESC_DVB_SHORT_EVENT 0x4D +#define DESC_DVB_EXTENDED_EVENT 0x4E +#define DESC_DVB_TIME_SHIFTED_EVENT 0x4F +#define DESC_DVB_COMPONENT 0x50 +#define DESC_DVB_MOSAIC 0x51 +#define DESC_DVB_STREAM_IDENTIFIER 0x52 +#define DESC_DVB_CA_IDENTIFIER 0x53 +#define DESC_DVB_CONTENT 0x54 +#define DESC_DVB_PARENTAL_RATING 0x55 +#define DESC_DVB_TELETEXT 0x56 +#define DESC_DVB_TELEPHONE 0x57 +#define DESC_DVB_LOCAL_TIME_OFFSET 0x58 +#define DESC_DVB_SUBTITLING 0x59 +#define DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM 0x5A +#define DESC_DVB_MULTILINGUAL_NETWORK_NAME 0x5B +#define DESC_DVB_MULTILINGUAL_BOUQUET_NAME 0x5C +#define DESC_DVB_MULTILINGUAL_SERVICE_NAME 0x5D +#define DESC_DVB_MULTILINGUAL_COMPONENT 0x5E +#define DESC_DVB_PRIVATE_DATA 0x5F +#define DESC_DVB_SERVICE_MOVE 0x60 +#define DESC_DVB_SHORT_SMOOTHING_BUFFER 0x61 +#define DESC_DVB_FREQUENCY_LIST 0x62 +#define DESC_DVB_PARTIAL_TRANSPORT_STREAM 0x63 +#define DESC_DVB_DATA_BROADCAST 0x64 +#define DESC_DVB_SCRAMBLING 0x65 +#define DESC_DVB_DATA_BROADCAST_ID 0x66 +#define DESC_DVB_TRANSPORT_STREAM 0x67 +#define DESC_DVB_DSNG 0x68 +#define DESC_DVB_PDC 0x69 +#define DESC_DVB_AC3 0x6A +#define DESC_DVB_ANCILLARY_DATA 0x6B +#define DESC_DVB_CELL_LIST 0x6C +#define DESC_DVB_CELL_FREQUENCY_LINK 0x6D +#define DESC_DVB_ANNOUNCEMENT_SUPPORT 0x6E +#define DESC_DVB_APPLICATION_SIGNALLING 0x6F +#define DESC_DVB_ADAPTATION_FIELD_DATA 0x70 +#define DESC_DVB_SERVICE_IDENTIFIER 0x71 +#define DESC_DVB_SERVICE_AVAILABILITY 0x72 +#define DESC_DVB_DEFAULT_AUTHORITY 0x73 +#define DESC_DVB_RELATED_CONTENT 0x74 +#define DESC_DVB_TVA_ID 0x75 +#define DESC_DVB_CONTENT_IDENTIFIER 0x76 +#define DESC_DVB_TIMESLICE_FEC_IDENTIFIER 0x77 +#define DESC_DVB_ECM_REPETITION_RATE 0x78 +#define DESC_DVB_S2_SATELLITE_DELIVERY_SYSTEM 0x79 +#define DESC_DVB_ENHANCED_AC3 0x7A +#define DESC_DVB_DTS 0x7B +#define DESC_DVB_AAC 0x7C +/* 0x7D and 0x7E are reserved for future use */ +#define DESC_DVB_EXTENSION 0x7F +/* 0x80 - 0xFE are user defined */ +#define DESC_DTG_LOGICAL_CHANNEL 0x83 /* from DTG D-Book */ +/* 0xFF is forbidden */ + +/* common for all descriptors */ +#define DESC_TAG(desc) (desc[0]) +#define DESC_LENGTH(desc) (desc[1]) + +/* video_stream_descriptor */ +#define DESC_VIDEO_STREAM_multiple_framerate_flag(desc) (((desc)[2] & 0x80) == 0x80) +#define DESC_VIDEO_STREAM_frame_rate_code(desc) (((desc)[2] & 0x38) >> 3) +#define DESC_VIDEO_STREAM_MPEG_1_only_flag(desc) (((desc)[2] & 0x04) == 0x04) +#define DESC_VIDEO_STREAM_constrained_parameter_flag(desc) (((desc)[2] & 0x02) == 0x02) +#define DESC_VIDEO_STREAM_still_picture_flag(desc) (((desc)[2] & 0x01) == 0x01) +/* if (MPEG_1_only_flag == 1) */ +#define DESC_VIDEO_STREAM_profile_and_level_indication(desc) ((desc)[3]) +#define DESC_VIDEO_STREAM_chroma_format(desc) (((desc)[4] & 0xc0) >> 6) +#define DESC_VIDEO_STREAM_frame_rate_extension_flag(desc) (((desc)[4] & 0x20) == 0x20) + +/* audio_stream_descriptor */ +#define DESC_AUDIO_STREAM_free_format_flag(desc) (((desc)[2] & 0x80) == 0x80) +#define DESC_AUDIO_STREAM_ID(desc) (((desc)[2] & 0x40) == 0x40) +#define DESC_AUDIO_STREAM_layer(desc) (((desc)[2] & 0x30) >> 4) +#define DESC_AUDIO_STREAM_variable_rate_audio_indicator(desc) (((desc)[2] & 0x08) == 0x08) + +/* hierarchy_descriptor */ +#define DESC_HIERARCHY_hierarchy_type(desc) (((desc)[2] & 0x0f)) +#define DESC_HIERARCHY_hierarchy_layer_index(desc) (((desc)[3] & 0x3f)) +#define DESC_HIERARCHY_hierarchy_embedded_layer_index(desc) (((desc)[4] & 0x3f)) +#define DESC_HIERARCHY_hierarchy_channel(desc) (((desc)[5] & 0x3f)) + +/* registration_descriptor */ +#define DESC_REGISTRATION_format_identifier(desc) (GST_READ_UINT32_BE ((desc)+2)) +#define DESC_REGISTRATION_additional_ident_info_len(desc) ((desc)[1] - 4) +#define DESC_REGISTRATION_additional_ident_info(desc) (&(desc)[6]) + +/* data_stream_alignment_descriptor */ +#define DESC_DATA_STREAM_ALIGNMENT_alignment_type(desc) ((desc)[2]) + +/* target_background_grid_descriptor */ +#define DESC_TARGET_BACKGROUND_GRID_horizontal_size(desc) (GST_READ_UINT16_BE ((desc)+2) >> 2) +#define DESC_TARGET_BACKGROUND_GRID_vertical_size(desc) ((GST_READ_UINT32_BE ((desc)+2) & 0x0003fff0) >> 4) +#define DESC_TARGET_BACKGROUND_GRID_aspect_ratio_information(desc) ((desc)[5] & 0x0f) + +/* video_window_descriptor */ +#define DESC_VIDEO_WINDOW_horizontal_offset(desc) (GST_READ_UINT16_BE ((desc)+2) >> 2) +#define DESC_VIDEO_WINDOW_vertical_offset(desc) ((GST_READ_UINT32_BE ((desc)+2) & 0x0003fff0) >> 4) +#define DESC_VIDEO_WINDOW_window_priority(desc) ((desc)[5] & 0x0f) + +/* CA_descriptor */ +#define DESC_CA_system_ID(desc) (GST_READ_UINT16_BE ((desc)+2)) +#define DESC_CA_PID(desc) (GST_READ_UINT16_BE ((desc)+2) & 0x1fff) + +/* ISO_639_language_descriptor */ +#define DESC_ISO_639_LANGUAGE_codes_n(desc) ((desc[1]) >> 2) +#define DESC_ISO_639_LANGUAGE_language_code_nth(desc,i) (&(desc[2 + (4*i)])) +#define DESC_ISO_639_LANGUAGE_audio_type_nth(desc,i) ((desc)[5 + (4*i)]) + +/* system_clock_descriptor */ +#define DESC_SYSTEM_CLOCK_external_clock_reference_indicator(desc) (((desc)[2] & 0x80) == 0x80) +#define DESC_SYSTEM_CLOCK_clock_accuracy_integer(desc) ((desc)[2] & 0x3f) +#define DESC_SYSTEM_CLOCK_clock_accuracy_exponent(desc) (((desc)[3] & 0xe0) >> 5) + +/* multiplex_buffer_utilization_descriptor */ +#define DESC_MULTIPLEX_BUFFER_UTILISATION_bound_valid_flag(desc) (((desc)[2] & 0x80) == 0x80) +#define DESC_MULTIPLEX_BUFFER_UTILISATION_LTW_offset_lower_bound(desc) (GST_READ_UINT16_BE ((desc)+2) & 0x7fff) +#define DESC_MULTIPLEX_BUFFER_UTILISATION_LTW_offset_upper_bound(desc) (GST_READ_UINT16_BE ((desc)+4) & 0x7fff) + +/* copyright_descriptor */ +#define DESC_COPYRIGHT_copyright_identifier(desc) (GST_READ_UINT32_BE ((desc)+2)) +#define DESC_COPYRIGHT_additional_copyright_info_len(desc) ((desc)[1] - 4) +#define DESC_COPYRIGHT_additional_copyright_info(desc) (&(desc)[6]) + +/* maximum_bitrate_descriptor */ +#define DESC_MAXIMUM_BITRAT_maximum_bitrate(desc) (((((guint32)desc[2]) & 0x3f) << 16) | \ + GST_READ_UINT16_BE ((desc)+3)) + +/* private_data_indicator_descriptor */ +#define DESC_PRIVATE_DATA_INDICATOR_indicator(desc) (GST_READ_UINT32_BE(&desc[2])) + +/* smoothing_buffer_descriptor */ +#define DESC_SMOOTHING_BUFFER_sb_leak_rate(desc) (((((guint32)desc[2]) & 0x3f) << 16) | \ + GST_READ_UINT16_BE ((desc)+3)) +#define DESC_SMOOTHING_BUFFER_sb_size(desc) (((((guint32)desc[5]) & 0x3f) << 16) | \ + GST_READ_UINT16_BE ((desc)+6)) +/* STD_descriptor */ +#define DESC_STD_leak_valid_flag(desc) (((desc)[2] & 0x01) == 0x01) + +/* ibp_descriptor */ +#define DESC_IBP_closed_gop_flag(desc) (((desc)[2] & 0x80) == 0x80) +#define DESC_IBP_identical_gop_flag(desc) (((desc)[2] & 0x40) == 0x40) +#define DESC_IBP_max_gop_length(desc) (GST_READ_UINT16_BE ((desc)+6) & 0x3fff) + +/* time_code descriptor */ +#define DESC_TIMECODE_video_pid(desc) (GST_READ_UINT16_BE ((desc) + 2) & 0x1fff) + +/* Stream identifier descriptor */ +#define DESC_DVB_STREAM_IDENTIFIER_component_tag(desc) (desc[2]) + +/* DVB Network Name descriptor */ +#define DESC_DVB_NETWORK_NAME_length(desc) (GST_READ_UINT8((desc)+1)) +#define DESC_DVB_NETWORK_NAME_text(desc) (desc+2) + +/* DVB Service Descriptor */ +#define DESC_DVB_SERVICE_type(desc) (desc[2]) +#define DESC_DVB_SERVICE_provider_name_length(desc) (desc[3]) +#define DESC_DVB_SERVICE_provider_name_text(desc) (desc+4) +#define DESC_DVB_SERVICE_name_length(desc) (desc[4 + DESC_DVB_SERVICE_provider_name_length(desc)]) +#define DESC_DVB_SERVICE_name_text(desc) (desc + 5 + DESC_DVB_SERVICE_provider_name_length(desc)) + +/* DVB Component Descriptor */ +#define DESC_DVB_COMPONENT_stream_content(desc) (desc[2] & 0x0F) +#define DESC_DVB_COMPONENT_type(desc) (desc[3]) +#define DESC_DVB_COMPONENT_tag(desc) (desc[4]) +#define DESC_DVB_COMPONENT_language(desc) (desc + 5) + +/* DVB Bouquet Name Descriptor */ +#define DESC_DVB_BOUQUET_NAME_text(desc) (desc + 2) + +/* DVB Short Event Descriptor */ +#define DESC_DVB_SHORT_EVENT_name_text(desc) (desc + 6) +#define DESC_DVB_SHORT_EVENT_name_length(desc) (desc[5]) +#define DESC_DVB_SHORT_EVENT_description_text(desc) (desc + 6 + DESC_DVB_SHORT_EVENT_name_length(desc) + 1) +#define DESC_DVB_SHORT_EVENT_description_length(desc) (desc[6 + DESC_DVB_SHORT_EVENT_name_length(desc)]) + +/* DVB Extended Event Descriptor */ +#define DESC_DVB_EXTENDED_EVENT_descriptor_number(desc) ((desc[2] & 0xF0) >> 4) +#define DESC_DVB_EXTENDED_EVENT_last_descriptor_number(desc) (desc[2] & 0x0F) +#define DESC_DVB_EXTENDED_EVENT_iso639_language_code(desc) (desc + 3) +#define DESC_DVB_EXTENDED_EVENT_items_length(desc) (desc[6]) +#define DESC_DVB_EXTENDED_EVENT_items(desc) (desc + 7) +#define DESC_DVB_EXTENDED_EVENT_text_length(desc) (desc[7 + DESC_DVB_EXTENDED_EVENT_items_length(desc)]) +#define DESC_DVB_EXTENDED_EVENT_text(desc) (desc + 7 + DESC_DVB_EXTENDED_EVENT_items_length(desc) + 1) + +/* DVB Satellite Delivery System Descriptor */ +#define DESC_DVB_SATELLITE_DELIVERY_SYSTEM_frequency(desc) (desc + 2) +#define DESC_DVB_SATELLITE_DELIVERY_SYSTEM_orbital_position(desc) (desc + 6) +#define DESC_DVB_SATELLITE_DELIVERY_SYSTEM_west_east_flag(desc) ((desc[8] & 0x80) == 0x80) +#define DESC_DVB_SATELLITE_DELIVERY_SYSTEM_polarization(desc) ((desc[8] >> 5) & 0x3) +#define DESC_DVB_SATELLITE_DELIVERY_SYSTEM_modulation(desc) (desc[8] & 0x1F) +#define DESC_DVB_SATELLITE_DELIVERY_SYSTEM_symbol_rate(desc) (desc + 9) +#define DESC_DVB_SATELLITE_DELIVERY_SYSTEM_fec_inner(desc) (desc[12] & 0x0F) + +/* DVB Terrestrial Delivery System Descriptor */ +#define DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_frequency(desc) (GST_READ_UINT32_BE((desc) + 2)) +#define DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_bandwidth(desc) ((desc[6] >> 5) & 0x7) +#define DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_constellation(desc) ((desc[7] >> 6) & 0x3) +#define DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_hierarchy(desc) ((desc[7] >> 3) & 0x7) +#define DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_code_rate_hp(desc) (desc[7] & 0x7) +#define DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_code_rate_lp(desc) ((desc[8] >> 5) & 0x7) +#define DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_guard_interval(desc) ((desc[8] >> 3) & 0x3) +#define DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_transmission_mode(desc) ((desc[8] >> 1) & 0x3) +#define DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_other_frequency(desc) ((desc[8] & 0x01) == 0x01) + +/* DVB Cable Delivery System Descriptor */ +#define DESC_DVB_CABLE_DELIVERY_SYSTEM_frequency(desc) (desc + 2) +#define DESC_DVB_CABLE_DELIVERY_SYSTEM_fec_outer(desc) (desc[7] & 0x0F) +#define DESC_DVB_CABLE_DELIVERY_SYSTEM_modulation(desc) (desc[8]) +#define DESC_DVB_CABLE_DELIVERY_SYSTEM_symbol_rate(desc) (desc + 9) +#define DESC_DVB_CABLE_DELIVERY_SYSTEM_fec_inner(desc) (desc[12] & 0x0F) + +/* DVB Data Broadcast Descriptor */ +#define DESC_DVB_DATA_BROADCAST_data_broadcast_id(desc) (GST_READ_UINT16_BE((desc) + 2)) +#define DESC_DVB_DATA_BROADCAST_component_tag(desc) (desc[4]) +#define DESC_DVB_DATA_BROADCAST_selector_length(desc) (desc[5]) +#define DESC_DVB_DATA_BROADCAST_selector(desc) (desc + 6) +#define DESC_DVB_DATA_BROADCAST_iso639_language_code(desc) (desc + 6 + DESC_DVB_DATA_BROADCAST_selector_length(desc)) +#define DESC_DVB_DATA_BROADCAST_text_length(desc) (desc + 9 + DESC_DVB_DATA_BROADCAST_selector_length(desc)) +#define DESC_DVB_DATA_BROADCAST_text(desc) (desc + 10 + DESC_DVB_DATA_BROADCAST_selector_length(desc)) + +/* DVB Data Broadcast Id Descriptor */ +#define DESC_DVB_DATA_BROADCAST_ID_data_broadcast_id(desc) (GST_READ_UINT16_BE((desc) + 2)) +#define DESC_DVB_DATA_BROADCAST_ID_id_selector_byte(desc) (desc + 4) + +/* DVB Carousel Identifier Descriptor */ +#define DESC_DVB_CAROUSEL_IDENTIFIER_carousel_id(desc) (GST_READ_UINT32_BE((desc) + 2)) + +/* registration_descriptor format IDs */ +#define DRF_ID_HDMV 0x48444d56 +#define DRF_ID_VC1 0x56432D31 /* defined in RP227 */ + +typedef struct { + guint n_desc; + guint8 data_length; + guint8 *data; +} GstMPEGDescriptor; + +void gst_mpegtsdesc_init_debug (void); +GstMPEGDescriptor* gst_mpeg_descriptor_parse (guint8 *data, guint size); +void gst_mpeg_descriptor_free (GstMPEGDescriptor *desc); + +guint gst_mpeg_descriptor_n_desc (GstMPEGDescriptor *desc); +guint8* gst_mpeg_descriptor_find (GstMPEGDescriptor *desc, gint tag); +GArray* gst_mpeg_descriptor_find_all (GstMPEGDescriptor * desc, gint tag); + +guint8* gst_mpeg_descriptor_nth (GstMPEGDescriptor *desc, guint i); + +#endif /* __GST_MPEG_DESC_H__ */ diff --git a/gst/mpegtsdemux/gsttsdemux.c b/gst/mpegtsdemux/gsttsdemux.c new file mode 100644 index 000000000..fc9aa8ddd --- /dev/null +++ b/gst/mpegtsdemux/gsttsdemux.c @@ -0,0 +1,47 @@ +/* + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mpegtsbase.h" +#include "mpegtspacketizer.h" +#include "mpegtsparse.h" +#include "tsdemux.h" + + +static gboolean +plugin_init (GstPlugin * plugin) +{ + if (!gst_mpegtsbase_plugin_init (plugin)) + return FALSE; + if (!gst_mpegtsparse_plugin_init (plugin)) + return FALSE; + if (!gst_ts_demux_plugin_init (plugin)) + return FALSE; + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "mpegtsdemux", + "MPEG TS demuxer", + plugin_init, VERSION, + GST_LICENSE_UNKNOWN, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); diff --git a/gst/mpegtsdemux/mpegtsbase.c b/gst/mpegtsdemux/mpegtsbase.c new file mode 100644 index 000000000..8eb89bff2 --- /dev/null +++ b/gst/mpegtsdemux/mpegtsbase.c @@ -0,0 +1,1258 @@ +/* + * mpegtsbase.c - + * Copyright (C) 2007 Alessandro Decina + * 2010 Edward Hervey + * + * Authors: + * Alessandro Decina <alessandro@nnva.org> + * Zaheer Abbas Merali <zaheerabbas at merali dot org> + * Edward Hervey <edward.hervey@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> + +#include <gst/gst-i18n-plugin.h> +#include "mpegtsbase.h" +#include "gstmpegdesc.h" + +/* latency in mseconds */ +#define TS_LATENCY 700 + +#define TABLE_ID_UNSET 0xFF +#define RUNNING_STATUS_RUNNING 4 + +GST_DEBUG_CATEGORY_STATIC (mpegts_base_debug); +#define GST_CAT_DEFAULT mpegts_base_debug + +static GQuark QUARK_PROGRAMS; +static GQuark QUARK_PROGRAM_NUMBER; +static GQuark QUARK_PID; +static GQuark QUARK_PCR_PID; +static GQuark QUARK_STREAMS; +static GQuark QUARK_STREAM_TYPE; + +static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/mpegts, " "systemstream = (boolean) true ") + ); + +enum +{ + ARG_0, + /* FILL ME */ +}; + +static void mpegts_base_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void mpegts_base_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void mpegts_base_dispose (GObject * object); +static void mpegts_base_finalize (GObject * object); +static void mpegts_base_free_program (MpegTSBaseProgram * program); +static void mpegts_base_free_stream (MpegTSBaseStream * ptream); +static gboolean mpegts_base_sink_activate (GstPad * pad); +static gboolean mpegts_base_sink_activate_pull (GstPad * pad, gboolean active); +static gboolean mpegts_base_sink_activate_push (GstPad * pad, gboolean active); +static GstFlowReturn mpegts_base_chain (GstPad * pad, GstBuffer * buf); +static gboolean mpegts_base_sink_event (GstPad * pad, GstEvent * event); +static GstStateChangeReturn mpegts_base_change_state (GstElement * element, + GstStateChange transition); +static void _extra_init (GType type); +static void mpegts_base_get_tags_from_sdt (MpegTSBase * base, + GstStructure * sdt_info); +static void mpegts_base_get_tags_from_eit (MpegTSBase * base, + GstStructure * eit_info); + +GST_BOILERPLATE_FULL (MpegTSBase, mpegts_base, GstElement, GST_TYPE_ELEMENT, + _extra_init); + + +static const guint32 crc_tab[256] = { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, + 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, + 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, + 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, + 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, + 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, + 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, + 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, + 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, + 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, + 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, + 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, + 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, + 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, + 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, + 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, + 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, + 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, + 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, + 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, + 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, + 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 +}; + +/* relicenced to LGPL from fluendo ts demuxer */ +static guint32 +mpegts_base_calc_crc32 (guint8 * data, guint datalen) +{ + gint i; + guint32 crc = 0xffffffff; + + for (i = 0; i < datalen; i++) { + crc = (crc << 8) ^ crc_tab[((crc >> 24) ^ *data++) & 0xff]; + } + return crc; +} + +static void +_extra_init (GType type) +{ + QUARK_PROGRAMS = g_quark_from_string ("programs"); + QUARK_PROGRAM_NUMBER = g_quark_from_string ("program-number"); + QUARK_PID = g_quark_from_string ("pid"); + QUARK_PCR_PID = g_quark_from_string ("pcr-pid"); + QUARK_STREAMS = g_quark_from_string ("streams"); + QUARK_STREAM_TYPE = g_quark_from_string ("stream-type"); +} + +static void +mpegts_base_base_init (gpointer klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_template)); +} + +static void +mpegts_base_class_init (MpegTSBaseClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *element_class; + + element_class = GST_ELEMENT_CLASS (klass); + element_class->change_state = mpegts_base_change_state; + + gobject_class = G_OBJECT_CLASS (klass); + gobject_class->set_property = mpegts_base_set_property; + gobject_class->get_property = mpegts_base_get_property; + gobject_class->dispose = mpegts_base_dispose; + gobject_class->finalize = mpegts_base_finalize; + +} + +static void +mpegts_base_reset (MpegTSBase * base) +{ + mpegts_packetizer_clear (base->packetizer); + memset (base->is_pes, 0, 8192); + memset (base->known_psi, 0, 8192); + + /* PAT */ + base->known_psi[0] = TRUE; + + /* FIXME : Commenting the Following lines is to be in sync with the following + * commit + * + * 61a885613316ce7657c36a6cd215b43f9dc67b79 + * mpegtsparse: don't free PAT structure which may still be needed later + */ + + /* if (base->pat != NULL) */ + /* gst_structure_free (base->pat); */ + /* base->pat = NULL; */ + /* pmt pids will be added and removed dynamically */ + +} + +static void +mpegts_base_init (MpegTSBase * base, MpegTSBaseClass * klass) +{ + base->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink"); + gst_pad_set_activate_function (base->sinkpad, mpegts_base_sink_activate); + gst_pad_set_activatepull_function (base->sinkpad, + mpegts_base_sink_activate_pull); + gst_pad_set_activatepush_function (base->sinkpad, + mpegts_base_sink_activate_push); + gst_pad_set_chain_function (base->sinkpad, mpegts_base_chain); + gst_pad_set_event_function (base->sinkpad, mpegts_base_sink_event); + gst_element_add_pad (GST_ELEMENT (base), base->sinkpad); + + base->disposed = FALSE; + base->packetizer = mpegts_packetizer_new (); + base->programs = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) mpegts_base_free_program); + + base->is_pes = g_new0 (gboolean, 8192); + base->known_psi = g_new0 (gboolean, 8192); + mpegts_base_reset (base); + base->program_size = sizeof (MpegTSBaseProgram); + base->stream_size = sizeof (MpegTSBaseStream); + + base->mode = BASE_MODE_STREAMING; + base->first_pat_offset = -1; +} + +static void +mpegts_base_dispose (GObject * object) +{ + MpegTSBase *base = GST_MPEGTS_BASE (object); + + if (!base->disposed) { + g_object_unref (base->packetizer); + base->disposed = TRUE; + g_free (base->known_psi); + g_free (base->is_pes); + } + + if (G_OBJECT_CLASS (parent_class)->dispose) + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +mpegts_base_finalize (GObject * object) +{ + MpegTSBase *base = GST_MPEGTS_BASE (object); + + if (base->pat) { + gst_structure_free (base->pat); + base->pat = NULL; + } + g_hash_table_destroy (base->programs); + + if (G_OBJECT_CLASS (parent_class)->finalize) + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +mpegts_base_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + /* MpegTSBase *base = GST_MPEGTS_BASE (object); */ + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +mpegts_base_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + /* MpegTSBase *base = GST_MPEGTS_BASE (object); */ + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +/* returns NULL if no matching descriptor found * + * otherwise returns a descriptor that needs to * + * be freed */ +guint8 * +mpegts_get_descriptor_from_stream (MpegTSBaseStream * stream, guint8 tag) +{ + GValueArray *descriptors = NULL; + GstStructure *stream_info = stream->stream_info; + guint8 *retval = NULL; + int i; + + gst_structure_get (stream_info, "descriptors", G_TYPE_VALUE_ARRAY, + &descriptors, NULL); + if (descriptors) { + for (i = 0; i < descriptors->n_values; i++) { + GValue *value = g_value_array_get_nth (descriptors, i); + guint8 *desc = g_value_dup_boxed (value); + if (DESC_TAG (desc) == tag) { + retval = desc; + break; + } + } + g_value_array_free (descriptors); + } + return retval; +} + +/* returns NULL if no matching descriptor found * + * otherwise returns a descriptor that needs to * + * be freed */ +guint8 * +mpegts_get_descriptor_from_program (MpegTSBaseProgram * program, guint8 tag) +{ + GValueArray *descriptors = NULL; + GstStructure *program_info; + guint8 *retval = NULL; + int i; + + if (G_UNLIKELY (program == NULL)) + return NULL; + program_info = program->pmt_info; + gst_structure_get (program_info, "descriptors", G_TYPE_VALUE_ARRAY, + &descriptors, NULL); + if (descriptors) { + for (i = 0; i < descriptors->n_values; i++) { + GValue *value = g_value_array_get_nth (descriptors, i); + GString *desc = g_value_dup_boxed (value); + if (DESC_TAG (desc->str) == tag) { + retval = (guint8 *) desc->str; + g_string_free (desc, FALSE); + break; + } else + g_string_free (desc, FALSE); + } + g_value_array_free (descriptors); + } + return retval; +} + +MpegTSBaseProgram * +mpegts_base_add_program (MpegTSBase * base, + gint program_number, guint16 pmt_pid) +{ + MpegTSBaseProgram *program; + + program = g_malloc0 (base->program_size); + program->program_number = program_number; + program->pmt_pid = pmt_pid; + program->pcr_pid = G_MAXUINT16; + program->streams = g_new0 (MpegTSBaseStream *, 0x2000); + program->patcount = 0; + + g_hash_table_insert (base->programs, + GINT_TO_POINTER (program_number), program); + + return program; +} + +MpegTSBaseProgram * +mpegts_base_get_program (MpegTSBase * base, gint program_number) +{ + MpegTSBaseProgram *program; + + program = (MpegTSBaseProgram *) g_hash_table_lookup (base->programs, + GINT_TO_POINTER ((gint) program_number)); + + return program; +} + +#if 0 +static GstPad * +mpegts_base_activate_program (MpegTSBase * base, MpegTSBaseProgram * program) +{ + MpegTSBasePad *tspad; + gchar *pad_name; + + pad_name = g_strdup_printf ("program_%d", program->program_number); + + tspad = mpegts_base_create_tspad (base, pad_name); + tspad->program_number = program->program_number; + tspad->program = program; + program->tspad = tspad; + g_free (pad_name); + gst_pad_set_active (tspad->pad, TRUE); + program->active = TRUE; + + return tspad->pad; +} + +static GstPad * +mpegts_base_deactivate_program (MpegTSBase * base, MpegTSBaseProgram * program) +{ + MpegTSBasePad *tspad; + + tspad = program->tspad; + gst_pad_set_active (tspad->pad, FALSE); + program->active = FALSE; + + /* tspad will be destroyed in GstElementClass::pad_removed */ + + return tspad->pad; +} +#endif + + +static void +mpegts_base_free_program (MpegTSBaseProgram * program) +{ + guint i; + + if (program->pmt_info) + gst_structure_free (program->pmt_info); + + for (i = 0; i < 0x2000; i++) + if (program->streams[i]) + mpegts_base_free_stream (program->streams[i]); + + if (program->tags) + gst_tag_list_free (program->tags); + + g_free (program); +} + +void +mpegts_base_remove_program (MpegTSBase * base, gint program_number) +{ + MpegTSBaseProgram *program; + MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base); + + if (klass->program_stopped) { + program = + (MpegTSBaseProgram *) g_hash_table_lookup (base->programs, + GINT_TO_POINTER (program_number)); + klass->program_stopped (base, program); + } + g_hash_table_remove (base->programs, GINT_TO_POINTER (program_number)); + +} + +static MpegTSBaseStream * +mpegts_base_program_add_stream (MpegTSBase * base, + MpegTSBaseProgram * program, guint16 pid, guint8 stream_type, + GstStructure * stream_info) +{ + MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base); + MpegTSBaseStream *stream; + + GST_DEBUG ("pid:0x%04x, stream_type:0x%03x, stream_info:%" GST_PTR_FORMAT, + pid, stream_type, stream_info); + + stream = g_malloc0 (base->stream_size); + stream->pid = pid; + stream->stream_type = stream_type; + stream->stream_info = stream_info; + + program->streams[pid] = stream; + + if (klass->stream_added) + klass->stream_added (base, stream, program); + + return stream; +} + +static void +mpegts_base_free_stream (MpegTSBaseStream * stream) +{ + g_free (stream); +} + +void +mpegts_base_program_remove_stream (MpegTSBase * base, + MpegTSBaseProgram * program, guint16 pid) +{ + MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base); + + /* If subclass needs it, inform it of the stream we are about to remove */ + if (klass->stream_removed) + klass->stream_removed (base, program->streams[pid]); + + mpegts_base_free_stream (program->streams[pid]); + program->streams[pid] = NULL; +} + +static void +mpegts_base_deactivate_pmt (MpegTSBase * base, MpegTSBaseProgram * program) +{ + gint i; + guint pid; + guint stream_type; + GstStructure *stream; + const GValue *streams; + const GValue *value; + MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base); + + if (program->pmt_info) { + /* Inform subclasses we're deactivating this program */ + if (klass->program_stopped) + klass->program_stopped (base, program); + + streams = gst_structure_id_get_value (program->pmt_info, QUARK_STREAMS); + + for (i = 0; i < gst_value_list_get_size (streams); ++i) { + value = gst_value_list_get_value (streams, i); + stream = g_value_get_boxed (value); + gst_structure_id_get (stream, QUARK_PID, G_TYPE_UINT, &pid, + QUARK_STREAM_TYPE, G_TYPE_UINT, &stream_type, NULL); + mpegts_base_program_remove_stream (base, program, (guint16) pid); + base->is_pes[pid] = FALSE; + } + /* remove pcr stream */ + mpegts_base_program_remove_stream (base, program, program->pcr_pid); + base->is_pes[program->pcr_pid] = FALSE; + } +} + + +gboolean +mpegts_base_is_psi (MpegTSBase * base, MpegTSPacketizerPacket * packet) +{ + gboolean retval = FALSE; + guint8 table_id; + int i; + static const guint8 si_tables[] = + { 0x00, 0x01, 0x02, 0x03, 0x40, 0x41, 0x42, 0x46, 0x4A, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, + 0x72, 0x73, 0x7E, 0x7F, TABLE_ID_UNSET + }; + + if (base->known_psi[packet->pid]) + retval = TRUE; + + /* check is it is a pes pid */ + if (base->is_pes[packet->pid]) + return FALSE; + + if (!retval) { + if (packet->payload_unit_start_indicator) { + table_id = *(packet->data); + i = 0; + while (si_tables[i] != TABLE_ID_UNSET) { + if (G_UNLIKELY (si_tables[i] == table_id)) { + GST_DEBUG_OBJECT (base, "Packet has table id 0x%x", table_id); + retval = TRUE; + break; + } + i++; + } + } else { + MpegTSPacketizerStream *stream = (MpegTSPacketizerStream *) + base->packetizer->streams[packet->pid]; + + if (stream) { + i = 0; + GST_DEBUG_OBJECT (base, "section table id: 0x%x", + stream->section_table_id); + while (si_tables[i] != TABLE_ID_UNSET) { + if (G_UNLIKELY (si_tables[i] == stream->section_table_id)) { + retval = TRUE; + break; + } + i++; + } + } + } + } + + GST_LOG_OBJECT (base, "Packet of pid 0x%x is psi: %d", packet->pid, retval); + return retval; +} + +static void +mpegts_base_apply_pat (MpegTSBase * base, GstStructure * pat_info) +{ + const GValue *value; + GstStructure *old_pat; + GstStructure *program_info; + guint program_number; + guint pid; + MpegTSBaseProgram *program; + gint i; + const GValue *programs; + MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base); + + old_pat = base->pat; + base->pat = gst_structure_copy (pat_info); + + GST_INFO_OBJECT (base, "PAT %" GST_PTR_FORMAT, pat_info); + + gst_element_post_message (GST_ELEMENT_CAST (base), + gst_message_new_element (GST_OBJECT (base), + gst_structure_copy (pat_info))); + + programs = gst_structure_id_get_value (pat_info, QUARK_PROGRAMS); + /* activate the new table */ + for (i = 0; i < gst_value_list_get_size (programs); ++i) { + value = gst_value_list_get_value (programs, i); + + program_info = g_value_get_boxed (value); + gst_structure_id_get (program_info, QUARK_PROGRAM_NUMBER, G_TYPE_UINT, + &program_number, QUARK_PID, G_TYPE_UINT, &pid, NULL); + + program = mpegts_base_get_program (base, program_number); + if (program) { + if (program->pmt_pid != pid) { + if (program->pmt_pid != G_MAXUINT16) { + /* pmt pid changed */ + /* FIXME: when this happens it may still be pmt pid of another + * program, so setting to False may make it go through expensive + * path in is_psi unnecessarily */ + base->known_psi[program->pmt_pid] = FALSE; + } + + program->pmt_pid = pid; + base->known_psi[pid] = TRUE; + } + } else { + base->known_psi[pid] = TRUE; + program = mpegts_base_add_program (base, program_number, pid); + } + program->patcount += 1; + } + + if (old_pat) { + /* deactivate the old table */ + + programs = gst_structure_id_get_value (old_pat, QUARK_PROGRAMS); + for (i = 0; i < gst_value_list_get_size (programs); ++i) { + value = gst_value_list_get_value (programs, i); + + program_info = g_value_get_boxed (value); + gst_structure_id_get (program_info, + QUARK_PROGRAM_NUMBER, G_TYPE_UINT, &program_number, + QUARK_PID, G_TYPE_UINT, &pid, NULL); + + program = mpegts_base_get_program (base, program_number); + if (program == NULL) { + GST_DEBUG_OBJECT (base, "broken PAT, duplicated entry for program %d", + program_number); + continue; + } + + if (--program->patcount > 0) + /* the program has been referenced by the new pat, keep it */ + continue; + + GST_INFO_OBJECT (base, "PAT removing program %" GST_PTR_FORMAT, + program_info); + + if (klass->program_stopped) { + klass->program_stopped (base, program); + } + mpegts_base_deactivate_pmt (base, program); + mpegts_base_remove_program (base, program_number); + /* FIXME: when this happens it may still be pmt pid of another + * program, so setting to False may make it go through expensive + * path in is_psi unnecessarily */ + base->known_psi[pid] = TRUE; + mpegts_packetizer_remove_stream (base->packetizer, pid); + } + + gst_structure_free (old_pat); + } +#if 0 + mpegts_base_sync_program_pads (base); +#endif +} + +static void +mpegts_base_apply_pmt (MpegTSBase * base, + guint16 pmt_pid, GstStructure * pmt_info) +{ + MpegTSBaseProgram *program; + guint program_number; + guint pcr_pid; + guint pid; + guint stream_type; + GstStructure *stream; + gint i; + const GValue *new_streams; + const GValue *value; + MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base); + + if (G_UNLIKELY (base->first_pat_offset == -1)) { + GST_WARNING ("Got pmt without pat first. Returning"); + return; + } + + gst_structure_id_get (pmt_info, + QUARK_PROGRAM_NUMBER, G_TYPE_UINT, &program_number, + QUARK_PCR_PID, G_TYPE_UINT, &pcr_pid, NULL); + new_streams = gst_structure_id_get_value (pmt_info, QUARK_STREAMS); + + program = mpegts_base_get_program (base, program_number); + if (program) { + /* deactivate old pmt */ ; + mpegts_base_deactivate_pmt (base, program); + if (program->pmt_info) + gst_structure_free (program->pmt_info); + program->pmt_info = NULL; + } else { + /* no PAT?? */ + base->known_psi[pmt_pid] = TRUE; + program = mpegts_base_add_program (base, program_number, pid); + } + + /* activate new pmt */ + program->pmt_info = gst_structure_copy (pmt_info); + program->pmt_pid = pmt_pid; + program->pcr_pid = pcr_pid; + mpegts_base_program_add_stream (base, program, (guint16) pcr_pid, -1, NULL); + base->is_pes[pcr_pid] = TRUE; + + for (i = 0; i < gst_value_list_get_size (new_streams); ++i) { + value = gst_value_list_get_value (new_streams, i); + stream = g_value_get_boxed (value); + + gst_structure_id_get (stream, QUARK_PID, G_TYPE_UINT, &pid, + QUARK_STREAM_TYPE, G_TYPE_UINT, &stream_type, NULL); + mpegts_base_program_add_stream (base, program, + (guint16) pid, (guint8) stream_type, stream); + base->is_pes[pid] = TRUE; + + } + + if (klass->program_started != NULL) { + klass->program_started (base, program); + } + + GST_DEBUG_OBJECT (base, "new pmt %" GST_PTR_FORMAT, pmt_info); + + gst_element_post_message (GST_ELEMENT_CAST (base), + gst_message_new_element (GST_OBJECT (base), + gst_structure_copy (pmt_info))); +} + +static void +mpegts_base_apply_nit (MpegTSBase * base, + guint16 pmt_pid, GstStructure * nit_info) +{ + GST_DEBUG_OBJECT (base, "NIT %" GST_PTR_FORMAT, nit_info); + + gst_element_post_message (GST_ELEMENT_CAST (base), + gst_message_new_element (GST_OBJECT (base), + gst_structure_copy (nit_info))); +} + +static void +mpegts_base_apply_sdt (MpegTSBase * base, + guint16 pmt_pid, GstStructure * sdt_info) +{ + GST_DEBUG_OBJECT (base, "SDT %" GST_PTR_FORMAT, sdt_info); + + mpegts_base_get_tags_from_sdt (base, sdt_info); + + gst_element_post_message (GST_ELEMENT_CAST (base), + gst_message_new_element (GST_OBJECT (base), + gst_structure_copy (sdt_info))); +} + +static void +mpegts_base_apply_eit (MpegTSBase * base, + guint16 pmt_pid, GstStructure * eit_info) +{ + GST_DEBUG_OBJECT (base, "EIT %" GST_PTR_FORMAT, eit_info); + + mpegts_base_get_tags_from_eit (base, eit_info); + + gst_element_post_message (GST_ELEMENT_CAST (base), + gst_message_new_element (GST_OBJECT (base), + gst_structure_copy (eit_info))); +} + +static void +mpegts_base_apply_tdt (MpegTSBase * base, + guint16 tdt_pid, GstStructure * tdt_info) +{ + gst_element_post_message (GST_ELEMENT_CAST (base), + gst_message_new_element (GST_OBJECT (base), + gst_structure_copy (tdt_info))); + + GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, + gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, + gst_structure_copy (tdt_info))); +} + + +gboolean +mpegts_base_handle_psi (MpegTSBase * base, MpegTSPacketizerSection * section) +{ + gboolean res = TRUE; + GstStructure *structure = NULL; + + /* table ids 0x70 - 0x73 do not have a crc */ + if (G_LIKELY (section->table_id < 0x70 || section->table_id > 0x73)) { + if (G_UNLIKELY (mpegts_base_calc_crc32 (GST_BUFFER_DATA (section->buffer), + GST_BUFFER_SIZE (section->buffer)) != 0)) { + GST_WARNING_OBJECT (base, "bad crc in psi pid 0x%x", section->pid); + return FALSE; + } + } + + switch (section->table_id) { + case 0x00: + /* PAT */ + structure = mpegts_packetizer_parse_pat (base->packetizer, section); + if (G_LIKELY (structure)) { + mpegts_base_apply_pat (base, structure); + if (base->first_pat_offset == -1) { + + base->first_pat_offset = GST_BUFFER_OFFSET (section->buffer); + GST_DEBUG ("First PAT offset: %" G_GUINT64_FORMAT, + base->first_pat_offset); + } + + } else + res = FALSE; + + break; + case 0x02: + structure = mpegts_packetizer_parse_pmt (base->packetizer, section); + if (G_LIKELY (structure)) + mpegts_base_apply_pmt (base, section->pid, structure); + else + res = FALSE; + + break; + case 0x40: + /* NIT, actual network */ + case 0x41: + /* NIT, other network */ + structure = mpegts_packetizer_parse_nit (base->packetizer, section); + if (G_LIKELY (structure)) + mpegts_base_apply_nit (base, section->pid, structure); + else + res = FALSE; + + break; + case 0x42: + case 0x46: + structure = mpegts_packetizer_parse_sdt (base->packetizer, section); + if (G_LIKELY (structure)) + mpegts_base_apply_sdt (base, section->pid, structure); + else + res = FALSE; + break; + case 0x4E: + case 0x4F: + /* EIT, present/following */ + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + /* EIT, schedule */ + structure = mpegts_packetizer_parse_eit (base->packetizer, section); + if (G_LIKELY (structure)) + mpegts_base_apply_eit (base, section->pid, structure); + else + res = FALSE; + break; + case 0x70: + /* TDT (Time and Date table) */ + structure = mpegts_packetizer_parse_tdt (base->packetizer, section); + if (G_LIKELY (structure)) + mpegts_base_apply_tdt (base, section->pid, structure); + else + res = FALSE; + break; + default: + break; + } + + if (structure) + gst_structure_free (structure); + + return res; +} + +static void +mpegts_base_get_tags_from_sdt (MpegTSBase * base, GstStructure * sdt_info) +{ + const GValue *services; + guint i; + + services = gst_structure_get_value (sdt_info, "services"); + + for (i = 0; i < gst_value_list_get_size (services); i++) { + const GstStructure *service; + const gchar *sid_str; + gchar *tmp; + gint program_number; + MpegTSBaseProgram *program; + + service = gst_value_get_structure (gst_value_list_get_value (services, i)); + + /* get program_number from structure name + * which looks like service-%d */ + sid_str = gst_structure_get_name (service); + tmp = g_strstr_len (sid_str, -1, "-"); + program_number = atoi (++tmp); + + program = mpegts_base_get_program (base, program_number); + if (program && !program->tags) { + program->tags = gst_tag_list_new_full (GST_TAG_ARTIST, + gst_structure_get_string (service, "name"), NULL); + } + } +} + +static void +mpegts_base_get_tags_from_eit (MpegTSBase * base, GstStructure * eit_info) +{ + const GValue *events; + guint i; + guint program_number; + MpegTSBaseProgram *program; + gboolean present_following; + + gst_structure_get_uint (eit_info, "service-id", &program_number); + program = mpegts_base_get_program (base, program_number); + + gst_structure_get_boolean (eit_info, "present-following", &present_following); + + if (program && present_following) { + events = gst_structure_get_value (eit_info, "events"); + + for (i = 0; i < gst_value_list_get_size (events); i++) { + const GstStructure *event; + const gchar *title; + guint status; + guint event_id; + guint duration; + + event = gst_value_get_structure (gst_value_list_get_value (events, i)); + + title = gst_structure_get_string (event, "name"); + gst_structure_get_uint (event, "event-id", &event_id); + gst_structure_get_uint (event, "running-status", &status); + + if (title && event_id != program->event_id + && status == RUNNING_STATUS_RUNNING) { + gst_structure_get_uint (event, "duration", &duration); + + program->event_id = event_id; + program->tags = gst_tag_list_new_full (GST_TAG_TITLE, + title, GST_TAG_DURATION, duration * GST_SECOND, NULL); + } + } + } +} + + +static gboolean +mpegts_base_sink_event (GstPad * pad, GstEvent * event) +{ + gboolean res; + MpegTSBase *base = GST_MPEGTS_BASE (gst_object_get_parent (GST_OBJECT (pad))); + + GST_WARNING_OBJECT (base, "Got event %s", + gst_event_type_get_name (GST_EVENT_TYPE (event))); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NEWSEGMENT: + /* FIXME : STORE NEW SEGMENT ! */ + gst_event_unref (event); + res = FALSE; + break; + case GST_EVENT_FLUSH_STOP: + mpegts_packetizer_clear (base->packetizer); + /* Passthrough */ + default: + res = GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, event); + gst_event_unref (event); + } + + gst_object_unref (base); + return res; +} + +static inline GstFlowReturn +mpegts_base_push (MpegTSBase * base, MpegTSPacketizerPacket * packet, + MpegTSPacketizerSection * section) +{ + MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base); + + /* Call implementation */ + if (G_UNLIKELY (klass->push == NULL)) { + GST_ERROR_OBJECT (base, "Class doesn't have a 'push' implementation !"); + return GST_FLOW_ERROR; + } + + return klass->push (base, packet, section); +} + +static GstFlowReturn +mpegts_base_chain (GstPad * pad, GstBuffer * buf) +{ + GstFlowReturn res = GST_FLOW_OK; + MpegTSBase *base; + gboolean based; + MpegTSPacketizerPacketReturn pret; + MpegTSPacketizer2 *packetizer; + MpegTSPacketizerPacket packet; + MpegTSBaseClass *klass; + + base = GST_MPEGTS_BASE (gst_object_get_parent (GST_OBJECT (pad))); + klass = GST_MPEGTS_BASE_GET_CLASS (base); + packetizer = base->packetizer; + + mpegts_packetizer_push (base->packetizer, buf); + while (((pret = + mpegts_packetizer_next_packet (base->packetizer, + &packet)) != PACKET_NEED_MORE) && res == GST_FLOW_OK) { + if (G_UNLIKELY (pret == PACKET_BAD)) + /* bad header, skip the packet */ + goto next; + + /* base PSI data */ + if (packet.payload != NULL && mpegts_base_is_psi (base, &packet)) { + MpegTSPacketizerSection section; + based = mpegts_packetizer_push_section (packetizer, &packet, §ion); + if (G_UNLIKELY (!based)) + /* bad section data */ + goto next; + + if (G_LIKELY (section.complete)) { + /* section complete */ + based = mpegts_base_handle_psi (base, §ion); + gst_buffer_unref (section.buffer); + + if (G_UNLIKELY (!based)) + /* bad PSI table */ + goto next; + } + /* we need to push section packet downstream */ + res = mpegts_base_push (base, &packet, §ion); + + } else { + /* push the packet downstream */ + res = mpegts_base_push (base, &packet, NULL); + } + + next: + mpegts_packetizer_clear_packet (base->packetizer, &packet); + } + + gst_object_unref (base); + return res; +} + +static GstFlowReturn +mpegts_base_scan (MpegTSBase * base) +{ + GstFlowReturn ret; + GstBuffer *buf; + guint i; + MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base); + + GST_DEBUG ("Scanning for initial sync point"); + + /* Find initial sync point */ + for (i = 0; i < 10; i++) { + GST_DEBUG ("Grabbing %d => %d", + i * 50 * MPEGTS_MAX_PACKETSIZE, 50 * MPEGTS_MAX_PACKETSIZE); + ret = gst_pad_pull_range (base->sinkpad, i * 50 * MPEGTS_MAX_PACKETSIZE, + 50 * MPEGTS_MAX_PACKETSIZE, &buf); + if (G_UNLIKELY (ret != GST_FLOW_OK)) + goto beach; + + /* Push to packetizer */ + mpegts_packetizer_push (base->packetizer, buf); + + if (mpegts_packetizer_has_packets (base->packetizer)) { + /* Mark the initial sync point and remember the packetsize */ + base->initial_sync_point = base->seek_offset = base->packetizer->offset; + GST_DEBUG ("Sync point is now %" G_GUINT64_FORMAT, base->seek_offset); + base->packetsize = base->packetizer->packet_size; + + /* If the subclass can seek for timestamps, do that */ + if (klass->find_timestamps) { + guint64 offset; + mpegts_packetizer_clear (base->packetizer); + + ret = klass->find_timestamps (base, 0, &offset); + + base->initial_sync_point = base->seek_offset = + base->packetizer->offset = base->first_pat_offset; + GST_DEBUG ("Sync point is now %" G_GUINT64_FORMAT, base->seek_offset); + } + goto beach; + } + } + + GST_WARNING ("Didn't find initial sync point"); + ret = GST_FLOW_ERROR; + +beach: + mpegts_packetizer_clear (base->packetizer); + return ret; + +} + + +static void +mpegts_base_loop (MpegTSBase * base) +{ + GstFlowReturn ret = GST_FLOW_ERROR; + switch (base->mode) { + case BASE_MODE_SCANNING: + /* Find first sync point */ + ret = mpegts_base_scan (base); + if (G_UNLIKELY (ret != GST_FLOW_OK)) + goto error; + base->mode = BASE_MODE_STREAMING; + GST_DEBUG ("Changing to Streaming"); + break; + case BASE_MODE_SEEKING: + /* FIXME : yes, we should do something here */ + base->mode = BASE_MODE_STREAMING; + break; + case BASE_MODE_STREAMING: + { + GstBuffer *buf; + + GST_DEBUG ("Pulling data from %" G_GUINT64_FORMAT, base->seek_offset); + + ret = gst_pad_pull_range (base->sinkpad, base->seek_offset, + 100 * base->packetsize, &buf); + if (G_UNLIKELY (ret != GST_FLOW_OK)) + goto error; + base->seek_offset += GST_BUFFER_SIZE (buf); + ret = mpegts_base_chain (base->sinkpad, buf); + if (G_UNLIKELY (ret != GST_FLOW_OK)) + goto error; + } + break; + } + + return; + +error: + { + const gchar *reason = gst_flow_get_name (ret); + GST_DEBUG_OBJECT (base, "Pausing task, reason %s", reason); + if (ret == GST_FLOW_UNEXPECTED) + GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, gst_event_new_eos ()); + else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) { + GST_ELEMENT_ERROR (base, STREAM, FAILED, + (_("Internal data stream error.")), + ("stream stopped, reason %s", reason)); + GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, gst_event_new_eos ()); + } + gst_pad_pause_task (base->sinkpad); + } +} + +static gboolean +mpegts_base_sink_activate (GstPad * pad) +{ + if (gst_pad_check_pull_range (pad)) { + GST_DEBUG_OBJECT (pad, "activating pull"); + return gst_pad_activate_pull (pad, TRUE); + } else { + GST_DEBUG_OBJECT (pad, "activating push"); + return gst_pad_activate_push (pad, TRUE); + } +} + +static gboolean +mpegts_base_sink_activate_pull (GstPad * pad, gboolean active) +{ + MpegTSBase *base = GST_MPEGTS_BASE (GST_OBJECT_PARENT (pad)); + if (active) { + base->mode = BASE_MODE_SCANNING; + return gst_pad_start_task (pad, (GstTaskFunction) mpegts_base_loop, base); + } else + return gst_pad_stop_task (pad); +} + +static gboolean +mpegts_base_sink_activate_push (GstPad * pad, gboolean active) +{ + return TRUE; +} + + +static GstStateChangeReturn +mpegts_base_change_state (GstElement * element, GstStateChange transition) +{ + MpegTSBase *base; + GstStateChangeReturn ret; + + base = GST_MPEGTS_BASE (element); + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + switch (transition) { + case GST_STATE_CHANGE_PAUSED_TO_READY: + mpegts_base_reset (base); + break; + default: + break; + } + + return ret; +} + +gboolean +gst_mpegtsbase_plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (mpegts_base_debug, "mpegtsbase", 0, + "MPEG transport stream base class"); + + gst_mpegtsdesc_init_debug (); + + return TRUE; +} diff --git a/gst/mpegtsdemux/mpegtsbase.h b/gst/mpegtsdemux/mpegtsbase.h new file mode 100644 index 000000000..168f2ff1c --- /dev/null +++ b/gst/mpegtsdemux/mpegtsbase.h @@ -0,0 +1,169 @@ +/* + * mpegtsbase.h - GStreamer MPEG transport stream base class + * Copyright (C) 2009 Edward Hervey <edward.hervey@collabora.co.uk> + * 2007 Alessandro Decina + * + * Authors: + * Alessandro Decina <alessandro@nnva.org> + * Edward Hervey <edward.hervey@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef GST_MPEG_TS_BASE_H +#define GST_MPEG_TS_BASE_H + +#include <gst/gst.h> +#include "mpegtspacketizer.h" + +G_BEGIN_DECLS + +#define GST_TYPE_MPEGTS_BASE \ + (mpegts_base_get_type()) +#define GST_MPEGTS_BASE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MPEGTS_BASE,MpegTSBase)) +#define GST_MPEGTS_BASE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MPEGTS_BASE,MpegTSBaseClass)) +#define GST_IS_MPEGTS_BASE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MPEGTS_BASE)) +#define GST_IS_MPEGTS_BASE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MPEGTS_BASE)) +#define GST_MPEGTS_BASE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_MPEGTS_BASE, MpegTSBaseClass)) + +typedef struct _MpegTSBase MpegTSBase; +typedef struct _MpegTSBaseClass MpegTSBaseClass; +typedef struct _MpegTSBaseStream MpegTSBaseStream; +typedef struct _MpegTSBaseProgram MpegTSBaseProgram; + +struct _MpegTSBaseStream +{ + guint16 pid; + guint8 stream_type; + GstStructure* stream_info; +}; + +struct _MpegTSBaseProgram +{ + gint program_number; + guint16 pmt_pid; + guint16 pcr_pid; + GstStructure *pmt_info; + MpegTSBaseStream **streams; + gint patcount; + + /* Pending Tags for the program */ + GstTagList *tags; + guint event_id; +}; + +typedef enum { + BASE_MODE_SCANNING, + BASE_MODE_SEEKING, + BASE_MODE_STREAMING +} MpegTSBaseMode; + +struct _MpegTSBase { + GstElement element; + + GstPad *sinkpad; + + /* pull-based behaviour */ + MpegTSBaseMode mode; + + /* location of first sync point */ + guint64 initial_sync_point; + + /* Current pull offset (also set by seek handler) */ + guint64 seek_offset; + + /* Cached packetsize */ + guint16 packetsize; + + /* the following vars must be protected with the OBJECT_LOCK as they can be + * accessed from the application thread and the streaming thread */ + GHashTable *programs; + + GstStructure *pat; + MpegTSPacketizer2 *packetizer; + + /* arrays that say whether a pid is a known psi pid or a pes pid + * FIXME: Make these bit arrays so we can make them 8 times smaller */ + gboolean *known_psi; + gboolean *is_pes; + + gboolean disposed; + + /* size of the MpegTSBaseProgram structure, can be overridden + * by subclasses if they have their own MpegTSBaseProgram subclasses. */ + gsize program_size; + + /* size of the MpegTSBaseStream structure, can be overridden + * by subclasses if they have their own MpegTSBaseStream subclasses */ + gsize stream_size; + + /*Offset from the origin to the first PAT (pullmode) */ + guint64 first_pat_offset; +}; + +struct _MpegTSBaseClass { + GstElementClass parent_class; + + /* Virtual methods */ + GstFlowReturn (*push) (MpegTSBase *base, MpegTSPacketizerPacket *packet, MpegTSPacketizerSection * section); + gboolean (*push_event) (MpegTSBase *base, GstEvent * event); + /* program_started gets called when program's pmt arrives for first time */ + void (*program_started) (MpegTSBase *base, MpegTSBaseProgram *program); + /* program_stopped gets called when pat no longer has program's pmt */ + void (*program_stopped) (MpegTSBase *base, MpegTSBaseProgram *program); + + /* stream_added is called whenever a new stream has been identified */ + void (*stream_added) (MpegTSBase *base, MpegTSBaseStream *stream, MpegTSBaseProgram *program); + /* stream_removed is called whenever a stream is no longer referenced */ + void (*stream_removed) (MpegTSBase *base, MpegTSBaseStream *stream); + + /* find_timestamps is called to find PCR */ + GstFlowReturn (*find_timestamps) (MpegTSBase * base, guint64 initoff, guint64 *offset); + + /* signals */ + void (*pat_info) (GstStructure *pat); + void (*pmt_info) (GstStructure *pmt); + void (*nit_info) (GstStructure *nit); + void (*sdt_info) (GstStructure *sdt); + void (*eit_info) (GstStructure *eit); +}; + +GType mpegts_base_get_type(void); + +MpegTSBaseProgram *mpegts_base_get_program (MpegTSBase * base, gint program_number); +MpegTSBaseProgram *mpegts_base_add_program (MpegTSBase * base, gint program_number, guint16 pmt_pid); + +guint8 *mpegts_get_descriptor_from_stream (MpegTSBaseStream * stream, guint8 tag); +guint8 *mpegts_get_descriptor_from_program (MpegTSBaseProgram * program, guint8 tag); + + +gboolean gst_mpegtsbase_plugin_init (GstPlugin * plugin); + +gboolean mpegts_base_is_psi (MpegTSBase * base, MpegTSPacketizerPacket * packet); +gboolean mpegts_base_handle_psi (MpegTSBase * base, MpegTSPacketizerSection * section); + +void mpegts_base_program_remove_stream (MpegTSBase * base, MpegTSBaseProgram * program, guint16 pid); + +void mpegts_base_remove_program(MpegTSBase *base, gint program_number); +G_END_DECLS + +#endif /* GST_MPEG_TS_BASE_H */ diff --git a/gst/mpegtsdemux/mpegtspacketizer.c b/gst/mpegtsdemux/mpegtspacketizer.c new file mode 100644 index 000000000..f27918a0e --- /dev/null +++ b/gst/mpegtsdemux/mpegtspacketizer.c @@ -0,0 +1,2714 @@ +/* + * mpegtspacketizer.c - + * Copyright (C) 2007, 2008 Alessandro Decina, Zaheer Merali + * + * Authors: + * Zaheer Merali <zaheerabbas at merali dot org> + * Alessandro Decina <alessandro@nnva.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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <string.h> + +#include "mpegtspacketizer.h" +#include "gstmpegdesc.h" + +GST_DEBUG_CATEGORY_STATIC (mpegts_packetizer_debug); +#define GST_CAT_DEFAULT mpegts_packetizer_debug + +static GQuark QUARK_PAT; +static GQuark QUARK_TRANSPORT_STREAM_ID; +static GQuark QUARK_PROGRAM_NUMBER; +static GQuark QUARK_PID; +static GQuark QUARK_PROGRAMS; + +static GQuark QUARK_PMT; +static GQuark QUARK_PCR_PID; +static GQuark QUARK_VERSION_NUMBER; +static GQuark QUARK_DESCRIPTORS; +static GQuark QUARK_STREAM_TYPE; +static GQuark QUARK_STREAMS; + +static GQuark QUARK_NIT; +static GQuark QUARK_NETWORK_ID; +static GQuark QUARK_CURRENT_NEXT_INDICATOR; +static GQuark QUARK_ACTUAL_NETWORK; +static GQuark QUARK_NETWORK_NAME; +static GQuark QUARK_ORIGINAL_NETWORK_ID; +static GQuark QUARK_TRANSPORTS; + +static GQuark QUARK_SDT; +static GQuark QUARK_ACTUAL_TRANSPORT_STREAM; +static GQuark QUARK_SERVICES; + +static GQuark QUARK_EIT; +static GQuark QUARK_SERVICE_ID; +static GQuark QUARK_PRESENT_FOLLOWING; +static GQuark QUARK_SEGMENT_LAST_SECTION_NUMBER; +static GQuark QUARK_LAST_TABLE_ID; +static GQuark QUARK_EVENTS; + +static void _init_local (void); +G_DEFINE_TYPE_EXTENDED (MpegTSPacketizer2, mpegts_packetizer, G_TYPE_OBJECT, 0, + _init_local ()); + +static void mpegts_packetizer_dispose (GObject * object); +static void mpegts_packetizer_finalize (GObject * object); +static gchar *convert_to_utf8 (const gchar * text, gint length, guint start, + const gchar * encoding, gboolean is_multibyte, GError ** error); +static gchar *get_encoding (const gchar * text, guint * start_text, + gboolean * is_multibyte); +static gchar *get_encoding_and_convert (const gchar * text, guint length); + +#define CONTINUITY_UNSET 255 +#define MAX_CONTINUITY 15 +#define VERSION_NUMBER_UNSET 255 +#define TABLE_ID_UNSET 0xFF + +static gint +mpegts_packetizer_stream_subtable_compare (gconstpointer a, gconstpointer b) +{ + MpegTSPacketizerStreamSubtable *asub, *bsub; + + asub = (MpegTSPacketizerStreamSubtable *) a; + bsub = (MpegTSPacketizerStreamSubtable *) b; + + if (asub->table_id == bsub->table_id && + asub->subtable_extension == bsub->subtable_extension) + return 0; + return -1; +} + +static MpegTSPacketizerStreamSubtable * +mpegts_packetizer_stream_subtable_new (guint8 table_id, + guint16 subtable_extension) +{ + MpegTSPacketizerStreamSubtable *subtable; + + subtable = g_new0 (MpegTSPacketizerStreamSubtable, 1); + subtable->version_number = VERSION_NUMBER_UNSET; + subtable->table_id = table_id; + subtable->subtable_extension = subtable_extension; + subtable->crc = 0; + return subtable; +} + +static MpegTSPacketizerStream * +mpegts_packetizer_stream_new (void) +{ + MpegTSPacketizerStream *stream; + + stream = (MpegTSPacketizerStream *) g_new0 (MpegTSPacketizerStream, 1); + stream->section_adapter = gst_adapter_new (); + stream->continuity_counter = CONTINUITY_UNSET; + stream->subtables = NULL; + stream->section_table_id = TABLE_ID_UNSET; + return stream; +} + +static void +mpegts_packetizer_stream_free (MpegTSPacketizerStream * stream) +{ + gst_adapter_clear (stream->section_adapter); + g_object_unref (stream->section_adapter); + g_slist_foreach (stream->subtables, (GFunc) g_free, NULL); + g_slist_free (stream->subtables); + g_free (stream); +} + +static void +mpegts_packetizer_clear_section (MpegTSPacketizer2 * packetizer, + MpegTSPacketizerStream * stream) +{ + gst_adapter_clear (stream->section_adapter); + stream->continuity_counter = CONTINUITY_UNSET; + stream->section_length = 0; + stream->section_table_id = TABLE_ID_UNSET; +} + +static void +mpegts_packetizer_class_init (MpegTSPacketizer2Class * klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->dispose = mpegts_packetizer_dispose; + gobject_class->finalize = mpegts_packetizer_finalize; +} + +static void +mpegts_packetizer_init (MpegTSPacketizer2 * packetizer) +{ + packetizer->adapter = gst_adapter_new (); + packetizer->offset = 0; + packetizer->empty = TRUE; + packetizer->streams = g_new0 (MpegTSPacketizerStream *, 8192); + packetizer->know_packet_size = FALSE; +} + +static void +mpegts_packetizer_dispose (GObject * object) +{ + MpegTSPacketizer2 *packetizer = GST_MPEGTS_PACKETIZER (object); + + if (!packetizer->disposed) { + if (packetizer->know_packet_size && packetizer->caps != NULL) { + gst_caps_unref (packetizer->caps); + packetizer->caps = NULL; + packetizer->know_packet_size = FALSE; + } + if (packetizer->streams) { + int i; + for (i = 0; i < 8192; i++) { + if (packetizer->streams[i]) + mpegts_packetizer_stream_free (packetizer->streams[i]); + } + g_free (packetizer->streams); + } + + gst_adapter_clear (packetizer->adapter); + g_object_unref (packetizer->adapter); + packetizer->disposed = TRUE; + packetizer->offset = 0; + packetizer->empty = TRUE; + } + + if (G_OBJECT_CLASS (mpegts_packetizer_parent_class)->dispose) + G_OBJECT_CLASS (mpegts_packetizer_parent_class)->dispose (object); +} + +static void +mpegts_packetizer_finalize (GObject * object) +{ + if (G_OBJECT_CLASS (mpegts_packetizer_parent_class)->finalize) + G_OBJECT_CLASS (mpegts_packetizer_parent_class)->finalize (object); +} + +static gboolean +mpegts_packetizer_parse_adaptation_field_control (MpegTSPacketizer2 * + packetizer, MpegTSPacketizerPacket * packet) +{ + guint8 length, afcflags; + guint8 *data; + + length = *packet->data++; + + if (packet->adaptation_field_control == 0x02) { + /* no payload, adaptation field of 183 bytes */ + if (length != 183) { + GST_DEBUG ("PID %d afc == 0x%x and length %d != 183", + packet->pid, packet->adaptation_field_control, length); + } + } else if (length > 182) { + GST_DEBUG ("PID %d afc == 0x%01x and length %d > 182", + packet->pid, packet->adaptation_field_control, length); + } + + if (packet->data + length > packet->data_end) { + GST_DEBUG ("PID %d afc length %d overflows the buffer current %d max %d", + packet->pid, length, (gint) (packet->data - packet->data_start), + (gint) (packet->data_end - packet->data_start)); + return FALSE; + } + + data = packet->data; + packet->data += length; + + afcflags = packet->afc_flags = *data++; + + /* PCR */ + if (afcflags & MPEGTS_AFC_PCR_FLAG) { + guint32 pcr1; + guint16 pcr2; + guint64 pcr, pcr_ext; + + pcr1 = GST_READ_UINT32_BE (data); + pcr2 = GST_READ_UINT16_BE (data + 4); + pcr = ((guint64) pcr1) << 1; + pcr |= (pcr2 & 0x8000) >> 15; + pcr_ext = (pcr2 & 0x01ff); + packet->pcr = pcr * 300 + pcr_ext % 300;; + *data += 6; + } + + /* OPCR */ + if (afcflags & MPEGTS_AFC_OPCR_FLAG) { + guint32 pcr1; + guint16 pcr2; + guint64 pcr, pcr_ext; + + pcr1 = GST_READ_UINT32_BE (data); + pcr2 = GST_READ_UINT16_BE (data + 4); + pcr = ((guint64) pcr1) << 1; + pcr |= (pcr2 & 0x8000) >> 15; + pcr_ext = (pcr2 & 0x01ff); + packet->opcr = pcr * 300 + pcr_ext % 300;; + *data += 6; + } + + return TRUE; +} + +static gboolean +mpegts_packetizer_parse_packet (MpegTSPacketizer2 * packetizer, + MpegTSPacketizerPacket * packet) +{ + guint8 *data; + + data = packet->data_start; + data++; + + packet->payload_unit_start_indicator = (*data >> 6) & 0x01; + packet->pid = GST_READ_UINT16_BE (data) & 0x1FFF; + data += 2; + + packet->adaptation_field_control = (*data >> 4) & 0x03; + packet->continuity_counter = *data & 0x0F; + data += 1; + + packet->data = data; + + if (packet->adaptation_field_control & 0x02) + if (!mpegts_packetizer_parse_adaptation_field_control (packetizer, packet)) + return FALSE; + + if (packet->adaptation_field_control & 0x01) + packet->payload = packet->data; + else + packet->payload = NULL; + + return TRUE; +} + +static gboolean +mpegts_packetizer_parse_section_header (MpegTSPacketizer2 * packetizer, + MpegTSPacketizerStream * stream, MpegTSPacketizerSection * section) +{ + guint8 tmp; + guint8 *data, *crc_data; + MpegTSPacketizerStreamSubtable *subtable; + GSList *subtable_list = NULL; + + section->complete = TRUE; + /* get the section buffer, pass the ownership to the caller */ + section->buffer = gst_adapter_take_buffer (stream->section_adapter, + 3 + stream->section_length); + data = GST_BUFFER_DATA (section->buffer); + GST_BUFFER_OFFSET (section->buffer) = stream->offset; + + section->table_id = *data++; + /* if table_id is 0 (pat) then ignore the subtable extension */ + if ((data[0] & 0x80) == 0 || section->table_id == 0) + section->subtable_extension = 0; + else + section->subtable_extension = GST_READ_UINT16_BE (data + 2); + + subtable = mpegts_packetizer_stream_subtable_new (section->table_id, + section->subtable_extension); + + subtable_list = g_slist_find_custom (stream->subtables, subtable, + mpegts_packetizer_stream_subtable_compare); + if (subtable_list) { + g_free (subtable); + subtable = (MpegTSPacketizerStreamSubtable *) (subtable_list->data); + } else { + stream->subtables = g_slist_prepend (stream->subtables, subtable); + } + + section->section_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; + + /* skip to the version byte */ + data += 2; + + tmp = *data++; + section->version_number = (tmp >> 1) & 0x1F; + section->current_next_indicator = tmp & 0x01; + + if (!section->current_next_indicator) + goto not_applicable; + + /* CRC is at the end of the section */ + crc_data = + GST_BUFFER_DATA (section->buffer) + GST_BUFFER_SIZE (section->buffer) - 4; + section->crc = GST_READ_UINT32_BE (crc_data); + + if (section->version_number == subtable->version_number && + section->crc == subtable->crc) + goto not_applicable; + + subtable->version_number = section->version_number; + subtable->crc = section->crc; + stream->section_table_id = section->table_id; + + return TRUE; + +not_applicable: + GST_LOG + ("not applicable pid %d table_id %d subtable_extension %d, current_next %d version %d, crc 0x%x", + section->pid, section->table_id, section->subtable_extension, + section->current_next_indicator, section->version_number, section->crc); + section->complete = FALSE; + gst_buffer_unref (section->buffer); + return TRUE; +} + +static gboolean +mpegts_packetizer_parse_descriptors (MpegTSPacketizer2 * packetizer, + guint8 ** buffer, guint8 * buffer_end, GValueArray * descriptors) +{ + guint8 tag, length; + guint8 *data; + GValue value = { 0 }; + GString *desc; + + data = *buffer; + + while (data < buffer_end) { + tag = *data++; + length = *data++; + + if (data + length > buffer_end) { + GST_WARNING ("invalid descriptor length %d now at %d max %d", length, + (gint) (data - *buffer), (gint) (buffer_end - *buffer)); + goto error; + } + + /* include tag and length */ + desc = g_string_new_len ((gchar *) data - 2, length + 2); + data += length; + /* G_TYPE_GSTING is a GBoxed type and is used so properly marshalled from python */ + g_value_init (&value, G_TYPE_GSTRING); + g_value_take_boxed (&value, desc); + g_value_array_append (descriptors, &value); + g_value_unset (&value); + } + + if (data != buffer_end) { + GST_WARNING ("descriptors size %d expected %d", (gint) (data - *buffer), + (gint) (buffer_end - *buffer)); + goto error; + } + + *buffer = data; + + return TRUE; +error: + return FALSE; +} + +GstStructure * +mpegts_packetizer_parse_pat (MpegTSPacketizer2 * packetizer, + MpegTSPacketizerSection * section) +{ + GstStructure *pat_info = NULL; + guint8 *data, *end; + guint transport_stream_id; + guint8 tmp; + guint program_number; + guint pmt_pid; + GValue entries = { 0 }; + GValue value = { 0 }; + GstStructure *entry = NULL; + gchar *struct_name; + + data = GST_BUFFER_DATA (section->buffer); + + section->table_id = *data++; + section->section_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; + + transport_stream_id = GST_READ_UINT16_BE (data); + data += 2; + + tmp = *data++; + section->version_number = (tmp >> 1) & 0x1F; + section->current_next_indicator = tmp & 0x01; + + /* skip section_number and last_section_number */ + data += 2; + + pat_info = gst_structure_id_new (QUARK_PAT, + QUARK_TRANSPORT_STREAM_ID, G_TYPE_UINT, transport_stream_id, NULL); + g_value_init (&entries, GST_TYPE_LIST); + /* stop at the CRC */ + end = GST_BUFFER_DATA (section->buffer) + GST_BUFFER_SIZE (section->buffer); + while (data < end - 4) { + program_number = GST_READ_UINT16_BE (data); + data += 2; + + pmt_pid = GST_READ_UINT16_BE (data) & 0x1FFF; + data += 2; + + struct_name = g_strdup_printf ("program-%d", program_number); + entry = gst_structure_new (struct_name, NULL); + g_free (struct_name); + gst_structure_id_set (entry, QUARK_PROGRAM_NUMBER, G_TYPE_UINT, + program_number, QUARK_PID, G_TYPE_UINT, pmt_pid, NULL); + + g_value_init (&value, GST_TYPE_STRUCTURE); + g_value_take_boxed (&value, entry); + gst_value_list_append_value (&entries, &value); + g_value_unset (&value); + } + + gst_structure_id_set_value (pat_info, QUARK_PROGRAMS, &entries); + g_value_unset (&entries); + + if (data != end - 4) { + /* FIXME: check the CRC before parsing the packet */ + GST_ERROR ("at the end of PAT data != end - 4"); + gst_structure_free (pat_info); + + return NULL; + } + + return pat_info; +} + +GstStructure * +mpegts_packetizer_parse_pmt (MpegTSPacketizer2 * packetizer, + MpegTSPacketizerSection * section) +{ + GstStructure *pmt = NULL; + guint8 *data, *end; + guint16 program_number; + guint8 tmp; + guint pcr_pid; + guint program_info_length; + guint8 stream_type; + guint16 pid; + guint stream_info_length; + GValueArray *descriptors; + GValue stream_value = { 0 }; + GValue programs = { 0 }; + GstStructure *stream_info = NULL; + gchar *struct_name; + + /* fixed header + CRC == 16 */ + if (GST_BUFFER_SIZE (section->buffer) < 16) { + GST_WARNING ("PID %d invalid PMT size %d", + section->pid, section->section_length); + goto error; + } + + data = GST_BUFFER_DATA (section->buffer); + end = data + GST_BUFFER_SIZE (section->buffer); + + section->table_id = *data++; + section->section_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; + + program_number = GST_READ_UINT16_BE (data); + data += 2; + + tmp = *data++; + section->version_number = (tmp >> 1) & 0x1F; + section->current_next_indicator = tmp & 0x01; + + /* skip section_number and last_section_number */ + data += 2; + + pcr_pid = GST_READ_UINT16_BE (data) & 0x1FFF; + data += 2; + + program_info_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; + + pmt = gst_structure_id_new (QUARK_PMT, + QUARK_PROGRAM_NUMBER, G_TYPE_UINT, program_number, + QUARK_PCR_PID, G_TYPE_UINT, pcr_pid, + QUARK_VERSION_NUMBER, G_TYPE_UINT, section->version_number, NULL); + + if (program_info_length) { + /* check that the buffer is large enough to contain at least + * program_info_length bytes + CRC */ + if (data + program_info_length + 4 > end) { + GST_WARNING ("PID %d invalid program info length %d left %d", + section->pid, program_info_length, (gint) (end - data)); + goto error; + } + + descriptors = g_value_array_new (0); + if (!mpegts_packetizer_parse_descriptors (packetizer, + &data, data + program_info_length, descriptors)) { + g_value_array_free (descriptors); + goto error; + } + + gst_structure_id_set (pmt, QUARK_DESCRIPTORS, G_TYPE_VALUE_ARRAY, + descriptors, NULL); + g_value_array_free (descriptors); + } + + g_value_init (&programs, GST_TYPE_LIST); + /* parse entries, cycle until there's space for another entry (at least 5 + * bytes) plus the CRC */ + while (data <= end - 4 - 5) { + stream_type = *data++; + + pid = GST_READ_UINT16_BE (data) & 0x1FFF; + data += 2; + + stream_info_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; + + if (data + stream_info_length + 4 > end) { + GST_WARNING ("PID %d invalid stream info length %d left %d", section->pid, + stream_info_length, (gint) (end - data)); + g_value_unset (&programs); + goto error; + } + + struct_name = g_strdup_printf ("pid-%d", pid); + stream_info = gst_structure_new (struct_name, NULL); + g_free (struct_name); + gst_structure_id_set (stream_info, + QUARK_PID, G_TYPE_UINT, pid, QUARK_STREAM_TYPE, G_TYPE_UINT, + stream_type, NULL); + + if (stream_info_length) { + /* check for AC3 descriptor */ + GstMPEGDescriptor *desc = + gst_mpeg_descriptor_parse (data, stream_info_length); + if (desc != NULL) { + /* DVB AC3 */ + guint8 *desc_data; + if (gst_mpeg_descriptor_find (desc, DESC_DVB_AC3)) { + gst_structure_set (stream_info, "has-ac3", G_TYPE_BOOLEAN, TRUE, + NULL); + } + + /* DATA BROADCAST ID */ + desc_data = gst_mpeg_descriptor_find (desc, DESC_DVB_DATA_BROADCAST_ID); + if (desc_data) { + guint16 data_broadcast_id; + data_broadcast_id = + DESC_DVB_DATA_BROADCAST_ID_data_broadcast_id (desc_data); + gst_structure_set (stream_info, "data-broadcast-id", G_TYPE_UINT, + data_broadcast_id, NULL); + } + + /* DATA BROADCAST */ + desc_data = gst_mpeg_descriptor_find (desc, DESC_DVB_DATA_BROADCAST); + if (desc_data) { + GstStructure *databroadcast_info; + guint16 data_broadcast_id; + guint8 component_tag; + data_broadcast_id = + DESC_DVB_DATA_BROADCAST_data_broadcast_id (desc_data); + component_tag = DESC_DVB_DATA_BROADCAST_component_tag (desc_data); + databroadcast_info = gst_structure_new ("data-broadcast", "id", + G_TYPE_UINT, data_broadcast_id, "component-tag", component_tag, + NULL); + gst_structure_set (stream_info, "data-broadcast", GST_TYPE_STRUCTURE, + databroadcast_info, NULL); + } + + /* DVB CAROUSEL IDENTIFIER */ + desc_data = + gst_mpeg_descriptor_find (desc, DESC_DVB_CAROUSEL_IDENTIFIER); + if (desc_data) { + guint32 carousel_id; + carousel_id = DESC_DVB_CAROUSEL_IDENTIFIER_carousel_id (desc_data); + gst_structure_set (stream_info, "carousel-id", G_TYPE_UINT, + carousel_id, NULL); + } + + /* DVB STREAM IDENTIFIER */ + desc_data = gst_mpeg_descriptor_find (desc, DESC_DVB_STREAM_IDENTIFIER); + if (desc_data) { + guint8 component_tag; + component_tag = DESC_DVB_STREAM_IDENTIFIER_component_tag (desc_data); + gst_structure_set (stream_info, "component-tag", G_TYPE_UINT, + component_tag, NULL); + } + + /* ISO 639 LANGUAGE */ + desc_data = gst_mpeg_descriptor_find (desc, DESC_ISO_639_LANGUAGE); + if (desc_data && DESC_ISO_639_LANGUAGE_codes_n (desc_data)) { + gchar *lang_code; + gchar *language_n = (gchar *) + DESC_ISO_639_LANGUAGE_language_code_nth (desc_data, 0); + lang_code = g_strndup (language_n, 3); + gst_structure_set (stream_info, "lang-code", G_TYPE_STRING, + lang_code, NULL); + g_free (lang_code); + } + + gst_mpeg_descriptor_free (desc); + } + + descriptors = g_value_array_new (0); + if (!mpegts_packetizer_parse_descriptors (packetizer, + &data, data + stream_info_length, descriptors)) { + g_value_unset (&programs); + gst_structure_free (stream_info); + g_value_array_free (descriptors); + goto error; + } + + gst_structure_id_set (stream_info, + QUARK_DESCRIPTORS, G_TYPE_VALUE_ARRAY, descriptors, NULL); + g_value_array_free (descriptors); + + } + + g_value_init (&stream_value, GST_TYPE_STRUCTURE); + g_value_take_boxed (&stream_value, stream_info); + gst_value_list_append_value (&programs, &stream_value); + g_value_unset (&stream_value); + } + + gst_structure_id_set_value (pmt, QUARK_STREAMS, &programs); + g_value_unset (&programs); + + g_assert (data == end - 4); + + return pmt; + +error: + if (pmt) + gst_structure_free (pmt); + + return NULL; +} + +GstStructure * +mpegts_packetizer_parse_nit (MpegTSPacketizer2 * packetizer, + MpegTSPacketizerSection * section) +{ + GstStructure *nit = NULL, *transport = NULL, *delivery_structure = NULL; + guint8 *data, *end, *entry_begin; + guint16 network_id, transport_stream_id, original_network_id; + guint tmp; + guint16 descriptors_loop_length, transport_stream_loop_length; + GValue transports = { 0 }; + GValue transport_value = { 0 }; + GValueArray *descriptors = NULL; + + GST_DEBUG ("NIT"); + /* fixed header + CRC == 16 */ + if (GST_BUFFER_SIZE (section->buffer) < 23) { + GST_WARNING ("PID %d invalid NIT size %d", + section->pid, section->section_length); + goto error; + } + + data = GST_BUFFER_DATA (section->buffer); + end = data + GST_BUFFER_SIZE (section->buffer); + + section->table_id = *data++; + section->section_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; + + if (data + section->section_length != end) { + GST_WARNING ("PID %d invalid NIT section length %d expected %d", + section->pid, section->section_length, (gint) (end - data)); + goto error; + } + + network_id = GST_READ_UINT16_BE (data); + data += 2; + + tmp = *data++; + section->version_number = (tmp >> 1) & 0x1F; + section->current_next_indicator = tmp & 0x01; + + /* skip section_number and last_section_number */ + data += 2; + + descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; + + nit = gst_structure_id_new (QUARK_NIT, + QUARK_NETWORK_ID, G_TYPE_UINT, network_id, + QUARK_VERSION_NUMBER, G_TYPE_UINT, section->version_number, + QUARK_CURRENT_NEXT_INDICATOR, G_TYPE_UINT, + section->current_next_indicator, QUARK_ACTUAL_NETWORK, G_TYPE_BOOLEAN, + section->table_id == 0x40, NULL); + + /* see if the buffer is large enough */ + if (descriptors_loop_length) { + guint8 *networkname_descriptor; + GstMPEGDescriptor *mpegdescriptor; + + if (data + descriptors_loop_length > end - 4) { + GST_WARNING ("PID %d invalid NIT descriptors loop length %d", + section->pid, descriptors_loop_length); + gst_structure_free (nit); + goto error; + } + mpegdescriptor = gst_mpeg_descriptor_parse (data, descriptors_loop_length); + networkname_descriptor = + gst_mpeg_descriptor_find (mpegdescriptor, DESC_DVB_NETWORK_NAME); + if (networkname_descriptor != NULL) { + gchar *networkname_tmp; + + /* No need to bounds check this value as it comes from the descriptor length itself */ + guint8 networkname_length = + DESC_DVB_NETWORK_NAME_length (networkname_descriptor); + gchar *networkname = + (gchar *) DESC_DVB_NETWORK_NAME_text (networkname_descriptor); + + networkname_tmp = + get_encoding_and_convert (networkname, networkname_length); + gst_structure_id_set (nit, QUARK_NETWORK_NAME, G_TYPE_STRING, + networkname_tmp, NULL); + g_free (networkname_tmp); + } + gst_mpeg_descriptor_free (mpegdescriptor); + + descriptors = g_value_array_new (0); + if (!mpegts_packetizer_parse_descriptors (packetizer, + &data, data + descriptors_loop_length, descriptors)) { + gst_structure_free (nit); + g_value_array_free (descriptors); + goto error; + } + + gst_structure_id_set (nit, QUARK_DESCRIPTORS, G_TYPE_VALUE_ARRAY, + descriptors, NULL); + g_value_array_free (descriptors); + } + + transport_stream_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; + + g_value_init (&transports, GST_TYPE_LIST); + /* read up to the CRC */ + while (transport_stream_loop_length - 4 > 0) { + gchar *transport_name; + + entry_begin = data; + + if (transport_stream_loop_length < 10) { + /* each entry must be at least 6 bytes (+ 4bytes CRC) */ + GST_WARNING ("PID %d invalid NIT entry size %d", + section->pid, transport_stream_loop_length); + goto error; + } + + transport_stream_id = GST_READ_UINT16_BE (data); + data += 2; + + original_network_id = GST_READ_UINT16_BE (data); + data += 2; + + descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; + + transport_name = g_strdup_printf ("transport-%d", transport_stream_id); + transport = gst_structure_new (transport_name, NULL); + g_free (transport_name); + gst_structure_id_set (transport, + QUARK_TRANSPORT_STREAM_ID, G_TYPE_UINT, transport_stream_id, + QUARK_ORIGINAL_NETWORK_ID, G_TYPE_UINT, original_network_id, NULL); + + if (descriptors_loop_length) { + GstMPEGDescriptor *mpegdescriptor; + guint8 *delivery; + + if (data + descriptors_loop_length > end - 4) { + GST_WARNING ("PID %d invalid NIT entry %d descriptors loop length %d", + section->pid, transport_stream_id, descriptors_loop_length); + gst_structure_free (transport); + goto error; + } + mpegdescriptor = + gst_mpeg_descriptor_parse (data, descriptors_loop_length); + + if ((delivery = + gst_mpeg_descriptor_find (mpegdescriptor, + DESC_DVB_SATELLITE_DELIVERY_SYSTEM))) { + + guint8 *frequency_bcd = + DESC_DVB_SATELLITE_DELIVERY_SYSTEM_frequency (delivery); + guint32 frequency = + 10 * ((frequency_bcd[3] & 0x0F) + + 10 * ((frequency_bcd[3] & 0xF0) >> 4) + + 100 * (frequency_bcd[2] & 0x0F) + + 1000 * ((frequency_bcd[2] & 0xF0) >> 4) + + 10000 * (frequency_bcd[1] & 0x0F) + + 100000 * ((frequency_bcd[1] & 0xF0) >> 4) + + 1000000 * (frequency_bcd[0] & 0x0F) + + 10000000 * ((frequency_bcd[0] & 0xF0) >> 4)); + guint8 *orbital_bcd = + DESC_DVB_SATELLITE_DELIVERY_SYSTEM_orbital_position (delivery); + gfloat orbital = + (orbital_bcd[1] & 0x0F) / 10. + ((orbital_bcd[1] & 0xF0) >> 4) + + 10 * (orbital_bcd[0] & 0x0F) + 100 * ((orbital_bcd[0] & 0xF0) >> 4); + gboolean east = + DESC_DVB_SATELLITE_DELIVERY_SYSTEM_west_east_flag (delivery); + guint8 polarization = + DESC_DVB_SATELLITE_DELIVERY_SYSTEM_polarization (delivery); + const gchar *polarization_str; + guint8 modulation = + DESC_DVB_SATELLITE_DELIVERY_SYSTEM_modulation (delivery); + const gchar *modulation_str; + guint8 *symbol_rate_bcd = + DESC_DVB_SATELLITE_DELIVERY_SYSTEM_symbol_rate (delivery); + guint32 symbol_rate = + (symbol_rate_bcd[2] & 0x0F) + + 10 * ((symbol_rate_bcd[2] & 0xF0) >> 4) + + 100 * (symbol_rate_bcd[1] & 0x0F) + + 1000 * ((symbol_rate_bcd[1] & 0xF0) >> 4) + + 10000 * (symbol_rate_bcd[0] & 0x0F) + + 100000 * ((symbol_rate_bcd[0] & 0xF0) >> 4); + guint8 fec_inner = + DESC_DVB_SATELLITE_DELIVERY_SYSTEM_fec_inner (delivery); + const gchar *fec_inner_str; + + switch (polarization) { + case 0: + polarization_str = "horizontal"; + break; + case 1: + polarization_str = "vertical"; + break; + case 2: + polarization_str = "left"; + break; + case 3: + polarization_str = "right"; + break; + default: + polarization_str = ""; + } + switch (fec_inner) { + case 0: + fec_inner_str = "undefined"; + break; + case 1: + fec_inner_str = "1/2"; + break; + case 2: + fec_inner_str = "2/3"; + break; + case 3: + fec_inner_str = "3/4"; + break; + case 4: + fec_inner_str = "5/6"; + break; + case 5: + fec_inner_str = "7/8"; + break; + case 6: + fec_inner_str = "8/9"; + break; + case 0xF: + fec_inner_str = "none"; + break; + default: + fec_inner_str = "reserved"; + } + switch (modulation) { + case 0x00: + modulation_str = "undefined"; + break; + case 0x01: + modulation_str = "QAM16"; + break; + case 0x02: + modulation_str = "QAM32"; + break; + case 0x03: + modulation_str = "QAM64"; + break; + case 0x04: + modulation_str = "QAM128"; + break; + case 0x05: + modulation_str = "QAM256"; + break; + default: + modulation_str = "reserved"; + } + delivery_structure = gst_structure_new ("satellite", + "orbital", G_TYPE_FLOAT, orbital, + "east-or-west", G_TYPE_STRING, east ? "east" : "west", + "modulation", G_TYPE_STRING, modulation_str, + "frequency", G_TYPE_UINT, frequency, + "polarization", G_TYPE_STRING, polarization_str, + "symbol-rate", G_TYPE_UINT, symbol_rate, + "inner-fec", G_TYPE_STRING, fec_inner_str, NULL); + gst_structure_set (transport, "delivery", GST_TYPE_STRUCTURE, + delivery_structure, NULL); + } else if ((delivery = + gst_mpeg_descriptor_find (mpegdescriptor, + DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM))) { + + guint32 frequency = + DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_frequency (delivery) * 10; + guint8 bandwidth = + DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_bandwidth (delivery); + guint8 constellation = + DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_constellation (delivery); + guint8 hierarchy = + DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_hierarchy (delivery); + guint8 code_rate_hp = + DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_code_rate_hp (delivery); + guint8 code_rate_lp = + DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_code_rate_lp (delivery); + guint8 guard_interval = + DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_guard_interval (delivery); + guint8 transmission_mode = + DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_transmission_mode (delivery); + gboolean other_frequency = + DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_other_frequency (delivery); + const gchar *constellation_str, *code_rate_hp_str, *code_rate_lp_str, + *transmission_mode_str; + /* do the stuff */ + /* bandwidth is 8 if 0, 7 if 1, 6 if 2, reserved otherwise */ + if (bandwidth <= 2) + bandwidth = 8 - bandwidth; + else + bandwidth = 0; + switch (constellation) { + case 0: + constellation_str = "QPSK"; + break; + case 1: + constellation_str = "QAM16"; + break; + case 2: + constellation_str = "QAM64"; + break; + default: + constellation_str = "reserved"; + } + /* hierarchy is 4 if 3, 2 if 2, 1 if 1, 0 if 0, reserved if > 3 */ + if (hierarchy <= 3) { + if (hierarchy == 3) + hierarchy = 4; + } else { + hierarchy = 0; + } + + switch (code_rate_hp) { + case 0: + code_rate_hp_str = "1/2"; + break; + case 1: + code_rate_hp_str = "2/3"; + break; + case 2: + code_rate_hp_str = "3/4"; + break; + case 3: + code_rate_hp_str = "5/6"; + break; + case 4: + code_rate_hp_str = "7/8"; + break; + default: + code_rate_hp_str = "reserved"; + } + + switch (code_rate_lp) { + case 0: + code_rate_lp_str = "1/2"; + break; + case 1: + code_rate_lp_str = "2/3"; + break; + case 2: + code_rate_lp_str = "3/4"; + break; + case 3: + code_rate_lp_str = "5/6"; + break; + case 4: + code_rate_lp_str = "7/8"; + break; + default: + code_rate_lp_str = "reserved"; + } + /* guard is 32 if 0, 16 if 1, 8 if 2, 4 if 3 */ + switch (guard_interval) { + case 0: + guard_interval = 32; + break; + case 1: + guard_interval = 16; + break; + case 2: + guard_interval = 8; + break; + case 3: + guard_interval = 4; + break; + default: /* make it default to 32 */ + guard_interval = 32; + } + switch (transmission_mode) { + case 0: + transmission_mode_str = "2k"; + break; + case 1: + transmission_mode_str = "8k"; + break; + default: + transmission_mode_str = "reserved"; + } + delivery_structure = gst_structure_new ("terrestrial", + "frequency", G_TYPE_UINT, frequency, + "bandwidth", G_TYPE_UINT, bandwidth, + "constellation", G_TYPE_STRING, constellation_str, + "hierarchy", G_TYPE_UINT, hierarchy, + "code-rate-hp", G_TYPE_STRING, code_rate_hp_str, + "code-rate-lp", G_TYPE_STRING, code_rate_lp_str, + "guard-interval", G_TYPE_UINT, guard_interval, + "transmission-mode", G_TYPE_STRING, transmission_mode_str, + "other-frequency", G_TYPE_BOOLEAN, other_frequency, NULL); + gst_structure_set (transport, "delivery", GST_TYPE_STRUCTURE, + delivery_structure, NULL); + } else if ((delivery = + gst_mpeg_descriptor_find (mpegdescriptor, + DESC_DVB_CABLE_DELIVERY_SYSTEM))) { + + guint8 *frequency_bcd = + DESC_DVB_CABLE_DELIVERY_SYSTEM_frequency (delivery); + /* see en 300 468 section 6.2.13.1 least significant bcd digit + * is measured in 100Hz units so multiplier needs to be 100 to get + * into Hz */ + guint32 frequency = 100 * + ((frequency_bcd[3] & 0x0F) + + 10 * ((frequency_bcd[3] & 0xF0) >> 4) + + 100 * (frequency_bcd[2] & 0x0F) + + 1000 * ((frequency_bcd[2] & 0xF0) >> 4) + + 10000 * (frequency_bcd[1] & 0x0F) + + 100000 * ((frequency_bcd[1] & 0xF0) >> 4) + + 1000000 * (frequency_bcd[0] & 0x0F) + + 10000000 * ((frequency_bcd[0] & 0xF0) >> 4)); + guint8 modulation = + DESC_DVB_CABLE_DELIVERY_SYSTEM_modulation (delivery); + const gchar *modulation_str; + guint8 *symbol_rate_bcd = + DESC_DVB_CABLE_DELIVERY_SYSTEM_symbol_rate (delivery); + guint32 symbol_rate = + (symbol_rate_bcd[2] & 0x0F) + + 10 * ((symbol_rate_bcd[2] & 0xF0) >> 4) + + 100 * (symbol_rate_bcd[1] & 0x0F) + + 1000 * ((symbol_rate_bcd[1] & 0xF0) >> 4) + + 10000 * (symbol_rate_bcd[0] & 0x0F) + + 100000 * ((symbol_rate_bcd[0] & 0xF0) >> 4); + guint8 fec_inner = DESC_DVB_CABLE_DELIVERY_SYSTEM_fec_inner (delivery); + const gchar *fec_inner_str; + + switch (fec_inner) { + case 0: + fec_inner_str = "undefined"; + break; + case 1: + fec_inner_str = "1/2"; + break; + case 2: + fec_inner_str = "2/3"; + break; + case 3: + fec_inner_str = "3/4"; + break; + case 4: + fec_inner_str = "5/6"; + break; + case 5: + fec_inner_str = "7/8"; + break; + case 6: + fec_inner_str = "8/9"; + break; + case 0xF: + fec_inner_str = "none"; + break; + default: + fec_inner_str = "reserved"; + } + switch (modulation) { + case 0x00: + modulation_str = "undefined"; + break; + case 0x01: + modulation_str = "QAM16"; + break; + case 0x02: + modulation_str = "QAM32"; + break; + case 0x03: + modulation_str = "QAM64"; + break; + case 0x04: + modulation_str = "QAM128"; + break; + case 0x05: + modulation_str = "QAM256"; + break; + default: + modulation_str = "reserved"; + } + delivery_structure = gst_structure_new ("cable", + "modulation", G_TYPE_STRING, modulation_str, + "frequency", G_TYPE_UINT, frequency, + "symbol-rate", G_TYPE_UINT, symbol_rate, + "inner-fec", G_TYPE_STRING, fec_inner_str, NULL); + gst_structure_set (transport, "delivery", GST_TYPE_STRUCTURE, + delivery_structure, NULL); + } + /* free the temporary delivery structure */ + if (delivery_structure != NULL) { + gst_structure_free (delivery_structure); + delivery_structure = NULL; + } + if ((delivery = + gst_mpeg_descriptor_find (mpegdescriptor, + DESC_DTG_LOGICAL_CHANNEL))) { + guint8 *current_pos = delivery + 2; + GValue channel_numbers = { 0 }; + + g_value_init (&channel_numbers, GST_TYPE_LIST); + while (current_pos < delivery + DESC_LENGTH (delivery)) { + GstStructure *channel; + GValue channel_value = { 0 }; + guint16 service_id = GST_READ_UINT16_BE (current_pos); + guint16 logical_channel_number; + + current_pos += 2; + logical_channel_number = GST_READ_UINT16_BE (current_pos) & 0x03ff; + channel = + gst_structure_new ("channels", "service-id", G_TYPE_UINT, + service_id, "logical-channel-number", G_TYPE_UINT, + logical_channel_number, NULL); + g_value_init (&channel_value, GST_TYPE_STRUCTURE); + g_value_take_boxed (&channel_value, channel); + gst_value_list_append_value (&channel_numbers, &channel_value); + g_value_unset (&channel_value); + current_pos += 2; + } + gst_structure_set_value (transport, "channels", &channel_numbers); + g_value_unset (&channel_numbers); + } + if ((delivery = + gst_mpeg_descriptor_find (mpegdescriptor, + DESC_DVB_FREQUENCY_LIST))) { + guint8 *current_pos = delivery + 2; + GValue frequencies = { 0 }; + guint8 type; + + type = *current_pos & 0x03; + current_pos++; + + if (type) { + const gchar *fieldname = NULL; + g_value_init (&frequencies, GST_TYPE_LIST); + + while (current_pos < delivery + DESC_LENGTH (delivery) - 3) { + guint32 freq = 0; + guint8 *frequency_bcd = current_pos; + GValue frequency = { 0 }; + + switch (type) { + case 0x01: + /* satellite */ + freq = + 10 * ((frequency_bcd[3] & 0x0F) + + 10 * ((frequency_bcd[3] & 0xF0) >> 4) + + 100 * (frequency_bcd[2] & 0x0F) + + 1000 * ((frequency_bcd[2] & 0xF0) >> 4) + + 10000 * (frequency_bcd[1] & 0x0F) + + 100000 * ((frequency_bcd[1] & 0xF0) >> 4) + + 1000000 * (frequency_bcd[0] & 0x0F) + + 10000000 * ((frequency_bcd[0] & 0xF0) >> 4)); + break; + case 0x02: + /* cable */ + freq = 100 * + ((frequency_bcd[3] & 0x0F) + + 10 * ((frequency_bcd[3] & 0xF0) >> 4) + + 100 * (frequency_bcd[2] & 0x0F) + + 1000 * ((frequency_bcd[2] & 0xF0) >> 4) + + 10000 * (frequency_bcd[1] & 0x0F) + + 100000 * ((frequency_bcd[1] & 0xF0) >> 4) + + 1000000 * (frequency_bcd[0] & 0x0F) + + 10000000 * ((frequency_bcd[0] & 0xF0) >> 4)); + break; + case 0x03: + /* terrestrial */ + freq = GST_READ_UINT32_BE (current_pos) * 10; + break; + } + g_value_init (&frequency, G_TYPE_UINT); + g_value_set_uint (&frequency, freq); + gst_value_list_append_value (&frequencies, &frequency); + g_value_unset (&frequency); + current_pos += 4; + } + + switch (type) { + case 0x01: + fieldname = "frequency-list-satellite"; + break; + case 0x02: + fieldname = "frequency-list-cable"; + break; + case 0x03: + fieldname = "frequency-list-terrestrial"; + break; + } + + gst_structure_set_value (transport, fieldname, &frequencies); + g_value_unset (&frequencies); + } + } + gst_mpeg_descriptor_free (mpegdescriptor); + + descriptors = g_value_array_new (0); + if (!mpegts_packetizer_parse_descriptors (packetizer, + &data, data + descriptors_loop_length, descriptors)) { + gst_structure_free (transport); + g_value_array_free (descriptors); + goto error; + } + + gst_structure_id_set (transport, QUARK_DESCRIPTORS, G_TYPE_VALUE_ARRAY, + descriptors, NULL); + g_value_array_free (descriptors); + } + + g_value_init (&transport_value, GST_TYPE_STRUCTURE); + g_value_take_boxed (&transport_value, transport); + gst_value_list_append_value (&transports, &transport_value); + g_value_unset (&transport_value); + + transport_stream_loop_length -= data - entry_begin; + } + + if (data != end - 4) { + GST_WARNING ("PID %d invalid NIT parsed %d length %d", + section->pid, (gint) (data - GST_BUFFER_DATA (section->buffer)), + GST_BUFFER_SIZE (section->buffer)); + goto error; + } + + gst_structure_id_set_value (nit, QUARK_TRANSPORTS, &transports); + g_value_unset (&transports); + + GST_DEBUG ("NIT %" GST_PTR_FORMAT, nit); + + return nit; + +error: + if (nit) + gst_structure_free (nit); + + if (GST_VALUE_HOLDS_LIST (&transports)) + g_value_unset (&transports); + + return NULL; +} + +GstStructure * +mpegts_packetizer_parse_sdt (MpegTSPacketizer2 * packetizer, + MpegTSPacketizerSection * section) +{ + GstStructure *sdt = NULL, *service = NULL; + guint8 *data, *end, *entry_begin; + guint16 transport_stream_id, original_network_id, service_id; + guint tmp; + guint sdt_info_length; + gboolean EIT_schedule, EIT_present_following; + guint8 running_status; + gboolean scrambled; + guint descriptors_loop_length; + GValue services = { 0 }; + GValueArray *descriptors = NULL; + GValue service_value = { 0 }; + + GST_DEBUG ("SDT"); + /* fixed header + CRC == 16 */ + if (GST_BUFFER_SIZE (section->buffer) < 14) { + GST_WARNING ("PID %d invalid SDT size %d", + section->pid, section->section_length); + goto error; + } + + data = GST_BUFFER_DATA (section->buffer); + end = data + GST_BUFFER_SIZE (section->buffer); + + section->table_id = *data++; + section->section_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; + + if (data + section->section_length != end) { + GST_WARNING ("PID %d invalid SDT section length %d expected %d", + section->pid, section->section_length, (gint) (end - data)); + goto error; + } + + transport_stream_id = GST_READ_UINT16_BE (data); + data += 2; + + tmp = *data++; + section->version_number = (tmp >> 1) & 0x1F; + section->current_next_indicator = tmp & 0x01; + + /* skip section_number and last_section_number */ + data += 2; + + original_network_id = GST_READ_UINT16_BE (data); + data += 2; + + /* skip reserved byte */ + data += 1; + + sdt = gst_structure_id_new (QUARK_SDT, + QUARK_TRANSPORT_STREAM_ID, G_TYPE_UINT, transport_stream_id, + QUARK_VERSION_NUMBER, G_TYPE_UINT, section->version_number, + QUARK_CURRENT_NEXT_INDICATOR, G_TYPE_UINT, + section->current_next_indicator, QUARK_ORIGINAL_NETWORK_ID, G_TYPE_UINT, + original_network_id, QUARK_ACTUAL_TRANSPORT_STREAM, G_TYPE_BOOLEAN, + section->table_id == 0x42, NULL); + + sdt_info_length = section->section_length - 8; + g_value_init (&services, GST_TYPE_LIST); + /* read up to the CRC */ + while (sdt_info_length - 4 > 0) { + gchar *service_name; + + entry_begin = data; + + if (sdt_info_length < 9) { + /* each entry must be at least 5 bytes (+4 bytes for the CRC) */ + GST_WARNING ("PID %d invalid SDT entry size %d", + section->pid, sdt_info_length); + goto error; + } + + service_id = GST_READ_UINT16_BE (data); + data += 2; + + EIT_schedule = ((*data & 0x02) == 2); + EIT_present_following = (*data & 0x01) == 1; + + data += 1; + tmp = GST_READ_UINT16_BE (data); + + running_status = (*data >> 5) & 0x07; + scrambled = (*data >> 4) & 0x01; + descriptors_loop_length = tmp & 0x0FFF; + data += 2; + + /* TODO send tag event down relevant pad for channel name and provider */ + service_name = g_strdup_printf ("service-%d", service_id); + service = gst_structure_new (service_name, NULL); + g_free (service_name); + + if (descriptors_loop_length) { + guint8 *service_descriptor; + GstMPEGDescriptor *mpegdescriptor; + + if (data + descriptors_loop_length > end - 4) { + GST_WARNING ("PID %d invalid SDT entry %d descriptors loop length %d", + section->pid, service_id, descriptors_loop_length); + gst_structure_free (service); + goto error; + } + mpegdescriptor = + gst_mpeg_descriptor_parse (data, descriptors_loop_length); + service_descriptor = + gst_mpeg_descriptor_find (mpegdescriptor, DESC_DVB_SERVICE); + if (service_descriptor != NULL) { + gchar *servicename_tmp, *serviceprovider_name_tmp; + guint8 serviceprovider_name_length = + DESC_DVB_SERVICE_provider_name_length (service_descriptor); + gchar *serviceprovider_name = + (gchar *) DESC_DVB_SERVICE_provider_name_text (service_descriptor); + guint8 servicename_length = + DESC_DVB_SERVICE_name_length (service_descriptor); + gchar *servicename = + (gchar *) DESC_DVB_SERVICE_name_text (service_descriptor); + if (servicename_length + serviceprovider_name_length + 2 <= + DESC_LENGTH (service_descriptor)) { + const gchar *running_status_tmp; + switch (running_status) { + case 0: + running_status_tmp = "undefined"; + break; + case 1: + running_status_tmp = "not running"; + break; + case 2: + running_status_tmp = "starts in a few seconds"; + break; + case 3: + running_status_tmp = "pausing"; + break; + case 4: + running_status_tmp = "running"; + break; + default: + running_status_tmp = "reserved"; + } + servicename_tmp = + get_encoding_and_convert (servicename, servicename_length); + serviceprovider_name_tmp = + get_encoding_and_convert (serviceprovider_name, + serviceprovider_name_length); + + gst_structure_set (service, + "name", G_TYPE_STRING, servicename_tmp, + "provider-name", G_TYPE_STRING, serviceprovider_name_tmp, + "scrambled", G_TYPE_BOOLEAN, scrambled, + "running-status", G_TYPE_STRING, running_status_tmp, NULL); + + g_free (servicename_tmp); + g_free (serviceprovider_name_tmp); + } + } + gst_mpeg_descriptor_free (mpegdescriptor); + + descriptors = g_value_array_new (0); + if (!mpegts_packetizer_parse_descriptors (packetizer, + &data, data + descriptors_loop_length, descriptors)) { + gst_structure_free (service); + g_value_array_free (descriptors); + goto error; + } + + gst_structure_id_set (service, QUARK_DESCRIPTORS, G_TYPE_VALUE_ARRAY, + descriptors, NULL); + + g_value_array_free (descriptors); + } + + g_value_init (&service_value, GST_TYPE_STRUCTURE); + g_value_take_boxed (&service_value, service); + gst_value_list_append_value (&services, &service_value); + g_value_unset (&service_value); + + sdt_info_length -= data - entry_begin; + } + + if (data != end - 4) { + GST_WARNING ("PID %d invalid SDT parsed %d length %d", + section->pid, (gint) (data - GST_BUFFER_DATA (section->buffer)), + GST_BUFFER_SIZE (section->buffer)); + goto error; + } + + gst_structure_id_set_value (sdt, QUARK_SERVICES, &services); + g_value_unset (&services); + + return sdt; + +error: + if (sdt) + gst_structure_free (sdt); + + if (GST_VALUE_HOLDS_LIST (&services)) + g_value_unset (&services); + + return NULL; +} + +GstStructure * +mpegts_packetizer_parse_eit (MpegTSPacketizer2 * packetizer, + MpegTSPacketizerSection * section) +{ + GstStructure *eit = NULL, *event = NULL; + guint service_id, last_table_id, segment_last_section_number; + guint transport_stream_id, original_network_id; + gboolean free_ca_mode; + guint event_id, running_status; + guint64 start_and_duration; + guint16 mjd; + guint year, month, day, hour, minute, second; + guint duration; + guint8 *data, *end, *duration_ptr, *utc_ptr; + guint16 descriptors_loop_length; + GValue events = { 0 }; + GValue event_value = { 0 }; + GValueArray *descriptors = NULL; + gchar *event_name; + guint tmp; + + /* fixed header + CRC == 16 */ + if (GST_BUFFER_SIZE (section->buffer) < 18) { + GST_WARNING ("PID %d invalid EIT size %d", + section->pid, section->section_length); + goto error; + } + + data = GST_BUFFER_DATA (section->buffer); + end = data + GST_BUFFER_SIZE (section->buffer); + + section->table_id = *data++; + section->section_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; + + if (data + section->section_length != end) { + GST_WARNING ("PID %d invalid EIT section length %d expected %d", + section->pid, section->section_length, (gint) (end - data)); + goto error; + } + + service_id = GST_READ_UINT16_BE (data); + data += 2; + + tmp = *data++; + section->version_number = (tmp >> 1) & 0x1F; + section->current_next_indicator = tmp & 0x01; + + /* skip section_number and last_section_number */ + data += 2; + + transport_stream_id = GST_READ_UINT16_BE (data); + data += 2; + original_network_id = GST_READ_UINT16_BE (data); + data += 2; + segment_last_section_number = *data; + data += 1; + last_table_id = *data; + data += 1; + + eit = gst_structure_id_new (QUARK_EIT, + QUARK_VERSION_NUMBER, G_TYPE_UINT, section->version_number, + QUARK_CURRENT_NEXT_INDICATOR, G_TYPE_UINT, + section->current_next_indicator, QUARK_SERVICE_ID, G_TYPE_UINT, + service_id, QUARK_ACTUAL_TRANSPORT_STREAM, G_TYPE_BOOLEAN, + (section->table_id == 0x4E || (section->table_id >= 0x50 + && section->table_id <= 0x5F)), QUARK_PRESENT_FOLLOWING, + G_TYPE_BOOLEAN, (section->table_id == 0x4E + || section->table_id == 0x4F), QUARK_TRANSPORT_STREAM_ID, G_TYPE_UINT, + transport_stream_id, QUARK_ORIGINAL_NETWORK_ID, G_TYPE_UINT, + original_network_id, QUARK_SEGMENT_LAST_SECTION_NUMBER, G_TYPE_UINT, + segment_last_section_number, QUARK_LAST_TABLE_ID, G_TYPE_UINT, + last_table_id, NULL); + + g_value_init (&events, GST_TYPE_LIST); + while (data < end - 4) { + /* 12 is the minimum entry size + CRC */ + if (end - data < 12 + 4) { + GST_WARNING ("PID %d invalid EIT entry length %d", + section->pid, (gint) (end - 4 - data)); + gst_structure_free (eit); + goto error; + } + + event_id = GST_READ_UINT16_BE (data); + data += 2; + start_and_duration = GST_READ_UINT64_BE (data); + duration_ptr = data + 5; + utc_ptr = data + 2; + mjd = GST_READ_UINT16_BE (data); + if (mjd == G_MAXUINT16) { + year = 1900; + month = day = hour = minute = second = 0; + } else { + /* See EN 300 468 Annex C */ + year = (guint32) (((mjd - 15078.2) / 365.25)); + month = (guint8) ((mjd - 14956.1 - (guint) (year * 365.25)) / 30.6001); + day = mjd - 14956 - (guint) (year * 365.25) - (guint) (month * 30.6001); + if (month == 14 || month == 15) { + year++; + month = month - 1 - 12; + } else { + month--; + } + year += 1900; + hour = ((utc_ptr[0] & 0xF0) >> 4) * 10 + (utc_ptr[0] & 0x0F); + minute = ((utc_ptr[1] & 0xF0) >> 4) * 10 + (utc_ptr[1] & 0x0F); + second = ((utc_ptr[2] & 0xF0) >> 4) * 10 + (utc_ptr[2] & 0x0F); + } + + duration = (((duration_ptr[0] & 0xF0) >> 4) * 10 + + (duration_ptr[0] & 0x0F)) * 60 * 60 + + (((duration_ptr[1] & 0xF0) >> 4) * 10 + + (duration_ptr[1] & 0x0F)) * 60 + + ((duration_ptr[2] & 0xF0) >> 4) * 10 + (duration_ptr[2] & 0x0F); + + data += 8; + running_status = *data >> 5; + free_ca_mode = (*data >> 4) & 0x01; + descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; + + /* TODO: send tag event down relevant pad saying what is currently playing */ + event_name = g_strdup_printf ("event-%d", event_id); + event = gst_structure_new (event_name, + "event-id", G_TYPE_UINT, event_id, + "year", G_TYPE_UINT, year, + "month", G_TYPE_UINT, month, + "day", G_TYPE_UINT, day, + "hour", G_TYPE_UINT, hour, + "minute", G_TYPE_UINT, minute, + "second", G_TYPE_UINT, second, + "duration", G_TYPE_UINT, duration, + "running-status", G_TYPE_UINT, running_status, + "free-ca-mode", G_TYPE_BOOLEAN, free_ca_mode, NULL); + g_free (event_name); + + if (descriptors_loop_length) { + guint8 *event_descriptor; + GArray *component_descriptors; + GArray *extended_event_descriptors; + GstMPEGDescriptor *mpegdescriptor; + + if (data + descriptors_loop_length > end - 4) { + GST_WARNING ("PID %d invalid EIT descriptors loop length %d", + section->pid, descriptors_loop_length); + gst_structure_free (event); + goto error; + } + mpegdescriptor = + gst_mpeg_descriptor_parse (data, descriptors_loop_length); + event_descriptor = + gst_mpeg_descriptor_find (mpegdescriptor, DESC_DVB_SHORT_EVENT); + if (event_descriptor != NULL) { + gchar *eventname_tmp, *eventdescription_tmp; + guint8 eventname_length = + DESC_DVB_SHORT_EVENT_name_length (event_descriptor); + gchar *eventname = + (gchar *) DESC_DVB_SHORT_EVENT_name_text (event_descriptor); + guint8 eventdescription_length = + DESC_DVB_SHORT_EVENT_description_length (event_descriptor); + gchar *eventdescription = + (gchar *) DESC_DVB_SHORT_EVENT_description_text (event_descriptor); + if (eventname_length + eventdescription_length + 2 <= + DESC_LENGTH (event_descriptor)) { + + eventname_tmp = + get_encoding_and_convert (eventname, eventname_length), + eventdescription_tmp = + get_encoding_and_convert (eventdescription, + eventdescription_length); + + gst_structure_set (event, "name", G_TYPE_STRING, eventname_tmp, NULL); + gst_structure_set (event, "description", G_TYPE_STRING, + eventdescription_tmp, NULL); + g_free (eventname_tmp); + g_free (eventdescription_tmp); + } + } + extended_event_descriptors = gst_mpeg_descriptor_find_all (mpegdescriptor, + DESC_DVB_EXTENDED_EVENT); + if (extended_event_descriptors) { + int i; + guint8 *extended_descriptor; + /*GValue extended_items = { 0 }; */ + gchar *extended_text = NULL; + /*g_value_init (&extended_items, GST_TYPE_LIST); */ + for (i = 0; i < extended_event_descriptors->len; i++) { + extended_descriptor = g_array_index (extended_event_descriptors, + guint8 *, i); + if (DESC_DVB_EXTENDED_EVENT_descriptor_number (extended_descriptor) == + i) { + if (extended_text) { + gchar *tmp; + gchar *old_extended_text = extended_text; + tmp = get_encoding_and_convert ((gchar *) + DESC_DVB_EXTENDED_EVENT_text (extended_descriptor), + DESC_DVB_EXTENDED_EVENT_text_length (extended_descriptor)); + extended_text = g_strdup_printf ("%s%s", extended_text, tmp); + g_free (old_extended_text); + g_free (tmp); + } else { + extended_text = get_encoding_and_convert ((gchar *) + DESC_DVB_EXTENDED_EVENT_text (extended_descriptor), + DESC_DVB_EXTENDED_EVENT_text_length (extended_descriptor)); + } + } + } + if (extended_text) { + gst_structure_set (event, "extended-text", G_TYPE_STRING, + extended_text, NULL); + g_free (extended_text); + } + g_array_free (extended_event_descriptors, TRUE); + } + + component_descriptors = gst_mpeg_descriptor_find_all (mpegdescriptor, + DESC_DVB_COMPONENT); + if (component_descriptors) { + int i; + guint8 *comp_descriptor; + GValue components = { 0 }; + g_value_init (&components, GST_TYPE_LIST); + /* FIXME: do the component descriptor parsing less verbosely + * and better...a task for 0.10.6 */ + for (i = 0; i < component_descriptors->len; i++) { + GstStructure *component = NULL; + GValue component_value = { 0 }; + gint widescreen = 0; /* 0 for 4:3, 1 for 16:9, 2 for > 16:9 */ + gint freq = 25; /* 25 or 30 measured in Hertz */ + gboolean highdef = FALSE; + gboolean panvectors = FALSE; + const gchar *comptype = ""; + + comp_descriptor = g_array_index (component_descriptors, guint8 *, i); + switch (DESC_DVB_COMPONENT_stream_content (comp_descriptor)) { + case 0x01: + /* video */ + switch (DESC_DVB_COMPONENT_type (comp_descriptor)) { + case 0x01: + widescreen = 0; + freq = 25; + break; + case 0x02: + widescreen = 1; + panvectors = TRUE; + freq = 25; + break; + case 0x03: + widescreen = 1; + panvectors = FALSE; + freq = 25; + break; + case 0x04: + widescreen = 2; + freq = 25; + break; + case 0x05: + widescreen = 0; + freq = 30; + break; + case 0x06: + widescreen = 1; + panvectors = TRUE; + freq = 30; + break; + case 0x07: + widescreen = 1; + panvectors = FALSE; + freq = 30; + break; + case 0x08: + widescreen = 2; + freq = 30; + break; + case 0x09: + widescreen = 0; + highdef = TRUE; + freq = 25; + break; + case 0x0A: + widescreen = 1; + highdef = TRUE; + panvectors = TRUE; + freq = 25; + break; + case 0x0B: + widescreen = 1; + highdef = TRUE; + panvectors = FALSE; + freq = 25; + break; + case 0x0C: + widescreen = 2; + highdef = TRUE; + freq = 25; + break; + case 0x0D: + widescreen = 0; + highdef = TRUE; + freq = 30; + break; + case 0x0E: + widescreen = 1; + highdef = TRUE; + panvectors = TRUE; + freq = 30; + break; + case 0x0F: + widescreen = 1; + highdef = TRUE; + panvectors = FALSE; + freq = 30; + break; + case 0x10: + widescreen = 2; + highdef = TRUE; + freq = 30; + break; + } + component = gst_structure_new ("video", "high-definition", + G_TYPE_BOOLEAN, TRUE, "frequency", G_TYPE_INT, freq, + "tag", G_TYPE_INT, DESC_DVB_COMPONENT_tag (comp_descriptor), + NULL); + if (widescreen == 0) { + gst_structure_set (component, "aspect-ratio", + G_TYPE_STRING, "4:3", NULL); + } else if (widescreen == 2) { + gst_structure_set (component, "aspect-ratio", G_TYPE_STRING, + "> 16:9", NULL); + } else { + gst_structure_set (component, "aspect-ratio", G_TYPE_STRING, + "16:9", "pan-vectors", G_TYPE_BOOLEAN, panvectors, NULL); + } + break; + case 0x02: /* audio */ + comptype = "undefined"; + switch (DESC_DVB_COMPONENT_type (comp_descriptor)) { + case 0x01: + comptype = "single channel mono"; + break; + case 0x02: + comptype = "dual channel mono"; + break; + case 0x03: + comptype = "stereo"; + break; + case 0x04: + comptype = "multi-channel multi-lingual"; + break; + case 0x05: + comptype = "surround"; + break; + case 0x40: + comptype = "audio description for the visually impaired"; + break; + case 0x41: + comptype = "audio for the hard of hearing"; + break; + } + component = gst_structure_new ("audio", "type", G_TYPE_STRING, + comptype, "tag", G_TYPE_INT, + DESC_DVB_COMPONENT_tag (comp_descriptor), NULL); + break; + case 0x03: /* subtitles/teletext/vbi */ + comptype = "reserved"; + switch (DESC_DVB_COMPONENT_type (comp_descriptor)) { + case 0x01: + comptype = "EBU Teletext subtitles"; + break; + case 0x02: + comptype = "associated EBU Teletext"; + break; + case 0x03: + comptype = "VBI data"; + break; + case 0x10: + comptype = "Normal DVB subtitles"; + break; + case 0x11: + comptype = "Normal DVB subtitles for 4:3"; + break; + case 0x12: + comptype = "Normal DVB subtitles for 16:9"; + break; + case 0x13: + comptype = "Normal DVB subtitles for 2.21:1"; + break; + case 0x20: + comptype = "Hard of hearing DVB subtitles"; + break; + case 0x21: + comptype = "Hard of hearing DVB subtitles for 4:3"; + break; + case 0x22: + comptype = "Hard of hearing DVB subtitles for 16:9"; + break; + case 0x23: + comptype = "Hard of hearing DVB subtitles for 2.21:1"; + break; + } + component = gst_structure_new ("teletext", "type", G_TYPE_STRING, + comptype, "tag", G_TYPE_INT, + DESC_DVB_COMPONENT_tag (comp_descriptor), NULL); + break; + } + if (component) { + g_value_init (&component_value, GST_TYPE_STRUCTURE); + g_value_take_boxed (&component_value, component); + gst_value_list_append_value (&components, &component_value); + g_value_unset (&component_value); + component = NULL; + } + } + gst_structure_set_value (event, "components", &components); + g_value_unset (&components); + g_array_free (component_descriptors, TRUE); + } + gst_mpeg_descriptor_free (mpegdescriptor); + + descriptors = g_value_array_new (0); + if (!mpegts_packetizer_parse_descriptors (packetizer, + &data, data + descriptors_loop_length, descriptors)) { + gst_structure_free (event); + g_value_array_free (descriptors); + goto error; + } + gst_structure_id_set (event, QUARK_DESCRIPTORS, G_TYPE_VALUE_ARRAY, + descriptors, NULL); + g_value_array_free (descriptors); + } + + g_value_init (&event_value, GST_TYPE_STRUCTURE); + g_value_take_boxed (&event_value, event); + gst_value_list_append_value (&events, &event_value); + g_value_unset (&event_value); + } + + if (data != end - 4) { + GST_WARNING ("PID %d invalid EIT parsed %d length %d", + section->pid, (gint) (data - GST_BUFFER_DATA (section->buffer)), + GST_BUFFER_SIZE (section->buffer)); + goto error; + } + + gst_structure_id_set_value (eit, QUARK_EVENTS, &events); + g_value_unset (&events); + + GST_DEBUG ("EIT %" GST_PTR_FORMAT, eit); + + return eit; + +error: + if (eit) + gst_structure_free (eit); + + if (GST_VALUE_HOLDS_LIST (&events)) + g_value_unset (&events); + + return NULL; +} + +GstStructure * +mpegts_packetizer_parse_tdt (MpegTSPacketizer2 * packetizer, + MpegTSPacketizerSection * section) +{ + GstStructure *tdt = NULL; + guint16 mjd; + guint year, month, day, hour, minute, second; + guint8 *data, *end, *utc_ptr; + + GST_DEBUG ("TDT"); + /* length always 8 */ + if (G_UNLIKELY (GST_BUFFER_SIZE (section->buffer) != 8)) { + GST_WARNING ("PID %d invalid TDT size %d", + section->pid, section->section_length); + goto error; + } + + data = GST_BUFFER_DATA (section->buffer); + end = data + GST_BUFFER_SIZE (section->buffer); + + section->table_id = *data++; + section->section_length = GST_READ_UINT16_BE (data) & 0x0FFF; + data += 2; + + if (data + section->section_length != end) { + GST_WARNING ("PID %d invalid TDT section length %d expected %d", + section->pid, section->section_length, (gint) (end - data)); + goto error; + } + + mjd = GST_READ_UINT16_BE (data); + data += 2; + utc_ptr = data; + if (mjd == G_MAXUINT16) { + year = 1900; + month = day = hour = minute = second = 0; + } else { + /* See EN 300 468 Annex C */ + year = (guint32) (((mjd - 15078.2) / 365.25)); + month = (guint8) ((mjd - 14956.1 - (guint) (year * 365.25)) / 30.6001); + day = mjd - 14956 - (guint) (year * 365.25) - (guint) (month * 30.6001); + if (month == 14 || month == 15) { + year++; + month = month - 1 - 12; + } else { + month--; + } + year += 1900; + hour = ((utc_ptr[0] & 0xF0) >> 4) * 10 + (utc_ptr[0] & 0x0F); + minute = ((utc_ptr[1] & 0xF0) >> 4) * 10 + (utc_ptr[1] & 0x0F); + second = ((utc_ptr[2] & 0xF0) >> 4) * 10 + (utc_ptr[2] & 0x0F); + } + tdt = gst_structure_new ("tdt", + "year", G_TYPE_UINT, year, + "month", G_TYPE_UINT, month, + "day", G_TYPE_UINT, day, + "hour", G_TYPE_UINT, hour, + "minute", G_TYPE_UINT, minute, "second", G_TYPE_UINT, second, NULL); + + return tdt; + +error: + if (tdt) + gst_structure_free (tdt); + + return NULL; +} + +void +mpegts_packetizer_clear (MpegTSPacketizer2 * packetizer) +{ + if (packetizer->know_packet_size) { + packetizer->know_packet_size = FALSE; + packetizer->packet_size = 0; + if (packetizer->caps != NULL) { + gst_caps_unref (packetizer->caps); + packetizer->caps = NULL; + } + } + if (packetizer->streams) { + int i; + for (i = 0; i < 8192; i++) { + if (packetizer->streams[i]) { + mpegts_packetizer_stream_free (packetizer->streams[i]); + } + } + memset (packetizer->streams, 0, 8192 * sizeof (MpegTSPacketizerStream *)); + } + + gst_adapter_clear (packetizer->adapter); + packetizer->offset = 0; + packetizer->empty = TRUE; +} + +void +mpegts_packetizer_remove_stream (MpegTSPacketizer2 * packetizer, gint16 pid) +{ + MpegTSPacketizerStream *stream = packetizer->streams[pid]; + if (stream) { + GST_INFO ("Removing stream for PID %d", pid); + mpegts_packetizer_stream_free (stream); + packetizer->streams[pid] = NULL; + } +} + +MpegTSPacketizer2 * +mpegts_packetizer_new (void) +{ + MpegTSPacketizer2 *packetizer; + + packetizer = + GST_MPEGTS_PACKETIZER (g_object_new (GST_TYPE_MPEGTS_PACKETIZER, NULL)); + + return packetizer; +} + +void +mpegts_packetizer_push (MpegTSPacketizer2 * packetizer, GstBuffer * buffer) +{ + if (G_UNLIKELY (packetizer->empty)) { + packetizer->empty = FALSE; + packetizer->offset = GST_BUFFER_OFFSET (buffer); + } + + GST_DEBUG ("Pushing %u byte from offset %" G_GUINT64_FORMAT, + GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer)); + gst_adapter_push (packetizer->adapter, buffer); +} + +static gboolean +mpegts_try_discover_packet_size (MpegTSPacketizer2 * packetizer) +{ + guint8 *dest; + int i, pos = -1, j; + static const guint psizes[] = { + MPEGTS_NORMAL_PACKETSIZE, + MPEGTS_M2TS_PACKETSIZE, + MPEGTS_DVB_ASI_PACKETSIZE, + MPEGTS_ATSC_PACKETSIZE + }; + + + dest = g_malloc (MPEGTS_MAX_PACKETSIZE * 4); + /* wait for 3 sync bytes */ + while (packetizer->adapter->size >= MPEGTS_MAX_PACKETSIZE * 4) { + + /* check for sync bytes */ + gst_adapter_copy (packetizer->adapter, dest, 0, MPEGTS_MAX_PACKETSIZE * 4); + /* find first sync byte */ + pos = -1; + for (i = 0; i < MPEGTS_MAX_PACKETSIZE; i++) { + if (dest[i] == 0x47) { + for (j = 0; j < 4; j++) { + guint packetsize = psizes[j]; + /* check each of the packet size possibilities in turn */ + if (dest[i] == 0x47 && dest[i + packetsize] == 0x47 && + dest[i + packetsize * 2] == 0x47 && + dest[i + packetsize * 3] == 0x47) { + packetizer->know_packet_size = TRUE; + packetizer->packet_size = packetsize; + packetizer->caps = gst_caps_new_simple ("video/mpegts", + "systemstream", G_TYPE_BOOLEAN, TRUE, + "packetsize", G_TYPE_INT, packetsize, NULL); + if (packetsize == MPEGTS_M2TS_PACKETSIZE) + pos = i - 4; + else + pos = i; + break; + } + } + break; + } + } + + if (packetizer->know_packet_size) + break; + + /* Skip MPEGTS_MAX_PACKETSIZE */ + gst_adapter_flush (packetizer->adapter, MPEGTS_MAX_PACKETSIZE); + packetizer->offset += MPEGTS_MAX_PACKETSIZE; + } + + g_free (dest); + + if (packetizer->know_packet_size) { + GST_DEBUG ("have packetsize detected: %d of %u bytes", + packetizer->know_packet_size, packetizer->packet_size); + /* flush to sync byte */ + if (pos > 0) { + GST_DEBUG ("Flushing out %d bytes", pos); + gst_adapter_flush (packetizer->adapter, pos); + packetizer->offset += pos; + } else if (!packetizer->know_packet_size) { + /* drop invalid data and move to the next possible packets */ + gst_adapter_flush (packetizer->adapter, MPEGTS_MAX_PACKETSIZE); + } + } + + return packetizer->know_packet_size; +} + +gboolean +mpegts_packetizer_has_packets (MpegTSPacketizer2 * packetizer) +{ + if (G_UNLIKELY (packetizer->know_packet_size == FALSE)) { + if (!mpegts_try_discover_packet_size (packetizer)) + return FALSE; + } + return packetizer->adapter->size >= packetizer->packet_size; +} + +MpegTSPacketizerPacketReturn +mpegts_packetizer_next_packet (MpegTSPacketizer2 * packetizer, + MpegTSPacketizerPacket * packet) +{ + guint avail; + + packet->buffer = NULL; + + if (G_UNLIKELY (!packetizer->know_packet_size)) { + if (!mpegts_try_discover_packet_size (packetizer)) + return PACKET_NEED_MORE; + } + + while ((avail = packetizer->adapter->size) >= packetizer->packet_size) { + packet->buffer = gst_adapter_take_buffer (packetizer->adapter, + packetizer->packet_size); + /* M2TS packets don't start with the sync byte, all other variants do */ + if (packetizer->packet_size == MPEGTS_M2TS_PACKETSIZE) { + packet->data_start = GST_BUFFER_DATA (packet->buffer) + 4; + } else { + packet->data_start = GST_BUFFER_DATA (packet->buffer); + } + /* ALL mpeg-ts variants contain 188 bytes of data. Those with bigger packet + * sizes contain either extra data (timesync, FEC, ..) either before or after + * the data */ + packet->data_end = packet->data_start + 188; + GST_BUFFER_OFFSET (packet->buffer) = packet->offset = packetizer->offset; + GST_DEBUG ("offset %" G_GUINT64_FORMAT, packet->offset); + packetizer->offset += packetizer->packet_size; + GST_MEMDUMP ("buffer", GST_BUFFER_DATA (packet->buffer), 16); + GST_MEMDUMP ("data_start", packet->data_start, 16); + + /* Check sync byte */ + if (G_UNLIKELY (packet->data_start[0] != 0x47)) { + guint i; + GstBuffer *tmpbuf; + + GST_LOG ("Lost sync %d", packetizer->packet_size); + /* Find the 0x47 in the buffer */ + for (i = 0; i < packetizer->packet_size; i++) + if (GST_BUFFER_DATA (packet->buffer)[i] == 0x47) + break; + if (G_UNLIKELY (i == packetizer->packet_size)) { + GST_ERROR ("REALLY lost the sync"); + gst_buffer_unref (packet->buffer); + goto done; + } + /* Pop out the remaining data... */ + GST_BUFFER_DATA (packet->buffer) += i; + GST_BUFFER_SIZE (packet->buffer) -= i; + GST_BUFFER_OFFSET (packet->buffer) += i; + tmpbuf = + gst_adapter_take_buffer (packetizer->adapter, + packetizer->adapter->size); + /* ... and push everything back in */ + gst_adapter_push (packetizer->adapter, packet->buffer); + gst_adapter_push (packetizer->adapter, tmpbuf); + continue; + } + + return mpegts_packetizer_parse_packet (packetizer, packet); + } + +done: + return PACKET_NEED_MORE; +} + +void +mpegts_packetizer_clear_packet (MpegTSPacketizer2 * packetizer, + MpegTSPacketizerPacket * packet) +{ + memset (packet, 0, sizeof (MpegTSPacketizerPacket)); +} + +gboolean +mpegts_packetizer_push_section (MpegTSPacketizer2 * packetizer, + MpegTSPacketizerPacket * packet, MpegTSPacketizerSection * section) +{ + gboolean res = FALSE; + MpegTSPacketizerStream *stream; + guint8 pointer, table_id; + guint16 subtable_extension; + guint section_length; + GstBuffer *sub_buf; + guint8 *data; + + data = packet->data; + section->pid = packet->pid; + + if (packet->payload_unit_start_indicator == 1) { + pointer = *data++; + if (data + pointer > packet->data_end) { + GST_WARNING ("PID %d PSI section pointer points past the end " + "of the buffer", packet->pid); + goto out; + } + + data += pointer; + } + /* TDT and TOT sections (see ETSI EN 300 468 5.2.5) + * these sections do not extend to several packets so we don't need to use the + * sections filter. */ + if (packet->pid == 0x14) { + table_id = data[0]; + section->section_length = GST_READ_UINT24_BE (data) & 0x000FFF; + section->buffer = gst_buffer_create_sub (packet->buffer, + data - GST_BUFFER_DATA (packet->buffer), section->section_length + 3); + section->table_id = table_id; + section->complete = TRUE; + res = TRUE; + GST_DEBUG ("TDT section pid:%d table_id:%d section_length: %d\n", + packet->pid, table_id, section->section_length); + goto out; + } + + /* create a sub buffer from the start of the section (table_id and + * section_length included) to the end */ + sub_buf = gst_buffer_create_sub (packet->buffer, + data - GST_BUFFER_DATA (packet->buffer), packet->data_end - data); + + + stream = packetizer->streams[packet->pid]; + if (stream == NULL) { + stream = mpegts_packetizer_stream_new (); + packetizer->streams[packet->pid] = stream; + } + + if (packet->payload_unit_start_indicator) { + table_id = *data++; + /* subtable_extension should be read from 4th and 5th bytes only if + * section_syntax_indicator is 1 */ + if ((data[0] & 0x80) == 0) + subtable_extension = 0; + else + subtable_extension = GST_READ_UINT16_BE (data + 2); + GST_DEBUG ("pid: %d table_id %d sub_table_extension %d", + packet->pid, table_id, subtable_extension); + + section_length = GST_READ_UINT16_BE (data) & 0x0FFF; + + if (stream->continuity_counter != CONTINUITY_UNSET) { + GST_DEBUG + ("PID %d table_id %d sub_table_extension %d payload_unit_start_indicator set but section " + "not complete (last_continuity: %d continuity: %d sec len %d buffer %d avail %d", + packet->pid, table_id, subtable_extension, stream->continuity_counter, + packet->continuity_counter, section_length, GST_BUFFER_SIZE (sub_buf), + stream->section_adapter->size); + mpegts_packetizer_clear_section (packetizer, stream); + } else { + GST_DEBUG + ("pusi set and new stream section is %d long and data we have is: %d", + section_length, (gint) (packet->data_end - packet->data)); + } + stream->continuity_counter = packet->continuity_counter; + stream->section_length = section_length; + stream->section_table_id = table_id; + stream->offset = packet->offset; + gst_adapter_push (stream->section_adapter, sub_buf); + + res = TRUE; + } else if (stream->continuity_counter != CONTINUITY_UNSET && + (packet->continuity_counter == stream->continuity_counter + 1 || + (stream->continuity_counter == MAX_CONTINUITY && + packet->continuity_counter == 0))) { + stream->continuity_counter = packet->continuity_counter; + gst_adapter_push (stream->section_adapter, sub_buf); + + res = TRUE; + } else { + if (stream->continuity_counter == CONTINUITY_UNSET) + GST_DEBUG ("PID %d waiting for pusi", packet->pid); + else + GST_DEBUG ("PID %d section discontinuity " + "(last_continuity: %d continuity: %d", packet->pid, + stream->continuity_counter, packet->continuity_counter); + mpegts_packetizer_clear_section (packetizer, stream); + gst_buffer_unref (sub_buf); + } + + if (res) { + /* we pushed some data in the section adapter, see if the section is + * complete now */ + + /* >= as sections can be padded and padding is not included in + * section_length */ + if (stream->section_adapter->size >= stream->section_length + 3) { + res = mpegts_packetizer_parse_section_header (packetizer, + stream, section); + + /* flush stuffing bytes */ + mpegts_packetizer_clear_section (packetizer, stream); + } else { + GST_DEBUG ("section not complete"); + /* section not complete yet */ + section->complete = FALSE; + } + } else { + GST_WARNING ("section not complete"); + section->complete = FALSE; + } + +out: + packet->data = data; + GST_DEBUG ("result: %d complete: %d", res, section->complete); + return res; +} + +static void +_init_local (void) +{ + GST_DEBUG_CATEGORY_INIT (mpegts_packetizer_debug, "mpegtspacketizer", 0, + "MPEG transport stream parser"); + + QUARK_PAT = g_quark_from_string ("pat"); + QUARK_TRANSPORT_STREAM_ID = g_quark_from_string ("transport-stream-id"); + QUARK_PROGRAM_NUMBER = g_quark_from_string ("program-number"); + QUARK_PID = g_quark_from_string ("pid"); + QUARK_PROGRAMS = g_quark_from_string ("programs"); + + QUARK_PMT = g_quark_from_string ("pmt"); + QUARK_PCR_PID = g_quark_from_string ("pcr-pid"); + QUARK_VERSION_NUMBER = g_quark_from_string ("version-number"); + QUARK_DESCRIPTORS = g_quark_from_string ("descriptors"); + QUARK_STREAM_TYPE = g_quark_from_string ("stream-type"); + QUARK_STREAMS = g_quark_from_string ("streams"); + + QUARK_NIT = g_quark_from_string ("nit"); + QUARK_NETWORK_ID = g_quark_from_string ("network-id"); + QUARK_CURRENT_NEXT_INDICATOR = g_quark_from_string ("current-next-indicator"); + QUARK_ACTUAL_NETWORK = g_quark_from_string ("actual-network"); + QUARK_NETWORK_NAME = g_quark_from_string ("network-name"); + QUARK_ORIGINAL_NETWORK_ID = g_quark_from_string ("original-network-id"); + QUARK_TRANSPORTS = g_quark_from_string ("transports"); + + QUARK_SDT = g_quark_from_string ("sdt"); + QUARK_ACTUAL_TRANSPORT_STREAM = + g_quark_from_string ("actual-transport-stream"); + QUARK_SERVICES = g_quark_from_string ("services"); + + QUARK_EIT = g_quark_from_string ("eit"); + QUARK_SERVICE_ID = g_quark_from_string ("service-id"); + QUARK_PRESENT_FOLLOWING = g_quark_from_string ("present-following"); + QUARK_SEGMENT_LAST_SECTION_NUMBER = + g_quark_from_string ("segment-last-section-number"); + QUARK_LAST_TABLE_ID = g_quark_from_string ("last-table-id"); + QUARK_EVENTS = g_quark_from_string ("events"); +} + +/** + * @text: The text you want to get the encoding from + * @start_text: Location where the beginning of the actual text is stored + * @is_multibyte: Location where information whether it's a multibyte encoding + * or not is stored + * @returns: Name of encoding or NULL of encoding could not be detected. + * + * The returned string should be freed with g_free () when no longer needed. + */ +static gchar * +get_encoding (const gchar * text, guint * start_text, gboolean * is_multibyte) +{ + gchar *encoding; + guint8 firstbyte; + + g_return_val_if_fail (text != NULL, NULL); + + firstbyte = (guint8) text[0]; + + if (firstbyte == 0x01) { + encoding = g_strdup ("iso8859-5"); + *start_text = 1; + *is_multibyte = FALSE; + } else if (firstbyte == 0x02) { + encoding = g_strdup ("iso8859-6"); + *start_text = 1; + *is_multibyte = FALSE; + } else if (firstbyte == 0x03) { + encoding = g_strdup ("iso8859-7"); + *start_text = 1; + *is_multibyte = FALSE; + } else if (firstbyte == 0x04) { + encoding = g_strdup ("iso8859-8"); + *start_text = 1; + *is_multibyte = FALSE; + } else if (firstbyte == 0x05) { + encoding = g_strdup ("iso8859-9"); + *start_text = 1; + *is_multibyte = FALSE; + } else if (firstbyte >= 0x20) { + encoding = g_strdup ("iso6937"); + *start_text = 0; + *is_multibyte = FALSE; + } else if (firstbyte == 0x10) { + guint16 table; + gchar table_str[6]; + + text++; + table = GST_READ_UINT16_BE (text); + g_snprintf (table_str, 6, "%d", table); + + encoding = g_strconcat ("iso8859-", table_str, NULL); + *start_text = 3; + *is_multibyte = FALSE; + } else if (firstbyte == 0x11) { + encoding = g_strdup ("ISO-10646/UCS2"); + *start_text = 1; + *is_multibyte = TRUE; + } else if (firstbyte == 0x12) { + // That's korean encoding. + // The spec says it's encoded in KSC 5601, but iconv only knows KSC 5636. + // Couldn't find any information about either of them. + encoding = NULL; + *start_text = 1; + *is_multibyte = TRUE; + } else { + // reserved + encoding = NULL; + *start_text = 0; + *is_multibyte = FALSE; + } + + GST_DEBUG + ("Found encoding %s, first byte is 0x%02x, start_text: %u, is_multibyte: %d", + encoding, firstbyte, *start_text, *is_multibyte); + + return encoding; +} + +/** + * @text: The text to convert. It may include pango markup (<b> and </b>) + * @length: The length of the string -1 if it's nul-terminated + * @start: Where to start converting in the text + * @encoding: The encoding of text + * @is_multibyte: Whether the encoding is a multibyte encoding + * @error: The location to store the error, or NULL to ignore errors + * @returns: UTF-8 encoded string + * + * Convert text to UTF-8. + */ +static gchar * +convert_to_utf8 (const gchar * text, gint length, guint start, + const gchar * encoding, gboolean is_multibyte, GError ** error) +{ + gchar *new_text; + GByteArray *sb; + gint i; + + g_return_val_if_fail (text != NULL, NULL); + g_return_val_if_fail (encoding != NULL, NULL); + + text += start; + + sb = g_byte_array_sized_new (length * 1.1); + + if (is_multibyte) { + if (length == -1) { + while (*text != '\0') { + guint16 code = GST_READ_UINT16_BE (text); + + switch (code) { + case 0xE086: /* emphasis on */ + case 0xE087: /* emphasis off */ + /* skip it */ + break; + case 0xE08A:{ + guint8 nl[] = { 0x0A, 0x00 }; // new line + g_byte_array_append (sb, nl, 2); + break; + } + default: + g_byte_array_append (sb, (guint8 *) text, 2); + break; + } + + text += 2; + } + } else { + for (i = 0; i < length; i += 2) { + guint16 code = GST_READ_UINT16_BE (text); + + switch (code) { + case 0xE086: /* emphasis on */ + case 0xE087: /* emphasis off */ + /* skip it */ + break; + case 0xE08A:{ + guint8 nl[] = { 0x0A, 0x00 }; // new line + g_byte_array_append (sb, nl, 2); + break; + } + default: + g_byte_array_append (sb, (guint8 *) text, 2); + break; + } + + text += 2; + } + } + } else { + if (length == -1) { + while (*text != '\0') { + guint8 code = (guint8) (*text); + + switch (code) { + case 0x86: /* emphasis on */ + case 0x87: /* emphasis off */ + /* skip it */ + break; + case 0x8A: + g_byte_array_append (sb, (guint8 *) "\n", 1); + break; + default: + g_byte_array_append (sb, &code, 1); + break; + } + + text++; + } + } else { + for (i = 0; i < length; i++) { + guint8 code = (guint8) (*text); + + switch (code) { + case 0x86: /* emphasis on */ + case 0x87: /* emphasis off */ + /* skip it */ + break; + case 0x8A: + g_byte_array_append (sb, (guint8 *) "\n", 1); + break; + default: + g_byte_array_append (sb, &code, 1); + break; + } + + text++; + } + } + } + + if (sb->len > 0) { + new_text = + g_convert ((gchar *) sb->data, sb->len, "utf-8", encoding, NULL, NULL, + error); + } else { + new_text = g_strdup (""); + } + + g_byte_array_free (sb, TRUE); + + return new_text; +} + +static gchar * +get_encoding_and_convert (const gchar * text, guint length) +{ + GError *error = NULL; + gchar *converted_str; + gchar *encoding; + guint start_text = 0; + gboolean is_multibyte; + + g_return_val_if_fail (text != NULL, NULL); + + if (length == 0) + return g_strdup (""); + + encoding = get_encoding (text, &start_text, &is_multibyte); + + if (encoding == NULL) { + GST_WARNING ("Could not detect encoding"); + converted_str = g_strndup (text, length); + } else { + converted_str = convert_to_utf8 (text, length - start_text, start_text, + encoding, is_multibyte, &error); + if (error != NULL) { + GST_WARNING ("Could not convert string, encoding is %s: %s", + encoding, error->message); + g_error_free (error); + error = NULL; + + /* The first part of ISO 6937 is identical to ISO 8859-9, but + * they differ in the second part. Some channels don't + * provide the first byte that indicates ISO 8859-9 encoding. + * If decoding from ISO 6937 failed, we try ISO 8859-9 here. + */ + if (strcmp (encoding, "iso6937") == 0) { + GST_INFO ("Trying encoding ISO 8859-9"); + converted_str = convert_to_utf8 (text, length, 0, + "iso8859-9", FALSE, &error); + if (error != NULL) { + GST_WARNING + ("Could not convert string while assuming encoding ISO 8859-9: %s", + error->message); + g_error_free (error); + goto failed; + } + } else { + goto failed; + } + } + + g_free (encoding); + } + + return converted_str; + +failed: + { + g_free (encoding); + text += start_text; + return g_strndup (text, length - start_text); + } +} diff --git a/gst/mpegtsdemux/mpegtspacketizer.h b/gst/mpegtsdemux/mpegtspacketizer.h new file mode 100644 index 000000000..e0be1e09f --- /dev/null +++ b/gst/mpegtsdemux/mpegtspacketizer.h @@ -0,0 +1,167 @@ +/* + * mpegtspacketizer.h - + * Copyright (C) 2007 Alessandro Decina + * + * Authors: + * Alessandro Decina <alessandro@nnva.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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef GST_MPEGTS_PACKETIZER_H +#define GST_MPEGTS_PACKETIZER_H + +#include <gst/gst.h> +#include <gst/base/gstadapter.h> +#include <glib.h> + +#define MPEGTS_NORMAL_PACKETSIZE 188 +#define MPEGTS_M2TS_PACKETSIZE 192 +#define MPEGTS_DVB_ASI_PACKETSIZE 204 +#define MPEGTS_ATSC_PACKETSIZE 208 + +#define MPEGTS_MIN_PACKETSIZE MPEGTS_NORMAL_PACKETSIZE +#define MPEGTS_MAX_PACKETSIZE MPEGTS_ATSC_PACKETSIZE + +#define MPEGTS_AFC_PCR_FLAG 0x10 +#define MPEGTS_AFC_OPCR_FLAG 0x08 + +G_BEGIN_DECLS + +#define GST_TYPE_MPEGTS_PACKETIZER \ + (mpegts_packetizer_get_type()) +#define GST_MPEGTS_PACKETIZER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MPEGTS_PACKETIZER,MpegTSPacketizer2)) +#define GST_MPEGTS_PACKETIZER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MPEGTS_PACKETIZER,MpegTSPacketizer2Class)) +#define GST_IS_MPEGTS_PACKETIZER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MPEGTS_PACKETIZER)) +#define GST_IS_MPEGTS_PACKETIZER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MPEGTS_PACKETIZER)) + +typedef struct _MpegTSPacketizer2 MpegTSPacketizer2; +typedef struct _MpegTSPacketizer2Class MpegTSPacketizer2Class; + +typedef struct +{ + guint continuity_counter; + GstAdapter *section_adapter; + guint8 section_table_id; + guint section_length; + GSList *subtables; + guint64 offset; +} MpegTSPacketizerStream; + +struct _MpegTSPacketizer2 { + GObject object; + + GstAdapter *adapter; + /* streams hashed by pid */ + MpegTSPacketizerStream **streams; + gboolean disposed; + gboolean know_packet_size; + guint16 packet_size; + GstCaps *caps; + + /* current offset of the tip of the adapter */ + guint64 offset; + gboolean empty; +}; + +struct _MpegTSPacketizer2Class { + GObjectClass object_class; +}; + +typedef struct +{ + GstBuffer *buffer; + gint16 pid; + guint8 payload_unit_start_indicator; + guint8 adaptation_field_control; + guint8 continuity_counter; + guint8 *payload; + + guint8 *data_start; + guint8 *data_end; + guint8 *data; + + guint8 afc_flags; + guint64 pcr; + guint64 opcr; + guint64 offset; +} MpegTSPacketizerPacket; + +typedef struct +{ + gboolean complete; + GstBuffer *buffer; + gint16 pid; + guint8 table_id; + guint16 subtable_extension; + guint section_length; + guint8 version_number; + guint8 current_next_indicator; + guint32 crc; +} MpegTSPacketizerSection; + +typedef struct +{ + guint8 table_id; + /* the spec says sub_table_extension is the fourth and fifth byte of a + * section when the section_syntax_indicator is set to a value of "1". If + * section_syntax_indicator is 0, sub_table_extension will be set to 0 */ + guint16 subtable_extension; + guint8 version_number; + guint32 crc; +} MpegTSPacketizerStreamSubtable; + +typedef enum { + PACKET_BAD = FALSE, + PACKET_OK = TRUE, + PACKET_NEED_MORE +} MpegTSPacketizerPacketReturn; + +GType mpegts_packetizer_get_type(void); + +MpegTSPacketizer2 *mpegts_packetizer_new (void); +void mpegts_packetizer_clear (MpegTSPacketizer2 *packetizer); +void mpegts_packetizer_push (MpegTSPacketizer2 *packetizer, GstBuffer *buffer); +gboolean mpegts_packetizer_has_packets (MpegTSPacketizer2 *packetizer); +MpegTSPacketizerPacketReturn mpegts_packetizer_next_packet (MpegTSPacketizer2 *packetizer, + MpegTSPacketizerPacket *packet); +void mpegts_packetizer_clear_packet (MpegTSPacketizer2 *packetizer, + MpegTSPacketizerPacket *packet); +void mpegts_packetizer_remove_stream(MpegTSPacketizer2 *packetizer, + gint16 pid); + +gboolean mpegts_packetizer_push_section (MpegTSPacketizer2 *packetzer, + MpegTSPacketizerPacket *packet, MpegTSPacketizerSection *section); +GstStructure *mpegts_packetizer_parse_pat (MpegTSPacketizer2 *packetizer, + MpegTSPacketizerSection *section); +GstStructure *mpegts_packetizer_parse_pmt (MpegTSPacketizer2 *packetizer, + MpegTSPacketizerSection *section); +GstStructure *mpegts_packetizer_parse_nit (MpegTSPacketizer2 *packetizer, + MpegTSPacketizerSection *section); +GstStructure *mpegts_packetizer_parse_sdt (MpegTSPacketizer2 *packetizer, + MpegTSPacketizerSection *section); +GstStructure *mpegts_packetizer_parse_eit (MpegTSPacketizer2 *packetizer, + MpegTSPacketizerSection *section); +GstStructure *mpegts_packetizer_parse_tdt (MpegTSPacketizer2 *packetizer, + MpegTSPacketizerSection *section); + +G_END_DECLS + +#endif /* GST_MPEGTS_PACKETIZER_H */ diff --git a/gst/mpegtsdemux/mpegtsparse.c b/gst/mpegtsdemux/mpegtsparse.c new file mode 100644 index 000000000..ede74ae82 --- /dev/null +++ b/gst/mpegtsdemux/mpegtsparse.c @@ -0,0 +1,718 @@ +/* + * mpegtsparse.c - + * Copyright (C) 2007 Alessandro Decina + * + * Authors: + * Alessandro Decina <alessandro@nnva.org> + * Zaheer Abbas Merali <zaheerabbas at merali dot org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> + +#include "mpegtsbase.h" +#include "mpegtsparse.h" +#include "gstmpegdesc.h" + +/* latency in mseconds */ +#define TS_LATENCY 700 + +#define TABLE_ID_UNSET 0xFF +#define RUNNING_STATUS_RUNNING 4 + +GST_DEBUG_CATEGORY_STATIC (mpegts_parse_debug); +#define GST_CAT_DEFAULT mpegts_parse_debug + +typedef struct _MpegTSParsePad MpegTSParsePad; + +typedef struct +{ + MpegTSBaseProgram program; + gint selected; + gboolean active; + MpegTSParsePad *tspad; +} MpegTSParseProgram; + +struct _MpegTSParsePad +{ + GstPad *pad; + + /* the program number that the peer wants on this pad */ + gint program_number; + MpegTSParseProgram *program; + + /* set to FALSE before a push and TRUE after */ + gboolean pushed; + + /* the return of the latest push */ + GstFlowReturn flow_return; + + GstTagList *tags; + guint event_id; +}; + +static GstStaticPadTemplate src_template = +GST_STATIC_PAD_TEMPLATE ("src%d", GST_PAD_SRC, + GST_PAD_REQUEST, + GST_STATIC_CAPS ("video/mpegts, " "systemstream = (boolean) true ") + ); + +static GstStaticPadTemplate program_template = +GST_STATIC_PAD_TEMPLATE ("program_%d", GST_PAD_SRC, + GST_PAD_SOMETIMES, + GST_STATIC_CAPS ("video/mpegts, " "systemstream = (boolean) true ") + ); + +enum +{ + ARG_0, + PROP_PROGRAM_NUMBERS, + /* FILL ME */ +}; + +static void +mpegts_parse_program_started (MpegTSBase * base, MpegTSBaseProgram * program); +static void +mpegts_parse_program_stopped (MpegTSBase * base, MpegTSBaseProgram * program); + +static GstFlowReturn +mpegts_parse_push (MpegTSBase * base, MpegTSPacketizerPacket * packet, + MpegTSPacketizerSection * section); +static void mpegts_parse_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void mpegts_parse_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void mpegts_parse_finalize (GObject * object); + +static MpegTSParsePad *mpegts_parse_create_tspad (MpegTSParse2 * parse, + const gchar * name); +static void mpegts_parse_destroy_tspad (MpegTSParse2 * parse, + MpegTSParsePad * tspad); +static GstPad *mpegts_parse_activate_program (MpegTSParse2 * parse, + MpegTSParseProgram * program); +static void mpegts_parse_reset_selected_programs (MpegTSParse2 * parse, + gchar * programs); + +static void mpegts_parse_pad_removed (GstElement * element, GstPad * pad); +static GstPad *mpegts_parse_request_new_pad (GstElement * element, + GstPadTemplate * templ, const gchar * name); +static void mpegts_parse_release_pad (GstElement * element, GstPad * pad); +static gboolean mpegts_parse_src_pad_query (GstPad * pad, GstQuery * query); +static gboolean push_event (MpegTSBase * base, GstEvent * event); + +GST_BOILERPLATE (MpegTSParse2, mpegts_parse, MpegTSBase, GST_TYPE_MPEGTS_BASE); + +static void +mpegts_parse_base_init (gpointer klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&program_template)); + + gst_element_class_set_details_simple (element_class, + "MPEG transport stream parser", "Codec/Parser", + "Parses MPEG2 transport streams", + "Alessandro Decina <alessandro@nnva.org>, " + "Zaheer Abbas Merali <zaheerabbas at merali dot org>"); +} + +static void +mpegts_parse_class_init (MpegTSParse2Class * klass) +{ + GObjectClass *gobject_class; + GstElementClass *element_class; + MpegTSBaseClass *ts_class; + + element_class = GST_ELEMENT_CLASS (klass); + element_class->pad_removed = mpegts_parse_pad_removed; + element_class->request_new_pad = mpegts_parse_request_new_pad; + element_class->release_pad = mpegts_parse_release_pad; + + gobject_class = G_OBJECT_CLASS (klass); + gobject_class->set_property = mpegts_parse_set_property; + gobject_class->get_property = mpegts_parse_get_property; + gobject_class->finalize = mpegts_parse_finalize; + + g_object_class_install_property (gobject_class, PROP_PROGRAM_NUMBERS, + g_param_spec_string ("program-numbers", + "Program Numbers", + "Colon separated list of programs", "", + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + ts_class = GST_MPEGTS_BASE_CLASS (klass); + ts_class->push = GST_DEBUG_FUNCPTR (mpegts_parse_push); + ts_class->push_event = GST_DEBUG_FUNCPTR (push_event); + ts_class->program_started = GST_DEBUG_FUNCPTR (mpegts_parse_program_started); + ts_class->program_stopped = GST_DEBUG_FUNCPTR (mpegts_parse_program_stopped); +} + +static void +mpegts_parse_init (MpegTSParse2 * parse, MpegTSParse2Class * klass) +{ + parse->need_sync_program_pads = FALSE; + parse->program_numbers = g_strdup (""); + parse->pads_to_add = NULL; + parse->pads_to_remove = NULL; + GST_MPEGTS_BASE (parse)->program_size = sizeof (MpegTSParseProgram); +} + +static void +mpegts_parse_finalize (GObject * object) +{ + MpegTSParse2 *parse = GST_MPEGTS_PARSE (object); + + g_free (parse->program_numbers); + + if (G_OBJECT_CLASS (parent_class)->finalize) + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +mpegts_parse_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + MpegTSParse2 *parse = GST_MPEGTS_PARSE (object); + + switch (prop_id) { + case PROP_PROGRAM_NUMBERS: + mpegts_parse_reset_selected_programs (parse, g_value_dup_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +mpegts_parse_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + MpegTSParse2 *parse = GST_MPEGTS_PARSE (object); + + switch (prop_id) { + case PROP_PROGRAM_NUMBERS: + g_value_set_string (value, parse->program_numbers); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static GstPad * +mpegts_parse_activate_program (MpegTSParse2 * parse, + MpegTSParseProgram * program) +{ + MpegTSParsePad *tspad; + gchar *pad_name; + + pad_name = + g_strdup_printf ("program_%d", + ((MpegTSBaseProgram *) program)->program_number); + + tspad = mpegts_parse_create_tspad (parse, pad_name); + tspad->program_number = ((MpegTSBaseProgram *) program)->program_number; + tspad->program = program; + program->tspad = tspad; + g_free (pad_name); + gst_pad_set_active (tspad->pad, TRUE); + program->active = TRUE; + + return tspad->pad; +} + +static gboolean +push_event (MpegTSBase * base, GstEvent * event) +{ + MpegTSParse2 *parse = (MpegTSParse2 *) base; + GList *tmp; + + for (tmp = GST_ELEMENT_CAST (parse)->srcpads; tmp; tmp = tmp->next) { + GstPad *pad = (GstPad *) tmp->data; + if (pad) { + gst_event_ref (event); + gst_pad_push_event (pad, event); + } + } + return TRUE; +} + +static GstPad * +mpegts_parse_deactivate_program (MpegTSParse2 * parse, + MpegTSParseProgram * program) +{ + MpegTSParsePad *tspad; + + tspad = program->tspad; + gst_pad_set_active (tspad->pad, FALSE); + program->active = FALSE; + + /* tspad will be destroyed in GstElementClass::pad_removed */ + + return tspad->pad; +} + +static void +mpegts_parse_sync_program_pads (MpegTSParse2 * parse) +{ + GList *walk; + + GST_INFO_OBJECT (parse, "begin sync pads"); + for (walk = parse->pads_to_remove; walk; walk = walk->next) + gst_element_remove_pad (GST_ELEMENT (parse), GST_PAD (walk->data)); + + for (walk = parse->pads_to_add; walk; walk = walk->next) + gst_element_add_pad (GST_ELEMENT (parse), GST_PAD (walk->data)); + + if (parse->pads_to_add) + g_list_free (parse->pads_to_add); + + if (parse->pads_to_remove) + g_list_free (parse->pads_to_remove); + + GST_OBJECT_LOCK (parse); + parse->pads_to_remove = NULL; + parse->pads_to_add = NULL; + parse->need_sync_program_pads = FALSE; + GST_OBJECT_UNLOCK (parse); + + GST_INFO_OBJECT (parse, "end sync pads"); +} + +static void +foreach_program_activate_or_deactivate (gpointer key, gpointer value, + gpointer data) +{ + MpegTSParse2 *parse = GST_MPEGTS_PARSE (data); + MpegTSParseProgram *program = (MpegTSParseProgram *) value; + + /* at this point selected programs have program->selected == 2, + * unselected programs thay may have to be deactivated have selected == 1 and + * unselected inactive programs have selected == 0 */ + + switch (--program->selected) { + case 1: + /* selected */ + if (!program->active + && ((MpegTSBaseProgram *) program)->pmt_pid != G_MAXUINT16) + parse->pads_to_add = + g_list_append (parse->pads_to_add, + mpegts_parse_activate_program (parse, program)); + else { + program->selected = 2; + } + break; + case 0: + /* unselected */ + if (program->active) + parse->pads_to_remove = g_list_append (parse->pads_to_remove, + mpegts_parse_deactivate_program (parse, program)); + break; + case -1: + /* was already unselected */ + program->selected = 0; + break; + default: + g_return_if_reached (); + } +} + +static void +mpegts_parse_reset_selected_programs (MpegTSParse2 * parse, + gchar * program_numbers) +{ + GST_OBJECT_LOCK (parse); + if (parse->program_numbers) + g_free (parse->program_numbers); + + parse->program_numbers = program_numbers; + + if (*parse->program_numbers != '\0') { + gint program_number; + MpegTSParseProgram *program; + gchar **progs, **walk; + + progs = g_strsplit (parse->program_numbers, ":", 0); + + walk = progs; + while (*walk != NULL) { + program_number = strtol (*walk, NULL, 0); + program = + (MpegTSParseProgram *) mpegts_base_get_program ((MpegTSBase *) parse, + program_number); + if (program == NULL) + /* create the program, it will get activated once we get a PMT for it */ + program = (MpegTSParseProgram *) mpegts_base_add_program ((MpegTSBase *) + parse, program_number, G_MAXUINT16); + program->selected = 2; + ++walk; + } + g_strfreev (progs); + } + + g_hash_table_foreach (((MpegTSBase *) parse)->programs, + foreach_program_activate_or_deactivate, parse); + + if (parse->pads_to_remove || parse->pads_to_add) + parse->need_sync_program_pads = TRUE; + GST_OBJECT_UNLOCK (parse); +} + + +static MpegTSParsePad * +mpegts_parse_create_tspad (MpegTSParse2 * parse, const gchar * pad_name) +{ + GstPad *pad; + MpegTSParsePad *tspad; + + pad = gst_pad_new_from_static_template (&program_template, pad_name); + gst_pad_set_query_function (pad, + GST_DEBUG_FUNCPTR (mpegts_parse_src_pad_query)); + + /* create our wrapper */ + tspad = g_new0 (MpegTSParsePad, 1); + tspad->pad = pad; + tspad->program_number = -1; + tspad->program = NULL; + tspad->pushed = FALSE; + tspad->flow_return = GST_FLOW_NOT_LINKED; + gst_pad_set_element_private (pad, tspad); + + return tspad; +} + +static void +mpegts_parse_destroy_tspad (MpegTSParse2 * parse, MpegTSParsePad * tspad) +{ + if (tspad->tags) { + gst_tag_list_free (tspad->tags); + } + + /* free the wrapper */ + g_free (tspad); +} + +static void +mpegts_parse_pad_removed (GstElement * element, GstPad * pad) +{ + MpegTSParsePad *tspad; + MpegTSParse2 *parse = GST_MPEGTS_PARSE (element); + + if (gst_pad_get_direction (pad) == GST_PAD_SINK) + return; + + tspad = (MpegTSParsePad *) gst_pad_get_element_private (pad); + mpegts_parse_destroy_tspad (parse, tspad); + + if (GST_ELEMENT_CLASS (parent_class)->pad_removed) + GST_ELEMENT_CLASS (parent_class)->pad_removed (element, pad); +} + +static GstPad * +mpegts_parse_request_new_pad (GstElement * element, GstPadTemplate * template, + const gchar * unused) +{ + MpegTSParse2 *parse; + gchar *name; + GstPad *pad; + + g_return_val_if_fail (template != NULL, NULL); + g_return_val_if_fail (GST_IS_MPEGTS_PARSE (element), NULL); + + parse = GST_MPEGTS_PARSE (element); + + GST_OBJECT_LOCK (element); + name = g_strdup_printf ("src%d", parse->req_pads++); + GST_OBJECT_UNLOCK (element); + + pad = mpegts_parse_create_tspad (parse, name)->pad; + gst_pad_set_active (pad, TRUE); + gst_element_add_pad (element, pad); + g_free (name); + + return pad; +} + +static void +mpegts_parse_release_pad (GstElement * element, GstPad * pad) +{ + g_return_if_fail (GST_IS_MPEGTS_PARSE (element)); + + gst_pad_set_active (pad, FALSE); + /* we do the cleanup in GstElement::pad-removed */ + gst_element_remove_pad (element, pad); +} + +static GstFlowReturn +mpegts_parse_tspad_push_section (MpegTSParse2 * parse, MpegTSParsePad * tspad, + MpegTSPacketizerSection * section, GstBuffer * buffer) +{ + GstFlowReturn ret = GST_FLOW_NOT_LINKED; + gboolean to_push = TRUE; + + if (tspad->program_number != -1) { + if (tspad->program) { + /* we push all sections to all pads except PMTs which we + * only push to pads meant to receive that program number */ + if (section->table_id == 0x02) { + /* PMT */ + if (section->subtable_extension != tspad->program_number) + to_push = FALSE; + } + } else { + /* there's a program filter on the pad but the PMT for the program has not + * been parsed yet, ignore the pad until we get a PMT */ + to_push = FALSE; + ret = GST_FLOW_OK; + } + } + GST_DEBUG_OBJECT (parse, + "pushing section: %d program number: %d table_id: %d", to_push, + tspad->program_number, section->table_id); + if (to_push) { + ret = gst_pad_push (tspad->pad, buffer); + } else { + gst_buffer_unref (buffer); + if (gst_pad_is_linked (tspad->pad)) + ret = GST_FLOW_OK; + } + + return ret; +} + +static GstFlowReturn +mpegts_parse_tspad_push (MpegTSParse2 * parse, MpegTSParsePad * tspad, + guint16 pid, GstBuffer * buffer) +{ + GstFlowReturn ret = GST_FLOW_NOT_LINKED; + MpegTSBaseStream **pad_pids = NULL; + + if (tspad->program_number != -1) { + if (tspad->program) { + MpegTSBaseProgram *bp = (MpegTSBaseProgram *) tspad->program; + pad_pids = bp->streams; + if (bp->tags) { + gst_element_found_tags_for_pad (GST_ELEMENT_CAST (parse), tspad->pad, + bp->tags); + bp->tags = NULL; + } + } else { + /* there's a program filter on the pad but the PMT for the program has not + * been parsed yet, ignore the pad until we get a PMT */ + gst_buffer_unref (buffer); + ret = GST_FLOW_OK; + goto out; + } + } + + if (pad_pids == NULL || pad_pids[pid]) { + /* push if there's no filter or if the pid is in the filter */ + ret = gst_pad_push (tspad->pad, buffer); + } else { + gst_buffer_unref (buffer); + if (gst_pad_is_linked (tspad->pad)) + ret = GST_FLOW_OK; + } + +out: + return ret; +} + +static void +pad_clear_for_push (GstPad * pad, MpegTSParse2 * parse) +{ + MpegTSParsePad *tspad = (MpegTSParsePad *) gst_pad_get_element_private (pad); + + tspad->flow_return = GST_FLOW_NOT_LINKED; + tspad->pushed = FALSE; +} + +static GstFlowReturn +mpegts_parse_push (MpegTSBase * base, MpegTSPacketizerPacket * packet, + MpegTSPacketizerSection * section) +{ + MpegTSParse2 *parse = (MpegTSParse2 *) base; + guint32 pads_cookie; + gboolean done = FALSE; + GstPad *pad = NULL; + MpegTSParsePad *tspad; + guint16 pid; + GstBuffer *buffer; + GstFlowReturn ret; + GList *srcpads; + + if (G_UNLIKELY (parse->need_sync_program_pads)) + mpegts_parse_sync_program_pads (parse); + + pid = packet->pid; + buffer = gst_buffer_make_metadata_writable (packet->buffer); + /* we have the same caps on all the src pads */ + gst_buffer_set_caps (buffer, base->packetizer->caps); + + GST_OBJECT_LOCK (parse); + /* clear tspad->pushed on pads */ + g_list_foreach (GST_ELEMENT_CAST (parse)->srcpads, + (GFunc) pad_clear_for_push, parse); + if (GST_ELEMENT_CAST (parse)->srcpads) + ret = GST_FLOW_NOT_LINKED; + else + ret = GST_FLOW_OK; + + /* Get cookie and source pads list */ + pads_cookie = GST_ELEMENT_CAST (parse)->pads_cookie; + srcpads = GST_ELEMENT_CAST (parse)->srcpads; + if (G_LIKELY (srcpads)) { + pad = GST_PAD_CAST (srcpads->data); + g_object_ref (pad); + } + GST_OBJECT_UNLOCK (parse); + + while (pad && !done) { + tspad = gst_pad_get_element_private (pad); + + if (G_LIKELY (!tspad->pushed)) { + /* ref the buffer as gst_pad_push takes a ref but we want to reuse the + * same buffer for next pushes */ + gst_buffer_ref (buffer); + if (section) { + tspad->flow_return = + mpegts_parse_tspad_push_section (parse, tspad, section, buffer); + } else { + tspad->flow_return = + mpegts_parse_tspad_push (parse, tspad, pid, buffer); + } + tspad->pushed = TRUE; + + if (G_UNLIKELY (tspad->flow_return != GST_FLOW_OK + && tspad->flow_return != GST_FLOW_NOT_LINKED)) { + /* return the error upstream */ + ret = tspad->flow_return; + done = TRUE; + } + + } + + if (ret == GST_FLOW_NOT_LINKED) + ret = tspad->flow_return; + + g_object_unref (pad); + + if (G_UNLIKELY (!done)) { + GST_OBJECT_LOCK (parse); + if (G_UNLIKELY (pads_cookie != GST_ELEMENT_CAST (parse)->pads_cookie)) { + /* resync */ + GST_DEBUG ("resync"); + pads_cookie = GST_ELEMENT_CAST (parse)->pads_cookie; + srcpads = GST_ELEMENT_CAST (parse)->srcpads; + } else { + GST_DEBUG ("getting next pad"); + /* Get next pad */ + srcpads = g_list_next (srcpads); + } + + if (srcpads) { + pad = GST_PAD_CAST (srcpads->data); + g_object_ref (pad); + } else + done = TRUE; + GST_OBJECT_UNLOCK (parse); + } + } + + gst_buffer_unref (buffer); + packet->buffer = NULL; + + return ret; +} + +static void +mpegts_parse_program_started (MpegTSBase * base, MpegTSBaseProgram * program) +{ + MpegTSParse2 *parse = GST_MPEGTS_PARSE (base); + MpegTSParseProgram *parseprogram = (MpegTSParseProgram *) program; + if (parseprogram->selected == 2) { + parse->pads_to_add = + g_list_append (parse->pads_to_add, + mpegts_parse_activate_program (parse, parseprogram)); + parseprogram->selected = 1; + parse->need_sync_program_pads = TRUE; + } + +} + +static void +mpegts_parse_program_stopped (MpegTSBase * base, MpegTSBaseProgram * program) +{ + MpegTSParse2 *parse = GST_MPEGTS_PARSE (base); + MpegTSParseProgram *parseprogram = (MpegTSParseProgram *) program; + + if (parseprogram->active) { + parse->pads_to_remove = + g_list_append (parse->pads_to_remove, + mpegts_parse_deactivate_program (parse, parseprogram)); + parse->need_sync_program_pads = TRUE; + } +} + +static gboolean +mpegts_parse_src_pad_query (GstPad * pad, GstQuery * query) +{ + MpegTSParse2 *parse = GST_MPEGTS_PARSE (gst_pad_get_parent (pad)); + gboolean res; + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_LATENCY: + { + if ((res = gst_pad_peer_query (((MpegTSBase *) parse)->sinkpad, query))) { + gboolean is_live; + GstClockTime min_latency, max_latency; + + gst_query_parse_latency (query, &is_live, &min_latency, &max_latency); + if (is_live) { + min_latency += TS_LATENCY * GST_MSECOND; + if (max_latency != GST_CLOCK_TIME_NONE) + max_latency += TS_LATENCY * GST_MSECOND; + } + + gst_query_set_latency (query, is_live, min_latency, max_latency); + } + + break; + } + default: + res = gst_pad_query_default (pad, query); + } + gst_object_unref (parse); + return res; +} + +gboolean +gst_mpegtsparse_plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (mpegts_parse_debug, "tsparse", 0, + "MPEG transport stream parser"); + + gst_mpegtsdesc_init_debug (); + + return gst_element_register (plugin, "tsparse", + GST_RANK_NONE, GST_TYPE_MPEGTS_PARSE); +} diff --git a/gst/mpegtsdemux/mpegtsparse.h b/gst/mpegtsdemux/mpegtsparse.h new file mode 100644 index 000000000..ef722dd5e --- /dev/null +++ b/gst/mpegtsdemux/mpegtsparse.h @@ -0,0 +1,71 @@ +/* + * mpegts_parse.h - GStreamer MPEG transport stream parser + * Copyright (C) 2007 Alessandro Decina + * + * Authors: + * Alessandro Decina <alessandro@nnva.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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef GST_MPEG_TS_PARSE_H +#define GST_MPEG_TS_PARSE_H + +#include <gst/gst.h> +#include "mpegtsbase.h" +#include "mpegtspacketizer.h" + +G_BEGIN_DECLS + +#define GST_TYPE_MPEGTS_PARSE \ + (mpegts_parse_get_type()) +#define GST_MPEGTS_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MPEGTS_PARSE,MpegTSParse2)) +#define GST_MPEGTS_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MPEGTS_PARSE,MpegTSParse2Class)) +#define GST_IS_MPEGTS_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MPEGTS_PARSE)) +#define GST_IS_MPEGTS_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MPEGTS_PARSE)) + +typedef struct _MpegTSParse2 MpegTSParse2; +typedef struct _MpegTSParse2Class MpegTSParse2Class; + +struct _MpegTSParse2 { + MpegTSBase parent; + + /* the following vars must be protected with the OBJECT_LOCK as they can be + * accessed from the application thread and the streaming thread */ + gchar *program_numbers; + GList *pads_to_add; + GList *pads_to_remove; + guint req_pads; + + gboolean need_sync_program_pads; +}; + +struct _MpegTSParse2Class { + MpegTSBaseClass parent_class; +}; + +GType mpegts_parse_get_type(void); + +gboolean gst_mpegtsparse_plugin_init (GstPlugin * plugin); + +G_END_DECLS + +#endif /* GST_MPEG_TS_PARSE_H */ diff --git a/gst/mpegtsdemux/tsdemux.c b/gst/mpegtsdemux/tsdemux.c new file mode 100644 index 000000000..97dd3802b --- /dev/null +++ b/gst/mpegtsdemux/tsdemux.c @@ -0,0 +1,1491 @@ +/* + * tsdemux.c + * Copyright (C) 2009 Zaheer Abbas Merali + * 2010 Edward Hervey + * + * Authors: + * Zaheer Abbas Merali <zaheerabbas at merali dot org> + * Edward Hervey <edward.hervey@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> + +#include "mpegtsbase.h" +#include "tsdemux.h" +#include "gstmpegdesc.h" +#include "gstmpegdefs.h" +#include "mpegtspacketizer.h" + +/* latency in mseconds */ +#define TS_LATENCY 700 + +#define TABLE_ID_UNSET 0xFF + +/* Size of the pendingbuffers array. */ +#define TS_MAX_PENDING_BUFFERS 256 + +GST_DEBUG_CATEGORY_STATIC (ts_demux_debug); +#define GST_CAT_DEFAULT ts_demux_debug + +static GQuark QUARK_TSDEMUX; +static GQuark QUARK_PID; +static GQuark QUARK_PCR; +static GQuark QUARK_OPCR; +static GQuark QUARK_PTS; +static GQuark QUARK_DTS; +static GQuark QUARK_OFFSET; + + + +typedef enum +{ + PENDING_PACKET_EMPTY = 0, /* No pending packet/buffer + * Push incoming buffers to the array */ + PENDING_PACKET_HEADER, /* PES header needs to be parsed + * Push incoming buffers to the array */ + PENDING_PACKET_BUFFER, /* Currently filling up output buffer + * Push incoming buffers to the bufferlist */ + PENDING_PACKET_DISCONT /* Discontinuity in incoming packets + * Drop all incoming buffers */ +} PendingPacketState; + +typedef struct _TSDemuxStream TSDemuxStream; + +struct _TSDemuxStream +{ + MpegTSBaseStream stream; + + GstPad *pad; + + /* set to FALSE before a push and TRUE after */ + gboolean pushed; + + /* the return of the latest push */ + GstFlowReturn flow_return; + + /* Output data */ + PendingPacketState state; + /* Pending buffers array. */ + /* These buffers are stored in this array until the PES header (if needed) + * is succesfully parsed. */ + GstBuffer *pendingbuffers[TS_MAX_PENDING_BUFFERS]; + guint8 nbpending; + + /* Current data to be pushed out */ + GstBufferList *current; + GstBufferListIterator *currentit; + GList *currentlist; + + GstClockTime pts; +}; + +#define VIDEO_CAPS \ + GST_STATIC_CAPS (\ + "video/mpeg, " \ + "mpegversion = (int) { 1, 2, 4 }, " \ + "systemstream = (boolean) FALSE; " \ + "video/x-h264;" \ + "video/x-dirac;" \ + "video/x-wmv," \ + "wmvversion = (int) 3, " \ + "format = (fourcc) WVC1" \ + ) + +#define AUDIO_CAPS \ + GST_STATIC_CAPS ( \ + "audio/mpeg, " \ + "mpegversion = (int) { 1, 4 };" \ + "audio/x-lpcm, " \ + "width = (int) { 16, 20, 24 }, " \ + "rate = (int) { 48000, 96000 }, " \ + "channels = (int) [ 1, 8 ], " \ + "dynamic_range = (int) [ 0, 255 ], " \ + "emphasis = (boolean) { FALSE, TRUE }, " \ + "mute = (boolean) { FALSE, TRUE }; " \ + "audio/x-ac3; audio/x-eac3;" \ + "audio/x-dts;" \ + "audio/x-private-ts-lpcm" \ + ) + +/* Can also use the subpicture pads for text subtitles? */ +#define SUBPICTURE_CAPS \ + GST_STATIC_CAPS ("subpicture/x-pgs; video/x-dvd-subpicture") + +static GstStaticPadTemplate video_template = +GST_STATIC_PAD_TEMPLATE ("video_%04x", GST_PAD_SRC, + GST_PAD_SOMETIMES, + VIDEO_CAPS); + +static GstStaticPadTemplate audio_template = +GST_STATIC_PAD_TEMPLATE ("audio_%04x", + GST_PAD_SRC, + GST_PAD_SOMETIMES, + AUDIO_CAPS); + +static GstStaticPadTemplate subpicture_template = +GST_STATIC_PAD_TEMPLATE ("subpicture_%04x", + GST_PAD_SRC, + GST_PAD_SOMETIMES, + SUBPICTURE_CAPS); + +static GstStaticPadTemplate private_template = +GST_STATIC_PAD_TEMPLATE ("private_%04x", + GST_PAD_SRC, + GST_PAD_SOMETIMES, + GST_STATIC_CAPS_ANY); + +enum +{ + ARG_0, + PROP_PROGRAM_NUMBER, + PROP_EMIT_STATS, + /* FILL ME */ +}; + +/* Pad functions */ +static const GstQueryType *gst_ts_demux_srcpad_query_types (GstPad * pad); +static gboolean gst_ts_demux_srcpad_query (GstPad * pad, GstQuery * query); + + +/* mpegtsbase methods */ +static void +gst_ts_demux_program_started (MpegTSBase * base, MpegTSBaseProgram * program); +static void +gst_ts_demux_program_stopped (MpegTSBase * base, MpegTSBaseProgram * program); +static GstFlowReturn +gst_ts_demux_push (MpegTSBase * base, MpegTSPacketizerPacket * packet, + MpegTSPacketizerSection * section); +static void +gst_ts_demux_stream_added (MpegTSBase * base, MpegTSBaseStream * stream, + MpegTSBaseProgram * program); +static void +gst_ts_demux_stream_removed (MpegTSBase * base, MpegTSBaseStream * stream); +static GstFlowReturn +find_timestamps (MpegTSBase * base, guint64 initoff, guint64 * offset); +static void gst_ts_demux_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_ts_demux_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_ts_demux_finalize (GObject * object); +static GstFlowReturn +process_pcr (MpegTSBase * base, guint64 initoff, GstClockTime * pcr, + guint numpcr, gboolean isinitial); +static gboolean push_event (MpegTSBase * base, GstEvent * event); +static void _extra_init (GType type); + +GST_BOILERPLATE_FULL (GstTSDemux, gst_ts_demux, MpegTSBase, + GST_TYPE_MPEGTS_BASE, _extra_init); + +static void +_extra_init (GType type) +{ + QUARK_TSDEMUX = g_quark_from_string ("tsdemux"); + QUARK_PID = g_quark_from_string ("pid"); + QUARK_PCR = g_quark_from_string ("pcr"); + QUARK_OPCR = g_quark_from_string ("opcr"); + QUARK_PTS = g_quark_from_string ("pts"); + QUARK_DTS = g_quark_from_string ("dts"); + QUARK_OFFSET = g_quark_from_string ("offset"); +} + +static void +gst_ts_demux_base_init (gpointer klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&video_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&audio_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&subpicture_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&private_template)); + + gst_element_class_set_details_simple (element_class, + "MPEG transport stream demuxer", + "Codec/Demuxer", + "Demuxes MPEG2 transport streams", + "Zaheer Abbas Merali <zaheerabbas at merali dot org>;" + " Edward Hervey <edward.hervey@collabora.co.uk>"); +} + +static void +gst_ts_demux_class_init (GstTSDemuxClass * klass) +{ + GObjectClass *gobject_class; + MpegTSBaseClass *ts_class; + + gobject_class = G_OBJECT_CLASS (klass); + gobject_class->set_property = gst_ts_demux_set_property; + gobject_class->get_property = gst_ts_demux_get_property; + gobject_class->finalize = gst_ts_demux_finalize; + + g_object_class_install_property (gobject_class, PROP_PROGRAM_NUMBER, + g_param_spec_int ("program-number", "Program number", + "Program Number to demux for (-1 to ignore)", -1, G_MAXINT, + -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_EMIT_STATS, + g_param_spec_boolean ("emit-stats", "Emit statistics", + "Emit messages for every pcr/opcr/pts/dts", FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + + ts_class = GST_MPEGTS_BASE_CLASS (klass); + ts_class->push = GST_DEBUG_FUNCPTR (gst_ts_demux_push); + ts_class->push_event = GST_DEBUG_FUNCPTR (push_event); + ts_class->program_started = GST_DEBUG_FUNCPTR (gst_ts_demux_program_started); + ts_class->program_stopped = GST_DEBUG_FUNCPTR (gst_ts_demux_program_stopped); + ts_class->stream_added = gst_ts_demux_stream_added; + ts_class->stream_removed = gst_ts_demux_stream_removed; + ts_class->find_timestamps = GST_DEBUG_FUNCPTR (find_timestamps); +} + +static void +gst_ts_demux_init (GstTSDemux * demux, GstTSDemuxClass * klass) +{ + demux->need_newsegment = TRUE; + demux->program_number = -1; + demux->duration = GST_CLOCK_TIME_NONE; + GST_MPEGTS_BASE (demux)->stream_size = sizeof (TSDemuxStream); +} + +static void +gst_ts_demux_finalize (GObject * object) +{ + if (G_OBJECT_CLASS (parent_class)->finalize) + G_OBJECT_CLASS (parent_class)->finalize (object); +} + + + +static void +gst_ts_demux_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstTSDemux *demux = GST_TS_DEMUX (object); + + switch (prop_id) { + case PROP_PROGRAM_NUMBER: + /* FIXME: do something if program is switched as opposed to set at + * beginning */ + demux->program_number = g_value_get_int (value); + break; + case PROP_EMIT_STATS: + demux->emit_statistics = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gst_ts_demux_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstTSDemux *demux = GST_TS_DEMUX (object); + + switch (prop_id) { + case PROP_PROGRAM_NUMBER: + g_value_set_int (value, demux->program_number); + break; + case PROP_EMIT_STATS: + g_value_set_boolean (value, demux->emit_statistics); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static const GstQueryType * +gst_ts_demux_srcpad_query_types (GstPad * pad) +{ + static const GstQueryType query_types[] = { + GST_QUERY_DURATION, + 0 + }; + + return query_types; +} + +static gboolean +gst_ts_demux_srcpad_query (GstPad * pad, GstQuery * query) +{ + gboolean res = TRUE; + GstTSDemux *demux; + + demux = GST_TS_DEMUX (gst_pad_get_parent (pad)); + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_DURATION: + { + GstFormat format; + + gst_query_parse_duration (query, &format, NULL); + /* can only get position in time */ + if (format != GST_FORMAT_TIME) + goto wrong_format; + + gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration); + break; + } + default: + res = gst_pad_query_default (pad, query); + break; + } + +done: + gst_object_unref (demux); + return res; + +wrong_format: + { + GST_DEBUG_OBJECT (demux, "only query duration on TIME is supported"); + res = FALSE; + goto done; + } +} + + +static gboolean +push_event (MpegTSBase * base, GstEvent * event) +{ + GstTSDemux *demux = (GstTSDemux *) base; + guint i; + + if (G_UNLIKELY (demux->program == NULL)) + return FALSE; + + for (i = 0; i < 0x2000; i++) { + if (demux->program->streams[i]) { + if (((TSDemuxStream *) demux->program->streams[i])->pad) { + gst_event_ref (event); + gst_pad_push_event (((TSDemuxStream *) demux->program->streams[i])->pad, + event); + } + } + } + + return TRUE; +} + +static GstFlowReturn +tsdemux_combine_flows (GstTSDemux * demux, TSDemuxStream * stream, + GstFlowReturn ret) +{ + guint i; + + /* Store the value */ + stream->flow_return = ret; + + /* any other error that is not-linked can be returned right away */ + if (ret != GST_FLOW_NOT_LINKED) + goto done; + + /* Only return NOT_LINKED if all other pads returned NOT_LINKED */ + for (i = 0; i < 0x2000; i++) { + if (demux->program->streams[i]) { + stream = (TSDemuxStream *) demux->program->streams[i]; + if (stream->pad) { + ret = stream->flow_return; + /* some other return value (must be SUCCESS but we can return + * other values as well) */ + if (ret != GST_FLOW_NOT_LINKED) + goto done; + } + } + /* if we get here, all other pads were unlinked and we return + * NOT_LINKED then */ + } + +done: + return ret; +} + +static GstPad * +create_pad_for_stream (GstTSDemux * demux, MpegTSBaseStream * bstream, + MpegTSBaseProgram * program) +{ + TSDemuxStream *stream = (TSDemuxStream *) bstream; + gchar *name = NULL; + GstCaps *caps = NULL; + GstPadTemplate *template = NULL; + guint8 *desc = NULL; + GstPad *pad = NULL; + + + GST_LOG ("Attempting to create pad for stream 0x%04x with stream_type %d", + bstream->pid, bstream->stream_type); + + switch (bstream->stream_type) { + case ST_VIDEO_MPEG1: + case ST_VIDEO_MPEG2: + GST_LOG ("mpeg video"); + template = gst_static_pad_template_get (&video_template); + name = g_strdup_printf ("video_%04x", bstream->pid); + caps = gst_caps_new_simple ("video/mpeg", + "mpegversion", G_TYPE_INT, + bstream->stream_type == ST_VIDEO_MPEG1 ? 1 : 2, "systemstream", + G_TYPE_BOOLEAN, FALSE, NULL); + + break; + case ST_AUDIO_MPEG1: + case ST_AUDIO_MPEG2: + GST_LOG ("mpeg audio"); + template = gst_static_pad_template_get (&audio_template); + name = g_strdup_printf ("audio_%04x", bstream->pid); + caps = + gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 1, + NULL); + break; + case ST_PRIVATE_DATA: + GST_LOG ("private data"); + desc = + mpegts_get_descriptor_from_stream ((MpegTSBaseStream *) stream, + DESC_DVB_AC3); + if (desc) { + GST_LOG ("ac3 audio"); + template = gst_static_pad_template_get (&audio_template); + name = g_strdup_printf ("audio_%04x", bstream->pid); + caps = gst_caps_new_simple ("audio/x-ac3", NULL); + g_free (desc); + break; + } + desc = + mpegts_get_descriptor_from_stream ((MpegTSBaseStream *) stream, + DESC_DVB_ENHANCED_AC3); + if (desc) { + GST_LOG ("ac3 audio"); + template = gst_static_pad_template_get (&audio_template); + name = g_strdup_printf ("audio_%04x", bstream->pid); + caps = gst_caps_new_simple ("audio/x-eac3", NULL); + g_free (desc); + break; + } + desc = + mpegts_get_descriptor_from_stream ((MpegTSBaseStream *) stream, + DESC_DVB_TELETEXT); + if (desc) { + GST_LOG ("teletext"); + template = gst_static_pad_template_get (&private_template); + name = g_strdup_printf ("private_%04x", bstream->pid); + caps = gst_caps_new_simple ("private/teletext", NULL); + g_free (desc); + break; + } + desc = + mpegts_get_descriptor_from_stream ((MpegTSBaseStream *) stream, + DESC_DVB_SUBTITLING); + if (desc) { + GST_LOG ("subtitling"); + template = gst_static_pad_template_get (&private_template); + name = g_strdup_printf ("private_%04x", bstream->pid); + caps = gst_caps_new_simple ("subpicture/x-dvb", NULL); + g_free (desc); + } + /* hack for itv hd (sid 10510, video pid 3401 */ + if (program->program_number == 10510 && bstream->pid == 3401) { + template = gst_static_pad_template_get (&video_template); + name = g_strdup_printf ("video_%04x", bstream->pid); + caps = gst_caps_new_simple ("video/x-h264", NULL); + } + break; + case ST_HDV_AUX_V: + /* We don't expose those streams since they're only helper streams */ + /* template = gst_static_pad_template_get (&private_template); */ + /* name = g_strdup_printf ("private_%04x", bstream->pid); */ + /* caps = gst_caps_new_simple ("hdv/aux-v", NULL); */ + break; + case ST_HDV_AUX_A: + /* We don't expose those streams since they're only helper streams */ + /* template = gst_static_pad_template_get (&private_template); */ + /* name = g_strdup_printf ("private_%04x", bstream->pid); */ + /* caps = gst_caps_new_simple ("hdv/aux-a", NULL); */ + break; + case ST_PRIVATE_SECTIONS: + case ST_MHEG: + case ST_DSMCC: + break; + case ST_AUDIO_AAC: + template = gst_static_pad_template_get (&audio_template); + name = g_strdup_printf ("audio_%04x", bstream->pid); + caps = gst_caps_new_simple ("audio/mpeg", + "mpegversion", G_TYPE_INT, 4, NULL); + break; + case ST_VIDEO_MPEG4: + template = gst_static_pad_template_get (&video_template); + name = g_strdup_printf ("video_%04x", bstream->pid); + caps = gst_caps_new_simple ("video/mpeg", + "mpegversion", G_TYPE_INT, 4, + "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); + break; + case ST_VIDEO_H264: + template = gst_static_pad_template_get (&video_template); + name = g_strdup_printf ("video_%04x", bstream->pid); + caps = gst_caps_new_simple ("video/x-h264", NULL); + break; + case ST_VIDEO_DIRAC: + desc = + mpegts_get_descriptor_from_stream ((MpegTSBaseStream *) stream, + DESC_REGISTRATION); + if (desc) { + if (DESC_LENGTH (desc) >= 4) { + if (DESC_REGISTRATION_format_identifier (desc) == 0x64726163) { + GST_LOG ("dirac"); + /* dirac in hex */ + template = gst_static_pad_template_get (&video_template); + name = g_strdup_printf ("video_%04x", bstream->pid); + caps = gst_caps_new_simple ("video/x-dirac", NULL); + } + } + g_free (desc); + } + break; + case ST_PRIVATE_EA: /* Try to detect a VC1 stream */ + { + desc = + mpegts_get_descriptor_from_stream ((MpegTSBaseStream *) stream, + DESC_REGISTRATION); + if (desc) { + if (DESC_LENGTH (desc) >= 4) { + if (DESC_REGISTRATION_format_identifier (desc) == DRF_ID_VC1) { + GST_WARNING ("0xea private stream type found but no descriptor " + "for VC1. Assuming plain VC1."); + template = gst_static_pad_template_get (&video_template); + name = g_strdup_printf ("video_%04x", bstream->pid); + caps = gst_caps_new_simple ("video/x-wmv", + "wmvversion", G_TYPE_INT, 3, + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('W', 'V', 'C', '1'), + NULL); + } + } + g_free (desc); + } + break; + } + case ST_BD_AUDIO_AC3: + { + /* REGISTRATION DRF_ID_HDMV */ + desc = mpegts_get_descriptor_from_program (program, DESC_REGISTRATION); + if (desc) { + if (DESC_REGISTRATION_format_identifier (desc) == DRF_ID_HDMV) { + template = gst_static_pad_template_get (&audio_template); + name = g_strdup_printf ("audio_%04x", bstream->pid); + caps = gst_caps_new_simple ("audio/x-eac3", NULL); + } + g_free (desc); + } + if (template) + break; + + /* DVB_ENHANCED_AC3 */ + desc = + mpegts_get_descriptor_from_stream ((MpegTSBaseStream *) stream, + DESC_DVB_ENHANCED_AC3); + if (desc) { + template = gst_static_pad_template_get (&audio_template); + name = g_strdup_printf ("audio_%04x", bstream->pid); + caps = gst_caps_new_simple ("audio/x-eac3", NULL); + g_free (desc); + break; + } + + /* DVB_AC3 */ + desc = + mpegts_get_descriptor_from_stream ((MpegTSBaseStream *) stream, + DESC_DVB_AC3); + if (!desc) + GST_WARNING ("AC3 stream type found but no corresponding " + "descriptor to differentiate between AC3 and EAC3. " + "Assuming plain AC3."); + else + g_free (desc); + template = gst_static_pad_template_get (&audio_template); + name = g_strdup_printf ("audio_%04x", bstream->pid); + caps = gst_caps_new_simple ("audio/x-ac3", NULL); + break; + } + case ST_BD_AUDIO_EAC3: + template = gst_static_pad_template_get (&audio_template); + name = g_strdup_printf ("audio_%04x", bstream->pid); + caps = gst_caps_new_simple ("audio/x-eac3", NULL); + break; + case ST_PS_AUDIO_DTS: + template = gst_static_pad_template_get (&audio_template); + name = g_strdup_printf ("audio_%04x", bstream->pid); + caps = gst_caps_new_simple ("audio/x-dts", NULL); + break; + case ST_PS_AUDIO_LPCM: + template = gst_static_pad_template_get (&audio_template); + name = g_strdup_printf ("audio_%04x", bstream->pid); + caps = gst_caps_new_simple ("audio/x-lpcm", NULL); + break; + case ST_BD_AUDIO_LPCM: + template = gst_static_pad_template_get (&audio_template); + name = g_strdup_printf ("audio_%04x", bstream->pid); + caps = gst_caps_new_simple ("audio/x-private-ts-lpcm", NULL); + break; + case ST_PS_DVD_SUBPICTURE: + template = gst_static_pad_template_get (&subpicture_template); + name = g_strdup_printf ("subpicture_%04x", bstream->pid); + caps = gst_caps_new_simple ("video/x-dvd-subpicture", NULL); + break; + case ST_BD_PGS_SUBPICTURE: + template = gst_static_pad_template_get (&subpicture_template); + name = g_strdup_printf ("subpicture_%04x", bstream->pid); + caps = gst_caps_new_simple ("subpicture/x-pgs", NULL); + break; + } + if (template && name && caps) { + GST_LOG ("stream:%p creating pad with name %s and caps %s", stream, name, + gst_caps_to_string (caps)); + pad = gst_pad_new_from_template (template, name); + gst_pad_use_fixed_caps (pad); + gst_pad_set_caps (pad, caps); + gst_pad_set_query_type_function (pad, gst_ts_demux_srcpad_query_types); + gst_pad_set_query_function (pad, gst_ts_demux_srcpad_query); + gst_caps_unref (caps); + } + + g_free (name); + + return pad; +} + +static void +gst_ts_demux_stream_added (MpegTSBase * base, MpegTSBaseStream * bstream, + MpegTSBaseProgram * program) +{ + GstTSDemux *tsdemux = (GstTSDemux *) base; + TSDemuxStream *stream = (TSDemuxStream *) bstream; + + if (!stream->pad) { + /* Create the pad */ + if (bstream->stream_type != 0xff) + stream->pad = create_pad_for_stream (tsdemux, bstream, program); + stream->pts = GST_CLOCK_TIME_NONE; + } + stream->flow_return = GST_FLOW_OK; +} + +static void +gst_ts_demux_stream_removed (MpegTSBase * base, MpegTSBaseStream * bstream) +{ + TSDemuxStream *stream = (TSDemuxStream *) bstream; + if (stream) { + if (stream->pad) { + /* Unref the pad, clear it */ + gst_object_unref (stream->pad); + stream->pad = NULL; + } + stream->flow_return = GST_FLOW_NOT_LINKED; + } +} + +static void +activate_pad_for_stream (GstTSDemux * tsdemux, TSDemuxStream * stream) +{ + if (stream->pad) { + GST_DEBUG_OBJECT (tsdemux, "Activating pad %s:%s for stream %p", + GST_DEBUG_PAD_NAME (stream->pad), stream); + gst_pad_set_active (stream->pad, TRUE); + gst_element_add_pad ((GstElement *) tsdemux, stream->pad); + GST_DEBUG_OBJECT (stream->pad, "done adding pad"); + } else + GST_WARNING_OBJECT (tsdemux, "stream %p has no pad", stream); +} + +static void +gst_ts_demux_program_started (MpegTSBase * base, MpegTSBaseProgram * program) +{ + GstTSDemux *demux = GST_TS_DEMUX (base); + + if (demux->program_number == -1 || + demux->program_number == program->program_number) { + guint i; + + GST_LOG ("program %d started", program->program_number); + demux->program_number = program->program_number; + demux->program = program; + + /* Activate all stream pads, the pads will already have been created */ + + /* FIXME : Actually, we don't want to activate *ALL* streams ! + * For example, we don't want to expose HDV AUX private streams, we will just + * be using them directly for seeking and metadata. */ + if (base->mode != BASE_MODE_SCANNING) + for (i = 0; i < 0x2000; i++) + if (program->streams[i]) + activate_pad_for_stream (demux, + (TSDemuxStream *) program->streams[i]); + + /* Inform scanner we have got our program */ + demux->current_program_number = program->program_number; + } +} + +static void +gst_ts_demux_program_stopped (MpegTSBase * base, MpegTSBaseProgram * program) +{ + guint i; + GstTSDemux *demux = GST_TS_DEMUX (base); + TSDemuxStream *localstream = NULL; + + GST_LOG ("program %d stopped", program->program_number); + + if (program != demux->program) + return; + + for (i = 0; i < 0x2000; i++) { + if (demux->program->streams[i]) { + localstream = (TSDemuxStream *) program->streams[i]; + if (localstream->pad) { + GST_DEBUG ("HAVE PAD %s:%s", GST_DEBUG_PAD_NAME (localstream->pad)); + if (gst_pad_is_active (localstream->pad)) + gst_element_remove_pad (GST_ELEMENT_CAST (demux), localstream->pad); + else + gst_object_unref (localstream->pad); + localstream->pad = NULL; + } + } + } + demux->program = NULL; + demux->program_number = -1; +} + +static gboolean +process_section (MpegTSBase * base) +{ + GstTSDemux *demux = GST_TS_DEMUX (base); + gboolean based; + gboolean done = FALSE; + MpegTSPacketizerPacket packet; + MpegTSPacketizerPacketReturn pret; + + while ((!done) + && ((pret = + mpegts_packetizer_next_packet (base->packetizer, + &packet)) != PACKET_NEED_MORE)) { + if (G_UNLIKELY (pret == PACKET_BAD)) + /* bad header, skip the packet */ + goto next; + + /* base PSI data */ + if (packet.payload != NULL && mpegts_base_is_psi (base, &packet)) { + MpegTSPacketizerSection section; + + based = + mpegts_packetizer_push_section (base->packetizer, &packet, §ion); + if (G_UNLIKELY (!based)) + /* bad section data */ + goto next; + + if (G_LIKELY (section.complete)) { + /* section complete */ + GST_DEBUG ("Section Complete"); + based = mpegts_base_handle_psi (base, §ion); + gst_buffer_unref (section.buffer); + if (G_UNLIKELY (!based)) + /* bad PSI table */ + goto next; + + } + + if (demux->program != NULL) { + GST_DEBUG ("Got Program"); + done = TRUE; + } + } + next: + mpegts_packetizer_clear_packet (base->packetizer, &packet); + } + return done; +} + + +static GstFlowReturn +find_timestamps (MpegTSBase * base, guint64 initoff, guint64 * offset) +{ + + GstFlowReturn ret = GST_FLOW_OK; + GstBuffer *buf; + gboolean done = FALSE; + GstFormat format = GST_FORMAT_BYTES; + gint64 total_bytes; + guint64 scan_offset; + guint i = 0; + GstClockTime initial, final; + GstTSDemux *demux = GST_TS_DEMUX (base); + + GST_DEBUG ("Scanning for timestamps"); + + /* Flush what remained from before */ + mpegts_packetizer_clear (base->packetizer); + + /* Start scanning from know PAT offset */ + while (!done) { + ret = + gst_pad_pull_range (base->sinkpad, i * 50 * MPEGTS_MAX_PACKETSIZE, + 50 * MPEGTS_MAX_PACKETSIZE, &buf); + if (ret != GST_FLOW_OK) + goto beach; + mpegts_packetizer_push (base->packetizer, buf); + done = process_section (base); + i++; + } + mpegts_packetizer_clear (base->packetizer); + done = FALSE; + i = 1; + + + *offset = base->seek_offset; + + /* Search for the first PCRs */ + ret = process_pcr (base, base->first_pat_offset, &initial, 10, TRUE); + mpegts_packetizer_clear (base->packetizer); + /* Remove current program so we ensure looking for a PAT when scanning the + * for the final PCR */ + mpegts_base_remove_program (base, demux->current_program_number); + + if (ret != GST_FLOW_OK) { + GST_WARNING ("Problem getting initial PCRs"); + goto beach; + } + + /* Find end position */ + if (G_UNLIKELY (!gst_pad_query_peer_duration (base->sinkpad, &format, + &total_bytes) || format != GST_FORMAT_BYTES)) { + GST_WARNING_OBJECT (base, "Couldn't get upstream size in bytes"); + ret = GST_FLOW_ERROR; + mpegts_packetizer_clear (base->packetizer); + return ret; + } + GST_DEBUG ("Upstream is %" G_GINT64_FORMAT " bytes", total_bytes); + + scan_offset = total_bytes - 4000 * MPEGTS_MAX_PACKETSIZE; + + GST_DEBUG ("Scanning for last sync point between:%" G_GINT64_FORMAT + " and the end:%" G_GINT64_FORMAT, scan_offset, total_bytes); + while ((!done) && (scan_offset < total_bytes)) { + ret = + gst_pad_pull_range (base->sinkpad, + scan_offset, 50 * MPEGTS_MAX_PACKETSIZE, &buf); + if (ret != GST_FLOW_OK) + goto beach; + + mpegts_packetizer_push (base->packetizer, buf); + done = process_section (base); + scan_offset += 50 * MPEGTS_MAX_PACKETSIZE; + } + + mpegts_packetizer_clear (base->packetizer); + + GST_DEBUG ("Searching PCR"); + ret = + process_pcr (base, total_bytes - 4000 * MPEGTS_MAX_PACKETSIZE, &final, 10, + FALSE); + + if (ret != GST_FLOW_OK) { + GST_DEBUG ("Problem getting last PCRs"); + goto beach; + } + + demux->duration = final - initial; + + GST_DEBUG ("Done, duration:%" GST_TIME_FORMAT, + GST_TIME_ARGS (demux->duration)); + +beach: + + mpegts_packetizer_clear (base->packetizer); + /* Remove current program */ + mpegts_base_remove_program (base, demux->current_program_number); + + return ret; +} + +static GstFlowReturn +process_pcr (MpegTSBase * base, guint64 initoff, GstClockTime * pcr, + guint numpcr, gboolean isinitial) +{ + GstTSDemux *demux = GST_TS_DEMUX (base); + GstFlowReturn ret = GST_FLOW_OK; + MpegTSBaseProgram *program; + GstBuffer *buf; + guint nbpcr, i = 0; + guint32 pcrmask, pcrpattern; + guint64 pcrs[50]; + guint64 pcroffs[50]; + GstByteReader br; + + GST_DEBUG ("initoff:%" G_GUINT64_FORMAT ", numpcr:%d, isinitial:%d", + initoff, numpcr, isinitial); + + /* Get the program */ + program = demux->program; + if (G_UNLIKELY (program == NULL)) + return GST_FLOW_ERROR; + + /* First find the first X PCR */ + nbpcr = 0; + /* Mask/pattern is PID:PCR_PID, AFC&0x02 */ + /* sync_byte (0x47) : 8bits => 0xff + * transport_error_indicator : 1bit ACTIVATE + * payload_unit_start_indicator : 1bit IGNORE + * transport_priority : 1bit IGNORE + * PID : 13bit => 0x9f 0xff + * transport_scrambling_control : 2bit + * adaptation_field_control : 2bit + * continuity_counter : 4bit => 0x30 + */ + pcrmask = 0xff9fff20; + pcrpattern = 0x47000020 | ((program->pcr_pid & 0x1fff) << 8); + + for (i = 0; (i < 20) && (nbpcr < numpcr); i++) { + guint offset, size; + + ret = + gst_pad_pull_range (base->sinkpad, + initoff + i * 500 * base->packetsize, 500 * base->packetsize, &buf); + + if (G_UNLIKELY (ret != GST_FLOW_OK)) + goto beach; + + gst_byte_reader_init_from_buffer (&br, buf); + + offset = 0; + size = GST_BUFFER_SIZE (buf); + + /* FIXME : We should jump to next packet instead of scanning everything */ + while ((size >= br.size) && (nbpcr < numpcr) + && (offset = + gst_byte_reader_masked_scan_uint32 (&br, pcrmask, pcrpattern, + offset, size)) != -1) { + /* Potential PCR */ +/* GST_DEBUG ("offset %" G_GUINT64_FORMAT, GST_BUFFER_OFFSET (buf) + offset); + GST_MEMDUMP ("something", GST_BUFFER_DATA (buf) + offset, 16);*/ + if ((*(br.data + offset + 5)) & 0x10) { + guint16 pcr2; + guint64 pcr, pcr_ext; + + pcr = ((guint64) GST_READ_UINT32_BE (br.data + offset + 6)) << 1; + pcr2 = GST_READ_UINT16_BE (br.data + offset + 10); + pcr |= (pcr2 & 0x8000) >> 15; + pcr_ext = (pcr2 & 0x01ff); + pcr = pcr * 300 + pcr_ext % 300; + + GST_DEBUG ("Found PCR %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT + " at offset %" G_GUINT64_FORMAT, pcr, + GST_TIME_ARGS (PCRTIME_TO_GSTTIME (pcr)), + GST_BUFFER_OFFSET (buf) + offset); + pcrs[nbpcr] = pcr; + pcroffs[nbpcr] = GST_BUFFER_OFFSET (buf) + offset; + /* Safeguard against bogus PCR (by detecting if it's the same as the + * previous one or wheter the difference with the previous one is + * greater than 10mins */ + if (nbpcr > 1) { + if (pcrs[nbpcr] == pcrs[nbpcr - 1]) { + GST_WARNING ("Found same PCR at different offset"); + } else if ((pcrs[nbpcr] - pcrs[nbpcr - 1]) > + (guint64) 10 * 60 * 27000000) { + GST_WARNING ("PCR differs with previous PCR by more than 10 mins"); + } else + nbpcr += 1; + } else + nbpcr += 1; + } + /* Move offset forward by 1 */ + size -= offset + 1; + offset += 1; + + } + } + +beach: + GST_DEBUG ("Found %d PCR", nbpcr); + if (nbpcr) { + if (isinitial) + *pcr = PCRTIME_TO_GSTTIME (pcrs[0]); + else + *pcr = PCRTIME_TO_GSTTIME (pcrs[nbpcr - 1]); + GST_DEBUG ("pcrdiff:%" GST_TIME_FORMAT " offsetdiff %" G_GUINT64_FORMAT, + GST_TIME_ARGS (PCRTIME_TO_GSTTIME (pcrs[nbpcr - 1] - pcrs[0])), + pcroffs[nbpcr - 1] - pcroffs[0]); + GST_DEBUG ("Estimated bitrate %" G_GUINT64_FORMAT, + gst_util_uint64_scale (GST_SECOND, pcroffs[nbpcr - 1] - pcroffs[0], + PCRTIME_TO_GSTTIME (pcrs[nbpcr - 1] - pcrs[0]))); + GST_DEBUG ("Average PCR interval %" G_GUINT64_FORMAT, + (pcroffs[nbpcr - 1] - pcroffs[0]) / nbpcr); + } + /* Swallow any errors if it happened during the end scanning */ + if (!isinitial) + ret = GST_FLOW_OK; + return ret; +} + + + + +static inline void +gst_ts_demux_record_pcr (GstTSDemux * demux, TSDemuxStream * stream, + guint64 pcr, guint64 offset) +{ + MpegTSBaseStream *bs = (MpegTSBaseStream *) stream; + + GST_LOG ("pid 0x%04x pcr:%" GST_TIME_FORMAT " at offset %" + G_GUINT64_FORMAT, bs->pid, + GST_TIME_ARGS (PCRTIME_TO_GSTTIME (pcr)), offset); + + if (G_UNLIKELY (demux->emit_statistics)) { + GstStructure *st; + st = gst_structure_id_empty_new (QUARK_TSDEMUX); + gst_structure_id_set (st, + QUARK_PID, G_TYPE_UINT, bs->pid, + QUARK_OFFSET, G_TYPE_UINT64, offset, QUARK_PCR, G_TYPE_UINT64, pcr, + NULL); + gst_element_post_message (GST_ELEMENT_CAST (demux), + gst_message_new_element (GST_OBJECT (demux), st)); + } +} + +static inline void +gst_ts_demux_record_opcr (GstTSDemux * demux, TSDemuxStream * stream, + guint64 opcr, guint64 offset) +{ + MpegTSBaseStream *bs = (MpegTSBaseStream *) stream; + + GST_LOG ("pid 0x%04x opcr:%" GST_TIME_FORMAT " at offset %" + G_GUINT64_FORMAT, bs->pid, + GST_TIME_ARGS (PCRTIME_TO_GSTTIME (opcr)), offset); + + if (G_UNLIKELY (demux->emit_statistics)) { + GstStructure *st; + st = gst_structure_id_empty_new (QUARK_TSDEMUX); + gst_structure_id_set (st, + QUARK_PID, G_TYPE_UINT, bs->pid, + QUARK_OFFSET, G_TYPE_UINT64, offset, + QUARK_OPCR, G_TYPE_UINT64, opcr, NULL); + gst_element_post_message (GST_ELEMENT_CAST (demux), + gst_message_new_element (GST_OBJECT (demux), st)); + } +} + +static inline void +gst_ts_demux_record_pts (GstTSDemux * demux, TSDemuxStream * stream, + guint64 pts, guint64 offset) +{ + MpegTSBaseStream *bs = (MpegTSBaseStream *) stream; + + GST_LOG ("pid 0x%04x pts:%" GST_TIME_FORMAT " at offset %" + G_GUINT64_FORMAT, bs->pid, + GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (pts)), offset); + + if (G_UNLIKELY (demux->emit_statistics)) { + GstStructure *st; + st = gst_structure_id_empty_new (QUARK_TSDEMUX); + gst_structure_id_set (st, + QUARK_PID, G_TYPE_UINT, bs->pid, + QUARK_OFFSET, G_TYPE_UINT64, offset, QUARK_PTS, G_TYPE_UINT64, pts, + NULL); + gst_element_post_message (GST_ELEMENT_CAST (demux), + gst_message_new_element (GST_OBJECT (demux), st)); + } +} + +static inline void +gst_ts_demux_record_dts (GstTSDemux * demux, TSDemuxStream * stream, + guint64 dts, guint64 offset) +{ + MpegTSBaseStream *bs = (MpegTSBaseStream *) stream; + + GST_LOG ("pid 0x%04x dts:%" GST_TIME_FORMAT " at offset %" + G_GUINT64_FORMAT, bs->pid, + GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (dts)), offset); + + if (G_UNLIKELY (demux->emit_statistics)) { + GstStructure *st; + st = gst_structure_id_empty_new (QUARK_TSDEMUX); + gst_structure_id_set (st, + QUARK_PID, G_TYPE_UINT, bs->pid, + QUARK_OFFSET, G_TYPE_UINT64, offset, QUARK_DTS, G_TYPE_UINT64, dts, + NULL); + gst_element_post_message (GST_ELEMENT_CAST (demux), + gst_message_new_element (GST_OBJECT (demux), st)); + } +} + +static GstFlowReturn +gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream) +{ + GstFlowReturn res = GST_FLOW_OK; + guint8 *data; + guint32 length; + guint32 psc_stid; + guint8 stid; + guint16 pesplength; + guint8 PES_header_data_length = 0; + + data = GST_BUFFER_DATA (stream->pendingbuffers[0]); + length = GST_BUFFER_SIZE (stream->pendingbuffers[0]); + + GST_MEMDUMP ("Header buffer", data, MIN (length, 32)); + + /* packet_start_code_prefix 24 + * stream_id 8*/ + psc_stid = GST_READ_UINT32_BE (data); + data += 4; + length -= 4; + if (G_UNLIKELY ((psc_stid & 0xffffff00) != 0x00000100)) { + GST_WARNING ("WRONG PACKET START CODE !"); + goto discont; + } + stid = psc_stid & 0x000000ff; + GST_LOG ("stream_id:0x%02x", stid); + + /* PES_packet_length 16 */ + /* FIXME : store the expected pes length somewhere ? */ + pesplength = GST_READ_UINT16_BE (data); + data += 2; + length -= 2; + GST_LOG ("PES_packet_length:%d", pesplength); + + /* FIXME : Only parse header on streams which require it (see table 2-21) */ + if (stid != 0xbf) { + guint8 p1, p2; + guint64 pts, dts; + p1 = *data++; + p2 = *data++; + PES_header_data_length = *data++ + 3; + length -= 3; + + GST_LOG ("0x%02x 0x%02x 0x%02x", p1, p2, PES_header_data_length); + GST_LOG ("PES header data length:%d", PES_header_data_length); + + /* '10' 2 + * PES_scrambling_control 2 + * PES_priority 1 + * data_alignment_indicator 1 + * copyright 1 + * original_or_copy 1 */ + if (G_UNLIKELY ((p1 & 0xc0) != 0x80)) { + GST_WARNING ("p1 >> 6 != 0x2"); + goto discont; + } + + /* PTS_DTS_flags 2 + * ESCR_flag 1 + * ES_rate_flag 1 + * DSM_trick_mode_flag 1 + * additional_copy_info_flag 1 + * PES_CRC_flag 1 + * PES_extension_flag 1*/ + + /* PES_header_data_length 8 */ + if (G_UNLIKELY (length < PES_header_data_length)) { + GST_WARNING ("length < PES_header_data_length"); + goto discont; + } + + /* PTS 32 */ + if ((p2 & 0x80)) { /* PTS */ + READ_TS (data, pts, discont); + gst_ts_demux_record_pts (demux, stream, pts, + GST_BUFFER_OFFSET (stream->pendingbuffers[0])); + length -= 4; + GST_BUFFER_TIMESTAMP (stream->pendingbuffers[0]) = + MPEGTIME_TO_GSTTIME (pts); + + if (!GST_CLOCK_TIME_IS_VALID (stream->pts)) { + stream->pts = GST_BUFFER_TIMESTAMP (stream->pendingbuffers[0]); + } + + } + /* DTS 32 */ + if ((p2 & 0x40)) { /* DTS */ + READ_TS (data, dts, discont); + gst_ts_demux_record_dts (demux, stream, dts, + GST_BUFFER_OFFSET (stream->pendingbuffers[0])); + length -= 4; + } + /* ESCR 48 */ + if ((p2 & 0x20)) { + GST_LOG ("ESCR present"); + data += 6; + length -= 6; + } + /* ES_rate 24 */ + if ((p2 & 0x10)) { + GST_LOG ("ES_rate present"); + data += 3; + length -= 3; + } + /* DSM_trick_mode 8 */ + if ((p2 & 0x08)) { + GST_LOG ("DSM_trick_mode present"); + data += 1; + length -= 1; + } + } + + /* Remove PES headers */ + GST_BUFFER_DATA (stream->pendingbuffers[0]) += 6 + PES_header_data_length; + GST_BUFFER_SIZE (stream->pendingbuffers[0]) -= 6 + PES_header_data_length; + + /* FIXME : responsible for switching to PENDING_PACKET_BUFFER and + * creating the bufferlist */ + if (1) { + /* Append to the buffer list */ + if (G_UNLIKELY (stream->current == NULL)) { + guint8 i; + + /* Create a new bufferlist */ + stream->current = gst_buffer_list_new (); + stream->currentit = gst_buffer_list_iterate (stream->current); + stream->currentlist = NULL; + gst_buffer_list_iterator_add_group (stream->currentit); + + /* Push pending buffers into the list */ + for (i = stream->nbpending; i; i--) + stream->currentlist = + g_list_prepend (stream->currentlist, stream->pendingbuffers[i - 1]); + memset (stream->pendingbuffers, 0, TS_MAX_PENDING_BUFFERS); + stream->nbpending = 0; + } + stream->state = PENDING_PACKET_BUFFER; + } + + return res; + +discont: + stream->state = PENDING_PACKET_DISCONT; + return res; +} + + /* ONLY CALL THIS: + * * WITH packet->payload != NULL + * * WITH pending/current flushed out if beginning of new PES packet + */ +static inline void +gst_ts_demux_queue_data (GstTSDemux * demux, TSDemuxStream * stream, + MpegTSPacketizerPacket * packet) +{ + GstBuffer *buf; + + GST_DEBUG ("state:%d", stream->state); + + buf = packet->buffer; + /* HACK : Instead of creating a new buffer, we just modify the data/size + * of the buffer to point to the payload */ + GST_BUFFER_DATA (buf) = packet->payload; + GST_BUFFER_SIZE (buf) = packet->data_end - packet->payload; + + if (stream->state == PENDING_PACKET_EMPTY) { + if (G_UNLIKELY (!packet->payload_unit_start_indicator)) { + stream->state = PENDING_PACKET_DISCONT; + GST_WARNING ("Didn't get the first packet of this PES"); + } else { + GST_LOG ("EMPTY=>HEADER"); + stream->state = PENDING_PACKET_HEADER; + if (stream->pad) { + GST_DEBUG ("Setting pad caps on buffer %p", buf); + gst_buffer_set_caps (buf, GST_PAD_CAPS (stream->pad)); + } + } + } + + if (stream->state == PENDING_PACKET_HEADER) { + GST_LOG ("HEADER: appending data to array"); + /* Append to the array */ + stream->pendingbuffers[stream->nbpending++] = buf; + + /* parse the header */ + gst_ts_demux_parse_pes_header (demux, stream); + } else if (stream->state == PENDING_PACKET_BUFFER) { + GST_LOG ("BUFFER: appending data to bufferlist"); + stream->currentlist = g_list_prepend (stream->currentlist, buf); + } + + + return; +} + +static GstFlowReturn +gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream) +{ + GstFlowReturn res = GST_FLOW_OK; + MpegTSBaseStream *bs = (MpegTSBaseStream *) stream; + + + guint i; + GstClockTime tinypts = GST_CLOCK_TIME_NONE; + GstClockTime stop = GST_CLOCK_TIME_NONE; + GstEvent *newsegmentevent; + + GST_DEBUG ("stream:%p, pid:0x%04x stream_type:%d state:%d pad:%s:%s", + stream, bs->pid, bs->stream_type, stream->state, + GST_DEBUG_PAD_NAME (stream->pad)); + + if (G_UNLIKELY (stream->current == NULL)) { + GST_LOG ("stream->current == NULL"); + goto beach; + } + + if (G_UNLIKELY (stream->state == PENDING_PACKET_EMPTY)) { + GST_LOG ("EMPTY: returning"); + goto beach; + } + + /* We have a confirmed buffer, let's push it out */ + if (stream->state == PENDING_PACKET_BUFFER) { + GST_LOG ("BUFFER: pushing out pending data"); + stream->currentlist = g_list_reverse (stream->currentlist); + gst_buffer_list_iterator_add_list (stream->currentit, stream->currentlist); + gst_buffer_list_iterator_free (stream->currentit); + + + if (stream->pad) { + + if (demux->need_newsegment) { + + for (i = 0; i < 0x2000; i++) { + + if (demux->program->streams[i]) { + if ((!GST_CLOCK_TIME_IS_VALID (tinypts)) + || (((TSDemuxStream *) demux->program->streams[i])->pts < + tinypts)) + tinypts = ((TSDemuxStream *) demux->program->streams[i])->pts; + } + + + } + + if (GST_CLOCK_TIME_IS_VALID (demux->duration)) + stop = tinypts + demux->duration; + + GST_DEBUG ("Sending newsegment event"); + newsegmentevent = + gst_event_new_new_segment (0, 1.0, GST_FORMAT_TIME, tinypts, stop, + 0); + + push_event ((MpegTSBase *) demux, newsegmentevent); + + demux->need_newsegment = FALSE; + } + + GST_DEBUG_OBJECT (stream->pad, "Pushing buffer list "); + + res = gst_pad_push_list (stream->pad, stream->current); + GST_DEBUG_OBJECT (stream->pad, "Returned %s", gst_flow_get_name (res)); + /* FIXME : combine flow returns */ + res = tsdemux_combine_flows (demux, stream, res); + GST_DEBUG_OBJECT (stream->pad, "combined %s", gst_flow_get_name (res)); + } + } + +beach: + /* Reset everything */ + GST_LOG ("Resetting to EMPTY"); + stream->state = PENDING_PACKET_EMPTY; + + /* for (i = 0; i < stream->nbpending; i++) */ + /* gst_buffer_unref (stream->pendingbuffers[i]); */ + memset (stream->pendingbuffers, 0, TS_MAX_PENDING_BUFFERS); + stream->nbpending = 0; + + stream->current = NULL; + + + + return res; +} + +static GstFlowReturn +gst_ts_demux_handle_packet (GstTSDemux * demux, TSDemuxStream * stream, + MpegTSPacketizerPacket * packet, MpegTSPacketizerSection * section) +{ + GstFlowReturn res = GST_FLOW_OK; + + GST_DEBUG ("buffer:%p, data:%p", GST_BUFFER_DATA (packet->buffer), + packet->data); + GST_LOG ("pid 0x%04x pusi:%d, afc:%d, cont:%d, payload:%p", + packet->pid, + packet->payload_unit_start_indicator, + packet->adaptation_field_control, + packet->continuity_counter, packet->payload); + + if (section) { + GST_DEBUG ("section complete:%d, buffer size %d", + section->complete, GST_BUFFER_SIZE (section->buffer)); + } + + if (G_UNLIKELY (packet->payload_unit_start_indicator)) + /* Flush previous data */ + res = gst_ts_demux_push_pending_data (demux, stream); + + if (packet->adaptation_field_control & 0x2) { + if (packet->afc_flags & MPEGTS_AFC_PCR_FLAG) + gst_ts_demux_record_pcr (demux, stream, packet->pcr, + GST_BUFFER_OFFSET (packet->buffer)); + if (packet->afc_flags & MPEGTS_AFC_OPCR_FLAG) + gst_ts_demux_record_opcr (demux, stream, packet->opcr, + GST_BUFFER_OFFSET (packet->buffer)); + } + + if (packet->payload) + gst_ts_demux_queue_data (demux, stream, packet); + + return res; +} + +static GstFlowReturn +gst_ts_demux_push (MpegTSBase * base, MpegTSPacketizerPacket * packet, + MpegTSPacketizerSection * section) +{ + GstTSDemux *demux = GST_TS_DEMUX_CAST (base); + TSDemuxStream *stream = NULL; + GstFlowReturn res = GST_FLOW_OK; + + if (G_LIKELY (demux->program)) { + stream = (TSDemuxStream *) demux->program->streams[packet->pid]; + + if (stream) { + res = gst_ts_demux_handle_packet (demux, stream, packet, section); + } else if (packet->buffer) + gst_buffer_unref (packet->buffer); + } else { + if (packet->buffer) + gst_buffer_unref (packet->buffer); + } + return res; +} + +gboolean +gst_ts_demux_plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (ts_demux_debug, "tsdemux", 0, + "MPEG transport stream demuxer"); + + return gst_element_register (plugin, "tsdemux", + GST_RANK_SECONDARY, GST_TYPE_TS_DEMUX); +} diff --git a/gst/mpegtsdemux/tsdemux.h b/gst/mpegtsdemux/tsdemux.h new file mode 100644 index 000000000..bfee2df42 --- /dev/null +++ b/gst/mpegtsdemux/tsdemux.h @@ -0,0 +1,78 @@ +/* + * tsdemux - GStreamer MPEG transport stream demuxer + * Copyright (C) 2009 Zaheer Abbas Merali + * 2010 Edward Hervey + * + * Authors: + * Zaheer Abbas Merali <zaheerabbas at merali dot org> + * Edward Hervey <edward.hervey@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef GST_TS_DEMUX_H +#define GST_TS_DEMUX_H + +#include <gst/gst.h> +#include <gst/base/gstbytereader.h> +#include "mpegtsbase.h" +#include "mpegtspacketizer.h" + +G_BEGIN_DECLS +#define GST_TYPE_TS_DEMUX \ + (gst_ts_demux_get_type()) +#define GST_TS_DEMUX(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TS_DEMUX,GstTSDemux)) +#define GST_TS_DEMUX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TS_DEMUX,GstTSDemuxClass)) +#define GST_IS_TS_DEMUX(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TS_DEMUX)) +#define GST_IS_TS_DEMUX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TS_DEMUX)) +#define GST_TS_DEMUX_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_TS_DEMUX, GstTSDemuxClass)) +#define GST_TS_DEMUX_CAST(obj) ((GstTSDemux*) obj) +typedef struct _GstTSDemux GstTSDemux; +typedef struct _GstTSDemuxClass GstTSDemuxClass; + +struct _GstTSDemux +{ + MpegTSBase parent; + + /* the following vars must be protected with the OBJECT_LOCK as they can be + * accessed from the application thread and the streaming thread */ + guint program_number; /* Required program number (ignore:-1) */ + gboolean emit_statistics; + + /*< private >*/ + MpegTSBaseProgram *program; /* Current program */ + guint current_program_number; + gboolean need_newsegment; + GstClockTime duration; /* Total duration */ +}; + +struct _GstTSDemuxClass +{ + MpegTSBaseClass parent_class; +}; + +GType gst_ts_demux_get_type (void); + +gboolean gst_ts_demux_plugin_init (GstPlugin * plugin); + +G_END_DECLS +#endif /* GST_TS_DEMUX_H */ diff --git a/gst/mpegtsmux/mpegtsmux.c b/gst/mpegtsmux/mpegtsmux.c index c185039b1..0ed2403dd 100644 --- a/gst/mpegtsmux/mpegtsmux.c +++ b/gst/mpegtsmux/mpegtsmux.c @@ -712,7 +712,7 @@ mpegtsmux_collected (GstCollectPads * pads, MpegTsMux * mux) } tsmux_stream_add_data (best->stream, GST_BUFFER_DATA (buf), - GST_BUFFER_SIZE (buf), buf, pts, -1); + GST_BUFFER_SIZE (buf), buf, pts, -1, !delta); best->queued_buf = NULL; mux->is_delta = delta; @@ -800,28 +800,15 @@ static void mpegtsmux_release_pad (GstElement * element, GstPad * pad) { MpegTsMux *mux = GST_MPEG_TSMUX (element); - MpegTsPadData *pad_data = NULL; GST_DEBUG_OBJECT (mux, "Pad %" GST_PTR_FORMAT " being released", pad); - /* Get the MpegTsPadData out of the pad */ - GST_OBJECT_LOCK (pad); - pad_data = (MpegTsPadData *) gst_pad_get_element_private (pad); - if (G_LIKELY (pad_data)) { - /* Free codec data reference if any */ - if (pad_data->codec_data) { - GST_DEBUG_OBJECT (element, "releasing codec_data reference"); - gst_buffer_unref (pad_data->codec_data); - pad_data->codec_data = NULL; - } - if (pad_data->prepare_data && pad_data->free_func) { - pad_data->free_func (pad_data->prepare_data); - pad_data->prepare_data = pad_data->free_func = NULL; - } + if (mux->collect) { + gst_collect_pads_remove_pad (mux->collect, pad); } - GST_OBJECT_UNLOCK (pad); - gst_collect_pads_remove_pad (mux->collect, pad); + /* chain up */ + gst_element_remove_pad (element, pad); } static gboolean diff --git a/gst/mpegtsmux/tsmux/tsmuxstream.c b/gst/mpegtsmux/tsmux/tsmuxstream.c index 62c244fb2..f147bfcdb 100644 --- a/gst/mpegtsmux/tsmux/tsmuxstream.c +++ b/gst/mpegtsmux/tsmux/tsmuxstream.c @@ -100,6 +100,8 @@ struct TsMuxStreamBuffer gint64 pts; gint64 dts; + gboolean random_access; + void *user_data; }; @@ -372,6 +374,14 @@ tsmux_stream_initialize_pes_packet (TsMuxStream * stream) stream->pi.flags |= TSMUX_PACKET_FLAG_PES_WRITE_PTS; } + if (stream->buffers) { + TsMuxStreamBuffer *buf = (TsMuxStreamBuffer *) (stream->buffers->data); + if (buf->random_access) { + stream->pi.flags |= TSMUX_PACKET_FLAG_RANDOM_ACCESS; + stream->pi.flags |= TSMUX_PACKET_FLAG_ADAPTATION; + } + } + return TRUE; } @@ -589,6 +599,7 @@ tsmux_stream_write_pes_header (TsMuxStream * stream, guint8 * data) * @user_data: user data to pass to release func * @pts: PTS of access unit in @data * @dts: DTS of access unit in @data + * @random_access: TRUE if random access point (keyframe) * * Submit @len bytes of @data into @stream. @pts and @dts can be set to the * timestamp (against a 90Hz clock) of the first access unit in @data. A @@ -599,7 +610,7 @@ tsmux_stream_write_pes_header (TsMuxStream * stream, guint8 * data) */ void tsmux_stream_add_data (TsMuxStream * stream, guint8 * data, guint len, - void *user_data, gint64 pts, gint64 dts) + void *user_data, gint64 pts, gint64 dts, gboolean random_access) { TsMuxStreamBuffer *packet; @@ -609,6 +620,7 @@ tsmux_stream_add_data (TsMuxStream * stream, guint8 * data, guint len, packet->data = data; packet->size = len; packet->user_data = user_data; + packet->random_access = random_access; packet->pts = pts; packet->dts = dts; diff --git a/gst/mpegtsmux/tsmux/tsmuxstream.h b/gst/mpegtsmux/tsmux/tsmuxstream.h index b384d39a2..47ad842e9 100644 --- a/gst/mpegtsmux/tsmux/tsmuxstream.h +++ b/gst/mpegtsmux/tsmux/tsmuxstream.h @@ -201,7 +201,8 @@ void tsmux_stream_set_buffer_release_func (TsMuxStream *stream, /* Add a new buffer to the pool of available bytes. If pts or dts are not -1, they * indicate the PTS or DTS of the first access unit within this packet */ void tsmux_stream_add_data (TsMuxStream *stream, guint8 *data, guint len, - void *user_data, gint64 pts, gint64 dts); + void *user_data, gint64 pts, gint64 dts, + gboolean random_access); void tsmux_stream_pcr_ref (TsMuxStream *stream); void tsmux_stream_pcr_unref (TsMuxStream *stream); diff --git a/gst/mpegvideoparse/mpegpacketiser.c b/gst/mpegvideoparse/mpegpacketiser.c index b3be15acd..694c4761d 100644 --- a/gst/mpegvideoparse/mpegpacketiser.c +++ b/gst/mpegvideoparse/mpegpacketiser.c @@ -636,9 +636,7 @@ mpeg_util_parse_picture_hdr (MPEGPictureHdr * hdr, guint8 * data, guint8 * end) /* Skip the start code */ data += 4; - hdr->temp_ref = (data[0] << 2) | (data[1] >> 6); hdr->pic_type = (data[1] >> 3) & 0x07; - if (hdr->pic_type == 0 || hdr->pic_type > 4) return FALSE; /* Corrupted picture packet */ diff --git a/gst/mpegvideoparse/mpegpacketiser.h b/gst/mpegvideoparse/mpegpacketiser.h index d82018e08..88b1ca58a 100644 --- a/gst/mpegvideoparse/mpegpacketiser.h +++ b/gst/mpegvideoparse/mpegpacketiser.h @@ -86,7 +86,6 @@ struct MPEGSeqHdr struct MPEGPictureHdr { - guint16 temp_ref; guint8 pic_type; }; diff --git a/gst/mpegvideoparse/mpegvideoparse.c b/gst/mpegvideoparse/mpegvideoparse.c index 6bff3733b..70fdc89af 100644 --- a/gst/mpegvideoparse/mpegvideoparse.c +++ b/gst/mpegvideoparse/mpegvideoparse.c @@ -92,10 +92,6 @@ gst_mpegvideoparse_change_state (GstElement * element, static void mpv_send_pending_segs (MpegVideoParse * mpegvideoparse); static void mpv_clear_pending_segs (MpegVideoParse * mpegvideoparse); -static GstClockTime mpegvideoparse_get_timestamp_from_reference (MPEGSeqHdr * - seq_hdr, GstClockTime ref_ts, gint32 ref); -static GstClockTime mpegvideoparse_get_time_code (guint8 * cur, - MPEGSeqHdr * seq_hdr); static GstElementClass *parent_class = NULL; @@ -167,9 +163,6 @@ mpv_parse_reset (MpegVideoParse * mpegvideoparse) mpegvideoparse->seq_hdr.fps_n = mpegvideoparse->seq_hdr.par_w = 0; mpegvideoparse->seq_hdr.fps_d = mpegvideoparse->seq_hdr.par_h = 1; - mpegvideoparse->ref_ts = GST_CLOCK_TIME_NONE; - mpegvideoparse->base_time_code = GST_CLOCK_TIME_NONE; - mpv_clear_pending_segs (mpegvideoparse); } @@ -411,30 +404,6 @@ picture_type_name (guint8 pct) } #endif /* GST_DISABLE_GST_DEBUG */ -static GstClockTime -mpegvideoparse_get_timestamp_from_reference (MPEGSeqHdr * seq_hdr, - GstClockTime ref_ts, gint32 ref) -{ - - if (ref < 0) { - GstClockTime duration; - - duration = gst_util_uint64_scale_int (ref * GST_SECOND * -1, - seq_hdr->fps_d, seq_hdr->fps_n); - - if (duration > ref_ts) - return ref_ts; - else - return ref_ts - duration; - } - - if (ref == 0) - return ref_ts; - - return ref_ts + gst_util_uint64_scale_int (ref * GST_SECOND, - seq_hdr->fps_d, seq_hdr->fps_n); -} - static gboolean mpegvideoparse_handle_picture (MpegVideoParse * mpegvideoparse, GstBuffer * buf) { @@ -463,43 +432,8 @@ mpegvideoparse_handle_picture (MpegVideoParse * mpegvideoparse, GstBuffer * buf) GST_LOG_OBJECT (mpegvideoparse, "Picture type is %s", picture_type_name (hdr.pic_type)); - - if (GST_BUFFER_TIMESTAMP (buf) == GST_CLOCK_TIME_NONE) { - if (mpegvideoparse->ref_ts != GST_CLOCK_TIME_NONE) { - GST_BUFFER_TIMESTAMP (buf) = - mpegvideoparse_get_timestamp_from_reference - (&mpegvideoparse->seq_hdr, mpegvideoparse->ref_ts, - hdr.temp_ref - mpegvideoparse->temp_ref); - } - } else { - /* we got a timestamp from upstream, use this timestamp as our reference now */ - mpegvideoparse->ref_ts = GST_BUFFER_TIMESTAMP (buf); - mpegvideoparse->temp_ref = hdr.temp_ref; - } - - GST_DEBUG_OBJECT (mpegvideoparse, - "Picture timestamp %" GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); - } else if (cur[0] == MPEG_PACKET_GOP) { - if (GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) { - mpegvideoparse->base_time_code = - mpegvideoparse_get_time_code (cur, - &mpegvideoparse->seq_hdr) - GST_BUFFER_TIMESTAMP (buf); - mpegvideoparse->ref_ts = GST_BUFFER_TIMESTAMP (buf); - mpegvideoparse->temp_ref = 0; - } else { - if (mpegvideoparse->base_time_code == GST_CLOCK_TIME_NONE) { - mpegvideoparse->base_time_code = - mpegvideoparse_get_time_code (cur, &mpegvideoparse->seq_hdr); - mpegvideoparse->ref_ts = 0; - mpegvideoparse->temp_ref = 0; - } else { - mpegvideoparse->ref_ts = - mpegvideoparse_get_time_code (cur, - &mpegvideoparse->seq_hdr) - mpegvideoparse->base_time_code; - mpegvideoparse->temp_ref = 0; - } - } + /* FIXME: Can use the picture type and number of fields to track a + * timestamp */ } cur = mpeg_util_find_start_code (&sync_word, cur, end); } @@ -507,10 +441,11 @@ mpegvideoparse_handle_picture (MpegVideoParse * mpegvideoparse, GstBuffer * buf) return TRUE; } -static GstClockTime -mpegvideoparse_get_time_code (guint8 * cur, MPEGSeqHdr * seq_hdr) +#if 0 +static guint64 +gst_mpegvideoparse_time_code (guchar * gop, MPEGSeqHdr * seq_hdr) { - guint32 data = GST_READ_UINT32_BE (cur + 1); + guint32 data = GST_READ_UINT32_BE (gop); guint64 seconds; guint8 frames; @@ -523,6 +458,7 @@ mpegvideoparse_get_time_code (guint8 * cur, MPEGSeqHdr * seq_hdr) return seconds * GST_SECOND + gst_util_uint64_scale_int (frames * GST_SECOND, seq_hdr->fps_d, seq_hdr->fps_n); } +#endif static void gst_mpegvideoparse_flush (MpegVideoParse * mpegvideoparse) diff --git a/gst/mpegvideoparse/mpegvideoparse.h b/gst/mpegvideoparse/mpegvideoparse.h index fa5cfd46a..b514863ff 100644 --- a/gst/mpegvideoparse/mpegvideoparse.h +++ b/gst/mpegvideoparse/mpegvideoparse.h @@ -49,11 +49,6 @@ struct _MpegVideoParse { gint64 next_offset; gboolean need_discont; - /* Timestamp calculation */ - GstClockTime ref_ts; - guint16 temp_ref; - GstClockTime base_time_code; - /* Info from the Sequence Header */ MPEGSeqHdr seq_hdr; GstBuffer *seq_hdr_buf; diff --git a/gst/mve/gstmvedemux.c b/gst/mve/gstmvedemux.c index e60d88020..a101a9059 100644 --- a/gst/mve/gstmvedemux.c +++ b/gst/mve/gstmvedemux.c @@ -288,14 +288,11 @@ static GstFlowReturn gst_mve_buffer_alloc_for_pad (GstMveDemuxStream * stream, guint32 size, GstBuffer ** buffer) { - GstFlowReturn ret = - gst_pad_alloc_buffer_and_set_caps (stream->pad, stream->offset, - size, stream->caps, buffer); - - if (ret == GST_FLOW_OK) - GST_BUFFER_TIMESTAMP (*buffer) = stream->last_ts; - - return ret; + *buffer = gst_buffer_new_and_alloc (size); + gst_buffer_set_caps (*buffer, stream->caps); + GST_BUFFER_TIMESTAMP (*buffer) = stream->last_ts; + GST_BUFFER_OFFSET (*buffer) = stream->offset; + return GST_FLOW_OK; } static GstFlowReturn diff --git a/gst/mxf/mxfdemux.c b/gst/mxf/mxfdemux.c index 6e1faa0f4..55704b9c0 100644 --- a/gst/mxf/mxfdemux.c +++ b/gst/mxf/mxfdemux.c @@ -611,11 +611,11 @@ gst_mxf_demux_choose_package (GstMXFDemux * demux) for (i = 0; i < demux->preface->content_storage->n_packages; i++) { if (demux->preface->content_storage->packages[i] && - MXF_IS_METADATA_MATERIAL_PACKAGE (demux->preface->content_storage-> - packages[i])) { + MXF_IS_METADATA_MATERIAL_PACKAGE (demux->preface-> + content_storage->packages[i])) { ret = - MXF_METADATA_GENERIC_PACKAGE (demux->preface->content_storage-> - packages[i]); + MXF_METADATA_GENERIC_PACKAGE (demux->preface-> + content_storage->packages[i]); break; } } @@ -775,8 +775,8 @@ gst_mxf_demux_update_essence_tracks (GstMXFDemux * demux) essence_container); if (track->parent.type == MXF_METADATA_TRACK_PICTURE_ESSENCE) { - if (MXF_IS_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR (track->parent. - descriptor[0])) + if (MXF_IS_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR (track-> + parent.descriptor[0])) mxf_ul_to_string (&MXF_METADATA_GENERIC_PICTURE_ESSENCE_DESCRIPTOR (track->parent.descriptor[0])->picture_essence_coding, essence_compression); @@ -785,8 +785,8 @@ gst_mxf_demux_update_essence_tracks (GstMXFDemux * demux) g_strdup_printf ("video/x-mxf-%s-%s", essence_container, essence_compression); } else if (track->parent.type == MXF_METADATA_TRACK_SOUND_ESSENCE) { - if (MXF_IS_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR (track->parent. - descriptor[0])) + if (MXF_IS_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR (track-> + parent.descriptor[0])) mxf_ul_to_string (&MXF_METADATA_GENERIC_SOUND_ESSENCE_DESCRIPTOR (track->parent.descriptor[0])->sound_essence_compression, essence_compression); @@ -795,8 +795,8 @@ gst_mxf_demux_update_essence_tracks (GstMXFDemux * demux) g_strdup_printf ("audio/x-mxf-%s-%s", essence_container, essence_compression); } else if (track->parent.type == MXF_METADATA_TRACK_DATA_ESSENCE) { - if (MXF_IS_METADATA_GENERIC_DATA_ESSENCE_DESCRIPTOR (track->parent. - descriptor[0])) + if (MXF_IS_METADATA_GENERIC_DATA_ESSENCE_DESCRIPTOR (track-> + parent.descriptor[0])) mxf_ul_to_string (&MXF_METADATA_GENERIC_DATA_ESSENCE_DESCRIPTOR (track->parent.descriptor[0])->data_essence_coding, essence_compression); @@ -805,6 +805,7 @@ gst_mxf_demux_update_essence_tracks (GstMXFDemux * demux) g_strdup_printf ("application/x-mxf-%s-%s", essence_container, essence_compression); } else { + name = NULL; g_assert_not_reached (); } @@ -1420,8 +1421,8 @@ gst_mxf_demux_pad_set_component (GstMXFDemux * demux, GstMXFDemuxPad * pad, pad->current_component_index); pad->current_component = - MXF_METADATA_SOURCE_CLIP (sequence->structural_components[pad-> - current_component_index]); + MXF_METADATA_SOURCE_CLIP (sequence-> + structural_components[pad->current_component_index]); if (pad->current_component == NULL) { GST_ERROR_OBJECT (demux, "No such structural component"); return GST_FLOW_ERROR; @@ -1429,8 +1430,8 @@ gst_mxf_demux_pad_set_component (GstMXFDemux * demux, GstMXFDemuxPad * pad, if (!pad->current_component->source_package || !pad->current_component->source_package->top_level - || !MXF_METADATA_GENERIC_PACKAGE (pad->current_component-> - source_package)->tracks) { + || !MXF_METADATA_GENERIC_PACKAGE (pad-> + current_component->source_package)->tracks) { GST_ERROR_OBJECT (demux, "Invalid component"); return GST_FLOW_ERROR; } @@ -2997,8 +2998,8 @@ gst_mxf_demux_pad_set_last_stop (GstMXFDemux * demux, GstMXFDemuxPad * p, for (i = 0; i < p->material_track->parent.sequence->n_structural_components; i++) { clip = - MXF_METADATA_SOURCE_CLIP (p->material_track->parent.sequence-> - structural_components[i]); + MXF_METADATA_SOURCE_CLIP (p->material_track->parent. + sequence->structural_components[i]); if (clip->parent.duration <= 0) break; @@ -3076,8 +3077,8 @@ gst_mxf_demux_seek_push (GstMXFDemux * demux, GstEvent * event) if (format != GST_FORMAT_TIME) goto wrong_format; - flush = ! !(flags & GST_SEEK_FLAG_FLUSH); - keyframe = ! !(flags & GST_SEEK_FLAG_KEY_UNIT); + flush = !!(flags & GST_SEEK_FLAG_FLUSH); + keyframe = !!(flags & GST_SEEK_FLAG_KEY_UNIT); /* Work on a copy until we are sure the seek succeeded. */ memcpy (&seeksegment, &demux->segment, sizeof (GstSegment)); @@ -3209,8 +3210,8 @@ gst_mxf_demux_seek_pull (GstMXFDemux * demux, GstEvent * event) if (rate <= 0.0) goto wrong_rate; - flush = ! !(flags & GST_SEEK_FLAG_FLUSH); - keyframe = ! !(flags & GST_SEEK_FLAG_KEY_UNIT); + flush = !!(flags & GST_SEEK_FLAG_FLUSH); + keyframe = !!(flags & GST_SEEK_FLAG_KEY_UNIT); if (flush) { GstEvent *e; diff --git a/gst/qtmux/atoms.c b/gst/qtmux/atoms.c index 2fcb45f2b..bdba5bc5a 100644 --- a/gst/qtmux/atoms.c +++ b/gst/qtmux/atoms.c @@ -538,6 +538,7 @@ atom_ctts_init (AtomCTTS * ctts) atom_full_init (&ctts->header, FOURCC_ctts, 0, 0, 0, flags); atom_array_init (&ctts->entries, 128); + ctts->do_pts = FALSE; } static AtomCTTS * @@ -613,7 +614,7 @@ atom_co64_init (AtomSTCO64 * co64) { guint8 flags[3] = { 0, 0, 0 }; - atom_full_init (&co64->header, FOURCC_co64, 0, 0, 0, flags); + atom_full_init (&co64->header, FOURCC_stco, 0, 0, 0, flags); atom_array_init (&co64->entries, 256); } @@ -2019,7 +2020,7 @@ atom_stbl_copy_data (AtomSTBL * stbl, guint8 ** buffer, guint64 * size, if (!atom_stsz_copy_data (&stbl->stsz, buffer, size, offset)) { return 0; } - if (stbl->ctts) { + if (stbl->ctts && stbl->ctts->do_pts) { if (!atom_ctts_copy_data (stbl->ctts, buffer, size, offset)) { return 0; } @@ -2520,6 +2521,8 @@ static void atom_stco64_add_entry (AtomSTCO64 * stco64, guint64 entry) { atom_array_append (&stco64->entries, entry, 256); + if (entry > G_MAXUINT32) + stco64->header.header.type = FOURCC_co64; } static void @@ -2551,6 +2554,8 @@ atom_ctts_add_entry (AtomCTTS * ctts, guint32 nsamples, guint32 offset) nentry.samplecount = nsamples; nentry.sampleoffset = offset; atom_array_append (&ctts->entries, nentry, 256); + if (offset != 0) + ctts->do_pts = TRUE; } else { entry->samplecount += nsamples; } @@ -2567,8 +2572,7 @@ atom_stbl_add_ctts_entry (AtomSTBL * stbl, guint32 nsamples, guint32 offset) void atom_stbl_add_samples (AtomSTBL * stbl, guint32 nsamples, guint32 delta, - guint32 size, guint64 chunk_offset, gboolean sync, - gboolean do_pts, gint64 pts_offset) + guint32 size, guint64 chunk_offset, gboolean sync, gint64 pts_offset) { atom_stts_add_entry (&stbl->stts, nsamples, delta); atom_stsz_add_entry (&stbl->stsz, nsamples, size); @@ -2577,18 +2581,17 @@ atom_stbl_add_samples (AtomSTBL * stbl, guint32 nsamples, guint32 delta, atom_stco64_get_entry_count (&stbl->stco64), nsamples); if (sync) atom_stbl_add_stss_entry (stbl); - if (do_pts) - atom_stbl_add_ctts_entry (stbl, nsamples, pts_offset); + /* always store to arrange for consistent content */ + atom_stbl_add_ctts_entry (stbl, nsamples, pts_offset); } void atom_trak_add_samples (AtomTRAK * trak, guint32 nsamples, guint32 delta, - guint32 size, guint64 chunk_offset, gboolean sync, - gboolean do_pts, gint64 pts_offset) + guint32 size, guint64 chunk_offset, gboolean sync, gint64 pts_offset) { AtomSTBL *stbl = &trak->mdia.minf.stbl; atom_stbl_add_samples (stbl, nsamples, delta, size, chunk_offset, sync, - do_pts, pts_offset); + pts_offset); } /* trak and moov molding */ @@ -2708,41 +2711,6 @@ atom_moov_update_duration (AtomMOOV * moov) moov->mvex.mehd.fragment_duration = duration; } -static void -atom_set_type (Atom * atom, guint32 fourcc) -{ - atom->type = fourcc; -} - -static void -atom_stbl_set_64bits (AtomSTBL * stbl, gboolean use) -{ - if (use) { - atom_set_type (&stbl->stco64.header.header, FOURCC_co64); - } else { - atom_set_type (&stbl->stco64.header.header, FOURCC_stco); - } -} - -static void -atom_trak_set_64bits (AtomTRAK * trak, gboolean use) -{ - atom_stbl_set_64bits (&trak->mdia.minf.stbl, use); -} - -void -atom_moov_set_64bits (AtomMOOV * moov, gboolean large_file) -{ - GList *traks = moov->traks; - - while (traks) { - AtomTRAK *trak = (AtomTRAK *) traks->data; - - atom_trak_set_64bits (trak, large_file); - traks = g_list_next (traks); - } -} - void atom_moov_set_fragmented (AtomMOOV * moov, gboolean fragmented) { @@ -3626,18 +3594,17 @@ atom_sdtp_add_samples (AtomSDTP * sdtp, guint8 val) static void atom_trun_add_samples (AtomTRUN * trun, guint32 delta, guint32 size, - guint32 flags, gboolean do_pts, gint64 pts_offset) + guint32 flags, gint64 pts_offset) { TRUNSampleEntry nentry; - if (do_pts) { + if (pts_offset != 0) trun->header.flags[1] |= TR_COMPOSITION_TIME_OFFSETS; - } nentry.sample_duration = delta; nentry.sample_size = size; nentry.sample_flags = flags; - nentry.sample_composition_time_offset = do_pts ? pts_offset : 0; + nentry.sample_composition_time_offset = pts_offset; atom_array_append (&trun->entries, nentry, 256); trun->sample_count++; } @@ -3670,7 +3637,7 @@ atom_traf_add_trun (AtomTRAF * traf, AtomTRUN * trun) void atom_traf_add_samples (AtomTRAF * traf, guint32 delta, guint32 size, - gboolean sync, gboolean do_pts, gint64 pts_offset, gboolean sdtp_sync) + gboolean sync, gint64 pts_offset, gboolean sdtp_sync) { AtomTRUN *trun; guint32 flags; @@ -3716,8 +3683,7 @@ atom_traf_add_samples (AtomTRAF * traf, guint32 delta, guint32 size, } } - atom_trun_add_samples (traf->truns->data, delta, size, flags, do_pts, - pts_offset); + atom_trun_add_samples (traf->truns->data, delta, size, flags, pts_offset); if (traf->sdtps) atom_sdtp_add_samples (traf->sdtps->data, 0x10 | ((flags & 0xff) >> 4)); diff --git a/gst/qtmux/atoms.h b/gst/qtmux/atoms.h index d074df429..d1241184d 100644 --- a/gst/qtmux/atoms.h +++ b/gst/qtmux/atoms.h @@ -479,6 +479,7 @@ typedef struct _AtomCTTS /* also entry count here */ ATOM_ARRAY (CTTSEntry) entries; + gboolean do_pts; } AtomCTTS; typedef struct _AtomSTBL @@ -806,7 +807,7 @@ void atom_ftyp_free (AtomFTYP *ftyp); AtomTRAK* atom_trak_new (AtomsContext *context); void atom_trak_add_samples (AtomTRAK * trak, guint32 nsamples, guint32 delta, guint32 size, guint64 chunk_offset, gboolean sync, - gboolean do_pts, gint64 pts_offset); + gint64 pts_offset); void atom_trak_add_elst_entry (AtomTRAK * trak, guint32 duration, guint32 media_time, guint32 rate); guint32 atom_trak_get_timescale (AtomTRAK *trak); @@ -814,14 +815,13 @@ guint32 atom_trak_get_id (AtomTRAK * trak); void atom_stbl_add_samples (AtomSTBL * stbl, guint32 nsamples, guint32 delta, guint32 size, guint64 chunk_offset, gboolean sync, - gboolean do_pts, gint64 pts_offset); + gint64 pts_offset); AtomMOOV* atom_moov_new (AtomsContext *context); void atom_moov_free (AtomMOOV *moov); guint64 atom_moov_copy_data (AtomMOOV *atom, guint8 **buffer, guint64 *size, guint64* offset); void atom_moov_update_timescale (AtomMOOV *moov, guint32 timescale); void atom_moov_update_duration (AtomMOOV *moov); -void atom_moov_set_64bits (AtomMOOV *moov, gboolean large_file); void atom_moov_set_fragmented (AtomMOOV *moov, gboolean fragmented); void atom_moov_chunks_add_offset (AtomMOOV *moov, guint32 offset); void atom_moov_add_trak (AtomMOOV *moov, AtomTRAK *trak); @@ -851,8 +851,7 @@ guint64 atom_moof_copy_data (AtomMOOF *moof, guint8 **buffer, guint64 AtomTRAF * atom_traf_new (AtomsContext * context, guint32 track_ID); void atom_traf_free (AtomTRAF * traf); void atom_traf_add_samples (AtomTRAF * traf, guint32 delta, - guint32 size, gboolean sync, - gboolean do_pts, gint64 pts_offset, + guint32 size, gboolean sync, gint64 pts_offset, gboolean sdtp_sync); guint32 atom_traf_get_sample_num (AtomTRAF * traf); void atom_moof_add_traf (AtomMOOF *moof, AtomTRAF *traf); diff --git a/gst/qtmux/atomsrecovery.c b/gst/qtmux/atomsrecovery.c index c9684b1f3..1f5a287d1 100644 --- a/gst/qtmux/atomsrecovery.c +++ b/gst/qtmux/atomsrecovery.c @@ -761,7 +761,7 @@ trak_recov_data_add_sample (TrakRecovData * trak, TrakBufferEntryInfo * b) { trak->duration += b->nsamples * b->delta; atom_stbl_add_samples (&trak->stbl, b->nsamples, b->delta, b->size, - b->chunk_offset, b->sync, b->do_pts, b->pts_offset); + b->chunk_offset, b->sync, b->pts_offset); } /** diff --git a/gst/qtmux/gstqtmux.c b/gst/qtmux/gstqtmux.c index 5ef009a7c..1477db7c8 100644 --- a/gst/qtmux/gstqtmux.c +++ b/gst/qtmux/gstqtmux.c @@ -1,7 +1,9 @@ /* Quicktime muxer plugin for GStreamer * Copyright (C) 2008-2010 Thiago Santos <thiagoss@embedded.ufcg.edu.br> * Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net> - * + * Copyright (C) 2010 Nokia Corporation. All rights reserved. + * Contact: Stefan Kost <stefan.kost@nokia.com> + * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either @@ -62,6 +64,36 @@ * The fragmented file features defined (only) in ISO Base Media are used by * ISMV files making up (a.o.) Smooth Streaming (ismlmux). * + * A few properties (<link linkend="GstQTMux--movie-timescale">movie-timescale</link>, + * <link linkend="GstQTMux--trak-timescale">trak-timescale</link>) allow adjusting + * some technical parameters, which might be useful in (rare) cases to resolve + * compatibility issues in some situations. + * + * Some other properties influence the result more fundamentally. + * A typical mov/mp4 file's metadata (aka moov) is located at the end of the file, + * somewhat contrary to this usually being called "the header". + * However, a <link linkend="GstQTMux--faststart">faststart</link> file will + * (with some effort) arrange this to be located near start of the file, + * which then allows it e.g. to be played while downloading. + * Alternatively, rather than having one chunk of metadata at start (or end), + * there can be some metadata at start and most of the other data can be spread + * out into fragments of <link linkend="GstQTMux--fragment-duration">fragment-duration</link>. + * If such fragmented layout is intended for streaming purposes, then + * <link linkend="GstQTMux--streamable">streamable</link> allows foregoing to add + * index metadata (at the end of file). + * + * <link linkend="GstQTMux--dts-method">dts-method</link> allows selecting a + * method for managing input timestamps (stay tuned for 0.11 to have this + * automagically settled). The default delta/duration method should handle nice + * (aka perfect streams) just fine, but may experience problems otherwise + * (e.g. input stream with re-ordered B-frames and/or with frame dropping). + * The re-ordering approach re-assigns incoming timestamps in ascending order + * to incoming buffers and offers an alternative in such cases. In cases where + * that might fail, the remaining method can be tried, which is exact and + * according to specs, but might experience playback on not so spec-wise players. + * Note that this latter approach also requires one to enable + * <link linkend="GstQTMux--presentation-timestamp">presentation-timestamp</link>. + * * <refsect2> * <title>Example pipelines</title> * |[ @@ -108,6 +140,36 @@ GST_DEBUG_CATEGORY_STATIC (gst_qt_mux_debug); #define GST_CAT_DEFAULT gst_qt_mux_debug +enum +{ + DTS_METHOD_DD, + DTS_METHOD_REORDER, + DTS_METHOD_ASC +}; + +static GType +gst_qt_mux_dts_method_get_type (void) +{ + static GType gst_qt_mux_dts_method = 0; + + if (!gst_qt_mux_dts_method) { + static const GEnumValue dts_methods[] = { + {DTS_METHOD_DD, "delta/duration", "dd"}, + {DTS_METHOD_REORDER, "reorder", "reorder"}, + {DTS_METHOD_ASC, "ascending", "asc"}, + {0, NULL, NULL}, + }; + + gst_qt_mux_dts_method = + g_enum_register_static ("GstQTMuxDtsMethods", dts_methods); + } + + return gst_qt_mux_dts_method; +} + +#define GST_TYPE_QT_MUX_DTS_METHOD \ + (gst_qt_mux_dts_method_get_type ()) + /* QTMux signals and args */ enum { @@ -118,22 +180,21 @@ enum enum { PROP_0, - PROP_LARGE_FILE, PROP_MOVIE_TIMESCALE, PROP_TRAK_TIMESCALE, - PROP_DO_CTTS, PROP_FAST_START, PROP_FAST_START_TEMP_FILE, PROP_MOOV_RECOV_FILE, PROP_FRAGMENT_DURATION, - PROP_STREAMABLE + PROP_STREAMABLE, + PROP_DTS_METHOD, + PROP_DO_CTTS, }; /* some spare for header size as well */ #define MDAT_LARGE_FILE_LIMIT ((guint64) 1024 * 1024 * 1024 * 2) #define MAX_TOLERATED_LATENESS (GST_SECOND / 10) -#define DEFAULT_LARGE_FILE FALSE #define DEFAULT_MOVIE_TIMESCALE 1000 #define DEFAULT_TRAK_TIMESCALE 0 #define DEFAULT_DO_CTTS FALSE @@ -142,6 +203,7 @@ enum #define DEFAULT_MOOV_RECOV_FILE NULL #define DEFAULT_FRAGMENT_DURATION 0 #define DEFAULT_STREAMABLE FALSE +#define DEFAULT_DTS_METHOD DTS_METHOD_DD static void gst_qt_mux_finalize (GObject * object); @@ -229,11 +291,6 @@ gst_qt_mux_class_init (GstQTMuxClass * klass) gobject_class->get_property = gst_qt_mux_get_property; gobject_class->set_property = gst_qt_mux_set_property; - g_object_class_install_property (gobject_class, PROP_LARGE_FILE, - g_param_spec_boolean ("large-file", "Support for large files", - "Uses 64bits to some fields instead of 32bits, " - "providing support for large files", - DEFAULT_LARGE_FILE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_MOVIE_TIMESCALE, g_param_spec_uint ("movie-timescale", "Movie timescale", "Timescale to use in the movie (units per second)", @@ -251,6 +308,11 @@ gst_qt_mux_class_init (GstQTMuxClass * klass) "(in addition to decoding time) (use with caution)", DEFAULT_DO_CTTS, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_DTS_METHOD, + g_param_spec_enum ("dts-method", "dts-method", + "Method to determine DTS time", + GST_TYPE_QT_MUX_DTS_METHOD, DEFAULT_DTS_METHOD, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_FAST_START, g_param_spec_boolean ("faststart", "Format file to faststart", "If the file should be formated for faststart (headers first). ", @@ -291,6 +353,8 @@ gst_qt_mux_class_init (GstQTMuxClass * klass) static void gst_qt_mux_pad_reset (GstQTPad * qtpad) { + gint i; + qtpad->fourcc = 0; qtpad->is_out_of_order = FALSE; qtpad->have_dts = FALSE; @@ -301,6 +365,16 @@ gst_qt_mux_pad_reset (GstQTPad * qtpad) qtpad->prepare_buf_func = NULL; qtpad->avg_bitrate = 0; qtpad->max_bitrate = 0; + qtpad->ts_n_entries = 0; + + qtpad->buf_head = 0; + qtpad->buf_tail = 0; + for (i = 0; i < G_N_ELEMENTS (qtpad->buf_entries); i++) { + if (qtpad->buf_entries[i]) { + gst_buffer_unref (qtpad->buf_entries[i]); + qtpad->buf_entries[i] = NULL; + } + } if (qtpad->last_buf) gst_buffer_replace (&qtpad->last_buf, NULL); @@ -359,6 +433,7 @@ gst_qt_mux_reset (GstQTMux * qtmux, gboolean alloc) for (walk = qtmux->extra_atoms; walk; walk = g_slist_next (walk)) { AtomInfo *ainfo = (AtomInfo *) walk->data; ainfo->free_func (ainfo->atom); + g_free (ainfo); } g_slist_free (qtmux->extra_atoms); qtmux->extra_atoms = NULL; @@ -394,13 +469,9 @@ gst_qt_mux_init (GstQTMux * qtmux, GstQTMuxClass * qtmux_klass) { GstElementClass *klass = GST_ELEMENT_CLASS (qtmux_klass); GstPadTemplate *templ; - GstCaps *caps; templ = gst_element_class_get_pad_template (klass, "src"); qtmux->srcpad = gst_pad_new_from_template (templ, "src"); - caps = gst_caps_copy (gst_pad_get_pad_template_caps (qtmux->srcpad)); - gst_pad_set_caps (qtmux->srcpad, caps); - gst_caps_unref (caps); gst_pad_use_fixed_caps (qtmux->srcpad); gst_element_add_pad (GST_ELEMENT (qtmux), qtmux->srcpad); @@ -723,6 +794,7 @@ gst_qt_mux_add_3gp_keywords (GstQTMux * qtmux, const GstTagList * list, return; kwds = g_strsplit (keywords, ",", 0); + g_free (keywords); size = 0; for (i = 0; kwds[i]; i++) { @@ -1403,23 +1475,20 @@ gst_qt_mux_set_header_on_caps (GstQTMux * mux, GstBuffer * buf) static void gst_qt_mux_configure_moov (GstQTMux * qtmux, guint32 * _timescale) { - gboolean large_file, fragmented; + gboolean fragmented; guint32 timescale; GST_OBJECT_LOCK (qtmux); timescale = qtmux->timescale; - large_file = qtmux->large_file; fragmented = qtmux->fragment_sequence > 0; GST_OBJECT_UNLOCK (qtmux); /* inform lower layers of our property wishes, and determine duration. * Let moov take care of this using its list of traks; * so that released pads are also included */ - GST_DEBUG_OBJECT (qtmux, "Large file support: %d", large_file); GST_DEBUG_OBJECT (qtmux, "Updating timescale to %" G_GUINT32_FORMAT, timescale); atom_moov_update_timescale (qtmux->moov, timescale); - atom_moov_set_64bits (qtmux->moov, large_file); atom_moov_set_fragmented (qtmux->moov, fragmented); atom_moov_update_duration (qtmux->moov); @@ -1505,9 +1574,14 @@ static GstFlowReturn gst_qt_mux_start_file (GstQTMux * qtmux) { GstFlowReturn ret = GST_FLOW_OK; + GstCaps *caps; GST_DEBUG_OBJECT (qtmux, "starting file"); + caps = gst_caps_copy (gst_pad_get_pad_template_caps (qtmux->srcpad)); + gst_pad_set_caps (qtmux->srcpad, caps); + gst_caps_unref (caps); + /* let downstream know we think in BYTES and expect to do seeking later on */ gst_pad_push_event (qtmux->srcpad, gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1, 0)); @@ -1645,6 +1719,11 @@ gst_qt_mux_stop_file (GstQTMux * qtmux) GstCollectData *cdata = (GstCollectData *) walk->data; GstQTPad *qtpad = (GstQTPad *) cdata; + if (!qtpad->last_buf) { + GST_DEBUG_OBJECT (qtmux, "Pad %s has no buffers", + GST_PAD_NAME (qtpad->collect.pad)); + continue; + } /* send last buffer */ GST_DEBUG_OBJECT (qtmux, "Sending the last buffer for pad %s", GST_PAD_NAME (qtpad->collect.pad)); @@ -1821,8 +1900,7 @@ ftyp_error: static GstFlowReturn gst_qt_mux_pad_fragment_add_buffer (GstQTMux * qtmux, GstQTPad * pad, GstBuffer * buf, gboolean force, guint32 nsamples, gint64 dts, - guint32 delta, guint32 size, gboolean sync, gboolean do_pts, - gint64 pts_offset) + guint32 delta, guint32 size, gboolean sync, gint64 pts_offset) { GstFlowReturn ret = GST_FLOW_OK; @@ -1896,7 +1974,7 @@ init: } /* add buffer and metadata */ - atom_traf_add_samples (pad->traf, delta, size, sync, do_pts, pts_offset, + atom_traf_add_samples (pad->traf, delta, size, sync, pts_offset, pad->sync && sync); atom_array_append (&pad->fragment_buffers, buf, 256); pad->fragment_duration -= delta; @@ -1914,12 +1992,50 @@ init: return ret; } -/* check whether @a differs from @b by order of @magn */ -static gboolean inline -gst_qtmux_check_difference (GstQTMux * qtmux, GstClockTime a, - GstClockTime b, GstClockTime magn) +/* sigh, tiny list helpers to re-order stuff */ +static void +gst_qt_mux_push_ts (GstQTMux * qtmux, GstQTPad * pad, GstClockTime ts) { - return ((a >= b) ? (a - b >= (magn >> 1)) : (b - a >= (magn >> 1))); + gint i; + + for (i = 0; (i < QTMUX_NO_OF_TS) && (i < pad->ts_n_entries); i++) { + if (ts > pad->ts_entries[i]) + break; + } + memmove (&pad->ts_entries[i + 1], &pad->ts_entries[i], + sizeof (GstClockTime) * (pad->ts_n_entries - i)); + pad->ts_entries[i] = ts; + pad->ts_n_entries++; +} + +/* takes ownership of @buf */ +static GstBuffer * +gst_qt_mux_get_asc_buffer_ts (GstQTMux * qtmux, GstQTPad * pad, GstBuffer * buf) +{ + const gint wrap = G_N_ELEMENTS (pad->buf_entries); + GstClockTime ts; + + /* store buffer and ts, latter ordered */ + if (buf) { + pad->buf_entries[pad->buf_tail++] = buf; + pad->buf_tail %= wrap; + gst_qt_mux_push_ts (qtmux, pad, GST_BUFFER_TIMESTAMP (buf)); + } + + if (pad->ts_n_entries && (!buf || pad->ts_n_entries >= QTMUX_NO_OF_TS)) { + ts = pad->ts_entries[--pad->ts_n_entries]; + buf = pad->buf_entries[pad->buf_head]; + pad->buf_entries[pad->buf_head++] = NULL; + pad->buf_head %= wrap; + buf = gst_buffer_make_metadata_writable (buf); + GST_BUFFER_TIMESTAMP (buf) = ts; + GST_DEBUG_OBJECT (qtmux, "next buffer uses reordered ts %" GST_TIME_FORMAT, + GST_TIME_ARGS (ts)); + } else { + buf = NULL; + } + + return buf; } /* @@ -1931,10 +2047,12 @@ gst_qt_mux_add_buffer (GstQTMux * qtmux, GstQTPad * pad, GstBuffer * buf) GstBuffer *last_buf = NULL; GstClockTime duration; guint nsamples, sample_size; - guint64 scaled_duration, chunk_offset; - gint64 last_dts; + guint64 chunk_offset; + gint64 last_dts, scaled_duration; gint64 pts_offset = 0; gboolean sync = FALSE, do_pts = FALSE; + gboolean drain = (buf == NULL); + GstFlowReturn ret; if (!pad->fourcc) goto not_negotiated; @@ -1944,6 +2062,15 @@ gst_qt_mux_add_buffer (GstQTMux * qtmux, GstQTPad * pad, GstBuffer * buf) buf = pad->prepare_buf_func (pad, buf, qtmux); } +again: + if (G_UNLIKELY (qtmux->dts_method == DTS_METHOD_REORDER)) { + buf = gst_qt_mux_get_asc_buffer_ts (qtmux, pad, buf); + if (!buf) { + GST_DEBUG_OBJECT (qtmux, "no reordered buffer yet"); + return GST_FLOW_OK; + } + } + last_buf = pad->last_buf; if (last_buf == NULL) { #ifndef GST_DISABLE_GST_DEBUG @@ -1963,27 +2090,34 @@ gst_qt_mux_add_buffer (GstQTMux * qtmux, GstQTPad * pad, GstBuffer * buf) gst_buffer_ref (last_buf); /* nasty heuristic mess to guestimate dealing with DTS/PTS, - * while also trying to stay close to input ts to preserve sync, so: + * while also trying to stay close to input ts to preserve sync, + * so in DTS_METHOD_DD: * - prefer using input ts where possible - * - if those detected out-of-order (*), and input duration available, - * mark as out-of-order and fallback to duration - * - if in out-of-order, need to preserve sync between streams, and adding - * durations might drift, so try to resync when we expect - * input ts == (sum of durations), which is at some keyframe input frame. + * - if those detected out-of-order (*), mark as out-of-order + * - if in out-of-order, then + * - if duration available, use that as delta + * Also mind to preserve sync between streams, and adding + * durations might drift, so try to resync when we expect + * input ts == (sum of durations), which is at some keyframe input frame. + * - if no duration available, we are actually in serious trouble and need + * to hack around that, so we fail. + * To remedy failure, alternatively, in DTS_METHOD_REORDER: + * - collect some buffers and re-order timestamp, + * then process the oldest buffer with smallest timestamps. + * This should typically compensate for some codec's handywork with ts. + * ... but in case this makes ts end up where not expected: + * - keep each ts with its buffer and still keep a list of most recent X ts, + * use the (ascending) minimum of those as DTS (and the difference as ts delta), + * and use this DTS as a basis to obtain a (positive) CTS offset. + * This should yield exact PTS == buffer ts, but it seems not all players + * out there are aware of ctts pts ... * - * (*) if input ts out-of-order, or if ts differs from (sum of durations) - * by an (approx) order-of-duration magnitude + * 0.11 Phew, can we (pretty) please please sort out DTS/PTS on buffers ... */ if (G_LIKELY (buf) && !pad->is_out_of_order) { if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (last_buf) && GST_BUFFER_TIMESTAMP_IS_VALID (buf))) { - if ((GST_BUFFER_TIMESTAMP (buf) < GST_BUFFER_TIMESTAMP (last_buf)) || - (!GST_CLOCK_TIME_IS_VALID (pad->first_ts) && - GST_BUFFER_DURATION_IS_VALID (last_buf) && - gst_qtmux_check_difference (qtmux, - GST_BUFFER_TIMESTAMP (last_buf) + - GST_BUFFER_DURATION (last_buf), GST_BUFFER_TIMESTAMP (buf), - GST_BUFFER_DURATION (last_buf)))) { + if ((GST_BUFFER_TIMESTAMP (buf) < GST_BUFFER_TIMESTAMP (last_buf))) { GST_DEBUG_OBJECT (qtmux, "detected out-of-order input"); pad->is_out_of_order = TRUE; } @@ -1995,9 +2129,16 @@ gst_qt_mux_add_buffer (GstQTMux * qtmux, GstQTPad * pad, GstBuffer * buf) } } + /* would have to be some unusual input, but not impossible */ + if (G_UNLIKELY (qtmux->dts_method == DTS_METHOD_REORDER && + pad->is_out_of_order)) { + goto no_order; + } + /* fall back to duration if last buffer or * out-of-order (determined previously), otherwise use input ts */ - if (buf == NULL || pad->is_out_of_order) { + if (buf == NULL || + (pad->is_out_of_order && qtmux->dts_method == DTS_METHOD_DD)) { if (!GST_BUFFER_DURATION_IS_VALID (last_buf)) { /* be forgiving for some possibly last upstream flushed buffer */ if (buf) @@ -2010,9 +2151,7 @@ gst_qt_mux_add_buffer (GstQTMux * qtmux, GstQTPad * pad, GstBuffer * buf) /* avoid drift in sum timestamps, * so use input timestamp for suitable keyframe */ if (buf && !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) && - GST_BUFFER_TIMESTAMP (buf) >= pad->last_dts && - !gst_qtmux_check_difference (qtmux, pad->last_dts + duration, - GST_BUFFER_TIMESTAMP (buf), duration)) { + GST_BUFFER_TIMESTAMP (buf) >= pad->last_dts) { GST_DEBUG_OBJECT (qtmux, "resyncing out-of-order input to ts; " "replacing %" GST_TIME_FORMAT " by %" GST_TIME_FORMAT, GST_TIME_ARGS (pad->last_dts + duration), @@ -2020,8 +2159,37 @@ gst_qt_mux_add_buffer (GstQTMux * qtmux, GstQTPad * pad, GstBuffer * buf) duration = GST_BUFFER_TIMESTAMP (buf) - pad->last_dts; } } - } else { + } else if (qtmux->dts_method != DTS_METHOD_ASC) { duration = GST_BUFFER_TIMESTAMP (buf) - GST_BUFFER_TIMESTAMP (last_buf); + } else { + GstClockTime ts; + + g_assert (qtmux->dts_method == DTS_METHOD_ASC); + if (!qtmux->guess_pts) + goto need_pts; + + /* add timestamp to queue; keeps in descending order */ + gst_qt_mux_push_ts (qtmux, pad, GST_BUFFER_TIMESTAMP (last_buf)); + /* chuck out smallest/last one if we have enough */ + if (G_LIKELY (pad->ts_n_entries > QTMUX_NO_OF_TS)) + pad->ts_n_entries--; + /* peek the now smallest timestamp */ + ts = pad->ts_entries[pad->ts_n_entries - 1]; + /* these tails are expected to be (strictly) ascending with + * large enough history */ + GST_DEBUG_OBJECT (qtmux, "ASC method; base timestamp %" GST_TIME_FORMAT, + GST_TIME_ARGS (ts)); + if (ts >= pad->last_dts) { + duration = ts - pad->last_dts; + } else { + /* fallback to previous value, negative ct offset might handle */ + GST_WARNING_OBJECT (qtmux, "unexpected decrease in timestamp"); + duration = 0; + } + /* arrange for small non-zero duration/delta << expected frame time */ + ts = gst_util_uint64_scale (10, GST_SECOND, + atom_trak_get_timescale (pad->trak)); + duration = MAX (duration, ts); } gst_buffer_replace (&pad->last_buf, buf); @@ -2142,8 +2310,8 @@ gst_qt_mux_add_buffer (GstQTMux * qtmux, GstQTPad * pad, GstBuffer * buf) /* note that a new chunk is started each time (not fancy but works) */ if (qtmux->moov_recov_file) { if (!atoms_recov_write_trak_samples (qtmux->moov_recov_file, pad->trak, - nsamples, scaled_duration, sample_size, chunk_offset, sync, do_pts, - pts_offset)) { + nsamples, (gint32) scaled_duration, sample_size, chunk_offset, sync, + do_pts, pts_offset)) { GST_WARNING_OBJECT (qtmux, "Failed to write sample information to " "recovery file, disabling recovery"); fclose (qtmux->moov_recov_file); @@ -2156,15 +2324,23 @@ gst_qt_mux_add_buffer (GstQTMux * qtmux, GstQTPad * pad, GstBuffer * buf) if (qtmux->fragment_sequence) { /* ensure that always sync samples are marked as such */ - return gst_qt_mux_pad_fragment_add_buffer (qtmux, pad, last_buf, - buf == NULL, nsamples, last_dts, scaled_duration, sample_size, - !pad->sync || sync, do_pts, pts_offset); + ret = gst_qt_mux_pad_fragment_add_buffer (qtmux, pad, last_buf, + buf == NULL, nsamples, last_dts, (gint32) scaled_duration, sample_size, + !pad->sync || sync, pts_offset); } else { - atom_trak_add_samples (pad->trak, nsamples, scaled_duration, sample_size, - chunk_offset, sync, do_pts, pts_offset); - return gst_qt_mux_send_buffer (qtmux, last_buf, &qtmux->mdat_size, TRUE); + atom_trak_add_samples (pad->trak, nsamples, (gint32) scaled_duration, + sample_size, chunk_offset, sync, pts_offset); + ret = gst_qt_mux_send_buffer (qtmux, last_buf, &qtmux->mdat_size, TRUE); + } + + if (G_UNLIKELY (drain && qtmux->dts_method == DTS_METHOD_REORDER && + ret == GST_FLOW_OK)) { + buf = NULL; + goto again; } + return ret; + /* ERRORS */ bail: { @@ -2179,6 +2355,18 @@ no_time: ("Received buffer without timestamp/duration.")); goto bail; } +no_order: + { + GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL), + ("DTS method failed to re-order timestamps.")); + goto bail; + } +need_pts: + { + GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL), + ("Selected DTS method also needs PTS enabled.")); + goto bail; + } fragmented_sample: { GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL), @@ -3068,9 +3256,6 @@ gst_qt_mux_get_property (GObject * object, GST_OBJECT_LOCK (qtmux); switch (prop_id) { - case PROP_LARGE_FILE: - g_value_set_boolean (value, qtmux->large_file); - break; case PROP_MOVIE_TIMESCALE: g_value_set_uint (value, qtmux->timescale); break; @@ -3080,6 +3265,9 @@ gst_qt_mux_get_property (GObject * object, case PROP_DO_CTTS: g_value_set_boolean (value, qtmux->guess_pts); break; + case PROP_DTS_METHOD: + g_value_set_enum (value, qtmux->dts_method); + break; case PROP_FAST_START: g_value_set_boolean (value, qtmux->fast_start); break; @@ -3123,9 +3311,6 @@ gst_qt_mux_set_property (GObject * object, GST_OBJECT_LOCK (qtmux); switch (prop_id) { - case PROP_LARGE_FILE: - qtmux->large_file = g_value_get_boolean (value); - break; case PROP_MOVIE_TIMESCALE: qtmux->timescale = g_value_get_uint (value); break; @@ -3135,6 +3320,9 @@ gst_qt_mux_set_property (GObject * object, case PROP_DO_CTTS: qtmux->guess_pts = g_value_get_boolean (value); break; + case PROP_DTS_METHOD: + qtmux->dts_method = g_value_get_enum (value); + break; case PROP_FAST_START: qtmux->fast_start = g_value_get_boolean (value); break; diff --git a/gst/qtmux/gstqtmux.h b/gst/qtmux/gstqtmux.h index 227eb2abd..3a2cb492f 100644 --- a/gst/qtmux/gstqtmux.h +++ b/gst/qtmux/gstqtmux.h @@ -78,6 +78,8 @@ typedef struct _GstQTPad GstQTPad; typedef GstBuffer * (*GstQTPadPrepareBufferFunc) (GstQTPad * pad, GstBuffer * buf, GstQTMux * qtmux); +#define QTMUX_NO_OF_TS 10 + struct _GstQTPad { GstCollectData collect; /* we extend the CollectData */ @@ -102,6 +104,11 @@ struct _GstQTPad /* store the first timestamp for comparing with other streams and * know if there are late streams */ GstClockTime first_ts; + GstClockTime ts_entries[QTMUX_NO_OF_TS + 2]; + guint ts_n_entries; + GstBuffer *buf_entries[QTMUX_NO_OF_TS + 2]; + guint buf_head; + guint buf_tail; /* all the atom and chunk book-keeping is delegated here * unowned/uncounted reference, parent MOOV owns */ @@ -173,8 +180,8 @@ struct _GstQTMux guint32 trak_timescale; AtomsTreeFlavor flavor; gboolean fast_start; - gboolean large_file; gboolean guess_pts; + gint dts_method; gchar *fast_start_file_path; gchar *moov_recov_file_path; guint32 fragment_duration; diff --git a/gst/rawparse/gstaudioparse.c b/gst/rawparse/gstaudioparse.c index 1341c57e3..d4f82bad4 100644 --- a/gst/rawparse/gstaudioparse.c +++ b/gst/rawparse/gstaudioparse.c @@ -373,6 +373,11 @@ gst_audio_parse_set_channel_positions (GstAudioParse * ap, GstStructure * s) GValue pos_array = { 0, }; gint i; + if (!ap->channel_positions && ap->channels <= 2) { + /* Implicit mapping for 1- and 2-channel audio is okay */ + return; + } + g_value_init (&pos_array, GST_TYPE_ARRAY); if (ap->channel_positions @@ -382,7 +387,8 @@ gst_audio_parse_set_channel_positions (GstAudioParse * ap, GstStructure * s) for (i = 0; i < ap->channels; i++) gst_value_array_append_value (&pos_array, g_value_array_get_nth (ap->channel_positions, i)); - } else if (ap->channels != 1 && ap->channels != 2) { + } else { + /* >2 channels and no explicit mapping */ GValue pos_none = { 0, }; GST_WARNING_OBJECT (ap, "Using NONE channel positions"); diff --git a/gst/rtpvp8/Makefile.am b/gst/rtpvp8/Makefile.am new file mode 100644 index 000000000..05bf5d7c4 --- /dev/null +++ b/gst/rtpvp8/Makefile.am @@ -0,0 +1,15 @@ +plugin_LTLIBRARIES = libgstrtpvp8.la + +libgstrtpvp8_la_SOURCES = gstrtpvp8.c \ + gstrtpvp8depay.c \ + gstrtpvp8pay.c + +noinst_HEADERS = gstrtpvp8depay.h \ + gstrtpvp8pay.h + +libgstrtpvp8_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) $(GST_CFLAGS) +libgstrtpvp8_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstrtp-@GST_MAJORMINOR@ \ + $(GST_BASE_LIBS) $(GST_LIBS) +libgstrtpvp8_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstrtpvp8_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/gst/rtpvp8/gstrtpvp8.c b/gst/rtpvp8/gstrtpvp8.c new file mode 100644 index 000000000..e27db1879 --- /dev/null +++ b/gst/rtpvp8/gstrtpvp8.c @@ -0,0 +1,21 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstrtpvp8pay.h" +#include "gstrtpvp8depay.h" + +static gboolean +plugin_init (GstPlugin * plugin) +{ + gst_rtp_vp8_depay_plugin_init (plugin); + gst_rtp_vp8_pay_plugin_init (plugin); + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "rtpvp8", + "rtpvp8", + plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/gst/rtpvp8/gstrtpvp8depay.c b/gst/rtpvp8/gstrtpvp8depay.c new file mode 100644 index 000000000..d9d222654 --- /dev/null +++ b/gst/rtpvp8/gstrtpvp8depay.c @@ -0,0 +1,194 @@ +/* + * gst-rtp-vp8-depay.c - Source for GstRtpVP8Depay + * Copyright (C) 2011 Sjoerd Simons <sjoerd@luon.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "gstrtpvp8depay.h" + +GST_DEBUG_CATEGORY_STATIC (gst_rtp_vp8_depay_debug); +#define GST_CAT_DEFAULT gst_rtp_vp8_depay_debug + +GST_BOILERPLATE (GstRtpVP8Depay, gst_rtp_vp8_depay, GstBaseRTPDepayload, + GST_TYPE_BASE_RTP_DEPAYLOAD); + +static GstStaticPadTemplate gst_rtp_vp8_depay_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-vp8")); + +static GstStaticPadTemplate gst_rtp_vp8_depay_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp, " + "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING "," + "clock-rate = (int) 90000," + "media = (string) \"video\"," + "encoding-name = (string) \"VP8-DRAFT-0-3-2\"")); + +static void +gst_rtp_vp8_depay_init (GstRtpVP8Depay * self, GstRtpVP8DepayClass * klass) +{ + self->adapter = gst_adapter_new (); + self->started = FALSE; +} + +static void gst_rtp_vp8_depay_dispose (GObject * object); +static GstBuffer *gst_rtp_vp8_depay_process (GstBaseRTPDepayload * depayload, + GstBuffer * buf); +static gboolean gst_rtp_vp8_depay_set_caps (GstBaseRTPDepayload * depayload, + GstCaps * caps); + +static void +gst_rtp_vp8_depay_base_init (gpointer klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_rtp_vp8_depay_sink_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_rtp_vp8_depay_src_template)); + + gst_element_class_set_details_simple (element_class, "RTP VP8 depayloader", + "Codec/Depayloader/Network/RTP", + "Extracts VP8 video from RTP packets)", + "Sjoerd Simons <sjoerd@luon.net>"); +} + +static void +gst_rtp_vp8_depay_class_init (GstRtpVP8DepayClass * gst_rtp_vp8_depay_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (gst_rtp_vp8_depay_class); + GstBaseRTPDepayloadClass *depay_class = + (GstBaseRTPDepayloadClass *) (gst_rtp_vp8_depay_class); + + object_class->dispose = gst_rtp_vp8_depay_dispose; + + depay_class->process = gst_rtp_vp8_depay_process; + depay_class->set_caps = gst_rtp_vp8_depay_set_caps; + + GST_DEBUG_CATEGORY_INIT (gst_rtp_vp8_depay_debug, "rtpvp8depay", 0, + "VP8 Video RTP Depayloader"); +} + +static void +gst_rtp_vp8_depay_dispose (GObject * object) +{ + GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (object); + + if (self->adapter != NULL) + g_object_unref (self->adapter); + self->adapter = NULL; + + /* release any references held by the object here */ + + if (G_OBJECT_CLASS (parent_class)->dispose) + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static GstBuffer * +gst_rtp_vp8_depay_process (GstBaseRTPDepayload * depay, GstBuffer * buf) +{ + GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (depay); + GstBuffer *payload; + guint8 *data; + guint offset; + guint size = gst_rtp_buffer_get_payload_len (buf); + + if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) { + GST_LOG_OBJECT (self, "Discontinuity, flushing adapter"); + gst_adapter_clear (self->adapter); + self->started = FALSE; + } + + /* At least one header and one vp8 byte */ + if (G_UNLIKELY (size < 2)) + goto too_small; + + data = gst_rtp_buffer_get_payload (buf); + + if (G_UNLIKELY (!self->started)) { + /* Check if this is the start of a VP8 frame, otherwise bail */ + if ((data[0] & 0x1) == 0) + return NULL; + + self->started = TRUE; + } + + offset = 1; + if ((data[0] & 0x10) != 0) { + /* Skip Picture identifier bytes */ + for (; (data[offset] & 0x80) != 0; offset++) { + /* should be at least one more pictureID byte and at least one byte in + * the vp8 payload */ + if (G_UNLIKELY (offset + 2 >= size)) + goto too_small; + } + offset++; + } + + if (G_UNLIKELY (offset >= size)) + goto too_small; + + payload = gst_rtp_buffer_get_payload_subbuffer (buf, offset, -1); + gst_adapter_push (self->adapter, payload); + + /* Marker indicates that it was the last rtp packet for this frame */ + if (gst_rtp_buffer_get_marker (buf)) { + GstBuffer *out; + + out = gst_adapter_take_buffer (self->adapter, + gst_adapter_available (self->adapter)); + + self->started = FALSE; + return out; + } + + return NULL; + +too_small: + GST_LOG_OBJECT (self, "Invalid rtp packet (too small), ignoring"); + gst_adapter_clear (self->adapter); + self->started = FALSE; + return NULL; +} + +static gboolean +gst_rtp_vp8_depay_set_caps (GstBaseRTPDepayload * depayload, GstCaps * caps) +{ + GstCaps *srccaps = gst_caps_new_simple ("video/x-vp8", + "framerate", GST_TYPE_FRACTION, 0, 1, + NULL); + + gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload), srccaps); + gst_caps_unref (srccaps); + + return TRUE; +} + +gboolean +gst_rtp_vp8_depay_plugin_init (GstPlugin * plugin) +{ + return gst_element_register (plugin, "rtpvp8depay", + GST_RANK_MARGINAL, GST_TYPE_RTP_VP8_DEPAY); +} diff --git a/gst/rtpvp8/gstrtpvp8depay.h b/gst/rtpvp8/gstrtpvp8depay.h new file mode 100644 index 000000000..872615602 --- /dev/null +++ b/gst/rtpvp8/gstrtpvp8depay.h @@ -0,0 +1,63 @@ +/* + * gst-rtp-vp8-depay.h - Header for GstRtpVP8Depay + * Copyright (C) 2011 Sjoerd Simons <sjoerd@luon.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __GST_RTP_VP8_DEPAY_H__ +#define __GST_RTP_VP8_DEPAY_H__ + +#include <glib-object.h> +#include <gst/base/gstadapter.h> +#include <gst/rtp/gstbasertpdepayload.h> + +G_BEGIN_DECLS typedef struct _GstRtpVP8Depay GstRtpVP8Depay; +typedef struct _GstRtpVP8DepayClass GstRtpVP8DepayClass; + +struct _GstRtpVP8DepayClass +{ + GstBaseRTPDepayloadClass parent_class; +}; + +struct _GstRtpVP8Depay +{ + GstBaseRTPDepayload parent; + GstAdapter *adapter; + gboolean started; +}; + +GType gst_rtp_vp8_depay_get_type (void); + +/* TYPE MACROS */ +#define GST_TYPE_RTP_VP8_DEPAY \ + (gst_rtp_vp8_depay_get_type()) +#define GST_RTP_VP8_DEPAY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_RTP_VP8_DEPAY, GstRtpVP8Depay)) +#define GST_RTP_VP8_DEPAY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_RTP_VP8_DEPAY, \ + GstRtpVP8DepayClass)) +#define GST_IS_RTP_VP8_DEPAY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_RTP_VP8_DEPAY)) +#define GST_IS_RTP_VP8_DEPAY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_RTP_VP8_DEPAY)) +#define GST_RTP_VP8_DEPAY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTP_VP8_DEPAY, \ + GstRtpVP8DepayClass)) + +gboolean gst_rtp_vp8_depay_plugin_init (GstPlugin * plugin); + +G_END_DECLS +#endif /* #ifndef __GST_RTP_VP8_DEPAY_H__ */ diff --git a/gst/rtpvp8/gstrtpvp8pay.c b/gst/rtpvp8/gstrtpvp8pay.c new file mode 100644 index 000000000..0ea577713 --- /dev/null +++ b/gst/rtpvp8/gstrtpvp8pay.c @@ -0,0 +1,453 @@ +/* + * gst-rtp-vp8-pay.c - Source for GstRtpVP8Pay + * Copyright (C) 2011 Sjoerd Simons <sjoerd@luon.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <gst/base/gstbitreader.h> +#include <gst/rtp/gstrtppayloads.h> +#include <gst/rtp/gstrtpbuffer.h> +#include "gstrtpvp8pay.h" + +#define FI_FRAG_UNFRAGMENTED 0x0 +#define FI_FRAG_START 0x1 +#define FI_FRAG_MIDDLE 0x2 +#define FI_FRAG_END 0x3 + +GST_DEBUG_CATEGORY_STATIC (gst_rtp_vp8_pay_debug); +#define GST_CAT_DEFAULT gst_rtp_vp8_pay_debug + +GST_BOILERPLATE (GstRtpVP8Pay, gst_rtp_vp8_pay, GstBaseRTPPayload, + GST_TYPE_BASE_RTP_PAYLOAD); + +static GstStaticPadTemplate gst_rtp_vp8_pay_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp, " + "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING "," + "clock-rate = (int) 90000, encoding-name = (string) \"VP8-DRAFT-0-3-2\"")); + +static GstStaticPadTemplate gst_rtp_vp8_pay_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-vp8")); + +static void +gst_rtp_vp8_pay_init (GstRtpVP8Pay * obj, GstRtpVP8PayClass * klass) +{ +} + +static GstFlowReturn gst_rtp_vp8_pay_handle_buffer (GstBaseRTPPayload * payload, + GstBuffer * buffer); +static gboolean gst_rtp_vp8_pay_set_caps (GstBaseRTPPayload * payload, + GstCaps * caps); + +static void +gst_rtp_vp8_pay_base_init (gpointer klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_rtp_vp8_pay_sink_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_rtp_vp8_pay_src_template)); + + gst_element_class_set_details_simple (element_class, "RTP VP8 payloader", + "Codec/Payloader/Network/RTP", + "Puts VP8 video in RTP packets)", "Sjoerd Simons <sjoerd@luon.net>"); +} + +static void +gst_rtp_vp8_pay_class_init (GstRtpVP8PayClass * gst_rtp_vp8_pay_class) +{ + GstBaseRTPPayloadClass *pay_class = + GST_BASE_RTP_PAYLOAD_CLASS (gst_rtp_vp8_pay_class); + + pay_class->handle_buffer = gst_rtp_vp8_pay_handle_buffer; + pay_class->set_caps = gst_rtp_vp8_pay_set_caps; + + GST_DEBUG_CATEGORY_INIT (gst_rtp_vp8_pay_debug, "rtpvp8pay", 0, + "VP8 Video RTP Payloader"); +} + +static gsize +gst_rtp_vp8_calc_payload_len (GstBaseRTPPayload * payload) +{ + return gst_rtp_buffer_calc_payload_len (GST_BASE_RTP_PAYLOAD_MTU (payload) - + 1, 0, 0); +} + +/* When growing the vp8 header keep gst_rtp_vp8_calc_payload_len in sync */ +static GstBuffer * +gst_rtp_vp8_create_header_buffer (gboolean start, gboolean mark, guint fi, + GstBuffer * in) +{ + GstBuffer *out; + guint8 *p; + + out = gst_rtp_buffer_new_allocate (1, 0, 0); + p = gst_rtp_buffer_get_payload (out); + /* Hardcode I = 0 and N = 0, only set FI and B */ + p[0] = (fi & 0x3) << 1 | (start ? 1 : 0); + + gst_rtp_buffer_set_marker (out, mark); + + GST_BUFFER_DURATION (out) = GST_BUFFER_DURATION (in); + GST_BUFFER_TIMESTAMP (out) = GST_BUFFER_TIMESTAMP (in); + + return out; +} + + +static gboolean +gst_rtp_vp8_pay_parse_frame (GstRtpVP8Pay * self, GstBuffer * buffer) +{ + GstBitReader *reader; + int i; + gboolean keyframe; + guint32 header_size; + guint8 version; + guint8 tmp8; + guint8 *data; + guint8 partitions; + + reader = gst_bit_reader_new_from_buffer (buffer); + + if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < 3)) + goto error; + + data = GST_BUFFER_DATA (buffer); + + self->is_keyframe = keyframe = ((data[0] & 0x1) == 0); + version = (data[0] >> 1) & 0x7; + + /* keyframe, version and show_frame use 5 bits */ + header_size = data[2] << 11 | data[1] << 3 | (data[0] >> 5); + + /* Include the uncompressed data blob in the header */ + header_size += keyframe ? 10 : 3; + + if (!gst_bit_reader_skip (reader, 24)) + goto error; + + if (keyframe) { + /* check start tag: 0x9d 0x01 0x2a */ + if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 8) || tmp8 != 0x9d) + goto error; + + if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 8) || tmp8 != 0x01) + goto error; + + if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 8) || tmp8 != 0x2a) + goto error; + + /* Skip horizontal size code (16 bits) vertical size code (16 bits), + * color space (1 bit) and clamping type (1 bit) */ + if (!gst_bit_reader_skip (reader, 34)) + goto error; + } + + /* segmentation_enabled */ + if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 1)) + goto error; + + if (tmp8 != 0) { + gboolean update_mb_segmentation_map; + gboolean update_segment_feature_data; + + if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 2)) + goto error; + + update_mb_segmentation_map = (tmp8 & 0x2) != 0; + update_segment_feature_data = (tmp8 & 0x1) != 0; + + if (update_segment_feature_data) { + /* skip segment feature mode */ + if (!gst_bit_reader_skip (reader, 1)) + goto error; + + for (i = 0; i < 4; i++) { + /* quantizer update */ + if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 1)) + goto error; + + if (tmp8 != 0) { + /* skip quantizer value (7 bits) and sign (1 bit) */ + if (!gst_bit_reader_skip (reader, 8)) + goto error; + } + } + + for (i = 0; i < 4; i++) { + /* loop filter update */ + if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 1)) + goto error; + + if (tmp8 != 0) { + /* skip lf update value (6 bits) and sign (1 bit) */ + if (!gst_bit_reader_skip (reader, 7)) + goto error; + } + } + } + + if (update_mb_segmentation_map) { + for (i = 0; i < 3; i++) { + /* segment prob update */ + if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 1)) + goto error; + + if (tmp8 != 0) { + /* skip segment prob */ + if (!gst_bit_reader_skip (reader, 8)) + goto error; + } + } + } + } + + /* skip filter type (1 bit), loop filter level (6 bits) and + * sharpness level (3 bits) */ + if (!gst_bit_reader_skip (reader, 10)) + goto error; + + /* loop_filter_adj_enabled */ + if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 1)) + goto error; + + if (tmp8 != 0) { + /* loop filter adj enabled */ + + /* mode_ref_lf_delta_update */ + if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 1)) + goto error; + + if (tmp8 != 0) { + /* mode_ref_lf_data_update */ + int i; + + for (i = 0; i < 8; i++) { + /* 8 updates, 1 bit indicate whether there is one and if follow by a + * 7 bit update */ + if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 1)) + goto error; + + if (tmp8 != 0) { + /* skip delta magnitude (6 bits) and sign (1 bit) */ + if (!gst_bit_reader_skip (reader, 7)) + goto error; + } + } + } + } + + if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 2)) + goto error; + + partitions = 1 << tmp8; + + /* Check if things are still sensible */ + if (header_size + (partitions - 1) * 3 >= GST_BUFFER_SIZE (buffer)) + goto error; + + /* partition data is right after the frame header */ + data = GST_BUFFER_DATA (buffer) + header_size; + + /* Set up mapping, count the initial header as a partition to make other + * sections of the code easier */ + self->n_partitions = partitions + 1; + self->partition_offset[0] = 0; + self->partition_size[0] = header_size + (partitions - 1) * 3; + + self->partition_offset[1] = self->partition_size[0]; + for (i = 1; i < partitions; i++) { + guint size = (data[2] << 16 | data[1] << 8 | data[0]); + + data += 3; + self->partition_size[i] = size; + self->partition_offset[i + 1] = self->partition_offset[i] + size; + } + + /* Check that our partition offsets and sizes don't go outsize the buffer + * size. */ + if (self->partition_offset[i] >= GST_BUFFER_SIZE (buffer)) + goto error; + + self->partition_size[i] = GST_BUFFER_SIZE (buffer) + - self->partition_offset[i]; + + self->partition_offset[i + 1] = GST_BUFFER_SIZE (buffer); + + gst_bit_reader_free (reader); + return TRUE; + +error: + GST_DEBUG ("Failed to parse frame"); + gst_bit_reader_free (reader); + return FALSE; +} + +static guint +gst_rtp_vp8_fit_partitions (GstRtpVP8Pay * self, gint first, gsize available) +{ + guint num = 0; + int i; + + g_assert (first < self->n_partitions); + + for (i = first; + i < self->n_partitions && self->partition_size[i] < available; i++) { + num++; + available -= self->partition_size[i]; + } + + return num; +} + +static GstBuffer * +gst_rtp_vp8_create_sub (GstRtpVP8Pay * self, + GstBuffer * buffer, guint current, guint num) +{ + guint offset = self->partition_offset[current]; + guint size = self->partition_offset[current + num] - offset; + + return gst_buffer_create_sub (buffer, offset, size); +} + + +static guint +gst_rtp_vp8_payload_next (GstRtpVP8Pay * self, + GstBufferListIterator * it, guint first, GstBuffer * buffer) +{ + guint num; + GstBuffer *header; + GstBuffer *sub; + gboolean mark; + gsize available = gst_rtp_vp8_calc_payload_len (GST_BASE_RTP_PAYLOAD (self)); + + g_assert (first < 9); + + /* How many partitions can we fit */ + num = gst_rtp_vp8_fit_partitions (self, first, available); + + if (num > 0) { + mark = (first + num == self->n_partitions); + /* whole set of partitions, payload them and done */ + header = gst_rtp_vp8_create_header_buffer (first == 0, mark, + FI_FRAG_UNFRAGMENTED, buffer); + sub = gst_rtp_vp8_create_sub (self, buffer, first, num); + + gst_buffer_list_iterator_add_group (it); + gst_buffer_list_iterator_add (it, header); + gst_buffer_list_iterator_add (it, sub); + } else { + /* Fragmented packets */ + guint offset = self->partition_offset[first]; + guint left = self->partition_size[first]; + gboolean start = (first == 0); + + header = gst_rtp_vp8_create_header_buffer (start, FALSE, + FI_FRAG_START, buffer); + sub = gst_buffer_create_sub (buffer, offset, available); + offset += available; + + gst_buffer_list_iterator_add_group (it); + gst_buffer_list_iterator_add (it, header); + gst_buffer_list_iterator_add (it, sub); + + left -= available; + + for (; left > available; left -= available) { + header = gst_rtp_vp8_create_header_buffer (start, FALSE, + FI_FRAG_MIDDLE, buffer); + + sub = gst_buffer_create_sub (buffer, offset, available); + offset += available; + + gst_buffer_list_iterator_add_group (it); + gst_buffer_list_iterator_add (it, header); + gst_buffer_list_iterator_add (it, sub); + } + + mark = (first + 1 == self->n_partitions); + + header = gst_rtp_vp8_create_header_buffer (start, mark, + FI_FRAG_END, buffer); + sub = gst_buffer_create_sub (buffer, offset, left); + + gst_buffer_list_iterator_add_group (it); + gst_buffer_list_iterator_add (it, header); + gst_buffer_list_iterator_add (it, sub); + + return 1; + } + + return num; +} + + +static GstFlowReturn +gst_rtp_vp8_pay_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buffer) +{ + GstRtpVP8Pay *self = GST_RTP_VP8_PAY (payload); + GstFlowReturn ret; + GstBufferList *list; + GstBufferListIterator *it; + guint current; + + if (G_UNLIKELY (!gst_rtp_vp8_pay_parse_frame (self, buffer))) { + /* FIXME throw flow error */ + g_message ("Failed to parse frame"); + return GST_FLOW_ERROR; + } + + list = gst_buffer_list_new (); + it = gst_buffer_list_iterate (list); + + for (current = 0; current < self->n_partitions;) { + guint n; + + n = gst_rtp_vp8_payload_next (self, it, current, buffer); + current += n; + } + + ret = gst_basertppayload_push_list (payload, list); + gst_buffer_list_iterator_free (it); + + return ret; +} + +static gboolean +gst_rtp_vp8_pay_set_caps (GstBaseRTPPayload * payload, GstCaps * caps) +{ + gst_basertppayload_set_options (payload, "video", TRUE, + "VP8-DRAFT-0-3-2", 90000); + return gst_basertppayload_set_outcaps (payload, NULL); +} + +gboolean +gst_rtp_vp8_pay_plugin_init (GstPlugin * plugin) +{ + return gst_element_register (plugin, "rtpvp8pay", + GST_RANK_MARGINAL, GST_TYPE_RTP_VP8_PAY); +} diff --git a/gst/rtpvp8/gstrtpvp8pay.h b/gst/rtpvp8/gstrtpvp8pay.h new file mode 100644 index 000000000..19a2e0147 --- /dev/null +++ b/gst/rtpvp8/gstrtpvp8pay.h @@ -0,0 +1,65 @@ +/* + * gst-rtp-vp8-pay.h - Header for GstRtpVP8Pay + * Copyright (C) 2011 Sjoerd Simons <sjoerd@luon.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __GST_RTP_VP8_PAY_H__ +#define __GST_RTP_VP8_PAY_H__ + +#include <glib-object.h> +#include <gst/base/gstadapter.h> +#include <gst/rtp/gstbasertppayload.h> + +G_BEGIN_DECLS typedef struct _GstRtpVP8Pay GstRtpVP8Pay; +typedef struct _GstRtpVP8PayClass GstRtpVP8PayClass; + +struct _GstRtpVP8PayClass +{ + GstBaseRTPPayloadClass parent_class; +}; + +struct _GstRtpVP8Pay +{ + GstBaseRTPPayload parent; + gboolean is_keyframe; + gint n_partitions; + /* Treat frame header & tag & partition size block as the first partition, + * folowed by max. 8 data partitions. last offset is the end of the buffer */ + guint partition_offset[10]; + guint partition_size[9]; +}; + +GType gst_rtp_vp8_pay_get_type (void); + +/* TYPE MACROS */ +#define GST_TYPE_RTP_VP8_PAY \ + (gst_rtp_vp8_pay_get_type()) +#define GST_RTP_VP8_PAY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_RTP_VP8_PAY, GstRtpVP8Pay)) +#define GST_RTP_VP8_PAY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_RTP_VP8_PAY, GstRtpVP8PayClass)) +#define GST_IS_RTP_VP8_PAY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_RTP_VP8_PAY)) +#define GST_IS_RTP_VP8_PAY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_RTP_VP8_PAY)) +#define GST_RTP_VP8_PAY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTP_VP8_PAY, GstRtpVP8PayClass)) + +gboolean gst_rtp_vp8_pay_plugin_init (GstPlugin * plugin); + +G_END_DECLS +#endif /* #ifndef __GST_RTP_VP8_PAY_H__ */ diff --git a/gst/selector/.gitignore b/gst/selector/.gitignore deleted file mode 100644 index 1cf1f1b30..000000000 --- a/gst/selector/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -gstselector-marshal.c -gstselector-marshal.h diff --git a/gst/selector/Makefile.am b/gst/selector/Makefile.am deleted file mode 100644 index 0e43cce17..000000000 --- a/gst/selector/Makefile.am +++ /dev/null @@ -1,24 +0,0 @@ -glib_gen_prefix = gst_selector -glib_gen_basename = gstselector - -include $(top_srcdir)/common/gst-glib-gen.mak - -built_sources = gstselector-marshal.c -built_headers = gstselector-marshal.h - -BUILT_SOURCES = $(built_sources) $(built_headers) - -CLEANFILES = $(BUILT_SOURCES) - -EXTRA_DIST = gstselector-marshal.list - -plugin_LTLIBRARIES = libgstselector.la - -libgstselector_la_SOURCES = gstselector.c gstinputselector.c gstoutputselector.c -nodist_libgstselector_la_SOURCES = $(built_sources) -libgstselector_la_CFLAGS = $(GST_CFLAGS) -libgstselector_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) -libgstselector_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstselector_la_LIBTOOLFLAGS = --tag=disable-static - -noinst_HEADERS = gstinputselector.h gstoutputselector.h diff --git a/gst/selector/gstoutputselector.c b/gst/selector/gstoutputselector.c deleted file mode 100644 index 9b75da2c2..000000000 --- a/gst/selector/gstoutputselector.c +++ /dev/null @@ -1,519 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.com>) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/** - * SECTION:element-output-selector - * @see_also: #GstOutputSelector, #GstInputSelector - * - * Direct input stream to one out of N output pads. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <string.h> - -#include "gstoutputselector.h" - -GST_DEBUG_CATEGORY_STATIC (output_selector_debug); -#define GST_CAT_DEFAULT output_selector_debug - -static GstStaticPadTemplate gst_output_selector_sink_factory = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -static GstStaticPadTemplate gst_output_selector_src_factory = -GST_STATIC_PAD_TEMPLATE ("src%d", - GST_PAD_SRC, - GST_PAD_REQUEST, - GST_STATIC_CAPS_ANY); - -enum -{ - PROP_0, - PROP_ACTIVE_PAD, - PROP_RESEND_LATEST, - PROP_LAST -}; - -#define _do_init(bla) \ -GST_DEBUG_CATEGORY_INIT (output_selector_debug, \ - "output-selector", 0, "An output stream selector element"); - -GST_BOILERPLATE_FULL (GstOutputSelector, gst_output_selector, GstElement, - GST_TYPE_ELEMENT, _do_init); - -static void gst_output_selector_dispose (GObject * object); -static void gst_output_selector_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_output_selector_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec); -static GstPad *gst_output_selector_request_new_pad (GstElement * element, - GstPadTemplate * templ, const gchar * unused); -static void gst_output_selector_release_pad (GstElement * element, - GstPad * pad); -static GstFlowReturn gst_output_selector_chain (GstPad * pad, GstBuffer * buf); -static GstFlowReturn gst_output_selector_buffer_alloc (GstPad * pad, - guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf); -static GstStateChangeReturn gst_output_selector_change_state (GstElement * - element, GstStateChange transition); -static gboolean gst_output_selector_handle_sink_event (GstPad * pad, - GstEvent * event); - -static void -gst_output_selector_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details_simple (element_class, "Output selector", - "Generic", - "1-to-N output stream selectoring", - "Stefan Kost <stefan.kost@nokia.com>"); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_output_selector_sink_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_output_selector_src_factory)); -} - -static void -gst_output_selector_class_init (GstOutputSelectorClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->dispose = gst_output_selector_dispose; - - gobject_class->set_property = - GST_DEBUG_FUNCPTR (gst_output_selector_set_property); - gobject_class->get_property = - GST_DEBUG_FUNCPTR (gst_output_selector_get_property); - - g_object_class_install_property (gobject_class, PROP_ACTIVE_PAD, - g_param_spec_object ("active-pad", "Active pad", - "Currently active src pad", GST_TYPE_PAD, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_RESEND_LATEST, - g_param_spec_boolean ("resend-latest", "Resend latest buffer", - "Resend latest buffer after a switch to a new pad", FALSE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - gstelement_class->request_new_pad = - GST_DEBUG_FUNCPTR (gst_output_selector_request_new_pad); - gstelement_class->release_pad = - GST_DEBUG_FUNCPTR (gst_output_selector_release_pad); - - gstelement_class->change_state = gst_output_selector_change_state; -} - -static void -gst_output_selector_init (GstOutputSelector * sel, - GstOutputSelectorClass * g_class) -{ - sel->sinkpad = - gst_pad_new_from_static_template (&gst_output_selector_sink_factory, - "sink"); - gst_pad_set_chain_function (sel->sinkpad, - GST_DEBUG_FUNCPTR (gst_output_selector_chain)); - gst_pad_set_event_function (sel->sinkpad, - GST_DEBUG_FUNCPTR (gst_output_selector_handle_sink_event)); - gst_pad_set_bufferalloc_function (sel->sinkpad, - GST_DEBUG_FUNCPTR (gst_output_selector_buffer_alloc)); - /* - gst_pad_set_setcaps_function (sel->sinkpad, - GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps)); - gst_pad_set_getcaps_function (sel->sinkpad, - GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps)); - */ - - gst_element_add_pad (GST_ELEMENT (sel), sel->sinkpad); - - /* srcpad management */ - sel->active_srcpad = NULL; - sel->nb_srcpads = 0; - gst_segment_init (&sel->segment, GST_FORMAT_TIME); - sel->pending_srcpad = NULL; - - sel->resend_latest = FALSE; - sel->latest_buffer = NULL; -} - -static void -gst_output_selector_reset (GstOutputSelector * osel) -{ - if (osel->pending_srcpad != NULL) { - gst_object_unref (osel->pending_srcpad); - osel->pending_srcpad = NULL; - } - if (osel->latest_buffer != NULL) { - gst_buffer_unref (osel->latest_buffer); - osel->latest_buffer = NULL; - } - gst_segment_init (&osel->segment, GST_FORMAT_UNDEFINED); -} - -static void -gst_output_selector_dispose (GObject * object) -{ - GstOutputSelector *osel = GST_OUTPUT_SELECTOR (object); - - gst_output_selector_reset (osel); - - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static void -gst_output_selector_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstOutputSelector *sel = GST_OUTPUT_SELECTOR (object); - - switch (prop_id) { - case PROP_ACTIVE_PAD: - { - GstPad *next_pad; - - next_pad = g_value_get_object (value); - - GST_INFO_OBJECT (sel, "Activating pad %s:%s", - GST_DEBUG_PAD_NAME (next_pad)); - - GST_OBJECT_LOCK (object); - if (next_pad != sel->active_srcpad) { - /* switch to new srcpad in next chain run */ - if (sel->pending_srcpad != NULL) { - GST_INFO ("replacing pending switch"); - gst_object_unref (sel->pending_srcpad); - } - if (next_pad) - gst_object_ref (next_pad); - sel->pending_srcpad = next_pad; - } else { - GST_INFO ("pad already active"); - if (sel->pending_srcpad != NULL) { - gst_object_unref (sel->pending_srcpad); - sel->pending_srcpad = NULL; - } - } - GST_OBJECT_UNLOCK (object); - break; - } - case PROP_RESEND_LATEST:{ - sel->resend_latest = g_value_get_boolean (value); - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_output_selector_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstOutputSelector *sel = GST_OUTPUT_SELECTOR (object); - - switch (prop_id) { - case PROP_ACTIVE_PAD: - GST_OBJECT_LOCK (object); - g_value_set_object (value, - sel->pending_srcpad ? sel->pending_srcpad : sel->active_srcpad); - GST_OBJECT_UNLOCK (object); - break; - case PROP_RESEND_LATEST:{ - GST_OBJECT_LOCK (object); - g_value_set_boolean (value, sel->resend_latest); - GST_OBJECT_UNLOCK (object); - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static GstFlowReturn -gst_output_selector_buffer_alloc (GstPad * pad, guint64 offset, guint size, - GstCaps * caps, GstBuffer ** buf) -{ - GstOutputSelector *sel; - GstFlowReturn res; - GstPad *allocpad; - - sel = GST_OUTPUT_SELECTOR (GST_PAD_PARENT (pad)); - res = GST_FLOW_NOT_LINKED; - - GST_OBJECT_LOCK (sel); - allocpad = sel->pending_srcpad ? sel->pending_srcpad : sel->active_srcpad; - if (allocpad) { - /* if we had a previous pad we used for allocating a buffer, continue using - * it. */ - GST_DEBUG_OBJECT (sel, "using pad %s:%s for alloc", - GST_DEBUG_PAD_NAME (allocpad)); - gst_object_ref (allocpad); - GST_OBJECT_UNLOCK (sel); - - res = gst_pad_alloc_buffer (allocpad, offset, size, caps, buf); - gst_object_unref (allocpad); - - GST_OBJECT_LOCK (sel); - } else { - /* fallback case, allocate a buffer of our own, add pad caps. */ - GST_DEBUG_OBJECT (pad, "fallback buffer alloc"); - *buf = NULL; - res = GST_FLOW_OK; - } - GST_OBJECT_UNLOCK (sel); - - GST_DEBUG_OBJECT (sel, "buffer alloc finished: %s", gst_flow_get_name (res)); - - return res; -} - -static GstPad * -gst_output_selector_request_new_pad (GstElement * element, - GstPadTemplate * templ, const gchar * name) -{ - gchar *padname; - GstPad *srcpad; - GstOutputSelector *osel; - - osel = GST_OUTPUT_SELECTOR (element); - - GST_DEBUG_OBJECT (osel, "requesting pad"); - - GST_OBJECT_LOCK (osel); - padname = g_strdup_printf ("src%d", osel->nb_srcpads++); - srcpad = gst_pad_new_from_template (templ, padname); - GST_OBJECT_UNLOCK (osel); - - gst_pad_set_active (srcpad, TRUE); - gst_element_add_pad (GST_ELEMENT (osel), srcpad); - - /* Set the first requested src pad as active by default */ - if (osel->active_srcpad == NULL) { - osel->active_srcpad = srcpad; - } - g_free (padname); - - return srcpad; -} - -static void -gst_output_selector_release_pad (GstElement * element, GstPad * pad) -{ - GstOutputSelector *osel; - - osel = GST_OUTPUT_SELECTOR (element); - - GST_DEBUG_OBJECT (osel, "releasing pad"); - - gst_pad_set_active (pad, FALSE); - - gst_element_remove_pad (GST_ELEMENT_CAST (osel), pad); -} - -static gboolean -gst_output_selector_switch (GstOutputSelector * osel) -{ - gboolean res = FALSE; - GstEvent *ev = NULL; - GstSegment *seg = NULL; - gint64 start = 0, position = 0; - - /* Switch */ - GST_OBJECT_LOCK (GST_OBJECT (osel)); - GST_INFO ("switching to pad %" GST_PTR_FORMAT, osel->pending_srcpad); - if (gst_pad_is_linked (osel->pending_srcpad)) { - osel->active_srcpad = osel->pending_srcpad; - res = TRUE; - } - gst_object_unref (osel->pending_srcpad); - osel->pending_srcpad = NULL; - GST_OBJECT_UNLOCK (GST_OBJECT (osel)); - - /* Send NEWSEGMENT event and latest buffer if switching succeeded */ - if (res) { - /* Send NEWSEGMENT to the pad we are going to switch to */ - seg = &osel->segment; - /* If resending then mark newsegment start and position accordingly */ - if (osel->resend_latest && osel->latest_buffer && - GST_BUFFER_TIMESTAMP_IS_VALID (osel->latest_buffer)) { - start = position = GST_BUFFER_TIMESTAMP (osel->latest_buffer); - } else { - start = position = seg->last_stop; - } - ev = gst_event_new_new_segment (TRUE, seg->rate, - seg->format, start, seg->stop, position); - if (!gst_pad_push_event (osel->active_srcpad, ev)) { - GST_WARNING_OBJECT (osel, - "newsegment handling failed in %" GST_PTR_FORMAT, - osel->active_srcpad); - } - - /* Resend latest buffer to newly switched pad */ - if (osel->resend_latest && osel->latest_buffer) { - GST_INFO ("resending latest buffer"); - gst_pad_push (osel->active_srcpad, gst_buffer_ref (osel->latest_buffer)); - } - } else { - GST_WARNING_OBJECT (osel, "switch failed, pad not linked"); - } - - return res; -} - -static GstFlowReturn -gst_output_selector_chain (GstPad * pad, GstBuffer * buf) -{ - GstFlowReturn res; - GstOutputSelector *osel; - GstClockTime last_stop, duration; - - osel = GST_OUTPUT_SELECTOR (gst_pad_get_parent (pad)); - - /* - * The _switch function might push a buffer if 'resend-latest' is true. - * - * Elements/Applications (e.g. camerabin) might use pad probes to - * switch output-selector's active pad. If we simply switch and don't - * recheck any pending pad switch the following codepath could end - * up pushing a buffer on a non-active pad. This is bad. - * - * So we always should check the pending_srcpad before going further down - * the chain and pushing the new buffer - */ - while (osel->pending_srcpad) { - /* Do the switch */ - gst_output_selector_switch (osel); - } - - if (osel->latest_buffer) { - gst_buffer_unref (osel->latest_buffer); - osel->latest_buffer = NULL; - } - - if (osel->resend_latest) { - /* Keep reference to latest buffer to resend it after switch */ - osel->latest_buffer = gst_buffer_ref (buf); - } - - /* Keep track of last stop and use it in NEWSEGMENT start after - switching to a new src pad */ - last_stop = GST_BUFFER_TIMESTAMP (buf); - if (GST_CLOCK_TIME_IS_VALID (last_stop)) { - duration = GST_BUFFER_DURATION (buf); - if (GST_CLOCK_TIME_IS_VALID (duration)) { - last_stop += duration; - } - GST_LOG_OBJECT (osel, "setting last stop %" GST_TIME_FORMAT, - GST_TIME_ARGS (last_stop)); - gst_segment_set_last_stop (&osel->segment, osel->segment.format, last_stop); - } - - GST_LOG_OBJECT (osel, "pushing buffer to %" GST_PTR_FORMAT, - osel->active_srcpad); - res = gst_pad_push (osel->active_srcpad, buf); - gst_object_unref (osel); - - return res; -} - -static GstStateChangeReturn -gst_output_selector_change_state (GstElement * element, - GstStateChange transition) -{ - GstOutputSelector *sel; - GstStateChangeReturn result; - - sel = GST_OUTPUT_SELECTOR (element); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - break; - default: - break; - } - - result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_output_selector_reset (sel); - break; - default: - break; - } - - return result; -} - -static gboolean -gst_output_selector_handle_sink_event (GstPad * pad, GstEvent * event) -{ - gboolean res = TRUE; - GstOutputSelector *sel; - GstPad *output_pad = NULL; - - sel = GST_OUTPUT_SELECTOR (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT: - { - gboolean update; - GstFormat format; - gdouble rate, arate; - gint64 start, stop, time; - - gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, - &start, &stop, &time); - - GST_DEBUG_OBJECT (sel, - "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, " - "format %d, " "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %" - G_GINT64_FORMAT, update, rate, arate, format, start, stop, time); - - gst_segment_set_newsegment_full (&sel->segment, update, - rate, arate, format, start, stop, time); - - /* Send newsegment to all src pads */ - gst_pad_event_default (pad, event); - break; - } - case GST_EVENT_EOS: - /* Send eos to all src pads */ - gst_pad_event_default (pad, event); - break; - default: - /* Send other events to pending or active src pad */ - output_pad = - sel->pending_srcpad ? sel->pending_srcpad : sel->active_srcpad; - res = gst_pad_push_event (output_pad, event); - break; - } - - gst_object_unref (sel); - - return res; -} diff --git a/gst/selector/gstoutputselector.h b/gst/selector/gstoutputselector.h deleted file mode 100644 index 5389d4735..000000000 --- a/gst/selector/gstoutputselector.h +++ /dev/null @@ -1,66 +0,0 @@ -/* GStreamer - * Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.com>) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GST_OUTPUT_SELECTOR_H__ -#define __GST_OUTPUT_SELECTOR_H__ - -#include <gst/gst.h> - -G_BEGIN_DECLS - -#define GST_TYPE_OUTPUT_SELECTOR \ - (gst_output_selector_get_type()) -#define GST_OUTPUT_SELECTOR(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_OUTPUT_SELECTOR, GstOutputSelector)) -#define GST_OUTPUT_SELECTOR_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_OUTPUT_SELECTOR, GstOutputSelectorClass)) -#define GST_IS_OUTPUT_SELECTOR(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_OUTPUT_SELECTOR)) -#define GST_IS_OUTPUT_SELECTOR_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_OUTPUT_SELECTOR)) - -typedef struct _GstOutputSelector GstOutputSelector; -typedef struct _GstOutputSelectorClass GstOutputSelectorClass; - -struct _GstOutputSelector { - GstElement element; - - GstPad *sinkpad; - - GstPad *active_srcpad; - GstPad *pending_srcpad; - guint nb_srcpads; - - GstSegment segment; - - /* resend latest buffer after switch */ - gboolean resend_latest; - GstBuffer *latest_buffer; - -}; - -struct _GstOutputSelectorClass { - GstElementClass parent_class; -}; - -GType gst_output_selector_get_type (void); - -G_END_DECLS - -#endif /* __GST_OUTPUT_SELECTOR_H__ */ diff --git a/gst/selector/gstselector-marshal.list b/gst/selector/gstselector-marshal.list deleted file mode 100644 index 1102f04cb..000000000 --- a/gst/selector/gstselector-marshal.list +++ /dev/null @@ -1,2 +0,0 @@ -INT64:VOID -VOID:OBJECT,INT64,INT64 diff --git a/gst/selector/selector.vcproj b/gst/selector/selector.vcproj deleted file mode 100644 index f28880d73..000000000 --- a/gst/selector/selector.vcproj +++ /dev/null @@ -1,148 +0,0 @@ -<?xml version="1.0" encoding="Windows-1252"?> -<VisualStudioProject - ProjectType="Visual C++" - Version="7.10" - Name="selector" - ProjectGUID="{979C216F-0ACF-4956-AE00-055A42D678CF}" - Keyword="Win32Proj"> - <Platforms> - <Platform - Name="Win32"/> - </Platforms> - <Configurations> - <Configuration - Name="Debug|Win32" - OutputDirectory="../../win32/Debug" - IntermediateDirectory="../../win32/Debug" - ConfigurationType="2" - CharacterSet="2"> - <Tool - Name="VCCLCompilerTool" - Optimization="0" - AdditionalIncludeDirectories="../../../gstreamer/win32;../../../gstreamer;../../../gstreamer/libs;../../../glib;../../../glib/glib;../../../glib/gmodule;"../../gst-libs";../../../popt/include;../../../libxml2/include/libxml2" - PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;selector_EXPORTS;HAVE_CONFIG_H;_USE_MATH_DEFINES" - MinimalRebuild="TRUE" - BasicRuntimeChecks="3" - RuntimeLibrary="3" - UsePrecompiledHeader="0" - WarningLevel="3" - Detect64BitPortabilityProblems="TRUE" - DebugInformationFormat="4"/> - <Tool - Name="VCCustomBuildTool"/> - <Tool - Name="VCLinkerTool" - AdditionalDependencies="glib-2.0.lib gmodule-2.0.lib gthread-2.0.lib gobject-2.0.lib libgstreamer.lib gstbytestream.lib iconv.lib intl.lib" - OutputFile="$(OutDir)/gstselector.dll" - LinkIncremental="2" - AdditionalLibraryDirectories="../../../gstreamer/win32/Debug;../../../glib/glib;../../../glib/gmodule;../../../glib/gthread;../../../glib/gobject;../../../gettext/lib;../../../libiconv/lib" - ModuleDefinitionFile="" - GenerateDebugInformation="TRUE" - ProgramDatabaseFile="$(OutDir)/selectro.pdb" - SubSystem="2" - OptimizeReferences="2" - ImportLibrary="$(OutDir)/gstselectro.lib" - TargetMachine="1"/> - <Tool - Name="VCMIDLTool"/> - <Tool - Name="VCPostBuildEventTool" - CommandLine="copy /Y $(TargetPath) c:\gstreamer\plugins"/> - <Tool - Name="VCPreBuildEventTool"/> - <Tool - Name="VCPreLinkEventTool"/> - <Tool - Name="VCResourceCompilerTool"/> - <Tool - Name="VCWebServiceProxyGeneratorTool"/> - <Tool - Name="VCXMLDataGeneratorTool"/> - <Tool - Name="VCWebDeploymentTool"/> - <Tool - Name="VCManagedWrapperGeneratorTool"/> - <Tool - Name="VCAuxiliaryManagedWrapperGeneratorTool"/> - </Configuration> - <Configuration - Name="Release|Win32" - OutputDirectory="../../win32/Release" - IntermediateDirectory="../../win32/Release" - ConfigurationType="2" - CharacterSet="2"> - <Tool - Name="VCCLCompilerTool" - AdditionalIncludeDirectories="../../../gstreamer/win32;../../../gstreamer;../../../gstreamer/libs;../../../glib;../../../glib/glib;../../../glib/gmodule;"../../gst-libs";../../../popt/include;../../../libxml2/include/libxml2" - PreprocessorDefinitions="WIN32;NDEBUG;GST_DISABLE_GST_DEBUG;_WINDOWS;_USRDLL;selector_EXPORTS;HAVE_CONFIG_H;_USE_MATH_DEFINES" - RuntimeLibrary="2" - UsePrecompiledHeader="0" - WarningLevel="3" - Detect64BitPortabilityProblems="TRUE" - DebugInformationFormat="3"/> - <Tool - Name="VCCustomBuildTool"/> - <Tool - Name="VCLinkerTool" - AdditionalDependencies="glib-2.0.lib gmodule-2.0.lib gthread-2.0.lib gobject-2.0.lib libgstreamer.lib gstbytestream.lib iconv.lib intl.lib" - OutputFile="$(OutDir)/gstselector.dll" - LinkIncremental="1" - AdditionalLibraryDirectories="../../../gstreamer/win32/Release;../../../glib/glib;../../../glib/gmodule;../../../glib/gthread;../../../glib/gobject;../../../gettext/lib;../../../libiconv/lib" - ModuleDefinitionFile="" - GenerateDebugInformation="TRUE" - SubSystem="2" - OptimizeReferences="2" - EnableCOMDATFolding="2" - ImportLibrary="$(OutDir)/gstselector.lib" - TargetMachine="1"/> - <Tool - Name="VCMIDLTool"/> - <Tool - Name="VCPostBuildEventTool" - CommandLine="copy /Y $(TargetPath) c:\gstreamer\plugins"/> - <Tool - Name="VCPreBuildEventTool"/> - <Tool - Name="VCPreLinkEventTool"/> - <Tool - Name="VCResourceCompilerTool"/> - <Tool - Name="VCWebServiceProxyGeneratorTool"/> - <Tool - Name="VCXMLDataGeneratorTool"/> - <Tool - Name="VCWebDeploymentTool"/> - <Tool - Name="VCManagedWrapperGeneratorTool"/> - <Tool - Name="VCAuxiliaryManagedWrapperGeneratorTool"/> - </Configuration> - </Configurations> - <References> - </References> - <Files> - <Filter - Name="Source Files" - Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" - UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"> - <File - RelativePath=".\gstselector.c"> - </File> - </Filter> - <Filter - Name="Header Files" - Filter="h;hpp;hxx;hm;inl;inc;xsd" - UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"> - <File - RelativePath=".\gstselector.h"> - </File> - </Filter> - <Filter - Name="Resource Files" - Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" - UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"> - </Filter> - </Files> - <Globals> - </Globals> -</VisualStudioProject> diff --git a/gst/smoothwave/demo-osssrc.c b/gst/smoothwave/demo-osssrc.c deleted file mode 100644 index 9c55a3b35..000000000 --- a/gst/smoothwave/demo-osssrc.c +++ /dev/null @@ -1,52 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include <gtk/gtk.h> -#include <gst/gst.h> - -extern gboolean _gst_plugin_spew; - -gboolean idle_func (gpointer data); - -GtkWidget *drawingarea; - -int -main (int argc, char *argv[]) -{ - GstElement *bin; - GstElement *src; - GstElement *wave; - GstElement *ximage; - - gst_init (&argc, &argv); - gst_plugin_load ("libsmoothwave.so"); - gtk_init (&argc, &argv); - - bin = gst_pipeline_new ("bin"); - - src = gst_element_factory_make ("sinesrc", "src"); - wave = gst_element_factory_make ("smoothwave", "wave"); - ximage = gst_element_factory_make (DEFAULT_VIDEOSINK, "sink"); - g_return_val_if_fail (src != NULL, -1); - g_return_val_if_fail (wave != NULL, -1); - g_return_val_if_fail (ximage != NULL, -1); - - - gst_bin_add_many (GST_BIN (bin), src, wave, ximage, NULL); - g_return_val_if_fail (gst_element_link_many (src, wave, ximage, - NULL) != FALSE, -1); - - gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING); - g_idle_add (idle_func, bin); - - gtk_main (); - - return 0; -} - -gboolean -idle_func (gpointer data) -{ - gst_bin_iterate (GST_BIN (data)); - return TRUE; -} diff --git a/gst/valve/Makefile.am b/gst/valve/Makefile.am deleted file mode 100644 index 4662a13b5..000000000 --- a/gst/valve/Makefile.am +++ /dev/null @@ -1,9 +0,0 @@ -plugin_LTLIBRARIES = libgstvalve.la - -libgstvalve_la_SOURCES = gstvalve.c gstvalve.h - -libgstvalve_la_CFLAGS = $(GST_CFLAGS) -libgstvalve_la_LIBADD = $(GST_LIBS) -libgstvalve_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstvalve_la_LIBTOOLFLAGS = --tag=disable-static - diff --git a/gst/valve/gstvalve.c b/gst/valve/gstvalve.c deleted file mode 100644 index 977a4afa0..000000000 --- a/gst/valve/gstvalve.c +++ /dev/null @@ -1,284 +0,0 @@ -/* GStreamer - * Copyright 2007-2009 Collabora Ltd - * @author: Olivier Crete <olivier.crete@collabora.co.uk> - * Copyright 2007-2009 Nokia Corporation - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - */ - -/** - * SECTION:element-valve - * - * The valve is a simple element that drops buffers when the #GstValve::drop - * property is set to %TRUE and lets then through otherwise. - * - * Any downstream error received while the #GstValve::drop property is %FALSE - * is ignored. So downstream element can be set to %GST_STATE_NULL and removed, - * without using pad blocking. - * - * Last reviewed on 2008-02-10 (0.10.11) - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstvalve.h" - -#include <string.h> - -GST_DEBUG_CATEGORY (valve_debug); -#define GST_CAT_DEFAULT (valve_debug) - -static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -/* Valve signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -enum -{ - ARG_0, - ARG_DROP, -}; - - - - -static void gst_valve_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_valve_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec); - -static gboolean gst_valve_event (GstPad * pad, GstEvent * event); -static GstFlowReturn gst_valve_buffer_alloc (GstPad * pad, guint64 offset, - guint size, GstCaps * caps, GstBuffer ** buf); -static GstFlowReturn gst_valve_chain (GstPad * pad, GstBuffer * buffer); -static GstCaps *gst_valve_getcaps (GstPad * pad); - -#define _do_init(bla) \ - GST_DEBUG_CATEGORY_INIT (valve_debug, "valve", 0, "Valve"); - -GST_BOILERPLATE_FULL (GstValve, gst_valve, GstElement, - GST_TYPE_ELEMENT, _do_init); - -static void -gst_valve_base_init (gpointer klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&srctemplate)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sinktemplate)); - - gst_element_class_set_details_simple (element_class, "Valve element", - "Filter", - "This element drops all packets when drop is TRUE", - "Olivier Crete <olivier.crete@collabora.co.uk>"); -} - -static void -gst_valve_class_init (GstValveClass * klass) -{ - GObjectClass *gobject_class; - - gobject_class = (GObjectClass *) klass; - - gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_valve_set_property); - gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_valve_get_property); - - g_object_class_install_property (gobject_class, ARG_DROP, - g_param_spec_boolean ("drop", - "Drops all buffers if TRUE", - "If this property if TRUE, the element will drop all buffers, " - "if its FALSE, it will let them through", - FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -} - -static void -gst_valve_init (GstValve * valve, GstValveClass * klass) -{ - valve->drop = FALSE; - valve->discont = FALSE; - - valve->srcpad = gst_pad_new_from_static_template (&srctemplate, "src"); - gst_pad_set_getcaps_function (valve->srcpad, - GST_DEBUG_FUNCPTR (gst_valve_getcaps)); - gst_element_add_pad (GST_ELEMENT (valve), valve->srcpad); - - valve->sinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink"); - gst_pad_set_chain_function (valve->sinkpad, - GST_DEBUG_FUNCPTR (gst_valve_chain)); - gst_pad_set_event_function (valve->sinkpad, - GST_DEBUG_FUNCPTR (gst_valve_event)); - gst_pad_set_bufferalloc_function (valve->sinkpad, - GST_DEBUG_FUNCPTR (gst_valve_buffer_alloc)); - gst_pad_set_getcaps_function (valve->sinkpad, - GST_DEBUG_FUNCPTR (gst_valve_getcaps)); - gst_element_add_pad (GST_ELEMENT (valve), valve->sinkpad); -} - - -static void -gst_valve_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec) -{ - GstValve *valve = GST_VALVE (object); - - switch (prop_id) { - case ARG_DROP: - g_atomic_int_set (&valve->drop, g_value_get_boolean (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_valve_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec) -{ - GstValve *valve = GST_VALVE (object); - - switch (prop_id) { - case ARG_DROP: - g_value_set_boolean (value, g_atomic_int_get (&valve->drop)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static GstFlowReturn -gst_valve_chain (GstPad * pad, GstBuffer * buffer) -{ - GstValve *valve = GST_VALVE (GST_OBJECT_PARENT (pad)); - GstFlowReturn ret = GST_FLOW_OK; - - if (g_atomic_int_get (&valve->drop)) { - gst_buffer_unref (buffer); - valve->discont = TRUE; - } else { - if (valve->discont) { - buffer = gst_buffer_make_metadata_writable (buffer); - GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); - } - - ret = gst_pad_push (valve->srcpad, buffer); - } - - - /* Ignore errors if "drop" was changed while the thread was blocked - * downwards - */ - if (g_atomic_int_get (&valve->drop)) - ret = GST_FLOW_OK; - - return ret; -} - - -static gboolean -gst_valve_event (GstPad * pad, GstEvent * event) -{ - GstValve *valve = GST_VALVE (gst_pad_get_parent_element (pad)); - gboolean ret = TRUE; - - if (g_atomic_int_get (&valve->drop)) - gst_event_unref (event); - else - ret = gst_pad_push_event (valve->srcpad, event); - - /* Ignore errors if "drop" was changed while the thread was blocked - * downwards. - */ - if (g_atomic_int_get (&valve->drop)) - ret = TRUE; - - gst_object_unref (valve); - return ret; -} - -static GstFlowReturn -gst_valve_buffer_alloc (GstPad * pad, guint64 offset, guint size, - GstCaps * caps, GstBuffer ** buf) -{ - GstValve *valve = GST_VALVE (gst_pad_get_parent_element (pad)); - GstFlowReturn ret = GST_FLOW_OK; - - if (g_atomic_int_get (&valve->drop)) - *buf = NULL; - else - ret = gst_pad_alloc_buffer (valve->srcpad, offset, size, caps, buf); - - /* Ignore errors if "drop" was changed while the thread was blocked - * downwards - */ - if (g_atomic_int_get (&valve->drop)) - ret = GST_FLOW_OK; - - gst_object_unref (valve); - - return ret; -} - -static GstCaps * -gst_valve_getcaps (GstPad * pad) -{ - GstValve *valve = GST_VALVE (gst_pad_get_parent (pad)); - GstCaps *caps; - - if (pad == valve->sinkpad) - caps = gst_pad_peer_get_caps (valve->srcpad); - else - caps = gst_pad_peer_get_caps (valve->sinkpad); - - if (caps == NULL) - caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); - - gst_object_unref (valve); - - return caps; -} - - -static gboolean -plugin_init (GstPlugin * plugin) -{ - return gst_element_register (plugin, "valve", - GST_RANK_MARGINAL, GST_TYPE_VALVE); -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "valve", - "Valve", - plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/gst/valve/gstvalve.h b/gst/valve/gstvalve.h deleted file mode 100644 index 9e15df571..000000000 --- a/gst/valve/gstvalve.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Farsight Voice+Video library - * - * Copyright 2007 Collabora Ltd, - * Copyright 2007 Nokia Corporation - * @author: Olivier Crete <olivier.crete@collabora.co.uk> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - */ - -#ifndef __GST_VALVE_H__ -#define __GST_VALVE_H__ - -#include <gst/gst.h> - -G_BEGIN_DECLS -/* #define's don't like whitespacey bits */ -#define GST_TYPE_VALVE \ - (gst_valve_get_type()) -#define GST_VALVE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), \ - GST_TYPE_VALVE,GstValve)) -#define GST_VALVE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), \ - GST_TYPE_VALVE,GstValveClass)) -#define GST_IS_VALVE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VALVE)) -#define GST_IS_VALVE_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VALVE)) -typedef struct _GstValve GstValve; -typedef struct _GstValveClass GstValveClass; -typedef struct _GstValvePrivate GstValvePrivate; - -/** - * GstValve: - * - * The private valve structure - */ -struct _GstValve -{ - /*< private >*/ - GstElement parent; - - /* atomic boolean */ - volatile gint drop; - - /* Protected by the stream lock */ - gboolean discont; - - GstPad *srcpad; - GstPad *sinkpad; - - /*< private > */ - gpointer _gst_reserved[GST_PADDING]; -}; - -struct _GstValveClass -{ - GstElementClass parent_class; - - /*< private > */ - gpointer _gst_reserved[GST_PADDING]; -}; - -GType gst_valve_get_type (void); - -G_END_DECLS -#endif /* __GST_VALVE_H__ */ diff --git a/gst/videomeasure/gstvideomeasure_ssim.c b/gst/videomeasure/gstvideomeasure_ssim.c index acbe781a2..a99fa9ff3 100644 --- a/gst/videomeasure/gstvideomeasure_ssim.c +++ b/gst/videomeasure/gstvideomeasure_ssim.c @@ -1110,7 +1110,7 @@ gst_ssim_class_init (GstSSimClass * klass) gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&gst_ssim_sink_modified_template)); gst_element_class_set_details_simple (gstelement_class, "SSim", - "Filter/Converter/Video", + "Filter/Analyzer/Video", "Calculate Y-SSIM for n+2 YUV video streams", "РуÑлан Ижбулатов <lrn1986 _at_ gmail _dot_ com>"); diff --git a/gst/videoparsers/Makefile.am b/gst/videoparsers/Makefile.am new file mode 100644 index 000000000..028959d0f --- /dev/null +++ b/gst/videoparsers/Makefile.am @@ -0,0 +1,18 @@ +plugin_LTLIBRARIES = libgstvideoparsersbad.la + +libgstvideoparsersbad_la_SOURCES = plugin.c \ + h263parse.c gsth263parse.c \ + gsth264parse.c h264parse.c \ + gstdiracparse.c dirac_parse.c +libgstvideoparsersbad_la_CFLAGS = \ + $(GST_PLUGINS_BAD_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) +libgstvideoparsersbad_la_LIBADD = \ + $(top_builddir)/gst-libs/gst/baseparse/libgstbaseparse-$(GST_MAJORMINOR).la \ + $(GST_BASE_LIBS) $(GST_LIBS) +libgstvideoparsersbad_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstvideoparsersbad_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = gsth263parse.h h263parse.h \ + gsth264parse.h h264parse.h \ + gstdiracparse.h dirac_parse.h + diff --git a/gst/videoparsers/dirac_parse.c b/gst/videoparsers/dirac_parse.c new file mode 100644 index 000000000..3a3193d92 --- /dev/null +++ b/gst/videoparsers/dirac_parse.c @@ -0,0 +1,498 @@ + +#include "dirac_parse.h" +#include <string.h> + +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) + +typedef struct _Unpack Unpack; + +struct _Unpack +{ + unsigned char *data; + int n_bits_left; + int index; + int guard_bit; +}; + +static void schro_unpack_init_with_data (Unpack * unpack, unsigned char *data, + int n_bytes, unsigned int guard_bit); + +static unsigned int schro_unpack_decode_bit (Unpack * unpack); +static unsigned int schro_unpack_decode_uint (Unpack * unpack); + + +void schro_video_format_set_std_video_format (DiracSequenceHeader * format, + int index); +void schro_video_format_set_std_frame_rate (DiracSequenceHeader * format, + int index); +void schro_video_format_set_std_aspect_ratio (DiracSequenceHeader * format, + int index); +void schro_video_format_set_std_signal_range (DiracSequenceHeader * format, + int index); +void schro_video_format_set_std_colour_spec (DiracSequenceHeader * format, + int index); + + + + +int +dirac_sequence_header_parse (DiracSequenceHeader * header, + unsigned char *data, int n_bytes) +{ + int bit; + int index; + Unpack _unpack; + Unpack *unpack = &_unpack; + int major_version; + int minor_version; + int profile; + int level; + + memset (header, 0, sizeof (*header)); + + schro_unpack_init_with_data (unpack, data, n_bytes, 1); + + /* parse parameters */ + major_version = schro_unpack_decode_uint (unpack); + minor_version = schro_unpack_decode_uint (unpack); + profile = schro_unpack_decode_uint (unpack); + level = schro_unpack_decode_uint (unpack); + + /* base video header */ + index = schro_unpack_decode_uint (unpack); + schro_video_format_set_std_video_format (header, index); + + header->major_version = major_version; + header->minor_version = minor_version; + header->profile = profile; + header->level = level; + + /* source parameters */ + /* frame dimensions */ + bit = schro_unpack_decode_bit (unpack); + if (bit) { + header->width = schro_unpack_decode_uint (unpack); + header->height = schro_unpack_decode_uint (unpack); + } + + /* chroma header */ + bit = schro_unpack_decode_bit (unpack); + if (bit) { + header->chroma_format = schro_unpack_decode_uint (unpack); + } + + /* scan header */ + bit = schro_unpack_decode_bit (unpack); + if (bit) { + header->interlaced = schro_unpack_decode_uint (unpack); + } + + /* frame rate */ + bit = schro_unpack_decode_bit (unpack); + if (bit) { + index = schro_unpack_decode_uint (unpack); + if (index == 0) { + header->frame_rate_numerator = schro_unpack_decode_uint (unpack); + header->frame_rate_denominator = schro_unpack_decode_uint (unpack); + } else { + schro_video_format_set_std_frame_rate (header, index); + } + } + + /* aspect ratio */ + bit = schro_unpack_decode_bit (unpack); + if (bit) { + index = schro_unpack_decode_uint (unpack); + if (index == 0) { + header->aspect_ratio_numerator = schro_unpack_decode_uint (unpack); + header->aspect_ratio_denominator = schro_unpack_decode_uint (unpack); + } else { + schro_video_format_set_std_aspect_ratio (header, index); + } + } + + /* clean area */ + bit = schro_unpack_decode_bit (unpack); + if (bit) { + header->clean_width = schro_unpack_decode_uint (unpack); + header->clean_height = schro_unpack_decode_uint (unpack); + header->left_offset = schro_unpack_decode_uint (unpack); + header->top_offset = schro_unpack_decode_uint (unpack); + } + + /* signal range */ + bit = schro_unpack_decode_bit (unpack); + if (bit) { + index = schro_unpack_decode_uint (unpack); + if (index == 0) { + header->luma_offset = schro_unpack_decode_uint (unpack); + header->luma_excursion = schro_unpack_decode_uint (unpack); + header->chroma_offset = schro_unpack_decode_uint (unpack); + header->chroma_excursion = schro_unpack_decode_uint (unpack); + } else { + schro_video_format_set_std_signal_range (header, index); + } + } + + /* colour spec */ + bit = schro_unpack_decode_bit (unpack); + if (bit) { + index = schro_unpack_decode_uint (unpack); + schro_video_format_set_std_colour_spec (header, index); + if (index == 0) { + /* colour primaries */ + bit = schro_unpack_decode_bit (unpack); + if (bit) { + header->colour_primaries = schro_unpack_decode_uint (unpack); + } + /* colour matrix */ + bit = schro_unpack_decode_bit (unpack); + if (bit) { + header->colour_matrix = schro_unpack_decode_uint (unpack); + } + /* transfer function */ + bit = schro_unpack_decode_bit (unpack); + if (bit) { + header->transfer_function = schro_unpack_decode_uint (unpack); + } + } + } + + header->interlaced_coding = schro_unpack_decode_uint (unpack); + + return 1; +} + +/* standard stuff */ + +static DiracSequenceHeader schro_video_formats[] = { + {0, 0, 0, 0, + 0, /* custom */ + 640, 480, SCHRO_CHROMA_420, + FALSE, FALSE, + 24000, 1001, 1, 1, + 640, 480, 0, 0, + 0, 255, 128, 255, + 0, 0, 0}, + {0, 0, 0, 0, + 1, /* QSIF525 */ + 176, 120, SCHRO_CHROMA_420, + FALSE, FALSE, + 15000, 1001, 10, 11, + 176, 120, 0, 0, + 0, 255, 128, 255, + 1, 1, 0}, + {0, 0, 0, 0, + 2, /* QCIF */ + 176, 144, SCHRO_CHROMA_420, + FALSE, TRUE, + 25, 2, 12, 11, + 176, 144, 0, 0, + 0, 255, 128, 255, + 2, 1, 0}, + {0, 0, 0, 0, + 3, /* SIF525 */ + 352, 240, SCHRO_CHROMA_420, + FALSE, FALSE, + 15000, 1001, 10, 11, + 352, 240, 0, 0, + 0, 255, 128, 255, + 1, 1, 0}, + {0, 0, 0, 0, + 4, /* CIF */ + 352, 288, SCHRO_CHROMA_420, + FALSE, TRUE, + 25, 2, 12, 11, + 352, 288, 0, 0, + 0, 255, 128, 255, + 2, 1, 0}, + {0, 0, 0, 0, + 5, /* 4SIF525 */ + 704, 480, SCHRO_CHROMA_420, + FALSE, FALSE, + 15000, 1001, 10, 11, + 704, 480, 0, 0, + 0, 255, 128, 255, + 1, 1, 0}, + {0, 0, 0, 0, + 6, /* 4CIF */ + 704, 576, SCHRO_CHROMA_420, + FALSE, TRUE, + 25, 2, 12, 11, + 704, 576, 0, 0, + 0, 255, 128, 255, + 2, 1, 0}, + {0, 0, 0, 0, + 7, /* SD480I-60 */ + 720, 480, SCHRO_CHROMA_422, + TRUE, FALSE, + 30000, 1001, 10, 11, + 704, 480, 8, 0, + 64, 876, 512, 896, + 1, 1, 0}, + {0, 0, 0, 0, + 8, /* SD576I-50 */ + 720, 576, SCHRO_CHROMA_422, + TRUE, TRUE, + 25, 1, 12, 11, + 704, 576, 8, 0, + 64, 876, 512, 896, + 2, 1, 0}, + {0, 0, 0, 0, + 9, /* HD720P-60 */ + 1280, 720, SCHRO_CHROMA_422, + FALSE, TRUE, + 60000, 1001, 1, 1, + 1280, 720, 0, 0, + 64, 876, 512, 896, + 0, 0, 0}, + {0, 0, 0, 0, + 10, /* HD720P-50 */ + 1280, 720, SCHRO_CHROMA_422, + FALSE, TRUE, + 50, 1, 1, 1, + 1280, 720, 0, 0, + 64, 876, 512, 896, + 0, 0, 0}, + {0, 0, 0, 0, + 11, /* HD1080I-60 */ + 1920, 1080, SCHRO_CHROMA_422, + TRUE, TRUE, + 30000, 1001, 1, 1, + 1920, 1080, 0, 0, + 64, 876, 512, 896, + 0, 0, 0}, + {0, 0, 0, 0, + 12, /* HD1080I-50 */ + 1920, 1080, SCHRO_CHROMA_422, + TRUE, TRUE, + 25, 1, 1, 1, + 1920, 1080, 0, 0, + 64, 876, 512, 896, + 0, 0, 0}, + {0, 0, 0, 0, + 13, /* HD1080P-60 */ + 1920, 1080, SCHRO_CHROMA_422, + FALSE, TRUE, + 60000, 1001, 1, 1, + 1920, 1080, 0, 0, + 64, 876, 512, 896, + 0, 0, 0}, + {0, 0, 0, 0, + 14, /* HD1080P-50 */ + 1920, 1080, SCHRO_CHROMA_422, + FALSE, TRUE, + 50, 1, 1, 1, + 1920, 1080, 0, 0, + 64, 876, 512, 896, + 0, 0, 0}, + {0, 0, 0, 0, + 15, /* DC2K */ + 2048, 1080, SCHRO_CHROMA_444, + FALSE, TRUE, + 24, 1, 1, 1, + 2048, 1080, 0, 0, + 256, 3504, 2048, 3584, + 3, 0, 0}, + {0, 0, 0, 0, + 16, /* DC4K */ + 4096, 2160, SCHRO_CHROMA_444, + FALSE, TRUE, + 24, 1, 1, 1, + 2048, 1536, 0, 0, + 256, 3504, 2048, 3584, + 3, 0, 0}, +}; + +void +schro_video_format_set_std_video_format (DiracSequenceHeader * format, + int index) +{ + + if (index < 0 || index >= ARRAY_SIZE (schro_video_formats)) { + return; + } + + memcpy (format, schro_video_formats + index, sizeof (DiracSequenceHeader)); +} + +typedef struct _SchroFrameRate SchroFrameRate; +struct _SchroFrameRate +{ + int numerator; + int denominator; +}; + +static SchroFrameRate schro_frame_rates[] = { + {0, 0}, + {24000, 1001}, + {24, 1}, + {25, 1}, + {30000, 1001}, + {30, 1}, + {50, 1}, + {60000, 1001}, + {60, 1}, + {15000, 1001}, + {25, 2} +}; + +void +schro_video_format_set_std_frame_rate (DiracSequenceHeader * format, int index) +{ + if (index < 1 || index >= ARRAY_SIZE (schro_frame_rates)) { + return; + } + + format->frame_rate_numerator = schro_frame_rates[index].numerator; + format->frame_rate_denominator = schro_frame_rates[index].denominator; +} + +typedef struct _SchroPixelAspectRatio SchroPixelAspectRatio; +struct _SchroPixelAspectRatio +{ + int numerator; + int denominator; +}; + +static const SchroPixelAspectRatio schro_aspect_ratios[] = { + {0, 0}, + {1, 1}, + {10, 11}, + {12, 11}, + {40, 33}, + {16, 11}, + {4, 3} +}; + +void +schro_video_format_set_std_aspect_ratio (DiracSequenceHeader * format, + int index) +{ + if (index < 1 || index >= ARRAY_SIZE (schro_aspect_ratios)) { + return; + } + + format->aspect_ratio_numerator = schro_aspect_ratios[index].numerator; + format->aspect_ratio_denominator = schro_aspect_ratios[index].denominator; + +} + +typedef struct _SchroSignalRangeStruct SchroSignalRangeStruct; +struct _SchroSignalRangeStruct +{ + int luma_offset; + int luma_excursion; + int chroma_offset; + int chroma_excursion; +}; + +static const SchroSignalRangeStruct schro_signal_ranges[] = { + {0, 0, 0, 0}, + {0, 255, 128, 255}, + {16, 219, 128, 224}, + {64, 876, 512, 896}, + {256, 3504, 2048, 3584} +}; + +void +schro_video_format_set_std_signal_range (DiracSequenceHeader * format, int i) +{ + if (i < 1 || i >= ARRAY_SIZE (schro_signal_ranges)) { + return; + } + + format->luma_offset = schro_signal_ranges[i].luma_offset; + format->luma_excursion = schro_signal_ranges[i].luma_excursion; + format->chroma_offset = schro_signal_ranges[i].chroma_offset; + format->chroma_excursion = schro_signal_ranges[i].chroma_excursion; +} + +typedef struct _SchroColourSpecStruct SchroColourSpecStruct; +struct _SchroColourSpecStruct +{ + int colour_primaries; + int colour_matrix; + int transfer_function; +}; + +static const SchroColourSpecStruct schro_colour_specs[] = { + { /* Custom */ + SCHRO_COLOUR_PRIMARY_HDTV, + SCHRO_COLOUR_MATRIX_HDTV, + SCHRO_TRANSFER_CHAR_TV_GAMMA}, + { /* SDTV 525 */ + SCHRO_COLOUR_PRIMARY_SDTV_525, + SCHRO_COLOUR_MATRIX_SDTV, + SCHRO_TRANSFER_CHAR_TV_GAMMA}, + { /* SDTV 625 */ + SCHRO_COLOUR_PRIMARY_SDTV_625, + SCHRO_COLOUR_MATRIX_SDTV, + SCHRO_TRANSFER_CHAR_TV_GAMMA}, + { /* HDTV */ + SCHRO_COLOUR_PRIMARY_HDTV, + SCHRO_COLOUR_MATRIX_HDTV, + SCHRO_TRANSFER_CHAR_TV_GAMMA}, + { /* Cinema */ + SCHRO_COLOUR_PRIMARY_CINEMA, + SCHRO_COLOUR_MATRIX_HDTV, + SCHRO_TRANSFER_CHAR_TV_GAMMA} +}; + +void +schro_video_format_set_std_colour_spec (DiracSequenceHeader * format, int i) +{ + if (i < 0 || i >= ARRAY_SIZE (schro_colour_specs)) { + return; + } + + format->colour_primaries = schro_colour_specs[i].colour_primaries; + format->colour_matrix = schro_colour_specs[i].colour_matrix; + format->transfer_function = schro_colour_specs[i].transfer_function; +} + + +/* unpack */ + +static void +schro_unpack_init_with_data (Unpack * unpack, unsigned char *data, + int n_bytes, unsigned int guard_bit) +{ + memset (unpack, 0, sizeof (Unpack)); + + unpack->data = data; + unpack->n_bits_left = 8 * n_bytes; + unpack->guard_bit = guard_bit; +} + +static unsigned int +schro_unpack_decode_bit (Unpack * unpack) +{ + int bit; + + if (unpack->n_bits_left < 1) { + return unpack->guard_bit; + } + bit = (unpack->data[unpack->index >> 3] >> (7 - (unpack->index & 7))) & 1; + unpack->index++; + unpack->n_bits_left--; + + return bit; +} + +static unsigned int +schro_unpack_decode_uint (Unpack * unpack) +{ + int count; + int value; + + count = 0; + value = 0; + while (!schro_unpack_decode_bit (unpack)) { + count++; + value <<= 1; + value |= schro_unpack_decode_bit (unpack); + } + + return (1 << count) - 1 + value; +} diff --git a/gst/videoparsers/dirac_parse.h b/gst/videoparsers/dirac_parse.h new file mode 100644 index 000000000..9dc4ffec5 --- /dev/null +++ b/gst/videoparsers/dirac_parse.h @@ -0,0 +1,178 @@ + +#ifndef __DIRAC_PARSE_H__ +#define __DIRAC_PARSE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +typedef enum _SchroParseCode { + SCHRO_PARSE_CODE_SEQUENCE_HEADER = 0x00, + SCHRO_PARSE_CODE_END_OF_SEQUENCE = 0x10, + SCHRO_PARSE_CODE_AUXILIARY_DATA = 0x20, + SCHRO_PARSE_CODE_PADDING = 0x30, + + SCHRO_PARSE_CODE_INTRA_REF = 0x0c, + SCHRO_PARSE_CODE_INTRA_NON_REF = 0x08, + SCHRO_PARSE_CODE_INTRA_REF_NOARITH = 0x4c, + SCHRO_PARSE_CODE_INTRA_NON_REF_NOARITH = 0x48, + + SCHRO_PARSE_CODE_INTER_REF_1 = 0x0d, + SCHRO_PARSE_CODE_INTER_REF_1_NOARITH = 0x4d, + SCHRO_PARSE_CODE_INTER_REF_2 = 0x0e, + SCHRO_PARSE_CODE_INTER_REF_2_NOARITH = 0x4e, + + SCHRO_PARSE_CODE_INTER_NON_REF_1 = 0x09, + SCHRO_PARSE_CODE_INTER_NON_REF_1_NOARITH = 0x49, + SCHRO_PARSE_CODE_INTER_NON_REF_2 = 0x0a, + SCHRO_PARSE_CODE_INTER_NON_REF_2_NOARITH = 0x4a, + + SCHRO_PARSE_CODE_LD_INTRA_REF = 0xcc, + SCHRO_PARSE_CODE_LD_INTRA_NON_REF = 0xc8 +} SchroParseCode; + +#define SCHRO_PARSE_CODE_PICTURE(is_ref,n_refs,is_lowdelay,is_noarith) \ + (8 | ((is_ref)<<2) | (n_refs) | ((is_lowdelay)<<7) | ((is_noarith)<<6)) + +#define SCHRO_PARSE_CODE_IS_SEQ_HEADER(x) ((x) == SCHRO_PARSE_CODE_SEQUENCE_HEADER) +#define SCHRO_PARSE_CODE_IS_END_OF_SEQUENCE(x) ((x) == SCHRO_PARSE_CODE_END_OF_SEQUENCE) +#define SCHRO_PARSE_CODE_IS_AUXILIARY_DATA(x) ((x) == SCHRO_PARSE_CODE_AUXILIARY_DATA) +#define SCHRO_PARSE_CODE_IS_PADDING(x) ((x) == SCHRO_PARSE_CODE_PADDING) +#define SCHRO_PARSE_CODE_IS_PICTURE(x) ((x) & 0x8) +#define SCHRO_PARSE_CODE_IS_LOW_DELAY(x) (((x) & 0x88) == 0x88) +#define SCHRO_PARSE_CODE_IS_CORE_SYNTAX(x) (((x) & 0x88) == 0x08) +#define SCHRO_PARSE_CODE_USING_AC(x) (((x) & 0x48) == 0x08) +#define SCHRO_PARSE_CODE_IS_REFERENCE(x) (((x) & 0xc) == 0x0c) +#define SCHRO_PARSE_CODE_IS_NON_REFERENCE(x) (((x) & 0xc) == 0x08) +#define SCHRO_PARSE_CODE_NUM_REFS(x) ((x) & 0x3) +#define SCHRO_PARSE_CODE_IS_INTRA(x) (SCHRO_PARSE_CODE_IS_PICTURE(x) && SCHRO_PARSE_CODE_NUM_REFS(x) == 0) +#define SCHRO_PARSE_CODE_IS_INTER(x) (SCHRO_PARSE_CODE_IS_PICTURE(x) && SCHRO_PARSE_CODE_NUM_REFS(x) > 0) + +#define SCHRO_PARSE_HEADER_SIZE (4+1+4+4) + +typedef enum _SchroVideoFormatEnum { + SCHRO_VIDEO_FORMAT_CUSTOM = 0, + SCHRO_VIDEO_FORMAT_QSIF, + SCHRO_VIDEO_FORMAT_QCIF, + SCHRO_VIDEO_FORMAT_SIF, + SCHRO_VIDEO_FORMAT_CIF, + SCHRO_VIDEO_FORMAT_4SIF, + SCHRO_VIDEO_FORMAT_4CIF, + SCHRO_VIDEO_FORMAT_SD480I_60, + SCHRO_VIDEO_FORMAT_SD576I_50, + SCHRO_VIDEO_FORMAT_HD720P_60, + SCHRO_VIDEO_FORMAT_HD720P_50, + SCHRO_VIDEO_FORMAT_HD1080I_60, + SCHRO_VIDEO_FORMAT_HD1080I_50, + SCHRO_VIDEO_FORMAT_HD1080P_60, + SCHRO_VIDEO_FORMAT_HD1080P_50, + SCHRO_VIDEO_FORMAT_DC2K_24, + SCHRO_VIDEO_FORMAT_DC4K_24 +} SchroVideoFormatEnum; + +typedef enum _SchroChromaFormat { + SCHRO_CHROMA_444 = 0, + SCHRO_CHROMA_422, + SCHRO_CHROMA_420 +} SchroChromaFormat; + +#define SCHRO_CHROMA_FORMAT_H_SHIFT(format) (((format) == SCHRO_CHROMA_444)?0:1) +#define SCHRO_CHROMA_FORMAT_V_SHIFT(format) (((format) == SCHRO_CHROMA_420)?1:0) + +typedef enum _SchroSignalRange { + SCHRO_SIGNAL_RANGE_CUSTOM = 0, + SCHRO_SIGNAL_RANGE_8BIT_FULL = 1, + SCHRO_SIGNAL_RANGE_8BIT_VIDEO = 2, + SCHRO_SIGNAL_RANGE_10BIT_VIDEO = 3, + SCHRO_SIGNAL_RANGE_12BIT_VIDEO = 4 +} SchroSignalRange; + +typedef enum _SchroColourSpec { + SCHRO_COLOUR_SPEC_CUSTOM = 0, + SCHRO_COLOUR_SPEC_SDTV_525 = 1, + SCHRO_COLOUR_SPEC_SDTV_625 = 2, + SCHRO_COLOUR_SPEC_HDTV = 3, + SCHRO_COLOUR_SPEC_CINEMA = 4 +} SchroColourSpec; + +typedef enum _SchroColourPrimaries { + SCHRO_COLOUR_PRIMARY_HDTV = 0, + SCHRO_COLOUR_PRIMARY_SDTV_525 = 1, + SCHRO_COLOUR_PRIMARY_SDTV_625 = 2, + SCHRO_COLOUR_PRIMARY_CINEMA = 3 +} SchroColourPrimaries; + +typedef enum _SchroColourMatrix { + SCHRO_COLOUR_MATRIX_HDTV = 0, + SCHRO_COLOUR_MATRIX_SDTV = 1, + SCHRO_COLOUR_MATRIX_REVERSIBLE = 2 +}SchroColourMatrix; + +typedef enum _SchroTransferFunction { + SCHRO_TRANSFER_CHAR_TV_GAMMA = 0, + SCHRO_TRANSFER_CHAR_EXTENDED_GAMUT = 1, + SCHRO_TRANSFER_CHAR_LINEAR = 2, + SCHRO_TRANSFER_CHAR_DCI_GAMMA = 3 +} SchroTransferFunction; + + + +typedef struct _DiracSequenceHeader DiracSequenceHeader; + +struct _DiracSequenceHeader { + int major_version; + int minor_version; + int profile; + int level; + + int index; + int width; + int height; + int chroma_format; + + int interlaced; + int top_field_first; + + int frame_rate_numerator; + int frame_rate_denominator; + int aspect_ratio_numerator; + int aspect_ratio_denominator; + + int clean_width; + int clean_height; + int left_offset; + int top_offset; + + int luma_offset; + int luma_excursion; + int chroma_offset; + int chroma_excursion; + + int colour_primaries; + int colour_matrix; + int transfer_function; + + int interlaced_coding; + + int unused0; + int unused1; + int unused2; +}; + + +int dirac_sequence_header_parse (DiracSequenceHeader *header, + unsigned char *data, int length); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/gst/videoparsers/gstdiracparse.c b/gst/videoparsers/gstdiracparse.c new file mode 100644 index 000000000..4ddcd3a5a --- /dev/null +++ b/gst/videoparsers/gstdiracparse.c @@ -0,0 +1,352 @@ +/* GStreamer + * Copyright (C) 2010 David Schleef <ds@schleef.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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/** + * SECTION:element-gstdiracparse + * + * The gstdiracparse element does FIXME stuff. + * + * <refsect2> + * <title>Example launch line</title> + * |[ + * gst-launch -v fakesrc ! gstdiracparse ! FIXME ! fakesink + * ]| + * FIXME Describe what the pipeline does. + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gst/gst.h> +#include <gst/base/gstbytereader.h> +#include <gst/baseparse/gstbaseparse.h> +#include "gstdiracparse.h" + +/* prototypes */ + + +static void gst_dirac_parse_set_property (GObject * object, + guint property_id, const GValue * value, GParamSpec * pspec); +static void gst_dirac_parse_get_property (GObject * object, + guint property_id, GValue * value, GParamSpec * pspec); +static void gst_dirac_parse_dispose (GObject * object); +static void gst_dirac_parse_finalize (GObject * object); + +static gboolean gst_dirac_parse_start (GstBaseParse * parse); +static gboolean gst_dirac_parse_stop (GstBaseParse * parse); +static gboolean gst_dirac_parse_set_sink_caps (GstBaseParse * parse, + GstCaps * caps); +static gboolean gst_dirac_parse_check_valid_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, guint * framesize, gint * skipsize); +static GstFlowReturn gst_dirac_parse_parse_frame (GstBaseParse * parse, + GstBaseParseFrame * frame); +static gboolean gst_dirac_parse_convert (GstBaseParse * parse, + GstFormat src_format, gint64 src_value, GstFormat dest_format, + gint64 * dest_value); +static gboolean gst_dirac_parse_event (GstBaseParse * parse, GstEvent * event); +static gboolean gst_dirac_parse_src_event (GstBaseParse * parse, + GstEvent * event); +static GstFlowReturn gst_dirac_parse_pre_push_frame (GstBaseParse * parse, + GstBaseParseFrame * frame); + +enum +{ + PROP_0 +}; + +/* pad templates */ + +static GstStaticPadTemplate gst_dirac_parse_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/unknown") + ); + +static GstStaticPadTemplate gst_dirac_parse_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/unknown") + ); + +/* class initialization */ + +GST_BOILERPLATE (GstDiracParse, gst_dirac_parse, GstBaseParse, + GST_TYPE_BASE_PARSE); + +static void +gst_dirac_parse_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_dirac_parse_src_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_dirac_parse_sink_template)); + + gst_element_class_set_details_simple (element_class, "FIXME", + "Generic", "FIXME", "David Schleef <ds@schleef.org>"); +} + +static void +gst_dirac_parse_class_init (GstDiracParseClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstBaseParseClass *base_parse_class = GST_BASE_PARSE_CLASS (klass); + + gobject_class->set_property = gst_dirac_parse_set_property; + gobject_class->get_property = gst_dirac_parse_get_property; + gobject_class->dispose = gst_dirac_parse_dispose; + gobject_class->finalize = gst_dirac_parse_finalize; + base_parse_class->start = GST_DEBUG_FUNCPTR (gst_dirac_parse_start); + base_parse_class->stop = GST_DEBUG_FUNCPTR (gst_dirac_parse_stop); + base_parse_class->set_sink_caps = + GST_DEBUG_FUNCPTR (gst_dirac_parse_set_sink_caps); + base_parse_class->check_valid_frame = + GST_DEBUG_FUNCPTR (gst_dirac_parse_check_valid_frame); + base_parse_class->parse_frame = + GST_DEBUG_FUNCPTR (gst_dirac_parse_parse_frame); + base_parse_class->convert = GST_DEBUG_FUNCPTR (gst_dirac_parse_convert); + base_parse_class->event = GST_DEBUG_FUNCPTR (gst_dirac_parse_event); + base_parse_class->src_event = GST_DEBUG_FUNCPTR (gst_dirac_parse_src_event); + base_parse_class->pre_push_frame = + GST_DEBUG_FUNCPTR (gst_dirac_parse_pre_push_frame); + +} + +static void +gst_dirac_parse_init (GstDiracParse * diracparse, + GstDiracParseClass * diracparse_class) +{ + gst_base_parse_set_min_frame_size (GST_BASE_PARSE (diracparse), 13); + +} + +void +gst_dirac_parse_set_property (GObject * object, guint property_id, + const GValue * value, GParamSpec * pspec) +{ + GstDiracParse *diracparse; + + g_return_if_fail (GST_IS_DIRAC_PARSE (object)); + diracparse = GST_DIRAC_PARSE (object); + + switch (property_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +void +gst_dirac_parse_get_property (GObject * object, guint property_id, + GValue * value, GParamSpec * pspec) +{ + GstDiracParse *diracparse; + + g_return_if_fail (GST_IS_DIRAC_PARSE (object)); + diracparse = GST_DIRAC_PARSE (object); + + switch (property_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +void +gst_dirac_parse_dispose (GObject * object) +{ + GstDiracParse *diracparse; + + g_return_if_fail (GST_IS_DIRAC_PARSE (object)); + diracparse = GST_DIRAC_PARSE (object); + + /* clean up as possible. may be called multiple times */ + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +void +gst_dirac_parse_finalize (GObject * object) +{ + GstDiracParse *diracparse; + + g_return_if_fail (GST_IS_DIRAC_PARSE (object)); + diracparse = GST_DIRAC_PARSE (object); + + /* clean up object here */ + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + + +static gboolean +gst_dirac_parse_start (GstBaseParse * parse) +{ + return TRUE; +} + +static gboolean +gst_dirac_parse_stop (GstBaseParse * parse) +{ + return TRUE; +} + +static gboolean +gst_dirac_parse_set_sink_caps (GstBaseParse * parse, GstCaps * caps) +{ + /* Called when sink caps are set */ + return TRUE; +} + +static gboolean +gst_dirac_parse_frame_header (GstDiracParse * diracparse, + GstBuffer * buffer, guint * framesize) +{ + int next_header; + + next_header = GST_READ_UINT32_BE (GST_BUFFER_DATA (buffer) + 5); + + *framesize = next_header; + return TRUE; +} + +static gboolean +gst_dirac_parse_check_valid_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, guint * framesize, gint * skipsize) +{ + GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (frame->buffer); + GstDiracParse *diracparse = GST_DIRAC_PARSE (parse); + int off; + guint32 next_header; + gboolean sync; + gboolean drain; + + if (G_UNLIKELY (GST_BUFFER_SIZE (frame->buffer) < 13)) + return FALSE; + + off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffffff, + 0x42424344, 0, GST_BUFFER_SIZE (frame->buffer)); + + if (off < 0) { + *skipsize = GST_BUFFER_SIZE (frame->buffer) - 3; + return FALSE; + } + + GST_LOG_OBJECT (parse, "possible sync at buffer offset %d", off); + + if (off > 0) { + GST_ERROR ("skipping %d", off); + *skipsize = off; + return FALSE; + } + + if (!gst_dirac_parse_frame_header (diracparse, frame->buffer, framesize)) { + GST_ERROR ("bad header"); + *skipsize = 3; + return FALSE; + } + + GST_LOG ("framesize %d", *framesize); + + sync = GST_BASE_PARSE_FRAME_SYNC (frame); + drain = GST_BASE_PARSE_FRAME_DRAIN (frame); + + if (!sync && !drain) { + guint32 next_sync_word; + + next_header = GST_READ_UINT32_BE (GST_BUFFER_DATA (frame->buffer) + 5); + GST_LOG ("next header %d", next_header); + + if (!gst_byte_reader_skip (&reader, next_header) || + !gst_byte_reader_get_uint32_be (&reader, &next_sync_word)) { + gst_base_parse_set_min_frame_size (parse, next_header + 4); + *skipsize = 0; + return FALSE; + } else { + if (next_sync_word != 0x42424344) { + *skipsize = 3; + return FALSE; + } else { + gst_base_parse_set_min_frame_size (parse, next_header); + + } + } + } + + return TRUE; +} + +static GstFlowReturn +gst_dirac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) +{ + //GstDiracParse * diracparse = GST_DIRAC_PARSE (parse); + + /* Called when processing incoming buffers. Function should parse + a checked frame. */ + /* MUST implement */ + + if (GST_PAD_CAPS (GST_BASE_PARSE_SRC_PAD (parse)) == NULL) { + GstCaps *caps = gst_caps_new_simple ("video/x-dirac", NULL); + + gst_buffer_set_caps (frame->buffer, caps); + gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps); + gst_caps_unref (caps); + + } + + gst_base_parse_set_min_frame_size (parse, 13); + + return GST_FLOW_OK; +} + +static gboolean +gst_dirac_parse_convert (GstBaseParse * parse, GstFormat src_format, + gint64 src_value, GstFormat dest_format, gint64 * dest_value) +{ + /* Convert between formats */ + + return FALSE; +} + +static gboolean +gst_dirac_parse_event (GstBaseParse * parse, GstEvent * event) +{ + /* Sink pad event handler */ + + return FALSE; +} + +static gboolean +gst_dirac_parse_src_event (GstBaseParse * parse, GstEvent * event) +{ + /* Src pad event handler */ + + return FALSE; +} + +static GstFlowReturn +gst_dirac_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame) +{ + + return GST_FLOW_OK; +} diff --git a/gst/videoparsers/gstdiracparse.h b/gst/videoparsers/gstdiracparse.h new file mode 100644 index 000000000..64a1b8123 --- /dev/null +++ b/gst/videoparsers/gstdiracparse.h @@ -0,0 +1,52 @@ +/* GStreamer + * Copyright (C) 2010 REAL_NAME <EMAIL_ADDRESS> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _GST_DIRAC_PARSE_H_ +#define _GST_DIRAC_PARSE_H_ + +#include <gst/gst.h> +#include <gst/baseparse/gstbaseparse.h> + +G_BEGIN_DECLS + +#define GST_TYPE_DIRAC_PARSE (gst_dirac_parse_get_type()) +#define GST_DIRAC_PARSE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DIRAC_PARSE,GstDiracParse)) +#define GST_DIRAC_PARSE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DIRAC_PARSE,GstDiracParseClass)) +#define GST_IS_DIRAC_PARSE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DIRAC_PARSE)) +#define GST_IS_DIRAC_PARSE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DIRAC_PARSE)) + +typedef struct _GstDiracParse GstDiracParse; +typedef struct _GstDiracParseClass GstDiracParseClass; + +struct _GstDiracParse +{ + GstBaseParse base_diracparse; + +}; + +struct _GstDiracParseClass +{ + GstBaseParseClass base_diracparse_class; +}; + +GType gst_dirac_parse_get_type (void); + +G_END_DECLS + +#endif diff --git a/gst/videoparsers/gsth263parse.c b/gst/videoparsers/gsth263parse.c new file mode 100644 index 000000000..b727f6212 --- /dev/null +++ b/gst/videoparsers/gsth263parse.c @@ -0,0 +1,359 @@ +/* GStreamer H.263 Parser + * Copyright (C) <2010> Arun Raghavan <arun.raghavan@collabora.co.uk> + * Copyright (C) <2010> Edward Hervey <edward.hervey@collabora.co.uk> + * Copyright (C) <2010> Collabora Multimedia + * Copyright (C) <2010> Nokia Corporation + * + * Some bits C-c,C-v'ed and s/4/3 from h264parse: + * (C) 2005 Michal Benes <michal.benes@itonis.tv> + * (C) 2008 Wim Taymans <wim.taymans@gmail.com> + * (C) 2009 Mark Nauwelaerts <mnauw users sf 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <gst/base/gstbytereader.h> +#include "gsth263parse.h" + +GST_DEBUG_CATEGORY (h263_parse_debug); +#define GST_CAT_DEFAULT h263_parse_debug + +static GstStaticPadTemplate srctemplate = +GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-h263, variant = (string) itu, " + "parsed = (boolean) true") + ); + +static GstStaticPadTemplate sinktemplate = +GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-h263, variant = (string) itu, " + "parsed = (boolean) false") + ); + +GST_BOILERPLATE (GstH263Parse, gst_h263_parse, GstElement, GST_TYPE_BASE_PARSE); + +static gboolean gst_h263_parse_start (GstBaseParse * parse); +static gboolean gst_h263_parse_stop (GstBaseParse * parse); +static gboolean gst_h263_parse_sink_event (GstBaseParse * parse, + GstEvent * event); +static gboolean gst_h263_parse_check_valid_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, guint * framesize, gint * skipsize); +static GstFlowReturn gst_h263_parse_parse_frame (GstBaseParse * parse, + GstBaseParseFrame * frame); + +static void +gst_h263_parse_base_init (gpointer g_class) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&srctemplate)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&sinktemplate)); + gst_element_class_set_details_simple (gstelement_class, "H.263 parser", + "Codec/Parser/Video", + "Parses H.263 streams", + "Arun Raghavan <arun.raghavan@collabora.co.uk>," + "Edward Hervey <edward.hervey@collabora.co.uk>"); + + GST_DEBUG_CATEGORY_INIT (h263_parse_debug, "h263parse", 0, "h263 parser"); +} + +static void +gst_h263_parse_class_init (GstH263ParseClass * klass) +{ + GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass); + + /* Override BaseParse vfuncs */ + parse_class->start = GST_DEBUG_FUNCPTR (gst_h263_parse_start); + parse_class->stop = GST_DEBUG_FUNCPTR (gst_h263_parse_stop); + parse_class->event = GST_DEBUG_FUNCPTR (gst_h263_parse_sink_event); + parse_class->check_valid_frame = + GST_DEBUG_FUNCPTR (gst_h263_parse_check_valid_frame); + parse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_h263_parse_parse_frame); +} + +static void +gst_h263_parse_init (GstH263Parse * h263parse, GstH263ParseClass * g_class) +{ +} + +static gboolean +gst_h263_parse_start (GstBaseParse * parse) +{ + GstH263Parse *h263parse = GST_H263_PARSE (parse); + + GST_DEBUG ("Start"); + + h263parse->bitrate = 0; + h263parse->profile = -1; + h263parse->level = -1; + + h263parse->state = PARSING; + + gst_base_parse_set_min_frame_size (parse, 512); + + return TRUE; +} + +static gboolean +gst_h263_parse_stop (GstBaseParse * parse) +{ + GST_DEBUG ("Stop"); + + return TRUE; +} + +static gboolean +gst_h263_parse_sink_event (GstBaseParse * parse, GstEvent * event) +{ + GstH263Parse *h263parse; + gboolean res = FALSE; + + h263parse = GST_H263_PARSE (parse); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_TAG: + { + GstTagList *taglist; + + gst_event_parse_tag (event, &taglist); + + if (gst_tag_list_get_uint (taglist, GST_TAG_BITRATE, &h263parse->bitrate)) + GST_DEBUG ("Got bitrate tag: %u", h263parse->bitrate); + + break; + } + + default: + break; + } + + return res; +} + +static guint +find_psc (GstBuffer * buffer, guint skip) +{ + GstByteReader br; + guint psc_pos = -1, psc; + + gst_byte_reader_init_from_buffer (&br, buffer); + + if (!gst_byte_reader_set_pos (&br, skip)) + goto out; + + gst_byte_reader_peek_uint24_be (&br, &psc); + + /* Scan for the picture start code (22 bits - 0x0020) */ + while ((gst_byte_reader_get_remaining (&br) >= 3)) { + if (gst_byte_reader_peek_uint24_be (&br, &psc) && + ((psc & 0xffffc0) == 0x000080)) { + psc_pos = gst_byte_reader_get_pos (&br); + break; + } else + gst_byte_reader_skip (&br, 1); + } + +out: + return psc_pos; +} + +static void +gst_h263_parse_set_src_caps (GstH263Parse * h263parse, H263Params * params) +{ + GstStructure *st; + GstCaps *caps, *sink_caps; + gint fr_num, fr_denom; + + g_assert (h263parse->state == PASSTHROUGH || h263parse->state == GOT_HEADER); + + caps = GST_PAD_CAPS (GST_BASE_PARSE_SINK_PAD (h263parse)); + if (caps) { + caps = gst_caps_copy (caps); + } else { + caps = gst_caps_new_simple ("video/x-h263", + "variant", G_TYPE_STRING, "itu", NULL); + } + gst_caps_set_simple (caps, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); + + sink_caps = GST_PAD_CAPS (GST_BASE_PARSE_SINK_PAD (h263parse)); + if (sink_caps && (st = gst_caps_get_structure (sink_caps, 0)) && + gst_structure_get_fraction (st, "framerate", &fr_num, &fr_denom)) { + /* Got it in caps - nothing more to do */ + GST_DEBUG ("Sink caps override framerate from headers"); + } else { + /* Caps didn't have the framerate - get it from params */ + gst_h263_parse_get_framerate (params, &fr_num, &fr_denom); + } + gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, fr_num, fr_denom, + NULL); + + if (h263parse->state == GOT_HEADER) { + gst_caps_set_simple (caps, + "annex-d", G_TYPE_BOOLEAN, (params->features & H263_OPTION_UMV_MODE), + "annex-e", G_TYPE_BOOLEAN, (params->features & H263_OPTION_SAC_MODE), + "annex-f", G_TYPE_BOOLEAN, (params->features & H263_OPTION_AP_MODE), + "annex-g", G_TYPE_BOOLEAN, (params->features & H263_OPTION_PB_MODE), + "annex-i", G_TYPE_BOOLEAN, (params->features & H263_OPTION_AIC_MODE), + "annex-j", G_TYPE_BOOLEAN, (params->features & H263_OPTION_DF_MODE), + "annex-k", G_TYPE_BOOLEAN, (params->features & H263_OPTION_SS_MODE), + "annex-m", G_TYPE_BOOLEAN, (params->type == PICTURE_IMPROVED_PB), + "annex-n", G_TYPE_BOOLEAN, (params->features & H263_OPTION_RPS_MODE), + "annex-q", G_TYPE_BOOLEAN, (params->features & H263_OPTION_RRU_MODE), + "annex-r", G_TYPE_BOOLEAN, (params->features & H263_OPTION_ISD_MODE), + "annex-s", G_TYPE_BOOLEAN, (params->features & H263_OPTION_AIV_MODE), + "annex-t", G_TYPE_BOOLEAN, (params->features & H263_OPTION_MQ_MODE), + "annex-u", G_TYPE_BOOLEAN, (params->features & H263_OPTION_ERPS_MODE), + "annex-v", G_TYPE_BOOLEAN, (params->features & H263_OPTION_DPS_MODE), + NULL); + + h263parse->profile = gst_h263_parse_get_profile (params); + if (h263parse->profile != -1) + gst_caps_set_simple (caps, "profile", G_TYPE_UINT, h263parse->profile, + NULL); + + h263parse->level = gst_h263_parse_get_level (params, h263parse->profile, + h263parse->bitrate, fr_num, fr_denom); + if (h263parse->level != -1) + gst_caps_set_simple (caps, "level", G_TYPE_UINT, h263parse->level, NULL); + } + + gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (GST_BASE_PARSE (h263parse)), caps); + gst_caps_unref (caps); +} + +static gboolean +gst_h263_parse_check_valid_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, guint * framesize, gint * skipsize) +{ + GstH263Parse *h263parse; + GstBuffer *buffer; + guint psc_pos, next_psc_pos; + + h263parse = GST_H263_PARSE (parse); + buffer = frame->buffer; + + if (GST_BUFFER_SIZE (buffer) < 3) + return FALSE; + + psc_pos = find_psc (buffer, 0); + + if (psc_pos == -1) { + /* PSC not found, need more data */ + if (GST_BUFFER_SIZE (buffer) > 3) + psc_pos = GST_BUFFER_SIZE (buffer) - 3; + else + psc_pos = 0; + goto more; + } + + /* Found the start of the frame, now try to find the end */ + next_psc_pos = psc_pos + 3; + next_psc_pos = find_psc (buffer, next_psc_pos); + + if (next_psc_pos == -1) { + if (GST_BASE_PARSE_FRAME_DRAIN (frame)) + /* FLUSH/EOS, it's okay if we can't find the next frame */ + next_psc_pos = GST_BUFFER_SIZE (buffer); + else + goto more; + } + + /* We should now have a complete frame */ + + /* If this is the first frame, parse and set srcpad caps */ + if (h263parse->state == PARSING) { + H263Params *params = NULL; + GstFlowReturn res; + + res = gst_h263_parse_get_params (¶ms, buffer, FALSE, &h263parse->state); + if (res != GST_FLOW_OK || h263parse->state != GOT_HEADER) { + GST_WARNING ("Couldn't parse header - setting passthrough mode"); + gst_base_parse_set_format (parse, + GST_BASE_PARSE_FORMAT_PASSTHROUGH, TRUE); + } else { + /* Set srcpad caps since we now have sufficient information to do so */ + gst_h263_parse_set_src_caps (h263parse, params); + } + + if (params) + g_free (params); + } + + *skipsize = psc_pos; + *framesize = next_psc_pos - psc_pos; + + /* XXX: After getting a keyframe, should we adjust min_frame_size to + * something smaller so we don't end up collecting too many non-keyframes? */ + + GST_DEBUG ("Found a frame of size %d at pos %d", *framesize, *skipsize); + + return TRUE; + +more: + /* Ask for 1024 bytes more - this is an arbitrary choice */ + gst_base_parse_set_min_frame_size (parse, GST_BUFFER_SIZE (buffer) + 1024); + + *skipsize = psc_pos; + + return FALSE; +} + +static GstFlowReturn +gst_h263_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) +{ + GstH263Parse *h263parse; + GstBuffer *buffer; + GstFlowReturn res; + H263Params *params = NULL; + + h263parse = GST_H263_PARSE (parse); + buffer = frame->buffer; + + res = gst_h263_parse_get_params (¶ms, buffer, TRUE, &h263parse->state); + if (res != GST_FLOW_OK) + goto out; + + if (h263parse->state == PASSTHROUGH || h263parse->state == PARSING) { + /* There's a feature we don't support, or we didn't have enough data to + * parse the header, which should not be possible. Either way, go into + * passthrough mode and let downstream handle it if it can. */ + GST_WARNING ("Couldn't parse header - setting passthrough mode"); + gst_base_parse_set_format (parse, GST_BASE_PARSE_FORMAT_PASSTHROUGH, TRUE); + goto out; + } + + /* h263parse->state is now GOT_HEADER */ + + gst_buffer_set_caps (buffer, + GST_PAD_CAPS (GST_BASE_PARSE_SRC_PAD (GST_BASE_PARSE (h263parse)))); + + if (gst_h263_parse_is_delta_unit (params)) + GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT); + else + GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT); + +out: + g_free (params); + return res; +} diff --git a/gst/videoparsers/gsth263parse.h b/gst/videoparsers/gsth263parse.h new file mode 100644 index 000000000..571f100d5 --- /dev/null +++ b/gst/videoparsers/gsth263parse.h @@ -0,0 +1,71 @@ +/* GStreamer H.263 Parser + * Copyright (C) <2010> Arun Raghavan <arun.raghavan@collabora.co.uk> + * Copyright (C) <2010> Edward Hervey <edward.hervey@collabora.co.uk> + * Copyright (C) <2010> Collabora Multimedia + * Copyright (C) <2010> Nokia Corporation + * + * Some bits C-c,C-v'ed and s/4/3 from h264parse: + * (C) 2005 Michal Benes <michal.benes@itonis.tv> + * (C) 2008 Wim Taymans <wim.taymans@gmail.com> + * (C) 2009 Mark Nauwelaerts <mnauw users sf 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_H263_PARSE_H__ +#define __GST_H263_PARSE_H__ + +#include <gst/gst.h> +#include <gst/base/gstadapter.h> +#include <gst/baseparse/gstbaseparse.h> + +#include "h263parse.h" + +G_BEGIN_DECLS + +#define GST_TYPE_H263_PARSE \ + (gst_h263_parse_get_type()) +#define GST_H263_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_H263_PARSE,GstH263Parse)) +#define GST_H263_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_H263_PARSE,GstH263ParseClass)) +#define GST_IS_H263_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_H263_PARSE)) +#define GST_IS_H263_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_H263_PARSE)) + +GType gst_h263_parse_get_type (void); + +typedef struct _GstH263Parse GstH263Parse; +typedef struct _GstH263ParseClass GstH263ParseClass; + +struct _GstH263Parse +{ + GstBaseParse baseparse; + + gint profile, level; + guint bitrate; + + H263ParseState state; +}; + +struct _GstH263ParseClass +{ + GstBaseParseClass parent_class; +}; + +G_END_DECLS +#endif diff --git a/gst/videoparsers/gsth264parse.c b/gst/videoparsers/gsth264parse.c new file mode 100644 index 000000000..799303ea3 --- /dev/null +++ b/gst/videoparsers/gsth264parse.c @@ -0,0 +1,1150 @@ +/* GStreamer H.264 Parser + * Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + * Copyright (C) <2010> Collabora Multimedia + * Copyright (C) <2010> Nokia Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <gst/base/gstbytereader.h> +#include <gst/base/gstbytewriter.h> +#include "gsth264parse.h" + +#include <string.h> + +GST_DEBUG_CATEGORY (h264_parse_debug); +#define GST_CAT_DEFAULT h264_parse_debug + +#define DEFAULT_SPLIT_PACKETIZED FALSE +#define DEFAULT_CONFIG_INTERVAL (0) + +enum +{ + PROP_0, + PROP_SPLIT_PACKETIZED, + PROP_CONFIG_INTERVAL, + PROP_LAST +}; + +enum +{ + GST_H264_PARSE_FORMAT_NONE, + GST_H264_PARSE_FORMAT_AVC, + GST_H264_PARSE_FORMAT_BYTE +}; + +enum +{ + GST_H264_PARSE_ALIGN_NONE = 0, + GST_H264_PARSE_ALIGN_NAL, + GST_H264_PARSE_ALIGN_AU +}; + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-h264, parsed = (boolean) false")); + +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-h264, parsed = (boolean) true")); + +GST_BOILERPLATE (GstH264Parse, gst_h264_parse, GstElement, GST_TYPE_BASE_PARSE); + +static void gst_h264_parse_finalize (GObject * object); + +static gboolean gst_h264_parse_start (GstBaseParse * parse); +static gboolean gst_h264_parse_stop (GstBaseParse * parse); +static gboolean gst_h264_parse_check_valid_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, guint * framesize, gint * skipsize); +static GstFlowReturn gst_h264_parse_parse_frame (GstBaseParse * parse, + GstBaseParseFrame * frame); +static GstFlowReturn gst_h264_parse_pre_push_frame (GstBaseParse * parse, + GstBaseParseFrame * frame); + +static void gst_h264_parse_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_h264_parse_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static gboolean gst_h264_parse_set_caps (GstBaseParse * parse, GstCaps * caps); +static GstFlowReturn gst_h264_parse_chain (GstPad * pad, GstBuffer * buffer); + +static void +gst_h264_parse_base_init (gpointer g_class) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&srctemplate)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&sinktemplate)); + + gst_element_class_set_details_simple (gstelement_class, "H.264 parser", + "Codec/Parser/Video", + "Parses H.264 streams", + "Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>"); + + GST_DEBUG_CATEGORY_INIT (h264_parse_debug, "h264parse", 0, "h264 parser"); +} + +static void +gst_h264_parse_class_init (GstH264ParseClass * klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass); + + gobject_class->finalize = gst_h264_parse_finalize; + gobject_class->set_property = gst_h264_parse_set_property; + gobject_class->get_property = gst_h264_parse_get_property; + + g_object_class_install_property (gobject_class, PROP_SPLIT_PACKETIZED, + g_param_spec_boolean ("split-packetized", "Split packetized", + "Split NAL units of packetized streams", DEFAULT_SPLIT_PACKETIZED, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_CONFIG_INTERVAL, + g_param_spec_uint ("config-interval", + "SPS PPS Send Interval", + "Send SPS and PPS Insertion Interval in seconds (sprop parameter sets " + "will be multiplexed in the data stream when detected.) (0 = disabled)", + 0, 3600, DEFAULT_CONFIG_INTERVAL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); + + /* Override BaseParse vfuncs */ + parse_class->start = GST_DEBUG_FUNCPTR (gst_h264_parse_start); + parse_class->stop = GST_DEBUG_FUNCPTR (gst_h264_parse_stop); + parse_class->check_valid_frame = + GST_DEBUG_FUNCPTR (gst_h264_parse_check_valid_frame); + parse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_h264_parse_parse_frame); + parse_class->pre_push_frame = + GST_DEBUG_FUNCPTR (gst_h264_parse_pre_push_frame); + parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_h264_parse_set_caps); +} + +static void +gst_h264_parse_init (GstH264Parse * h264parse, GstH264ParseClass * g_class) +{ + h264parse->frame_out = gst_adapter_new (); + + /* retrieve and intercept baseparse. + * Quite HACKish, but fairly OK since it is needed to perform avc packet + * splitting, which is the penultimate de-parsing */ + h264parse->parse_chain = + GST_PAD_CHAINFUNC (GST_BASE_PARSE_SINK_PAD (h264parse)); + gst_pad_set_chain_function (GST_BASE_PARSE_SINK_PAD (h264parse), + gst_h264_parse_chain); +} + + +static void +gst_h264_parse_finalize (GObject * object) +{ + GstH264Parse *h264parse = GST_H264_PARSE (object); + + g_object_unref (h264parse->frame_out); +} + +static void +gst_h264_parse_reset_frame (GstH264Parse * h264parse) +{ + /* done parsing; reset state */ + h264parse->last_nal_pos = 0; + h264parse->next_sc_pos = 0; + h264parse->picture_start = FALSE; + h264parse->update_caps = FALSE; + h264parse->idr_pos = -1; + h264parse->keyframe = FALSE; + h264parse->frame_start = FALSE; +} + +static void +gst_h264_parse_reset (GstH264Parse * h264parse) +{ + h264parse->width = 0; + h264parse->height = 0; + h264parse->fps_num = 0; + h264parse->fps_den = 0; + gst_buffer_replace (&h264parse->codec_data, NULL); + h264parse->nal_length_size = 4; + h264parse->packetized = FALSE; + + h264parse->align = GST_H264_PARSE_ALIGN_NONE; + h264parse->format = GST_H264_PARSE_FORMAT_NONE; + + h264parse->last_report = GST_CLOCK_TIME_NONE; + h264parse->push_codec = FALSE; + + gst_h264_parse_reset_frame (h264parse); +} + +static gboolean +gst_h264_parse_start (GstBaseParse * parse) +{ + GstH264Parse *h264parse = GST_H264_PARSE (parse); + + GST_DEBUG ("Start"); + gst_h264_parse_reset (h264parse); + + gst_h264_params_create (&h264parse->params, GST_ELEMENT (h264parse)); + + gst_base_parse_set_min_frame_size (parse, 512); + + return TRUE; +} + +static gboolean +gst_h264_parse_stop (GstBaseParse * parse) +{ + GstH264Parse *h264parse = GST_H264_PARSE (parse); + + GST_DEBUG ("Stop"); + gst_h264_parse_reset (h264parse); + + gst_h264_params_free (h264parse->params); + h264parse->params = NULL; + + return TRUE; +} + +static const gchar * +gst_h264_parse_get_string (GstH264Parse * parse, gboolean format, gint code) +{ + if (format) { + switch (code) { + case GST_H264_PARSE_FORMAT_AVC: + return "avc"; + case GST_H264_PARSE_FORMAT_BYTE: + return "byte-stream"; + default: + return "none"; + } + } else { + switch (code) { + case GST_H264_PARSE_ALIGN_NAL: + return "nal"; + case GST_H264_PARSE_ALIGN_AU: + return "au"; + default: + return "none"; + } + } +} + +/* check downstream caps to configure format and alignment */ +static void +gst_h264_parse_negotiate (GstH264Parse * h264parse) +{ + GstCaps *caps; + guint format = GST_H264_PARSE_FORMAT_NONE; + guint align = GST_H264_PARSE_ALIGN_NONE; + + caps = gst_pad_get_allowed_caps (GST_BASE_PARSE_SRC_PAD (h264parse)); + GST_DEBUG_OBJECT (h264parse, "allowed caps: %" GST_PTR_FORMAT, caps); + + if (caps && gst_caps_get_size (caps) > 0) { + GstStructure *s = gst_caps_get_structure (caps, 0); + const gchar *str = NULL; + + if ((str = gst_structure_get_string (s, "stream-format"))) { + if (strcmp (str, "avc") == 0) { + format = GST_H264_PARSE_FORMAT_AVC; + } else if (strcmp (str, "byte-stream") == 0) { + format = GST_H264_PARSE_FORMAT_BYTE; + } else { + GST_DEBUG_OBJECT (h264parse, "unknown stream-format: %s", str); + } + } + + if ((str = gst_structure_get_string (s, "alignment"))) { + if (strcmp (str, "au") == 0) { + align = GST_H264_PARSE_ALIGN_AU; + } else if (strcmp (str, "nal") == 0) { + align = GST_H264_PARSE_ALIGN_NAL; + } else { + GST_DEBUG_OBJECT (h264parse, "unknown alignment: %s", str); + } + } + } + + if (caps) + gst_caps_unref (caps); + + /* default */ + if (!format) + format = GST_H264_PARSE_FORMAT_BYTE; + if (!align) + align = GST_H264_PARSE_ALIGN_AU; + + GST_DEBUG_OBJECT (h264parse, "selected format %s, alignment %s", + gst_h264_parse_get_string (h264parse, TRUE, format), + gst_h264_parse_get_string (h264parse, FALSE, align)); + + h264parse->format = format; + h264parse->align = align; +} + +static GstBuffer * +gst_h264_parse_wrap_nal (GstH264Parse * h264parse, guint format, guint8 * data, + guint size) +{ + GstBuffer *buf; + const guint nl = h264parse->nal_length_size; + + buf = gst_buffer_new_and_alloc (size + nl + 4); + if (format == GST_H264_PARSE_FORMAT_AVC) { + GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf), size << (32 - 8 * nl)); + } else { + g_assert (nl == 4); + GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf), 1); + } + + GST_BUFFER_SIZE (buf) = size + nl; + memcpy (GST_BUFFER_DATA (buf) + nl, data, size); + + return buf; +} + +/* SPS/PPS/IDR considered key, all others DELTA; + * so downstream waiting for keyframe can pick up at SPS/PPS/IDR */ +#define NAL_TYPE_IS_KEY(nt) (((nt) == 5) || ((nt) == 7) || ((nt) == 8)) + +/* caller guarantees 2 bytes of nal payload */ +static void +gst_h264_parse_process_nal (GstH264Parse * h264parse, guint8 * data, + gint sc_pos, gint nal_pos, guint nal_size) +{ + guint nal_type; + + g_return_if_fail (nal_size >= 2); + g_return_if_fail (nal_pos - sc_pos > 0 && nal_pos - sc_pos <= 4); + + /* lower layer collects params */ + gst_h264_params_parse_nal (h264parse->params, data + nal_pos, nal_size); + + /* we have a peek as well */ + nal_type = data[nal_pos] & 0x1f; + h264parse->keyframe |= NAL_TYPE_IS_KEY (nal_type); + + switch (nal_type) { + case NAL_SPS: + case NAL_PPS: + /* parameters might have changed, force caps check */ + GST_DEBUG_OBJECT (h264parse, "triggering src caps check"); + h264parse->update_caps = TRUE; + /* found in stream, no need to forcibly push at start */ + h264parse->push_codec = FALSE; + break; + case NAL_SLICE: + case NAL_SLICE_DPA: + case NAL_SLICE_DPB: + case NAL_SLICE_DPC: + /* real frame data */ + h264parse->frame_start |= (h264parse->params->first_mb_in_slice == 0); + /* if we need to sneak codec NALs into the stream, + * this is a good place, so fake it as IDR + * (which should be at start anyway) */ + if (G_LIKELY (!h264parse->push_codec)) + break; + /* fall-through */ + case NAL_SLICE_IDR: + /* real frame data */ + h264parse->frame_start |= (h264parse->params->first_mb_in_slice == 0); + /* mark where config needs to go if interval expired */ + /* mind replacement buffer if applicable */ + if (h264parse->format == GST_H264_PARSE_FORMAT_AVC) + h264parse->idr_pos = gst_adapter_available (h264parse->frame_out); + else + h264parse->idr_pos = sc_pos; + GST_DEBUG_OBJECT (h264parse, "marking IDR in frame at offset %d", + h264parse->idr_pos); + break; + } + + /* if AVC output needed, collect properly prefixed nal in adapter, + * and use that to replace outgoing buffer data later on */ + if (h264parse->format == GST_H264_PARSE_FORMAT_AVC) { + GstBuffer *buf; + + GST_LOG_OBJECT (h264parse, "collecting NAL in AVC frame"); + buf = gst_h264_parse_wrap_nal (h264parse, h264parse->format, + data + nal_pos, nal_size); + gst_adapter_push (h264parse->frame_out, buf); + } +} + +/* caller guarantees at least 2 bytes of nal payload for each nal + * returns TRUE if next_nal indicates that nal terminates an AU */ +static inline gboolean +gst_h264_parse_collect_nal (GstH264Parse * h264parse, guint8 * nal, + guint8 * next_nal) +{ + gint nal_type; + gboolean complete; + + if (h264parse->align == GST_H264_PARSE_ALIGN_NAL) + return TRUE; + + /* determine if AU complete */ + nal_type = nal[0] & 0x1f; + GST_LOG_OBJECT (h264parse, "nal type: %d", nal_type); + /* coded slice NAL starts a picture, + * i.e. other types become aggregated in front of it */ + h264parse->picture_start |= (nal_type == 1 || nal_type == 2 || nal_type == 5); + + /* consider a coded slices (IDR or not) to start a picture, + * (so ending the previous one) if first_mb_in_slice == 0 + * (non-0 is part of previous one) */ + /* NOTE this is not entirely according to Access Unit specs in 7.4.1.2.4, + * but in practice it works in sane cases, needs not much parsing, + * and also works with broken frame_num in NAL + * (where spec-wise would fail) */ + nal_type = next_nal[0] & 0x1f; + GST_LOG_OBJECT (h264parse, "next nal type: %d", nal_type); + complete = h264parse->picture_start && (nal_type >= 6 && nal_type <= 9); + complete |= h264parse->picture_start && + (nal_type == 1 || nal_type == 2 || nal_type == 5) && + /* first_mb_in_slice == 0 considered start of frame */ + (next_nal[1] & 0x80); + + GST_LOG_OBJECT (h264parse, "au complete: %d", complete); + + return complete; +} + +/* finds next startcode == 00 00 01, along with a subsequent byte */ +static guint +gst_h264_parse_find_sc (GstBuffer * buffer, guint skip) +{ + GstByteReader br; + guint sc_pos = -1; + + gst_byte_reader_init_from_buffer (&br, buffer); + + /* NALU not empty, so we can at least expect 1 (even 2) bytes following sc */ + sc_pos = gst_byte_reader_masked_scan_uint32 (&br, 0xffffff00, 0x00000100, + skip, gst_byte_reader_get_remaining (&br) - skip); + + return sc_pos; +} + +static gboolean +gst_h264_parse_check_valid_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, guint * framesize, gint * skipsize) +{ + GstH264Parse *h264parse = GST_H264_PARSE (parse); + GstBuffer *buffer = frame->buffer; + gint sc_pos, nal_pos, next_sc_pos, next_nal_pos; + guint8 *data; + guint size; + gboolean drain; + + /* expect at least 3 bytes startcode == sc, and 2 bytes NALU payload */ + if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < 5)) + return FALSE; + + /* need to configure aggregation */ + if (G_UNLIKELY (h264parse->format == GST_H264_PARSE_FORMAT_NONE)) + gst_h264_parse_negotiate (h264parse); + + data = GST_BUFFER_DATA (buffer); + size = GST_BUFFER_SIZE (buffer); + + GST_LOG_OBJECT (h264parse, "last_nal_pos: %d, last_scan_pos %d", + h264parse->last_nal_pos, h264parse->next_sc_pos); + + nal_pos = h264parse->last_nal_pos; + next_sc_pos = h264parse->next_sc_pos; + + if (!next_sc_pos) { + sc_pos = gst_h264_parse_find_sc (buffer, 0); + + if (sc_pos == -1) { + /* SC not found, need more data */ + sc_pos = GST_BUFFER_SIZE (buffer) - 3; + goto more; + } + + nal_pos = sc_pos + 3; + next_sc_pos = nal_pos; + /* sc might have 2 or 3 0-bytes */ + if (sc_pos > 0 && data[sc_pos - 1] == 00) + sc_pos--; + GST_LOG_OBJECT (h264parse, "found sc at offset %d", sc_pos); + } else { + /* previous checks already arrange sc at start */ + sc_pos = 0; + } + + drain = GST_BASE_PARSE_FRAME_DRAIN (frame); + while (TRUE) { + gint prev_sc_pos; + + next_sc_pos = gst_h264_parse_find_sc (buffer, next_sc_pos); + if (next_sc_pos == -1) { + GST_LOG_OBJECT (h264parse, "no next sc"); + if (drain) { + /* FLUSH/EOS, it's okay if we can't find the next frame */ + next_sc_pos = size; + next_nal_pos = size; + } else { + next_sc_pos = size - 3; + goto more; + } + } else { + next_nal_pos = next_sc_pos + 3; + if (data[next_sc_pos - 1] == 00) + next_sc_pos--; + GST_LOG_OBJECT (h264parse, "found next sc at offset %d", next_sc_pos); + /* need at least 1 more byte of next NAL */ + if (!drain && (next_nal_pos == size - 1)) + goto more; + } + + /* determine nal's sc position */ + prev_sc_pos = nal_pos - 3; + g_assert (prev_sc_pos >= 0); + if (prev_sc_pos > 0 && data[prev_sc_pos - 1] == 0) + prev_sc_pos--; + + /* already consume and gather info from NAL */ + gst_h264_parse_process_nal (h264parse, data, prev_sc_pos, nal_pos, + next_sc_pos - nal_pos); + if (next_nal_pos >= size - 1 || + gst_h264_parse_collect_nal (h264parse, data + nal_pos, + data + next_nal_pos)) + break; + + /* move along */ + next_sc_pos = nal_pos = next_nal_pos; + } + + *skipsize = sc_pos; + *framesize = next_sc_pos - sc_pos; + + return TRUE; + +more: + /* Ask for 1024 bytes more - this is an arbitrary choice */ + gst_base_parse_set_min_frame_size (parse, GST_BUFFER_SIZE (buffer) + 1024); + + /* skip up to initial startcode */ + *skipsize = sc_pos; + /* resume scanning here next time */ + h264parse->last_nal_pos = nal_pos; + h264parse->next_sc_pos = next_sc_pos; + + return FALSE; +} + +/* byte together avc codec data based on collected pps and sps so far */ +static GstBuffer * +gst_h264_parse_make_codec_data (GstH264Parse * h264parse) +{ + GstBuffer *buf, *nal; + gint i, sps_size = 0, pps_size = 0, num_sps = 0, num_pps = 0; + guint8 profile_idc = 0, profile_comp = 0, level_idc = 0; + gboolean found = FALSE; + guint8 *data; + + /* only nal payload in stored nals */ + + for (i = 0; i < MAX_SPS_COUNT; i++) { + if ((nal = h264parse->params->sps_nals[i])) { + num_sps++; + /* size bytes also count */ + sps_size += GST_BUFFER_SIZE (nal) + 2; + if (GST_BUFFER_SIZE (nal) >= 4) { + found = TRUE; + profile_idc = (GST_BUFFER_DATA (nal))[1]; + profile_comp = (GST_BUFFER_DATA (nal))[2]; + level_idc = (GST_BUFFER_DATA (nal))[3]; + } + } + } + for (i = 0; i < MAX_PPS_COUNT; i++) { + if ((nal = h264parse->params->pps_nals[i])) { + num_pps++; + /* size bytes also count */ + pps_size += GST_BUFFER_SIZE (nal) + 2; + } + } + + GST_DEBUG_OBJECT (h264parse, + "constructing codec_data: num_sps=%d, num_pps=%d", num_sps, num_pps); + + if (!found || !num_pps) + return NULL; + + buf = gst_buffer_new_and_alloc (5 + 1 + sps_size + 1 + pps_size); + data = GST_BUFFER_DATA (buf); + + data[0] = 1; /* AVC Decoder Configuration Record ver. 1 */ + data[1] = profile_idc; /* profile_idc */ + data[2] = profile_comp; /* profile_compability */ + data[3] = level_idc; /* level_idc */ + data[4] = 0xfc | (4 - 1); /* nal_length_size_minus1 */ + data[5] = 0xe0 | num_sps; /* number of SPSs */ + + data += 6; + for (i = 0; i < MAX_SPS_COUNT; i++) { + if ((nal = h264parse->params->sps_nals[i])) { + GST_WRITE_UINT16_BE (data, GST_BUFFER_SIZE (nal)); + memcpy (data + 2, GST_BUFFER_DATA (nal), GST_BUFFER_SIZE (nal)); + data += 2 + GST_BUFFER_SIZE (nal); + } + } + + data[0] = num_pps; + data++; + for (i = 0; i < MAX_PPS_COUNT; i++) { + if ((nal = h264parse->params->pps_nals[i])) { + GST_WRITE_UINT16_BE (data, GST_BUFFER_SIZE (nal)); + memcpy (data + 2, GST_BUFFER_DATA (nal), GST_BUFFER_SIZE (nal)); + data += 2 + GST_BUFFER_SIZE (nal); + } + } + + return buf; +} + +static void +gst_h264_parse_update_src_caps (GstH264Parse * h264parse) +{ + GstH264ParamsSPS *sps; + GstCaps *caps = NULL, *sink_caps; + gboolean modified = FALSE; + GstBuffer *buf = NULL; + + if (G_UNLIKELY (!GST_PAD_CAPS (GST_BASE_PARSE_SRC_PAD (h264parse)))) + modified = TRUE; + else if (G_UNLIKELY (!h264parse->update_caps)) + return; + + /* carry over input caps as much as possible; override with our own stuff */ + sink_caps = GST_PAD_CAPS (GST_BASE_PARSE_SINK_PAD (h264parse)); + if (sink_caps) + gst_caps_ref (sink_caps); + else + sink_caps = gst_caps_new_simple ("video/x-h264", NULL); + + sps = h264parse->params->sps; + GST_DEBUG_OBJECT (h264parse, "sps: %p", sps); + + /* only codec-data for nice-and-clean au aligned packetized avc format */ + if (h264parse->format == GST_H264_PARSE_FORMAT_AVC && + h264parse->align == GST_H264_PARSE_ALIGN_AU) { + buf = gst_h264_parse_make_codec_data (h264parse); + if (buf && h264parse->codec_data) { + if (GST_BUFFER_SIZE (buf) != GST_BUFFER_SIZE (h264parse->codec_data) || + memcmp (GST_BUFFER_DATA (buf), + GST_BUFFER_DATA (h264parse->codec_data), GST_BUFFER_SIZE (buf))) + modified = TRUE; + } else { + if (h264parse->codec_data) + buf = gst_buffer_ref (h264parse->codec_data); + modified = TRUE; + } + } + + if (G_UNLIKELY (!sps)) { + caps = gst_caps_copy (sink_caps); + } else if (G_UNLIKELY (h264parse->width != sps->width || + h264parse->height != sps->height || h264parse->fps_num != sps->fps_num + || h264parse->fps_den != sps->fps_den || modified)) { + caps = gst_caps_copy (sink_caps); + /* sps should give this */ + gst_caps_set_simple (caps, "width", G_TYPE_INT, sps->width, + "height", G_TYPE_INT, sps->height, NULL); + h264parse->height = sps->height; + h264parse->width = sps->width; + /* but not necessarily or reliably this */ + if ((!h264parse->fps_num || !h264parse->fps_den) && + sps->fps_num > 0 && sps->fps_den > 0) { + gst_caps_set_simple (caps, "framerate", + GST_TYPE_FRACTION, sps->fps_num, sps->fps_den, NULL); + h264parse->fps_num = sps->fps_num; + h264parse->fps_den = sps->fps_den; + gst_base_parse_set_frame_props (GST_BASE_PARSE (h264parse), + h264parse->fps_num, h264parse->fps_den, 0, 0); + } + } + + if (caps) { + gst_caps_set_simple (caps, "stream-format", G_TYPE_STRING, + gst_h264_parse_get_string (h264parse, TRUE, h264parse->format), + "alignment", G_TYPE_STRING, + gst_h264_parse_get_string (h264parse, FALSE, h264parse->align), NULL); + if (buf) { + gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, buf, NULL); + gst_buffer_replace (&h264parse->codec_data, buf); + gst_buffer_unref (buf); + buf = NULL; + } else { + GstStructure *s; + /* remove any left-over codec-data hanging around */ + s = gst_caps_get_structure (caps, 0); + gst_structure_remove_field (s, "codec_data"); + } + gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (h264parse), caps); + gst_caps_unref (caps); + } + + gst_caps_unref (sink_caps); + if (buf) + gst_buffer_unref (buf); +} + +static GstFlowReturn +gst_h264_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) +{ + GstH264Parse *h264parse; + GstBuffer *buffer; + guint av; + + h264parse = GST_H264_PARSE (parse); + buffer = frame->buffer; + + gst_h264_parse_update_src_caps (h264parse); + + gst_h264_params_get_timestamp (h264parse->params, + &GST_BUFFER_TIMESTAMP (buffer), &GST_BUFFER_DURATION (buffer), + h264parse->frame_start); + + if (h264parse->keyframe) + GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT); + else + GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT); + + /* replace with transformed AVC output if applicable */ + av = gst_adapter_available (h264parse->frame_out); + if (av) { + GstBuffer *buf; + + buf = gst_adapter_take_buffer (h264parse->frame_out, av); + gst_buffer_copy_metadata (buf, buffer, GST_BUFFER_COPY_ALL); + gst_buffer_replace (&frame->buffer, buf); + } + + return GST_FLOW_OK; +} + +/* sends a codec NAL downstream, decorating and transforming as needed. + * No ownership is taken of @nal */ +static GstFlowReturn +gst_h264_parse_push_codec_buffer (GstH264Parse * h264parse, GstBuffer * nal, + GstClockTime ts) +{ + nal = gst_h264_parse_wrap_nal (h264parse, h264parse->format, + GST_BUFFER_DATA (nal), GST_BUFFER_SIZE (nal)); + + GST_BUFFER_TIMESTAMP (nal) = ts; + GST_BUFFER_DURATION (nal) = 0; + + gst_buffer_set_caps (nal, GST_PAD_CAPS (GST_BASE_PARSE_SRC_PAD (h264parse))); + + return gst_pad_push (GST_BASE_PARSE_SRC_PAD (h264parse), nal); +} + +static GstFlowReturn +gst_h264_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame) +{ + GstH264Parse *h264parse; + GstBuffer *buffer; + + h264parse = GST_H264_PARSE (parse); + buffer = frame->buffer; + + /* periodic SPS/PPS sending */ + if (h264parse->interval > 0 || h264parse->push_codec) { + GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer); + guint64 diff; + + /* init */ + if (!GST_CLOCK_TIME_IS_VALID (h264parse->last_report)) { + h264parse->last_report = timestamp; + } + + if (h264parse->idr_pos >= 0) { + GST_LOG_OBJECT (h264parse, "IDR nal at offset %d", h264parse->idr_pos); + + if (timestamp > h264parse->last_report) + diff = timestamp - h264parse->last_report; + else + diff = 0; + + GST_LOG_OBJECT (h264parse, + "now %" GST_TIME_FORMAT ", last SPS/PPS %" GST_TIME_FORMAT, + GST_TIME_ARGS (timestamp), GST_TIME_ARGS (h264parse->last_report)); + + GST_DEBUG_OBJECT (h264parse, + "interval since last SPS/PPS %" GST_TIME_FORMAT, + GST_TIME_ARGS (diff)); + + if (GST_TIME_AS_SECONDS (diff) >= h264parse->interval || + h264parse->push_codec) { + GstBuffer *codec_nal; + gint i; + GstClockTime new_ts; + + /* avoid overwriting a perfectly fine timestamp */ + new_ts = GST_CLOCK_TIME_IS_VALID (timestamp) ? timestamp : + h264parse->last_report; + + if (h264parse->align == GST_H264_PARSE_ALIGN_NAL) { + /* send separate config NAL buffers */ + GST_DEBUG_OBJECT (h264parse, "- sending SPS/PPS"); + for (i = 0; i < MAX_SPS_COUNT; i++) { + if ((codec_nal = h264parse->params->sps_nals[i])) { + GST_DEBUG_OBJECT (h264parse, "sending SPS nal"); + gst_h264_parse_push_codec_buffer (h264parse, codec_nal, + timestamp); + h264parse->last_report = new_ts; + } + } + for (i = 0; i < MAX_PPS_COUNT; i++) { + if ((codec_nal = h264parse->params->pps_nals[i])) { + GST_DEBUG_OBJECT (h264parse, "sending PPS nal"); + gst_h264_parse_push_codec_buffer (h264parse, codec_nal, + timestamp); + h264parse->last_report = new_ts; + } + } + } else { + /* insert config NALs into AU */ + GstByteWriter bw; + GstBuffer *new_buf; + const gboolean bs = h264parse->format == GST_H264_PARSE_FORMAT_BYTE; + + gst_byte_writer_init_with_size (&bw, GST_BUFFER_SIZE (buffer), FALSE); + gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (buffer), + h264parse->idr_pos); + GST_DEBUG_OBJECT (h264parse, "- inserting SPS/PPS"); + for (i = 0; i < MAX_SPS_COUNT; i++) { + if ((codec_nal = h264parse->params->sps_nals[i])) { + GST_DEBUG_OBJECT (h264parse, "inserting SPS nal"); + gst_byte_writer_put_uint32_be (&bw, + bs ? 1 : GST_BUFFER_SIZE (codec_nal)); + gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (codec_nal), + GST_BUFFER_SIZE (codec_nal)); + h264parse->last_report = new_ts; + } + } + for (i = 0; i < MAX_PPS_COUNT; i++) { + if ((codec_nal = h264parse->params->pps_nals[i])) { + GST_DEBUG_OBJECT (h264parse, "inserting PPS nal"); + gst_byte_writer_put_uint32_be (&bw, + bs ? 1 : GST_BUFFER_SIZE (codec_nal)); + gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (codec_nal), + GST_BUFFER_SIZE (codec_nal)); + h264parse->last_report = new_ts; + } + } + gst_byte_writer_put_data (&bw, + GST_BUFFER_DATA (buffer) + h264parse->idr_pos, + GST_BUFFER_SIZE (buffer) - h264parse->idr_pos); + /* collect result and push */ + new_buf = gst_byte_writer_reset_and_get_buffer (&bw); + gst_buffer_copy_metadata (new_buf, buffer, GST_BUFFER_COPY_ALL); + gst_buffer_replace (&frame->buffer, new_buf); + } + } + /* we pushed whatever we had */ + h264parse->push_codec = FALSE; + } + } + + gst_h264_parse_reset_frame (h264parse); + + return GST_FLOW_OK; +} + +static gboolean +gst_h264_parse_set_caps (GstBaseParse * parse, GstCaps * caps) +{ + GstH264Parse *h264parse; + GstStructure *str; + const GValue *value; + GstBuffer *buffer = NULL; + guint size; + + h264parse = GST_H264_PARSE (parse); + + /* reset */ + h264parse->push_codec = FALSE; + + str = gst_caps_get_structure (caps, 0); + + /* accept upstream info if provided */ + gst_structure_get_int (str, "width", &h264parse->width); + gst_structure_get_int (str, "height", &h264parse->height); + gst_structure_get_fraction (str, "framerate", &h264parse->fps_num, + &h264parse->fps_den); + + /* packetized video has a codec_data */ + if ((value = gst_structure_get_value (str, "codec_data"))) { + guint8 *data; + guint num_sps, num_pps, profile, len; + gint i; + + GST_DEBUG_OBJECT (h264parse, "have packetized h264"); + /* make note for optional split processing */ + h264parse->packetized = TRUE; + + buffer = gst_value_get_buffer (value); + if (!buffer) + goto wrong_type; + data = GST_BUFFER_DATA (buffer); + size = GST_BUFFER_SIZE (buffer); + + /* parse the avcC data */ + if (size < 7) + goto avcc_too_small; + /* parse the version, this must be 1 */ + if (data[0] != 1) + goto wrong_version; + + /* AVCProfileIndication */ + /* profile_compat */ + /* AVCLevelIndication */ + profile = (data[1] << 16) | (data[2] << 8) | data[3]; + GST_DEBUG_OBJECT (h264parse, "profile %06x", profile); + + /* 6 bits reserved | 2 bits lengthSizeMinusOne */ + /* this is the number of bytes in front of the NAL units to mark their + * length */ + h264parse->nal_length_size = (data[4] & 0x03) + 1; + GST_DEBUG_OBJECT (h264parse, "nal length %u", h264parse->nal_length_size); + + num_sps = data[5] & 0x1f; + data += 6; + size -= 6; + for (i = 0; i < num_sps; i++) { + len = GST_READ_UINT16_BE (data); + if (size < len + 2 || len < 2) + goto avcc_too_small; + /* digest for later reference */ + gst_h264_parse_process_nal (h264parse, data, 0, 2, len); + data += len + 2; + size -= len + 2; + } + num_pps = data[0]; + data++; + size++; + for (i = 0; i < num_pps; i++) { + len = GST_READ_UINT16_BE (data); + if (size < len + 2 || len < 2) + goto avcc_too_small; + /* digest for later reference */ + gst_h264_parse_process_nal (h264parse, data, 0, 2, len); + data += len + 2; + size -= len + 2; + } + } else { + GST_DEBUG_OBJECT (h264parse, "have bytestream h264"); + /* nothing to pre-process */ + h264parse->packetized = FALSE; + /* we have 4 sync bytes */ + h264parse->nal_length_size = 4; + } + + if (h264parse->packetized) { + if (h264parse->split_packetized) { + GST_DEBUG_OBJECT (h264parse, + "converting AVC to nal bytestream prior to parsing"); + /* negotiate behaviour with upstream */ + gst_h264_parse_negotiate (h264parse); + if (h264parse->format == GST_H264_PARSE_FORMAT_BYTE) { + /* arrange to insert codec-data in-stream if needed */ + h264parse->push_codec = h264parse->packetized; + } + } else { + GST_DEBUG_OBJECT (h264parse, "passing on packetized AVC"); + /* no choice to negotiate */ + h264parse->format = GST_H264_PARSE_FORMAT_AVC; + h264parse->align = GST_H264_PARSE_ALIGN_AU; + /* fallback codec-data */ + h264parse->codec_data = gst_buffer_ref (buffer); + /* pass through unharmed, though _chain will parse a bit */ + gst_base_parse_set_format (parse, + GST_BASE_PARSE_FORMAT_PASSTHROUGH, TRUE); + /* we did parse codec-data and might supplement src caps */ + gst_h264_parse_update_src_caps (h264parse); + } + } + + /* src caps are only arranged for later on */ + return TRUE; + + /* ERRORS */ +avcc_too_small: + { + GST_DEBUG_OBJECT (h264parse, "avcC size %u < 7", size); + goto refuse_caps; + } +wrong_version: + { + GST_DEBUG_OBJECT (h264parse, "wrong avcC version"); + goto refuse_caps; + } +wrong_type: + { + GST_DEBUG_OBJECT (h264parse, "wrong codec-data type"); + goto refuse_caps; + } +refuse_caps: + { + GST_WARNING_OBJECT (h264parse, "refused caps %" GST_PTR_FORMAT, caps); + return FALSE; + } +} + +static GstFlowReturn +gst_h264_parse_chain (GstPad * pad, GstBuffer * buffer) +{ + GstH264Parse *h264parse = GST_H264_PARSE (GST_PAD_PARENT (pad)); + + if (h264parse->packetized && buffer) { + GstByteReader br; + GstBuffer *sub; + GstFlowReturn ret = GST_FLOW_OK; + guint32 len; + const guint nl = h264parse->nal_length_size; + + GST_LOG_OBJECT (h264parse, "processing packet buffer of size %d", + GST_BUFFER_SIZE (buffer)); + gst_byte_reader_init_from_buffer (&br, buffer); + while (ret == GST_FLOW_OK && gst_byte_reader_get_remaining (&br)) { + GST_DEBUG_OBJECT (h264parse, "AVC nal offset %d", + gst_byte_reader_get_pos (&br)); + if (gst_byte_reader_get_remaining (&br) < nl) + goto parse_failed; + switch (nl) { + case 4: + len = gst_byte_reader_get_uint32_be_unchecked (&br); + break; + case 3: + len = gst_byte_reader_get_uint24_be_unchecked (&br); + break; + case 2: + len = gst_byte_reader_get_uint16_be_unchecked (&br); + break; + case 1: + len = gst_byte_reader_get_uint8_unchecked (&br); + break; + default: + goto not_negotiated; + break; + } + GST_DEBUG_OBJECT (h264parse, "AVC nal size %d", len); + if (gst_byte_reader_get_remaining (&br) < len) + goto parse_failed; + if (h264parse->split_packetized) { + /* convert to NAL aligned byte stream input */ + sub = gst_h264_parse_wrap_nal (h264parse, GST_H264_PARSE_FORMAT_BYTE, + (guint8 *) gst_byte_reader_get_data_unchecked (&br, len), len); + /* at least this should make sense */ + GST_BUFFER_TIMESTAMP (sub) = GST_BUFFER_TIMESTAMP (buffer); + GST_LOG_OBJECT (h264parse, "pushing NAL of size %d", len); + ret = h264parse->parse_chain (pad, sub); + } else { + /* pass-through: no looking for frames (and nal processing), + * so need to parse to collect data here */ + /* NOTE: so if it is really configured to do so, + * pre_push can/will still insert codec-data at intervals, + * which is not really pure pass-through, but anyway ... */ + gst_h264_parse_process_nal (h264parse, + GST_BUFFER_DATA (buffer), gst_byte_reader_get_pos (&br) - nl, + gst_byte_reader_get_pos (&br), len); + gst_byte_reader_skip_unchecked (&br, len); + } + } + if (h264parse->split_packetized) + return ret; + } + +exit: + /* nal processing in pass-through might have collected stuff; + * ensure nothing happens with this later on */ + gst_adapter_clear (h264parse->frame_out); + + return h264parse->parse_chain (pad, buffer); + + /* ERRORS */ +not_negotiated: + { + GST_DEBUG_OBJECT (h264parse, "insufficient data to split input"); + return GST_FLOW_NOT_NEGOTIATED; + } +parse_failed: + { + if (h264parse->split_packetized) { + GST_ELEMENT_ERROR (h264parse, STREAM, FAILED, (NULL), + ("invalid AVC input data")); + return GST_FLOW_ERROR; + } else { + /* do not meddle to much in this case */ + GST_DEBUG_OBJECT (h264parse, "parsing packet failed"); + goto exit; + } + } +} + +static void +gst_h264_parse_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstH264Parse *parse; + + parse = GST_H264_PARSE (object); + + switch (prop_id) { + case PROP_SPLIT_PACKETIZED: + parse->split_packetized = g_value_get_boolean (value); + break; + case PROP_CONFIG_INTERVAL: + parse->interval = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_h264_parse_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstH264Parse *parse; + + parse = GST_H264_PARSE (object); + + switch (prop_id) { + case PROP_SPLIT_PACKETIZED: + g_value_set_boolean (value, parse->split_packetized); + break; + case PROP_CONFIG_INTERVAL: + g_value_set_uint (value, parse->interval); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} diff --git a/gst/videoparsers/gsth264parse.h b/gst/videoparsers/gsth264parse.h new file mode 100644 index 000000000..7f42bc5d9 --- /dev/null +++ b/gst/videoparsers/gsth264parse.h @@ -0,0 +1,93 @@ +/* GStreamer H.264 Parser + * Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + * Copyright (C) <2010> Collabora Multimedia + * Copyright (C) <2010> Nokia Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_H264_PARSE_H__ +#define __GST_H264_PARSE_H__ + +#include <gst/gst.h> +#include <gst/baseparse/gstbaseparse.h> + +#include "h264parse.h" + +G_BEGIN_DECLS + +typedef struct _H264Params H264Params; + +#define GST_TYPE_H264_PARSE \ + (gst_h264_parse_get_type()) +#define GST_H264_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_H264_PARSE,GstH264Parse)) +#define GST_H264_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_H264_PARSE,GstH264ParseClass)) +#define GST_IS_H264_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_H264_PARSE)) +#define GST_IS_H264_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_H264_PARSE)) + +GType gst_h264_parse_get_type (void); + +typedef struct _GstH264Parse GstH264Parse; +typedef struct _GstH264ParseClass GstH264ParseClass; + +struct _GstH264Parse +{ + GstBaseParse baseparse; + + GstPadChainFunction parse_chain; + + /* stream */ + gint width, height; + gint fps_num, fps_den; + GstBuffer *codec_data; + guint nal_length_size; + gboolean packetized; + + /* state */ + GstH264Params *params; + guint align; + guint format; + + GstClockTime last_report; + gboolean push_codec; + + /* frame parsing */ + guint last_nal_pos; + guint next_sc_pos; + gint idr_pos; + gboolean update_caps; + GstAdapter *frame_out; + gboolean keyframe; + gboolean frame_start; + /* AU state */ + gboolean picture_start; + + /* props */ + gboolean split_packetized; + guint interval; +}; + +struct _GstH264ParseClass +{ + GstBaseParseClass parent_class; +}; + +G_END_DECLS +#endif diff --git a/gst/videoparsers/h263parse.c b/gst/videoparsers/h263parse.c new file mode 100644 index 000000000..ace1e18a2 --- /dev/null +++ b/gst/videoparsers/h263parse.c @@ -0,0 +1,666 @@ +/* GStreamer H.263 Parser + * Copyright (C) <2010> Arun Raghavan <arun.raghavan@collabora.co.uk> + * Copyright (C) <2010> Edward Hervey <edward.hervey@collabora.co.uk> + * Copyright (C) <2010> Collabora Multimedia + * Copyright (C) <2010> Nokia Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <gst/base/gstbitreader.h> +#include "gsth263parse.h" + +GST_DEBUG_CATEGORY_EXTERN (h263_parse_debug); +#define GST_CAT_DEFAULT h263_parse_debug + +gboolean +gst_h263_parse_is_delta_unit (H263Params * params) +{ + return (params->type == PICTURE_I); +} + +/* Reads adapter and tries to populate params. 'fast' mode can be used to + * extract a subset of the data (for now, it quits once we have the picture + * type. */ +GstFlowReturn +gst_h263_parse_get_params (H263Params ** params_p, GstBuffer * buffer, + gboolean fast, H263ParseState * state) +{ + static const guint8 partable[6][2] = { + {1, 0}, + {1, 1}, + {12, 11}, + {10, 11}, + {16, 11}, + {40, 33} + }; + + static const guint16 sizetable[8][2] = { + {0, 0}, + {128, 96}, + {176, 144}, + {352, 288}, + {704, 576}, + {1408, 1152} + }; + + static const gchar *source_format_name[] = { + "Forbidden", + "sub-QCIF", + "QCIF", + "CIF", + "4CIF", + "16CIF", + "Reserved", + "Extended PType" + }; + + H263Params *params; + GstBitReader br; + guint8 tr; + guint32 psc, temp32; + guint8 temp8, pquant; + gboolean hasplusptype; + + *params_p = g_new0 (H263Params, 1); + params = *params_p; + + /* FIXME: we can optimise a little by checking the value of available + * instead of calling using the bit reader's get_bits_* functions. */ + gst_bit_reader_init_from_buffer (&br, buffer); + + /* Default PCF is CIF PCF = 30000/1001 */ + params->pcfnum = 30000; + params->pcfdenom = 1001; + + GST_DEBUG ("NEW BUFFER"); + if (!gst_bit_reader_get_bits_uint32 (&br, &psc, 22) || + !gst_bit_reader_get_bits_uint8 (&br, &tr, 8) || + !gst_bit_reader_get_bits_uint8 (&br, &temp8, 8)) + goto more; + + /* PSC : Picture Start Code 22 bits + * TR : Temporal Reference 8 bits + * PTYPE : Type Information variable + * bit 1 : Always "1" + * bit 2 : Always "0" + * bit 3 : Split Screen Indicator + * bit 4 : Document Camera Indicator + * bit 6-8 : Source Format + * if 111 : extended PTYPE is present */ + + /* 5.1.1 PSC : Picture Start Code (0x0020) 22 bits */ + /* FIXME : Scan for the PSC instead of assuming it's always present + * and at the beginning. */ + if (G_UNLIKELY (psc != 0x0020)) { + GST_WARNING ("Invalid PSC"); + goto beach; + } + + /* 5.1.2 TR : Temporal Reference 8 bits */ + GST_DEBUG (" Temporal Reference : %d", tr); + params->temporal_ref = tr; + + if ((temp8 >> 6) != 0x2) { + GST_WARNING ("Invalid PTYPE"); + goto beach; + } + + /* 5.1.3 PTYPE : Type Information variable length */ + params->splitscreen = (temp8 & 0x20) == 0x20; + params->documentcamera = (temp8 & 0x10) == 0x10; + params->fullpicturefreezerelease = (temp8 & 0x08) == 0x08; + params->format = temp8 & 0x07; + + hasplusptype = (temp8 & 0x07) == 0x07; + + GST_DEBUG (" Split Screen Indicator : %s", + params->splitscreen ? "on" : "off"); + GST_DEBUG (" Document camera indicator : %s", + params->documentcamera ? "on" : "off"); + GST_DEBUG (" Full Picture Freeze Release : %s", + params->fullpicturefreezerelease ? "on" : "off"); + GST_DEBUG (" Source format 0x%x (%s)", params->format, + source_format_name[params->format]); + + if (!hasplusptype) { + guint8 ptype2; + + /* Fill in width/height based on format */ + params->width = sizetable[params->format][0]; + params->height = sizetable[params->format][1]; + + /* Default PAR is 12/11 */ + params->parnum = 12; + params->pardenom = 11; + + /* 5.1.3 : Remainder of PTYPE 5 bits */ + if (!gst_bit_reader_get_bits_uint8 (&br, &ptype2, 5)) + goto more; + + params->type = (ptype2 & 0x10) == 0x10; + if ((ptype2 & 0x08) == 0x08) + params->features |= H263_OPTION_UMV_MODE; + if ((ptype2 & 0x04) == 0x04) + params->features |= H263_OPTION_SAC_MODE; + if ((ptype2 & 0x02) == 0x02) + params->features |= H263_OPTION_AP_MODE; + if ((ptype2 & 0x01) == 0x01) { + params->features |= H263_OPTION_PB_MODE; + params->type = PICTURE_PB; + } + + GST_DEBUG (" Picture Coding Type : %s", + (ptype2 & 0x10) == 0x10 ? "INTER (P-picture)" : "INTRA (I-picture)"); + GST_DEBUG (" Unrestricted Motion Vector mode (Annex D) : %s", + (ptype2 & 0x08) == 0x08 ? "on" : "off"); + GST_DEBUG (" Syntax-basex Arithmetic Coding mode (Annex E) : %s", + (ptype2 & 0x04) == 0x04 ? "on" : "off"); + GST_DEBUG (" Advanced Prediction mode (Annex F) : %s", + (ptype2 & 0x02) == 0x02 ? "on" : "off"); + GST_DEBUG (" PB Frames mode (Annex G) : %s", + (ptype2 & 0x01) == 0x01 ? "on" : "off"); + + if (fast) + goto done; + } + + if (hasplusptype) { + guint8 ufep; + guint8 cpm; + guint32 opptype, mpptype; + + /* 5.1.4 PLUSPTYPE */ + + /* 5.1.4.1 UFEP : Update Full Extended PTYPE (3 bits) */ + if (!gst_bit_reader_get_bits_uint8 (&br, &ufep, 3)) + goto more; + GST_DEBUG (" UFEP 0x%x", ufep); + + if (ufep == 1) { + /* 5.1.4.2 OPPTYPE : The Optional Part of PLUSPTYPE (OPPTYPE) (18 bits) */ + if (!gst_bit_reader_get_bits_uint32 (&br, &opptype, 18)) + goto more; + + /* Last 4 bits are always "1000" */ + if ((opptype & 0xf) != 0x8) { + GST_WARNING ("Corrupted OPTTYPE"); + goto beach; + } + params->format = opptype >> 15; + params->custompcfpresent = (opptype & 0x4000) == 0x4000; + if (opptype & 0x2000) + params->features |= H263_OPTION_UMV_MODE; + if (opptype & 0x1000) + params->features |= H263_OPTION_SAC_MODE; + if (opptype & 0x0800) + params->features |= H263_OPTION_AP_MODE; + if (opptype & 0x0400) + params->features |= H263_OPTION_AIC_MODE; + if (opptype & 0x0200) + params->features |= H263_OPTION_DF_MODE; + if (opptype & 0x0100) + params->features |= H263_OPTION_SS_MODE; + if (opptype & 0x0080) + params->features |= H263_OPTION_RPS_MODE; + if (opptype & 0x0040) + params->features |= H263_OPTION_ISD_MODE; + if (opptype & 0x0020) + params->features |= H263_OPTION_AIV_MODE; + if (opptype & 0x0010) + params->features |= H263_OPTION_MQ_MODE; + /* Bit 15 is set to 1 to avoid looking like a start code */ + if (opptype & 0x0004) + params->features |= H263_OPTION_ERPS_MODE; + if (opptype & 0x0002) + params->features |= H263_OPTION_DPS_MODE; + } + + /* 5.1.4.3 MPPTYPE : The mandatory part of PLUSPTYPE (9 bits) */ + if (!gst_bit_reader_get_bits_uint32 (&br, &mpptype, 9)) + goto more; + + /* Last 3 bits are always "001" */ + if ((mpptype & 0x7) != 1) { + GST_WARNING ("Corrupted MPPTYPE"); + goto beach; + } + + params->type = mpptype >> 6; + GST_DEBUG (" Picture Coding Type : %d", params->type); + + if (fast) + goto done; + + if (mpptype & 0x2000) + params->features |= H263_OPTION_RPR_MODE; + if (mpptype & 0x1000) + params->features |= H263_OPTION_RRU_MODE; + + /* 5.1.20 CPM : Continuous Presence Multipoint and Video Multiplex (1 bit) */ + if (!gst_bit_reader_get_bits_uint8 (&br, &cpm, 1)) + goto more; + GST_DEBUG (" Continuous Presence Multipoint and Video Multiplex : %d", cpm); + + if (cpm) { + /* 5.1.21 PSBI : Picture Sub-Bitstream Indicator (2 bits) */ + guint8 psbi; + if (!gst_bit_reader_get_bits_uint8 (&br, &psbi, 2)) + goto more; + GST_DEBUG (" Picture Sub-Bitstream Indicator (PSBI):%d", psbi); + } + + if (ufep == 1) { + guint32 cpfmt; + + /* 5.1.5 CPFMT : Custom Picture Format (23 bits) */ + if (!gst_bit_reader_get_bits_uint32 (&br, &cpfmt, 23)) + goto more; + if (!(cpfmt & 0x200)) { + GST_WARNING ("Corrupted CPFMT (0x%x)", cpfmt); + goto beach; + } + temp8 = cpfmt >> 19; + params->width = (((cpfmt >> 10) & 0x1f) + 1) * 4; + params->height = (cpfmt & 0x1f) * 4; + + if (temp8 == 0xf) { + guint32 epar; + /* 5.1.6 EPAR : Extended Pixel Aspect Ratio (16bits) */ + if (!gst_bit_reader_get_bits_uint32 (&br, &epar, 16)) + goto more; + params->parnum = epar >> 8; + params->pardenom = epar & 0xf; + } else { + params->parnum = partable[temp8][0]; + params->pardenom = partable[temp8][1]; + } + + if (params->custompcfpresent) { + /* 5.1.7 CPCFC : Custom Picture Clock Frequency Code (8bits) */ + /* (we store this as a frame rate) */ + if (!gst_bit_reader_get_bits_uint8 (&br, &temp8, 8)) + goto more; + GST_DEBUG (" Custom PCF is present (%d)", (int) temp8); + params->pcfnum = gst_util_uint64_scale_int (1800000, 1, temp8 & 0x7f); + params->pcfdenom = (temp8 & 0x80) ? 1001 : 1000; + /* 5.1.8 ETR : Extended Temp8oral Reference (2bits) */ + if (!gst_bit_reader_get_bits_uint8 (&br, &temp8, 2)) + goto more; + params->temporal_ref |= temp8 << 8; + } + + if (params->features & H263_OPTION_UMV_MODE) { + guint8 i; + /* 5.1.9 UUI : Unlimited Unrestricted Motion Vectors Indicator (variable length) */ + if (!gst_bit_reader_get_bits_uint8 (&br, &i, 1)) + goto more; + if (i == 0) { + if (!gst_bit_reader_get_bits_uint8 (&br, &i, 1)) + goto more; + if (i != 1) { + GST_WARNING ("Corrupted UUI (0%u)", (guint) i); + goto beach; + } + params->uui = UUI_IS_01; + } else { + params->uui = UUI_IS_1; + } + } + + if (params->features & H263_OPTION_SS_MODE) { + /* 5.1.10 SSS : Slice Structured Submode bits (2bits) */ + if (!gst_bit_reader_get_bits_uint8 (&br, ¶ms->sss, 2)) + goto more; + } + + /* WE DO NOT SUPPORT optional Temporal, SNR, and Spatial Scalability mode */ + /* 5.1.11 ELNUM : Enhancement Layer Number (4bits) */ + /* 5.1.12 RLNUM : Reference Layer Number (4bits) */ + + if (params->features & H263_OPTION_RPS_MODE) { + /* 5.1.13 RPSMF : Reference Picture Selection Mode Flags (3bits) */ + /* FIXME : We just swallow the bits */ + if (!gst_bit_reader_get_bits_uint8 (&br, &temp8, 3)) + goto more; + + /* 5.1.14 TRPI : Temporal Reference for Prediction Indication (1bit) */ + if (!gst_bit_reader_get_bits_uint8 (&br, &temp8, 1)) + goto more; + + if (temp8) { + /* 5.1.15 TRP : Temporal Reference for Prediction (10bits) */ + /* FIXME : We just swallow the bits */ + if (!gst_bit_reader_get_bits_uint32 (&br, &temp32, 10)) + goto more; + } + + /* 5.1.16 BCI Back-Channel message Indication (variable length) */ + if (!gst_bit_reader_get_bits_uint8 (&br, &temp8, 1)) + goto more; + if (temp8 == 1) { + /* 5.1.17 BCM Back-Channel Message (variable length) */ + GST_ERROR ("We won't support Back-Channel Message (BCM)"); + goto beach; + } else { + if (!gst_bit_reader_get_bits_uint8 (&br, &temp8, 1)) + goto more; + if (temp8 != 1) { + GST_WARNING ("Corrupted BCI"); + goto beach; + } + } + } /* END H263_OPTION_RPS_MODE */ + } + + GST_DEBUG (" Advanced INTRA Coding mode (Annex I) : %s", + (params->features & H263_OPTION_AIC_MODE ? "on" : "off")); + GST_DEBUG (" Deblocking Filter mode (Annex J) : %s", + (params->features & H263_OPTION_DF_MODE ? "on" : "off")); + GST_DEBUG (" Slice Structured mode (Annex K) : %s", + (params->features & H263_OPTION_SS_MODE ? "on" : "off")); + GST_DEBUG (" Reference Picture Selection mode (Annex N) : %s", + (params->features & H263_OPTION_RPS_MODE ? "on" : "off")); + GST_DEBUG (" Independent Segment Decoding mode (Annex R) : %s", + (params->features & H263_OPTION_ISD_MODE ? "on" : "off")); + GST_DEBUG (" Alternative INTER VLC mode (Annex S) : %s", + (params->features & H263_OPTION_AIV_MODE ? "on" : "off")); + GST_DEBUG (" Modified Quantization mode (Annex T) : %s", + (params->features & H263_OPTION_MQ_MODE ? "on" : "off")); + GST_DEBUG (" Enhanced Reference Picture Selection mode (Annex U) : %s", + (params->features & H263_OPTION_ERPS_MODE ? "on" : "off")); + GST_DEBUG (" Enhanced Data Partitioned Slices mode (Annex V) : %s", + (params->features & H263_OPTION_DPS_MODE ? "on" : "off")); + + /* END ufep == 1 */ + /* WE DO NOT SUPPORT optional Reference Picture Resampling mode */ + /* 5.1.18 RPRP : Reference Picture Resampling Parameters (variable length) */ + } + + /* END hasplusptype */ + /* 5.1.19 PQUANT : Quantizer Information (5 bits) */ + if (!gst_bit_reader_get_bits_uint8 (&br, &pquant, 5)) + goto more; + GST_DEBUG (" PQUANT : 0x%x", pquant); + + if (!hasplusptype) { + guint8 cpm; + /* 5.1.20 CPM : Continuous Presence Multipoint and Video Multiplex (1 bit) */ + if (!gst_bit_reader_get_bits_uint8 (&br, &cpm, 1)) + goto more; + GST_DEBUG (" Continuous Presence Multipoint and Video Multiplex : %d", cpm); + + if (cpm) { + /* 5.1.21 PSBI : Picture Sub-Bitstream Indicator (2 bits) */ + guint8 psbi; + if (!gst_bit_reader_get_bits_uint8 (&br, &psbi, 2)) + goto more; + GST_DEBUG (" Picture Sub-Bitstream Indicator (PSBI):%d", psbi); + } + } + + if (params->type & (PICTURE_PB | PICTURE_IMPROVED_PB)) { + /* 5.1.22 TRb : Temporal Reference for B-pictures in PB-frames (3/5bits) */ + /* FIXME : We just swallow the bits */ + if (!gst_bit_reader_get_bits_uint8 (&br, &temp8, + params->custompcfpresent ? 5 : 3)) + goto more; + + /* 5.1.23 DBQUANT : Quantization information for B-pictures in PB-frames (2bits) */ + if (!gst_bit_reader_get_bits_uint8 (&br, &temp8, 2)) + goto more; + } + + GST_DEBUG (" Framerate defined by the stream is %d/%d", + params->pcfnum, params->pcfdenom); + + /* We ignore the PEI and PSUPP - these may occur in any frame, and can be + * ignored by decoders that don't support them, except for bits of Annex W */ + + /* FIXME: Annex H (Forward Error Correction) requires that we poke into the + * stream data. */ + + /* FIXME: Annex P (Reference Picture Resampling) can be signaled implicitly + * as well as in the header. Should we set the field to false in caps if it + * is not specfied by the header? */ + + /* FIXME: Annex U (Enhanced Reference Picture Selection) poses a problem - we + * have no means of specifying what sub-modes, if any, are used. */ + +done: + *state = GOT_HEADER; +more: + return GST_FLOW_OK; + +beach: + *state = PASSTHROUGH; + return GST_FLOW_OK; +} + +gint +gst_h263_parse_get_profile (H263Params * params) +{ + gboolean c, d, d1, d21, d22, e, f, f2, g, h, i, j, k, k0, k1, k2, l, m, n, o, + p, q, r, s, t, u, v, w; + + /* FIXME: some parts of Annex C can be discovered, others can not */ + c = FALSE; + d = (params->features & H263_OPTION_UMV_MODE) != 0; + /* d1: Annex D.1; d21: Annex D.2 with UUI=1; d22: Annex D.2 with UUI=01 */ + d1 = (d && params->uui == UUI_ABSENT); + d21 = (d && params->uui == UUI_IS_1); + d22 = (d && params->uui == UUI_IS_01); + e = (params->features & H263_OPTION_SAC_MODE) != 0; + /* f:Annex F.2 or F.3 may be used; f2: only Annex F.2 is used (we have no + * way of detecting this right now */ + f = (params->features & H263_OPTION_AP_MODE) != 0; + f2 = FALSE; + g = (params->features & H263_OPTION_PB_MODE) != 0; + h = FALSE; + i = (params->features & H263_OPTION_AIC_MODE) != 0; + j = (params->features & H263_OPTION_DF_MODE) != 0; + k = (params->features & H263_OPTION_SS_MODE) != 0; + /* k0: Annex K without submodes; k1: Annex K with ASO; k2: Annex K with RS */ + k0 = (k && params->sss == 0x0); + k1 = (k && params->sss == 0x2); + k2 = (k && params->sss == 0x1); + l = FALSE; + m = (params->type == PICTURE_IMPROVED_PB); + n = (params->features & H263_OPTION_RPS_MODE) != 0; + o = FALSE; + p = FALSE; + q = (params->features & H263_OPTION_RRU_MODE) != 0; + r = (params->features & H263_OPTION_ISD_MODE) != 0; + s = (params->features & H263_OPTION_AIV_MODE) != 0; + t = (params->features & H263_OPTION_MQ_MODE) != 0; + u = (params->features & H263_OPTION_ERPS_MODE) != 0; + v = (params->features & H263_OPTION_DPS_MODE) != 0; + w = FALSE; + + /* FIXME: The use of UUI in Annex D seems to be in contradiction with the + * profile definition in Annex X. Afaict, D.2 with UUI not present is not a + * meaningful state. */ + + /* FIXME: We have no way to distinguish between the use of section F.2 (four + * motion vectors per macroblock) and F.3 (overlapped block motion + * compensation), so we assume that they are either both present else neither + * is. This means if a profile supports only F.2 and not F.3, but we see that + * Advanced Prediction mode (Annex F) is used, we assume this profile does + * not apply. */ + + /* FIXME: We assume there is no error correction (Annex H) to avoid having to + * parse the stream to look for its existence. */ + + /* FIXME: Profiles 1 and 5-8 need the detection of Annex L.4 which can happen + * anywhere in the stream, so we just assume it doesn't exist and hope for + * the best. */ + + /* FIXME: Annex O support is TBD. */ + + /* FIXME: see note for Annex P elsewhere in this file. */ + + /* FIXME: Annex W.6.3.{8,11} suffer the same fate as Annex L.4 above. */ + + /* FIXME: We have no way of figuring out submodes when Annex U is used. Here + * we always assume no submode is used. */ + + if (!c && !d && !e && !f && !g && !h && !i && !j && !k && !l && !m && !n && + !o && !p && !q && !r && !s && !t && !u && !v && !w) + return 0; + if (!c && (!d || d1) && !e && (!f || f2) && !g && !h && !k && !l && !m && + !n && !o && !p && !q && !r && !s && !u && !v && !w) + return 1; + if (!c && (!d || d1) && !e && !g && !h && !i && !j && !k && !l && !m && !n && + !o && !p && !q && !r && !s && !t && !u && !v && !w) + return 2; + if (!c && (!d || d1) && !e && (!f || f2) && !g && !h && (!k || k0) && !l && + !m && !n && !o && !p && !q && !r && !s && !u && !v && !w) + return 3; + if (!c && (!d || d1) && !e && (!f || f2) && !g && !h && (!k || k0) && !l && + !m && !n && !o && !p && !q && !r && !s && !u && !w) + return 4; + if (!c && (!d || d1 || d21) && !e && !g && !h && !k && !l && !m && !n && + !o && !p && !q && !r && !s && !v && !w) + return 5; + if (!c && (!d || d1 || d21) && !e && !g && !h && (!k || k0 || k1) && !l && + !m && !n && !o && !p && !q && !r && !s && !v && !w) + return 6; + if (!c && (!d || d1 || d21) && !e && !g && !h && !k && !l && !m && !n && + !o && !p && !q && !r && !s && !v && !w) + return 7; + if (!c && (!d || d1 || d21) && !e && !g && !h && (!k || k0 || k1) && !l && + !m && !n && !o && !p && !q && !r && !s && !v && !w) + /* FIXME: needs Annex O and Annex P support */ + return 8; + + return -1; +} + +#define H263_PROFILE_NOT_0_2(profile) \ + ((profile) != -1 && (profile) != 0 && (profile) != 2) + +#define H263_FMT_UPTO_QCIF(params) \ + ((params)->format == PICTURE_FMT_SUB_QCIF || \ + (params)->format == PICTURE_FMT_QCIF) +#define H263_FMT_UPTO_CIF(params) \ + ((params)->format == PICTURE_FMT_SUB_QCIF || \ + (params)->format == PICTURE_FMT_QCIF || \ + (params)->format == PICTURE_FMT_CIF) +#define H263_FMT_CUSTOM_UPTO_QCIF(params) \ + ((params)->format == PICTURE_FMT_RESERVED1 && \ + (params)->height <= 144 && \ + (params)->width <= 176) +#define H263_FMT_CUSTOM_UPTO_CIF(params) \ + ((params)->format == PICTURE_FMT_RESERVED1 && \ + (params)->height <= 288 && \ + (params)->width <= 352) + +#define GST_FRACTION_LE(f1, f2) \ + ((gst_value_compare (&(f1), &(f2)) == GST_VALUE_LESS_THAN) || \ + (gst_value_compare (&(f1), &(f2)) == GST_VALUE_EQUAL)) + +gint +gst_h263_parse_get_level (H263Params * params, gint profile, + guint bitrate, gint fps_num, gint fps_denom) +{ + GValue fps15 = { 0, }; + GValue fps30 = { 0, }; + GValue fps50 = { 0, }; + GValue fps60 = { 0, }; + GValue fps = { 0, }; + + if (bitrate == 0) { + GST_DEBUG ("Can't calculate level since bitrate is unknown"); + return -1; + } + + g_value_init (&fps15, GST_TYPE_FRACTION); + g_value_init (&fps30, GST_TYPE_FRACTION); + g_value_init (&fps50, GST_TYPE_FRACTION); + g_value_init (&fps60, GST_TYPE_FRACTION); + g_value_init (&fps, GST_TYPE_FRACTION); + + gst_value_set_fraction (&fps15, 15000, 1001); + gst_value_set_fraction (&fps30, 30000, 1001); + gst_value_set_fraction (&fps50, 50, 1); + gst_value_set_fraction (&fps60, 60000, 1001); + + gst_value_set_fraction (&fps, fps_num, fps_denom); + + /* Level 10 */ + if (H263_FMT_UPTO_QCIF (params) && GST_FRACTION_LE (fps, fps15) && + bitrate <= 64000) + return 10; + + /* Level 20 */ + if (((H263_FMT_UPTO_QCIF (params) && GST_FRACTION_LE (fps, fps30)) || + (params->format == PICTURE_FMT_CIF && GST_FRACTION_LE (fps, fps15))) + && bitrate <= 128000) + return 20; + + /* Level 30 */ + if (H263_FMT_UPTO_CIF (params) && GST_FRACTION_LE (fps, fps30) && + bitrate <= 384000) + return 30; + + /* Level 40 */ + if (H263_FMT_UPTO_CIF (params) && GST_FRACTION_LE (fps, fps30) && + bitrate <= 2048000) + return 40; + + /* Level 45 */ + if ((H263_FMT_UPTO_QCIF (params) || (H263_FMT_CUSTOM_UPTO_QCIF (params) && + H263_PROFILE_NOT_0_2 (profile))) && + GST_FRACTION_LE (fps, fps15) && + /* (!h263parse->custompcfpresent || H263_PROFILE_NOT_0_2(profile)) && */ + bitrate <= 128000) + return 45; + + /* Level 50 */ + if ((H263_FMT_UPTO_CIF (params) || H263_FMT_CUSTOM_UPTO_CIF (params)) && + (GST_FRACTION_LE (fps, fps50) || + (params->width <= 352 && params->height <= 240 && + GST_FRACTION_LE (fps, fps60))) && (bitrate <= 4096000)) + return 50; + + /* Level 60 */ + if (((params->width <= 720 && params->height <= 288 && + GST_FRACTION_LE (fps, fps50)) || + (params->width <= 720 && params->height <= 240 && + GST_FRACTION_LE (fps, fps60))) && (bitrate <= 8192000)) + return 60; + + /* Level 70 */ + if (((params->width <= 720 && params->height <= 576 && + GST_FRACTION_LE (fps, fps50)) || + (params->width <= 720 && params->height <= 480 && + GST_FRACTION_LE (fps, fps60))) && (bitrate <= 16384000)) + return 70; + + GST_DEBUG ("Weird - didn't match any profile!"); + return -1; +} + +void +gst_h263_parse_get_framerate (H263Params * params, gint * num, gint * denom) +{ + *num = params->pcfnum; + *denom = params->pcfdenom; +} diff --git a/gst/videoparsers/h263parse.h b/gst/videoparsers/h263parse.h new file mode 100644 index 000000000..2e66f0e48 --- /dev/null +++ b/gst/videoparsers/h263parse.h @@ -0,0 +1,144 @@ +/* GStreamer H.263 Parser + * Copyright (C) <2010> Arun Raghavan <arun.raghavan@collabora.co.uk> + * Copyright (C) <2010> Edward Hervey <edward.hervey@collabora.co.uk> + * Copyright (C) <2010> Collabora Multimedia + * Copyright (C) <2010> Nokia Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_H263_PARAMS_H__ +#define __GST_H263_PARAMS_H__ + +#include <gst/gst.h> +#include <gst/base/gstadapter.h> +#include <gst/baseparse/gstbaseparse.h> + +G_BEGIN_DECLS + +typedef enum +{ + PARSING = 0, + GOT_HEADER, + PASSTHROUGH +} H263ParseState; + +/* H263 Optional Features */ +typedef enum +{ + /* Optional Unrestricted Motion Vector (UMV) mode (see Annex D) */ + H263_OPTION_UMV_MODE = 1 << 0, + /* Optional Syntax-based Arithmetic Coding (SAC) mode (see Annex E) */ + H263_OPTION_SAC_MODE = 1 << 1, + /* Optional Advanced Prediction mode (AP) (see Annex F) */ + H263_OPTION_AP_MODE = 1 << 2, + /* Optional PB-frames mode (see Annex G) */ + H263_OPTION_PB_MODE = 1 << 3, + /* Optional Advanced INTRA Coding (AIC) mode (see Annex I) */ + H263_OPTION_AIC_MODE = 1 << 4, + /* Optional Deblocking Filter (DF) mode (see Annex J) */ + H263_OPTION_DF_MODE = 1 << 5, + /* Optional Slice Structured (SS) mode (see Annex K) */ + H263_OPTION_SS_MODE = 1 << 6, + /* Optional Reference Picture Selection (RPS) mode (see Annex N) */ + H263_OPTION_RPS_MODE = 1 << 7, + /* Optional Independent Segment Decoding (ISD) mode (see Annex R) */ + H263_OPTION_ISD_MODE = 1 << 8, + /* Optional Alternative INTER VLC (AIV) mode (see Annex S) */ + H263_OPTION_AIV_MODE = 1 << 9, + /* Optional Modified Quantization (MQ) mode (see Annex T) */ + H263_OPTION_MQ_MODE = 1 << 10, + /* Optional Reference Picture Resampling (RPR) mode (see Annex P) */ + H263_OPTION_RPR_MODE = 1 << 11, + /* Optional Reduced-Resolution Update (RRU) mode (see Annex Q) */ + H263_OPTION_RRU_MODE = 1 << 12, + /* Optional Enhanced Reference Picture Selection (ERPS) mode (see Annex U) */ + H263_OPTION_ERPS_MODE = 1 << 13, + /* Optional Data Partitioned Slices (DPS) mode (see Annex V) */ + H263_OPTION_DPS_MODE = 1 << 14 +} H263OptionalFeatures; + +/* H263 Picture Types */ +typedef enum +{ + PICTURE_I = 0, /* I-picture (INTRA) Baseline */ + PICTURE_P, /* P-picture (INTER) Baseline */ + PICTURE_IMPROVED_PB, /* Improved PB-frame (Annex M) */ + PICTURE_B, /* B-picture (Annex O) */ + PICTURE_EI, /* EI-picture (Annex O) */ + PICTURE_EP, /* EP-picture (Annex O) */ + PICTURE_RESERVED1, + PICTURE_RESERVED2, + PICTURE_PB /* PB-frame (See Annex G) */ +} H263PictureType; + +/* H263 Picture Format */ +typedef enum +{ + PICTURE_FMT_FORBIDDEN_0 = 0, + PICTURE_FMT_SUB_QCIF, + PICTURE_FMT_QCIF, + PICTURE_FMT_CIF, + PICTURE_FMT_4CIF, + PICTURE_FMT_16CIF, + PICTURE_FMT_RESERVED1, + PICTURE_FMT_EXTENDEDPTYPE +} H263PictureFormat; + +typedef enum +{ + UUI_ABSENT = 0, + UUI_IS_1, + UUI_IS_01, +} H263UUI; + + +typedef struct _H263Params H263Params; + +struct _H263Params +{ + guint32 temporal_ref; + + H263OptionalFeatures features; + + gboolean splitscreen; + gboolean documentcamera; + gboolean fullpicturefreezerelease; + gboolean custompcfpresent; + H263UUI uui; + guint8 sss; + + H263PictureFormat format; + + H263PictureType type; + + guint32 width; + guint32 height; + guint8 parnum, pardenom; + gint32 pcfnum, pcfdenom; +}; + +gboolean gst_h263_parse_is_delta_unit (H263Params * params); +GstFlowReturn gst_h263_parse_get_params (H263Params ** params_p, + GstBuffer * buffer, gboolean fast, H263ParseState * state); +void gst_h263_parse_get_framerate (H263Params * params, + gint * num, gint * denom); +gint gst_h263_parse_get_profile (H263Params * params); +gint gst_h263_parse_get_level (H263Params * params, gint profile, + guint bitrate, gint fps_num, gint fps_denom); + +G_END_DECLS +#endif diff --git a/gst/videoparsers/h264parse.c b/gst/videoparsers/h264parse.c new file mode 100644 index 000000000..f0ec757f8 --- /dev/null +++ b/gst/videoparsers/h264parse.c @@ -0,0 +1,1042 @@ +/* GStreamer H.264 Parser + * Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + * Copyright (C) <2010> Collabora Multimedia + * Copyright (C) <2010> Nokia Corporation + * + * Some bits C-c,C-v'ed and s/4/3 from h264parse: + * (C) 2005 Michal Benes <michal.benes@itonis.tv> + * (C) 2008 Wim Taymans <wim.taymans@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "h264parse.h" + +#include <string.h> + +GST_DEBUG_CATEGORY_EXTERN (h264_parse_debug); +#define GST_CAT_DEFAULT h264_parse_debug + +/* simple bitstream parser, automatically skips over + * emulation_prevention_three_bytes. */ +typedef struct +{ + const guint8 *orig_data; + const guint8 *data; + const guint8 *end; + /* bitpos in the cache of next bit */ + gint head; + /* cached bytes */ + guint64 cache; +} GstNalBs; + +static void +gst_nal_bs_init (GstNalBs * bs, const guint8 * data, guint size) +{ + bs->orig_data = data; + bs->data = data; + bs->end = data + size; + bs->head = 0; + /* fill with something other than 0 to detect emulation prevention bytes */ + bs->cache = 0xffffffff; +} + +static inline void +gst_nal_bs_get_data (GstNalBs * bs, const guint8 ** data, guint * size) +{ + *data = bs->orig_data; + *size = bs->end - bs->orig_data; +} + +static guint32 +gst_nal_bs_read (GstNalBs * bs, guint n) +{ + guint32 res = 0; + gint shift; + + if (n == 0) + return res; + + /* fill up the cache if we need to */ + while (bs->head < n) { + guint8 byte; + gboolean check_three_byte; + + check_three_byte = TRUE; + next_byte: + if (bs->data >= bs->end) { + /* we're at the end, can't produce more than head number of bits */ + n = bs->head; + break; + } + /* get the byte, this can be an emulation_prevention_three_byte that we need + * to ignore. */ + byte = *bs->data++; + if (check_three_byte && byte == 0x03 && ((bs->cache & 0xffff) == 0)) { + /* next byte goes unconditionally to the cache, even if it's 0x03 */ + check_three_byte = FALSE; + goto next_byte; + } + /* shift bytes in cache, moving the head bits of the cache left */ + bs->cache = (bs->cache << 8) | byte; + bs->head += 8; + } + + /* bring the required bits down and truncate */ + if ((shift = bs->head - n) > 0) + res = bs->cache >> shift; + else + res = bs->cache; + + /* mask out required bits */ + if (n < 32) + res &= (1 << n) - 1; + + bs->head = shift; + + return res; +} + +static gboolean +gst_nal_bs_eos (GstNalBs * bs) +{ + return (bs->data >= bs->end) && (bs->head == 0); +} + +/* read unsigned Exp-Golomb code */ +static gint +gst_nal_bs_read_ue (GstNalBs * bs) +{ + gint i = 0; + + while (gst_nal_bs_read (bs, 1) == 0 && !gst_nal_bs_eos (bs) && i < 32) + i++; + + return ((1 << i) - 1 + gst_nal_bs_read (bs, i)); +} + +/* read signed Exp-Golomb code */ +static gint +gst_nal_bs_read_se (GstNalBs * bs) +{ + gint i = 0; + + i = gst_nal_bs_read_ue (bs); + /* (-1)^(i+1) Ceil (i / 2) */ + i = (i + 1) / 2 * (i & 1 ? 1 : -1); + + return i; +} + +/* end parser helper */ + +static void +gst_h264_params_store_nal (GstH264Params * params, GstBuffer ** store, gint id, + GstNalBs * bs) +{ + const guint8 *data; + GstBuffer *buf; + guint size; + + g_return_if_fail (MAX_SPS_COUNT == MAX_PPS_COUNT); + + if (id >= MAX_SPS_COUNT) { + GST_DEBUG_OBJECT (params->el, + "unable to store nal, id out-of-range %d", id); + return; + } + + gst_nal_bs_get_data (bs, &data, &size); + buf = gst_buffer_new_and_alloc (size); + memcpy (GST_BUFFER_DATA (buf), data, size); + gst_buffer_replace (store + id, buf); +} + +static GstH264ParamsSPS * +gst_h264_params_get_sps (GstH264Params * params, guint8 sps_id, gboolean set) +{ + GstH264ParamsSPS *sps; + + g_return_val_if_fail (params != NULL, NULL); + + if (G_UNLIKELY (sps_id >= MAX_SPS_COUNT)) { + GST_WARNING_OBJECT (params->el, + "requested sps_id=%04x out of range", sps_id); + return NULL; + } + + sps = ¶ms->sps_buffers[sps_id]; + if (set) { + if (sps->valid) { + params->sps = sps; + } else { + GST_WARNING_OBJECT (params->el, "invalid sps not selected"); + params->sps = NULL; + sps = NULL; + } + } + + return sps; +} + +static GstH264ParamsPPS * +gst_h264_params_get_pps (GstH264Params * params, guint8 pps_id, gboolean set) +{ + GstH264ParamsPPS *pps; + + g_return_val_if_fail (params != NULL, NULL); + + if (G_UNLIKELY (pps_id >= MAX_PPS_COUNT)) { + GST_WARNING_OBJECT (params->el, + "requested pps_id=%04x out of range", pps_id); + return NULL; + } + + pps = ¶ms->pps_buffers[pps_id]; + if (set) { + if (pps->valid) { + params->pps = pps; + } else { + GST_WARNING_OBJECT (params->el, "invalid pps not selected"); + params->pps = NULL; + pps = NULL; + } + } + + return pps; +} + +static gboolean +gst_h264_params_decode_sps_vui_hrd (GstH264Params * params, + GstH264ParamsSPS * sps, GstNalBs * bs) +{ + gint sched_sel_idx; + + sps->cpb_cnt_minus1 = gst_nal_bs_read_ue (bs); + if (sps->cpb_cnt_minus1 > 31U) { + GST_WARNING_OBJECT (params->el, "cpb_cnt_minus1 = %d out of range", + sps->cpb_cnt_minus1); + return FALSE; + } + + /* bit_rate_scale */ + gst_nal_bs_read (bs, 4); + /* cpb_size_scale */ + gst_nal_bs_read (bs, 4); + + for (sched_sel_idx = 0; sched_sel_idx <= sps->cpb_cnt_minus1; sched_sel_idx++) { + /* bit_rate_value_minus1 */ + gst_nal_bs_read_ue (bs); + /* cpb_size_value_minus1 */ + gst_nal_bs_read_ue (bs); + /* cbr_flag */ + gst_nal_bs_read (bs, 1); + } + + sps->initial_cpb_removal_delay_length_minus1 = gst_nal_bs_read (bs, 5); + sps->cpb_removal_delay_length_minus1 = gst_nal_bs_read (bs, 5); + sps->dpb_output_delay_length_minus1 = gst_nal_bs_read (bs, 5); + sps->time_offset_length_minus1 = gst_nal_bs_read (bs, 5); + + return TRUE; +} + +static gboolean +gst_h264_params_decode_sps_vui (GstH264Params * params, GstH264ParamsSPS * sps, + GstNalBs * bs) +{ + if (G_UNLIKELY (!sps)) + return FALSE; + + /* aspect_ratio_info_present_flag */ + if (gst_nal_bs_read (bs, 1)) { + /* aspect_ratio_idc */ + if (gst_nal_bs_read (bs, 8) == 255) { + /* Extended_SAR */ + /* sar_width */ + gst_nal_bs_read (bs, 16); + /* sar_height */ + gst_nal_bs_read (bs, 16); + } + } + + /* overscan_info_present_flag */ + if (gst_nal_bs_read (bs, 1)) { + /* overscan_appropriate_flag */ + gst_nal_bs_read (bs, 1); + } + + /* video_signal_type_present_flag */ + if (gst_nal_bs_read (bs, 1)) { + /* video_format */ + gst_nal_bs_read (bs, 3); + /* video_full_range_flag */ + gst_nal_bs_read (bs, 1); + + /* colour_description_present_flag */ + if (gst_nal_bs_read (bs, 1)) { + /* colour_primaries */ + gst_nal_bs_read (bs, 8); + /* transfer_characteristics */ + gst_nal_bs_read (bs, 8); + /* matrix_coefficients */ + gst_nal_bs_read (bs, 8); + } + } + + /* chroma_loc_info_present_flag */ + if (gst_nal_bs_read (bs, 1)) { + /* chroma_sample_loc_type_top_field */ + gst_nal_bs_read_ue (bs); + /* chroma_sample_loc_type_bottom_field */ + gst_nal_bs_read_ue (bs); + } + + sps->timing_info_present_flag = gst_nal_bs_read (bs, 1); + if (sps->timing_info_present_flag) { + guint32 num_units_in_tick = gst_nal_bs_read (bs, 32); + guint32 time_scale = gst_nal_bs_read (bs, 32); + + /* If any of these parameters = 0, discard all timing_info */ + if (time_scale == 0) { + GST_WARNING_OBJECT (params->el, + "time_scale = 0 detected in stream (incompliant to H.264 E.2.1)." + " Discarding related info."); + } else if (num_units_in_tick == 0) { + GST_WARNING_OBJECT (params->el, + "num_units_in_tick = 0 detected in stream (incompliant to H.264 E.2.1)." + " Discarding related info."); + } else { + sps->num_units_in_tick = num_units_in_tick; + sps->time_scale = time_scale; + sps->fixed_frame_rate_flag = gst_nal_bs_read (bs, 1); + GST_LOG_OBJECT (params->el, "timing info: dur=%d/%d fixed=%d", + num_units_in_tick, time_scale, sps->fixed_frame_rate_flag); + } + } + + sps->nal_hrd_parameters_present_flag = gst_nal_bs_read (bs, 1); + if (sps->nal_hrd_parameters_present_flag) { + gst_h264_params_decode_sps_vui_hrd (params, sps, bs); + } + sps->vcl_hrd_parameters_present_flag = gst_nal_bs_read (bs, 1); + if (sps->vcl_hrd_parameters_present_flag) { + gst_h264_params_decode_sps_vui_hrd (params, sps, bs); + } + if (sps->nal_hrd_parameters_present_flag + || sps->vcl_hrd_parameters_present_flag) { + gst_nal_bs_read (bs, 1); /* low_delay_hrd_flag */ + } + + sps->pic_struct_present_flag = gst_nal_bs_read (bs, 1); + + /* derive framerate */ + /* FIXME verify / also handle other cases */ + if (sps->fixed_frame_rate_flag && sps->frame_mbs_only_flag && + !sps->pic_struct_present_flag) { + sps->fps_num = sps->time_scale; + sps->fps_den = sps->num_units_in_tick; + /* picture is a frame = 2 fields */ + sps->fps_den *= 2; + GST_LOG_OBJECT (params->el, "framerate %d/%d", sps->fps_num, sps->fps_den); + } + + return TRUE; +} + +static gboolean +gst_h264_params_decode_sps (GstH264Params * params, GstNalBs * bs) +{ + guint8 profile_idc, level_idc; + guint8 sps_id; + GstH264ParamsSPS *sps = NULL; + guint subwc[] = { 1, 2, 2, 1 }; + guint subhc[] = { 1, 2, 1, 1 }; + guint chroma; + guint fc_top, fc_bottom, fc_left, fc_right; + gint width, height; + + profile_idc = gst_nal_bs_read (bs, 8); + /* constraint_set0_flag */ + gst_nal_bs_read (bs, 1); + /* constraint_set1_flag */ + gst_nal_bs_read (bs, 1); + /* constraint_set1_flag */ + gst_nal_bs_read (bs, 1); + /* constraint_set1_flag */ + gst_nal_bs_read (bs, 1); + /* reserved */ + gst_nal_bs_read (bs, 4); + level_idc = gst_nal_bs_read (bs, 8); + + sps_id = gst_nal_bs_read_ue (bs); + sps = gst_h264_params_get_sps (params, sps_id, FALSE); + if (G_UNLIKELY (sps == NULL)) + return FALSE; + + gst_h264_params_store_nal (params, params->sps_nals, sps_id, bs); + + /* could be redefined mid stream, arrange for clear state */ + memset (sps, 0, sizeof (*sps)); + + GST_LOG_OBJECT (params->el, "sps id %d", sps_id); + sps->valid = TRUE; + /* validate and force activate this one if it is the first SPS we see */ + if (params->sps == NULL) + params->sps = sps; + + sps->profile_idc = profile_idc; + sps->level_idc = level_idc; + + if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 + || profile_idc == 244 || profile_idc == 44 || + profile_idc == 83 || profile_idc == 86) { + gint scp_flag = 0; + + /* chroma_format_idc */ + if ((chroma = gst_nal_bs_read_ue (bs)) == 3) { + /* separate_colour_plane_flag */ + sps->scp_flag = gst_nal_bs_read (bs, 1); + } + /* bit_depth_luma_minus8 */ + gst_nal_bs_read_ue (bs); + /* bit_depth_chroma_minus8 */ + gst_nal_bs_read_ue (bs); + /* qpprime_y_zero_transform_bypass_flag */ + gst_nal_bs_read (bs, 1); + /* seq_scaling_matrix_present_flag */ + if (gst_nal_bs_read (bs, 1)) { + gint i, j, m, d; + + m = (chroma != 3) ? 8 : 12; + for (i = 0; i < m; i++) { + /* seq_scaling_list_present_flag[i] */ + d = gst_nal_bs_read (bs, 1); + if (d) { + gint lastScale = 8, nextScale = 8, deltaScale; + + j = (i < 6) ? 16 : 64; + for (; j > 0; j--) { + if (nextScale != 0) { + deltaScale = gst_nal_bs_read_se (bs); + nextScale = (lastScale + deltaScale + 256) % 256; + } + if (nextScale != 0) + lastScale = nextScale; + } + } + } + } + if (scp_flag) + chroma = 0; + } else { + /* inferred value */ + chroma = 1; + } + + /* between 0 and 12 */ + sps->log2_max_frame_num_minus4 = gst_nal_bs_read_ue (bs); + if (sps->log2_max_frame_num_minus4 > 12) { + GST_WARNING_OBJECT (params->el, + "log2_max_frame_num_minus4 = %d out of range" " [0,12]", + sps->log2_max_frame_num_minus4); + return FALSE; + } + + sps->pic_order_cnt_type = gst_nal_bs_read_ue (bs); + if (sps->pic_order_cnt_type == 0) { + sps->log2_max_pic_order_cnt_lsb_minus4 = gst_nal_bs_read_ue (bs); + } else if (sps->pic_order_cnt_type == 1) { + gint d; + + /* delta_pic_order_always_zero_flag */ + gst_nal_bs_read (bs, 1); + /* offset_for_non_ref_pic */ + gst_nal_bs_read_ue (bs); + /* offset_for_top_to_bottom_field */ + gst_nal_bs_read_ue (bs); + /* num_ref_frames_in_pic_order_cnt_cycle */ + d = gst_nal_bs_read_ue (bs); + for (; d > 0; d--) { + /* offset_for_ref_frame[i] */ + gst_nal_bs_read_ue (bs); + } + } + + /* max_num_ref_frames */ + gst_nal_bs_read_ue (bs); + /* gaps_in_frame_num_value_allowed_flag */ + gst_nal_bs_read (bs, 1); + /* pic_width_in_mbs_minus1 */ + width = gst_nal_bs_read_ue (bs); + /* pic_height_in_map_units_minus1 */ + height = gst_nal_bs_read_ue (bs); + + sps->frame_mbs_only_flag = gst_nal_bs_read (bs, 1); + if (!sps->frame_mbs_only_flag) { + /* mb_adaptive_frame_field_flag */ + gst_nal_bs_read (bs, 1); + } + + width++; + width *= 16; + height++; + height *= 16 * (2 - sps->frame_mbs_only_flag); + + /* direct_8x8_inference_flag */ + gst_nal_bs_read (bs, 1); + /* frame_cropping_flag */ + if (gst_nal_bs_read (bs, 1)) { + /* frame_crop_left_offset */ + fc_left = gst_nal_bs_read_ue (bs); + /* frame_crop_right_offset */ + fc_right = gst_nal_bs_read_ue (bs); + /* frame_crop_top_offset */ + fc_top = gst_nal_bs_read_ue (bs); + /* frame_crop_bottom_offset */ + fc_bottom = gst_nal_bs_read_ue (bs); + } else { + fc_left = fc_right = fc_top = fc_bottom = 0; + } + + GST_LOG_OBJECT (params->el, "decoding SPS: profile_idc = %d, " + "level_idc = %d, sps_id = %d, pic_order_cnt_type = %d, " + "frame_mbs_only_flag = %d", + sps->profile_idc, sps->level_idc, sps_id, sps->pic_order_cnt_type, + sps->frame_mbs_only_flag); + + /* calculate width and height */ + GST_LOG_OBJECT (params->el, "initial width=%d, height=%d", width, height); + GST_LOG_OBJECT (params->el, "crop (%d,%d)(%d,%d)", + fc_left, fc_top, fc_right, fc_bottom); + if (chroma > 3) { + GST_LOG_OBJECT (params->el, "chroma=%d in SPS is out of range", chroma); + return FALSE; + } + width -= (fc_left + fc_right) * subwc[chroma]; + height -= + (fc_top + fc_bottom) * subhc[chroma] * (2 - sps->frame_mbs_only_flag); + if (width < 0 || height < 0) { + GST_WARNING_OBJECT (params->el, "invalid width/height in SPS"); + return FALSE; + } + GST_LOG_OBJECT (params->el, "final width=%u, height=%u", width, height); + sps->width = width; + sps->height = height; + + sps->vui_parameters_present_flag = gst_nal_bs_read (bs, 1); + if (sps->vui_parameters_present_flag) { + /* discard parsing problem */ + gst_h264_params_decode_sps_vui (params, sps, bs); + } + + return TRUE; +} + +static gboolean +gst_h264_params_decode_pps (GstH264Params * params, GstNalBs * bs) +{ + guint8 pps_id; + GstH264ParamsPPS *pps = NULL; + + pps_id = gst_nal_bs_read_ue (bs); + + pps = gst_h264_params_get_pps (params, pps_id, FALSE); + if (G_UNLIKELY (pps == NULL)) + return FALSE; + + /* validate and set */ + pps->valid = TRUE; + params->pps = pps; + + gst_h264_params_store_nal (params, params->pps_nals, pps_id, bs); + + pps->sps_id = gst_nal_bs_read_ue (bs); + GST_LOG_OBJECT (params->el, "pps %d referencing sps %d", pps_id, pps->sps_id); + + /* activate referenced sps */ + if (!gst_h264_params_get_sps (params, pps->sps_id, TRUE)) + return FALSE; + + /* not parsing the rest for the time being */ + return TRUE; +} + +static gboolean +gst_h264_params_decode_sei_buffering_period (GstH264Params * params, + GstNalBs * bs) +{ +#ifdef EXTRA_PARSE + guint8 sps_id; + gint sched_sel_idx; + GstH264ParamsSPS *sps; + + sps_id = gst_nal_bs_read_ue (bs); + sps = gst_h264_params_get_sps (params, sps_id, TRUE); + if (G_UNLIKELY (sps == NULL)) + return FALSE; + + if (sps->nal_hrd_parameters_present_flag) { + for (sched_sel_idx = 0; sched_sel_idx <= sps->cpb_cnt_minus1; + sched_sel_idx++) { + params->initial_cpb_removal_delay[sched_sel_idx] + = gst_nal_bs_read (bs, + sps->initial_cpb_removal_delay_length_minus1 + 1); + /* initial_cpb_removal_delay_offset */ + gst_nal_bs_read (bs, sps->initial_cpb_removal_delay_length_minus1 + 1); + } + } + + if (sps->vcl_hrd_parameters_present_flag) { + for (sched_sel_idx = 0; sched_sel_idx <= sps->cpb_cnt_minus1; + sched_sel_idx++) { + params->initial_cpb_removal_delay[sched_sel_idx] + = gst_nal_bs_read (bs, + sps->initial_cpb_removal_delay_length_minus1 + 1); + /* initial_cpb_removal_delay_offset */ + gst_nal_bs_read (bs, sps->initial_cpb_removal_delay_length_minus1 + 1); + } + } +#endif + + if (params->ts_trn_nb == GST_CLOCK_TIME_NONE || + params->dts == GST_CLOCK_TIME_NONE) + params->ts_trn_nb = 0; + else + params->ts_trn_nb = params->dts; + + GST_LOG_OBJECT (params->el, + "new buffering period; ts_trn_nb updated: %" GST_TIME_FORMAT, + GST_TIME_ARGS (params->ts_trn_nb)); + + return 0; +} + +static gboolean +gst_h264_params_decode_sei_picture_timing (GstH264Params * params, + GstNalBs * bs) +{ + GstH264ParamsSPS *sps = params->sps; + + if (sps == NULL) { + GST_WARNING_OBJECT (params->el, + "SPS == NULL; delayed decoding of picture timing info not implemented "); + return FALSE; + } + + if (sps->nal_hrd_parameters_present_flag + || sps->vcl_hrd_parameters_present_flag) { + params->sei_cpb_removal_delay = + gst_nal_bs_read (bs, sps->cpb_removal_delay_length_minus1 + 1); + /* sei_dpb_output_delay */ + gst_nal_bs_read (bs, sps->dpb_output_delay_length_minus1 + 1); + } + + if (sps->pic_struct_present_flag) { +#ifdef EXTRA_PARSE + /* pic_struct to NumClockTS lookup table */ + static const guint8 sei_num_clock_ts_table[9] = + { 1, 1, 1, 2, 2, 3, 3, 2, 3 }; + guint i, num_clock_ts; + guint sei_ct_type = 0; +#endif + + params->sei_pic_struct = gst_nal_bs_read (bs, 4); + GST_LOG_OBJECT (params, "pic_struct:%d", params->sei_pic_struct); + if (params->sei_pic_struct > SEI_PIC_STRUCT_FRAME_TRIPLING) + return FALSE; + +#ifdef EXTRA_PARSE + num_clock_ts = sei_num_clock_ts_table[params->sei_pic_struct]; + + for (i = 0; i < num_clock_ts; i++) { + /* clock_timestamp_flag */ + if (gst_nal_bs_read (bs, 1)) { + guint full_timestamp_flag; + + sei_ct_type |= 1 << gst_nal_bs_read (bs, 2); + /* nuit_field_based_flag */ + gst_nal_bs_read (bs, 1); + /* counting_type */ + gst_nal_bs_read (bs, 5); + full_timestamp_flag = gst_nal_bs_read (bs, 1); + /* discontinuity_flag */ + gst_nal_bs_read (bs, 1); + /* cnt_dropped_flag */ + gst_nal_bs_read (bs, 1); + /* n_frames */ + gst_nal_bs_read (bs, 8); + if (full_timestamp_flag) { + /* seconds_value 0..59 */ + gst_nal_bs_read (bs, 6); + /* minutes_value 0..59 */ + gst_nal_bs_read (bs, 6); + /* hours_value 0..23 */ + gst_nal_bs_read (bs, 5); + } else { + /* seconds_flag */ + if (gst_nal_bs_read (bs, 1)) { + /* seconds_value range 0..59 */ + gst_nal_bs_read (bs, 6); + /* minutes_flag */ + if (gst_nal_bs_read (bs, 1)) { + /* minutes_value 0..59 */ + gst_nal_bs_read (bs, 6); + /* hours_flag */ + if (gst_nal_bs_read (bs, 1)) + /* hours_value 0..23 */ + gst_nal_bs_read (bs, 5); + } + } + } + if (sps->time_offset_length_minus1 >= 0) { + /* time_offset */ + gst_nal_bs_read (bs, sps->time_offset_length_minus1 + 1); + } + } + } + + GST_LOG_OBJECT (params, "ct_type:%X", sei_ct_type); +#endif + } + + return TRUE; +} + +static gboolean +gst_h264_params_decode_sei (GstH264Params * params, GstNalBs * bs) +{ + guint8 tmp; + GstH264ParamsSEIPayloadType payloadType = 0; + gint8 payloadSize = 0; + + do { + tmp = gst_nal_bs_read (bs, 8); + payloadType += tmp; + } while (tmp == 255); + do { + tmp = gst_nal_bs_read (bs, 8); + payloadSize += tmp; + } while (tmp == 255); + + GST_LOG_OBJECT (params->el, + "SEI message received: payloadType = %d, payloadSize = %d bytes", + payloadType, payloadSize); + + switch (payloadType) { + case SEI_BUF_PERIOD: + if (!gst_h264_params_decode_sei_buffering_period (params, bs)) + return FALSE; + break; + case SEI_PIC_TIMING: + /* TODO: According to H264 D2.2 Note1, it might be the case that the + * picture timing SEI message is encountered before the corresponding SPS + * is specified. Need to hold down the message and decode it later. */ + if (!gst_h264_params_decode_sei_picture_timing (params, bs)) + return FALSE; + break; + default: + GST_LOG_OBJECT (params->el, + "SEI message of payloadType = %d is received but not parsed", + payloadType); + break; + } + + return TRUE; +} + +static gboolean +gst_h264_params_decode_slice_header (GstH264Params * params, GstNalBs * bs) +{ + GstH264ParamsSPS *sps; + GstH264ParamsPPS *pps; + guint8 pps_id; + + params->first_mb_in_slice = gst_nal_bs_read_ue (bs); + params->slice_type = gst_nal_bs_read_ue (bs); + + pps_id = gst_nal_bs_read_ue (bs); + GST_LOG_OBJECT (params->el, "slice header references pps id %d", pps_id); + pps = gst_h264_params_get_pps (params, pps_id, TRUE); + if (G_UNLIKELY (pps == NULL)) + return FALSE; + sps = gst_h264_params_get_sps (params, pps->sps_id, TRUE); + if (G_UNLIKELY (sps == NULL)) + return FALSE; + + if (sps->scp_flag) { + /* colour_plane_id */ + gst_nal_bs_read (bs, 2); + } + + /* frame num */ + gst_nal_bs_read (bs, sps->log2_max_pic_order_cnt_lsb_minus4 + 4); + + if (!sps->frame_mbs_only_flag) { + params->field_pic_flag = gst_nal_bs_read (bs, 1); + if (params->field_pic_flag) + params->bottom_field_flag = gst_nal_bs_read (bs, 1); + } + + /* not parsing the rest for the time being */ + return TRUE; +} + +/* only payload in @data */ +gboolean +gst_h264_params_parse_nal (GstH264Params * params, guint8 * data, gint size) +{ + GstH264ParamsNalUnitType nal_type; + GstNalBs bs; + gint nal_ref_idc; + gboolean res = TRUE; + + g_return_val_if_fail (params != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (size != 0, FALSE); + + nal_type = (data[0] & 0x1f); + nal_ref_idc = (data[0] & 0x60) >> 5; + + GST_LOG_OBJECT (params->el, "NAL type: %d, ref_idc: %d", nal_type, + nal_ref_idc); + + gst_nal_bs_init (&bs, data + 1, size - 1); + /* optimality HACK */ + bs.orig_data = data; + + /* first parse some things needed to get to the frame type */ + switch (nal_type) { + case NAL_SLICE: + case NAL_SLICE_DPA: + case NAL_SLICE_DPB: + case NAL_SLICE_DPC: + case NAL_SLICE_IDR: + { + gint first_mb_in_slice, slice_type; + + gst_h264_params_decode_slice_header (params, &bs); + first_mb_in_slice = params->first_mb_in_slice; + slice_type = params->slice_type; + + GST_LOG_OBJECT (params->el, "first MB: %d, slice type: %d", + first_mb_in_slice, slice_type); + + switch (slice_type) { + case 0: + case 5: + case 3: + case 8: /* SP */ + /* P frames */ + GST_LOG_OBJECT (params->el, "we have a P slice"); + break; + case 1: + case 6: + /* B frames */ + GST_LOG_OBJECT (params->el, "we have a B slice"); + break; + case 2: + case 7: + case 4: + case 9: + /* I frames */ + GST_LOG_OBJECT (params->el, "we have an I slice"); + break; + } + break; + } + case NAL_SEI: + GST_LOG_OBJECT (params->el, "SEI NAL"); + res = gst_h264_params_decode_sei (params, &bs); + break; + case NAL_SPS: + GST_LOG_OBJECT (params->el, "SPS NAL"); + res = gst_h264_params_decode_sps (params, &bs); + break; + case NAL_PPS: + GST_LOG_OBJECT (params->el, "PPS NAL"); + res = gst_h264_params_decode_pps (params, &bs); + break; + case NAL_AU_DELIMITER: + GST_LOG_OBJECT (params->el, "AU delimiter NAL"); + break; + default: + GST_LOG_OBJECT (params->el, "unparsed NAL"); + break; + } + + return res; +} + +void +gst_h264_params_get_timestamp (GstH264Params * params, + GstClockTime * out_ts, GstClockTime * out_dur, gboolean frame) +{ + GstH264ParamsSPS *sps = params->sps; + GstClockTime upstream; + gint duration = 1; + + g_return_if_fail (out_dur != NULL); + g_return_if_fail (out_ts != NULL); + + upstream = *out_ts; + + if (!frame) { + GST_LOG_OBJECT (params->el, "no frame data -> 0 duration"); + *out_dur = 0; + goto exit; + } else { + *out_ts = upstream; + } + + if (!sps) { + GST_DEBUG_OBJECT (params->el, "referred SPS invalid"); + goto exit; + } else if (!sps->timing_info_present_flag) { + GST_DEBUG_OBJECT (params->el, + "unable to compute timestamp: timing info not present"); + goto exit; + } else if (sps->time_scale == 0) { + GST_DEBUG_OBJECT (params->el, + "unable to compute timestamp: time_scale = 0 " + "(this is forbidden in spec; bitstream probably contains error)"); + goto exit; + } + + if (sps->pic_struct_present_flag && params->sei_pic_struct != (guint8) - 1) { + /* Note that when h264parse->sei_pic_struct == -1 (unspecified), there + * are ways to infer its value. This is related to computing the + * TopFieldOrderCnt and BottomFieldOrderCnt, which looks + * complicated and thus not implemented for the time being. Yet + * the value we have here is correct for many applications + */ + switch (params->sei_pic_struct) { + case SEI_PIC_STRUCT_TOP_FIELD: + case SEI_PIC_STRUCT_BOTTOM_FIELD: + duration = 1; + break; + case SEI_PIC_STRUCT_FRAME: + case SEI_PIC_STRUCT_TOP_BOTTOM: + case SEI_PIC_STRUCT_BOTTOM_TOP: + duration = 2; + break; + case SEI_PIC_STRUCT_TOP_BOTTOM_TOP: + case SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM: + duration = 3; + break; + case SEI_PIC_STRUCT_FRAME_DOUBLING: + duration = 4; + break; + case SEI_PIC_STRUCT_FRAME_TRIPLING: + duration = 6; + break; + default: + GST_DEBUG_OBJECT (params, + "h264parse->sei_pic_struct of unknown value %d. Not parsed", + params->sei_pic_struct); + break; + } + } else { + duration = params->field_pic_flag ? 1 : 2; + } + + GST_LOG_OBJECT (params->el, "frame tick duration %d", duration); + + /* + * h264parse.264 C.1.2 Timing of coded picture removal (equivalent to DTS): + * Tr,n(0) = initial_cpb_removal_delay[ SchedSelIdx ] / 90000 + * Tr,n(n) = Tr,n(nb) + Tc * cpb_removal_delay(n) + * where + * Tc = num_units_in_tick / time_scale + */ + + if (params->ts_trn_nb != GST_CLOCK_TIME_NONE) { + GST_LOG_OBJECT (params->el, "buffering based ts"); + /* buffering period is present */ + if (upstream != GST_CLOCK_TIME_NONE) { + /* If upstream timestamp is valid, we respect it and adjust current + * reference point */ + params->ts_trn_nb = upstream - + (GstClockTime) gst_util_uint64_scale_int + (params->sei_cpb_removal_delay * GST_SECOND, + sps->num_units_in_tick, sps->time_scale); + } else { + /* If no upstream timestamp is given, we write in new timestamp */ + upstream = params->dts = params->ts_trn_nb + + (GstClockTime) gst_util_uint64_scale_int + (params->sei_cpb_removal_delay * GST_SECOND, + sps->num_units_in_tick, sps->time_scale); + } + } else { + GstClockTime dur; + + GST_LOG_OBJECT (params->el, "duration based ts"); + /* naive method: no removal delay specified + * track upstream timestamp and provide best guess frame duration */ + dur = gst_util_uint64_scale_int (duration * GST_SECOND, + sps->num_units_in_tick, sps->time_scale); + /* sanity check */ + if (dur < GST_MSECOND) { + GST_DEBUG_OBJECT (params->el, "discarding dur %" GST_TIME_FORMAT, + GST_TIME_ARGS (dur)); + } else { + *out_dur = dur; + } + } + +exit: + if (GST_CLOCK_TIME_IS_VALID (upstream)) + *out_ts = params->dts = upstream; + + if (GST_CLOCK_TIME_IS_VALID (*out_dur) && + GST_CLOCK_TIME_IS_VALID (params->dts)) + params->dts += *out_dur; +} + +void +gst_h264_params_create (GstH264Params ** _params, GstElement * element) +{ + GstH264Params *params; + + g_return_if_fail (_params != NULL); + + params = g_new0 (GstH264Params, 1); + params->el = element; + + params->dts = GST_CLOCK_TIME_NONE; + params->ts_trn_nb = GST_CLOCK_TIME_NONE; + + *_params = params; +} + +void +gst_h264_params_free (GstH264Params * params) +{ + gint i; + + g_return_if_fail (params != NULL); + + for (i = 0; i < MAX_SPS_COUNT; i++) + gst_buffer_replace (¶ms->sps_nals[i], NULL); + for (i = 0; i < MAX_PPS_COUNT; i++) + gst_buffer_replace (¶ms->sps_nals[i], NULL); + + g_free (params); +} diff --git a/gst/videoparsers/h264parse.h b/gst/videoparsers/h264parse.h new file mode 100644 index 000000000..141564bce --- /dev/null +++ b/gst/videoparsers/h264parse.h @@ -0,0 +1,186 @@ +/* GStreamer H.264 Parser + * Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + * Copyright (C) <2010> Collabora Multimedia + * Copyright (C) <2010> Nokia Corporation + * + * Some bits C-c,C-v'ed and s/4/3 from h264parse: + * (C) 2005 Michal Benes <michal.benes@itonis.tv> + * (C) 2008 Wim Taymans <wim.taymans@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_H264_PARAMS_H__ +#define __GST_H264_PARAMS_H__ + +#include <gst/gst.h> + +G_BEGIN_DECLS + +typedef enum +{ + NAL_UNKNOWN = 0, + NAL_SLICE = 1, + NAL_SLICE_DPA = 2, + NAL_SLICE_DPB = 3, + NAL_SLICE_DPC = 4, + NAL_SLICE_IDR = 5, + NAL_SEI = 6, + NAL_SPS = 7, + NAL_PPS = 8, + NAL_AU_DELIMITER = 9, + NAL_SEQ_END = 10, + NAL_STREAM_END = 11, + NAL_FILTER_DATA = 12 +} GstH264ParamsNalUnitType; + +/* SEI type */ +typedef enum +{ + SEI_BUF_PERIOD = 0, + SEI_PIC_TIMING = 1 + /* and more... */ +} GstH264ParamsSEIPayloadType; + +/* SEI pic_struct type */ +typedef enum +{ + SEI_PIC_STRUCT_FRAME = 0, + SEI_PIC_STRUCT_TOP_FIELD = 1, + SEI_PIC_STRUCT_BOTTOM_FIELD = 2, + SEI_PIC_STRUCT_TOP_BOTTOM = 3, + SEI_PIC_STRUCT_BOTTOM_TOP = 4, + SEI_PIC_STRUCT_TOP_BOTTOM_TOP = 5, + SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM = 6, + SEI_PIC_STRUCT_FRAME_DOUBLING = 7, + SEI_PIC_STRUCT_FRAME_TRIPLING = 8 +} GstH264ParamsSEIPicStructType; + +typedef struct _GstH264Params GstH264Params; +typedef struct _GstH264ParamsSPS GstH264ParamsSPS; +typedef struct _GstH264ParamsPPS GstH264ParamsPPS; + +#define MAX_SPS_COUNT 32 +#define MAX_PPS_COUNT 32 + +/* SPS: sequential parameter sets */ +struct _GstH264ParamsSPS +{ + gboolean valid; + + /* raw values */ + guint8 profile_idc; + guint8 level_idc; + + guint8 sps_id; + + guint8 pic_order_cnt_type; + + guint8 log2_max_frame_num_minus4; + gboolean frame_mbs_only_flag; + guint8 log2_max_pic_order_cnt_lsb_minus4; + + gboolean frame_cropping_flag; + gboolean scp_flag; + + /* VUI parameters */ + gboolean vui_parameters_present_flag; + + gboolean timing_info_present_flag; + guint32 num_units_in_tick; + guint32 time_scale; + gboolean fixed_frame_rate_flag; + + gboolean nal_hrd_parameters_present_flag; + gboolean vcl_hrd_parameters_present_flag; + + /* hrd parameters */ + guint8 cpb_cnt_minus1; + gint initial_cpb_removal_delay_length_minus1; + gint cpb_removal_delay_length_minus1; + gint dpb_output_delay_length_minus1; + gboolean time_offset_length_minus1; + + gboolean pic_struct_present_flag; + + /* ... and probably more ... */ + + /* derived values */ + gint width, height; + gint fps_num, fps_den; +}; + +/* PPS: pic parameter sets */ +struct _GstH264ParamsPPS +{ + gboolean valid; + + /* raw values */ + guint8 pps_id; + guint8 sps_id; +}; + +struct _GstH264Params +{ + /* debug purposes */ + GstElement *el; + + /* SPS: sequential parameter set */ + GstH264ParamsSPS sps_buffers[MAX_SPS_COUNT]; + /* current SPS; most recent one in stream or referenced by PPS */ + GstH264ParamsSPS *sps; + /* PPS: sequential parameter set */ + GstH264ParamsPPS pps_buffers[MAX_PPS_COUNT]; + /* current PPS; most recent one in stream */ + GstH264ParamsPPS *pps; + + /* extracted from slice header or otherwise relevant nal */ + guint8 first_mb_in_slice; + guint8 slice_type; + gboolean field_pic_flag; + gboolean bottom_field_flag; + + /* SEI: supplemental enhancement messages */ +#ifdef EXTRA_PARSE + /* buffering period */ + guint32 initial_cpb_removal_delay[32]; +#endif + /* picture timing */ + guint32 sei_cpb_removal_delay; + guint8 sei_pic_struct; + /* And more... */ + + /* cached timestamps */ + /* (trying to) track upstream dts and interpolate */ + GstClockTime dts; + /* dts at start of last buffering period */ + GstClockTime ts_trn_nb; + + /* collected SPS and PPS NALUs */ + GstBuffer *sps_nals[MAX_SPS_COUNT]; + GstBuffer *pps_nals[MAX_PPS_COUNT]; +}; + +gboolean gst_h264_params_parse_nal (GstH264Params * params, guint8 * nal, gint size); +void gst_h264_params_get_timestamp (GstH264Params * params, + GstClockTime * out_ts, GstClockTime * out_dur, + gboolean frame); +void gst_h264_params_create (GstH264Params ** _params, GstElement * element); +void gst_h264_params_free (GstH264Params * params); + + +G_END_DECLS +#endif diff --git a/gst/videoparsers/plugin.c b/gst/videoparsers/plugin.c new file mode 100644 index 000000000..cfd8a4828 --- /dev/null +++ b/gst/videoparsers/plugin.c @@ -0,0 +1,49 @@ +/* GStreamer video parsers + * Copyright (C) 2011 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + * Copyright (C) 2009 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gsth263parse.h" +#include "gsth264parse.h" +#include "gstdiracparse.h" + +static gboolean +plugin_init (GstPlugin * plugin) +{ + gboolean ret; + + ret = gst_element_register (plugin, "h263parse", + GST_RANK_NONE, GST_TYPE_H263_PARSE); + ret = gst_element_register (plugin, "h264parse", + GST_RANK_NONE, GST_TYPE_H264_PARSE); + ret = gst_element_register (plugin, "diracparse", + GST_RANK_NONE, GST_TYPE_DIRAC_PARSE); + + return ret; +} + + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "videoparsersbad", + "videoparsers", + plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); diff --git a/gst/y4m/Makefile.am b/gst/y4m/Makefile.am new file mode 100644 index 000000000..e8e52421d --- /dev/null +++ b/gst/y4m/Makefile.am @@ -0,0 +1,13 @@ + +plugin_LTLIBRARIES = libgsty4mdec.la + +libgsty4mdec_la_SOURCES = gsty4mdec.c +libgsty4mdec_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) +libgsty4mdec_la_LIBADD = \ + $(GST_BASE_PLUGINS_LIBS) -lgstvideo-@GST_MAJORMINOR@ \ + $(GST_BASE_LIBS) -lgstbase-@GST_MAJORMINOR@ \ + $(GST_LIBS) +libgsty4mdec_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgsty4mdec_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = gsty4mdec.h diff --git a/gst/y4m/gsty4mdec.c b/gst/y4m/gsty4mdec.c new file mode 100644 index 000000000..0e6c3fab6 --- /dev/null +++ b/gst/y4m/gsty4mdec.c @@ -0,0 +1,747 @@ +/* GStreamer + * Copyright (C) 2010 David Schleef <ds@schleef.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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/** + * SECTION:element-gsty4mdec + * + * The gsty4mdec element decodes uncompressed video in YUV4MPEG format. + * + * <refsect2> + * <title>Example launch line</title> + * |[ + * gst-launch -v filesrc location=file.y4m ! y4mdec ! xvimagesink + * ]| + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gst/gst.h> +#include <gst/video/video.h> +#include "gsty4mdec.h" + +#include <stdlib.h> +#include <string.h> + +#define MAX_SIZE 32768 + +GST_DEBUG_CATEGORY (y4mdec_debug); +#define GST_CAT_DEFAULT y4mdec_debug + +/* prototypes */ + + +static void gst_y4m_dec_set_property (GObject * object, + guint property_id, const GValue * value, GParamSpec * pspec); +static void gst_y4m_dec_get_property (GObject * object, + guint property_id, GValue * value, GParamSpec * pspec); +static void gst_y4m_dec_dispose (GObject * object); +static void gst_y4m_dec_finalize (GObject * object); + +static GstFlowReturn gst_y4m_dec_chain (GstPad * pad, GstBuffer * buffer); +static gboolean gst_y4m_dec_sink_event (GstPad * pad, GstEvent * event); + +static gboolean gst_y4m_dec_src_event (GstPad * pad, GstEvent * event); +static gboolean gst_y4m_dec_src_query (GstPad * pad, GstQuery * query); + +static GstStateChangeReturn +gst_y4m_dec_change_state (GstElement * element, GstStateChange transition); + +enum +{ + PROP_0 +}; + +/* pad templates */ + +static GstStaticPadTemplate gst_y4m_dec_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-yuv4mpeg, y4mversion=2") + ); + +static GstStaticPadTemplate gst_y4m_dec_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{I420,Y42B,Y444}")) + ); + +/* class initialization */ + +GST_BOILERPLATE (GstY4mDec, gst_y4m_dec, GstElement, GST_TYPE_ELEMENT); + +static void +gst_y4m_dec_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_y4m_dec_src_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_y4m_dec_sink_template)); + + gst_element_class_set_details_simple (element_class, + "YUV4MPEG demuxer/decoder", "Codec/Demuxer", + "Demuxes/decodes YUV4MPEG streams", "David Schleef <ds@schleef.org>"); +} + +static void +gst_y4m_dec_class_init (GstY4mDecClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gobject_class->set_property = gst_y4m_dec_set_property; + gobject_class->get_property = gst_y4m_dec_get_property; + gobject_class->dispose = gst_y4m_dec_dispose; + gobject_class->finalize = gst_y4m_dec_finalize; + element_class->change_state = GST_DEBUG_FUNCPTR (gst_y4m_dec_change_state); + +} + +static void +gst_y4m_dec_init (GstY4mDec * y4mdec, GstY4mDecClass * y4mdec_class) +{ + y4mdec->adapter = gst_adapter_new (); + + y4mdec->sinkpad = + gst_pad_new_from_static_template (&gst_y4m_dec_sink_template, "sink"); + gst_pad_set_event_function (y4mdec->sinkpad, + GST_DEBUG_FUNCPTR (gst_y4m_dec_sink_event)); + gst_pad_set_chain_function (y4mdec->sinkpad, + GST_DEBUG_FUNCPTR (gst_y4m_dec_chain)); + gst_element_add_pad (GST_ELEMENT (y4mdec), y4mdec->sinkpad); + + y4mdec->srcpad = gst_pad_new_from_static_template (&gst_y4m_dec_src_template, + "src"); + gst_pad_set_event_function (y4mdec->srcpad, + GST_DEBUG_FUNCPTR (gst_y4m_dec_src_event)); + gst_pad_set_query_function (y4mdec->srcpad, + GST_DEBUG_FUNCPTR (gst_y4m_dec_src_query)); + gst_pad_use_fixed_caps (y4mdec->srcpad); + gst_element_add_pad (GST_ELEMENT (y4mdec), y4mdec->srcpad); + +} + +void +gst_y4m_dec_set_property (GObject * object, guint property_id, + const GValue * value, GParamSpec * pspec) +{ + GstY4mDec *y4mdec; + + g_return_if_fail (GST_IS_Y4M_DEC (object)); + y4mdec = GST_Y4M_DEC (object); + + switch (property_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +void +gst_y4m_dec_get_property (GObject * object, guint property_id, + GValue * value, GParamSpec * pspec) +{ + GstY4mDec *y4mdec; + + g_return_if_fail (GST_IS_Y4M_DEC (object)); + y4mdec = GST_Y4M_DEC (object); + + switch (property_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +void +gst_y4m_dec_dispose (GObject * object) +{ + GstY4mDec *y4mdec; + + g_return_if_fail (GST_IS_Y4M_DEC (object)); + y4mdec = GST_Y4M_DEC (object); + + /* clean up as possible. may be called multiple times */ + if (y4mdec->adapter) { + g_object_unref (y4mdec->adapter); + y4mdec->adapter = NULL; + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +void +gst_y4m_dec_finalize (GObject * object) +{ + GstY4mDec *y4mdec; + + g_return_if_fail (GST_IS_Y4M_DEC (object)); + y4mdec = GST_Y4M_DEC (object); + + /* clean up object here */ + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static GstStateChangeReturn +gst_y4m_dec_change_state (GstElement * element, GstStateChange transition) +{ + GstY4mDec *y4mdec; + GstStateChangeReturn ret; + + g_return_val_if_fail (GST_IS_Y4M_DEC (element), GST_STATE_CHANGE_FAILURE); + y4mdec = GST_Y4M_DEC (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + 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: + break; + case GST_STATE_CHANGE_READY_TO_NULL: + break; + default: + break; + } + + return ret; +} + +static GstClockTime +gst_y4m_dec_frames_to_timestamp (GstY4mDec * y4mdec, int frame_index) +{ + return gst_util_uint64_scale (frame_index, GST_SECOND * y4mdec->fps_d, + y4mdec->fps_n); +} + +static int +gst_y4m_dec_timestamp_to_frames (GstY4mDec * y4mdec, GstClockTime timestamp) +{ + return gst_util_uint64_scale (timestamp, y4mdec->fps_n, + GST_SECOND * y4mdec->fps_d); +} + +static int +gst_y4m_dec_bytes_to_frames (GstY4mDec * y4mdec, gint64 bytes) +{ + if (bytes < y4mdec->header_size) + return 0; + return (bytes - y4mdec->header_size) / (y4mdec->frame_size + 6); +} + +static gint64 +gst_y4m_dec_frames_to_bytes (GstY4mDec * y4mdec, int frame_index) +{ + return y4mdec->header_size + (y4mdec->frame_size + 6) * frame_index; +} + +static GstClockTime +gst_y4m_dec_bytes_to_timestamp (GstY4mDec * y4mdec, gint64 bytes) +{ + return gst_y4m_dec_frames_to_timestamp (y4mdec, + gst_y4m_dec_bytes_to_frames (y4mdec, bytes)); +} + + +static gboolean +gst_y4m_dec_parse_header (GstY4mDec * y4mdec, char *header) +{ + char *end; + int format = 420; + int interlaced_char = 0; + + if (memcmp (header, "YUV4MPEG2 ", 10) != 0) { + return FALSE; + } + + header += 10; + while (*header) { + GST_DEBUG_OBJECT (y4mdec, "parsing at '%s'", header); + switch (*header) { + case ' ': + header++; + break; + case 'C': + header++; + format = strtoul (header, &end, 10); + if (end == header) + goto error; + header = end; + break; + case 'W': + header++; + y4mdec->width = strtoul (header, &end, 10); + if (end == header) + goto error; + header = end; + break; + case 'H': + header++; + y4mdec->height = strtoul (header, &end, 10); + if (end == header) + goto error; + header = end; + break; + case 'I': + header++; + if (header[0] == 0) { + GST_WARNING_OBJECT (y4mdec, "Expecting interlaced flag"); + return FALSE; + } + interlaced_char = header[0]; + header++; + break; + case 'F': + header++; + y4mdec->fps_n = strtoul (header, &end, 10); + if (end == header) + goto error; + header = end; + if (header[0] != ':') { + GST_WARNING_OBJECT (y4mdec, "Expecting :"); + return FALSE; + } + header++; + y4mdec->fps_d = strtoul (header, &end, 10); + if (end == header) + goto error; + header = end; + break; + case 'A': + header++; + y4mdec->par_n = strtoul (header, &end, 10); + if (end == header) + goto error; + header = end; + if (header[0] != ':') { + GST_WARNING_OBJECT (y4mdec, "Expecting :"); + return FALSE; + } + header++; + y4mdec->par_d = strtoul (header, &end, 10); + if (end == header) + goto error; + header = end; + break; + default: + GST_WARNING_OBJECT (y4mdec, "Unknown y4m header field '%c', ignoring", + *header); + while (*header && *header != ' ') + header++; + break; + } + } + + switch (format) { + case 420: + y4mdec->format = GST_VIDEO_FORMAT_I420; + break; + case 422: + y4mdec->format = GST_VIDEO_FORMAT_Y42B; + break; + case 444: + y4mdec->format = GST_VIDEO_FORMAT_Y444; + break; + default: + GST_WARNING_OBJECT (y4mdec, "unknown y4m format %d", format); + return FALSE; + } + + if (y4mdec->width <= 0 || y4mdec->width > MAX_SIZE || + y4mdec->height <= 0 || y4mdec->height > MAX_SIZE) { + GST_WARNING_OBJECT (y4mdec, "Dimensions %dx%d out of range", + y4mdec->width, y4mdec->height); + return FALSE; + } + + y4mdec->frame_size = gst_video_format_get_size (y4mdec->format, + y4mdec->width, y4mdec->height); + + switch (interlaced_char) { + case 0: + case '?': + case 'p': + y4mdec->interlaced = FALSE; + break; + case 't': + case 'b': + y4mdec->interlaced = TRUE; + y4mdec->tff = (interlaced_char == 't'); + break; + default: + GST_WARNING_OBJECT (y4mdec, "Unknown interlaced char '%c'", + interlaced_char); + return FALSE; + break; + } + + if (y4mdec->fps_n == 0) + y4mdec->fps_n = 1; + if (y4mdec->fps_d == 0) + y4mdec->fps_d = 1; + if (y4mdec->par_n == 0) + y4mdec->par_n = 1; + if (y4mdec->par_d == 0) + y4mdec->par_d = 1; + + return TRUE; +error: + GST_WARNING_OBJECT (y4mdec, "Expecting number y4m header at '%s'", header); + return FALSE; +} + +static GstFlowReturn +gst_y4m_dec_chain (GstPad * pad, GstBuffer * buffer) +{ + GstY4mDec *y4mdec; + int n_avail; + GstFlowReturn flow_ret = GST_FLOW_OK; +#define MAX_HEADER_LENGTH 80 + char header[MAX_HEADER_LENGTH]; + int i; + int len; + + y4mdec = GST_Y4M_DEC (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT (y4mdec, "chain"); + + if (GST_BUFFER_IS_DISCONT (buffer)) { + GST_DEBUG ("got discont"); + gst_adapter_clear (y4mdec->adapter); + } + + gst_adapter_push (y4mdec->adapter, buffer); + n_avail = gst_adapter_available (y4mdec->adapter); + + if (!y4mdec->have_header) { + gboolean ret; + GstCaps *caps; + + if (n_avail < MAX_HEADER_LENGTH) + return GST_FLOW_OK; + + gst_adapter_copy (y4mdec->adapter, (guint8 *) header, 0, MAX_HEADER_LENGTH); + + header[MAX_HEADER_LENGTH - 1] = 0; + for (i = 0; i < MAX_HEADER_LENGTH; i++) { + if (header[i] == 0x0a) + header[i] = 0; + } + + ret = gst_y4m_dec_parse_header (y4mdec, header); + if (!ret) { + GST_ELEMENT_ERROR (y4mdec, STREAM, DECODE, + ("Failed to parse YUV4MPEG header"), (NULL)); + return GST_FLOW_ERROR; + } + + y4mdec->header_size = strlen (header) + 1; + gst_adapter_flush (y4mdec->adapter, y4mdec->header_size); + + caps = gst_video_format_new_caps_interlaced (y4mdec->format, + y4mdec->width, y4mdec->height, + y4mdec->fps_n, y4mdec->fps_d, + y4mdec->par_n, y4mdec->par_d, y4mdec->interlaced); + ret = gst_pad_set_caps (y4mdec->srcpad, caps); + gst_caps_unref (caps); + if (!ret) { + GST_DEBUG_OBJECT (y4mdec, "Couldn't set caps on src pad"); + return GST_FLOW_ERROR; + } + + y4mdec->have_header = TRUE; + } + + if (y4mdec->have_new_segment) { + GstEvent *event; + GstClockTime start = gst_y4m_dec_bytes_to_timestamp (y4mdec, + y4mdec->segment_start); + GstClockTime stop = gst_y4m_dec_bytes_to_timestamp (y4mdec, + y4mdec->segment_stop); + GstClockTime position = gst_y4m_dec_bytes_to_timestamp (y4mdec, + y4mdec->segment_position); + + event = gst_event_new_new_segment (FALSE, 1.0, + GST_FORMAT_TIME, start, stop, position); + + gst_pad_push_event (y4mdec->srcpad, event); + //gst_event_unref (event); + + y4mdec->have_new_segment = FALSE; + y4mdec->frame_index = gst_y4m_dec_bytes_to_frames (y4mdec, + y4mdec->segment_position); + GST_DEBUG ("new frame_index %d", y4mdec->frame_index); + + } + + while (1) { + n_avail = gst_adapter_available (y4mdec->adapter); + if (n_avail < MAX_HEADER_LENGTH) + break; + + gst_adapter_copy (y4mdec->adapter, (guint8 *) header, 0, MAX_HEADER_LENGTH); + header[MAX_HEADER_LENGTH - 1] = 0; + for (i = 0; i < MAX_HEADER_LENGTH; i++) { + if (header[i] == 0x0a) + header[i] = 0; + } + if (memcmp (header, "FRAME", 5) != 0) { + GST_ELEMENT_ERROR (y4mdec, STREAM, DECODE, + ("Failed to parse YUV4MPEG frame"), (NULL)); + flow_ret = GST_FLOW_ERROR; + break; + } + + len = strlen (header); + if (n_avail < y4mdec->frame_size + len + 1) { + /* not enough data */ + GST_DEBUG ("not enough data for frame %d < %d", + n_avail, y4mdec->frame_size + len + 1); + break; + } + + gst_adapter_flush (y4mdec->adapter, len + 1); + + buffer = gst_adapter_take_buffer (y4mdec->adapter, y4mdec->frame_size); + + GST_BUFFER_CAPS (buffer) = gst_caps_ref (GST_PAD_CAPS (y4mdec->srcpad)); + GST_BUFFER_TIMESTAMP (buffer) = + gst_y4m_dec_frames_to_timestamp (y4mdec, y4mdec->frame_index); + GST_BUFFER_DURATION (buffer) = + gst_y4m_dec_frames_to_timestamp (y4mdec, y4mdec->frame_index) - + GST_BUFFER_TIMESTAMP (buffer); + if (y4mdec->interlaced && y4mdec->tff) { + GST_BUFFER_FLAG_SET (buffer, GST_VIDEO_BUFFER_TFF); + } + + y4mdec->frame_index++; + + flow_ret = gst_pad_push (y4mdec->srcpad, buffer); + if (flow_ret != GST_FLOW_OK) + break; + } + + gst_object_unref (y4mdec); + GST_DEBUG ("returning %d", flow_ret); + return flow_ret; +} + +static gboolean +gst_y4m_dec_sink_event (GstPad * pad, GstEvent * event) +{ + gboolean res; + GstY4mDec *y4mdec; + + y4mdec = GST_Y4M_DEC (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT (y4mdec, "event"); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_START: + res = gst_pad_push_event (y4mdec->srcpad, event); + break; + case GST_EVENT_FLUSH_STOP: + res = gst_pad_push_event (y4mdec->srcpad, event); + break; + case GST_EVENT_NEWSEGMENT: + { + gboolean update; + gdouble rate; + gdouble applied_rate; + GstFormat format; + gint64 start; + gint64 stop; + gint64 position; + + gst_event_parse_new_segment_full (event, &update, &rate, + &applied_rate, &format, &start, &stop, &position); + + GST_DEBUG ("new_segment: update: %d rate: %g applied_rate: %g " + "format: %d start: %" G_GUINT64_FORMAT " stop: %" G_GUINT64_FORMAT + " position %" G_GUINT64_FORMAT, + update, rate, applied_rate, format, start, stop, position); + + if (format == GST_FORMAT_BYTES) { + y4mdec->segment_start = start; + y4mdec->segment_stop = stop; + y4mdec->segment_position = position; + y4mdec->have_new_segment = TRUE; + } + + res = TRUE; + //res = gst_pad_push_event (y4mdec->srcpad, event); + } + break; + case GST_EVENT_EOS: + res = gst_pad_push_event (y4mdec->srcpad, event); + break; + default: + res = gst_pad_push_event (y4mdec->srcpad, event); + break; + } + + gst_object_unref (y4mdec); + return res; +} + +static gboolean +gst_y4m_dec_src_event (GstPad * pad, GstEvent * event) +{ + gboolean res; + GstY4mDec *y4mdec; + + y4mdec = GST_Y4M_DEC (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT (y4mdec, "event"); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_SEEK: + { + gdouble rate; + GstFormat format; + GstSeekFlags flags; + GstSeekType start_type, stop_type; + gint64 start, stop; + int framenum; + guint64 byte; + + gst_event_parse_seek (event, &rate, &format, &flags, &start_type, + &start, &stop_type, &stop); + + if (format != GST_FORMAT_TIME) { + res = FALSE; + break; + } + + framenum = gst_y4m_dec_timestamp_to_frames (y4mdec, start); + GST_DEBUG ("seeking to frame %d", framenum); + + byte = gst_y4m_dec_frames_to_bytes (y4mdec, framenum); + GST_DEBUG ("offset %d", (int) byte); + + gst_event_unref (event); + event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, + start_type, byte, stop_type, -1); + + res = gst_pad_push_event (y4mdec->sinkpad, event); + } + break; + default: + res = gst_pad_push_event (y4mdec->sinkpad, event); + break; + } + + gst_object_unref (y4mdec); + return res; +} + +static gboolean +gst_y4m_dec_src_query (GstPad * pad, GstQuery * query) +{ + GstY4mDec *y4mdec = GST_Y4M_DEC (gst_pad_get_parent (pad)); + gboolean res = FALSE; + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_DURATION: + { + GstFormat format; + GstPad *peer; + + GST_DEBUG ("duration query"); + + gst_query_parse_duration (query, &format, NULL); + + if (format != GST_FORMAT_TIME) { + res = FALSE; + GST_DEBUG_OBJECT (y4mdec, "not handling duration query in format %d", + format); + break; + } + + peer = gst_pad_get_peer (y4mdec->sinkpad); + if (peer) { + GstQuery *peer_query = gst_query_new_duration (GST_FORMAT_BYTES); + + res = gst_pad_query (peer, peer_query); + if (res) { + gint64 duration; + int n_frames; + + gst_query_parse_duration (peer_query, &format, &duration); + + n_frames = gst_y4m_dec_bytes_to_frames (y4mdec, duration); + GST_DEBUG ("duration in frames %d", n_frames); + + duration = gst_y4m_dec_frames_to_timestamp (y4mdec, n_frames); + GST_DEBUG ("duration in time %" GST_TIME_FORMAT, + GST_TIME_ARGS (duration)); + + gst_query_set_duration (query, GST_FORMAT_TIME, duration); + res = TRUE; + } + + gst_query_unref (peer_query); + gst_object_unref (peer); + } + break; + } + default: + res = gst_pad_query_default (pad, query); + break; + } + + gst_object_unref (y4mdec); + return res; +} + + +static gboolean +plugin_init (GstPlugin * plugin) +{ + + gst_element_register (plugin, "y4mdec", GST_RANK_SECONDARY, + gst_y4m_dec_get_type ()); + + GST_DEBUG_CATEGORY_INIT (y4mdec_debug, "y4mdec", 0, "y4mdec element"); + + return TRUE; +} + + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "y4mdec", + "FIXME", plugin_init, VERSION, "LGPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/gst/y4m/gsty4mdec.h b/gst/y4m/gsty4mdec.h new file mode 100644 index 000000000..6ea6ca118 --- /dev/null +++ b/gst/y4m/gsty4mdec.h @@ -0,0 +1,76 @@ +/* GStreamer + * Copyright (C) 2010 David Schleef <ds@schleef.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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _GST_Y4M_DEC_H_ +#define _GST_Y4M_DEC_H_ + +#include <gst/gst.h> +#include <gst/base/gstadapter.h> + +G_BEGIN_DECLS + +#define GST_TYPE_Y4M_DEC (gst_y4m_dec_get_type()) +#define GST_Y4M_DEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_Y4M_DEC,GstY4mDec)) +#define GST_Y4M_DEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_Y4M_DEC,GstY4mDecClass)) +#define GST_IS_Y4M_DEC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_Y4M_DEC)) +#define GST_IS_Y4M_DEC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_Y4M_DEC)) + +typedef struct _GstY4mDec GstY4mDec; +typedef struct _GstY4mDecClass GstY4mDecClass; + +struct _GstY4mDec +{ + GstElement base_y4mdec; + + GstPad *sinkpad; + GstPad *srcpad; + GstAdapter *adapter; + + /* state */ + gboolean have_header; + int frame_index; + int header_size; + + gboolean have_new_segment; + gint64 segment_start; + gint64 segment_stop; + gint64 segment_position; + + int width; + int height; + GstVideoFormat format; + gboolean interlaced; + gboolean tff; + int fps_n; + int fps_d; + int par_n; + int par_d; + int frame_size; +}; + +struct _GstY4mDecClass +{ + GstElementClass base_y4mdec_class; +}; + +GType gst_y4m_dec_get_type (void); + +G_END_DECLS + +#endif diff --git a/m4/Makefile.am b/m4/Makefile.am index e03a94a61..8357591cf 100644 --- a/m4/Makefile.am +++ b/m4/Makefile.am @@ -7,19 +7,14 @@ EXTRA_DIST = \ as-slurp-ffmpeg.m4 \ check-libheader.m4 \ codeset.m4 \ - esd.m4 \ freetype2.m4 \ gconf-2.m4 \ gettext.m4 \ glibc21.m4 \ - glib.m4 \ gst-artsc.m4 \ gst-fionread.m4 \ - gst-matroska.m4 \ gst-sdl.m4 \ - gst-shout2.m4 \ gst-sid.m4 \ - gtk.m4 \ iconv.m4 \ intdiv0.m4 \ inttypes_h.m4 \ @@ -32,8 +27,6 @@ EXTRA_DIST = \ lib-prefix.m4 \ lrintf.m4 \ lrint.m4 \ - ogg.m4 \ progtest.m4 \ stdint_h.m4 \ - uintmax_t.m4 \ - vorbis.m4 + uintmax_t.m4 diff --git a/m4/esd.m4 b/m4/esd.m4 deleted file mode 100644 index 1812fd027..000000000 --- a/m4/esd.m4 +++ /dev/null @@ -1,202 +0,0 @@ -# Configure paths for ESD -# Manish Singh 98-9-30 -# stolen back from Frank Belew -# stolen from Manish Singh -# Shamelessly stolen from Owen Taylor - -dnl AM_PATH_ESD([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) -dnl Test for ESD, and define ESD_CFLAGS and ESD_LIBS -dnl -AC_DEFUN([AM_PATH_ESD], -[dnl -dnl Get the cflags and libraries from the esd-config script -dnl -AC_ARG_WITH(esd-prefix, - AC_HELP_STRING([--with-esd-prefix=PFX], - [prefix where ESD is installed (optional)]), - esd_prefix="$withval", esd_prefix="") - -AC_ARG_WITH(esd-exec-prefix, - AC_HELP_STRING([--with-esd-exec-prefix=PFX], - [exec prefix where ESD is installed (optional)]), - esd_exec_prefix="$withval", esd_exec_prefix="") - -AC_ARG_ENABLE(esdtest, - AC_HELP_STRING([--disable-esdtest], - [do not try to compile and run a test ESD program]), - , enable_esdtest=yes) - - if test x$esd_exec_prefix != x ; then - esd_args="$esd_args --exec-prefix=$esd_exec_prefix" - if test x${ESD_CONFIG+set} != xset ; then - ESD_CONFIG=$esd_exec_prefix/bin/esd-config - fi - fi - if test x$esd_prefix != x ; then - esd_args="$esd_args --prefix=$esd_prefix" - if test x${ESD_CONFIG+set} != xset ; then - ESD_CONFIG=$esd_prefix/bin/esd-config - fi - fi - - AC_PATH_PROG(ESD_CONFIG, esd-config, no) - min_esd_version=ifelse([$1], ,0.2.7,$1) - AC_MSG_CHECKING(for ESD - version >= $min_esd_version) - no_esd="" - if test "$ESD_CONFIG" = "no" ; then - no_esd=yes - else - AC_LANG_SAVE - AC_LANG_C - ESD_CFLAGS=`$ESD_CONFIG $esdconf_args --cflags` - ESD_LIBS=`$ESD_CONFIG $esdconf_args --libs` - - esd_major_version=`$ESD_CONFIG $esd_args --version | \ - sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` - esd_minor_version=`$ESD_CONFIG $esd_args --version | \ - sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` - esd_micro_version=`$ESD_CONFIG $esd_config_args --version | \ - sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` - if test "x$enable_esdtest" = "xyes" ; then - ac_save_CFLAGS="$CFLAGS" - ac_save_LIBS="$LIBS" - CFLAGS="$CFLAGS $ESD_CFLAGS" - LIBS="$LIBS $ESD_LIBS" -dnl -dnl Now check if the installed ESD is sufficiently new. (Also sanity -dnl checks the results of esd-config to some extent -dnl - rm -f conf.esdtest - AC_TRY_RUN([ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <esd.h> - -char* -my_strdup (char *str) -{ - char *new_str; - - if (str) - { - new_str = malloc ((strlen (str) + 1) * sizeof(char)); - strcpy (new_str, str); - } - else - new_str = NULL; - - return new_str; -} - -int main () -{ - int major, minor, micro; - char *tmp_version; - - system ("touch conf.esdtest"); - - /* HP/UX 9 (%@#!) writes to sscanf strings */ - tmp_version = my_strdup("$min_esd_version"); - if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { - printf("%s, bad version string\n", "$min_esd_version"); - exit(1); - } - - if (($esd_major_version > major) || - (($esd_major_version == major) && ($esd_minor_version > minor)) || - (($esd_major_version == major) && ($esd_minor_version == minor) && ($esd_micro_version >= micro))) - { - return 0; - } - else - { - printf("\n*** 'esd-config --version' returned %d.%d.%d, but the minimum version\n", $esd_major_version, $esd_minor_version, $esd_micro_version); - printf("*** of ESD required is %d.%d.%d. If esd-config is correct, then it is\n", major, minor, micro); - printf("*** best to upgrade to the required version.\n"); - printf("*** If esd-config was wrong, set the environment variable ESD_CONFIG\n"); - printf("*** to point to the correct copy of esd-config, and remove the file\n"); - printf("*** config.cache before re-running configure\n"); - return 1; - } -} - -],, no_esd=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) - CFLAGS="$ac_save_CFLAGS" - LIBS="$ac_save_LIBS" - AC_LANG_RESTORE - fi - fi - if test "x$no_esd" = x ; then - AC_MSG_RESULT(yes) - ifelse([$2], , :, [$2]) - else - AC_MSG_RESULT(no) - if test "$ESD_CONFIG" = "no" ; then - echo "*** The esd-config script installed by ESD could not be found" - echo "*** If ESD was installed in PREFIX, make sure PREFIX/bin is in" - echo "*** your path, or set the ESD_CONFIG environment variable to the" - echo "*** full path to esd-config." - else - if test -f conf.esdtest ; then - : - else - echo "*** Could not run ESD test program, checking why..." - CFLAGS="$CFLAGS $ESD_CFLAGS" - LIBS="$LIBS $ESD_LIBS" - AC_LANG_SAVE - AC_LANG_C - AC_TRY_LINK([ -#include <stdio.h> -#include <esd.h> -], [ return 0; ], - [ echo "*** The test program compiled, but did not run. This usually means" - echo "*** that the run-time linker is not finding ESD or finding the wrong" - echo "*** version of ESD. If it is not finding ESD, you'll need to set your" - echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" - echo "*** to the installed location Also, make sure you have run ldconfig if that" - echo "*** is required on your system" - echo "***" - echo "*** If you have an old version installed, it is best to remove it, although" - echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"], - [ echo "*** The test program failed to compile or link. See the file config.log for the" - echo "*** exact error that occured. This usually means ESD was incorrectly installed" - echo "*** or that you have moved ESD since it was installed. In the latter case, you" - echo "*** may want to edit the esd-config script: $ESD_CONFIG" ]) - CFLAGS="$ac_save_CFLAGS" - LIBS="$ac_save_LIBS" - AC_LANG_RESTORE - fi - fi - ESD_CFLAGS="" - ESD_LIBS="" - ifelse([$3], , :, [$3]) - fi - AC_SUBST(ESD_CFLAGS) - AC_SUBST(ESD_LIBS) - rm -f conf.esdtest -]) - -dnl AM_ESD_SUPPORTS_MULTIPLE_RECORD([ACTION-IF-SUPPORTS [, ACTION-IF-NOT-SUPPORTS]]) -dnl Test, whether esd supports multiple recording clients (version >=0.2.21) -dnl -AC_DEFUN([AM_ESD_SUPPORTS_MULTIPLE_RECORD], -[dnl - AC_MSG_NOTICE([whether installed esd version supports multiple recording clients]) - ac_save_ESD_CFLAGS="$ESD_CFLAGS" - ac_save_ESD_LIBS="$ESD_LIBS" - AM_PATH_ESD(0.2.21, - ifelse([$1], , [ - AM_CONDITIONAL(ESD_SUPPORTS_MULTIPLE_RECORD, true) - AC_DEFINE(ESD_SUPPORTS_MULTIPLE_RECORD, 1, - [Define if you have esound with support of multiple recording clients.])], - [$1]), - ifelse([$2], , [AM_CONDITIONAL(ESD_SUPPORTS_MULTIPLE_RECORD, false)], [$2]) - if test "x$ac_save_ESD_CFLAGS" != x ; then - ESD_CFLAGS="$ac_save_ESD_CFLAGS" - fi - if test "x$ac_save_ESD_LIBS" != x ; then - ESD_LIBS="$ac_save_ESD_LIBS" - fi - ) -]) diff --git a/m4/glib.m4 b/m4/glib.m4 deleted file mode 100644 index b3c632b0e..000000000 --- a/m4/glib.m4 +++ /dev/null @@ -1,196 +0,0 @@ -# Configure paths for GLIB -# Owen Taylor 97-11-3 - -dnl AM_PATH_GLIB([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]]) -dnl Test for GLIB, and define GLIB_CFLAGS and GLIB_LIBS, if "gmodule" or -dnl gthread is specified in MODULES, pass to glib-config -dnl -AC_DEFUN([AM_PATH_GLIB], -[dnl -dnl Get the cflags and libraries from the glib-config script -dnl -AC_ARG_WITH(glib-prefix,[ --with-glib-prefix=PFX Prefix where GLIB is installed (optional)], - glib_config_prefix="$withval", glib_config_prefix="") -AC_ARG_WITH(glib-exec-prefix,[ --with-glib-exec-prefix=PFX Exec prefix where GLIB is installed (optional)], - glib_config_exec_prefix="$withval", glib_config_exec_prefix="") -AC_ARG_ENABLE(glibtest, [ --disable-glibtest Do not try to compile and run a test GLIB program], - , enable_glibtest=yes) - - if test x$glib_config_exec_prefix != x ; then - glib_config_args="$glib_config_args --exec-prefix=$glib_config_exec_prefix" - if test x${GLIB_CONFIG+set} != xset ; then - GLIB_CONFIG=$glib_config_exec_prefix/bin/glib-config - fi - fi - if test x$glib_config_prefix != x ; then - glib_config_args="$glib_config_args --prefix=$glib_config_prefix" - if test x${GLIB_CONFIG+set} != xset ; then - GLIB_CONFIG=$glib_config_prefix/bin/glib-config - fi - fi - - for module in . $4 - do - case "$module" in - gmodule) - glib_config_args="$glib_config_args gmodule" - ;; - gthread) - glib_config_args="$glib_config_args gthread" - ;; - esac - done - - AC_PATH_PROG(GLIB_CONFIG, glib-config, no) - min_glib_version=ifelse([$1], ,0.99.7,$1) - AC_MSG_CHECKING(for GLIB - version >= $min_glib_version) - no_glib="" - if test "$GLIB_CONFIG" = "no" ; then - no_glib=yes - else - GLIB_CFLAGS=`$GLIB_CONFIG $glib_config_args --cflags` - GLIB_LIBS=`$GLIB_CONFIG $glib_config_args --libs` - glib_config_major_version=`$GLIB_CONFIG $glib_config_args --version | \ - sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` - glib_config_minor_version=`$GLIB_CONFIG $glib_config_args --version | \ - sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` - glib_config_micro_version=`$GLIB_CONFIG $glib_config_args --version | \ - sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` - if test "x$enable_glibtest" = "xyes" ; then - ac_save_CFLAGS="$CFLAGS" - ac_save_LIBS="$LIBS" - CFLAGS="$CFLAGS $GLIB_CFLAGS" - LIBS="$GLIB_LIBS $LIBS" -dnl -dnl Now check if the installed GLIB is sufficiently new. (Also sanity -dnl checks the results of glib-config to some extent -dnl - rm -f conf.glibtest - AC_TRY_RUN([ -#include <glib.h> -#include <stdio.h> -#include <stdlib.h> - -int -main () -{ - int major, minor, micro; - char *tmp_version; - - system ("touch conf.glibtest"); - - /* HP/UX 9 (%@#!) writes to sscanf strings */ - tmp_version = g_strdup("$min_glib_version"); - if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { - printf("%s, bad version string\n", "$min_glib_version"); - exit(1); - } - - if ((glib_major_version != $glib_config_major_version) || - (glib_minor_version != $glib_config_minor_version) || - (glib_micro_version != $glib_config_micro_version)) - { - printf("\n*** 'glib-config --version' returned %d.%d.%d, but GLIB (%d.%d.%d)\n", - $glib_config_major_version, $glib_config_minor_version, $glib_config_micro_version, - glib_major_version, glib_minor_version, glib_micro_version); - printf ("*** was found! If glib-config was correct, then it is best\n"); - printf ("*** to remove the old version of GLIB. You may also be able to fix the error\n"); - printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); - printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); - printf("*** required on your system.\n"); - printf("*** If glib-config was wrong, set the environment variable GLIB_CONFIG\n"); - printf("*** to point to the correct copy of glib-config, and remove the file config.cache\n"); - printf("*** before re-running configure\n"); - } - else if ((glib_major_version != GLIB_MAJOR_VERSION) || - (glib_minor_version != GLIB_MINOR_VERSION) || - (glib_micro_version != GLIB_MICRO_VERSION)) - { - printf("*** GLIB header files (version %d.%d.%d) do not match\n", - GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION); - printf("*** library (version %d.%d.%d)\n", - glib_major_version, glib_minor_version, glib_micro_version); - } - else - { - if ((glib_major_version > major) || - ((glib_major_version == major) && (glib_minor_version > minor)) || - ((glib_major_version == major) && (glib_minor_version == minor) && (glib_micro_version >= micro))) - { - return 0; - } - else - { - printf("\n*** An old version of GLIB (%d.%d.%d) was found.\n", - glib_major_version, glib_minor_version, glib_micro_version); - printf("*** You need a version of GLIB newer than %d.%d.%d. The latest version of\n", - major, minor, micro); - printf("*** GLIB is always available from ftp://ftp.gtk.org.\n"); - printf("***\n"); - printf("*** If you have already installed a sufficiently new version, this error\n"); - printf("*** probably means that the wrong copy of the glib-config shell script is\n"); - printf("*** being found. The easiest way to fix this is to remove the old version\n"); - printf("*** of GLIB, but you can also set the GLIB_CONFIG environment to point to the\n"); - printf("*** correct copy of glib-config. (In this case, you will have to\n"); - printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); - printf("*** so that the correct libraries are found at run-time))\n"); - } - } - return 1; -} -],, no_glib=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) - CFLAGS="$ac_save_CFLAGS" - LIBS="$ac_save_LIBS" - fi - fi - if test "x$no_glib" = x ; then - AC_MSG_RESULT(yes) - ifelse([$2], , :, [$2]) - else - AC_MSG_RESULT(no) - if test "$GLIB_CONFIG" = "no" ; then - echo "*** The glib-config script installed by GLIB could not be found" - echo "*** If GLIB was installed in PREFIX, make sure PREFIX/bin is in" - echo "*** your path, or set the GLIB_CONFIG environment variable to the" - echo "*** full path to glib-config." - else - if test -f conf.glibtest ; then - : - else - echo "*** Could not run GLIB test program, checking why..." - CFLAGS="$CFLAGS $GLIB_CFLAGS" - LIBS="$LIBS $GLIB_LIBS" - AC_TRY_LINK([ -#include <glib.h> -#include <stdio.h> -], [ return ((glib_major_version) || (glib_minor_version) || (glib_micro_version)); ], - [ echo "*** The test program compiled, but did not run. This usually means" - echo "*** that the run-time linker is not finding GLIB or finding the wrong" - echo "*** version of GLIB. If it is not finding GLIB, you'll need to set your" - echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" - echo "*** to the installed location Also, make sure you have run ldconfig if that" - echo "*** is required on your system" - echo "***" - echo "*** If you have an old version installed, it is best to remove it, although" - echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" - echo "***" - echo "*** If you have a RedHat 5.0 system, you should remove the GTK package that" - echo "*** came with the system with the command" - echo "***" - echo "*** rpm --erase --nodeps gtk gtk-devel" ], - [ echo "*** The test program failed to compile or link. See the file config.log for the" - echo "*** exact error that occured. This usually means GLIB was incorrectly installed" - echo "*** or that you have moved GLIB since it was installed. In the latter case, you" - echo "*** may want to edit the glib-config script: $GLIB_CONFIG" ]) - CFLAGS="$ac_save_CFLAGS" - LIBS="$ac_save_LIBS" - fi - fi - GLIB_CFLAGS="" - GLIB_LIBS="" - ifelse([$3], , :, [$3]) - fi - AC_SUBST(GLIB_CFLAGS) - AC_SUBST(GLIB_LIBS) - rm -f conf.glibtest -]) diff --git a/m4/gst-matroska.m4 b/m4/gst-matroska.m4 deleted file mode 100644 index b50caaa27..000000000 --- a/m4/gst-matroska.m4 +++ /dev/null @@ -1,262 +0,0 @@ -# Configure paths for libebml - -dnl PATH_EBML([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) -dnl Test for libebml, and define EBML_CFLAGS and EBML_LIBS -dnl -AC_DEFUN([PATH_EBML], -[dnl -dnl Get the cflags and libraries -dnl -AC_ARG_WITH(ebml-prefix,[ --with-ebml-prefix=PFX Prefix where libebml is installed (optional)], ebml_prefix="$withval", ebml_prefix="") -AC_ARG_WITH(ebml-include,[ --with-ebml-include=DIR Path to where the libebml include files installed (optional)], ebml_include="$withval", ebml_include="") -AC_ARG_WITH(ebml-lib,[ --with-ebml-lib=DIR Path to where the libebml library installed (optional)], ebml_lib="$withval", ebml_lib="") -AC_ARG_ENABLE(ebmltest, [ --disable-ebmltest Do not try to compile and run a test EBML program],, enable_ebmltest=yes) - - if test "x$ebml_prefix" != "x"; then - ebml_args="$ebml_args --prefix=$ebml_prefix" - if test "x$ebml_include" != "x"; then - EBML_CFLAGS="-I$ebml_include" - else - EBML_CFLAGS="-I$ebml_prefix/include/ebml" - fi - if test "x$ebml_lib" != "x"; then - EBML_LIBS="-L$ebml_lib" - else - EBML_LIBS="-L$ebml_prefix/lib" - fi - elif test "x$prefix" != "xNONE"; then - ebml_args="$ebml_args --prefix=$prefix" - if test "x$ebml_include" != "x"; then - EBML_CFLAGS="-I$ebml_include" - else - EBML_CFLAGS="-I$prefix/include/ebml" - fi - if test "x$ebml_lib" != "x"; then - EBML_LIBS="-L$ebml_lib" - else - EBML_LIBS="-L$prefix/lib" - fi - else - if test "x$ebml_include" != "x"; then - EBML_CFLAGS="-I$ebml_include" - else - EBML_CFLAGS="-I/usr/include/ebml -I/usr/local/include/ebml" - fi - if test "x$ebml_lib" != "x"; then - EBML_LIBS="-L$ebml_lib" - else - EBML_LIBS="-L/usr/local/lib" - fi - fi - - EBML_LIBS="$EBML_LIBS -lebml" - - AC_MSG_CHECKING(for EBML) - no_ebml="" - - - if test "x$enable_ebmltest" = "xyes" ; then - ac_save_CFLAGS="$CFLAGS" - ac_save_LIBS="$LIBS" - CFLAGS="$CFLAGS $EBML_CFLAGS" - LIBS="$LIBS $EBML_LIBS" -dnl -dnl Now check if the installed EBML is sufficiently new. -dnl - rm -f conf.ebmltest - AC_TRY_RUN([ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <EbmlConfig.h> - -int main () -{ - system("touch conf.ebmltest"); - return 0; -} - -],, no_ebml=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) - CFLAGS="$ac_save_CFLAGS" - LIBS="$ac_save_LIBS" - fi - - if test "x$no_ebml" = "x" ; then - AC_MSG_RESULT(yes) - ifelse([$1], , :, [$1]) - else - AC_MSG_RESULT(no) - if test -f conf.ebmltest ; then - : - else - echo "*** Could not run Ebml test program, checking why..." - CFLAGS="$CFLAGS $EBML_CFLAGS" - LIBS="$LIBS $EBML_LIBS" - AC_TRY_LINK([ -#include <stdio.h> -#include <EbmlConfig.h> -], [ return 0; ], - [ echo "*** The test program compiled, but did not run. This usually means" - echo "*** that the run-time linker is not finding EBML or finding the wrong" - echo "*** version of EBML. If it is not finding EBML, you'll need to set your" - echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" - echo "*** to the installed location Also, make sure you have run ldconfig if that" - echo "*** is required on your system" - echo "***" - echo "*** If you have an old version installed, it is best to remove it, although" - echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"], - [ echo "*** The test program failed to compile or link. See the file config.log for the" - echo "*** exact error that occured. This usually means EBML was incorrectly installed" - echo "*** or that you have moved EBML since it was installed." ]) - CFLAGS="$ac_save_CFLAGS" - LIBS="$ac_save_LIBS" - fi - EBML_CFLAGS="" - EBML_LIBS="" - ifelse([$2], , :, [$2]) - fi - AC_SUBST(EBML_CFLAGS) - AC_SUBST(EBML_LIBS) - rm -f conf.ebmltest -]) - -# Configure paths for libmatroska - -dnl PATH_MATROSKA(MIN_VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) -dnl Test for libmatroska, and define MATROSKA_CFLAGS and MATROSKA_LIBS -dnl -AC_DEFUN([PATH_MATROSKA], -[dnl -dnl Get the cflags and libraries -dnl -AC_ARG_WITH(matroska-prefix,[ --with-matroska-prefix=PFX Prefix where libmatroska is installed (optional)], matroska_prefix="$withval", matroska_prefix="") -AC_ARG_WITH(matroska-include,[ --with-matroska-include=DIR Path to where the libmatroska include files installed (optional)], matroska_include="$withval", matroska_include="") -AC_ARG_WITH(matroska-lib,[ --with-matroska-lib=DIR Path to where the libmatroska library installed (optional)], matroska_lib="$withval", matroska_lib="") -AC_ARG_ENABLE(matroskatest, [ --disable-matroskatest Do not try to compile and run a test Matroska program],, enable_matroskatest=yes) - - if test "x$matroska_prefix" != "x"; then - matroska_args="$matroska_args --prefix=$matroska_prefix" - if test "x$matroska_include" != "x"; then - MATROSKA_CFLAGS="-I$matroska_include" - else - MATROSKA_CFLAGS="-I$matroska_prefix/include/matroska" - fi - if test "x$matroska_lib" != "x"; then - MATROSKA_LIBS="-L$matroska_lib" - else - MATROSKA_LIBS="-L$matroska_prefix/lib" - fi - elif test "x$prefix" != "xNONE"; then - matroska_args="$matroska_args --prefix=$prefix" - if test "x$matroska_include" != "x"; then - MATROSKA_CFLAGS="-I$matroska_include" - else - MATROSKA_CFLAGS="-I$prefix/include/matroska" - fi - if test "x$matroska_lib" != "x"; then - MATROSKA_LIBS="-L$matroska_lib" - else - MATROSKA_LIBS="-L$prefix/lib" - fi - else - if test "x$matroska_include" != "x"; then - MATROSKA_CFLAGS="-I$matroska_include" - else - MATROSKA_CFLAGS="-I/usr/include/matroska -I/usr/local/include/matroska" - fi - if test "x$matroska_lib" != "x"; then - MATROSKA_LIBS="-L$matroska_lib" - else - MATROSKA_LIBS="-L/usr/local/lib" - fi - fi - - MATROSKA_LIBS="$MATROSKA_LIBS -lmatroska" - - AC_MSG_CHECKING(for Matroska) - no_matroska="" - - - if test "x$enable_matroskatest" = "xyes" ; then - ac_save_CXXFLAGS="$CXXFLAGS" - ac_save_LIBS="$LIBS" - CXXFLAGS="$CXXFLAGS $MATROSKA_CFLAGS $EBML_CFLAGS" - LIBS="$LIBS $MATROSKA_LIBS $EBML_LIBS" -dnl -dnl Now check if the installed Matroska is sufficiently new. -dnl - rm -f conf.matroskatest - AC_LANG_CPLUSPLUS - AC_TRY_RUN([ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <EbmlConfig.h> -#include <KaxVersion.h> - -using namespace LIBMATROSKA_NAMESPACE; - -int main () -{ - FILE *f; - f = fopen("conf.matroskatest", "wb"); - if (f == NULL) - return 1; - fprintf(f, "%s\n", KaxCodeVersion.c_str()); - fclose(f); - return 0; -} - -],, no_matroska=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) - AC_LANG_C - CXXFLAGS="$ac_save_CXXFLAGS" - LIBS="$ac_save_LIBS" - fi - - if test "x$no_matroska" = "x" -a -f conf.matroskatest ; then - AC_MSG_RESULT(yes) - - AC_MSG_CHECKING(Matroska version) - - matroska_version=`cat conf.matroskatest` - mk_MAJVER=`echo $1 | cut -d"." -f1` - mk_MINVER=`echo $1 | cut -d"." -f2` - mk_RELVER=`echo $1 | cut -d"." -f3` - mver_ok=`sed 's;\.;\ ;g' < conf.matroskatest | (read -a mver - if test ${mver[[0]]} -gt $mk_MAJVER ; then - mver_ok=1 - elif test ${mver[[0]]} -lt $mk_MAJVER ; then - mver_ok=0 - else - if test ${mver[[1]]} -gt $mk_MINVER ; then - mver_ok=1 - elif test ${mver[[1]]} -lt $mk_MINVER ; then - mver_ok=0 - else - if test ${mver[[2]]} -ge $mk_RELVER ; then - mver_ok=1 - else - mver_ok=0 - fi - fi - fi - echo $mver_ok )` - if test "$mver_ok" = "1" ; then - AC_MSG_RESULT($matroska_version ok) - ifelse([$2], , :, [$2]) - else - AC_MSG_RESULT($matroska_version too old) - echo '*** Your Matroska version is too old. Upgrade to at least version' - echo '*** $1 and re-run configure.' - ifelse([$3], , :, [$3]) - fi - - else - AC_MSG_RESULT(no) - ifelse([$3], , :, [$3]) - fi - - AC_SUBST(MATROSKA_CFLAGS) - AC_SUBST(MATROSKA_LIBS) - rm -f conf.matroskatest -]) diff --git a/m4/gst-shout2.m4 b/m4/gst-shout2.m4 deleted file mode 100644 index e85a76711..000000000 --- a/m4/gst-shout2.m4 +++ /dev/null @@ -1,102 +0,0 @@ -# Configure paths for libshout -# Jack Moffitt <jack@icecast.org> 08-06-2001 -# Shamelessly stolen from Owen Taylor and Manish Singh - -dnl AM_PATH_SHOUT2([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) -dnl Test for libshout 2, and define SHOUT2_CFLAGS and SHOUT2_LIBS -dnl -AC_DEFUN([AM_PATH_SHOUT2], -[dnl -dnl Get the cflags and libraries -dnl -AC_ARG_WITH(shout2-prefix,[ --with-shout2-prefix=PFX Prefix where libshout2 is installed (optional)], shout2_prefix="$withval", shout2_prefix="") -AC_ARG_ENABLE(shout2test, [ --disable-shout2test Do not try to compile and run a test shout2 program],, enable_shout2test=yes) - - if test "x$shout2_prefix" != "xNONE" ; then - SHOUT2_CFLAGS="-I$shout2_prefix/include" - SHOUT2_LIBS="-L$shout2_prefix/lib" - elif test "x$prefix" != "x"; then - SHOUT2_CFLAGS="-I$prefix/include" - SHOUT2_LIBS="-L$prefix/lib" - fi - - SHOUT2_LIBS="$SHOUT2_LIBS -lshout -lpthread" - - case $host in - *-*-solaris*) - SHOUT2_LIBS="$SHOUT2_LIBS -lnsl -lsocket -lresolv" - esac - - AC_MSG_CHECKING(for shout2) - no_shout2="" - - if test "x$enable_shout2test" = "xyes" ; then - ac_save_CFLAGS="$CFLAGS" - ac_save_LIBS="$LIBS" - CFLAGS="$CFLAGS $SHOUT2_CFLAGS $OGG_CFLAGS $VORBIS_CFLAGS" - LIBS="$LIBS $SHOUT2_LIBS $OGG_LIBS $VORBIS_LIBS" -dnl -dnl Now check if the installed shout2 is sufficiently new. -dnl - rm -f conf.shout2test - AC_TRY_RUN([ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <shout/shout.h> - -int main () -{ - int major, minor, patch; - - system("touch conf.shout2test"); - shout_version(&major, &minor, &patch); - if (major < 2) - return 1; - return 0; -} - -],, no_shout2=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) - CFLAGS="$ac_save_CFLAGS" - LIBS="$ac_save_LIBS" - fi - - if test "x$no_shout2" = "x" ; then - AC_MSG_RESULT(yes) - ifelse([$1], , :, [$1]) - else - AC_MSG_RESULT(no) - if test -f conf.shout2test ; then - : - else - echo "*** Could not run Shout2 test program, checking why..." - CFLAGS="$CFLAGS $SHOUT2_CFLAGS $OGG_CFLAGS $VORBIS_CFLAGS" - LIBS="$LIBS $SHOUT2_LIBS $OGG_LIBS $VORBIS_LIBS" - AC_TRY_LINK([ -#include <stdio.h> -#include <shout/shout.h> -], [ return 0; ], - [ echo "*** The test program compiled, but did not run. This usually means" - echo "*** that the run-time linker is not finding Shout2 or finding the wrong" - echo "*** version of Shout2. If it is not finding Shout2, you'll need to set your" - echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" - echo "*** to the installed location Also, make sure you have run ldconfig if that" - echo "*** is required on your system" - echo "***" - echo "*** If you have an old version installed, it is best to remove it, although" - echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"], - [ echo "*** The test program failed to compile or link. See the file config.log for the" - echo "*** exact error that occured. This usually means Shout2 was incorrectly installed" - echo "*** or that you have moved Shout2 since it was installed. In the latter case, you" - echo "*** may want to edit the shout-config script: $SHOUT2_CONFIG" ]) - CFLAGS="$ac_save_CFLAGS" - LIBS="$ac_save_LIBS" - fi - SHOUT2_CFLAGS="" - SHOUT2_LIBS="" - ifelse([$2], , :, [$2]) - fi - AC_SUBST(SHOUT2_CFLAGS) - AC_SUBST(SHOUT2_LIBS) - rm -f conf.shout2test -]) diff --git a/m4/gtk.m4 b/m4/gtk.m4 deleted file mode 100644 index f2dd47219..000000000 --- a/m4/gtk.m4 +++ /dev/null @@ -1,194 +0,0 @@ -# Configure paths for GTK+ -# Owen Taylor 97-11-3 - -dnl AM_PATH_GTK([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]]) -dnl Test for GTK, and define GTK_CFLAGS and GTK_LIBS -dnl -AC_DEFUN([AM_PATH_GTK], -[dnl -dnl Get the cflags and libraries from the gtk-config script -dnl -AC_ARG_WITH(gtk-prefix,[ --with-gtk-prefix=PFX Prefix where GTK is installed (optional)], - gtk_config_prefix="$withval", gtk_config_prefix="") -AC_ARG_WITH(gtk-exec-prefix,[ --with-gtk-exec-prefix=PFX Exec prefix where GTK is installed (optional)], - gtk_config_exec_prefix="$withval", gtk_config_exec_prefix="") -AC_ARG_ENABLE(gtktest, [ --disable-gtktest Do not try to compile and run a test GTK program], - , enable_gtktest=yes) - - for module in . $4 - do - case "$module" in - gthread) - gtk_config_args="$gtk_config_args gthread" - ;; - esac - done - - if test x$gtk_config_exec_prefix != x ; then - gtk_config_args="$gtk_config_args --exec-prefix=$gtk_config_exec_prefix" - if test x${GTK_CONFIG+set} != xset ; then - GTK_CONFIG=$gtk_config_exec_prefix/bin/gtk-config - fi - fi - if test x$gtk_config_prefix != x ; then - gtk_config_args="$gtk_config_args --prefix=$gtk_config_prefix" - if test x${GTK_CONFIG+set} != xset ; then - GTK_CONFIG=$gtk_config_prefix/bin/gtk-config - fi - fi - - AC_PATH_PROG(GTK_CONFIG, gtk-config, no) - min_gtk_version=ifelse([$1], ,0.99.7,$1) - AC_MSG_CHECKING(for GTK - version >= $min_gtk_version) - no_gtk="" - if test "$GTK_CONFIG" = "no" ; then - no_gtk=yes - else - GTK_CFLAGS=`$GTK_CONFIG $gtk_config_args --cflags` - GTK_LIBS=`$GTK_CONFIG $gtk_config_args --libs` - gtk_config_major_version=`$GTK_CONFIG $gtk_config_args --version | \ - sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` - gtk_config_minor_version=`$GTK_CONFIG $gtk_config_args --version | \ - sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` - gtk_config_micro_version=`$GTK_CONFIG $gtk_config_args --version | \ - sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` - if test "x$enable_gtktest" = "xyes" ; then - ac_save_CFLAGS="$CFLAGS" - ac_save_LIBS="$LIBS" - CFLAGS="$CFLAGS $GTK_CFLAGS" - LIBS="$GTK_LIBS $LIBS" -dnl -dnl Now check if the installed GTK is sufficiently new. (Also sanity -dnl checks the results of gtk-config to some extent -dnl - rm -f conf.gtktest - AC_TRY_RUN([ -#include <gtk/gtk.h> -#include <stdio.h> -#include <stdlib.h> - -int -main () -{ - int major, minor, micro; - char *tmp_version; - - system ("touch conf.gtktest"); - - /* HP/UX 9 (%@#!) writes to sscanf strings */ - tmp_version = g_strdup("$min_gtk_version"); - if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { - printf("%s, bad version string\n", "$min_gtk_version"); - exit(1); - } - - if ((gtk_major_version != $gtk_config_major_version) || - (gtk_minor_version != $gtk_config_minor_version) || - (gtk_micro_version != $gtk_config_micro_version)) - { - printf("\n*** 'gtk-config --version' returned %d.%d.%d, but GTK+ (%d.%d.%d)\n", - $gtk_config_major_version, $gtk_config_minor_version, $gtk_config_micro_version, - gtk_major_version, gtk_minor_version, gtk_micro_version); - printf ("*** was found! If gtk-config was correct, then it is best\n"); - printf ("*** to remove the old version of GTK+. You may also be able to fix the error\n"); - printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); - printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); - printf("*** required on your system.\n"); - printf("*** If gtk-config was wrong, set the environment variable GTK_CONFIG\n"); - printf("*** to point to the correct copy of gtk-config, and remove the file config.cache\n"); - printf("*** before re-running configure\n"); - } -#if defined (GTK_MAJOR_VERSION) && defined (GTK_MINOR_VERSION) && defined (GTK_MICRO_VERSION) - else if ((gtk_major_version != GTK_MAJOR_VERSION) || - (gtk_minor_version != GTK_MINOR_VERSION) || - (gtk_micro_version != GTK_MICRO_VERSION)) - { - printf("*** GTK+ header files (version %d.%d.%d) do not match\n", - GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION); - printf("*** library (version %d.%d.%d)\n", - gtk_major_version, gtk_minor_version, gtk_micro_version); - } -#endif /* defined (GTK_MAJOR_VERSION) ... */ - else - { - if ((gtk_major_version > major) || - ((gtk_major_version == major) && (gtk_minor_version > minor)) || - ((gtk_major_version == major) && (gtk_minor_version == minor) && (gtk_micro_version >= micro))) - { - return 0; - } - else - { - printf("\n*** An old version of GTK+ (%d.%d.%d) was found.\n", - gtk_major_version, gtk_minor_version, gtk_micro_version); - printf("*** You need a version of GTK+ newer than %d.%d.%d. The latest version of\n", - major, minor, micro); - printf("*** GTK+ is always available from ftp://ftp.gtk.org.\n"); - printf("***\n"); - printf("*** If you have already installed a sufficiently new version, this error\n"); - printf("*** probably means that the wrong copy of the gtk-config shell script is\n"); - printf("*** being found. The easiest way to fix this is to remove the old version\n"); - printf("*** of GTK+, but you can also set the GTK_CONFIG environment to point to the\n"); - printf("*** correct copy of gtk-config. (In this case, you will have to\n"); - printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); - printf("*** so that the correct libraries are found at run-time))\n"); - } - } - return 1; -} -],, no_gtk=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) - CFLAGS="$ac_save_CFLAGS" - LIBS="$ac_save_LIBS" - fi - fi - if test "x$no_gtk" = x ; then - AC_MSG_RESULT(yes) - ifelse([$2], , :, [$2]) - else - AC_MSG_RESULT(no) - if test "$GTK_CONFIG" = "no" ; then - echo "*** The gtk-config script installed by GTK could not be found" - echo "*** If GTK was installed in PREFIX, make sure PREFIX/bin is in" - echo "*** your path, or set the GTK_CONFIG environment variable to the" - echo "*** full path to gtk-config." - else - if test -f conf.gtktest ; then - : - else - echo "*** Could not run GTK test program, checking why..." - CFLAGS="$CFLAGS $GTK_CFLAGS" - LIBS="$LIBS $GTK_LIBS" - AC_TRY_LINK([ -#include <gtk/gtk.h> -#include <stdio.h> -], [ return ((gtk_major_version) || (gtk_minor_version) || (gtk_micro_version)); ], - [ echo "*** The test program compiled, but did not run. This usually means" - echo "*** that the run-time linker is not finding GTK or finding the wrong" - echo "*** version of GTK. If it is not finding GTK, you'll need to set your" - echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" - echo "*** to the installed location Also, make sure you have run ldconfig if that" - echo "*** is required on your system" - echo "***" - echo "*** If you have an old version installed, it is best to remove it, although" - echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" - echo "***" - echo "*** If you have a RedHat 5.0 system, you should remove the GTK package that" - echo "*** came with the system with the command" - echo "***" - echo "*** rpm --erase --nodeps gtk gtk-devel" ], - [ echo "*** The test program failed to compile or link. See the file config.log for the" - echo "*** exact error that occured. This usually means GTK was incorrectly installed" - echo "*** or that you have moved GTK since it was installed. In the latter case, you" - echo "*** may want to edit the gtk-config script: $GTK_CONFIG" ]) - CFLAGS="$ac_save_CFLAGS" - LIBS="$ac_save_LIBS" - fi - fi - GTK_CFLAGS="" - GTK_LIBS="" - ifelse([$3], , :, [$3]) - fi - AC_SUBST(GTK_CFLAGS) - AC_SUBST(GTK_LIBS) - rm -f conf.gtktest -]) diff --git a/m4/ogg.m4 b/m4/ogg.m4 deleted file mode 100644 index 0e1f1abf5..000000000 --- a/m4/ogg.m4 +++ /dev/null @@ -1,102 +0,0 @@ -# Configure paths for libogg -# Jack Moffitt <jack@icecast.org> 10-21-2000 -# Shamelessly stolen from Owen Taylor and Manish Singh - -dnl XIPH_PATH_OGG([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) -dnl Test for libogg, and define OGG_CFLAGS and OGG_LIBS -dnl -AC_DEFUN([XIPH_PATH_OGG], -[dnl -dnl Get the cflags and libraries -dnl -AC_ARG_WITH(ogg,[ --with-ogg=PFX Prefix where libogg is installed (optional)], ogg_prefix="$withval", ogg_prefix="") -AC_ARG_WITH(ogg-libraries,[ --with-ogg-libraries=DIR Directory where libogg library is installed (optional)], ogg_libraries="$withval", ogg_libraries="") -AC_ARG_WITH(ogg-includes,[ --with-ogg-includes=DIR Directory where libogg header files are installed (optional)], ogg_includes="$withval", ogg_includes="") -AC_ARG_ENABLE(oggtest, [ --disable-oggtest Do not try to compile and run a test Ogg program],, enable_oggtest=yes) - - if test "x$ogg_libraries" != "x" ; then - OGG_LIBS="-L$ogg_libraries" - elif test "x$ogg_prefix" != "x" ; then - OGG_LIBS="-L$ogg_prefix/lib" - elif test "x$prefix" != "xNONE" ; then - OGG_LIBS="-L$prefix/lib" - fi - - OGG_LIBS="$OGG_LIBS -logg" - - if test "x$ogg_includes" != "x" ; then - OGG_CFLAGS="-I$ogg_includes" - elif test "x$ogg_prefix" != "x" ; then - OGG_CFLAGS="-I$ogg_prefix/include" - elif test "x$prefix" != "xNONE"; then - OGG_CFLAGS="-I$prefix/include" - fi - - AC_MSG_CHECKING(for Ogg) - no_ogg="" - - - if test "x$enable_oggtest" = "xyes" ; then - ac_save_CFLAGS="$CFLAGS" - ac_save_LIBS="$LIBS" - CFLAGS="$CFLAGS $OGG_CFLAGS" - LIBS="$LIBS $OGG_LIBS" -dnl -dnl Now check if the installed Ogg is sufficiently new. -dnl - rm -f conf.oggtest - AC_TRY_RUN([ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ogg/ogg.h> - -int main () -{ - system("touch conf.oggtest"); - return 0; -} - -],, no_ogg=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) - CFLAGS="$ac_save_CFLAGS" - LIBS="$ac_save_LIBS" - fi - - if test "x$no_ogg" = "x" ; then - AC_MSG_RESULT(yes) - ifelse([$1], , :, [$1]) - else - AC_MSG_RESULT(no) - if test -f conf.oggtest ; then - : - else - echo "*** Could not run Ogg test program, checking why..." - CFLAGS="$CFLAGS $OGG_CFLAGS" - LIBS="$LIBS $OGG_LIBS" - AC_TRY_LINK([ -#include <stdio.h> -#include <ogg/ogg.h> -], [ return 0; ], - [ echo "*** The test program compiled, but did not run. This usually means" - echo "*** that the run-time linker is not finding Ogg or finding the wrong" - echo "*** version of Ogg. If it is not finding Ogg, you'll need to set your" - echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" - echo "*** to the installed location Also, make sure you have run ldconfig if that" - echo "*** is required on your system" - echo "***" - echo "*** If you have an old version installed, it is best to remove it, although" - echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"], - [ echo "*** The test program failed to compile or link. See the file config.log for the" - echo "*** exact error that occured. This usually means Ogg was incorrectly installed" - echo "*** or that you have moved Ogg since it was installed." ]) - CFLAGS="$ac_save_CFLAGS" - LIBS="$ac_save_LIBS" - fi - OGG_CFLAGS="" - OGG_LIBS="" - ifelse([$2], , :, [$2]) - fi - AC_SUBST(OGG_CFLAGS) - AC_SUBST(OGG_LIBS) - rm -f conf.oggtest -]) diff --git a/m4/vorbis.m4 b/m4/vorbis.m4 deleted file mode 100644 index 6a2889318..000000000 --- a/m4/vorbis.m4 +++ /dev/null @@ -1,128 +0,0 @@ -# Configure paths for libvorbis -# Jack Moffitt <jack@icecast.org> 10-21-2000 -# Shamelessly stolen from Owen Taylor and Manish Singh -# thomasvs added check for vorbis_bitrate_addblock which is new in rc3 -# thomasvs added check for OV_ECTL_RATEMANAGE_SET which is new in 1.0 final - -dnl XIPH_PATH_VORBIS([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) -dnl Test for libvorbis, and define VORBIS_CFLAGS and VORBIS_LIBS -dnl -AC_DEFUN([XIPH_PATH_VORBIS], -[dnl -dnl Get the cflags and libraries -dnl -AC_ARG_WITH(vorbis,[ --with-vorbis=PFX Prefix where libvorbis is installed (optional)], vorbis_prefix="$withval", vorbis_prefix="") -AC_ARG_WITH(vorbis-libraries,[ --with-vorbis-libraries=DIR Directory where libvorbis library is installed (optional)], vorbis_libraries="$withval", vorbis_libraries="") -AC_ARG_WITH(vorbis-includes,[ --with-vorbis-includes=DIR Directory where libvorbis header files are installed (optional)], vorbis_includes="$withval", vorbis_includes="") -AC_ARG_ENABLE(vorbistest, [ --disable-vorbistest Do not try to compile and run a test Vorbis program],, enable_vorbistest=yes) - - if test "x$vorbis_libraries" != "x" ; then - VORBIS_LIBS="-L$vorbis_libraries" - elif test "x$vorbis_prefix" != "x" ; then - VORBIS_LIBS="-L$vorbis_prefix/lib" - elif test "x$prefix" != "xNONE"; then - VORBIS_LIBS="-L$prefix/lib" - fi - - VORBIS_LIBS="$VORBIS_LIBS -lvorbis -lm" - VORBISFILE_LIBS="-lvorbisfile" - VORBISENC_LIBS="-lvorbisenc" - - if test "x$vorbis_includes" != "x" ; then - VORBIS_CFLAGS="-I$vorbis_includes" - elif test "x$vorbis_prefix" != "x" ; then - VORBIS_CFLAGS="-I$vorbis_prefix/include" - elif test "x$prefix" != "xNONE"; then - VORBIS_CFLAGS="-I$prefix/include" - fi - - - AC_MSG_CHECKING(for Vorbis) - no_vorbis="" - - - if test "x$enable_vorbistest" = "xyes" ; then - ac_save_CFLAGS="$CFLAGS" - ac_save_LIBS="$LIBS" - CFLAGS="$CFLAGS $VORBIS_CFLAGS $OGG_CFLAGS" - LIBS="$LIBS $VORBIS_LIBS $VORBISENC_LIBS $OGG_LIBS" -dnl -dnl Now check if the installed Vorbis is sufficiently new. -dnl - rm -f conf.vorbistest - AC_TRY_RUN([ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <vorbis/codec.h> -#include <vorbis/vorbisenc.h> - -int main () -{ - vorbis_block vb; - vorbis_dsp_state vd; - vorbis_info vi; - - vorbis_info_init (&vi); - vorbis_encode_init (&vi, 2, 44100, -1, 128000, -1); - vorbis_analysis_init (&vd, &vi); - vorbis_block_init (&vd, &vb); - /* this function was added in 1.0rc3, so this is what we're testing for */ - vorbis_bitrate_addblock (&vb); - - /* this define was added in 1.0 final */ -#ifdef OV_ECTL_RATEMANAGE_SET - system("touch conf.vorbistest"); - return 0; -#else - return -1; -#endif -} - -],, no_vorbis=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) - CFLAGS="$ac_save_CFLAGS" - LIBS="$ac_save_LIBS" - fi - - if test "x$no_vorbis" = "x" ; then - AC_MSG_RESULT(yes) - ifelse([$1], , :, [$1]) - else - AC_MSG_RESULT(no) - if test -f conf.vorbistest ; then - : - else - echo "*** Could not run Vorbis test program, checking why..." - CFLAGS="$CFLAGS $VORBIS_CFLAGS" - LIBS="$LIBS $VORBIS_LIBS $OGG_LIBS" - AC_TRY_LINK([ -#include <stdio.h> -#include <vorbis/codec.h> -], [ return 0; ], - [ echo "*** The test program compiled, but did not run. This usually means" - echo "*** that the run-time linker is not finding Vorbis or finding the wrong" - echo "*** version of Vorbis. If it is not finding Vorbis, you'll need to set your" - echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" - echo "*** to the installed location Also, make sure you have run ldconfig if that" - echo "*** is required on your system" - echo "***" - echo "*** If you have an old version installed, it is best to remove it, although" - echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"], - [ echo "*** The test program failed to compile or link. See the file config.log for the" - echo "*** exact error that occured. This usually means Vorbis was incorrectly installed" - echo "*** or that you have moved Vorbis since it was installed." ]) - CFLAGS="$ac_save_CFLAGS" - LIBS="$ac_save_LIBS" - fi - VORBIS_CFLAGS="" - VORBIS_LIBS="" - VORBISFILE_LIBS="" - VORBISENC_LIBS="" - ifelse([$2], , :, [$2]) - fi - AC_SUBST(VORBIS_CFLAGS) - AC_SUBST(VORBIS_LIBS) - AC_SUBST(VORBISFILE_LIBS) - AC_SUBST(VORBISENC_LIBS) - rm -f conf.vorbistest -]) @@ -1,31 +1,32 @@ # Bulgarian translation of gst-plugins-bad. -# Copyright (C) 2007, 2008, 2009 Free Software Fondation, Inc. +# Copyright (C) 2007, 2008, 2009, 2010 Free Software Fondation, Inc. # This file is distributed under the same license as the gst-plugins-bad package. -# Alexander Shopov <ash@contact.bg>, 2007, 2008, 2009. +# Alexander Shopov <ash@kambanaria.org>, 2007, 2008, 2009, 2010. +# # msgid "" msgstr "" -"Project-Id-Version: gst-plugins-bad 0.10.13.2\n" +"Project-Id-Version: gst-plugins-bad 0.10.18.2\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2010-10-19 23:33+0100\n" -"PO-Revision-Date: 2009-09-24 15:33+0300\n" -"Last-Translator: Alexander Shopov <ash@contact.bg>\n" +"POT-Creation-Date: 2011-01-07 20:26+0000\n" +"PO-Revision-Date: 2010-11-04 14:25+0200\n" +"Last-Translator: Alexander Shopov <ash@kambanaria.org>\n" "Language-Team: Bulgarian <dict@fsa-bg.org>\n" -"Language: bg\n" +"Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgid "Could not read title information for DVD." -msgstr "ИнформациÑта за заглавието на DVD-то не може да бъде прочетена." +msgstr "ИнформациÑта за заглавните чаÑти на DVD-то не може да бъде прочетена." #, c-format msgid "Failed to open DVD device '%s'." -msgstr "УÑтройÑтвото за DVD „%s“ не може да бъде отворено." +msgstr "Ðе може да Ñе чете от уÑтройÑтвото за DVD-та „%s“." msgid "Failed to set PGC based seeking." -msgstr "ÐеуÑпех при задаване на Ñ‚ÑŠÑ€Ñене чрез PGC." +msgstr "Ðе може да Ñе Ñ‚ÑŠÑ€Ñи по веригата на програмите (PGC)" msgid "" "Could not read DVD. This may be because the DVD is encrypted and a DVD " @@ -34,24 +35,24 @@ msgstr "" #, fuzzy msgid "Could not read DVD." -msgstr "ИнформациÑта за заглавието на DVD-то не може да бъде прочетена." +msgstr "ИнформациÑта за заглавните чаÑти на DVD-то не може да бъде прочетена." msgid "No file name specified for writing." -msgstr "Ðе е указано име на файл, в който да Ñе пише." +msgstr "Ðе е указано име на файл за запиÑ." #, c-format msgid "Could not open file \"%s\" for writing." -msgstr "Файлът „%s“ не може да бъде отворен за запиÑ." +msgstr "Файлът „%s“ не може да Ñе отвори за запиÑ." msgid "Internal data stream error." -msgstr "Вътрешна грешка в потока от данни." +msgstr "Вътрешна грешка в потока на данни." #, c-format msgid "Could not write to file \"%s\"." -msgstr "Във файла „%s“ не може да Ñе пише." +msgstr "Ðе може да Ñе запиÑва във файла „%s“." msgid "Internal data flow error." -msgstr "Вътрешна грешка в потока от данни." +msgstr "Вътрешна грешка в потока на данни." #, c-format msgid "Device \"%s\" does not exist." @@ -63,14 +64,8 @@ msgstr "УÑтройÑтвото „%s“ не може да бъде отвор #, c-format msgid "Could not get settings from frontend device \"%s\"." -msgstr "Ðе могат да бъдат получени наÑтройките от уÑтройÑтвото „%s“." +msgstr "ÐаÑтройките на уÑтройÑтвото „%s“ не могат да бъдат получени." #, c-format msgid "Could not open file \"%s\" for reading." -msgstr "Файлът „%s“ не може да бъде отворен за четене." - -#~ msgid "%s %d" -#~ msgstr "%s %d" - -#~ msgid "Internal clock error." -#~ msgstr "Вътрешна грешка в чаÑовника." +msgstr "Файлът „%s“ не може да Ñе отвори за четене." @@ -1,31 +1,31 @@ -# Catalan translation for GStreamer. -# Copyright © 2004 Free Software Foundation, Inc. -# This file is distributed under the same licence as the gst-plugins package. -# Jordi Mallach <jordi@sindominio.net>, 2004. +# Catalan translation for gst-plugins-bad. +# Copyright © 2004, 2005, 2010 Free Software Foundation, Inc. +# This file is distributed under the same licence as the gst-plugins-bad package. +# Jordi Mallach <jordi@sindominio.net>, 2004, 2005, 2010. # msgid "" msgstr "" -"Project-Id-Version: gst-plugins 0.8.3\n" +"Project-Id-Version: gst-plugins-bad 0.10.18.2\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2010-10-19 23:33+0100\n" -"PO-Revision-Date: 2004-08-05 15:48+0200\n" +"POT-Creation-Date: 2011-01-07 20:26+0000\n" +"PO-Revision-Date: 2010-11-04 21:02+0100\n" "Last-Translator: Jordi Mallach <jordi@sindominio.net>\n" "Language-Team: Catalan <ca@dodds.net>\n" "Language: ca\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n!=1;\n" -#, fuzzy msgid "Could not read title information for DVD." -msgstr "No s'ha pogut escriure al fitxer «%s»." +msgstr "No s'ha pogut llegir la informació del tÃtol del DVD." -#, fuzzy, c-format +#, c-format msgid "Failed to open DVD device '%s'." -msgstr "No s'ha pogut tancar el dispositiu de control «%s»." +msgstr "No s'ha pogut obrir el dispositiu de DVD «%s»." msgid "Failed to set PGC based seeking." -msgstr "" +msgstr "No s'ha pogut establir la cerca basada en PGC." msgid "" "Could not read DVD. This may be because the DVD is encrypted and a DVD " @@ -34,185 +34,37 @@ msgstr "" #, fuzzy msgid "Could not read DVD." -msgstr "No s'ha pogut escriure al fitxer «%s»." +msgstr "No s'ha pogut llegir la informació del tÃtol del DVD." -#, fuzzy msgid "No file name specified for writing." -msgstr "No s'ha especificat cap nom de fitxer." +msgstr "No s'ha especificat cap nom de fitxer per a l'escriptura." #, c-format msgid "Could not open file \"%s\" for writing." -msgstr "No s'ha pogut obrir el fitxer «%s» per a l'escriptura." +msgstr "No s'ha pogut obrir «%s» per a l'escriptura." msgid "Internal data stream error." -msgstr "" +msgstr "S'ha produït un error intern de flux de dades." #, c-format msgid "Could not write to file \"%s\"." msgstr "No s'ha pogut escriure al fitxer «%s»." msgid "Internal data flow error." -msgstr "" +msgstr "S'ha produït un error intern de flux de dades." #, c-format msgid "Device \"%s\" does not exist." msgstr "El dispositiu «%s» no existeix." -#, fuzzy, c-format +#, c-format msgid "Could not open frontend device \"%s\"." -msgstr "No s'ha pogut tancar el dispositiu de control «%s»." +msgstr "No s'ha pogut crear el dispositiu frontal «%s»." -#, fuzzy, c-format +#, c-format msgid "Could not get settings from frontend device \"%s\"." -msgstr "No s'han pogut obtenir búfers suficients del dispositiu «%s»." +msgstr "No s'ha pogut obtenir els parà metres des del dispositiu frontal «%s»." #, c-format msgid "Could not open file \"%s\" for reading." msgstr "No s'ha pogut obrir el fitxer «%s» per a la lectura." - -#, fuzzy -#~ msgid "PCM 1" -#~ msgstr "PCM" - -#, fuzzy -#~ msgid "PCM 2" -#~ msgstr "PCM-2" - -#, fuzzy -#~ msgid "PCM 3" -#~ msgstr "PCM" - -#, fuzzy -#~ msgid "PCM 4" -#~ msgstr "PCM" - -#~ msgid "Error closing file \"%s\"." -#~ msgstr "S'ha produït un error en tancar el fitxer «%s»." - -#~ msgid "Could not open CD device for reading." -#~ msgstr "No s'ha pogut obrir el dispositiu de CD per a la lectura." - -#~ msgid "Could not open vfs file \"%s\" for reading." -#~ msgstr "No s'ha pogut obrir el fitxer vfs «%s» per a la lectura." - -#~ msgid "Could not open vfs file \"%s\" for writing: %s." -#~ msgstr "No s'ha pogut obrir el fitxer vfs «%s» per a l'escriptura: %s." - -#~ msgid "No filename given" -#~ msgstr "No s'ha donat cap nom de fitxer" - -#~ msgid "Could not close vfs file \"%s\"." -#~ msgstr "No s'ha pogut tancar el fitxer vfs «%s»." - -#~ msgid "No or invalid input audio, AVI stream will be corrupt." -#~ msgstr "" -#~ "L'entrada d'à udio no existeix o és invà lida, el flux AVI serà corrupte." - -#~ msgid "" -#~ "The %s element could not be found. This element is essential for " -#~ "playback. Please install the right plug-in and verify that it works by " -#~ "running 'gst-inspect %s'" -#~ msgstr "" -#~ "No s'ha pogut trobar l'element %s. Aquest element és essencial per a la " -#~ "reproducció. Si us plau, instal·leu el connector adequat i verifiqueu que " -#~ "funciona correctament executant «gst-inspect %s»" - -#~ msgid "" -#~ "No usable colorspace element could be found.\n" -#~ "Please install one and restart." -#~ msgstr "" -#~ "No s'ha trobat cap element d'espai de color utilitzable.\n" -#~ "Si us plau, instal·leu un i reinicieu." - -#~ msgid "Could not open control device \"%s\" for writing." -#~ msgstr "" -#~ "No s'ha pogut obrir el dispositiu de control «%s» per a l'escriptura." - -#~ msgid "Could not configure audio device \"%s\"." -#~ msgstr "No s'ha pogut configurar el dispositiu d'à udio «%s»." - -#~ msgid "Could not set audio device \"%s\" to %d Hz." -#~ msgstr "No s'ha pogut establir el dispositiu d'à udio «%s» a %d Hz." - -#~ msgid "Could not close audio device \"%s\"." -#~ msgstr "No s'ha pogut tancar el dispositiu d'à udio «%s»." - -#~ msgid "Could not open video device \"%s\" for writing." -#~ msgstr "No s'ha pogut obrir el dispositiu de vÃdeo «%s» per a l'escriptura." - -#~ msgid "Could not close video device \"%s\"." -#~ msgstr "No s'ha pogut tancar el dispositiu de vÃdeo «%s»." - -#~ msgid "Could not write to device \"%s\"." -#~ msgstr "No s'ha pogut escriure al dispositiu «%s»." - -#~ msgid "OSS device \"%s\" is already in use by another program." -#~ msgstr "El dispositiu OSS «%s» ja està en ús per un altre programa." - -#~ msgid "Could not access device \"%s\", check its permissions." -#~ msgstr "" -#~ "No s'ha pogut accedir al dispositiu «%s», comproveu els seus permisos." - -#~ msgid "Could not open device \"%s\" for writing." -#~ msgstr "No s'ha pogut obrir el dispositiu «%s» per a l'escriptura." - -#~ msgid "Could not open device \"%s\" for reading." -#~ msgstr "No s'ha pogut obrir el dispositiu «%s» per a la lectura." - -#~ msgid "Your OSS device could not be probed correctly" -#~ msgstr "No s'ha pogut detectar el vostre dispositiu d'OSS correctament" - -#~ msgid "Synth" -#~ msgstr "Sintetitzador" - -#~ msgid "CD" -#~ msgstr "CD" - -#~ msgid "Mixer" -#~ msgstr "Mesclador" - -#~ msgid "In-gain" -#~ msgstr "Ganà ncia-entrada" - -#~ msgid "Line-1" -#~ msgstr "LÃnia-1" - -#~ msgid "Line-2" -#~ msgstr "LÃnia-2" - -#~ msgid "Line-3" -#~ msgstr "LÃnia-3" - -#~ msgid "Digital-2" -#~ msgstr "Digital-2" - -#~ msgid "Digital-3" -#~ msgstr "Digital-3" - -#~ msgid "Phone-in" -#~ msgstr "Telèfon-entrada" - -#~ msgid "Phone-out" -#~ msgstr "Telèfon-sortida" - -#~ msgid "Radio" -#~ msgstr "Rà dio" - -#~ msgid "No device specified." -#~ msgstr "No s'ha especificat cap dispositiu." - -#~ msgid "Could not open device \"%s\" for reading and writing." -#~ msgstr "" -#~ "No s'ha pogut obrir el dispositiu «%s» per a l'escriptura i lectura." - -#~ msgid "Device is not open." -#~ msgstr "El dispositiu no està obert." - -#~ msgid "Device is open." -#~ msgstr "El dispositiu està obert." - -#~ msgid "Device \"%s\" is not a capture device." -#~ msgstr "El dispositiu «%s» no és un dispositiu de captura." - -#~ msgid "Could not get buffers from device \"%s\"." -#~ msgstr "No s'han pogut obtenir els búfers del dispositiu «%s»." @@ -1,13 +1,13 @@ # Japanese traslation for gst-plugins-bad # This file is put in the public domain. # -# Makoto Kato <makoto.kt@gmail.com>, 2009. +# Makoto Kato <makoto.kt@gmail.com>, 2009-2010. msgid "" msgstr "" -"Project-Id-Version: gst-plugins-bad 0.10.11.2\n" +"Project-Id-Version: gst-plugins-bad 0.10.18.2\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/\n" -"POT-Creation-Date: 2010-10-19 23:33+0100\n" -"PO-Revision-Date: 2009-06-01 20:27+0900\n" +"POT-Creation-Date: 2011-01-07 20:26+0000\n" +"PO-Revision-Date: 2010-10-26 16:31+0900\n" "Last-Translator: Makoto Kato <makoto.kt@gmail.com>\n" "Language-Team: Japanese <translation-team-ja@lists.sourceforge.net>\n" "Language: ja\n" @@ -25,7 +25,7 @@ msgid "Failed to open DVD device '%s'." msgstr "DVD デãƒã‚¤ã‚¹ '%s' ã®ã‚ªãƒ¼ãƒ—ンã«å¤±æ•—ã—ã¾ã—ãŸ" msgid "Failed to set PGC based seeking." -msgstr "" +msgstr "PGCを利用ã—ãŸã‚·ãƒ¼ã‚¯ã«å¤±æ•—ã—ã¾ã—ãŸã€‚" msgid "" "Could not read DVD. This may be because the DVD is encrypted and a DVD " @@ -72,6 +72,61 @@ msgstr "èªã¿è¾¼ã¿ç”¨ã«ãƒ•ã‚¡ã‚¤ãƒ« \"%s\" ã‚’é–‹ãã“ã¨ãŒã§ãã¾ã›ã‚“ã #~ msgid "Internal clock error." #~ msgstr "内部クãƒãƒƒã‚¯ã‚¨ãƒ©ãƒ¼" +#~ msgid "Could not open audio device for mixer control handling." +#~ msgstr "" +#~ "ミã‚サーãŒã‚³ãƒ³ãƒˆãƒãƒ¼ãƒ«ã™ã‚‹ã‚ªãƒ¼ãƒ‡ã‚£ã‚ªãƒ‡ãƒã‚¤ã‚¹ã‚’é–‹ãã“ã¨ãŒã§ãã¾ã›ã‚“。" + +#~ msgid "Low" +#~ msgstr "低音" + +#~ msgid "Medium" +#~ msgstr "ä¸éŸ³" + +#~ msgid "High" +#~ msgstr "高音" + +#~ msgid "Production" +#~ msgstr "プãƒãƒ€ã‚¯ã‚·ãƒ§ãƒ³" + +#~ msgid "Off" +#~ msgstr "Off" + +#~ msgid "On" +#~ msgstr "On" + +#~ msgid "Stereo" +#~ msgstr "ステレオ" + +#~ msgid "Surround sound" +#~ msgstr "サラウンドサウンド" + +#~ msgid "Input mix" +#~ msgstr "入力ミックス" + +#~ msgid "Front" +#~ msgstr "フãƒãƒ³ãƒˆ" + +#~ msgid "Rear" +#~ msgstr "リア" + +#~ msgid "Side" +#~ msgstr "サイド" + +#~ msgid "Center / LFE" +#~ msgstr "センター / LFE" + +#~ msgid "Microphone" +#~ msgstr "マイクãƒãƒ•ã‚©ãƒ³" + +#~ msgid "Front panel microphone" +#~ msgstr "フãƒãƒ³ãƒˆãƒ‘ãƒãƒ«ã®ãƒžã‚¤ã‚¯ãƒãƒ•ã‚©ãƒ³" + +#~ msgid "Input" +#~ msgstr "入力" + +#~ msgid "Line-in" +#~ msgstr "ライン入力" + #~ msgid "PCM 1" #~ msgstr "PCM 1" @@ -84,12 +139,99 @@ msgstr "èªã¿è¾¼ã¿ç”¨ã«ãƒ•ã‚¡ã‚¤ãƒ« \"%s\" ã‚’é–‹ãã“ã¨ãŒã§ãã¾ã›ã‚“ã #~ msgid "PCM 4" #~ msgstr "PCM 4" +#~ msgid "Green connector" +#~ msgstr "緑色コãƒã‚¯ã‚¿" + +#~ msgid "Green front panel connector" +#~ msgstr "緑色ã®ãƒ•ãƒãƒ³ãƒˆãƒ‘ãƒãƒ«ã®ã‚³ãƒã‚¯ã‚¿" + +#~ msgid "Pink connector" +#~ msgstr "ピンク色コãƒã‚¯ã‚¿" + +#~ msgid "Pink front panel connector" +#~ msgstr "ピンク色ã®ãƒ•ãƒãƒ³ãƒˆãƒ‘ãƒãƒ«ã‚³ãƒã‚¯ã‚¿" + +#~ msgid "Blue connector" +#~ msgstr "é’色コãƒã‚¯ã‚¿" + +#~ msgid "Orange connector" +#~ msgstr "オレンジ色コãƒã‚¯ã‚¿" + +#~ msgid "Black connector" +#~ msgstr "黒色コãƒã‚¯ã‚¿" + +#~ msgid "Gray connector" +#~ msgstr "グレー色コãƒã‚¯ã‚¿" + +#~ msgid "White connector" +#~ msgstr "白色コãƒã‚¯ã‚¿" + +#~ msgid "Red connector" +#~ msgstr "赤色コãƒã‚¯ã‚¿" + +#~ msgid "Yellow connector" +#~ msgstr "黄色コãƒã‚¯ã‚¿" + #~ msgid "Green connector function" #~ msgstr "緑色コãƒã‚¯ã‚¿æ©Ÿèƒ½" +#~ msgid "Front panel line-in" +#~ msgstr "プãƒãƒ³ãƒˆãƒ‘ãƒãƒ«ã®ãƒ©ã‚¤ãƒ³å…¥åŠ›" + +#~ msgid "Headphones" +#~ msgstr "ヘッドフォン" + +#~ msgid "Front panel headphones" +#~ msgstr "フãƒãƒ³ãƒˆãƒ‘ãƒãƒ«ã®ãƒ˜ãƒƒãƒ‰ãƒ•ã‚©ãƒ³" + +#~ msgid "PCM" +#~ msgstr "PCM" + +#~ msgid "Virtual mixer input" +#~ msgstr "仮想ミã‚サー入力" + +#~ msgid "Virtual mixer output" +#~ msgstr "仮想ミã‚サー出力" + #~ msgid "Virtual mixer channel configuration" #~ msgstr "仮想ミックスãƒãƒ£ãƒ³ãƒãƒ«è¨å®š" +#~ msgid "" +#~ "Could not open audio device for playback. Device is being used by another " +#~ "application." +#~ msgstr "" +#~ "プレイãƒãƒƒã‚¯ç”¨ã«ã‚ªãƒ¼ãƒ‡ã‚£ã‚ªãƒ‡ãƒã‚¤ã‚¹ã‚’é–‹ãã“ã¨ãŒã§ãã¾ã›ã‚“ã§ã—ãŸã€‚デãƒã‚¤ã‚¹ã¯" +#~ "ä»–ã®ã‚¢ãƒ—リケーションã«ã‚ˆã£ã¦ä½¿ã‚ã‚Œã¦ã„ã¾ã™ã€‚" + +#~ msgid "" +#~ "Could not open audio device for playback. You don't have permission to " +#~ "open the device." +#~ msgstr "" +#~ "プレイãƒãƒƒã‚¯ç”¨ã«ã‚ªãƒ¼ãƒ‡ã‚£ã‚ªãƒ‡ãƒã‚¤ã‚¹ã‚’é–‹ãã“ã¨ãŒã§ãã¾ã›ã‚“ã§ã—ãŸã€‚デãƒã‚¤ã‚¹ã‚’" +#~ "é–‹ããŸã‚ã®æ¨©é™ã‚’æŒã£ã¦ã„ã¾ã›ã‚“。" + +#~ msgid "Could not open audio device for playback." +#~ msgstr "プレイãƒãƒƒã‚¯ç”¨ã«ã‚ªãƒ¼ãƒ‡ã‚£ã‚ªãƒ‡ãƒã‚¤ã‚¹ã‚’é–‹ãã“ã¨ãŒã§ãã¾ã›ã‚“ã§ã—ãŸã€‚" + +#~ msgid "" +#~ "Could not open audio device for playback. This version of the Open Sound " +#~ "System is not supported by this element." +#~ msgstr "" +#~ "プレイãƒãƒƒã‚¯ç”¨ã«ã‚ªãƒ¼ãƒ‡ã‚£ã‚ªãƒ‡ãƒã‚¤ã‚¹ã‚’é–‹ãã“ã¨ãŒã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã“ã® Open " +#~ "Sound System ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã¯ã“ã®ã‚¨ãƒ¬ãƒ¡ãƒ³ãƒˆã«ã‚ˆã£ã¦ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¾ã›ã‚“。" + +#~ msgid "Playback is not supported by this audio device." +#~ msgstr "プレイãƒãƒƒã‚¯ã¯ã“ã®ã‚ªãƒ¼ãƒ‡ã‚£ã‚ªãƒ‡ãƒã‚¤ã‚¹ã«ã‚ˆã£ã¦ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¾ã›ã‚“。" + +#~ msgid "Audio playback error." +#~ msgstr "オーディオプレイãƒãƒƒã‚¯ã‚¨ãƒ©ãƒ¼" + +#~ msgid "Recording is not supported by this audio device." +#~ msgstr "録音ã¯ã“ã®ã‚ªãƒ¼ãƒ‡ã‚£ã‚ªãƒ‡ãƒã‚¤ã‚¹ã«ã‚ˆã£ã¦ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¾ã›ã‚“。" + +#~ msgid "Error recording from audio device." +#~ msgstr "オーディオデãƒã‚¤ã‚¹ã‹ã‚‰ã®éŒ²éŸ³æ™‚ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚" + #~ msgid "Failed to configure TwoLAME encoder. Check your encoding parameters." #~ msgstr "" #~ "TwoLAME エンコーダーã®æ§‹æˆã«å¤±æ•—ã—ã¾ã—ãŸã€‚エンコーディングパラメータを" diff --git a/sys/applemedia/coremediactx.h b/sys/applemedia/coremediactx.h index 4125ecdf5..0220b3e19 100644 --- a/sys/applemedia/coremediactx.h +++ b/sys/applemedia/coremediactx.h @@ -46,9 +46,6 @@ G_BEGIN_DECLS #define GST_IS_CORE_MEDIA_CTX_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CORE_MEDIA_CTX)) -#define GST_DYN_SYM_SPEC(type, name) \ - { G_STRINGIFY (name), G_STRUCT_OFFSET (type, name) } - typedef struct _GstCoreMediaCtx GstCoreMediaCtx; typedef struct _GstCoreMediaCtxClass GstCoreMediaCtxClass; diff --git a/sys/applemedia/cvapi.c b/sys/applemedia/cvapi.c index 73186f8f5..4307f0737 100644 --- a/sys/applemedia/cvapi.c +++ b/sys/applemedia/cvapi.c @@ -37,6 +37,7 @@ gst_cv_api_class_init (GstCVApiClass * klass) } #define SYM_SPEC(name) GST_DYN_SYM_SPEC (GstCVApi, name) +#define SYM_SPEC_OPTIONAL(name) GST_DYN_SYM_SPEC_OPTIONAL (GstCVApi, name) GstCVApi * gst_cv_api_obtain (GError ** error) @@ -53,7 +54,7 @@ gst_cv_api_obtain (GError ** error) SYM_SPEC (CVPixelBufferGetBytesPerRowOfPlane), SYM_SPEC (CVPixelBufferGetHeight), SYM_SPEC (CVPixelBufferGetHeightOfPlane), - SYM_SPEC (CVPixelBufferGetIOSurface), + SYM_SPEC_OPTIONAL (CVPixelBufferGetIOSurface), SYM_SPEC (CVPixelBufferGetPlaneCount), SYM_SPEC (CVPixelBufferGetTypeID), SYM_SPEC (CVPixelBufferIsPlanar), diff --git a/sys/applemedia/dynapi-internal.h b/sys/applemedia/dynapi-internal.h index b584ea76b..d6624d100 100644 --- a/sys/applemedia/dynapi-internal.h +++ b/sys/applemedia/dynapi-internal.h @@ -30,6 +30,7 @@ struct _GstDynSymSpec { const gchar * name; guint offset; + gboolean is_required; }; gpointer _gst_dyn_api_new (GType derived_type, const gchar * filename, diff --git a/sys/applemedia/dynapi.c b/sys/applemedia/dynapi.c index 87ff10ccb..139fabd66 100644 --- a/sys/applemedia/dynapi.c +++ b/sys/applemedia/dynapi.c @@ -142,9 +142,10 @@ _gst_dyn_api_new (GType derived_type, const gchar * filename, names_not_found = g_array_new (TRUE, FALSE, sizeof (gchar *)); for (i = 0; symbols[i].name != NULL; i++) { - if (!g_module_symbol (priv->module, symbols[i].name, - (gpointer *) (((guint8 *) api) + symbols[i].offset))) { - g_array_append_val (names_not_found, symbols[i].name); + const GstDynSymSpec *s = &symbols[i]; + if (!g_module_symbol (priv->module, s->name, + (gpointer *) (((guint8 *) api) + s->offset)) && s->is_required) { + g_array_append_val (names_not_found, s->name); } } diff --git a/sys/applemedia/dynapi.h b/sys/applemedia/dynapi.h index 2b125ba8c..4be83b2c0 100644 --- a/sys/applemedia/dynapi.h +++ b/sys/applemedia/dynapi.h @@ -38,7 +38,9 @@ G_BEGIN_DECLS (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DYN_API)) #define GST_DYN_SYM_SPEC(type, name) \ - { G_STRINGIFY (name), G_STRUCT_OFFSET (type, name) } + { G_STRINGIFY (name), G_STRUCT_OFFSET (type, name), TRUE } +#define GST_DYN_SYM_SPEC_OPTIONAL(type, name) \ + { G_STRINGIFY (name), G_STRUCT_OFFSET (type, name), FALSE } typedef struct _GstDynApi GstDynApi; typedef struct _GstDynApiClass GstDynApiClass; diff --git a/sys/applemedia/miovideosrc.c b/sys/applemedia/miovideosrc.c index a2d1fa6be..7b0e428c4 100644 --- a/sys/applemedia/miovideosrc.c +++ b/sys/applemedia/miovideosrc.c @@ -83,8 +83,6 @@ static void gst_mio_video_src_probe_interface_init (gpointer g_iface, static void gst_mio_video_src_init_interfaces (GType type); -static GstPushSrcClass *parent_class; - GST_BOILERPLATE_FULL (GstMIOVideoSrc, gst_mio_video_src, GstPushSrc, GST_TYPE_PUSH_SRC, gst_mio_video_src_init_interfaces); diff --git a/sys/applemedia/qtkitvideosrc.m b/sys/applemedia/qtkitvideosrc.m index 7e2ceefd3..67388f051 100644 --- a/sys/applemedia/qtkitvideosrc.m +++ b/sys/applemedia/qtkitvideosrc.m @@ -86,7 +86,8 @@ typedef enum _QueueState { HAS_FRAME_OR_STOP_REQUEST, } QueueState; -static GstPushSrcClass * parent_class; +GST_BOILERPLATE (GstQTKitVideoSrc, gst_qtkit_video_src, GstPushSrc, + GST_TYPE_PUSH_SRC); @interface GstQTKitVideoSrcImpl : NSObject { GstElement *element; @@ -241,9 +242,12 @@ openFailed: GstStructure *s; NSDictionary *outputAttrs; BOOL success; + NSRunLoop *mainRunLoop; g_assert (device != nil); + GST_INFO ("setting up session"); + s = gst_caps_get_structure (caps, 0); gst_structure_get_int (s, "width", &width); gst_structure_get_int (s, "height", &height); @@ -276,6 +280,16 @@ openFailed: [output setDelegate:self]; [session startRunning]; + mainRunLoop = [NSRunLoop mainRunLoop]; + if ([mainRunLoop currentMode] == nil) { + /* QTCaptureSession::addInput and QTCaptureSession::addOutput call + * NSObject::performSelectorOnMainThread internally. If the mainRunLoop is + * not running we need to run it for a while for those methods to complete + */ + GST_INFO ("mainRunLoop not running"); + [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]]; + } + return YES; } @@ -340,7 +354,7 @@ openFailed: { [queueLock lock]; stopRequest = NO; - [queueLock unlock]; + [queueLock unlockWithCondition:NO_FRAMES]; return YES; } @@ -374,6 +388,8 @@ openFailed: return; } + GST_INFO ("got new frame"); + if ([queue count] == FRAME_QUEUE_SIZE) [queue removeLastObject]; @@ -451,9 +467,6 @@ enum PROP_DEVICE_INDEX }; -GST_BOILERPLATE (GstQTKitVideoSrc, gst_qtkit_video_src, GstPushSrc, - GST_TYPE_PUSH_SRC); - static void gst_qtkit_video_src_finalize (GObject * obj); static void gst_qtkit_video_src_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); diff --git a/sys/applemedia/vtdec.c b/sys/applemedia/vtdec.c index eb5d2f1ac..22db2e869 100644 --- a/sys/applemedia/vtdec.c +++ b/sys/applemedia/vtdec.c @@ -45,7 +45,7 @@ static VTDecompressionSessionRef gst_vtdec_create_session (GstVTDec * self, static void gst_vtdec_destroy_session (GstVTDec * self, VTDecompressionSessionRef * session); static GstFlowReturn gst_vtdec_decode_buffer (GstVTDec * self, GstBuffer * buf); -static void gst_vtdec_output_frame (void *data, gsize unk1, VTStatus result, +static void gst_vtdec_enqueue_frame (void *data, gsize unk1, VTStatus result, gsize unk2, CVBufferRef cvbuf); static CMSampleBufferRef gst_vtdec_sample_buffer_from (GstVTDec * self, @@ -358,7 +358,7 @@ gst_vtdec_create_session (GstVTDec * self, CMFormatDescriptionRef fmt_desc) gst_vtutil_dict_set_i32 (pb_attrs, *(cv->kCVPixelBufferBytesPerRowAlignmentKey), 2 * self->negotiated_width); - callback.func = gst_vtdec_output_frame; + callback.func = gst_vtdec_enqueue_frame; callback.data = self; status = self->ctx->vt->VTDecompressionSessionCreate (NULL, fmt_desc, @@ -407,13 +407,20 @@ gst_vtdec_decode_buffer (GstVTDec * self, GstBuffer * buf) self->cur_inbuf = NULL; gst_buffer_unref (buf); + if (self->cur_outbufs->len > 0) { + if (!gst_vtdec_negotiate_downstream (self)) + ret = GST_FLOW_NOT_NEGOTIATED; + } + for (i = 0; i != self->cur_outbufs->len; i++) { GstBuffer *buf = g_ptr_array_index (self->cur_outbufs, i); - if (ret == GST_FLOW_OK) + if (ret == GST_FLOW_OK) { + gst_buffer_set_caps (buf, GST_PAD_CAPS (self->srcpad)); ret = gst_pad_push (self->srcpad, buf); - else + } else { gst_buffer_unref (buf); + } } g_ptr_array_set_size (self->cur_outbufs, 0); @@ -421,7 +428,7 @@ gst_vtdec_decode_buffer (GstVTDec * self, GstBuffer * buf) } static void -gst_vtdec_output_frame (void *data, gsize unk1, VTStatus result, gsize unk2, +gst_vtdec_enqueue_frame (void *data, gsize unk1, VTStatus result, gsize unk2, CVBufferRef cvbuf) { GstVTDec *self = GST_VTDEC_CAST (data); @@ -430,11 +437,7 @@ gst_vtdec_output_frame (void *data, gsize unk1, VTStatus result, gsize unk2, if (result != kVTSuccess) goto beach; - if (!gst_vtdec_negotiate_downstream (self)) - goto beach; - buf = gst_core_video_buffer_new (self->ctx, cvbuf); - gst_buffer_set_caps (buf, GST_PAD_CAPS (self->srcpad)); gst_buffer_copy_metadata (buf, self->cur_inbuf, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS); diff --git a/sys/applemedia/vtenc.c b/sys/applemedia/vtenc.c index 43a16229e..c7878482c 100644 --- a/sys/applemedia/vtenc.c +++ b/sys/applemedia/vtenc.c @@ -77,7 +77,7 @@ static VTStatus gst_vtenc_session_configure_property_double (GstVTEnc * self, VTCompressionSessionRef session, CFStringRef name, gdouble value); static GstFlowReturn gst_vtenc_encode_frame (GstVTEnc * self, GstBuffer * buf); -static VTStatus gst_vtenc_output_buffer (void *data, int a2, int a3, int a4, +static VTStatus gst_vtenc_enqueue_buffer (void *data, int a2, int a3, int a4, CMSampleBufferRef sbuf, int a6, int a7); static gboolean gst_vtenc_buffer_is_keyframe (GstVTEnc * self, CMSampleBufferRef sbuf); @@ -411,9 +411,7 @@ gst_vtenc_negotiate_downstream (GstVTEnc * self, CMSampleBufferRef sbuf) gst_buffer_unref (codec_data); } - GST_OBJECT_UNLOCK (self); result = gst_pad_set_caps (self->srcpad, caps); - GST_OBJECT_LOCK (self); gst_caps_unref (caps); @@ -502,7 +500,7 @@ gst_vtenc_create_session (GstVTEnc * self) gst_vtutil_dict_set_i32 (pb_attrs, *(cv->kCVPixelBufferHeightKey), self->negotiated_height); - callback.func = gst_vtenc_output_buffer; + callback.func = gst_vtenc_enqueue_buffer; callback.data = self; status = vt->VTCompressionSessionCreate (NULL, @@ -770,13 +768,22 @@ gst_vtenc_encode_frame (GstVTEnc * self, GstBuffer * buf) self->cur_inbuf = NULL; gst_buffer_unref (buf); + if (self->cur_outbufs->len > 0) { + GstCoreMediaBuffer *cmbuf = + GST_CORE_MEDIA_BUFFER_CAST (g_ptr_array_index (self->cur_outbufs, 0)); + if (!gst_vtenc_negotiate_downstream (self, cmbuf->sample_buf)) + ret = GST_FLOW_NOT_NEGOTIATED; + } + for (i = 0; i != self->cur_outbufs->len; i++) { GstBuffer *buf = g_ptr_array_index (self->cur_outbufs, i); - if (ret == GST_FLOW_OK) + if (ret == GST_FLOW_OK) { + gst_buffer_set_caps (buf, GST_PAD_CAPS (self->srcpad)); ret = gst_pad_push (self->srcpad, buf); - else + } else { gst_buffer_unref (buf); + } } g_ptr_array_set_size (self->cur_outbufs, 0); @@ -792,7 +799,7 @@ cv_error: } static VTStatus -gst_vtenc_output_buffer (void *data, int a2, int a3, int a4, +gst_vtenc_enqueue_buffer (void *data, int a2, int a3, int a4, CMSampleBufferRef sbuf, int a6, int a7) { GstVTEnc *self = data; @@ -812,11 +819,7 @@ gst_vtenc_output_buffer (void *data, int a2, int a3, int a4, } self->expect_keyframe = FALSE; - if (!gst_vtenc_negotiate_downstream (self, sbuf)) - goto beach; - buf = gst_core_media_buffer_new (self->ctx, sbuf); - gst_buffer_set_caps (buf, GST_PAD_CAPS (self->srcpad)); gst_buffer_copy_metadata (buf, self->cur_inbuf, GST_BUFFER_COPY_TIMESTAMPS); if (is_keyframe) { GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); diff --git a/sys/directdraw/gstdirectdrawsink.c b/sys/directdraw/gstdirectdrawsink.c index 15f79d12a..05c81367a 100644 --- a/sys/directdraw/gstdirectdrawsink.c +++ b/sys/directdraw/gstdirectdrawsink.c @@ -821,9 +821,11 @@ gst_directdraw_sink_draw_borders (GstDirectDrawSink * ddrawsink, RECT dst_rect) OffsetRect (&win_rect, win_point.x, win_point.y); /* We acquire a drawing context */ - if (IDirectDrawSurface7_GetDC (ddrawsink->primary_surface, &hdc) == DD_OK) { + if ((hdc = GetDC (ddrawsink->video_window))) { HBRUSH brush = CreateSolidBrush (RGB (0, 0, 0)); + /* arrange for logical coordinates that match screen coordinates */ + SetWindowOrgEx (hdc, win_point.x, win_point.y, NULL); /* Left border */ if (dst_rect.left > win_rect.left) { fill_rect.left = win_rect.left; @@ -857,7 +859,7 @@ gst_directdraw_sink_draw_borders (GstDirectDrawSink * ddrawsink, RECT dst_rect) FillRect (hdc, &fill_rect, brush); } DeleteObject (brush); - IDirectDrawSurface7_ReleaseDC (ddrawsink->primary_surface, hdc); + ReleaseDC (ddrawsink->video_window, hdc); } } @@ -904,6 +906,19 @@ gst_directdraw_sink_show_frame (GstBaseSink * bsink, GstBuffer * buf) GetClientRect (ddrawsink->video_window, &destsurf_rect); OffsetRect (&destsurf_rect, dest_surf_point.x, dest_surf_point.y); + /* Check to see if we have an area to draw to. + * When the window is minimized, it will trigger the + * "IDirectDrawSurface7_Blt (object's offscreen surface)" warning, + * with a msg that the rectangle is invalid */ + if (destsurf_rect.right <= destsurf_rect.left || + destsurf_rect.bottom <= destsurf_rect.top) { + GST_OBJECT_UNLOCK (ddrawsink); + GST_DEBUG_OBJECT (ddrawsink, "invalid rendering window rectangle " + "(%ld, %ld), (%ld, %ld)", destsurf_rect.left, destsurf_rect.top, + destsurf_rect.right, destsurf_rect.bottom); + goto beach; + } + if (ddrawsink->keep_aspect_ratio) { /* center image to dest image keeping aspect ratio */ src_rect.top = 0; @@ -1004,6 +1019,7 @@ gst_directdraw_sink_show_frame (GstBaseSink * bsink, GstBuffer * buf) "returned %s", DDErrorString (hRes)); } +beach: return GST_FLOW_OK; } diff --git a/sys/dvb/README b/sys/dvb/README index 39bc052f6..1329da99b 100644 --- a/sys/dvb/README +++ b/sys/dvb/README @@ -5,10 +5,10 @@ GstDvbSrc makes it possible to view Digital TV with gstreamer. Try: - gst-launch dvbsrc freq=11954 pol=h srate=27500 pids=210:220 - ! flutsdemux es-pids=210:220 name=demux ! queue ! mpeg2dec ! - xvimagesink } - demux. ! queue ! mad ! osssink + gst-launch dvbsrc frequency=11954 polarity=h symbol-rate=27500 pids=210:220 + ! mpegtsdemux es-pids=210:220 name=demux ! queue ! mpeg2dec + ! xvimagesink demux. ! queue ! mad ! audioconvert ! autoaudiosink + diff --git a/sys/dvb/camswclient.c b/sys/dvb/camswclient.c index b68b0a7b8..98781f3a9 100644 --- a/sys/dvb/camswclient.c +++ b/sys/dvb/camswclient.c @@ -25,6 +25,8 @@ #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> +#include <stdio.h> +#include <string.h> #include <gst/gst.h> @@ -78,7 +80,7 @@ cam_sw_client_open (CamSwClient * client, const char *sock_path) g_return_val_if_fail (sock_path != NULL, FALSE); addr.sun_family = AF_UNIX; - strncpy (addr.sun_path, sock_path, UNIX_PATH_MAX); + strncpy (addr.sun_path, sock_path, sizeof (addr.sun_path)); GST_INFO ("connecting to softcam socket: %s", sock_path); client->sock = socket (PF_UNIX, SOCK_STREAM, 0); diff --git a/sys/dvb/gstdvbsrc.c b/sys/dvb/gstdvbsrc.c index bce25f69b..2f18431ad 100644 --- a/sys/dvb/gstdvbsrc.c +++ b/sys/dvb/gstdvbsrc.c @@ -45,7 +45,6 @@ #include <sys/ioctl.h> #include <sys/poll.h> #include <fcntl.h> -#include <error.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> @@ -118,7 +117,7 @@ gst_dvbsrc_code_rate_get_type (void) { static GType dvbsrc_code_rate_type = 0; static GEnumValue code_rate_types[] = { - {FEC_NONE, "NONE", "NONE"}, + {FEC_NONE, "NONE", "none"}, {FEC_1_2, "1/2", "1/2"}, {FEC_2_3, "2/3", "2/3"}, {FEC_3_4, "3/4", "3/4"}, @@ -127,7 +126,7 @@ gst_dvbsrc_code_rate_get_type (void) {FEC_6_7, "6/7", "6/7"}, {FEC_7_8, "7/8", "7/8"}, {FEC_8_9, "8/9", "8/9"}, - {FEC_AUTO, "AUTO", ""}, + {FEC_AUTO, "AUTO", "auto"}, {0, NULL, NULL}, }; @@ -144,15 +143,15 @@ gst_dvbsrc_modulation_get_type (void) { static GType dvbsrc_modulation_type = 0; static GEnumValue modulation_types[] = { - {QPSK, "QPSK", "QPSK"}, - {QAM_16, "QAM 16", "QAM 16"}, - {QAM_32, "QAM 32", "QAM 32"}, - {QAM_64, "QAM 64", "QAM 64"}, - {QAM_128, "QAM 128", "QAM 128"}, - {QAM_256, "QAM 256", "QAM 256"}, - {QAM_AUTO, "AUTO", "AUTO"}, - {VSB_8, "8VSB", "8VSB"}, - {VSB_16, "16VSB", "16VSB"}, + {QPSK, "QPSK", "qpsk"}, + {QAM_16, "QAM 16", "qam-16"}, + {QAM_32, "QAM 32", "qam-32"}, + {QAM_64, "QAM 64", "qam-64"}, + {QAM_128, "QAM 128", "qam-128"}, + {QAM_256, "QAM 256", "qam-256"}, + {QAM_AUTO, "AUTO", "auto"}, + {VSB_8, "8VSB", "8vsb"}, + {VSB_16, "16VSB", "16vsb"}, {0, NULL, NULL}, }; @@ -169,9 +168,9 @@ gst_dvbsrc_transmission_mode_get_type (void) { static GType dvbsrc_transmission_mode_type = 0; static GEnumValue transmission_mode_types[] = { - {TRANSMISSION_MODE_2K, "2k", "2k"}, - {TRANSMISSION_MODE_8K, "8k", "8k"}, - {TRANSMISSION_MODE_AUTO, "AUTO", "AUTO"}, + {TRANSMISSION_MODE_2K, "2K", "2k"}, + {TRANSMISSION_MODE_8K, "8K", "8k"}, + {TRANSMISSION_MODE_AUTO, "AUTO", "auto"}, {0, NULL, NULL}, }; @@ -213,7 +212,7 @@ gst_dvbsrc_guard_get_type (void) {GUARD_INTERVAL_1_16, "16", "16"}, {GUARD_INTERVAL_1_8, "8", "8"}, {GUARD_INTERVAL_1_4, "4", "4"}, - {GUARD_INTERVAL_AUTO, "AUTO", "AUTO"}, + {GUARD_INTERVAL_AUTO, "AUTO", "auto"}, {0, NULL, NULL}, }; @@ -229,11 +228,11 @@ gst_dvbsrc_hierarchy_get_type (void) { static GType dvbsrc_hierarchy_type = 0; static GEnumValue hierarchy_types[] = { - {HIERARCHY_NONE, "NONE", "NONE"}, + {HIERARCHY_NONE, "NONE", "none"}, {HIERARCHY_1, "1", "1"}, {HIERARCHY_2, "2", "2"}, {HIERARCHY_4, "4", "4"}, - {HIERARCHY_AUTO, "AUTO", "AUTO"}, + {HIERARCHY_AUTO, "AUTO", "auto"}, {0, NULL, NULL}, }; @@ -250,9 +249,9 @@ gst_dvbsrc_inversion_get_type (void) { static GType dvbsrc_inversion_type = 0; static GEnumValue inversion_types[] = { - {INVERSION_OFF, "OFF", "OFF"}, - {INVERSION_ON, "ON", "ON"}, - {INVERSION_AUTO, "AUTO", "AUTO"}, + {INVERSION_OFF, "OFF", "off"}, + {INVERSION_ON, "ON", "on"}, + {INVERSION_AUTO, "AUTO", "auto"}, {0, NULL, NULL}, }; diff --git a/sys/vdpau/gstvdpvideopostprocess.c b/sys/vdpau/gstvdpvideopostprocess.c index 1091c0e8c..0b6f33870 100644 --- a/sys/vdpau/gstvdpvideopostprocess.c +++ b/sys/vdpau/gstvdpvideopostprocess.c @@ -248,6 +248,9 @@ gst_vdp_vpp_get_required_pictures (GstVdpVideoPostProcess * vpp) case GST_VDP_DEINTERLACE_METHOD_TEMPORAL_SPATIAL: ret = 2; break; + default: + g_assert_not_reached (); + break; } return ret; diff --git a/sys/vdpau/h264/gstvdph264dec.c b/sys/vdpau/h264/gstvdph264dec.c index 2a237b150..4abc00961 100644 --- a/sys/vdpau/h264/gstvdph264dec.c +++ b/sys/vdpau/h264/gstvdph264dec.c @@ -168,8 +168,7 @@ gst_vdp_h264_dec_calculate_poc (GstVdpH264Dec * h264_dec, GstH264Slice * slice) { GstH264Picture *pic; GstH264Sequence *seq; - - guint poc; + guint poc = 0; pic = slice->picture; seq = pic->sequence; diff --git a/sys/winks/ksvideohelpers.c b/sys/winks/ksvideohelpers.c index 8399762e6..1772e5bcc 100644 --- a/sys/winks/ksvideohelpers.c +++ b/sys/winks/ksvideohelpers.c @@ -309,6 +309,7 @@ ks_video_append_video_stream_cfg_fields (GstStructure * structure, const KS_VIDEO_STREAM_CONFIG_CAPS * vscc) { GValue val = { 0, }; + gint64 min_n, min_d; gint64 max_n, max_d; g_return_val_if_fail (structure, FALSE); @@ -335,16 +336,13 @@ ks_video_append_video_stream_cfg_fields (GstStructure * structure, } /* framerate */ + compress_fraction (NANOSECONDS, vscc->MinFrameInterval, &min_n, &min_d); compress_fraction (NANOSECONDS, vscc->MaxFrameInterval, &max_n, &max_d); - if (vscc->MinFrameInterval == vscc->MaxFrameInterval) { + if (min_n == max_n && min_d == max_d) { g_value_init (&val, GST_TYPE_FRACTION); gst_value_set_fraction (&val, max_n, max_d); } else { - gint64 min_n, min_d; - - compress_fraction (NANOSECONDS, vscc->MinFrameInterval, &min_n, &min_d); - g_value_init (&val, GST_TYPE_FRACTION_RANGE); gst_value_set_fraction_range_full (&val, max_n, max_d, min_n, min_d); } diff --git a/sys/winscreencap/gstgdiscreencapsrc.c b/sys/winscreencap/gstgdiscreencapsrc.c index 3ead8a9a4..ff9ea7b72 100644 --- a/sys/winscreencap/gstgdiscreencapsrc.c +++ b/sys/winscreencap/gstgdiscreencapsrc.c @@ -541,12 +541,16 @@ gst_gdiscreencapsrc_screen_capture (GstGDIScreenCapSrc * src, GstBuffer * buf) GetCursorInfo (&ci); if (ci.flags & CURSOR_SHOWING) { ICONINFO ii; + GetIconInfo (ci.hCursor, &ii); DrawIconEx (src->memDC, ci.ptScreenPos.x - src->src_rect.left - ii.xHotspot, ci.ptScreenPos.y - src->src_rect.top - ii.yHotspot, ci.hCursor, 0, 0, 0, NULL, DI_DEFAULTSIZE | DI_NORMAL | DI_COMPAT); + + DeleteObject (ii.hbmColor); + DeleteObject (ii.hbmMask); } } diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 695af1189..9de5de291 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -14,7 +14,7 @@ TESTS_ENVIRONMENT = \ GST_PLUGIN_SYSTEM_PATH= \ GST_PLUGIN_PATH=$(top_builddir)/gst:$(top_builddir)/sys:$(top_builddir)/ext:$(GST_PLUGINS_FFMPEG_DIR):$(GST_PLUGINS_UGLY_DIR):$(GST_PLUGINS_GOOD_DIR):$(GST_PLUGINS_BASE_DIR):$(GST_PLUGINS_DIR) \ GST_PLUGIN_LOADING_WHITELIST="gstreamer@$(GST_PLUGINS_DIR):gst-plugins-base@$(GSTPB_PLUGINS_DIR):gst-plugins-good:gst-plugins-ugly:gst-ffmpeg:gst-plugins-bad@$(top_builddir)" \ - GST_STATE_IGNORE_ELEMENTS="apexsink camerabin cdaudio dc1394src dccpclientsrc dccpclientsink dccpserversrc dccpserversink dvbsrc dvbbasebin dfbvideosink festival gsettingsvideosrc gsettingsvideosink gsettingsaudiosrc gsettingsaudiosink nassink rsndvdbin sdlaudiosink sdlvideosink vcdsrc rfbsrc vdpauyuvvideo vdpauvideoyuv vdpaumpegdec neonhttpsrc" + GST_STATE_IGNORE_ELEMENTS="apexsink camerabin camerabin2 cdaudio dc1394src dccpclientsrc dccpclientsink dccpserversrc dccpserversink dvbsrc dvbbasebin dfbvideosink festival gsettingsvideosrc gsettingsvideosink gsettingsaudiosrc gsettingsaudiosink nassink rsndvdbin sdlaudiosink sdlvideosink vcdsrc rfbsrc vdpauyuvvideo vdpauvideoyuv vdpaumpegdec vdpaumpeg4dec vdpauh264dec vdpauvideopostprocess vdpausink neonhttpsrc" plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@ @@ -127,6 +127,12 @@ VALGRIND_TO_FIX = \ VALGRIND_TESTS_DISABLE = \ $(VALGRIND_TO_FIX) +if BUILD_EXPERIMENTAL +EXPERIMENTAL_CHECKS=elements/camerabin2 \ + elements/imagecapturebin \ + elements/viewfinderbin +endif + # these tests don't even pass # neon: too flaky (almost always fails 'the first time') noinst_PROGRAMS = \ @@ -146,6 +152,7 @@ check_PROGRAMS = \ elements/ac3parse \ elements/amrparse \ elements/autoconvert \ + elements/autovideoconvert \ elements/asfmux \ elements/camerabin \ elements/dataurisrc \ @@ -154,7 +161,6 @@ check_PROGRAMS = \ $(check_jifmux) \ elements/jpegparse \ elements/qtmux \ - elements/selector \ elements/mxfdemux \ elements/mxfmux \ elements/id3mux \ @@ -163,34 +169,53 @@ check_PROGRAMS = \ $(check_mimic) \ elements/rtpmux \ $(check_schro) \ - elements/valve \ $(check_vp8) \ $(check_zbar) \ $(check_orc) \ - pipelines/tagschecking + pipelines/tagschecking \ + $(EXPERIMENTAL_CHECKS) noinst_HEADERS = elements/mxfdemux.h TESTS = $(check_PROGRAMS) AM_CFLAGS = $(GST_CHECK_CFLAGS) $(GST_OPTION_CFLAGS) \ - -DGST_TEST_FILES_PATH="\"$(TEST_FILES_DIRECTORY)\"" + -DGST_TEST_FILES_PATH="\"$(TEST_FILES_DIRECTORY)\"" \ + -UG_DISABLE_ASSERT -UG_DISABLE_CAST_CHECKS LDADD = $(GST_CHECK_LIBS) elements_camerabin_CFLAGS = \ - -I$(top_builddir)/gst-libs \ - $(GST_CFLAGS) $(GST_BASE_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \ - $(GST_PLUGINS_BAD_CFLAGS) $(GST_CHECK_CFLAGS) \ - -DGST_USE_UNSTABLE_API + $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS) -DGST_USE_UNSTABLE_API elements_camerabin_LDADD = \ - $(top_builddir)/gst-libs/gst/interfaces/libgstphotography-@GST_MAJORMINOR@.la \ - $(GST_LIBS) $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS) \ - $(GST_CHECK_LIBS) \ - -lgstinterfaces-@GST_MAJORMINOR@ + $(top_builddir)/gst-libs/gst/interfaces/libgstphotography-@GST_MAJORMINOR@.la \ + $(GST_PLUGINS_BASE_LIBS) -lgstinterfaces-@GST_MAJORMINOR@ \ + $(GST_BASE_LIBS) $(GST_LIBS) $(LDADD) + elements_camerabin_SOURCES = elements/camerabin.c -elements_jifmux_CFLAGS = $(GST_CHECK_CFLAGS) $(GST_OPTION_CFLAGS) $(AM_CFLAGS) $(EXIF_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) -elements_jifmux_LDADD = $(GST_CHECK_LIBS) $(EXIF_LIBS) $(LDADD) $(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_MAJORMINOR) +if BUILD_EXPERIMENTAL +elements_camerabin2_CFLAGS = \ + $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS) -DGST_USE_UNSTABLE_API +elements_camerabin2_LDADD = \ + $(top_builddir)/gst-libs/gst/interfaces/libgstphotography-@GST_MAJORMINOR@.la \ + $(top_builddir)/gst-libs/gst/basecamerabinsrc/libgstbasecamerabinsrc-@GST_MAJORMINOR@.la \ + -lgstpbutils-$(GST_MAJORMINOR) \ + $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_LIBS) $(LDADD) +elements_camerabin2_SOURCES = elements/camerabin2.c + +elements_imagecapturebin_CFLAGS = \ + $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS) -DGST_USE_UNSTABLE_API +elements_imagecapturebin_LDADD = \ + $(GST_PLUGINS_BASE_LIBS) -lgstapp-@GST_MAJORMINOR@ \ + $(GST_BASE_LIBS) $(GST_LIBS) $(LDADD) +elements_imagecapturebin_SOURCES = elements/imagecapturebin.c +endif + +elements_jifmux_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(EXIF_CFLAGS) $(AM_CFLAGS) +elements_jifmux_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_MAJORMINOR) $(GST_CHECK_LIBS) $(EXIF_LIBS) $(LDADD) elements_jifmux_SOURCES = elements/jifmux.c elements_timidity_CFLAGS = $(GST_BASE_CFLAGS) $(AM_CFLAGS) @@ -200,17 +225,17 @@ elements_kate_CFLAGS = $(GST_BASE_CFLAGS) $(AM_CFLAGS) elements_kate_LDADD = $(GST_BASE_LIBS) $(LDADD) elements_rtpmux_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AM_CFLAGS) -elements_rtpmux_LDADD = $(GST_BASE_LIBS) $(LDADD) -lgstrtp-0.10 - -elements_valve_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AM_CFLAGS) -elements_valve_LDADD = $(GST_BASE_LIBS) $(LDADD) -lgstrtp-0.10 +elements_rtpmux_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstrtp-0.10 $(GST_BASE_LIBS) $(LDADD) elements_assrender_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AM_CFLAGS) -elements_assrender_LDADD = $(GST_BASE_LIBS) $(LDADD) -lgstvideo-0.10 -lgstapp-0.10 +elements_assrender_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-0.10 -lgstapp-0.10 $(GST_BASE_LIBS) $(LDADD) # parser unit test convenience lib noinst_LTLIBRARIES = libparser.la libparser_la_SOURCES = elements/parser.c elements/parser.h +libparser_la_CFLAGS = \ + -I$(top_srcdir)/tests/check \ + $(GST_CHECK_CFLAGS) $(GST_OPTION_CFLAGS) elements_aacparse_LDADD = libparser.la $(LDADD) diff --git a/tests/check/elements/.gitignore b/tests/check/elements/.gitignore index 7c1133db4..8a748233c 100644 --- a/tests/check/elements/.gitignore +++ b/tests/check/elements/.gitignore @@ -5,7 +5,9 @@ amrparse asfmux assrender autoconvert +autovideoconvert camerabin +camerabin2 deinterleave dataurisrc faac @@ -14,6 +16,7 @@ flacparse gdpdepay gdppay id3mux +imagecapturebin interleave jifmux jpegparse @@ -31,11 +34,12 @@ rganalysis rglimiter rgvolume rtpmux -selector +schroenc spectrum timidity y4menc -valve +videorecordingbin +viewfinderbin vp8dec vp8enc zbar diff --git a/tests/check/elements/asfmux.c b/tests/check/elements/asfmux.c index 6c3dab511..abc641f97 100644 --- a/tests/check/elements/asfmux.c +++ b/tests/check/elements/asfmux.c @@ -156,6 +156,7 @@ check_asfmux_pad (GstStaticPadTemplate * srctemplate, GstBuffer *inbuffer; GstCaps *caps; GstFlowReturn ret; + GList *l; asfmux = setup_asfmux (srctemplate, sinkname); fail_unless (gst_element_set_state (asfmux, @@ -172,6 +173,8 @@ check_asfmux_pad (GstStaticPadTemplate * srctemplate, fail_unless (ret == GST_FLOW_OK, "Pad push returned: %d", ret); cleanup_asfmux (asfmux, sinkname); + for (l = buffers; l; l = l->next) + gst_buffer_unref (l->data); g_list_free (buffers); buffers = NULL; } diff --git a/tests/check/elements/autoconvert.c b/tests/check/elements/autoconvert.c index c36247f70..037795378 100644 --- a/tests/check/elements/autoconvert.c +++ b/tests/check/elements/autoconvert.c @@ -20,7 +20,7 @@ */ #ifdef HAVE_CONFIG_H -# include "config.h" +#include "config.h" #endif #include <gst/gst.h> @@ -77,6 +77,8 @@ set_autoconvert_factories (GstElement * autoconvert) } g_object_set (G_OBJECT (autoconvert), "factories", factories, NULL); + + g_list_free (factories); } typedef struct diff --git a/tests/check/elements/autovideoconvert.c b/tests/check/elements/autovideoconvert.c new file mode 100644 index 000000000..c4e9e5105 --- /dev/null +++ b/tests/check/elements/autovideoconvert.c @@ -0,0 +1,139 @@ +/* GStreamer + * + * unit test for autovideoconvert element + * Copyright (C) 2009 Jan Schmidt <thaytan@noraisin.net> + * Copyright (C) 2010 ST-Ericsson SA + * @author: Benjamin Gaignard <benjamin.gaignard@stericsson.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <gst/gst.h> +#include <gst/check/gstcheck.h> + +typedef struct +{ + GMainLoop *loop; + gboolean eos; +} OnMessageUserData; + +static void +on_message_cb (GstBus * bus, GstMessage * message, gpointer user_data) +{ + OnMessageUserData *d = user_data; + + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_ERROR: + case GST_MESSAGE_WARNING: + g_assert_not_reached (); + break; + case GST_MESSAGE_EOS: + g_main_loop_quit (d->loop); + d->eos = TRUE; + break; + default: + break; + } +} + +static void +run_test (const gchar * pipeline_string) +{ + GstElement *pipeline; + GstBus *bus; + GMainLoop *loop; + OnMessageUserData omud = { NULL, }; + GstStateChangeReturn ret; + + GST_DEBUG ("Testing pipeline '%s'", pipeline_string); + + pipeline = gst_parse_launch (pipeline_string, NULL); + fail_unless (pipeline != NULL); + loop = g_main_loop_new (NULL, FALSE); + + bus = gst_element_get_bus (pipeline); + fail_unless (bus != NULL); + gst_bus_add_signal_watch (bus); + + omud.loop = loop; + omud.eos = FALSE; + + g_signal_connect (bus, "message", (GCallback) on_message_cb, &omud); + + gst_object_unref (bus); + + ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); + fail_unless (ret == GST_STATE_CHANGE_SUCCESS + || ret == GST_STATE_CHANGE_ASYNC); + + g_main_loop_run (loop); + + fail_unless (gst_element_set_state (pipeline, + GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS); + + fail_unless (omud.eos == TRUE); + + gst_object_unref (pipeline); + g_main_loop_unref (loop); + +} + +GST_START_TEST (test_autovideoconvert_rbg2bayer) +{ + gchar *pipeline; + + pipeline = + g_strdup_printf + ("videotestsrc num-buffers=1 ! video/x-raw-rgb,bpp=32,depth=32,width=100,height=100,framerate=10/1 ! autovideoconvert ! video/x-raw-bayer,width=100,height=100,format=bggr,framerate=10/1 ! fakesink"); + + run_test (pipeline); + g_free (pipeline); +} + +GST_END_TEST; + +GST_START_TEST (test_autovideoconvert_ffmpegcolorspace) +{ + gchar *pipeline; + + pipeline = + g_strdup_printf + ("videotestsrc num-buffers=1 ! video/x-raw-rgb,bpp=32,width=100,height=100,framerate=10/1 ! autovideoconvert ! video/x-raw-rgb,bpp=16,width=100,height=100,framerate=10/1 ! fakesink"); + + run_test (pipeline); + g_free (pipeline); +} + +GST_END_TEST; + +static Suite * +autovideoconvert_suite (void) +{ + Suite *s = suite_create ("autovideoconvert"); + TCase *tc_basic = tcase_create ("general"); + + suite_add_tcase (s, tc_basic); + tcase_add_test (tc_basic, test_autovideoconvert_rbg2bayer); + tcase_add_test (tc_basic, test_autovideoconvert_ffmpegcolorspace); + + return s; +} + +GST_CHECK_MAIN (autovideoconvert); diff --git a/tests/check/elements/camerabin.c b/tests/check/elements/camerabin.c index f5dbfdc03..0df4f9b5b 100644 --- a/tests/check/elements/camerabin.c +++ b/tests/check/elements/camerabin.c @@ -579,6 +579,7 @@ GST_START_TEST (test_video_recording) /* Set preview-caps */ g_object_set (camera, "preview-caps", preview_caps, NULL); + gst_caps_unref (preview_caps); /* check that the camera is idle */ g_object_get (camera, "idle", &idle, NULL); @@ -626,6 +627,7 @@ GST_START_TEST (test_video_recording_with_flags) /* Set preview-caps */ g_object_set (camera, "preview-caps", preview_caps, NULL); + gst_caps_unref (preview_caps); GST_INFO ("starting capture"); g_signal_emit_by_name (camera, "capture-start", NULL); @@ -712,6 +714,7 @@ GST_START_TEST (test_video_recording_no_audio) /* Set preview-caps */ g_object_set (camera, "preview-caps", preview_caps, NULL); + gst_caps_unref (preview_caps); GST_INFO ("starting capture"); g_signal_emit_by_name (camera, "capture-start", NULL); diff --git a/tests/check/elements/camerabin2.c b/tests/check/elements/camerabin2.c new file mode 100644 index 000000000..53e6ccc17 --- /dev/null +++ b/tests/check/elements/camerabin2.c @@ -0,0 +1,1196 @@ +/* GStreamer + * + * unit test for camerabin2 basic operations + * Copyright (C) 2010 Nokia Corporation <multimedia@maemo.org> + * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <unistd.h> +#include <glib.h> +#include <gst/gst.h> +#include <gst/video/video.h> +#include <gst/check/gstcheck.h> +#include <gst/basecamerabinsrc/gstbasecamerasrc.h> +#include <gst/pbutils/encoding-profile.h> + +#define IMAGE_FILENAME "image" +#define VIDEO_FILENAME "video" +#define CAPTURE_COUNT 3 +#define VIDEO_DURATION 5 + +#define VIDEO_PAD_SUPPORTED_CAPS GST_VIDEO_CAPS_RGB ", width=600, height=480" +#define IMAGE_PAD_SUPPORTED_CAPS GST_VIDEO_CAPS_RGB ", width=800, height=600" + +/* custom test camera src element */ +#define GST_TYPE_TEST_CAMERA_SRC \ + (gst_test_camera_src_get_type()) +#define GST_TEST_CAMERA_SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TEST_CAMERA_SRC,GstTestCameraSrc)) +#define GST_TEST_CAMERA_SRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TEST_CAMERA_SRC,GstTestCameraSrcClass)) +#define GST_IS_TEST_REVERSE_NEGOTIATION_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TEST_CAMERA_SRC)) +#define GST_IS_TEST_REVERSE_NEGOTIATION_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TEST_CAMERA_SRC)) +#define GST_TEST_CAMERA_SRC_CAST(obj) ((GstTestCameraSrc *)obj) + +typedef struct _GstTestCameraSrc GstTestCameraSrc; +typedef struct _GstTestCameraSrcClass GstTestCameraSrcClass; +struct _GstTestCameraSrc +{ + GstBaseCameraSrc element; + + GstPad *vfpad; + GstPad *vidpad; + GstPad *imgpad; + + GstCameraBinMode mode; +}; + +struct _GstTestCameraSrcClass +{ + GstBaseCameraSrcClass parent_class; +}; + +GType gst_test_camera_src_get_type (void); + +GST_BOILERPLATE (GstTestCameraSrc, + gst_test_camera_src, GstBaseCameraSrc, GST_TYPE_BASE_CAMERA_SRC); + +static gboolean +gst_test_camera_src_set_mode (GstBaseCameraSrc * src, GstCameraBinMode mode) +{ + GstTestCameraSrc *self = GST_TEST_CAMERA_SRC (src); + + self->mode = mode; + return TRUE; +} + +static GstCaps * +gst_test_camera_src_get_caps (GstPad * pad) +{ + GstTestCameraSrc *self = (GstTestCameraSrc *) GST_PAD_PARENT (pad); + GstCaps *result = NULL; + + if (pad == self->vfpad) { + result = gst_caps_new_any (); + } else if (pad == self->vidpad) { + result = gst_caps_from_string (VIDEO_PAD_SUPPORTED_CAPS); + } else if (pad == self->imgpad) { + result = gst_caps_from_string (IMAGE_PAD_SUPPORTED_CAPS); + } else { + g_assert_not_reached (); + } + + return result; +} + +static void +gst_test_camera_src_base_init (gpointer g_class) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_set_details_simple (gstelement_class, + "Test Camera Src", + "Camera/Src", + "Some test camera src", + "Thiago Santos <thiago.sousa.santos@collabora.co.uk>"); +} + +static void +gst_test_camera_src_class_init (GstTestCameraSrcClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseCameraSrcClass *gstbasecamera_class; + + gobject_class = G_OBJECT_CLASS (klass); + gstelement_class = GST_ELEMENT_CLASS (klass); + gstbasecamera_class = GST_BASE_CAMERA_SRC_CLASS (klass); + + gstbasecamera_class->set_mode = gst_test_camera_src_set_mode; +} + +static void +gst_test_camera_src_init (GstTestCameraSrc * self, + GstTestCameraSrcClass * g_class) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); + GstPadTemplate *template; + + /* create pads */ + template = gst_element_class_get_pad_template (gstelement_class, + GST_BASE_CAMERA_SRC_VIEWFINDER_PAD_NAME); + self->vfpad = gst_pad_new_from_template (template, + GST_BASE_CAMERA_SRC_VIEWFINDER_PAD_NAME); + gst_element_add_pad (GST_ELEMENT_CAST (self), self->vfpad); + + template = gst_element_class_get_pad_template (gstelement_class, + GST_BASE_CAMERA_SRC_IMAGE_PAD_NAME); + self->imgpad = gst_pad_new_from_template (template, + GST_BASE_CAMERA_SRC_IMAGE_PAD_NAME); + gst_element_add_pad (GST_ELEMENT_CAST (self), self->imgpad); + + template = gst_element_class_get_pad_template (gstelement_class, + GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME); + self->vidpad = gst_pad_new_from_template (template, + GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME); + gst_element_add_pad (GST_ELEMENT_CAST (self), self->vidpad); + + /* add get caps functions */ + gst_pad_set_getcaps_function (self->vfpad, gst_test_camera_src_get_caps); + gst_pad_set_getcaps_function (self->vidpad, gst_test_camera_src_get_caps); + gst_pad_set_getcaps_function (self->imgpad, gst_test_camera_src_get_caps); +} + +/* end of custom test camera src element */ + + +static GstElement *camera; +static GMainLoop *main_loop; +guint32 test_id = 0; + +static GstBuffer *preview_buffer; +static GstCaps *preview_caps; +static GstTagList *tags_found; + +static gboolean +validity_bus_cb (GstBus * bus, GstMessage * message, gpointer data); + +static void +validate_taglist_foreach (const GstTagList * list, const gchar * tag, + gpointer user_data) +{ + GstTagList *other = GST_TAG_LIST (user_data); + + const GValue *val1 = gst_tag_list_get_value_index (list, tag, 0); + const GValue *val2 = gst_tag_list_get_value_index (other, tag, 0); + + fail_if (val1 == NULL); + fail_if (val2 == NULL); + + fail_unless (gst_value_can_intersect (val1, val2)); +} + + +/* helper function for filenames */ +static const gchar * +make_test_file_name (const gchar * base_name, gint num) +{ + static gchar file_name[1000]; + + /* num == -1 means to keep the %d in the resulting string to be used on + * multifilesink like location */ + if (num == -1) { + g_snprintf (file_name, 999, "%s" G_DIR_SEPARATOR_S + "gstcamerabin2test_%s_%u_%%03d.cap", g_get_tmp_dir (), base_name, + test_id); + } else { + g_snprintf (file_name, 999, "%s" G_DIR_SEPARATOR_S + "gstcamerabin2test_%s_%u_%03d.cap", g_get_tmp_dir (), base_name, + test_id, num); + } + + GST_INFO ("capturing to: %s", file_name); + return file_name; +} + +/* configuration */ + +static gboolean +capture_bus_cb (GstBus * bus, GstMessage * message, gpointer data) +{ + GMainLoop *loop = (GMainLoop *) data; + const GstStructure *st; + + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_ERROR:{ + GError *err = NULL; + gchar *debug = NULL; + + gst_message_parse_error (message, &err, &debug); + GST_WARNING ("ERROR: %s [%s]", err->message, debug); + g_error_free (err); + g_free (debug); + /* Write debug graph to file */ + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (camera), + GST_DEBUG_GRAPH_SHOW_ALL, "camerabin.error"); + + fail_if (TRUE, "error while capturing"); + g_main_loop_quit (loop); + break; + } + case GST_MESSAGE_WARNING:{ + GError *err = NULL; + gchar *debug = NULL; + + gst_message_parse_warning (message, &err, &debug); + GST_WARNING ("WARNING: %s [%s]", err->message, debug); + g_error_free (err); + g_free (debug); + /* Write debug graph to file */ + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (camera), + GST_DEBUG_GRAPH_SHOW_ALL, "camerabin.warning"); + break; + } + case GST_MESSAGE_EOS: + GST_DEBUG ("eos"); + g_main_loop_quit (loop); + break; + default: + st = gst_message_get_structure (message); + if (st && gst_structure_has_name (st, "image-captured")) { + gboolean ready = FALSE; + GST_INFO ("image captured"); + g_object_get (camera, "ready-for-capture", &ready, NULL); + fail_if (!ready, "not ready for capture"); + } else if (st && gst_structure_has_name (st, + GST_BASE_CAMERA_SRC_PREVIEW_MESSAGE_NAME)) { + GstBuffer *buf; + const GValue *value; + + value = gst_structure_get_value (st, "buffer"); + fail_unless (value != NULL); + buf = gst_value_get_buffer (value); + + if (preview_buffer) + gst_buffer_unref (preview_buffer); + preview_buffer = gst_buffer_ref (buf); + } + break; + } + return TRUE; +} + +static void +check_preview_image (void) +{ + fail_unless (preview_buffer != NULL); + if (preview_caps) { + fail_unless (GST_BUFFER_CAPS (preview_buffer) != NULL); + fail_unless (gst_caps_can_intersect (GST_BUFFER_CAPS (preview_buffer), + preview_caps)); + } +} + +static void +extract_jpeg_tags (const gchar * filename, gint num) +{ + GstBus *bus; + GMainLoop *loop = g_main_loop_new (NULL, FALSE); + const gchar *filepath = make_test_file_name (filename, num); + gchar *pipeline_str = g_strdup_printf ("filesrc location=%s ! " + "jpegparse ! fakesink", filepath); + GstElement *pipeline; + + pipeline = gst_parse_launch (pipeline_str, NULL); + fail_unless (pipeline != NULL); + g_free (pipeline_str); + + bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); + gst_bus_add_watch (bus, (GstBusFunc) validity_bus_cb, loop); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + g_main_loop_run (loop); + gst_element_set_state (pipeline, GST_STATE_NULL); + + gst_object_unref (bus); + gst_object_unref (pipeline); +} + +static void +setup_wrappercamerabinsrc_videotestsrc (void) +{ + GstBus *bus; + GstElement *vfbin; + GstElement *fakevideosink; + GstElement *src; + GstElement *testsrc; + + GST_INFO ("init"); + + test_id = g_random_int (); + + main_loop = g_main_loop_new (NULL, TRUE); + + camera = gst_check_setup_element ("camerabin2"); + fakevideosink = gst_element_factory_make ("fakesink", NULL); + src = gst_element_factory_make ("wrappercamerabinsrc", NULL); + testsrc = gst_element_factory_make ("videotestsrc", NULL); + + preview_caps = gst_caps_new_simple ("video/x-raw-rgb", "width", G_TYPE_INT, + 320, "height", G_TYPE_INT, 240, NULL); + + g_object_set (G_OBJECT (testsrc), "is-live", TRUE, "peer-alloc", FALSE, NULL); + g_object_set (G_OBJECT (src), "video-src", testsrc, NULL); + g_object_set (G_OBJECT (camera), "camera-src", src, "preview-caps", + preview_caps, NULL); + gst_object_unref (src); + gst_object_unref (testsrc); + + vfbin = gst_bin_get_by_name (GST_BIN (camera), "vf-bin"); + g_object_set (G_OBJECT (vfbin), "video-sink", fakevideosink, NULL); + gst_object_unref (vfbin); + gst_object_unref (fakevideosink); + + bus = gst_pipeline_get_bus (GST_PIPELINE (camera)); + gst_bus_add_watch (bus, (GstBusFunc) capture_bus_cb, main_loop); + gst_object_unref (bus); + + GST_INFO ("init finished"); +} + +static void +teardown (void) +{ + gst_element_set_state (camera, GST_STATE_NULL); + + if (camera) + gst_check_teardown_element (camera); + camera = NULL; + + if (main_loop) + g_main_loop_unref (main_loop); + main_loop = NULL; + + if (preview_caps) + gst_caps_unref (preview_caps); + preview_caps = NULL; + + if (preview_buffer) + gst_buffer_unref (preview_buffer); + preview_buffer = NULL; + + if (tags_found) + gst_tag_list_free (tags_found); + tags_found = NULL; + + GST_INFO ("done"); +} + +static gboolean +validity_bus_cb (GstBus * bus, GstMessage * message, gpointer data) +{ + GMainLoop *loop = (GMainLoop *) data; + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_ERROR:{ + GError *err = NULL; + gchar *debug = NULL; + + gst_message_parse_error (message, &err, &debug); + + GST_ERROR ("Error: %s : %s", err->message, debug); + g_error_free (err); + g_free (debug); + + fail_if (TRUE, "validating captured data failed"); + g_main_loop_quit (loop); + } + break; + case GST_MESSAGE_EOS: + g_main_loop_quit (loop); + GST_DEBUG ("eos"); + break; + case GST_MESSAGE_TAG:{ + GstTagList *taglist = NULL; + + gst_message_parse_tag (message, &taglist); + if (tags_found) { + gst_tag_list_insert (tags_found, taglist, GST_TAG_MERGE_REPLACE); + gst_tag_list_free (taglist); + } else { + tags_found = taglist; + } + } + break; + default: + break; + } + return TRUE; +} + +/* checks that tags in @tags_a are in @tags_b */ +static gboolean +taglist_is_subset (GstTagList * tags_a, GstTagList * tags_b) +{ + gst_tag_list_foreach (tags_a, validate_taglist_foreach, tags_b); + return TRUE; +} + +/* Validate captured files by playing them with playbin + * and checking that no errors occur. */ +static gboolean +check_file_validity (const gchar * filename, gint num, GstTagList * taglist, + gint width, gint height) +{ + GstBus *bus; + GstPad *pad; + GstCaps *caps; + gint caps_width, caps_height; + GstState state; + + GMainLoop *loop = g_main_loop_new (NULL, FALSE); + GstElement *playbin = gst_element_factory_make ("playbin2", NULL); + GstElement *fakevideo = gst_element_factory_make ("fakesink", NULL); + GstElement *fakeaudio = gst_element_factory_make ("fakesink", NULL); + gchar *uri = g_strconcat ("file://", make_test_file_name (filename, num), + NULL); + + GST_DEBUG ("checking uri: %s", uri); + g_object_set (G_OBJECT (playbin), "uri", uri, "video-sink", fakevideo, + "audio-sink", fakeaudio, NULL); + + bus = gst_pipeline_get_bus (GST_PIPELINE (playbin)); + gst_bus_add_watch (bus, (GstBusFunc) validity_bus_cb, loop); + + gst_element_set_state (playbin, GST_STATE_PAUSED); + + if (width != 0 && height != 0) { + gst_element_get_state (playbin, &state, NULL, GST_SECOND * 3); + + g_signal_emit_by_name (playbin, "get-video-pad", 0, &pad, NULL); + g_assert (pad != NULL); + caps = gst_pad_get_negotiated_caps (pad); + + g_assert (gst_structure_get_int (gst_caps_get_structure (caps, 0), + "width", &caps_width)); + g_assert (gst_structure_get_int (gst_caps_get_structure (caps, 0), + "height", &caps_height)); + + g_assert (width == caps_width); + g_assert (height == caps_height); + + gst_caps_unref (caps); + gst_object_unref (pad); + } + + gst_element_set_state (playbin, GST_STATE_PLAYING); + g_main_loop_run (loop); + gst_element_set_state (playbin, GST_STATE_NULL); + + /* special handling for images (jpg) as jpegparse isn't plugged by + * default due to its current low rank */ + if (taglist && strstr (filename, "image")) { + extract_jpeg_tags (filename, num); + } + + if (taglist) { + fail_unless (tags_found != NULL); + fail_unless (taglist_is_subset (taglist, tags_found)); + } + + g_free (uri); + gst_object_unref (bus); + gst_object_unref (playbin); + + return TRUE; +} + +static gboolean +filter_buffer_count (GstPad * pad, GstMiniObject * obj, gpointer data) +{ + gint *counter = data; + + (*counter)++; + + return TRUE; +} + +GST_START_TEST (test_single_image_capture) +{ + if (!camera) + return; + + /* set still image mode */ + g_object_set (camera, "mode", 1, + "location", make_test_file_name (IMAGE_FILENAME, -1), NULL); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + GST_INFO ("starting capture"); + fail_unless (camera != NULL); + g_signal_emit_by_name (camera, "start-capture", NULL); + + g_timeout_add_seconds (3, (GSourceFunc) g_main_loop_quit, main_loop); + g_main_loop_run (main_loop); + + /* check that we got a preview image */ + check_preview_image (); + + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + check_file_validity (IMAGE_FILENAME, 0, NULL, 0, 0); +} + +GST_END_TEST; + + +GST_START_TEST (test_multiple_image_captures) +{ + gint i; + gint widths[] = { 800, 640, 1280 }; + gint heights[] = { 600, 480, 1024 }; + + if (!camera) + return; + + /* set still image mode */ + g_object_set (camera, "mode", 1, + "location", make_test_file_name (IMAGE_FILENAME, -1), NULL); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + fail_unless (camera != NULL); + GST_INFO ("starting capture"); + + for (i = 0; i < 3; i++) { + GstCaps *caps; + + caps = gst_caps_new_simple ("video/x-raw-rgb", "width", G_TYPE_INT, + widths[i], "height", G_TYPE_INT, heights[i], NULL); + + g_object_set (camera, "image-capture-caps", caps, NULL); + gst_caps_unref (caps); + + g_signal_emit_by_name (camera, "start-capture", NULL); + + g_timeout_add_seconds (3, (GSourceFunc) g_main_loop_quit, main_loop); + g_main_loop_run (main_loop); + + check_preview_image (); + } + + g_usleep (G_USEC_PER_SEC * 3); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + for (i = 0; i < 3; i++) { + check_file_validity (IMAGE_FILENAME, i, NULL, widths[i], heights[i]); + } +} + +GST_END_TEST; + +GST_START_TEST (test_single_video_recording) +{ + if (!camera) + return; + + /* Set video recording mode */ + g_object_set (camera, "mode", 2, + "location", make_test_file_name (VIDEO_FILENAME, -1), NULL); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + + GST_INFO ("starting capture"); + fail_unless (camera != NULL); + g_signal_emit_by_name (camera, "start-capture", NULL); + + /* Record for one seconds */ + g_timeout_add_seconds (VIDEO_DURATION, (GSourceFunc) g_main_loop_quit, + main_loop); + g_main_loop_run (main_loop); + + g_signal_emit_by_name (camera, "stop-capture", NULL); + + check_preview_image (); + + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + + check_file_validity (VIDEO_FILENAME, 0, NULL, 0, 0); +} + +GST_END_TEST; + +GST_START_TEST (test_multiple_video_recordings) +{ + gint i; + gint widths[] = { 800, 640, 1280 }; + gint heights[] = { 600, 480, 1024 }; + gint fr[] = { 20, 30, 5 }; + + if (!camera) + return; + + /* Set video recording mode */ + g_object_set (camera, "mode", 2, NULL); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + + GST_INFO ("starting capture"); + fail_unless (camera != NULL); + for (i = 0; i < 3; i++) { + GstCaps *caps; + + caps = gst_caps_new_simple ("video/x-raw-rgb", "width", G_TYPE_INT, + widths[i], "height", G_TYPE_INT, heights[i], "framerate", + GST_TYPE_FRACTION, fr[i], 1, NULL); + + g_object_set (camera, "video-capture-caps", caps, + "location", make_test_file_name (VIDEO_FILENAME, i), NULL); + + gst_caps_unref (caps); + + g_signal_emit_by_name (camera, "start-capture", NULL); + g_timeout_add_seconds (VIDEO_DURATION, (GSourceFunc) g_main_loop_quit, + main_loop); + g_main_loop_run (main_loop); + g_signal_emit_by_name (camera, "stop-capture", NULL); + + check_preview_image (); + + g_timeout_add_seconds (1, (GSourceFunc) g_main_loop_quit, main_loop); + g_main_loop_run (main_loop); + } + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + + for (i = 0; i < 3; i++) { + check_file_validity (VIDEO_FILENAME, i, NULL, widths[i], heights[i]); + } +} + +GST_END_TEST; + +GST_START_TEST (test_image_video_cycle) +{ + gint i; + + if (!camera) + return; + + /* set filepaths for image and videos */ + g_object_set (camera, "mode", 1, NULL); + g_object_set (camera, "location", make_test_file_name (IMAGE_FILENAME, -1), + NULL); + g_object_set (camera, "mode", 2, NULL); + g_object_set (camera, "location", make_test_file_name (VIDEO_FILENAME, -1), + NULL); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + + GST_INFO ("starting capture"); + for (i = 0; i < 2; i++) { + /* take a picture */ + g_object_set (camera, "mode", 1, NULL); + g_signal_emit_by_name (camera, "start-capture", NULL); + g_timeout_add_seconds (3, (GSourceFunc) g_main_loop_quit, main_loop); + g_main_loop_run (main_loop); + + check_preview_image (); + + /* now go to video */ + g_object_set (camera, "mode", 2, NULL); + g_signal_emit_by_name (camera, "start-capture", NULL); + g_timeout_add_seconds (VIDEO_DURATION, (GSourceFunc) g_main_loop_quit, + main_loop); + g_main_loop_run (main_loop); + g_signal_emit_by_name (camera, "stop-capture", NULL); + + check_preview_image (); + + /* wait for capture to finish */ + g_usleep (G_USEC_PER_SEC); + } + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + + /* validate all the files */ + for (i = 0; i < 2; i++) { + check_file_validity (IMAGE_FILENAME, i, NULL, 0, 0); + check_file_validity (VIDEO_FILENAME, i, NULL, 0, 0); + } +} + +GST_END_TEST; + + +GST_START_TEST (test_image_capture_previews) +{ + gint i; + gint widths[] = { 800, 640, 1280 }; + gint heights[] = { 600, 480, 1024 }; + + if (!camera) + return; + + /* set still image mode */ + g_object_set (camera, "mode", 1, + "location", make_test_file_name (IMAGE_FILENAME, -1), NULL); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + fail_unless (camera != NULL); + GST_INFO ("starting capture"); + + for (i = 0; i < 3; i++) { + GstCaps *caps; + + caps = gst_caps_new_simple ("video/x-raw-rgb", "width", G_TYPE_INT, + widths[i], "height", G_TYPE_INT, heights[i], NULL); + + g_object_set (camera, "preview-caps", caps, NULL); + gst_caps_replace (&preview_caps, caps); + gst_caps_unref (caps); + + g_signal_emit_by_name (camera, "start-capture", NULL); + + g_timeout_add_seconds (3, (GSourceFunc) g_main_loop_quit, main_loop); + g_main_loop_run (main_loop); + + check_preview_image (); + + if (preview_buffer) + gst_buffer_unref (preview_buffer); + preview_buffer = NULL; + gst_caps_replace (&preview_caps, NULL); + } + + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); +} + +GST_END_TEST; + + +GST_START_TEST (test_image_capture_with_tags) +{ + gint i; + GstTagList *taglists[3]; + + if (!camera) + return; + + taglists[0] = gst_tag_list_new_full (GST_TAG_COMMENT, "test1", + GST_TAG_GEO_LOCATION_LATITUDE, 36.6, GST_TAG_GEO_LOCATION_LONGITUDE, + -12.5, + GST_TAG_COPYRIGHT, "My copyright notice", + GST_TAG_DEVICE_MANUFACTURER, "MyFavoriteBrand", + GST_TAG_DEVICE_MODEL, "123v42.1", + GST_TAG_DESCRIPTION, "some description", + GST_TAG_APPLICATION_NAME, "camerabin2 test", + GST_TAG_GEO_LOCATION_ELEVATION, 300.85, NULL); + taglists[1] = gst_tag_list_new_full (GST_TAG_COMMENT, "test2", + GST_TAG_GEO_LOCATION_LATITUDE, 1.6, GST_TAG_GEO_LOCATION_LONGITUDE, + 0.0, + GST_TAG_COPYRIGHT, "some cp", + GST_TAG_DEVICE_MANUFACTURER, "ABRAND", + GST_TAG_DEVICE_MODEL, "abcd", + GST_TAG_DESCRIPTION, "desc", + GST_TAG_APPLICATION_NAME, "another cam test", + GST_TAG_GEO_LOCATION_ELEVATION, 10.0, NULL); + taglists[2] = gst_tag_list_new_full (GST_TAG_COMMENT, "test3", + GST_TAG_GEO_LOCATION_LATITUDE, 1.3, GST_TAG_GEO_LOCATION_LONGITUDE, + -5.0, + GST_TAG_COPYRIGHT, "CC", + GST_TAG_DEVICE_MANUFACTURER, "Homemade", + GST_TAG_DEVICE_MODEL, "xpto", + GST_TAG_DESCRIPTION, "another description", + GST_TAG_APPLICATION_NAME, "cam2 test", + GST_TAG_GEO_LOCATION_ELEVATION, 0.0, NULL); + + /* set still image mode */ + g_object_set (camera, "mode", 1, + "location", make_test_file_name (IMAGE_FILENAME, -1), NULL); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + fail_unless (camera != NULL); + GST_INFO ("starting capture"); + + for (i = 0; i < 3; i++) { + gst_tag_setter_merge_tags (GST_TAG_SETTER (camera), taglists[i], + GST_TAG_MERGE_REPLACE); + + g_signal_emit_by_name (camera, "start-capture", NULL); + + g_timeout_add_seconds (3, (GSourceFunc) g_main_loop_quit, main_loop); + g_main_loop_run (main_loop); + } + + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + + for (i = 0; i < 3; i++) { + check_file_validity (IMAGE_FILENAME, i, taglists[i], 0, 0); + gst_tag_list_free (taglists[i]); + } +} + +GST_END_TEST; + + +GST_START_TEST (test_video_capture_with_tags) +{ + gint i; + GstTagList *taglists[3]; + + if (!camera) + return; + + taglists[0] = gst_tag_list_new_full (GST_TAG_COMMENT, "test1", NULL); + taglists[1] = gst_tag_list_new_full (GST_TAG_COMMENT, "test2", NULL); + taglists[2] = gst_tag_list_new_full (GST_TAG_COMMENT, "test3", NULL); + + /* set video mode */ + g_object_set (camera, "mode", 2, + "location", make_test_file_name (VIDEO_FILENAME, -1), NULL); + + /* set a profile that has xmp support for more tags being saved */ + { + GstEncodingContainerProfile *profile; + GstCaps *caps; + + caps = + gst_caps_new_simple ("video/quicktime", "variant", G_TYPE_STRING, + "apple", NULL); + profile = gst_encoding_container_profile_new ("qt", "jpeg+qt", caps, NULL); + gst_caps_unref (caps); + + caps = gst_caps_new_simple ("image/jpeg", NULL); + if (!gst_encoding_container_profile_add_profile (profile, + (GstEncodingProfile *) gst_encoding_video_profile_new (caps, + NULL, NULL, 1))) { + GST_WARNING_OBJECT (camera, "Failed to create encoding profiles"); + } + gst_caps_unref (caps); + + g_object_set (camera, "video-profile", profile, NULL); + gst_encoding_profile_unref (profile); + } + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + fail_unless (camera != NULL); + GST_INFO ("starting capture"); + + for (i = 0; i < 3; i++) { + gst_tag_setter_merge_tags (GST_TAG_SETTER (camera), taglists[i], + GST_TAG_MERGE_REPLACE); + + g_signal_emit_by_name (camera, "start-capture", NULL); + + g_timeout_add_seconds (3, (GSourceFunc) g_main_loop_quit, main_loop); + g_main_loop_run (main_loop); + + g_signal_emit_by_name (camera, "stop-capture", NULL); + g_usleep (G_USEC_PER_SEC * 3); + } + + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + + for (i = 0; i < 2; i++) { + check_file_validity (VIDEO_FILENAME, i, taglists[i], 0, 0); + gst_tag_list_free (taglists[i]); + } +} + +GST_END_TEST; + + +GST_START_TEST (test_supported_caps) +{ + GstCaps *padcaps = NULL; + GstCaps *expectedcaps; + GstElement *src; + + if (!camera) + return; + + src = g_object_new (GST_TYPE_TEST_CAMERA_SRC, NULL); + g_object_set (camera, "camera-src", src, NULL); + gst_object_unref (src); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + g_assert (camera != NULL); + + expectedcaps = gst_caps_from_string (VIDEO_PAD_SUPPORTED_CAPS); + g_object_get (G_OBJECT (camera), "video-capture-supported-caps", &padcaps, + NULL); + g_assert (expectedcaps != NULL); + g_assert (padcaps != NULL); + g_assert (gst_caps_is_equal (padcaps, expectedcaps)); + gst_caps_unref (expectedcaps); + gst_caps_unref (padcaps); + + expectedcaps = gst_caps_from_string (IMAGE_PAD_SUPPORTED_CAPS); + g_object_get (G_OBJECT (camera), "image-capture-supported-caps", &padcaps, + NULL); + g_assert (expectedcaps != NULL); + g_assert (padcaps != NULL); + g_assert (gst_caps_is_equal (padcaps, expectedcaps)); + gst_caps_unref (expectedcaps); + gst_caps_unref (padcaps); + + gst_element_set_state (camera, GST_STATE_NULL); +} + +GST_END_TEST; + + +GST_START_TEST (test_image_custom_filter) +{ + GstElement *vf_filter; + GstElement *image_filter; + GstElement *preview_filter; + GstPad *pad; + gint vf_probe_counter = 0; + gint image_probe_counter = 0; + gint preview_probe_counter = 0; + + if (!camera) + return; + + vf_filter = gst_element_factory_make ("identity", "vf-filter"); + image_filter = gst_element_factory_make ("identity", "img-filter"); + preview_filter = gst_element_factory_make ("identity", "preview-filter"); + + pad = gst_element_get_static_pad (vf_filter, "src"); + gst_pad_add_buffer_probe (pad, (GCallback) filter_buffer_count, + &vf_probe_counter); + gst_object_unref (pad); + + pad = gst_element_get_static_pad (image_filter, "src"); + gst_pad_add_buffer_probe (pad, (GCallback) filter_buffer_count, + &image_probe_counter); + gst_object_unref (pad); + + pad = gst_element_get_static_pad (preview_filter, "src"); + gst_pad_add_buffer_probe (pad, (GCallback) filter_buffer_count, + &preview_probe_counter); + gst_object_unref (pad); + + /* set still image mode and filters */ + g_object_set (camera, "mode", 1, + "location", make_test_file_name (IMAGE_FILENAME, -1), + "viewfinder-filter", vf_filter, "image-filter", image_filter, + "preview-filter", preview_filter, NULL); + + gst_object_unref (vf_filter); + gst_object_unref (preview_filter); + gst_object_unref (image_filter); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + GST_INFO ("starting capture"); + fail_unless (camera != NULL); + g_signal_emit_by_name (camera, "start-capture", NULL); + + g_timeout_add_seconds (3, (GSourceFunc) g_main_loop_quit, main_loop); + g_main_loop_run (main_loop); + + /* check that we got a preview image */ + check_preview_image (); + + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + check_file_validity (IMAGE_FILENAME, 0, NULL, 0, 0); + + fail_unless (vf_probe_counter > 0); + fail_unless (image_probe_counter == 1); + fail_unless (preview_probe_counter == 1); +} + +GST_END_TEST; + + +GST_START_TEST (test_video_custom_filter) +{ + GstElement *vf_filter; + GstElement *video_filter; + GstElement *preview_filter; + GstPad *pad; + gint vf_probe_counter = 0; + gint video_probe_counter = 0; + gint preview_probe_counter = 0; + + if (!camera) + return; + + vf_filter = gst_element_factory_make ("identity", "vf-filter"); + video_filter = gst_element_factory_make ("identity", "video-filter"); + preview_filter = gst_element_factory_make ("identity", "preview-filter"); + + pad = gst_element_get_static_pad (vf_filter, "src"); + gst_pad_add_buffer_probe (pad, (GCallback) filter_buffer_count, + &vf_probe_counter); + gst_object_unref (pad); + + pad = gst_element_get_static_pad (video_filter, "src"); + gst_pad_add_buffer_probe (pad, (GCallback) filter_buffer_count, + &video_probe_counter); + gst_object_unref (pad); + + pad = gst_element_get_static_pad (preview_filter, "src"); + gst_pad_add_buffer_probe (pad, (GCallback) filter_buffer_count, + &preview_probe_counter); + gst_object_unref (pad); + + /* set still image mode and filters */ + g_object_set (camera, "mode", 2, + "location", make_test_file_name (VIDEO_FILENAME, -1), + "viewfinder-filter", vf_filter, "video-filter", video_filter, + "preview-filter", preview_filter, NULL); + + gst_object_unref (vf_filter); + gst_object_unref (preview_filter); + gst_object_unref (video_filter); + + if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_WARNING ("setting camerabin to PLAYING failed"); + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + gst_object_unref (camera); + camera = NULL; + } + GST_INFO ("starting capture"); + fail_unless (camera != NULL); + g_signal_emit_by_name (camera, "start-capture", NULL); + + g_timeout_add_seconds (VIDEO_DURATION, (GSourceFunc) g_main_loop_quit, + main_loop); + g_main_loop_run (main_loop); + g_signal_emit_by_name (camera, "stop-capture", NULL); + + /* check that we got a preview image */ + check_preview_image (); + + gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL); + check_file_validity (VIDEO_FILENAME, 0, NULL, 0, 0); + + fail_unless (vf_probe_counter > 0); + fail_unless (video_probe_counter > 0); + fail_unless (preview_probe_counter == 1); +} + +GST_END_TEST; + + +typedef struct _TestCaseDef +{ + const gchar *name; + gpointer setup_func; +} TestCaseDef; + +TestCaseDef tests[] = { + {"wrappercamerabinsrc", setup_wrappercamerabinsrc_videotestsrc} +}; + +static Suite * +camerabin_suite (void) +{ + GstElementFactory *jpegenc_factory; + Suite *s = suite_create ("camerabin2"); + gint i; + TCase *tc_generic = tcase_create ("generic"); + + jpegenc_factory = gst_element_factory_find ("jpegenc"); + if (jpegenc_factory == NULL) { + GST_WARNING ("Skipping camerabin2 tests because jpegenc is missing"); + goto end; + } + + suite_add_tcase (s, tc_generic); + tcase_add_checked_fixture (tc_generic, setup_wrappercamerabinsrc_videotestsrc, + teardown); + tcase_add_test (tc_generic, test_supported_caps); + + for (i = 0; i < G_N_ELEMENTS (tests); i++) { + TCase *tc_basic = tcase_create (tests[i].name); + suite_add_tcase (s, tc_basic); + + /* Increase timeout due to video recording */ + tcase_set_timeout (tc_basic, 60); + tcase_add_checked_fixture (tc_basic, tests[i].setup_func, teardown); + + tcase_add_test (tc_basic, test_single_image_capture); + tcase_add_test (tc_basic, test_single_video_recording); + tcase_add_test (tc_basic, test_image_video_cycle); + if (gst_plugin_feature_check_version ((GstPluginFeature *) jpegenc_factory, + 0, 10, 27)) + tcase_add_test (tc_basic, test_multiple_image_captures); + else + GST_WARNING ("Skipping image capture test because -good 0.10.27 is " + "needed"); + tcase_add_test (tc_basic, test_multiple_video_recordings); + + tcase_add_test (tc_basic, test_image_capture_previews); + tcase_add_test (tc_basic, test_image_capture_with_tags); + + tcase_add_test (tc_basic, test_video_capture_with_tags); + + tcase_add_test (tc_basic, test_image_custom_filter); + tcase_add_test (tc_basic, test_video_custom_filter); + } + +end: + return s; +} + +GST_CHECK_MAIN (camerabin); diff --git a/tests/check/elements/imagecapturebin.c b/tests/check/elements/imagecapturebin.c new file mode 100644 index 000000000..5c5f73613 --- /dev/null +++ b/tests/check/elements/imagecapturebin.c @@ -0,0 +1,410 @@ +/* GStreamer unit test for the imagecapturebin element + * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <gst/check/gstcheck.h> +#include <gst/app/gstappsink.h> +#include <gst/app/gstappsrc.h> + +#define N_BUFFERS 3 + +typedef struct +{ + GstElement *pipe; + GstElement *src; + GstElement *icbin; +} GstImageCaptureBinTestContext; + +static void +gstimagecapturebin_init_test_context (GstImageCaptureBinTestContext * ctx, + const gchar * src, gint num_buffers) +{ + fail_unless (ctx != NULL); + + ctx->pipe = gst_pipeline_new ("pipeline"); + fail_unless (ctx->pipe != NULL); + ctx->src = gst_element_factory_make (src, "src"); + fail_unless (ctx->src != NULL, "Failed to create src element"); + ctx->icbin = gst_element_factory_make ("imagecapturebin", "icbin"); + fail_unless (ctx->icbin != NULL, "Failed to create imagecapturebin element"); + + if (num_buffers > 0) + g_object_set (ctx->src, "num-buffers", num_buffers, NULL); + + fail_unless (gst_bin_add (GST_BIN (ctx->pipe), ctx->src)); + fail_unless (gst_bin_add (GST_BIN (ctx->pipe), ctx->icbin)); + fail_unless (gst_element_link_many (ctx->src, ctx->icbin, NULL)); +} + +static void +gstimagecapturebin_unset_test_context (GstImageCaptureBinTestContext * ctx) +{ + gst_element_set_state (ctx->pipe, GST_STATE_NULL); + gst_object_unref (ctx->pipe); + memset (ctx, 0, sizeof (GstImageCaptureBinTestContext)); +} + +static gchar * +make_test_file_name (void) +{ + return g_strdup_printf ("%s" G_DIR_SEPARATOR_S + "imagecapturebintest_%%d.cap", g_get_tmp_dir ()); +} + +static gboolean +get_file_info (const gchar * filename, gint * width, gint * height) +{ + GstElement *playbin = gst_element_factory_make ("playbin2", NULL); + GstElement *fakesink = gst_element_factory_make ("fakesink", NULL); + GstState state = GST_STATE_NULL; + GstPad *pad; + GstCaps *caps; + gchar *uri = g_strdup_printf ("file://%s", filename); + + g_object_set (playbin, "video-sink", fakesink, NULL); + g_object_set (playbin, "uri", uri, NULL); + g_free (uri); + + gst_element_set_state (playbin, GST_STATE_PAUSED); + + gst_element_get_state (playbin, &state, NULL, GST_SECOND * 5); + + fail_unless (state == GST_STATE_PAUSED); + + g_signal_emit_by_name (playbin, "get-video-pad", 0, &pad, NULL); + caps = gst_pad_get_negotiated_caps (pad); + fail_unless (gst_structure_get_int (gst_caps_get_structure (caps, 0), "width", + width)); + fail_unless (gst_structure_get_int (gst_caps_get_structure (caps, 0), + "height", height)); + + gst_object_unref (pad); + gst_element_set_state (playbin, GST_STATE_NULL); + gst_object_unref (playbin); + return TRUE; +} + +static GstBuffer * +create_video_buffer (GstCaps * caps) +{ + GstElement *pipeline; + GstElement *cf; + GstElement *sink; + GstBuffer *buffer; + + pipeline = + gst_parse_launch + ("videotestsrc num-buffers=1 ! capsfilter name=cf ! appsink name=sink", + NULL); + g_assert (pipeline != NULL); + + cf = gst_bin_get_by_name (GST_BIN (pipeline), "cf"); + sink = gst_bin_get_by_name (GST_BIN (pipeline), "sink"); + + g_object_set (G_OBJECT (cf), "caps", caps, NULL); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + + buffer = gst_app_sink_pull_buffer (GST_APP_SINK (sink)); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); + gst_object_unref (sink); + gst_object_unref (cf); + return buffer; +} + + +GST_START_TEST (test_simple_capture) +{ + GstImageCaptureBinTestContext ctx; + GstBus *bus; + GstMessage *msg; + gchar *test_file_name; + gint i; + + gstimagecapturebin_init_test_context (&ctx, "videotestsrc", N_BUFFERS); + bus = gst_element_get_bus (ctx.pipe); + + test_file_name = make_test_file_name (); + g_object_set (ctx.icbin, "location", test_file_name, NULL); + + fail_if (gst_element_set_state (ctx.pipe, GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE); + + msg = gst_bus_timed_pop_filtered (bus, GST_SECOND * 10, + GST_MESSAGE_EOS | GST_MESSAGE_ERROR); + fail_unless (msg != NULL); + fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS); + gst_message_unref (msg); + + /* check there are N_BUFFERS files */ + for (i = 0; i < N_BUFFERS; i++) { + gchar *filename; + FILE *f; + + filename = g_strdup_printf (test_file_name, i); + + fail_unless (g_file_test (filename, G_FILE_TEST_EXISTS)); + fail_unless (g_file_test (filename, G_FILE_TEST_IS_REGULAR)); + fail_if (g_file_test (filename, G_FILE_TEST_IS_SYMLINK)); + + /* check the file isn't empty */ + f = fopen (filename, "r"); + fseek (f, 0, SEEK_END); + fail_unless (ftell (f) > 0); + fclose (f); + + g_free (filename); + } + + gstimagecapturebin_unset_test_context (&ctx); + gst_object_unref (bus); + g_free (test_file_name); +} + +GST_END_TEST; + + +GST_START_TEST (test_multiple_captures_different_caps) +{ + GstImageCaptureBinTestContext ctx; + GstBus *bus; + GstMessage *msg; + gchar *test_file_name; + gint i; + gint widths[] = { 100, 300, 200 }; + gint heights[] = { 300, 200, 100 }; + GstPad *pad; + + gstimagecapturebin_init_test_context (&ctx, "appsrc", N_BUFFERS); + bus = gst_element_get_bus (ctx.pipe); + + test_file_name = make_test_file_name (); + g_object_set (ctx.icbin, "location", test_file_name, NULL); + fail_if (gst_element_set_state (ctx.pipe, GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE); + + /* push data directly because set_caps and buffer pushes on appsrc + * are not serialized into the flow, so we can't guarantee the buffers + * have the caps we want on them when pushed */ + pad = gst_element_get_static_pad (ctx.src, "src"); + + /* push the buffers */ + for (i = 0; i < N_BUFFERS; i++) { + GstCaps *caps; + GstBuffer *buf; + + caps = gst_caps_new_simple ("video/x-raw-yuv", "width", G_TYPE_INT, + widths[i], "height", G_TYPE_INT, heights[i], "framerate", + GST_TYPE_FRACTION, 1, 1, "format", GST_TYPE_FOURCC, + GST_MAKE_FOURCC ('I', '4', '2', '0'), NULL); + + buf = create_video_buffer (caps); + fail_if (buf == NULL); + + fail_unless (gst_pad_push (pad, buf) == GST_FLOW_OK); + gst_caps_unref (caps); + } + gst_app_src_end_of_stream (GST_APP_SRC (ctx.src)); + gst_object_unref (pad); + + msg = gst_bus_timed_pop_filtered (bus, GST_SECOND * 10, + GST_MESSAGE_EOS | GST_MESSAGE_ERROR); + fail_unless (msg != NULL); + fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS); + gst_message_unref (msg); + + /* check there are N_BUFFERS files */ + for (i = 0; i < N_BUFFERS; i++) { + gchar *filename; + FILE *f; + gint width = 0, height = 0; + + filename = g_strdup_printf (test_file_name, i); + + fail_unless (g_file_test (filename, G_FILE_TEST_EXISTS)); + fail_unless (g_file_test (filename, G_FILE_TEST_IS_REGULAR)); + fail_if (g_file_test (filename, G_FILE_TEST_IS_SYMLINK)); + + /* check the file isn't empty */ + f = fopen (filename, "r"); + fseek (f, 0, SEEK_END); + fail_unless (ftell (f) > 0); + fclose (f); + + /* get the file info */ + fail_unless (get_file_info (filename, &width, &height)); + fail_unless (width == widths[i]); + fail_unless (height == heights[i]); + + g_free (filename); + } + + gstimagecapturebin_unset_test_context (&ctx); + gst_object_unref (bus); + g_free (test_file_name); +} + +GST_END_TEST; + +GST_START_TEST (test_setting_encoder) +{ + GstImageCaptureBinTestContext ctx; + GstBus *bus; + GstMessage *msg; + GstElement *encoder; + gchar *test_file_name; + gint i; + + gstimagecapturebin_init_test_context (&ctx, "videotestsrc", N_BUFFERS); + bus = gst_element_get_bus (ctx.pipe); + + test_file_name = make_test_file_name (); + g_object_set (ctx.icbin, "location", test_file_name, NULL); + + encoder = gst_element_factory_make ("jpegenc", NULL); + g_object_set (ctx.icbin, "image-encoder", encoder, NULL); + + fail_if (gst_element_set_state (ctx.pipe, GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE); + + msg = gst_bus_timed_pop_filtered (bus, GST_SECOND * 10, + GST_MESSAGE_EOS | GST_MESSAGE_ERROR); + fail_unless (msg != NULL); + fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS); + + /* check there are N_BUFFERS files */ + for (i = 0; i < N_BUFFERS; i++) { + gchar *filename; + FILE *f; + + filename = g_strdup_printf (test_file_name, i); + + fail_unless (g_file_test (filename, G_FILE_TEST_EXISTS)); + fail_unless (g_file_test (filename, G_FILE_TEST_IS_REGULAR)); + fail_if (g_file_test (filename, G_FILE_TEST_IS_SYMLINK)); + + /* check the file isn't empty */ + f = fopen (filename, "r"); + fseek (f, 0, SEEK_END); + fail_unless (ftell (f) > 0); + fclose (f); + + g_free (filename); + } + + gstimagecapturebin_unset_test_context (&ctx); + gst_object_unref (bus); + g_free (test_file_name); +} + +GST_END_TEST; + +GST_START_TEST (test_setting_muxer) +{ + GstImageCaptureBinTestContext ctx; + GstBus *bus; + GstMessage *msg; + GstElement *encoder; + gchar *test_file_name; + gint i; + + gstimagecapturebin_init_test_context (&ctx, "videotestsrc", N_BUFFERS); + bus = gst_element_get_bus (ctx.pipe); + + test_file_name = make_test_file_name (); + g_object_set (ctx.icbin, "location", test_file_name, NULL); + + encoder = gst_element_factory_make ("pngenc", NULL); + g_object_set (ctx.icbin, "image-encoder", encoder, NULL); + + encoder = gst_element_factory_make ("identity", NULL); + g_object_set (ctx.icbin, "image-muxer", encoder, NULL); + + fail_if (gst_element_set_state (ctx.pipe, GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE); + + msg = gst_bus_timed_pop_filtered (bus, GST_SECOND * 10, + GST_MESSAGE_EOS | GST_MESSAGE_ERROR); + fail_unless (msg != NULL); + fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS); + + /* check there are N_BUFFERS files */ + for (i = 0; i < N_BUFFERS; i++) { + gchar *filename; + FILE *f; + + filename = g_strdup_printf (test_file_name, i); + + fail_unless (g_file_test (filename, G_FILE_TEST_EXISTS)); + fail_unless (g_file_test (filename, G_FILE_TEST_IS_REGULAR)); + fail_if (g_file_test (filename, G_FILE_TEST_IS_SYMLINK)); + + /* check the file isn't empty */ + f = fopen (filename, "r"); + fseek (f, 0, SEEK_END); + fail_unless (ftell (f) > 0); + fclose (f); + + g_free (filename); + } + + gstimagecapturebin_unset_test_context (&ctx); + gst_object_unref (bus); + g_free (test_file_name); +} + +GST_END_TEST; + +static Suite * +imagecapturebin_suite (void) +{ + GstElementFactory *jpegenc_factory; + + Suite *s = suite_create ("imagecapturebin"); + TCase *tc_chain = tcase_create ("general"); + + jpegenc_factory = gst_element_factory_find ("jpegenc"); + + suite_add_tcase (s, tc_chain); + if (jpegenc_factory) { + tcase_add_test (tc_chain, test_simple_capture); + + /* only adds this test if jpegenc contains the fix for its getcaps + * The fix on good: dcbba0932dc579abd6aab4460fa1a416374eda1b */ + if (gst_plugin_feature_check_version ((GstPluginFeature *) jpegenc_factory, + 0, 10, 27)) + tcase_add_test (tc_chain, test_multiple_captures_different_caps); + else + GST_WARNING ("Skipped test that needs gst-plugins-good 0.10.27"); + + tcase_add_test (tc_chain, test_setting_encoder); + tcase_add_test (tc_chain, test_setting_muxer); + } else + GST_WARNING ("Skipped imagecapturebin tests because jpegenc is missing"); + + return s; +} + +GST_CHECK_MAIN (imagecapturebin); diff --git a/tests/check/elements/jifmux.c b/tests/check/elements/jifmux.c index 3ec32dfba..f76d77a84 100644 --- a/tests/check/elements/jifmux.c +++ b/tests/check/elements/jifmux.c @@ -807,6 +807,7 @@ check_content (ExifContent * content, void *user_data) fail_unless (strcmp (str, taglist_str) == 0); test_data->result = TRUE; + g_free (taglist_str); } break; case EXIF_TYPE_RATIONAL:{ @@ -886,6 +887,7 @@ check_content (ExifContent * content, void *user_data) } test_data->result = TRUE; + gst_buffer_unref (buf); } break; default: @@ -927,6 +929,7 @@ generate_jif_file_with_tags_from_taglist (GstTagList * taglist, pipeline = gst_parse_launch (launchline, NULL); fail_unless (pipeline != NULL); + g_free (launchline); jifmux = gst_bin_get_by_name (GST_BIN (pipeline), "jifmux0"); fail_unless (jifmux != NULL); @@ -939,9 +942,10 @@ generate_jif_file_with_tags_from_taglist (GstTagList * taglist, fail_if (gst_element_set_state (pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE); - msg = gst_bus_timed_pop_filtered (bus, GST_SECOND * 5, GST_MESSAGE_EOS | + msg = gst_bus_timed_pop_filtered (bus, GST_SECOND * 10, GST_MESSAGE_EOS | GST_MESSAGE_ERROR); - fail_if (!msg || GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR); + fail_if (!msg); + fail_if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR); gst_message_unref (msg); gst_object_unref (bus); diff --git a/tests/check/elements/parser.c b/tests/check/elements/parser.c index b0b4c8212..759688991 100644 --- a/tests/check/elements/parser.c +++ b/tests/check/elements/parser.c @@ -24,7 +24,7 @@ */ #include <gst/check/gstcheck.h> -#include "parser.h" +#include "elements/parser.h" /* context state variables */ diff --git a/tests/check/elements/qtmux.c b/tests/check/elements/qtmux.c index 69816f704..1db618cec 100644 --- a/tests/check/elements/qtmux.c +++ b/tests/check/elements/qtmux.c @@ -355,6 +355,36 @@ GST_START_TEST (test_audio_pad_frag_streamable) GST_END_TEST; +GST_START_TEST (test_reuse) +{ + GstElement *qtmux = setup_qtmux (&srcvideotemplate, "video_%d"); + GstBuffer *inbuffer; + GstCaps *caps; + + gst_element_set_state (qtmux, GST_STATE_PLAYING); + gst_element_set_state (qtmux, GST_STATE_NULL); + gst_element_set_state (qtmux, GST_STATE_PLAYING); + gst_pad_set_active (mysrcpad, TRUE); + gst_pad_set_active (mysinkpad, TRUE); + + inbuffer = gst_buffer_new_and_alloc (1); + fail_unless (inbuffer != NULL); + caps = gst_caps_copy (gst_pad_get_pad_template_caps (mysrcpad)); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + GST_BUFFER_TIMESTAMP (inbuffer) = 0; + GST_BUFFER_DURATION (inbuffer) = 40 * GST_MSECOND; + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + + /* send eos to have all written */ + fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()) == TRUE); + + cleanup_qtmux (qtmux, "video_%d"); +} + +GST_END_TEST; + static Suite * qtmux_suite (void) { @@ -369,6 +399,8 @@ qtmux_suite (void) tcase_add_test (tc_chain, test_video_pad_frag_streamable); tcase_add_test (tc_chain, test_audio_pad_frag_streamable); + tcase_add_test (tc_chain, test_reuse); + return s; } diff --git a/tests/check/elements/selector.c b/tests/check/elements/selector.c deleted file mode 100644 index 56d2840ec..000000000 --- a/tests/check/elements/selector.c +++ /dev/null @@ -1,385 +0,0 @@ -/* GStreamer - * - * Unit test for selector plugin - * Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.com>) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include <gst/check/gstcheck.h> - -#define NUM_SELECTOR_PADS 4 -#define NUM_INPUT_BUFFERS 4 // buffers to send per each selector pad - -static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); -static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -/* Data probe cb to drop everything but count buffers and events */ -static gboolean -probe_cb (GstPad * pad, GstMiniObject * obj, gpointer user_data) -{ - gint count = 0; - const gchar *count_type = NULL; - - GST_LOG_OBJECT (pad, "got data"); - - if (GST_IS_BUFFER (obj)) { - count_type = "buffer_count"; - } else if (GST_IS_EVENT (obj)) { - count_type = "event_count"; - } else { - g_assert_not_reached (); - } - - /* increment and store count */ - count = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pad), count_type)); - count++; - g_object_set_data (G_OBJECT (pad), count_type, GINT_TO_POINTER (count)); - - /* drop everything */ - return FALSE; -} - -/* Create and link output pad: selector:src%d ! output_pad */ -static GstPad * -setup_output_pad (GstElement * element) -{ - GstPad *srcpad = NULL, *output_pad = NULL; - gulong probe_id = 0; - - /* create output_pad */ - output_pad = gst_pad_new_from_static_template (&sinktemplate, "sink"); - fail_if (output_pad == NULL, "Could not create a output_pad"); - - /* add probe */ - probe_id = gst_pad_add_data_probe (output_pad, G_CALLBACK (probe_cb), NULL); - g_object_set_data (G_OBJECT (output_pad), "probe_id", - GINT_TO_POINTER (probe_id)); - - /* request src pad */ - srcpad = gst_element_get_request_pad (element, "src%d"); - fail_if (srcpad == NULL, "Could not get source pad from %s", - GST_ELEMENT_NAME (element)); - - /* link pads and activate */ - fail_unless (gst_pad_link (srcpad, output_pad) == GST_PAD_LINK_OK, - "Could not link %s source and output pad", GST_ELEMENT_NAME (element)); - - gst_pad_set_active (output_pad, TRUE); - - GST_DEBUG_OBJECT (output_pad, "set up %" GST_PTR_FORMAT " ! %" GST_PTR_FORMAT, - srcpad, output_pad); - - gst_object_unref (srcpad); - ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1); - - return output_pad; -} - -/* Clean up output/input pad and respective selector request pad */ -static void -cleanup_pad (GstPad * pad, GstElement * element) -{ - GstPad *selpad = NULL; - guint probe_id = 0; - - fail_if (pad == NULL, "pad doesn't exist"); - - /* remove probe if necessary */ - probe_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pad), "probe_id")); - if (probe_id) - gst_pad_remove_data_probe (pad, probe_id); - - /* unlink */ - selpad = gst_pad_get_peer (pad); - if (GST_PAD_DIRECTION (selpad) == GST_PAD_SRC) { - gst_pad_unlink (selpad, pad); - } else { - gst_pad_unlink (pad, selpad); - } - - /* caps could have been set, make sure they get unset */ - gst_pad_set_caps (pad, NULL); - - GST_DEBUG_OBJECT (pad, "clean up %" GST_PTR_FORMAT " and %" GST_PTR_FORMAT, - selpad, pad); - - /* cleanup the pad */ - gst_pad_set_active (pad, FALSE); - ASSERT_OBJECT_REFCOUNT (pad, "pad", 1); - gst_object_unref (pad); - - /* cleanup selector pad, reffed by this function (_get_peer) and creator */ - gst_element_release_request_pad (element, selpad); - gst_object_unref (selpad); -} - -/* Duplicate and push given buffer many times to all input_pads */ -static void -push_input_buffers (GList * input_pads, GstBuffer * buf, gint num_buffers) -{ - GstBuffer *buf_in = NULL; - GList *l = input_pads; - GstPad *input_pad; - gint i = 0; - - while (l != NULL) { - input_pad = l->data; - GST_DEBUG_OBJECT (input_pad, "pushing %d buffers to %" GST_PTR_FORMAT, - num_buffers, input_pad); - for (i = 0; i < num_buffers; i++) { - buf_in = gst_buffer_copy (buf); - fail_unless (gst_pad_push (input_pad, buf_in) == GST_FLOW_OK, - "pushing buffer failed"); - } - l = g_list_next (l); - } -} - -/* Check that received buffers count match to expected buffers */ -static void -count_output_buffers (GList * output_pads, gint expected_buffers) -{ - gint count = 0; - GList *l = output_pads; - GstPad *output_pad = NULL; - - while (l != NULL) { - output_pad = l->data; - count = - GPOINTER_TO_INT (g_object_get_data (G_OBJECT (output_pad), - "buffer_count")); - GST_DEBUG_OBJECT (output_pad, "received %d buffers", count); - fail_unless (count == expected_buffers, - "received/expected buffer count doesn't match %d/%d", count, - expected_buffers); - count = - GPOINTER_TO_INT (g_object_get_data (G_OBJECT (output_pad), - "event_count")); - GST_DEBUG_OBJECT (output_pad, "received %d events", count); - l = g_list_next (l); - } -} - -/* Set selector active pad */ -static void -selector_set_active_pad (GstElement * elem, GstPad * selpad) -{ - gchar *padname = NULL; - - if (selpad) { - padname = gst_pad_get_name (selpad); - } - - g_object_set (G_OBJECT (elem), "active-pad", selpad, NULL); - GST_DEBUG_OBJECT (elem, "activated selector pad: %s", GST_STR_NULL (padname)); - g_free (padname); -} - -/* Push buffers and switch for each selector pad */ -static void -push_switched_buffers (GList * input_pads, - GstElement * elem, GList * peer_pads, gint num_buffers) -{ - GstBuffer *buf = NULL; - GstCaps *caps = NULL; - GList *l = peer_pads; - GstPad *selpad = NULL; - - /* setup dummy buffer */ - caps = gst_caps_from_string ("application/x-unknown"); - buf = gst_buffer_new_and_alloc (1); - gst_buffer_set_caps (buf, caps); - gst_caps_unref (caps); - - while (l != NULL) { - /* set selector pad */ - selpad = gst_pad_get_peer (GST_PAD (l->data)); - selector_set_active_pad (elem, selpad); - if (selpad) { - gst_object_unref (selpad); - } - /* push buffers */ - push_input_buffers (input_pads, buf, num_buffers); - /* switch to next selector pad */ - l = g_list_next (l); - } - - /* cleanup buffer */ - gst_buffer_unref (buf); -} - -/* Create output-selector with given number of src pads and switch - given number of input buffers to each src pad. - */ -static void -run_output_selector_buffer_count (gint num_output_pads, - gint num_buffers_per_output) -{ - /* setup input_pad ! selector ! output_pads */ - gint i = 0; - GList *output_pads = NULL, *input_pads = NULL; - GstElement *sel = gst_check_setup_element ("output-selector"); - GstPad *input_pad = gst_check_setup_src_pad (sel, &srctemplate, NULL); - - input_pads = g_list_append (input_pads, input_pad); - gst_pad_set_active (input_pad, TRUE); - for (i = 0; i < num_output_pads; i++) { - output_pads = g_list_append (output_pads, setup_output_pad (sel)); - } - - /* run the test */ - fail_unless (gst_element_set_state (sel, - GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, - "could not set to playing"); - push_switched_buffers (input_pads, sel, output_pads, num_buffers_per_output); - count_output_buffers (output_pads, num_buffers_per_output); - fail_unless (gst_element_set_state (sel, - GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null"); - - /* cleanup input_pad, selector and output_pads */ - gst_pad_set_active (input_pad, FALSE); - gst_check_teardown_src_pad (sel); - g_list_foreach (output_pads, (GFunc) cleanup_pad, sel); - g_list_free (output_pads); - g_list_free (input_pads); - gst_check_teardown_element (sel); -} - -/* Create and link input pad: input_pad ! selector:sink%d */ -static GstPad * -setup_input_pad (GstElement * element) -{ - GstPad *sinkpad = NULL, *input_pad = NULL; - - /* create input_pad */ - input_pad = gst_pad_new_from_static_template (&srctemplate, "src"); - fail_if (input_pad == NULL, "Could not create a input_pad"); - - /* request sink pad */ - sinkpad = gst_element_get_request_pad (element, "sink%d"); - fail_if (sinkpad == NULL, "Could not get sink pad from %s", - GST_ELEMENT_NAME (element)); - - /* link pads and activate */ - fail_unless (gst_pad_link (input_pad, sinkpad) == GST_PAD_LINK_OK, - "Could not link input_pad and %s sink", GST_ELEMENT_NAME (element)); - - gst_pad_set_active (input_pad, TRUE); - - GST_DEBUG_OBJECT (input_pad, "set up %" GST_PTR_FORMAT " ! %" GST_PTR_FORMAT, - input_pad, sinkpad); - - gst_object_unref (sinkpad); - ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 1); - - return input_pad; -} - -/* Create input-selector with given number of sink pads and switch - given number of input buffers to each sink pad. - */ -static void -run_input_selector_buffer_count (gint num_input_pads, - gint num_buffers_per_input) -{ - /* set up input_pads ! selector ! output_pad */ - gint i = 0, probe_id = 0; - GList *input_pads = NULL, *output_pads = NULL; - GstElement *sel = gst_check_setup_element ("input-selector"); - GstPad *output_pad = gst_check_setup_sink_pad (sel, &sinktemplate, NULL); - - output_pads = g_list_append (output_pads, output_pad); - gst_pad_set_active (output_pad, TRUE); - for (i = 0; i < num_input_pads; i++) { - input_pads = g_list_append (input_pads, setup_input_pad (sel)); - } - /* add probe */ - probe_id = gst_pad_add_data_probe (output_pad, G_CALLBACK (probe_cb), NULL); - g_object_set_data (G_OBJECT (output_pad), "probe_id", - GINT_TO_POINTER (probe_id)); - - /* run the test */ - fail_unless (gst_element_set_state (sel, - GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, - "could not set to playing"); - push_switched_buffers (input_pads, sel, input_pads, num_buffers_per_input); - count_output_buffers (output_pads, (num_input_pads * num_buffers_per_input)); - fail_unless (gst_element_set_state (sel, - GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null"); - - /* clean up */ - gst_pad_remove_data_probe (output_pad, probe_id); - gst_pad_set_active (output_pad, FALSE); - gst_check_teardown_sink_pad (sel); - GST_DEBUG ("setting selector pad to NULL"); - selector_set_active_pad (sel, NULL); // unref input-selector active pad - g_list_foreach (input_pads, (GFunc) cleanup_pad, sel); - g_list_free (input_pads); - g_list_free (output_pads); - gst_check_teardown_element (sel); -} - -/* Push buffers to input pad and check the - amount of buffers arrived to output pads */ -GST_START_TEST (test_output_selector_buffer_count); -{ - gint i, j; - - for (i = 0; i < NUM_SELECTOR_PADS; i++) { - for (j = 0; j < NUM_INPUT_BUFFERS; j++) { - run_output_selector_buffer_count (i, j); - } - } -} - -GST_END_TEST; - -/* Push buffers to input pads and check the - amount of buffers arrived to output pad */ -GST_START_TEST (test_input_selector_buffer_count); -{ - gint i, j; - - for (i = 0; i < NUM_SELECTOR_PADS; i++) { - for (j = 0; j < NUM_INPUT_BUFFERS; j++) { - run_input_selector_buffer_count (i, j); - } - } -} - -GST_END_TEST; - -static Suite * -selector_suite (void) -{ - Suite *s = suite_create ("selector"); - TCase *tc_chain = tcase_create ("general"); - - suite_add_tcase (s, tc_chain); - tcase_add_test (tc_chain, test_output_selector_buffer_count); - tcase_add_test (tc_chain, test_input_selector_buffer_count); - - return s; -} - -GST_CHECK_MAIN (selector); diff --git a/tests/check/elements/valve.c b/tests/check/elements/valve.c deleted file mode 100644 index d7971bd5a..000000000 --- a/tests/check/elements/valve.c +++ /dev/null @@ -1,135 +0,0 @@ -/* GStreamer - * - * unit test for the valve element - * - * Copyright 2009 Collabora Ltd. - * @author: Olivier Crete <olivier.crete@collabora.co.uk> - * Copyright 2009 Nokia Corp. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include <gst/check/gstcheck.h> -#include <gst/rtp/gstrtpbuffer.h> -#include <gst/gst.h> - - -static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int")); - -static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int")); - -gboolean event_received = FALSE; -gboolean buffer_allocated = FALSE; - -static gboolean -event_func (GstPad * pad, GstEvent * event) -{ - event_received = TRUE; - gst_event_unref (event); - return TRUE; -} - -static GstFlowReturn -bufferalloc_func (GstPad * pad, guint64 offset, guint size, GstCaps * caps, - GstBuffer ** buf) -{ - buffer_allocated = TRUE; - *buf = gst_buffer_new_and_alloc (size); - GST_BUFFER_OFFSET (*buf) = offset; - gst_buffer_set_caps (*buf, caps); - - return GST_FLOW_OK; -} - -GST_START_TEST (test_valve_basic) -{ - GstElement *valve; - GstPad *sink; - GstPad *src; - GstBuffer *buf; - GstCaps *caps; - - valve = gst_check_setup_element ("valve"); - - sink = gst_check_setup_sink_pad_by_name (valve, &sinktemplate, "src"); - src = gst_check_setup_src_pad_by_name (valve, &srctemplate, "sink"); - gst_pad_set_event_function (sink, event_func); - gst_pad_set_bufferalloc_function (sink, bufferalloc_func); - gst_pad_set_active (src, TRUE); - gst_pad_set_active (sink, TRUE); - gst_element_set_state (valve, GST_STATE_PLAYING); - - g_object_set (valve, "drop", FALSE, NULL); - - fail_unless (gst_pad_push_event (src, gst_event_new_eos ()) == TRUE); - fail_unless (event_received == TRUE); - fail_unless (gst_pad_alloc_buffer (src, 0, 10, NULL, &buf) == GST_FLOW_OK); - fail_unless (buffer_allocated == TRUE); - gst_buffer_unref (buf); - fail_unless (gst_pad_push (src, gst_buffer_new ()) == GST_FLOW_OK); - fail_unless (gst_pad_push (src, gst_buffer_new ()) == GST_FLOW_OK); - fail_unless (g_list_length (buffers) == 2); - caps = gst_pad_get_caps (src); - fail_unless (caps && gst_caps_is_equal (caps, - gst_pad_get_pad_template_caps (src))); - gst_caps_unref (caps); - - gst_check_drop_buffers (); - event_received = buffer_allocated = FALSE; - - g_object_set (valve, "drop", TRUE, NULL); - fail_unless (gst_pad_push_event (src, gst_event_new_eos ()) == TRUE); - fail_unless (event_received == FALSE); - fail_unless (gst_pad_alloc_buffer (src, 0, 10, NULL, &buf) == GST_FLOW_OK); - fail_unless (buffer_allocated == FALSE); - gst_buffer_unref (buf); - fail_unless (gst_pad_push (src, gst_buffer_new ()) == GST_FLOW_OK); - fail_unless (gst_pad_push (src, gst_buffer_new ()) == GST_FLOW_OK); - fail_unless (buffers == NULL); - caps = gst_pad_get_caps (src); - fail_unless (caps && gst_caps_is_equal (caps, - gst_pad_get_pad_template_caps (src))); - gst_caps_unref (caps); - - gst_pad_set_active (src, FALSE); - gst_pad_set_active (sink, FALSE); - gst_check_teardown_src_pad (valve); - gst_check_teardown_sink_pad (valve); - gst_check_teardown_element (valve); -} - -GST_END_TEST; - -static Suite * -valve_suite (void) -{ - Suite *s = suite_create ("valve"); - TCase *tc_chain; - - tc_chain = tcase_create ("valve_basic"); - tcase_add_test (tc_chain, test_valve_basic); - suite_add_tcase (s, tc_chain); - - return s; -} - -GST_CHECK_MAIN (valve) diff --git a/tests/check/elements/viewfinderbin.c b/tests/check/elements/viewfinderbin.c new file mode 100644 index 000000000..c5766052c --- /dev/null +++ b/tests/check/elements/viewfinderbin.c @@ -0,0 +1,103 @@ +/* GStreamer unit test for the viewfinderbin element + * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <gst/check/gstcheck.h> + +typedef struct +{ + GstElement *pipe; + GstElement *src; + GstElement *vfbin; +} GstViewFinderBinTestContext; + +static void +gstviewfinderbin_init_test_context (GstViewFinderBinTestContext * ctx, + gint num_buffers) +{ + GstElement *sink; + fail_unless (ctx != NULL); + + ctx->pipe = gst_pipeline_new ("pipeline"); + fail_unless (ctx->pipe != NULL); + ctx->src = gst_element_factory_make ("videotestsrc", "src"); + fail_unless (ctx->src != NULL, "Failed to create videotestsrc element"); + sink = gst_element_factory_make ("fakesink", NULL); + ctx->vfbin = gst_element_factory_make ("viewfinderbin", "vfbin"); + fail_unless (ctx->vfbin != NULL, "Failed to create viewfinderbin element"); + g_object_set (ctx->vfbin, "video-sink", sink, NULL); + gst_object_unref (sink); + + if (num_buffers > 0) + g_object_set (ctx->src, "num-buffers", num_buffers, NULL); + + fail_unless (gst_bin_add (GST_BIN (ctx->pipe), ctx->src)); + fail_unless (gst_bin_add (GST_BIN (ctx->pipe), ctx->vfbin)); + fail_unless (gst_element_link (ctx->src, ctx->vfbin)); +} + +static void +gstviewfinderbin_unset_test_context (GstViewFinderBinTestContext * ctx) +{ + gst_element_set_state (ctx->pipe, GST_STATE_NULL); + gst_object_unref (ctx->pipe); + memset (ctx, 0, sizeof (GstViewFinderBinTestContext)); +} + +GST_START_TEST (test_simple_run) +{ + GstViewFinderBinTestContext ctx; + GstBus *bus; + GstMessage *msg; + + gstviewfinderbin_init_test_context (&ctx, 10); + bus = gst_element_get_bus (ctx.pipe); + + fail_if (gst_element_set_state (ctx.pipe, GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE); + + msg = gst_bus_timed_pop_filtered (bus, GST_SECOND * 30, + GST_MESSAGE_EOS | GST_MESSAGE_ERROR); + fail_unless (msg != NULL); + fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS); + gst_message_unref (msg); + + gstviewfinderbin_unset_test_context (&ctx); + gst_object_unref (bus); +} + +GST_END_TEST; + +static Suite * +viewfinderbin_suite (void) +{ + Suite *s = suite_create ("viewfinderbin"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_simple_run); + + return s; +} + +GST_CHECK_MAIN (viewfinderbin); diff --git a/tests/check/pipelines/tagschecking.c b/tests/check/pipelines/tagschecking.c index ed17c3f1a..91a556c52 100644 --- a/tests/check/pipelines/tagschecking.c +++ b/tests/check/pipelines/tagschecking.c @@ -114,6 +114,7 @@ test_mux_tags (const gchar * tag_str, const gchar * caps, sent_tags = gst_structure_from_string (tag_str, NULL); fail_unless (sent_tags != NULL); gst_tag_setter_merge_tags (setter, sent_tags, GST_TAG_MERGE_REPLACE); + gst_tag_list_free (sent_tags); gst_element_set_state (pipeline, GST_STATE_PLAYING); g_main_loop_run (loop); @@ -246,6 +247,7 @@ test_tags (const gchar * tag_str, const gchar * caps, const gchar * muxer, GST_DEBUG ("testing tags : %s", tag_str); test_mux_tags (tag_str, caps, muxer, tmpfile); test_demux_tags (tag_str, demuxer, tmpfile); + g_free (tmpfile); } #define H264_CAPS "video/x-h264, width=(int)320, height=(int)240," \ diff --git a/tests/examples/Makefile.am b/tests/examples/Makefile.am index 0e92667d5..26833fb61 100644 --- a/tests/examples/Makefile.am +++ b/tests/examples/Makefile.am @@ -1,10 +1,5 @@ if HAVE_GTK -if USE_JACK -JACK_EXAMPLES=jack -else -JACK_EXAMPLES= -endif -GTK_EXAMPLES=camerabin mxf scaletempo +GTK_EXAMPLES=camerabin mxf scaletempo camerabin2 else GTK_EXAMPLES= endif @@ -15,5 +10,13 @@ else DIRECTFB_DIR= endif -SUBDIRS= $(DIRECTFB_DIR) $(GTK_EXAMPLES) $(JACK_EXAMPLES) switch -DIST_SUBDIRS= camerabin directfb jack mxf scaletempo switch +if BUILD_EXPERIMENTAL +CAMERABIN2=camerabin2 +else +CAMERABIN2= +endif + +SUBDIRS= $(DIRECTFB_DIR) $(GTK_EXAMPLES) +DIST_SUBDIRS= camerabin camerabin2 directfb mxf scaletempo + +include $(top_srcdir)/common/parallel-subdirs.mak diff --git a/tests/examples/camerabin/Makefile.am b/tests/examples/camerabin/Makefile.am index 5898a0ce5..9d74d91d7 100644 --- a/tests/examples/camerabin/Makefile.am +++ b/tests/examples/camerabin/Makefile.am @@ -21,7 +21,7 @@ gst_camera_LDADD = \ noinst_DATA = $(GST_CAMERABIN_UI_FILES) -INCLUDES = -DCAMERA_APPS_UIDIR=\""$(uidir)"\" +INCLUDES = -DCAMERA_APPS_UIDIR=\""$(srcdir)"\" else GST_CAMERABIN_GTK_EXAMPLES = @@ -29,7 +29,7 @@ endif gst_camera_perf_SOURCES = gst-camera-perf.c gst_camera_perf_CFLAGS = $(GST_CFLAGS) -gst_camera_perf_LDADD = $(GST_LIBS) +gst_camera_perf_LDADD = $(GST_LIBS) if HAVE_X11 diff --git a/tests/examples/camerabin/gst-camera.c b/tests/examples/camerabin/gst-camera.c index c837ba520..57ff706e1 100644 --- a/tests/examples/camerabin/gst-camera.c +++ b/tests/examples/camerabin/gst-camera.c @@ -65,8 +65,7 @@ gtk_widget_get_allocation (GtkWidget * w, GtkAllocation * a) #define PREVIEW_TIME_MS (2 * 1000) #define N_BURST_IMAGES 10 -#define DEFAULT_UI_FILE "gst-camera.ui" -#define SHARED_UI_FILE CAMERA_APPS_UIDIR"/"DEFAULT_UI_FILE +#define UI_FILE CAMERA_APPS_UIDIR G_DIR_SEPARATOR_S "gst-camera.ui" /* Names of default elements */ #define CAMERA_APP_VIDEOSRC "v4l2src" @@ -276,7 +275,11 @@ my_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data) /* FIXME: make sure to get XID in main thread */ gst_x_overlay_set_window_handle (GST_X_OVERLAY (message->src), +#if GTK_CHECK_VERSION (2, 91, 6) + GDK_WINDOW_XID (gtk_widget_get_window (ui_drawing)); +#else GDK_WINDOW_XWINDOW (gtk_widget_get_window (ui_drawing))); +#endif gst_message_unref (message); return GST_BUS_DROP; @@ -758,7 +761,7 @@ set_metadata (void) /* for more information about image metadata tags, see: * http://webcvs.freedesktop.org/gstreamer/gst-plugins-bad/tests/icles/metadata_editor.c * and for the mapping: - * http://webcvs.freedesktop.org/gstreamer/gst-plugins-bad/ext/metadata/metadata_mapping.htm?view=co + * http://webcvs.freedesktop.org/gstreamer/gst-plugins-bad/ext/metadata/metadata_mapping.htm?view=co */ GstTagSetter *setter = GST_TAG_SETTER (gst_camera_bin); @@ -1101,6 +1104,7 @@ format_value_callback (GtkScale * scale, gdouble value, gpointer user_data) static gint create_menu_items_from_structure (GstStructure * structure) { + GtkListStore *store; const GValue *framerate_list = NULL; const gchar *structure_name; GString *item_str = NULL; @@ -1155,8 +1159,10 @@ create_menu_items_from_structure (GstStructure * structure) goto range_found; } + store = GTK_LIST_STORE (gtk_combo_box_get_model (ui_cbbox_resolution)); for (j = 0; j < num_framerates; j++) { GstCaps *video_caps; + GtkTreeIter iter; if (framerate_list) { const GValue *item = gst_value_list_get_value (framerate_list, j); @@ -1167,7 +1173,8 @@ create_menu_items_from_structure (GstStructure * structure) g_string_append_printf (item_str, " (%" GST_FOURCC_FORMAT ")", GST_FOURCC_ARGS (fourcc)); g_string_append_printf (item_str, ", %dx%d at %d/%d", w, h, n, d); - gtk_combo_box_append_text (ui_cbbox_resolution, item_str->str); + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, item_str->str, -1); video_caps = gst_caps_new_simple (structure_name, "format", GST_TYPE_FOURCC, @@ -1614,14 +1621,9 @@ static gboolean ui_create (void) { GError *error = NULL; - const gchar *uifile = DEFAULT_UI_FILE; - - if (!g_file_test (uifile, G_FILE_TEST_EXISTS)) { - uifile = SHARED_UI_FILE; - } builder = gtk_builder_new (); - if (!gtk_builder_add_from_file (builder, uifile, &error)) { + if (!gtk_builder_add_from_file (builder, UI_FILE, &error)) { g_warning ("Couldn't load builder file: %s", error->message); g_error_free (error); goto done; diff --git a/tests/examples/camerabin/gst-camerabin-test.c b/tests/examples/camerabin/gst-camerabin-test.c index 6ebd1e237..73399e595 100644 --- a/tests/examples/camerabin/gst-camerabin-test.c +++ b/tests/examples/camerabin/gst-camerabin-test.c @@ -136,15 +136,6 @@ static gint view_framerate_num = 2825; static gint view_framerate_den = 100; static gboolean no_xwindow = FALSE; -/* photography interface command line options */ -static gfloat ev_compensation = 0.0; -static gint aperture = 0; -static gint flash_mode = 0; -static gint scene_mode = 6; -static gint64 exposure = 0; -static gint iso_speed = 0; -static gint wb_mode = 0; -static gint color_mode = 0; static gint mode = 1; static gint flags = 0x4f; static gboolean mute = FALSE; @@ -154,6 +145,24 @@ static gint capture_time = 10; static gint capture_count = 0; static gint capture_total = 1; +/* photography interface command line options */ +#define EV_COMPENSATION_NONE -G_MAXFLOAT +#define APERTURE_NONE -G_MAXINT +#define FLASH_MODE_NONE -G_MAXINT +#define SCENE_MODE_NONE -G_MAXINT +#define EXPOSURE_NONE -G_MAXINT64 +#define ISO_SPEED_NONE -G_MAXINT +#define WHITE_BALANCE_MODE_NONE -G_MAXINT +#define COLOR_TONE_MODE_NONE -G_MAXINT +static gfloat ev_compensation = EV_COMPENSATION_NONE; +static gint aperture = APERTURE_NONE; +static gint flash_mode = FLASH_MODE_NONE; +static gint scene_mode = SCENE_MODE_NONE; +static gint64 exposure = EXPOSURE_NONE; +static gint iso_speed = ISO_SPEED_NONE; +static gint wb_mode = WHITE_BALANCE_MODE_NONE; +static gint color_mode = COLOR_TONE_MODE_NONE; + /* audio capsfilter options */ static gint audio_bitrate = 128000; static gint audio_samplerate = 48000; @@ -174,6 +183,8 @@ static gchar *preview_caps_name = NULL; static Display *display = NULL; static Window window = 0; +GTimer *timer = NULL; + /* * Prototypes */ @@ -257,14 +268,14 @@ sync_bus_callback (GstBus * bus, GstMessage * message, gpointer data) size = GST_BUFFER_SIZE (buf); preview_filename = g_strdup_printf ("test_vga.rgb"); caps_string = gst_caps_to_string (GST_BUFFER_CAPS (buf)); - g_print ("writing buffer to %s, buffer caps: %s\n", - preview_filename, caps_string); + g_print ("writing buffer to %s, elapsed: %.2fs, buffer caps: %s\n", + preview_filename, g_timer_elapsed (timer, NULL), caps_string); g_free (caps_string); f = g_fopen (preview_filename, "w"); if (f) { written = fwrite (data_buf, size, 1, f); if (!written) { - g_print ("errro writing file\n"); + g_print ("error writing file\n"); } fclose (f); } else { @@ -634,14 +645,24 @@ run_pipeline (gpointer user_data) if (video_source) { if (GST_IS_ELEMENT (video_source) && gst_element_implements_interface (video_source, GST_TYPE_PHOTOGRAPHY)) { - g_object_set (video_source, "ev-compensation", ev_compensation, NULL); - g_object_set (video_source, "aperture", aperture, NULL); - g_object_set (video_source, "flash-mode", flash_mode, NULL); - g_object_set (video_source, "scene-mode", scene_mode, NULL); - g_object_set (video_source, "exposure", exposure, NULL); - g_object_set (video_source, "iso-speed", iso_speed, NULL); - g_object_set (video_source, "white-balance-mode", wb_mode, NULL); - g_object_set (video_source, "colour-tone-mode", color_mode, NULL); + /* Set GstPhotography interface options. If option not given as + command-line parameter use default of the source element. */ + if (scene_mode != SCENE_MODE_NONE) + g_object_set (video_source, "scene-mode", scene_mode, NULL); + if (ev_compensation != EV_COMPENSATION_NONE) + g_object_set (video_source, "ev-compensation", ev_compensation, NULL); + if (aperture != APERTURE_NONE) + g_object_set (video_source, "aperture", aperture, NULL); + if (flash_mode != FLASH_MODE_NONE) + g_object_set (video_source, "flash-mode", flash_mode, NULL); + if (exposure != EXPOSURE_NONE) + g_object_set (video_source, "exposure", exposure, NULL); + if (iso_speed != ISO_SPEED_NONE) + g_object_set (video_source, "iso-speed", iso_speed, NULL); + if (wb_mode != WHITE_BALANCE_MODE_NONE) + g_object_set (video_source, "white-balance-mode", wb_mode, NULL); + if (color_mode != COLOR_TONE_MODE_NONE) + g_object_set (video_source, "colour-tone-mode", color_mode, NULL); } g_object_unref (video_source); } @@ -649,6 +670,7 @@ run_pipeline (gpointer user_data) g_object_set (camera_bin, "zoom", zoom / 100.0f, NULL); capture_count++; + g_timer_start (timer); g_signal_emit_by_name (camera_bin, "capture-start", 0); @@ -669,27 +691,29 @@ main (int argc, char *argv[]) GOptionEntry options[] = { {"ev-compensation", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_STRING, &ev_option, - "EV compensation (-2.5..2.5, default = 0)", NULL}, + "EV compensation for source element GstPhotography interface", NULL}, {"aperture", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT, &aperture, - "Aperture (size of lens opening, default = 0 (auto))", NULL}, + "Aperture (size of lens opening) for source element GstPhotography interface", + NULL}, {"flash-mode", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT, &flash_mode, - "Flash mode (default = 0 (auto))", NULL}, + "Flash mode for source element GstPhotography interface", NULL}, {"scene-mode", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT, &scene_mode, - "Scene mode (default = 6 (auto))", NULL}, + "Scene mode for source element GstPhotography interface", NULL}, {"exposure", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT64, &exposure, - "Exposure (default = 0 (auto))", NULL}, + "Exposure time (in ms) for source element GstPhotography interface", + NULL}, {"iso-speed", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT, &iso_speed, - "ISO speed (default = 0 (auto))", NULL}, + "ISO speed for source element GstPhotography interface", NULL}, {"white-balance-mode", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT, &wb_mode, - "White balance mode (default = 0 (auto))", NULL}, + "White balance mode for source element GstPhotography interface", NULL}, {"colour-tone-mode", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT, &color_mode, - "Colour tone mode (default = 0 (auto))", NULL}, + "Colour tone mode for source element GstPhotography interface", NULL}, {"directory", '\0', 0, G_OPTION_ARG_STRING, &fn_option, "Directory for capture file(s) (default is current directory)", NULL}, {"mode", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT, &mode, @@ -757,10 +781,6 @@ main (int argc, char *argv[]) GOptionContext *ctx; GError *err = NULL; - /* if we fail to create xwindow should we care? */ - if (!no_xwindow) - create_host_window (); - if (!g_thread_supported ()) g_thread_init (NULL); @@ -773,6 +793,10 @@ main (int argc, char *argv[]) } g_option_context_free (ctx); + /* if we fail to create xwindow should we care? */ + if (!no_xwindow) + create_host_window (); + GST_DEBUG_CATEGORY_INIT (camerabin_test, "camerabin-test", 0, "camerabin test"); @@ -787,6 +811,8 @@ main (int argc, char *argv[]) if (filename->len == 0) filename = g_string_append (filename, "."); + timer = g_timer_new (); + /* init */ if (setup_pipeline ()) { loop = g_main_loop_new (NULL, FALSE); @@ -809,6 +835,7 @@ main (int argc, char *argv[]) g_free (src_csp); g_free (src_format); g_free (target_times); + g_timer_destroy (timer); if (window) XDestroyWindow (display, window); diff --git a/tests/examples/camerabin2/.gitignore b/tests/examples/camerabin2/.gitignore new file mode 100644 index 000000000..4a17e8d5c --- /dev/null +++ b/tests/examples/camerabin2/.gitignore @@ -0,0 +1,4 @@ +gst-camera2 +test_*.jpg +vid_* +img_* diff --git a/tests/examples/camerabin2/Makefile.am b/tests/examples/camerabin2/Makefile.am new file mode 100644 index 000000000..5fa753471 --- /dev/null +++ b/tests/examples/camerabin2/Makefile.am @@ -0,0 +1,33 @@ +GST_CAMERABIN_UI_FILES = gst-camera2.ui + +if HAVE_GTK + +GST_CAMERABIN_GTK_EXAMPLES = gst-camera2 + +gst_camera2_SOURCES = gst-camera2.h gst-camera2.c +gst_camera2_CFLAGS = \ + $(GST_PLUGINS_BAD_CFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) \ + $(GTK_CFLAGS) \ + $(GMODULE_EXPORT_CFLAGS) \ + -DGST_USE_UNSTABLE_API +gst_camera2_LDADD = \ + $(top_builddir)/gst-libs/gst/interfaces/libgstphotography-@GST_MAJORMINOR@.la \ + $(GST_PLUGINS_BASE_LIBS) \ + -lgstinterfaces-@GST_MAJORMINOR@ \ + $(GST_LIBS) \ + $(GTK_LIBS) \ + $(GMODULE_EXPORT_LIBS) + +noinst_DATA = $(GST_CAMERABIN_UI_FILES) + +INCLUDES = -DCAMERA_APPS_UIDIR=\""$(srcdir)"\" + +else +GST_CAMERABIN_GTK_EXAMPLES = +endif + +noinst_PROGRAMS = $(GST_CAMERABIN_GTK_EXAMPLES) + +EXTRA_DIST = $(GST_CAMERABIN_UI_FILES) + diff --git a/tests/examples/camerabin2/gst-camera2.c b/tests/examples/camerabin2/gst-camera2.c new file mode 100644 index 000000000..14e3be10f --- /dev/null +++ b/tests/examples/camerabin2/gst-camera2.c @@ -0,0 +1,186 @@ +/* + * GStreamer + * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/* + * This is a demo application to test the camerabin element. + * If you have question don't hesitate in contact me edgard.lima@indt.org.br + */ + +/* + * Includes + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "gst-camera2.h" + +#include <gst/gst.h> +#include <gst/interfaces/xoverlay.h> +#include <gtk/gtk.h> +#include <gdk/gdkx.h> +#include <gdk/gdkkeysyms.h> + +#define UI_FILE CAMERA_APPS_UIDIR G_DIR_SEPARATOR_S "gst-camera2.ui" + +static GstElement *camera; +static GtkBuilder *builder; + +void +on_mainWindow_delete_event (GtkWidget * widget, GdkEvent * event, gpointer data) +{ + gtk_main_quit (); +} + +void +on_captureButton_clicked (GtkButton * button, gpointer user_data) +{ + g_signal_emit_by_name (camera, "start-capture", NULL); +} + +void +on_stopCaptureButton_clicked (GtkButton * button, gpointer user_data) +{ + g_signal_emit_by_name (camera, "stop-capture", NULL); +} + +void +on_imageRButton_toggled (GtkToggleButton * button, gpointer user_data) +{ + if (gtk_toggle_button_get_active (button)) { + g_object_set (camera, "mode", 1, NULL); /* Image mode */ + } +} + +void +on_videoRButton_toggled (GtkToggleButton * button, gpointer user_data) +{ + if (gtk_toggle_button_get_active (button)) { + g_object_set (camera, "mode", 2, NULL); /* Video mode */ + } +} + +void +on_viewfinderArea_realize (GtkWidget * widget, gpointer data) +{ +#if GTK_CHECK_VERSION (2, 18, 0) + gdk_window_ensure_native (gtk_widget_get_window (widget)); +#endif +} + +static GstBusSyncReply +bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data) +{ + GtkWidget *ui_drawing; + + if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) + return GST_BUS_PASS; + + if (!gst_structure_has_name (message->structure, "prepare-xwindow-id")) + return GST_BUS_PASS; + + /* FIXME: make sure to get XID in main thread */ + ui_drawing = GTK_WIDGET (gtk_builder_get_object (builder, "viewfinderArea")); + gst_x_overlay_set_window_handle (GST_X_OVERLAY (message->src), + GDK_WINDOW_XWINDOW (gtk_widget_get_window (ui_drawing))); + + gst_message_unref (message); + return GST_BUS_DROP; +} + + +static gboolean +bus_callback (GstBus * bus, GstMessage * message, gpointer data) +{ + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_WARNING:{ + GError *err; + gchar *debug; + + gst_message_parse_warning (message, &err, &debug); + g_print ("Warning: %s\n", err->message); + g_error_free (err); + g_free (debug); + break; + } + case GST_MESSAGE_ERROR:{ + GError *err = NULL; + gchar *debug = NULL; + + gst_message_parse_error (message, &err, &debug); + g_print ("Error: %s : %s\n", err->message, debug); + g_error_free (err); + g_free (debug); + + gtk_main_quit (); + break; + } + case GST_MESSAGE_EOS: + /* end-of-stream */ + g_print ("Eos\n"); + gtk_main_quit (); + break; + case GST_MESSAGE_ELEMENT: + { + //handle_element_message (message); + break; + } + default: + /* unhandled message */ + break; + } + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + int ret = 0; + GtkWidget *ui_main_window; + GError *error = NULL; + GstBus *bus; + + gst_init (&argc, &argv); + gtk_init (&argc, &argv); + + builder = gtk_builder_new (); + if (!gtk_builder_add_from_file (builder, UI_FILE, &error)) { + g_warning ("Error: %s", error->message); + g_error_free (error); + return 1; + } + + camera = gst_element_factory_make ("camerabin2", "camera"); + bus = gst_pipeline_get_bus (GST_PIPELINE (camera)); + gst_bus_add_watch (bus, bus_callback, NULL); + gst_bus_set_sync_handler (bus, bus_sync_callback, NULL); + gst_object_unref (bus); + + ui_main_window = GTK_WIDGET (gtk_builder_get_object (builder, "mainWindow")); + gtk_builder_connect_signals (builder, NULL); + gtk_widget_show_all (ui_main_window); + + gst_element_set_state (camera, GST_STATE_PLAYING); + + gtk_main (); + + gst_element_set_state (camera, GST_STATE_NULL); + gst_object_unref (camera); + return ret; +} diff --git a/tests/examples/camerabin2/gst-camera2.h b/tests/examples/camerabin2/gst-camera2.h new file mode 100644 index 000000000..d96e2de63 --- /dev/null +++ b/tests/examples/camerabin2/gst-camera2.h @@ -0,0 +1,48 @@ +/* + * GStreamer + * Copyright (C) 2008 Nokia Corporation <multimedia@maemo.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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/* + * This is a demo application to test the camerabin element. + * If you have question don't hesitate in contact me edgard.lima@indt.org.br + */ + +#ifndef __GST_CAMERA_BIN_H__ +#define __GST_CAMERA_BIN_H__ + +#include <gtk/gtk.h> + +void +on_mainWindow_delete_event (GtkWidget * widget, GdkEvent * event, gpointer data); + +void +on_captureButton_clicked (GtkButton * button, gpointer user_data); + +void +on_stopCaptureButton_clicked (GtkButton * button, gpointer user_data); + +void +on_imageRButton_toggled (GtkToggleButton * button, gpointer user_data); + +void +on_videoRButton_toggled (GtkToggleButton * button, gpointer user_data); + +void +on_viewfinderArea_realize (GtkWidget * widget, gpointer data); + +#endif /* __GST_CAMERA_BIN_H__ */ diff --git a/tests/examples/camerabin2/gst-camera2.ui b/tests/examples/camerabin2/gst-camera2.ui new file mode 100644 index 000000000..48fe1410a --- /dev/null +++ b/tests/examples/camerabin2/gst-camera2.ui @@ -0,0 +1,109 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <requires lib="gtk+" version="2.16"/> + <!-- interface-naming-policy project-wide --> + <object class="GtkWindow" id="mainWindow"> + <property name="default_width">800</property> + <property name="default_height">600</property> + <signal name="delete_event" handler="on_mainWindow_delete_event"/> + <child> + <object class="GtkVBox" id="vbox1"> + <property name="visible">True</property> + <child> + <object class="GtkHBox" id="hbox1"> + <property name="visible">True</property> + <child> + <object class="GtkRadioButton" id="imageRButton"> + <property name="label" translatable="yes">Image</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="on_imageRButton_toggled"/> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="videoRButton"> + <property name="label" translatable="yes">Video</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + <property name="group">imageRButton</property> + <signal name="toggled" handler="on_videoRButton_toggled"/> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="hbox2"> + <property name="visible">True</property> + <child> + <object class="GtkDrawingArea" id="viewfinderArea"> + <property name="visible">True</property> + <signal name="realize" handler="on_viewfinderArea_realize"/> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkVBox" id="vbox2"> + <property name="visible">True</property> + <child> + <object class="GtkButton" id="captureButton"> + <property name="label" translatable="yes">Capture</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <signal name="clicked" handler="on_captureButton_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="stopCaptureButton"> + <property name="label" translatable="yes">Stop Capture</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <signal name="clicked" handler="on_stopCaptureButton_clicked"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> +</interface> diff --git a/tests/examples/indexing/indexmpeg.c b/tests/examples/indexing/indexmpeg.c index a670ad8af..c7d447326 100644 --- a/tests/examples/indexing/indexmpeg.c +++ b/tests/examples/indexing/indexmpeg.c @@ -91,7 +91,7 @@ setup_dynamic_linking (GstElement * pipeline, link->pipeline = pipeline; link->index = index; - g_signal_connect (G_OBJECT (element), "new_pad", G_CALLBACK (dynamic_link), + g_signal_connect (G_OBJECT (element), "new-pad", G_CALLBACK (dynamic_link), link); } @@ -225,7 +225,7 @@ main (gint argc, gchar * argv[]) index = gst_index_factory_make ("memindex"); if (index) { if (verbose) - g_signal_connect (G_OBJECT (index), "entry_added", + g_signal_connect (G_OBJECT (index), "entry-added", G_CALLBACK (entry_added), NULL); g_object_set (G_OBJECT (index), "resolver", 1, NULL); @@ -245,7 +245,7 @@ main (gint argc, gchar * argv[]) } /* setup some default info/error handlers */ - g_signal_connect (G_OBJECT (pipeline), "deep_notify", + g_signal_connect (G_OBJECT (pipeline), "deep-notify", G_CALLBACK (gst_element_default_deep_notify), NULL); g_signal_connect (G_OBJECT (pipeline), "error", G_CALLBACK (gst_element_default_error), NULL); diff --git a/tests/examples/jack/Makefile.am b/tests/examples/jack/Makefile.am deleted file mode 100644 index 4adfd1314..000000000 --- a/tests/examples/jack/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ -noinst_PROGRAMS = jack_client - -jack_client_SOURCES = jack_client.c -jack_client_CFLAGS = $(GST_CFLAGS) $(GTK_CFLAGS) $(JACK_CFLAGS) -jack_client_LDFLAGS = $(GST_LIBS) $(GTK_LIBS) $(JACK_LIBS) - diff --git a/tests/examples/jack/jack_client.c b/tests/examples/jack/jack_client.c deleted file mode 100644 index 99599ab5c..000000000 --- a/tests/examples/jack/jack_client.c +++ /dev/null @@ -1,79 +0,0 @@ -/* This app demonstrates the creation and use of a jack client in conjunction - * with the jack plugins. This way, an application can control the jack client - * directly. - */ - -#include <gst/gst.h> -#include <gtk/gtk.h> -#include <jack/jack.h> - -static gboolean -quit_cb (gpointer data) -{ - gtk_main_quit (); - return FALSE; -} - -int -main (int argc, char **argv) -{ - jack_client_t *src_client, *sink_client; - jack_status_t status; - GstElement *pipeline, *src, *sink; - GstStateChangeReturn ret; - - gst_init (&argc, &argv); - - /* create jack clients */ - src_client = jack_client_open ("src_client", JackNoStartServer, &status); - if (src_client == NULL) { - if (status & JackServerFailed) - g_print ("JACK server not running\n"); - else - g_print ("jack_client_open() failed, status = 0x%2.0x\n", status); - return 1; - } - - sink_client = jack_client_open ("sink_client", JackNoStartServer, &status); - if (sink_client == NULL) { - if (status & JackServerFailed) - g_print ("JACK server not running\n"); - else - g_print ("jack_client_open() failed, status = 0x%2.0x\n", status); - return 1; - } - - /* create gst elements */ - pipeline = gst_pipeline_new ("my_pipeline"); - - src = gst_element_factory_make ("jackaudiosrc", NULL); - sink = gst_element_factory_make ("jackaudiosink", NULL); - - g_object_set (src, "client", src_client, NULL); - g_object_set (sink, "client", sink_client, NULL); - - gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL); - - /* link everything together */ - if (!gst_element_link (src, sink)) { - g_print ("Failed to link elements!\n"); - return 1; - } - - /* run */ - ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); - if (ret == GST_STATE_CHANGE_FAILURE) { - g_print ("Failed to start up pipeline!\n"); - return 1; - } - - /* quit after 5 seconds */ - g_timeout_add (5000, (GSourceFunc) quit_cb, NULL); - gtk_main (); - - /* clean up */ - gst_element_set_state (pipeline, GST_STATE_NULL); - gst_object_unref (pipeline); - - return 0; -} diff --git a/tests/examples/switch/.gitignore b/tests/examples/switch/.gitignore deleted file mode 100644 index 7893c4354..000000000 --- a/tests/examples/switch/.gitignore +++ /dev/null @@ -1 +0,0 @@ -switcher diff --git a/tests/examples/switch/Makefile.am b/tests/examples/switch/Makefile.am deleted file mode 100644 index 9a7060485..000000000 --- a/tests/examples/switch/Makefile.am +++ /dev/null @@ -1,7 +0,0 @@ - -noinst_PROGRAMS = switcher - -switcher_SOURCES = switcher.c -switcher_CFLAGS = $(GST_CFLAGS) -switcher_LDFLAGS = $(GST_LIBS) - diff --git a/tests/examples/switch/switcher.c b/tests/examples/switch/switcher.c deleted file mode 100644 index 4742c0337..000000000 --- a/tests/examples/switch/switcher.c +++ /dev/null @@ -1,162 +0,0 @@ -/* GStreamer - * Copyright (C) 2003 Julien Moutte <julien@moutte.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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include <string.h> -#include <stdlib.h> - - -#include <gst/gst.h> - -static GMainLoop *loop = NULL; - -static gboolean -my_bus_callback (GstBus * bus, GstMessage * message, gpointer data) -{ - g_print ("Got %s message\n", GST_MESSAGE_TYPE_NAME (message)); - - switch (GST_MESSAGE_TYPE (message)) { - case GST_MESSAGE_ERROR:{ - GError *err; - gchar *debug; - - gst_message_parse_error (message, &err, &debug); - g_print ("Error: %s\n", err->message); - g_error_free (err); - g_free (debug); - - g_main_loop_quit (loop); - break; - } - case GST_MESSAGE_EOS: - /* end-of-stream */ - g_main_loop_quit (loop); - break; - default: - /* unhandled message */ - break; - } - - /* we want to be notified again the next time there is a message - * on the bus, so returning TRUE (FALSE means we want to stop watching - * for messages on the bus and our callback should not be called again) - */ - return TRUE; -} - - - -static gboolean -switch_timer (GstElement * video_switch) -{ - gint nb_sources; - GstPad *active_pad, *new_pad; - gchar *active_name; - - g_message ("switching"); - g_object_get (G_OBJECT (video_switch), "n-pads", &nb_sources, NULL); - g_object_get (G_OBJECT (video_switch), "active-pad", &active_pad, NULL); - - active_name = gst_pad_get_name (active_pad); - if (strcmp (active_name, "sink0") == 0) { - new_pad = gst_element_get_static_pad (video_switch, "sink1"); - } else { - new_pad = gst_element_get_static_pad (video_switch, "sink0"); - } - g_object_set (G_OBJECT (video_switch), "active-pad", new_pad, NULL); - g_free (active_name); - gst_object_unref (new_pad); - - g_message ("current number of sources : %d, active source %s", - nb_sources, gst_pad_get_name (active_pad)); - - return (GST_STATE (GST_ELEMENT (video_switch)) == GST_STATE_PLAYING); -} - -static void -last_message_received (GObject * segment) -{ - gchar *last_message; - - g_object_get (segment, "last_message", &last_message, NULL); - g_print ("last-message: %s\n", last_message); - g_free (last_message); -} - -int -main (int argc, char *argv[]) -{ - GstElement *pipeline, *src1, *src2, *video_switch, *video_sink, *segment; - GstElement *sink1_sync, *sink2_sync, *capsfilter; - GstBus *bus; - - /* Initing GStreamer library */ - gst_init (&argc, &argv); - - loop = g_main_loop_new (NULL, FALSE); - - pipeline = gst_pipeline_new ("pipeline"); - src1 = gst_element_factory_make ("videotestsrc", "src1"); - g_object_set (G_OBJECT (src1), "pattern", 0, NULL); - src2 = gst_element_factory_make ("videotestsrc", "src2"); - g_object_set (G_OBJECT (src2), "pattern", 1, NULL); - capsfilter = gst_element_factory_make ("capsfilter", "caps0"); - g_object_set (G_OBJECT (capsfilter), "caps", - gst_caps_from_string ("video/x-raw-rgb,width=640,height=480"), NULL); - video_switch = gst_element_factory_make ("input-selector", "video_switch"); - segment = gst_element_factory_make ("identity", "identity-segment"); - g_object_set (G_OBJECT (segment), "silent", TRUE, NULL); - g_signal_connect (G_OBJECT (segment), "notify::last-message", - G_CALLBACK (last_message_received), segment); - g_object_set (G_OBJECT (segment), "single-segment", TRUE, NULL); - video_sink = gst_element_factory_make ("ximagesink", "video_sink"); - g_object_set (G_OBJECT (video_sink), "sync", FALSE, NULL); - sink1_sync = gst_element_factory_make ("identity", "sink0_sync"); - g_object_set (G_OBJECT (sink1_sync), "sync", TRUE, NULL); - sink2_sync = gst_element_factory_make ("identity", "sink1_sync"); - g_object_set (G_OBJECT (sink2_sync), "sync", TRUE, NULL); - gst_bin_add_many (GST_BIN (pipeline), src1, src2, segment, video_switch, - video_sink, sink1_sync, sink2_sync, capsfilter, NULL); - gst_element_link (src1, sink1_sync); - gst_element_link (sink1_sync, video_switch); - gst_element_link (src2, capsfilter); - gst_element_link (capsfilter, sink2_sync); - gst_element_link (sink2_sync, video_switch); - gst_element_link (video_switch, segment); - gst_element_link (segment, /*scaler); - gst_element_link (scaler, */ video_sink); - - bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); - gst_bus_add_watch (bus, my_bus_callback, NULL); - gst_object_unref (bus); - gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); - - g_timeout_add (200, (GSourceFunc) switch_timer, video_switch); - - g_main_loop_run (loop); - - gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_READY); - - /* unref */ - gst_object_unref (GST_OBJECT (pipeline)); - - exit (0); -} diff --git a/tests/icles/.gitignore b/tests/icles/.gitignore index 94f42ab6f..dc69c1076 100644 --- a/tests/icles/.gitignore +++ b/tests/icles/.gitignore @@ -1,6 +1,5 @@ equalizer-test metadata_editor -output-selector-test pitch-test cog-test cog-test.c diff --git a/tests/icles/Makefile.am b/tests/icles/Makefile.am index 6ac25fd29..996c5cc5c 100644 --- a/tests/icles/Makefile.am +++ b/tests/icles/Makefile.am @@ -25,17 +25,5 @@ endif GST_METADATA_TESTS = #endif -equalizer_test_SOURCES = equalizer-test.c -equalizer_test_CFLAGS = $(GST_CFLAGS) -equalizer_test_LDADD = $(GST_LIBS) -equalizer_test_LDFLAGS = $(GST_PLUGIN_LDFLAGS) - -output_selector_test_SOURCES = output-selector-test.c -output_selector_test_CFLAGS = $(GST_CFLAGS) -output_selector_test_LDADD = $(GST_LIBS) -output_selector_test_LDFLAGS = $(GST_PLUGIN_LDFLAGS) - - -noinst_PROGRAMS = $(GST_SOUNDTOUCH_TESTS) $(GST_METADATA_TESTS) \ - equalizer-test output-selector-test +noinst_PROGRAMS = $(GST_SOUNDTOUCH_TESTS) $(GST_METADATA_TESTS) diff --git a/tests/icles/equalizer-test.c b/tests/icles/equalizer-test.c deleted file mode 100644 index d8fd8dda3..000000000 --- a/tests/icles/equalizer-test.c +++ /dev/null @@ -1,289 +0,0 @@ -/* GStreamer test for the equalizer element - * Copyright (C) 2007 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Will tests the equalizer by fading all bands in and out one by one and - * finaly all together. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <gst/gst.h> - -#include <stdlib.h> -#include <math.h> - -GST_DEBUG_CATEGORY_STATIC (equalizer_test_debug); -#define GST_CAT_DEFAULT equalizer_test_debug - -static GstBus *pipeline_bus; - -static gboolean -check_bus (GstClockTime max_wait_time) -{ - GstMessage *msg; - - msg = gst_bus_poll (pipeline_bus, GST_MESSAGE_ERROR | GST_MESSAGE_EOS, - max_wait_time); - - if (msg == NULL) - return FALSE; - - if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) { - GError *err = NULL; - gchar *debug = NULL; - - g_assert (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR); - gst_message_parse_error (msg, &err, &debug); - GST_ERROR ("ERROR: %s [%s]", err->message, debug); - g_print ("\n===========> ERROR: %s\n%s\n\n", err->message, debug); - g_error_free (err); - g_free (debug); - } - - if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS) { - g_print ("\n === EOS ===\n\n"); - } - - gst_message_unref (msg); - return TRUE; -} - -// fix below - -static void -equalizer_set_band_value (GstElement * eq, guint band, gdouble val) -{ - GstObject *child; - - child = gst_child_proxy_get_child_by_index (GST_CHILD_PROXY (eq), band); - g_object_set (child, "gain", val, NULL); - gst_object_unref (child); - g_print ("Band %2d: %.2f\n", band, val); -} - -static void -equalizer_set_all_band_values (GstElement * eq, guint num, gdouble val) -{ - gint i; - GstObject *child; - - for (i = 0; i < num; i++) { - child = gst_child_proxy_get_child_by_index (GST_CHILD_PROXY (eq), i); - g_object_set (child, "gain", val, NULL); - gst_object_unref (child); - } - g_print ("All bands: %.2f\n", val); -} - -// fix above - -static gboolean -equalizer_set_band_value_and_wait (GstElement * eq, guint band, gdouble val) -{ - equalizer_set_band_value (eq, band, val); - return check_bus (100 * GST_MSECOND); -} - -static gboolean -equalizer_set_all_band_values_and_wait (GstElement * eq, guint num, gdouble val) -{ - equalizer_set_all_band_values (eq, num, val); - return check_bus (100 * GST_MSECOND); -} - -static void -do_slider_fiddling (GstElement * playbin, GstElement * eq) -{ - gboolean stop; - guint num_bands, i; - gdouble d, step = 0.5; - - stop = FALSE; - - g_object_get (eq, "num-bands", &num_bands, NULL); - - g_print ("%u bands.\n", num_bands); - - while (!stop) { - for (i = 0; !stop && i < num_bands; ++i) { - d = -24.0; - while (!stop && d <= 12.0) { - stop = equalizer_set_band_value_and_wait (eq, i, d); - d += step; - } - d = 12.0; - while (!stop && d >= -24.0) { - stop = equalizer_set_band_value_and_wait (eq, i, d); - d -= step; - } - d = -24.0; - while (!stop && d <= 12.0) { - stop = equalizer_set_band_value_and_wait (eq, i, d); - d += step; - } - } - - d = 0.0; - while (!stop && d <= 12.0) { - stop = equalizer_set_all_band_values_and_wait (eq, num_bands, d); - d += step; - } - d = 12.0; - while (!stop && d >= -24.0) { - stop = equalizer_set_all_band_values_and_wait (eq, num_bands, d); - d -= step; - } - d = -24.0; - while (!stop && d <= 0.0) { - stop = equalizer_set_all_band_values_and_wait (eq, num_bands, d); - d += step; - } - } -} - -int -main (int argc, char **argv) -{ - gchar *opt_audiosink_str = NULL; - gchar **filenames = NULL; - const GOptionEntry test_goptions[] = { - {"audiosink", '\0', 0, G_OPTION_ARG_STRING, &opt_audiosink_str, - "audiosink to use (default: autoaudiosink)", NULL}, - {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL}, - {NULL, '\0', 0, 0, NULL, NULL, NULL} - }; - GOptionContext *ctx; - GError *opt_err = NULL; - - GstStateChangeReturn ret; - GstElement *playbin, *sink, *bin, *eq, *auconv; - GstPad *eq_sinkpad; - gchar *uri; - - if (!g_thread_supported ()) - g_thread_init (NULL); - - GST_DEBUG_CATEGORY_INIT (equalizer_test_debug, "equalizertest", 0, "eqtest"); - - /* command line option parsing */ - ctx = g_option_context_new ("FILENAME"); - g_option_context_add_group (ctx, gst_init_get_option_group ()); - g_option_context_add_main_entries (ctx, test_goptions, NULL); - - if (!g_option_context_parse (ctx, &argc, &argv, &opt_err)) { - g_error ("Error parsing command line options: %s", opt_err->message); - return -1; - } - - if (filenames == NULL || *filenames == NULL) { - g_printerr ("Please specify a file to play back\n"); - return -1; - } - - playbin = gst_element_factory_make ("playbin", "playbin"); - if (playbin == NULL) { - g_error ("Couldn't create 'playbin' element"); - return -1; - } - - if (opt_audiosink_str) { - g_print ("Trying audiosink '%s' ...", opt_audiosink_str); - sink = gst_element_factory_make (opt_audiosink_str, "sink"); - g_print ("%s\n", (sink) ? "ok" : "element couldn't be created"); - } else { - sink = NULL; - } - if (sink == NULL) { - g_print ("Trying audiosink '%s' ...", "autoaudiosink"); - sink = gst_element_factory_make ("autoaudiosink", "sink"); - g_print ("%s\n", (sink) ? "ok" : "element couldn't be created"); - } - if (sink == NULL) { - g_print ("Trying audiosink '%s' ...", "alsasink"); - sink = gst_element_factory_make ("alsasink", "sink"); - g_print ("%s\n", (sink) ? "ok" : "element couldn't be created"); - } - if (sink == NULL) { - g_print ("Trying audiosink '%s' ...", "osssink"); - sink = gst_element_factory_make ("osssink", "sink"); - g_print ("%s\n", (sink) ? "ok" : "element couldn't be created"); - } - - g_assert (sink != NULL); - - bin = gst_bin_new ("ausinkbin"); - g_assert (bin != NULL); - - eq = gst_element_factory_make ("equalizer-nbands", "equalizer"); - g_assert (eq != NULL); - - auconv = gst_element_factory_make ("audioconvert", "eqauconv"); - g_assert (auconv != NULL); - - gst_bin_add_many (GST_BIN (bin), eq, auconv, sink, NULL); - - if (!gst_element_link (eq, auconv)) - g_error ("Failed to link equalizer to audioconvert"); - - if (!gst_element_link (auconv, sink)) - g_error ("Failed to link audioconvert to audio sink"); - - eq_sinkpad = gst_element_get_static_pad (eq, "sink"); - g_assert (eq_sinkpad != NULL); - - gst_element_add_pad (bin, gst_ghost_pad_new (NULL, eq_sinkpad)); - gst_object_unref (eq_sinkpad); - - g_object_set (playbin, "audio-sink", bin, NULL); - - /* won't work: uri = gst_uri_construct ("file", filenames[0]); */ - uri = g_strdup_printf ("file://%s", filenames[0]); - g_object_set (playbin, "uri", uri, NULL); - g_free (uri); - - pipeline_bus = GST_ELEMENT_BUS (playbin); - - ret = gst_element_set_state (playbin, GST_STATE_PLAYING); - if (ret == GST_STATE_CHANGE_FAILURE) { - g_printerr ("Failed to set playbin to PLAYING\n"); - check_bus (1 * GST_SECOND); - return -1; - } - - ret = gst_element_get_state (playbin, NULL, NULL, 5 * GST_SECOND); - if (ret == GST_STATE_CHANGE_ASYNC) { - g_printerr ("Failed to go to PLAYING in 5 seconds, bailing out\n"); - return -1; - } else if (ret != GST_STATE_CHANGE_SUCCESS) { - g_printerr ("State change to PLAYING failed\n"); - check_bus (1 * GST_SECOND); - return -1; - } - - g_print ("Playing ...\n"); - do_slider_fiddling (playbin, eq); - - gst_element_set_state (playbin, GST_STATE_NULL); - gst_object_unref (playbin); - - return 0; -} diff --git a/tests/icles/output-selector-test.c b/tests/icles/output-selector-test.c deleted file mode 100644 index 1d54b34a2..000000000 --- a/tests/icles/output-selector-test.c +++ /dev/null @@ -1,155 +0,0 @@ -#include <gst/gst.h> - -#define SWITCH_TIMEOUT 1000 -#define NUM_VIDEO_BUFFERS 500 - -static GMainLoop *loop; - -/* Output selector src pads */ -static GstPad *osel_src1 = NULL; -static GstPad *osel_src2 = NULL; - -static gboolean -my_bus_callback (GstBus * bus, GstMessage * message, gpointer data) -{ - g_print ("Got %s message\n", GST_MESSAGE_TYPE_NAME (message)); - - switch (GST_MESSAGE_TYPE (message)) { - case GST_MESSAGE_ERROR:{ - GError *err; - gchar *debug; - - gst_message_parse_error (message, &err, &debug); - g_print ("Error: %s\n", err->message); - g_error_free (err); - g_free (debug); - - g_main_loop_quit (loop); - break; - } - case GST_MESSAGE_EOS: - /* end-of-stream */ - g_main_loop_quit (loop); - break; - default: - /* unhandled message */ - break; - } - /* we want to be notified again the next time there is a message - * on the bus, so returning TRUE (FALSE means we want to stop watching - * for messages on the bus and our callback should not be called again) - */ - return TRUE; -} - -static gboolean -switch_cb (gpointer user_data) -{ - GstElement *sel = GST_ELEMENT (user_data); - GstPad *old_pad, *new_pad = NULL; - - g_object_get (G_OBJECT (sel), "active-pad", &old_pad, NULL); - - if (old_pad == osel_src1) - new_pad = osel_src2; - else - new_pad = osel_src1; - - g_object_set (G_OBJECT (sel), "active-pad", new_pad, NULL); - - g_print ("switched from %s:%s to %s:%s\n", GST_DEBUG_PAD_NAME (old_pad), - GST_DEBUG_PAD_NAME (new_pad)); - - gst_object_unref (old_pad); - - return TRUE; - -} - -gint -main (gint argc, gchar * argv[]) -{ - GstElement *pipeline, *src, *toverlay, *osel, *sink1, *sink2, *convert; - GstPad *sinkpad; - GstBus *bus; - - /* init GStreamer */ - gst_init (&argc, &argv); - loop = g_main_loop_new (NULL, FALSE); - - /* create elements */ - pipeline = gst_element_factory_make ("pipeline", "pipeline"); - src = gst_element_factory_make ("videotestsrc", "src"); - toverlay = gst_element_factory_make ("timeoverlay", "timeoverlay"); - osel = gst_element_factory_make ("output-selector", "osel"); - convert = gst_element_factory_make ("ffmpegcolorspace", "convert"); - sink1 = gst_element_factory_make ("xvimagesink", "sink1"); - sink2 = gst_element_factory_make ("ximagesink", "sink2"); - - if (!pipeline || !src || !toverlay || !osel || !convert || !sink1 || !sink2) { - g_print ("missing element\n"); - return -1; - } - - /* add them to bin */ - gst_bin_add_many (GST_BIN (pipeline), src, toverlay, osel, convert, sink1, - sink2, NULL); - - /* set properties */ - g_object_set (G_OBJECT (src), "is-live", TRUE, NULL); - g_object_set (G_OBJECT (src), "do-timestamp", TRUE, NULL); - g_object_set (G_OBJECT (src), "num-buffers", NUM_VIDEO_BUFFERS, NULL); - g_object_set (G_OBJECT (sink1), "sync", FALSE, "async", FALSE, NULL); - g_object_set (G_OBJECT (sink2), "sync", FALSE, "async", FALSE, NULL); - g_object_set (G_OBJECT (osel), "resend-latest", TRUE, NULL); - - /* link src ! timeoverlay ! osel */ - if (!gst_element_link_many (src, toverlay, osel, NULL)) { - g_print ("linking failed\n"); - return -1; - } - - /* link output 1 */ - sinkpad = gst_element_get_static_pad (sink1, "sink"); - osel_src1 = gst_element_get_request_pad (osel, "src%d"); - if (gst_pad_link (osel_src1, sinkpad) != GST_PAD_LINK_OK) { - g_print ("linking output 1 failed\n"); - return -1; - } - gst_object_unref (sinkpad); - - /* link output 2 */ - sinkpad = gst_element_get_static_pad (convert, "sink"); - osel_src2 = gst_element_get_request_pad (osel, "src%d"); - if (gst_pad_link (osel_src2, sinkpad) != GST_PAD_LINK_OK) { - g_print ("linking output 2 failed\n"); - return -1; - } - gst_object_unref (sinkpad); - - if (!gst_element_link (convert, sink2)) { - g_print ("linking output 2 failed\n"); - return -1; - } - - /* add switch callback */ - g_timeout_add (SWITCH_TIMEOUT, switch_cb, osel); - - /* change to playing */ - bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); - gst_bus_add_watch (bus, my_bus_callback, loop); - gst_object_unref (bus); - - gst_element_set_state (pipeline, GST_STATE_PLAYING); - - /* now run */ - g_main_loop_run (loop); - - /* also clean up */ - gst_element_set_state (pipeline, GST_STATE_NULL); - gst_element_release_request_pad (osel, osel_src1); - gst_element_release_request_pad (osel, osel_src2); - gst_object_unref (GST_OBJECT (pipeline)); - - return 0; -} diff --git a/tools/Makefile.am b/tools/Makefile.am index 54cdae13e..641293052 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,20 +1,29 @@ +templatefiles=\ + element-templates/audiofilter \ + element-templates/audiosink \ + element-templates/audiosrc \ + element-templates/base \ + element-templates/baseaudiosink \ + element-templates/baseaudiosrc \ + element-templates/basertpdepayload \ + element-templates/basertppayload \ + element-templates/basesink \ + element-templates/basesrc \ + element-templates/basetransform \ + element-templates/cddabasesrc \ + element-templates/element \ + element-templates/gobject \ + element-templates/pushsrc \ + element-templates/sinkpad \ + element-templates/sinkpad-simple \ + element-templates/srcpad \ + element-templates/srcpad-simple \ + element-templates/tagdemux \ + element-templates/videosink + EXTRA_DIST = \ - element-maker \ - base.c \ - gobject.c \ - gstaudiofilter.c \ - gstaudiosink.c \ - gstaudiosrc.c \ - gstbaseaudiosink.c \ - gstbaseaudiosrc.c \ - gstbasertpdepayload.c \ - gstbasertppayload.c \ - gstbasesink.c \ - gstbasesrc.c \ - gstbasetransform.c \ - gstcddabasesrc.c \ - gstelement.c \ - gstpushsrc.c \ - gsttagdemux.c \ - gstvideosink.c + gst-element-maker \ + gst-app-maker \ + $(templatefiles) + diff --git a/tools/gstaudiofilter.c b/tools/element-templates/audiofilter index 018128153..2d0929364 100644 --- a/tools/gstaudiofilter.c +++ b/tools/element-templates/audiofilter @@ -1,7 +1,10 @@ +/* vim: set filetype=c: */ % ClassName GstAudioFilter % TYPE_CLASS_NAME GST_TYPE_AUDIO_FILTER +% pads +sinkpad-simple srcpad-simple % pkg-config gstreamer-audio-0.10 % includes diff --git a/tools/gstaudiosrc.c b/tools/element-templates/audiosink index 95f20e752..2a1b7a421 100644 --- a/tools/gstaudiosrc.c +++ b/tools/element-templates/audiosink @@ -1,55 +1,69 @@ +/* vim: set filetype=c: */ % ClassName -GstAudioSrc +GstAudioSink % TYPE_CLASS_NAME -GST_TYPE_AUDIO_SRC +GST_TYPE_AUDIO_SINK +% pads +sinkpad-simple % pkg-config gstreamer-audio-0.10 % includes -#include <gst/audio/gstaudiosrc.h> +#include <gst/audio/gstaudiosink.h> % prototypes static gboolean gst_replace_open (GstAudioSink * sink); static gboolean gst_replace_prepare (GstAudioSink * sink, GstRingBufferSpec * spec); static gboolean gst_replace_unprepare (GstAudioSink * sink); static gboolean gst_replace_close (GstAudioSink * sink); -static guint -gst_replace_write (GstAudioSink * sink, gpointer data, guint length); +static guint gst_replace_write (GstAudioSink * sink, gpointer data, guint length); static guint gst_replace_delay (GstAudioSink * sink); static void gst_replace_reset (GstAudioSink * sink); % declare-class - GstAudioSrc *audio_src_class = GST_AUDIO_SRC (klass); + GstAudioSinkClass *audio_sink_class = GST_AUDIO_SINK_CLASS (klass); % set-methods - audio_src_class-> = GST_DEBUG_FUNCPTR (gst_replace_); + audio_sink_class->open = GST_DEBUG_FUNCPTR (gst_replace_open); + audio_sink_class->prepare = GST_DEBUG_FUNCPTR (gst_replace_prepare); + audio_sink_class->unprepare = GST_DEBUG_FUNCPTR (gst_replace_unprepare); + audio_sink_class->close = GST_DEBUG_FUNCPTR (gst_replace_close); + audio_sink_class->write = GST_DEBUG_FUNCPTR (gst_replace_write); + audio_sink_class->delay = GST_DEBUG_FUNCPTR (gst_replace_delay); + audio_sink_class->reset = GST_DEBUG_FUNCPTR (gst_replace_reset); % methods static gboolean gst_replace_open (GstAudioSink * sink) { + return FALSE; } static gboolean gst_replace_prepare (GstAudioSink * sink, GstRingBufferSpec * spec) { + return FALSE; } static gboolean gst_replace_unprepare (GstAudioSink * sink) { + return FALSE; } static gboolean gst_replace_close (GstAudioSink * sink) { + return FALSE; } static guint gst_replace_write (GstAudioSink * sink, gpointer data, guint length) { + return 0; } static guint gst_replace_delay (GstAudioSink * sink) { + return 0; } static void diff --git a/tools/gstaudiosink.c b/tools/element-templates/audiosrc index 9c2a58c7b..fe4f6129f 100644 --- a/tools/gstaudiosink.c +++ b/tools/element-templates/audiosrc @@ -1,54 +1,70 @@ +/* vim: set filetype=c: */ % ClassName -GstAudioSink +GstAudioSrc % TYPE_CLASS_NAME -GST_TYPE_AUDIO_SINK +GST_TYPE_AUDIO_SRC +% pads +srcpad-simple % pkg-config gstreamer-audio-0.10 % includes -#include <gst/audio/gstaudiosink.h> +#include <gst/audio/gstaudiosrc.h> % prototypes static gboolean gst_replace_open (GstAudioSrc * src); static gboolean gst_replace_prepare (GstAudioSrc * src, GstRingBufferSpec * spec); static gboolean gst_replace_unprepare (GstAudioSrc * src); static gboolean gst_replace_close (GstAudioSrc * src); -static guint gst_replace_read (GstAudioSrc * src, gpointer data, guint length); +static guint +gst_replace_read (GstAudioSrc * src, gpointer data, guint length); static guint gst_replace_delay (GstAudioSrc * src); static void gst_replace_reset (GstAudioSrc * src); % declare-class - GstAudioSink *audio_sink_class = GST_AUDIO_SINK (klass); + GstAudioSrcClass *audio_src_class = GST_AUDIO_SRC_CLASS (klass); % set-methods - audio_sink_class-> = GST_DEBUG_FUNCPTR (gst_replace_); + audio_src_class->open = GST_DEBUG_FUNCPTR (gst_replace_open); + audio_src_class->prepare = GST_DEBUG_FUNCPTR (gst_replace_prepare); + audio_src_class->unprepare = GST_DEBUG_FUNCPTR (gst_replace_unprepare); + audio_src_class->close = GST_DEBUG_FUNCPTR (gst_replace_close); + audio_src_class->read = GST_DEBUG_FUNCPTR (gst_replace_read); + audio_src_class->delay = GST_DEBUG_FUNCPTR (gst_replace_delay); + audio_src_class->reset = GST_DEBUG_FUNCPTR (gst_replace_reset); % methods static gboolean gst_replace_open (GstAudioSrc * src) { + return FALSE; } static gboolean gst_replace_prepare (GstAudioSrc * src, GstRingBufferSpec * spec) { + return FALSE; } static gboolean gst_replace_unprepare (GstAudioSrc * src) { + return FALSE; } static gboolean gst_replace_close (GstAudioSrc * src) { + return FALSE; } static guint gst_replace_read (GstAudioSrc * src, gpointer data, guint length) { + return 0; } static guint gst_replace_delay (GstAudioSrc * src) { + return 0; } static void diff --git a/tools/base.c b/tools/element-templates/base index 990168a31..44d652892 100644 --- a/tools/base.c +++ b/tools/element-templates/base @@ -1,3 +1,4 @@ +/* vim: set filetype=c: */ % copyright /* GStreamer diff --git a/tools/gstbaseaudiosink.c b/tools/element-templates/baseaudiosink index 2f36e84c9..4d6555d7d 100644 --- a/tools/gstbaseaudiosink.c +++ b/tools/element-templates/baseaudiosink @@ -1,7 +1,10 @@ +/* vim: set filetype=c: */ % ClassName GstBaseAudioSink % TYPE_CLASS_NAME GST_TYPE_BASE_AUDIO_SINK +% pads +sinkpad-simple % pkg-config gstreamer-audio-0.10 % includes @@ -9,14 +12,14 @@ gstreamer-audio-0.10 % prototypes static GstRingBuffer *gst_replace_create_ringbuffer (GstBaseAudioSink * sink); % declare-class - GstBaseAudioSink *base_audio_sink_class = GST_BASE_AUDIO_SINK (klass); + GstBaseAudioSinkClass *base_audio_sink_class = GST_BASE_AUDIO_SINK_CLASS (klass); % set-methods - base_audio_sink_class-> = GST_DEBUG_FUNCPTR (gst_replace_); + base_audio_sink_class->create_ringbuffer = GST_DEBUG_FUNCPTR (gst_replace_create_ringbuffer); % methods static GstRingBuffer * gst_replace_create_ringbuffer (GstBaseAudioSink * sink) { - + return NULL; } % end diff --git a/tools/gstbaseaudiosrc.c b/tools/element-templates/baseaudiosrc index c87bb32c0..8b0e4ab0e 100644 --- a/tools/gstbaseaudiosrc.c +++ b/tools/element-templates/baseaudiosrc @@ -1,7 +1,10 @@ +/* vim: set filetype=c: */ % ClassName GstBaseAudioSrc % TYPE_CLASS_NAME GST_TYPE_BASE_AUDIO_SRC +% pads +srcpad-simple % pkg-config gstreamer-audio-0.10 % includes @@ -9,14 +12,15 @@ gstreamer-audio-0.10 % prototypes static GstRingBuffer *gst_replace_create_ringbuffer (GstBaseAudioSrc * src); % declare-class - GstBaseAudioSrc *base_audio_src_class = GST_BASE_AUDIO_SRC (klass); + GstBaseAudioSrcClass *base_audio_src_class = GST_BASE_AUDIO_SRC_CLASS (klass); % set-methods - base_audio_src_class-> = GST_DEBUG_FUNCPTR (gst_replace_); + base_audio_src_class->create_ringbuffer = GST_DEBUG_FUNCPTR (gst_replace_create_ringbuffer); % methods static GstRingBuffer * gst_replace_create_ringbuffer (GstBaseAudioSrc * src) { + return NULL; } % end diff --git a/tools/element-templates/baseparse b/tools/element-templates/baseparse new file mode 100644 index 000000000..ff56b3ca4 --- /dev/null +++ b/tools/element-templates/baseparse @@ -0,0 +1,109 @@ +% ClassName +GstBaseParse +% TYPE_CLASS_NAME +GST_TYPE_BASE_PARSE +% pkg-config +gstreamer-base-0.10 +% includes +#include <gst/baseparse/gstbaseparse.h> +% prototypes +static gboolean gst_replace_start (GstBaseParse *parse); +static gboolean gst_replace_stop (GstBaseParse *parse); +static gboolean gst_replace_set_sink_caps (GstBaseParse *parse, GstCaps *caps); +static gboolean gst_replace_check_valid_frame (GstBaseParse *parse, + GstBaseParseFrame *frame, guint *framesize, gint *skipsize); +static GstFlowReturn gst_replace_parse_frame (GstBaseParse *parse, + GstBaseParseFrame *frame); +static gboolean gst_replace_convert (GstBaseParse * parse, + GstFormat src_format, gint64 src_value, GstFormat dest_format, + gint64 * dest_value); +static gboolean gst_replace_event (GstBaseParse *parse, GstEvent *event); +static gboolean gst_replace_src_event (GstBaseParse *parse, GstEvent *event); +static GstFlowReturn gst_replace_pre_push_frame (GstBaseParse *parse, + GstBaseParseFrame *frame); +% declare-class + GstBaseParseClass *base_parse_class = GST_BASE_PARSE_CLASS (klass); +% set-methods + base_parse_class->start = GST_DEBUG_FUNCPTR (gst_replace_start); + base_parse_class->stop = GST_DEBUG_FUNCPTR (gst_replace_stop); + base_parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_replace_set_sink_caps); + base_parse_class->check_valid_frame = GST_DEBUG_FUNCPTR (gst_replace_check_valid_frame); + base_parse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_replace_parse_frame); + base_parse_class->pre_push_frame = GST_DEBUG_FUNCPTR (gst_replace_pre_push_frame); + base_parse_class->convert = GST_DEBUG_FUNCPTR (gst_replace_convert); + base_parse_class->event = GST_DEBUG_FUNCPTR (gst_replace_event); + base_parse_class->src_event = GST_DEBUG_FUNCPTR (gst_replace_src_event); +% methods + +static gboolean +gst_replace_start (GstBaseParse *parse) +{ + return TRUE; +} + +static gboolean +gst_replace_stop (GstBaseParse *parse) +{ + return TRUE; +} + +static gboolean +gst_replace_set_sink_caps (GstBaseParse *parse, GstCaps *caps) +{ + /* Called when sink caps are set */ + return TRUE; +} + +static gboolean +gst_replace_check_valid_frame (GstBaseParse *parse, + GstBaseParseFrame *frame, guint *framesize, gint *skipsize) +{ + /* Called when processing incoming buffers. Function should check + whether the buffer contains a valid frame */ + /* MUST implement */ + return TRUE; +} + +static GstFlowReturn +gst_replace_parse_frame (GstBaseParse *parse, + GstBaseParseFrame *frame) +{ + /* Called when processing incoming buffers. Function should parse + a checked frame. */ + /* MUST implement */ + return GST_FLOW_OK; +} + +static gboolean +gst_replace_convert (GstBaseParse * parse, GstFormat src_format, + gint64 src_value, GstFormat dest_format, gint64 * dest_value) +{ + /* Convert between formats */ + + return FALSE; +} + +static gboolean +gst_replace_event (GstBaseParse *parse, GstEvent *event) +{ + /* Sink pad event handler */ + + return FALSE; +} + +static gboolean +gst_replace_src_event (GstBaseParse *parse, GstEvent *event) +{ + /* Src pad event handler */ + + return FALSE; +} + +static GstFlowReturn +gst_replace_pre_push_frame (GstBaseParse *parse, GstBaseParseFrame *frame) +{ + + return GST_FLOW_OK; +} + +% end diff --git a/tools/gstbasertpdepayload.c b/tools/element-templates/basertpdepayload index b0810be25..8b40e5265 100644 --- a/tools/gstbasertpdepayload.c +++ b/tools/element-templates/basertpdepayload @@ -1,7 +1,10 @@ +/* vim: set filetype=c: */ % ClassName GstBaseRTPDepayload % TYPE_CLASS_NAME GST_TYPE_BASE_RTP_DEPAYLOAD +% pads +sinkpad-simple srcpad-simple % pkg-config gstreamer-rtp-0.10 % includes diff --git a/tools/gstbasertppayload.c b/tools/element-templates/basertppayload index a871e901c..1a5be183d 100644 --- a/tools/gstbasertppayload.c +++ b/tools/element-templates/basertppayload @@ -1,7 +1,10 @@ +/* vim: set filetype=c: */ % ClassName GstBaseRTPPayload % TYPE_CLASS_NAME GST_TYPE_BASE_RTP_PAYLOAD +% pads +sinkpad-simple srcpad-simple % pkg-config gstreamer-rtp-0.10 % includes diff --git a/tools/gstbasesink.c b/tools/element-templates/basesink index 6646dd9f9..bf018283d 100644 --- a/tools/gstbasesink.c +++ b/tools/element-templates/basesink @@ -1,7 +1,10 @@ +/* vim: set filetype=c: */ % ClassName GstBaseSink % TYPE_CLASS_NAME GST_TYPE_BASE_SINK +% pads +sinkpad-simple % pkg-config gstreamer-base-0.10 % includes diff --git a/tools/gstbasesrc.c b/tools/element-templates/basesrc index 240a16d25..0b7e56fc1 100644 --- a/tools/gstbasesrc.c +++ b/tools/element-templates/basesrc @@ -1,7 +1,10 @@ +/* vim: set filetype=c: */ % ClassName GstBaseSrc % TYPE_CLASS_NAME GST_TYPE_BASE_SRC +% pads +srcpad-simple % pkg-config gstreamer-base-0.10 % includes diff --git a/tools/gstbasetransform.c b/tools/element-templates/basetransform index 47d42d39f..e5fd24cf3 100644 --- a/tools/gstbasetransform.c +++ b/tools/element-templates/basetransform @@ -1,9 +1,14 @@ +/* vim: set filetype=c: */ % ClassName GstBaseTransform % TYPE_CLASS_NAME GST_TYPE_BASE_TRANSFORM +% pads +sinkpad-simple srcpad-simple % pkg-config gstreamer-base-0.10 +% pads +sinkpad-simple srcpad-simple % includes #include <gst/base/gstbasetransform.h> % prototypes diff --git a/tools/gstcddabasesrc.c b/tools/element-templates/cddabasesrc index d0e0a804f..d788d19c4 100644 --- a/tools/gstcddabasesrc.c +++ b/tools/element-templates/cddabasesrc @@ -1,7 +1,10 @@ +/* vim: set filetype=c: */ % ClassName GstCddaBaseSrc % TYPE_CLASS_NAME GST_TYPE_CDDA_BASE_SRC +% pads +srcpad-simple % pkg-config gstreamer-cdda-0.10 % includes diff --git a/tools/gstelement.c b/tools/element-templates/element index 293341cdd..ed025ee2b 100644 --- a/tools/gstelement.c +++ b/tools/element-templates/element @@ -1,7 +1,10 @@ +/* vim: set filetype=c: */ % ClassName GstElement % TYPE_CLASS_NAME GST_TYPE_ELEMENT +% pads +sinkpad srcpad % pkg-config gstreamer-0.10 % includes @@ -11,35 +14,24 @@ static GstPad *gst_replace_request_new_pad (GstElement * element, GstPadTemplate * templ, const gchar * name); static void gst_replace_release_pad (GstElement * element, GstPad * pad); static GstStateChangeReturn -gst_replace_get_state (GstElement * element, GstState * state, - GstState * pending, GstClockTime timeout); -static GstStateChangeReturn -gst_replace_set_state (GstElement * element, GstState state); -static GstStateChangeReturn gst_replace_change_state (GstElement * element, GstStateChange transition); -static void gst_replace_set_bus (GstElement * element, GstBus * bus); static GstClock *gst_replace_provide_clock (GstElement * element); static gboolean gst_replace_set_clock (GstElement * element, GstClock * clock); static GstIndex *gst_replace_get_index (GstElement * element); static void gst_replace_set_index (GstElement * element, GstIndex * index); static gboolean gst_replace_send_event (GstElement * element, GstEvent * event); -static const GstQueryType *gst_replace_get_query_types (GstElement * element); static gboolean gst_replace_query (GstElement * element, GstQuery * query); % declare-class GstElementClass *element_class = GST_ELEMENT_CLASS (klass); % set-methods element_class->request_new_pad = GST_DEBUG_FUNCPTR (gst_replace_request_new_pad); element_class->release_pad = GST_DEBUG_FUNCPTR (gst_replace_release_pad); - element_class->get_state = GST_DEBUG_FUNCPTR (gst_replace_get_state); - element_class->set_state = GST_DEBUG_FUNCPTR (gst_replace_set_state); element_class->change_state = GST_DEBUG_FUNCPTR (gst_replace_change_state); - element_class->set_bus = GST_DEBUG_FUNCPTR (gst_replace_set_bus); element_class->provide_clock = GST_DEBUG_FUNCPTR (gst_replace_provide_clock); element_class->set_clock = GST_DEBUG_FUNCPTR (gst_replace_set_clock); element_class->get_index = GST_DEBUG_FUNCPTR (gst_replace_get_index); element_class->set_index = GST_DEBUG_FUNCPTR (gst_replace_set_index); element_class->send_event = GST_DEBUG_FUNCPTR (gst_replace_send_event); - element_class->get_query_types = GST_DEBUG_FUNCPTR (gst_replace_get_query_types); element_class->query = GST_DEBUG_FUNCPTR (gst_replace_query); % methods @@ -59,31 +51,39 @@ gst_replace_release_pad (GstElement * element, GstPad * pad) } static GstStateChangeReturn -gst_replace_get_state (GstElement * element, GstState * state, - GstState * pending, GstClockTime timeout) -{ - - return GST_STATE_CHANGE_SUCCESS; -} - -static GstStateChangeReturn -gst_replace_set_state (GstElement * element, GstState state) -{ - - return GST_STATE_CHANGE_SUCCESS; -} - -static GstStateChangeReturn gst_replace_change_state (GstElement * element, GstStateChange transition) { - - return GST_STATE_CHANGE_SUCCESS; -} - -static void -gst_replace_set_bus (GstElement * element, GstBus * bus) -{ - + GstReplace *replace; + GstStateChangeReturn ret; + + g_return_val_if_fail (GST_IS_REPLACE (element), GST_STATE_CHANGE_FAILURE); + replace = GST_REPLACE (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + 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: + break; + case GST_STATE_CHANGE_READY_TO_NULL: + break; + default: + break; + } + + return ret; } static GstClock * @@ -120,13 +120,6 @@ gst_replace_send_event (GstElement * element, GstEvent * event) return TRUE; } -static const GstQueryType * -gst_replace_get_query_types (GstElement * element) -{ - - return NULL; -} - static gboolean gst_replace_query (GstElement * element, GstQuery * query) { diff --git a/tools/gobject.c b/tools/element-templates/gobject index dc5392d86..4ef34e6c2 100644 --- a/tools/gobject.c +++ b/tools/element-templates/gobject @@ -1,3 +1,4 @@ +/* vim: set filetype=c: */ % includes % prototypes diff --git a/tools/element-templates/pushsrc b/tools/element-templates/pushsrc new file mode 100644 index 000000000..56cc7a6bf --- /dev/null +++ b/tools/element-templates/pushsrc @@ -0,0 +1,235 @@ +/* vim: set filetype=c: */ +% ClassName +GstPushSrc +% TYPE_CLASS_NAME +GST_TYPE_PUSH_SRC +% pads +srcpad-simple +% pkg-config +gstreamer-base-0.10 +% includes +#include <gst/base/gstpushsrc.h> +% prototypes +static GstCaps *gst_replace_get_caps (GstBaseSrc * src); +static gboolean gst_replace_set_caps (GstBaseSrc * src, GstCaps * caps); +static gboolean gst_replace_negotiate (GstBaseSrc * src); +static gboolean gst_replace_newsegment (GstBaseSrc * src); +static gboolean gst_replace_start (GstBaseSrc * src); +static gboolean gst_replace_stop (GstBaseSrc * src); +static void +gst_replace_get_times (GstBaseSrc * src, GstBuffer * buffer, + GstClockTime * start, GstClockTime * end); +static gboolean gst_replace_get_size (GstBaseSrc * src, guint64 * size); +static gboolean gst_replace_is_seekable (GstBaseSrc * src); +static gboolean gst_replace_unlock (GstBaseSrc * src); +static gboolean gst_replace_event (GstBaseSrc * src, GstEvent * event); +static gboolean gst_replace_do_seek (GstBaseSrc * src, GstSegment * segment); +static gboolean gst_replace_query (GstBaseSrc * src, GstQuery * query); +static gboolean gst_replace_check_get_range (GstBaseSrc * src); +static void gst_replace_fixate (GstBaseSrc * src, GstCaps * caps); +static gboolean gst_replace_unlock_stop (GstBaseSrc * src); +static gboolean +gst_replace_prepare_seek_segment (GstBaseSrc * src, GstEvent * seek, + GstSegment * segment); +static GstFlowReturn gst_replace_create (GstPushSrc * src, GstBuffer ** buf); +% declare-class + GstBaseSrcClass *base_src_class = GST_BASE_SRC_CLASS (klass); + GstPushSrcClass *push_src_class = GST_PUSH_SRC_CLASS (klass); +% set-methods + base_src_class->get_caps = GST_DEBUG_FUNCPTR (gst_replace_get_caps); + base_src_class->set_caps = GST_DEBUG_FUNCPTR (gst_replace_set_caps); + base_src_class->negotiate = GST_DEBUG_FUNCPTR (gst_replace_negotiate); + base_src_class->newsegment = GST_DEBUG_FUNCPTR (gst_replace_newsegment); + base_src_class->start = GST_DEBUG_FUNCPTR (gst_replace_start); + base_src_class->stop = GST_DEBUG_FUNCPTR (gst_replace_stop); + base_src_class->get_times = GST_DEBUG_FUNCPTR (gst_replace_get_times); + base_src_class->get_size = GST_DEBUG_FUNCPTR (gst_replace_get_size); + base_src_class->is_seekable = GST_DEBUG_FUNCPTR (gst_replace_is_seekable); + base_src_class->unlock = GST_DEBUG_FUNCPTR (gst_replace_unlock); + base_src_class->event = GST_DEBUG_FUNCPTR (gst_replace_event); + base_src_class->do_seek = GST_DEBUG_FUNCPTR (gst_replace_do_seek); + base_src_class->query = GST_DEBUG_FUNCPTR (gst_replace_query); + base_src_class->check_get_range = GST_DEBUG_FUNCPTR (gst_replace_check_get_range); + base_src_class->fixate = GST_DEBUG_FUNCPTR (gst_replace_fixate); + base_src_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_replace_unlock_stop); + base_src_class->prepare_seek_segment = GST_DEBUG_FUNCPTR (gst_replace_prepare_seek_segment); + + push_src_class->create = GST_DEBUG_FUNCPTR (gst_replace_create); +% methods + +static GstCaps * +gst_replace_get_caps (GstBaseSrc * src) +{ + GstReplace *replace = GST_REPLACE (src); + + GST_DEBUG_OBJECT (replace, "get_caps"); + + return NULL; +} + +static gboolean +gst_replace_set_caps (GstBaseSrc * src, GstCaps * caps) +{ + GstReplace *replace = GST_REPLACE (src); + + GST_DEBUG_OBJECT (replace, "set_caps"); + + return TRUE; +} + +static gboolean +gst_replace_negotiate (GstBaseSrc * src) +{ + GstReplace *replace = GST_REPLACE (src); + + GST_DEBUG_OBJECT (replace, "negotiate"); + + return TRUE; +} + +static gboolean +gst_replace_newsegment (GstBaseSrc * src) +{ + GstReplace *replace = GST_REPLACE (src); + + GST_DEBUG_OBJECT (replace, "newsegment"); + + return TRUE; +} + +static gboolean +gst_replace_start (GstBaseSrc * src) +{ + GstReplace *replace = GST_REPLACE (src); + + GST_DEBUG_OBJECT (replace, "start"); + + return TRUE; +} + +static gboolean +gst_replace_stop (GstBaseSrc * src) +{ + GstReplace *replace = GST_REPLACE (src); + + GST_DEBUG_OBJECT (replace, "stop"); + + return TRUE; +} + +static void +gst_replace_get_times (GstBaseSrc * src, GstBuffer * buffer, + GstClockTime * start, GstClockTime * end) +{ + GstReplace *replace = GST_REPLACE (src); + + GST_DEBUG_OBJECT (replace, "get_times"); +} + +static gboolean +gst_replace_get_size (GstBaseSrc * src, guint64 * size) +{ + GstReplace *replace = GST_REPLACE (src); + + GST_DEBUG_OBJECT (replace, "get_size"); + + return TRUE; +} + +static gboolean +gst_replace_is_seekable (GstBaseSrc * src) +{ + GstReplace *replace = GST_REPLACE (src); + + GST_DEBUG_OBJECT (replace, "is_seekable"); + + return FALSE; +} + +static gboolean +gst_replace_unlock (GstBaseSrc * src) +{ + GstReplace *replace = GST_REPLACE (src); + + GST_DEBUG_OBJECT (replace, "unlock"); + + return TRUE; +} + +static gboolean +gst_replace_event (GstBaseSrc * src, GstEvent * event) +{ + GstReplace *replace = GST_REPLACE (src); + + GST_DEBUG_OBJECT (replace, "event"); + + return TRUE; +} + +static gboolean +gst_replace_do_seek (GstBaseSrc * src, GstSegment * segment) +{ + GstReplace *replace = GST_REPLACE (src); + + GST_DEBUG_OBJECT (replace, "do_seek"); + + return FALSE; +} + +static gboolean +gst_replace_query (GstBaseSrc * src, GstQuery * query) +{ + GstReplace *replace = GST_REPLACE (src); + + GST_DEBUG_OBJECT (replace, "query"); + + return TRUE; +} + +static gboolean +gst_replace_check_get_range (GstBaseSrc * src) +{ + GstReplace *replace = GST_REPLACE (src); + + GST_DEBUG_OBJECT (replace, "get_range"); + + return FALSE; +} + +static void +gst_replace_fixate (GstBaseSrc * src, GstCaps * caps) +{ + GstReplace *replace = GST_REPLACE (src); + + GST_DEBUG_OBJECT (replace, "fixate"); +} + +static gboolean +gst_replace_unlock_stop (GstBaseSrc * src) +{ + GstReplace *replace = GST_REPLACE (src); + + GST_DEBUG_OBJECT (replace, "stop"); + + return TRUE; +} + +static gboolean +gst_replace_prepare_seek_segment (GstBaseSrc * src, GstEvent * seek, + GstSegment * segment) +{ + GstReplace *replace = GST_REPLACE (src); + + GST_DEBUG_OBJECT (replace, "seek_segment"); + + return FALSE; +} + +static GstFlowReturn +gst_replace_create (GstPushSrc * src, GstBuffer ** buf) +{ + + return GST_FLOW_OK; +} +% end + diff --git a/tools/element-templates/sinkpad b/tools/element-templates/sinkpad new file mode 100644 index 000000000..6d3bad1fb --- /dev/null +++ b/tools/element-templates/sinkpad @@ -0,0 +1,312 @@ +/* vim: set filetype=c: */ + +% instance-members + GstPad *sinkpad; +% prototypes + +static GstCaps* gst_replace_sink_getcaps (GstPad *pad); +static gboolean gst_replace_sink_setcaps (GstPad *pad, GstCaps *caps); +static gboolean gst_replace_sink_acceptcaps (GstPad *pad, GstCaps *caps); +static void gst_replace_sink_fixatecaps (GstPad *pad, GstCaps *caps); +static gboolean gst_replace_sink_activate (GstPad *pad); +static gboolean gst_replace_sink_activatepush (GstPad *pad, gboolean active); +static gboolean gst_replace_sink_activatepull (GstPad *pad, gboolean active); +static GstPadLinkReturn gst_replace_sink_link (GstPad *pad, GstPad *peer); +static void gst_replace_sink_unlink (GstPad *pad); +static GstFlowReturn gst_replace_sink_chain (GstPad *pad, GstBuffer *buffer); +static GstFlowReturn gst_replace_sink_chainlist (GstPad *pad, GstBufferList *bufferlist); +static gboolean gst_replace_sink_event (GstPad *pad, GstEvent *event); +static gboolean gst_replace_sink_query (GstPad *pad, GstQuery *query); +static GstFlowReturn gst_replace_sink_bufferalloc (GstPad *pad, guint64 offset, guint size, + GstCaps *caps, GstBuffer **buf); +static GstIterator * gst_replace_sink_iterintlink (GstPad *pad); + +% pad-template +static GstStaticPadTemplate gst_replace_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/unknown") + ); + +% base-init + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_replace_sink_template)); +% instance-init + + replace->sinkpad = gst_pad_new_from_static_template (&gst_replace_sink_template + , + "sink"); + gst_pad_set_getcaps_function (replace->sinkpad, + GST_DEBUG_FUNCPTR(gst_replace_sink_getcaps)); + gst_pad_set_setcaps_function (replace->sinkpad, + GST_DEBUG_FUNCPTR(gst_replace_sink_setcaps)); + gst_pad_set_acceptcaps_function (replace->sinkpad, + GST_DEBUG_FUNCPTR(gst_replace_sink_acceptcaps)); + gst_pad_set_fixatecaps_function (replace->sinkpad, + GST_DEBUG_FUNCPTR(gst_replace_sink_fixatecaps)); + gst_pad_set_activate_function (replace->sinkpad, + GST_DEBUG_FUNCPTR(gst_replace_sink_activate)); + gst_pad_set_activatepush_function (replace->sinkpad, + GST_DEBUG_FUNCPTR(gst_replace_sink_activatepush)); + gst_pad_set_activatepull_function (replace->sinkpad, + GST_DEBUG_FUNCPTR(gst_replace_sink_activatepull)); + gst_pad_set_link_function (replace->sinkpad, + GST_DEBUG_FUNCPTR(gst_replace_sink_link)); + gst_pad_set_unlink_function (replace->sinkpad, + GST_DEBUG_FUNCPTR(gst_replace_sink_unlink)); + gst_pad_set_chain_function (replace->sinkpad, + GST_DEBUG_FUNCPTR(gst_replace_sink_chain)); + gst_pad_set_chain_list_function (replace->sinkpad, + GST_DEBUG_FUNCPTR(gst_replace_sink_chainlist)); + gst_pad_set_event_function (replace->sinkpad, + GST_DEBUG_FUNCPTR(gst_replace_sink_event)); + gst_pad_set_query_function (replace->sinkpad, + GST_DEBUG_FUNCPTR(gst_replace_sink_query)); + gst_pad_set_bufferalloc_function (replace->sinkpad, + GST_DEBUG_FUNCPTR(gst_replace_sink_bufferalloc)); + gst_pad_set_iterate_internal_links_function (replace->sinkpad, + GST_DEBUG_FUNCPTR(gst_replace_sink_iterintlink)); + gst_element_add_pad (GST_ELEMENT(replace), replace->sinkpad); + + +% methods + +static GstCaps* +gst_replace_sink_getcaps (GstPad *pad) +{ + GstReplace *replace; + GstCaps *caps; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "getcaps"); + + caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); + + gst_object_unref (replace); + return caps; +} + +static gboolean +gst_replace_sink_setcaps (GstPad *pad, GstCaps *caps) +{ + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "setcaps"); + + + gst_object_unref (replace); + return TRUE; +} + +static gboolean +gst_replace_sink_acceptcaps (GstPad *pad, GstCaps *caps) +{ + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "acceptcaps"); + + + gst_object_unref (replace); + return TRUE; +} + +static void +gst_replace_sink_fixatecaps (GstPad *pad, GstCaps *caps) +{ + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "fixatecaps"); + + + gst_object_unref (replace); +} + +static gboolean +gst_replace_sink_activate (GstPad *pad) +{ + GstReplace *replace; + gboolean ret; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "activate"); + + if (gst_pad_check_pull_range (pad)) { + GST_DEBUG_OBJECT (pad, "activating pull"); + ret = gst_pad_activate_pull (pad, TRUE); + } else { + GST_DEBUG_OBJECT (pad, "activating push"); + ret = gst_pad_activate_push (pad, TRUE); + } + + gst_object_unref (replace); + return ret; +} + +static gboolean +gst_replace_sink_activatepush (GstPad *pad, gboolean active) +{ + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "activatepush"); + + + gst_object_unref (replace); + return TRUE; +} + +static gboolean +gst_replace_sink_activatepull (GstPad *pad, gboolean active) +{ + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "activatepull"); + + + gst_object_unref (replace); + return TRUE; +} + +static GstPadLinkReturn +gst_replace_sink_link (GstPad *pad, GstPad *peer) +{ + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "link"); + + + gst_object_unref (replace); + return GST_PAD_LINK_OK; +} + +static void +gst_replace_sink_unlink (GstPad *pad) +{ + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "unlink"); + + + gst_object_unref (replace); +} + +static GstFlowReturn +gst_replace_sink_chain (GstPad *pad, GstBuffer *buffer) +{ + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "chain"); + + + gst_object_unref (replace); + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_replace_sink_chainlist (GstPad *pad, GstBufferList *bufferlist) +{ + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "chainlist"); + + + gst_object_unref (replace); + return GST_FLOW_OK; +} + +static gboolean +gst_replace_sink_event (GstPad *pad, GstEvent *event) +{ + gboolean res; + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "event"); + + switch (GST_EVENT_TYPE (event)) { + default: + res = gst_pad_event_default (pad, event); + break; + } + + gst_object_unref (replace); + return res; +} + +static gboolean +gst_replace_sink_query (GstPad *pad, GstQuery *query) +{ + gboolean res; + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "query"); + + switch (GST_QUERY_TYPE(query)) { + default: + res = gst_pad_query_default (pad, query); + break; + } + + gst_object_unref (replace); + return res; +} + +static GstFlowReturn +gst_replace_sink_bufferalloc (GstPad *pad, guint64 offset, guint size, + GstCaps *caps, GstBuffer **buf) +{ + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "bufferalloc"); + + + *buf = gst_buffer_new_and_alloc (size); + gst_buffer_set_caps (*buf, caps); + + gst_object_unref (replace); + return GST_FLOW_OK; +} + +static GstIterator * +gst_replace_sink_iterintlink (GstPad *pad) +{ + GstReplace *replace; + GstIterator *iter; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "iterintlink"); + + iter = gst_pad_iterate_internal_links_default (pad); + + gst_object_unref (replace); + return iter; +} + +% end + diff --git a/tools/element-templates/sinkpad-simple b/tools/element-templates/sinkpad-simple new file mode 100644 index 000000000..e8538b6ec --- /dev/null +++ b/tools/element-templates/sinkpad-simple @@ -0,0 +1,24 @@ +/* vim: set filetype=c: */ + +% instance-members + GstPad *sinkpad; +% prototypes +% pad-template +static GstStaticPadTemplate gst_replace_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/unknown") + ); + +% base-init + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_replace_sink_template)); +% instance-init + + replace->sinkpad = gst_pad_new_from_static_template (&gst_replace_sink_template + , + "sink"); +% methods +% end + diff --git a/tools/element-templates/srcpad b/tools/element-templates/srcpad new file mode 100644 index 000000000..d1f799267 --- /dev/null +++ b/tools/element-templates/srcpad @@ -0,0 +1,275 @@ +/* vim: set filetype=c: */ + +% instance-members + GstPad *srcpad; +% prototypes + +static GstCaps* gst_replace_src_getcaps (GstPad *pad); +static gboolean gst_replace_src_setcaps (GstPad *pad, GstCaps *caps); +static gboolean gst_replace_src_acceptcaps (GstPad *pad, GstCaps *caps); +static void gst_replace_src_fixatecaps (GstPad *pad, GstCaps *caps); +static gboolean gst_replace_src_activate (GstPad *pad); +static gboolean gst_replace_src_activatepush (GstPad *pad, gboolean active); +static gboolean gst_replace_src_activatepull (GstPad *pad, gboolean active); +static GstPadLinkReturn gst_replace_src_link (GstPad *pad, GstPad *peer); +static void gst_replace_src_unlink (GstPad *pad); +static GstFlowReturn gst_replace_src_getrange (GstPad *pad, guint64 offset, guint length, + GstBuffer **buffer); +static gboolean gst_replace_src_event (GstPad *pad, GstEvent *event); +static gboolean gst_replace_src_query (GstPad *pad, GstQuery *query); +static GstIterator * gst_replace_src_iterintlink (GstPad *pad); + +% pad-template +static GstStaticPadTemplate gst_replace_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/unknown") + ); + +% base-init + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_replace_src_template)); +% instance-init + + replace->srcpad = gst_pad_new_from_static_template (&gst_replace_src_template + , + "src"); + gst_pad_set_getcaps_function (replace->srcpad, + GST_DEBUG_FUNCPTR(gst_replace_src_getcaps)); + gst_pad_set_setcaps_function (replace->srcpad, + GST_DEBUG_FUNCPTR(gst_replace_src_setcaps)); + gst_pad_set_acceptcaps_function (replace->srcpad, + GST_DEBUG_FUNCPTR(gst_replace_src_acceptcaps)); + gst_pad_set_fixatecaps_function (replace->srcpad, + GST_DEBUG_FUNCPTR(gst_replace_src_fixatecaps)); + gst_pad_set_activate_function (replace->srcpad, + GST_DEBUG_FUNCPTR(gst_replace_src_activate)); + gst_pad_set_activatepush_function (replace->srcpad, + GST_DEBUG_FUNCPTR(gst_replace_src_activatepush)); + gst_pad_set_activatepull_function (replace->srcpad, + GST_DEBUG_FUNCPTR(gst_replace_src_activatepull)); + gst_pad_set_link_function (replace->srcpad, + GST_DEBUG_FUNCPTR(gst_replace_src_link)); + gst_pad_set_unlink_function (replace->srcpad, + GST_DEBUG_FUNCPTR(gst_replace_src_unlink)); + gst_pad_set_getrange_function (replace->srcpad, + GST_DEBUG_FUNCPTR(gst_replace_src_getrange)); + gst_pad_set_event_function (replace->srcpad, + GST_DEBUG_FUNCPTR(gst_replace_src_event)); + gst_pad_set_query_function (replace->srcpad, + GST_DEBUG_FUNCPTR(gst_replace_src_query)); + gst_pad_set_iterate_internal_links_function (replace->srcpad, + GST_DEBUG_FUNCPTR(gst_replace_src_iterintlink)); + gst_element_add_pad (GST_ELEMENT(replace), replace->srcpad); + + +% methods + +static GstCaps* +gst_replace_src_getcaps (GstPad *pad) +{ + GstReplace *replace; + GstCaps *caps; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "getcaps"); + + caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); + + gst_object_unref (replace); + return caps; +} + +static gboolean +gst_replace_src_setcaps (GstPad *pad, GstCaps *caps) +{ + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "setcaps"); + + + gst_object_unref (replace); + return TRUE; +} + +static gboolean +gst_replace_src_acceptcaps (GstPad *pad, GstCaps *caps) +{ + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "acceptcaps"); + + + gst_object_unref (replace); + return TRUE; +} + +static void +gst_replace_src_fixatecaps (GstPad *pad, GstCaps *caps) +{ + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "fixatecaps"); + + + gst_object_unref (replace); +} + +static gboolean +gst_replace_src_activate (GstPad *pad) +{ + GstReplace *replace; + gboolean ret; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "activate"); + + if (gst_pad_check_pull_range (pad)) { + GST_DEBUG_OBJECT (pad, "activating pull"); + ret = gst_pad_activate_pull (pad, TRUE); + } else { + GST_DEBUG_OBJECT (pad, "activating push"); + ret = gst_pad_activate_push (pad, TRUE); + } + + gst_object_unref (replace); + return ret; +} + +static gboolean +gst_replace_src_activatepush (GstPad *pad, gboolean active) +{ + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "activatepush"); + + + gst_object_unref (replace); + return TRUE; +} + +static gboolean +gst_replace_src_activatepull (GstPad *pad, gboolean active) +{ + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "activatepull"); + + + gst_object_unref (replace); + return TRUE; +} + +static GstPadLinkReturn +gst_replace_src_link (GstPad *pad, GstPad *peer) +{ + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "link"); + + + gst_object_unref (replace); + return GST_PAD_LINK_OK; +} + +static void +gst_replace_src_unlink (GstPad *pad) +{ + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "unlink"); + + + gst_object_unref (replace); +} + +static GstFlowReturn +gst_replace_src_getrange (GstPad *pad, guint64 offset, guint length, + GstBuffer **buffer) +{ + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "getrange"); + + + gst_object_unref (replace); + return GST_FLOW_OK; +} + +static gboolean +gst_replace_src_event (GstPad *pad, GstEvent *event) +{ + gboolean res; + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "event"); + + switch (GST_EVENT_TYPE (event)) { + default: + res = gst_pad_event_default (pad, event); + break; + } + + gst_object_unref (replace); + return res; +} + +static gboolean +gst_replace_src_query (GstPad *pad, GstQuery *query) +{ + gboolean res; + GstReplace *replace; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "query"); + + switch (GST_QUERY_TYPE(query)) { + default: + res = gst_pad_query_default (pad, query); + break; + } + + gst_object_unref (replace); + return res; +} + +static GstIterator * +gst_replace_src_iterintlink (GstPad *pad) +{ + GstReplace *replace; + GstIterator *iter; + + replace = GST_REPLACE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT(replace, "iterintlink"); + + iter = gst_pad_iterate_internal_links_default (pad); + + gst_object_unref (replace); + return iter; +} + +% end + diff --git a/tools/element-templates/srcpad-simple b/tools/element-templates/srcpad-simple new file mode 100644 index 000000000..0fca9157e --- /dev/null +++ b/tools/element-templates/srcpad-simple @@ -0,0 +1,24 @@ +/* vim: set filetype=c: */ + +% instance-members + GstPad *srcpad; +% prototypes +% pad-template +static GstStaticPadTemplate gst_replace_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/unknown") + ); + +% base-init + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_replace_src_template)); +% instance-init + + replace->srcpad = gst_pad_new_from_static_template (&gst_replace_src_template + , + "src"); +% methods +% end + diff --git a/tools/gsttagdemux.c b/tools/element-templates/tagdemux index 7ddec9d87..8517c5802 100644 --- a/tools/gsttagdemux.c +++ b/tools/element-templates/tagdemux @@ -1,7 +1,10 @@ +/* vim: set filetype=c: */ % ClassName GstTagDemux % TYPE_CLASS_NAME GST_TYPE_TAG_DEMUX +% pads +sinkpad-simple srcpad-simple % pkg-config gstreamer-tag-0.10 % includes diff --git a/tools/gstvideosink.c b/tools/element-templates/videosink index ce12a07f3..d26de559b 100644 --- a/tools/gstvideosink.c +++ b/tools/element-templates/videosink @@ -1,7 +1,10 @@ +/* vim: set filetype=c: */ % ClassName GstVideoSink % TYPE_CLASS_NAME GST_TYPE_VIDEO_SINK +% pads +sinkpad-simple % pkg-config gstreamer-video-0.10 % includes diff --git a/tools/gst-app-maker b/tools/gst-app-maker new file mode 100755 index 000000000..f90944213 --- /dev/null +++ b/tools/gst-app-maker @@ -0,0 +1,545 @@ +#!/bin/sh + + +prefix=gst +templatedir=element-templates + +while [ "$1" ] ; do + case $1 in + --help) + cat <<-EOF +Usage: element-maker [OPTIONS] _NAME BASE_CLASS +Create a GStreamer application from a template. +Options: + --help Print this information + --prefix PREFIX Use PREFIX instead of "gst" +Example: 'gst-app-maker my_app' will create the file gstmyapp.c. +EOF + exit 0 + ;; + --prefix) + shift + prefix=$1 + ;; + -*) + echo Unknown option: $1 + exit 1 + ;; + *) + if [ "$name" = "" ]; then + name=$1 + else + echo Ignored: $1 + fi + esac + shift +done + +if [ "$name" = "" ] ; then + echo "Usage: element-maker [OPTIONS] ELEMENT_NAME BASE_CLASS" + exit 1 +fi + + +PREFIX=$(echo $prefix | sed -e 's/\(.*\)/\U\1/') +NAME=$(echo $name | sed -e 's/\(.*\)/\U\1/') +Prefix=$(echo $prefix | sed -e 's/_\(.\)/\U\1/g' -e 's/^\(.\)/\U\1/') +Name=$(echo $name | sed -e 's/_\(.\)/\U\1/g' -e 's/^\(.\)/\U\1/') + +GST_IS_REPLACE=${PREFIX}_IS_${NAME} +GST_REPLACE=${PREFIX}_${NAME} +GST_TYPE_REPLACE=${PREFIX}_TYPE_${NAME} +GstReplace=${Prefix}${Name} +gst_replace=${prefix}_${name} +gstreplace=${prefix}$(echo $name | sed -e 's/_//g') +replace=$(echo $name | sed -e 's/_//g') + +if [ "$REAL_NAME" = "" ] ; then + REAL_NAME=FIXME +fi +if [ "$EMAIL_ADDRESS" = "" ] ; then + EMAIL_ADDRESS=fixme@example.com +fi + + + +generate () +{ + +cat <<-EOF +/* GstReplace + * Copyright (C) $(date +%Y) $REAL_NAME <$EMAIL_ADDRESS> + * Copyright (C) 2010 Entropy Wave Inc + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gst/gst.h> + +#define GETTEXT_PACKAGE "replace" + + +typedef struct _GstReplace GstReplace; +struct _GstReplace { + GstElement *pipeline; + GstBus *bus; + GMainLoop *main_loop; + + GstElement *source_element; + GstElement *sink_element; + + gboolean paused_for_buffering; + guint timer_id; +}; + +GstReplace * gst_replace_new (void); +void gst_replace_free (GstReplace *replace); +void gst_replace_create_pipeline (GstReplace *replace); +void gst_replace_create_pipeline_playbin (GstReplace *replace, const char *uri); +void gst_replace_start (GstReplace *replace); +void gst_replace_stop (GstReplace *replace); + +static gboolean gst_replace_handle_message (GstBus *bus, GstMessage *message, + gpointer data); +static gboolean onesecond_timer (gpointer priv); + + +gboolean verbose; + +static GOptionEntry entries[] = +{ + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be verbose", NULL }, + + { NULL } + +}; + +int +main (int argc, char *argv[]) +{ + GError *error = NULL; + GOptionContext *context; + GstReplace *replace; + GMainLoop *main_loop; + + if (!g_thread_supported ()) g_thread_init(NULL); + + context = g_option_context_new ("- FIXME"); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + g_option_context_add_group (context, gst_init_get_option_group ()); + if (!g_option_context_parse (context, &argc, &argv, &error)) { + g_print ("option parsing failed: %s\n", error->message); + exit (1); + } + g_option_context_free (context); + + replace = gst_replace_new (); + + if (argc > 1) { + gchar *uri; + if (gst_uri_is_valid (argv[1])) { + uri = g_strdup (argv[1]); + } else { + uri = g_filename_to_uri (argv[1], NULL, NULL); + } + gst_replace_create_pipeline_playbin (replace, uri); + g_free (uri); + } else { + gst_replace_create_pipeline (replace); + } + + gst_replace_start (replace); + + main_loop = g_main_loop_new (NULL, TRUE); + replace->main_loop = main_loop; + + g_main_loop_run (main_loop); + + exit (0); +} + + +GstReplace * +gst_replace_new (void) +{ + GstReplace *replace; + + replace = g_new0 (GstReplace, 1); + + return replace; +} + +void +gst_replace_free (GstReplace *replace) +{ + if (replace->source_element) { + gst_object_unref (replace->source_element); + replace->source_element = NULL; + } + if (replace->sink_element) { + gst_object_unref (replace->sink_element); + replace->sink_element = NULL; + } + + if (replace->pipeline) { + gst_element_set_state (replace->pipeline, GST_STATE_NULL); + gst_object_unref (replace->pipeline); + replace->pipeline = NULL; + } + g_free (replace); +} + +void +gst_replace_create_pipeline_playbin (GstReplace *replace, const char *uri) +{ + GstElement *pipeline; + GError *error = NULL; + + pipeline = gst_pipeline_new (NULL); + gst_bin_add (GST_BIN(pipeline), + gst_element_factory_make ("playbin2", "source")); + + if (error) { + g_print("pipeline parsing error: %s\n", error->message); + gst_object_unref (pipeline); + return; + } + + replace->pipeline = pipeline; + + gst_pipeline_set_auto_flush_bus (GST_PIPELINE(pipeline), FALSE); + replace->bus = gst_pipeline_get_bus (GST_PIPELINE(pipeline)); + gst_bus_add_watch (replace->bus, gst_replace_handle_message, replace); + + replace->source_element = gst_bin_get_by_name (GST_BIN(pipeline), "source"); + g_print("source_element is %p\n", replace->source_element); + + g_print("setting uri to %s\n", uri); + g_object_set (replace->source_element, "uri", uri, NULL); +} + +void +gst_replace_create_pipeline (GstReplace *replace) +{ + GString *pipe_desc; + GstElement *pipeline; + GError *error = NULL; + + pipe_desc = g_string_new (""); + + g_string_append (pipe_desc, "videotestsrc name=source num-buffers=100 ! "); + g_string_append (pipe_desc, "timeoverlay ! "); + g_string_append (pipe_desc, "xvimagesink name=sink "); + g_string_append (pipe_desc, "audiotestsrc samplesperbuffer=1600 num-buffers=100 ! "); + g_string_append (pipe_desc, "alsasink "); + + if (verbose) g_print ("pipeline: %s\n", pipe_desc->str); + + pipeline = (GstElement *) gst_parse_launch (pipe_desc->str, &error); + g_string_free (pipe_desc, FALSE); + + if (error) { + g_print("pipeline parsing error: %s\n", error->message); + gst_object_unref (pipeline); + return; + } + + replace->pipeline = pipeline; + + gst_pipeline_set_auto_flush_bus (GST_PIPELINE(pipeline), FALSE); + replace->bus = gst_pipeline_get_bus (GST_PIPELINE(pipeline)); + gst_bus_add_watch (replace->bus, gst_replace_handle_message, replace); + + replace->source_element = gst_bin_get_by_name (GST_BIN(pipeline), "source"); + replace->sink_element = gst_bin_get_by_name (GST_BIN(pipeline), "sink"); +} + +void +gst_replace_start (GstReplace *replace) +{ + gst_element_set_state (replace->pipeline, GST_STATE_READY); + + replace->timer_id = g_timeout_add (1000, onesecond_timer, replace); +} + +void +gst_replace_stop (GstReplace *replace) +{ + gst_element_set_state (replace->pipeline, GST_STATE_NULL); + + g_source_remove (replace->timer_id); +} + +static void +gst_replace_handle_eos (GstReplace *replace) +{ + gst_replace_stop (replace); +} + +static void +gst_replace_handle_error (GstReplace *replace, GError *error, + const char *debug) +{ + g_print ("error: %s\n", error->message); + gst_replace_stop (replace); +} + +static void +gst_replace_handle_warning (GstReplace *replace, GError *error, + const char *debug) +{ + g_print ("warning: %s\n", error->message); +} + +static void +gst_replace_handle_info (GstReplace *replace, GError *error, + const char *debug) +{ + g_print ("info: %s\n", error->message); +} + +static void +gst_replace_handle_null_to_ready (GstReplace *replace) +{ + gst_element_set_state (replace->pipeline, GST_STATE_PAUSED); + +} + +static void +gst_replace_handle_ready_to_paused (GstReplace *replace) +{ + if (!replace->paused_for_buffering) { + gst_element_set_state (replace->pipeline, GST_STATE_PLAYING); + } +} + +static void +gst_replace_handle_paused_to_playing (GstReplace *replace) +{ + +} + +static void +gst_replace_handle_playing_to_paused (GstReplace *replace) +{ + +} + +static void +gst_replace_handle_paused_to_ready (GstReplace *replace) +{ + +} + +static void +gst_replace_handle_ready_to_null (GstReplace *replace) +{ + g_main_loop_quit (replace->main_loop); + +} + + +static gboolean +gst_replace_handle_message (GstBus *bus, GstMessage *message, + gpointer data) +{ + GstReplace *replace = (GstReplace *) data; + + switch (GST_MESSAGE_TYPE(message)) { + case GST_MESSAGE_EOS: + gst_replace_handle_eos (replace); + break; + case GST_MESSAGE_ERROR: + { + GError *error = NULL; + gchar *debug; + + gst_message_parse_error (message, &error, &debug); + gst_replace_handle_error (replace, error, debug); + } + break; + case GST_MESSAGE_WARNING: + { + GError *error = NULL; + gchar *debug; + + gst_message_parse_warning (message, &error, &debug); + gst_replace_handle_warning (replace, error, debug); + } + break; + case GST_MESSAGE_INFO: + { + GError *error = NULL; + gchar *debug; + + gst_message_parse_info (message, &error, &debug); + gst_replace_handle_info (replace, error, debug); + } + break; + case GST_MESSAGE_TAG: + { + GstTagList *tag_list; + + gst_message_parse_tag (message, &tag_list); + if (verbose) g_print("tag\n"); + } + break; + case GST_MESSAGE_STATE_CHANGED: + { + GstState oldstate, newstate, pending; + + gst_message_parse_state_changed (message, &oldstate, &newstate, + &pending); + if (GST_ELEMENT(message->src) == replace->pipeline) { + if (verbose) g_print("state change from %s to %s\n", + gst_element_state_get_name (oldstate), + gst_element_state_get_name (newstate)); + switch (GST_STATE_TRANSITION(oldstate, newstate)) { + case GST_STATE_CHANGE_NULL_TO_READY: + gst_replace_handle_null_to_ready (replace); + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + gst_replace_handle_ready_to_paused (replace); + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + gst_replace_handle_paused_to_playing (replace); + break; + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + gst_replace_handle_playing_to_paused (replace); + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + gst_replace_handle_paused_to_ready (replace); + break; + case GST_STATE_CHANGE_READY_TO_NULL: + gst_replace_handle_ready_to_null (replace); + break; + default: + if (verbose) g_print("unknown state change from %s to %s\n", + gst_element_state_get_name (oldstate), + gst_element_state_get_name (newstate)); + } + } + } + break; + case GST_MESSAGE_BUFFERING: + { + int percent; + gst_message_parse_buffering (message, &percent); + //g_print("buffering %d\n", percent); + if (!replace->paused_for_buffering && percent < 100) { + g_print ("pausing for buffing\n"); + replace->paused_for_buffering = TRUE; + gst_element_set_state (replace->pipeline, GST_STATE_PAUSED); + } else if (replace->paused_for_buffering && percent == 100) { + g_print ("unpausing for buffing\n"); + replace->paused_for_buffering = FALSE; + gst_element_set_state (replace->pipeline, GST_STATE_PLAYING); + } + } + break; + case GST_MESSAGE_STATE_DIRTY: + case GST_MESSAGE_CLOCK_PROVIDE: + case GST_MESSAGE_CLOCK_LOST: + case GST_MESSAGE_NEW_CLOCK: + case GST_MESSAGE_STRUCTURE_CHANGE: + case GST_MESSAGE_STREAM_STATUS: + break; + case GST_MESSAGE_STEP_DONE: + case GST_MESSAGE_APPLICATION: + case GST_MESSAGE_ELEMENT: + case GST_MESSAGE_SEGMENT_START: + case GST_MESSAGE_SEGMENT_DONE: + case GST_MESSAGE_DURATION: + case GST_MESSAGE_LATENCY: + case GST_MESSAGE_ASYNC_START: + case GST_MESSAGE_ASYNC_DONE: + case GST_MESSAGE_REQUEST_STATE: + case GST_MESSAGE_STEP_START: + case GST_MESSAGE_QOS: + default: + if (verbose) { + g_print ("message: %s\n", GST_MESSAGE_TYPE_NAME (message)); + } + break; + } + + return TRUE; +} + + + +static gboolean +onesecond_timer (gpointer priv) +{ + //GstReplace *replace = (GstReplace *)priv; + + g_print(".\n"); + + return TRUE; +} + + + +/* helper functions */ + +#if 0 +gboolean +have_element (const gchar *element_name) +{ + GstPluginFeature *feature; + + feature = gst_default_registry_find_feature (element_name, + GST_TYPE_ELEMENT_FACTORY); + if (feature) { + g_object_unref (feature); + return TRUE; + } + return FALSE; +} +#endif + +EOF + +} + +generate | sed \ + -e "s/GST_BASE_REPLACE/$GST_BASE_REPLACE/g" \ + -e "s/GST_TYPE_BASE_REPLACE/$GST_TYPE_BASE_REPLACE/g" \ + -e "s/GstBaseReplace/$GstBaseReplace/g" \ + -e "s/GST_IS_REPLACE/$GST_IS_REPLACE/g" \ + -e "s/GST_REPLACE/$GST_REPLACE/g" \ + -e "s/GST_TYPE_REPLACE/$GST_TYPE_REPLACE/g" \ + -e "s/GstReplace/$GstReplace/g" \ + -e "s/gst_replace/$gst_replace/g" \ + -e "s/gstreplace/$gstreplace/g" \ + -e "s/replace/$replace/g" >$gstreplace.c + +gst-indent $gstreplace.c + +gcc -Wall $(pkg-config --cflags gstreamer-0.10) -c -o $gstreplace.o $gstreplace.c +gcc -o $gstreplace $gstreplace.o $(pkg-config --libs gstreamer-0.10) + + diff --git a/tools/element-maker b/tools/gst-element-maker index 02127a97a..53b26cac8 100755 --- a/tools/element-maker +++ b/tools/gst-element-maker @@ -2,6 +2,7 @@ prefix=gst +templatedir=element-templates while [ "$1" ] ; do case $1 in @@ -43,7 +44,7 @@ if [ "$name" = "" -o "$class" = "" ] ; then exit 1 fi -if [ ! -f "gst$class.c" ] ; then +if [ ! -f "element-templates/$class" ] ; then echo "Template file for $class not found." exit 1 fi @@ -69,10 +70,11 @@ if [ "$EMAIL_ADDRESS" = "" ] ; then EMAIL_ADDRESS=fixme@example.com fi -source=gst$class.c -pkg=`grep -A 10000 '^% pkg-config' $source | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1` -GST_TYPE_BASE_REPLACE=`grep -A 10000 '^% TYPE_CLASS_NAME' $source | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1` -GstBaseReplace=`grep -A 10000 '^% ClassName' $source | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1` + +pkg=`grep -A 10000 '^% pkg-config' $templatedir/$class | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1` +GST_TYPE_BASE_REPLACE=`grep -A 10000 '^% TYPE_CLASS_NAME' $templatedir/$class | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1` +GstBaseReplace=`grep -A 10000 '^% ClassName' $templatedir/$class | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1` +pads=`grep -A 10000 '^% pads' $templatedir/$class | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1` generate () { @@ -93,8 +95,8 @@ cat <<-EOF * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, + * Boston, MA 02110-1335, USA. */ EOF @@ -102,19 +104,18 @@ cat <<-EOF /** * SECTION:element-$gstreplace * - * The $gstreplace element does FIXME stuff. + * The $replace element does FIXME stuff. * * <refsect2> * <title>Example launch line</title> * |[ - * gst-launch -v fakesrc ! $gstreplace ! FIXME ! fakesink + * gst-launch -v fakesrc ! $replace ! FIXME ! fakesink * ]| * FIXME Describe what the pipeline does. * </refsect2> */ EOF -#grep -A 10000 '^% copyright' base.c | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 cat <<EOF @@ -122,22 +123,28 @@ cat <<EOF #include "config.h" #endif +#include <gst/gst.h> EOF -grep -A 10000 '^% includes' base.c | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 -grep -A 10000 '^% includes' gobject.c | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 -grep -A 10000 '^% includes' $source | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 +grep -A 10000 '^% includes' $templatedir/gobject | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 +grep -A 10000 '^% includes' $templatedir/$class | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 cat <<EOF #include "gstreplace.h" +GST_DEBUG_CATEGORY_STATIC (gst_replace_debug_category); +#define GST_CAT_DEFAULT gst_replace_debug_category + /* prototypes */ EOF -grep -A 10000 '^% prototypes' base.c | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 -grep -A 10000 '^% prototypes' gobject.c | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 -grep -A 10000 '^% prototypes' $source | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 +grep -A 10000 '^% prototypes' $templatedir/gobject | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 +grep -A 10000 '^% prototypes' $templatedir/$class | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 +for each in $pads +do + grep -A 10000 '^% prototypes' $templatedir/$each | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 +done cat <<EOF @@ -148,52 +155,53 @@ enum /* pad templates */ -static GstStaticPadTemplate gst_replace_sink_template = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/unknown") - ); +EOF -static GstStaticPadTemplate gst_replace_src_template = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/unknown") - ); +for each in $pads +do + grep -A 10000 '^% pad-template' $templatedir/$each | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 +done + +cat <<EOF /* class initialization */ -GST_BOILERPLATE (GstReplace, gst_replace, GstBaseReplace, - GST_TYPE_BASE_REPLACE); +#define DEBUG_INIT(bla) \\ + GST_DEBUG_CATEGORY_INIT (gst_replace_debug_category, "replace", 0, \\ + "debug category for replace element"); + +GST_BOILERPLATE_FULL (GstReplace, gst_replace, GstBaseReplace, + GST_TYPE_BASE_REPLACE, DEBUG_INIT); static void gst_replace_base_init (gpointer g_class) { GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_replace_src_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_replace_sink_template)); +EOF + +for each in $pads +do + grep -A 10000 '^% base-init' $templatedir/$each | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 +done + +cat <<EOF - gst_element_class_set_details_simple (element_class, "FIXME", - "Generic", "FIXME", "$REAL_NAME <$EMAIL_ADDRESS>"); + gst_element_class_set_details_simple (element_class, "FIXME Long name", + "Generic", "FIXME Description", "$REAL_NAME <$EMAIL_ADDRESS>"); } static void gst_replace_class_init (GstReplaceClass * klass) { EOF -grep -A 10000 '^% declare-class' base.c | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 -grep -A 10000 '^% declare-class' gobject.c | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 -grep -A 10000 '^% declare-class' $source | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 +grep -A 10000 '^% declare-class' $templatedir/gobject | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 +grep -A 10000 '^% declare-class' $templatedir/$class | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 echo -grep -A 10000 '^% set-methods' base.c | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 -grep -A 10000 '^% set-methods' gobject.c | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 -grep -A 10000 '^% set-methods' $source | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 +grep -A 10000 '^% set-methods' $templatedir/gobject | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 +grep -A 10000 '^% set-methods' $templatedir/$class | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 cat <<EOF @@ -202,14 +210,25 @@ cat <<EOF static void gst_replace_init (GstReplace * replace, GstReplaceClass * replace_class) { +EOF +for each in $pads +do + grep -A 10000 '^% instance-init' $templatedir/$each | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 +done + + +cat <<EOF } EOF -grep -A 10000 '^% methods' base.c | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 -grep -A 10000 '^% methods' gobject.c | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 -grep -A 10000 '^% methods' $source | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 +grep -A 10000 '^% methods' $templatedir/gobject | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 +grep -A 10000 '^% methods' $templatedir/$class | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 +for each in $pads +do + grep -A 10000 '^% methods' $templatedir/$each | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 +done cat <<EOF @@ -224,16 +243,24 @@ plugin_init (GstPlugin * plugin) return TRUE; } +#ifndef VERSION #define VERSION "0.0.FIXME" +#endif +#ifndef PACKAGE #define PACKAGE "FIXME_package" +#endif +#ifndef PACKAGE_NAME #define PACKAGE_NAME "FIXME_package_name" -#define PACKAGE_ORIGIN "http://FIXME.org/" +#endif +#ifndef GST_PACKAGE_ORIGIN +#define GST_PACKAGE_ORIGIN "http://FIXME.org/" +#endif GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, "replace", - "FIXME", - plugin_init, VERSION, "LGPL", PACKAGE_NAME, PACKAGE_ORIGIN) + "FIXME plugin description", + plugin_init, VERSION, "LGPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN) EOF @@ -243,7 +270,27 @@ EOF generate_header () { -grep -A 10000 '^% copyright' base.c | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 +cat <<-EOF +/* GStreamer + * Copyright (C) $(date +%Y) $REAL_NAME <$EMAIL_ADDRESS> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +EOF cat <<EOF #ifndef _GST_REPLACE_H_ @@ -251,9 +298,8 @@ cat <<EOF EOF -grep -A 10000 '^% includes' base.c | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 -grep -A 10000 '^% includes' gobject.c | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 -grep -A 10000 '^% includes' $source | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 +grep -A 10000 '^% includes' $templatedir/gobject | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 +grep -A 10000 '^% includes' $templatedir/$class | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 cat <<EOF @@ -277,6 +323,14 @@ struct _GstReplace { GstBaseReplace base_replace; +EOF + +for each in $pads +do + grep -A 10000 '^% instance-members' $templatedir/$each | tail -n +2|grep -m 1 -B 10000 '^%'|head -n -1 +done + +cat <<EOF }; struct _GstReplaceClass @@ -323,7 +377,7 @@ gst-indent $gstreplace.c echo pkg is $pkg -gcc -Wall $(pkg-config --cflags gstreamer-0.10 $pkg) -c -o $gstreplace.o $gstreplace.c +gcc -Wall -fPIC $(pkg-config --cflags gstreamer-0.10 $pkg) -c -o $gstreplace.o $gstreplace.c gcc -shared -o $gstreplace.so $gstreplace.o $(pkg-config --libs gstreamer-0.10 $pkg) diff --git a/tools/gstpushsrc.c b/tools/gstpushsrc.c deleted file mode 100644 index 5db8e7630..000000000 --- a/tools/gstpushsrc.c +++ /dev/null @@ -1,22 +0,0 @@ -% ClassName -GstPushSrc -% TYPE_CLASS_NAME -GST_TYPE_PUSH_SRC -% pkg-config -gstreamer-base-0.10 -% includes -#include <gst/base/gstpushsrc.h> -% prototypes -static GstFlowReturn gst_replace_create (GstPushSrc * src, GstBuffer ** buf); -% declare-class - GstPushSrc *pushsrc_class = GST_PUSHSRC (klass); -% set-methods - pushsrc_class-> = GST_DEBUG_FUNCPTR (gst_replace_); -% methods - -static GstFlowReturn -gst_replace_create (GstPushSrc * src, GstBuffer ** buf) -{ - -} -% end |