diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c61aa7a529..944ad035e4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1 +1 @@ -include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/master/gitlab/ci_template.yml" +include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/1.18/gitlab/ci_template.yml" diff --git a/ChangeLog b/ChangeLog index 628a07a4ff..d349d5ebed 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8412 @@ +=== release 1.18.6 === + +2022-02-02 15:06:47 +0000 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gst-plugins-good.doap: + * meson.build: + Release 1.18.6 + +2022-01-26 11:22:31 +0530 Nirbheek Chauhan + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: Fix critical while serializing timeout element message + The "cause" field wasn't registered as a GEnumValue, so do that. + Fixes this critical in gst_structure_to_string(): + `gst_value_serialize: assertion 'G_IS_VALUE (value)' failed` + Part-of: + +2021-12-10 17:36:30 +0100 Célestin Marot + + * gst/multifile/gstmultifilesrc.c: + multifilesrc: fix caps leak + since `gst_caps_replace()` and `gst_pad_set_caps()` both ref the caps and neither of them takes the ownership of the caps -> it must be unreffed in `gst_multi_file_src_set_property()` + to test the leak (on Unix): `echo coucou > /tmp/file.txt && GST_TRACERS=leaks GST_DEBUG="GST_TRACER:7" gst-launch-1.0 multifilesrc location=/tmp/file.txt caps='txt' ! fakesink` + Part-of: + +2021-11-18 16:27:17 +0000 Tobias Reineke + + * ext/shout2/gstshout2.c: + shout2: Add compatibility for libshout >= 2.4.2 + In libshout >=2.4.2 shout_open() can return SHOUTERR_RETRY in addition + to SHOUTERR_BUSY. + The nonblocking example in libshout fixes the problem in a similar + way, as mentioned by the author in this issue: + https://gitlab.xiph.org/xiph/icecast-libshout/-/issues/2316 + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/848 + Part-of: + +2021-11-01 10:08:32 +0700 Trung Do + + * sys/v4l2/gstv4l2object.c: + v4l2: Update fmt if padded height is greater than fmt height + If padded height is greater, buffer bytesused could be larger than plane length, + and cause VIDIOC_QBUF failure. + Part-of: + +2021-11-09 13:36:28 +0800 Haihua Hu + + * sys/v4l2/gstv4l2bufferpool.c: + v4l2bufferpool: set video alignment of video meta + need apply video alignment info on video meta, downstream + element can get buffer alignment from video meta + Part-of: + +2021-11-01 16:32:10 +0100 Erlend Eriksen + + * gst/isomp4/gstqtmux.c: + qtmux: Fix deadlock in gst_qt_mux_prepare_moov_recovery + Regression from 5766731bd4200c3a374522a749386f740347661a + Part-of: + +2021-09-11 09:24:35 +0300 Sebastian Dröge + + * docs/gst_plugins_cache.json: + * gst/matroska/matroska-demux.c: + * gst/matroska/matroska-ids.h: + * gst/matroska/matroska-mux.c: + matroska: Add support for muxing/demuxing ffv1 + Previously only demuxing when stored via the RIFF/AVI mapping was + supported. + See https://github.com/FFmpeg/FFV1/blob/master/ffv1.md#matroska-file-format + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/923 + Part-of: + +2021-09-14 17:26:27 +0900 Seungha Yang + + * gst/isomp4/qtdemux.c: + qtdemux: Try to build AAC codec-data whenever it's possible + AAC codec_data is a just collection of AAC profile, samplerate, and + channels. We can know samplerate and channels from parsed + SampleEntry data. Although the AAC profile is unknown there, + let's assume it as AAC-LC like we've been doing for the version 1 + atom. + Part-of: + +2021-09-09 00:12:38 +0100 Tim-Philipp Müller + + * docs/gst_plugins_cache.json: + * meson.build: + Back to development + +=== release 1.18.5 === + +2021-09-08 20:02:48 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * docs/gst_plugins_cache.json: + * gst-plugins-good.doap: + * meson.build: + Release 1.18.5 + +2021-08-03 19:12:11 +0900 Seungha Yang + + * ext/jpeg/gstjpegdec.c: + jpegdec: Fix crash when interlaced field height is not DCT block size aligned + In case of interlaced JPEG file, we are doubling stride. + The scratch scan line should take account of it as well. + Part-of: + +2021-04-13 09:23:12 +0530 Nirbheek Chauhan + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: Remove some dead code + stop is not used after this point, nor do we create a new segment + here since 84725d62b57bc74ce34abde755f35bf8f948f94d + Part-of: + +2021-04-10 02:53:51 +0530 Nirbheek Chauhan + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: Do not overwrite the known duration after a seek + This breaks the duration query and also the seeking query. + Broke in 5f1a732bc7b76a6f1b8aa5f26b6e76fbca0261c7 + Part-of: + +2021-04-10 04:40:46 +0530 Nirbheek Chauhan + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: Just assign the segment instead of memcpy + Assignments copy by value, we don't need to memcpy... + Part-of: + +2021-04-10 03:09:44 +0530 Nirbheek Chauhan + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: De-dup seek event seqnums to avoid multiple seeks + Seek events are sent upstream on each sink, so if we receive multiple + seeks with the same seqnum, we must only perform one seek, not N seeks + where N = the number of sinks in the pipeline connected to rtspsrc. + This is the same thing done by demuxers like qtdemux or matrsokademux. + Part-of: + +2021-07-08 02:22:20 +0200 Mathieu Duponchelle + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: always use factory property when set + Part-of: + +2021-09-02 08:38:54 +0300 Sebastian Dröge + + * gst/avi/gstavidemux.c: + avidemux: Also detect 0x000001 as H264 byte-stream start code in codec_data + This works around some AVI files storing byte-stream data in the + codec_data. The previous workaround was only checking for + 0x00000001 (4 bytes) instead of 0x000001 (3 bytes). + Part-of: + +2021-08-27 14:32:45 +0200 Edward Hervey + + * gst/isomp4/qtdemux.c: + qtdemux: Force stream-start push when re-using EOS'd streams + When re-using streams, we *do* need to push a `stream-start` event downstream if + we previously were EOS'd. Failure to do that would never remove the EOS status + on all downstream elements and cause weird issues. + Part-of: + +2021-08-24 13:28:22 +0100 Tim-Philipp Müller + + * gst/isomp4/qtdemux.c: + qtdemux: add depth for ProRes 4:4:4:4 variants if available + Might be 24bpp in case an alpha channel is coded but + the image is always opaque. + Part-of: + +2021-08-22 23:16:26 +0000 Ruslan Khamidullin + + * gst/isomp4/gstqtmux.c: + qtmux: for Apple ProRes, allow overriding pixel bit depth for 4:4:4:4 variants + e.g. when exporting an opaque image, yet with alpha channel. + Apple ProRes certification requires that, when a ProRes-writing + application *knows* that the entire frame is opaque, the application + writes only RGB without alpha even when the clip is RGBA. For that, + this tiny change allows the app to override pixel depth when writing ProRes. + Part-of: + +2021-06-16 16:30:59 +0530 Nirbheek Chauhan + + * gst/rtp/gstrtph265depay.c: + rtph265depay: update codec_data in caps regardless of format + Updating of codec_data in the caps is important to propagate changes + in sps/pps/vps via NALs. Without this, downstream does not renegotiate + when upstream changes resolution. + The comment referring to rtph264pay is from 2015 and is out of date. + rtph264pay stopped doing that in 2017 with commit + dabeed52a995d27e16eba9e4617e61eb0bcd44c4 + Part-of: + +2021-08-15 12:26:38 +0300 Sebastian Dröge + + * ext/soup/gstsouphttpsrc.c: + souphttpsrc: Always use the content decoder but set `Accept-Encoding: identity` if no compression should be used + Some servers respond with gzip-encoded responses regardless of whether + the request allowed it to be used in the response. By always having the + content decoder enabled, these invalid responses can be decoded + correctly while for well-behaving servers the `compress` property + selects between allowing compressed responses or not. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/833 + Part-of: + +2021-07-01 13:18:45 +0300 Sebastian Dröge + + * gst/rtpmanager/gstrtpssrcdemux.c: + rtpssrcdemux: Remove pads and reset the element also in READY->NULL + Mostly for completeness. + Part-of: + +2021-07-01 13:18:09 +0300 Sebastian Dröge + + * gst/rtpmanager/gstrtpptdemux.c: + rtpptdemux: Remove pads also in PAUSED->READY + They're based on per-stream information and that should be reset + whenever going to READY state. + Part-of: + +2021-06-26 20:00:03 +0900 Seungha Yang + + * gst/udp/gstmultiudpsink.c: + multiudpsink: Fix broken SO_SNDBUF get/set on Windows + SO_SNDBUF has been undefined on Windows because of missing WinSock2.h + include. And don't use native socket functions (e.g., setsockopt()) + if code is expected to be built on Windows. We don't link ws2_32.lib + for this plugin. + Part-of: + +2020-11-03 15:58:30 +0200 Sebastian Dröge + + * ext/qt/gstqsgtexture.cc: + * ext/qt/gstqsgtexture.h: + * ext/qt/qtitem.cc: + qmlglsink: Keep old buffers around a bit longer if they were bound by QML + We don't know exactly when QML will stop using them but it should be + safe to unref them after at least 2 more buffers were bound. + Part-of: + +2021-06-03 20:33:45 +1000 Matthew Waters + + * ext/qt/qtitem.cc: + qtitem: don't potentially leak a large number of buffers + The only other place where these queued buffers are removed, is in + setCaps() but that is not called at all on shutdown so this list of + buffers could not be removed. + Part-of: + +2021-05-29 12:54:22 +0100 Tim-Philipp Müller + + * gst/rtp/gstrtpjpegpay.c: + rtpjpegpay: fix image corruption when compiled with MSVC on Windows + On Windows with MSVC, jpeg_header_size would end up 2 bytes larger + than it should be. This then leads to the first 2 bytes of the + actual jpeg image data to be dropped, because we think those + belong to the header, which results in an undecodable image when + reconstructed in the depayloader. + What happens is that when the compiler evaluates + jpeg_header_size = mem.offset + read_u16_and_inc_offset_by_2(&mem); + it actually uses the mem.offset value after it has been increased + by the function call on the right hand size of the equation. + From section 6.5 of the C99 spec: + 3. The grouping of operators and operands is indicated by the syntax [74]. + Except as specified later (for the function-call (), &&, ||, ?:, and + comma operators), the order of evaluation of subexpressions and the + order in which side effects take place are both unspecified. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/889 + Part-of: + +2021-05-26 00:23:56 +0900 Seungha Yang + + * gst/deinterlace/gstdeinterlace.c: + deinterlace: Drop "field-order" field while transforming caps + Like other basetransform subclasses are doing, drop field + which can be converted by deinterlace. + Part-of: + +2021-05-25 20:10:34 +0900 Seungha Yang + + * gst/deinterlace/gstdeinterlace.c: + deinterlace: Drop field-order field if outputting progressive + Progressive with field-order doesn't make sense + Part-of: + +2021-05-23 15:14:11 +0100 Tim-Philipp Müller + + * gst/wavparse/gstwavparse.c: + wavparse: use g_strndup() for copying text data + So we don't rely on NUL terminators inside the data. + Part-of: + +2021-05-23 13:29:07 +0100 Tim-Philipp Müller + + * gst/wavparse/gstwavparse.c: + wavparse: clean up adtl/note/labl chunk parsing + We were passing the size of the adtl chunk to the note/labl + sub-chunk parsing function, which means we may memdup lots of + data after the chunk string's NUL terminator that doesn't + really belong to it. + Part-of: + +2021-05-23 13:24:21 +0100 Tim-Philipp Müller + + * gst/wavparse/gstwavparse.c: + wavparse: guard against overflow when comparing chunk sizes + Could be rewritten as lsize > (size - 8) a well, but the + extra check seems clearer. Doesn't look like it was problematic, + lsize wasn't actually used when parsing the sub-chunks. + Part-of: + +2021-05-07 11:16:47 +0200 Jan Alexander Steffens (heftig) + + * gst/udp/gstudpsrc.c: + udpsrc: Plug leaks of saddr in error cases + Part-of: + +2021-05-07 11:16:21 +0200 Jan Alexander Steffens (heftig) + + * gst/udp/gstudpsrc.c: + udpsrc: Whitespace + Part-of: + +2021-05-07 00:43:44 +0200 Jan Alexander Steffens (heftig) + + * gst/deinterlace/gstdeinterlace.c: + deinterlace: Plug a method subobject leak + Changing the method would leak the previous method. + Part-of: + +2021-04-30 08:12:47 +1000 Jan Schmidt + + * gst/isomp4/atoms.c: + * gst/isomp4/atoms.h: + qtmux: Make sure to write 64-bit STCO table when needed. + qtmux attempts to choose between writing a 32-bit stco chunk offset table + when it can, but switch to a 64-bit co64 table when file offsets go over + 4GB. + This patch fixes a problem where the atom handling code was checking + mdat-relative offsets instead of the final file offset (computed by + adding the mdat position plus the mdat-relative offset) - leading to + problems where files with a size between 4GB and 4GB+offset-of-the-mdat + would write incorrect STCO tables with some samples having truncated + 32-bit offsets. + Smaller files write STCO correctly, larger files would switch to + co64 and also output correctly. + Part-of: + +2021-04-22 15:01:32 +0800 Hou Qi + + * sys/v4l2/gstv4l2object.c: + v4l2object: Add interlace-mode back to caps for camera + skip_try_fmt_probes is set to TRUE for v4l2src to skip interlace-mode and + colorimetry when probe caps. gst_v4l2_object_set_format_full() will add + colorimetry back to caps when iterating over the negotiated caps. There is + one case that v4l2src is first in preview state then starts recording. + v4l2src caps will change with an additional interlace-mode structure after + renegotiation, then v4l2src needs to reset. But this camera driver can't + orphan buffer pool, it causes require buffer failed as streaming is still + in active state. + To fix this, also need to add interlace-mode back to caps for camera to + avoid reset. + Part-of: + +2021-04-22 08:57:23 +0200 Edward Hervey + + * gst/rtpmanager/gstrtpjitterbuffer.c: + rtpjitterbuffer: Avoid generation of invalid timestamps + When updating timestamps and timer timeouts with a new offset, make sure that + the resulting value is valid (and not a negative (signed) value which ends up in + a massive (unsigned) value). + Fixes #571 + Part-of: + +2021-04-19 01:29:33 -0400 Doug Nazar + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: Fix race saving seek event seqnum. + We need to save the seek seqnum before the flush stop event + since that will start the basesrc task which may send the segment + event before we're ready. + Part-of: + +2021-04-13 11:30:51 +0300 Sebastian Dröge + + * gst/rtpmanager/gstrtpjitterbuffer.c: + rtpjitterbuffer: Check srcresult before waiting on the condition variable too + It might've been set to FLUSHING between the last check and the waiting, + and in that case we'd be waiting here forever now. + Part-of: + +2021-04-10 01:55:28 +0530 Nirbheek Chauhan + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: Using multicast UDP has no relation to seekability + The transport has no relation to whether a media can be seeked. The + range response having a duration is the correct thing to check for. + Part-of: + +2021-04-10 01:54:48 +0530 Nirbheek Chauhan + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: Add more logging for range parsing and seekable + Part-of: + +2021-04-06 17:02:34 +0530 Nirbheek Chauhan + + * gst/rtpmanager/rtpjitterbuffer.c: + rtpjitterbuffer: More logging when calculating rfc7273 timestamps + This code can be fragile, since it is very exacting in the timestamps + that it will accept. Add more logging so it's easier to debug issues + and figure out whether it's a bug in the calculation or something + wrong in the incoming buffers. + Part-of: + +2021-03-18 19:52:53 +1100 Matthew Waters + + * ext/jack/gstjack.c: + * ext/jack/gstjackaudiosink.c: + * ext/jack/gstjackaudiosrc.c: + * ext/pulse/pulsesink.h: + * ext/qt/gstqsgtexture.cc: + * ext/qt/gstqtglutility.cc: + * ext/qt/qtglrenderer.cc: + * ext/qt/qtitem.cc: + * ext/qt/qtwindow.cc: + * ext/vpx/gstvpxdec.c: + * ext/vpx/gstvpxenc.c: + * gst/audioparsers/gstac3parse.h: + * sys/rpicamsrc/gstrpicamsrc.c: + * sys/ximage/ximageutil.c: + gst: don't use volatile to mean atomic + volatile is not sufficient to provide atomic guarantees and real atomics + should be used instead. GCC 11 has started warning about using volatile + with atomic operations. + https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1719 + Discovered in https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/868 + Part-of: + +2021-03-26 16:26:22 +0800 Hou Qi + + * sys/v4l2/gstv4l2object.c: + v4l2object: Use default colorimetry if that in caps is unknown + Some streams have unknown colorimetry in caps, but v4l2object sets + default values for each primaries. It will cause check colorimetry + fail when do gst_v4l2_video_colorimetry_matches(). + To fix this, need to keep the unknown colorimetry in caps same as + the default value set by v4l2object. + Part-of: + +2021-03-23 16:59:28 +0800 Hou Qi + + * sys/v4l2/gstv4l2object.c: + v4l2object: Avoid colorimetry mismatch for streams with invalid colorimetry + video-info sets gst colorimetry to default value when colorimetry in caps + is unparsable or invalid. Then v4l2object uses this gst colorimetry to do + mapping with v4l2 colorimetry. This may cause colorimetry mismatch when + check mapped gst colorimetry with that read from caps directly. + To fix this, need to correct gst colorimetry as that parsed from video-info + when check gst_v4l2_video_colorimetry_matches(). + Part-of: + +2021-03-19 10:52:26 +0800 Hou Qi + + * sys/v4l2/gstv4l2object.c: + v4l2object: Add support for hdr10 stream playback + Colorimetry of hdr10 video is bt2100-pq with transfer as + GST_VIDEO_TRANSFER_SMPTE2084. So map GST_VIDEO_TRANSFER_SMPTE2084 + to V4L2_XFER_FUNC_SMPTE2084 to support hdr10 stream playback. + Part-of: + +2021-03-18 17:42:02 +0000 Alba Mendez + + * docs/gst_plugins_cache.json: + * gst/rtsp/gstrtspsrc.c: + rtspsrc: Fix more signals + Behaviour change in GLib causes select-stream signal to discard + the value returned by handlers. See !909 for more info. + Part-of: + +2021-03-17 15:54:59 +0530 Nirbheek Chauhan + + * docs/gst_plugins_cache.json: + * gst/rtsp/gstrtspsrc.c: + Update docs cache and fix before-send signal doc syntax + The docs for before-send were missing because of this + Part-of: + +2021-03-17 13:18:34 +0530 Nirbheek Chauhan + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: Fix accumulation of before-send signal return values + Since glib 2.62, the accumulated return values in RUN_CLEANUP override the + accumulated return values in RUN_FIRST. Since: + 1. We have a default handler that always returns TRUE, and + 2. User handlers are only run in RUN_FIRST, and + 3. Our accumulator just takes the latest return value + We were discarding the return value from the user handler and always + sending messages even if the user handler said not to. See + https://gitlab.gnome.org/GNOME/glib/-/issues/2352 for more details. + This signal does not need RUN_CLEANUP or RUN_FIRST, so just change it + to RUN_LAST so that it's emitted exactly once and accumulated once. + With this fix, this signal can now be used to intercept PAUSE when + going to GST_STATE_NULL so that the server does a TEARDOWN (if + necessary) and not a PAUSE, which will confuse other RTSP clients when + playing shared media. + Part-of: + +2021-03-16 19:25:36 +0200 Sebastian Dröge + + * gst/rtpmanager/gstrtpjitterbuffer.c: + rtpjitterbuffer: Fix parsing of the mediaclk:direct= field + Due to an off-by-one when parsing the string, the most significant digit + or the clock offset was skipped when parsing the offset. + Part-of: + +2021-03-15 19:49:05 +0000 Tim-Philipp Müller + + * docs/gst_plugins_cache.json: + * meson.build: + Back to development + +=== release 1.18.4 === + +2021-03-15 17:48:28 +0000 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * docs/gst_plugins_cache.json: + * gst-plugins-good.doap: + * meson.build: + Release 1.18.4 + +2021-03-04 13:05:19 +0200 Sebastian Dröge + + * gst/matroska/matroska-demux.c: + * gst/matroska/matroska-ids.h: + matroskademux: Fix extraction of multichannel WavPack + The old code had a couple of issues that all lead to potential memory + safety bugs. + - Use a constant for the Wavpack4Header size instead of using sizeof. + It's written out into the data and not from the struct and who knows + what special alignment/padding requirements some C compilers have. + - gst_buffer_set_size() does not realloc the buffer when setting a + bigger size than allocated, it only allows growing up to the maximum + allocated size. Instead use a GstAdapter to collect all the blocks + and take out everything at once in the end. + - Check that enough data is actually available in the input and + otherwise handle it an error in all cases instead of silently + ignoring it. + Among other things this fixes out of bounds writes because the code + assumed gst_buffer_set_size() can grow the buffer and simply wrote after + the end of the buffer. + Thanks to Natalie Silvanovich for reporting. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/859 + Part-of: + +2021-03-03 11:31:52 +0200 Sebastian Dröge + + * gst/matroska/matroska-demux.c: + matroskademux: Initialize track context out parameter to NULL before parsing + Various error return paths don't set it to NULL and callers are only + checking if the pointer is NULL. As it's allocated on the stack this + usually contains random stack memory, and more often than not the memory + of a previously parsed track. + This then causes all kinds of memory corruptions further down the line. + Thanks to Natalie Silvanovich for reporting. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/858 + Part-of: + +2021-01-18 15:54:43 +0100 Philipp Zabel + + * sys/v4l2/gstv4l2object.c: + v4l2object: handle GST_VIDEO_TRANSFER_BT601 + V4L2 makes no difference between the BT.601 and BT.709 transfer + functions [1], but GStreamer does since 1.18 [2]. + Adapt gst_v4l2_object_get_colorspace() and + gst_v4l2_object_set_format_full(). + [1] https://linuxtv.org/downloads/v4l-dvb-apis-new/userspace-api/v4l/colorspaces-details.html#colorspace-smpte-170m-v4l2-colorspace-smpte170m + [2] https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/724 + Part-of: + +2021-03-07 21:25:01 +0000 Vladimir Menshakov + + * docs/gst_plugins_cache.json: + * ext/wavpack/gstwavpackdec.c: + * ext/wavpack/gstwavpackdec.h: + wavpackdec: Add floating point format support + This commit negotiate F32 audio format if MODE_FLOAT used in wavpack file. + Wavpack float mode is always in 32-bit IEEE format. + The following pipeline plays distorted audio if source file is encoded in float mode: + gst-launch-1.0 filesrc ... ! wavpackparse ! wavpackdec ! pulsesink + Part-of: + +2021-03-01 14:32:40 +0800 Hou Qi + + * sys/v4l2/gstv4l2videodec.c: + v4l2videodec: Do not expose profiles/levels in vp8/vp9 template caps + Vp8/vp9 supported profiles/levels are listed in decoder sink caps, but + there is no parser for these two formats and the demuxers also don't have + these information. It causes negotiation fail between demuxers and decoder + when check caps "accept = gst_caps_is_subset (caps, template_caps);". + To fix this, need to remove profiles/levels for vp8/vp9 formats in decoder + sink caps. + Fix #854 + Part-of: + +2021-02-24 13:25:43 +0100 Philipp Zabel + + * sys/v4l2/gstv4l2videodec.c: + v4l2videodec: fix src side frame rate negotiation + Negotiating v4l2h264dec ! v4l2h264enc transcoding pipelines fails in + case the encoder does not accept framerate=(fraction)0/1. + The acquired caps used for downstream negotiation are determined from + gst_v4l2_object_acquire_format(), which sets the GstVideoInfo::fps_n + and ::fps_d fields to 0. + To fix this, copy the frame rate from the sink side. + Part-of: + +2021-02-16 16:20:05 +0200 Jordan Petridis + + * sys/rpicamsrc/meson.build: + rpicamsrc: depend on posix threads and vchiq_arm + Could only test on rpi 3b+ + Close #839 + Part-of: + +2021-02-16 22:20:17 +1100 Ashley Brighthope + + * gst/wavenc/gstwavenc.c: + wavenc: Fixed INFO chunk corruption, caused by odd sized data not being padded. Code style was updated. + Part-of: + +2021-02-04 13:43:17 +0800 Bing Song + + * sys/v4l2/gstv4l2videoenc.c: + v4l2videoenc: support resolution change stream encode. + Resolution change stream transcoding will drain before send new video + frame buffer. Need encode video frame after process EOS. + Part-of: + +2021-01-14 01:12:06 +0800 Bing Song + + * sys/v4l2/gstv4l2h265codec.c: + v4l2h265codec: fix HEVC profile string issue. + Keep HEVC profile compatible with other module. + Part-of: + +2020-12-15 10:41:40 +0800 Bing Song + + * sys/v4l2/gstv4l2object.c: + * sys/v4l2/gstv4l2object.h: + v4l2object: Need keep same transfer as input caps. + GST_VIDEO_TRANSFER_BT2020_12 and GST_VIDEO_TRANSFER_BT2020_10 will + be mapped to V4L2_XFER_FUNC_709. Need check input caps when map + V4L2_XFER_FUNC_709 back to GST_VIDEO_TRANSFER_BT2020_12 and + GST_VIDEO_TRANSFER_BT2020_10 + Fixes: https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/816 + Part-of: + +2021-01-14 02:17:10 +0000 Tim-Philipp Müller + + * docs/gst_plugins_cache.json: + * meson.build: + Back to development + +=== release 1.18.3 === + +2021-01-13 21:08:50 +0000 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * docs/gst_plugins_cache.json: + * gst-plugins-good.doap: + * meson.build: + Release 1.18.3 + +2021-01-07 16:57:27 +0800 Hou Qi + + * docs/gst_plugins_cache.json: + * sys/v4l2/gstv4l2object.c: + v4l2object: Map correct video format for RGBA + Map V4L2_PIX_FMT_RGBA32 pixel format to GST_VIDEO_FORMAT_RGBA instead of + GST_VIDEO_FORMAT_RGB video format to support RGBA. + Fixes #823 + Part-of: + +2020-12-09 20:20:18 +1100 Matthew Waters + + * docs/gst_plugins_cache.json: + * gst/videofilter/gstvideoflip.c: + * gst/videofilter/gstvideoflip.h: + * tests/check/elements/videoflip.c: + videoflip: fix possible crash when setting the video-direction while running + A classic case of not enough locking. + One interesting thing with this is the interaction between the + rotation value and caps negotiation. i.e. the width/height of the caps + can be swapped depending on the video-direction property. We can't lock + the entirety of the caps negotiation for obvious reasons so we need to + do something else. This takes the approach of trying to use a single + rotation value throughout the entirety of the negotiation and then + subsequent output frame in a kind of latching sequence. + Fixes: https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/792 + Part-of: + +2020-12-09 19:49:47 +1100 Matthew Waters + + * tests/check/elements/videoflip.c: + * tests/check/meson.build: + tests: add tests for videoflip + Part-of: + +2020-12-30 13:38:46 +0100 Ignacio Casal Quinteiro + + * gst/deinterlace/meson.build: + deinterlace: force -DPREFIX on macos + This is due to a bug in meson where it will not detect properly + the compiler if the symbols need an undercore. + https://github.com/mesonbuild/meson/issues/5482 + Fixes #821 + Part-of: + +2020-12-10 14:27:49 +0200 Vivia Nikolaidou + + * gst/multifile/gstsplitmuxsink.c: + * gst/multifile/gstsplitmuxsink.h: + splitmuxsink: Avoid deadlock when releasing a pad from a running muxer + Might not drain correctly + Part-of: + +2020-12-12 03:28:56 +1100 Jan Schmidt + + * tests/check/elements/splitmuxsink.c: + splitmuxsink: Unit test - check format/opened/closed sequence + Check the sequence of format-location/fragment-opened/fragment-closed + events is respected. There should be 1 format-location call for each + fragment-opened message, and 1 fragment-closed for each. + Part-of: + +2020-12-09 00:40:52 +1100 Jan Schmidt + + * gst/multifile/gstsplitmuxsink.c: + * gst/multifile/gstsplitmuxsink.h: + splitmuxsink: Fix for 'reference bytes muxed' check. + https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/merge_requests/798 + introduced a check in the need-new-fragment logic to avoid starting a + new fragment unless there has been some data on the reference stream, + but the check is done against the number of bytes that have been + received on the input, not the number that were released for output + into the current fragment. + Fix the check to remember and test against bytes that have been sent + for output. + This also fixes a problem where starting a new fragment fails to + request a new filename from the format-location signal. + Part-of: + +2020-09-15 00:27:24 +1000 Jan Schmidt + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: Add debug for fragment opened/closed msgs + When posting fragment-opened and fragment-closed messages, + put a debug statement in the logs + Part-of: + +2020-08-18 16:06:14 +1000 Jan Schmidt + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: Convert asserts into element errors. + Change some g_assert into element errors so that they can be + caught and the pipeline shut down. + Part-of: + +2020-12-06 23:56:49 +0000 Tim-Philipp Müller + + * docs/gst_plugins_cache.json: + * meson.build: + Back to development + +=== release 1.18.2 === + +2020-12-06 13:22:58 +0000 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * docs/gst_plugins_cache.json: + * gst-plugins-good.doap: + * meson.build: + Release 1.18.2 + +2020-11-15 11:30:07 +0000 Jose Quaresma + + * sys/rpicamsrc/meson.build: + rpicamsrc: add vchostif library as it is required to build successful + fix: undefined reference to `vc_gencmd' + /usr/src/debug/gstreamer1.0-plugins-good/1.18.1-r0/build/../gst-plugins-good-1.18.1/sys/rpicamsrc/RaspiCamControl.c:1440: undefined reference to `vc_gencmd' + Part-of: + +2020-11-24 22:11:50 +0530 Nirbheek Chauhan + + * gst/deinterlace/meson.build: + * meson.build: + deinterlace: Enable x86 assembly with nasm on MSVC + We need to remove x86inc.asm from the list of compiled assembly files + because it is not supposed to be compiled separately. It is directly + included by yadif.asm, and it exports no symbols. + The object file was getting ignored on all platforms except on msvc + where it was causing a linker hang when building with debugging + enabled because the object file had no debug symbols (or similar). + We've seen this before in FFmpeg too, which uses nasm: + https://gitlab.freedesktop.org/gstreamer/meson-ports/ffmpeg/-/merge_requests/46 + Part-of: + +2020-10-29 02:38:16 +1100 Jan Schmidt + + * gst/isomp4/gstqtmux.c: + qtmux: Chain up when releasing pad, and fix some locking. + Release pads by calling up into aggregator so it can do the right + things. Don't clean up the pad until after that. + Add some missing locks around some accesses to shared pad state. + Part-of: + +2020-11-12 09:32:30 +0800 Bing Song + + * docs/gst_plugins_cache.json: + * sys/v4l2/gstv4l2object.c: + v4l2: caps negotiate wrong as interlace feature + gst_caps_simplify() will move interlace format before normal video + format. It will cause caps negotiate prefer interlaced caps which + isn't expected. Seperate normal caps and interlaced caps and then + merge it will keep prefer progress video format. + Add ARGB/BGRA for interlaced caps. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/802 + Part-of + Part-of: + +2020-11-13 14:58:44 +0200 Vivia Nikolaidou + + * gst/audioparsers/gstaacparse.c: + aacparse: Fix caps change handling + In baseparse we set the fixed caps flag on all src pads, therefore the + source pad caps query in get_allowed_caps will return the current caps. + Current caps won't necessarily intersect with the new caps (e.g. sample + rate change). Replace get_allowed_caps with peer_query_caps. + Part-of: + +2020-11-10 18:18:12 +0000 ChrisDuncanAnyvision + + * gst/rtsp/gstrtspsrc.c: + * gst/rtsp/gstrtspsrc.h: + rtspsrc: Ensure same group-id used for both TCP/UDP stream-start events + Part-of: + +2020-11-10 16:17:23 +0000 ChrisDuncanAnyvision + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: Use consistent URI hashed stream-id for UDP and TCP/Interleaved streams + Part-of: + +2020-11-01 10:30:27 +0200 Sebastian Dröge + + * gst/flv/gstflvmux.c: + flvmux: Release pads via GstAggregator + See https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/merge_requests/797 + Part-of: + +2020-10-31 12:52:04 +1100 Jan Schmidt + + * tests/check/elements/splitmuxsrc.c: + splitmuxsrc: Fix comment in a test + Fix a comment in the splitmuxsrc robust muxing test so it + describes the test properly. + Part-of: + +2020-10-31 12:49:08 +1100 Jan Schmidt + + * gst/multifile/gstsplitmuxsink.c: + * gst/multifile/gstsplitmuxsink.h: + splitmuxsink: Change EOS catching logic. + Add a new state for ending the overall stream, and use it to decide + whether to pass the final EOS message up the bus instead of dropping + it. Fixes a small race that makes the testsuite sometimes not generate + the last fragment(s) sometimes because the wrong EOS gets + allowed through too early. + Part-of: + +2020-10-31 02:19:07 +1100 Jan Schmidt + + * gst/multifile/gstsplitmuxsink.c: + * gst/multifile/gstsplitmuxsink.h: + splitmuxsink: Don't use the element state lock + Using the element state lock to avoid splitmuxsink shutting + down while doing element manipulations can lead to a deadlock on + shutdown if a fragment switch happens at exactly the wrong moment. + Use a private mutex and a shutdown boolean instead. + Part-of: + +2020-10-30 03:38:15 +1100 Jan Schmidt + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: Don't busy loop on a non-ready pad. + If a pad gets into the check_completed_gop method and then + the underlying conditions change on the reference context, + things could get stuck in a busy loop when the context should + instead jump back out and wait for more data. + Part-of: + +2020-10-30 03:36:51 +1100 Jan Schmidt + + * gst/multifile/gstsplitmuxsrc.c: + splitmuxsrc: Mark running=false on shutdown. + Make sure that any late gst_element_call_async() callbacks + know that the elements is shutting down and bail out instead + of operating on the element we're trying to stop. + Fixes a spurious test failure in elements_splitmuxsrc + Part-of: + +2020-10-29 02:36:35 +1100 Jan Schmidt + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: Forward EOS messages from async fragments. + Re-enable forwarding EOS messages from fragments that are completing + asynchronously, so that splitmuxsink itself won't go EOS until they + are complete. This was disabled to work around a bug in core that + is fixed in + https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/683 + Part-of: + +2020-09-17 22:56:01 +1000 Jan Schmidt + + * gst/multifile/gstsplitmuxsink.c: + * gst/multifile/gstsplitmuxsink.h: + splitmuxsink: Never start a new fragment with no reference buffers + If there has been no bytes from the reference stream muxed into + the current fragment, then time can't have advanced, there's no + GOP... this fragment would be broken or empty, so wait for some + data on the reference buffer. + Part-of: + +2020-10-27 23:43:49 +1100 Jan Schmidt + + * gst/matroska/matroska-mux.c: + matroska-mux: Fix sparse stream crash + https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/merge_requests/656 + introduced an invalid memory access when debug is enabled, by casting + the wrong pointer to a GstCollectPad. Fixing that showed the original + change was incorrect and leads to an infinite loop in the + testsuite. This patch fixes both problems. + Part-of: + +2020-10-27 12:34:19 +0000 Tim-Philipp Müller + + * docs/gst_plugins_cache.json: + * meson.build: + Back to development + +=== release 1.18.1 === + +2020-10-26 11:12:10 +0000 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * docs/gst_plugins_cache.json: + * gst-plugins-good.doap: + * meson.build: + Release 1.18.1 + +2020-10-23 10:32:18 -0400 Nicolas Dufresne + + * sys/v4l2/gstv4l2object.c: + Revert "v4l2object: Only offer inactive pools and if needed" + This reverts commit 85b9893e963ea5d342289e318daeefba35ff4a07. + This change caused a regression reported in #796. Basically the pool get + deactivated by basesrc and the encoder does not recover. Recovering with + current design would cause insertion of an unwanted keyframe. + This is being reverted in 1.18 only, a proper solution is wanted for 1.20. + Part-of: + +2020-10-22 15:29:01 -0300 Thibault Saunier + + * ext/vpx/gstvpxenc.c: + vpx: Fix the check to unfixed/unknown framerate to set bitrate + 0/1 means unknown framerate not X/0 (which is illegal). + Part-of: + +2020-10-16 16:05:45 -0700 Bastien Reboulet + + * ext/qt/qtitem.cc: + qmlglsink: fix crash when created/destroyed in quick succession + The crash is caused by a race condition where the render thread + calls a method on the QtGLVideoItem instance that was + previously destroyed by the main thread. + Also, less frequently, QtGLVideoItem::onSceneGraphInitialized + is called when QQuickItem::window is null, also causing a crash. + Fixes #798 + Part-of: + +2020-10-22 09:17:26 -0400 Arun Raghavan + + * gst/rtp/gstrtputils.c: + rtputils: Count metas with an empty tag list for copying/keeping + The GstMetaInfos registered in core do not set their tags to NULL, but + instead use an empty list (non-NULL list with a single NULL value). + Let's check explicitly for that so as to not miss some metas. + Part-of: + +2020-09-23 15:25:36 -0400 Nicolas Dufresne + + * gst/rtpmanager/gstrtpbin.c: + rtpbin: Remove the rtpjitterbuffer with the stream + Since !348, the jitterbuffer was only removed with the session. This restores + the original behaviour and removes the jitterbuffer when the stream is + removed. This avoid accumulating jitterbuffer objects into the bin when a + session is reused. + Part-of: + +2020-09-23 13:26:51 -0400 Nicolas Dufresne + + * gst/rtpmanager/gstrtpbin.c: + rtpbin: Cleanup dead code + The rtpjitterbuffer is now part of the session elements, we no longer need + to do the ref_sink dance when signalling it. It is already owned by the bin + when signalled. Also, the code that handles generic session elements already + handle the ref_sink() calls since: + 03dc22951bacb6fdc3868c8f801e6a52c33a745f + Part-of: + +2020-09-18 16:09:20 +1000 Matthew Waters + + * gst/rtp/gstrtph264depay.c: + * gst/rtp/gstrtph264depay.h: + * gst/rtp/gstrtph265depay.c: + * gst/rtp/gstrtph265depay.h: + * tests/check/elements/rtph264.c: + rtph26*depay: drop FU's without a corresponding start bit + If we have not received a FU with a start bit set, any subsequent FU + data is not useful at all and would result in an invalid stream. + This case is constructed from multiple requirements in + RFC 3984 Section 5.8 and RFC 7798 Section 4.4.3. Following are excerpts + from RFC 3984 but RFC 7798 contains similar language. + The FU in a single FU case is forbidden: + A fragmented NAL unit MUST NOT be transmitted in one FU; i.e., the + Start bit and End bit MUST NOT both be set to one in the same FU + header. + and dropping is possible: + If a fragmentation unit is lost, the receiver SHOULD discard all + following fragmentation units in transmission order corresponding to + the same fragmented NAL unit. + The jump in seqnum case is supported by this from the specification + instead of implementing the forbidden_zero_bit mangling: + If a fragmentation unit is lost, the receiver SHOULD discard all + following fragmentation units in transmission order corresponding to + the same fragmented NAL unit. + A receiver in an endpoint or in a MANE MAY aggregate the first n-1 + fragments of a NAL unit to an (incomplete) NAL unit, even if fragment + n of that NAL unit is not received. In this case, the + forbidden_zero_bit of the NAL unit MUST be set to one to indicate a + syntax violation. + Part-of: + +2020-09-20 21:06:19 +0900 Seungha Yang + + * gst/imagefreeze/gstimagefreeze.c: + imagefreeze: Response caps query from srcpad + ... and chain up to default query handler for unhandled query types. + Unhandled query shouldn't be returned with FALSE if there's no special needs. + Part-of: + +2020-09-14 10:15:35 +0300 Sebastian Dröge + + * docs/gst_plugins_cache.json: + * gst/rtp/gstrtpmp4gdepay.c: + rtpmp4gdepay: Allow lower-case "aac-hbr" instead of correct "AAC-hbr" + Various live555 based products are using the wrong "mode" string or + seem to assume case-insensitive matching, which is wrong. + Examples for this are the Yuan SC6C0N1 mini and the Kiloview E2. + Part-of: + +2020-09-07 23:20:58 +0800 Ricky Tang + + * docs/gst_plugins_cache.json: + * gst/rtsp/gstrtspsrc.c: + rtspsrc: Fix push-backchannel-buffer parameter mismatch + When using python, signal parameter must match with function. + Part-of: + +2020-09-10 11:24:32 +0200 Jérôme Laheurte + + * ext/jpeg/gstjpegdec.c: + jpegdec: check buffer size before dereferencing. Fixes #541 + Some cameras (Panacast) have buggy drivers/firmware which send + invalid JPEG frames, containing no data, which makes jpegdec + crash because it assumes the frame is at least 2 bytes long. + Part-of: + +2020-09-10 11:11:00 +0200 Jan Alexander Steffens (heftig) + + * gst/flv/gstflvmux.c: + flvmux: Improve logging of gst_flv_mux_buffer_to_tag_internal + Part-of: + +2020-09-09 15:12:53 +0200 Jan Alexander Steffens (heftig) + + * gst/flv/gstflvmux.c: + flvmux: Move stream skipping to GstAggregatorPadClass.skip_buffer + Besides looking like the correct place to put this, it allows us to drop + the entire aggregator queue. The old implementation only dropped at most + one buffer for each call of aggregate. + Part-of: + +2020-09-08 17:35:50 +0200 Havard Graff + + * sys/v4l2/gstv4l2object.c: + v4l2object: plug memory-leak + Part-of: + +2020-09-08 20:57:33 +0200 Mathieu Duponchelle + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: fix sink pad release while PLAYING + - Release the split mux lock while removing the probes + - Flush the sinkpad to unblock other pads + - Turn check_completed_gop into a do while statement, when + waking up we want to recheck whether the current GOP is + ready for sending + Part-of: + +2020-09-08 17:44:17 +0100 Tim-Philipp Müller + + * docs/gst_plugins_cache.json: + * meson.build: + Back to development + +=== release 1.18.0 === + +2020-09-08 00:05:14 +0100 Tim-Philipp Müller + + * .gitlab-ci.yml: + * ChangeLog: + * NEWS: + * README: + * RELEASE: + * docs/gst_plugins_cache.json: + * gst-plugins-good.doap: + * meson.build: + Release 1.18.0 + +2020-09-07 22:39:02 +0100 Tim-Philipp Müller + + * meson.build: + * scripts/dist-translations.py: + * scripts/meson.build: + meson: dist pot file in tarballs + Part-of: + +2020-09-07 12:13:18 +0300 Sebastian Dröge + + * gst/isomp4/atoms.c: + * gst/isomp4/qtdemux.c: + * gst/matroska/matroska-demux.c: + * gst/matroska/matroska-mux.c: + gst: Update for gst_video_transfer_function_*() function renaming + Part-of: + +2020-08-31 15:01:32 +0200 Jan Alexander Steffens (heftig) + + * gst/flv/gstflvmux.c: + flvmux: Avoid crash when best pad gets flushed + The 'best' pad might receive a flush event between us picking it and us + popping the buffer. In this case, the buffer will be missing. + Part-of: + +2020-08-31 13:43:42 +0200 Jan Alexander Steffens (heftig) + + * gst/flv/gstflvmux.c: + flvmux: Correct breaks in gst_flv_mux_find_best_pad + The code seems to use `continue` and `break` as if both refer to the + surrounding `while` loop. But because `break` breaks out of the + `switch`, they actually have the same effect. + This may have caused the loop not to terminate when it should. E.g. when + `skip_backwards_streams` drops a buffer we should abort the aggregation + and wait for all pads to be filled again. Instead, we might have just + selected a subsequent pad as our new "best". + Replace `break` with `done = TRUE; break`, and `continue` with `break`. + Then simplify the code a bit. + Part-of: + +2020-05-13 11:31:38 +0200 Dmitriy Purgin + + * ext/qt/README.md: + * ext/qt/qtplugin.pro: + gstqmlgl: build on Windows with qmake without pkgconfig; update instructions on building for Windows + Part-of: + +2020-08-21 12:12:48 +0200 Philipp Zabel + + * meson.build: + meson: fix build failure if orc is enabled but none of its users are + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/778 + Part-of: + +2020-08-20 14:26:04 +0200 Zeid Bekli + + * gst/rtp/gstrtpL16depay.c: + rtpL16depay: unref buffer on error + gst_rtp_L16_depay_process to unref buffer on wrong payload size or + reorder failure. + Part-of: + +=== release 1.17.90 === + +2020-08-20 16:11:58 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * docs/gst_plugins_cache.json: + * gst-plugins-good.doap: + * meson.build: + Release 1.17.90 + +2020-08-18 10:27:52 +0300 Sebastian Dröge + + * gst/rtp/gstrtputils.c: + rtputils: Don't call NULL GstMeta transform function + It's optional and if it does not exist then no transformation is + possible. + Part-of: + +2020-08-13 15:27:25 -0400 Julian Bouzas + + * gst/rtp/gstrtp.c: + rtp: Do not register rtpreddec and rtpredenc twice + Part-of: + +2020-08-12 12:21:43 +0300 Sebastian Dröge + + * gst/rtpmanager/gstrtpjitterbuffer.c: + * gst/rtpmanager/gstrtpsession.c: + * gst/rtpmanager/rtpsession.c: + * gst/rtpmanager/rtpsource.c: + rtpmanager: Improve readability of "stats" docs by making the fields an actual list + Otherwise they end up all in the same line one after another. + Also add docs for the "avg-jitter" stats field of the jitterbuffer. + Part-of: + +2020-08-11 17:24:11 -0400 Nicolas Dufresne + + * sys/v4l2/gstv4l2h264codec.c: + v4l2h264codec: Map newly defined profile/levels + Part-of: + +2020-08-11 17:18:42 -0400 Nicolas Dufresne + + * sys/v4l2/ext/types-compat.h: + * sys/v4l2/ext/v4l2-common.h: + * sys/v4l2/ext/v4l2-controls.h: + * sys/v4l2/ext/videodev2.h: + v4l2: Sync headers with kernel 5.9 + Part-of: + +2020-08-06 13:15:10 +0200 Víctor Manuel Jáquez Leal + + * sys/v4l2/gstv4l2deviceprovider.c: + * sys/v4l2/gstv4l2object.c: + * sys/v4l2/gstv4l2object.h: + * sys/v4l2/gstv4l2radio.c: + * sys/v4l2/gstv4l2sink.c: + * sys/v4l2/gstv4l2src.c: + * sys/v4l2/gstv4l2transform.c: + * sys/v4l2/gstv4l2videodec.c: + * sys/v4l2/gstv4l2videoenc.c: + * sys/v4l2/v4l2_calls.c: + v4l2: use GstV4l2Error in gst_v4l2_open() + gst_v4l2_open() is called by gst_v4l2_device_provider_probe_device(), + where the GstV4l2Object is created without an associated GstElement. + If gst_v4l2_open() fails, it raises a bus message, but without an + element, a precondition check fails on + gst_element_message_full_with_details() generating a crash if running + with fatal-warnings debug mode. + GstV4l2Error is a helper to raise error bus messages when it is + appropiated. This patch changes the direct bus messages to this + helper, and the elements will actually send the error message. + Part-of: + +2020-08-10 20:20:53 +0300 Vivia Nikolaidou + + * gst/flv/gstflvmux.c: + flvmux: Return NEED_DATA when we drop a buffer + When we are dropping a buffer in find_best_pad (e.g. waiting for a + keyframe, or skipping backwards timestamp), return + GST_AGGREGATOR_FLOW_NEED_DATA to make sure we have enough data at the + next run. Otherwise, a stream that accidentally fell behind (e.g. + relinking race, or just waiting for a keyframe) will never get the + opportunity to catch up to the other one, because the other one will + always keep advancing. + Part-of: + +2020-08-10 20:20:04 +0300 Vivia Nikolaidou + + * gst/flv/gstflvmux.c: + flvmux: Return NEED_DATA when no best pad is found + Part-of: + +2020-08-10 20:17:38 +0300 Vivia Nikolaidou + + * gst/flv/gstflvmux.c: + flvmux: Fix possible crash on GST_ITERATOR_RESYNC + Wrong pointer type + Part-of: + +2020-08-10 15:49:55 +1000 Matthew Waters + + * ext/qt/qtglrenderer.cc: + qmlgloverlay: fix multiple elements with Qt 5.15 + With Qt 5.15 multiple qmlgloverlay elements would produce: + ASSERT: "!m_gl->property(QSG_RENDERCONTEXT_PROPERTY).isValid()" in file /path/to/qt5/qtdeclarative/src/quick/scenegraph/qsgdefaultrendercontext.cpp, line 121 + Workaround by setting the (seeminigly unused) property before + initialization. + Part-of: + +2020-08-05 10:41:33 +0300 Sebastian Dröge + + * docs/gst_plugins_cache.json: + * gst/rtp/gstrtph264pay.c: + * gst/rtp/gstrtph265pay.c: + * tests/check/elements/rtp-payloading.c: + * tests/check/elements/rtph264.c: + * tests/check/elements/rtph265.c: + rtph26[45]pay: Change default aggregate-mode to "none" for backwards compatibility + We didn't aggregate at all in previous versions and there are apparently + various RTP implementations that don't handle aggregation well at all. + As part of this also document that for RTSP it is recommended to keep it + set to "none" while for WebRTC it should be set to "zero-latency". + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/749 + Part-of: + +2020-07-24 16:58:34 +1000 Matthew Waters + + * ext/gtk/meson.build: + * ext/qt/meson.build: + * meson.build: + * tests/examples/gtk/meson.build: + build: update for gl pkg-config file split + Part-of: + +2020-07-31 13:50:13 +0200 Jan Alexander Steffens (heftig) + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: Make sure flushing doesn't block + * Trying to disconnect a stream from a running splitmuxsink by flushing + it results in the FLUSH_START blocking in the stream queue's + gst_pad_pause_task because the flush did not unblock + complete_or_wait_on_out, so add a check for ctx->flushing there. + * Add a GST_SPLITMUX_BROADCAST_INPUT so check_completed_gop notices + flushing changed and the incoming push is unblocked. + * Pass the FLUSH_STOP along to the muxer without waiting. + Part-of: + +2020-08-04 15:49:43 +0300 Vivia Nikolaidou + + * gst/imagefreeze/gstimagefreeze.c: + imagefreeze: Wait until we have a clock + Otherwise it can happen that it tries to get the clock in PAUSED state + in live mode, which does not exist. + Thanks to Sebastian Dröge for helping debugging. + Fixes #775 + Part-of: + +2020-07-31 11:05:02 +0100 Tim-Philipp Müller + + * gst/isomp4/qtdemux.c: + qtdemux: extract bit depth from codec data for ALAC + The info in the sound sample description might not be + accurate if it's an older version atom. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/771 + Part-of: + +2020-07-28 18:46:30 +0300 Jordan Petridis + + * gst/auparse/gstauparse.c: + auparse: fix compiler warnings + GCC 10 was complaining like following. It really is complaining about default cases returning + with potentially unitialized *desval, but those cases in the switch should never be hit. + ``` + ../subprojects/gst-plugins-good/gst/auparse/gstauparse.c: In function 'gst_au_parse_chain': + ../subprojects/gst-plugins-good/gst/auparse/gstauparse.c:481:37: error: 'timestamp' may be used uninitialized in this function [-Werror=maybe-uninitialized] + 481 | GST_BUFFER_TIMESTAMP (outbuf) = timestamp; + ../subprojects/gst-plugins-good/gst/auparse/gstauparse.c:482:36: error: 'duration' may be used uninitialized in this function [-Werror=maybe-uninitialized] + 482 | GST_BUFFER_DURATION (outbuf) = duration; + ../subprojects/gst-plugins-good/gst/auparse/gstauparse.c:480:34: error: 'offset' may be used uninitialized in this function [-Werror=maybe-uninitialized] + 480 | GST_BUFFER_OFFSET (outbuf) = offset; + cc1: all warnings being treated as errors + ``` + Part-of: + +2020-07-29 14:06:55 +0300 George Kiagiadakis + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: drop stream-start message posted by the internal udp sink(s) + See #1368 + Part-of: + +2020-07-22 16:24:15 +0900 Hosang Lee + + * tests/check/elements/qtdemux.c: + tests: qtdemux: test correct pad names are created + Test correct pad names are created in accordance to their media type + in mss mode. + Part-of: + +2020-06-16 17:23:44 +0900 Hosang Lee + + * gst/isomp4/qtdemux.c: + qtdemux: create correct pad names in encrypted streams + Refer to "original-media-type" when setting stream's subtype + for encrypted streams in mss mode. + Part-of: + +2020-07-22 14:31:13 -0400 Thibault Saunier + + * gst/matroska/matroska-mux.c: + matroskamux: Do caps renegotiation when it only adds fields + Matroskamux can accept caps renegotiation if the new caps is a + superset of the old one, meaning upstream added new info to + the caps. + Same logic as a5f22f03aa25b04726f78ae619f40b3b648f7d48 in qtmux. + Part-of: + +2020-07-24 14:02:26 +0100 Tim-Philipp Müller + + * gst/rtpmanager/gstrtpfunnel.c: + rtpfunnel: protect internal srccaps with lock + These are modified from sink pad event handlers, so + could be accessed from multiple threads at the same + time. + Part-of: + +2020-02-23 23:44:16 +0100 Havard Graff + + * gst/rtpmanager/gstrtpfunnel.c: + rtpfunnel: copy caps before sending them in a caps-event + Reason being we don't want downstream to own a ref to our + internal caps. + Part-of: + +2020-07-27 15:41:26 +0200 Mathieu Duponchelle + + * gst/rtpmanager/gstrtpjitterbuffer.c: + * gst/rtpmanager/gstrtpsession.c: + * gst/rtpmanager/rtpsession.c: + * gst/rtpmanager/rtpsource.c: + rtpmanager: fix various documentation issues + Improper naming of properties, improper links, misc + Part-of: + +2020-07-24 17:13:04 +0100 Tim-Philipp Müller + + * sys/rpicamsrc/RaspiCapture.c: + rpicamsrc: hypothetical fix for data pointer calculation + mmal buffer header docs say data is valid for length bytes + from offset. In practice offset always seems to be 0 so + far though. + Part-of: + +2020-07-24 16:35:43 +0100 Tim-Philipp Müller + + * sys/rpicamsrc/RaspiCapture.c: + rpicamsrc: mark buffers as header and keyframe/delta-unit + Part-of: + +2020-07-24 16:14:00 +0100 Tim-Philipp Müller + + * sys/rpicamsrc/RaspiCapture.c: + * sys/rpicamsrc/RaspiCapture.h: + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: fix nal alignment of output buffers + We claim output buffers are nal-aligned, but that wasn't + actually true: We would push out a partial nal in case + the nal doesn't fit into the max encoder-selected output + buffer size, and then the next buffer would not start + with a sync marker. That's not right and makes h264parse + unhappy. + Instead accumulate buffers until we have a full frame + (we can't rely on the NAL_END flag, it's always set). + Fixes #768 + Part-of: + +2020-07-13 23:43:48 +0100 Tim-Philipp Müller + + * sys/rpicamsrc/meson.build: + rpicamsrc: fix "Could not find component vc.ril.camera" on recent raspios + Make extra sure all the required mmal libs such as libmmal_vc_client.so + actually get linked and stay linked. Otherwise the above error happens + it seems. + buster (10.4) with meson 0.55 and pi ref 2020-05-27 + pi-gen, 825107f04027269db77426046f5085475b1ea22f, stage5 + Part-of: + +2020-07-13 17:01:42 +0100 Tim-Philipp Müller + + * po/POTFILES: + * sys/rpicamsrc/gstrpicamsrcdeviceprovider.c: + rpicamsrc: deviceprovider: hook up i18n properly + Part-of: + +2020-07-13 16:55:48 +0100 Tim-Philipp Müller + + * sys/rpicamsrc/gstrpicamsrcdeviceprovider.c: + rpicamsrc: deviceprovider: advertise (M)JPEG as well + Part-of: + +2020-07-13 16:50:58 +0100 Tim-Philipp Müller + + * sys/rpicamsrc/gstrpicamsrcdeviceprovider.c: + rpicamsrc: deviceprovider: also advertise constrained-baseline profile + Part-of: + +2020-07-23 16:58:00 +0200 Stéphane Cerveau + + * meson.build: + meson: add a plugin summary + This summary displays a list of plugins which + have been enabled. + Part-of: + +2020-07-22 09:46:47 +0800 Haihua Hu + + * sys/v4l2/gstv4l2object.h: + * sys/v4l2/v4l2_calls.c: + v4l2: enhance v4l2 control interface to support string type CID + add string type cid support for v4l2 implementation + Part-of: + +2020-07-01 15:17:47 +0200 Stéphane Cerveau + + * gst/isomp4/fourcc.h: + * gst/isomp4/qtdemux.c: + * gst/isomp4/qtdemux_types.c: + qtdemux: add Dolby Vision fourcc + This identifiers are registered in the MPEG-RA and defined + to be used by the Dolby Vision AVC/HEVC streams. + This is a first step to present the stream to the decoder. + Additional box parsing of DOVIConfigurationBox is necessary + to complete the media presentation with proper Dolby Vision + enhancements. + Part-of: + +2020-05-17 15:51:09 +1000 Luke Yelavich + + * gst/imagefreeze/gstimagefreeze.c: + imagefreeze: Copy GstCapsFeatures to caps for source pad + Allows using imagefreeze with buffers in GLMemory. The following pipeline + works. + gst-launch-1.0 filesrc location=image.jpg ! jpegdec ! glupload ! \ + imagefreeze ! glcolorconvert ! glimagesinkelement + Part-of: + +2020-07-20 18:20:59 +0100 Tim-Philipp Müller + + * gst/rtpmanager/rtptwcc.h: + rtpmanager: fix "redefinition of typedef RTPTWCCManager" compiler warning + G_DECLARE_FINAL_TYPE includes this typedef as well. + Part-of: + +2020-07-17 16:39:25 -0400 Olivier Crête + + * gst/rtp/gstrtpac3pay.c: + * gst/rtp/gstrtpamrpay.c: + * gst/rtp/gstrtpceltpay.c: + * gst/rtp/gstrtpg723pay.c: + * gst/rtp/gstrtpg729pay.c: + * gst/rtp/gstrtpgsmpay.c: + * gst/rtp/gstrtpgstpay.c: + * gst/rtp/gstrtpmp2tpay.c: + * gst/rtp/gstrtpmp4apay.c: + * gst/rtp/gstrtpmp4gpay.c: + * gst/rtp/gstrtpmpapay.c: + * gst/rtp/gstrtpsbcpay.c: + * gst/rtp/gstrtpspeexpay.c: + * gst/rtp/gstrtpvorbispay.c: + rtp*pay: Allocate using the base class for audio codecs + This is required to add RTP header extensions from the + meta automatically. + Part-of: + +2020-07-14 13:14:09 +0200 Ognyan Tonchev + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: Fix segfault with illegal free + set_get_param_q is not a pointer so it is illegal to call g_queue_free_full(). + Freeing the requests by popping them from the queue instead. + Part-of: + +2020-07-15 14:40:42 +0300 Raul Tambre + + * ext/qt/qtitem.cc: + QtGLVideoItem: Use QSharedPointer::data() for better compatibility + Older Qt versions didn't have QSharedPointer::get(), which is just a modern alias for QSharedPointer::data(). + FAILED: ext/qt/libgstqmlgl.so.p/qtitem.cc.o + c++ -Iext/qt/libgstqmlgl.so.p -Iext/qt -I../ext/qt -I. -I.. -I../gst-libs -I/usr/include/glib-2.0 -I/usr/lib/aarch64-linux-gnu/glib-2.0/include -I/usr/include/gstreamer-1.0 -I/usr/include/orc-0.4 -I/usr/lib/aarch64-linux-gnu/gstreamer-1.0/include -I/usr/include/aarch64-linux-gnu/qt5/QtCore -I/usr/include/aarch64-linux-gnu/qt5 -I/usr/include/aarch64-linux-gnu/qt5/QtGui -I/usr/include/aarch64-linux-gnu/qt5/QtQml -I/usr/include/aarch64-linux-gnu/qt5/QtNetwork -I/usr/include/aarch64-linux-gnu/qt5/QtQuick -I/usr/include/aarch64-linux-gnu/qt5/QtX11Extras -I/usr/include/libdrm -flto -fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -std=c++11 -Wmissing-declarations -Wredundant-decls -Wwrite-strings -Winit-self -Wmissing-include-dirs -Wno-multichar -Wvla -Wpointer-arith -g -fdebug-prefix-map=/opt/good/src=. -Wformat -Werror=format-security -O3 -march=native -Wno-error -Wdate-time -fPIC -pthread -DHAVE_CONFIG_H -DHAVE_QT_X11 -DHAVE_QT_EGLFS -MD -MQ ext/qt/libgstqmlgl.so.p/qtitem.cc.o -MF ext/qt/libgstqmlgl.so.p/qtitem.cc.o.d -o ext/qt/libgstqmlgl.so.p/qtitem.cc.o -c ../ext/qt/qtitem.cc + In file included from /usr/include/gstreamer-1.0/gst/gst.h:55:0, + from /usr/include/gstreamer-1.0/gst/video/video.h:23, + from ../ext/qt/qtitem.cc:27: + ../ext/qt/qtitem.cc: In destructor ‘virtual QtGLVideoItem::~QtGLVideoItem()’: + ../ext/qt/qtitem.cc:138:86: error: ‘class QSharedPointer’ has no member named ‘get’ + GST_INFO ("%p Destroying QtGLVideoItem and invalidating the proxy %p", this, proxy.get()); + ^ + /usr/include/gstreamer-1.0/gst/gstinfo.h:682:31: note: in definition of macro ‘GST_CAT_LEVEL_LOG’ + (GObject *) (object), __VA_ARGS__); \ + ^~~~~~~~~~~ + ../ext/qt/qtitem.cc:138:3: note: in expansion of macro ‘GST_INFO’ + GST_INFO ("%p Destroying QtGLVideoItem and invalidating the proxy %p", this, proxy.get()); + ^ + Part-of: + +2020-07-14 14:24:20 +0100 Justin Chadwell + + * gst/isomp4/qtdemux.c: + * tests/check/elements/qtdemux.c: + qtdemux: fix allocation explosion with stsd entries + Previously, the user input for stsd entries is trusted completely, and + so a maliciously crafted file could choose the length of the stsd + entries arbitrarily and cause qtdemux to try to allocate up to 2GB of + memory (half of a 32 bit max int). + This patch fixes this by sanity checking the stsd input against the + size of the entire stsd atom. + Part-of: + +2020-07-13 10:37:19 +0100 Justin Chadwell + + * gst/isomp4/qtdemux.c: + * tests/check/elements/qtdemux.c: + qtdemux: fix crashes when input stream contained no stsd entries + During trak parsing, we need to check for the existence of stsd_entries, + otherwise, we end up with a NULL pointer to them. It is entirely + possible for the stsd to exist, but for it to have no entries, which the + previous checks did not take into account. + This patch adds a simply check to ensure that all files that do not + contain a stsd entry are deemed corrupt, and adds a test case to prevent + a regression. + Part-of: + +2020-07-15 12:40:17 +0100 Tim-Philipp Müller + + * docs/gst_plugins_cache.json: + docs: update for new pixel formats + https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/753 + https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/754 + Part-of: + +2020-07-10 21:43:14 +0100 Tim-Philipp Müller + + * sys/rpicamsrc/meson.build: + rpicamsrc: fix build with older meson versions + assert() used to require two arguments. + Part-of: + +2020-07-10 13:08:55 +0000 Tim-Philipp Müller + + * tests/examples/meson.build: + * tests/examples/rpicamsrc/meson.build: + * tests/examples/rpicamsrc/test_color_balance.c: + * tests/examples/rpicamsrc/test_orientation.c: + examples: hook up rpicamsrc examples + webrtc one should probably go into gst-examples. + Part-of: + +2020-07-10 00:42:13 +0100 Tim-Philipp Müller + + * tests/examples/rpicamsrc/test_color_balance.c: + * tests/examples/rpicamsrc/test_orientation.c: + * tests/examples/rpicamsrc/webrtc-unidirectional-h264.c: + examples: fix indentation of rpicamsrc examples + Part-of: + +2020-07-09 19:08:34 +0000 Tim-Philipp Müller + + * docs/gst_plugins_cache.json: + * docs/meson.build: + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: flesh out docs and add to plugin docs cache + Part-of: + +2020-07-09 18:04:10 +0000 Tim-Philipp Müller + + * sys/rpicamsrc/gstrpicamsrc.c: + * sys/rpicamsrc/gstrpicamsrc.h: + rpicamsrc: enable video orientation/direction unconditionally + Part-of: + +2020-07-09 17:37:01 +0000 Tim-Philipp Müller + + * sys/rpicamsrc/gstrpicam-enums-template.c: + * sys/rpicamsrc/gstrpicam-enums-template.h: + rpicamsrc: remove mkenums template files which are no longer needed + They were still being used by the autotools build, but that's gone. + Part-of: + +2020-07-09 17:35:15 +0000 Tim-Philipp Müller + + * sys/rpicamsrc/RaspiCLI.c: + * sys/rpicamsrc/RaspiCamControl.c: + * sys/rpicamsrc/RaspiCapture.c: + * sys/rpicamsrc/RaspiPreview.c: + * sys/rpicamsrc/RaspiStill.c: + * sys/rpicamsrc/RaspiStillYUV.c: + * sys/rpicamsrc/gstrpicamsrc.c: + * sys/rpicamsrc/gstrpicamsrcdeviceprovider.c: + rpicamsrc: fix indentation + Not touching the Raspi* files. + Part-of: + +2020-07-09 17:31:49 +0000 Tim-Philipp Müller + + * sys/rpicamsrc/RaspiCapture.c: + * sys/rpicamsrc/RaspiCapture.h: + * sys/rpicamsrc/gstrpicamsrc.c: + * sys/rpicamsrc/meson.build: + rpicamsrc: fix and silence some compiler warnings + Some are in system headers, and in Raspi files we want + to keep modifications to a minimum. + Part-of: + +2020-07-09 16:07:30 +0000 Tim-Philipp Müller + + * meson_options.txt: + * sys/meson.build: + * sys/rpicamsrc/gstrpicamsrc.c: + * sys/rpicamsrc/gstrpicamsrcdeviceprovider.c: + * sys/rpicamsrc/gstrpicamsrcdeviceprovider.h: + * sys/rpicamsrc/meson.build: + rpicamsrc: hook up to build + Part-of: + +2020-07-09 11:46:30 +0000 Tim-Philipp Müller + + Merge branch 'plugin-move-rpicamsrc' + Move rpicamsrc from https://github.com/thaytan/gst-rpicamsrc/ + It's a useful little element and works well, so might as well + make sure it's widely available so people can stop piping + raspivid output into fdsrc. + Part-of: + +2020-05-02 19:27:20 +0000 Tim-Philipp Müller + + * sys/rpicamsrc/gstrpicam-enums-template.c: + * sys/rpicamsrc/gstrpicam-enums-template.h: + rpicamsrc: sync autotools with glib-mkenum usage in meson build + +2020-05-02 18:28:10 +0000 Tim-Philipp Müller + + * sys/rpicamsrc/gstrpicamsrc.c: + * sys/rpicamsrc/meson.build: + rpicamsrc: meson: use gnome.glib_mkenums_simple() and fix build as Meson subproject + While at it also fix up the type defines, e.g. + GST_RPI_CAM_TYPE_RPI_CAM_SRC_EXPOSURE_MODE -> GST_RPI_CAM_SRC_TYPE_EXPOSURE_MODE + +2020-05-03 11:09:47 +0000 Tim-Philipp Müller + + * sys/rpicamsrc/gstplugin.map: + * sys/rpicamsrc/meson.build: + rpicamsrc: meson: drop map file and fix plugin symbol export with newer gstreamer versions + Use -fvisibility instead of a map file for symbol export, so that + the right symbols get exported with newer gstreamer versions. Older + GStreamer versions also still work of course. + Fixes blacklisting/plugin-loading issues with GStreamer >= 1.14 + Fixes https://github.com/thaytan/gst-rpicamsrc/issues/984, + closes https://github.com/thaytan/gst-rpicamsrc/issues/94 + and https://github.com/thaytan/gst-rpicamsrc/issues/67 + +2018-07-16 19:49:21 +1000 Jan Schmidt + + * sys/rpicamsrc/RaspiCapture.c: + rpicamsrc: Attempt to workaround MMAL timeout bug + mmal_queue_timedwait() might spuriously return immediately + if called at exactly the wrong instant due to an internal + off-by-one bug. Attempt to work around that and just retry. + +2018-07-16 19:30:26 +1000 Jan Schmidt + + * sys/rpicamsrc/RaspiCapture.c: + * sys/rpicamsrc/RaspiCapture.h: + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Improve timeout error + Propagate timeout errors so they're not reported + generically + +2018-06-21 22:50:28 +1000 Jan Schmidt + + * tests/examples/rpicamsrc/webrtc-unidirectional-h264.c: + rpicamsrc: webrtc example: Add a STUN server to the configuration + To let the webrtc example work through NAT firewalls + +2018-06-21 22:44:25 +1000 Jan Schmidt + + * tests/examples/rpicamsrc/webrtc-unidirectional-h264.c: + rpicamsrc: webrtc example: Modify HTML to support other ports than 57778 + +2018-06-21 21:45:32 +1000 Jan Schmidt + + * tests/examples/rpicamsrc/webrtc-unidirectional-h264.c: + rpicamsrc: webrtc example: Remove external fmtp insertion + GStreamer 1.14.2 should contain the backport of gst-plugins-bad + commit 5c450c5 adding FEC and RTX support, and incidentally + the fmtp field in the SDP + +2018-06-21 20:33:03 +1000 Jan Schmidt + + * tests/examples/rpicamsrc/webrtc-unidirectional-h264.c: + rpicamsrc: webrtc example: Set the locale + Make the date format in the overlay respect the current + locale + +2018-06-20 15:36:42 +0000 Jan Schmidt + + * sys/rpicamsrc/RaspiCapture.c: + rpicamsrc: Don't destroy the camera component on startup error + Just disable the camera component when it fails to start. The + most common reason is that the camera device is already in use, + and if we just disable the mmal component correct cleanup + will happen later + +2018-05-12 21:13:52 +0000 Jan Schmidt + + * tests/examples/rpicamsrc/webrtc-unidirectional-h264.c: + rpicamsrc: Add webrtc streaming example + Add an example for testing webrtc streaming from the rpi + camera, based on the code from + https://bugzilla.gnome.org/show_bug.cgi?id=795404 + Requires GStreamer 1.14.1 or git master + +2018-05-12 19:57:43 +0000 Jan Schmidt + + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Expose constrained-baseline profile + constrained-baseline is a useful profile for streaming to iOS + devices, and seems to work in the firmware, so let's publish it + +2018-03-28 22:00:10 +1100 Jan Schmidt + + * sys/rpicamsrc/RaspiCapture.h: + * sys/rpicamsrc/gstrpicamsrc.c: + * sys/rpicamsrc/gstrpicamsrcdeviceprovider.c: + rpicamsrc: Add define and increase reported maximum FPS from 90 to 1000 + +2017-11-14 15:01:21 +1100 Jan Schmidt + + * sys/rpicamsrc/RaspiCapture.c: + rpicamsrc: Expand frame timeout from 100ms to 500ms + rpicamsrc on a normal rpi camera doesn't start up fast enough, + and always fails the new 100ms timeout. A better solution + might be to have a longer timeout for the first frame, but + shorter once frames are running - but this quick fix will at + least make rpicamsrc work again. + +2017-11-08 09:14:35 +0000 Georgii Staroselskii + + * sys/rpicamsrc/RaspiCapture.c: + rpicamsrc: RaspiCapture: use mmal_queue_timedwait() for buffer queueing + If an external camera was disconnected, there were no feedback in an + application. It seems reasonable to wait on mmal_queue no longer than + 100ms. If it's stuck we just return a FLOW_ERROR and let the application + decide what to do later. + +2017-11-07 15:14:06 +0000 Georgii Staroselskii + + * sys/rpicamsrc/RaspiCapture.c: + rpicamsrc: RaspiCapture: handle MMAL_EVENT_ERROR + +2017-07-01 00:51:13 +1000 Jan Schmidt + + * sys/rpicamsrc/RaspiCapture.c: + * sys/rpicamsrc/RaspiCapture.h: + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Implement use-stc property to disable STC timestamps + If use-stc=false, then rpicamsrc won't apply + the camera timestamping to outgoing buffers, instead + relying on real-time timestamping by the + GStreamer clock. It means slightly less accuracy + and more jitter in timestamps, but might help on some + CSI inputs with broken timestamping. + +2017-05-19 20:55:35 +1000 Jan Schmidt + + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Fix the descriptions of text annotation colour properties + The text annotation colour properties take an integer value + corresponding to a VUY colour, not a text string like + the copy-pasted description from raspivid suggests. + Fixes https://github.com/thaytan/gst-rpicamsrc/issues/59 + +2017-01-27 12:58:29 +1100 Jan Schmidt + + * sys/rpicamsrc/RaspiCapture.c: + rpicamsrc: Implement dynamic bitrate update + Use mmal_port_set_parameter_uint32 to update the encoder + bitrate. + Fixes https://github.com/thaytan/gst-rpicamsrc/issues/60 + +2016-10-08 11:12:09 +0000 Jan Schmidt + + * sys/rpicamsrc/gstrpicamsrc.c: + * sys/rpicamsrc/gstrpicamsrc.h: + rpicamsrc: Set outgoing buffer durations based on negotiated framerate. + make sure outgoing buffers have at least some duration set, + otherwise it leads to strange situations, like qtmux writing + out a file that doesn't include the final frame inside the + playable segment, because no-duration = 0 duration there. + +2016-10-08 11:10:30 +0000 Jan Schmidt + + * sys/rpicamsrc/RaspiCapture.c: + rpicamsrc: Destroy mmal pool on shutdown always. + Avoid hangs on the next run because we didn't clean up the mmal pool + last time we shutdown. + +2016-10-03 15:29:49 +0000 Jan Schmidt + + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Switch back to MJPEG codec for image/jpeg + The JPEG codec hangs, not sure why yet. The MJPEG + codec doesn't provide a quality setting, and sometimes + freezes on shutdown, but otherwise seems more + reliable + +2016-10-03 14:00:54 +0000 Jan Schmidt + + * sys/rpicamsrc/RaspiCapture.c: + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Don't try and set H264 params with JPEG codec + +2016-10-03 02:34:50 +1100 Jan Schmidt + + * sys/rpicamsrc/RaspiCapture.c: + * sys/rpicamsrc/RaspiCapture.h: + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: First attempt at implementing MJPEG and raw video support + +2016-09-19 12:06:05 +0000 Tim-Philipp Müller + + * sys/rpicamsrc/gstplugin.map: + * sys/rpicamsrc/meson.build: + rpicamsrc: Add experimental build using the Meson build system + Builds in about 10 seconds vs. 77 seconds with autotools. + +2016-08-30 17:00:41 +0200 Xabier Rodriguez Calvar + + * sys/rpicamsrc/gstrpicamsrc.c: + * sys/rpicamsrc/gstrpicamsrc.h: + rpicamsrc: Implement GstVideoDirection interface + Instead of implementing a custom property, we implement that interface. + +2016-07-21 02:29:57 +1000 Jan Schmidt + + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: MMAL gives buffers with nal alignment, not AU + Fix the output caps, our buffers are not AU aligned, since + the SPS / PPS are given in separate packets at the start. + +2016-07-08 15:32:21 +0200 Xabier Rodriguez Calvar + + * sys/rpicamsrc/gstrpicamsrc.c: + * sys/rpicamsrc/gstrpicamsrc.h: + rpicamsrc: Create orientation property + Its behavior and choices are analog to the ones present in [gl]videoflip + for the method property. + +2016-01-03 08:26:23 +1100 Jan Schmidt + + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: basesrc event handlers should not unref + Don't unref the passed event when handling events via + the GstBaseSrc src pad event handler - basesrc does + the unref. That breaks handling of upstream + force-key-unit events by unreffing twice. + Fixes https://github.com/thaytan/gst-rpicamsrc/issues/43 + +2015-12-17 14:16:10 +1100 Jan Schmidt + + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Add property getters for preview window position. + Add the lines in get_property() for the preview-x/y/w/h properties + so the values can be retrieved without causing critical warnings. + Fixes https://github.com/thaytan/gst-rpicamsrc/issues/42 + +2015-12-02 01:20:10 +1100 Jan Schmidt + + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Add preview-x/y/w/h properties + Expose properties for setting the position of the preview + window on the screen + +2015-10-21 21:11:36 +1100 Jan Schmidt + + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Add properties for configuring annotation text size and colour. + Map the raspivid setting for annotation text size and colours + to properties. + +2015-10-08 10:32:32 +0200 ibauer + + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Changed awb-gain-blue use the correct enum PROP_AWB_GAIN_BLUE and not PROP_AWB_GAIN_RED + +2015-07-19 01:48:35 +1000 Jan Schmidt + + * sys/rpicamsrc/RaspiCapture.c: + rpicamsrc: Fix buffer PTS calculation + Timestamps from MMAL are in microseconds, + so make sure to convert to nanoseconds before + using them to adjust the GStreamer buffer time + +2015-05-11 11:16:52 +0200 Philippe Normand + + * sys/rpicamsrc/gstrpicamsrc.c: + * tests/examples/rpicamsrc/test_orientation.c: + rpicamsrc: Basic orientation interface support + The (h,v)flip attributes are now supported through this interface. + It should also be possible to support (h,v)center attributes using the + ROI properties. + +2015-05-11 21:29:58 +1000 Jan Schmidt + + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Describe awb-mode=off in lowercase + Change the descriptions for the awb-gain-blue and awb-gain-red + properties to say 'awb-mode=off' instead of 'awb-mode=OFF' + See https://github.com/thaytan/gst-rpicamsrc/issues/26 + +2015-05-11 10:17:18 +0200 Philippe Normand + + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: colorbalance: protect with config_lock mutex + +2015-05-05 19:03:43 +0200 Philippe Normand + + * tests/examples/rpicamsrc/test_color_balance.c: + rpicamsrc: add test-color-balance example + This small test will display a live video preview of the rpicam with + the balance controls being updated once a second. The controls to + update can be disabled in the source by setting the CONTROL_* macros + values to 0. + +2015-04-29 16:36:18 +0200 Philippe Normand + + * sys/rpicamsrc/gstrpicamsrc.c: + * sys/rpicamsrc/gstrpicamsrc.h: + rpicamsrc: Implement GstColorBalance interface + Fixes https://github.com/thaytan/gst-rpicamsrc/issues/24 + +2015-04-27 22:56:32 +1000 Jan Schmidt + + * sys/rpicamsrc/RaspiCapture.c: + * sys/rpicamsrc/RaspiCapture.h: + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Fix initial config setting. + Make sure to update the captsure config before starting + capture. Since the capture component now keeps a local + copy of the config, it's not updated automatically. + +2015-04-27 04:05:42 +1000 Jan Schmidt + + * sys/rpicamsrc/RaspiCapture.c: + rpicamsrc: Disable bitrate, quantisation and intra-refresh dynamic changes + The firmware rejects dynamic changes of those encoder params. + +2015-04-27 04:05:04 +1000 Jan Schmidt + + * sys/rpicamsrc/RaspiCapture.h: + rpicamsrc: Send vcos_log_warn via GStreamer debug messages + +2015-04-27 02:43:14 +1000 Jan Schmidt + + * tests/examples/rpicamsrc/dynamicprops.py: + rpicamsrc: Add dynamic properties example + Python example of adjusting saturation on the fly + +2015-04-27 00:54:54 +1000 Jan Schmidt + + * sys/rpicamsrc/RaspiCapture.c: + * sys/rpicamsrc/RaspiCapture.h: + * sys/rpicamsrc/gstrpicamsrc.c: + * sys/rpicamsrc/gstrpicamsrc.h: + rpicamsrc: Update properties dynamically where possible + Update camera and encoder properties at runtime + where possible + Fixes https://github.com/thaytan/gst-rpicamsrc/issues/19 + and https://github.com/thaytan/gst-rpicamsrc/issues/23 + +2015-04-27 00:40:23 +1000 Jan Schmidt + + * sys/rpicamsrc/RaspiPreview.c: + * sys/rpicamsrc/RaspiPreview.h: + rpicamsrc: split preview config and state + +2015-04-21 02:45:59 +1000 Jan Schmidt + + * sys/rpicamsrc/RaspiCapture.c: + rpicamsrc: Clear intra-refresh MMAL param struct. + Use memset on the stack allocated MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T + struct. Apparently mmal_port_parameter_get() doesn't retrieve all + parameters, causing random failures when we set the intra-refresh + param on the encoder. + Fixes https://github.com/thaytan/gst-rpicamsrc/issues/22 for me. + +2015-04-21 01:17:55 +1000 Jan Schmidt + + * sys/rpicamsrc/RaspiCamControl.c: + * sys/rpicamsrc/RaspiCamControl.h: + * sys/rpicamsrc/RaspiCapture.c: + rpicamsrc: Merge changes from userland repo + Current to b69f807ce59189457662c2144a8e7e12dc776988 + No integration of stereoscopic support as yet + +2015-04-21 00:02:27 +1000 Jan Schmidt + + * sys/rpicamsrc/gstrpicam_types.h: + rpicamsrc: Map intra-refresh cyclic-rows to the correct MMAL param. + +2015-03-10 00:22:40 +1100 Jan Schmidt + + * sys/rpicamsrc/RaspiCapture.c: + * sys/rpicamsrc/RaspiCapture.h: + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Use MMAL PTS and STC to calculate GStreamer timestamps + Don't apply timestamps based on output time from the encoder, + but use the MMAL STC and capture PTS to generate a GStreamer + timestamp that more accurately resembles the input (and would + preserve reordering should the encoder ever add B-frames). + Fixes https://github.com/thaytan/gst-rpicamsrc/issues/16 + +2015-03-07 02:11:25 +1100 Jan Schmidt + + * sys/rpicamsrc/RaspiCapture.c: + rpicamsrc: Defer encoder creation until after caps are negotiated + This ensures the encoder is created with the profile + negotiated with downstream + +2015-03-07 01:17:30 +1100 Jan Schmidt + + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Read and set H.264 profile from negotiated caps + +2015-03-06 03:43:07 +1100 Jan Schmidt + + * sys/rpicamsrc/gstrpicam_types.h: + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Add intra-refresh-type property, and set default keyframe spacing to -1 (auto) + This plus other recent commits mostly fix + bug https://github.com/thaytan/gst-rpicamsrc/issues/16 + +2015-03-06 03:05:24 +1100 Jan Schmidt + + * sys/rpicamsrc/gstrpicam_types.h: + * sys/rpicamsrc/gstrpicamsrc.c: + * sys/rpicamsrc/gstrpicamsrc.h: + rpicamsrc: Add annotation-mode and annotation-text properties + +2015-03-06 02:42:00 +1100 Jan Schmidt + + * sys/rpicamsrc/gstrpicamsrc.c: + * sys/rpicamsrc/gstrpicamsrc.h: + rpicamsrc: implement sensor-mode property + +2015-03-06 01:27:44 +1100 Jan Schmidt + + * sys/rpicamsrc/RaspiCapture.c: + * sys/rpicamsrc/RaspiCapture.h: + rpicamsrc: More conversion to GStreamer logging + +2015-03-06 01:15:48 +1100 Jan Schmidt + + * sys/rpicamsrc/gstrpicam_types.h: + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Implement drc property + +2015-03-06 01:09:16 +1100 Jan Schmidt + + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: add awb-gain-red and awb-gain-blue properties + +2015-03-06 00:52:37 +1100 Jan Schmidt + + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Add camera-number property + +2015-03-06 00:45:05 +1100 Jan Schmidt + + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: add inline-headers and shutter-speed properties + +2015-03-06 00:21:31 +1100 Jan Schmidt + + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Add quantisation-parameter property, support variable bitrate + Allow birate=0 and implement the quantisation-parameter property + Fixes https://github.com/thaytan/gst-rpicamsrc/issues/21 + +2015-03-05 17:01:33 +1100 Jan Schmidt + + * sys/rpicamsrc/RaspiCLI.c: + * sys/rpicamsrc/RaspiCLI.h: + * sys/rpicamsrc/RaspiCamControl.c: + * sys/rpicamsrc/RaspiCamControl.h: + * sys/rpicamsrc/RaspiCapture.c: + * sys/rpicamsrc/RaspiCapture.h: + * sys/rpicamsrc/RaspiPreview.c: + * sys/rpicamsrc/RaspiPreview.h: + rpicamsrc: Incorporate raspivid changes from upstream + Merge all changes for new features from upstream + raspberrypi userland, up to commit 0de0b2 + +2015-01-05 02:21:16 +1100 Jan Schmidt + + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Add keyframe-interval property to the element + +2014-10-30 00:45:18 +0000 Tim-Philipp Müller + + * sys/rpicamsrc/RaspiCamControl.c: + * sys/rpicamsrc/RaspiCamControl.h: + * sys/rpicamsrc/gstrpicamsrcdeviceprovider.c: + rpicamsrc: deviceprovider: check if camera is detected and supported + +2014-10-29 00:43:51 +0000 Tim-Philipp Müller + + * sys/rpicamsrc/gstrpicamsrc.c: + * sys/rpicamsrc/gstrpicamsrcdeviceprovider.c: + * sys/rpicamsrc/gstrpicamsrcdeviceprovider.h: + rpicamsrc: Add GstDeviceProvider for rpi camera module + +2014-09-27 14:31:10 +0100 Tim-Philipp Müller + + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: avoid single-element lists in template caps + +2014-10-09 20:38:41 +0000 Vivia Nikolaidou + + * sys/rpicamsrc/RaspiCapture.c: + * sys/rpicamsrc/RaspiCapture.h: + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Add force-key-unit event support + +2014-03-13 00:16:18 +1100 Jan Schmidt + + * sys/rpicamsrc/RaspiCamControl.c: + * sys/rpicamsrc/RaspiCapture.c: + * sys/rpicamsrc/RaspiCapture.h: + * sys/rpicamsrc/RaspiPreview.c: + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Move all debug output to go via GStreamer logs + Fixes https://github.com/thaytan/gst-rpicamsrc/issues/9 + +2013-10-19 18:52:25 +1100 Jan Schmidt + + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Update maximum framerate to 90 fps + +2013-10-14 02:39:00 +1100 Jan Schmidt + + * sys/rpicamsrc/RaspiCamControl.c: + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Enable image effects + +2013-10-13 18:01:00 +1100 Jan Schmidt + + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Re-flow element source code with gst-indent + +2013-10-13 17:46:07 +1100 Jan Schmidt + + * sys/rpicamsrc/gstrpicam-enums-template.c: + * sys/rpicamsrc/gstrpicam-enums-template.h: + * sys/rpicamsrc/gstrpicam_types.h: + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Implement a bunch of the raspivid command-line params + Add properties for controlling various parts of the capture + +2013-10-13 01:29:08 +1100 Jan Schmidt + + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: Tell basesrc to timestamp buffers for us, for now. + +2013-10-13 01:20:51 +1100 Jan Schmidt + + * sys/rpicamsrc/RaspiCamControl.c: + * sys/rpicamsrc/RaspiCapture.c: + * sys/rpicamsrc/RaspiCapture.h: + * sys/rpicamsrc/gstrpicamsrc.c: + * sys/rpicamsrc/gstrpicamsrc.h: + rpicamsrc: Initial caps nego and properties. + Support caps negotiation for H.264 frame size and framerate. + Add bitrate, saturation, brightness, contrast, sharpness properties. + +2013-10-12 19:23:03 +1100 Jan Schmidt + + * sys/rpicamsrc/RaspiCapture.c: + * sys/rpicamsrc/RaspiCapture.h: + * sys/rpicamsrc/gstrpicamsrc.c: + rpicamsrc: First version which generates buffers on the src pad + Fixed to 1920x1080 h264 regardless of caps. + +2013-10-12 12:42:07 +1100 Jan Schmidt + + * sys/rpicamsrc/RaspiCamControl.c: + * sys/rpicamsrc/RaspiCapture.c: + * sys/rpicamsrc/RaspiCapture.h: + * sys/rpicamsrc/RaspiStill.c: + * sys/rpicamsrc/gstrpicamsrc.c: + * sys/rpicamsrc/gstrpicamsrc.h: + rpicamsrc: Checkpoint. Version which writes directly to test.out + Switch to plain basesrc for parent class + +2013-10-11 19:17:05 +1100 Jan Schmidt + + * sys/rpicamsrc/RaspiCamControl.c: + * sys/rpicamsrc/RaspiCamControl.h: + * sys/rpicamsrc/RaspiCapture.c: + * sys/rpicamsrc/RaspiCapture.h: + * sys/rpicamsrc/RaspiPreview.c: + * sys/rpicamsrc/RaspiPreview.h: + * sys/rpicamsrc/RaspiStill.c: + * sys/rpicamsrc/RaspiStillYUV.c: + * sys/rpicamsrc/gstrpicamsrc.c: + * sys/rpicamsrc/gstrpicamsrc.h: + rpicamsrc: checkpoint + +2013-10-10 23:47:38 +1100 Jan Schmidt + + * sys/rpicamsrc/gstrpicamsrc.c: + * sys/rpicamsrc/gstrpicamsrc.h: + rpicamsrc: Initial commit + Simple modified gst-template to use BaseCameraSrc + Incorporate Broadcom mmal headers + +2018-04-19 13:57:26 +0200 Michael Olbrich + + * ext/soup/gstsouphttpsrc.c: + souphttpsrc: don't fail when seeking past the end of the content + Range errors are already turned into EOS when the size is not known. + Do the same thing if the request as outside the known content size. + This can be triggered by seeking in a queue2: + - Ensure that the range containing the end of the file is available. + - Seek into this range from a different range. + - queue2 creates a seek event with start= + - this results in a "Requested Range Not Satisfiable" error + Fixes #452 + Part-of: + +2019-11-10 21:19:09 +0100 Michael Olbrich + + * ext/soup/gstsouphttpsrc.c: + souphttpsrc: don't update the size on error + Any data corresponding length in the message is not part of the requested + file. + Part-of: + +2020-06-18 19:12:46 +1000 Matthew Waters + + * ext/qt/qtglrenderer.cc: + qt/gloverlay: fix using OpenGL after destroying Qml + Qml somewhat unhelpfully seems to uncurrent our OpenGL context on its + destruction. Work around that by uncurrenting and recurrenting again. + Part-of: + +2020-07-08 17:02:34 +0100 Tim-Philipp Müller + + * meson.build: + * scripts/extract-release-date-from-doap-file.py: + meson: set release date from .doap file for releases + Part-of: + +2020-07-07 12:36:01 +0300 Sebastian Dröge + + * gst/isomp4/gstqtmux.c: + qtmux: Don't lock object lock twice in prefill mode + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/762 + Part-of: + +2020-07-04 01:02:02 +0100 Tim-Philipp Müller + + * gst/audiofx/meson.build: + * gst/deinterlace/meson.build: + * gst/videobox/meson.build: + * gst/videomixer/meson.build: + * meson.build: + * scripts/update-orc-dist-files.py: + meson: add update-orc-dist target + Add target to update backup orc -dist.[ch] files. + Part-of: + +2020-05-26 10:27:35 -0400 Xavier Claessens + + * sys/v4l2/gstv4l2videodec.c: + v4l2: Do not renegotiate if only framerate changed + Part-of: + +2020-07-02 09:15:08 +0300 Sebastian Dröge + + * ext/flac/gstflacenc.c: + flacenc: Pass audio info from set_format() to query_total_samples() explicitly + This fixes writing of the seek table header. + gst_audio_encoder_get_audio_info() will still return old/unset audio + info until set_format() has actually returned, which then results in + query_total_samples() to always return 0. + Thanks to Jacob Kauffmann for debugging this and finding the main cause. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/756 + Part-of: + +2020-07-03 02:03:33 +0100 Tim-Philipp Müller + + * docs/gst_plugins_cache.json: + * meson.build: + Back to development + +=== release 1.17.2 === + +2020-07-03 00:27:47 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * docs/gst_plugins_cache.json: + * gst-plugins-good.doap: + * meson.build: + Release 1.17.2 + +2020-07-02 07:53:14 +0530 Nirbheek Chauhan + + * gst/deinterlace/meson.build: + * meson.build: + deinterlace: Disable nasm support on x32 + The assembly assumes pointers are 64-bit, so just disable it. + Closes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/757 + Part-of: + +2020-07-01 18:19:09 +0530 Nirbheek Chauhan + + * gst/deinterlace/meson.build: + deinterlace: Fix build on x32 + Need to pass `-f elfx32` to nasm in that case. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/757 + Part-of: + +2020-07-01 16:17:19 +1000 Jan Schmidt + + * gst/matroska/matroska-mux.c: + matroska-mux: Wait for caps on sparse streams + Don't set sparse streams to non-waiting at the collectpads + level until after capa arrive, as we need caps on all + pads before the file headers get written, or else the + subtitle track will be silently absent in the final file. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/724 + Part-of: + +2020-07-01 16:13:27 +1000 Jan Schmidt + + * gst/matroska/matroska-mux.c: + matroska-mux: Warn on late caps arrival + As well as warning when caps change after the headers + were already written, make sure to warn if the *first* caos + arrive late too. + Part-of: + +2020-06-30 18:37:06 +0300 Sebastian Dröge + + * gst/imagefreeze/gstimagefreeze.c: + imagefreeze: Return TRUE from the LATENCY query handling + We always answer it successfully no matter what. + The default return value in the function is FALSE even if the code below + sets it again to FALSE. + Part-of: + +2020-06-29 11:53:39 +0300 Sebastian Dröge + + * tests/check/elements/imagefreeze.c: + imagefreeze: Add test for new live mode + Part-of: + +2020-06-29 10:10:09 +0300 Sebastian Dröge + + * docs/gst_plugins_cache.json: + * gst/imagefreeze/gstimagefreeze.c: + * gst/imagefreeze/gstimagefreeze.h: + imagefreeze: Add a live mode + Previously imagefreeze would always operate as non-live element and + output frames as fast as possible according to the configured segment + (via SEEK events) and the negotiated framerate from start to stop or the + other way around. + With the new live mode (enabled via the is-live property) it would only + output frames in PLAYING. Frames would be output according to the + negotiated framerate unless it would be too late, in which case it would + jump ahead and skip over the requirement amount of frames. + This makes it possible to actually use imagefreeze in live pipelines + without having to manually ensure somehow that it would start outputting + at the current running time and without still risking to fall behind + without recovery. + Part-of: + +2020-06-28 22:26:23 +0300 Sebastian Dröge + + * gst/imagefreeze/gstimagefreeze.c: + imagefreeze: Correctly answer the LATENCY query + We never run as a live element, even if upstream is live, and never + output any buffers with latency but immediately generate buffers as + fast as we can according to the negotiated framerate. + Passing the query upstream would proxy whatever mode of operation + upstream has, which has nothing to do with how we produce buffers. + Part-of: + +2020-06-25 14:15:51 -0400 Nicolas Dufresne + + * sys/v4l2/gstv4l2bufferpool.c: + v4l2: Fix threading issues in orphaning mechanism + The pool orphaning function was colling internal _stop() virtual function + implementation. This is not thread safe, as a private lock inside the buffer + pool is supposed to be held. Fix this by keeping delayed _stop() and orphaning + the GstV4L2Allocator instead (REQBUFS(0)). + Then, protect the orphaned boolean with the object lock for the case a buffer + is being released after we have orphaned the buffer. That would otherwise + cause a QBUF to happen while the queue is no longer owned by the buffer pool. + This boolean is otherwise used and set from the streaming lock, or after + threads have been stopped (final cleanup). + Part-of: + +2020-06-26 16:43:37 -0400 Nicolas Dufresne + + * sys/v4l2/gstv4l2bufferpool.c: + v4l2bufferpoool: Fix requeueue after seek when importing + When the buffer pool is importing buffer, it will requeue num_allocated on + streamon. As this value was not set for DMABuf import and USERPTR, no buffer + was queued back. + Part-of: + +2020-06-26 16:39:42 -0400 Nicolas Dufresne + + * sys/v4l2/gstv4l2bufferpool.c: + Revert "v4l2bufferpool: request the maximum number of buffers for USERPTR" + This reverts commit 6bf9f4bd77a4c6cce8786893feea7d601a6e6030. + Part-of: + +2020-06-26 16:37:06 -0400 Nicolas Dufresne + + * sys/v4l2/gstv4l2bufferpool.c: + Revert "v4l2bufferpool: request the maximum number of buffers for DMABUF" + This reverts commit 94e323c10f2d7fa85bf63f357d203ca5305800c6. + Fixes #754 + Part-of: + +2020-06-26 14:48:14 -0400 Nicolas Dufresne + + * sys/v4l2/gstv4l2bufferpool.c: + v4l2bufferpool: Only resurrect the right amount of buffers + On streamon, we need to resurrect (queue back) some buffers, as during + flushign seek we'd endup with an empty queued. We initially started with + resurrecting as many as we could without blocking, but that miss-behaved with + dynamic CREATE_BUFS, causing the pool to grow dramatically. This was limited + by the number of allocated buffers, but this still tried to resurrect too many + buffers for the first run, as activating the pool will queued buffers. + In this patch, we calculte the missing detal in the queue and only try and + resurrect that amount of buffers. + Part-of: + +2020-06-26 13:11:04 -0400 Nicolas Dufresne + + * sys/v4l2/gstv4l2object.c: + v4l2object: Only offer inactive pools and if needed + Avoid offering a pool if it's not needed or if it's still active. + This works around the fact the we only have one pool in V4L2. + Part-of: + +2020-06-24 21:58:07 +0530 Nirbheek Chauhan + + * ext/qt/gstqtglutility.cc: + * ext/qt/meson.build: + qt: Rework how we find the Qt QPA header + Instead of querying the Qt include path from the dependency or from + qmake, rely on the qt5qml_dep to set the include path to QtGui + correctly, and look for the header inside the private includedir. + Then we can use that path to include the header directly. + Reported in https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/issues/780#note_548092 + Part-of: + +2020-06-24 22:04:55 +0530 Nirbheek Chauhan + + * ext/qt/meson.build: + qt: Only check for moc-qt5/moc in PATH if not cross-compiling + This is an extra check that's only needed for working around Linux + distribution packaging. `moc` is not required in the cross file. + Part-of: + +2020-06-26 13:10:00 -0400 Nicolas Dufresne + + * sys/v4l2/gstv4l2allocator.c: + v4l2allocator: Don't do REQBUFS(0) on inactive allocator + If the allocator is no longer active, it means the memory has already + been freed, calling REQBUF(0) would make no sense. + Part-of: + +2020-06-26 11:05:25 -0400 Nicolas Dufresne + + * sys/v4l2/gstv4l2bufferpool.c: + v4l2bufferpool: Avoid set_flushing warning + The gst_buffer_pool_set_flushing() warns when that function is called + on an inactive pool. Avoid the warning by checking the state, this is + similar to what we do in gst_v4l2_object_unlock(). + Part-of: + +2020-06-26 09:53:13 -0400 Nicolas Dufresne + + * sys/v4l2/gstv4l2allocator.c: + v4l2allocator: Fix data offset / bytesused size validation + The check was too strict causing spurious warning. Now check for <= so that 0 + sized buffer do not cause a warning. + Part-of: + +2020-06-25 16:46:23 -0400 Nicolas Dufresne + + * sys/v4l2/gstv4l2videoenc.c: + v4l2videoenc: Fix negotiation caps leak + Part-of: + +2020-06-26 19:28:31 +0100 Tim-Philipp Müller + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: flesh out docs for format-location* signals + Make explicit that the returned strings need to be g_free()-able. + Fixes #753 + Part-of: + +2020-06-25 16:47:42 -0400 Nicolas Dufresne + + * sys/v4l2/gstv4l2videoenc.c: + v4l2videoenc: Skip negotiation of profiles/level if no codec + The codec structure is optional and not used for fwht test codec. This + was leading to a crash dereferencing NULL pointer. + Part-of: + +2020-05-03 13:17:46 +0200 Havard Graff + + * gst/rtpmanager/rtpstats.c: + rtpstats: guard against division by zero + Part-of: + +2020-06-17 23:23:58 +0200 Havard Graff + + * gst/rtpmanager/rtptwcc.c: + rtptwcc: fix pruning of ack'ed twcc-packets + Fixes #750 + Part-of: + +2020-06-24 21:15:47 +0530 Nirbheek Chauhan + + * tests/examples/qt/qmloverlay/meson.build: + * tests/examples/qt/qmlsink-dynamically-added/meson.build: + * tests/examples/qt/qmlsink/meson.build: + * tests/examples/qt/qmlsrc/meson.build: + meson: Build Qt5 tests with -std=c++11 + We already do this for the plugin. + https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/issues/780#note_548179 + Part-of: + +2020-06-25 12:58:48 +0300 Sebastian Dröge + + * docs/gst_plugins_cache.json: + * gst/multifile/gstsplitmuxsink.c: + * gst/multifile/gstsplitmuxsink.h: + splitmuxsink: Add new properties for setting muxer/sink presets + Part-of: + +2020-06-24 17:04:51 +0200 Mathieu Duponchelle + + * docs/gst_plugins_cache.json: + * gst/autodetect/gstautodetect.c: + autodetect: mark filter-caps property as DOC_SHOW_DEFAULT + When generating the cache we inspect the base class through + an instance of one of its subclasses. We don't want potential + assignments in subclasses initialization to leak into the + base class documentation + Part-of: + +2020-06-24 16:45:27 +0200 Mathieu Duponchelle + + * docs/gst_plugins_cache.json: + * ext/vpx/gstvpxenc.c: + vpxenc: mark all properties as GST_DOC_SHOW_DEFAULT + When generating the cache we inspect the base class through + an instance of one of its subclasses. We don't want potential + assignments in subclasses initialization to leak into the + base class documentation + Part-of: + +2020-06-23 19:04:03 +0200 Mathieu Duponchelle + + * docs/gst_plugins_cache.json: + * gst/equalizer/gstiirequalizer.c: + docs: mark GstIirEqualizer as plugin API + +2020-06-23 12:47:44 -0400 Thibault Saunier + + * ext/vpx/gstvp8enc.c: + * ext/vpx/gstvp9enc.c: + vpx: Fix links to baseclass properties + +2020-06-23 02:50:35 +0200 Mathieu Duponchelle + + * docs/gst_plugins_cache.json: + * sys/v4l2/tuner.c: + * sys/v4l2/tunerchannel.c: + docs: mark more types as plugin API + +2020-06-23 00:02:34 +0200 Mathieu Duponchelle + + * docs/gst_plugins_cache.json: + plugins_cache: add base classes + +2020-06-23 00:02:21 +0200 Mathieu Duponchelle + + * docs/meson.build: + meson: mark plugins cache target as always stale + +2020-06-21 01:34:43 +0200 Mathieu Duponchelle + + * ext/gtk/gstgtkbasesink.c: + * ext/vpx/gstvpxdec.c: + * ext/vpx/gstvpxenc.c: + * gst/audiofx/audiofxbasefirfilter.c: + * gst/audiofx/audiofxbaseiirfilter.c: + * gst/autodetect/gstautodetect.c: + docs: mark more types as plugin API + +2020-06-19 22:54:38 -0400 Thibault Saunier + + * docs/gst_plugins_cache.json: + doc: Stop documenting properties from parents + +2020-06-21 20:11:06 +0800 He Junyan + + * gst/deinterlace/yadif.c: + deinterlace: Add the missing ORC_RESTRICT define. + ORC_RESTRICT may not be defined in yadif.c and cause build error. + Part-of: + +2019-06-06 09:41:13 +0200 Havard Graff + + * tests/check/elements/rtpsession.c: + rtpsession: make tests more stable + Part-of: + +2020-06-20 20:42:37 +0100 Tim-Philipp Müller + + * docs/gst_plugins_cache.json: + docs: update plugin cache for new version + Some default values include our version string, like + user agent strings. + +2020-06-20 00:28:11 +0100 Tim-Philipp Müller + + * meson.build: + Back to development + +=== release 1.17.1 === + +2020-06-19 19:18:59 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * docs/gst_plugins_cache.json: + * gst-plugins-good.doap: + * meson.build: + Release 1.17.1 + +2020-06-19 20:24:12 +0900 Seungha Yang + + * gst/deinterlace/meson.build: + meson: deinterlace: Check host cpu type for asm build + Add host cpu type check as we would enable asm only for x86_64 + Part-of: + +2020-06-19 19:54:08 +0900 Seungha Yang + + * meson.build: + meson: Fix build error with MSVC caused by ARCH_X86_64 define + ARCH_X86_64 define will enable GCC specific code path in dv_types.h + while building dv plugin. + Part-of: + +2020-06-19 10:32:45 +0100 Tim-Philipp Müller + + * docs/gst_plugins_cache.json: + * ext/shout2/gstshout2.c: + shout2: advertise documentation caps properly + shout2send caps depend on what the libshout2 + version in question supports, but the + documentation caps should always be the same. + Part-of: + +2019-05-26 20:20:03 +1000 Jan Schmidt + + * gst/isomp4/meson.build: + * gst/isomp4/qtdemux.c: + * gst/isomp4/qtdemux.h: + * gst/isomp4/qtdemux_tags.c: + * gst/isomp4/qtdemux_tags.h: + qtdemux: Split tag reading functions out + Move some code out of the enormous qtdemux.c into a separate + qtdemux_tags helper, and make some structs available via qtdemux.h + to accommodate that. + Part-of: + +2019-05-26 05:05:06 +1000 Jan Schmidt + + * gst/isomp4/meson.build: + * gst/isomp4/qtdemux.c: + * gst/isomp4/qtdemux_tree.c: + * gst/isomp4/qtdemux_tree.h: + qtdemux: Move some tree parsing files out to a separate file. + Reduce a tiny bit of the bulk of qtdemux.c by moving some + agnostic helper functions out. + Part-of: + +2019-05-26 01:24:54 +1000 Jan Schmidt + + * gst/isomp4/atoms.c: + * gst/isomp4/qtdemux.c: + qtdemux: Factor out svmi parsing. Fix bounds checking. + Move the SVMI stereoscopic atom parsing out to a helper + function to shrink qtdemux_parse_trak a bit. + Add a bounds check that the received atom is large enough + before parsing it. + Add a note to the atom parser that svmi comes from the + MPEG-A spec 23000-11. + Part-of: + +2020-06-15 13:05:49 +0200 Guillaume Desmottes + + * ext/pulse/pulsedeviceprovider.c: + pulse: fix discovery of newly added devices + Fix regression introduced in 7bc5e28d85992b03e5852879b8d4d96043496caf + preventing the device provider to send the device-added message for new + devices. + By early returning the patch was discarding add/remove events. + Fix #735 + Part-of: + +2020-06-18 10:47:28 +0100 Tim-Philipp Müller + + * tests/examples/qt/qmlsink-dynamically-added/meson.build: + * tests/examples/qt/qmlsink-dynamically-added/play.pro: + * tests/examples/qt/qmlsink-dynamically-added/qmlsink-dyn-added.qrc: + examples: qmlsink: rename qrc file to avoid naming conflicts with older meson versions + Would get "Tried to create target "qt5-qmlsink_qrc", but a + target of that name already exists." with older meson versions. + Work around that by renaming the qrc file. + Part-of: + +2020-06-17 16:42:16 +0530 Nirbheek Chauhan + + * meson.build: + meson: Check the nasm version with run_command + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/751 + Part-of: + +2020-06-16 19:34:01 +0900 Seungha Yang + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: Don't return TRUE for unhandled query + Expected return value for unhandled query is FALSE + Part-of: + +2020-06-16 11:52:38 +0300 Vivia Nikolaidou + + * gst/deinterlace/meson.build: + * gst/deinterlace/x86/x86inc.asm: + * gst/deinterlace/x86/yadif.asm: + * gst/deinterlace/yadif.c: + * gst/deinterlace/yadif.h: + * meson.build: + * meson_options.txt: + deinterlace: Add yadif ASM optimisations + Measured to be about 3.4x faster than C + Part-of: + +2020-06-12 13:21:02 +0300 Vivia Nikolaidou + + * gst/deinterlace/yadif.c: + deinterlace: Fix invalid read in yadif + Part-of: + +2020-06-12 12:18:11 +1000 Matthew Waters + + * ext/qt/qtglrenderer.cc: + qt/gloverlay: reset OpenGL state after Qt drawing + Reset to the original OpenGL state as required by the GStreamer OpenGL + API contract. Fixes output with a glimagesink element downstream. + Part-of: + +2020-06-12 12:16:49 +1000 Matthew Waters + + * ext/qt/qtglrenderer.cc: + qt/gloverlay: reset current OpenGL context after Qt + Qt may replace the drawable with its own which breaks output if Qt is + not displaying the resulting video as used with e.g. glimagesink. + Part-of: + +2020-06-12 09:52:56 +0300 Sebastian Dröge + + * gst/flv/gstflvdemux.c: + flvdemux: Change a GST_ERROR_OBJECT() back to GST_DEBUG_OBJECT() + It was accidentally changed in https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/merge_requests/436 + Part-of: + +2020-06-11 20:39:33 +0300 Jordan Petridis + + * gst/isomp4/gstqtmux.c: + * sys/v4l2/gstv4l2videodec.c: + Use gst_element_class_set_metadata when passing dynamic strings + gst_element_class_set_metadata is meant to only be used with + static or inlined strings, which isn't the case for the 2 elements + here resulting in use-after-free later on. + https://gstreamer.freedesktop.org/documentation/gstreamer/gstelement.html?gi-language=c#gst_element_class_set_static_metadata + Part-of: + +2020-06-10 13:56:22 +0000 Sebastian Dröge + + * gst/rtpmanager/gstrtpjitterbuffer.c: + Revert "rtpjitterbuffer: Avoid deadlock on flush" + This reverts commit 54810bf44f27d9c180730f58f16f6e172c7b0bc8 + Part-of: + +2020-06-09 15:12:13 -0400 Thibault Saunier + + * docs/gst_plugins_cache.json: + docs: Update plugins cache + +2020-06-09 13:09:20 -0700 U. Artie Eoff + + * gst/rtpmanager/gstrtpjitterbuffer.c: + rtpjitterbuffer: g_queue_clear_full introduced in glib 2.60 + Define g_queue_clear_full if glib < 2.60. + Fixes #747 + Part-of: + +2020-06-08 11:33:16 -0400 Thibault Saunier + + * docs/gst_plugins_cache.json: + * gst/rtpmanager/rtpsession.c: + rtpsession: Make internal-ssrc as show default for doc + +2020-06-08 10:56:02 -0400 Thibault Saunier + + * docs/gst_plugins_cache.json: + docs: Update plugins cache + +2020-06-09 15:21:25 +0100 Tim-Philipp Müller + + * tests/check/meson.build: + tests: don't pull in all -bad plugin, only allow the one we need + Set up our plugin include list for tests in such a way that + we don't pull in *all* plugins from -bad but only the one + used in the splitmuxsink unit test, i.e. the timecode plugin, + so we don't accidentally use other encoders/decoders such as + nvenc/dec for example. + Part-of: + +2020-06-08 17:41:13 -0400 Nicolas Dufresne + + * gst/rtpmanager/rtptimerqueue.c: + rtptimerqueue: Fix leak on timer collision + While the caller should make sure this does not happen, make sure timer + collision are not silently ignored and leaked. + Fixes #726 + Part-of: + +2020-03-27 15:48:32 -0400 Nicolas Dufresne + + * gst/rtpmanager/gstrtpjitterbuffer.c: + rtpjitterbuffer: Keep JBUF lock while processing timers + Until now, do_expected_timeout() was shortly dropping the JBUF_LOCK in order + to push RTX event event without causing deadlock. As a side effect, some + CPU hung would happen as the timerqueue would get filled while looping over + the due timers. To mitigate this, we were processing the lost timer first and + placing into a queue the remainign to be processed later. + In the gap caused by an unlock, we could endup receiving one of the seqnum + present in the pending timers. In that case, the timer would not be found and + a new one was created. When we then update the expected timer, the seqnum + would already exist and the updated timer would be lost. + In this patch we remove the unlock from do_expected_timeout() and place all + pending RTX event into a queue (instead of pending timer). Then, as soon as + we have selected a timer to wait (or if there is no timer to wait for) we send + all the upstream RTX events. As we no longer unlock, we no longer need to pop + more then one timer from the queue, and we do so with the lock held, which + blocks any new colliding timers from being created. + Part-of: + +2020-06-08 09:33:10 +0200 Guillaume Desmottes + + * tests/check/elements/vp9enc.c: + tests: vp9enc: enforce I420 format + Test was not enforcing a video format on videotestsrc. I420 was picked + as it was the first format in GST_VIDEO_FORMATS_ALL which will no longer + be true (gst-plugins-base!689). + Part-of: + +2020-05-30 08:55:19 +0200 Edward Hervey + + * gst/rtpmanager/gstrtpjitterbuffer.c: + rtpjitterbuffer: Avoid deadlock on flush + When a GST_EVENT_FLUSH_START reaches the jitterbuffer, there is a chance that + our task is currently blocking waiting for a timer. + There was two problems: + * That wait wasn't checking for flushing situations + * The flushing handling wasn't waking up that conditional (to check whether it + should abort) + Part-of: + +2020-06-06 00:42:25 +0200 Mathieu Duponchelle + + * ext/aalib/gstaasink.c: + * ext/aalib/gstaatv.c: + * ext/dv/gstdvdec.c: + * ext/flac/gstflacenc.c: + * ext/gdk_pixbuf/gstgdkpixbufoverlay.c: + * ext/jack/gstjackaudiosink.c: + * ext/jpeg/gstjpegdec.c: + * ext/lame/gstlamemp3enc.c: + * ext/libcaca/gstcacasink.c: + * ext/libcaca/gstcacatv.c: + * ext/shout2/gstshout2.c: + * ext/speex/gstspeexenc.c: + * ext/twolame/gsttwolamemp2enc.c: + * ext/vpx/gstvpxdec.c: + * ext/vpx/gstvpxenc.c: + * ext/wavpack/gstwavpackenc.c: + * gst/alpha/gstalpha.c: + * gst/audiofx/audioamplify.c: + * gst/audiofx/audiochebband.c: + * gst/audiofx/audiocheblimit.c: + * gst/audiofx/audiodynamic.c: + * gst/audiofx/audiopanorama.c: + * gst/audiofx/audiowsincband.c: + * gst/audiofx/audiowsinclimit.c: + * gst/deinterlace/gstdeinterlace.c: + * gst/effectv/gstop.c: + * gst/effectv/gstradioac.c: + * gst/effectv/gstripple.c: + * gst/flv/gstflvmux.c: + * gst/isomp4/gstqtmux.c: + * gst/multifile/gstmultifilesink.c: + * gst/rtp/gstrtpdvpay.c: + * gst/rtp/gstrtph263ppay.c: + * gst/rtp/gstrtph264pay.c: + * gst/rtp/gstrtph265pay.c: + * gst/rtp/gstrtpilbcdepay.c: + * gst/rtp/gstrtpvp8pay.c: + * gst/rtp/gstrtpvp9pay.c: + * gst/rtpmanager/gstrtpbin.c: + * gst/rtpmanager/gstrtpjitterbuffer.c: + * gst/rtpmanager/gstrtpsession.c: + * gst/rtsp/gstrtspsrc.c: + * gst/smpte/gstsmpte.c: + * gst/smpte/gstsmptealpha.c: + * gst/videobox/gstvideobox.c: + * gst/videofilter/gstvideoflip.c: + * gst/videofilter/gstvideomedian.c: + * gst/videomixer/videomixer2.c: + * sys/v4l2/gstv4l2object.c: + plugins: uddate gst_type_mark_as_plugin_api() calls + +2020-06-05 11:49:17 +0300 Sebastian Dröge + + * gst/rtpmanager/gstrtpbin.c: + rtpbin: Initialize uninitialized variable correctly + `last_out` would be used uninitialized if the element has no `set-active` + signal. Initialize it to -1 as that's what the "default" value is + further below. + CID 1455443 + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/727 + Part-of: + +2015-11-26 17:52:29 +0100 Mikhail Fludkov + + * ext/vpx/gstvp9enc.c: + * ext/vpx/gstvpxenc.c: + * ext/vpx/gstvpxenc.h: + * tests/check/elements/vp8enc.c: + * tests/check/elements/vp9enc.c: + vpxenc: Add new bit-per-pixel property to select a better "default" bitrate + As part of this also change the default bitrate value to 0. The default + value was 256000 previously. In reality, if the property was not set the + bitrate value would be scaled according to the resolution which is not + very intuitive behavior. It is better to use 0 for this purpose. Now + together with newly introduced property "bits-per-pixel" 0 means to + assign the bitrate according to resolution/framerate. + The default bitrates are now + - 1.2Mbps for VP8 720p@30fps + - 0.8Mbps for VP9 720p@30fps + and scaled accordingly for different resolutions/framerates. + Previously the default bitrate was also not scaled according to the + framerate but only took the resolution into account. + This also fixes the side effect of setting bitrate to 0. Previously + encoder would not produce any data at all. + Addition from Sebastian Dröge to assume + 30fps if no framerate is given in the caps instead of not calculating + any bitrate at all. + Part-of: + +2020-06-03 18:35:58 -0400 Thibault Saunier + + * docs/meson.build: + doc: Require hotdoc >= 0.11.0 + +2020-06-02 14:58:47 -0400 Thibault Saunier + + * gst/rtpmanager/gstrtpjitterbuffer.c: + doc: Fix wrong link to GString in rtpjitterbuffer + +2020-05-27 16:01:22 +0300 Sebastian Dröge + + * docs/gst_plugins_cache.json: + docs: Update gst_plugins_cache.json + +2020-05-30 01:29:03 +0200 Mathieu Duponchelle + + * ext/aalib/gstaasink.c: + * ext/aalib/gstaatv.c: + * ext/dv/gstdvdec.c: + * ext/flac/gstflacenc.c: + * ext/gdk_pixbuf/gstgdkpixbufoverlay.c: + * ext/jack/gstjackaudiosink.c: + * ext/jpeg/gstjpegdec.c: + * ext/lame/gstlamemp3enc.c: + * ext/libcaca/gstcacasink.c: + * ext/libcaca/gstcacatv.c: + * ext/shout2/gstshout2.c: + * ext/speex/gstspeexenc.c: + * ext/twolame/gsttwolamemp2enc.c: + * ext/vpx/gstvpxdec.c: + * ext/vpx/gstvpxenc.c: + * ext/wavpack/gstwavpackenc.c: + * gst/alpha/gstalpha.c: + * gst/audiofx/audioamplify.c: + * gst/audiofx/audiochebband.c: + * gst/audiofx/audiocheblimit.c: + * gst/audiofx/audiodynamic.c: + * gst/audiofx/audiopanorama.c: + * gst/audiofx/audiowsincband.c: + * gst/audiofx/audiowsinclimit.c: + * gst/deinterlace/gstdeinterlace.c: + * gst/effectv/gstop.c: + * gst/effectv/gstradioac.c: + * gst/effectv/gstripple.c: + * gst/flv/gstflvmux.c: + * gst/isomp4/gstqtmux.c: + * gst/multifile/gstmultifilesink.c: + * gst/rtp/gstrtpdvpay.c: + * gst/rtp/gstrtph263ppay.c: + * gst/rtp/gstrtph264pay.c: + * gst/rtp/gstrtph265pay.c: + * gst/rtp/gstrtpilbcdepay.c: + * gst/rtp/gstrtpvp8pay.c: + * gst/rtp/gstrtpvp9pay.c: + * gst/rtpmanager/gstrtpbin.c: + * gst/rtpmanager/gstrtpjitterbuffer.c: + * gst/rtpmanager/gstrtpsession.c: + * gst/rtsp/gstrtspsrc.c: + * gst/smpte/gstsmpte.c: + * gst/smpte/gstsmptealpha.c: + * gst/videobox/gstvideobox.c: + * gst/videofilter/gstvideoflip.c: + * gst/videofilter/gstvideomedian.c: + * gst/videomixer/videomixer2.c: + * sys/v4l2/gstv4l2object.c: + plugins: Use gst_type_mark_as_plugin_api() for all non-element plugin types + +2018-02-28 15:46:51 +0100 Stian Selnes + + * ext/vpx/gstvpxdec.c: + * tests/check/elements/vp8dec.c: + vpxdec: Check that output width and height != 0 + For VP8 it's possible to signal width or height to be 0, but it does + not make sense to do so. For VP9 it's impossible. Hence, we most + likely have a corrupt stream. Trying to negotiate caps downstream with + either width or height as 0 will fail with something like + gst_video_decoder_negotiate_default: assertion 'GST_VIDEO_INFO_WIDTH (&state->info) != 0' failed + Part-of: + +2020-05-29 00:45:03 +0900 Seungha Yang + + * ext/speex/gstspeexdec.c: + * ext/speex/gstspeexenc.c: + speex: Fix crash on Windows caused by cross-CRT issue + Use speex_header_free() to free memory which was allocated by + library. Cross-CRT issue should not happen on 1.17 Cerbero build + but might happen custom build or so. + Part-of: + +2020-05-27 22:33:31 +0300 Sebastian Dröge + + * gst/rtsp/gstrtspsrc.h: + rtspsrc: Use the correct type for storing the max-rtcp-rtp-time-diff property + It's an integer property and rtpbin also expects an integer. Passing it + as a GstClockTime (guint64) to g_object_set() will cause problems, and + on big endian MIPS apparently causes crashes. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/737 + Part-of: + +2020-05-27 12:42:38 +0100 Tim-Philipp Müller + + * tests/check/meson.build: + tests: fix meson test env setup to make sure we use the right gst-plugin-scanner + If core is built as a subproject (e.g. as in gst-build), make sure to use + the gst-plugin-scanner from the built subproject. Without this, gstreamer + might accidentally use the gst-plugin-scanner from the install prefix if + that exists, which in turn might drag in gst library versions we didn't + mean to drag in. Those gst library versions might then be older than + what our current build needs, and might cause our newly-built plugins + to get blacklisted in the test registry because they rely on a symbol + that the wrongly-pulled in gst lib doesn't have. + This should fix running of unit tests in gst-build when invoking + meson test or ninja test from outside the devenv for the case where + there is an older or different-version gst-plugin-scanner installed + in the install prefix. + In case no gst-plugin-scanner is installed in the install prefix, this + will fix "GStreamer-WARNING: External plugin loader failed. This most + likely means that the plugin loader helper binary was not found or + could not be run. You might need to set the GST_PLUGIN_SCANNER + environment variable if your setup is unusual." warnings when running + the unit tests. + In the case where we find GStreamer core via pkg-config we use + a newly-added pkg-config var "pluginscannerdir" to get the right + directory. This has the benefit of working transparently for both + installed and uninstalled pkg-config files/setups. + Part-of: + +2020-05-25 20:11:31 -0400 Thibault Saunier + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: Error out when failling to receive message response + And let it rety twice. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/717 + Part-of: + +2020-05-21 17:12:55 -0400 Nicolas Dufresne + + * sys/v4l2/gstv4l2videoenc.c: + v4l2: videodec: Fix broken template caps + The profiles and levels were applied to the common caps instead of the copy. + That had the side effect of setting profiles/level from one CODEC onto + another. Leaving to encoder not being registered or not-negotiated errors. + Part-of: + +2020-05-21 17:09:39 -0400 Nicolas Dufresne + + * sys/v4l2/gstv4l2codec.c: + * sys/v4l2/gstv4l2codec.h: + * sys/v4l2/gstv4l2videodec.c: + * sys/v4l2/gstv4l2videoenc.c: + v4l2: codec: Fix GValue leak + The levels and profiles probe function returned a dynamically allocated GValue + that was leaked. Simplify this by using a stack allocated GValue and a boolean + return value. + Part-of: + +2020-05-21 16:39:53 -0400 Nicolas Dufresne + + * sys/v4l2/gstv4l2codec.c: + v4l2codec: Remove uneeded factorisation + There is only one user of that function and the split only increase + complexicity. + Part-of: + +2020-05-20 17:30:59 -0400 Nicolas Dufresne + + * sys/v4l2/gstv4l2src.c: + v4l2src: Ignore non-increasing sequence number + With older kernel, older driver or just broken drivers, the sequence number + may not be increasing. This simply ignore the sequence in this case. This + would otherwise miss-leading large amount of lost frame being reported. + Fixes #729 + Part-of: + +2020-05-18 13:17:14 +1000 Matthew Waters + + * ext/qt/gstqtoverlay.cc: + * ext/qt/gstqtoverlay.h: + * tests/examples/qt/qmloverlay/main.cpp: + qtoverlay: add the root item as a property + Part-of: + +2020-05-20 13:17:13 +0300 Sebastian Dröge + + * gst/flv/gstflvdemux.c: + flvdemux: Send gap events if one of the streams falls behind the other by more than 3s + Same mechanism and threshold as in other demuxers. + Part-of: + +2020-05-20 12:53:56 +0300 Sebastian Dröge + + * gst/flv/gstflvdemux.h: + flvdemux: Remove unused audio_linked/video_linked booleans + Part-of: + +2020-05-20 10:46:45 +0200 Edward Hervey + + * gst/flv/gstflvdemux.c: + * gst/flv/gstflvdemux.h: + flvdemux: Answer bitrate queries from upstream + If upstream (such as queue2 in urisourcebin) asks for our bitrate, check if we + have stored audio/video bitrates, and use them. + Part-of: + +2020-05-20 10:45:16 +0200 Edward Hervey + + * gst/flv/gstflvdemux.c: + flvdemux: Handle empty metadata strings + g_utf8_validate() errors out on empty string. But empty strings are valid, + so only check if they're not + Part-of: + +2020-05-20 10:44:19 +0200 Edward Hervey + + * gst/flv/gstflvdemux.c: + flvdemux: Set ACCEPT_TEMPLATE flag on sinkpad + A demuxer can accept any caps matching its sinkpad template caps + Part-of: + +2020-05-15 19:20:45 +0300 Raul Tambre + + * ext/qt/qtglrenderer.cc: + qtglrenderer.cc: Fix compiling + 46bfb7d247aef880c15300dad63eb2bbf6dc4928 fixed a format warning without checking if it actually compiled. + toUtf8() returns QByteArray so we need to assign it to a temporary variable to be able to get the raw string data from it. + Part-of: + +2020-05-15 06:07:25 +0000 Raul Tambre + + * ext/qt/qtglrenderer.cc: + qtglrenderer.cc: Fix -Wformat-security warning + Part-of: + +2020-05-12 04:35:37 +0530 Nirbheek Chauhan + + * ext/qt/meson.build: + * ext/taglib/meson.build: + * meson.build: + * sys/osxvideo/meson.build: + meson: Pass native: false to add_languages() + This is needed for cross-compiling without a build machine compiler + available. The option was added in 0.54, but we only need this in + Cerbero and it doesn't break older versions so it should be ok. + Part-of: + +2020-05-12 04:33:43 +0530 Nirbheek Chauhan + + * ext/qt/meson.build: + * ext/taglib/meson.build: + * meson.build: + meson: Make C++ compiler detection not be automagic + It is now controlled by the qt5 and/or taglib options. We won't + silently fail to build taglib now. + Part-of: + +2020-05-12 04:32:01 +0530 Nirbheek Chauhan + + * ext/gtk/meson.build: + * ext/qt/meson.build: + * meson.build: + * tests/examples/gtk/meson.build: + meson: Fix gstgl checks for qt and gtk + Also rename from build_ to have_, which is more accurate. + Part-of: + +2020-05-12 04:30:13 +0530 Nirbheek Chauhan + + * ext/qt/meson.build: + * tests/examples/qt/meson.build: + * tests/examples/qt/qmloverlay/meson.build: + * tests/examples/qt/qmlsink-dynamically-added/meson.build: + * tests/examples/qt/qmlsink/meson.build: + * tests/examples/qt/qmlsrc/meson.build: + meson: Revamp qt5qml plugin and example build code + Stricter and simpler. For example, now we properly error out when + gstreamer-gl-1.0 was not found when the qt5 plugin is enabled or when + a C++ compiler is not enabled. + Part-of: + +2020-05-09 03:09:03 +1000 Jan Schmidt + + * gst/deinterlace/yadif.c: + deinterlace: Split out NULL checks in yadif + Separate out explicit NULL checks for fields we depend on so + that coverity can hopefully verify dependencies better. + Part-of: + +2020-05-09 03:07:33 +1000 Jan Schmidt + + * gst/deinterlace/tvtime/greedy.c: + deinterlace: Handle NV12/NV21 for the greedyl mode. + Don't fall back on the default interpolate_scanline function, which + blindly tries to copy from the next field, which can be NULL in + mixed progressive/interlaced streams + Part-of: + +2020-05-05 16:59:56 +0300 Vivia Nikolaidou + + * gst/deinterlace/yadif.c: + deinterlace: Support packed formats for YADIF + Part-of: + +2020-05-06 11:04:18 +0300 Vivia Nikolaidou + + * gst/deinterlace/gstdeinterlacemethod.c: + deinterlace: Call the planar functions for the Y plane of nv12/nv21 + In some algorithms (like yadif), the Y plane has to be handled different + than the UV plane. Therefore, the planar_y functions are now called for + the Y plane, and the nv12/nv21 functions are handling only the UV/VU + planes respectively. + Part-of: + +2020-01-03 02:34:59 +1100 Jan Schmidt + + * gst/deinterlace/gstdeinterlace.c: + * gst/deinterlace/gstdeinterlace.h: + * gst/deinterlace/meson.build: + * gst/deinterlace/yadif.c: + * gst/deinterlace/yadif.h: + deinterlace: Add C implementation of YADIF + Import the YADIF deinterlacer from ffmpeg and modify + it to match the simple deinterlace scanlines structure. + Part-of: + +2020-01-03 02:33:25 +1100 Jan Schmidt + + * gst/deinterlace/gstdeinterlacemethod.c: + * gst/deinterlace/gstdeinterlacemethod.h: + deinterlace: Allow for 5 fields for interpolation + Add an extra field to the simple deinterlace implementation, + so that methods can potentially use 5 fields - the current + field, and 2 before and 2 after. + Part-of: + +2020-05-07 01:17:25 +1000 Jan Schmidt + + * gst/deinterlace/gstdeinterlace.c: + deinterlace: Force renegotiation when changing mode + Switching the deinterlacing mode on-the-fly from disabled to + auto used to work, but was broken by commit #1f21747c some + years ago. + Force re-negotiation with downstream when the mode or + fields properties are changed, otherwise deinterlace + never switches out of the passthrough mode. + Part-of: + +2020-04-23 15:32:58 +0800 nian.yan + + * ext/jpeg/gstjpegenc.c: + jpegenc: remove meta copy in jpegenc + GstVideoEncoder takes care of the Meta copy, so there is no need in + jpegenc + Fixes http://gstreamer-devel.966125.n4.nabble.com/jpegenc-copy-GstMeta-twice-tt4693981.html + Part-of: + +2020-05-05 17:47:28 +0300 Sebastian Dröge + + * gst/imagefreeze/gstimagefreeze.c: + * gst/imagefreeze/gstimagefreeze.h: + imagefreeze: Handle flushing correctly + First of all get rid of the atomic seeking boolean, which was only ever + set and never read. Replace it with a flushing boolean that is used in + the loop function to distinguish no buffer because of flushing and no + buffer because of an error as otherwise we could end up in a + GST_FLOW_ERROR case during flushing. + Also only reset the state of imagefreeze in flush-stop when all + processing is stopped instead of doing it as part of flush-start. + And last, get a reference to the imagefreeze buffer in the loop function + in the very beginning and work from that as otherwise it could in theory + be replaced or set to NULL in the meantime as we release and re-take the + mutex a couple of times during the loop function. + Part-of: + +2020-05-06 06:48:24 +0200 Edward Hervey + + * gst/videobox/gstvideobox.c: + videbox: Use MIN instead of CLAMP for uint + an unsigned int is always positive. + CID #206207 + CID #206208 + CID #206209 + CID #206210 + CID #206211 + Part-of: + +2020-05-06 06:35:27 +0200 Edward Hervey + + * gst/avi/gstavidemux.c: + avidemux: Avoid potential double-free + stream->name was being freed (without being NULL-ed) before we were certain it + would be set again. + CID #1456071 + Part-of: + +2020-05-05 17:30:48 +0200 Edward Hervey + + * gst/deinterlace/gstdeinterlace.c: + deinterlace: Don't leak frame in error case + CID #1455494 + Part-of: + +2020-05-05 15:19:49 +0200 Edward Hervey + + * gst/multifile/gstsplitmuxsrc.c: + slitmuxsrc: Properly stop the loop if not part reader is present + Previously this would end up in a refcounting loop of hell. + Part-of: + +2020-03-31 14:32:19 +0300 Vivia Nikolaidou + + * gst/flv/gstflvmux.c: + * gst/flv/gstflvmux.h: + flvmux: Add skip-backwards-streams property + Backwards timestamps confuse librtmp, even if they're only backwards + relative to the other stream. If the timestamp of a stream is going + backwards related to the other stream, this property allows the muxer to + skip a few buffers until it reaches the timestamp of the other stream. + Part-of: + +2020-03-31 14:10:35 +0300 Vivia Nikolaidou + + * gst/flv/gstflvmux.c: + flvmux: Allow requesting streamable pads after header is written + Allows us to request pads after writing header for streamable flv's. + For non-streamable it doesn't make sense to request a new pad after + writing the header, because the headers have been written already and we + can't add the new stream. But for streamable, any clients that connect + after the new pad has been added will be able to see both streams. + Part-of: + +2020-04-27 18:11:32 +1000 Matthew Waters + + * ext/qt/gstqtglutility.cc: + qt/x11: also pass the window for gstgl -> qt context + Removes this warning from Qt: + QGLXContext: Multiple configs for FBConfig ID -1 + QSGContext::initialize: depth buffer support missing, expect rendering errors + Part-of: + +2020-04-27 15:34:15 +1000 Matthew Waters + + * ext/qt/qtglrenderer.cc: + * ext/qt/qtglrenderer.h: + qt: perform surface creation in the main thread + As is required when creating a QWindow instance set out in the Qt + documentation. + Part-of: + +2020-04-22 15:32:31 -0400 Olivier Crête + + * gst/isomp4/fourcc.h: + * gst/isomp4/qtdemux.c: + qtdemux: Add 'mp3 ' fourcc that VLC seems to produce now + Part-of: + +2020-04-22 14:09:37 +0300 Sebastian Dröge + + * gst/rtpmanager/rtpjitterbuffer.c: + * gst/rtpmanager/rtpjitterbuffer.h: + rtpjitterbuffer: Properly free internal packets queue in finalize() + As we override the GLib item with our own structure, we cannot use any + function from GList or GQueue that would try to free the RTPJitterBufferItem. + In this patch, we move away from g_queue_new() which forces using + g_queue_free(). This this function could use g_slice_free() if there is any items + left in the queue. Passing the wrong size to GSLice may cause data corruption + and crash. + A better approach would be to use a proper intrusive linked list + implementation but that's left as an exercise for the next person + running into crashes caused by this. + Be ware that this regression was introduced 6 years ago in the following + commit [0], the call to flush() looked useless, as there was a g_queue_free() + afterward. + Signed-off-by: Nicolas Dufresne + [0] https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/commit/479c7642fd953edf1291a0ed4a3d53618418019c + Part-of: + +2020-04-20 19:43:57 +0900 Seungha Yang + + * tests/check/elements/splitmuxsink.c: + * tests/check/elements/splitmuxsinktimecode.c: + * tests/check/meson.build: + tests: splitmuxsink: Add more timecode based split test + ... and split test cases to run tests in parallel + +2020-04-10 23:52:45 +0900 Seungha Yang + + * gst/multifile/gstsplitmuxsink.c: + * gst/multifile/gstsplitmuxsink.h: + splitmuxsink: Enhancement for timecode based split + The calculated threshold for timecode might be varying depending on + "max-size-timecode" and framerate. + For instance, with framerate 29.97 (30000/1001) and + "max-size-timecode=00:02:00;02", every fragment will have identical + number of frames 3598. However, when "max-size-timecode=00:02:00;00", + calculated next keyframe via gst_video_time_code_add_interval() + can be different per fragment, but this is the nature of timecode. + To compensate such timecode drift, we should keep track of expected + timecode of next fragment based on observed timecode. + +2020-04-11 00:35:16 +0900 Seungha Yang + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: Post error when requested timecode interval is invalid + In case we cannot rely on max-size-timecode for split decision, + post error instead of crashing + +2020-04-16 16:47:50 +0200 Havard Graff + + * gst/rtpmanager/gstrtpjitterbuffer.c: + * tests/check/elements/rtpjitterbuffer.c: + rtpjitterbuffer: don't use RTX packets in rate-calc and reset-logic + The problem was this: + Due to the highly irregular arrival of RTX-packet the max-misorder variable + could be pushed very low. (-10). + If you then at some point get a big in the sequence-numbers (62 in the + test) you end up sending RTX-requests for some of those packets, and then + if the sender answers those requests, you are going to get a bunch of + RTX-packets arriving. (-13 and then 5 more packets in the test) + Now, if max-misorder is pushed very low at this point, these RTX-packets + will trigger the handle_big_gap_buffer() logic, and because they arriving + so neatly in order, (as they would, since they have been requested like + that), the gst_rtp_jitter_buffer_reset() will be called, and two things + will happen: + 1. priv->next_seqnum will be set to the first RTX packet + 2. the 5 RTX-packet will be pushed into the chain() function + However, at this point, these RTX-packets are no longer valid, the + jitterbuffer has already pushed lost-events for these, so they will now + be dropped on the floor, and never make it to the waiting loop-function. + And, since we now have a priv->next_seqnum that will never arrive + in the loop-function, the jitterbuffer is now stalled forever, and will + not push out another buffer. + The proposed fixes: + 1. Don't use RTX in calculation of the packet-rate. + 2. Don't use RTX in large-gap logic, as they are likely to be dropped. + +2020-04-15 12:36:29 -0400 Nicolas Dufresne + + * sys/v4l2/gstv4l2videodec.c: + v4l2videodec: Increase internal bitstream pool size + This patch will now set the maximum of buffers to 32, allowing to grow the + pool for drivers that supports that and will respect the minimum buffers + reported by the driver. This was made to fix a stall with the virtio CODEC + driver. + Fixes #672 + +2020-04-15 17:50:31 +0300 Sebastian Dröge + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: Do split-at-running-time splitting based on the time of the start of the GOP + If the start of the GOP is >= the requested running time, put it into a + new fragment. That is, split-at-running-time would always ensure that a + split happens as early as possible after the given running time. + Previously it was comparing against the current incoming timestamp, + which does not tell us what we actually want to know as it has no direct + relation to the GOP start/end. + +2020-04-15 13:21:05 +0300 Sebastian Dröge + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: Fix off-by-one in running time comparison for split-at-running-time + If we get a keyframe exactly at the requested running time we would only + split on the next keyframe afterwards due to wrong usage of > vs. >=. + +2020-04-09 12:23:44 -0400 Thibault Saunier + + * gst/rtsp/gstrtspsrc.c: + * gst/rtsp/gstrtspsrc.h: + rtspsrc: Properly set segments seqnums after seeks + +2020-04-08 19:49:00 +0300 Vivia Nikolaidou + + * gst/flv/gstflvdemux.c: + flvdemux: Don't write an empty string as a tag + To stop warnings like: + GStreamer-WARNING **: 19:47:48.186: Trying to set empty string on + taglist field 'encoder'. Please file a bug. + +2020-04-08 12:34:40 -0400 Nicolas Dufresne + + * sys/v4l2/gstv4l2bufferpool.c: + v4l2bufferpool: request the maximum number of buffers for USERPTR + This is to match what we now do for DMABuf importation. + +2019-11-20 15:32:29 +0100 Michael Olbrich + + * sys/v4l2/gstv4l2bufferpool.c: + v4l2bufferpool: request the maximum number of buffers for DMABUF + There are often only two buffers queued in the kernel so no new buffers are + requested. + With every qbuf, the kernel receives a new DMABUF for the specified index. + This most likely differs from the last DMABUF and the old cached entry is + released. This results in a lot of map/unmap overhead if the kernel driver + needs a mapping for the buffer. + With a larger queue, it's quite likely, that both old and new DMABUFs are + also mapped for another index. So the map/unmap is skipped, because the + mapping is reference counted. + The corresponding allocated buffers don't contain any actual memory, so + allocating them is quite cheep. So the log message is updated to clarify + this. + +2020-04-08 09:45:17 -0400 Thibault Saunier + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: Avoid stack overflow recursing waiting for response + Instead of recursing, simply implement a loop with gotos, the same + way it was done before 812175288769d647ed6388755aed386378d9210c + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/710 + +2020-04-06 16:25:59 +0300 Sebastian Dröge + + * gst/isomp4/gstqtmux.c: + * gst/isomp4/gstqtmux.h: + qtmux: Add property for enforcing the creation of chunks in single-stream files + This is disabled by default as it unnecessarily creates bigger headers + but it is something that is required by some applications and most + notably the Apple ProRes spec. + +2020-04-03 00:16:10 +1100 Jan Schmidt + + * gst/flv/gstflvmux.c: + flvmux: Fix invalid padlist accesses. + Request pads can released at any time, so make sure to hold + the object lock when iterating the element sinkpads list where + that's safe, or to use other safe pad iteration patterns in + other places. + When choosing a best pad, return a reference to the pad to make sure it + stays alive for output in the aggregator srcpad task. + Should fix a spurious valgrind error in the CI flvmux tests and some + other potential problems if the request sink pads are released while + the element is running.. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/714 + +2018-10-22 15:41:56 +0300 Vivia Nikolaidou + + * gst/isomp4/atoms.c: + * gst/isomp4/atoms.h: + * gst/isomp4/fourcc.h: + * gst/isomp4/gstqtmux.c: + * gst/isomp4/gstqtmux.h: + qtmux: Add option to create a timecode trak in non-mov flavors + Even if timecode trak is officially unsupported in non-mov flavors, + some software still supports it, e.g. Final Cut Pro X: + https://developer.apple.com/library/archive/technotes/tn2174/_index.html + The user might still expect to see the timecode information in the + non-mov file despite it being officially unsupported , because other + software e.g. QuickTime will create a timecode trak even in mp4 files. + Furthermore, software that supports timecode trak in non-mov flavors + will also display the file duration in "timecode units" instead of real + clock time, which is not necessarily the same for 29.97 fps and friends. + This might confuse users, who see a different duration for the same + framerate and amount of frames depending on whether the container is mp4 + or mov. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/512 + +2020-01-16 09:30:39 +0200 Sebastian Dröge + + * gst/rtp/gstrtpL16depay.c: + * gst/rtp/gstrtpL24depay.c: + * gst/rtp/gstrtpL8depay.c: + rtpLXXdepay: Set the UNPOSITIONED flag on the audio-info when configuring an unpositioned layout + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/688 + +2020-04-01 13:19:46 +0200 Kristofer Björkström + + * gst/rtp/gstrtpjpegpay.c: + * tests/check/elements/rtpjpeg.c: + * tests/check/meson.build: + rtpjpeg: Use gst_memory_map() instead of gst_buffer_map() + gst_buffer_map () results in memcopying when a GstBuffer contains + more than one GstMemory. + This has quite an impact on performance on systems with limited amount + of resources. With this patch the whole GstBuffer will not be mapped at + once, instead each individual GstMemory will be iterated and mapped + separately. + +2020-04-01 13:17:03 +0200 Kristofer Björkström + + * gst/rtp/gstbuffermemory.c: + * gst/rtp/gstbuffermemory.h: + buffermemory: keep track of buffer size and current offset + Added the possibility to get current offset and the total size of the + buffer. + +2020-04-03 10:29:18 +0200 Havard Graff + + * gst/rtp/gstrtpopuspay.c: + * tests/check/elements/rtpopus.c: + * tests/check/meson.build: + rtpopuspay: make depay ! pay work + There is a use-case for a server to re-payload opus going through it. + Problem was that the payloader requires channels in the caps, but + this is not something the depayloader can parse out of the stream, meaning + caps-negotiation would fail. + Removing the requirement of channels in the template-caps fixes this. + +2020-04-03 16:49:25 +0900 Seungha Yang + + * tests/check/elements/splitmuxsink.c: + * tests/check/elements/splitmuxsrc.c: + * tests/check/meson.build: + tests: Split splitmux test case + Since we are adding more and more tests into splitmux, + we need to split it to avoid CI timeout. + +2020-04-03 13:45:56 +0900 Seungha Yang + + * gst/multifile/gstsplitmuxsink.c: + * gst/multifile/gstsplitmuxsink.h: + * tests/check/elements/splitmux.c: + splitmuxsink: Don't send too many force key unit event + splitmuxsink should requst keyframe depending on configured + threshold and previously requested time in order to avoid too many + keyframe request. + +2020-03-20 21:32:36 +1100 Jan Schmidt + + * gst/matroska/matroska-demux.c: + matroska: Check the return value of gst_segment_do_seek() + gst_segment_do_seek() can fail. + +2018-06-08 13:12:01 +0300 Sebastian Dröge + + * gst/isomp4/qtdemux.c: + qtdemux: Send instant-rate-change event if requested in the SEEK event + Handle an instant rate change seek immediately by reflecting + it downstream as an instant-rate-change event, and do no + further seek handling. + +2018-05-15 18:26:16 +0300 Sebastian Dröge + + * gst/matroska/matroska-demux.c: + matroska-demux: Send instant-rate-change event if requested in the SEEK event + Short-circuit instant rate change events by generating + a downstream instant-rate-change event and doing no further + seek processing. + +2020-03-10 23:16:00 +0900 Seungha Yang + + * gst/matroska/matroska-demux.c: + * gst/matroska/matroska-mux.c: + matroska: Update for video-hdr struct change + See the change of -base https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/594 + +2020-03-31 15:51:27 -0400 Aaron Boxer + + * gst/rtpmanager/gstrtpbin.c: + rtpbin: make warning messages more meaningful + +2020-03-27 19:24:03 +0100 Nicolas Pernas Maradei + + * gst/rtpmanager/gstrtpsession.c: + rtpsession: rename RTCP thread + RTP session starts a new thread for RTCP and names it + "rtpsession-rtcp-thread" which happens to be longer than the maximum 16B + allowed by pthread_setname_np and causes the naming to fail. + See docs for more details. + This commit simply shortens the thread's name so it can actually be set. + +2020-03-30 22:26:33 +0200 Havard Graff + + * gst/rtpmanager/gstrtpjitterbuffer.c: + * gst/rtpmanager/rtpjitterbuffer.c: + * gst/rtpmanager/rtpjitterbuffer.h: + rtpjitterbuffer: create specific API for appending buffers, events etc + To avoid specifying a bunch of mystic variables. + +2020-02-10 17:33:54 +0100 Havard Graff + + * tests/check/elements/rtpjitterbuffer.c: + rtpjitterbuffer: various test-improvements + Mainly generalize all the latest tests that have found various stalls + in the jitterbuffer, so that they only consist of a series of packets + with various seqnum/rtptime/rtx combinations, arriving at a specific time. + This means future tests can be more easily written to prove certain + behavior does not cause stalls. + Also fix the warning on windows: + warning C4244: 'initializing': conversion from 'double' to 'gint', possible loss of data + +2020-03-27 14:07:04 +0100 Havard Graff + + * gst/rtpmanager/gstrtpjitterbuffer.c: + rtpjitterbuffer: fix waiting timer/queue code + Changing the types from boolean to guint due to the ++ operand used on + them, and only call JBUF_SIGNAL_QUEUE after settling down, + or else you end up signaling the waiting code in chain() for every buffer + pushed out. + +2020-03-23 19:55:37 +0200 Sebastian Dröge + + * gst/isomp4/gstqtmux.c: + qtmux: Error out instead of crashing if reserved-max-duration is 0 or no samples could be created in prefill mode + +2020-03-12 15:16:44 +0200 Sebastian Dröge + + * ext/gdk_pixbuf/gstgdkpixbufoverlay.c: + gdkpixbufoverlay: Use GST_VIDEO_OVERLAY_COMPOSITION_BLEND_FORMATS for the supported formats + We don't do any blending by ourselves since a while now. + Note that this is a regression in "supported" formats: previously + ARGB64 was supported, for example, but in practice it caused blending to + not take place at all. + +2020-03-24 00:23:24 +1100 Jan Schmidt + + * gst/multifile/gstsplitmuxpartreader.c: + * gst/multifile/gstsplitmuxpartreader.h: + * gst/multifile/gstsplitmuxsrc.c: + * gst/multifile/gstsplitmuxsrc.h: + splitmuxsrc: Fix some deadlock conditions and a crash + When switching the splitmuxsrc state back to NULL quickly, it + can encounter deadlocks shutting down the part readers that + are still starting up, or encounter a crash if the splitmuxsrc + cleaned up the parts before the async callback could run. + Taking the state lock to post async-start / async-done messages can + deadlock if the state change function is trying to shut down the + element, so use some finer grained locks for that. + +2020-03-24 00:18:54 +1100 Jan Schmidt + + * tests/check/elements/splitmux.c: + splitmux: Make the unit test faster + The playback test is considerably faster if it runs with the + appsink set to sync=false + +2020-03-25 22:14:36 +0900 Seungha Yang + + * tests/check/elements/splitmux.c: + * tests/check/meson.build: + tests: splitmux: Add test for timecode based split + +2020-03-25 21:20:07 +0900 Seungha Yang + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: Split fragment only if queued time is larger than threshold + The queued time includes the duration of the last queued frame + (i.e., new keyframe) so the condition check should not be inclusive. + Note that the new fragment will be cut excluding the last frame + and therefore if the condition is inclusive way, + the fragment might have one frame shorter duration for all keyframe + stream such as jpeg or all-inter video streams. + +2020-03-25 21:01:00 +0900 Seungha Yang + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: Don't need to trace next timecode for split decision + Since the commit 94bb76b6b9c48981d3ad42a8c4370b9658db4229, splitmuxsink + will split fragments based on queued time and the threshold of that. + So don't need to store the next timecode for split decision. + +2018-08-08 09:27:19 +0200 Guillaume Desmottes + + * sys/v4l2/gstv4l2bufferpool.c: + * sys/v4l2/gstv4l2object.c: + * sys/v4l2/gstv4l2object.h: + * sys/v4l2/gstv4l2src.c: + * sys/v4l2/gstv4l2src.h: + v4l2: add alternate interlace mode + When using this mode each frame is split in two fields, each one being + transferred using its own buffer. + This is implemented with the V4L2_FIELD_ALTERNATE field format in v4l2. + This mode is enabled using a caps filter such as + "v4l2src ! video/x-raw\(format:Interlaced\)" + Here are the main changes related to this feature: + - use the INTERLACED caps feature with this mode. + - in this mode both fields of a given frame have the same sequence/offset + so adjust the algorithm checking for lost field/frame accordingly. + - double pool's min number of buffers as each frame requires 2 buffers. + Fix #504 + Co-authored-by: Zeeshan Ali + +2020-02-05 13:03:51 +0530 Guillaume Desmottes + + * sys/v4l2/gstv4l2object.c: + v4l2: display field when setting or trying format + Ease debugging interlacing pipelines. + +2020-01-30 12:35:02 +0530 Guillaume Desmottes + + * sys/v4l2/gstv4l2bufferpool.c: + * sys/v4l2/gstv4l2object.c: + * sys/v4l2/gstv4l2object.h: + * sys/v4l2/gstv4l2transform.c: + * sys/v4l2/gstv4l2videoenc.c: + v4l2: pass v4l2object to GST_V4L2_MIN_BUFFERS() + Will be used to double the number of buffers in alternate interlace + mode. + +2020-01-30 12:09:12 +0530 Guillaume Desmottes + + * sys/v4l2/gstv4l2object.c: + v4l2: use GST_VIDEO_INFO_FIELD_HEIGHT() + Use GST_VIDEO_INFO_FIELD_HEIGHT() instead of GST_VIDEO_INFO_HEIGHT() + when we actually want the field height rather than the frame height. + So far both are equals but that won't longer be the case when + implementing alternate interlace mode. + +2020-03-24 22:08:27 +0900 Seungha Yang + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: Mark some split decision related properties as MUTABLE_READY + The change of various criteria for split decision while muxing is on progress + wouldn't work well as expected. + +2020-03-24 13:45:00 +0900 Seungha Yang + + * gst/multifile/gstsplitmuxsink.c: + * gst/multifile/gstsplitmuxsink.h: + splitmuxsink: Take account queued time and max-size-timecode for split decision + Not only the requested keyframe time, the queued size should be + a criterion for the split decision of timecode based mode + (same as max-size-time based split case). + +2020-03-24 12:55:27 +1100 Matthew Waters + + * ext/qt/gstqtoverlay.cc: + qmlgloverlay: fix usage without an qmlglsink in the pipeline + Without a qmlglsink, we need to retrieve the window system display + ourselves rather than relying solely on qmlglsink to have priority on + the choice of display. + +2020-03-23 21:32:04 -0400 Xavier Claessens + + * gst/rtpmanager/rtptwcc.c: + * gst/videocrop/gstvideocrop.c: + * tests/check/elements/rtpbin.c: + * tests/check/elements/rtpsession.c: + Fix usage of C99 + It's 2020, way too early for that, let's stick to C89 for now. + +2020-03-23 16:34:46 +0900 Seungha Yang + + * sys/v4l2/gstv4l2bufferpool.c: + * sys/v4l2/gstv4l2object.h: + v4l2bufferpool: Use unique name for v4l2bufferpool object + Assign unique sequence number to an object name for better debugging + +2020-03-23 14:02:22 +1100 Matthew Waters + + * ext/qt/qtglrenderer.cc: + qmlgloverlay: don't leak resources freed on a different GL thread + deleting a QOpenGLFrameBufferObject needs to occur on the same thread it + was created on in order to actually free the relevant resources + immediately. Otherwise, they will be queued for deletion and not freed + until the associated QOpenGLContext is destroyed. + +2020-03-20 09:14:01 +1100 Matthew Waters + + * ext/qt/gstqtglutility.cc: + qt: reorganize include defines + +2020-03-19 23:17:21 +0100 Havard Graff + + * gst/rtpmanager/gstrtpjitterbuffer.c: + * gst/rtpmanager/rtptimerqueue.c: + * gst/rtpmanager/rtptimerqueue.h: + * tests/check/elements/rtptimerqueue.c: + rtptimerqueue: remove ->num from the timer + This concept was only used by the "multi"-lost timer, and since that + one is not around any longer, the "num" concept is superfluous. + +2020-03-19 23:37:26 +0100 Havard Graff + + * gst/rtpmanager/gstrtpjitterbuffer.c: + * tests/check/elements/rtpjitterbuffer.c: + rtpjitterbuffer: remove the concept of "already-lost" + This is a concept that only applies when a buffer arrives in the chain + function, and it has already been scheduled as part of a "multi"-lost + timer. + However, "multi"-lost timers are now a thing of the past, making this + whole concept superflous, and this buffer is now simply counted as "late", + having already been pushed out (albeit as a lost-event). + +2020-03-19 23:12:04 +0100 Havard Graff + + * gst/rtpmanager/gstrtpjitterbuffer.c: + * tests/check/elements/rtpjitterbuffer.c: + rtpjitterbuffer: immediately insert a lost-event on multiple lost packets + There is a problem with the code today, where a single timer will + be scheduled for a series of lost packets, and then if the first packet + in that series arrives, it will cause a rescheduling of that timer, going + from a "multi"-timer to a single-timer, causing a lot of the packets + in that timer to be unaccounted for, and creating a situation in where + the jitterbuffer will never again push out another packet. + This patch solves the problem by instead of scheduling those lost packets + as another timer, it instead asks to have that lost-event pushed straight + out. + This very much goes with the intent of the code here: These packets are + so desperately late that no cure exists, and we might as well get the + lost-event out of the way and get on with it. + This change has some interesting knock-on effect being presented in + later commits. It completely removes the concept of "already-lost", so + that is why that test has been disabled in this commit, to be + removed later. + +2020-03-19 23:03:50 +0100 Havard Graff + + * tests/check/elements/rtpjitterbuffer.c: + rtpjitterbuffer: rework large-gap tests + Make sure to set the time the buffer is supposed to arrive at, so + as not to trigger an artificial situation. + +2020-03-19 12:17:22 +0100 Havard Graff + + * gst/rtpmanager/gstrtpjitterbuffer.c: + rtpjitterbuffer: refactor lost_timeout code + Split it up in code related to the timer, (do_lost_timeout) and code + to insert a lost-item/event and update private jitterbuffer-variables. + +2019-10-18 17:43:36 +0200 Havard Graff + + * tests/check/elements/rtpjitterbuffer.c: + * tests/check/elements/rtptimerqueue.c: + * tests/check/meson.build: + test/check: split out rtptimerqueue-tests in a separate file + +2020-02-05 09:56:23 +0100 Dmitriy Purgin + + * ext/qt/qtplugin.pro: + gstqmlgl: Link to opengl32.lib on MinGW + +2020-03-19 23:51:47 +0900 Seungha Yang + + * gst/isomp4/gstqtmux.c: + qtmux: Fix build warning + gstqtmux.c(644): warning C4133: '=': + incompatible types - from 'gboolean (__cdecl *)(GstAggregator *,GstAggregatorPad *,GstEvent *)' + to 'GstFlowReturn (__cdecl *)(GstAggregator *,GstAggregatorPad *,GstEvent *)' + +2020-03-19 23:05:49 +1100 Jan Schmidt + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: Reset cleanly for reuse + Reset the splitmuxsink completely when changing states so that + it can be reused. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/1241 + +2020-02-17 22:37:10 -0600 Zebediah Figura + + * gst/audioparsers/gstmpegaudioparse.c: + * gst/audioparsers/gstmpegaudioparse.h: + mpegaudioparse: Use a constant bit rate to convert between time and bytes if possible. + This should result in no worse accuracy than the base parse element, and may + result in better accuracy. In particular, the number of bytes processed at any + given point, as accumulated by baseparse, can be only accurate to + (1 / # of frames) bytes per second, and if we try to seek immediately after + pausing the pipeline to a large offset, this small inaccuracy can propagate to + something noticeable. + The use case that prompted this patch is a 45-minute MPEG-1 layer 3 file, which + has a constant bit rate but no seek tables. Trying to seek the pipeline + immediately after pauisng it, without the ACCURATE flag, to a location 41 + minutes in, yields a location that is, even with , + still audibly incorrect. This patch yields a much closer position, no longer + audibly incorrect, and likely within a frame of the most correct position. + +2020-03-04 22:10:40 +0100 Mathieu Duponchelle + + * gst/isomp4/gstqtmux.c: + qtmux: fix renegotiation check + By the time sink_event is called, the pad's current caps have + already been updated. To address this, implement sink_event_pre_queue, + and check if the pad can be renegotiated there. + Fixes #707 + +2020-03-12 20:34:47 +0900 Seungha Yang + + * gst/multifile/gstsplitmuxsink.c: + * gst/multifile/gstsplitmuxsink.h: + * tests/check/elements/splitmux.c: + splitmuxsink: Decouple keyframe request and the decision for fragmentation + Split the decision for keyframe request and fragmentation in order to + ensure periodic keyframe request. + +2020-02-26 18:29:06 +1100 Matthew Waters + + * ext/qt/gstqtglutility.cc: + * ext/qt/gstqtoverlay.cc: + * ext/qt/qtglrenderer.cc: + * ext/qt/qtglrenderer.h: + * ext/qt/qtitem.cc: + * tests/examples/qt/qmloverlay/main.cpp: + * tests/examples/qt/qmloverlay/overlay2.qml: + * tests/examples/qt/qmloverlay/qmloverlay.qrc: + qt: add a qml overlay filter element [part 2] + It takes a qml scene description and renders it using a possible input + stream. + Currently supported on GLX and WGL. + Follow up to (as that MR had an old version of the commit): + - https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/merge_requests/475 + - 4778d7166a02caf793df4f845dc35b6933d87c81: qt: add a qml overlay filter element + +2020-02-26 18:29:06 +1100 Matthew Waters + + * ext/qt/gstplugin.cc: + * ext/qt/gstqtglutility.cc: + * ext/qt/gstqtglutility.h: + * ext/qt/gstqtoverlay.cc: + * ext/qt/gstqtoverlay.h: + * ext/qt/meson.build: + * ext/qt/qtglrenderer.cc: + * ext/qt/qtglrenderer.h: + * tests/examples/qt/meson.build: + * tests/examples/qt/qmloverlay/main.cpp: + * tests/examples/qt/qmloverlay/main.qml: + * tests/examples/qt/qmloverlay/meson.build: + * tests/examples/qt/qmloverlay/overlay.qml: + * tests/examples/qt/qmloverlay/qmloverlay.qrc: + qt: add a qml overlay filter element + It takes a qml scene description and renders it using a possible input + stream. + Currently supported on GLX and WGL. + +2020-02-25 21:47:14 +1100 Matthew Waters + + * ext/qt/gstqsgtexture.cc: + * ext/qt/qtitem.cc: + qt: don't always activate/deactivate our GstGLContext + Techincally it is enough to activate at the beginning and then forget. + +2020-02-04 19:43:52 +1100 Matthew Waters + + * tests/examples/qt/meson.build: + * tests/examples/qt/qmlsink-dynamically-added/.gitignore: + * tests/examples/qt/qmlsink-dynamically-added/main.cpp: + * tests/examples/qt/qmlsink-dynamically-added/main.qml: + * tests/examples/qt/qmlsink-dynamically-added/meson.build: + * tests/examples/qt/qmlsink-dynamically-added/play.pro: + * tests/examples/qt/qmlsink-dynamically-added/qmlsink.qrc: + test/qml: add an dynamically adding qmlglsink element + The example shows how to add qmlglsink to an already running pipeline + with pre-existing OpenGL elements. + +2020-02-04 19:40:45 +1100 Matthew Waters + + * ext/qt/gstqtsink.cc: + qmlglsink: propagate the context up the the application + Allows the application to be notified of the OpenGL context creation. + +2020-02-03 15:59:34 +1100 Matthew Waters + + * ext/qt/qtitem.cc: + qtitem: fix leak of caps + +2020-03-15 19:28:18 +0100 Niels De Graef + + * ext/wavpack/gstwavpackdec.h: + * ext/wavpack/gstwavpackenc.h: + wavpack: Use G_DECLARE_FINAL_TYPE + +2020-03-15 19:26:18 +0100 Niels De Graef + + * ext/vpx/gstvp8dec.h: + * ext/vpx/gstvp8enc.h: + * ext/vpx/gstvp9dec.h: + * ext/vpx/gstvp9enc.h: + * ext/vpx/gstvpxdec.h: + * ext/vpx/gstvpxenc.h: + vpx: Use G_DECLARE_FINAL_TYPE + +2020-03-15 19:22:00 +0100 Niels De Graef + + * ext/twolame/gsttwolamemp2enc.h: + twolame: Use G_DECLARE_FINAL_TYPE + +2020-03-15 19:20:49 +0100 Niels De Graef + + * ext/taglib/gstapev2mux.h: + * ext/taglib/gstid3v2mux.h: + taglib: Use G_DECLARE_FINAL_TYPE + +2020-03-15 19:18:39 +0100 Niels De Graef + + * ext/speex/gstspeexdec.h: + * ext/speex/gstspeexenc.h: + speex: Use G_DECLARE_FINAL_TYPE + +2020-03-15 19:16:22 +0100 Niels De Graef + + * ext/soup/gstsouphttpclientsink.h: + soup: Use G_DECLARE_FINAL_TYPE + +2020-03-15 19:14:17 +0100 Niels De Graef + + * ext/shout2/gstshout2.c: + * ext/shout2/gstshout2.h: + shout2: Use G_DECLARE_FINAL_TYPE + +2020-03-15 19:11:52 +0100 Niels De Graef + + * ext/raw1394/gst1394clock.h: + * ext/raw1394/gstdv1394src.c: + * ext/raw1394/gstdv1394src.h: + * ext/raw1394/gsthdv1394src.h: + raw1394: Use G_DECLARE_FINAL_TYPE + +2020-03-15 19:06:50 +0100 Niels De Graef + + * ext/qt/gstqtsink.h: + * ext/qt/gstqtsrc.h: + qt: Use G_DECLARE_FINAL_TYPE + +2020-03-15 19:00:18 +0100 Niels De Graef + + * ext/pulse/pulsedeviceprovider.h: + * ext/pulse/pulsesink.h: + * ext/pulse/pulsesrc.h: + pulse: Use G_DECLARE_FINAL_TYPE + +2020-03-15 18:54:33 +0100 Niels De Graef + + * ext/mpg123/gstmpg123audiodec.h: + mpg123: Use G_DECLARE_FINAL_TYPE + +2020-03-15 18:52:57 +0100 Niels De Graef + + * ext/libpng/gstpng.h: + * ext/libpng/gstpngdec.h: + * ext/libpng/gstpngenc.h: + libpng: Use G_DECLARE_FINAL_TYPE + +2020-03-15 18:49:53 +0100 Niels De Graef + + * ext/libcaca/gstcacasink.h: + * ext/libcaca/gstcacatv.h: + libcaca: Use G_DECLARE_FINAL_TYPE + +2020-03-15 18:40:28 +0100 Niels De Graef + + * ext/lame/gstlamemp3enc.h: + lame: Use G_DECLARE_FINAL_TYPE + +2020-03-14 17:52:38 +0100 Niels De Graef + + * ext/jack/gstjackaudiosink.h: + * ext/jack/gstjackaudiosrc.h: + jack: Use G_DECLARE_FINAL_TYPE + +2020-03-14 17:43:50 +0100 Niels De Graef + + * ext/gtk/gstgtkbasesink.h: + * ext/gtk/gstgtkglsink.h: + * ext/gtk/gstgtksink.h: + gtk: Use G_DECLARE_FINAL_TYPE + +2020-03-13 18:47:49 +0100 Niels De Graef + + * ext/gdk_pixbuf/gstgdkpixbufdec.h: + * ext/gdk_pixbuf/gstgdkpixbufoverlay.h: + * ext/gdk_pixbuf/gstgdkpixbufsink.h: + gdk_pixbuf: Use G_DECLARE_FINAL_TYPE + +2020-03-13 18:42:38 +0100 Niels De Graef + + * ext/flac/gstflacdec.h: + * ext/flac/gstflacenc.h: + * ext/flac/gstflactag.h: + flax: Use G_DECLARE_FINAL_TYPE + +2020-03-13 18:39:38 +0100 Niels De Graef + + * ext/dv/gstdvdec.h: + * ext/dv/gstdvdemux.h: + dv: Use G_DECLARE_FINAL_TYPE + +2020-03-12 19:24:57 +0100 Niels De Graef + + * ext/cairo/gstcairooverlay.h: + cairo: Use G_DECLARE_FINAL_TYPE + +2020-03-12 19:20:42 +0100 Niels De Graef + + * ext/aalib/gstaasink.h: + * ext/aalib/gstaatv.h: + aalib: Use G_DECLARE_FINAL_TYPE + +2020-03-12 16:55:44 +0000 Tim-Philipp Müller + + * tests/check/elements/rtp-payloading.c: + tests: rtp-payloading: add minimal vp8/vp9 rtp payloading/depayloading test + +2018-10-19 16:17:17 +0200 Stian Selnes + + * gst/rtp/gstrtpvp8pay.c: + * gst/rtp/gstrtpvp9pay.c: + rtpvp8pay, rtpvp9pay: fix caps leak in set_caps() + +2020-03-12 11:22:56 +0100 Edward Hervey + + * gst/videomixer/videomixer2.c: + videomixer: Don't leak peer caps + +2020-02-11 16:19:15 -0300 Thibault Saunier + + * docs/gst_plugins_cache.json: + * gst/multifile/gstimagesequencesrc.c: + * gst/multifile/gstimagesequencesrc.h: + * gst/multifile/gstmultifile.c: + * gst/multifile/meson.build: + imagesequencesrc: Cleanup and add some features + * Implement the GstURIHandlerInterface + * Rework the locking + * Implement backward seeking handling + * Generate documentation + +2016-04-10 02:25:32 +0000 Fabian Orccon + + * gst/multifile/gstimagesequencesrc.c: + * gst/multifile/gstimagesequencesrc.h: + Add an imagesequencesrc element to stream sequence of images + See: https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/121 + +2020-03-05 08:55:44 -0800 Gordon Hart + + * sys/v4l2/gstv4l2src.c: + v4l2src: decrease gst_v4l2src_create log verbosity + Lower the verbosity of the 'sync' log message emitted + each buffer from gst_v4l2src_create down to LOG(6) + from INFO(4). This brings the logging behavior of + v4l2src closer to the GStreamer guidelines, which + recommend the INFO level be reserved for rare or + one-off messages. + +2020-03-10 17:19:46 +0800 yychao + + * gst/isomp4/qtdemux.c: + qtdemux: Add support for AC4 + The caps received from qtdemux for AC-4 content are audio/x-gst-fourcc-ac_4 + Based on patch by: Savinderjit Kaur + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/413 + +2020-03-10 21:07:12 +1100 Matthew Waters + + * gst/imagefreeze/gstimagefreeze.c: + * gst/imagefreeze/gstimagefreeze.h: + imagefreeze: handle reconfigure events on the srcpad + +2020-03-05 22:47:16 +1100 Matthew Waters + + * gst/imagefreeze/gstimagefreeze.c: + imagefreeze: properly ignore setting caps failures + Ignore the return value of gst_pad_set_caps() so that setcaps will set a + framerate that is usable. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/705 + +2020-03-05 22:45:32 +1100 Matthew Waters + + * gst/imagefreeze/gstimagefreeze.c: + imagefreeze: don't fail sending sticky events downstream + They will be repropagated anyway. + +2020-03-09 23:31:09 +0100 Markus Ebner + + * gst/videocrop/gstvideocrop.c: + videocrop: Add support for Y41B and Y42B + +2020-03-09 23:25:03 +0100 Markus Ebner + + * gst/videocrop/gstvideocrop.c: + * gst/videocrop/gstvideocrop.h: + videocrop: Add support for Y444 + - Refactored the planar transform method to support all video formats + that are stored planar, independent of the used subsampling + - Added support for Y444 + +2020-03-09 23:23:50 +0100 Markus Ebner + + * gst/videocrop/gstvideocrop.c: + videocrop: Use G_VALUE_INIT to initialize GValues + +2020-02-28 19:35:34 +0200 Sebastian Dröge + + * ext/jpeg/gstjpegdec.c: + jpegdec: Configure JPEG chroma-siting for YUV formats + +2020-02-06 09:23:24 +0100 Ognyan Tonchev + + * gst/rtp/gstbuffermemory.c: + * gst/rtp/gstbuffermemory.h: + * gst/rtp/gstrtph264pay.c: + * gst/rtp/gstrtph265pay.c: + * gst/rtp/meson.build: + * tests/check/elements/rtph264.c: + rtph26x: Use gst_memory_map() instead of gst_buffer_map() in avc mode + gst_buffer_map () results in memcopying when a GstBuffer contains + more than one GstMemory and when AVC (length-prefixed) alignment is used. + This has quite an impact on performance on systems with limited amount of + resources. With this patch the whole GstBuffer will not be mapped at once, + instead each individual GstMemory will be iterated and mapped separately. + +2019-11-26 15:08:20 +0100 Milian Wolff + + * ext/qt/gstqtgl.h: + qmlgl: ensure Qt defines GLsync to fix compile on some platforms + By explictly including QtGui/qopengl.h we force the code path that + defines GLsync in the Qt-specific way. Without that, some platforms + failed to compile the qmlgl plugin, since neither Qt nor gstreamer + defined GLsync then, leading to e.g.: + ``` + make[4]: Entering directory '/.../gst-plugins-good-1.16.1/ext/qt' + CXX libgstqmlgl_la-qtitem.lo + In file included from gstqtgl.h:32, + from qtitem.h:27, + from qtitem.cc:28: + /.../usr/include/gstreamer-1.0/ + gst/gl/gstglfuncs.h:93:17: error: expected identifier before ‘*’ token + ret (GSTGLAPI *name) args; + ^ + /.../usr/include/gstreamer-1.0/ + gst/gl/glprototypes/sync.h:27:1: note: in expansion of macro + ‘GST_GL_EXT_FUNCTION’ + GST_GL_EXT_FUNCTION (GLsync, FenceSync, + ^~~~~~~~~~~~~~~~~~~ + ``` + +2020-03-02 13:50:55 +0100 Havard Graff + + * gst/rtpmanager/rtpsession.c: + * gst/rtpmanager/rtptwcc.c: + * gst/rtpmanager/rtptwcc.h: + rtptwcc: make RTPTWCCManager a GObject + +2020-03-04 11:17:16 +0100 Havard Graff + + * gst/rtpmanager/gstrtpjitterbuffer.c: + * tests/check/elements/rtpjitterbuffer.c: + rtpjitterbuffer: fix stalling when resetting timers + When calling gst_rtp_jitter_buffer_reset you pass in a seqnum. + This is considered the starting-point for a new stream. + However, the old behavior would unref this buffer, basically lying to + the thread that is pushing out buffers saying that it can expect + this buffer, when it would never arrive. The resulting effect being no + more buffer pushed out of the jitterbuffer, and it would buffer + incoming data indefinitely. + By instead inserting the buffer in the gap_packets queue, the _reset() + function will take responsibility for using that as the first buffer + of the new stream. + Fixes #703 + +2020-02-21 02:14:11 +1100 Jan Schmidt + + * gst/multifile/gstsplitmuxpartreader.c: + * gst/multifile/gstsplitmuxpartreader.h: + * gst/multifile/gstsplitmuxsrc.c: + * tests/check/elements/splitmux.c: + splitmux: Avoid negative DTS + In order to concatenate fragments, splitmuxsrc offsets + the start of each fragment PTS to 0 to align it with the + previous file. This means that DTS can go negative for + the first fragment, with really bad results. + Add a fixed offset to outgoing timestamp ranges to + avoid that. + +2020-03-04 03:43:51 +1100 Jan Schmidt + + * gst/isomp4/gstqtmux.c: + qtmux: Remove warning in the log for mono video + Vanilla mono video was generating a spurious warning into the debug log + that's just misleading. Handle mono caps explicitly to avoid the warning. + +2020-01-27 12:29:18 +0530 Guillaume Desmottes + + * gst/deinterlace/gstdeinterlace.c: + * gst/deinterlace/gstdeinterlacemethod.c: + deinterlace: add alternate support + In this mode each field is carried using its own buffer. + Allow deinterlace to negotiate caps with the Interlaced feature and + adjust the algorithm fetching lines. + Fix #620 + +2020-02-03 13:08:39 +0530 Guillaume Desmottes + + * gst/deinterlace/gstdeinterlacemethod.c: + deinterlace: add wrapper to get field lines from history + No semantic change so far, will be used to implement alternate support. + +2020-02-04 16:48:21 +0530 Guillaume Desmottes + + * gst/deinterlace/gstdeinterlacemethod.c: + deinterlace: stop checking line index boundaries + The LINE2() macro already prevents out of bound indexes using CLAMP_HI() + and CLAMP_LOW(). + +2020-01-20 12:30:12 +0530 Guillaume Desmottes + + * gst/deinterlace/gstdeinterlace.c: + * gst/deinterlace/gstdeinterlace.h: + deinterlace: fix video info on output frames + Output frames used to have their interlace mode set to the same one as + the input. This breaks their field and comp heights when deinterlacing + an alternate stream. + +2020-01-14 14:51:07 +0530 Guillaume Desmottes + + * gst/deinterlace/gstdeinterlace.c: + deinterlace: use output caps to compute buffer size + In interlace-mode=alternate the input buffers have half the size of the + output ones as each field has its own buffer. + +2020-02-29 08:10:56 -0500 Jennifer Berringer + + * gst/audioparsers/gstflacparse.c: + flacparse: fix broken reordering of flac metadata + Each FLAC metadata block starts with a flag denoting whether it is the + last metadata block. The existing flacparse code moves any existing + VORBISCOMMENT block to immediately follow the STREAMINFO block without + changing any block's last-metadata-block flag. If no VORBISCOMMENT block + exists, it created one with the last-metadata-block flag set to true. + This results in gstflacdec sometimes giving bad headers to libflac when + trying to play perfectly valid FLAC files depending on the file's + metadata ordering. Depending on the contents of the other metadata + blocks, current versions of libflac may or may not return + FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER when given this broken + metadata. This is most noticeable with files that have a large cover art + image attached where VORBISCOMMENT is the very last metadata block with + no PADDING afterwards. + This patch changes that behavior so that: + 1. For FLAC files that already have a VORBISCOMMENT block, the metadata + order is preserved. + 2. For FLAC files that do not have a VORBISCOMMENT block, the generated + dummy VORBISCOMMENT is placed immediately after STREAMINFO and + inherits the last-metadata-block flag from STREAMINFO. + https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/484 + +2020-02-27 14:50:51 +0900 Yeongjin Jeong + + * tests/check/elements/flvmux.c: + tests: flvmux: Instead of using the testclock, just send eos event for drain + When using the testclock for determining clock in test, it is sometimes observed + that the clock entry is not registered in time by the aggregator. So deadlock occurs + between the aggregator and the test thread. + +2020-02-28 14:23:51 +0200 Sebastian Dröge + + * gst/isomp4/qtdemux.c: + qtdemux: Try to infer useful header values for raw audio if the sound sample descriptions contain zero values + +2020-02-28 14:00:51 +0200 Sebastian Dröge + + * gst/isomp4/qtdemux.c: + qtdemux: Also use the enda atom for determining endianess of in32, fl32 and fl64 formats + Previously it was only used for in24. + +2020-02-28 13:59:42 +0200 Sebastian Dröge + + * gst/isomp4/qtdemux.c: + qtdemux: Fix up header information for various fixed-format raw audio formats + Sometimes the headers contain useless, wrong or zero values for e.g. the + sample size with these formats. There's only a single valid value for + them so let's set these instead. + +2020-02-28 13:59:06 +0200 Sebastian Dröge + + * gst/isomp4/qtdemux.c: + qtdemux: Don't print "unhandled type" warnings for various other raw audio fourccs + +2020-02-28 13:57:37 +0200 Sebastian Dröge + + * gst/isomp4/fourcc.h: + * gst/isomp4/qtdemux.c: + qtdemux: Add some more raw audio fourccs to the header instead of duplicating them + +2020-02-25 21:14:54 +0530 Nirbheek Chauhan + + * gst/rtpmanager/gstrtpjitterbuffer.c: + rtpjitterbuffer: Don't use glib format modifiers with sscanf + We do not have a way to know the format modifiers to use with string + functions provided by the system. G_GUINT64_FORMAT and other string + modifiers only work for glib string formatting functions. We cannot + use them for string functions provided by the stdlib. See: + https://developer.gnome.org/glib/stable/glib-Basic-Types.html#glib-Basic-Types.description + ``` + ../gst/rtpmanager/gstrtpjitterbuffer.c: In function 'gst_jitter_buffer_sink_parse_caps': + ../gst/rtpmanager/gstrtpjitterbuffer.c:1523:32: error: unknown conversion type character 'l' in format [-Werror=format=] + || sscanf (mediaclk, "direct=%" G_GUINT64_FORMAT, &clock_offset) != 1) + ^~~~~~~~~~ + In file included from /home/nirbheek/cerbero/build/dist/windows_x86/include/glib-2.0/glib/gtypes.h:32, + from /home/nirbheek/cerbero/build/dist/windows_x86/include/glib-2.0/glib/galloca.h:32, + from /home/nirbheek/cerbero/build/dist/windows_x86/include/glib-2.0/glib.h:30, + from /home/nirbheek/cerbero/build/dist/windows_x86/include/gstreamer-1.0/gst/gst.h:27, + from /home/nirbheek/cerbero/build/dist/windows_x86/include/gstreamer-1.0/gst/rtp/gstrtpbuffer.h:27, + from ../gst/rtpmanager/gstrtpjitterbuffer.c:108: + /home/nirbheek/cerbero/build/dist/windows_x86/lib/glib-2.0/include/glibconfig.h:69:28: note: format string is defined here + #define G_GUINT64_FORMAT "llu" + ^ + ../gst/rtpmanager/gstrtpjitterbuffer.c:1523:32: error: too many arguments for format [-Werror=format-extra-args] + || sscanf (mediaclk, "direct=%" G_GUINT64_FORMAT, &clock_offset) != 1) + ^~~~~~~~~~ + ``` + See also: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/379 + +2020-02-24 15:25:07 +0200 Sebastian Dröge + + * gst/isomp4/gstqtmux.c: + qtmux: Add support for 8k resolutions in prefill mode with ProRes + +2020-02-25 11:06:43 +0200 Sebastian Dröge + + * gst/rtpmanager/rtptimerqueue.c: + rtpjitterbuffer: Include string.h for memcpy() / memset() + Usually something else is pulling it in somehow already, but not on + Windows. + +2020-02-24 13:06:27 +0000 Håvard Graff + + * gst/rtpmanager/rtpsession.c: + * tests/check/elements/rtpsession.c: + rtpsession: fix crash when no extension-header present for twcc + +2020-02-21 09:34:30 +0100 Johan Bjäreholt + + * gst/matroska/matroska-mux.c: + matroska-mux: Fix incorrect rounding of timestamps + Previously we saved the buffer_timestamp straight into + mux->cluster_time. Since the cluster time saved into the file does not + have as high precision as GstClockTime depending on the timecodescale + the rounding of relative_timestamp was invalid as mux->cluster_time + which it was calculated relative to was not equal to the cluster time + written to the matroska file. + Example of "mkvinfo -v" of how it looks before and after this change in + an scenario where previously timestamps got out of order because of this + issue. + Notice the timestamp of the SimpleBlock right before and right after the + Cluster now being in order. The consequence of this however is that the + cluster timestamp is not necessarily the same as the timestamp of the + first buffer in the cluster however (in case it's rounded up). + Before + | + SimpleBlock (track number 1, 1 frame(s), timecode 126.922s = 00:02:06.922) + | + Frame with size 432 + | + SimpleBlock (track number 2, 1 frame(s), timecode 126.933s = 00:02:06.933) + | + Frame with size 329 + | + SimpleBlock (track number 2, 1 frame(s), timecode 126.955s = 00:02:06.955) + | + Frame with size 333 + |+ Cluster + | + Cluster timecode: 126.954s + | + Cluster previous size: 97344 + | + SimpleBlock (key, track number 1, 1 frame(s), timecode 126.954s = 00:02:06.954) + | + Frame with size 61239 + | + SimpleBlock (track number 2, 1 frame(s), timecode 126.975s = 00:02:06.975) + | + Frame with size 338 + After + | + SimpleBlock (track number 1, 1 frame(s), timecode 135.456s = 00:02:15.456) + | + Frame with size 2260 + | + SimpleBlock (track number 2, 1 frame(s), timecode 135.468s = 00:02:15.468) + | + Frame with size 332 + | + SimpleBlock (track number 2, 1 frame(s), timecode 135.490s = 00:02:15.490) + | + Frame with size 335 + |+ Cluster + | + Cluster timecode: 135.489s + | + Cluster previous size: 158758 + | + SimpleBlock (key, track number 1, 1 frame(s), timecode 135.490s = 00:02:15.490) + | + Frame with size 88070 + | + SimpleBlock (track number 2, 1 frame(s), timecode 135.511s = 00:02:15.511) + | + Frame with size 336 + +2020-02-19 15:59:19 +1100 Jake Barnes + + * ext/soup/gstsouphttpsrc.c: + souphttpsrc: Fix cookies property + Disable session sharing and cookie jar when cookies property is set. + The cookie jar actually replaces or removes any existing Cookie header + set on the message, so the cookies property was effectively being + ignored. There doesn't appear to be a way to inject the cookies into the + jar without having to specify matching domains etc., so it's not + possible to simulate the old behaviour of unconditionally sending the + cookies with all messages, besides simply disabling the cookie jar. + +2020-02-20 09:06:10 +0100 Stefano Buora + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: remove useless function calls + Comparing gst_rtspsrc_loop_interleaved and gst_rtspsrc_loop_udp, and investigating on timeout issues, it sounds like a piece of code has been originally copied from udp to the interleaved one. The timeout variable is never used inside the interleaved one. No side effect has been seen in the removed function calls. + The debug message removed is pointless as the timeout used is "src->tcp_timeout" that is fixed. + The presence of the two timeout drove my team in investigating if the reference to the tcp_timeout was correct (it is). Hence we removed the misleading reference to the local timeout variable. + +2020-02-20 13:43:13 +1100 Matthew Waters + + * gst/rtpmanager/gstrtpbin.c: + rtpbin: fix typo setting max-dropout/misorder-time + we were setting the max-dropout-time to the value of the + max-misorder-time which by default has a factor of 30 difference in + value. + +2020-02-19 20:27:54 +0900 Seungha Yang + + * gst/isomp4/fourcc.h: + * gst/isomp4/qtdemux.c: + qtdemux: Parse VP Codec Configuration Box + The VP Codec Configuration Box (vpcC) contains vp9 profile and + colorimetry information. Especially the profile information might + be useful for downstream to select capable decoder element. + +2020-02-18 18:36:36 +0900 Yeongjin Jeong + + * tests/check/elements/flvmux.c: + tests: flvmux: Add test for rollover timestamp + The timestamps that exceed uint32 maximum value should be handled to rollover. + +2020-02-18 14:58:00 +0900 Yeongjin Jeong + + * gst/flv/gstflvmux.c: + flvmux: Support rollover in timestamp + For live streams, if we keep the stream for a long time, the timestamp + will be larger than max_uint32. In that case, timestamp should be handled + as a rollover timestamp rather than a backward timestamp. + +2020-02-17 15:03:28 +0100 Havard Graff + + * gst/rtpmanager/gstrtpjitterbuffer.c: + rtpjitterbuffer: don't use the timer-object after JBUF_UNLOCK + It could have been freed (rtp_timer_free) in the meantime. + +2019-06-29 18:06:11 +0200 Havard Graff + + * gst/rtpmanager/gstrtpsession.c: + * gst/rtpmanager/meson.build: + * gst/rtpmanager/rtpsession.c: + * gst/rtpmanager/rtpsession.h: + * gst/rtpmanager/rtpsource.c: + * gst/rtpmanager/rtpstats.c: + * gst/rtpmanager/rtpstats.h: + * gst/rtpmanager/rtptwcc.c: + * gst/rtpmanager/rtptwcc.h: + * tests/check/elements/rtpsession.c: + rtpmanager: Google Transport-Wide Congestion Control RTP Extension + Generating and parsing the RTCP-messages described in: + https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01 + +2020-02-14 10:08:05 +0000 Håvard Graff + + * gst/rtpmanager/gstrtpfunnel.c: + * tests/check/elements/rtpfunnel.c: + rtpfunnel: various cleanups + * Organize GstRtpFunnelPad and GstRtpFunnel separately + * Use G_GNUC_UNUSED instead of (void) casts + * Don't call an event "caps" + * Use semicolons after GST_END_TEST (helps gst-indent) + +2020-01-29 23:51:45 +0200 Sebastian Dröge + + * gst/isomp4/qtdemux.c: + qtdemux: Merge sample tables for raw audio streams with one container sample per audio sample + Instead of having chunks with one sample per raw audio sample, have + chunks with a single sample that contains lots of raw audio samples. If + necessary these are still split again later when reading the stream. + With this we are allocating a lot less memory for the parsed sample + tables and can play files that previously triggered our limit of 200MB + for the sample table. For example, one file here would previously + allocate 3.5GB for the sample table and now only allocates 70KB. + +2020-01-13 11:55:42 +0200 Sebastian Dröge + + * gst/isomp4/qtdemux.c: + qtdemux: Add a minimum buffer size for raw audio to not output one buffer per frame + Outputting 48000 buffers per second is not a good idea performance-wise. + If a container sample is less than 1024 raw audio frames, combine + multiple samples to get at least 1024 raw audio samples as long as + they're stored contiguous in the file. + For the other direction, if a container sample contains more than 4096 + samples there is already code for splitting them up. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=692750 + +2020-02-11 21:52:41 +0100 Mathieu Duponchelle + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: fix requested range + When the server replies with a range "now-", it is presumed to + be a "live" stream and we should request a similar range. + This was the case prior to my refactoring to make use of + gst_rtsp_range_to_string in 5f1a732bc7b76a6f1b8aa5f26b6e76fbca0261c7, + this commit restores the behaviour for that case. + +2017-07-13 13:49:07 +0200 Mikhail Fludkov + + * gst/rtpmanager/gstrtpptdemux.c: + * tests/check/elements/rtpptdemux.c: + * tests/check/meson.build: + rtpptdemux: set payload to caps inside gst_rtp_pt_demux_get_caps + Refactoring to remove duplicate code and add test + +2017-03-16 20:57:54 +0100 Stian Selnes + + * gst/rtpmanager/gstrtpptdemux.c: + rtpptdemux: Fix debug to use GST_DEBUG_OBJECT + +2016-09-14 16:49:26 +0200 Mikhail Fludkov + + * gst/rtpmanager/gstrtpbin.c: + rtpbin: use max-streams on rtpssrcdemux + The proper way of capping on max-streams is to do it in rtpssrcdemux. + This patch uses the newly introduced property on rtpssrcdemux. Previous + behavior would not prevent rtpssrcdemux spawning new pads for every new + ssrc and potentialy causing performance trouble during teardown. + +2017-01-18 14:32:03 +0000 John Bassett + + * gst/rtpmanager/gstrtpssrcdemux.c: + * tests/check/elements/rtpssrcdemux.c: + rtpssrcdemux: Handle RTCP APP packets + Fix crash when processing RTCP APP packets. + +2017-01-12 16:05:59 +0000 John Bassett + + * gst/rtpmanager/gstrtpssrcdemux.c: + * tests/check/elements/rtpssrcdemux.c: + rtpssrcdemux: Bad RTP/RTCP packet is not fatal + When used for processing bundled media streams within rtpbin the rtpssrcdemux element may + receive bad RTP and RTCP packets, these should not be treated as a fatal error. + +2016-09-14 16:41:02 +0200 Mikhail Fludkov + + * gst/rtpmanager/gstrtpssrcdemux.c: + * gst/rtpmanager/gstrtpssrcdemux.h: + * tests/check/elements/rtpssrcdemux.c: + rtpssrcdemux: introduce max-streams property + The property is useful against atacks when the sender changes SSRC for + every RTP packet. The property with the same name introduced in rtpbin + was not enough, because we still can end up with thousands of pads + allocated in rtpssrcdemux. + +2020-02-10 14:22:47 +0100 Havard Graff + + * tests/check/elements/rtpssrcdemux.c: + rtpssrcdemux: fix test warnings + +2020-02-07 10:03:49 +0100 Alexander Lapajne + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: Fix for segmentation fault when handling set/get_parameter requests + gstrtspsrc uses a queue, set_get_param_q, to store set param and get + param requests. The requests are put on the queue by calling + get_parameters() and set_parameter(). A thread which executs in + gst_rtspsrc_thread() then pops requests from the queue and processes + them. The crash occured because the queue became empty and a NULL + request object was then used. The reason that the queue became empty + is that it was popped even when the thread was NOT processing a get + parameter or set parameter command. The fix is to make sure that the + queue is ONLY popped when the command being processed is a set + parameter or get parameter command. + +2019-09-27 16:52:06 -0400 Olivier Crête + + * gst/rtpmanager/rtpsource.c: + * tests/check/elements/rtpsession.c: + rtpsession: Add test for packet rate maths + +2019-09-10 19:03:02 +0100 olivier.crete@collabora.com + + * gst/rtpmanager/rtpstats.c: + rtpstats: Base the packet rate average on the packet rate itself + Do this so that the average update speed is in time instead of varying + based on the actual packet arrival rate. + +2019-09-10 18:59:02 +0100 olivier.crete@collabora.com + + * gst/rtpmanager/rtpstats.c: + rtpstats: Don't save the ts & seqnum if the avg is not updated + This makes it update correctly when you have more than one packet per + frame. + +2020-02-05 12:48:45 +0530 Guillaume Desmottes + + * sys/v4l2/gstv4l2object.c: + v4l2: map GST_VIDEO_FORMAT_BGR15 + The GstVideoFormat to v4l2 conversion was missing for BGR15. + +2020-02-05 12:00:00 +0530 Guillaume Desmottes + + * sys/v4l2/gstv4l2object.c: + v4l2: fix crash on invalid caps + gst_v4l2_object_set_format_full() was returning FALSE without setting + an error. Caller code (gst_v4l2src_fixate()) was then derefing a + NULL pointer when trying to handle the error. + +2020-01-27 16:00:30 +0200 Sebastian Dröge + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: Include actual sink element in the fragment-opened/closed messages + If not configuring the sinks via the "location" property this can be + useful to know for which sink the fragment was actually opened/closed, + especially if finalization of the fragments is happening asynchronously. + +2020-01-29 12:05:07 +0100 Juergen Werner + + * gst/rtpmanager/rtpjitterbuffer.c: + rtpjitterbuffer: fix scaling from RTP-time to NTP-time + The scaling was inverse. + +2020-01-27 23:59:05 +0100 Mathieu Duponchelle + + * gst/rtpmanager/gstrtprtxsend.c: + * gst/rtpmanager/gstrtprtxsend.h: + * tests/check/elements/rtprtx.c: + rtprtxsend: allow generic input caps + When connected to an upstream rtpfunnel element, payload-type, + ssrc and clock-rate will not be present in the received caps. + rtprtxsend can already deal with only the clock rate being + present there, a new property is exposed to allow users to + provide a payload-type -> clock-rate map, this enables the + use of the max-size-time property for bundled streams. + +2020-01-27 15:17:27 -0800 Julien Isorce + + * ext/vpx/gstvpxenc.c: + vp8enc/vp8enc: set 1 for the default value of VP8E_SET_STATIC_THRESHOLD + In Google webrtc, the setting VP8E_SET_STATIC_THRESHOLD is set to 1 + (except when the content is known to be static very often in which + case it is set to 100, i.e. when sharing screen with Google Hangouts). + The cpu usage drops a lot when using 1 for above setting because it + allows the encoder to skip static/low content blocks. The current + 0 default value uses too much cpu and confuses the user regarding + the cpu usage expectations. User expects vp8enc to use low cpu by + default. + Documentation of VP8E_SET_STATIC_THRESHOLD: + https://github.com/webmproject/libvpx/blob/master/vpx/vp8cx.h#L188 + chromium/webrtc: + https://chromium.googlesource.com/external/webrtc/+/b484ec0082948ae086c2ba4142b4d2bf8bc4dd4b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc#822 + Closes #58 + +2020-01-27 17:16:02 -0500 Nicolas Dufresne + + * ext/jpeg/gstjpegdec.c: + jpegdec: Check return value of gst_buffer_map() + Without this check, the element will crash instead of returning an + error. + +2020-01-27 15:52:42 +0200 Sebastian Dröge + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: Check the correct sink class for the existence of the "location" property + +2020-01-13 11:58:12 +0200 Sebastian Dröge + + * gst/isomp4/qtdemux.c: + qtdemux: Always prefer information from v1/v2 sound sample description over sample description entry + ffmpeg is doing the same and various files in the wild have bogus + information in the sample description if the same information is also + duplicated afterwards in the v1/v2 sound sample desription. + Previously we only did this for non-raw audio due to + https://bugzilla.gnome.org/show_bug.cgi?id=374914 + but this specific file is already worked around differently. It still + works after this change. + Also remove ad-hoc GST_READ_DOUBLE_BE re-implementation and move the + switch for legacy audio formats after reading all the sample + descriptions as we want to override the values from there. + +2020-01-13 20:02:58 +0200 Sebastian Dröge + + * gst/avi/gstavimux.c: + * gst/avi/gstavimux.h: + avimux: Add support for >2 raw audio channels + For this case write a WAVEFORMATEXTENSIBLE header and also reorder the + raw audio channels to the AVI channel order if needed. + +2020-01-13 20:07:01 +0200 Sebastian Dröge + + * gst/wavenc/gstwavenc.c: + wavenc: Fix writing of the channel mask with >2 channels + The channel position is an enum but the conversion code assumed it's a + mask. Convert accordingly. + +2020-01-10 16:30:33 +0100 Kristofer Björkström + + * gst/rtp/gstrtph265pay.c: + * tests/check/elements/rtph265.c: + rtph265pay: TID for NALU type 48 was always set to 7 + A typo bug: | instead of & resulted in TID alwasy being set to 7 + for the aggregated NALU of type 48 + +2020-01-10 14:54:26 +0200 Sebastian Dröge + + * gst/imagefreeze/gstimagefreeze.c: + * gst/imagefreeze/gstimagefreeze.h: + imagefreeze: Add support for replacing the output buffer + By default imagefreeze will still reject new buffers after the first one + and immediately return GST_FLOW_EOS but the new allow-replace property + allows to change this. + Whenever updating the buffer we now also keep track of the configured + caps of the buffer and from the source pad task negotiate correctly + based on the potentially updated caps. + Only the very first time negotiation of a framerate with downstream is + performed, afterwards only the caps themselves apart from the framerate + are updated. + +2020-01-09 18:43:02 +0000 Alicia Boya García + + * gst/isomp4/qtdemux.c: + qtdemux: Fix race on pad reconnection + Elements emitting frames through several srcpads should use a + flow combiner to aggregate the chain returns and therefore only return + GST_FLOW_NOT_LINKED to upstream when all the downstream pads have + received GST_FLOW_NOT_LINKED. + In addition to that, in order to handle pads being relinked downstream, + the flow combiner should be reset in response to RECONFIGURE events. + This ensures that a both srcpads process a chain operation before a + GST_FLOW_NOT_LINKED can be propagated upstream (which would usually stop + the pipeline). + Otherwise, in a configuration with two srcpads, only one linked at a + time, after the relink the element could chain data through the now + unlinked pad and the flow combiner would resolve as GST_FLOW_NOT_LINKED + (stopping the pipeline) just because the now linked pad has not been + chained yet to update the flow combiner. + This patch adds handling of RECONFIGURE events to qtdemux. Also, since + this event handling causes the flow combiner to be used from a thread + other than the qtdemux streaming thread, usages of the flow combiner + has been guarded by the object lock. + +2020-01-07 01:20:24 +0900 Seungha Yang + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: Fix assertion failure on set_property() + GValue might have null object. + (gst-inspect-1.0:10304): GStreamer-CRITICAL ... + gst_object_ref_sink: assertion 'object != NULL' failed + +2020-01-03 15:16:02 +0100 Daniel Molkentin + + * gst/videocrop/gstvideocrop.c: + videocrop: allow properties to be animated by GstController + +2019-12-24 08:24:51 -0500 Aaron Boxer + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: improved handling of control concatenation with base + Also, `control_url` variable has been renamed to `control_path`, + as it is actually a path. + +2019-12-06 12:34:15 -0500 Aaron Boxer + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: append aggregate control string to base URL before query string + Appending control string to end of query changes meaning of query string + Fixes #650 + +2019-12-28 23:01:19 +0000 Eric Marks + + * ext/aalib/gstaasink.c: + * ext/aalib/gstaatv.c: + * ext/aalib/gstaatv.h: + * ext/aalib/meson.build: + * ext/libcaca/gstcacasink.c: + * ext/libcaca/gstcacatv.c: + * ext/libcaca/gstcacatv.h: + * ext/libcaca/meson.build: + aasink & cacasink: add filter aatv & cacatv + Add transform filter capabilities to aasink and cacasink in the form of new elements aatv and cacatv. + +2019-06-06 11:03:34 +0200 Niels De Graef + + * gst/alpha/gstalpha.h: + * gst/alpha/gstalphacolor.h: + alpha: Cleanup using G_DECLARE_FINAL_TYPE + We started depending on GLib 2.44, so we can clean up all the GObject + boilerplate macros. + +2019-12-18 16:07:18 +0100 Stéphane Cerveau + + * ext/shout2/gstshout2.c: + * gst/multipart/multipartmux.c: + * sys/ximage/gstximagesrc.c: + good: use of g_value_dup_string + Use helper method to get string from GValue. + +2019-12-19 23:48:09 +0100 Havard Graff + + * gst/rtpmanager/gstrtpbin.c: + * tests/check/elements/rtpbin.c: + rtpbin: fix shutdown crash in rtpbin + The key is to make sure the jitterbuffer is set to NULL *before* the + ptdemux. + The race that existed would basically happen when ptdemux had reached + READY, and the jitterbuffer would then push a buffer, triggering a new + pad with a new payloadtype being added and ghosted to the rtpbin itself. + However, the srcpad of the ptdemux would now be inactive, and all the + sticky-event pushed on it would be swallowed, not allowing any to reach + the ghost-pad. Then the buffer in-flight would come to the ghostpad, + and we would assert that a buffer arrived before the necessary + events. + By simply re-ordering the state-changes, we ensure that there will be + no buffer racing into the ptdemux while its state is being changed, + and the problem disappears completely. + Notice also that there is not point in disconnecting the signals on the + ptdemux before this point, since we need the push-thread to settle + down before we can do this in a non-racy way. + +2019-09-12 14:22:10 -0600 Aaron Boxer + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: avoid seek DISCONT when only rate changes in same direction + Not setting DISCONT avoids a noticable delay when seeking + with only rate changing, in the same direction as current + rate. + +2019-12-10 18:13:11 -0500 Olivier Crête + + * gst/rtsp/gstrtspsrc.c: + * gst/rtsp/gstrtspsrc.h: + rtspsrc: Remove deprecated GTimeVal + GTimeVal won't work past 2038 + +2019-12-10 17:13:45 -0500 Olivier Crête + + * sys/osxaudio/gstosxcoreaudiohal.c: + osxaudio: Remove deprecated GTimeVal + +2019-12-18 12:19:27 +0200 Sebastian Dröge + + * gst/avi/gstavimux.c: + avimux: Add support for S24LE and S32LE raw audio + avidemux already handles this correctly. + +2019-12-16 21:07:08 +0200 Sebastian Dröge + + * gst/avi/gstavimux.c: + avimux: Allow muxing v210 video into AVI + avidemux already handles this. + +2019-12-16 18:43:44 +0200 Vivia Nikolaidou + + * gst/flv/gstflvdemux.c: + flvdemux: Don't replace video codec data when we receive a PAR + Receiving a pixel-aspect-ratio should trigger a caps change, but not + replace the existing video codec tag + +2019-12-12 20:20:35 +0100 Mathieu Duponchelle + + * gst/isomp4/gstqtmux.c: + qtmux: protect access to GstElement.sinkpads + +2019-12-03 15:30:06 +0100 Mathieu Duponchelle + + * gst/isomp4/gstqtmux.c: + * gst/isomp4/gstqtmux.h: + * tests/check/elements/qtmux.c: + qtmux: port to GstAggregator + +2019-12-16 13:03:51 +0100 Joakim Johansson + + * gst/rtsp/gstrtspsrc.c: + gstrtspsrc: Add missing lock on free set_get_param_q + Otherwise is it possible to get a crash in gst_rtspsrc_set_parameter. + +2019-12-12 18:53:00 +0200 Sebastian Dröge + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: Increment fragment_id even if no fragment location was provided + Applications might handle locations and generally configuration of the + sink by themselves instead of having splitmuxsink set the location on + the sink. Nonetheless it makes sense to increment the fragment_id that + is passed to the signal so that applications know which fragment is + requested. + +2019-12-12 10:59:35 +0100 Jan Alexander Steffens (heftig) + + * gst/flv/gstflvmux.c: + flvmux: Use the last DTS for the metadata timestamp + This avoids creating a timestamp regression during a stream. + https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/merge_requests/429 + +2019-12-11 17:30:50 +0100 Mathieu Duponchelle + + * gst/isomp4/qtdemux.c: + qtdemux: send GAP events for lagging audio and video streams too + The logic is taken straight from matroskademux, see + 77403d0afee635f2de6c2e53a23e1f50ad0d00fa + +2019-12-10 23:48:35 +0900 Seungha Yang + + * gst/flv/gstflvmux.c: + * meson.build: + flvmux: Use thread-safe gmtime_r if available + gmtime on *nix is not thread-safe. + +2019-12-05 14:58:40 +0000 Stéphane Cerveau + + * gst/multifile/gstsplitmuxsink.c: + * gst/multifile/gstsplitmuxsink.h: + splitmuxsink: provides a start-index property + Allow to change the fragment-id start index. + +2019-12-03 11:36:07 +0100 Philipp Zabel + + * ext/qt/meson.build: + qmlglsink: fix build on EGL platform without X11 headers + If Mesa is built without X11 headers, building against Mesa EGL headers + requires a dependency on egl.pc, to define MESA_EGL_NO_X11_HEADERS. + This fixes a build error when compiling ext/qt/gstqtglutility.cc: + In file included from /usr/include/EGL/egl.h:39, + from /usr/include/gstreamer-1.0/gst/gl/egl/gstegl.h:44, + from ../gst-plugins-good-1.16.1/ext/qt/gstqtglutility.cc:43: + /usr/include/EGL/eglplatform.h:124:10: fatal error: X11/Xlib.h: No such file or directory + +2019-12-04 01:03:49 +0000 Tim-Philipp Müller + + * gst/rtp/gstrtpjpegdepay.c: + rtpjpegdepay: outputs framed jpeg + Add parsed=true to output caps, as we always output + whole frames, timestamped and all. Means also that + the output can be decoded by avdec_mjpeg wihout + plugging an extra parser (which has no rank). + +2019-12-03 13:47:22 +0100 Jan Alexander Steffens (heftig) + + * gst/flv/gstflvmux.c: + flvmux: Correct metadata handling in file and stream mode + In file mode, only push one onMetaData at the start of the stream. + In stream mode, always push complete onMetaData. They get replaced, not + merged. + https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/merge_requests/418 + +2019-12-03 13:46:09 +0100 Jan Alexander Steffens (heftig) + + * gst/flv/gstflvmux.c: + flvmux: Don't calculate duration in streamable mode + There's no header to rewrite, so the duration is left unused. + https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/merge_requests/418 + +2016-11-30 15:55:01 +0100 Havard Graff + + * gst/rtp/gstrtpL16depay.c: + rtpL16depay: don't crash if data is not modulo channels*width + +2019-12-02 19:00:45 +0000 Tim-Philipp Müller + + * meson.build: + * pkgconfig/gstreamer-plugins-good-uninstalled.pc.in: + * pkgconfig/meson.build: + pkgconfig: remove gst-plugins-good-1.0-uninstalled.pc + This was never installed and it was only used by the uninstalled + autotools dev environment to locate the -good plugins for use + in unit tests in gstreamer modules higher up the stack. + It is no longer needed now that we no longer have an autotools build. + +2017-10-10 15:45:28 +0200 Håvard Graff + + * pkgconfig/meson.build: + meson.build: use join_paths() on prefix + So that "/" are correct on Windows. + +2017-06-30 09:48:58 +0200 Havard Graff + + * gst/rtp/gstrtpopuspay.c: + rtpopuspay: use baseclass allocator for buffers + That way we get some of the meta -> rtp-extension goodies. + +2019-11-29 20:46:26 +0900 Seungha Yang + + * ext/vpx/gstvp9dec.c: + vp9dec: Fix broken 4:4:4 8bits decoding + VPX_IMG_FMT_I444 pixel format with sRGB colorspace means + GBR data. + Fixes: https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/651 + +2019-10-18 17:45:43 +0200 Havard Graff + + * tests/check/elements/rtpsession.c: + rtpsession: add test for requesting FIR after having requested PLI + +2019-11-26 15:00:18 +0100 Havard Graff + + * tests/check/elements/rtpjitterbuffer.c: + rtpjitterbuffer: make test more stable + +2019-11-29 14:23:49 +0100 Havard Graff + + * gst/rtpmanager/gstrtpsession.c: + * tests/check/elements/rtpsession.c: + rtpsession: add locking for clear-pt-map + ...or it will segfault from time to time... + +2018-05-31 10:29:43 +0200 Linus Svensson + + * gst/matroska/matroska-mux.c: + * gst/matroska/matroska-mux.h: + * gst/matroska/matroska-read-common.c: + matroskamux: Add property to set DateUTC + Add a property that makes it possible for an application to set the + DateUTC header field in matroska files. This is useful for live feeds, + where the DateUTC header can be set to a UTC timestamp, matching the + beginning of the file. + Needs gstreamer!323 + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/481 + +2018-05-31 11:20:36 +0200 Linus Svensson + + * gst/matroska/ebml-ids.h: + * gst/matroska/ebml-read.c: + * gst/matroska/ebml-write.c: + * gst/matroska/matroska-mux.c: + matroskamux: Use nanosecond precision for DateUTC + DateUTC is specified with nanosecond precision in matroska, make use of + that. + +2018-10-17 02:28:13 +0000 Nicolas Dufresne + + * sys/v4l2/gstv4l2bufferpool.c: + * sys/v4l2/gstv4l2bufferpool.h: + v4l2bufferpool: Queue number of allocated buffers to capture + Before we do streamon, we queue all capture buffers by calling + resurrect. When the driver supports CREATE_BUFS, this would lead + to buffers being allocated till the maximum of 32 is reached. + Instead, we now save the number of allocated buffers and queue this + amount. + +2019-11-19 14:23:48 +0100 Jan Alexander Steffens (heftig) + + * gst/matroska/matroska-mux.c: + matroskamux: Pass the right size to gst_collect_pads_add_pad + We were lucky that GstMatroskamuxPad is larger than GstMatroskaPad. + https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/merge_requests/393 + +2019-11-18 13:27:42 -0500 Nicolas Dufresne + + * sys/v4l2/gstv4l2object.c: + v4l2object: Workaround bad TRY_FMT colorimetry implementation + libv4l2 reset the colorpace to 0 and does not do any request to the + driver. This yields an invalid colorspace which currently cause a + negotiation failure. This workaround by ignoring bad values during the + TRY_FMT step. + +2019-11-04 17:18:30 +0800 aogun + + * gst/audioparsers/gstaacparse.c: + aacparse: fix wrong offset of adts channel + +2019-10-07 12:45:00 +0900 Seungha Yang + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: Don't take lock during posting message + An application might try to access splitmuxsink from sync message handler + by g_object_{get,set} which takes lock also. In general, we don't + take lock around message handler. + +2019-09-12 15:21:24 -0400 Scott Kanowitz + + * ext/jpeg/gstjpegdec.c: + jpegdec: Fix incorrect logic in EOI tag detection + This change fixes the reversed logic in the EOI tag detection + code. + +2019-08-26 08:03:24 +0200 Niels De Graef + + * ext/cairo/gstcairooverlay.c: + * ext/raw1394/gstdv1394src.c: + * ext/shout2/gstshout2.c: + * gst/rtp/rtpstorage.c: + * gst/rtpmanager/gstrtpbin.c: + * gst/rtpmanager/gstrtpjitterbuffer.c: + * gst/rtpmanager/gstrtpptdemux.c: + * gst/rtpmanager/gstrtpsession.c: + * gst/rtpmanager/gstrtpssrcdemux.c: + * gst/rtpmanager/rtpsession.c: + * gst/rtsp/gstrtpdec.c: + * gst/rtsp/gstrtspsrc.c: + * gst/udp/gstdynudpsink.c: + * gst/udp/gstmultiudpsink.c: + * sys/v4l2/tuner.c: + * sys/v4l2/tunerchannel.c: + Don't pass default GLib marshallers for signals + By passing `NULL` to `g_signal_new` instead of a marshaller, GLib will + actually internally optimize the signal (if the marshaller is available + in GLib itself) by also setting the valist marshaller. This makes the + signal emission a bit more performant than the regular marshalling, + which still needs to box into `GValue` and call libffi in case of a + generic marshaller. + Note that for custom marshallers, one would use + `g_signal_set_va_marshaller()` with the valist marshaller instead. + +2019-11-14 17:33:08 -0500 Nicolas Dufresne + + * gst/rtpmanager/gstrtpjitterbuffer.c: + rtpjitterbuffer: Check the exit condition after executing timers + The do_expected_timeout() function may release the JBUF_LOCK, so we need + to check if nothing wanted the timer thread to exit after this call. + The side effect was that we may endup going back into waiting for a timer + which will cause arbitrary delay on tear down (or deadlock when test + clock is used). + Fixes #653 + +2019-11-14 17:20:51 -0500 Nicolas Dufresne + + * gst/rtpmanager/gstrtpjitterbuffer.c: + rtpjitterbuffer: Check exit condition immediately after JBUF_WAIT + JBUF_WAIT_QUEUE drops the JBUF_LOCK, which means the stop condition + for the chain function may have changed (change_state to NULL). Check + this immediately after the wait so that we don't delay shutting down. + +2019-11-12 17:28:22 -0500 Nicolas Dufresne + + * gst/videocrop/gstvideocrop.c: + videocrop: Also update the coordinate when in-place + This update is needed when the output caps is not changed (e.g. we are + moving a viewport around). + Fixes #669 + +2019-11-11 13:19:08 -0500 Nicolas Dufresne + + * gst/videocrop/gstvideocrop.c: + videocrop: Don't always re-run the allocation query + When in-place, running an allocation is not useful since videocrop + is not implicated in the allocation. So only force the allocation + query for the case it was in passthrough. This is needed since the + change in the crop region will likely pull us out of this mode. For the + case we where neither in passthrough or in-place, the allocation query + is already ran by the baseclass, so nothing special is needed. + This fixes performance issues when changing the crop region per frame. + This was reproduced using videocrop2-test. + +2019-11-11 13:18:52 -0500 Nicolas Dufresne + + * gst/videocrop/gstvideocrop.c: + videocrop: Cleanup spurious assignment + These are just writing the same thing a second time. + +2018-11-07 09:00:02 +0100 Michael Olbrich + + * ext/jpeg/gstjpegdec.c: + * ext/jpeg/gstjpegdec.h: + jpegdec: don't overwrite the last valid line + If the the height is not a multiple of the macro block size then the memory + of the last line is reused for all extra lines. This is no problem if the + last line is duplicated properly. However, if the extra lines are not + initialized properly during encoding, then the last visible line is + overwritten with undefined data. + Use a extra buffer to avoid this problem. + +2019-11-07 12:28:58 +0100 Stéphane Cerveau + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: add fakesink support + fakesink does not support "location" property and was generating + a warning. + +2018-12-12 19:07:39 +0300 Sergey Nazaryev + + * gst/udp/gstmultiudpsink.c: + multiudpsink: don't lose scope_id + +2019-11-05 21:41:55 +0530 Nirbheek Chauhan + + * ext/vpx/meson.build: + vpx: Error out if enabled and no features found + Seee: https://gitlab.freedesktop.org/gstreamer/cerbero/issues/200 + +2019-05-25 21:19:21 +0200 Guillaume Desmottes + + * sys/v4l2/gstv4l2object.c: + v4l2object: update match_buffer_layout() debug messages + It's no longer used only to try importing buffers. + +2019-05-23 10:49:39 +0200 Guillaume Desmottes + + * sys/v4l2/gstv4l2object.c: + v4l2object: try matching buffer layout from downstream + Ask v4l2 to produce buffers matching the buffer layout requested + downstream. + +2019-05-21 10:31:46 +0200 Guillaume Desmottes + + * sys/v4l2/gstv4l2object.c: + v4l2object: factor out gst_v4l2_object_match_buffer_layout() + No semantic change. + +2019-10-20 12:17:25 +0200 Havard Graff + + * gst/rtpmanager/rtpjitterbuffer.c: + * tests/check/elements/rtpjitterbuffer.c: + rtpjitterbuffer: make sure not to drop packets based on skew + One of the jitterbuffers functions is to try and make sense of weird + network behavior. + It is quite unhelpful for the jitterbuffer to start dropping packets + itself when what you are trying to achieve is better network resilience. + In the case of a skew, this could often mean the sender has restarted + in some fashion, and then dropping the very first buffer of this "new" + stream could often mean missing valuable information, like in the case + of video and I-frames. + This patch simply reverts back to the old behavior, prior to https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/commit/8d955fc32b552b2db933c67f3cfa31d987f36b81 + and includes the simplest test I could write to demonstrate the behavior, + where a single packet arrives "perfectly", then a 50ms gap happens, + and then two more packets arrive in perfect order after that. + # Conflicts: + # tests/check/elements/rtpjitterbuffer.c + +2019-04-17 12:40:22 +0530 Guillaume Desmottes + + * sys/v4l2/gstv4l2transform.c: + v4l2transform: use alignments from upstream when importing on sink + Try configuring the v4l2 output with the alignments from upstream when + importing its buffers. This allows us to support importing with + non-standard strides and/or heights if supported by the driver. + +2019-04-17 12:25:14 +0530 Guillaume Desmottes + + * sys/v4l2/gstv4l2object.c: + v4l2object: add support for vertical padding when importing buffers + We were already supporting horizontal padding by setting bytesperline to + the buffer stride but not vertical one. + We are now updating the format height with the padded height and crop to + the actual video resolution if needed. + +2019-04-17 11:46:10 +0530 Guillaume Desmottes + + * sys/v4l2/gstv4l2object.c: + v4l2object: fix debug message if driver rejects stride + The 'want' and 'got' strides were inversed. + +2019-04-15 11:43:41 +0530 Guillaume Desmottes + + * sys/v4l2/gstv4l2object.c: + v4l2: improve logs when importing buffers + Log strides and offsets from upstream. + Also fix a typo. + +2019-10-29 14:05:48 +0000 James Cowgill + + * sys/v4l2/gstv4l2videodec.c: + v4l2videodec: ensure pool exists before orphaning it + In commit e2ff87732d0b ("v4l2videodec: support orphaning") support for + orphaning the capture buffer pool was added when the format is + renegotiated. However, the commit forgot to check that a pool existed + before doing this. This is needed because it's possible for the format + to be renegotiated before a capture pool is allocated, which would + result in trying to orphan a NULL pool and lead to a NULL pointer + dereference. + Fix this by checking a pool exists first. If the pool doesn't exist, + there are no buffers to be reclaimed, so skip the allocation query in + that case. + +2019-10-25 22:03:18 +1100 Matthew Waters + + * ext/qt/qtwindow.cc: + qmlglsrc: read from the back buffer when use-default-fbo = TRUE + glReadBuffer(GL_COLOR_ATTACHMENT0) on the default framebuffer (0) is + invalid GL API usage and would result in a GL error being thrown. + +2019-10-25 21:47:01 +1100 Matthew Waters + + * ext/qt/gstqtsrc.cc: + qmlglsrc: fix vertical flip matrix + Some time ago libgstgl defined the majorness of matrices it uses. + The majorness used by qmlglsrc was incompatible with the libgstgl. + +2019-07-30 12:07:18 +0200 Patricia Muscalu + + * gst/isomp4/gstqtmux.c: + * gst/isomp4/gstqtmux.h: + qtmux: Fix memory leak while pushing fragmented data + The memory leak occurs in the case when the buffer has been + added to the fragment_buffers array of the current pad and + never been sent because of the push failure of the previous + buffers: moof or mdat header or fragmented buffer(s). + +2019-10-11 14:20:15 +0200 Edward Hervey + + * gst/debugutils/cpureport.c: + * gst/debugutils/cpureport.h: + * gst/debugutils/progressreport.c: + * gst/debugutils/progressreport.h: + * gst/flv/gstflvmux.c: + * gst/isomp4/atoms.c: + * gst/isomp4/qtdemux.c: + * gst/matroska/matroska-mux.c: + * gst/rtpmanager/gstrtpbin.c: + * gst/rtpmanager/gstrtpsession.c: + * gst/udp/gstmultiudpsink.c: + * sys/v4l2/gstv4l2src.c: + good: Avoid usage of deprecated API + GTimeval and related functions are now deprecated in glib. + Replacement APIs have been present since 2.26 + +2019-07-15 07:46:56 +0200 Javier Celaya + + * sys/osxaudio/meson.build: + osxaudio: misspelled dependency + When building osxaudio, the required 'AudioToolbox' dependency is + misspelled as 'AudioToolBox', which crashes the build with error: + ld: framework not found AudioToolBox + +2019-06-09 00:43:00 +0100 Tim-Philipp Müller + + * .gitignore: + * .gitmodules: + * Makefile.am: + * README: + * autogen.sh: + * common: + * configure.ac: + * docs/.gitignore: + * ext/Makefile.am: + * ext/aalib/Makefile.am: + * ext/cairo/Makefile.am: + * ext/dv/Makefile.am: + * ext/flac/Makefile.am: + * ext/gdk_pixbuf/Makefile.am: + * ext/gtk/Makefile.am: + * ext/jack/.gitignore: + * ext/jack/Makefile.am: + * ext/jpeg/Makefile.am: + * ext/lame/Makefile.am: + * ext/libcaca/Makefile.am: + * ext/libpng/Makefile.am: + * ext/mpg123/Makefile.am: + * ext/pulse/Makefile.am: + * ext/qt/.gitignore: + * ext/qt/Makefile.am: + * ext/raw1394/.gitignore: + * ext/raw1394/Makefile.am: + * ext/shout2/Makefile.am: + * ext/soup/Makefile.am: + * ext/speex/Makefile.am: + * ext/taglib/.gitignore: + * ext/taglib/Makefile.am: + * ext/twolame/Makefile.am: + * ext/vpx/Makefile.am: + * ext/wavpack/Makefile.am: + * gst/Makefile.am: + * gst/alpha/Makefile.am: + * gst/apetag/Makefile.am: + * gst/audiofx/.gitignore: + * gst/audiofx/Makefile.am: + * gst/audioparsers/Makefile.am: + * gst/auparse/.gitignore: + * gst/auparse/Makefile.am: + * gst/autodetect/Makefile.am: + * gst/avi/.gitignore: + * gst/avi/Makefile.am: + * gst/cutter/Makefile.am: + * gst/debugutils/Makefile.am: + * gst/deinterlace/Makefile.am: + * gst/dtmf/Makefile.am: + * gst/effectv/Makefile.am: + * gst/equalizer/.gitignore: + * gst/equalizer/Makefile.am: + * gst/flv/Makefile.am: + * gst/flx/Makefile.am: + * gst/goom/.gitignore: + * gst/goom/Makefile.am: + * gst/goom2k1/.gitignore: + * gst/goom2k1/Makefile.am: + * gst/icydemux/Makefile.am: + * gst/id3demux/Makefile.am: + * gst/imagefreeze/Makefile.am: + * gst/interleave/Makefile.am: + * gst/isomp4/Makefile.am: + * gst/law/Makefile.am: + * gst/level/.gitignore: + * gst/level/Makefile.am: + * gst/matroska/Makefile.am: + * gst/monoscope/.gitignore: + * gst/monoscope/Makefile.am: + * gst/multifile/Makefile.am: + * gst/multipart/Makefile.am: + * gst/replaygain/Makefile.am: + * gst/rtp/Makefile.am: + * gst/rtpmanager/Makefile.am: + * gst/rtsp/.gitignore: + * gst/rtsp/Makefile.am: + * gst/shapewipe/Makefile.am: + * gst/smpte/Makefile.am: + * gst/spectrum/.gitignore: + * gst/spectrum/Makefile.am: + * gst/udp/Makefile.am: + * gst/videobox/Makefile.am: + * gst/videocrop/Makefile.am: + * gst/videofilter/.gitignore: + * gst/videofilter/Makefile.am: + * gst/videomixer/Makefile.am: + * gst/wavenc/Makefile.am: + * gst/wavparse/.gitignore: + * gst/wavparse/Makefile.am: + * gst/y4m/Makefile.am: + * m4/.gitignore: + * m4/Makefile.am: + * m4/README: + * m4/a52.m4: + * m4/aalib.m4: + * m4/as-ffmpeg.m4: + * m4/as-liblame.m4: + * m4/as-slurp-ffmpeg.m4: + * m4/check-libheader.m4: + * m4/freetype2.m4: + * m4/glib.m4: + * m4/gst-alsa.m4: + * m4/gst-artsc.m4: + * m4/gst-fionread.m4: + * m4/gst-ivorbis.m4: + * m4/gst-matroska.m4: + * m4/gst-sdl.m4: + * m4/gst-shout2.m4: + * m4/gst-sid.m4: + * m4/gtk.m4: + * m4/libfame.m4: + * m4/ogg.m4: + * m4/vorbis.m4: + * pkgconfig/.gitignore: + * pkgconfig/Makefile.am: + * po/.gitignore: + * po/Makevars: + * po/POTFILES: + * sys/Makefile.am: + * sys/directsound/Makefile.am: + * sys/oss/.gitignore: + * sys/oss/Makefile.am: + * sys/oss4/Makefile.am: + * sys/osxaudio/Makefile.am: + * sys/osxvideo/Makefile.am: + * sys/v4l2/Makefile.am: + * sys/waveform/Makefile.am: + * sys/ximage/Makefile.am: + * tests/Makefile.am: + * tests/check/.gitignore: + * tests/check/Makefile.am: + * tests/check/elements/.gitignore: + * tests/check/generic/.gitignore: + * tests/check/pipelines/.gitignore: + * tests/examples/Makefile.am: + * tests/examples/audiofx/.gitignore: + * tests/examples/audiofx/Makefile.am: + * tests/examples/cairo/.gitignore: + * tests/examples/cairo/Makefile.am: + * tests/examples/equalizer/.gitignore: + * tests/examples/equalizer/Makefile.am: + * tests/examples/gtk/.gitignore: + * tests/examples/gtk/Makefile.am: + * tests/examples/jack/Makefile.am: + * tests/examples/level/.gitignore: + * tests/examples/level/Makefile.am: + * tests/examples/qt/qmlsink/.gitignore: + * tests/examples/qt/qmlsrc/.gitignore: + * tests/examples/rtp/.gitignore: + * tests/examples/rtp/Makefile.am: + * tests/examples/rtsp/Makefile.am: + * tests/examples/shapewipe/.gitignore: + * tests/examples/shapewipe/Makefile.am: + * tests/examples/spectrum/.gitignore: + * tests/examples/spectrum/Makefile.am: + * tests/examples/v4l2/.gitignore: + * tests/examples/v4l2/Makefile.am: + * tests/files/Makefile.am: + * tests/icles/.gitignore: + * tests/icles/Makefile.am: + Remove autotools build system + +2019-10-13 12:46:58 +0100 Tim-Philipp Müller + + * sys/v4l2/gstv4l2videoenc.c: + v4l2videoenc: fix wrong type cast + Follow-up to commit 1b752c0f !361 + +2019-09-25 12:36:32 +0000 HuQian + + * sys/v4l2/gstv4l2object.c: + is a typo here? gstv4l2object.c + +2019-10-11 12:27:12 +0000 Kevin Song + + * sys/v4l2/gstv4l2videodec.c: + v4l2videodec: Check stop in flush() to avoid race condition. + Backward playback will drain and flush every frame. Stop playback + when backward playback have race condition between exit thread and + streaming thread flush. Add one check to avoid it. + Fixes #639 + +2019-10-11 10:33:20 +0800 Fuwei Tang + + * sys/v4l2/gstv4l2videoenc.c: + v4l2videoenc: fix type conversion errors + +2019-09-02 08:27:35 -0400 Aaron Boxer + + * NEWS: + * docs/gst_plugins_cache.json: + * ext/dv/gstdvdemux.c: + * ext/flac/gstflactag.c: + * ext/gdk_pixbuf/gstgdkpixbufdec.c: + * ext/gtk/gstgtkbasesink.c: + * ext/jack/gstjackaudioclient.c: + * ext/jpeg/Makefile.am: + * ext/pulse/pulsesink.c: + * ext/qt/qtwindow.cc: + * ext/raw1394/gstdv1394src.h: + * ext/taglib/gstid3v2mux.cc: + * ext/wavpack/gstwavpackenc.c: + * gst/audiofx/audiodynamic.c: + * gst/audiofx/audiofxbasefirfilter.c: + * gst/audiofx/audiofxbasefirfilter.h: + * gst/audiofx/gstscaletempo.c: + * gst/audiofx/gstscaletempoplugin.c: + * gst/autodetect/gstautodetect.c: + * gst/avi/gstavidemux.c: + * gst/avi/gstavimux.c: + * gst/debugutils/progressreport.c: + * gst/debugutils/rndbuffersize.c: + * gst/deinterlace/gstdeinterlace.c: + * gst/deinterlace/tvtime/sse.h: + * gst/deinterlace/tvtime/tomsmocomp/SearchLoopBottom.inc: + * gst/deinterlace/tvtime/tomsmocomp/StrangeBob.inc: + * gst/deinterlace/tvtime/tomsmocomp/WierdBob.inc: + * gst/deinterlace/tvtime/vfir.c: + * gst/dtmf/gstdtmfsrc.c: + * gst/dtmf/gstrtpdtmfdepay.c: + * gst/dtmf/gstrtpdtmfsrc.c: + * gst/effectv/gstedge.c: + * gst/effectv/gstquark.c: + * gst/flv/gstflvdemux.c: + * gst/flv/gstindex.c: + * gst/interleave/deinterleave.c: + * gst/isomp4/gstqtmux.c: + * gst/isomp4/qtdemux.c: + * gst/isomp4/qtdemux_lang.c: + * gst/level/gstlevel.c: + * gst/matroska/ebml-write.c: + * gst/matroska/matroska-demux.c: + * gst/matroska/matroska-mux.c: + * gst/matroska/matroska-parse.c: + * gst/matroska/matroska-read-common.c: + * gst/monoscope/monoscope.c: + * gst/multifile/gstmultifilesrc.c: + * gst/multifile/gstsplitmuxpartreader.c: + * gst/multifile/gstsplitmuxsink.c: + * gst/multifile/gstsplitmuxsrc.c: + * gst/multifile/patternspec.c: + * gst/replaygain/replaygain.h: + * gst/rtp/README: + * gst/rtp/gstrtpdvdepay.c: + * gst/rtp/gstrtpg726pay.c: + * gst/rtp/gstrtpgstpay.c: + * gst/rtp/gstrtph261pay.c: + * gst/rtp/gstrtph263pay.c: + * gst/rtp/gstrtph263ppay.c: + * gst/rtp/gstrtph264depay.c: + * gst/rtp/gstrtph264pay.c: + * gst/rtp/gstrtph265depay.c: + * gst/rtp/gstrtpjpegdepay.c: + * gst/rtp/gstrtpjpegpay.c: + * gst/rtp/gstrtpmp4adepay.c: + * gst/rtp/gstrtpmp4gdepay.c: + * gst/rtp/gstrtpmp4gpay.c: + * gst/rtp/gstrtpmp4vpay.c: + * gst/rtp/gstrtpredenc.c: + * gst/rtp/gstrtptheoradepay.c: + * gst/rtp/gstrtpulpfecenc.c: + * gst/rtp/gstrtpvorbisdepay.c: + * gst/rtp/gstrtpvrawdepay.c: + * gst/rtp/rtpstorage.c: + * gst/rtp/rtpulpfeccommon.c: + * gst/rtp/rtpulpfeccommon.h: + * gst/rtpmanager/gstrtpbin.c: + * gst/rtpmanager/gstrtpjitterbuffer.c: + * gst/rtpmanager/gstrtpptdemux.c: + * gst/rtpmanager/gstrtpptdemux.h: + * gst/rtpmanager/gstrtprtxreceive.c: + * gst/rtpmanager/gstrtprtxsend.c: + * gst/rtpmanager/gstrtpsession.c: + * gst/rtpmanager/gstrtpssrcdemux.c: + * gst/rtpmanager/rtpjitterbuffer.c: + * gst/rtpmanager/rtpsession.c: + * gst/rtpmanager/rtpsession.h: + * gst/rtpmanager/rtpsource.c: + * gst/rtsp/README: + * gst/rtsp/gstrtspsrc.c: + * gst/spectrum/gstspectrum.h: + * gst/udp/gstmultiudpsink.c: + * gst/udp/gstudpsrc.c: + * gst/videobox/gstvideobox.c: + * gst/videocrop/gstvideocrop.c: + * gst/videofilter/gstvideoflip.c: + * gst/videomixer/README: + * gst/videomixer/videomixer2.c: + * gst/wavenc/gstwavenc.c: + * gst/wavparse/gstwavparse.c: + * hooks/pre-commit.hook: + * m4/aalib.m4: + * m4/freetype2.m4: + * m4/glib.m4: + * m4/gst-fionread.m4: + * m4/gst-matroska.m4: + * m4/gst-sdl.m4: + * m4/gst-shout2.m4: + * m4/gtk.m4: + * m4/libfame.m4: + * m4/ogg.m4: + * m4/vorbis.m4: + * sys/oss4/oss4-audio.c: + * sys/oss4/oss4-soundcard.h: + * sys/osxaudio/gstosxcoreaudio.c: + * sys/osxvideo/osxvideosink.m: + * sys/v4l2/gstv4l2.c: + * sys/v4l2/gstv4l2allocator.c: + * sys/v4l2/gstv4l2bufferpool.c: + * sys/v4l2/gstv4l2bufferpool.h: + * sys/v4l2/gstv4l2object.c: + * sys/v4l2/gstv4l2src.c: + * sys/v4l2/gstv4l2transform.c: + * sys/v4l2/gstv4l2videodec.c: + * sys/v4l2/gstv4l2videoenc.c: + * sys/v4l2/v4l2_calls.c: + * sys/waveform/gstwaveformsink.c: + * sys/ximage/gstximagesrc.c: + * sys/ximage/ximageutil.h: + * tests/check/elements/jpegdec.c: + * tests/check/elements/level.c: + * tests/check/elements/qtmux.c: + * tests/check/elements/rgvolume.c: + * tests/check/elements/rtp-payloading.c: + * tests/check/elements/rtpbin.c: + * tests/check/elements/rtpjitterbuffer.c: + * tests/check/elements/rtpred.c: + * tests/check/elements/rtprtx.c: + * tests/check/elements/rtpsession.c: + * tests/check/elements/rtpstorage.c: + * tests/check/elements/splitmux.c: + * tests/check/pipelines/simple-launch-lines.c: + * tests/examples/cairo/cairo_overlay.c: + * tests/examples/gtk/glliveshader.c: + * tests/examples/rtp/client-rtpaux.c: + * tests/examples/v4l2/camctrl.c: + documentation: fix a number of typos + +2019-10-04 20:31:56 +0000 Simon Arnling Bååth + + * gst/rtpmanager/gstrtpjitterbuffer.c: + * tests/check/elements/rtpjitterbuffer.c: + gstrtpjitterbuffer: Custom messages when dropping packets + This commit adds custom element messages for when gstrtpjitterbuffer + drops an incoming rtp packets due to for example arriving too late. + Applications can listen to these messages on the bus which enables + actions to be taken when packets are dropped due to for example high + network jitter. + Two properties has been added, one to enable posting drop messages and + one to set a minimum time between each message to enable throttling the + posting of messages as high drop rates. + +2019-09-03 16:46:30 -0400 Thibault Saunier + + * gst/isomp4/qtdemux.c: + * gst/isomp4/qtdemux.h: + qtdemux: Specify REDIRECT information in error message + There are in the wild (mp4) streams that basically contain no tracks + but do have a redirect info[0], in which case, we won't be able + to expose any pad (there are no tracks) so we can't post anything but + an error on the bus, as: + - it can't send EOS downstream, it has no pad, + - posting an EOS message will be useless as PAUSED state can't be + reached and there is no sink in the pipeline meaning GstBin will + simply ignore it + The approach here is to to add details to the ERROR message with a + `redirect-location` field which elements like playbin handle and use right + away. + [0]: http://movietrailers.apple.com/movies/paramount/terminator-dark-fate/terminator-dark-fate-trailer-2_480p.mov + +2019-09-26 18:39:48 -0400 Olivier Crête + + * gst/rtpmanager/gstrtpjitterbuffer.c: + * tests/check/elements/rtpjitterbuffer.c: + rtpjitterbuffer: Cancel timers instead of just unlocking loop thread + When the queue is full (and adding more packets would risk a seqnum + roll-over), the best approach is to just start pushing out packets + from the other side. Just pushing out the packets results in the + timers being left hanging with old seqnums, so it's safer to just + execute them immediately in this case. It does limit the timer space + to the time it takes to receiver about 32k packets, but without + extended sequence number, this is the best RTP can do. + This also results in the test no longer needed to have timeouts or + timers as pushing packets in drives everything. + Fixes #619 + +2019-09-27 14:04:28 -0400 Nicolas Dufresne + + * gst/rtpmanager/gstrtpjitterbuffer.c: + rtpjitterbuffer: Optimize offset update + As we are applying the same offset over all timers, there timer + ordering won't change, so we can safely skip time-reordering. + +2019-09-27 16:21:22 -0400 Nicolas Dufresne + + * gst/rtpmanager/rtptimerqueue.c: + rtptimerqueue: Optimize reschedule optations + This basically add ability to choose between inserting from head, tail + or in-place in order to try and minimize the distance to walk through in + the timer queue. This removes an overhead we had seen on high drop rate. + +2019-09-27 14:04:03 -0400 Nicolas Dufresne + + * gst/rtpmanager/gstrtpjitterbuffer.c: + rtpjitterbuffer: Fix a typo in comment + +2019-07-02 15:52:25 -0400 Nicolas Dufresne + + * gst/rtpmanager/gstrtpjitterbuffer.c: + rtpjitterbuffer: Don't use stats timer on the timers queue + The timer passed to update_timers may be from the stats timer. At the + moment, we could endup rescheduling (reusing) that timer onto the normal + timer queue, unschedul it as if it was from the normal timer queue or + duplicate it into the stats timer queue again. This was protected before + as the with the fact the stats timer didn't have a valid idx. + +2019-06-21 14:08:26 -0400 Nicolas Dufresne + + * gst/rtpmanager/gstrtpjitterbuffer.c: + rtpjitterbuffer: Update timers on ts-offset changes + As the offset is already applied now, we need to update and reschedule + all timers each time the offset is changed. I'm not sure who expect this + to be retro-actively applied, but there was a unit test for it. + +2019-06-20 15:59:48 -0400 Nicolas Dufresne + + * gst/rtpmanager/gstrtpjitterbuffer.c: + * tests/check/elements/rtpjitterbuffer.c: + rtpjitterbuffer: No need to wake the timer thread on head changes + If the jitterbuffer head change, there is no need to systematically + wakeup the timer thread. The timer thread will be waken up on if + an earlier timeout has been pushed. This prevent some more spurious + wakeup when the system is loaded. As a side effect, cranking the clock + may set the clock at an earlier position. + +2019-06-18 19:07:29 -0400 Nicolas Dufresne + + * gst/rtpmanager/gstrtpjitterbuffer.c: + * gst/rtpmanager/rtptimerqueue.h: + rtpjittterbuffer: Port timers array to RtpTimerQueue + In this patch we now make use of the new RtpTimerQueue instead of the + old GArray. This required a lot of changes all over the place, some of + the important changes are that `timer->timeout` is no longer a PTS but + the actual timeout. This was required to get the RtpTimerQueue sorting + right. The applied offset is saved as `timer->offset`, this allow + retreiving back the PTS when needed. + The clockid updates only happens once per incoming packet. If the + currently schedule timer is before the earliest timer in the queue, we + no longer wakeup the thread. This way, if other timers get setup in the + meantime, this will reduce the number of wakup. + The timer loop code has been mostly rewritten, though the behaviour of + running the lost timers first has been kept (even though there is no + test to show what would be the side effect of doing this differently). + Fixes #608 + +2019-06-14 14:29:36 -0400 Nicolas Dufresne + + * gst/rtpmanager/gstrtpjitterbuffer.c: + rtpjittterbuffer: Port from TimerQueue to RtpTimerQueue + +2019-06-13 17:08:31 -0400 Nicolas Dufresne + + * gst/rtpmanager/gstrtpjitterbuffer.c: + * gst/rtpmanager/rtptimerqueue.h: + rtpjitterbuffer: Port use the new RtpTimer structure + First iteration toward porting to the new timer queue. + +2019-06-12 09:59:31 -0400 Nicolas Dufresne + + * gst/rtpmanager/Makefile.am: + * gst/rtpmanager/gstrtpjitterbuffer.c: + * gst/rtpmanager/meson.build: + * gst/rtpmanager/rtptimerqueue.c: + * gst/rtpmanager/rtptimerqueue.h: + * tests/check/Makefile.am: + * tests/check/elements/rtpjitterbuffer.c: + * tests/check/meson.build: + rtptimerqueue: Consolidate a data structure for timers + Implement a single timer queue for all timers. The goal is to always use + ordered queues for storing timers. This way, extracting timers for + execution becomes O(1). This also allow separating the clock wait + scheduling from the timer itself and ensure that we only wake up the + timer thread when strictly needed. + The knew data structure is still O(n) on insertions and reschedule, + but we now use proximity optimization so that normal cases should be + really fast. The GList structure is also embeded intot he RtpTimer + structure to reduce the number of allocations. + +2019-06-10 16:46:05 -0400 Nicolas Dufresne + + * tests/check/elements/rtpjitterbuffer.c: + tests: jitterbuffer: Demacroify some helpers + There is no reason for these to be macros anymore. This makes the + test helper much more readable. + +2019-06-06 14:44:27 -0400 Nicolas Dufresne + + * gst/rtpmanager/gstrtpjitterbuffer.c: + * gst/rtpmanager/rtpjitterbuffer.c: + * gst/rtpmanager/rtpjitterbuffer.h: + rtpjitterbuffer: Move item structure outside of the element + This moves the RtpJitterBufferStructure type, alloc, free into + rtpjitterbuffer.c/h implementation. jitterbuffer.c strictly rely on + the fact this structure is compatible with GList, and so it make more + sense to keep encapsulate it. Also, anything that could possibly + reduce the amount of code in the element is a win. + In order to support that move, a function pointer to free the data + was added. This also allow making the free function option when + flushing the jitterbuffer. + +2019-06-06 13:09:29 -0400 Nicolas Dufresne + + * gst/rtpmanager/gstrtpjitterbuffer.c: + rtpjitterbuffer: Constify timer pointers where possible + This helps understanding which function modify the Timerdata + and which one does not. This is not always obvious from thelper + name considering recalculate_timer() does not. + +2019-09-27 08:46:22 +0200 Philipp Zabel + + * sys/v4l2/Makefile.am: + * sys/v4l2/gstv4l2mpeg2codec.c: + * sys/v4l2/gstv4l2mpeg2codec.h: + * sys/v4l2/gstv4l2videodec.c: + * sys/v4l2/meson.build: + v4l2: Add MPEG-2 profile and level support + Add support for V4L2 MPEG-2 decoders reporting supported profiles and + levels. + +2019-09-23 14:34:20 +0200 Philipp Zabel + + * sys/v4l2/gstv4l2object.c: + v4l2object: add support for ABGR, xBGR, RGBA, and RGBx formats + Map them to the new V4L2_PIX_FMT_{BGRA32,BGRX32,RGBA32,RGBX32} pixel + formats. + +2019-09-23 14:10:15 +0200 Philipp Zabel + + * sys/v4l2/ext/v4l2-controls.h: + * sys/v4l2/ext/videodev2.h: + v4l2: update kernel headers to latest from media tree + Update to the latest installed headers (output of make headers_install) + from the media tree, keeping the slight modifications to the includes. + This includes typo fixes in enum v4l2_mpeg_video_multi_slice_mode, + MPEG-2 level and profile enums, new FWHT and H.264 Qp controls, new + RGB(A) formats, and new continuous bytestream and dynamic resolution + format flags. + +2017-12-19 18:23:16 +0100 Mathieu Duponchelle + + * gst/rtpmanager/gstrtpbin.c: + * gst/rtpmanager/gstrtpbin.h: + rtpbin: add request-jitterbuffer signal + This can be used to pass the threadsharing jitterbuffer from + gst-plugins-rs for example. + +2019-09-23 18:46:16 +1000 Matthew Waters + + * gst/isomp4/qtdemux.c: + build: fix werror build with newer gcc + In file included from ../../../../dist/linux_x86_64/include/gstreamer-1.0/gst/gst.h:55, + from ../../../../dist/linux_x86_64/include/gstreamer-1.0/gst/tag/tag.h:25, + from ../gst/isomp4/qtdemux.c:56: + In function ‘qtdemux_inspect_transformation_matrix’, + inlined from ‘qtdemux_parse_trak’ at ../gst/isomp4/qtdemux.c:10676:5, + inlined from ‘qtdemux_parse_tree’ at ../gst/isomp4/qtdemux.c:14210:5: + ../../../../dist/linux_x86_64/include/gstreamer-1.0/gst/gstinfo.h:645:5: error: ‘%s’ directive argument is null [-Werror=format-overflow=] + 645 | gst_debug_log ((cat), (level), __FILE__, GST_FUNCTION, __LINE__, \ + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 646 | (GObject *) (object), __VA_ARGS__); \ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ../../../../dist/linux_x86_64/include/gstreamer-1.0/gst/gstinfo.h:1062:35: note: in expansion of macro ‘GST_CAT_LEVEL_LOG’ + 1062 | #define GST_DEBUG_OBJECT(obj,...) GST_CAT_LEVEL_LOG (GST_CAT_DEFAULT, GST_LEVEL_DEBUG, obj, __VA_ARGS__) + | ^~~~~~~~~~~~~~~~~ + ../gst/isomp4/qtdemux.c:10294:5: note: in expansion of macro ‘GST_DEBUG_OBJECT’ + 10294 | GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s", + | ^~~~~~~~~~~~~~~~ + ../gst/isomp4/qtdemux.c: In function ‘qtdemux_parse_tree’: + ../gst/isomp4/qtdemux.c:10294:64: note: format string is defined here + 10294 | GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s", + | ^~ + +2019-09-18 18:31:27 +0300 Sebastian Dröge + + * gst/isomp4/atoms.c: + qtmux: Use the new helper functions for mapping the colr atom values to colorimetry + +2019-09-18 18:29:27 +0300 Sebastian Dröge + + * gst/isomp4/qtdemux.c: + qtdemux: Use the new helper functions for mapping the colr atom values to colorimetry + +2019-09-10 22:44:20 +0200 Mathieu Duponchelle + + * docs/gst_plugins_cache.json: + docs: update plugin cache + +2019-09-10 22:43:49 +0200 Mathieu Duponchelle + + * gst/smpte/barboxwipes.c: + smpte: don't register transition types twice + +2019-09-08 20:43:17 -0400 Doug Nazar + + * gst/alpha/gstalpha.c: + alpha: Fix one_over_kc calculation + On arm/aarch64, converting from float directly to unsigned int uses + a different opcode and negative numbers result in 0. Cast to + signed int first. + +2019-07-31 16:17:36 +1000 Jan Schmidt + + * gst/multifile/gstsplitmuxsink.c: + * gst/multifile/gstsplitmuxsink.h: + * tests/check/elements/splitmux.c: + splitmux: Add muxer-pad-map property + Add a property which explicitly maps splitmuxsink pads to the + muxer pads they should connect to, overriding the implicit logic + that tries to match pads but yields arbitrary names. + +2019-07-26 02:21:59 +1000 Jan Schmidt + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: In async mode, retain previous muxer pad names. + When running in async-finalize mode, request new pads from the muxer + using the same names as old pads, instead of letting the muxer assign + new ones based on the pad template name. + +2019-07-26 02:13:31 +1000 Jan Schmidt + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: Mark split-* signals as action signals. Doc fixes. + Add the G_SIGNAL_ACTION flag to the split-* signals on splitmuxsink, + and make some improvements to their docstrings + +2019-08-29 22:11:02 +0900 Seungha Yang + + * gst/isomp4/gstqtmux.c: + qtmux: Fix incompatible type warning with MSVC + gstqtmux.c(5582): warning C4133: 'function': + incompatible types - from 'GstVideoMultiviewFlags *' to 'guint *' + +2019-09-02 16:33:05 +0200 Mathieu Duponchelle + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: fix git diff indentation + +2019-08-30 22:42:58 +0200 Mathieu Duponchelle + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: normalize variable to boolean + +2019-08-29 21:29:34 +0200 Mathieu Duponchelle + + * gst/rtsp/gstrtspsrc.c: + * gst/rtsp/gstrtspsrc.h: + rtspsrc: clip output segment on accurate seeks + The output segment is only used in ONVIF mode. + The previous behaviour was to output a segment computed from + the Range response sent by the server. + In ONVIF mode, servers will start serving from the appropriate + synchronization point (keyframe), and the Range in response will + start at that position. + This means rtspsrc can now perform truly accurate seeks in that + mode, by clipping the output segment to the values requested in + the seek. The decoder will then discard out of segment buffers + and playback will start without artefacts at the exact requested + position, similar to the behaviour of a demuxer when an accurate + seek is requested. + +2019-08-30 14:00:26 +1000 Matthew Waters + + * ext/vpx/gstvpxenc.c: + vpx: fix macos werror build + ../ext/vpx/gstvpxenc.c:1723:49: error: format specifies type 'long' but the argument has type 'vpx_codec_pts_t' (aka 'long long') [-Werror,-Wformat] + ", gst frame pts: %" G_GINT64_FORMAT, pkt->data.frame.pts, pts); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~ + /Library/Frameworks/GStreamer.framework/Versions/1.0/include/gstreamer-1.0/gst/gstinfo.h:1065:96: note: expanded from macro 'GST_TRACE_OBJECT' + #define GST_TRACE_OBJECT(obj,...) GST_CAT_LEVEL_LOG (GST_CAT_DEFAULT, GST_LEVEL_TRACE, obj, __VA_ARGS__) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~ + /Library/Frameworks/GStreamer.framework/Versions/1.0/include/gstreamer-1.0/gst/gstinfo.h:646:31: note: expanded from macro 'GST_CAT_LEVEL_LOG' + (GObject *) (object), __VA_ARGS__); \ + ^~~~~~~~~~~ + ../ext/vpx/gstvpxenc.c:1723:70: error: format specifies type 'long' but the argument has type 'vpx_codec_pts_t' (aka 'long long') [-Werror,-Wformat] + ", gst frame pts: %" G_GINT64_FORMAT, pkt->data.frame.pts, pts); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~ + /Library/Frameworks/GStreamer.framework/Versions/1.0/include/gstreamer-1.0/gst/gstinfo.h:1065:96: note: expanded from macro 'GST_TRACE_OBJECT' + #define GST_TRACE_OBJECT(obj,...) GST_CAT_LEVEL_LOG (GST_CAT_DEFAULT, GST_LEVEL_TRACE, obj, __VA_ARGS__) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~ + /Library/Frameworks/GStreamer.framework/Versions/1.0/include/gstreamer-1.0/gst/gstinfo.h:646:31: note: expanded from macro 'GST_CAT_LEVEL_LOG' + (GObject *) (object), __VA_ARGS__); \ + ^~~~~~~~~~~ + +2019-08-30 13:37:59 +1000 Matthew Waters + + * sys/osxvideo/cocoawindow.m: + osxvideosink: call superclass in reshape + Fixes macos werror build + ../sys/osxvideo/cocoawindow.m:437:1: error: method possibly missing a [super reshape] call [-Werror,-Wobjc-missing-super-calls] + } + ^ + +2019-08-23 18:56:01 +0200 Mathieu Duponchelle + + * ext/flac/gstflacdec.c: + * ext/flac/gstflacenc.c: + * ext/lame/gstlamemp3enc.c: + * ext/pulse/pulsesink.c: + * ext/pulse/pulsesrc.c: + * ext/speex/gstspeexdec.c: + * ext/speex/gstspeexenc.c: + * ext/vpx/gstvp8dec.c: + * ext/vpx/gstvp8enc.c: + * ext/vpx/gstvp9dec.c: + * ext/vpx/gstvp9enc.c: + * ext/wavpack/gstwavpackdec.c: + * ext/wavpack/gstwavpackenc.c: + * gst/audiofx/audiofirfilter.c: + * gst/audiofx/audioiirfilter.c: + * gst/isomp4/gstqtmux-doc.c: + * gst/isomp4/gstqtmux.c: + * gst/shapewipe/gstshapewipe.c: + docstrings: port ulinks to markdown links + +2019-08-10 12:33:46 +0100 Tim-Philipp Müller + + * gst/replaygain/gstrganalysis.c: + * gst/replaygain/gstrglimiter.c: + * gst/replaygain/gstrgvolume.c: + replaygain: fix up doc links to defunct replaygain.org website + Fixes #624 + +2019-08-22 00:18:51 +0900 Seungha Yang + + * ext/soup/gstsouphttpsrc.c: + souphttpsrc: Fix incompatible type build warning + gstsouphttpsrc.c(2191): warning C4133: + '=': incompatible types - from 'guint (__cdecl *)(GType)' to 'GstURIType (__cdecl *)(GType)' + +2019-08-19 11:07:56 +0100 Tim-Philipp Müller + + * ext/vpx/gstvpxdec.c: + * ext/vpx/meson.build: + vpx: bump libvpx requirement to 1.5.0 + Was released in Nov 2015. + +2019-08-19 11:03:00 +0100 Tim-Philipp Müller + + * ext/vpx/meson.build: + vpx: avoid confusing meson configure output when checking for vpx versions + Used to print: + |Run-time dependency vpx found: YES 1.7.0 + |Message: libvpx provides VP8 encoder interface (vpx_codec_vp8_cx_algo) + |Message: libvpx provides VP8 decoder interface (vpx_codec_vp8_dx_algo) + |Message: libvpx provides VP9 encoder interface (vpx_codec_vp9_cx_algo) + |Message: libvpx provides VP9 decoder interface (vpx_codec_vp9_dx_algo) + |Dependency vpx found: YES (cached) + |Dependency vpx found: NO found '1.7.0' but need: '>=1.8.0' + |Run-time dependency vpx found: NO (tried pkgconfig and cmake) + We can check the version of the found dep in a way that + doesn't produce this confusing output. + +2019-08-19 07:30:17 +0000 Amr Mahdi + + * gst/wavparse/gstwavparse.c: + wavparse: Fix push mode ignoring audio with a size smaller than segment buffer + In push mode (streaming), if the audio size is smaller than segment buffer size, it would be ignored. + This happens because when the plugin receives an EOS signal while a single audio chunk that is less than the segment buffer size is buffered, it does not + flush this chunk. The fix is to flush the data chunk when it receives an EOS signal and has a single (first) chunk buffered. + How to reproduce: + 1. Run gst-launch with tcp source + ``` + gst-launch-1.0 tcpserversrc port=3000 ! wavparse ignore-length=0 ! audioconvert ! filesink location=bug.wav + ``` + 2. Send a wav file with unspecified data chunk length (0). Attached a test file + ``` + cat test.wav | nc localhost 3000 + ``` + 3. Compare the length of the source file and output file + ``` + ls -l test.wav bug.wav + -rw-rw-r-- 1 amr amr 0 Aug 15 11:07 bug.wav + -rwxrwxr-x 1 amr amr 3564 Aug 15 11:06 test.wav + ``` + The expected length of the result of the gst-lauch pipeline should be the same as the test file minus the headers (44), which is ```3564 - 44 = 3520``` but the actual output length is ```0``` + After the fix: + ``` + ls -l test.wav fix.wav + -rw-rw-r-- 1 amr amr 3520 Aug 15 11:09 fix.wav + -rwxrwxr-x 1 amr amr 3564 Aug 15 11:06 test.wav + ``` + +2019-08-12 18:56:34 +0300 Sebastian Dröge + + * gst/rtp/gstrtpvp8depay.c: + * gst/rtp/gstrtpvp8depay.h: + rtpvp8depay: Add property for waiting until the next keyframe after packet loss + If VP8 is not encoded with error resilience enabled then any packet loss + causes very bad artefacts when decoding and waiting for the next + keyframe instead improves user experience considerably. + +2019-08-06 22:27:40 -0400 Nicolas Dufresne + + * sys/v4l2/ext/types-compat.h: + v4l2: Fix type compatibility issue with glibc 2.30 + From now on, we will use linux/types.h on Linux, and use typedef of the + various flavour of BSD. + Fixes #635 + +2019-08-07 18:29:25 -0400 Mathieu Duponchelle + + * tests/check/gst-plugins-good.supp: + valgrind: suppress Cond error coming from gnutls + taken from https://salsa.debian.org/debian/flatpak/commit/fb4a8dda211c4bc036781f2b0d706266e95ce068 + +2019-07-10 22:07:05 +0300 Mart Raudsepp + + * gst/matroska/matroska-demux.c: + * gst/matroska/matroska-demux.h: + matroska: Provide audio lead-in for some lossy formats + Various audio formats require an audio lead-in to decode it properly. + Most parsers would take care of it, but when a container like matroska is + involved, the demuxer handles the seeking and without its own lead-in + handling would never even pass the lead-in data to the parser. + This commit provides an initial implementation of that for audio/mpeg, + audio/x-ac3 and audio/x-eac3 by calculating the worst case lead-in time + needed from known samplerate, potential lead-in frames need and the + maximum blocksize possible for the format (as we don't parse that out + exactly in matroskademux) and seeking that much earlier in case of + accurate seeks. This is especially important for NLE use-cases with GES. + If accurate seeking to a position that happens to have a video keyframe, + it'll go back to the previous keyframe than needed, but with typical + video files that's the best we can do anyway without falling back to + scanning the clusters, as typically only keyframes are indexed in + Cueing Data. + If the media doesn't have a CUE, then we bisect for the cluster to seek + to with the same modified time as well in case of accurate seeking, + ensuring sufficient lead-in. This code path is typically hit only with + (suboptimal) audio-only matroska files, e.g. when created with ffmpeg, + which doesn't add a CUE for audio-only mkv muxing. + +2019-03-11 15:15:12 +0100 Antonio Ospite + + * tests/check/elements/rtpbin_buffer_list.c: + test: rtpbin_buffer_list: add a test for invalid packets in buffer list + Upstream elements can send all kinds of data in a buffer list, so cover + the case of an invalid RTP packet mixed with valid RTP packets. + +2019-03-11 15:12:03 +0100 Antonio Ospite + + * tests/check/elements/rtpbin_buffer_list.c: + test: rtpbin_buffer_list: add a test for multiplexed RTP and RTCP + RTP and RTCP packets can be muxed together on the same channel (see + RFC5761) and can arrive in the same buffer list. + The GStreamer rtpsession element support RFC5761, so add a test to cover + this case for buffer lists too. + +2019-03-11 15:09:27 +0100 Antonio Ospite + + * tests/check/elements/rtpbin_buffer_list.c: + test: rtpbin_buffer_list: add a test for different timestamps in buffer list + Buffers with different timestamps (e.g. packets belonging to different + frames) can arrive together in the same buffer list, + Add a test to cover this case. + +2019-03-12 15:24:26 +0100 Antonio Ospite + + * tests/check/elements/rtpbin_buffer_list.c: + test: rtpbin_buffer_list: add function to check timestamp + +2019-04-02 18:02:19 +0200 Antonio Ospite + + * tests/check/elements/rtpbin_buffer_list.c: + test: rtpbin_buffer_list: add a test about reordered or duplicated seqnums + +2019-04-02 17:52:54 +0200 Antonio Ospite + + * tests/check/elements/rtpbin_buffer_list.c: + test: rtpbin_buffer_list: add a test for lange jump in seqnums with recovery + +2019-04-02 17:50:35 +0200 Antonio Ospite + + * tests/check/elements/rtpbin_buffer_list.c: + test: rtpbin_buffer_list: add a test for large jump in sequence numbers + +2019-04-02 17:47:27 +0200 Antonio Ospite + + * tests/check/elements/rtpbin_buffer_list.c: + test: rtpbin_buffer_list: add a test for wrapping sequence numbers + +2019-03-11 15:07:08 +0100 Antonio Ospite + + * tests/check/elements/rtpbin_buffer_list.c: + test: rtpbin_buffer_list: add a test for permissible gap in sequence numbers + +2019-03-11 15:03:31 +0100 Antonio Ospite + + * tests/check/elements/rtpbin_buffer_list.c: + test: rtpbin_buffer_list: add a test for the case of failed probation + When a new source fails to pass the probation period (i.e. new packets + have non-consecutive sequence numbers), then no buffer shall be pushed + downstream. Add a test to validate this case. + +2019-03-12 15:23:16 +0100 Antonio Ospite + + * tests/check/elements/rtpbin_buffer_list.c: + test: rtpbin_buffer_list: add function to check sequence number + +2019-04-03 14:46:35 +0200 Antonio Ospite + + * tests/check/elements/rtpbin_buffer_list.c: + test: rtpbin_buffer_list: add test to verify that receiving stats are correct + Add a test to verify that stats about received packets are correct when + using buffer lists in the rtpsession receive path. + Split get_session_source_stats() in two to be able to get stats from + a GstRtpSession object directly. + +2019-02-27 16:17:57 +0100 Antonio Ospite + + * tests/check/elements/rtpbin_buffer_list.c: + test: rtpbin_buffer_list: add a test for buffer lists on the recv path + +2019-02-27 17:03:44 +0100 Antonio Ospite + + * gst/rtpmanager/gstrtpsession.c: + rtpsession: add support for buffer lists on the recv path + The send path in rtpsession processes the buffer list along the way, + sharing info and stats between packets in the same list, because it + assumes that all packets in a buffer list are from the same frame. + However, in the receiving path packets can arrive in all sorts of + arrangements: + - different sources, + - different frames (different timestamps), + - different types (multiplexed RTP and RTCP, invalid RTP packets). + so a more general approach should be used to correctly support buffer + lists in the receive path. + It turns out that it's simpler and more robust to process buffers + individually inside the rtpsession element even if they come in a buffer + list, and then reassemble a new buffer list when pushing the buffers + downstream. + This avoids complicating the existing code to make all functions + buffer-list-aware with the risk of introducing regressions, + To support buffer lists in the receive path and reduce the "push + overhead" in the pipeline, a new private field named processed_list is + added to GstRtpSessionPrivate, it is set in the chain_list handler and + used in the process_rtp callback; this is to achieve the following: + - iterate over the incoming buffer list; + - process the packets one by one; + - add the valid ones to a new buffer list; + - push the new buffer list downstream. + The processed_list field is reset before pushing a buffer list to be on + the safe side in case a single buffer was to be pushed by upstream + at some later point. + NOTE: + The proposed modifications do not change the behavior of the send path. + The process_rtp callback is called in rtpsource.c by the push_rtp + callback (via source_push_rtp) only when the source is not internal. + So even though push_rtp is also called in the send path, it won't end up + using process_rtp in this case because the source would be internal in + the send path. + The reasoning from above may suggest a future refactoring: push_rtp + might be split to better differentiate the send and receive path. + +2019-08-07 10:01:34 -0400 Doug Nazar + + * gst/matroska/matroska-demux.c: + * gst/matroska/matroska-ids.c: + * gst/matroska/matroska-ids.h: + * gst/matroska/matroska-parse.c: + matroska: Handle interlaced field order + +2019-08-07 12:09:46 +0000 Amr Mahdi + + * gst/wavparse/gstwavparse.c: + wavparse: Fix ignoring of last chunk in push mode + In push mode (streaming), if the last audio payload chunk is less than the segment rate buffer size, it would be ignored since the plugin waits until it has at least segment rate bufer size of audio. + The fix is to introduce a flushing flag that indicates that no more audio will be available so that the plugin can recognize this condition and flush the data is has even if it is less + than the desired segment rate buffer size. + +2019-08-06 16:27:37 +0200 Robert Tiemann + + * ext/soup/gstsouphttpsrc.c: + souphttpsrc: Log any error returned by soup_session_send() + +2019-08-07 11:42:21 +0900 luke.lin + + * gst/isomp4/qtdemux.c: + qtdemux: enlarge the maximal atom size + For 8K content, frame size is over 25MB, and cause the negotiation failure. + Enlarge the limitation of QTDEMUX_MAX_ATOM_SIZE to 32MB. + +2019-07-27 04:05:01 +0200 Mathieu Duponchelle + + * gst/rtsp/gstrtspsrc.c: + * gst/rtsp/gstrtspsrc.h: + rtspsrc: expose and implement is-live property + This is useful to support the ONVIF case: when is-live is set to + FALSE and onvif-rate-control is no, the client can control the + rate of delivery and arrange for the server to block and still + keep sending when unblocked, without requiring back and forth + PAUSE / PLAY requests. This enables, amongst other things, fast + frame stepping on the client side. + When is-live is FALSE, we don't use a manager at all. This case + was actually already pretty well handled by the current code. The + standard manager, rtpbin, is simply no longer needed in this case. + Applications can instantiate a downloadbuffer after rtspsrc if + needed. + +2019-07-27 04:03:44 +0200 Mathieu Duponchelle + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: reset_time when flush stopping + +2019-07-12 22:33:08 +0200 Mathieu Duponchelle + + * gst/rtsp/gstrtspsrc.c: + * gst/rtsp/gstrtspsrc.h: + rtspsrc: expose and implement onvif-mode property + Refactor the code for parsing and generating the Range, taking + advantage of existing API in GstRtspTimeRange. + Only use the TCP protocol in that mode, as per the specification. + Generate an accurate segment when in that mode, and signal to the + depayloader that it should not generate its own segment, through + the "onvif-mode" field in the caps, see + + for more information. + Translate trickmode seek flags to their ONVIF representation + Expose an onvif-rate-control property + +2019-07-01 20:38:20 +0200 Mathieu Duponchelle + + * gst/rtsp/gstrtspsrc.c: + * gst/rtsp/gstrtspsrc.h: + rtspsrc: improve handling of rate in seeks + +2019-07-31 21:55:16 +0200 Mathieu Duponchelle + + * gst/rtpmanager/gstrtpfunnel.c: + rtpfunnel: forward correct segment when switching pad + Forwarding a single segment event from the pad that first gets + chained is incorrect: when that first event was sent by an element + such as x264enc, with its offset start, we end pushing out of segment + buffers for the other pad(s). + Instead, everytime the active pad changes, forward the appropriate + segment event. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/1028 + +2019-08-05 19:35:36 +0300 Sebastian Dröge + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: Use new GstRTSPMessage API to set message body from a buffer directly + +2019-04-04 13:17:34 +0200 Antonio Ospite + + * gst/rtpmanager/rtpsource.c: + rtpsource: fix receiver source stats to consider previously queued packets + When it is not clear yet if a packet relative to a source should be + pushed, the packet is put into a queue, this happens in two cases: + - the source is still in probation; + - there is a large jump in seqnum, and it is not clear what + the cause is, future packets will help making a guess. + In either case stats about received packets are not updated at all; and + even if they were, when init_seq() is called it resets all receiver + stats, effectively loosing any possible stat about previously received + packets. + Fix this by taking into account the queued packets and update the stats + when calling init_seq(). + +2019-04-09 10:46:39 +0200 Antonio Ospite + + * gst/rtpmanager/rtpsource.c: + rtpsource: clarify meaning of the octets-sent and octets-received stats + The octets-send and octets-received stats count the payload bytes + excluding RTP and lower level headers, clarify that in the + documentation. + +2019-04-04 13:16:36 +0200 Antonio Ospite + + * gst/rtpmanager/rtpsource.c: + rtpsource: expose field bytes_received in RTPSourceStats + Since commit c971d1a9a (rtpsource: refactor bitrate estimation, + 2010-03-02) bytes_received filed in RTPSourceStats is set but then never + used again, expose it so that it can be used by user code to verify how + many bytes have been received. + +2019-06-21 17:46:36 +0200 Antonio Ospite + + * gst/rtpmanager/rtpsession.c: + * gst/rtpmanager/rtpsource.c: + * gst/rtpmanager/rtpstats.h: + rtpmanager: consider UDP and IP headers in bandwidth calculation + According to RFC3550 lower-level headers should be considered for + bandwidth calculation. + See https://tools.ietf.org/html/rfc3550#section-6.2 paragraph 4: + Bandwidth calculations for control and data traffic include + lower-layer transport and network protocols (e.g., UDP and IP) since + that is what the resource reservation system would need to know. + Fix the source data to accommodate that. + Assume UDPv4 over IP for now, this is a simplification but it's good + enough for now. + While at it define a constant and use that instead of a magic number. + NOTE: this change basically reverts the logic of commit 529f443a6 + (rtpsource: use payload size to estimate bitrate, 2010-03-02) + +2019-08-01 15:02:23 +0900 Seungha Yang + + * gst/isomp4/qtdemux.c: + qtdemux: Use empty-array safe way to cleanup GPtrArray + Fix assertion fail + GLib-CRITICAL **: g_ptr_array_remove_range: assertion 'index_ < rarray->len' failed + +2019-08-01 14:28:04 +0000 Marc Leeman + + * gst/rtp/gstrtpmp4vpay.c: + * gst/rtp/gstrtpmp4vpay.h: + rtpmp4vpay: config-interval -1 send at idr + adjust/port from rtph264pay and allow sending the configuration data at + every IDR + The payloader was stripping the configuration data when the + config-interval was set to 0. The code was written in such a way !(a > + 0) that it stripped the config when it was set at -1 (send config_data + as soon as possible). + This resulted in some MPEG4 streams where no GOP/VOP-I was detected to + be sent out without configuration. + +2019-07-27 14:21:34 -0400 Doug Nazar + + * gst/matroska/matroska-demux.c: + matroskademux: Ignore crc32 element while peeking at cluster. + +2019-07-25 21:21:26 +0530 Guillaume Desmottes + + * ext/gtk/gstgtkglsink.c: + * ext/gtk/gstgtkglsink.h: + gtkglsink: fix crash when widget is resized after element destruction + Prevent _size_changed_cb() to be called after gtkglsink has been finalized. + Fix #632 + +2019-07-26 02:45:51 +0200 Mathieu Duponchelle + + * gst/isomp4/qtdemux.c: + qtdemux: fix reverse playback EOS conditions + In reverse playback, we don't want to rely on the position of the current + keyframe to decide a stream is EOS: the last GOP we push will start with + a keyframe, which position is likely to be outside of the segment. + Instead, let the normal seek_to_previous_keyframe mechanism do its job, + it works just fine. + +2019-07-23 01:42:02 +0200 Mathieu Duponchelle + + * gst/isomp4/qtdemux.c: + qtdemux: fix key unit seek corner case + If a key unit seek is performed with a time position that matches + the offset of a keyframe, but not its actual PTS, we need to + adjust the segment nevertheless. + For example consider the following case: + * stream starts with a keyframe at 0 nanosecond, lasting 40 milliseconds + * user does a key unit seek at 20 milliseconds + * we don't adjust the segment as the time position is "over" a keyframe + * we push a segment that starts at 20 milliseconds + * we push a buffer with PTS == 0 + * an element downstream (eg rtponviftimestamp) tries to calculate the + stream time of the buffer, fails to do so and drops it + +2019-07-25 15:08:54 +0300 Sebastian Dröge + + * ext/jpeg/gstjpegdec.c: + jpegdec: Don't dereference NULL input state if we have no caps in TIME segments + Simply assume that the JPEG frame is not going to be interlaced instead + of crashing. + +2019-07-22 10:28:50 +0200 Knut Andre Tidemann + + * gst/rtp/gstrtpopuspay.c: + rtp: opuspay: fix memory leak in gst_rtp_opus_pay_setcaps. + The src caps were never dereferenced, causing a memory leak. + +2019-07-12 20:51:44 +0200 Mathieu Duponchelle + + * gst/isomp4/qtdemux.c: + * gst/isomp4/qtdemux.h: + qtdemux: implement support for trickmode interval + When the seek event contains a (newly-added) trickmode interval, + and TRICKMODE_KEY_UNITS was requested, only let through keyframes + separated with the required interval + +2019-07-17 19:12:19 +0530 Nirbheek Chauhan + + * docs/meson.build: + meson: Don't generate doc cache when no plugins are enabled + Fixes gst-build with -Dauto-features=disabled + +2019-07-15 23:24:05 +0900 Seungha Yang + + * gst/matroska/matroska-demux.c: + * gst/matroska/matroska-mux.c: + matroska: Port to color_{primaries,transfer,matrix}_to_iso + ... and remove duplicated code. + +2019-05-25 22:08:05 +1000 Jan Schmidt + + * gst/multifile/gstsplitmuxsink.c: + * gst/multifile/gstsplitmuxsink.h: + * tests/check/elements/splitmux.c: + splitmuxsink: add the ability to mux auxilliary video streams + The primary video stream is used to select fragment cut points + at keyframe boundaries. Auxilliary video streams may be + broken up at any packet - so fragments may not start with a keyframe + for those streams. + +2019-06-11 23:17:30 +1000 Jan Schmidt + + * gst/multifile/gstsplitmuxsrc.c: + splitmuxsrc: Add video_%d pad template. + splitmuxsrc actually supports multiple video pads. Make that clear, + especially since it was already creating pads named "video_0" etc. + +2019-07-09 23:12:45 +0200 Mathieu Duponchelle + + * gst/isomp4/qtdemux.c: + qtdemux: fix conditions for end of segment in reverse playback + The time_position field of the stream is offset by the media_start + of its QtDemuxSegment compared to the start of the GstSegment of + the demuxer, take it into account when making comparisons. + +2019-07-09 23:06:12 +0900 Seungha Yang + + * gst/matroska/matroska-demux.c: + matroskademux: Fix mismatched transfer characteristic + TransferCharacteristics(18) should be ARIB STD-B67 (HLG) + See https://www.webmproject.org/docs/container/#TransferCharacteristics + Also map more color primaries indexes which have been handled by matroska-mux. + +2019-07-09 19:49:57 +0900 Seungha Yang + + * sys/v4l2/gstv4l2transform.c: + * sys/v4l2/gstv4l2videodec.c: + * sys/v4l2/gstv4l2videoenc.c: + v4l2: Remove misleading comments + gst_pad_template_new() does not take ownership of the caps + +2019-01-23 18:27:06 -0500 Olivier Crête + + * tests/check/elements/rtpsession.c: + rtp session: Add test for collision loopback detection + Ignore further collisions if the remote SSRC change with ours, it's + probably because someone is sending us back the packets we send out. + +2019-01-23 18:14:23 -0500 Olivier Crête + + * tests/check/elements/rtpsession.c: + rtpsession tests: Add test for third-party collision detection + Add tests to validate the code that ignores the same packets coming + from 2 different sources (an third-party collision). + +2019-01-23 17:19:15 -0500 Olivier Crête + + * tests/check/elements/rtpsession.c: + rtpsession: Add test for collision on incoming packets + Make sure that the collision is properly detected on incoming packets. + +2019-01-23 17:09:27 -0500 Olivier Crête + + * tests/check/elements/rtpsession.c: + rtpsession test: Verify that on-ssrc-collision message is emitted + +2019-01-23 16:58:22 -0500 Olivier Crête + + * gst/rtpmanager/rtpsession.c: + * tests/check/elements/rtpsession.c: + rtpsession: Also send conflict event when sending packet + If the conflict is detected when sending a packet, then also send an + upstream event to tell the source to reconfigure itself. + Also ignore the collision if we see more than one collision from the same + remote source to avoid problems on loops. + +2019-04-15 16:32:03 -0700 Song Bing + + * sys/v4l2/gstv4l2transform.c: + v4l2transform: set right buffer count. + Set right buffer count to avoid one buffer. + +2019-06-27 19:47:41 -0400 Olivier Crête + + * gst/rtp/gstrtph265pay.c: + * gst/rtp/gstrtph265pay.h: + * tests/check/elements/rtph265.c: + rtph265pay: Also immediately send packet if it is a suffix NAL + Immediately send packet if it contains any suffix NAL, this is required + in case they come after the VCL nal to not have to wait until the next frame. + +2019-06-27 19:46:01 -0400 Olivier Crête + + * gst/rtp/gstrtph265pay.c: + rtph265pay: Don't drop second byte of NAL header + At least keep 2 bytes per NAL even if the second one is 0, the + second byte of the NAL header could very well be 0. + +2019-06-26 16:42:44 -0400 Olivier Crête + + * gst/rtp/gstrtph264pay.c: + * gst/rtp/gstrtph265pay.c: + rtph26xpay: Avoid print when there is no bundle at end of packet + +2019-06-26 16:25:01 -0400 Olivier Crête + + * gst/rtp/gstrtph264pay.c: + * gst/rtp/gstrtph265pay.c: + * tests/check/elements/rtp-payloading.c: + * tests/check/elements/rtph264.c: + * tests/check/elements/rtph265.c: + rtph26xpay: Wait until there is a VCL or suffix NAL to send + With unit tests. + +2019-06-19 17:16:03 -0400 Olivier Crête + + * tests/check/elements/rtph265.c: + rtph265pay test: Add unit tests for aggregation + +2019-06-18 19:07:38 -0400 Olivier Crête + + * gst/rtp/gstrtph265pay.c: + * gst/rtp/gstrtph265pay.h: + * tests/check/elements/rtp-payloading.c: + * tests/check/elements/rtph265.c: + rtph265pay: Implement Aggregation packets + Align with rtph264pay + +2019-06-18 15:03:09 -0400 Olivier Crête + + * tests/check/elements/rtph264.c: + rtph264pay test: Add unit tests for aggregation + +2019-06-18 13:45:15 -0400 Olivier Crête + + * gst/rtp/gstrtph264pay.c: + * gst/rtp/gstrtph264pay.h: + rtph264pay: Report latency when in maximal aggregation mode + +2019-06-17 11:31:53 -0400 Olivier Crête + + * gst/rtp/gstrtph264pay.c: + * gst/rtp/gstrtph264pay.h: + * tests/check/elements/rtph264.c: + rtph264pay: Default to not adding latency when aggregating + Send the bundle as soon as there is one VCL unit in the packet at + the end of an incoming buffer. + The DELTA_UNIT flag is not reliable, so ignore it. + +2019-06-14 16:54:23 -0400 Olivier Crête + + * tests/check/elements/rtp-payloading.c: + rtp-payloading test: Fix working to 1.0 buffers instead of groups + +2019-06-13 18:07:35 -0400 Olivier Crête + + * gst/rtp/gstrtph264pay.c: + * gst/rtp/gstrtph265pay.c: + rtph265pay: Replace fragmentation while-loop with for-loop + Align with rtph264pay + +2019-06-13 17:42:05 -0400 Olivier Crête + + * gst/rtp/gstrtph265pay.c: + rtph265pay: Rename payload_len to max_fragment_size + Align to rtph264pay + +2019-06-13 17:30:08 -0400 Olivier Crête + + * gst/rtp/gstrtph265pay.c: + rtph265pay: Clean up _payload_nal + Move determining whether we need to fragment at all into the + fragmenter. + Align with rtph264pay + +2019-06-13 17:23:26 -0400 Olivier Crête + + * gst/rtp/gstrtph265pay.c: + rtph265pay: Extract sending fragments into _payload_nal_fragment + Align with rtph264pay + +2019-06-13 16:22:57 -0400 Olivier Crête + + * gst/rtp/gstrtph265pay.c: + rtph265pay: Extract sending a single packet into _payload_nal_single + Align with rtph264pay + +2019-06-13 16:14:31 -0400 Olivier Crête + + * gst/rtp/gstrtph265pay.c: + rtph265pay: Define and use FU_A_TYPE_ID + Align with rtph264pay + +2019-06-13 16:08:37 -0400 Olivier Crête + + * gst/rtp/gstrtph265pay.c: + rtph265pay: Use snake_case variables + Align with rtph264pay + +2019-06-13 16:04:39 -0400 Olivier Crête + + * gst/rtp/gstrtph265pay.c: + rtph265pay: Clean up whitespace and syntax + Align with rtph264pay + +2018-07-03 19:39:25 +0200 Jan Alexander Steffens (heftig) + + * gst/rtp/gstrtph264pay.c: + * gst/rtp/gstrtph264pay.h: + * tests/check/elements/rtp-payloading.c: + * tests/check/elements/rtph264.c: + rtph264pay: Support STAP-A bundling + Add a new property "do-aggregate"* to the H.264 RTP payloader which + enables STAP-A aggregation as per [RFC-6184][1]. With aggregation enabled, + packets are bundled instead of sent immediately, up until the MTU size. + Bundles also end at access unit boundaries or when packets have to be + fragmented. + *: The property-name is kept generic since it might apply more widely, + e.g. STAP-B or MTAP. + [1]: https://tools.ietf.org/html/rfc6184#section-5.7 + Closes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/434 + +2018-11-05 17:15:39 +0100 Jan Alexander Steffens (heftig) + + * gst/rtp/gstrtph264pay.c: + rtph264pay: Fix delta-unit/discont handling when injecting SPS/PPS + Apply the wanted delta-unit and discont to the first packet; following + packets for this frame are always delta units and not discont. + +2018-11-05 19:03:45 +0100 Jan Alexander Steffens (heftig) + + * gst/rtp/gstrtph264pay.c: + rtph264pay: Replace fragmentation while-loop with for-loop + +2018-11-05 18:57:38 +0100 Jan Alexander Steffens (heftig) + + * gst/rtp/gstrtph264pay.c: + rtph264pay: Calculate the right max_fragments + +2018-11-05 18:36:35 +0100 Jan Alexander Steffens (heftig) + + * gst/rtp/gstrtph264pay.c: + rtph264pay: Rename payload_len to max_fragment_size + +2018-11-05 18:34:40 +0100 Jan Alexander Steffens (heftig) + + * gst/rtp/gstrtph264pay.c: + rtph264pay: Clean up _payload_nal_fragment + +2018-11-05 18:06:19 +0100 Jan Alexander Steffens (heftig) + + * gst/rtp/gstrtph264pay.c: + rtph264pay: Clean up _payload_nal + Move determining whether we need to fragment at all into the fragmenter. + +2018-11-05 18:04:13 +0100 Jan Alexander Steffens (heftig) + + * gst/rtp/gstrtph264pay.c: + rtph264pay: Clean up _payload_nal_single + +2018-11-05 17:55:23 +0100 Jan Alexander Steffens (heftig) + + * gst/rtp/gstrtph264pay.c: + rtph264pay: Extract sending fragments into _payload_nal_fragment + +2018-11-05 17:49:52 +0100 Jan Alexander Steffens (heftig) + + * gst/rtp/gstrtph264pay.c: + rtph264pay: Extract sending a single packet into _payload_nal_single + +2018-11-05 17:10:03 +0100 Jan Alexander Steffens (heftig) + + * gst/rtp/gstrtph264pay.c: + rtph264pay: Define and use FU_A_TYPE_ID + +2018-11-05 17:07:06 +0100 Jan Alexander Steffens (heftig) + + * gst/rtp/gstrtph264pay.c: + rtph264pay: Use snake_case variables + +2018-11-05 17:04:14 +0100 Jan Alexander Steffens (heftig) + + * gst/rtp/gstrtph264pay.c: + rtph264pay: Clean up whitespace and syntax + +2019-06-06 16:05:31 -0400 Olivier Crête + + * gst/rtpmanager/gstrtpjitterbuffer.c: + * gst/rtpmanager/rtpjitterbuffer.c: + * gst/rtpmanager/rtpjitterbuffer.h: + rtpjitterbuffer: Unlock output if the queue is full + +2019-06-29 23:17:28 -0600 Thomas Bluemel + + * gst/rtpmanager/gstrtpjitterbuffer.c: + * gst/rtpmanager/rtpjitterbuffer.c: + rtpjitterbuffer: Ignore unsolicited rtx packets. + If an rtx packet arrives that hasn't been requested (it might + have been requested from prior to a reset), ignore it so that + it doesn't inadvertently trigger a clock skew. + +2019-06-29 23:16:44 -0600 Havard Graff + + * tests/check/elements/rtpjitterbuffer.c: + rtpjitterbuffer: Add unit test for unsolicited rtx affecting skew + +2019-06-13 15:45:28 -0600 Thomas Bluemel + + * gst/rtpmanager/gstrtpjitterbuffer.c: + * gst/rtpmanager/rtpjitterbuffer.c: + * gst/rtpmanager/rtpjitterbuffer.h: + * tests/check/elements/rtpbin.c: + * tests/check/elements/rtpjitterbuffer.c: + rtpjitterbuffer: Only calculate skew or reset if no gap. + In the case of reordered packets, calculating skew would cause + pts values to be off. Only calculate skew when packets come + in as expected. Also, late RTX packets should not trigger + clock skew adjustments. + Fixes #612 + +2019-07-02 21:21:05 +0300 Mart Raudsepp + + * gst/isomp4/qtdemux.c: + qtdemux: Provide a 30 frames lead-in for MP3 + mpegaudioparse suggests MP3 needs 10 or 30 frames of lead-in (depending on + mpegaudioversion, which we don't know here), thus provide at least 30 frames + lead-in for such cases as a followup to commit cbfa4531ee5ef. + +2019-05-24 10:31:39 -0400 Olivier Crête + + * gst/rtpmanager/gstrtpjitterbuffer.c: + rtpjitterbuffer: max-dropout-time gets cast to int32 + So any value over MAXINT32 gets considered as negative and is silently ignored. + +2019-07-02 13:00:32 +0200 Mathieu Duponchelle + + * gst/isomp4/qtdemux.c: + qtdemux: do_seek can never be called with a NULL event + +2019-07-01 22:38:41 +0200 Mathieu Duponchelle + + * gst/isomp4/qtdemux.c: + qtdemux: only adjust segment time when adjusting segment start + We ended up setting segment.time to segment.position when doing + reverse playback, which is obviously wrong. + +2019-07-01 13:54:13 +0200 Mathieu Duponchelle + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: unref the event in element seek handler + +2019-06-29 00:25:26 +0200 Mathieu Duponchelle + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: handle seek event on the element + Without this, the user has to wait for rtspsrc to have sent a PLAY + request and exposed its pads before seeking it. + +2019-06-26 18:03:29 -0400 Nicolas Dufresne + + * gst/udp/gstmultiudpsink.c: + multiudpsink: Add missing socket.h include + Without this include, macro like SO_BINDTODEVICE is not visible and + associated feature gets out-compiled. This also affects the support for + SO_SNDBUF. + +2019-06-24 17:35:15 +0200 Jan Alexander Steffens (heftig) + + * gst/flv/gstflvmux.c: + flvmux: Clear new_tags if sending metadata in header + This avoids sending an additional metadata object right after the + headers. + +2018-06-13 14:55:29 -0700 Song Bing + + * sys/v4l2/gstv4l2videodec.c: + v4l2videodec: Fix drain() function return type + Return right type for drain() function. + +2019-06-24 14:28:39 +0300 Mart Raudsepp + + * gst/audioparsers/gstaacparse.c: + * gst/audioparsers/gstac3parse.c: + * gst/audioparsers/gstamrparse.c: + * gst/audioparsers/gstdcaparse.c: + * gst/audioparsers/gstsbcparse.c: + * gst/audioparsers/gstwavpackparse.c: + audioparsers: add back segment clipping to parsers that have lost it + The pre_push_frame default clipping behaviour was introduced in 2010 + with commit 30be03004e82 and modified with commit 4163969a2422 in 2011, + when most parsers didn't implement a pre_push_frame yet. Not having it + meant that clipping was done by default. Those that did implement a + pre_push_frame (flacparse and mpegaudioparse) at the time, had the flag + adjusted as part of the 2011 refactor work. + All other parsers got a pre_push_frame vfunc implementation only in + 2013, but seem to have forgot to keep the clipping behaviour, as + was done automatically when a pre_push_frame implementation doesn't + exist for the parser. aacparse lost it with commit 91d4abcea in + July 2013; the others in Dec 2013 as part of AUDIO_CODEC tag posting + in commits 6f89b430e, d2ab5199b, 29f2cae12, 753d3c23a and 292780574. + +2019-06-24 09:42:31 +0000 Tim-Philipp Müller + + * sys/v4l2/gstv4l2codec.c: + v4l2: fix compiler warning due to c99-ism + +2019-06-19 14:28:28 +0200 Jan Alexander Steffens (heftig) + + * tests/check/elements/flvmux.c: + test: flvmux: Test changing caps with one sinkpad + These tests segfault without the preceding crash fix. + +2019-06-19 14:08:06 +0200 Jan Alexander Steffens (heftig) + + * tests/check/elements/flvmux.c: + test: flvmux: Use gst_harness_sink_push_many + And check its return value. + +2019-06-19 12:31:46 +0200 Jan Alexander Steffens (heftig) + + * gst/flv/gstflvmux.c: + flvmux: Simplify an if-else chain + Merge the identical branches and turn the condition around to make it + easier to read. + +2019-06-19 12:28:22 +0200 Jan Alexander Steffens (heftig) + + * gst/flv/gstflvmux.c: + flvmux: Avoid crash when changing caps without both streams + mux->video_pad and mux->audio_pad can be NULL if the corresponding pad + has not been requested. + +2019-06-12 15:57:48 +0300 Sebastian Dröge + + * gst/rtp/gstrtpgstpay.c: + rtpgstpay: Send caps anyway if caps are pending in the adapter but are different from the new ones + Otherwise it can happen that we receive a caps event, then another caps + event and only then buffers. We would then send out the first caps event + in the stream but mark buffers with the caps version of the second caps + event. + +2019-06-12 14:57:24 +0300 Sebastian Dröge + + * gst/rtp/gstrtpgstdepay.c: + * gst/rtp/gstrtpgstdepay.h: + rtpgstdepay: Only store the current caps and drop old caps immediately + Otherwise it can happen that we already collected 7 caps, miss the 8th + caps packet (packet loss) and then re-use the 1st caps for the following + buffers instead of the 8th caps which will likely cause errors further + downstream unless both caps are accidentally the same. + Keeping old caps around does not seem to have any value other than + potentially causing errors. We would always receive new caps whenever + they change (even if they were previous ones) and it's very unlikely + that they happen to be exactly the same as the previous ones. + Also after having received new caps or a buffer with a next caps + version, no buffers with old caps version will arrive anymore. + +2019-06-15 02:00:43 +1000 Jan Schmidt + + * gst/rtpmanager/rtpjitterbuffer.c: + rtpjitterbuffer: Clear clock master before unreffing + Make sure to clear any master clock on the media_clock + before unreffing it to release the timer callback that's + updating the clock and keeping it reffed. + +2019-06-16 11:07:31 +1000 Jan Schmidt + + * gst/matroska/matroska-ids.c: + matroska: Initialise a video_context field to satisfy valgrind + Clear the mastering_display_info_present field explicitly + after reallocating the track context into a video context + to avoid uninitialised warnings in valgrind + +2019-06-14 17:34:31 -0400 Thibault Saunier + + * gst/multifile/gstmultifilesink.c: + docs: Fix link to strings + We can't link to #gchar* this way. + +2019-06-14 00:17:22 +0200 Mathieu Duponchelle + + * gst/rtpmanager/gstrtpjitterbuffer.c: + * tests/check/elements/rtpjitterbuffer.c: + jitterbuffer: unset DTS on output buffers + +2019-05-22 21:40:52 +0200 Mathieu Duponchelle + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: set the same seqnum on flush_start / flush_stop + It's currently not made mandatory by aggregator, but it might + eventually be, and is more consistent behaviour + See https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/977 + +2019-06-13 11:55:04 +0200 Mikhail Fludkov + + * gst/rtpmanager/gstrtpjitterbuffer.c: + * tests/check/elements/rtpjitterbuffer.c: + rtpjitterbuffer: late packets shouldn't affect PTS of the following packet + If, say, a rtx-packet arrives really late, this can have a dramatic + effect on the jitterbuffer clock-skew logic, having it being reset + and losing track of the current dts-to-pts calculations, directly affecting + the packets that arrive later. + This is demonstrated in the test, where a RTX packet is pushed in really + late, and without this patch the last packet will have its PTS affected + by this, where as a late RTX packet should be redundant information, and + not affect anything. + +2019-06-12 10:47:39 +0200 Mikhail Fludkov + + * gst/rtpmanager/gstrtpjitterbuffer.c: + * tests/check/elements/rtpjitterbuffer.c: + rtpjitterbuffer: fix rtx delay calulation when large packet spacing + +2016-11-24 18:18:01 +0100 Stian Selnes + + * gst/rtpmanager/gstrtpjitterbuffer.c: + * tests/check/elements/rtpjitterbuffer.c: + rtpjitterbuffer: Fix delay for EXPECTED timers added by gaps + This patch corrects the delay set on EXPECTED timers that are added when + processing gaps. Previously the delay could be too small so that + 'timout + delay' was much less than 'now', causing the following retries + to be scheduled too early. (They were sent earlier than + rtx-retry-timeout after the previous timeout.) + +2018-11-20 16:11:12 +0100 Havard Graff + + * gst/rtpmanager/rtpstats.c: + * tests/check/elements/rtpjitterbuffer.c: + rtpjitterbuffer: don't try and calculate packet-rate if seqnum are jumping + Turns out that the "big-gap"-logic of the jitterbuffer has been horribly + broken. + For people using lost-events, an RTP-stream with a gap in sequencenumbers, + would produce exactly that many lost-events immediately. + So if your sequence-numbers jumped 20000, you would get 20000 lost-events + in your pipeline... + The test that looks after this logic "test_push_big_gap", basically + incremented the DTS of the buffer equal to the gap that was introduced, + so that in fact this would be more of a "large pause" test, than an + actual gap/discontinuity in the sequencenumbers. + Once the test was modified to not increment DTS (buffer arrival time) with + a similar gap, all sorts of crazy started happening, including adding + thousands of timers, and the logic that should have kicked in, the + "handle_big_gap_buffer"-logic, was not called at all, why? + Because the number max_dropout is calculated using the packet-rate, and + the packet-rate logic would, in this particular test, report that + the new packet rate was over 400000 packets per second!!! + I believe the right fix is to don't try and update the packet-rate if + there is any jumps in the sequence-numbers, and only do these calculations + for nice, sequential streams. + +2019-06-12 11:16:22 +0200 Havard Graff + + * tests/check/elements/rtpjitterbuffer.c: + rtpjitterbuffer: fix unused variables + +2019-06-12 02:42:42 +1000 Jan Schmidt + + * gst/multifile/gstsplitmuxsrc.c: + splitmuxsrc: Protect initial pad configuration with the object lock + gst_splitmux_src_activate_part() configures the pad information + before starting the pad task, but occasionally the changes it makes + to the pad are not seen in the pad task because they're not + protected by the right locking. Use the pad's object lock to + protect those variables. + +2019-06-12 01:42:20 +1000 Jan Schmidt + + * gst/multifile/gstsplitmuxsrc.c: + splitmuxsrc: Restart pad task on a reconfigure + On a reconfigure event, restart streaming on the pad so + that switching tracks in playbin works cleanly + +2019-06-11 18:40:09 +1000 Jan Schmidt + + * gst/multifile/gstsplitmuxsrc.c: + * gst/multifile/gstsplitmuxsrc.h: + splitmuxsrc: Use an RW lock instead of a mutex to protect the pad list + Fix a deadlock around the pads list by using an RW lock to + allow simultaneous readers. The pad list doesn't really changes + except at startup and shutdown. + +2019-06-11 23:18:24 +1000 Jan Schmidt + + * gst/multifile/gstsplitmuxsrc.c: + splitmuxsrc: Ignore duplicate seeks + Use the seqnum to ignore duplicated seek events. + +2019-05-29 09:20:07 +1000 Jan Schmidt + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: Improve debug output + Make the debug output less confusing by not mentioning a src + pad when doing calculations on the sink pad side. + Improve debug around why a GOP is considered overflowing a fragment + +2019-05-29 09:20:07 +1000 Jan Schmidt + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: Give internal queues useful names + Makes debug output more useful + +2019-06-05 23:13:33 +0300 Mart Raudsepp + + * gst/isomp4/qtdemux.c: + qtdemux: Provide a 2 frames lead-in for audio decoders + AAC and various other audio codecs need a couple frames of lead-in to + decode it properly. The parser elements like aacparse take care of it + via gst_base_parse_set_frame_rate, but when inside a container, the + demuxer is doing the seek segment handling and never gives lead-in + data downstream. + Handle this similar to going back to a keyframe with video, in the + same place. Without a lead-in, the start of the segment is silence, + when it shouldn't, which becomes especially evident in NLE use cases. + +2019-05-28 20:14:49 +0300 Mart Raudsepp + + * gst/isomp4/qtdemux.c: + qtdemux: remove indent exception and reindent + As the indent disabling isn't playing along for a following fix, + remove the indent disabling and reindent in a way that doesn't + look too stupid. + +2019-03-08 14:43:20 +0000 Philippe Normand + + * sys/v4l2/gstv4l2h264codec.c: + v4l2: Fix H.264 level 3 string representation + The string_to_level function handles "3" so the level_to_string function should + do the same, to prevent caps negotiation issues. + +2019-03-04 11:05:29 +0000 Philippe Normand + + * sys/v4l2/Makefile.am: + * sys/v4l2/gstv4l2.c: + * sys/v4l2/gstv4l2codec.c: + * sys/v4l2/gstv4l2codec.h: + * sys/v4l2/gstv4l2fwhtenc.c: + * sys/v4l2/gstv4l2h263enc.c: + * sys/v4l2/gstv4l2h264codec.c: + * sys/v4l2/gstv4l2h264codec.h: + * sys/v4l2/gstv4l2h264enc.c: + * sys/v4l2/gstv4l2h264enc.h: + * sys/v4l2/gstv4l2h265codec.c: + * sys/v4l2/gstv4l2h265codec.h: + * sys/v4l2/gstv4l2h265enc.c: + * sys/v4l2/gstv4l2h265enc.h: + * sys/v4l2/gstv4l2jpegenc.c: + * sys/v4l2/gstv4l2mpeg4codec.c: + * sys/v4l2/gstv4l2mpeg4codec.h: + * sys/v4l2/gstv4l2mpeg4enc.c: + * sys/v4l2/gstv4l2mpeg4enc.h: + * sys/v4l2/gstv4l2videodec.c: + * sys/v4l2/gstv4l2videodec.h: + * sys/v4l2/gstv4l2videoenc.c: + * sys/v4l2/gstv4l2videoenc.h: + * sys/v4l2/gstv4l2vp8codec.c: + * sys/v4l2/gstv4l2vp8codec.h: + * sys/v4l2/gstv4l2vp8enc.c: + * sys/v4l2/gstv4l2vp8enc.h: + * sys/v4l2/gstv4l2vp9codec.c: + * sys/v4l2/gstv4l2vp9codec.h: + * sys/v4l2/gstv4l2vp9enc.c: + * sys/v4l2/gstv4l2vp9enc.h: + * sys/v4l2/meson.build: + v4l2: Profile and level probing support for encoders and decoders + There used to be some profile/level support in encoders. This code was moved to + GstV4l2Codecs and is now also used for decoders. The caps templates for the + H.264, H.265, MPEG4, VP8 and VP9 encoders and decoders should now reflect the + profiles and levels advertised by the kernel. + +2019-06-03 16:21:12 -0400 Aaron Boxer + + * gst/matroska/matroska-mux.c: + matroskamux: fix typo in property description + +2019-06-04 13:39:00 -0400 Nicolas Dufresne + + * tests/check/gst-plugins-good.supp: + supp: Ignore leaks caused by shout/sethostent + sethostent() seems to be using a global state and we endup with leaks from + that API when called through shout_init(). We had the option to only + ignore the shout case, but the impression is that if we have shout and + another sethostend user, as it's a global state, we may endup with a + different stack trace for the same leak. So in the end, we just ignore + memory allocated by sethostent in general. + +2019-04-30 17:28:25 -0400 Thibault Saunier + + * ext/pulse/pulsedeviceprovider.c: + pulse-device: Hide the alsa device provider if we provide alsa devices + +2019-05-21 15:25:03 -0400 Nicolas Dufresne + + * gst/rtpmanager/gstrtpssrcdemux.c: + * tests/check/elements/rtpssrcdemux.c: + rtpssrcdemux: Avoid taking streamlock out-of-band + In this change we now protect the internal srcpads list using the + stream lock and limit usage of the internal stream lock to + preventing data flowing on the other src pad type while creating + and signalling the new pad. + This fixes a deadlock with RTPBin shutdown lock. These two locks would + end up being taken in two different order, which caused a deadlock. More + generally, we should not rely on a streamlock when handling out-of-band + data, so as a side effect, we should not take a stream lock when + iterating internal links. + +2019-05-27 18:08:54 +0900 Damian Hobson-Garcia + + * sys/v4l2/gstv4l2object.c: + v4l2object: Orphan buffer pool on object_stop if supported + Use V4L2 buffer orphaning, on recent kernels so that + the device can be restarted immediately with + a new buffer pool during renogatiation. + +2019-05-30 13:12:31 +0900 Damian Hobson-Garcia + + * sys/v4l2/gstv4l2bufferpool.c: + v4l2bufferpool: Free orphaned allocator resources when buffers are released + Allocator resources cannot be freed when a buffer pool is orphaned + while its buffers are in use. They should, however, be freed once those + buffers are no longer needed. This patch disposes of any buffers + belonging to an orphaned pool as they are released, and makes sure + that the allocator is cleaned up when the last buffer is returned. + +2019-05-30 11:13:07 +0900 Damian Hobson-Garcia + + * sys/v4l2/gstv4l2bufferpool.c: + v4l2bufferpool: return TRUE when buffer pool orphaning succeeds + When trying to orphan a buffer pool, successfully return and unref + the pool when the pool is either successfully stopped or orphaned. + Indicate failure and leave the pool untouched otherwise. + +2019-05-31 23:04:11 +0200 Niels De Graef + + * configure.ac: + * gst/udp/gstmultiudpsink.c: + * gst/udp/gstmultiudpsink.h: + * gst/udp/gstudpsrc.c: + * meson.build: + meson: Bump minimal GLib version to 2.44 + This means we can use some newer features and get rid of some + boilerplate code using the G_DECLARE_* macros. + As discussed on IRC, 2.44 is old enough by now to start depending on it. + +2018-09-05 21:10:51 +0300 Sebastian Dröge + + * gst/isomp4/gstqtmux.c: + * gst/isomp4/gstqtmux.h: + qtmux: Use size of first closed caption buffer in prefill mode + It must be accurate for all samples to work in Final Cut properly, so + the best we can do is to assume that all samples are the same as the + first. Bigger samples are truncated, smaller samples are padded. + +2019-05-29 22:06:58 +0200 Mathieu Duponchelle + + * docs/meson.build: + * ext/lame/gstlamemp3enc.c: + * ext/mpg123/gstmpg123audiodec.c: + * ext/taglib/gstapev2mux.cc: + * ext/taglib/gstid3v2mux.cc: + * ext/twolame/gsttwolamemp2enc.c: + * gst/autodetect/gstautoaudiosink.c: + * gst/autodetect/gstautoaudiosrc.c: + * gst/autodetect/gstautovideosink.c: + * gst/autodetect/gstautovideosrc.c: + * gst/dtmf/gstdtmfsrc.c: + * gst/dtmf/gstrtpdtmfdepay.c: + * gst/dtmf/gstrtpdtmfsrc.c: + * gst/level/gstlevel.c: + * gst/rtp/gstrtpL8depay.c: + * gst/rtp/gstrtpL8pay.c: + * gst/rtp/gstrtpreddec.c: + * gst/rtp/gstrtpredenc.c: + * gst/rtp/gstrtpulpfecdec.c: + * gst/rtp/gstrtpulpfecenc.c: + * gst/spectrum/gstspectrum.c: + * sys/v4l2/gstv4l2object.c: + doc: remove xml from comments + +2019-05-29 11:02:26 +0100 Tim-Philipp Müller + + * docs/gst_plugins_cache.json: + docs: update plugins cache + And add gtk+ and qt plugins + +2019-05-29 10:58:40 +0100 Tim-Philipp Müller + + * ext/dv/meson.build: + * ext/gtk/meson.build: + * ext/qt/meson.build: + * sys/osxaudio/meson.build: + * sys/osxvideo/meson.build: + * sys/waveform/meson.build: + dv, gtk, qt, osxaudio, osxvideo, waveform: add to plugins list + Makes sure the paths for these plugins are included in the + uninstalled plugin paths list. And also for the docs. + Fixes #604 + +2019-04-18 15:31:00 +0300 Sebastian Dröge + + * gst/matroska/matroska-mux.c: + * gst/matroska/matroska-mux.h: + matroskamux: Add new property to offset all streams to start at zero + This takes the timestamp of the earliest stream and offsets it so that + it starts at 0. Some software (VLC, ffmpeg-based) does not properly + handle Matroska files that start at timestamps much bigger than zero. + Closes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/449 + +2019-05-28 14:13:56 +0100 Tim-Philipp Müller + + * gst/rtp/gstrtpmp4gdepay.c: + * gst/rtp/gstrtpmp4gdepay.h: + rtpmp4gdepay: don't spam debug log for broken ADTS-in-RTP AAC + Print warning only once. + +2019-05-22 18:06:04 +0300 Sebastian Dröge + + * gst/multifile/gstsplitmuxsink.c: + splitmuxsink: Only set running time on finalizing sink element when in async-finalize mode + There is only a single sink element in async-finalize mode, and we would + keep the running time from previous fragments set in that case. As we + don't ever set the running time for the very last fragment on EOS, this + would mean that the closing time reported for the very last fragment is + the same as the closing time of the previous fragment. + +2015-03-26 13:08:32 -0400 Nicolas Dufresne + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: Remove uneeded keep-alive hack + The rtsp connection code has been fixed now. + https://bugzilla.gnome.org/show_bug.cgi?id=744209 + +2019-05-26 17:46:06 +0300 Vivia Nikolaidou + + * gst/rtpmanager/gstrtpjitterbuffer.c: + rtpjitterbuffer: Print GstClockTimeDiff as GST_STIME_FORMAT + +2019-05-25 19:45:02 +0200 Mathieu Duponchelle + + * docs/gst_plugins_cache.json: + doc: update plugin cache + +2019-05-25 17:25:02 +0200 Mathieu Duponchelle + + * gst/videomixer/videomixer2.c: + videomixer: the documentation for GstVideoMixer2Pad is not exposed + +2019-05-25 16:56:32 +0200 Mathieu Duponchelle + + * ext/gdk_pixbuf/gstgdkpixbufsink.c: + * ext/soup/gstsouphttpsrc.c: + * ext/vpx/gstvp8enc.c: + * ext/vpx/gstvp9enc.c: + * gst/isomp4/gstqtmux-doc.c: + * gst/isomp4/gstqtmux.c: + * gst/multifile/gstmultifilesrc.c: + * gst/rtpmanager/gstrtprtxqueue.c: + * gst/rtpmanager/gstrtpsession.c: + * gst/rtsp/gstrtspsrc.c: + * gst/smpte/gstsmpte.c: + * gst/smpte/gstsmptealpha.c: + * gst/spectrum/gstspectrum.c: + doc: fix element section documentations + Element sections were not rendered anymore after the hotdoc + port, fixing this revealed a few incorrect links. + +2019-02-19 12:15:19 -0500 Nicolas Dufresne + + * gst/rtpmanager/gstrtpbin.c: + rtpbin: Improve RTPStorage action signal documentation + This is a tiny clarification as the storage was loosely named "storage". + This change clarify that the storage is specificaly used for received RTP + packets. This is unlike the storage found in rtprtxsend that stores a + backlog of sent RTP packets. + +2019-05-05 22:16:36 +0900 Seungha Yang + + * gst/matroska/matroska-demux.c: + * gst/matroska/matroska-mux.c: + matroska: Add BT2020_10, PQ and HLG transfer functions + The direct use of newly added transfer functions + +2019-05-23 12:38:06 +0300 Sebastian Dröge + + * ext/aalib/meson.build: + aasink: Generate pkg-config file for the plugin + +2019-05-22 11:01:17 +0900 Seungha Yang + + * gst/multifile/gstmultifilesink.c: + multifilesink: Fix documentation of max-file-duration property + The max-file-duration property works with max-duration mode + +2019-05-14 17:36:14 -0400 Nicolas Dufresne + + * gst/rtpmanager/rtpsession.c: + * tests/check/elements/rtpsession.c: + rtpsession: Always keep at least one NACK on early RTCP + We recently added code to remove outdate NACK to avoid using bandwidth + for packet that have no chance of arriving on time. Though, this had a + side effect, which is that it was to get an early RTCP packet with no + feedback into it. This was pretty useless but also had a side effect, + which is that the RTX RTT value would never be updated. So we we stared + having late RTX request due to high RTT, we'd never manage to recover. + This fixes the regression by making sure we keep at least one NACK in + this situation. This is really light on the bandwidth and allow for + quick recover after the RTT have spiked higher then the jitterbuffer + capacity. + +2019-05-16 09:14:19 -0400 Thibault Saunier + + * docs/meson.build: + docs: Stop building the doc cache by default + Fixes https://gitlab.freedesktop.org/gstreamer/gst-docs/issues/36 + +2019-05-13 22:53:59 -0400 Thibault Saunier + + * docs/gst_plugins_cache.json: + docs: Update plugins documentation cache + +2019-04-23 12:28:23 -0400 Thibault Saunier + + * ext/soup/gstsouputils.c: + * gst/goom/flying_stars_fx.c: + * gst/goom/goom_tools.h: + * gst/rtpmanager/gstrtpbin.c: + * gst/rtpmanager/gstrtpmux.h: + * sys/v4l2/gstv4l2object.c: + doc: Fix some docstrings + +2018-10-22 11:39:55 +0200 Thibault Saunier + + * Makefile.am: + * configure.ac: + * docs/Makefile.am: + * docs/all_index.md: + * docs/gst_api_version.in: + * docs/gst_plugins_cache.json: + * docs/index.md: + * docs/meson.build: + * docs/plugins/.gitignore: + * docs/plugins/Makefile.am: + * docs/plugins/gst-plugins-good-plugins-docs.sgml: + * docs/plugins/gst-plugins-good-plugins-sections.txt: + * docs/plugins/gst-plugins-good-plugins.args: + * docs/plugins/gst-plugins-good-plugins.hierarchy: + * docs/plugins/gst-plugins-good-plugins.interfaces: + * docs/plugins/gst-plugins-good-plugins.prerequisites: + * docs/plugins/gst-plugins-good-plugins.signals: + * docs/plugins/gst-plugins-good-plugins.types: + * docs/plugins/inspect/plugin-1394.xml: + * docs/plugins/inspect/plugin-aasink.xml: + * docs/plugins/inspect/plugin-alaw.xml: + * docs/plugins/inspect/plugin-alpha.xml: + * docs/plugins/inspect/plugin-alphacolor.xml: + * docs/plugins/inspect/plugin-apetag.xml: + * docs/plugins/inspect/plugin-audiofx.xml: + * docs/plugins/inspect/plugin-audioparsers.xml: + * docs/plugins/inspect/plugin-auparse.xml: + * docs/plugins/inspect/plugin-autodetect.xml: + * docs/plugins/inspect/plugin-avi.xml: + * docs/plugins/inspect/plugin-cacasink.xml: + * docs/plugins/inspect/plugin-cairo.xml: + * docs/plugins/inspect/plugin-cutter.xml: + * docs/plugins/inspect/plugin-debug.xml: + * docs/plugins/inspect/plugin-deinterlace.xml: + * docs/plugins/inspect/plugin-directsound.xml: + * docs/plugins/inspect/plugin-dtmf.xml: + * docs/plugins/inspect/plugin-dv.xml: + * docs/plugins/inspect/plugin-effectv.xml: + * docs/plugins/inspect/plugin-equalizer.xml: + * docs/plugins/inspect/plugin-flac.xml: + * docs/plugins/inspect/plugin-flv.xml: + * docs/plugins/inspect/plugin-flxdec.xml: + * docs/plugins/inspect/plugin-gdkpixbuf.xml: + * docs/plugins/inspect/plugin-goom.xml: + * docs/plugins/inspect/plugin-goom2k1.xml: + * docs/plugins/inspect/plugin-gtk.xml: + * docs/plugins/inspect/plugin-icydemux.xml: + * docs/plugins/inspect/plugin-id3demux.xml: + * docs/plugins/inspect/plugin-imagefreeze.xml: + * docs/plugins/inspect/plugin-interleave.xml: + * docs/plugins/inspect/plugin-isomp4.xml: + * docs/plugins/inspect/plugin-jack.xml: + * docs/plugins/inspect/plugin-jpeg.xml: + * docs/plugins/inspect/plugin-lame.xml: + * docs/plugins/inspect/plugin-level.xml: + * docs/plugins/inspect/plugin-matroska.xml: + * docs/plugins/inspect/plugin-monoscope.xml: + * docs/plugins/inspect/plugin-mpg123.xml: + * docs/plugins/inspect/plugin-mulaw.xml: + * docs/plugins/inspect/plugin-multifile.xml: + * docs/plugins/inspect/plugin-multipart.xml: + * docs/plugins/inspect/plugin-navigationtest.xml: + * docs/plugins/inspect/plugin-oss4.xml: + * docs/plugins/inspect/plugin-ossaudio.xml: + * docs/plugins/inspect/plugin-osxaudio.xml: + * docs/plugins/inspect/plugin-osxvideo.xml: + * docs/plugins/inspect/plugin-png.xml: + * docs/plugins/inspect/plugin-pulseaudio.xml: + * docs/plugins/inspect/plugin-qmlgl.xml: + * docs/plugins/inspect/plugin-replaygain.xml: + * docs/plugins/inspect/plugin-rtp.xml: + * docs/plugins/inspect/plugin-rtpmanager.xml: + * docs/plugins/inspect/plugin-rtsp.xml: + * docs/plugins/inspect/plugin-shapewipe.xml: + * docs/plugins/inspect/plugin-shout2.xml: + * docs/plugins/inspect/plugin-smpte.xml: + * docs/plugins/inspect/plugin-soup.xml: + * docs/plugins/inspect/plugin-spectrum.xml: + * docs/plugins/inspect/plugin-speex.xml: + * docs/plugins/inspect/plugin-taglib.xml: + * docs/plugins/inspect/plugin-twolame.xml: + * docs/plugins/inspect/plugin-udp.xml: + * docs/plugins/inspect/plugin-video4linux2.xml: + * docs/plugins/inspect/plugin-videobox.xml: + * docs/plugins/inspect/plugin-videocrop.xml: + * docs/plugins/inspect/plugin-videofilter.xml: + * docs/plugins/inspect/plugin-videomixer.xml: + * docs/plugins/inspect/plugin-vpx.xml: + * docs/plugins/inspect/plugin-waveform.xml: + * docs/plugins/inspect/plugin-wavenc.xml: + * docs/plugins/inspect/plugin-wavpack.xml: + * docs/plugins/inspect/plugin-wavparse.xml: + * docs/plugins/inspect/plugin-ximagesrc.xml: + * docs/plugins/inspect/plugin-y4menc.xml: + * docs/random/ChangeLog-0.8: + * docs/random/PORTED_09: + * docs/sitemap.txt: + * docs/version.entities.in: + * ext/aalib/meson.build: + * ext/cairo/meson.build: + * ext/flac/meson.build: + * ext/gdk_pixbuf/meson.build: + * ext/jack/meson.build: + * ext/jpeg/meson.build: + * ext/lame/meson.build: + * ext/libcaca/meson.build: + * ext/libpng/meson.build: + * ext/mpg123/meson.build: + * ext/pulse/meson.build: + * ext/raw1394/meson.build: + * ext/shout2/meson.build: + * ext/soup/meson.build: + * ext/speex/meson.build: + * ext/taglib/meson.build: + * ext/twolame/meson.build: + * ext/vpx/meson.build: + * ext/wavpack/meson.build: + * gst/alpha/meson.build: + * gst/apetag/meson.build: + * gst/audiofx/meson.build: + * gst/audioparsers/meson.build: + * gst/auparse/meson.build: + * gst/autodetect/meson.build: + * gst/avi/meson.build: + * gst/cutter/meson.build: + * gst/debugutils/meson.build: + * gst/deinterlace/meson.build: + * gst/dtmf/meson.build: + * gst/effectv/meson.build: + * gst/equalizer/meson.build: + * gst/flv/meson.build: + * gst/flx/meson.build: + * gst/goom/filters.c: + * gst/goom/meson.build: + * gst/goom2k1/meson.build: + * gst/icydemux/meson.build: + * gst/id3demux/meson.build: + * gst/imagefreeze/meson.build: + * gst/interleave/meson.build: + * gst/isomp4/meson.build: + * gst/law/meson.build: + * gst/law/mulaw-conversion.c: + * gst/level/meson.build: + * gst/matroska/meson.build: + * gst/monoscope/meson.build: + * gst/multifile/meson.build: + * gst/multipart/meson.build: + * gst/replaygain/meson.build: + * gst/rtp/meson.build: + * gst/rtpmanager/gstrtpptdemux.c: + * gst/rtpmanager/meson.build: + * gst/rtsp/meson.build: + * gst/shapewipe/meson.build: + * gst/smpte/meson.build: + * gst/spectrum/meson.build: + * gst/udp/meson.build: + * gst/videobox/meson.build: + * gst/videocrop/meson.build: + * gst/videofilter/meson.build: + * gst/videomixer/meson.build: + * gst/wavenc/meson.build: + * gst/wavparse/meson.build: + * gst/y4m/meson.build: + * meson.build: + * meson_options.txt: + * sys/directsound/meson.build: + * sys/oss/meson.build: + * sys/oss4/meson.build: + * sys/v4l2/meson.build: + * sys/ximage/meson.build: + doc: Port documentation to hotdoc + +2018-11-12 08:05:45 -0300 Thibault Saunier + + * gst/isomp4/gstqtmux.c: + * gst/rtpmanager/gstrtpbin.c: + * gst/rtpmanager/gstrtpsession.c: + * gst/rtpmanager/rtpsession.c: + Mark some properties as DOC_SHOW_DEFAULT + +2018-10-22 11:39:24 +0200 Thibault Saunier + + * ext/aalib/gstaasink.c: + * ext/cairo/gstcairooverlay.c: + * ext/dv/gstdvdec.c: + * ext/dv/gstdvdemux.c: + * ext/flac/gstflacdec.c: + * ext/flac/gstflacenc.c: + * ext/flac/gstflactag.c: + * ext/gdk_pixbuf/gstgdkpixbufoverlay.c: + * ext/gdk_pixbuf/gstgdkpixbufsink.c: + * ext/jack/gstjackaudioclient.c: + * ext/jack/gstjackaudiosink.c: + * ext/jack/gstjackaudiosink.h: + * ext/jack/gstjackaudiosrc.c: + * ext/jpeg/gstjpegdec.c: + * ext/jpeg/gstjpegenc.c: + * ext/jpeg/gstsmokedec.c: + * ext/jpeg/gstsmokeenc.c: + * ext/libcaca/gstcacasink.c: + * ext/libpng/gstpngdec.c: + * ext/libpng/gstpngenc.c: + * ext/pulse/pulsesink.c: + * ext/pulse/pulsesrc.c: + * ext/raw1394/gstdv1394src.c: + * ext/raw1394/gsthdv1394src.c: + * ext/shout2/gstshout2.c: + * ext/soup/gstsouphttpclientsink.c: + * ext/soup/gstsouphttpsrc.c: + * ext/speex/gstspeexdec.c: + * ext/speex/gstspeexenc.c: + * ext/vpx/gstvp8dec.c: + * ext/vpx/gstvp8enc.c: + * ext/vpx/gstvp9dec.c: + * ext/vpx/gstvp9enc.c: + * ext/wavpack/gstwavpackdec.c: + * ext/wavpack/gstwavpackenc.c: + * gst/alpha/gstalpha.c: + * gst/alpha/gstalpha.h: + * gst/alpha/gstalphacolor.c: + * gst/apetag/gstapedemux.c: + * gst/audiofx/audioamplify.c: + * gst/audiofx/audiochebband.c: + * gst/audiofx/audiocheblimit.c: + * gst/audiofx/audiodynamic.c: + * gst/audiofx/audioecho.c: + * gst/audiofx/audiofirfilter.c: + * gst/audiofx/audioiirfilter.c: + * gst/audiofx/audioinvert.c: + * gst/audiofx/audiokaraoke.c: + * gst/audiofx/audiopanorama.c: + * gst/audiofx/audiowsincband.c: + * gst/audiofx/audiowsinclimit.c: + * gst/audiofx/gstscaletempo.c: + * gst/audioparsers/gstaacparse.c: + * gst/audioparsers/gstac3parse.c: + * gst/audioparsers/gstamrparse.c: + * gst/audioparsers/gstdcaparse.c: + * gst/audioparsers/gstflacparse.c: + * gst/audioparsers/gstmpegaudioparse.c: + * gst/audioparsers/gstsbcparse.c: + * gst/audioparsers/gstwavpackparse.c: + * gst/auparse/gstauparse.c: + * gst/autodetect/gstautoaudiosink.c: + * gst/autodetect/gstautoaudiosrc.c: + * gst/autodetect/gstautovideosink.c: + * gst/autodetect/gstautovideosrc.c: + * gst/avi/gstavidemux.c: + * gst/avi/gstavimux.c: + * gst/avi/gstavisubtitle.c: + * gst/cutter/gstcutter.c: + * gst/debugutils/breakmydata.c: + * gst/debugutils/gstcapssetter.c: + * gst/debugutils/gstpushfilesrc.c: + * gst/debugutils/gsttaginject.c: + * gst/debugutils/progressreport.c: + * gst/debugutils/rndbuffersize.c: + * gst/deinterlace/gstdeinterlace.c: + * gst/dtmf/gstdtmfsrc.c: + * gst/dtmf/gstrtpdtmfdepay.c: + * gst/dtmf/gstrtpdtmfsrc.c: + * gst/effectv/gstaging.c: + * gst/effectv/gstdice.c: + * gst/effectv/gstedge.c: + * gst/effectv/gstop.c: + * gst/effectv/gstquark.c: + * gst/effectv/gstradioac.c: + * gst/effectv/gstrev.c: + * gst/effectv/gstripple.c: + * gst/effectv/gstshagadelic.c: + * gst/effectv/gststreak.c: + * gst/effectv/gstvertigo.c: + * gst/effectv/gstwarp.c: + * gst/equalizer/gstiirequalizer10bands.c: + * gst/equalizer/gstiirequalizer3bands.c: + * gst/equalizer/gstiirequalizernbands.c: + * gst/flv/gstflvdemux.c: + * gst/flv/gstflvmux.c: + * gst/flv/gstindex.c: + * gst/flx/gstflxdec.c: + * gst/goom/filters.c: + * gst/goom/goom_config.h: + * gst/goom/goom_filters.h: + * gst/goom/goom_plugin_info.h: + * gst/goom/gstgoom.c: + * gst/goom/ifs.c: + * gst/goom/sound_tester.h: + * gst/goom2k1/filters.h: + * gst/goom2k1/goom_core.h: + * gst/goom2k1/gstgoom.c: + * gst/icydemux/gsticydemux.c: + * gst/id3demux/gstid3demux.c: + * gst/imagefreeze/gstimagefreeze.c: + * gst/interleave/deinterleave.c: + * gst/interleave/interleave.c: + * gst/isomp4/gstqtmoovrecover.c: + * gst/isomp4/gstqtmux-doc.c: + * gst/isomp4/gstqtmux.c: + * gst/isomp4/qtdemux.c: + * gst/law/alaw-decode.c: + * gst/law/alaw-encode.c: + * gst/law/mulaw-conversion.c: + * gst/law/mulaw-decode.c: + * gst/law/mulaw-encode.c: + * gst/level/gstlevel.c: + * gst/matroska/matroska-demux.c: + * gst/matroska/matroska-mux.c: + * gst/matroska/matroska-parse.c: + * gst/matroska/webm-mux.c: + * gst/monoscope/gstmonoscope.c: + * gst/multifile/gstmultifilesink.c: + * gst/multifile/gstmultifilesrc.c: + * gst/multifile/gstsplitfilesrc.c: + * gst/multifile/gstsplitmuxsink.c: + * gst/multifile/gstsplitmuxsrc.c: + * gst/multipart/multipartdemux.c: + * gst/multipart/multipartmux.c: + * gst/replaygain/gstrganalysis.c: + * gst/replaygain/gstrglimiter.c: + * gst/replaygain/gstrgvolume.c: + * gst/rtp/gstrtpL16depay.c: + * gst/rtp/gstrtpL16pay.c: + * gst/rtp/gstrtpL24depay.c: + * gst/rtp/gstrtpL24pay.c: + * gst/rtp/gstrtpac3depay.c: + * gst/rtp/gstrtpac3pay.c: + * gst/rtp/gstrtpamrdepay.c: + * gst/rtp/gstrtpamrpay.c: + * gst/rtp/gstrtpbvdepay.c: + * gst/rtp/gstrtpbvpay.c: + * gst/rtp/gstrtph261depay.c: + * gst/rtp/gstrtph261pay.c: + * gst/rtp/gstrtph264depay.c: + * gst/rtp/gstrtph265depay.c: + * gst/rtp/gstrtph265pay.c: + * gst/rtp/gstrtpj2kdepay.c: + * gst/rtp/gstrtpj2kpay.c: + * gst/rtp/gstrtpjpegpay.c: + * gst/rtp/gstrtpklvdepay.c: + * gst/rtp/gstrtpklvpay.c: + * gst/rtp/gstrtpstreamdepay.c: + * gst/rtp/gstrtpstreampay.c: + * gst/rtpmanager/gstrtpbin.c: + * gst/rtpmanager/gstrtpdtmfmux.c: + * gst/rtpmanager/gstrtpjitterbuffer.c: + * gst/rtpmanager/gstrtpmux.c: + * gst/rtpmanager/gstrtpptdemux.c: + * gst/rtpmanager/gstrtpptdemux.h: + * gst/rtpmanager/gstrtprtxqueue.c: + * gst/rtpmanager/gstrtprtxreceive.c: + * gst/rtpmanager/gstrtprtxsend.c: + * gst/rtpmanager/gstrtpsession.c: + * gst/rtpmanager/gstrtpssrcdemux.c: + * gst/rtpmanager/rtpsession.c: + * gst/rtsp/gstrtpdec.c: + * gst/shapewipe/gstshapewipe.c: + * gst/smpte/gstsmpte.c: + * gst/smpte/gstsmptealpha.c: + * gst/spectrum/gstspectrum.c: + * gst/udp/gstmultiudpsink.c: + * gst/udp/gstudpsink.c: + * gst/udp/gstudpsrc.c: + * gst/videobox/gstvideobox.c: + * gst/videocrop/gstaspectratiocrop.c: + * gst/videocrop/gstvideocrop.c: + * gst/videofilter/gstgamma.c: + * gst/videofilter/gstvideobalance.c: + * gst/videofilter/gstvideoflip.c: + * gst/videomixer/videomixer2.c: + * gst/wavenc/gstwavenc.c: + * gst/wavparse/gstwavparse.c: + * gst/y4m/gsty4mencode.c: + * sys/directsound/gstdirectsoundsink.c: + * sys/oss/gstosssink.c: + * sys/oss/gstosssrc.c: + * sys/oss4/oss4-sink.c: + * sys/oss4/oss4-source.c: + * sys/osxaudio/gstosxaudiosink.c: + * sys/osxaudio/gstosxaudiosrc.c: + * sys/v4l2/gstv4l2radio.c: + * sys/v4l2/gstv4l2sink.c: + * sys/v4l2/gstv4l2src.c: + * sys/v4l2/tuner.c: + * sys/v4l2/tunerchannel.c: + * sys/v4l2/tunernorm.c: + * sys/waveform/gstwaveformsink.c: + * sys/ximage/gstximagesrc.c: + docs: Port all docstring to gtk-doc markdown + +2019-05-02 22:14:35 -0700 Thiago Santos + + * gst/rtsp/gstrtspsrc.c: + rtspsrc: do not try to send EOS with invalid seqnum + The second udpsrc (rtcp) might not have seen the segment event if it was + not enabled or if rtcp is not available on the server. So if the + application tries to send an EOS event it will try to set an invalid + seqnum to the event. + +2019-04-24 13:54:12 -0400 Nicolas Dufresne + + * gst/rtpmanager/rtpsource.c: + rtpsource: Add more information to probation warning + +2019-04-24 13:47:54 -0400 Nicolas Dufresne + + * gst/rtpmanager/rtpsession.c: + * tests/check/elements/rtpsession.c: + rtpsession: Call on-new-ssrc earlier + Right now, we may call on-new-ssrc after we have processed the first + RTP packet. This prevents properly configuring the source as some + property like "probation" are copied internally for use as a + decreasing counter. For this specific property, it prevents the + application from disabling probation on auxiliary sparse stream. + Probation is harmful on sparse streams since the probation algorithm + assume frequent and contiguous RTP packets. + +2019-02-19 13:34:49 +0900 Seungha Yang + + * gst/matroska/matroska-mux.c: + matroskamux: Write MasteringMetadata and Max{CLL,FALL} + Enable muxing with HDR meta data if upstream provided it + +2019-02-18 23:28:50 +0900 Seungha Yang + + * gst/matroska/matroska-demux.c: + * gst/matroska/matroska-ids.c: + * gst/matroska/matroska-ids.h: + matroskademux: Add support parsing HDR metadata + Set SMPTE ST 2086 mastering-display-metadata and + content-light-level to caps, if any + +2019-02-19 18:27:23 +0900 Seungha Yang + + * gst/matroska/ebml-write.c: + * gst/matroska/ebml-write.h: + * gst/matroska/matroska-ids.h: + * gst/matroska/matroska-mux.c: + * gst/matroska/matroska-mux.h: + * gst/matroska/matroska-read-common.h: + matroska: Remove white space + +2019-05-01 10:00:51 +0300 Sebastian Dröge + + * gst/rtp/gstrtpvrawdepay.c: + rtprawdepay: Don't get rid of the buffer pool on FLUSH_STOP + We expect there to be a pool as long as the caps are known and + FLUSH_STOP is not resetting the caps. Getting rid of the pool would + cause assertions. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/584 + +2019-02-08 10:09:17 +0100 Danny Smith + + * gst/rtpmanager/gstrtpbin.c: + rtpbin: Free storage when freeing session + +2019-04-25 21:52:42 +0300 Sebastian Dröge + + * gst/matroska/matroska-mux.c: + matroskamux: Fix typo in error message + +2019-04-25 11:19:06 +0300 Sebastian Dröge + + * gst/imagefreeze/gstimagefreeze.c: + imagefreeze: Only set the DISCONT flag on the first buffer after segment start + +2019-04-24 02:38:32 +0900 okuoku + + * ext/jack/gstjackaudiosink.c: + * ext/jack/gstjackaudiosrc.c: + jack: Use jack_free(3) to release ports + Port objects acquired with jack_get_ports() need to be freed with + jack_free(3), not stdlib free(). + On Windows, Jack may be linked against different libc than GStreamer + libraries so free()ing port objects directly might cause crash because + of libc mismatch. + +2019-04-23 10:10:01 +0100 Philippe Normand + + * gst/audiofx/gstscaletempo.c: + scaletempo: Advertise interleaved layout in caps templates + Scaletempo doesn't support non-interleaved layout. Not explicitely stating this + would trigger critical warnings and a caps negotiation failure when scaletempo + is used as playbin audio-filter. + Patch suggested by George Kiagiadakis . + Fixes #591 + +2019-04-21 20:12:28 +0900 Seungha Yang + + * gst/matroska/meson.build: + meson: matroska: Ensure header dependency not only library + Library existence does not guarantee header. + +2018-11-13 13:48:11 +0100 Robert Rosengren + + * gst/udp/gstmultiudpsink.c: + multidupsink: Use gst_net_utils_set_socket_tos for QoS DSCP + Util function in net library exists for setting QoS DSCP on socket, hence + use it to simplify code. + +2019-04-19 10:27:38 +0100 Tim-Philipp Müller + + * README: + * RELEASE: + * configure.ac: + * docs/plugins/gst-plugins-good-plugins.args: + * docs/plugins/inspect/plugin-1394.xml: + * docs/plugins/inspect/plugin-aasink.xml: + * docs/plugins/inspect/plugin-alaw.xml: + * docs/plugins/inspect/plugin-alpha.xml: + * docs/plugins/inspect/plugin-alphacolor.xml: + * docs/plugins/inspect/plugin-apetag.xml: + * docs/plugins/inspect/plugin-audiofx.xml: + * docs/plugins/inspect/plugin-audioparsers.xml: + * docs/plugins/inspect/plugin-auparse.xml: + * docs/plugins/inspect/plugin-autodetect.xml: + * docs/plugins/inspect/plugin-avi.xml: + * docs/plugins/inspect/plugin-cacasink.xml: + * docs/plugins/inspect/plugin-cairo.xml: + * docs/plugins/inspect/plugin-cutter.xml: + * docs/plugins/inspect/plugin-debug.xml: + * docs/plugins/inspect/plugin-deinterlace.xml: + * docs/plugins/inspect/plugin-dtmf.xml: + * docs/plugins/inspect/plugin-dv.xml: + * docs/plugins/inspect/plugin-effectv.xml: + * docs/plugins/inspect/plugin-equalizer.xml: + * docs/plugins/inspect/plugin-flac.xml: + * docs/plugins/inspect/plugin-flv.xml: + * docs/plugins/inspect/plugin-flxdec.xml: + * docs/plugins/inspect/plugin-gdkpixbuf.xml: + * docs/plugins/inspect/plugin-goom.xml: + * docs/plugins/inspect/plugin-goom2k1.xml: + * docs/plugins/inspect/plugin-gtk.xml: + * docs/plugins/inspect/plugin-icydemux.xml: + * docs/plugins/inspect/plugin-id3demux.xml: + * docs/plugins/inspect/plugin-imagefreeze.xml: + * docs/plugins/inspect/plugin-interleave.xml: + * docs/plugins/inspect/plugin-isomp4.xml: + * docs/plugins/inspect/plugin-jack.xml: + * docs/plugins/inspect/plugin-jpeg.xml: + * docs/plugins/inspect/plugin-lame.xml: + * docs/plugins/inspect/plugin-level.xml: + * docs/plugins/inspect/plugin-matroska.xml: + * docs/plugins/inspect/plugin-mpg123.xml: + * docs/plugins/inspect/plugin-mulaw.xml: + * docs/plugins/inspect/plugin-multifile.xml: + * docs/plugins/inspect/plugin-multipart.xml: + * docs/plugins/inspect/plugin-navigationtest.xml: + * docs/plugins/inspect/plugin-oss4.xml: + * docs/plugins/inspect/plugin-ossaudio.xml: + * docs/plugins/inspect/plugin-png.xml: + * docs/plugins/inspect/plugin-pulseaudio.xml: + * docs/plugins/inspect/plugin-qmlgl.xml: + * docs/plugins/inspect/plugin-replaygain.xml: + * docs/plugins/inspect/plugin-rtp.xml: + * docs/plugins/inspect/plugin-rtpmanager.xml: + * docs/plugins/inspect/plugin-rtsp.xml: + * docs/plugins/inspect/plugin-shapewipe.xml: + * docs/plugins/inspect/plugin-shout2.xml: + * docs/plugins/inspect/plugin-smpte.xml: + * docs/plugins/inspect/plugin-soup.xml: + * docs/plugins/inspect/plugin-spectrum.xml: + * docs/plugins/inspect/plugin-speex.xml: + * docs/plugins/inspect/plugin-taglib.xml: + * docs/plugins/inspect/plugin-twolame.xml: + * docs/plugins/inspect/plugin-udp.xml: + * docs/plugins/inspect/plugin-video4linux2.xml: + * docs/plugins/inspect/plugin-videobox.xml: + * docs/plugins/inspect/plugin-videocrop.xml: + * docs/plugins/inspect/plugin-videofilter.xml: + * docs/plugins/inspect/plugin-videomixer.xml: + * docs/plugins/inspect/plugin-vpx.xml: + * docs/plugins/inspect/plugin-wavenc.xml: + * docs/plugins/inspect/plugin-wavpack.xml: + * docs/plugins/inspect/plugin-wavparse.xml: + * docs/plugins/inspect/plugin-ximagesrc.xml: + * docs/plugins/inspect/plugin-y4menc.xml: + * meson.build: + Back to development + === release 1.16.0 === 2019-04-19 00:23:16 +0100 Tim-Philipp Müller @@ -74859,7 +83268,7 @@ flacparse: Initialize variables. Fixes build on $#@*( macosx -2010-01-11 22:41:57 +0300 +2010-01-11 22:41:57 +0300 ������ ��������� * gst/audioparsers/gstaacparse.c: * gst/audioparsers/gstamrparse.c: @@ -100649,7 +109058,7 @@ mdat atoms. Also keep adapter/offset better in sync with upstream and fix some debug statements. Fixes #587426. -2009-07-06 10:40:31 +0200 Philip Jgenstedt +2009-07-06 10:40:31 +0200 Philip J�genstedt * gst/avi/gstavidemux.c: avidemux: Replace deprecated GST_DISABLE_DEBUG with correct macro. Fixes #587826 diff --git a/NEWS b/NEWS index 817de13720..d46aab467a 100644 --- a/NEWS +++ b/NEWS @@ -1,15 +1,14 @@ +GStreamer 1.18 Release Notes +GStreamer 1.18.0 was originally released on 8 September 2020. -GSTREAMER 1.16 RELEASE NOTES +The latest bug-fix release in the 1.18 series is 1.18.6 and was released +on 2 February 2022. - -GStreamer 1.16.0 was originally released on 19 April 2019. - -See https://gstreamer.freedesktop.org/releases/1.16/ for the latest +See https://gstreamer.freedesktop.org/releases/1.18/ for the latest version of this document. -_Last updated: Friday 19 April 2019, 00:00 UTC (log)_ - +Last updated: Wednesday 2 February 2022, 11:30 UTC (log) Introduction @@ -20,1373 +19,3352 @@ framework! As always, this release is again packed with many new features, bug fixes and other improvements. - Highlights -- GStreamer WebRTC stack gained support for data channels for - peer-to-peer communication based on SCTP, BUNDLE support, as well as - support for multiple TURN servers. +- GstTranscoder: new high level API for applications to transcode + media files from one format to another + +- High Dynamic Range (HDR) video information representation and + signalling enhancements + +- Instant playback rate change support + +- Active Format Description (AFD) and Bar Data support + +- RTSP server and client implementations gained ONVIF trick modes + support -- AV1 video codec support for Matroska and QuickTime/MP4 containers - and more configuration options and supported input formats for the - AOMedia AV1 encoder +- Hardware-accelerated video decoding on Windows via DXVA2 / + Direct3D11 -- Support for Closed Captions and other Ancillary Data in video +- Microsoft Media Foundation plugin for video capture and + hardware-accelerated video encoding on Windows -- Support for planar (non-interleaved) raw audio +- qmlgloverlay: New overlay element that renders a QtQuick scene over + the top of an input video stream -- GstVideoAggregator, compositor and OpenGL mixer elements are now in - -base +- imagesequencesrc: New element to easily create a video stream from a + sequence of jpeg or png images -- New alternate fields interlace mode where each buffer carries a - single field +- dashsink: New sink to produce DASH content -- WebM and Matroska ContentEncryption support in the Matroska demuxer +- dvbsubenc: New DVB Subtitle encoder element -- new WebKit WPE-based web browser source element +- MPEG-TS muxing now also supports TV broadcast compliant muxing with + constant bitrate muxing and SCTE-35 support -- Video4Linux: HEVC encoding and decoding, JPEG encoding, and improved - dmabuf import/export +- rtmp2: New RTMP client source and sink element from-scratch + implementation -- Hardware-accelerated Nvidia video decoder gained support for VP8/VP9 - decoding, whilst the encoder gained support for H.265/HEVC encoding. +- svthevcenc: New SVT-HEVC-based H.265 video encoder -- Many improvements to the Intel Media SDK based hardware-accelerated - video decoder and encoder plugin (msdk): dmabuf import/export for - zero-copy integration with other components; VP9 decoding; 10-bit - HEVC encoding; video post-processing (vpp) support including - deinterlacing; and the video decoder now handles dynamic resolution - changes. +- vaapioverlay: New compositor element using VA-API -- The ASS/SSA subtitle overlay renderer can now handle multiple - subtitles that overlap in time and will show them on screen - simultaneously +- rtpmanager gained support for Google’s Transport-Wide Congestion + Control (twcc) RTP extension -- The Meson build is now feature-complete (*) and it is now the - recommended build system on all platforms. The Autotools build is - scheduled to be removed in the next cycle. +- splitmuxsink and splitmuxsrc gained support for auxiliary video + streams -- The GStreamer Rust bindings and Rust plugins module are now - officially part of upstream GStreamer. +- webrtcbin now contains some initial support for renegotiation + involving stream addition and removal -- The GStreamer Editing Services gained a gesdemux element that allows - directly playing back serialized edit list with playbin or - (uri)decodebin +- RTP support was enhanced with new RTP source and sink elements to + easily set up RTP streaming via rtp:// URIs -- Many performance improvements +- avtp: New Audio Video Transport Protocol (AVTP) plugin for + Time-Sensitive Applications +- Support for the Video Services Forum’s Reliable Internet Stream + Transport (RIST) TR-06-1 Simple Profile + +- Universal Windows Platform (UWP) support + +- rpicamsrc: New element for capturing from the Raspberry Pi camera + +- RTSP Server TCP interleaved backpressure handling improvements as + well as support for Scale/Speed headers + +- GStreamer Editing Services gained support for nested timelines, + per-clip speed rate control and the OpenTimelineIO format. + +- Autotools build system has been removed in favour of Meson Major new features and changes -Noteworthy new API - -- GstAggregator has a new "min-upstream-latency" property that forces - a minimum aggregate latency for the input branches of an aggregator. - This is useful for dynamic pipelines where branches with a higher - latency might be added later after the pipeline is already up and - running and where a change in the latency would be disruptive. This - only applies to the case where at least one of the input branches is - live though, it won’t force the aggregator into live mode in the - absence of any live inputs. - -- GstBaseSink gained a "processing-deadline" property and - setter/getter API to configure a processing deadline for live - pipelines. The processing deadline is the acceptable amount of time - to process the media in a live pipeline before it reaches the sink. - This is on top of the systemic latency that is normally reported by - the latency query. This defaults to 20ms and should make pipelines - such as v4l2src ! xvimagesink not claim that all frames are late in - the QoS events. Ideally, this should replace the "max-lateness" - property for most applications. - -- RTCP Extended Reports (XR) parsing according to RFC 3611: - Loss/Duplicate RLE, Packet Receipt Times, Receiver Reference Time, - Delay since the last Receiver (DLRR), Statistics Summary, and VoIP - Metrics reports. This only provides the ability to parse such - packets, generation of XR packets is not supported yet and XR - packets are not automatically parsed by rtpbin / rtpsession but must - be actively handled by the application. - -- a new mode for interlaced video was added where each buffer carries - a single field of interlaced video, with buffer flags indicating - whether the field is the top field or bottom field. Top and bottom - fields are expected to alternate in this mode. Caps for this - interlace mode must also carry a format:Interlaced caps feature to - ensure backwards compatibility. - -- The video library has gained support for three new raw pixel - formats: - - - Y410: packed 4:4:4 YUV, 10 bits per channel - - Y210: packed 4:2:2 YUV, 10 bits per channel - - NV12_10LE40: fully-packed 10-bit variant of NV12_10LE32, - i.e. without the padding bits - -- GstRTPSourceMeta is a new meta that can be used to transport - information about the origin of depayloaded or decoded RTP buffers, - e.g. when mixing audio from multiple sources into a single stream. A - new "source-info" property on the RTP depayloader base class - determines whether depayloaders should put this meta on outgoing - buffers. Similarly, the same property on RTP payloaders determines - whether they should use the information from this meta to construct - the CSRCs list on outgoing RTP buffers. - -- gst_sdp_message_from_text() is a convenience constructor to parse - SDPs from a string which is particularly useful for language - bindings. - -Support for Planar (Non-Interleaved) Raw Audio - -Raw audio samples are usually passed around in interleaved form in -GStreamer, which means that if there are multiple audio channels the -samples for each channel are interleaved in memory, e.g. -|LEFT|RIGHT|LEFT|RIGHT|LEFT|RIGHT| for stereo audio. A non-interleaved -or planar arrangement in memory would look like -|LEFT|LEFT|LEFT|RIGHT|RIGHT|RIGHT| instead, possibly with -|LEFT|LEFT|LEFT| and |RIGHT|RIGHT|RIGHT| residing in separate memory -chunks or separated by some padding. - -GStreamer has always had signalling for non-interleaved audio since -version 1.0, but it was never actually properly implemented in any -elements. audioconvert would advertise support for it, but wasn’t -actually able to handle it correctly. - -With this release we now have full support for non-interleaved audio as -well, which means more efficient integration with external APIs that -handle audio this way, but also more efficient processing of certain -operations like interleaving multiple 1-channel streams into a -multi-channel stream which can be done without memory copies now. - -New API to support this has been added to the GStreamer Audio support -library: There is now a new GstAudioMeta which describes how data is -laid out inside the buffer, and buffers with non-interleaved audio must -always carry this meta. To access the non-interleaved audio samples you -must map such buffers with gst_audio_buffer_map() which works much like -gst_buffer_map() or gst_video_frame_map() in that it will populate a -little GstAudioBuffer helper structure passed to it with the number of -samples, the number of planes and pointers to the start of each plane in -memory. This function can also be used to map interleaved audio buffers -in which case there will be only one plane of interleaved samples. - -Of course support for this has also been implemented in the various -audio helper and conversion APIs, base classes, and in elements such as -audioconvert, audioresample, audiotestsrc, audiorate. - -Support for Closed Captions and Other Ancillary Data in Video - -The video support library has gained support for detecting and -extracting Ancillary Data from videos as per the SMPTE S291M -specification, including: - -- a VBI (Vertical Blanking Interval) parser that can detect and - extract Ancillary Data from Vertical Blanking Interval lines of - component signals. This is currently supported for videos in v210 - and UYVY format. - -- a new GstMeta for closed captions: GstVideoCaptionMeta. This - supports the two types of closed captions, CEA-608 and CEA-708, - along with the four different ways they can be transported (other - systems are a superset of those). - -- a VBI (Vertical Blanking Interval) encoder for writing ancillary - data to the Vertical Blanking Interval lines of component signals. - -The new closedcaption plugin in gst-plugins-bad then makes use of all -this new infrastructure and provides the following elements: - -- cccombiner: a closed caption combiner that takes a closed captions - stream and another stream and adds the closed captions as - GstVideoCaptionMeta to the buffers of the other stream. - -- ccextractor: a closed caption extractor which will take - GstVideoCaptionMeta from input buffers and output them as a separate - closed captions stream. - -- ccconverter: a closed caption converter that can convert between - different formats - -- line21encoder, line21decoder: inject/extract line21 closed captions - to/from SD video streams - -- cc708overlay: decodes CEA 608/708 captions and overlays them on - video - -Additionally, the following elements have also gained Closed Caption -support: - -- qtdemux and qtmux support CEA 608/708 Closed Caption tracks - -- mpegvideoparse, h264parse extracts Closed Captions from MPEG-2/H.264 - video streams - -- avviddec, avvidenc, x264enc got support for extracting/injecting - Closed Captions - -- decklinkvideosink can output closed captions and decklinkvideosrc - can extract closed captions - -- playbin and playbin3 learned how to autoplug CEA 608/708 CC overlay - elements - -- the externally maintained ajavideosrc element for AJA capture cards - has support for extracting closed captions +Noteworthy new features and API + +Instant playback rate changes + +Changing the playback rate as quickly as possible so far always required +a flushing seek. This generally works, but has the disadvantage of +flushing all data from the playback pipeline and requiring the demuxer +or parser to do a full-blown seek including resetting its internal state +and resetting the position of the data source. It might also require +considerable decoding effort to get to the right position to resume +playback from at the higher rate. + +This release adds a new mechanism to achieve quasi-instant rate changes +in certain playback pipelines without interrupting the flow of data in +the pipeline. This is activated by sending a seek with the +GST_SEEK_FLAG_INSTANT_RATE_CHANGE flag and start_type = stop_type = +GST_SEEK_TYPE_NONE. This flag does not work for all pipelines, in which +case it is necessary to fall back to sending a full flushing seek to +change the playback rate. When using this flag, the seek event is only +allowed to change the current rate and can modify the trickmode flags +(e.g. keyframe only or not), but it is not possible to change the +current playback position, playback direction or do a flush. + +This is particularly useful for streaming use cases like HLS or DASH +where the streaming download should not be interrupted when changing +rate. + +Instant rate changing is handled in the pipeline in a specific sequence +which is detailed in the seeking design docs. Most elements don’t need +to worry about this, only elements that sync to the clock need some +special handling which is implemented in the GstBaseSink base class, so +should be taken care of automatically in most normal playback pipelines +and sink elements. + +See Jan’s GStreamer Conference 2019 talk “Changing Playback Rate +Instantly” for more information. + +You can try this feature by passing the -i command line option to +gst-play-1.0. It is supported at least by qtdemux, tsdemux, hlsdemux, +and dashdemux. + +Google Transport-Wide Congestion Control + +rtpmanager now supports the parsing and generating of RTCP messages for +the Google Transport-Wide Congestion Control RTP Extension, as described +in: +https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01. + +This “just” provides the required plumbing/infrastructure, it does not +actually make effect any actual congestion control on the sender side, +but rather provides information for applications to use to make such +decisions. + +See Håvard’s “Google Transport-Wide Congestion Control” talk for more +information about this feature. + +GstTranscoder: a new high-level transcoding API for applications + +The new GstTranscoder library, along with transcodebin and +uritranscodebin elements, provides high level API for applications to +transcode media files from one format to another. Watch Thibault’s talk +“GstTranscoder: A High Level API to Quickly Implement Transcoding +Capabilities in your Applications” for more information. + +This also comes with a gst-transcoder-1.0 command line utility to +transcode one URI into another URI based on the specified encoding +profile. + +Active Format Description (AFD) and Bar Data support + +The GstVideo Ancillary Data API has gained support for Active Format +Description (AFD) and Bar data. + +This includes various two new buffer metas: GstVideoAFDMeta and +GstVideoBarMeta. + +GStreamer now also parses and extracts AFD/Bar data in the h264/h265 +video parsers, and supports both capturing them and outputting them in +the decklink elements. See Aaron’s lightning talk at the GStreamer +Conference for more background. + +ONVIF trick modes support in both GStreamer RTSP server and client + +- Support for the various trick modes described in section 6 of the + ONVIF streaming spec has been implemented in both gst-rtsp-server + and rtspsrc. +- Various new properties in rtspsrc must be set to take advantage of + the ONVIF support +- Examples are available here: test-onvif-server.c and + test-onvif-client.c +- Watch Mathieu Duponchelle’s talk “Implementing a Trickmode Player + with ONVIF, RTSP and GStreamer” for more information and a live + demo. + +GStreamer Codecs library with decoder base classes + +This introduces a new library in gst-plugins-bad which contains a set of +base classes that handle bitstream parsing and state tracking for the +purpose of decoding different codecs. Currently H264, H265, VP8 and VP9 +are supported. These bases classes are meant primarily for internal use +in GStreamer and are used in various decoder elements in connection with +low level decoding APIs like DXVA, NVDEC, VAAPI and V4L2 State Less +decoders. The new library is named gstreamer-codecs-1.0 / +libgstcodecs-1.0 and is not yet guaranteed to be API stable across major +versions. + +MPEG-TS muxing improvements + +The GStreamer MPEG-TS muxer has seen major improvements on various +fronts in this cycle: + +- It has been ported to the GstAggregator base class which means it + can work in defined-latency mode with live input sources and + continue streaming if one of the inputs stops producing data. + +- atscmux, a new ATSC-specific tsmux subclass + +- Constant Bit Rate (CBR) muxing support via the new bitrate property + which allows setting the target bitrate in bps. If this is set the + muxer will insert null packets as padding to achieve the desired + multiplex-wide constant bitrate. + +- compliance fixes for TV broadcasting use cases (esp. ATSC). See + Jan’s talk “TV Broadcast compliant MPEG-TS” for details. + +- Streams can now be added and removed at runtime: Until now, any + streams in tsmux had to be present when the element started + outputting its first buffer. Now they can appear at any point during + the stream, or even disappear and reappear later using the same PID. + +- new pcr-interval property allows applications to configure the + desired interval instead of hardcoding it + +- basic SCTE-35 support. This is enabled by setting the scte-35-pid + property on the muxer. Sending SCTE-35 commands is then done by + creating the appropriate SCTE-35 GstMpegtsSection and sending them + on the muxer. + +- MPEG-2 AAC handling improvements + +New elements + +- New qmlgloverlay element for rendering a QtQuick scene over the top + of a video stream. qmlgloverlay requires that Qt support adopting an + external OpenGL context and is known to work on X11 and Windows. + Wayland is known not to work due to limitations within Qt. Check out + the example to see how it works. -The rsclosedcaption plugin in the Rust plugins collection includes a -MacCaption (MCC) file parser and encoder. +- The clocksync element is a generic element that can be placed in a + pipeline to synchronise passing buffers to the clock at that point. + This is similar to identity sync=true, but because it isn’t + GstBaseTransform-based, it can process GstBufferLists without + breaking them into separate GstBuffers. It is also more discoverable + than the identity option. Note that you do not need to insert this + element into your pipeline to make GStreamer sync to the pipeline + clock, this is usually handled automatically by the elements in the + pipeline (sources and sinks mostly). This element is useful to feed + non-live input such as local files into elements that expect live + input such as webrtcbin.` + +- New imagesequencesrc element to easily create a video stream from a + sequence of JPEG or PNG images (or any other encoding where the type + can be detected), basically a multifilesrc made specifically for + image sequences. + +- rpicamsrc element for capturing raw or encoded video (H.264, MJPEG) + from the Raspberry Pi camera. This works much like the popular + raspivid command line utility but outputs data nicely timestamped + and formatted in order to integrate nicely with other GStreamer + elements. Also comes with a device provider so applications can + discover the camera if available. + +- aatv and cacatv video filters that transform video ASCII art style + +- avtp: new Audio Video Transport Protocol (AVTP) plugin for Linux. + See Andre Guedes’ talk “Audio/Video Bridging (AVB) support in + GStreamer” for more details. + +- clockselect: a pipeline element that enables clock selection/forcing + via gst-launch pipeline syntax. + +- dashsink: Add new sink to produce DASH content. See Stéphane’s talk + or blog post for details. + +- dvbsubenc: a DVB subtitle encoder element + +- microdns: a libmicrodns-based mdns device provider to discover RTSP + cameras on the local network + +- mlaudiosink: new audio sink element for the Magic Leap platform, + accompanied by an MLSDK implementation in the amc plugin -New Elements - -- overlaycomposition: New element that allows applications to draw - GstVideoOverlayCompositions on a stream. The element will emit the - "draw" signal for each video buffer, and the application then - generates an overlay for that frame (or not). This is much more - performant than e.g. cairooverlay for many use cases, e.g. because - pixel format conversions can be avoided or the blitting of the - overlay can be delegated to downstream elements (such as - gloverlaycompositor). It’s particularly useful for cases where only - a small section of the video frame should be drawn on. +- msdkvp9enc: VP9 encoder element for the Intel MediaSDK -- gloverlaycompositor: New OpenGL-based compositor element that - flattens any overlays from GstVideoOverlayCompositionMetas into the - video stream. This element is also always part of glimagesink. +- rist: new plugin implementing support for the Video Services Forum’s + Reliable Internet Stream Transport (RIST) TR-06-1 Simple Profile. + See Nicolas’ blog post “GStreamer support for the RIST + Specification” for more details. + +- rtmp2: new RTMP client source and sink elements with fully + asynchronous network operations, better robustness and additional + features such as handling ping and stats messages, and adobe-style + authentication. The new rtmp2src and rtmp2sink elements should be + API-compatible with the old rtmpsrc / rtmpsink elements and should + work as drop-in replacements. -- glalpha: New element that adds an alpha channel to a video stream. - The values of the alpha channel can either be set to a constant or - can be dynamically calculated via chroma keying. It is similar to - the existing alpha element but based on OpenGL. Calculations are - done in floating point so results may not be identical to the output - of the existing alpha element. +- new RTP source and sink elements to easily set up RTP streaming via + rtp:// URIs: The rtpsink and rtpsrc elements add an URI interface so + that streams can be decoded with decodebin using rtp:// URIs. These + can be used as follows: ``` gst-launch-1.0 videotestsrc ! x264enc ! + rtph264pay config-interval=3 ! rtpsink uri=rtp://239.1.1.1:1234 -- rtpfunnel funnels together RTP streams into a single session. Use - cases include multiplexing and bundle. webrtcbin uses it to - implement BUNDLE support. + gst-launch-1.0 videotestsrc ! x264enc ! rtph264pay config-interval=1 + ! rtpsink uri=rtp://239.1.2.3:5000 gst-launch-1.0 rtpsrc + uri=rtp://239.1.2.3:5000?encoding-name=H264 ! rtph264depay ! + avdec_h264 ! videoconvert ! xvimagesink -- testsrcbin is a source element that provides an audio and/or video - stream and also announces them using the recently-introduced - GstStream API. This is useful for testing elements such as playbin3 - or uridecodebin3 etc. + gst-launch-1.0 videotestsrc ! avenc_mpeg4 ! rtpmp4vpay + config-interval=1 ! rtpsink uri=rtp://239.1.2.3:5000 gst-launch-1.0 + rtpsrc uri=rtp://239.1.2.3:5000?encoding-name=MP4V-ES ! rtpmp4vdepay + ! avdec_mpeg4 ! videoconvert ! xvimagesink ``` -- New closed caption elements: cccombiner, ccextractor, ccconverter, - line21encoder, line21decoder and cc708overlay (see above) +- svthevcenc: new SVT-HEVC-based H.265 video encoder -- wpesrc: new source element acting as a Web Browser based on WebKit - WPE +- switchbin: new helper element which chooses between a set of + processing chains (paths) based on input caps, and changes the + active chain if new caps arrive. Paths are child objects, which are + accessed by the GstChildProxy interface. See the switchbin + documentation for a usage example. -- Two new OpenCV-based elements: cameracalibrate and cameraundistort - that can communicate to figure out distortion correction parameters - for a camera and correct for the distortion. +- vah264dec: new experimental va plugin with an element for H.264 + decoding with VA-API using GStreamer’s new stateless decoder + infrastructure (see Linux section below). + +- v4l2codecs: introduce an V4L2 CODECs Accelerator supporting the new + CODECs uAPI in the Linux kernel (see Linux section below) -- New sctp plugin based on usrsctp with sctpenc and sctpdec elements. - These elements are used inside webrtcbin for implementing data - channels. +- zxing new plugin to detect QR codes and barcodes, based on libzxing + +- also see the Rust plugins section below which contains plenty of new + exciting plugins written in Rust! New element features and additions -- playbin3, playbin and playsink have gained a new "text-offset" - property to adjust the positioning of the selected subtitle stream - vis-a-vis the audio and video streams. This uses subtitleoverlay’s - new "subtitle-ts-offset" property. GstPlayer has gained matching API - for this, namely gst_player_get_text_video_offset(). - -- playbin3 buffering improvements: in network playback scenarios there - may be multiple inputs to decodebin3, and buffering will be done - before decodebin3 using queue2 or downloadbuffer elements inside - urisourcebin. Since this is before any parsers or demuxers there may - not be any bitrate information available for the various streams, so - it was difficult to configure the buffering there smartly within - global constraints. This was improved now: The queue2 elements - inside urisourcebin will now use the new bitrate query to figure out - a bitrate estimate for the stream if no bitrate was provided by - upstream, and urisourcebin will use the bitrates of the individual - queues to distribute the globally-set "buffer-size" budget in bytes - to the various queues. urisourcebin also gained "low-watermark" and - "high-watermark" properties which will be proxied to the internal - queues, as well as a read-only "statistics" property which allows - querying of the minimum/maximum/average byte and time levels of the - queues inside the urisourcebin in question. - -- splitmuxsink has gained a couple of new features: - - - new "async-finalize" mode: This mode is useful for muxers or - outputs that can take a long time to finalize a file. Instead of - blocking the whole upstream pipeline while the muxer is doing - its stuff, we can unlink it and spawn a new muxer + sink - combination to continue running normally. This requires us to - receive the muxer and sink (if needed) as factories via the new - "muxer-factory" and "sink-factory" properties, optionally - accompanied by their respective properties structures (set via - the new "muxer-properties" and "sink-properties" properties). - There are also new "muxer-added" and "sink-added" signals in - case custom code has to be called for them to configure them. - - - "split-at-running-time" action signal: When called by the user, - this action signal ends the current file (and starts a new one) - as soon as the given running time is reached. If called multiple - times, running times are queued up and processed in the order - they were given. - - - "split-after" action signal to finish outputting the current GOP - to the current file and then start a new file as soon as the GOP - is finished and a new GOP is opened (unlike the existing - "split-now" which immediately finishes the current file and - writes the current GOP into the next newly-started file). - - - "reset-muxer" property: when unset, the muxer is reset using - flush events instead of setting its state to NULL and back. This - means the muxer can keep state across resets, e.g. mpegtsmux - will keep the continuity counter continuous across segments as - required by hlssink2. - -- qtdemux gained PIFF track encryption box support in addition to the - already-existing PIFF sample encryption support, and also allows - applications to select which encryption system to use via a - "drm-preferred-decryption-system-id" context in case there are - multiple options. - -- qtmux: the "start-gap-threshold" property determines now whether an - edit list will be created to account for small gaps or offsets at - the beginning of a stream in case the start timestamps of tracks - don’t line up perfectly. Previously the threshold was hard-coded to - 1% of the (video) frame duration, now it is 0 by default (so edit - list will be created even for small differences), but fully - configurable. - -- rtpjitterbuffer has improved end-of-stream handling - -- rtpmp4vpay will be preferred over rtpmp4gpay for MPEG-4 video in - autoplugging scenarios now - -- rtspsrc now allows applications to send RTSP SET_PARAMETER and - GET_PARAMETER requests using action signals. - -- rtspsrc has a small (100ms) configurable teardown delay by default - to try and make sure an RTSP TEARDOWN request gets sent out when the - source element shuts down. This will block the downward PAUSED to - READY state change for a short time, but can be disabled where it’s - a problem. Some servers only allow a limited number of concurrent - clients, so if no proper TEARDOWN is sent new clients may have - problems connecting to the server for a while. - -- souphttpsrc behaves better with low bitrate streams now. Before it - would increase the read block size too quickly which could lead to - it not reading any data from the socket for a very long time with - low bitrate streams that are output live downstream. This could lead - to servers kicking off the client. - -- filesink: do internal buffering to avoid performance regression with - small writes since we bypass libc buffering by using writev() - instead of fwrite() - -- identity: add "eos-after" property and fix "error-after" property - when the element is reused - -- input-selector: lets context queries pass through, so that - e.g. upstream OpenGL elements can use contexts and displays - advertised by downstream elements - -- queue2: avoid ping-pong between 0% and 100% buffering messages if - upstream is pushing buffers larger than one of its limits, plus - performance optimisations - -- opusdec: new "phase-inversion" property to control phase inversion. - When enabled, this will slightly increase stereo quality, but - produces a stream that when downmixed to mono will suffer audio - distortions. - -- The x265enc HEVC encoder also exposes a "key-int-max" property to - configure the maximum allowed GOP size now. - -- decklinkvideosink has seen stability improvements for long-running - pipelines (potential crash due to overflow of leaked clock refcount) - and clock-slaving improvements when performing flushing seeks - (causing stalls in the output timeline), pausing and/or buffering. - -- srtpdec, srtpenc: add support for MKIs which allow multiple keys to - be used with a single SRTP stream - -- srtpdec, srtpenc: add support for AES-GCM and also add support for - it in gst-rtsp-server and rtspsrc. - -- The srt Secure Reliable Transport plugin has integrated server and - client elements srt{client,server}{src,sink} into one (srtsrc and - srtsink), since SRT connection mode can be changed by uri - parameters. +GStreamer core + +- filesink: Add a new “full” buffer mode. Previously the default and + full modes were the same. Now the default mode is like before: it + accumulates all buffers in a buffer list until the threshold is + reached and then writes them all out, potentially in multiple + writes. The new full mode works by always copying memory to a single + memory area and writing everything out with a single write once the + threshold is reached. + +- multiqueue: Add stats property and + current-level-{buffers, bytes, time} pad properties to query the + current levels of the corresponding internal queue. -- h264parse and h265parse will handle SEI recovery point messages and - mark recovery points as keyframes as well (in addition to IDR - frames) +Plugins Base -- webrtcbin: "add-turn-server" action signal to pass multiple ICE - relays (TURN servers). +- alsa: implement a device provider -- The removesilence element has received various new features and - properties, such as a "threshold" property, detecting silence only - after minimum silence time/buffers, a "silent" property to control - bus message notifications as well as a "squash" property. +- alsasrc: added use-driver-timestamp property to force use of + pipeline timestamps (and disable driver timestamps) if so desired -- AOMedia AV1 decoder gained support for 10/12bit decoding whilst the - AV1 encoder supports more image formats and subsamplings now and - acquired support for rate control and profile related configuration. +- audioconvert: fix changing the mix-matrix property at runtime -- The Fraunhofer fdkaac plugin can now be built against the 2.0.0 - version API and has improved multichannel support +- appsrc: added support for segment forwarding or custom GstSegments + via GstSample, enabled via the handle-segment-change property. This + only works for segments in TIME format for now. -- kmssink now supports unpadded 24-bit RGB and can configure mode - setting from video info, which enables display of multi-planar - formats such as I420 or NV12 with modesetting. It has also gained a - number of new properties: The "restore-crtc" property does what it - says on the tin and is enabled by default. "plane-properties" and - "connector-properties" can be used to pass custom properties to the - DRM. +- compositor: various performance optimisations, checkerboard drawing + fixes, and support for VUYA format -- waylandsink has a "fullscreen" property now and supports the - XDG-Shell protocol. +- encodebin: Fix and refactor smart encoding; ensure that a single + segment is pushed into encoders; improve force-key-unit event + handling. -- decklinkvideosink, decklinkvideosrc support selecting between - half/full duplex +- opusenc: Add low delay option (audio-type=restricted-lowdelay) to + disable the SILK layer and achieve only 5ms delay. -- The vulkan plugin gained support for macOS and iOS via MoltenVK in - addition to the existing support for X11 and Wayland +- opusdec: add stats property to retrieve various decoder statistics. -- imagefreeze has a new num-buffers property to limit the number of - buffers that are produced and to send an EOS event afterwards +- uridecodebin3: Let decodebin3 do its stream selection if no one + answers -- webrtcbin has a new, introspectable get-transceiver signal in - addition to the old get-transceivers signal that couldn’t be used - from bindings +- decodebin3: Avoid overriding explicit user selection of streams -- Support for per-element latency information was added to the latency - tracer +- playbin: add flag to force use of software decoders over any + hardware decoders that might also be available + +- playbin3, playbin: propagate sink context + +- rawvideoparse: Fix tiling support, allow setting colorimetry + +- subparse: output plain utf8 text instead of pango-markup formatted + text if downstream requires it, useful for interop with elements + that only accept utf8-formatted subtitles such as muxers or closed + caption converters. + +- tcpserversrc, tcpclientsrc: add stats property with TCP connection + stats (some are only available on Linux though) + +- timeoverlay: add show-times-as-dates, datetime-format and + datetime-epoch properties to display times with dates + +- videorate: Fix changing rate property during playback; reverse + playback fixes; update QoS events taking into account our rate + +- videoscale: pass through and transform size sensitive metas instead + of just dropping them + +Plugins Good + +- avidemux can handle H.265 video now. Our advice remains to + immediately cease all contact and communication with anyone who + hands you H.265 video in an AVI container, however. + +- avimux: Add support for S24LE and S32LE raw audio and v210 raw video + formats; support more than 2 channels of raw audio. + +- souphttpsrc: disable session sharing and cookie jar when the cookies + property is set; correctly handle seeks past the end of the content + +- deinterlace: new YADIF deinterlace method which should provide + better quality than the existing methods and is LGPL licensed; + alternate fields are supported as input to the deinterlacer as well + now, and there were also fixes for switching the deinterlace mode on + the fly. + +- flvmux: in streamable mode allow adding new pads even if the initial + header has already been written. Old clients will only process the + initial stream, new clients will get a header with the new streams. + The skip-backwards-streams property can be used to force flvmux to + skip and drop a few buffers rather than produce timestamps that go + backward and confuse librtmp-based clients. There’s also better + handling for timestamp rollover when streaming for a long time. + +- imagefreeze: Add live mode, which can be enabled via the new is-live + property. In this mode frames will only be output in PLAYING state + according to the negotiated framerate, skipping frames if the output + can’t keep up (e.g. because it’s blocked downstream). This makes it + possible to actually use imagefreeze in live pipelines without + having to manually ensure somehow that it starts outputting at the + current running time and without still risking to fall behind + without recovery. + +- matroskademux, qtdemux: Provide audio lead-in for some lossy formats + when doing accurate seeks, to make sure we can actually decode + samples at the desired position. This is especially important for + non-linear audio/video editing use-cases. + +- matroskademux, matroskamux: Handle interlaced field order (tff, bff) + +- matroskamux: + + - new offset-to-zero property to offset all streams to start at + zero. This takes the timestamp of the earliest stream and + offsets it so that it starts at 0. Some software (VLC, + ffmpeg-based) does not properly handle Matroska files that start + at timestamps much bigger than zero, which could happen with + live streams. + - added a creation-time property to explicitly set the creation + time to write into the file headers. Useful when remuxing, for + example, but also for live feeds where the DateUTC header can be + set a UTC timestamp corresponding to the beginning of the file. + - the muxer now also always waits for caps on sparse streams, and + warns if caps arrive after the header has already been sent, + otherwise the subtitle track might be silently absent in the + final file. This might affect applications that send sparse data + into matroskamux via an appsrc element, which will usually not + send out the initial caps before it sends out the first buffer. + +- pulseaudio: device provider improvements: fix discovery of + newly-added devices and hide the alsa device provider if we provide + alsa devices + +- qtdemux: raw audio handling improvements, support for AC4 audio, and + key-units trickmode interval support + +- qtmux: + + - was ported to the GstAggregator base class which allows for + better handling of live inputs, but might entail minor + behavioural changes for sparse inputs if inputs are not live. + - has also gained a force-create-timecode-trak property to create + a timecode trak in non-mov flavors, which may not be supported + by Apple but is supported by other software such as Final Cut + Pro X + - also a force-chunks property to force the creation of chunks + even in single-stream files, which is required for Apple ProRes + certification. + - also supports 8k resolutions in prefill mode with ProRes. + +- rtpbin gained a request-jitterbuffer signal which allows + applications to plug in their own jitterbuffer implementation such + as the threadsharing jitterbuffer from the Rust plugins, for + example. + +- rtprtxsend: add clock-rate-map property to allow generic RTP input + caps without a clock-rate whilst still supporting the max-size-time + property for bundled streams. + +- rtpssrcdemux: introduce max-streams property to guard against + attacks where the sender changes SSRC for every RTP packet. + +- rtph264pay, rtph264pay: implement STAP-A and various aggregation + modes controled by the new aggegrate-mode property: none to not + aggregate NAL units (as before), zero-latency to aggregate NAL units + until a VCL or suffix unit is included, or max to aggregate all NAL + units with the same timestamp (which adds one frame of latency). The + default has been kept at none for backwards compatibility reasons + and because various RTP/RTSP implementions don’t handle aggregation + well. For WebRTC use cases this should be set to zero-latency, + however. + +- rtpmp4vpay: add support for config-interval=-1 to resend headers + with each IDR keyframe, like other video payloaders. + +- rtpvp8depay: Add wait-for-keyframe property for waiting until the + next keyframe after packet loss. Useful if the video stream was not + encoded with error resilience enabled, in which case packet loss + tends to cause very bad artefacts when decoding, and waiting for the + next keyframe instead improves user experience considerably. + +- splitmuxsink and splitmuxsrc can now handle auxiliary video streams + in addition to the primary video stream. The primary video stream is + still used to select fragment cut points at keyframe boundaries. + Auxilliary video streams may be broken up at any packet - so + fragments may not start with a keyframe for those streams. + +- splitmuxsink: + + - new muxer-preset and sink-preset properties for setting + muxer/sink presets + - a new start-index property to set the initial fragment id + - and a new muxer-pad-map property which explicitly maps + splitmuxsink pads to the muxer pads they should connect to, + overriding the implicit logic that tries to match pads but + yields arbitrary names. + - Also includes the actual sink element in the fragment-opened and + fragment-closed element messages now, which is especially useful + for sinks without a location property or when finalisation of + the fragments is done asynchronously. + +- videocrop: add support for Y444, Y41B and Y42B pixel formats + +- vp8enc, vp9enc: change default value of VP8E_SET_STATIC_THRESHOLD + from 0 to 1 which matches what Google WebRTC does and results in + lower CPU usage; also added a new bit-per-pixel property to select a + better default bitrate + +- v4l2: add support for ABGR, xBGR, RGBA, and RGBx formats and for + handling interlaced video in alternate fields interlace mode (one + field per buffer instead of one frame per picture with both fields + interleaved) + +- v4l2: Profile and level probing support for H264, H265, MPEG-4, + MPEG-2, VP8, and VP9 video encoders and decoders + +Plugins Ugly + +- asfdemux: extract more metadata: disc number and disc count + +- x264enc: + + - respect YouTube bitrate recommendation when user sets the + YouTube profile preset + - separate high-10 video formats from 8-bit formats to improve + depth negotiation and only advertise suitable input raw formats + for the desired output depth + - forward downstream colorimetry and chroma-site restrictions to + upstream elements + - support more color primaries/mappings + +Plugins Bad + +- av1enc: add threads, row-mt and tile-{columns,rows} properties for + this AOMedia AV1 encoder + +- ccconverter: implement support for CDP framerate conversions + +- ccextractor: Add remove-caption-meta property to remove caption + metas from the outgoing video buffers + +- decklink: add support for 2K DCI video modes, widescreen NTSC/PAL, + and for parsing/outputting AFD/Bar data. Also implement a simple + device provider for Decklink devices. + +- dtlsrtpenc: add rtp-sync property which synchronises RTP streams to + the pipeline clock before passing them to funnel for merging with + RTCP. + +- fdkaac: also decode MPEG-2 AAC; encoder now supports more + multichannel/surround sound layouts + +- hlssink2: add action signals for custom playlist/fragment handling: + Instead of always going through the file system API we allow the + application to modify the behaviour. For the playlist itself and + fragments, the application can provide a GOutputStream. In addition + the sink notifies the application whenever a fragment can be + deleted. + +- interlace: can now output data in alternate fields mode; added field + switching mode for 2:2 field pattern + +- iqa: Add a mode property to enable strict mode that checks that all + the input streams have the exact same number of frames; also + implement the child proxy interface + +- mpeg2enc: add disable-encode-retries property for lower CPU usage + +- mpeg4videoparse: allow re-sending codec config at IDR via + config-interval=-1 + +- mpegtsparse: new alignment property to determine number of TS + packets per output buffer, useful for feeding an MPEG-TS stream for + sending via udpsink. This can be used in combination with the + split-on-rai property that makes sure to start a new output buffer + for any TS packet with the Random Access Indicator set. Also set + delta unit buffer flag on non-random-access buffers. + +- mpegdemux: add an ignore-scr property to ignore the SCR in + non-compliant MPEG-PS streams with a broken SCR, which will work as + long as PTS/DTS in the PES header is consistently increasing. + +- tsdemux: + + - add an ignore-pcr property to ignore MPEG-TS streams with broken + PCR streams on which we can’t reliably recover correct + timestamps. + - new latency property to allow applications to lower the + advertised worst-case latency of 700ms if they know their + streams support this (must have timestamps in higher frequency + than required by the spec) + - support for AC4 audio + +- msdk - Intel Media SDK plugin for hardware-accelerated video + decoding and encoding on Windows and Linux: + + - mappings for more video formats: Y210, Y410, P012_LE, Y212_LE + - encoders now support bitrate changes and input format changes in + playing state + - msdkh264enc, msdkh265enc: add support for CEA708 closed caption + insertion + - msdkh264enc, msdkh265enc: set Region of Interest (ROI) region + from ROI metas + - msdkh264enc, msdkh265enc: new tune property to enable low-power + mode + - msdkh265enc: add support 12-bit 4:2:0 encoding and 8-bit 4:2:2 + encoding and VUYA, Y210, and Y410 as input formats + - msdkh265enc: add support for screen content coding extension + - msdkh265dec: add support for main-12/main-12-intra, + main-422-10/main-422-10-intra 10bit, + main-422-10/main-422-10-intra 8bit, + main-422-12/main-422-12-intra, main-444-10/main-444-10-intra, + main-444-12/main-444-12-intra, and main-444 profiles + - msdkvp9dec: add support for 12-bit 4:4:4 + - msdkvpp: add support for Y410 and Y210 formats, cropping via + properties, and a new video-direction property. + +- mxf: Add support for CEA-708 CDP from S436 essence tracks. mxfdemux + can now handle Apple ProRes + +- nvdec: add H264 + H265 stateless codec implementation nvh264sldec + and nvh265sldec with fewer features but improved latency. You can + set the environment variable GST_USE_NV_STATELESS_CODEC=h264 to use + the stateless decoder variant as nvh264dec instead of the “normal” + NVDEC decoder implementation. + +- nvdec: add support for 12-bit 4:4:4/4:2:0 and 10-bit 4:2:0 decoding + +- nvenc: + + - add more rate-control options, support for B-frame encoding (if + device supports it), an aud property to toggle Access Unit + Delimiter insertion, and qp-{min,max,const}-{i,p,b} properties. + - the weighted-pred property enables weighted prediction. + - support for more input formats, namely 8-bit and 10-bit RGB + formats (BGRA, RGBA, RGB10A2, BGR10A2) and YV12 and VUYA. + - on-the-fly resolution changes are now supported as well. + - in case there are multiple GPUs on the system, there are also + per-GPU elements registered now, since different devices will + have different capabilities. + - nvh265enc can now support 10-bit YUV 4:4:4 encoding and 8-bit + 4:4:4 / 10-bit 4:2:0 formats up to 8K resolution (with some + devices). In case of HDR content HDR related SEI nals will be + inserted automatically. + +- openjpeg: enable multi-threaded decoding and add support for + sub-frame encoding (for lower latency) + +- rtponviftimestamp: add opt-out “drop-out-of-segment” property + +- spanplc: new stats property + +- srt: add support for IPv6 and for using hostnames instead of IP + addresses; add streamid property, but also allow passing the id via + the stream URI; add wait-for-connection property to srtsink + +- timecodestamper: this element was rewritten with an updated API + (properties); it has gained many new properties, seeking support and + support for linear timecode (LTC) from an audio stream. + +- uvch264src now comes with a device provider to advertise available + camera sources that support this interface (mostly Logitech C920s) + +- wpe: Add software rendering support and support for mouse scroll + events + +- x265enc: support more 8/10/12 bits 4:2:0, 4:2:2 and 4:4:4 profiles; + add support for mastering display info and content light level + encoding SEIs + +gst-libav + +- Add mapping for SpeedHQ video codec used by NDI + +- Add mapping for aptX and aptX-HD + +- avivf_mux: support VP9 and AV1 + +- avvidenc: shift output buffer timestamps and output segment by 1h + just like x264enc does, to allow for negative DTS. + +- avviddec: Limit default number of decoder threads on systems with + more than 16 cores, as the number of threads used in avdec has a + direct impact on the latency of the decoder, which is of as many + frames as threads, so a large numbers of threads can make for + latency levels that can be problematic in some applications. + +- avviddec: Add thread-type property that allows applications to + specify the preferred multithreading method (auto, frame, slice). + Note that thread-type=frame may introduce additional latency + especially in live pipelines, since it introduces a decoding delay + of number of thread frames. Plugin and library moves -- The stereo element was moved from -bad into the existing audiofx - plugin in -good. If you get duplicate type registration warnings - when upgrading, check that you don’t have a stale stereoplugin lying - about somewhere. - -GstVideoAggregator, compositor, and OpenGL mixer elements moved from -bad to -base - -GstVideoAggregator is a new base class for raw video mixers and muxers -and is based on GstAggregator. It provides defined-latency mixing of raw -video inputs and ensures that the pipeline won’t stall even if one of -the input streams stops producing data. - -As part of the move to stabilise the API there were some last-minute API -changes and clean-ups, but those should mostly affect internal elements. -Most notably, the "ignore-eos" pad property was renamed to -"repeat-after-eos" and the conversion code was moved to a -GstVideoAggregatorConvertPad subclass to avoid code duplication, make -things less awkward for subclasses like the OpenGL-based video mixer, -and make the API more consistent with the audio aggregator API. - -It is used by the compositor element, which is a replacement for -‘videomixer’ which did not handle live inputs very well. compositor -should behave much better in that respect and generally behave as one -would expected in most scenarios. - -The compositor element has gained support for per-pad blending mode -operators (SOURCE, OVER, ADD) which determines what operator to use for -blending this pad over the previous ones. This can be used to implement -crossfading and the available operators can be extended in the future as -needed. - -A number of OpenGL-based video mixer elements (glvideomixer, glmixerbin, -glvideomixerelement, glstereomix, glmosaic) which are built on top of -GstVideoAggregator have also been moved from -bad to -base now. These -elements have been merged into the existing OpenGL plugin, so if you get -duplicate type registration warnings when upgrading, check that you -don’t have a stale openglmixers plugin lying about somewhere. +- There were no plugin moves or library moves in this cycle. -Plugin removals +- The rpicamsrc element was moved into -good from an external + repository on github. -The following plugins have been removed from gst-plugins-bad: +Plugin removals -- The experimental daala plugin has been removed, since it’s not so - useful now that all effort is focused on AV1 instead, and it had to - be enabled explicitly with --enable-experimental anyway. +The following elements or plugins have been removed: -- The spc plugin has been removed. It has been replaced by the gme - plugin. +- The yadif video deinterlacing plugin from gst-plugins-bad, which was + one of the few GPL licensed plugins, has been removed in favour of + deinterlace method=yadif. -- The acmmp3dec and acmenc plugins for Windows have been removed. ACM - is an ancient legacy API and there was no point in keeping the - plugins around for a licensed MP3 decoder now that the MP3 patents - have expired and we have a decoder in -good. We also didn’t ship - these in our cerbero-built Windows packages, so it’s unlikely that - they’ll be missed. +- The avdec_cdgraphics CD Graphics video decoder element from + gst-libav was never usable in GStreamer and we now have a cdgdec + element written in Rust in gst-plugins-rs to replace it. +- The VDPAU plugin has been unmaintained and unsupported for a very + long time and does not have the feature set we expect from + hardware-accelerated video decoders. It’s been superseded by the + nvcodec plugin leveraging NVIDIA’s NVDEC API. Miscellaneous API additions -- GstBitwriter: new generic bit writer API to complement the existing - bit reader - -- gst_buffer_new_wrapped_bytes() creates a wrap buffer from a GBytes - -- gst_caps_set_features_simple() sets a caps feature on all the - structures of a GstCaps - -- New GST_QUERY_BITRATE query: This allows determining from downstream - what the expected bitrate of a stream may be which is useful in - queue2 for setting time based limits when upstream does not provide - timing information. tsdemux, qtdemux and matroskademux have basic - support for this query on their sink pads. - -- elements: there is a new “Hardware” class specifier. Elements - interacting with hardware devices should specify this classifier in - their element factory class metadata. This is useful to advertise as - one might need to put such elements into READY state to test if the - hardware is present in the system for example. - -- protection: Add a new definition for unspecified system protection, - GST_PROTECTION_UNSPECIFIED_SYSTEM_ID - -- take functions for various mini objects that didn’t have them yet: - gst_query_take(), gst_message_take(), gst_tag_list_take(), - gst_buffer_list_take(). Unlike the various _replace() functions - _take() does not increase the reference count but takes ownership of - the mini object passed. - -- clear functions for various mini object types and GstObject which - unrefs the object or mini object (if non-NULL) and sets the variable - pointed to to NULL: gst_clear_structure(), gst_clear_tag_list(), - gst_clear_query(), gst_clear_message(), gst_clear_event(), - gst_clear_caps(), gst_clear_buffer_list(), gst_clear_buffer(), - gst_clear_mini_object(), gst_clear_object() - -- miniobject: new API gst_mini_object_add_parent() and - gst_mini_object_remove_parent() to set parent pointers on mini - objects to ensure correct writability: Every container of - miniobjects now needs to store itself as parent in the child object, - and remove itself again later. A mini object is then only writable - if there is at most one parent, that parent is writable itself, and - the reference count of the mini object is 1. GstBuffer (for - memories), GstBufferList (for buffers), GstSample (for caps, buffer, - bufferlist), and GstVideoOverlayComposition were updated - accordingly. Without this it was possible to have e.g. a buffer list - with a refcount of 2 used in two places at once that both modify the - same buffer with refcount 1 at the same time wrongly thinking it is - writable even though it’s really not. - -- poll: add API to watch for POLLPRI and stop treating POLLPRI as a - read. This is useful to wait for video4linux events which are - signalled via POLLPRI. - -- sample: new API to update the contents of a GstSample and make it - writable: gst_sample_set_buffer(), gst_sample_set_caps(), - gst_sample_set_segment(), gst_sample_set_info(), plus - gst_sample_is_writable() and gst_sample_make_writable(). This makes - it possible to reuse a sample object and avoid unnecessary memory - allocations, for example in appsink. - -- ClockIDs now keep a weak reference to underlying clock to avoid - crashes in basesink in corner cases where a clock goes away while - the ClockID is still in use, plus some new API - (gst_clock_id_get_clock(), gst_clock_id_uses_clock()) to check the - clock a ClockID is linked to. - -- The GstCheck unit test library gained a - fail_unless_equals_clocktime() convenience macro as well as some new - GstHarness API for for proposing meta APIs from the allocation - query: gst_harness_add_propose_allocation_meta(). ASSERT_CRITICAL() - checks in unit tests are now skipped if GStreamer was compiled with - GST_DISABLE_GLIB_CHECKS. - -- gst_audio_buffer_truncate() convenience function to truncate a raw - audio buffer - -- GstDiscoverer has support for caching the results of discovery in - the default cache directory. This can be enabled with the use-cache - property and is disabled by default. - -- GstMeta that are attached to GstBuffers are now always stored in the - order in which they were added. - -- Additional support for signalling ONVIF specific features were - added: the SEEK event can store a trickmode-interval now and support - for the Rate-Control and Frames RTSP headers was added to the RTSP - library. - - -Miscellaneous performance and memory optimisations +GStreamer core + +- gst_task_resume(): This new API allows resuming a task if it was + paused, while leaving it in stopped state if it was stopped or not + started yet. This can be useful for callback-based driver workflows, + where you basically want to pause and resume the task when buffers + are notified while avoiding the race with a gst_task_stop() coming + from another thread. + +- info: add printf extensions GST_TIMEP_FORMAT and GST_STIMEP_FORMAT + for printing GstClockTime/GstClockTimeDiff pointers, which is much + more convenient to use in debug log statements than the usual + GST_TIME_FORMAT-followed-by-GST_TIME_ARGS dance. Also add an + explicit GST_STACK_TRACE_SHOW_NONE enum value. + +- gst_element_get_current_clock_time() and + gst_element_get_current_running_time(): new helper functions for + getting an element clock’s time, and the clock time minus base time, + respectively. Useful when adding additional input branches to + elements such as compositor, audiomixer, flvmux, interleave or + input-selector to determine initial pad offsets and such. + +- seeking: Add GST_SEEK_FLAG_TRICKMODE_FORWARD_PREDICTED to just skip + B-frames during trick mode, showing both keyframes + P-frame, and + add support for it in h264parse and h265parse. + +- elementfactory: add GST_ELEMENT_FACTORY_TYPE_HARDWARE to allow + elements to advertise that they are hardware-based or interact with + hardware. This has multiple applications: + + - it makes it possible to easily differentiate hardware and + software based element implementations such as audio or video + encoders and decoders. This is useful in order to force the use + of software decoders for specific use cases, or to check if a + selected decoder is actually hardware-accelerated or not. + - elements interacting with hardware and their respective drivers + typically don’t know the actually supported capabilities until + the element is set into at least READY state and can open a + device handle and probe the hardware. + +- gst_uri_from_string_escaped(): identical to gst_uri_from_string() + except that the userinfo and fragment components of the URI will not + be unescaped while parsing. This is needed for correctly parsing + usernames or passwords with : in them . + +- paramspecs: new GstParamSpec flag GST_PARAM_CONDITIONALLY_AVAILABLE + to indicate that a property might not always exist. + +- gst_bin_iterate_all_by_element_factory_name() finds elements in a + bin by factory name + +- pad: gst_pad_get_single_internal_link() is a new convenience + function to return the single internal link of a pad, which is + useful e.g. to retrieve the output pad of a new multiqueue request + pad. + +- datetime: Add constructors to create datetimes with timestamps in + microseconds, gst_date_time_new_from_unix_epoch_local_time_usecs() + and gst_date_time_new_from_unix_epoch_utc_usecs(). + +- gst_debug_log_get_lines() gets debug log lines formatted in the same + way the default log handler would print them + +- GstSystemClock: Add GST_CLOCK_TYPE_TAI as GStreamer abstraction for + CLOCK_TAI, to support transmission offloading features where network + packets are timestamped with the time they are deemed to be actually + transmitted. Useful in combination with the new AVTP plugin. + +- miscellaneous utility functions: gst_clear_uri(), + gst_structure_take(). + +- harness: Added gst_harness_pull_until_eos() + +- GstBaseSrc: + + - gst_base_src_new_segment() allows subclasses to update the + segment to be used at runtime from the ::create() function. This + deprecates gst_base_src_new_seamless_segment() + - gst_base_src_negotiate() allows subclasses to trigger format + renegotiation at runtime from inside the ::create() or ::alloc() + function + +- GstBaseSink: new stats property and gst_base_sink_get_stats() method + to retrieve various statistics such as average frame rate and + dropped/rendered buffers. + +- GstBaseTransform: gst_base_transform_reconfigure() is now public + API, useful for subclasses that need to completely re-implement the + ::submit_input_buffer() virtual method + +- GstAggregator: + + - gst_aggregator_update_segment() allows subclasses to update the + output segment at runtime. Subclasses should use this function + rather than push a segment event onto the source pad directly. + - new sample selection API: + - subclasses should now call gst_aggregator_selected_samples() + from their ::aggregate() implementation to signal that they + have selected the next samples they will aggregate + - GstAggregator will then emit the samples-selected signal + where handlers can then look up samples per pad via + gst_aggregator_peek_next_sample(). + - This is useful for example to atomically update input pad + properties in mixer subclasses such as compositor. + Applications can now update properties with precise control + of when these changes will take effect, and for which input + buffer(s). + - gst_aggregator_finish_buffer_list() allows subclasses to push + out a buffer list, improving efficiency in some cases. + - a ::negotiate() virtual method was added, for consistency with + other base classes and to allow subclasses to completely + override the negotiation behaviour. + - the new ::sink_event_pre_queue() and ::sink_query_pre_queue() + virtual methods allow subclasses to intercept or handle + serialized events and queries before they’re queued up + internally. + +GStreamer Plugins Base Libraries + +Audio library + +- audioaggregator, audiomixer: new output-buffer-duration-fraction + property which allows use cases such as keeping the buffers output + by compositor on one branch and audiomixer on another perfectly + aligned, by requiring the compositor to output a n/d frame rate, and + setting output-buffer-duration-fraction to d/n on the audiomixer. + +- GstAudioDecoder: new max-errors property so applications can + configure at what point the decoder should error out, or tell it to + just keep going + +- gst_audio_make_raw_caps() and gst_audio_formats_raw() are + bindings-friendly versions of the GST_AUDIO_CAPS_MAKE() C macro. + +- gst_audio_info_from_caps() now handles encoded audio formats as well + +PbUtils library + +- GstEncodingProfile: + - Do not restrict number of similar profiles in a container + - add GstValue serialization function +- codec utils now support more H.264/H.265 profiles/levels and have + improved extension handling + +RTP library + +- rtpbasepayloader: Add scale-rtptime property for scaling RTP + timestamp according to the segment rate (equivalent to RTSP speed + parameter). This is useful for ONVIF trickmodes via RTSP. + +- rtpbasepayload: add experimental property for embedding twcc + sequencenumbers for Transport-Wide Congestion Control (gated behind + the GST_RTP_ENABLE_EXPERIMENTAL_TWCC_PROPERTY environment + variable) - more generic API for enabling this is expected to land + in the next development cycle. + +- rtcpbuffer: add RTPFB_TYPE_TWCC for Transport-Wide Congestion + Control + +- rtpbuffer: add + gst_rtp_buffer_get_extension_onebyte_header_from_bytes()``, so that one can parse theGBytes` + returned by gst_rtp_buffer_get_extension_bytes() + +- rtpbasedepayload: Add max-reorder property to make the + previously-hardcoded value when to consider a sender to have + restarted configurable. In some scenarios it’s particularly useful + to set max-reorder=0 to disable the behaviour that the depayloader + will drop packets: when max-reorder is set to 0 all + reordered/duplicate packets are considered coming from a restarted + sender. + +RTSP library + +- add gst_rtsp_url_get_request_uri_with_control() to create request + uri combined with control url + +- GstRTSPConnection: add the possibility to limit the Content-Length + for RTSP messages via + gst_rtsp_connection_set_content_length_limit(). The same + functionality is also exposed in gst-rtsp-server. + +SDP library + +- add support for parsing the extmap attribute from caps and storing + inside caps The extmap attribute allows mapping RTP extension header + IDs to well-known RTP extension header specifications. See RFC8285 + for details. + +Tags library + +- update to latest iso-code and support more languages + +- add tags for acoustid id & acoustid fingerprint, plus MusicBrainz ID + handling fixes + +Video library + +- High Dynamic Range (HDR) video information representation and + signalling enhancements: + + - New APIs for HDR video information representation and + signalling: + - GstVideoMasteringDisplayInfo: display color volume info as + per SMPTE ST 2086 + - GstVideoContentLightLevel: content light level specified in + CEA-861.3, Appendix A. + - plus functions to serialise/deserialise and add them to or + parse them from caps + - gst_video_color_{matrix,primaries,transfer}_{to,from}_iso(): + new utilility functions for conversion from/to ISO/IEC + 23001-8 + - add ARIB STD-B67 transfer chracteristic function + - add SMPTE ST 2084 support and BT 2100 colorimetry + - define bt2020-10 transfer characteristics for clarity: + bt707, bt2020-10, and bt2020-12 transfer characteristics are + functionally identical but have their own unique values in + the specification. + - h264parse, h265parse: Parse mastering display info and content + light level from SEIs. + - matroskademux: parse HDR metadata + - matroskamux: Write MasteringMetadata and Max{CLL,FALL}. Enable + muxing with HDR meta data if upstream provided it + - avviddec: Extract HDR information if any and map bt2020-10, PQ + and HLG transfer functions + +- added bt601 transfer function (for completeness) + +- support for more pixel formats: + + - Y412 (packed 12 bits 4:4:4:4) + - Y212 (packed 12 bits 4:2:2) + - P012 (semi-planar 4:2:0) + - P016_{LE,BE} (semi-planar 16 bits 4:2:0) + - Y444_16{LE,BE} (planar 16 bits 4:4:4) + - RGB10A2_LE (packed 10-bit RGB with 2-bit alpha channel) + - NV12_32L32 (NV12 with 32x32 tiles in linear order) + - NV12_4L4 (NV12 with 4x4 tiles in linear order) + +- GstVideoDecoder: + + - new max-errors property so applications can configure at what + point the decoder should error out, or tell it to just keep + going + + - new qos property to disable dropping frames because of QoS, and + post QoS messages on the bus when dropping frames. This is + useful for example in a scenario where the decoded video is + tee-ed off to go into a live sink that syncs to the clock in one + branch, and an encoding and save to file pipeline in the other + branch. In that case one wouldn’t want QoS events from the video + sink make the decoder drop frames because that would also leave + gaps in the encoding branch then. + +- GstVideoEncoder: + + - gst_video_encoder_finish_subframe() is new API to push out + subframes (e.g. slices), so encoders can split the encoding into + subframes, which can be useful to reduce the overall end-to-end + latency as we no longer need to wait for the full frame to be + encoded to start decoding or sending out the data. + - new min-force-key-unit-interval property allows configuring the + minimum interval between force-key-unit requests and prevents a + big bitrate increase if a lot of key-units are requested in a + short period of time (as might happen in live streaming RTP + pipelines when packet loss is detected). + - various force-key-unit event handling fixes + +- GstVideoAggregator, compositor, glvideomixer: expose + max-last-buffer-repeat property on pads. This can be used to have a + compositor display either the background or a stream on a lower + zorder after a live input stream freezes for a certain amount of + time, for example because of network issues. + +- gst_video_format_info_component() is new API to find out which + components are packed into a given plane, which is useful to prevent + us from assuming a 1-1 mapping between planes and components. + +- gst_video_make_raw_caps() and gst_video_formats_raw() are + bindings-friendly versions of the GST_VIDEO_CAPS_MAKE() C macro. + +- video-blend: Add support for blending on top of 16 bit per component + formats, which makes sure we can support every currently supported + raw video format for blending subtitles or logos on top of video. + +- GST_VIDEO_BUFFER_IS_TOP_FIELD() and + GST_VIDEO_BUFFER_IS_BOTTOM_FIELD() convenience macros to check + whether the video buffer contains only the top field or bottom field + of an interlaced picture. + +- GstVideoMeta now includes an alignment field with the + GstVideoAlignment so buffer producers can explicitly specify the + exact geometry of the planes, allowing users to easily know the + padded size and height of each plane. Default values will be used if + this is not set. + + Use gst_video_meta_set_alignment() to set the alignment and + gst_video_meta_get_plane_size() or gst_video_meta_get_plane_height() + to compute the plane sizes or plane heights based on the information + in the video meta. + +- gst_video_info_align_full() works like gst_video_info_align() but + also retrieves the plane sizes. + +MPEG-TS library + +- support for SCTE-35 sections + +- extend support for ATSC tables: + + - System Time Table (STT) + - Master Guide Table (MGT) + - Rating Region Table (RRT) + +Miscellaneous performance, latency and memory optimisations As always there have been many performance and memory usage improvements -across all components and modules. Some of them (such as dmabuf -import/export) have already been mentioned elsewhere so won’t be -repeated here. +across all components and modules. Some of them have already been +mentioned elsewhere so won’t be repeated here. The following list is only a small snapshot of some of the more interesting optimisations that haven’t been mentioned in other contexts yet: -- The GstVideoEncoder and GstVideoDecoder base classes now release the - STREAM_LOCK when pushing out buffers, which means (multi-threaded) - encoders and decoders can now receive and continue to process input - buffers whilst waiting for downstream elements in the pipeline to - process the buffer that was pushed out. This increases throughput - and reduces processing latency, also and especially for - hardware-accelerated encoder/decoder elements. +- caps negotiation, structure and GValue performance optimizations -- GstQueueArray has seen a few API additions - (gst_queue_array_peek_nth(), gst_queue_array_set_clear_func(), - gst_queue_array_clear()) so that it can be used in other places like - GstAdapter instead of a GList, which reduces allocations and - improves performance. +- systemclock: clock waiting performance improvements (moved from + GstPoll to GCond for waiting), especially on Windows. -- appsink now reuses the sample object in pull_sample() if possible +- rtpsession: add support for buffer lists on the recv path for better + performance with higher packet rate streams. -- rtpsession only starts the RTCP thread when it’s actually needed now +- rtpjitterbuffer: internal timer handling has been rewritten for + better performance, see Nicolas’ talk “Revisiting RTP Jitter Buffer + Timers” for more details. -- udpsrc uses a buffer pool now and the GstUdpSrc object structure was - optimised for better cache performance +- H.264/H.265 parsers and RTP payloaders/depayloaders have been + optimised for latency to make sure data is processed and pushed out + as quickly as possible -GstPlayer +- video-scaler: correctness and performance improvements, esp. for + interlaced formats and GBRA -- API was added to fine-tune the synchronisation offset between - subtitles and video +- GstVideoEncoder has gained new API to push out subframes + (e.g. slices), so encoders can split the encoding into subframes, + which can be useful to reduce the overall end-to-end latency as we + no longer need to wait for the full frame to be encoded to start + decoding or sending out the data. + This is complemented by the new GST_VIDEO_BUFFER_FLAG_MARKER which + is a video-specific buffer flag to mark the end of a video frame, so + elements can know that they have received all data for a frame + without waiting for the beginning of the next frame. This is similar + to how the RTP marker flag is used in many RTP video mappings. -Miscellaneous changes + The video encoder base class now also releases the internal stream + lock before pushing out data, so as to not block the input side of + things from processing more data in the meantime. -- As a result of moving to newer FFmpeg APIs, encoder and decoder - elements exposed by the GStreamer FFmpeg wrapper plugin (gst-libav) - may have seen possibly incompatible changes to property names and/or - types, and not all properties exposed might be functional. We are - still reviewing the new properties and aim to minimise breaking - changes at least for the most commonly-used properties, so please - report any issues you run into! +Miscellaneous other changes and enhancements + +- it is now possible to modify the initial rank of plugin features + without modifying the source code or writing code to do so + programmatically via the GST_PLUGIN_FEATURE_RANK environment + variable. Users can adjust the rank of plugin(s) by passing a + comma-separated list of feature:rank pairs where rank can be a + numerical value or one of NONE, MARGINAL, SECONDARY, PRIMARY, and + MAX. Example: GST_PLUGIN_FEATURE_RANK=myh264dec:MAX,avdec_h264:NONE + sets the rank of the myh264dec element feature to the maximum and + that of avdec_h264 to 0 (none), thus ensuring that myh264dec is + prefered as H264 decoder in an autoplugging context. + +- GstDeviceProvider now does a static probe on start as fallback for + providers that don’t support dynamic probing to make things easier + for users + +WebRTC + +- webrtcbin now contains initial support for renegotiation involving + stream addition and removal. There are a number of caveats to this + initial renegotiation support and many complex scenarios are known + to require some work. + +- webrtcbin now exposes the internal ICE object for advanced + configuration options. Using the internal ICE object, it is possible + to toggle UDP or TCP connection usage as well as provide local + network addresses. + +- Fix a number of call flows within webrtcbin’s GstPromise handling + where a promise was never replied to. This has been fixed and now a + promise will always receive a reply. + +- webrtcbin now exposes a latency property for configuring the + internal rtpjitterbuffer latency and buffering when receiving + streams. + +- webrtcbin now only synchronises the RTP part of a stream, allowing + RTCP messages to skip synchronisation entirely. + +- Fixed most of the webrtcbin state properties (connection-state, + ice-connection-state, signaling-state, but not ice-gathering-state + as that requires newer API in libnice and will be fixed in the next + release series) to advance through the state values correctly. Also + implemented DTLS connection states in the DTLS elements so that + peer-connection-state is not always new. + +- webrtcbin now accounts for the a=ice-lite attribute in a remote SDP + offer and will configure the internal ICE implementation + accordingly. + +- webrtcbin will now resolve .local candidate addresses using the + system DNS resolver. .local candidate addresses are now produced by + web browsers to help protect the privacy of users. + +- webrtcbin will now add candidates found in the SDP to the internal + ICE agent. This was previously unsupported and required using the + add-ice-candidate signal manually from the application. + +- webrtcbin will now correctly parse a TURN URI that contains a + username or password with a : in it. + +- The GStreamer WebRTC library gained a GstWebRTCDataChannel object + roughly matching the interface exposed by the WebRTC specification + to allow for easier binding generation and use of data channels. OpenGL integration -- The OpenGL mixer elements have been moved from -bad to - gst-plugins-base (see above) +GStreamer OpenGL bindings/build related changes -- The Mesa GBM backend now supports headless mode +- The GStreamer OpenGL library (libgstgl) now ships pkg-config files + for platform-specific API where libgstgl provides a public + integration interface and a pkg-config file for a dependency on the + detected OpenGL headers. The new list of pkg-config files in + addition to the original gstreamer-gl-1.0 are gstreamer-gl-x11-1.0, + gstreamer-gl-wayland-1.0, gstreamer-gl-egl-1.0, and + gstreamer-gl-prototypes-1.0 (for OpenGL headers when including + gst/gl/gstglfuncs.h). -- gloverlaycompositor: New OpenGL-based compositor element that - flattens any overlays from GstVideoOverlayCompositionMetas into the - video stream. +- GStreamer OpenGL now ships some platform-specific introspection data + for platforms that have a public interface. This should allow for + easier integration with bindings involving platform specific + functionality. The new introspection data files are named + GstGLX11-1.0, GstGLWayland-1.0, and GstGLEGL-1.0. -- glalpha: New element that adds an alpha channel to a video stream. - The values of the alpha channel can either be set to a constant or - can be dynamically calculated via chroma keying. It is similar to - the existing alpha element but based on OpenGL. Calculations are - done in floating point so results may not be identical to the output - of the existing alpha element. +GStreamer OpenGL Features -- glupload: Implement direct dmabuf uploader, the idea being that some - GPUs (like the Vivante series) can actually perform the YUV->RGB - conversion internally, so no custom conversion shaders are needed. - To make use of this feature, we need an additional uploader that can - import DMABUF FDs and also directly pass the pixel format, relying - on the GPU to do the conversion. +- The iOS implementation no longer accesses UIKit objects off the main + thread fixing a loud warning message when used in iOS applications. -- The OpenGL library no longer restores the OpenGL viewport. This is a - performance optimization to not require performing multiple - expensive glGet*() function calls per frame. This affects any - application or plugin use of the following functions and objects: - - glcolorconvert library object (not the element) - - glviewconvert library object (not the element) - - gst_gl_framebuffer_draw_to_texture() - - custom GstGLWindow implementations +- Support for mouse and keyboard handling using the GstNavigation + interface was added for the wayland implementation complementing the + already existing support for the X11 and Windows implementations. +- A new helper base class for source elements, GstGLBaseSrc is + provided to ease writing source elements producing OpenGL video + frames. -Tracing framework and debugging improvements +- Support for some more 12-bit and 16-bit video formats (Y412_LE, + Y412_BE, Y212_LE, Y212_BE, P012_LE, P012_BE, P016, NV16, NV61) was + added to glcolorconvert. -- There is now a GDB PRETTY PRINTER FOR VARIOUS GSTREAMER TYPES: For - GstObject pointers the type and name is added, e.g. - 0x5555557e4110 [GstDecodeBin|decodebin0]. For GstMiniObject pointers - the object type is added, e.g. 0x7fffe001fc50 [GstBuffer]. For - GstClockTime and GstClockTimeDiff the time is also printed in human - readable form, e.g. 150116219955 [+0:02:30.116219955]. +- glupload can now import dma-buf’s into external-oes textures. -- GDB EXTENSION WITH TWO CUSTOM GDB COMMANDS gst-dot AND gst-print: +- A new display type for EGLDevice-based systems was added. It is + currently opt-in by using either the GST_GL_PLATFORM=egl-device + environment variable or manual construction + (gst_gl_display_egl_device_new*()) due to compatibility issues with + some platforms. - - gst-dot creates dot files that a very close to what - GST_DEBUG_BIN_TO_DOT_FILE() produces, but object properties and - buffer contents such as codec-data in caps are not available. +- Support was added for WinRT/UWP using the ANGLE project for running + OpenGL-based pipelines within a UWP application. - - gst-print produces high-level information about a GStreamer - object. This is currently limited to pads for GstElements and - events for the pads. The output may look like this: +- Various elements now support changing the GstGLDisplay to be used at + runtime in simple cases. This is primarily helpful for changing or + adding an OpenGL-based video sink that must share an OpenGL context + with an external source to an already running pipeline. -- gst_structure_to_string() now serialises the actual value of - pointers when serialising GstStructures instead of claiming they’re - NULL. This makes debug logging in various places less confusing, - because it’s clear now that structure fields actually hold valid - objects. Such object pointer values will never be deserialised - however. +GStreamer Vulkan integration +- There is now a GStreamer Vulkan library to provide integration + points and helpers with applications and external GStreamer Vulkan + based elements. The structure of the library is modelled similarly + to the already existing GStreamer OpenGL library. Please note that + the API is still unstable and may change in future releases, + particularly around memory handling. The GStreamer Vulkan library + contains objects for sharing the vkInstance, vkDevice, vkQueue, + vkImage, VkMemory, etc with other elements and/or the application as + well as some helper objects for using Vulkan in an application or + element. + +- Added support for building and running on/for the Android and + Windows systems to complement the existing XCB, Wayland, MacOS, and + iOS implementations. + +- XCB gained support for mouse/keyboard events using the GstNavigation + API. + +- New vulkancolorconvert element for converting between color formats. + vulkancolorconvert can currently convert to/from all 8-bit RGBA + formats as well as 8-bit RGBA formats to/from the YUV formats AYUV, + NV12, and YUY2. + +- New vulkanviewconvert element for converting between stereo view + layouts. vulkanviewconvert can currently convert between all of the + single memory formats (side-by-side, top-bottom, column-interleaved, + row-interleaved, checkerboard, left, right, mono). + +- New vulkanimageidentity element for a blit from the input vulkan + image/s to a new vulkan image/s. + +- The vulkansink element can now scale the input image to the output + window/surface size where that information is available. + +- The vulkanupload element can now configure a transfer from system + memory to VulkanImage-based memory. Previously, this required two + vulkanupload elements. + +Tracing framework and debugging improvements + +- gst_tracing_get_active_tracers() returns a list of active tracer + objects. This can be used to interact with tracers at runtime using + GObject API such as action signals. This has been implemented in the + leaks tracer for snapshotting and retrieving leaked/active objects + at runtime. + +- The leaks tracer can now be interacted with programmatically at + runtime via GObject action signals: + + - get-live-object returns a list of live (allocated) traced + objects + - log-live-objects logs a list of live objects into the debug log. + This is the same as sending the SIGUSR1 signal on unix systems, + but works on all operating systems including Windows. + - activity-start-tracking, activity-get-checkpoint, + activity-log-checkpoint, activity-stop-tracking: add support for + tracking and checkpointing objects, similar to what was + previously available via SIGUSR2 on unix systems, but works on + all operating systems including Windows. + +- various GStreamer gdb debug helper improvements: + + - new ‘gst-pipeline-tree’ command + - more gdb helper functions: gst_element_pad(), gst_pipeline() and + gst_bin_get() + - support for queries and buffers + - print more info for segment events, print event seqnums, object + pointers and structures + - improve gst-print command to show more pad and element + information Tools -- gst-inspect-1.0 has coloured output now and will automatically use a - pager if the output does not fit on a page. This only works in a - UNIX environment and if the output is not piped, and on Windows 10 - build 16257 or newer. If you don’t like the colours you can disable - them by setting the GST_INSPECT_NO_COLORS=1 environment variable or - passing the --no-color command line option. +gst-launch-1.0 +- now prints the pipeline position and duration if available when the + pipeline is advancing. This is hopefully more user-friendly and + gives visual feedback on the terminal that the pipeline is actually + up and running. This can be disabled with the --no-position command + line option. -GStreamer RTSP server +- the parse-launch pipeline syntax now has support for presets: + use@preset=" after an element to load a preset. -- Improved backlog handling when using TCP interleaved for data - transport. Before there was a fixed maximum size for backlog - messages, which was prone to deadlocks and made it difficult to - control memory usage with the watch backlog. The RTSP server now - limits queued TCP data messages to one per stream, moving queuing of - the data into the pipeline and leaving the RTSP connection - responsive to RTSP messages in both directions, preventing all those - problems. +gst-inspect-1.0 -- Initial ULP Forward Error Correction support in rtspclientsink and - for RECORD mode in the server. +- new --color command line option to force coloured output even if not + connected to a tty -- API to explicitly enable retransmission requests (RTX) +gst-tester-1.0 (new) -- Lots of multicast-related fixes +- gst-tester-1.0 is a new tool for plugin developers to launch + .validatetest files with TAP compatible output, meaning it can + easily and cleanly be integrated with the meson test harness. It + allows you to use gst-validate (from the gst-devtools module) to + write integration tests in any GStreamer repository whilst keeping + the tests as close as possible to the code. The tool transparently + handles gst-validate being installed or not: if it is not installed + those integration tests will simply be skipped. -- rtsp-auth: Add support for parsing .htdigest files +gst-play-1.0 +- interactive keyboard controls now also work on Windows -GStreamer VAAPI +gst-transcoder-1.0 (new) -- Support Wayland’s display for context sharing, so the application - can pass its own wl_display in order to be used for the VAAPI - display creation. +- gst-transcoder-1.0 is a new command line tool to transcode one URI + into another URI based on the specified encoding profile using the + new GstTranscoder API (see above). -- A lot of work to support new Intel hardware using media-driver as VA - backend. +GStreamer RTSP server -- For non-x86 devices, VAAPI display can instantiate, through DRM, - with no PCI bus. This enables the usage of libva-v4l2-request - driver. +- Fix issue where the first few packets (i.e. keyframes) could + sometimes be dropped if the rtsp media pipeline had a live input. + This was a regression from GStreamer 1.14. There are more fixes + pending for that which will hopefully land in 1.18.1. + +- Fix backpressure handling when sending data in TCP interleave mode + where RTSP requests and responses and RTP/RTCP packets flow over the + same RTSP TCP connection: The previous implementation would at some + point stop sending data to other clients when a single client + stopped consuming data or did not consume data fast enough. This + obviously created problems for shared media, where the same stream + from a single producer pipeline is sent to multiple clients. Instead + we now manage a backlog in the server’s stream-transport component + and remove slow clients once this backlog exceeds a maximum duration + (which is currently hardcoded). + +- Onvif Streaming Specification trick modes support (see section at + the beginning) + +- Scale/Speed header support: Speed will deliver the data at the + requested speed, which means increasing the data bandwidth for + speeds > 1.0. Scale will attempt to do the same without affecting + the overall bandwidth requirement vis-a-vis normal playback speed + (e.g. it might drop data for fast-forward playback). + +- rtspclientsink: send buffer lists in one go for better performance -- Added support for XDG-shell protocol as wl_shell replacement which - is currently deprecated. This change add as dependency - wayland-protocol. +GStreamer VAAPI -- GstVaapiFilter, GstVaapiWindow, and GstVaapiDecoder classes now - inherit from GstObject, gaining all the GStreamer’s instrumentation - support. +- A lot of work was done adding support for media-driver (iHD), the + new VAAPI driver for Intel, mostly for Gen9 onwards. -- The metadata now specifies the plugin as Hardware class. +- Available color formats and frame sizes are now detected at run-time + according to the context configuration. -- H264 decoder is more stable with problematic streams. +- Gallium drivers have been re-enabled in the allowed drivers list -- In H265 decoder added support for profiles main-422-10 (P010_10LE), - main-444 (AYUV) and main-444-10 (Y410) +- Improved the mapping between VA formats and GStreamer formats by + generating a mapping table at run-time since even among different + drivers the mapping might be different, particularly for RGB with + little endianness. -- JPEG decoder handles dynamic resolution changes. +- The experimental Flexible Encoding Infrastructure (FEI) elements + have been removed since they were not really actively maintained or + tested. -- More specification adherence in H264 and H265 encoders. +- Enhanced the juggling of DMABuf buffers and VASurface metas +- New vaapioverlay element: a compositor element using VA VPP blend + capabilities to accelerate overlaying and compositing. Example + pipeline: -GStreamer OMX + gst-launch-1.0 -vf videotestsrc ! vaapipostproc ! tee name=testsrc ! queue \ + ! vaapioverlay sink_1::xpos=300 sink_1::alpha=0.75 name=overlay ! vaapisink \ + testsrc. ! queue ! overlay. -- Add support of NV16 format to video encoders input. +vaapipostproc -- Video decoders now handle the ALLOCATION query to tell upstream - about the number of buffers they require. Video encoders will also - use this query to adjust their number of allocated buffers - preventing starvation when using dynamic buffer mode. +- added video-orientation support, supporting frame mirroring and + rotation -- The OMX_PERFORMANCE debug category has been renamed to OMX_API_TRACE - and can now be used to track a widder variety of interactions - between OMX and GStreamer. +- added cropping support, either via properties (crop-left, + crop-right, crop-bottom and crop-top) or buffer meta. -- Video encoders will now detect frame rate only changes and will - inform OMX about it rather than doing a full format reset. +- new skin-tone-enhancenment-level property which is the iHD + replacement of the i965 driver’s sink-tone-level. Both are + incompatible with each other, so both were kept. -- Various Zynq UltraScale+ specific improvements: - - Video encoders are now able to import dmabuf from upstream. - - Support for HEVC range extension profiles and more AVC profiles. - - We can now request video encoders to generate an IDR using the - force key unit event. +- handle video colorimetry +- support HDR10 tone mapping -GStreamer Editing Services and NLE +vaapisink -- Added a gesdemux element, it is an auto pluggable element that - allows decoding edit list like files supported by GES +- resurrected wayland backend for non-weston compositors by extracting + the DMABuf from the VASurface and rendering it. -- Added gessrc which wraps a GESTimeline as a standard source element - (implementing the ges protocol handler) +- merged the video overlay API for wayland. Now applications can + define the “window” to render on. -- Added basic support for videorate::rate property potentially - allowing changing playback speed +- demoted the vaapisink element to secondary rank since libva + considers rendering as a second-class feature. -- Layer priority is now fully automatic and they should be moved with - the new ges_timeline_move_layer method, ges_layer_set_priority is - now deprecated. +VAAPI Encoders -- Added a ges_timeline_element_get_layer_priority so we can simply get - all information about GESTimelineElement position in the timeline +- new common target-percentage property which is the desired target + percentage of bitrate for variable rate control. -- GESVideoSource now auto orientates the images if it is defined in a - meta (overridable). +- encoders now extract their caps from the driver at registration + time. -- Added some PyGObject overrides to make the API more pythonic +- vaapivp9enc: added support for low power mode and support for + profile 2 (profile 0 by default) -- The threading model has been made more explicit with safe guard to - make sure not thread safe APIs are not used from the wrong threads. - It is also now possible to properly handle in what thread the API - should be used. +- vaapih264enc: new max-qp property that sets the maximum quantization + value. Support for ICQ and QBVR bitrate control mode, adding a + quality-factor property for these modes. Support baseline profile as + constrained-baseline -- Optimized GESClip and GESTrackElement creation +- vaapih265enc: -- Added a way to compile out the old, unused and deprecated - GESPitiviFormatter + - support for main-444 and main-12 encoding profiles. + - new max-qp property that sets the maximum quantization value. + - support for ICQ and QBVR bitrate control mode, adding a + quality-factor property for these modes. + - handle SCC profiles. + - num-tile-cols and num-tile-row properties to specify the number + of tiles to use. + - the low-delay-b property was deprecated and is now determined + automatically. + - improved profile selection through caps. -- Re implemented the timeline editing API making it faster and making - the code much more maintainable +VAAPI Decoders -- Simplified usage of nlecomposition outside GES by removing quirks in - it API usage and removing the need to treat it specially from an - application perspective. +- Decoder surfaces are not bound to their context any longer and can + thus be created and used dynamically, removing the deadlock + headache. -- ges-launch-1.0: +- Reverse playback is now fluid - - Added support to add titles to the timeline - - Enhance the help auto generating it from the code +- Forward Region-of-Interest (ROI) metas downstream -- Deprecate ges_timeline_load_from_uri as loading the timeline should - be done through a project now +- GLTextureUploadMeta uses DMABuf when GEM is not available. Now + Gallium drivers can use this meta for rendering with EGL. -- MANY leaks have been plugged and the unit testsuite is now “leak - free” +- vaapivp9dec: support for 4:2:2 and 4:4:4 chroma type streams +- vaapih265dec: skip all pictures prior to the first I-frame. Enable + passing range extension flags to the driver. Handle SCC profiles. -GStreamer validate +- vaapijpegdec: support for 4:0:0, 4:1:1, 4:2:2 and 4:4:4 chroma types + pictures -- Added an action type to verify the checksum of the sink last-sample +- vaapih264dec: handle baseline streams as constrained-baseline if + possible and make it more tolerant when encountering unknown NALs -- Added an include keyword to validate scenarios +GStreamer OMX -- Added the notion of variable in scenarios, with the set-vars keyword +- omxvideoenc: use new video encoder subframe API to push out slices + as soon as they’re ready -- Started adding support for “performance” like tests by allowing to - define the number of dropped buffers or the minimum buffer frequency - on a specific pad +- omxh264enc, omxh265enc: negotiate subframe mode via caps. To enable + it, force downstream caps to video/x-h264,alignment=nal or + video/x-h265,alignment=nal. -- Added a validateflow plugin which allows defining the data flow to - be seen on a particular pad and verifying that following runs match - the expectations +- omxh264enc: Add ref-frames property -- Added support for appsrc based test definition so we can instrument - the data pushed into the pipeline from scenarios +- Zynq ultrascale+ specific video encoder/decoder improvements: -- Added a mockdecryptor allowing adding tests with on encrypted files, - the element will potentially be instrumented with a validate - scenario + - GRAY8 format support + - support for alternate fields interlacing mode + - video encoder: look-ahead, long-term-ref, and long-term-freq + properties -- gst-validate-launcher: +GStreamer Editing Services and NLE - - Cleaned up output +- Added nested timelines and subproject support so that GES projects + can be used as clips, potentially serializing nested projects in the + main file or referencing external project files. - - Changed the default for “muting” tests as user doesn’t expect - hundreds of windows to show up when running the testsuite +- Implemented an OpenTimelineIO GES formatter. This means GES and + GStreamer can now load and save projects in all the formats + supported by otio. - - Fixed the outputted xunit files to be compatible with GitLab +- Implemented a GESMarkerList object which allow setting timed + metadata on any GES object. - - Added support to run tests on media files in push mode (using - pushfile://) +- Fixed audio rendering issues during clip transition by ensuring that + a single segment is pushed into encoders. - - Added support for running inside gst-build +- The GESUriClipAsset API is now MT safe. - - Added support for running ssim tests on rendered files +- Added ges_meta_container_register_static_meta() to allow fixing a + type for a specific metadata without actually setting a value. - - Added a way to simply define tests on pipelines through a simple - .json file +- The framepositioner element now handles resizing the project and + keeps the same positioning when the aspect ratio is not changed . - - Added a python app to easily run python testsuite reusing all - the launcher features +- Reworked the documentation, making it more comprehensive and much + more detailed. - - Added flatpak knowledge so we can print backtrace even when - running from within flatpak +- Added APIs to retrieve natural size and framerate of a clip (for + example in the case of URIClip it is the framerate/size of the + underlying file). - - Added a way to automatically generated “known issues” - suppressions lines +- ges_container_edit() is now deprecated and GESTimelineElement gained + the ges_timeline_element_edit() method so the editing API is now + usable from any element in the timeline. - - Added a way to rerun tests to check if they are flaky and added - a way to tolerate tests known to be flaky +- GESProject::loading was added so applications can be notified about + when a new timeline starts loading. - - Add a way to output html log files +- Implemented the GstStream API in GESTimeline. +- Added a way to add a timeoverlay inside the test source (potentially + with timecodes). -GStreamer Python Bindings +- Added APIs to convert times to frame numbers and vice versa: -- add binding for gst_pad_set_caps() + - ges_timeline_get_frame_time() -- pygobject dependency requirement was bumped to >= 3.8 + - ges_timeline_get_frame_at() -- new audiotestsrc, audioplot, and mixer plugin examples, and a - dynamic pipeline example + - ges_clip_asset_get_frame_time() + - ges_clip_get_timeline_time_from_source_frame() -GStreamer C# Bindings + Quite a few validate tests have been implemented to check the + behavior for various demuxer/codec formats -- bindings for the GstWebRTC library +- Added ges_layer_set_active_for_tracks() which allows muting layers + for the specified tracks +- Deprecated GESImageSource and GESMultiFileSource now that we have + imagesequencesrc which handles the imagesequence “protocol” -GStreamer Rust Bindings +- Stopped exposing ‘deinterlacing’ children properties for clip types + where they do not make sense. -The GStreamer Rust bindings are now officially part of the GStreamer -project and are also maintained in the GStreamer GitLab. +- Added support for simple time remapping effects -The releases will generally not be synchronized with the releases of -other GStreamer parts due to dependencies on other projects. +GStreamer validate -Also unlike the other GStreamer libraries, the bindings will not commit -to full API stability but instead will follow the approach that is -generally taken by Rust projects, e.g.: +- Introduced the concept of “Test files” allowing to implement “all + included” test cases, meaning that inside the file the following can + be defined: -1) 0.12.X will be completely API compatible with all other 0.12.Y - versions. -2) 0.12.X+1 will contain bugfixes and compatible new feature additions. -3) 0.13.0 will _not_ be backwards compatible with 0.12.X but projects - will be able to stay at 0.12.X without any problems as long as they - don’t need newer features. + - The application arguments + - The validate configurations + - The validate scenario -The current stable release is 0.12.2 and the next release series will be -0.13, probably around March 2019. + This replaces the previous big dictionary file in + gst-validate-launcher to implement specific test cases. -At this point the bindings cover most of GStreamer core (except for most -notably GstAllocator and GstMemory), and most parts of the app, audio, -base, check, editing-services, gl, net. pbutils, player, rtsp, -rtsp-server, sdp, video and webrtc libraries. + We set several variables inside the files (as well as inside + scenarios and config files) to make them relocatable. -Also included is support for creating subclasses of the following types -and writing GStreamer plugins: + The file format has been enhanced so it is easier to read and write, + for example line ending with a coma or (curly) brackets can now be + used as continuation marker so you do not need to add \ at the end + of lines to write a structure on several lines. -- gst::Element -- gst::Bin and gst::Pipeline -- gst::URIHandler and gst::ChildProxy -- gst::Pad, gst::GhostPad -- gst_base::Aggregator and gst_base::AggregatorPad -- gst_base::BaseSrc and gst_base::BaseSink -- gst_base::BaseTransform +- Support the imagesequence “protocol” and added integration tests for + it. -Changes to 0.12.X since 0.12.0 +- Added action types to allow the scenario to run the Test Clock for + better reproducibility of tests. -Fixed +- Support generating tests to check that seeking is frame accurate + (base on ssim). -- PTP clock constructor actually creates a PTP instead of NTP clock +- Added ways to record buffers checksum (in different ways) in the + validateflow module. -Added +- Added vp9 encoding tests. -- Bindings for GStreamer Editing Services -- Bindings for GStreamer Check testing library -- Bindings for the encoding profile API (encodebin) +- Enhanced seeking action types implementation to allow support for + segment seeks. -- VideoFrame, VideoInfo, AudioInfo, StructureRef implements Send and - Sync now -- VideoFrame has a function to get the raw FFI pointer -- From impls from the Error/Success enums to the combined enums like - FlowReturn -- Bin-to-dot file functions were added to the Bin trait -- gst_base::Adapter implements SendUnique now -- More complete bindings for the gst_video::VideoOverlay interface, - especially - gst_video::is_video_overlay_prepare_window_handle_message() +- Output improvements: -Changed + - Logs are now in markdown formats (and bat is used to dump them + if available). + - File format issues in scenarios/configs/tests files are nicely + reported with the line numbers now. -- All references were updated from GitHub to freedesktop.org GitLab -- Fix various links in the README.md -- Link to the correct location for the documentation -- Remove GitLab badge as that only works with gitlab.com currently +GStreamer Python Bindings -Changes in git master for 0.13 +- Python 2.x is no longer supported -Fixed +- Support mapping buffers without any memcpy: -- gst::tag::Album is the album tag now instead of artist sortname + - Added a ContextManager to make the API more pythonic -Added + with buf.map(Gst.MapFlags.READ | Gst.MapFlags.WRITE) as info: + info.data[42] = 0 -- Subclassing infrastructure was moved directly into the bindings, - making the gst-plugin crate deprecated. This involves many API - changes but generally cleans up code and makes it more flexible. - Take a look at the gst-plugins-rs crate for various examples. +- Added high-level helper API for constructing pipelines: -- Bindings for CapsFeatures and Meta -- Bindings for - ParentBufferMeta,VideoMetaandVideoOverlayCompositionMeta` -- Bindings for VideoOverlayComposition and VideoOverlayRectangle -- Bindings for VideoTimeCode + - Gst.Bin.make_and_add(factory_name, instance_name=None) + - Gst.Element.link_many(element, ...) -- UniqueFlowCombiner and UniqueAdapter wrappers that make use of the - Rust compile-time mutability checks and expose more API in a safe - way, and as a side-effect implement Sync and Send now +GStreamer C# Bindings -- More complete bindings for Allocation Query -- pbutils functions for codec descriptions -- TagList::iter() for iterating over all tags while getting a single - value per tag. The old ::iter_tag_list() function was renamed to - ::iter_generic() and still provides access to each value for a tag -- Bus::iter() and Bus::iter_timed() iterators around the corresponding - ::pop\*() functions +- Bind gst_buffer_new_wrapped() manually to fix memory handling. + +- Fix gst_promise_new_with_change_func() where bindgen didn’t properly + detect the func as a closure. + +- Declare GstVideoOverlayComposition and GstVideoOverlayRectangle as + opaque type and subclasses of Gst.MiniObject. This changes the API + but without this all usage will cause memory corruption or simply + not work. + +- on Windows, look for gstreamer, glib and gobject DLLs using the MSVC + naming convention (i.e. gstvideo-1.0-0.dll instead of + libgstvideo-1.0-0.dll). + + The names of these DLLs have to be hardcoded in the bindings, and + most C# users will probably be using the Microsoft toolchain anyway. + + This means that the MSVC compiler is now required to build the + bindings, MingW will no longer work out of the box. + +GStreamer Rust Bindings and Rust Plugins + +The GStreamer Rust bindings are released separately with a different +release cadence that’s tied to gtk-rs, but the latest release has +already been updated for the new GStreamer 1.18 API, so there’s +absolutely no excuse why your next GStreamer application can’t be +written in Rust anymore. + +gst-plugins-rs, the module containing GStreamer plugins written in Rust, +has also seen lots of activity with many new elements and plugins. + +What follows is a list of elements and plugins available in +gst-plugins-rs, so people don’t miss out on all those potentially useful +elements that have no C equivalent. + +Rust audio plugins + +- audiornnoise: New element for audio denoising which implements the + noise removal algorithm of the Xiph RNNoise library, in Rust +- rsaudioecho: Port of the audioecho element from gst-plugins-good + rsaudioloudnorm: Live audio loudness normalization element based on + the FFmpeg af_loudnorm filter +- claxondec: FLAC lossless audio codec decoder element based on the + pure-Rust claxon implementation +- csoundfilter: Audio filter that can use any filter defined via the + Csound audio programming language +- lewtondec: Vorbis audio decoder element based on the pure-Rust + lewton implementation + +Rust video plugins + +- cdgdec/cdgparse: Decoder and parser for the CD+G video codec based + on a pure-Rust CD+G implementation, used for example by karaoke CDs +- cea608overlay: CEA-608 Closed Captions overlay element +- cea608tott: CEA-608 Closed Captions to timed-text (e.g. VTT or SRT + subtitles) converter +- tttocea608: CEA-608 Closed Captions from timed-text converter +- mccenc/mccparse: MacCaption Closed Caption format encoder and parser +- sccenc/sccparse: Scenarist Closed Caption format encoder and parser +- dav1dec: AV1 video decoder based on the dav1d decoder implementation + by the VLC project +- rav1enc: AV1 video encoder based on the fast and pure-Rust rav1e + encoder implementation +- rsflvdemux: Alternative to the flvdemux FLV demuxer element from + gst-plugins-good, not feature-equivalent yet +- rsgifenc/rspngenc: GIF/PNG encoder elements based on the pure-Rust + implementations by the image-rs project + +Rust text plugins + +- textwrap: Element for line-wrapping timed text (e.g. subtitles) for + better screen-fitting, including hyphenation support for some + languages + +Rust network plugins + +- reqwesthttpsrc: HTTP(S) source element based on the Rust + reqwest/hyper HTTP implementations and almost feature-equivalent + with the main GStreamer HTTP source souphttpsrc +- s3src/s3sink: Source/sink element for the Amazon S3 cloud storage +- awstranscriber: Live audio to timed text transcription element using + the Amazon AWS Transcribe API + +Generic Rust plugins + +- sodiumencrypter/sodiumdecrypter: Encryption/decryption element based + on libsodium/NaCl +- togglerecord: Recording element that allows to pause/resume + recordings easily and considers keyframe boundaries +- fallbackswitch/fallbacksrc: Elements for handling potentially + failing (network) sources, restarting them on errors/timeout and + showing a fallback stream instead +- threadshare: Set of elements that provide alternatives for various + existing GStreamer elements but allow to share the streaming threads + between each other to reduce the number of threads +- rsfilesrc/rsfilesink: File source/sink elements as replacements for + the existing filesrc/filesink elements -- serde serialization of Value can also handle Buffer now +Build and Dependencies -- Extensive comments to all examples with explanations -- Transmuxing example showing how to use typefind, multiqueue and - dynamic pads -- basic-tutorial-12 was ported and added +- The Autotools build system has finally been removed in favour of the + Meson build system. Developers who currently use gst-uninstalled + should move to gst-build. + +- API and plugin documentation are no longer built with gtk_doc. The + gtk_doc documentation has been removed in favour of a new unified + documentation module built with hotdoc (also see “Documentation + improvements” section below). Distributors should use the + documentation release tarball instead of trying to package hotdoc + and building the documentation from scratch. + +- gst-plugins-bad now includes an internal copy of libusrsctp, as + there are problems in usrsctp with global shared state, lack of API + stability guarantees, and the absence of any kind of release + process. We also can’t rely on distros shipping a version with the + fixes we need. Both firefox and Chrome bundle their own copies too. + It is still possible to build against an external copy of usrsctp if + so desired. + +- nvcodec no longer needs the NVIDIA NVDEC/NVENC SDKs available at + build time, only at runtime. This allows distributions to ship this + plugin by default and it will just start to work when the required + run-time SDK libraries are installed by the user, without users + needing to build and install the plugin from source. + +- the gst-editing-services tarball is now named gst-editing-services + for consistency (used to be gstreamer-editing-services). + +- the gst-validate tarball has been superseded by the gst-devtools + tarball for consistency with the git module name. + +gst-build + +gst-build is a meta-module and serves primarily as our uninstalled +development environment. It makes it easy to build most of GStreamer, +but unlike Cerbero it only comes with a limited number of external +dependencies that can be built as subprojects if they are not found on +the system. + +gst-build is based on Meson and replaces the old autotools +gst-uninstalled script. + +- The ‘uninstalled’ target has been renamed to ‘devenv’ + +- Experimental gstreamer-full library containing all built plugins and + their deps when building with -Ddefault_library=static. A monolithic + library is easier to distribute, and may be required in some + environments. GStreamer core, GLib and GObject are always included, + but external dependencies are still dynamically linked. The + gst-full-libraries meson option allows adding other GStreamer + libraries to the gstreamer-full build. This is an experiment for now + and its behaviour or API may still change in future releases. + +- Add glib-networking as a subproject when glib is a subproject and + load gio modules in the devenv, tls option control whether to use + openssl or gnutls. + +- git-worktree: Allow multiple worktrees for subproject branches + +- Guard against meson being run from inside the uninstalled devenv, as + this might have unexpected consequences. + +- our ffmpeg and x264 meson ports have been updated to the latest + stable version (you might need to update the subprojects checkout + manually though, or just remove the checkouts so meson checks out + the latest version again; improvements for this are pending in + meson, but not merged yet). -Changed +Cerbero -- Rust 1.31 is the minimum supported Rust version now -- Update to latest gir code generator and glib bindings +Cerbero is a meta build system used to build GStreamer plus dependencies +on platforms where dependencies are not readily available, such as +Windows, Android, iOS and macOS. -- Functions returning e.g. gst::FlowReturn or other “combined” enums - were changed to return split enums like - Result to allow usage of the - standard Rust error handling. +General improvements + +- Recipe build steps are done in parallel wherever possible. This + leads to massive improvements in overall build time. +- Several recipes were ported to Meson, which improved build times +- Moved from using both GnuTLS and OpenSSL to only OpenSSL +- Moved from yasm to nasm for all assembly compilation +- Support zsh when running the cerbero shell command +- Numerous version upgrades for dependencies +- Default to xz for tarball binary packages. bz2 can be selected with + the --compress-method option to package. +- Added boolean variant for controlling the optimization level: + -v optimization +- Ship .pc pkgconfig files for all plugins in the binary packages +- CMake and nasm will only be built by Cerbero if the system versions + are unusable +- The nvcodec variant was removed and the nvcodec plugin is built by + default now (as it no longer requires the SDK to be installed at + build time, only at runtime) + +macOS / iOS + +- Minimum iOS SDK version bumped to 11.0 +- Minimum macOS SDK version bumped to 10.11 +- No longer need to manually add support for newer iOS SDK versions +- Added Vulkan elements via MoltenVK +- Build times were improved by code-signing all build tools +- macOS framework ships all gstreamer libraries instead of an outdated + subset +- Ship pkg-config in the macOS framework package +- fontconfig: Fix EXC_BAD_ACCESS crash on iOS ARM64 +- Improved App Store compatibility by setting LC_VERSION_MIN_MACOSX, + fixing relocations, and improved bitcode support -- MiniObject subclasses are now newtype wrappers around the underlying - GstRc wrapper. This does not change the API in any breaking - way for the current usages, but allows MiniObjects to also be - implemented in other crates and makes sure rustdoc places the - documentation in the right places. +Windows -- BinExt extension trait was renamed to GstBinExt to prevent conflicts - with gtk::Bin if both are imported +- MinGW-GCC toolchain was updated to 8.2. It uses the Universal CRT + instead of MSVCRT which eliminates cross-CRT issues in the Visual + Studio build. +- Require Windows 7 or newer for running binaries produced by Cerbero +- Require Windows x86_64 for running Cerbero to build binary packages +- Cerbero no longer uses C:/gstreamer/1.0 as a prefix when building. + That prefix is reserved for use by the MSI installers. +- Several recipes can now be buit with Visual Studio instead of MinGW. + Ported to meson: opus, libsrtp, harfbuzz, cairo, openh264, libsoup, + libusrsctp. Existing build system: libvpx, openssl. +- Support building using Visual Studio for 32-bit x86. Previously we + only supported building for 32-bit x86 using the MinGW toolchain. +- Fixed annoying msgmerge popups in the middle of cerbero builds +- Added configuration options vs_install_path and vs_install_version + for specifying custom search locations for older Visual Studio + versions that do not support vswhere. You can set these in + ~/.cerbero/cerbero.cbc where ~ is the MSYS homedir, not your Windows + homedir. +- New Windows-specific plugins: d3d11, mediafoundation, wasapi2 +- Numerous compatibility and reliability fixes when running Cerbero on + Windows, especially non-English locales +- proxy-libintl now exports the same symbols as gettext, which makes + it a drop-in replacement +- New mapping variant for selecting the Visual Studio CRT to use: + -v vscrt=. Valid values are md, mdd, and auto (default). A + separate prefix is used when building with either md (release) or + mdd (debug), and the outputted package will have +debug in the + filename. This variant is also used for selecting the correct Qt + libraries (debug vs release) to use when building with -v qt5 on + Windows. +- Support cross-compile on Windows to Windows ARM64 and ARMv7 +- Support cross-compile on Windows to the Universal Windows Platform + (UWP). Only the subset of plugins that can be built entirely with + Visual Studio will be selected in this case. To do so, use the + config/cross-uwp-universal.cbc configuration, which will build + ARM64, x86, and x86_64 binaries linked to the release CRT, with + optimizations enabled, and debugging turned on. You can combine this + with -v vscrt=mdd to produce binaries linked to the debug CRT. You + can turn off optimizations with the -v nooptimization variant. + +Windows MSI installer + +- Require Windows 7 or newer for running GStreamer +- Fixed some issues with shipping of pkg-config in the Windows + installers +- Plugin PDB debug files are now shipped in the development package, + not the runtime package +- Ship installers for 32-bit binaries built with Visual Studio +- Ship debug and release “universal” (ARM64, X86, and X86_64) tarballs + built for the Universal Windows Platform +- Windows MSI installers now install into separate prefixes when + building with MSVC and MinGW. Previously both would be installed + into C:/gstreamer/1.0/x86 or C:/gstreamer/1.0/x86_64. Now, the + installation prefixes are: + + ---------------------------------------------------------------------------------------------------------------- + Target Path Build options + --------------------------- ------------------------------------ ----------------------------------------------- + MinGW 32-bit C:/gstreamer/1.0/mingw_x86 -c config/win32.cbc + + MinGW 64-bit C:/gstreamer/1.0/mingw_x86_64 -c config/win64.cbc + + MSVC 32-bit C:/gstreamer/1.0/msvc_x86 -c config/win32.cbc -v visualstudio + + MSVC 64-bit C:/gstreamer/1.0/msvc_x86_64 -c config/win64.cbc -v visualstudio + + MSVC 32-bit (debug) C:/gstreamer/1.0/msvc-debug_x86 -c config/win32.cbc -v visualstudio,vscrt=mdd + + MSVC 64-bit (debug) C:/gstreamer/1.0/msvc-debug_x86_64 -c config/win64.cbc -v visualstudio,vscrt=mdd + ---------------------------------------------------------------------------------------------------------------- + +Note: UWP binary packages are tarballs, not MSI installers. + +Linux + +- Support creating MSI installers using WiX when cross-compiling to + Windows +- Support running cross-windows binaries with Wine when using the + shell and runit cerbero commands +- Added bash-completion support inside the cerbero shell on Linux +- Require a system-wide installation of openssl on Linux +- Added variant -v vaapi to build gstreamer-vaapi and the new gstva + plugin +- Debian packaging was disabled because it does not work. Help in + fixing this is appreciated. +- Trimmed the list of packages needed for bootstrap on Linux -- Buffer::from_slice() can’t possible return None +Android -- Various clippy warnings +- Updated to NDK r21 +- Support Vulkan +- Support Qt 5.14+ binary package layout +Platform-specific changes and improvements -GStreamer Rust Plugins +Android -Like the GStreamer Rust bindings, the Rust plugins are now officially -part of the GStreamer project and are also maintained in the GStreamer -GitLab. +- opensles: Remove hard-coded buffer-/latency-time values and allow + openslessink to handle 48kHz streams. -In the 0.3.x versions this contained infrastructure for writing -GStreamer plugins in Rust, and a set of plugins. +- photography interface and camera source: Add additional settings + relevant to Android such as: Exposure mode property, extra colour + tone values (aqua, emboss, sketch, neon), extra scene modes + (backlight, flowers, AR, HDR), and missing virtual methods for + exposure mode, analog gain, lens focus, colour temperature, min & + max exposure time. Add new effects and scene modes to Camera + parameters. -In git master that infrastructure was moved to the GLib and GStreamer -bindings directly, together with many other improvements that were made -possible by this, so the gst-plugins-rs repository only contains -GStreamer elements now. +macOS and iOS -Elements included are: +- vtdec can now output to Vulkan-backed memory for zerocopy support + with the Vulkan elements. -- Tutorials plugin: identity, rgb2gray and sinesrc with extensive - comments +Windows -- rsaudioecho, a port of the audiofx element +- d3d11videosink: new Direct3D11-based video sink with support for + HDR10 rendering if supported. + +- Hardware-accelerated video decoding on Windows via DXVA2 / + Direct3D11 using native Windows APIs rather than per-vendor SDKs + (like MSDK for Intel or NVCODEC for NVidia). Plus modern Direct3D11 + integration rather than the almost 20-year old Direct3D9 from + Windows XP times used in d3dvideosink. Formats supported for + decoding are H.264, H.265, VP8, and VP9, and zero-copy operation + should be supported in combination with the new d3d11videosink. See + Seungha’s blog post “Windows DXVA2 (via Direct3D 11) Support in + GStreamer 1.17” for more details. + +- Microsoft Media Foundation plugin for hardware-accelerated video + encoding on Windows using native Windows APIs rather than per-vendor + SDKs. Formats supported for encoding are H.264, H.265 and VP9. Also + includes audio encoders for AAC and MP3. See Seungha’s blog post + “Bringing Microsoft Media Foundation to GStreamer” for some more + details about this. + +- new mfvideosrc video capture source element using the latest Windows + APIs rather than ancient APIs used by ksvideosrc/winks. ksvideosrc + should be considered deprecated going forward. + +- d3d11: add d3d11convert, a color space conversion and rescaling + element using shaders, and introduce d3d11upload and d3d11download + elements that work just like glupload and gldownload but for D3D11. + +- Universal Windows Platform (UWP) support, including official + GStreamer binary packages for it. Check out Nirbheek’s latest blog + post “GStreamer 1.18 supports the Universal Windows Platform” for + more details. + +- systemclock correctness and reliability fixes, and also don’t start + the system clock at 0 any longer (which shouldn’t make any + difference to anyone, as absolute clock time values are supposed to + be meaningless in themselves, only the rate of increase matters). + +- toolchain specific plugin registry: the registry cache is now named + differently for MSVC and MinGW toolchains/packages, which should + avoid problems when switching between binaries built with a + different toolchain. + +- new wasapi2 plugin mainly to support UWP applications. The core + logic of this plugin is almost identical to existing wasapi plugin, + but the main target is Windows 10 and UWP. This plugin uses WinRT + APIs, so will likely not work on Windows 8 or older. Unlike the + existing wasapi plugin, this plugin supports automatic stream + routing (auto fallback when device was removed) and device level + mute/volume control. Exclusive streaming mode is not supported, + however, and loopback features are not implemented yet. It is also + only possible to build this plugin with MSVC and the Windows 10 SDK, + it can’t be cross-compiled with the MingW toolchain. + +- new dxgiscreencapsrc element which uses the Desktop Duplication API + to capture the desktop screen at high speed. This is only supported + on Windows 8 or later. Compared to the existing elements + dxgiscreencapsrc offers much better performance, works in High DPI + environments and draws an accurate mouse cursor. + +- d3dvideosink was downgraded to secondary rank, d3d11videosink is + preferred now. Support OverlayComposition for GPU overlay + compositing of subtitles and logos. + +- debug log output fixes, esp. with a non-UTF8 locale/codepage + +- speex, jack: fixed crashes on Windows caused by cross-CRT issues + +- gst-play-1.0 interactive keyboard controls now also work on Windows + +Linux + +- kmssink: Add support for P010 and P016 formats + +- vah264dec: new experimental va plugin with an element for H.264 + decoding with VA-API. This novel approach, different from + gstreamer-vaapi, uses the gstcodecs library for decoder state + handling, which it is hoped will make for cleaner code because it + uses VA-API without further layers or wrappers. Check out Víctor’s + blog post “New VA-API H.264 decoder in gst-plugins-bad” for the full + lowdown and the limitations of this new plugin, and how to give it a + spin. + +- v4l2codecs: introduce a V4L2 CODECs Accelerator. This plugin will + support the new CODECs uAPI in the Linux kernel, which consists of + an accelerator interface similar to DXVA, NVDEC, VDPAU and VAAPI. So + far H.264 and VP8 are supported. This is used on certain embedded + systems such as i.mx8m, rk3288, rk3399, Allwinner H-series SoCs. + +Documentation improvements + +- unified documentation containing tutorials, API docs, plugin docs, + etc. all under one roof, shipped in form of a documentation release + tarball containing both devhelp and html documentation. + +- all documentation is now generated using hotdoc, gtk-doc is no + longer used. Distributors should use the above-mentioned + documentation release tarball instead of trying to package hotdoc + and building the documentation from scratch. + +- there is now documentation for wrapper plugins like gst-libav and + frei0r, as well as tracer plugins. + +- for more info, check out Thibault’s “GStreamer Documentation” + lightning talk from the 2019 GStreamer Conference. + +- new API for plugins to support the documentation system: + + - new GParamSpecFlag GST_PARAM_DOC_SHOW_DEFAULT to make + gst-inspect-1.0 (and the documentation) show the paramspec’s + default value rather than the actually set value as default + - GstPadTemplate getter and setter for “documentation caps”, + gst_pad_template_set_documentation_caps() and + gst_pad_template_get_documentation_caps(): This can be used in + elements where the caps of pad templates are dynamically + generated and/or dependent on the environment, to override the + caps shown in the documentation (usually to advertise the full + set of possible caps). + - gst_type_mark_as_plugin_api() for marking types as plugin API, + used for plugin-internal types like enums, flags, pad + subclasses, boxed types, and such. + +Possibly Breaking Changes + +- GstVideo: the canonical list of raw video formats (for use in caps) + has been reordered, so video elements such as videotestsrc or + videoconvert might negotiate to a different format now than before. + The new format might be a higher-quality format or require more + processing overhead, which might affect pipeline performance. + +- mpegtsdemux used to wrongly advertise H.264 and H.265 video + elementary streams as alignment=nal. This has now been fixed and + changed to alignment=none, which means an h264parse or h265parse + element is now required after tsdemux for some pipelines where there + wasn’t one before, e.g. in transmuxing scenarios (tsdemux ! tsmux). + Pipelines without such a parser may now fail to link or error out at + runtime. As parsers after demuxers and before muxers have been + generally required for a long time now it is hoped that this will + only affect a small number of applications or pipelines. + +- The Android opensles audio source and sink used to have hard-coded + buffer-/latency-time values of 20ms. This is no longer needed with + newer Android versions and has now been removed. This means a higher + or lower value might now be negotiated by default, which can affect + pipeline performance and latency. -- rsfilesrc, rsfilesink +Known Issues -- rsflvdemux, a FLV demuxer. Not feature-equivalent with flvdemux yet +- GStreamer 1.18 versions <= 1.18.4 would fail to build on Linux with + Meson 0.58 due to an issue with the include directories. + GStreamer >= 1.18.5 includes a fix for this. -- threadshare plugin: ts-appsrc, ts-proxysrc/sink, ts-queue, ts-udpsrc - and ts-tcpclientsrc elements that use a fixed number of threads and - share them between instances. For more background about these - elements see Sebastian’s talk “When adding more threads adds more - problems - Thread-sharing between elements in GStreamer” at the - GStreamer Conference 2017. +Contributors -- rshttpsrc, a HTTP source around the hyper/reqwest Rust libraries. - Not feature-equivalent with souphttpsrc yet. +Aaron Boxer, Adam Duskett, Adam x Nilsson, Adrian Negreanu, Akinobu +Mita, Alban Browaeys, Alcaro, Alexander Lapajne, Alexandru Băluț, Alex +Ashley, Alex Hoenig, Alicia Boya García, Alistair Buxton, Ali Yousuf, +Ambareesh “Amby” Balaji, Amr Mahdi, Andoni Morales Alastruey, Andreas +Frisch, Andre Guedes, Andrew Branson, Andrey Sazonov, Antonio Ospite, +aogun, Arun Raghavan, Askar Safin, AsociTon, A. Wilcox, Axel Mårtensson, +Ayush Mittal, Bastian Bouchardon, Benjamin Otte, Bilal Elmoussaoui, +Brady J. Garvin, Branko Subasic, Camilo Celis Guzman, Carlos Rafael +Giani, Charlie Turner, Cheng-Chang Wu, Chris Ayoup, Chris Lord, +Christoph Reiter, cketti, Damian Hobson-Garcia, Daniel Klamt, Daniel +Molkentin, Danny Smith, David Bender, David Gunzinger, David Ing, David +Svensson Fors, David Trussel, Debarshi Ray, Derek Lesho, Devarsh +Thakkar, dhilshad, Dimitrios Katsaros, Dmitriy Purgin, Dmitry Shusharin, +Dominique Leuenberger, Dong Il Park, Doug Nazar, dudengke, Dylan McCall, +Dylan Yip, Ederson de Souza, Edward Hervey, Eero Nurkkala, Eike Hein, +ekwange, Eric Marks, Fabian Greffrath, Fabian Orccon, Fabio D’Urso, +Fabrice Bellet, Fabrice Fontaine, Fanchao L, Felix Yan, Fernando +Herrrera, Francisco Javier Velázquez-García, Freyr, Fuwei Tang, Gaurav +Kalra, George Kiagiadakis, Georgii Staroselskii, Georg Lippitsch, Georg +Ottinger, gla, Göran Jönsson, Gordon Hart, Gregor Boirie, Guillaume +Desmottes, Guillermo Rodríguez, Haakon Sporsheim, Haihao Xiang, Haihua +Hu, Havard Graff, Håvard Graff, Heinrich Kruger, He Junyan, Henry +Wilkes, Hosang Lee, Hou Qi, Hu Qian, Hyunjun Ko, ibauer, Ignacio Casal +Quinteiro, Ilya Smelykh, Jake Barnes, Jakub Adam, James Cowgill, James +Westman, Jan Alexander Steffens, Jan Schmidt, Jan Tojnar, Javier Celaya, +Jeffy Chen, Jennifer Berringer, Jens Göpfert, Jérôme Laheurte, Jim +Mason, Jimmy Ohn, J. Kim, Joakim Johansson, Jochen Henneberg, Johan +Bjäreholt, Johan Sternerup, John Bassett, Jonas Holmberg, Jonas Larsson, +Jonathan Matthew, Jordan Petridis, Jose Antonio Santos Cadenas, Josep +Torra, Jose Quaresma, Josh Matthews, Joshua M. Doe, Juan Navarro, +Juergen Werner, Julian Bouzas, Julien Isorce, Jun-ichi OKADA, Justin +Chadwell, Justin Kim, Keri Henare, Kevin JOLY, Kevin King, Kevin Song, +Knut Andre Tidemann, Kristofer Björkström, krivoguzovVlad, Kyrylo +Polezhaiev, Lenny Jorissen, Linus Svensson, Loïc Le Page, Loïc Minier, +Lucas Stach, Ludvig Rappe, Luka Blaskovic, luke.lin, Luke Yelavich, +Marcin Kolny, Marc Leeman, Marco Felsch, Marcos Kintschner, Marek +Olejnik, Mark Nauwelaerts, Markus Ebner, Martin Liska, Martin Theriault, +Mart Raudsepp, Matej Knopp, Mathieu Duponchelle, Mats Lindestam, Matthew +Read, Matthew Waters, Matus Gajdos, Maxim Paymushkin, Maxim P. +Dementiev, Michael Bunk, Michael Gruner, Michael Olbrich, Miguel París +Díaz, Mikhail Fludkov, Milian Wolff, Millan Castro, Muhammet Ilendemli, +Nacho García, Nayana Topolsky, Nian Yan, Nicola Murino, Nicolas +Dufresne, Nicolas Pernas Maradei, Niels De Graef, Nikita Bobkov, Niklas +Hambüchen, Nirbheek Chauhan, Ognyan Tonchev, okuoku, Oleksandr +Kvl,Olivier Crête, Ondřej Hruška, Pablo Marcos Oltra, Patricia Muscalu, +Peter Seiderer, Peter Workman, Philippe Normand, Philippe Renon, Philipp +Zabel, Pieter Willem Jordaan, Piotr Drąg, Ralf Sippl, Randy Li, Rasmus +Thomsen, Ratchanan Srirattanamet, Raul Tambre, Ray Tiley, Richard +Kreckel, Rico Tzschichholz, R Kh, Robert Rosengren, Robert Tiemann, +Roman Shpuntov, Roman Sivriver, Ruben Gonzalez, Rubén Gonzalez, +rubenrua, Ryan Huang, Sam Gigliotti, Santiago Carot-Nemesio, Saunier +Thibault, Scott Kanowitz, Sebastian Dröge, Sebastiano Barrera, Seppo +Yli-Olli, Sergey Nazaryev, Seungha Yang, Shinya Saito, Silvio +Lazzeretti, Simon Arnling Bååth, Siwon Kang, sohwan.park, Song Bing, +Soohyun Lee, Srimanta Panda, Stefano Buora, Stefan Sauer, Stéphane +Cerveau, Stian Selnes, Sumaid Syed, Swayamjeet, Thiago Santos, Thibault +Saunier, Thomas Bluemel, Thomas Coldrick, Thor Andreassen, Tim-Philipp +Müller, Ting-Wei Lan, Tobias Ronge, trilene, Tulio Beloqui, U. Artie +Eoff, VaL Doroshchuk, Varunkumar Allagadapa, Vedang Patel, Veerabadhran +G, Víctor Manuel Jáquez Leal, Vivek R, Vivia Nikolaidou, Wangfei, Wang +Zhanjun, Wim Taymans, Wonchul Lee, Xabier Rodriguez Calvar, Xavier +Claessens, Xidorn Quan, Xu Guangxin, Yan Wang, Yatin Maan, Yeongjin +Jeong, yychao, Zebediah Figura, Zeeshan Ali, Zeid Bekli, Zhiyuan Sraf, +Zoltán Imets, -- togglerecord, an element that allows to start/stop recording at any - time and keeps all audio/video streams in sync. +… and many others who have contributed bug reports, translations, sent +suggestions or helped testing. -- mccparse and mccenc, parsers and encoders for the MCC closed caption - file format. +Stable 1.18 branch -Changes to 0.3.X since 0.3.0 +After the 1.18.0 release there will be several 1.18.x bug-fix releases +which will contain bug fixes which have been deemed suitable for a +stable branch, but no new features or intrusive changes will be added to +a bug-fix release usually. The 1.18.x bug-fix releases will be made from +the git 1.18 branch, which will be a stable branch. + +1.18.0 + +1.18.0 was released on 8 September 2020. + +1.18.1 + +The first 1.18 bug-fix release (1.18.1) was released on 26 October 2020. + +This release only contains bugfixes and it should be safe to update from +1.18.0. + +Highlighted bugfixes in 1.18.1 + +- important security fixes +- bug fixes and memory leak fixes +- various stability and reliability improvements + +gstreamer + +- aggregator: make peek() has() pop() drop() buffer API threadsafe +- gstvalue: don’t write to const char * +- meson: Disallow DbgHelp for UWP build +- info: Fix build on Windows ARM64 device +- build: use cpu_family for arch checks +- basetransform: Fix in/outbuf confusion of _default_transform_meta +- Fix documentation +- info: Load DbgHelp.dll using g_module_open() +- padtemplate: mark documentation caps as may be leaked +- gstmeta: intern registered impl string +- aggregator: Hold SRC_LOCK while unblocking via SRC_BROADCAST() +- ptp_helper_post_install.sh: deal with none +- skip elements/leak.c if tracer is not available +- aggregator: Wake up source pad in PAUSED<->PLAYING transitions +- input-selector: Wake up blocking pads when releasing them +- ptp: Also handle gnu/kfreebsd + +gst-plugins-base + +- theoradec: Set telemetry options only if they are nonzero +- glslstage: delete shader on finalize of stage +- urisourcebin: Fix crash caused by use after free +- decodebin3: Store stream-start event on output pad before exposing + it +- Add some missing nullable annotations +- typefind/xdgmime: Validate mimetypes to be valid GstStructure names + before using them +- uridecodebin3: Forward upstream events to decodebin3 directly +- video-converter: Add fast paths from v210 to I420/YV12, Y42B, UYVY + and YUY2 +- videoaggregator: Limit accepted caps by template caps +- gstrtpbuffer: fix header extension length validation +- decodebin3: only force streams-selected seqnum after a + select-streams +- videodecoder: don’t copy interlace-mode from reference state +- enable abi checks +- multihandlesink: Don’t pass NULL caps to gst_caps_is_equal +- audio: video: Fix in/outbuf confusion of transform_meta +- meson: Always wrap “prefix” option with join_paths() to make Windows + happy +- videoaggregator: ensure peek_next_sample() uses the correct caps +- meson: Actually build gstgl without implicit include dirs +- videoaggregator: Don’t require any pads to be configured for + negotiating source pad caps +- gst-libs: gl: Fix documentation typo and clarify + gl_memory_texsubimage +- audioaggregator: Reset offset if the output rate is renegotiated +- video-anc: Implement transform functions for AFD/Bar metas +- appsrc: Wake up the create() function on caps changes +- rtpbasepayload: do not forget delayed segment when forwarding gaps + +gst-plugins-good + +- v4l2object: Only offer inactive pools and if needed +- vpx: Fix the check to unfixed/unknown framerate to set bitrate +- qmlglsink: fix crash when created/destroyed in quick succession +- rtputils: Count metas with an empty tag list for copying/keeping +- rtpbin: Remove the rtpjitterbuffer with the stream +- rtph26*depay: drop FU’s without a corresponding start bit +- imagefreeze: Response caps query from srcpad +- rtpmp4gdepay: Allow lower-case “aac-hbr” instead of correct + “AAC-hbr” +- rtspsrc: Fix push-backchannel-buffer parameter mismatch +- jpegdec: check buffer size before dereferencing +- flvmux: Move stream skipping to GstAggregatorPadClass.skip_buffer +- v4l2object: plug memory leak +- splitmuxsink: fix sink pad release while PLAYING + +gst-plugins-bad + +- codecparsers: h264parser: guard against ref_pic_markings overflow +- v4l2codecs: Various fixes +- h265parse: Don’t enable passthrough by default +- srt: Fix “Fix timestamping” +- srt: Fixes for 1.4.2 +- dtlsconnection: Ignore OpenSSL system call errors +- h265parse: set interlace-mode=interleaved on interlaced content +- Replace GPL v2 with LGPL v2 in COPYING file +- srt: Consume the error from gst_srt_object_write +- srt: Check socket state before retrieving payload size +- x265enc: fix deadlock on reconfig +- webrtc: Require gstreamer-sdp in the pkg-config file +- srtsrc: Fix timestamping +- mfvideosrc: Use only the first video stream per device +- srtobject: typecast SRTO_LINGER to linger +- decklink: Correctly order the different dependent mode tables +- wasapisrc: Make sure that wasapisrc produces data in loopback mode +- wpesrc: fix some caps leaks using the non-GL output +- smoothstreaming: clear live adapter on seek +- vtdec/vulkan: use Shared storage mode for IOSurface textures +- wpe: Move webview load waiting to WPEView +- wpe: Use proper callback for TLS errors signal handling +- kmssink: Do not source using padded width/height +- avtp: avtpaafdepay: fix crash when building caps +- opencv: set opencv_dep when option is disabled to fix the build +- line21encoder: miscellaneous enhancements +- Hls youtube issues with urisourcebin/queue2 +- rtmp2: Replace stats queue with stats lock +- rtmp2sink: support EOS event for graceful connection shutdown +- mpegtsmux: Make handling of sinkpads thread-safe +- hlssink2: Actually release splitmuxsink’s pads +- mpegtsmux: Don’t create streams with reserved PID + +gst-plugins-ugly + +- no changes + +gst-libav + +- avaudenc/avvidenc: Reopen encoding session if it’s required +- avauddec/audenc/videnc: Don’t return GST_FLOW_EOS when draining +- avauddec/avviddec: Avoid dropping non-OK flow return +- avcodecmap: Enable 24 bit WMA Lossless decoding + +gst-rtsp-server + +- rtsp-stream: collect rtp info when blocking +- rtsp-media: set a 0 storage size for TCP receivers +- rtsp-stream: preroll on gap events +- rtsp-media: do not unblock on unsuspend + +gstreamer-vaapi + +- decoder: don’t reply src caps query with allowed if pad is fixed +- plugins: decode: fix a DMA caps typo in ensure_allowed_srcpad_caps + +gstreamer-sharp + +- Add bindings for some missing 1.18 API + +gst-omx + +- omxvideodec: support interlace-mode=interleaved input + +gst-python + +- no changes + +gst-editing-services + +- ges: Do not recreate auto-transitions when changing clip assets +- ges: Fix a copy/paste mistake in meson file + +gst-integration-testsuites + +- medias: Update for h265parse passthrough behavior change +- update validate.test.h265parse.alternate test + +gst-build + +- windows: Detect Strawberry Perl and error out early +- {pygobject,pycairo}.wrap: point to stable refs + +Cerbero build tool and packaging changes in 1.18.1 + +- Add macOS Big Sur support +- gst-plugins-bad: Ship rtpmanagerbad plugin +- gstreamer-1.0: Don’t enable DbgHelp for UWP build +- pango: fix font corruption on windows +- cairo: use thread local storage to grant one windows HDC per thread +- small fixes for Xcode 12 +- cerbero: Re-add alsa-devel to bootstrap on Linux +- FreeType: update to 2.10.4 to fix security vulnerability + +Contributors to 1.18.1 + +Aaron Boxer, Adam Williamson, Andrew Wesie, Arun Raghavan, Bastien +Reboulet, Brent Gardner, Edward Hervey, François Laignel, Guillaume +Desmottes, Havard Graff, He Junyan, Hosang Lee, Jacek Tomaszewski, Jakub +Adam, Jan Alexander Steffens (heftig), Jan Schmidt, Jérôme Laheurte, +Jordan Petridis, Marc Leeman, Marian Cichy, Marijn Suijten, Mathieu +Duponchelle, Matthew Waters, Michael Tretter, Nazar Mokrynskyi, Nicolas +Dufresne, Niklas Hambüchen, Nirbheek Chauhan, Olivier Crête, Philippe +Normand, raghavendra, Ricky Tang, Sebastian Dröge, Seungha Yang, +sohwan.park, Stéphane Cerveau, Thibault Saunier, Tim-Philipp Müller, Tom +Schoonjans, Víctor Manuel Jáquez Leal, Will Miller, Xavier Claessens, Xℹ +Ruoyao, Zebediah Figura, -- All references were updated from GitHub to freedesktop.org GitLab -- Fix various links in the README.md -- Link to the correct location for the documentation +… and many others who have contributed bug reports, translations, sent +suggestions or helped testing. Thank you all! + +List of merge requests and issues fixed in 1.18.1 + +- List of Merge Requests applied in 1.18.1 +- List of Issues fixed in 1.18.1 + +1.18.2 + +The second 1.18 bug-fix release (1.18.2) was released on 6 December +2020. + +This release only contains bugfixes and it should be safe to update from +1.18.x. + +Highlighted bugfixes in 1.18.2 + +- Fix MPEG-TS timestamping regression when playing DVB streams +- compositor: fix artefacts in certain input scaling/conversion + situations and make sure that the output format is actually + supported, plus renegotiation fixes +- Fix sftp:// URI playback in decodebin/playbin via giosrc +- adaptivedemux/dashdemux/hlsdemux fixes +- rtsp-server fixes +- android media: fix crash when encoding AVC +- fix races in various unit tests +- lots of other bug fixes and memory leak fixes +- various stability, performance and reliability improvements +- g-i annotation fixes +- build fixes + +gstreamer + +- bin: When removing a sink, check if the EOS status changed +- info: colorize PIDs in log messages +- aggregator: Include min-upstream-latency in buffering time, helps + especially with performance issues on single core systems where + there are a lot of threads running +- typefind: copy seqnum to new segment event, fixing issues with + oggdemux operating in push mode with typefind operating in pull mode +- identity, clocksync: Also provide system clock if sync=false +- queue2: Fix modes in scheduling query handling +- harness: Handle element not being set cleanly +- g-i: Add some missing nullable annotations, and fix some nullable + annotations: + - gst_test_clock_process_next_clock_id() returns nullable + - gst_stream_type_get_name() is not nullable +- build: fix build issue when compiling for 32-bit architectures with + 64-bit time_t (e.g. riscv32) by increasing padding in + GstClockEntryImpl in gst_private.h + +gst-plugins-base + +- gl/eagl: internal view resize fixes for glimagesink +- video-converter: increase the number of cache lines for resampling, + fixes significant color issues and artefacts with “special” resizing + parameters in compositor +- compositor: Don’t crash in prepare_frame() if the pad was just + removed +- decodebin3: Properly handle caps query with no filter +- videoaggregator: Guarantee that the output format is supported +- videoaggregator: Fix locking around vagg->info +- gluploadelement: Avoid race condition of base class’ context +- gluploadelement: Avoid race condition of inside upload creation +- gl: Fix prototype of glGetSynciv() +- tcpserversink: Don’t assume g_socket_get_remote_address() succeeds +- video-aggregator: Fix renegotiation when using convert pads +- videoaggregator: document and fix locking in convert pad +- audiodecoder, videodecoder: Don’t reset max-errors property value in + reset() +- audioencoder: Fix incorrect GST_LOG_OBJECT usage +- pbutils: Fix segfault when using invalid encoding profile +- g-i: videometa: gir annotate the size of plane array in new API +- examples/gl/gtk: Add missing dependency on gstgl +- video: fix doc warning + +gst-plugins-good + +- rpicamsrc: add vchostif library as it is required to build + successful +- deinterlace: Enable x86 assembly with nasm on MSVC +- v4l2: caps negotiate wrong as interlace feature +- aacparse: Fix caps change handling +- rtspsrc: Use URI hash for stream id +- flvmux: Release pads via GstAggregator +- qtmux: Chain up when releasing pad, and fix some locking +- matroska-mux: Fix sparse stream crash +- Splitmux testsuite races + +gst-plugins-bad + +- tsparse: timestamp packetized buffers, fixing timestamp handling + regression in connection with dvbsrc in MeTV +- ttmlparse: fix issues in aggregation of input TTML +- mpegdemux: Set duration on seeking query if possible, fixes seeking + in MPEG-PS streams in gst-play-1.0 +- mpegtsdemux: Fix off by one error +- adaptivedemux: Store QoS values on the element +- adaptivedemux: Don’t calculate bitrate for header/index fragments +- hlsdemux: Don’t double-free variant streams on errors +- mpegtspacketizer: Handle PCR issues with adaptive streams +- player: call ref_sink on pipeline +- vkdeviceprovider: Avoid deadlock on physical device +- wlvideoformat: fix DMA format convertor +- Webrtc shutdown crashes +- decklink: Update enum value bounds check in gst_decklink_get_mode() +- decklink: correct framerate 2KDCI 23.98 +- amc: Fix crash when encoding AVC +- d3d11videoprocessor: Fix wrong input/output supportability check +- opencv: allow compilation against 4.5.x +- tests: svthevcenc: Fix test_encode_simple +- tests: dtls: Don’t set dtlsenc state before linking +- mpegtsmux: Restore intervals when creating TsMux +- adaptivedemux, hlsdemux, curl: Use actual object for logging +- gi: player: Fix get_current_subtitle_track() annotation + +gst-plugins-ugly + +- no changes + +gst-libav + +- avauddec: Check planar-ness of frame rather than context, fixes + issue with aptX HD decoding + +gst-rtsp-server + +- stream: collect a clock_rate when blocking +- media: Ignore GstRTSPStreamBlocking from incomplete streams, to + prevent cases with prerolling when the inactive stream prerolls + first and the server proceeds without waiting for the active stream. + When there are no complete streams (during DESCRIBE), we will listen + to all streams. +- media: Use guint64 for setting the size-time property on rtpstorage, + fixes potential crashes or memory corruption. +- media: Get rates only on sender streams, fixing issue with ONVIF + audio backchannel streams +- media: Plug memory leak + +gstreamer-vaapi + +- H265 decoder: Fix a typo in scc reference setting + +gstreamer-sharp + +- no changes + +gst-omx + +- no changes + +gst-python + +- no changes + +gst-editing-services + +- Fix static build +- ges_init(): Fix potential initialisation crash on error + +gst-integration-testsuites + +- no changes + +gst-build + +- gst-env: use Path.open() in get_pkgconfig_variable_from_pcfile(), + fixes issues with python 3.5 +- subprojects: pin orc to 0.4.32 release (was 0.4.29) and pin libpsl + to 0.21.1 (was master) -Changes in git master for 0.4 +Cerbero build tool and packaging changes in 1.18.2 -- togglerecord: Switch to parking_lot crate for mutexes/condition - variables for lower overhead -- Merge threadshare plugin here -- New closedcaption plugin with mccparse and mccenc elements -- New identity element for the tutorials plugin +- build-tools: copy the removed site.py from setuptools, fixing python + programs (like meson) from using libraries from incorrect places -- Register plugins statically in tests instead of relying on the - plugin loader to find the shared library in a specific place +Contributors to 1.18.2 -- Update to the latest API changes in the GLib and GStreamer bindings -- Update to the latest versions of all crates +Arun Raghavan, Bing Song, Chris Bass, Chris Duncan, Chris White, David +Keijser, David Phung, Edward Hervey, Fabrice Fontaine, Guillaume +Desmottes, Guiqin Zou, He Junyan, Jan Alexander Steffens (heftig), Jan +Schmidt, Jason Pereira, Jonathan Matthew, Jose Quaresma, Julian Bouzas, +Khem Raj, Kristofer Björkström, Marijn Suijten, Mart Raudsepp, Mathieu +Duponchelle, Matthew Waters, Nicola Murino, Nicolas Dufresne, Nirbheek +Chauhan, Olivier Crête, Philippe Normand, Rafostar, Randy Li, Sanchayan +Maity, Sebastian Dröge, Seungha Yang, Thibault Saunier, Tim-Philipp +Müller, Vivia Nikolaidou, Xavier Claessens +… and many others who have contributed bug reports, translations, sent +suggestions or helped testing. Thank you all! -Build and Dependencies +List of merge requests and issues fixed in 1.18.2 -- The MESON BUILD SYSTEM BUILD IS NOW FEATURE-COMPLETE (*) and it is - now the recommended build system on all platforms and also used by - Cerbero to build GStreamer on all platforms. The Autotools build is - scheduled to be removed in the next cycle. Developers who currently - use gst-uninstalled should move to gst-build. The build option - naming has been cleaned up and made consistent and there are now - feature options to enable/disable plugins and various other features - on a case-by-case basis. (*) with the exception of plugin docs which - will be handled differently in future - -- Symbol export in libraries is now controlled via explicit exports - using symbol visibility or export defines where supported, to ensure - consistency across all platforms. This also allows libraries to have - exports that vary based on detected platform features and configure - options as is the case with the GStreamer OpenGL integration library - for example. A few symbols that had been exported by accident in - earlier versions may no longer be exported. These symbols will not - have had declarations in any public header files then though and - would not have been usable. - -- The GStreamer FFmpeg wrapper plugin (gst-libav) now depends on - FFmpeg 4.x and uses the new FFmpeg 4.x API and stopped relying on - ancient API that was removed with the FFmpeg 4.x release. This means - that it is no longer possible to build this module against an older - system-provided FFmpeg 3.x version. Use the internal FFmpeg 4.x copy - instead if you build using autotools, or use gst-libav 1.14.x - instead which targets the FFmpeg 3.x API and _should_ work fine in - combination with a newer GStreamer. It’s difficult for us to support - both old and new FFmpeg APIs at the same time, apologies for any - inconvenience caused. - -- Hardware-accelerated Nvidia video encoder/decoder plugins nvdec and - nvenc can be built against CUDA Toolkit versions 9 and 10.0 now. The - dynlink interface has been dropped since it’s deprecated in 10.0. - -- The (optional) OpenCV requirement has been bumped to >= 3.0.0 and - the plugin can also be built against OpenCV 4.x now. - -- New sctp plugin based on usrsctp (for WebRTC data channels) +- List of Merge Requests applied in 1.18.2 +- List of Issues fixed in 1.18.2 -Cerbero +1.18.3 -Cerbero is a meta build system used to build GStreamer plus dependencies -on platforms where dependencies are not readily available, such as -Windows, Android, iOS and macOS. +The third 1.18 bug-fix release (1.18.3) was released on 13 January 2021. -Cerbero has seen a number of improvements: +This release only contains bugfixes and it should be safe to update from +1.18.x. -- Cerbero has been ported to Python 3 and requires Python 3.5 or newer - now +Highlighted bugfixes in 1.18.3 -- Source tarballs are now protected by checksums in the recipes to - guard against download errors and malicious takeover of projects or - websites. In addition, downloads are only allowed via secure - transports now and plain HTTP, FTP and git:// transports are not - allowed anymore. +- fix ogg playback regression for ogg files that also have ID3 or APE + tags +- compositor: fix artefacts and invalid memory access when blending + subsampled formats +- exported mini object ref/unref/copy functions for use in bindings + such as gstreamer-sharp +- Add support for Apple silicon (M1) to cerbero package builder +- Ship RIST plugin in binary packages +- various stability, performance and reliability improvements +- memory leak fixes +- build fixes -- There is now a new fetch-bootstrap command which downloads sources - required for bootstrapping, with an optional --build-tools-only - argument to match the bootstrap --build-tools-only command. +gstreamer -- The bootstrap, build, package and bundle-source commands gained a - new --offline switch that ensures that only sources from the cache - are used and never downloaded via the network. This is useful in - combination with the fetch and fetch-bootstrap commands that acquire - sources ahead of time before any build steps are executed. This - allows more control over the sources used and when sources are - updated, and is particularly useful for build environments that - don’t have network access. +- gst: Add non-inline ref/unref/copy/replace methods for various mini + objects (buffer, bufferlist, caps, context, event, memory, message, + promise, query, sample, taglist, uri) for use in bindings such as + gstreamer-sharp +- harness: don’t use GST_DEBUG_OBJECT with GstHarness which is not a + GObject -- bootstrap --assume-yes will automatically say ‘yes’ to any - interactive prompts during the bootstrap stage, such as those from - apt-get or yum. +gst-plugins-base -- bootstrap --system-only will only bootstrap the system without build - tools. +- audiorate: Make buffer writable before changing its metadata +- compositor: fix blending of subsampled components +- decodebin3: When reconfiguring a slot make sure that the ghostpad is + unlinked +- decodebin3: Release selection lock when pushing EOS +- encodebasebin: Ensure that parsers are compatible with selected + encoders +- tagdemux: resize and trim buffer in place to fix interaction with + oggdemux +- videoaggregator: Pop out old buffers on timeout +- video-blend: fix blending 8-bit and 16-bit frames together +- appsrc: fix signal documentation +- gl: document some GL caps specifics +- libvisual: workaround clang compiler warning -- Manifest support: The build manifest can be used in continuous - integration (CI) systems to fixate the Git revision of certain - projects so that all builds of a pipeline are on the same reference. - This is used in GStreamer’s gitlab CI for example. It can also be - used in order to re-produce a specific build. To set a manifest, you - can set manifest = 'my_manifest.xml' in your configuration file, or - use the --manifest command line option. The command line option will - take precedence over anything specific in the configuration file. +gst-plugins-good -- The new build-deps command can be used to build only the - dependencies of a recipe, without the recipe itself. +- deinterlace: fix build of assembly optimisations on macOS +- splitmuxsink: Avoid deadlock when releasing a pad from a running + muxer +- splitmuxsink: fix bogus fragment split +- v4l2object: Map correct video format for RGBA +- videoflip: fix possible crash when changing video-direction/method + while running -- new --list-variants command to list available variants +gst-plugins-bad -- variants can now be set on the command line via the -v option as a - comma-separated list. This overrides any variants set in any - configuration files. +- assrender: fix mutex handling in certain flushing/error situations +- dvbsuboverlay: Add support for dynamic resolution update +- dashsink: fix critical log of dynamic pipeline +- d3d11shader: Fix ID3DBlob object leak +- d3d11videosink: Prepare window once streaming started +- decklinkaudiosrc: Fix duration of the first audio frame after each + discont +- intervideosrc: fix negotiation of interlaced caps +- msdk: needn’t close mfx session when failed, fixes double free / + potential crash +- msdk: check GstMsdkContext instead of mfxSession instance +- srt: fix locking when retrieving stats +- rtmp2src: fix leaks when connection is cancelled during startup or + connection fails -- new qt5, intelmsdk and nvidia variants for enabling Qt5 and hardware - codec support. See the Enabling Optional Features with Variants - section in the Cerbero documentation for more details how to enable - and use these variants. +gst-plugins-ugly -- A new -t / --timestamp command line switch makes commands print - timestamps +- no changes +gst-libav -Platform-specific changes and improvements +- avauddec: Drain decoder on decoding failure, fixes timestamps after + decoding errors -Android +gst-rtsp-server -- toolchain: update compiler to clang and NDKr18. NDK r18 removed the - armv5 target and only has Android platforms that target at least - armv7 so the armv5 target is not useful anymore. +- rtsp-media: Only count senders when counting blocked streams +- rtsp-client: Only unref client watch context on finalize, to avoid + deadlock -- The way that GIO modules are named has changed due to upstream GLib - natively adding support for loading static GIO modules. This means - that any GStreamer application using gnutls for SSL/TLS on the - Android or iOS platforms (or any other setup using static libraries) - will fail to link looking for the g_io_module_gnutls_load_static() - function. The new function name is now - g_io_gnutls_load(gpointer data). data can be NULL for a static - library. Look at this commit for the necessary change in the - examples. +gstreamer-vaapi -- various build issues on Android have been fixed. +- no changes -macOS and iOS +gstreamer-sharp -- various build issues on iOS have been fixed. +- no changes -- the minimum required iOS version is now 9.0. The difference in - adoption between 8.0 and 9.0 is 0.1% and the bump to 9.0 fixes some - build issues. +gst-omx -- The way that GIO modules are named has changed due to upstream GLib - natively adding support for loading static GIO modules. This means - that any GStreamer application using gnutls for SSL/TLS on the - Android or iOS platforms (or any other setup using static libraries) - will fail to link looking for the g_io_module_gnutls_load_static() - function. The new function name is now - g_io_gnutls_load(gpointer data). data can be NULL for a static - library. Look at this commit for the necessary change in the - examples. +- no changes -Windows +gst-python -- The webrtcdsp element is shipped again as part of the Windows binary - packages, the build system issue has been resolved. +- no changes -- ‘Inconsistent DLL linkage’ warnings when building with MSVC have - been fixed +gst-editing-services -- Hardware-accelerated Nvidia video encoder/decoder plugins nvdec and - nvenc build on Windows now, also with MSVC and using Meson. +- launch: Ensure to add required ref to profiles from project +- tests: fix meson test env setup to make sure we use the right + gst-plugin-scanner -- The ksvideosrc camera capture plugin supports 16-bit grayscale video - now +gst-integration-testsuites -- The wasapisrc audio capture element implements loopback recording - from another output device or sink +- no changes -- wasapisink recover from low buffer levels in shared mode and some - exclusive mode fixes +gst-build -- dshowsrc now implements the GstDeviceMonitor interface +- meson: Update zlib.wrap to use wrapdb instead of github fork +Cerbero build tool and packaging changes in 1.18.3 -Contributors +- Add support for Apple silicon +- Build and ship RIST plugin -Aaron Boxer, Aleix Conchillo Flaqué, Alessandro Decina, Alexandru Băluț, -Alex Ashley, Alexey Chernov, Alicia Boya García, Amit Pandya, Andoni -Morales Alastruey, Andreas Frisch, Andre McCurdy, Andy Green, Anthony -Violo, Antoine Jacoutot, Antonio Ospite, Arun Raghavan, Aurelien Jarno, -Aurélien Zanelli, ayaka, Bananahemic, Bastian Köcher, Branko Subasic, -Brendan Shanks, Carlos Rafael Giani, Charlie Turner, Christoph Reiter, -Corentin Noël, Daeseok Youn, Damian Vicino, Dan Kegel, Daniel Drake, -Daniel Klamt, Danilo Spinella, Dardo D Kleiner, David Ing, David -Svensson Fors, Devarsh Thakkar, Dimitrios Katsaros, Edward Hervey, -Emilio Pozuelo Monfort, Enrique Ocaña González, Erlend Eriksen, Ezequiel -Garcia, Fabien Dessenne, Fabrizio Gennari, Florent Thiéry, Francisco -Velazquez, Freyr666, Garima Gaur, Gary Bisson, George Kiagiadakis, Georg -Lippitsch, Georg Ottinger, Geunsik Lim, Göran Jönsson, Guillaume -Desmottes, H1Gdev, Haihao Xiang, Haihua Hu, Harshad Khedkar, Havard -Graff, He Junyan, Hoonhee Lee, Hosang Lee, Hyunjun Ko, Ilya Smelykh, -Ingo Randolf, Iñigo Huguet, Jakub Adam, James Stevenson, Jan Alexander -Steffens, Jan Schmidt, Jerome Laheurte, Jimmy Ohn, Joakim Johansson, -Jochen Henneberg, Johan Bjäreholt, John-Mark Bell, John Bassett, John -Nikolaides, Jonathan Karlsson, Jonny Lamb, Jordan Petridis, Josep Torra, -Joshua M. Doe, Jos van Egmond, Juan Navarro, Julian Bouzas, Jun Xie, -Junyan He, Justin Kim, Kai Kang, Kim Tae Soo, Kirill Marinushkin, Kyrylo -Polezhaiev, Lars Petter Endresen, Linus Svensson, Louis-Francis -Ratté-Boulianne, Lucas Stach, Luis de Bethencourt, Luz Paz, Lyon Wang, -Maciej Wolny, Marc-André Lureau, Marc Leeman, Marco Trevisan (Treviño), -Marcos Kintschner, Marian Mihailescu, Marinus Schraal, Mark Nauwelaerts, -Marouen Ghodhbane, Martin Kelly, Matej Knopp, Mathieu Duponchelle, -Matteo Valdina, Matthew Waters, Matthias Fend, memeka, Michael Drake, -Michael Gruner, Michael Olbrich, Michael Tretter, Miguel Paris, Mike -Wey, Mikhail Fludkov, Naveen Cherukuri, Nicola Murino, Nicolas Dufresne, -Niels De Graef, Nirbheek Chauhan, Norbert Wesp, Ognyan Tonchev, Olivier -Crête, Omar Akkila, Pat DeSantis, Patricia Muscalu, Patrick Radizi, -Patrik Nilsson, Paul Kocialkowski, Per Forlin, Peter Körner, Peter -Seiderer, Petr Kulhavy, Philippe Normand, Philippe Renon, Philipp Zabel, -Pierre Labastie, Piotr Drąg, Roland Jon, Roman Sivriver, Roman Shpuntov, -Rosen Penev, Russel Winder, Sam Gigliotti, Santiago Carot-Nemesio, -Sean-Der, Sebastian Dröge, Seungha Yang, Shi Yan, Sjoerd Simons, Snir -Sheriber, Song Bing, Soon, Thean Siew, Sreerenj Balachandran, Stefan -Ringel, Stephane Cerveau, Stian Selnes, Suhas Nayak, Takeshi Sato, -Thiago Santos, Thibault Saunier, Thomas Bluemel, Tianhao Liu, -Tim-Philipp Müller, Tobias Ronge, Tomasz Andrzejak, Tomislav Tustonić, -U. Artie Eoff, Ulf Olsson, Varunkumar Allagadapa, Víctor Guzmán, Víctor -Manuel Jáquez Leal, Vincenzo Bono, Vineeth T M, Vivia Nikolaidou, Wang -Fei, wangzq, Whoopie, Wim Taymans, Wind Yuan, Wonchul Lee, Xabier -Rodriguez Calvar, Xavier Claessens, Haihao Xiang, Yacine Bandou, -Yeongjin Jeong, Yuji Kuwabara, Zeeshan Ali, +Contributors to 1.18.3 + +Andoni Morales Alastruey, Edward Hervey, Haihao Xiang, Haihua Hu, Hou +Qi, Ignacio Casal Quinteiro, Jakub Adam, Jan Alexander Steffens +(heftig), Jan Schmidt, Jordan Petridis, Lawrence Troup, Lim Siew Hoon, +Mathieu Duponchelle, Matthew Waters, Nicolas Dufresne, Raju Babannavar, +Sebastian Dröge, Seungha Yang, Thibault Saunier, Tim-Philipp Müller, +Tobias Ronge, Vivia Nikolaidou, … and many others who have contributed bug reports, translations, sent -suggestions or helped testing. +suggestions or helped testing. Thank you all! + +List of merge requests and issues fixed in 1.18.3 + +- List of Merge Requests applied in 1.18.3 +- List of Issues fixed in 1.18.3 + +1.18.4 + +The fourth 1.18 bug-fix release (1.18.4) was released on 15 March 2021. + +This release only contains bugfixes and security fixes and it should be +safe to update from 1.18.x. + +Highlighted bugfixes in 1.18.4 + +- important security fixes for ID3 tag reading, matroska and realmedia + parsing, and gst-libav audio decoding +- audiomixer, audioaggregator: input buffer handling fixes +- decodebin3: improve stream-selection message handling +- uridecodebin3: make “caps” property work +- wavenc: fix writing of INFO chunks in some cases +- v4l2: bt601 colorimetry, allow encoder resolution changes, fix + decoder frame rate negotiation +- decklinkvideosink: fix auto format detection, and fixes for 29.97fps + framerate output +- mpeg-2 video handling fixes when seeking +- avviddec: fix bufferpool negotiation and possible memory corruption + when changing resolution +- various stability, performance and reliability improvements +- memory leak fixes +- build fixes: rpicamsrc, qt overlay example, d3d11videosink on UWP + +gstreamer + +- info: Don’t leak log function user_data if the debug system is + compiled out +- task: Use SetThreadDescription() Win32 API for setting thread names, + which preserves thread names in dump files. +- buffer, memory: Mark info in map functions as caller-allocates and + pass allocation params as const pointers where possible +- clock: define AUTO_CLEANUP_FREE_FUNC for GstClockID + +gst-plugins-base + +- tag: id3v2: fix frame size check and potential invalid reads +- audio: Fix gst_audio_buffer_truncate() meta handling for + non-interleaved audio +- audioresample: respect buffer layout when draining +- audioaggregator: fix input_buffer ownership +- decodebin3: change stream selection message owner, so that the app + sends the stream-selection event to the right element +- rtspconnection: correct data_size when tunneled mode +- uridecodebin3: make caps property work +- video-converter: Don’t upsample invalid lines +- videodecoder: Fix racy critical when pool negotiation occurs during + flush +- video: Convert gst_video_info_to_caps() to take self as const ptr +- examples: added qt core dependency for qt overlay example + +gst-plugins-good +- matroskademux: header parsing fixes +- rpicamsrc: depend on posix threads and vchiq_arm to fix build on + raspios again +- wavenc: Fixed INFO chunk corruption, caused by odd sized data not + being padded +- wavpackdec: Add floating point format support to fix distortions in + some cases +- v4l2: recognize V4L2 bt601 colorimetry again +- v4l2videoenc: support resolution change stream encode +- v4l2h265codec: fix HEVC profile string issue +- v4l2object: Need keep same transfer as input caps +- v4l2videodec: Fix vp8 and vp9 streams can’t play on board with + vendor bsp +- v4l2videodec: fix src side frame rate negotiation -Stable 1.16 branch +gst-plugins-bad -After the 1.16.0 release there will be several 1.16.x bug-fix releases -which will contain bug fixes which have been deemed suitable for a -stable branch, but no new features or intrusive changes will be added to -a bug-fix release usually. The 1.16.x bug-fix releases will be made from -the git 1.16 branch, which is a stable branch. +- avwait: Don’t post messages with the mutex locked +- d3d11h264dec: Reconfigure decoder object on DPB size change and keep + track of actually configured DPB size +- dashsink: fix double unref of sinkpad caps +- decklinkvideosink: Use correct numerator for 29.97fps +- decklinkvideosink: fix auto format detection +- decklinksrc: Use a more accurate capture time +- d3d11videosink: Fix build error on UWP +- interlace: negotiation and buffer leak fixes +- mpegvideoparse: do not clip, so decoder receives data from keyframe + even if it’s before the segment start +- mpegtsparse: Fix switched DTS/PTS when set-timestamps=false +- nvh264sldec: Reopen decoder object if larger DPB size is required +- sdpsrc: fix double free if sdp is provided as string via the + property +- vulkan: Fix elements long name. -1.16.0 +gst-plugins-ugly -1.16.0 was released on 19 April 2019. +- rmdemux: Make sure we have enough data available when parsing + audio/video packets +gst-libav -Known Issues +- avviddec: take the maximum of the height/coded_height +- viddec: don’t configure an incorrect buffer pool when receiving a + gap event +- audiodec: fix stack overflow in gst_ffmpeg_channel_layout_to_gst() + +gst-rtsp-server + +- rtspclientsink: fix deadlock on shutdown if no data has been + received yet +- rtspclientsink: fix leaks in unit tests +- rtsp-stream: avoid deadlock in send_func +- rtsp-client: cleanup transports during TEARDOWN + +gstreamer-vaapi + +- h264 encoder: append encoder exposure to aud +- postproc: Fix a problem of propose_allocation when passthrough +- glx: Iterate over FBConfig and select 8 bit color size + +gstreamer-sharp + +- no changes + +gst-omx + +- no changes + +gst-python + +- no changes -- possibly breaking/incompatible changes to properties of wrapped - FFmpeg decoders and encoders (see above). +gst-editing-services -- The way that GIO modules are named has changed due to upstream GLib - natively adding support for loading static GIO modules. This means - that any GStreamer application using gnutls for SSL/TLS on the - Android or iOS platforms (or any other setup using static libraries) - will fail to link looking for the g_io_module_gnutls_load_static() - function. The new function name is now - g_io_gnutls_load(gpointer data). See Android/iOS sections above for - further details. +- group: Use proper group constructor + +gst-integration-testsuites + +- no changes + +gst-build + +- no changes + +Cerbero build tool and packaging changes in 1.18.4 + +- macOS: more BigSur fixes +- glib: Backport patch to set thread names on Windows 10 + +Contributors to 1.18.4 + +Alicia Boya García, Ashley Brighthope, Bing Song, Branko Subasic, Edward +Hervey, Guillaume Desmottes, Haihua Hu, He Junyan, Hou Qi, Jan Alexander +Steffens (heftig), Jeongki Kim, Jordan Petridis, Knobe, Kristofer +Björkström, Marijn Suijten, Matthew Waters, Paul Goulpié, Philipp Zabel, +Rafał Dzięgiel, Sebastian Dröge, Seungha Yang, Staz M, Stéphane Cerveau, +Thibault Saunier, Tim-Philipp Müller, Víctor Manuel Jáquez Leal, Vivia +Nikolaidou, Vladimir Menshakov, + +… and many others who have contributed bug reports, translations, sent +suggestions or helped testing. Thank you all! + +List of merge requests and issues fixed in 1.18.4 + +- List of Merge Requests applied in 1.18.4 +- List of Issues fixed in 1.18.4 + +1.18.5 + +The fifth 1.18 bug-fix release (1.18.5) was released on 8 September +2021. + +This release only contains bugfixes and security fixes and it should be +safe to update from 1.18.x. + +Highlighted bugfixes in 1.18.5 + +- basesink: fix reverse frame stepping +- downloadbuffer/sparsefile: several fixes for win32 +- systemclock: Update monotonic reference time when re-scheduling, + fixes high CPU usage with gnome-music when pausing playback +- audioaggregator: fix glitches when resyncing on discont +- compositor: Fix NV12 blend operation +- rtspconnection: Add IPv6 support for tunneled mode +- avidemux: fix playback of some H.264-in-AVI streams +- jpegdec: Fix crash when interlaced field height is not DCT block + size aligned +- qmlglsink: Keep old buffers around a bit longer if they were bound + by QML +- qml: qtitem: don’t potentially leak a large number of buffers +- rtpjpegpay: fix image corruption when compiled with MSVC on Windows +- rtspsrc: seeking improvements +- rtpjitterbuffer: Avoid generation of invalid timestamps +- rtspsrc: Fix behaviour of select-streams, new-manager, + request-rtcp-key and before-send signals with GLib >= 2.62 +- multiudpsink: Fix broken SO_SNDBUF get/set on Windows +- openh264enc: fix broken sps/pps header generation and some minor + leaks +- mpeg2enc: fix interlace-mode detection and unbound memory usage if + encoder can’t keep up +- mfvideosrc: Fix for negative MF stride and for negotiation when + interlace-mode is specified +- tsdemux: fix seek-with-stop regression and decoding errors after + seeking with dvdlpcmdec +- rtsp-server: seek handling improvements +- gst-libav: fix build (and other issues) with ffmpeg 4.4 +- cerbero: spandsp: Fix build error with Visual Studio 2019 +- win32 packages: Fix hang in GLib when G_SLICE environment variable + is set + +gstreamer + +- aggregator: Release the SRC lock while querying latency +- aggregator: Release pads’ peeked buffer when removing the pad or + finalizing it +- basesink: Don’t swap rstart/rstop when stepping +- basesrc: Print segments with GST_SEGMENT_FORMAT and not + GST_PTR_FORMAT +- childproxy: init value in gst_child_proxy_get_property() if needed +- clocksync: Fix providing system clock by default +- concat: Properly propagate seqnum of segment events +- concat: adjust running time offsets on downstream events +- concat: fix locking in SEGMENT event handler +- downloadbuffer/sparsefile: several fixes for win32 +- element: NULL the lists of contexts in dispose() +- multiqueue: Use running time of gap events for wakeups. +- multiqueue: Ensure peer pad exists when iterating internal links +- pad: Keep IDLE probe hook alive during immediate callback +- pad: Ensure last flow return is set on sink pads in push mode +- pad: Don’t spam the debug log at INFO level when default-chaining a + buffer list +- pad: clear probes holding mutex +- parse-launch: Fix a critical when using the : operator. +- parse-launch: Don’t do delayed property setting for top-level + properties. +- plugin: load plugins with unknown license strings +- ptpclock: Don’t leak the GList +- queue2: Refuse all serialized queries when posting buffering + messages +- systemclock: Update monotonic reference time when re-scheduling +- High CPU usage in 1.18 (but not master) when pausing playback in + gnome-music +- Don’t use volatile to mean atomic (fixes compiler warnings with + gcc 11) + +gst-plugins-base + +- appsrc: Don’t leak buffer list while wrongly unreffing buffer on + EOS/flushing +- audioaggregator: Don’t overwrite already written samples +- audioaggregator: Resync on the next buffer when dropping a buffer on + discont resyncing +- audiobasesink: Fix of double lock release +- audioaggregator: Don’t overwrite already written samples +- audiobasesrc: Fix divide by zero assertion +- clockoverlay: Fix broken string formatting by strftime() on Windows +- compositor: Fix NV12 blend operation +- giosrc: Don’t leak scheme string in gst_gio_src_query() +- giobasesink: Handle incomplete writes in gst_gio_base_sink_render() +- gl/wayland: Use consistent wl_display when creating work queue for + proxy wrapper +- gl: Fix build when Meson >= 0.58.0rc1 +- gl/wayland: provide a dummy global_remove function +- playbin2: fix base_time selection when flush seeking live (such as + with RTSP) +- rtspconnection: Add IPv6 support for tunneled mode +- rtspconnection: Consistently translate GIOError to GstRTSPResult + (for rtspsrc) +- rawbaseparse: check destination format correctly +- uridecodebin: Don’t force floating reference for future reusable + decodebin +- parsebin: Put stream flags in GstStream +- splitmuxsink: always use factory property when set +- video-converter: Set up matrix tables only once. +- videoscale: Performance degradation from 1.16.2 -> 1.18.4 +- videotestsrc: Fix a leak when computing alpha caps +- audio/video-converter: Plug some minor leaks +- audio,video-format: Make generate_raw_formats idempotent for + assertions +- Don’t use volatile to mean atomic (fixes compiler warnings with + gcc 11) +- Fix build issue on MinGW64 + +gst-plugins-good + +- avidemux: Also detect 0x000001 as H264 byte-stream start code in + codec_data +- deinterlace: Plug a method subobject leak +- deinterlace: Drop field-order field if outputting progressive +- jpegdec: Fix crash when interlaced field height is not DCT block + size aligned +- qmlglsink: Keep old buffers around a bit longer if they were bound + by QML +- qml: qtitem: don’t potentially leak a large number of buffers +- qtdemux: Force stream-start push when re-using EOS’d streams +- qtmux: for Apple ProRes, allow overriding pixel bit depth, e.g. when + exporting an opaque image, yet with alpha. +- qtmux: Make sure to write 64-bit STCO table when needed. +- rtpjpegpay: fix image corruption when compiled with MSVC on Windows +- rtpptdemux: Remove pads also in PAUSED->READY +- rtph265depay: update codec_data in caps regardless of format +- rtspsrc: Do not overwrite the known duration after a seek +- rtspsrc: De-dup seek event seqnums to avoid multiple seeks +- rtspsrc: Fix race saving seek event seqnum +- rtspsrc: Using multicast UDP has no relation to seekability, also + add some logging +- rtpjitterbuffer: Fix parsing of the mediaclk:direct= field +- rtpjitterbuffer: Avoid generation of invalid timestamps +- rtpjitterbuffer: Check srcresult before waiting on the condition + variable too +- rtpjitterbuffer: More logging when calculating rfc7273 timestamps +- rtspsrc: Fix more signals +- rtspsrc: Fix accumulation of before-send signal return values +- souphttpsrc: Always use the content decoder but set + `Accept-Encoding:… +- udpsrc: Plug leaks of saddr in error cases +- multiudpsink: Fix broken SO_SNDBUF get/set on Windows +- v4l2object: Add interlace-mode back to caps for camera +- v4l2object: Use default colorimetry if that in caps is unknown +- V4l2object: Avoid colorimetry mismatch for streams with invalid + colorimetry +- v4l2object: Add support for hdr10 stream playback +- wavparse: adtl/note/labl chunk parsing fixes +- Don’t use volatile to mean atomic (fixes compiler warnings with + gcc 11) +- 1.18.4: build fails with glib 2.67.6 and gcc-11: argument 2 of + ‘__atomic_load’ must not be a pointer to a ‘volatile’ type + +gst-plugins-bad + +- audiolatency: Use live mode audiotestsrc +- audiolatency: Handle audio buffers with invalid duration +- ccconverter: fix framerate caps negotiation from non-cdp to cdp +- dashdemux: Properly initalize GError, remove duplicate logging call +- dashdemux: Log protection events on corresponding pad +- dashdemux: fix dash_mpdparser_check_mpd_client_set_methods unit test +- h264parse,h265parse: Push parameter set NAL units again per + segment-done +- h265parse: Fix a typo in get_compatible_profile_caps() +- h265parse: don’t invalidate the last PPS when parsing a new SPS +- h264parse: improve PPS handling +- h2645parser: Catch overflows in AVC/HEVC NAL unit length + calculations +- interlace: Don’t set field-order field for progressive caps, fixes + negotiation issues +- interlace: Fix too small buffer size error +- jpegparse: Don’t generate timestamp for 0/1 framerates +- opencv: fix build error on macOS +- openexr: Fix build with OpenEXR 3 +- openh264enc: fix broken sps/pps header generation and some minor + leaks +- mpeg2enc: fix interlace-mode detection on input video +- mpeg2enc: Only allow 1 pending frame for encoding (fixes unbound + memory usage in case encoder can’t keep up with input) +- mfvideoenc: Don’t pass 0/1 framerate to MFT +- mfvideosrc: Fix for negative MF stride +- mfvideosrc: Fix negotiation when interlace-mode is specified +- mxfvanc: Handle empty ANC essence +- rtmp2src: workaround a GLib race when destroying a + GMainContext/GSource +- rtpsrc: Plug leak of rtcp_send_addr and fix setting URI back to NULL +- rtpsink: Return proper pad from _request_new_pad() +- rist: Plug leak of rtcp_send_addr +- rtmp2: Use correct size of write macro for param2. +- rtmp2/connection: Separate inner from outer cancelling +- tsmux: When selecting random PIDs, name the pads according to those + PIDs +- tsmux: Recheck existing pad PIDs when requesting a new pad with a + random pid +- tsdemux: fix seek with stop regression +- tsdemux: Clear all streams when rewinding, fixes the case where the + demuxer sends out partial invalid data downstream after a seek which + causes some decoders (such as dvdlpmdec) to error out +- v4l2slh264dec: Fix slice header bit size calculation +- videoparseutils: Fix for wrong CEA708 minimum size check +- waylandsink: Fix for missing initial configure +- wpe: Make threaded view singleton creation thread safe +- x265: Fix a deadlock when failing to create the x265enc +- Don’t use volatile to mean atomic (fixes compiler warnings with + gcc 11) + +gst-plugins-ugly + +- asfdemux/realmedia: Drop duplicate seek events +- Don’t use volatile to mean atomic (fixes compiler warnings with + gcc 11) + +gst-libav + +- avmux: Blacklist ttml subtitles (fixes crash with ffmpeg >= 4.4) +- avmux: fix segfault when a plugin’s long_name is NULL +- avviddec: Fix size of linesize parameter +- avviddec: Take into account coded_height for pool +- avdemux: fix build with FFmpeg 4.4 + +gst-rtsp-server + +- rtsp-media: Ensure the bus watch is removed during unprepare +- rtsp-media: Add one more case to seek avoidance +- rtsp-media: Improve skipping trickmode seek +- Fix a few memory leaks + +gstreamer-vaapi + +- plugins: Demote rank of vaapipostproc and vaapioverlay to match + other filters +- Don’t use volatile to mean atomic (fixes compiler warnings with + gcc 11) + +gst-editing-services + +- xml-formatter: Fix allocation size of buffer +- framepositioner: Fix runtime warning +- Don’t use volatile to mean atomic (fixes compiler warnings with + gcc 11) + +gst-devtools + +- scenario: Fix EOS handling in seek_forward.scenario +- validate-utils: Only modify structure fields that really need + updates +- Don’t use volatile to mean atomic (fixes compiler warnings with + gcc 11) + +gst-integration-testsuites + +- validate: Update interlace_deinterlace_alternate to remove + field-order from expected caps + +gst-build + +- git-update: Make fetching of external repos non-fatal on the CI +- gst-env: Windows: Fix looking for cmd_or_ps.ps1 in the wrong + directory +- Pin gst-plugins-rs subproject to 0.7 branch + +Cerbero build tool and packaging changes in 1.18.5 + +- cerbero: Add a dotted progress bar for urllib downloads +- libunwind: make sure all pkgconfig files get included in the devel + package +- openssl.recipe: Bump to 1.1.1k +- glib: Fix hang on Windows when G_SLICE env is configured +- utils: Support latest Debian release names +- enums: generate fedora version strings automatically +- Rework cmake build system +- spandsp: Fix build error with Visual Studio 2019 + +Contributors to 1.18.5 + +Alba Mendez, Andoni Morales Alastruey, Antonio Rojas, Bartłomiej +Kurzeja, Binh Truong, Daniel Knobe, Doug Nazar, Edward Hervey, He +Junyan, Hou Qi, Jan Alexander Steffens (heftig), Jan Schmidt, Marijn +Suijten, Mathieu Duponchelle, Matthew Waters, Michael Olbrich, Miguel +Paris, Nicholas Jackson, Nicolas Dufresne, Nirbheek Chauhan, Olivier +Crête, Per Förlin, Philippe Normand, Robin Burchell, Ruslan Khamidullin, +Scott Moreau, Sebastian Dröge, Sergei Kovalev, Seungha Yang, Stéphane +Cerveau, Steve McDaniel, Thibault Saunier, Tim-Philipp Müller, Víctor +Manuel Jáquez Leal, Xavier Claessens, Youngsoo Lee, + +… and many others who have contributed bug reports, translations, sent +suggestions or helped testing. Thank you all! + +List of merge requests and issues fixed in 1.18.5 + +- List of Merge Requests applied in 1.18.5 +- List of Issues fixed in 1.18.5 + +1.18.6 + +The sixth 1.18 bug-fix release (1.18.6) was released on 2 February 2022. + +This release only contains bugfixes and security fixes and it should be +safe to update from 1.18.x. + +Highlighted bugfixes in 1.18.6 + +- tagdemux: Fix crash when presented with malformed files (security + fix) +- video-converter: Fix broken gamma remap with high bitdepth YUV + output +- shout2send: Fix issues with libshout >= 2.4.2 +- mxfdemux: fix regression with VANC tracks that only contains packet + types we don’t handle +- Better plugin loading error reporting on Windows +- Fixes for deprecations in Python 3.10 +- build fixes, memory leak fixes, reliability fixes +- security fixes + +gstreamer + +- gstplugin: Fix for UWP build +- gstplugin: Better warnings on plugin load failure on Windows +- gst-ptp-helper: Do not disable multicast loopback +- concat: fix qos event handling +- pluginfeature: Fix object leak +- baseparse: fix invalid avg_bitrate after reset +- multiqueue: Fix query unref race on flush +- gst: Initialize optional event/message fields when parsing +- bitwriter: Fix the trailing bits lost when getting its data. +- multiqueue: never consider a queue that is not waiting +- input-selector: Use proper segments when cleaning cached buffers + +gst-plugins-base + +- tagdemux: Fix crash when presented with malformed files (security + fix) +- videoencoder: make sure the buffer is writable before modifying + metadata +- video-converter: Fix for broken gamma remap with high bitdepth YUV + output +- sdpmessage: fix mapping single char fmtp params +- oggdemux: fix a race in push mode when performing the duration seek +- uridecodebin: Fix critical warnings +- audio-converter: Fix resampling when there’s nothing to output +- tcp: fix build on Solaris +- uridecodebin3: Nullify current item after all play items are freed. +- audio-resampler: Fix segfault when we can’t output any frames +- urisourcebin: Handle sources with dynamic pads and pads already + present +- playbin2/3: autoplug/caps: don’t expand caps to ANY +- uridecodebin3/urisourcebin: Reusability fixes +- rtspconnection: Only reset timeout when socket is unused +- gstvideoaggregator.c: fix build with gcc 4.8 + +gst-plugins-good + +- rtspsrc: Fix critical while serializing timeout element message +- multifilesrc: fix caps leak +- shout2: Add compatibility for libshout >= 2.4.2 shout_open return + values +- v4l2: Update fmt if padded height is greater than fmt height +- v4l2bufferpool: set video alignment of video meta +- qtmux: fix deadlock in gst_qt_mux_prepare_moov_recovery +- matroska: Add support for muxing/demuxing ffv1 +- qtdemux: Try to build AAC codec-data whenever it’s possible + +gst-plugins-bad + +- interlace: Fix a double-unref on shutdown +- webrtcbin: Chain up to parent constructed method +- webrtc: fix log error message in function + gst_webrtc_bin_set_local_description +- mxfdemux: don’t error out if VANC track only contains packets we + don’t handle +- av1parser: Fix data type of film grain param +- assrender: Support RFC8081 mime types +- pitch: Specify layout as required for negotiation +- magicleap: update lumin_rt libraries names to the latest official + version +- codecs: h265decoder: Fix per-slice leak +- mpeg4videoparse: fix criticals trying to insert configs that don’t + exist yet +- webrtcbin: Always set SINK/SRC flags +- mpegtspacketizer: memcmp potentially seen_before data +- zxing: update to support version 1.1.1 + +gst-plugins-ugly + +- No changes + +gst-libav + +- avcodecmap: Add support for GBRA_10LE/BE + +gst-rtsp-server + +- rtsp-stream: fix get_rates raciness +- rtsp-media: Only unprepare a media if it was not already unpreparing + anyway +- rtsp-media: Unprepare suspended medias too +- rtsp-client: make sure sessmedia will not get freed while used +- rtsp-media: Also mark receive-only (RECORD) medias as prepared when + unsuspending +- rtsp-session: Don’t unref medias twice if it is removed inside… +- examples: Fix leak in appsrc2 example + +gstreamer-vaapi + +- libs: video-format: Check if formats map is not NULL +- vaapidecode: Autogenerate caps template +- vaapipostproc: copy over metadata also when using system allocated + buffer + +gst-python + +- Avoid treating float as int (fix for Python 3.10) + +gst-editing-services + +- meson: Remove duplicate definition of ‘examples’ option + +gst-devtools + +- No changes + +gst-integration-testsuites + +- No changes + +gst-build + +- env: Fix deprecations from python 3.10 +- Various fixes for macOS +- update FFmpeg wrap to 4.3.3 + +Cerbero build tool and packaging changes in 1.18.6 + +- Some fixes for Fedora 34 +- cerbero: Backport fix for removed loop param of PriorityQueue() +- cerbero: Fix support for Fedora 35 +- Add support for Visual Studio 2022 +- openssl.recipe: Fix crash on iOS TestFlight +- UnixBootstrapper: remove sudo as root user +- bzip2.recipe: bump version to 1.0.8 +- openssl.recipe: upgrade to version 1.1.1l + +Contributors to 1.18.6 + +Antonio Ospite, Célestin Marot, Dave Piché, Erlend Eriksen, Fabrice +Fontaine, Guillaume Desmottes, Haihua Hu, He Junyan, Jakub Adam, Jan +Alexander Steffens (heftig), Jan Schmidt, Jeremy Cline, Jordan Petridis, +Mathieu Duponchelle, Matthew Waters, Mengkejiergeli Ba, Michael Gruner, +Nirbheek Chauhan, Ognyan Tonchev, Pascal Hache, Rafał Dzięgiel, +Sebastian Dröge, Seungha Yang, Stéphane Cerveau, Teng En Ung,Thibault +Saunier, Thomas Klausner, Tim-Philipp Müller, Tobias Reineke, Tobias +Ronge, Tomasz Andrzejak, Trung Do, Víctor Manuel Jáquez Leal, Vivia +Nikolaidou, + +… and many others who have contributed bug reports, translations, sent +suggestions or helped testing. Thank you all! +List of merge requests and issues fixed in 1.18.6 -Schedule for 1.18 +- List of Merge Requests applied in 1.18.6 +- List of Issues fixed in 1.18.6 -Our next major feature release will be 1.18, and 1.17 will be the -unstable development version leading up to the stable 1.18 release. The -development of 1.17/1.18 will happen in the git master branch. +Schedule for 1.20 -The plan for the 1.18 development cycle is yet to be confirmed, but it -is possible that the next cycle will be a short one in which case -feature freeze would be perhaps around August 2019 with a new 1.18 -stable release in September. +Our next major feature release will be 1.20, and will be released in +early February 2022. You can track its progress on the 1.20 Release +Notes page. -1.18 will be backwards-compatible to the stable 1.16, 1.14, 1.12, 1.10, -1.8, 1.6, 1.4, 1.2 and 1.0 release series. +1.20 will be backwards-compatible to the stable 1.18, 1.16, 1.14, 1.12, +1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series. ------------------------------------------------------------------------ -_These release notes have been prepared by Tim-Philipp Müller with_ -_contributions from Sebastian Dröge, Guillaume Desmottes, Matthew -Waters, _ _Thibault Saunier, and Víctor Manuel Jáquez Leal._ +These release notes have been prepared by Tim-Philipp Müller with +contributions from Mathieu Duponchelle, Matthew Waters, Nirbheek +Chauhan, Sebastian Dröge, Thibault Saunier, and Víctor Manuel Jáquez +Leal. -_License: CC BY-SA 4.0_ +License: CC BY-SA 4.0 diff --git a/README b/README index c55b0a6c00..300b39868d 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -GStreamer 1.17.x development series +GStreamer 1.18.x stable series WHAT IT IS ---------- diff --git a/RELEASE b/RELEASE index 2323209e29..3ecdbf2f8a 100644 --- a/RELEASE +++ b/RELEASE @@ -1,18 +1,18 @@ -This is GStreamer gst-plugins-good 1.17.0.1. +This is GStreamer gst-plugins-good 1.18.6. -The GStreamer team is thrilled to announce a new major feature release in the -stable 1.0 API series of your favourite cross-platform multimedia framework! +The GStreamer team is thrilled to announce a new major feature release +of your favourite cross-platform multimedia framework! As always, this release is again packed with new features, bug fixes and other improvements. -The 1.16 release series adds new features on top of the 1.14 series and is +The 1.18 release series adds new features on top of the 1.16 series and is part of the API and ABI-stable 1.x release series of the GStreamer multimedia framework. -Full release notes will one day be found at: +Full release notes can be found at: - https://gstreamer.freedesktop.org/releases/1.16/ + https://gstreamer.freedesktop.org/releases/1.18/ Binaries for Android, iOS, Mac OS X and Windows will usually be provided shortly after the release. @@ -60,7 +60,7 @@ You can find source releases of gstreamer in the download directory: https://gstreamer.freedesktop.org/src/gstreamer/ The git repository and details how to clone it can be found at -https://cgit.freedesktop.org/gstreamer/gstreamer/ +https://gitlab.freedesktop.org/gstreamer/ ==== Homepage ==== @@ -82,7 +82,7 @@ for more details. For help and support, please subscribe to and send questions to the gstreamer-devel mailing list (see below for details). -There is also a #gstreamer IRC channel on the Freenode IRC network. +There is also a #gstreamer IRC channel on the OFTC IRC network. ==== Developers ==== diff --git a/docs/gst_plugins_cache.json b/docs/gst_plugins_cache.json index 8efa45201b..980bb573db 100644 --- a/docs/gst_plugins_cache.json +++ b/docs/gst_plugins_cache.json @@ -14,9 +14,11 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstURIHandler" + ], "klass": "Source/Video", "long-name": "Firewire (1394) DV video source", - "name": "dv1394src", "pad-templates": { "src": { "caps": "video/x-dv:\n format: { NTSC, PAL }\n systemstream: true\n", @@ -25,130 +27,110 @@ } }, "properties": { - "blocksize": { - "blurb": "Size in bytes to read per buffer (-1 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, "channel": { "blurb": "Channel number for listening", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "63", "max": "64", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "consecutive": { "blurb": "send n consecutive frames after skipping", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "1", "max": "2147483647", "min": "1", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "device-name": { "blurb": "user-friendly name of the device", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "Default", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": false }, - "do-timestamp": { - "blurb": "Apply current stream time to buffers", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, "drop-incomplete": { "blurb": "drop incomplete frames", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "guid": { "blurb": "select one of multiple DV devices by its GUID. use a hexadecimal like 0xhhhhhhhhhhhhhhhh. (0 = no guid)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "num-buffers": { - "blurb": "Number of buffers to output before sending EOS (-1 = unlimited)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "port": { "blurb": "Port number (-1 automatic)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "-1", "max": "16", "min": "-1", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "skip": { "blurb": "skip n frames", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "2147483647", "min": "0", - "type-name": "gint", - "writable": true - }, - "typefind": { - "blurb": "Run typefind before negotiating (deprecated, non-functional)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "use-avc": { "blurb": "Use AV/C VTR control", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, @@ -156,7 +138,8 @@ "signals": { "frame-dropped": { "args": [], - "retval": "void" + "return-type": "void", + "when": "last" } } }, @@ -172,9 +155,11 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstURIHandler" + ], "klass": "Source/Video", "long-name": "Firewire (1394) HDV video source", - "name": "hdv1394src", "pad-templates": { "src": { "caps": "video/mpegts:\n systemstream: true\n packetsize: 188\n", @@ -183,102 +168,70 @@ } }, "properties": { - "blocksize": { - "blurb": "Size in bytes to read per buffer (-1 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, "channel": { "blurb": "Channel number for listening", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "63", "max": "64", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "device-name": { "blurb": "user-friendly name of the device", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "Default", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": false }, - "do-timestamp": { - "blurb": "Apply current stream time to buffers", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, "guid": { "blurb": "select one of multiple DV devices by its GUID. use a hexadecimal like 0xhhhhhhhhhhhhhhhh. (0 = no guid)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "num-buffers": { - "blurb": "Number of buffers to output before sending EOS (-1 = unlimited)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "port": { "blurb": "Port number (-1 automatic)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "-1", "max": "16", "min": "-1", - "type-name": "gint", - "writable": true - }, - "typefind": { - "blurb": "Run typefind before negotiating (deprecated, non-functional)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "use-avc": { "blurb": "Use AV/C VTR control", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, @@ -287,13 +240,14 @@ }, "filename": "gst1394", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" }, "aasink": { - "description": "ASCII Art video sink", + "description": "ASCII Art video sink & filter", "elements": { "aasink": { "author": "Wim Taymans ", @@ -309,7 +263,6 @@ ], "klass": "Sink/Video", "long-name": "ASCII art video sink", - "name": "aasink", "pad-templates": { "sink": { "caps": "video/x-raw:\n format: I420\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", @@ -318,310 +271,725 @@ } }, "properties": { - "async": { - "blurb": "Go asynchronously to PAUSED", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "blocksize": { - "blurb": "Size in bytes to pull per buffer (0 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, "brightness": { "blurb": "brightness", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "2147483647", "min": "-2147483648", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "contrast": { "blurb": "contrast", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "16", "max": "2147483647", "min": "-2147483648", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "dither": { "blurb": "dither", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "no-dithering (0)", - "enum": true, - "type-name": "GstAASinkDitherers", - "values": [ - { - "desc": "no dithering", - "name": "no-dithering", - "value": "0" - }, - { - "desc": "error-distribution", - "name": "error-distribution", - "value": "1" - }, - { - "desc": "floyd-steelberg dithering", - "name": "floyd-steelberg-dithering", - "value": "2" - } - ], + "mutable": "null", + "readable": true, + "type": "GstAASinkDitherers", "writable": true }, "driver": { "blurb": "driver", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "x11 (0)", - "enum": true, - "type-name": "GstAASinkDrivers", - "values": [ - { - "desc": "X11 driver 1.1", - "name": "x11", - "value": "0" - }, - { - "desc": "Linux pc console driver 1.0", - "name": "linux", - "value": "1" - }, - { - "desc": "Slang driver 1.0", - "name": "slang", - "value": "2" - }, - { - "desc": "Curses driver 1.0", - "name": "curses", - "value": "3" - }, - { - "desc": "Standard output driver", - "name": "stdout", - "value": "4" - }, - { - "desc": "Standard error driver", - "name": "stderr", - "value": "5" - } - ], - "writable": true - }, - "enable-last-sample": { - "blurb": "Enable the last-sample property", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "GstAASinkDrivers", "writable": true }, "frame-time": { "blurb": "frame time", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "2147483647", "min": "-2147483648", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": false }, "frames-displayed": { "blurb": "frames displayed", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "2147483647", "min": "-2147483648", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": false }, "gamma": { "blurb": "gamma", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "1", "max": "5", "min": "0", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, "height": { "blurb": "height", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", + "controllable": false, + "default": "24", "max": "2147483647", "min": "-2147483648", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "inversion": { "blurb": "inversion", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "last-sample": { - "blurb": "The last sample received in the sink", + "randomval": { + "blurb": "randomval", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstSample", - "writable": false + "controllable": false, + "default": "0", + "max": "2147483647", + "min": "-2147483648", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true }, - "max-bitrate": { - "blurb": "The maximum bits per second to render (0 = disabled)", + "width": { + "blurb": "width", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "80", + "max": "2147483647", + "min": "-2147483648", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + } + }, + "rank": "none" + }, + "aatv": { + "author": "Eric Marks ", + "description": "ASCII art effect", + "hierarchy": [ + "GstAATv", + "GstVideoFilter", + "GstBaseTransform", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Filter/Effect/Video", + "long-name": "aaTV effect", + "pad-templates": { + "sink": { + "caps": "video/x-raw:\n format: { I420 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "video/x-raw:\n format: { RGBA }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "brightness": { + "blurb": "Brightness", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", + "max": "255", + "min": "-255", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "max-lateness": { - "blurb": "Maximum number of nanoseconds that a buffer can be late before it is dropped (-1 unlimited)", + "brightness-actual": { + "blurb": "Actual calculated foreground pixel fill percentage", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "5000000", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", + "controllable": false, + "default": "0.35", + "max": "1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gfloat", + "writable": false + }, + "brightness-auto": { + "blurb": "Automatically adjust brightness based on the previous frame's foreground pixel fill percentage", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "name": { - "blurb": "The name of the object", - "construct": true, + "brightness-max": { + "blurb": "Maximum target foreground pixel fill percentage for automatic brightness control", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "default": "0.4", + "max": "1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "brightness-min": { + "blurb": "Minimum target foreground pixel fill percentage for automatic brightness control", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "0.3", + "max": "1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, - "processing-deadline": { - "blurb": "Maximum processing deadline in nanoseconds", + "color-background": { + "blurb": "Color to use as the background for the ASCII text (big-endian ARGB).", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "15000000", - "max": "18446744073709551615", + "controllable": true, + "default": "-16777216", + "max": "-1", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "qos": { - "blurb": "Generate Quality-of-Service events upstream", + "color-rain": { + "blurb": "Automatically sets color-rain-bold, color-rain-normal, and color-rain-dim with progressively dimmer values (big-endian ARGB).", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": true, + "default": "-16711936", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "randomval": { - "blurb": "randomval", + "color-rain-bold": { + "blurb": "Sets the brightest color to use for foreground ASCII text rain overlays (big-endian ARGB).", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "-2147483648", - "type-name": "gint", + "controllable": true, + "default": "-16711936", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "render-delay": { - "blurb": "Additional render delay of the sink in nanoseconds", + "color-rain-dim": { + "blurb": "Sets the dimmest brightness color to use for foreground ASCII text rain overlays (big-endian ARGB).", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "18446744073709551615", + "controllable": true, + "default": "-16761088", + "max": "-1", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "show-preroll-frame": { - "blurb": "Whether to render video frames during preroll", - "construct": true, + "color-rain-normal": { + "blurb": "Sets the normal brightness color to use for foreground ASCII text rain overlays (big-endian ARGB).", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": true, + "default": "-16744704", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "stats": { - "blurb": "Sink Statistics", + "color-text": { + "blurb": "Automatically sets color-test-bold, color-text-normal, and color-text-dim with progressively dimmer values (big-endian ARGB).", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "application/x-gst-base-sink-stats, average-rate=(double)0, dropped=(guint64)0, rendered=(guint64)0;", - "type-name": "GstStructure", - "writable": false + "controllable": true, + "default": "-1", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true }, - "sync": { - "blurb": "Sync on the clock", + "color-text-bold": { + "blurb": "Sets the brightest color to use for foreground ASCII text (big-endian ARGB).", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": true, + "default": "-1", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "throttle-time": { - "blurb": "The time to keep between rendered buffers (0 = disabled)", + "color-text-dim": { + "blurb": "Sets the dimmest brightness color to use for foreground ASCII text (big-endian ARGB).", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "18446744073709551615", + "controllable": true, + "default": "-12632257", + "max": "-1", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "ts-offset": { - "blurb": "Timestamp offset in nanoseconds", + "color-text-normal": { + "blurb": "Sets the normal brightness color to use for foreground ASCII text (big-endian ARGB).", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "-9223372036854775808", - "type-name": "gint64", + "controllable": true, + "default": "-8421505", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "width": { - "blurb": "width", + "contrast": { + "blurb": "Contrast", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", - "max": "2147483647", - "min": "-2147483648", - "type-name": "gint", + "max": "255", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true - } + }, + "dither": { + "blurb": "Add noise to more closely approximate gray levels.", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "no-dithering (0)", + "mutable": "null", + "readable": true, + "type": "GstAATvDitherers", + "writable": true + }, + "font": { + "blurb": "AAlib Font", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "Standard-vga-8x8-font (0)", + "mutable": "null", + "readable": true, + "type": "GstAATvFonts", + "writable": true + }, + "gamma": { + "blurb": "Gamma correction", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "1", + "max": "5", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gfloat", + "writable": true + }, + "height": { + "blurb": "Height of the ASCII canvas", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "24", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + }, + "rain-delay-max": { + "blurb": "Maximum frame delay between rain motion", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "3", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + }, + "rain-delay-min": { + "blurb": "Minimum frame delay between rain motion", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + }, + "rain-length-max": { + "blurb": "Maximum length of a rain", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "30", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + }, + "rain-length-min": { + "blurb": "Minimum length of a rain", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "4", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + }, + "rain-mode": { + "blurb": "Set the direction of raindrops", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "none (0)", + "mutable": "null", + "readable": true, + "type": "GstAATvRainModes", + "writable": true + }, + "rain-spawn-rate": { + "blurb": "Percentage chance for a raindrop to spawn", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0.2", + "max": "1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gfloat", + "writable": true + }, + "randomval": { + "blurb": "Adds a random value in the range (-randomval/2,ranomval/2) to each pixel during rendering", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "255", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + }, + "width": { + "blurb": "Width of the ASCII canvas", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "80", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + } }, "rank": "none" } }, "filename": "gstaasink", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": { + "GstAASinkDitherers": { + "kind": "enum", + "values": [ + { + "desc": "no dithering", + "name": "no-dithering", + "value": "0" + }, + { + "desc": "error-distribution", + "name": "error-distribution", + "value": "1" + }, + { + "desc": "floyd-steelberg dithering", + "name": "floyd-steelberg-dithering", + "value": "2" + } + ] + }, + "GstAASinkDrivers": { + "kind": "enum", + "values": [ + { + "desc": "X11 driver 1.1", + "name": "x11", + "value": "0" + }, + { + "desc": "Linux pc console driver 1.0", + "name": "linux", + "value": "1" + }, + { + "desc": "Slang driver 1.0", + "name": "slang", + "value": "2" + }, + { + "desc": "Curses driver 1.0", + "name": "curses", + "value": "3" + }, + { + "desc": "Standard output driver", + "name": "stdout", + "value": "4" + }, + { + "desc": "Standard error driver", + "name": "stderr", + "value": "5" + } + ] + }, + "GstAATvDitherers": { + "kind": "enum", + "values": [ + { + "desc": "no dithering", + "name": "no-dithering", + "value": "0" + }, + { + "desc": "error-distribution", + "name": "error-distribution", + "value": "1" + }, + { + "desc": "floyd-steelberg dithering", + "name": "floyd-steelberg-dithering", + "value": "2" + } + ] + }, + "GstAATvFonts": { + "kind": "enum", + "values": [ + { + "desc": "vga8", + "name": "Standard-vga-8x8-font", + "value": "0" + }, + { + "desc": "vga9", + "name": "Standard-vga-8x9-font", + "value": "1" + }, + { + "desc": "mda14", + "name": "Standard-mda/vga-8x14-font", + "value": "2" + }, + { + "desc": "vga16", + "name": "Standard-vga-8x16-font", + "value": "3" + }, + { + "desc": "X8x13", + "name": "X-8x13-font", + "value": "4" + }, + { + "desc": "X8x13bold", + "name": "X-8x13bold-font", + "value": "5" + }, + { + "desc": "X8x16", + "name": "Standard-X-8x16-font", + "value": "6" + }, + { + "desc": "line", + "name": "line-Font-8x8", + "value": "7" + }, + { + "desc": "vgagl8", + "name": "Font-8x8-from-vgagl", + "value": "8" + }, + { + "desc": "courier", + "name": "Adobe-courier", + "value": "9" + } + ] + }, + "GstAATvRainModes": { + "kind": "enum", + "values": [ + { + "desc": "No Rain", + "name": "none", + "value": "0" + }, + { + "desc": "Rain Down", + "name": "down", + "value": "1" + }, + { + "desc": "Rain Up", + "name": "up", + "value": "2" + }, + { + "desc": "Rain Left", + "name": "left", + "value": "3" + }, + { + "desc": "Rain Right", + "name": "right", + "value": "4" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", + "tracers": {}, "url": "Unknown package origin" }, "alaw": { @@ -640,7 +1008,6 @@ ], "klass": "Codec/Decoder/Audio", "long-name": "A Law audio decoder", - "name": "alawdec", "pad-templates": { "sink": { "caps": "audio/x-alaw:\n rate: [ 8000, 192000 ]\n channels: [ 1, 2 ]\n", @@ -653,52 +1020,7 @@ "presence": "always" } }, - "properties": { - "min-latency": { - "blurb": "Aggregate output data to a minimum of latency time (ns)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "plc": { - "blurb": "Perform packet loss concealment (if supported)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "tolerance": { - "blurb": "Perfect ts while timestamp jitter/imperfection within tolerance (ns)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - } - }, + "properties": {}, "rank": "primary" }, "alawenc": { @@ -712,9 +1034,11 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstPreset" + ], "klass": "Codec/Encoder/Audio", "long-name": "A Law audio encoder", - "name": "alawenc", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: S16LE\n layout: interleaved\n rate: [ 8000, 192000 ]\n channels: [ 1, 2 ]\n", @@ -727,64 +1051,14 @@ "presence": "always" } }, - "properties": { - "hard-resync": { - "blurb": "Perform clipping and sample flushing upon discontinuity", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "mark-granule": { - "blurb": "Apply granule semantics to buffer metadata (implies perfect-timestamp)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": false - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-timestamp": { - "blurb": "Favour perfect timestamps over tracking upstream timestamps", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "tolerance": { - "blurb": "Consider discontinuity if timestamp jitter/imperfection exceeds tolerance (ns)", - "construct": false, - "construct-only": false, - "default": "40000000", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - } - }, + "properties": {}, "rank": "primary" } }, "filename": "gstalaw", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -806,7 +1080,6 @@ ], "klass": "Filter/Effect/Video", "long-name": "Alpha filter", - "name": "alpha", "pad-templates": { "sink": { "caps": "video/x-raw:\n format: { AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, BGRx, xBGR, RGBx, RGB, BGR, Y42B, YUY2, YVYU, UYVY, I420, YV12, Y41B }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", @@ -822,145 +1095,138 @@ "properties": { "alpha": { "blurb": "The value for the alpha channel", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "1", "max": "1", "min": "0", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, "angle": { "blurb": "Size of the colorcube to change", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "20", "max": "90", "min": "0", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, "black-sensitivity": { "blurb": "Sensitivity to dark colors", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "100", "max": "128", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "method": { "blurb": "How the alpha channels should be created", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "set (0)", - "enum": true, - "type-name": "GstAlphaMethod", - "values": [ - { - "desc": "Set/adjust alpha channel", - "name": "set", - "value": "0" - }, - { - "desc": "Chroma Key on pure green", - "name": "green", - "value": "1" - }, - { - "desc": "Chroma Key on pure blue", - "name": "blue", - "value": "2" - }, - { - "desc": "Chroma Key on custom RGB values", - "name": "custom", - "value": "3" - } - ], - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "GstAlphaMethod", "writable": true }, "noise-level": { "blurb": "Size of noise radius", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "2", "max": "64", "min": "0", - "type-name": "gfloat", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, "prefer-passthrough": { "blurb": "Don't do any processing for alpha=1.0 if possible", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "false", - "type-name": "gboolean", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "target-b": { "blurb": "The blue color value for custom RGB chroma keying", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "255", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "target-g": { "blurb": "The green color value for custom RGB chroma keying", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "255", "max": "255", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "target-r": { "blurb": "The red color value for custom RGB chroma keying", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "255", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "white-sensitivity": { "blurb": "Sensitivity to bright colors", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "100", "max": "128", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true } }, @@ -969,7 +1235,34 @@ }, "filename": "gstalpha", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": { + "GstAlphaMethod": { + "kind": "enum", + "values": [ + { + "desc": "Set/adjust alpha channel", + "name": "set", + "value": "0" + }, + { + "desc": "Chroma Key on pure green", + "name": "green", + "value": "1" + }, + { + "desc": "Chroma Key on pure blue", + "name": "blue", + "value": "2" + }, + { + "desc": "Chroma Key on custom RGB values", + "name": "custom", + "value": "3" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -991,7 +1284,6 @@ ], "klass": "Filter/Converter/Video", "long-name": "Alpha color filter", - "name": "alphacolor", "pad-templates": { "sink": { "caps": "video/x-raw:\n format: { RGBA, BGRA, ARGB, ABGR, AYUV }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", @@ -1004,38 +1296,14 @@ "presence": "always" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - } - }, + "properties": {}, "rank": "none" } }, "filename": "gstalphacolor", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -1044,7 +1312,7 @@ "description": "APEv1/2 tag reader", "elements": { "apedemux": { - "author": "Tim-Philipp M\u00fcller ", + "author": "Tim-Philipp Müller ", "description": "Read and output APE tags while demuxing the contents", "hierarchy": [ "GstApeDemux", @@ -1056,7 +1324,6 @@ ], "klass": "Codec/Demuxer/Metadata", "long-name": "APE tag demuxer", - "name": "apedemux", "pad-templates": { "sink": { "caps": "application/x-apetag:\n", @@ -1069,30 +1336,13 @@ "presence": "always" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, "rank": "primary" } }, "filename": "gstapetag", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -1101,7 +1351,7 @@ "description": "Audio effects plugin", "elements": { "audioamplify": { - "author": "Sebastian Dr\u00f6ge ", + "author": "Sebastian Dröge ", "description": "Amplifies an audio stream by a given factor", "hierarchy": [ "GstAudioAmplify", @@ -1114,7 +1364,6 @@ ], "klass": "Filter/Effect/Audio", "long-name": "Audio amplifier", - "name": "audioamplify", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: { S8, S16LE, S32LE, F32LE, F64LE }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: { (string)interleaved, (string)non-interleaved }\n", @@ -1130,74 +1379,35 @@ "properties": { "amplification": { "blurb": "Factor of amplification", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "1", "max": "3.40282e+38", "min": "-3.40282e+38", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, "clipping-method": { "blurb": "Selects how to handle values higher than the maximum", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "clip (0)", - "enum": true, - "type-name": "GstAudioAmplifyClippingMethod", - "values": [ - { - "desc": "Normal clipping (default)", - "name": "clip", - "value": "0" - }, - { - "desc": "Push overdriven values back from the opposite side", - "name": "wrap-negative", - "value": "1" - }, - { - "desc": "Push overdriven values back from the same side", - "name": "wrap-positive", - "value": "2" - }, - { - "desc": "No clipping", - "name": "none", - "value": "3" - } - ], - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "GstAudioAmplifyClippingMethod", "writable": true } }, "rank": "none" }, "audiochebband": { - "author": "Sebastian Dr\u00f6ge ", + "author": "Sebastian Dröge ", "description": "Chebyshev band pass and band reject filter", "hierarchy": [ "GstAudioChebBand", @@ -1211,7 +1421,6 @@ ], "klass": "Filter/Effect/Audio", "long-name": "Band pass & band reject filter", - "name": "audiochebband", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: { F32LE, F64LE }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: interleaved\n", @@ -1227,104 +1436,91 @@ "properties": { "lower-frequency": { "blurb": "Start frequency of the band (Hz)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "100000", "min": "0", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, "mode": { "blurb": "Low pass or high pass mode", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "band-pass (0)", - "enum": true, - "type-name": "GstAudioChebBandMode", - "values": [ - { - "desc": "Band pass (default)", - "name": "band-pass", - "value": "0" - }, - { - "desc": "Band reject", - "name": "band-reject", - "value": "1" - } - ], - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "GstAudioChebBandMode", "writable": true }, "poles": { "blurb": "Number of poles to use, will be rounded up to the next multiply of four", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "4", "max": "32", "min": "4", - "type-name": "gint", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "ripple": { "blurb": "Amount of ripple (dB)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0.25", "max": "200", "min": "0", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, "type": { "blurb": "Type of the chebychev filter", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "1", "max": "2", "min": "1", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "upper-frequency": { "blurb": "Stop frequency of the band (Hz)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "100000", "min": "0", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true } }, "rank": "none" }, "audiocheblimit": { - "author": "Sebastian Dr\u00f6ge ", + "author": "Sebastian Dröge ", "description": "Chebyshev low pass and high pass filter", "hierarchy": [ "GstAudioChebLimit", @@ -1338,7 +1534,6 @@ ], "klass": "Filter/Effect/Audio", "long-name": "Low pass & high pass filter", - "name": "audiocheblimit", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: { F32LE, F64LE }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: interleaved\n", @@ -1354,94 +1549,77 @@ "properties": { "cutoff": { "blurb": "Cut off frequency (Hz)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "100000", "min": "0", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, "mode": { "blurb": "Low pass or high pass mode", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "low-pass (0)", - "enum": true, - "type-name": "GstAudioChebLimitMode", - "values": [ - { - "desc": "Low pass (default)", - "name": "low-pass", - "value": "0" - }, - { - "desc": "High pass", - "name": "high-pass", - "value": "1" - } - ], - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "GstAudioChebLimitMode", "writable": true }, "poles": { "blurb": "Number of poles to use, will be rounded up to the next even number", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "4", "max": "32", "min": "2", - "type-name": "gint", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "ripple": { "blurb": "Amount of ripple (dB)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0.25", "max": "200", "min": "0", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, "type": { "blurb": "Type of the chebychev filter", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "1", "max": "2", "min": "1", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true } }, "rank": "none" }, "audiodynamic": { - "author": "Sebastian Dr\u00f6ge ", + "author": "Sebastian Dröge ", "description": "Compressor and Expander", "hierarchy": [ "GstAudioDynamic", @@ -1454,7 +1632,6 @@ ], "klass": "Filter/Effect/Audio", "long-name": "Dynamic range controller", - "name": "audiodynamic", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: { S16LE, F32LE }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: { (string)interleaved, (string)non-interleaved }\n", @@ -1470,95 +1647,61 @@ "properties": { "characteristics": { "blurb": "Selects whether the ratio should be applied smooth (soft-knee) or hard (hard-knee).", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "hard-knee (0)", - "enum": true, - "type-name": "GstAudioDynamicCharacteristics", - "values": [ - { - "desc": "Hard Knee (default)", - "name": "hard-knee", - "value": "0" - }, - { - "desc": "Soft Knee (smooth)", - "name": "soft-knee", - "value": "1" - } - ], + "mutable": "null", + "readable": true, + "type": "GstAudioDynamicCharacteristics", "writable": true }, "mode": { "blurb": "Selects whether the filter should work on loud samples (compressor) orquiet samples (expander).", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "compressor (0)", - "enum": true, - "type-name": "GstAudioDynamicMode", - "values": [ - { - "desc": "Compressor (default)", - "name": "compressor", - "value": "0" - }, - { - "desc": "Expander", - "name": "expander", - "value": "1" - } - ], - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "GstAudioDynamicMode", "writable": true }, "ratio": { "blurb": "Ratio that should be applied", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "1", "max": "3.40282e+38", "min": "0", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, "threshold": { "blurb": "Threshold until the filter is activated", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "1", "min": "0", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true } }, "rank": "none" }, "audioecho": { - "author": "Sebastian Dr\u00f6ge ", + "author": "Sebastian Dröge ", "description": "Adds an echo or reverb effect to an audio stream", "hierarchy": [ "GstAudioEcho", @@ -1571,7 +1714,6 @@ ], "klass": "Filter/Effect/Audio", "long-name": "Audio echo", - "name": "audioecho", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: { F32LE, F64LE }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: interleaved\n", @@ -1587,91 +1729,91 @@ "properties": { "delay": { "blurb": "Delay of the echo in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "1", "max": "18446744073709551615", "min": "1", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "feedback": { "blurb": "Amount of feedback", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "1", "min": "0", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, "intensity": { "blurb": "Intensity of the echo", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "1", "min": "0", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, "max-delay": { "blurb": "Maximum delay of the echo in nanoseconds (can't be changed in PLAYING or PAUSED state)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "1", "max": "18446744073709551615", "min": "1", - "type-name": "guint64", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "ready", + "readable": true, + "type": "guint64", "writable": true }, "surround-delay": { "blurb": "Delay Surround Channels when TRUE instead of applying an echo effect", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "surround-mask": { "blurb": "A bitmask of channels that are considered surround and delayed when surround-delay = TRUE", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "18446744073709551612", "max": "18446744073709551615", "min": "1", - "type-name": "guint64", + "mutable": "ready", + "readable": true, + "type": "guint64", "writable": true } }, "rank": "none" }, "audiofirfilter": { - "author": "Sebastian Dr\u00f6ge ", + "author": "Sebastian Dröge ", "description": "Generic audio FIR filter with custom filter kernel", "hierarchy": [ "GstAudioFIRFilter", @@ -1685,7 +1827,6 @@ ], "klass": "Filter/Effect/Audio", "long-name": "Audio FIR filter", - "name": "audiofirfilter", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: { F32LE, F64LE }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: interleaved\n", @@ -1699,61 +1840,29 @@ } }, "properties": { - "drain-on-changes": { - "blurb": "Drains the filter when its coefficients change", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, "kernel": { "blurb": "Filter kernel for the FIR filter", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GValueArray", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GValueArray", "writable": true }, "latency": { "blurb": "Filter latency in samples", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", - "writable": true - }, - "low-latency": { - "blurb": "Operate in low latency mode. This mode is slower but the latency will only be the filter pre-latency. Can only be changed in states < PAUSED!", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true } }, @@ -1761,14 +1870,18 @@ "signals": { "rate-changed": { "args": [ - "gint" + { + "name": "arg0", + "type": "gint" + } ], - "retval": "void" + "return-type": "void", + "when": "last" } } }, "audioiirfilter": { - "author": "Sebastian Dr\u00f6ge ", + "author": "Sebastian Dröge ", "description": "Generic audio IIR filter with custom filter kernel", "hierarchy": [ "GstAudioIIRFilter", @@ -1782,7 +1895,6 @@ ], "klass": "Filter/Effect/Audio", "long-name": "Audio IIR filter", - "name": "audioiirfilter", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: { F32LE, F64LE }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: interleaved\n", @@ -1798,40 +1910,24 @@ "properties": { "a": { "blurb": "Filter coefficients (denominator of transfer function)", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GValueArray", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GValueArray", "writable": true }, "b": { "blurb": "Filter coefficients (numerator of transfer function)", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GValueArray", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GValueArray", "writable": true } }, @@ -1839,14 +1935,18 @@ "signals": { "rate-changed": { "args": [ - "gint" + { + "name": "arg0", + "type": "gint" + } ], - "retval": "void" + "return-type": "void", + "when": "last" } } }, "audioinvert": { - "author": "Sebastian Dr\u00f6ge ", + "author": "Sebastian Dröge ", "description": "Swaps upper and lower half of audio samples", "hierarchy": [ "GstAudioInvert", @@ -1859,7 +1959,6 @@ ], "klass": "Filter/Effect/Audio", "long-name": "Audio inversion", - "name": "audioinvert", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: { S16LE, F32LE }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: { (string)interleaved, (string)non-interleaved }\n", @@ -1875,36 +1974,16 @@ "properties": { "degree": { "blurb": "Degree of inversion", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "1", "min": "0", - "type-name": "gfloat", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true } }, @@ -1924,7 +2003,6 @@ ], "klass": "Filter/Effect/Audio", "long-name": "AudioKaraoke", - "name": "audiokaraoke", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: { S16LE, F32LE }\n rate: [ 1, 2147483647 ]\n channels: 2\n channel-mask: 0x0000000000000003\n layout: interleaved\n", @@ -1940,66 +2018,58 @@ "properties": { "filter-band": { "blurb": "The Frequency band of the filter", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "220", "max": "441", "min": "0", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, "filter-width": { "blurb": "The Frequency width of the filter", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "100", "max": "100", "min": "0", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, "level": { "blurb": "Level of the effect (1.0 = full)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "1", "max": "1", "min": "0", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, "mono-level": { "blurb": "Level of the mono channel (1.0 = full)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "1", "max": "1", "min": "0", - "type-name": "gfloat", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true } }, @@ -2018,7 +2088,6 @@ ], "klass": "Filter/Effect/Audio", "long-name": "Stereo positioning", - "name": "audiopanorama", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: { F32LE, S16LE }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2 ]\n layout: interleaved\n", @@ -2034,64 +2103,35 @@ "properties": { "method": { "blurb": "Psychoacoustic mode keeps same perceived loudness, simple mode just controls volume of one channel.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "psychoacoustic (0)", - "enum": true, - "type-name": "GstAudioPanoramaMethod", - "values": [ - { - "desc": "Psychoacoustic Panning (default)", - "name": "psychoacoustic", - "value": "0" - }, - { - "desc": "Simple Panning", - "name": "simple", - "value": "1" - } - ], - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "GstAudioPanoramaMethod", "writable": true }, "panorama": { "blurb": "Position in stereo panorama (-1.0 left -> 1.0 right)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "1", "min": "-1", - "type-name": "gfloat", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true } }, "rank": "none" }, "audiowsincband": { - "author": "Thomas Vander Stichele , Steven W. Smith, Dreamlab Technologies Ltd. , Sebastian Dr\u00f6ge ", + "author": "Thomas Vander Stichele , Steven W. Smith, Dreamlab Technologies Ltd. , Sebastian Dröge ", "description": "Band pass and band reject windowed sinc filter", "hierarchy": [ "GstAudioWSincBand", @@ -2105,7 +2145,6 @@ ], "klass": "Filter/Effect/Audio", "long-name": "Band pass & band reject filter", - "name": "audiowsincband", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: { F32LE, F64LE }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: interleaved\n", @@ -2119,138 +2158,77 @@ } }, "properties": { - "drain-on-changes": { - "blurb": "Drains the filter when its coefficients change", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, "length": { "blurb": "Filter kernel length, will be rounded to the next odd number", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "101", "max": "256000", "min": "3", - "type-name": "gint", - "writable": true - }, - "low-latency": { - "blurb": "Operate in low latency mode. This mode is slower but the latency will only be the filter pre-latency. Can only be changed in states < PAUSED!", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "lower-frequency": { "blurb": "Cut-off lower frequency (Hz)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "100000", "min": "0", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, "mode": { "blurb": "Band pass or band reject mode", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "band-pass (0)", - "enum": true, - "type-name": "GstAudioWSincBandMode", - "values": [ - { - "desc": "Band pass (default)", - "name": "band-pass", - "value": "0" - }, - { - "desc": "Band reject", - "name": "band-reject", - "value": "1" - } - ], - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "GstAudioWSincBandMode", "writable": true }, "upper-frequency": { "blurb": "Cut-off upper frequency (Hz)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "100000", "min": "0", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, "window": { "blurb": "Window function to use", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "hamming (0)", - "enum": true, - "type-name": "GstAudioWSincBandWindow", - "values": [ - { - "desc": "Hamming window (default)", - "name": "hamming", - "value": "0" - }, - { - "desc": "Blackman window", - "name": "blackman", - "value": "1" - }, - { - "desc": "Gaussian window", - "name": "gaussian", - "value": "2" - }, - { - "desc": "Cosine window", - "name": "cosine", - "value": "3" - }, - { - "desc": "Hann window", - "name": "hann", - "value": "4" - } - ], + "mutable": "null", + "readable": true, + "type": "GstAudioWSincBandWindow", "writable": true } }, "rank": "none" }, "audiowsinclimit": { - "author": "Thomas Vander Stichele , Steven W. Smith, Dreamlab Technologies Ltd. , Sebastian Dr\u00f6ge ", + "author": "Thomas Vander Stichele , Steven W. Smith, Dreamlab Technologies Ltd. , Sebastian Dröge ", "description": "Low pass and high pass windowed sinc filter", "hierarchy": [ "GstAudioWSincLimit", @@ -2264,7 +2242,6 @@ ], "klass": "Filter/Effect/Audio", "long-name": "Low pass & high pass filter", - "name": "audiowsinclimit", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: { F32LE, F64LE }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: interleaved\n", @@ -2280,119 +2257,54 @@ "properties": { "cutoff": { "blurb": "Cut-off Frequency (Hz)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "100000", "min": "0", - "type-name": "gfloat", - "writable": true - }, - "drain-on-changes": { - "blurb": "Drains the filter when its coefficients change", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, "length": { "blurb": "Filter kernel length, will be rounded to the next odd number", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "101", "max": "256000", "min": "3", - "type-name": "gint", - "writable": true - }, - "low-latency": { - "blurb": "Operate in low latency mode. This mode is slower but the latency will only be the filter pre-latency. Can only be changed in states < PAUSED!", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "mode": { "blurb": "Low pass or high pass mode", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "low-pass (0)", - "enum": true, - "type-name": "GstAudioWSincLimitMode", - "values": [ - { - "desc": "Low pass (default)", - "name": "low-pass", - "value": "0" - }, - { - "desc": "High pass", - "name": "high-pass", - "value": "1" - } - ], - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "GstAudioWSincLimitMode", "writable": true }, "window": { "blurb": "Window function to use", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "hamming (0)", - "enum": true, - "type-name": "GstAudioWSincLimitWindow", - "values": [ - { - "desc": "Hamming window (default)", - "name": "hamming", - "value": "0" - }, - { - "desc": "Blackman window", - "name": "blackman", - "value": "1" - }, - { - "desc": "Gaussian window", - "name": "gaussian", - "value": "2" - }, - { - "desc": "Cosine window", - "name": "cosine", - "value": "3" - }, - { - "desc": "Hann window", - "name": "hann", - "value": "4" - } - ], + "mutable": "null", + "readable": true, + "type": "GstAudioWSincLimitWindow", "writable": true } }, @@ -2411,7 +2323,6 @@ ], "klass": "Filter/Effect/Rate/Audio", "long-name": "Scaletempo", - "name": "scaletempo", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: F32LE\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: interleaved\naudio/x-raw:\n format: F64LE\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: interleaved\naudio/x-raw:\n format: S16LE\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: interleaved\n", @@ -2425,68 +2336,60 @@ } }, "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, "overlap": { "blurb": "Percentage of stride to overlap", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0.2", "max": "1", "min": "0", - "type-name": "gdouble", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, "rate": { "blurb": "Current playback rate", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "2.14748e+09", "min": "-2.14748e+09", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": false }, "search": { "blurb": "Length in milliseconds to search for best overlap position", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "14", "max": "500", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "stride": { "blurb": "Length in milliseconds to output each stride", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "30", "max": "5000", "min": "1", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true } }, @@ -2521,43 +2424,28 @@ "properties": { "active": { "blurb": "active", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "true", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "stereo": { "blurb": "stereo", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0.01", "max": "1", "min": "0", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true } }, @@ -2566,7 +2454,249 @@ }, "filename": "gstaudiofx", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": { + "GstAudioAmplifyClippingMethod": { + "kind": "enum", + "values": [ + { + "desc": "Normal clipping (default)", + "name": "clip", + "value": "0" + }, + { + "desc": "Push overdriven values back from the opposite side", + "name": "wrap-negative", + "value": "1" + }, + { + "desc": "Push overdriven values back from the same side", + "name": "wrap-positive", + "value": "2" + }, + { + "desc": "No clipping", + "name": "none", + "value": "3" + } + ] + }, + "GstAudioChebBandMode": { + "kind": "enum", + "values": [ + { + "desc": "Band pass (default)", + "name": "band-pass", + "value": "0" + }, + { + "desc": "Band reject", + "name": "band-reject", + "value": "1" + } + ] + }, + "GstAudioChebLimitMode": { + "kind": "enum", + "values": [ + { + "desc": "Low pass (default)", + "name": "low-pass", + "value": "0" + }, + { + "desc": "High pass", + "name": "high-pass", + "value": "1" + } + ] + }, + "GstAudioDynamicCharacteristics": { + "kind": "enum", + "values": [ + { + "desc": "Hard Knee (default)", + "name": "hard-knee", + "value": "0" + }, + { + "desc": "Soft Knee (smooth)", + "name": "soft-knee", + "value": "1" + } + ] + }, + "GstAudioDynamicMode": { + "kind": "enum", + "values": [ + { + "desc": "Compressor (default)", + "name": "compressor", + "value": "0" + }, + { + "desc": "Expander", + "name": "expander", + "value": "1" + } + ] + }, + "GstAudioFXBaseFIRFilter": { + "hierarchy": [ + "GstAudioFXBaseFIRFilter", + "GstAudioFilter", + "GstBaseTransform", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "kind": "object", + "properties": { + "drain-on-changes": { + "blurb": "Drains the filter when its coefficients change", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "low-latency": { + "blurb": "Operate in low latency mode. This mode is slower but the latency will only be the filter pre-latency. Can only be changed in states < PAUSED!", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + } + } + }, + "GstAudioFXBaseIIRFilter": { + "hierarchy": [ + "GstAudioFXBaseIIRFilter", + "GstAudioFilter", + "GstBaseTransform", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "kind": "object" + }, + "GstAudioPanoramaMethod": { + "kind": "enum", + "values": [ + { + "desc": "Psychoacoustic Panning (default)", + "name": "psychoacoustic", + "value": "0" + }, + { + "desc": "Simple Panning", + "name": "simple", + "value": "1" + } + ] + }, + "GstAudioWSincBandMode": { + "kind": "enum", + "values": [ + { + "desc": "Band pass (default)", + "name": "band-pass", + "value": "0" + }, + { + "desc": "Band reject", + "name": "band-reject", + "value": "1" + } + ] + }, + "GstAudioWSincBandWindow": { + "kind": "enum", + "values": [ + { + "desc": "Hamming window (default)", + "name": "hamming", + "value": "0" + }, + { + "desc": "Blackman window", + "name": "blackman", + "value": "1" + }, + { + "desc": "Gaussian window", + "name": "gaussian", + "value": "2" + }, + { + "desc": "Cosine window", + "name": "cosine", + "value": "3" + }, + { + "desc": "Hann window", + "name": "hann", + "value": "4" + } + ] + }, + "GstAudioWSincLimitMode": { + "kind": "enum", + "values": [ + { + "desc": "Low pass (default)", + "name": "low-pass", + "value": "0" + }, + { + "desc": "High pass", + "name": "high-pass", + "value": "1" + } + ] + }, + "GstAudioWSincLimitWindow": { + "kind": "enum", + "values": [ + { + "desc": "Hamming window (default)", + "name": "hamming", + "value": "0" + }, + { + "desc": "Blackman window", + "name": "blackman", + "value": "1" + }, + { + "desc": "Gaussian window", + "name": "gaussian", + "value": "2" + }, + { + "desc": "Cosine window", + "name": "cosine", + "value": "3" + }, + { + "desc": "Hann window", + "name": "hann", + "value": "4" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -2587,7 +2717,6 @@ ], "klass": "Codec/Parser/Audio", "long-name": "AAC audio stream parser", - "name": "aacparse", "pad-templates": { "sink": { "caps": "audio/mpeg:\n mpegversion: { (int)2, (int)4 }\n", @@ -2600,36 +2729,11 @@ "presence": "always" } }, - "properties": { - "disable-passthrough": { - "blurb": "Force processing (disables passthrough)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, + "properties": {}, "rank": "primary + 1" }, "ac3parse": { - "author": "Tim-Philipp M\u00fcller ", + "author": "Tim-Philipp Müller ", "description": "AC3 parser", "hierarchy": [ "GstAc3Parse", @@ -2641,7 +2745,6 @@ ], "klass": "Codec/Parser/Converter/Audio", "long-name": "AC3 audio stream parser", - "name": "ac3parse", "pad-templates": { "sink": { "caps": "audio/x-ac3:\naudio/x-eac3:\naudio/ac3:\naudio/x-private1-ac3:\n", @@ -2654,32 +2757,7 @@ "presence": "always" } }, - "properties": { - "disable-passthrough": { - "blurb": "Force processing (disables passthrough)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, + "properties": {}, "rank": "primary + 1" }, "amrparse": { @@ -2695,7 +2773,6 @@ ], "klass": "Codec/Parser/Audio", "long-name": "AMR audio stream parser", - "name": "amrparse", "pad-templates": { "sink": { "caps": "audio/x-amr-nb-sh:\naudio/x-amr-wb-sh:\n", @@ -2708,36 +2785,11 @@ "presence": "always" } }, - "properties": { - "disable-passthrough": { - "blurb": "Force processing (disables passthrough)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, + "properties": {}, "rank": "primary + 1" }, "dcaparse": { - "author": "Tim-Philipp M\u00fcller ", + "author": "Tim-Philipp Müller ", "description": "DCA parser", "hierarchy": [ "GstDcaParse", @@ -2749,7 +2801,6 @@ ], "klass": "Codec/Parser/Audio", "long-name": "DTS Coherent Acoustics audio stream parser", - "name": "dcaparse", "pad-templates": { "sink": { "caps": "audio/x-dts:\naudio/x-private1-dts:\n", @@ -2762,36 +2813,11 @@ "presence": "always" } }, - "properties": { - "disable-passthrough": { - "blurb": "Force processing (disables passthrough)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, + "properties": {}, "rank": "primary + 1" }, "flacparse": { - "author": "Sebastian Dr\u00f6ge ", + "author": "Sebastian Dröge ", "description": "Parses audio with the FLAC lossless audio codec", "hierarchy": [ "GstFlacParse", @@ -2803,7 +2829,6 @@ ], "klass": "Codec/Parser/Audio", "long-name": "FLAC audio parser", - "name": "flacparse", "pad-templates": { "sink": { "caps": "audio/x-flac:\n", @@ -2819,34 +2844,14 @@ "properties": { "check-frame-checksums": { "blurb": "Check the overall checksums of every frame", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", - "writable": true - }, - "disable-passthrough": { - "blurb": "Force processing (disables passthrough)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, @@ -2865,7 +2870,6 @@ ], "klass": "Codec/Parser/Audio", "long-name": "MPEG1 Audio Parser", - "name": "mpegaudioparse", "pad-templates": { "sink": { "caps": "audio/mpeg:\n mpegversion: 1\n", @@ -2878,36 +2882,11 @@ "presence": "always" } }, - "properties": { - "disable-passthrough": { - "blurb": "Force processing (disables passthrough)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, + "properties": {}, "rank": "primary + 2" }, "sbcparse": { - "author": "Tim-Philipp M\u00fcller ", + "author": "Tim-Philipp Müller ", "description": "Parses an SBC bluetooth audio stream", "hierarchy": [ "GstSbcParse", @@ -2919,7 +2898,6 @@ ], "klass": "Codec/Parser/Audio", "long-name": "SBC audio parser", - "name": "sbcparse", "pad-templates": { "sink": { "caps": "audio/x-sbc:\n", @@ -2932,32 +2910,7 @@ "presence": "always" } }, - "properties": { - "disable-passthrough": { - "blurb": "Force processing (disables passthrough)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, + "properties": {}, "rank": "primary + 1" }, "wavpackparse": { @@ -2973,7 +2926,6 @@ ], "klass": "Codec/Parser/Audio", "long-name": "Wavpack audio stream parser", - "name": "wavpackparse", "pad-templates": { "sink": { "caps": "audio/x-wavpack:\naudio/x-wavpack-correction:\n", @@ -2986,38 +2938,14 @@ "presence": "always" } }, - "properties": { - "disable-passthrough": { - "blurb": "Force processing (disables passthrough)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, + "properties": {}, "rank": "primary + 1" } }, "filename": "gstaudioparsers", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -3037,7 +2965,6 @@ ], "klass": "Codec/Demuxer/Audio", "long-name": "AU audio demuxer", - "name": "auparse", "pad-templates": { "sink": { "caps": "audio/x-au:\n", @@ -3050,30 +2977,13 @@ "presence": "always" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, "rank": "secondary" } }, "filename": "gstauparse", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -3093,9 +3003,11 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstChildProxy" + ], "klass": "Sink/Audio", "long-name": "Auto audio sink", - "name": "autoaudiosink", "pad-templates": { "sink": { "caps": "ANY", @@ -3104,62 +3016,18 @@ } }, "properties": { - "async-handling": { - "blurb": "The bin will handle Asynchronous state changes", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "filter-caps": { - "blurb": "Filter sink candidates using these caps.", - "construct": false, - "construct-only": false, - "default": "audio/x-raw", - "type-name": "GstCaps", - "writable": true - }, - "message-forward": { - "blurb": "Forwards all children messages", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "sync": { - "blurb": "Sync on the clock", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, "ts-offset": { "blurb": "Timestamp offset in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "9223372036854775807", "min": "-9223372036854775808", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gint64", "writable": true } }, @@ -3177,9 +3045,11 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstChildProxy" + ], "klass": "Source/Audio", "long-name": "Auto audio source", - "name": "autoaudiosrc", "pad-templates": { "src": { "caps": "ANY", @@ -3187,56 +3057,7 @@ "presence": "always" } }, - "properties": { - "async-handling": { - "blurb": "The bin will handle Asynchronous state changes", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "filter-caps": { - "blurb": "Filter sink candidates using these caps.", - "construct": false, - "construct-only": false, - "default": "audio/x-raw", - "type-name": "GstCaps", - "writable": true - }, - "message-forward": { - "blurb": "Forwards all children messages", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "sync": { - "blurb": "Sync on the clock", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - } - }, + "properties": {}, "rank": "none" }, "autovideosink": { @@ -3251,9 +3072,11 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstChildProxy" + ], "klass": "Sink/Video", "long-name": "Auto video sink", - "name": "autovideosink", "pad-templates": { "sink": { "caps": "ANY", @@ -3262,62 +3085,18 @@ } }, "properties": { - "async-handling": { - "blurb": "The bin will handle Asynchronous state changes", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "filter-caps": { - "blurb": "Filter sink candidates using these caps.", - "construct": false, - "construct-only": false, - "default": "video/x-raw", - "type-name": "GstCaps", - "writable": true - }, - "message-forward": { - "blurb": "Forwards all children messages", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "sync": { - "blurb": "Sync on the clock", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, "ts-offset": { "blurb": "Timestamp offset in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "9223372036854775807", "min": "-9223372036854775808", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gint64", "writable": true } }, @@ -3335,9 +3114,11 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstChildProxy" + ], "klass": "Source/Video", "long-name": "Auto video source", - "name": "autovideosrc", "pad-templates": { "src": { "caps": "ANY", @@ -3345,62 +3126,54 @@ "presence": "always" } }, + "properties": {}, + "rank": "none" + } + }, + "filename": "gstautodetect", + "license": "LGPL", + "other-types": { + "GstAutoDetect": { + "hierarchy": [ + "GstAutoDetect", + "GstBin", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstChildProxy" + ], + "kind": "object", "properties": { - "async-handling": { - "blurb": "The bin will handle Asynchronous state changes", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, "filter-caps": { "blurb": "Filter sink candidates using these caps.", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "video/x-raw", - "type-name": "GstCaps", - "writable": true - }, - "message-forward": { - "blurb": "Forwards all children messages", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstCaps", "writable": true }, "sync": { "blurb": "Sync on the clock", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } - }, - "rank": "none" + } } }, - "filename": "gstautodetect", - "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -3420,7 +3193,6 @@ ], "klass": "Codec/Demuxer", "long-name": "Avi demuxer", - "name": "avidemux", "pad-templates": { "audio_%%u": { "caps": "audio/ms-gsm:\naudio/mpeg:\n mpegversion: 1\n layer: 3\naudio/mpeg:\n mpegversion: 1\n layer: 2\naudio/x-raw:\n format: { S8, U8, S16LE, U16LE, S24LE, U24LE, S32LE, U32LE }\n layout: interleaved\naudio/x-vorbis:\naudio/x-ac3:\naudio/x-dts:\naudio/mpeg:\n mpegversion: 4\naudio/x-alaw:\naudio/x-mulaw:\naudio/x-wms:\n bitrate: [ 0, 2147483647 ]\n block_align: [ 1, 2147483647 ]\naudio/x-adpcm:\n layout: microsoft\n block_align: [ 1, 2147483647 ]\naudio/x-adpcm:\n layout: dvi\n block_align: [ 1, 2147483647 ]\naudio/x-truespeech:\naudio/x-wma:\n wmaversion: 1\n bitrate: [ 0, 2147483647 ]\n block_align: [ 1, 2147483647 ]\naudio/x-wma:\n wmaversion: 2\n bitrate: [ 0, 2147483647 ]\n block_align: [ 1, 2147483647 ]\naudio/x-wma:\n wmaversion: 3\n bitrate: [ 0, 2147483647 ]\n block_align: [ 1, 2147483647 ]\naudio/x-vnd.sony.atrac3:\naudio/x-raw:\n format: { F32LE, F64LE }\n layout: interleaved\naudio/x-voxware:\n voxwaretype: 117\naudio/x-adpcm:\n layout: dk4\naudio/x-adpcm:\n layout: dk3\naudio/x-adpcm:\n layout: dvi\naudio/AMR:\naudio/AMR-WB:\naudio/x-siren:\napplication/x-ogg-avi:\naudio/x-avi-unknown:\n", @@ -3443,48 +3215,13 @@ "presence": "sometimes" }, "video_%%u": { - "caps": "video/mpeg:\n mpegversion: 4\n systemstream: false\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-asus:\n asusversion: 1\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-asus:\n asusversion: 2\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-cirrus-logic-accupak:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-camstudio:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-compressed-yuv:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-raw:\n format: { RGB8P, BGR, BGRx }\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-divx:\n divxversion: 3\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-divx:\n divxversion: 4\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-truemotion:\n trueversion: 1\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-dv:\n systemstream: false\n dvversion: 25\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-dv:\n systemstream: false\n dvversion: 50\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-divx:\n divxversion: 5\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/mpeg:\n mpegversion: 4\n systemstream: false\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-flash-video:\n flvversion: 1\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-vp6-flash:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h263:\n variant: itu\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h263:\n variant: lucent\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h264:\n variant: itu\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-huffyuv:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-intel-h263:\n variant: intel\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-raw:\n format: I420\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-indeo:\n indeoversion: 3\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-indeo:\n indeoversion: 4\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-indeo:\n indeoversion: 5\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h263:\n variant: lead\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h264:\n variant: lead\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h263:\n variant: microsoft\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/mpeg:\n mpegversion: 4\n systemstream: false\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nimage/jpeg:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-msmpeg:\n msmpegversion: 42\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-msmpeg:\n msmpegversion: 43\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/mpeg:\n systemstream: false\n mpegversion: 1\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/mpeg:\n systemstream: false\n mpegversion: 2\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-msmpeg:\n msmpegversion: 41\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-mszh:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nimage/png:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-rle:\n layout: microsoft\n depth: [ 1, 64 ]\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-indeo:\n indeoversion: 2\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/sp5x:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-truemotion:\n trueversion: 2\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-camtasia:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-ultimotion:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-raw:\n format: UYVY\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-ati-vcr:\n vcrversion: 1\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-ati-vcr:\n vcrversion: 2\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h263:\n variant: vdolive\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h263:\n variant: vivo\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-vmnc:\n version: 1\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-vp3:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h264:\n variant: videosoft\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-wmv:\n wmvversion: 1\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-wmv:\n wmvversion: 2\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-wmv:\n wmvversion: 3\n format: WMV3\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/mpeg:\n mpegversion: 4\n systemstream: false\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-xan:\n wcversion: 4\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-raw:\n format: YUY2\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-raw:\n format: YVU9\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-zlib:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-cinepak:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h264:\n variant: itu\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-msvideocodec:\n msvideoversion: 1\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h263:\n variant: xirlink\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-dirac:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-ffv:\n ffvversion: 1\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-kmvc:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-vp5:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-vp6:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-vp6-flash:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-vp7:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-vp8:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-mimic:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-apple-video:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-theora:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-fraps:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-aasc:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-raw:\n format: YV12\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-loco:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-zmbv:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-raw:\n format: v210\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-raw:\n format: r210\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-dv:\n systemstream: true\nvideo/x-avi-unknown:\n", + "caps": "video/mpeg:\n mpegversion: 4\n systemstream: false\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-asus:\n asusversion: 1\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-asus:\n asusversion: 2\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-cineform:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-cirrus-logic-accupak:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-camstudio:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-compressed-yuv:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-raw:\n format: { RGB8P, BGR, BGRx }\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-divx:\n divxversion: 3\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-divx:\n divxversion: 4\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-truemotion:\n trueversion: 1\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-dv:\n systemstream: false\n dvversion: 25\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-dv:\n systemstream: false\n dvversion: 50\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-divx:\n divxversion: 5\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/mpeg:\n mpegversion: 4\n systemstream: false\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-flash-video:\n flvversion: 1\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-vp6-flash:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h263:\n variant: itu\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h263:\n variant: lucent\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h264:\n variant: itu\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h265:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-huffyuv:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-intel-h263:\n variant: intel\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-raw:\n format: I420\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-indeo:\n indeoversion: 3\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-indeo:\n indeoversion: 4\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-indeo:\n indeoversion: 5\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h263:\n variant: lead\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h264:\n variant: lead\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h263:\n variant: microsoft\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/mpeg:\n mpegversion: 4\n systemstream: false\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nimage/jpeg:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-msmpeg:\n msmpegversion: 42\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-msmpeg:\n msmpegversion: 43\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/mpeg:\n systemstream: false\n mpegversion: 1\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/mpeg:\n systemstream: false\n mpegversion: 2\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-msmpeg:\n msmpegversion: 41\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-mszh:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nimage/png:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-rle:\n layout: microsoft\n depth: [ 1, 64 ]\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-indeo:\n indeoversion: 2\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/sp5x:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-truemotion:\n trueversion: 2\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-camtasia:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-ultimotion:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-raw:\n format: UYVY\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-ati-vcr:\n vcrversion: 1\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-ati-vcr:\n vcrversion: 2\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h263:\n variant: vdolive\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h263:\n variant: vivo\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-vmnc:\n version: 1\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-vp3:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h264:\n variant: videosoft\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-wmv:\n wmvversion: 1\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-wmv:\n wmvversion: 2\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-wmv:\n wmvversion: 3\n format: WMV3\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/mpeg:\n mpegversion: 4\n systemstream: false\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-xan:\n wcversion: 4\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-raw:\n format: YUY2\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-raw:\n format: YVU9\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-zlib:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-cinepak:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h264:\n variant: itu\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-msvideocodec:\n msvideoversion: 1\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-h263:\n variant: xirlink\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-dirac:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-ffv:\n ffvversion: 1\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-kmvc:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-vp5:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-vp6:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-vp6-flash:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-vp7:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-vp8:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-mimic:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-apple-video:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-theora:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-fraps:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-aasc:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-raw:\n format: YV12\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-loco:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-zmbv:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-raw:\n format: v210\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-raw:\n format: r210\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\nvideo/x-dv:\n systemstream: true\nvideo/x-avi-unknown:\n", "direction": "src", "presence": "sometimes" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, "rank": "primary", - "signals": { - "no-more-pads": { - "args": [], - "retval": "void" - }, - "pad-added": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "pad-removed": { - "args": [ - "GstPad" - ], - "retval": "void" - } - } + "signals": {} }, "avimux": { "author": "GStreamer maintainers ", @@ -3496,12 +3233,14 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstTagSetter" + ], "klass": "Codec/Muxer", "long-name": "Avi muxer", - "name": "avimux", "pad-templates": { "audio_%%u": { - "caps": "audio/x-raw:\n format: { U8, S16LE }\n rate: [ 1000, 96000 ]\n channels: [ 1, 2 ]\naudio/mpeg:\n mpegversion: 1\n layer: [ 1, 3 ]\n rate: [ 1000, 96000 ]\n channels: [ 1, 2 ]\naudio/mpeg:\n mpegversion: 4\n stream-format: raw\n rate: [ 1000, 96000 ]\n channels: [ 1, 2 ]\naudio/x-ac3:\n rate: [ 1000, 96000 ]\n channels: [ 1, 6 ]\naudio/x-alaw:\n rate: [ 1000, 48000 ]\n channels: [ 1, 2 ]\naudio/x-mulaw:\n rate: [ 1000, 48000 ]\n channels: [ 1, 2 ]\naudio/x-wma:\n rate: [ 1000, 96000 ]\n channels: [ 1, 2 ]\n wmaversion: [ 1, 2 ]\n", + "caps": "audio/x-raw:\n format: { U8, S16LE, S24LE, S32LE }\n rate: [ 1000, 96000 ]\n channels: [ 1, 65535 ]\naudio/mpeg:\n mpegversion: 1\n layer: [ 1, 3 ]\n rate: [ 1000, 96000 ]\n channels: [ 1, 2 ]\naudio/mpeg:\n mpegversion: 4\n stream-format: raw\n rate: [ 1000, 96000 ]\n channels: [ 1, 2 ]\naudio/x-ac3:\n rate: [ 1000, 96000 ]\n channels: [ 1, 6 ]\naudio/x-alaw:\n rate: [ 1000, 48000 ]\n channels: [ 1, 2 ]\naudio/x-mulaw:\n rate: [ 1000, 48000 ]\n channels: [ 1, 2 ]\naudio/x-wma:\n rate: [ 1000, 96000 ]\n channels: [ 1, 2 ]\n wmaversion: [ 1, 2 ]\n", "direction": "sink", "presence": "request" }, @@ -3511,7 +3250,7 @@ "presence": "always" }, "video_%%u": { - "caps": "video/x-raw:\n format: { YUY2, I420, BGR, BGRx, BGRA, GRAY8, UYVY }\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n framerate: [ 0/1, 2147483647/1 ]\nimage/jpeg:\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-divx:\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n framerate: [ 0/1, 2147483647/1 ]\n divxversion: [ 3, 5 ]\nvideo/x-msmpeg:\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n framerate: [ 0/1, 2147483647/1 ]\n msmpegversion: [ 41, 43 ]\nvideo/mpeg:\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n framerate: [ 0/1, 2147483647/1 ]\n mpegversion: { (int)1, (int)2, (int)4 }\n systemstream: false\nvideo/x-h263:\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-h264:\n stream-format: byte-stream\n alignment: au\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-dv:\n width: 720\n height: { (int)576, (int)480 }\n framerate: [ 0/1, 2147483647/1 ]\n systemstream: false\nvideo/x-huffyuv:\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-wmv:\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n framerate: [ 0/1, 2147483647/1 ]\n wmvversion: [ 1, 3 ]\nimage/x-jpc:\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-vp8:\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nimage/png:\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "caps": "video/x-raw:\n format: { YUY2, I420, BGR, BGRx, BGRA, GRAY8, UYVY, v210 }\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n framerate: [ 0/1, 2147483647/1 ]\nimage/jpeg:\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-divx:\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n framerate: [ 0/1, 2147483647/1 ]\n divxversion: [ 3, 5 ]\nvideo/x-msmpeg:\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n framerate: [ 0/1, 2147483647/1 ]\n msmpegversion: [ 41, 43 ]\nvideo/mpeg:\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n framerate: [ 0/1, 2147483647/1 ]\n mpegversion: { (int)1, (int)2, (int)4 }\n systemstream: false\nvideo/x-h263:\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-h264:\n stream-format: byte-stream\n alignment: au\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-dv:\n width: 720\n height: { (int)576, (int)480 }\n framerate: [ 0/1, 2147483647/1 ]\n systemstream: false\nvideo/x-huffyuv:\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-wmv:\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n framerate: [ 0/1, 2147483647/1 ]\n wmvversion: [ 1, 3 ]\nimage/x-jpc:\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-vp8:\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nimage/png:\n width: [ 16, 4096 ]\n height: [ 16, 4096 ]\n framerate: [ 0/1, 2147483647/1 ]\n", "direction": "sink", "presence": "request" } @@ -3519,26 +3258,14 @@ "properties": { "bigfile": { "blurb": "Support for openDML-2.0 (big) AVI files", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, @@ -3556,7 +3283,6 @@ ], "klass": "Codec/Parser/Subtitle", "long-name": "Avi subtitle parser", - "name": "avisubtitle", "pad-templates": { "sink": { "caps": "application/x-subtitle-avi:\n", @@ -3569,36 +3295,19 @@ "presence": "always" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, "rank": "primary" } }, "filename": "gstavi", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" }, "cacasink": { - "description": "Colored ASCII Art video sink", + "description": "Colored ASCII Art video sink & filter", "elements": { "cacasink": { "author": "Zeeshan Ali ", @@ -3613,7 +3322,6 @@ ], "klass": "Sink/Video", "long-name": "A colored ASCII art video sink", - "name": "cacasink", "pad-templates": { "sink": { "caps": "video/x-raw:\n format: { RGB, BGR, RGBx, xRGB, BGRx, xBGR, RGB16, RGB15 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", @@ -3624,199 +3332,150 @@ "properties": { "anti-aliasing": { "blurb": "Enables Anti-Aliasing", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", - "writable": true - }, - "async": { - "blurb": "Go asynchronously to PAUSED", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "blocksize": { - "blurb": "Size in bytes to pull per buffer (0 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "dither": { "blurb": "Set type of Dither", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "none (49)", - "enum": true, - "type-name": "GstCACASinkDithering", - "values": [ - { - "desc": "No dithering", - "name": "none", - "value": "49" - }, - { - "desc": "Ordered 2x2 Bayer dithering", - "name": "2x2", - "value": "50" - }, - { - "desc": "Ordered 4x4 Bayer dithering", - "name": "4x4", - "value": "51" - }, - { - "desc": "Ordered 8x8 Bayer dithering", - "name": "8x8", - "value": "52" - }, - { - "desc": "Random dithering", - "name": "random", - "value": "53" - } - ], - "writable": true - }, - "enable-last-sample": { - "blurb": "Enable the last-sample property", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "GstCACASinkDithering", "writable": true }, - "last-sample": { - "blurb": "The last sample received in the sink", + "screen-height": { + "blurb": "The height of the screen", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstSample", + "controllable": false, + "default": "25", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": false }, - "max-bitrate": { - "blurb": "The maximum bits per second to render (0 = disabled)", + "screen-width": { + "blurb": "The width of the screen", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "18446744073709551615", + "controllable": false, + "default": "80", + "max": "2147483647", "min": "0", - "type-name": "guint64", - "writable": true + "mutable": "null", + "readable": true, + "type": "gint", + "writable": false + } + }, + "rank": "none" + }, + "cacatv": { + "author": "Eric Marks ", + "description": "Colored ASCII art effect", + "hierarchy": [ + "GstCACATv", + "GstVideoFilter", + "GstBaseTransform", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Filter/Effect/Video", + "long-name": "CacaTV effect", + "pad-templates": { + "sink": { + "caps": "video/x-raw:\n format: { RGB, BGR, RGBx, xRGB, BGRx, xBGR, RGBA, RGB16, RGB15 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "sink", + "presence": "always" }, - "max-lateness": { - "blurb": "Maximum number of nanoseconds that a buffer can be late before it is dropped (-1 unlimited)", + "src": { + "caps": "video/x-raw:\n format: { ARGB }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "anti-aliasing": { + "blurb": "Enables Anti-Aliasing", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "canvas-height": { + "blurb": "The height of the canvas in characters", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "24", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "processing-deadline": { - "blurb": "Maximum processing deadline in nanoseconds", + "canvas-width": { + "blurb": "The width of the canvas in characters", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "20000000", - "max": "18446744073709551615", + "controllable": false, + "default": "80", + "max": "2147483647", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "qos": { - "blurb": "Generate Quality-of-Service events upstream", + "dither": { + "blurb": "Set type of Dither", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": " (0)", + "mutable": "null", + "readable": true, + "type": "GstCACATvDithering", "writable": true }, - "render-delay": { - "blurb": "Additional render delay of the sink in nanoseconds", + "font": { + "blurb": "selected libcaca font", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "screen-height": { - "blurb": "The height of the screen", - "construct": false, - "construct-only": false, - "default": "25", "max": "2147483647", "min": "0", - "type-name": "gint", - "writable": false - }, - "screen-width": { - "blurb": "The width of the screen", - "construct": false, - "construct-only": false, - "default": "80", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": false - }, - "stats": { - "blurb": "Sink Statistics", - "construct": false, - "construct-only": false, - "default": "application/x-gst-base-sink-stats, average-rate=(double)0, dropped=(guint64)0, rendered=(guint64)0;", - "type-name": "GstStructure", - "writable": false - }, - "sync": { - "blurb": "Sync on the clock", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "throttle-time": { - "blurb": "The time to keep between rendered buffers (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "ts-offset": { - "blurb": "Timestamp offset in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "-9223372036854775808", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true } }, @@ -3825,8 +3484,71 @@ }, "filename": "gstcacasink", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": { + "GstCACASinkDithering": { + "kind": "enum", + "values": [ + { + "desc": "No dithering", + "name": "none", + "value": "49" + }, + { + "desc": "Ordered 2x2 Bayer dithering", + "name": "2x2", + "value": "50" + }, + { + "desc": "Ordered 4x4 Bayer dithering", + "name": "4x4", + "value": "51" + }, + { + "desc": "Ordered 8x8 Bayer dithering", + "name": "8x8", + "value": "52" + }, + { + "desc": "Random dithering", + "name": "random", + "value": "53" + } + ] + }, + "GstCACATvDithering": { + "kind": "enum", + "values": [ + { + "desc": "No dither_mode", + "name": "none", + "value": "49" + }, + { + "desc": "Ordered 2x2 Bayer dither_mode", + "name": "2x2", + "value": "50" + }, + { + "desc": "Ordered 4x4 Bayer dither_mode", + "name": "4x4", + "value": "51" + }, + { + "desc": "Ordered 8x8 Bayer dither_mode", + "name": "8x8", + "value": "52" + }, + { + "desc": "Random dither_mode", + "name": "random", + "value": "53" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", + "tracers": {}, "url": "Unknown package origin" }, "cairo": { @@ -3845,7 +3567,6 @@ ], "klass": "Filter/Editor/Video", "long-name": "Cairo overlay", - "name": "cairooverlay", "pad-templates": { "sink": { "caps": "video/x-raw:\n format: { BGRx, BGRA, RGB16 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", @@ -3861,34 +3582,14 @@ "properties": { "draw-on-transparent-surface": { "blurb": "Let the draw signal work on a transparent surface and blend the results with the video at a later time", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "playing", + "readable": true, + "type": "gboolean", "writable": true } }, @@ -3896,24 +3597,37 @@ "signals": { "caps-changed": { "args": [ - "GstCaps" + { + "name": "arg0", + "type": "GstCaps" + } ], - "retval": "void" + "return-type": "void" }, "draw": { "args": [ - "CairoContext", - "guint64", - "guint64" + { + "name": "arg0", + "type": "CairoContext" + }, + { + "name": "arg1", + "type": "guint64" + }, + { + "name": "arg2", + "type": "guint64" + } ], - "retval": "void" + "return-type": "void" } } } }, "filename": "gstcairo", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -3933,7 +3647,6 @@ ], "klass": "Filter/Editor/Audio", "long-name": "Audio cutter", - "name": "cutter", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: { S8, S16LE }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: interleaved\n", @@ -3949,66 +3662,70 @@ "properties": { "leaky": { "blurb": "do we leak buffers when below threshold ?", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "pre-length": { "blurb": "Length of pre-recording buffer (in nanoseconds)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "200000000", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "run-length": { "blurb": "Length of drop below threshold before cut_stop (in nanoseconds)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "500000000", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "threshold": { "blurb": "Volume threshold before trigger", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0.1", "max": "1.79769e+308", "min": "-1.79769e+308", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, "threshold-dB": { "blurb": "Volume threshold before trigger (in dB)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "-46.0517", "max": "1.79769e+308", "min": "-1.79769e+308", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true } }, @@ -4017,7 +3734,8 @@ }, "filename": "gstcutter", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -4038,7 +3756,6 @@ ], "klass": "Testing", "long-name": "Break my data", - "name": "breakmydata", "pad-templates": { "sink": { "caps": "ANY", @@ -4052,68 +3769,60 @@ } }, "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, "probability": { "blurb": "probability for each byte in the buffer to be changed", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "0", "max": "1", "min": "0", - "type-name": "gdouble", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, "seed": { "blurb": "seed for randomness (initialized when going from READY to PAUSED)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "set-to": { "blurb": "set changed bytes to this value (-1 means random value", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "-1", "max": "255", "min": "-1", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "skip": { "blurb": "amount of bytes skipped at the beginning of stream", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true } }, @@ -4132,7 +3841,6 @@ ], "klass": "Generic", "long-name": "CapsSetter", - "name": "capssetter", "pad-templates": { "sink": { "caps": "ANY", @@ -4148,50 +3856,38 @@ "properties": { "caps": { "blurb": "Merge these caps (thereby overwriting) in the stream", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "ANY", - "type-name": "GstCaps", + "mutable": "null", + "readable": true, + "type": "GstCaps", "writable": true }, "join": { "blurb": "Match incoming caps' mime-type to mime-type of provided caps", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "replace": { "blurb": "Drop fields of incoming caps", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, @@ -4210,7 +3906,6 @@ ], "klass": "Testing", "long-name": "CPU report", - "name": "cpureport", "pad-templates": { "sink": { "caps": "ANY", @@ -4223,32 +3918,7 @@ "presence": "always" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - } - }, + "properties": {}, "rank": "none" }, "navseek": { @@ -4264,7 +3934,6 @@ ], "klass": "Filter/Video", "long-name": "Seek based on left-right arrows", - "name": "navseek", "pad-templates": { "sink": { "caps": "ANY", @@ -4278,38 +3947,18 @@ } }, "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, "seek-offset": { "blurb": "Time in seconds to seek by", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "5", "max": "1.79769e+308", "min": "0", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true } }, @@ -4328,7 +3977,6 @@ ], "klass": "Testing", "long-name": "Progress report", - "name": "progressreport", "pad-templates": { "sink": { "caps": "ANY", @@ -4344,67 +3992,59 @@ "properties": { "do-query": { "blurb": "Use a query instead of buffer metadata to determine stream position", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "format": { "blurb": "Format to use for the querying", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "auto", - "type-name": "gchararray", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, "silent": { "blurb": "Do not print output to stdout", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "update-freq": { "blurb": "Number of seconds between reports when data is flowing", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "5", "max": "2147483647", "min": "1", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true } }, "rank": "none" }, "pushfilesrc": { - "author": "Tim-Philipp M\u00fcller ", + "author": "Tim-Philipp Müller ", "description": "Implements pushfile:// URI-handler for push-based file access", "hierarchy": [ "GstPushFileSrc", @@ -4414,9 +4054,12 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstChildProxy", + "GstURIHandler" + ], "klass": "Testing", "long-name": "Push File Source", - "name": "pushfilesrc", "pad-templates": { "src": { "caps": "ANY", @@ -4427,100 +4070,96 @@ "properties": { "applied-rate": { "blurb": "Applied rate to use in TIME SEGMENT", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "1", "max": "1.79769e+308", "min": "2.22507e-308", - "type-name": "gdouble", - "writable": true - }, - "async-handling": { - "blurb": "The bin will handle Asynchronous state changes", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, "initial-timestamp": { "blurb": "Initial Buffer Timestamp (if time-segment TRUE)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "location": { "blurb": "Location of the file to read", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "message-forward": { - "blurb": "Forwards all children messages", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "ready", + "readable": true, + "type": "gchararray", "writable": true }, "rate": { "blurb": "Rate to use in TIME SEGMENT", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "1", "max": "1.79769e+308", "min": "2.22507e-308", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, "start-time": { "blurb": "Initial Start Time (if time-segment TRUE)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "9223372036854775807", "min": "0", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gint64", "writable": true }, "stream-time": { "blurb": "Initial Stream Time (if time-segment TRUE)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "9223372036854775807", "min": "0", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gint64", "writable": true }, "time-segment": { "blurb": "Emit TIME SEGMENTS", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, @@ -4538,7 +4177,6 @@ ], "klass": "Testing", "long-name": "Random buffer size", - "name": "rndbuffersize", "pad-templates": { "sink": { "caps": "ANY", @@ -4554,48 +4192,44 @@ "properties": { "max": { "blurb": "maximum buffer size", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "8192", "max": "2147483647", "min": "1", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "min": { "blurb": "minimum buffer size", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "1", "max": "2147483647", "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "seed": { "blurb": "seed for randomness (initialized when going from READY to PAUSED)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true } }, @@ -4614,7 +4248,6 @@ ], "klass": "Generic", "long-name": "TagInject", - "name": "taginject", "pad-templates": { "sink": { "caps": "ANY", @@ -4628,36 +4261,16 @@ } }, "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, "tags": { "blurb": "List of tags to inject into the target file", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", + "mutable": "null", + "readable": false, + "type": "gchararray", "writable": true } }, @@ -4676,7 +4289,6 @@ ], "klass": "Testing", "long-name": "Test plugin", - "name": "testsink", "pad-templates": { "sink": { "caps": "ANY", @@ -4687,212 +4299,111 @@ "properties": { "allowed-timestamp-deviation": { "blurb": "allowed average difference in usec between timestamp of next buffer and expected timestamp from analyzing last buffer", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "9223372036854775807", "min": "-1", - "type-name": "gint64", - "writable": true - }, - "async": { - "blurb": "Go asynchronously to PAUSED", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "blocksize": { - "blurb": "Size in bytes to pull per buffer (0 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "gint64", "writable": true }, "buffer-count": { "blurb": "number of buffers in stream", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "9223372036854775807", "min": "-1", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gint64", "writable": false }, - "enable-last-sample": { - "blurb": "Enable the last-sample property", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, "expected-buffer-count": { "blurb": "expected number of buffers in stream", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "9223372036854775807", "min": "-1", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gint64", "writable": true }, "expected-length": { "blurb": "expected length of stream", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "9223372036854775807", "min": "-1", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gint64", "writable": true }, "expected-md5": { "blurb": "expected md5 of processing the whole data", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "---", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "last-sample": { - "blurb": "The last sample received in the sink", - "construct": false, - "construct-only": false, - "type-name": "GstSample", - "writable": false - }, "length": { "blurb": "length of stream", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "9223372036854775807", "min": "-1", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gint64", "writable": false }, - "max-bitrate": { - "blurb": "The maximum bits per second to render (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "max-lateness": { - "blurb": "Maximum number of nanoseconds that a buffer can be late before it is dropped (-1 unlimited)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, "md5": { "blurb": "md5 of processing the whole data", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "---", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": false }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "processing-deadline": { - "blurb": "Maximum processing deadline in nanoseconds", - "construct": false, - "construct-only": false, - "default": "20000000", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "qos": { - "blurb": "Generate Quality-of-Service events upstream", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "render-delay": { - "blurb": "Additional render delay of the sink in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "stats": { - "blurb": "Sink Statistics", - "construct": false, - "construct-only": false, - "default": "application/x-gst-base-sink-stats, average-rate=(double)0, dropped=(guint64)0, rendered=(guint64)0;", - "type-name": "GstStructure", - "writable": false - }, - "sync": { - "blurb": "Sync on the clock", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "throttle-time": { - "blurb": "The time to keep between rendered buffers (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "timestamp-deviation": { - "blurb": "average difference in usec between timestamp of next buffer and expected timestamp from analyzing last buffer", + "timestamp-deviation": { + "blurb": "average difference in usec between timestamp of next buffer and expected timestamp from analyzing last buffer", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "9223372036854775807", "min": "-1", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gint64", "writable": false - }, - "ts-offset": { - "blurb": "Timestamp offset in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "-9223372036854775808", - "type-name": "gint64", - "writable": true } }, "rank": "none" @@ -4900,7 +4411,8 @@ }, "filename": "gstdebug", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -4909,7 +4421,7 @@ "description": "Deinterlacer", "elements": { "deinterlace": { - "author": "Martin Eikermann , Sebastian Dr\u00f6ge ", + "author": "Martin Eikermann , Sebastian Dröge ", "description": "Deinterlace Methods ported from DScaler/TvTime", "hierarchy": [ "GstDeinterlace", @@ -4920,15 +4432,14 @@ ], "klass": "Filter/Effect/Video/Deinterlace", "long-name": "Deinterlacer", - "name": "deinterlace", "pad-templates": { "sink": { - "caps": "video/x-raw:\n format: { AYUV, ARGB, ABGR, RGBA, BGRA, Y444, xRGB, xBGR, RGBx, BGRx, RGB, BGR, YUY2, YVYU, UYVY, Y42B, I420, YV12, Y41B, NV12, NV21 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(ANY):\n format: { I420, YV12, YUY2, UYVY, AYUV, VUYA, RGBx, BGRx, xRGB, xBGR, RGBA, BGRA, ARGB, ABGR, RGB, BGR, Y41B, Y42B, YVYU, Y444, v210, v216, Y210, Y410, NV12, NV21, GRAY8, GRAY16_BE, GRAY16_LE, v308, RGB16, BGR16, RGB15, BGR15, UYVP, A420, RGB8P, YUV9, YVU9, IYU1, ARGB64, AYUV64, r210, I420_10BE, I420_10LE, I422_10BE, I422_10LE, Y444_10BE, Y444_10LE, GBR, GBR_10BE, GBR_10LE, NV16, NV24, NV12_64Z32, A420_10BE, A420_10LE, A422_10BE, A422_10LE, A444_10BE, A444_10LE, NV61, P010_10BE, P010_10LE, IYU2, VYUY, GBRA, GBRA_10BE, GBRA_10LE, BGR10A2_LE, RGB10A2_LE, GBR_12BE, GBR_12LE, GBRA_12BE, GBRA_12LE, I420_12BE, I420_12LE, I422_12BE, I422_12LE, Y444_12BE, Y444_12LE, GRAY10_LE32, NV12_10LE32, NV16_10LE32, NV12_10LE40, Y444_16BE, Y444_16LE, P016_BE, P016_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "caps": "video/x-raw:\n format: { AYUV, ARGB, ABGR, RGBA, BGRA, Y444, xRGB, xBGR, RGBx, BGRx, RGB, BGR, YUY2, YVYU, UYVY, Y42B, I420, YV12, Y41B, NV12, NV21 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(ANY):\n format: { AYUV64, ARGB64, GBRA_12LE, GBRA_12BE, Y412_LE, Y412_BE, A444_10LE, GBRA_10LE, A444_10BE, GBRA_10BE, A422_10LE, A422_10BE, A420_10LE, A420_10BE, RGB10A2_LE, BGR10A2_LE, Y410, GBRA, ABGR, VUYA, BGRA, AYUV, ARGB, RGBA, A420, Y444_16LE, Y444_16BE, v216, P016_LE, P016_BE, Y444_12LE, GBR_12LE, Y444_12BE, GBR_12BE, I422_12LE, I422_12BE, Y212_LE, Y212_BE, I420_12LE, I420_12BE, P012_LE, P012_BE, Y444_10LE, GBR_10LE, Y444_10BE, GBR_10BE, r210, I422_10LE, I422_10BE, NV16_10LE32, Y210, v210, UYVP, I420_10LE, I420_10BE, P010_10LE, NV12_10LE32, NV12_10LE40, P010_10BE, Y444, GBR, NV24, xBGR, BGRx, xRGB, RGBx, BGR, IYU2, v308, RGB, Y42B, NV61, NV16, VYUY, UYVY, YVYU, YUY2, I420, YV12, NV21, NV12, NV12_64Z32, NV12_4L4, NV12_32L32, Y41B, IYU1, YVU9, YUV9, RGB16, BGR16, RGB15, BGR15, RGB8P, GRAY16_LE, GRAY16_BE, GRAY10_LE32, GRAY8 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "video/x-raw:\n format: { AYUV, ARGB, ABGR, RGBA, BGRA, Y444, xRGB, xBGR, RGBx, BGRx, RGB, BGR, YUY2, YVYU, UYVY, Y42B, I420, YV12, Y41B, NV12, NV21 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(ANY):\n format: { I420, YV12, YUY2, UYVY, AYUV, VUYA, RGBx, BGRx, xRGB, xBGR, RGBA, BGRA, ARGB, ABGR, RGB, BGR, Y41B, Y42B, YVYU, Y444, v210, v216, Y210, Y410, NV12, NV21, GRAY8, GRAY16_BE, GRAY16_LE, v308, RGB16, BGR16, RGB15, BGR15, UYVP, A420, RGB8P, YUV9, YVU9, IYU1, ARGB64, AYUV64, r210, I420_10BE, I420_10LE, I422_10BE, I422_10LE, Y444_10BE, Y444_10LE, GBR, GBR_10BE, GBR_10LE, NV16, NV24, NV12_64Z32, A420_10BE, A420_10LE, A422_10BE, A422_10LE, A444_10BE, A444_10LE, NV61, P010_10BE, P010_10LE, IYU2, VYUY, GBRA, GBRA_10BE, GBRA_10LE, BGR10A2_LE, RGB10A2_LE, GBR_12BE, GBR_12LE, GBRA_12BE, GBRA_12LE, I420_12BE, I420_12LE, I422_12BE, I422_12LE, Y444_12BE, Y444_12LE, GRAY10_LE32, NV12_10LE32, NV16_10LE32, NV12_10LE40, Y444_16BE, Y444_16LE, P016_BE, P016_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "caps": "video/x-raw:\n format: { AYUV, ARGB, ABGR, RGBA, BGRA, Y444, xRGB, xBGR, RGBx, BGRx, RGB, BGR, YUY2, YVYU, UYVY, Y42B, I420, YV12, Y41B, NV12, NV21 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(ANY):\n format: { AYUV64, ARGB64, GBRA_12LE, GBRA_12BE, Y412_LE, Y412_BE, A444_10LE, GBRA_10LE, A444_10BE, GBRA_10BE, A422_10LE, A422_10BE, A420_10LE, A420_10BE, RGB10A2_LE, BGR10A2_LE, Y410, GBRA, ABGR, VUYA, BGRA, AYUV, ARGB, RGBA, A420, Y444_16LE, Y444_16BE, v216, P016_LE, P016_BE, Y444_12LE, GBR_12LE, Y444_12BE, GBR_12BE, I422_12LE, I422_12BE, Y212_LE, Y212_BE, I420_12LE, I420_12BE, P012_LE, P012_BE, Y444_10LE, GBR_10LE, Y444_10BE, GBR_10BE, r210, I422_10LE, I422_10BE, NV16_10LE32, Y210, v210, UYVP, I420_10LE, I420_10BE, P010_10LE, NV12_10LE32, NV12_10LE40, P010_10BE, Y444, GBR, NV24, xBGR, BGRx, xRGB, RGBx, BGR, IYU2, v308, RGB, Y42B, NV61, NV16, VYUY, UYVY, YVYU, YUY2, I420, YV12, NV21, NV12, NV12_64Z32, NV12_4L4, NV12_32L32, Y41B, IYU1, YVU9, YUV9, RGB16, BGR16, RGB15, BGR15, RGB8P, GRAY16_LE, GRAY16_BE, GRAY10_LE32, GRAY8 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", "direction": "src", "presence": "always" } @@ -4936,214 +4447,86 @@ "properties": { "drop-orphans": { "blurb": "Drop orphan fields at the beginning of telecine patterns in active locking mode.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "fields": { "blurb": "Fields to use for deinterlacing", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "all (0)", - "enum": true, - "type-name": "GstDeinterlaceFields", - "values": [ - { - "desc": "All fields", - "name": "all", - "value": "0" - }, - { - "desc": "Top fields only", - "name": "top", - "value": "1" - }, - { - "desc": "Bottom fields only", - "name": "bottom", - "value": "2" - }, - { - "desc": "Automatically detect", - "name": "auto", - "value": "3" - } - ], + "mutable": "null", + "readable": true, + "type": "GstDeinterlaceFields", "writable": true }, "ignore-obscure": { "blurb": "Ignore obscure telecine patterns (only consider P, I and 2:3 variants).", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "locking": { "blurb": "Pattern locking mode", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "none (0)", - "enum": true, - "type-name": "GstDeinterlaceLocking", - "values": [ - { - "desc": "No pattern locking", - "name": "none", - "value": "0" - }, - { - "desc": "Choose passive/active locking depending on whether upstream is live", - "name": "auto", - "value": "1" - }, - { - "desc": "Block until pattern-locked. Use accurate timestamp interpolation within a pattern repeat.", - "name": "active", - "value": "2" - }, - { - "desc": "Do not block. Use na\u00efve timestamp adjustment until pattern-locked based on state history.", - "name": "passive", - "value": "3" - } - ], + "mutable": "null", + "readable": true, + "type": "GstDeinterlaceLocking", "writable": true }, "method": { "blurb": "Deinterlace Method", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "linear (4)", - "enum": true, - "type-name": "GstDeinterlaceMethods", - "values": [ - { - "desc": "Motion Adaptive: Motion Search", - "name": "tomsmocomp", - "value": "0" - }, - { - "desc": "Motion Adaptive: Advanced Detection", - "name": "greedyh", - "value": "1" - }, - { - "desc": "Motion Adaptive: Simple Detection", - "name": "greedyl", - "value": "2" - }, - { - "desc": "Blur Vertical", - "name": "vfir", - "value": "3" - }, - { - "desc": "Linear", - "name": "linear", - "value": "4" - }, - { - "desc": "Blur: Temporal (Do Not Use)", - "name": "linearblend", - "value": "5" - }, - { - "desc": "Double lines", - "name": "scalerbob", - "value": "6" - }, - { - "desc": "Weave (Do Not Use)", - "name": "weave", - "value": "7" - }, - { - "desc": "Progressive: Top Field First (Do Not Use)", - "name": "weavetff", - "value": "8" - }, - { - "desc": "Progressive: Bottom Field First (Do Not Use)", - "name": "weavebff", - "value": "9" - } - ], + "mutable": "null", + "readable": true, + "type": "GstDeinterlaceMethods", "writable": true }, "mode": { "blurb": "Deinterlace Mode", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "auto (0)", - "enum": true, - "type-name": "GstDeinterlaceModes", - "values": [ - { - "desc": "Auto detection (best effort)", - "name": "auto", - "value": "0" - }, - { - "desc": "Force deinterlacing", - "name": "interlaced", - "value": "1" - }, - { - "desc": "Run in passthrough mode", - "name": "disabled", - "value": "2" - }, - { - "desc": "Auto detection (strict)", - "name": "auto-strict", - "value": "3" - } - ], - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "GstDeinterlaceModes", "writable": true }, "tff": { "blurb": "Deinterlace top field first", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "auto (0)", - "enum": true, - "type-name": "GstDeinterlaceFieldLayout", - "values": [ - { - "desc": "Auto detection", - "name": "auto", - "value": "0" - }, - { - "desc": "Top field first", - "name": "tff", - "value": "1" - }, - { - "desc": "Bottom field first", - "name": "bff", - "value": "2" - } - ], + "mutable": "null", + "readable": true, + "type": "GstDeinterlaceFieldLayout", "writable": true } }, @@ -5152,7 +4535,164 @@ }, "filename": "gstdeinterlace", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": { + "GstDeinterlaceFieldLayout": { + "kind": "enum", + "values": [ + { + "desc": "Auto detection", + "name": "auto", + "value": "0" + }, + { + "desc": "Top field first", + "name": "tff", + "value": "1" + }, + { + "desc": "Bottom field first", + "name": "bff", + "value": "2" + } + ] + }, + "GstDeinterlaceFields": { + "kind": "enum", + "values": [ + { + "desc": "All fields", + "name": "all", + "value": "0" + }, + { + "desc": "Top fields only", + "name": "top", + "value": "1" + }, + { + "desc": "Bottom fields only", + "name": "bottom", + "value": "2" + }, + { + "desc": "Automatically detect", + "name": "auto", + "value": "3" + } + ] + }, + "GstDeinterlaceLocking": { + "kind": "enum", + "values": [ + { + "desc": "No pattern locking", + "name": "none", + "value": "0" + }, + { + "desc": "Choose passive/active locking depending on whether upstream is live", + "name": "auto", + "value": "1" + }, + { + "desc": "Block until pattern-locked. Use accurate timestamp interpolation within a pattern repeat.", + "name": "active", + "value": "2" + }, + { + "desc": "Do not block. Use naïve timestamp adjustment until pattern-locked based on state history.", + "name": "passive", + "value": "3" + } + ] + }, + "GstDeinterlaceMethods": { + "kind": "enum", + "values": [ + { + "desc": "Motion Adaptive: Motion Search", + "name": "tomsmocomp", + "value": "0" + }, + { + "desc": "Motion Adaptive: Advanced Detection", + "name": "greedyh", + "value": "1" + }, + { + "desc": "Motion Adaptive: Simple Detection", + "name": "greedyl", + "value": "2" + }, + { + "desc": "Blur Vertical", + "name": "vfir", + "value": "3" + }, + { + "desc": "Linear", + "name": "linear", + "value": "4" + }, + { + "desc": "Blur: Temporal (Do Not Use)", + "name": "linearblend", + "value": "5" + }, + { + "desc": "Double lines", + "name": "scalerbob", + "value": "6" + }, + { + "desc": "Weave (Do Not Use)", + "name": "weave", + "value": "7" + }, + { + "desc": "Progressive: Top Field First (Do Not Use)", + "name": "weavetff", + "value": "8" + }, + { + "desc": "Progressive: Bottom Field First (Do Not Use)", + "name": "weavebff", + "value": "9" + }, + { + "desc": "YADIF Adaptive Deinterlacer", + "name": "yadif", + "value": "10" + } + ] + }, + "GstDeinterlaceModes": { + "kind": "enum", + "values": [ + { + "desc": "Auto detection (best effort)", + "name": "auto", + "value": "0" + }, + { + "desc": "Force deinterlacing", + "name": "interlaced", + "value": "1" + }, + { + "desc": "Run in passthrough mode", + "name": "disabled", + "value": "2" + }, + { + "desc": "Auto detection (strict)", + "name": "auto-strict", + "value": "3" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -5173,7 +4713,6 @@ ], "klass": "Source/Audio", "long-name": "DTMF tone generator", - "name": "dtmfsrc", "pad-templates": { "src": { "caps": "audio/x-raw:\n format: S16LE\n rate: [ 1, 2147483647 ]\n channels: 1\n layout: interleaved\n", @@ -5182,66 +4721,18 @@ } }, "properties": { - "blocksize": { - "blurb": "Size in bytes to read per buffer (-1 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "do-timestamp": { - "blurb": "Apply current stream time to buffers", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, "interval": { "blurb": "Interval in ms between two tone packets", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "50", "max": "50", "min": "10", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "num-buffers": { - "blurb": "Number of buffers to output before sending EOS (-1 = unlimited)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "typefind": { - "blurb": "Run typefind before negotiating (deprecated, non-functional)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true } }, @@ -5260,7 +4751,6 @@ ], "klass": "Codec/Depayloader/Network", "long-name": "RTP DTMF packet depayloader", - "name": "rtpdtmfdepay", "pad-templates": { "sink": { "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: [ 0, 2147483647 ]\n encoding-name: TELEPHONE-EVENT\n", @@ -5276,64 +4766,30 @@ "properties": { "max-duration": { "blurb": "The maxumimum duration (ms) of the outgoing soundpacket. (0 = no limit)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", - "writable": true - }, - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, "unit-time": { "blurb": "The smallest unit (ms) the duration must be a multiple of (0 disables it)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "1000", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true } }, @@ -5352,7 +4808,6 @@ ], "klass": "Source/Network", "long-name": "RTP DTMF packet generator", - "name": "rtpdtmfsrc", "pad-templates": { "src": { "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: [ 0, 2147483647 ]\n encoding-name: TELEPHONE-EVENT\n", @@ -5361,136 +4816,116 @@ } }, "properties": { - "blocksize": { - "blurb": "Size in bytes to read per buffer (-1 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, "clock-rate": { "blurb": "The clock-rate at which to generate the dtmf packets", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "8000", "max": "-1", "min": "0", - "type-name": "guint", - "writable": true - }, - "do-timestamp": { - "blurb": "Apply current stream time to buffers", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "num-buffers": { - "blurb": "Number of buffers to output before sending EOS (-1 = unlimited)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "packet-redundancy": { "blurb": "Number of packets to send to indicate start and stop dtmf events", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "1", "max": "5", "min": "1", - "type-name": "guint", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "pt": { "blurb": "The payload type of the packets", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "96", "max": "128", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "seqnum": { "blurb": "The RTP sequence number of the last processed packet", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": false }, "seqnum-offset": { "blurb": "Offset to add to all outgoing seqnum (-1 = random)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "-1", "max": "2147483647", "min": "-1", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "ssrc": { "blurb": "The SSRC of the packets (-1 == random)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "-1", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "timestamp": { "blurb": "The RTP timestamp of the last processed packet", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": false }, "timestamp-offset": { "blurb": "Offset to add to all outgoing timestamps (-1 = random)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "-1", "max": "2147483647", "min": "-1", - "type-name": "gint", - "writable": true - }, - "typefind": { - "blurb": "Run typefind before negotiating (deprecated, non-functional)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true } }, @@ -5499,7 +4934,8 @@ }, "filename": "gstdtmf", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -5519,7 +4955,6 @@ ], "klass": "Codec/Decoder/Video", "long-name": "DV video decoder", - "name": "dvdec", "pad-templates": { "sink": { "caps": "video/x-dv:\n systemstream: false\n", @@ -5535,85 +4970,52 @@ "properties": { "clamp-chroma": { "blurb": "Clamp chroma", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "clamp-luma": { "blurb": "Clamp luma", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "drop-factor": { "blurb": "Only decode Nth frame", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "1", "max": "2147483647", "min": "1", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "dvdec0", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "quality": { "blurb": "Decoding quality", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "best (5)", - "enum": true, - "type-name": "GstDVDecQualityEnum", - "values": [ - { - "desc": "Monochrome, DC (Fastest)", - "name": "fastest", - "value": "0" - }, - { - "desc": "Monochrome, first AC coefficient", - "name": "monochrome-ac", - "value": "1" - }, - { - "desc": "Monochrome, highest quality", - "name": "monochrome-best", - "value": "2" - }, - { - "desc": "Colour, DC, fastest", - "name": "colour-fastest", - "value": "3" - }, - { - "desc": "Colour, using only the first AC coefficient", - "name": "colour-ac", - "value": "4" - }, - { - "desc": "Highest quality colour decoding", - "name": "best", - "value": "5" - } - ], + "mutable": "null", + "readable": true, + "type": "GstDVDecQualityEnum", "writable": true } }, @@ -5631,7 +5033,6 @@ ], "klass": "Codec/Demuxer", "long-name": "DV system stream demuxer", - "name": "dvdemux", "pad-templates": { "audio": { "caps": "audio/x-raw:\n format: S16LE\n layout: interleaved\n rate: { (int)32000, (int)44100, (int)48000 }\n channels: { (int)2, (int)4 }\n", @@ -5649,48 +5050,50 @@ "presence": "sometimes" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "dvdemux0", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, "rank": "primary", - "signals": { - "no-more-pads": { - "args": [], - "retval": "void" - }, - "pad-added": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "pad-removed": { - "args": [ - "GstPad" - ], - "retval": "void" - } - } + "signals": {} } }, "filename": "gstdv", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": { + "GstDVDecQualityEnum": { + "kind": "enum", + "values": [ + { + "desc": "Monochrome, DC (Fastest)", + "name": "fastest", + "value": "0" + }, + { + "desc": "Monochrome, first AC coefficient", + "name": "monochrome-ac", + "value": "1" + }, + { + "desc": "Monochrome, highest quality", + "name": "monochrome-best", + "value": "2" + }, + { + "desc": "Colour, DC, fastest", + "name": "colour-fastest", + "value": "3" + }, + { + "desc": "Colour, using only the first AC coefficient", + "name": "colour-ac", + "value": "4" + }, + { + "desc": "Highest quality colour decoding", + "name": "best", + "value": "5" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -5712,7 +5115,6 @@ ], "klass": "Filter/Effect/Video", "long-name": "AgingTV effect", - "name": "agingtv", "pad-templates": { "sink": { "caps": "video/x-raw:\n format: { BGRx, RGBx }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", @@ -5728,60 +5130,52 @@ "properties": { "color-aging": { "blurb": "Color Aging", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "dusts": { "blurb": "Dusts", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "true", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "pits": { "blurb": "Pits", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "true", - "type-name": "gboolean", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "scratch-lines": { "blurb": "Number of scratch lines", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "7", "max": "20", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true } }, @@ -5801,7 +5195,6 @@ ], "klass": "Filter/Effect/Video", "long-name": "DiceTV effect", - "name": "dicetv", "pad-templates": { "sink": { "caps": "video/x-raw:\n format: { RGBx, xRGB, BGRx, xBGR }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", @@ -5815,38 +5208,18 @@ } }, "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, "square-bits": { "blurb": "The size of the Squares", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "4", "max": "5", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true } }, @@ -5866,7 +5239,6 @@ ], "klass": "Filter/Effect/Video", "long-name": "EdgeTV effect", - "name": "edgetv", "pad-templates": { "sink": { "caps": "video/x-raw:\n format: { BGRx, RGBx }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", @@ -5879,36 +5251,11 @@ "presence": "always" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - } - }, + "properties": {}, "rank": "none" }, "optv": { - "author": "FUKUCHI, Kentarou , Sebastian Dr\u00f6ge ", + "author": "FUKUCHI, Kentarou , Sebastian Dröge ", "description": "Optical art meets real-time video effect", "hierarchy": [ "GstOpTV", @@ -5921,7 +5268,6 @@ ], "klass": "Filter/Effect/Video", "long-name": "OpTV effect", - "name": "optv", "pad-templates": { "sink": { "caps": "video/x-raw:\n format: { BGRx, RGBx }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", @@ -5937,77 +5283,42 @@ "properties": { "mode": { "blurb": "Mode", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "maelstrom (0)", - "enum": true, - "type-name": "GstOpTVMode", - "values": [ - { - "desc": "Maelstrom", - "name": "maelstrom", - "value": "0" - }, - { - "desc": "Radiation", - "name": "radiation", - "value": "1" - }, - { - "desc": "Horizontal Stripes", - "name": "horizontal-stripes", - "value": "2" - }, - { - "desc": "Vertical Stripes", - "name": "vertical-stripes", - "value": "3" - } - ], - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "GstOpTVMode", "writable": true }, "speed": { "blurb": "Effect speed", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "16", "max": "2147483647", "min": "-2147483648", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "threshold": { "blurb": "Luma threshold", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "60", "max": "2147483647", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true } }, @@ -6027,7 +5338,6 @@ ], "klass": "Filter/Effect/Video", "long-name": "QuarkTV effect", - "name": "quarktv", "pad-templates": { "sink": { "caps": "video/x-raw:\n format: { xRGB, xBGR, BGRx, RGBx }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", @@ -6041,45 +5351,25 @@ } }, "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, "planes": { "blurb": "Number of planes", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "16", "max": "64", "min": "1", - "type-name": "gint", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true } }, "rank": "none" }, "radioactv": { - "author": "FUKUCHI, Kentarou , Sebastian Dr\u00f6ge ", + "author": "FUKUCHI, Kentarou , Sebastian Dröge ", "description": "motion-enlightment effect", "hierarchy": [ "GstRadioacTV", @@ -6092,7 +5382,6 @@ ], "klass": "Filter/Effect/Video", "long-name": "RadioacTV effect", - "name": "radioactv", "pad-templates": { "sink": { "caps": "video/x-raw:\n format: { RGBx, BGRx }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", @@ -6108,106 +5397,52 @@ "properties": { "color": { "blurb": "Color", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "white (3)", - "enum": true, - "type-name": "GstRadioacTVColor", - "values": [ - { - "desc": "Red", - "name": "red", - "value": "0" - }, - { - "desc": "Green", - "name": "green", - "value": "1" - }, - { - "desc": "Blue", - "name": "blue", - "value": "2" - }, - { - "desc": "White", - "name": "white", - "value": "3" - } - ], + "mutable": "null", + "readable": true, + "type": "GstRadioacTVColor", "writable": true }, "interval": { "blurb": "Snapshot interval (in strobe mode)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "3", "max": "2147483647", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "mode": { "blurb": "Mode", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "normal (0)", - "enum": true, - "type-name": "GstRadioacTVMode", - "values": [ - { - "desc": "Normal", - "name": "normal", - "value": "0" - }, - { - "desc": "Strobe 1", - "name": "strobe1", - "value": "1" - }, - { - "desc": "Strobe 2", - "name": "strobe2", - "value": "2" - }, - { - "desc": "Trigger", - "name": "trigger", - "value": "3" - } - ], - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "GstRadioacTVMode", "writable": true }, "trigger": { "blurb": "Trigger (in trigger mode)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, @@ -6227,7 +5462,6 @@ ], "klass": "Filter/Effect/Video", "long-name": "RevTV effect", - "name": "revtv", "pad-templates": { "sink": { "caps": "video/x-raw:\n format: { BGRx, RGBx }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", @@ -6243,63 +5477,51 @@ "properties": { "delay": { "blurb": "Delay in frames between updates", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "1", "max": "100", "min": "1", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "gain": { "blurb": "Control gain", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "50", "max": "200", "min": "1", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "linespace": { "blurb": "Control line spacing", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "6", "max": "100", "min": "1", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true } }, "rank": "none" }, "rippletv": { - "author": "FUKUCHI, Kentarou , Sebastian Dr\u00f6ge ", + "author": "FUKUCHI, Kentarou , Sebastian Dröge ", "description": "RippleTV does ripple mark effect on the video input", "hierarchy": [ "GstRippleTV", @@ -6312,7 +5534,6 @@ ], "klass": "Filter/Effect/Video", "long-name": "RippleTV effect", - "name": "rippletv", "pad-templates": { "sink": { "caps": "video/x-raw:\n format: { BGRx, RGBx, xBGR, xRGB }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", @@ -6328,55 +5549,26 @@ "properties": { "mode": { "blurb": "Mode", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "motion-detection (0)", - "enum": true, - "type-name": "GstRippleTVMode", - "values": [ - { - "desc": "Motion Detection", - "name": "motion-detection", - "value": "0" - }, - { - "desc": "Rain", - "name": "rain", - "value": "1" - } - ], - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "GstRippleTVMode", "writable": true }, "reset": { "blurb": "Reset all current ripples", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": false, + "type": "gboolean", "writable": true } }, @@ -6396,7 +5588,6 @@ ], "klass": "Filter/Effect/Video", "long-name": "ShagadelicTV", - "name": "shagadelictv", "pad-templates": { "sink": { "caps": "video/x-raw:\n format: BGRx\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", @@ -6409,36 +5600,11 @@ "presence": "always" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - } - }, + "properties": {}, "rank": "none" }, "streaktv": { - "author": "FUKUCHI, Kentarou , Sebastian Dr\u00f6ge ", + "author": "FUKUCHI, Kentarou , Sebastian Dröge ", "description": "StreakTV makes after images of moving objects", "hierarchy": [ "GstStreakTV", @@ -6451,7 +5617,6 @@ ], "klass": "Filter/Effect/Video", "long-name": "StreakTV effect", - "name": "streaktv", "pad-templates": { "sink": { "caps": "video/x-raw:\n format: { BGRx, RGBx, xBGR, xRGB }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", @@ -6467,34 +5632,14 @@ "properties": { "feedback": { "blurb": "Feedback", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, @@ -6514,7 +5659,6 @@ ], "klass": "Filter/Effect/Video", "long-name": "VertigoTV effect", - "name": "vertigotv", "pad-templates": { "sink": { "caps": "video/x-raw:\n format: { RGBx, BGRx }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", @@ -6528,48 +5672,32 @@ } }, "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, "speed": { "blurb": "Control the speed of movement", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0.02", "max": "100", "min": "0.01", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, "zoom-speed": { "blurb": "Control the rate of zooming", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "1.01", "max": "1.1", "min": "1.01", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true } }, @@ -6589,7 +5717,6 @@ ], "klass": "Filter/Effect/Video", "long-name": "WarpTV effect", - "name": "warptv", "pad-templates": { "sink": { "caps": "video/x-raw:\n format: { RGBx, xRGB, BGRx, xBGR }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", @@ -6602,38 +5729,105 @@ "presence": "always" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - } - }, + "properties": {}, "rank": "none" } }, "filename": "gsteffectv", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": { + "GstOpTVMode": { + "kind": "enum", + "values": [ + { + "desc": "Maelstrom", + "name": "maelstrom", + "value": "0" + }, + { + "desc": "Radiation", + "name": "radiation", + "value": "1" + }, + { + "desc": "Horizontal Stripes", + "name": "horizontal-stripes", + "value": "2" + }, + { + "desc": "Vertical Stripes", + "name": "vertical-stripes", + "value": "3" + } + ] + }, + "GstRadioacTVColor": { + "kind": "enum", + "values": [ + { + "desc": "Red", + "name": "red", + "value": "0" + }, + { + "desc": "Green", + "name": "green", + "value": "1" + }, + { + "desc": "Blue", + "name": "blue", + "value": "2" + }, + { + "desc": "White", + "name": "white", + "value": "3" + } + ] + }, + "GstRadioacTVMode": { + "kind": "enum", + "values": [ + { + "desc": "Normal", + "name": "normal", + "value": "0" + }, + { + "desc": "Strobe 1", + "name": "strobe1", + "value": "1" + }, + { + "desc": "Strobe 2", + "name": "strobe2", + "value": "2" + }, + { + "desc": "Trigger", + "name": "trigger", + "value": "3" + } + ] + }, + "GstRippleTVMode": { + "kind": "enum", + "values": [ + { + "desc": "Motion Detection", + "name": "motion-detection", + "value": "0" + }, + { + "desc": "Rain", + "name": "rain", + "value": "1" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -6654,9 +5848,12 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstChildProxy", + "GstPreset" + ], "klass": "Filter/Effect/Audio", "long-name": "10 Band Equalizer", - "name": "equalizer-10bands", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: { S16LE, F32LE, F64LE }\n rate: [ 1000, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: interleaved\n", @@ -6672,126 +5869,142 @@ "properties": { "band0": { "blurb": "gain for the frequency band 29 Hz, ranging from -24 dB to +12 dB", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "12", "min": "-24", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, "band1": { "blurb": "gain for the frequency band 59 Hz, ranging from -24 dB to +12 dB", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "12", "min": "-24", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, "band2": { "blurb": "gain for the frequency band 119 Hz, ranging from -24 dB to +12 dB", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "12", "min": "-24", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, "band3": { "blurb": "gain for the frequency band 237 Hz, ranging from -24 dB to +12 dB", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "12", "min": "-24", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, "band4": { "blurb": "gain for the frequency band 474 Hz, ranging from -24 dB to +12 dB", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "12", "min": "-24", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, "band5": { "blurb": "gain for the frequency band 947 Hz, ranging from -24 dB to +12 dB", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "12", "min": "-24", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, "band6": { "blurb": "gain for the frequency band 1889 Hz, ranging from -24 dB to +12 dB", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "12", "min": "-24", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, "band7": { "blurb": "gain for the frequency band 3770 Hz, ranging from -24 dB to +12 dB", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "12", "min": "-24", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, "band8": { "blurb": "gain for the frequency band 7523 Hz, ranging from -24 dB to +12 dB", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "12", "min": "-24", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, "band9": { "blurb": "gain for the frequency band 15011 Hz, ranging from -24 dB to +12 dB", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "12", "min": "-24", - "type-name": "gdouble", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true } }, @@ -6810,9 +6023,12 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstChildProxy", + "GstPreset" + ], "klass": "Filter/Effect/Audio", "long-name": "3 Band Equalizer", - "name": "equalizer-3bands", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: { S16LE, F32LE, F64LE }\n rate: [ 1000, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: interleaved\n", @@ -6828,56 +6044,44 @@ "properties": { "band0": { "blurb": "gain for the frequency band 100 Hz, ranging from -24.0 to +12.0", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "12", "min": "-24", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, "band1": { "blurb": "gain for the frequency band 1100 Hz, ranging from -24.0 to +12.0", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "12", "min": "-24", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, "band2": { "blurb": "gain for the frequency band 11 kHz, ranging from -24.0 to +12.0", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "12", "min": "-24", - "type-name": "gdouble", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true } }, @@ -6896,9 +6100,12 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstChildProxy", + "GstPreset" + ], "klass": "Filter/Effect/Audio", "long-name": "N Band Equalizer", - "name": "equalizer-nbands", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: { S16LE, F32LE, F64LE }\n rate: [ 1000, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: interleaved\n", @@ -6912,38 +6119,18 @@ } }, "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, "num-bands": { "blurb": "number of different bands to use", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "10", "max": "64", "min": "1", - "type-name": "guint", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true } }, @@ -6952,7 +6139,25 @@ }, "filename": "gstequalizer", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": { + "GstIirEqualizer": { + "hierarchy": [ + "GstIirEqualizer", + "GstAudioFilter", + "GstBaseTransform", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstChildProxy", + "GstPreset" + ], + "kind": "object" + } + }, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -6961,7 +6166,7 @@ "description": "The FLAC Lossless compressor Codec", "elements": { "flacdec": { - "author": "Tim-Philipp M\u00fcller , Wim Taymans ", + "author": "Tim-Philipp Müller , Wim Taymans ", "description": "Decodes FLAC lossless audio streams", "hierarchy": [ "GstFlacDec", @@ -6973,7 +6178,6 @@ ], "klass": "Codec/Decoder/Audio", "long-name": "FLAC audio decoder", - "name": "flacdec", "pad-templates": { "sink": { "caps": "audio/x-flac:\n framed: true\n rate: [ 1, 655350 ]\n channels: [ 1, 8 ]\n", @@ -6986,52 +6190,7 @@ "presence": "always" } }, - "properties": { - "min-latency": { - "blurb": "Aggregate output data to a minimum of latency time (ns)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "plc": { - "blurb": "Perform packet loss concealment (if supported)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "tolerance": { - "blurb": "Perfect ts while timestamp jitter/imperfection within tolerance (ns)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - } - }, + "properties": {}, "rank": "primary" }, "flacenc": { @@ -7045,9 +6204,13 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstPreset", + "GstTagSetter", + "GstTocSetter" + ], "klass": "Codec/Encoder/Audio", "long-name": "FLAC audio encoder", - "name": "flacenc", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: { S8, S16LE, S24LE, S24_32LE }\n layout: interleaved\n rate: [ 1, 655350 ]\n channels: 1\naudio/x-raw:\n format: { S8, S16LE, S24LE, S24_32LE }\n layout: interleaved\n rate: [ 1, 655350 ]\n channels: 2\n channel-mask: 0x0000000000000003\naudio/x-raw:\n format: { S8, S16LE, S24LE, S24_32LE }\n layout: interleaved\n rate: [ 1, 655350 ]\n channels: 3\n channel-mask: 0x0000000000000007\naudio/x-raw:\n format: { S8, S16LE, S24LE, S24_32LE }\n layout: interleaved\n rate: [ 1, 655350 ]\n channels: 4\n channel-mask: 0x0000000000000033\naudio/x-raw:\n format: { S8, S16LE, S24LE, S24_32LE }\n layout: interleaved\n rate: [ 1, 655350 ]\n channels: 5\n channel-mask: 0x0000000000000037\naudio/x-raw:\n format: { S8, S16LE, S24LE, S24_32LE }\n layout: interleaved\n rate: [ 1, 655350 ]\n channels: 6\n channel-mask: 0x000000000000003f\naudio/x-raw:\n format: { S8, S16LE, S24LE, S24_32LE }\n layout: interleaved\n rate: [ 1, 655350 ]\n channels: 7\n channel-mask: 0x000000000000013f\naudio/x-raw:\n format: { S8, S16LE, S24LE, S24_32LE }\n layout: interleaved\n rate: [ 1, 655350 ]\n channels: 8\n channel-mask: 0x0000000000000c3f\n", @@ -7063,241 +6226,198 @@ "properties": { "blocksize": { "blurb": "Blocksize in samples", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "4608", "max": "65535", "min": "16", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "escape-coding": { "blurb": "search for escape codes in the entropy coding stage for slightly better compression", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "exhaustive-model-search": { "blurb": "do exhaustive search of LP coefficient quantization (expensive!)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", - "writable": true - }, - "hard-resync": { - "blurb": "Perform clipping and sample flushing upon discontinuity", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "loose-mid-side-stereo": { "blurb": "Loose mid side stereo", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "mark-granule": { - "blurb": "Apply granule semantics to buffer metadata (implies perfect-timestamp)", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": false - }, "max-lpc-order": { "blurb": "Max LPC order; 0 => use only fixed predictors", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "8", "max": "32", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "max-residual-partition-order": { "blurb": "Max residual partition order (above 4 doesn't usually help much)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "3", "max": "16", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "mid-side-stereo": { "blurb": "Do mid side stereo (only for stereo input)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "min-residual-partition-order": { "blurb": "Min residual partition order (above 4 doesn't usually help much)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "3", "max": "16", "min": "0", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "padding": { "blurb": "Write a PADDING block with this length in bytes", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-timestamp": { - "blurb": "Favour perfect timestamps over tracking upstream timestamps", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "qlp-coeff-prec-search": { "blurb": "false = use qlp_coeff_precision, true = search around qlp_coeff_precision, take best", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "qlp-coeff-precision": { "blurb": "Precision in bits of quantized linear-predictor coefficients; 0 = automatic", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "0", "max": "32", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "quality": { "blurb": "Speed versus compression tradeoff", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "5 (5)", - "enum": true, - "type-name": "GstFlacEncQuality", - "values": [ - { - "desc": "0 - Fastest compression", - "name": "0", - "value": "0" - }, - { - "desc": "1", - "name": "1", - "value": "1" - }, - { - "desc": "2", - "name": "2", - "value": "2" - }, - { - "desc": "3", - "name": "3", - "value": "3" - }, - { - "desc": "4", - "name": "4", - "value": "4" - }, - { - "desc": "5 - Default", - "name": "5", - "value": "5" - }, - { - "desc": "6", - "name": "6", - "value": "6" - }, - { - "desc": "7", - "name": "7", - "value": "7" - }, - { - "desc": "8 - Highest compression", - "name": "8", - "value": "8" - }, - { - "desc": "9 - Insane", - "name": "9", - "value": "9" - } - ], + "mutable": "null", + "readable": true, + "type": "GstFlacEncQuality", "writable": true }, "rice-parameter-search-dist": { "blurb": "0 = try only calc'd parameter k; else try all [k-dist..k+dist] parameters, use best", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "0", "max": "15", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "seekpoints": { "blurb": "Add SEEKTABLE metadata (if > 0, number of entries, if < 0, interval in sec)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "-10", "max": "2147483647", "min": "-2147483647", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "streamable-subset": { "blurb": "true to limit encoder to generating a Subset stream, else false", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", - "writable": true - }, - "tolerance": { - "blurb": "Consider discontinuity if timestamp jitter/imperfection exceeds tolerance (ns)", - "construct": false, - "construct-only": false, - "default": "40000000", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, @@ -7313,9 +6433,11 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstTagSetter" + ], "klass": "Formatter/Metadata", "long-name": "FLAC tagger", - "name": "flactag", "pad-templates": { "sink": { "caps": "audio/x-flac:\n", @@ -7328,30 +6450,69 @@ "presence": "always" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, "rank": "primary" } }, "filename": "gstflac", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": { + "GstFlacEncQuality": { + "kind": "enum", + "values": [ + { + "desc": "0 - Fastest compression", + "name": "0", + "value": "0" + }, + { + "desc": "1", + "name": "1", + "value": "1" + }, + { + "desc": "2", + "name": "2", + "value": "2" + }, + { + "desc": "3", + "name": "3", + "value": "3" + }, + { + "desc": "4", + "name": "4", + "value": "4" + }, + { + "desc": "5 - Default", + "name": "5", + "value": "5" + }, + { + "desc": "6", + "name": "6", + "value": "6" + }, + { + "desc": "7", + "name": "7", + "value": "7" + }, + { + "desc": "8 - Highest compression", + "name": "8", + "value": "8" + }, + { + "desc": "9 - Insane", + "name": "9", + "value": "9" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -7371,7 +6532,6 @@ ], "klass": "Codec/Demuxer", "long-name": "FLV Demuxer", - "name": "flvdemux", "pad-templates": { "audio": { "caps": "audio/x-adpcm:\n layout: swf\n channels: { (int)1, (int)2 }\n rate: { (int)5512, (int)11025, (int)22050, (int)44100 }\naudio/mpeg:\n mpegversion: 1\n layer: 3\n channels: { (int)1, (int)2 }\n rate: { (int)5512, (int)8000, (int)11025, (int)22050, (int)44100 }\n parsed: true\naudio/mpeg:\n mpegversion: 4\n stream-format: raw\n framed: true\naudio/x-nellymoser:\n channels: { (int)1, (int)2 }\n rate: { (int)5512, (int)8000, (int)11025, (int)16000, (int)22050, (int)44100 }\naudio/x-raw:\n format: { U8, S16LE }\n layout: interleaved\n channels: { (int)1, (int)2 }\n rate: { (int)5512, (int)11025, (int)22050, (int)44100 }\naudio/x-alaw:\n channels: { (int)1, (int)2 }\n rate: 8000\naudio/x-mulaw:\n channels: { (int)1, (int)2 }\n rate: 8000\naudio/x-speex:\n channels: 1\n rate: 16000\n", @@ -7389,46 +6549,11 @@ "presence": "sometimes" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, "rank": "primary", - "signals": { - "no-more-pads": { - "args": [], - "retval": "void" - }, - "pad-added": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "pad-removed": { - "args": [ - "GstPad" - ], - "retval": "void" - } - } + "signals": {} }, "flvmux": { - "author": "Sebastian Dr\u00f6ge ", + "author": "Sebastian Dröge ", "description": "Muxes video/audio streams into a FLV stream", "hierarchy": [ "GstFlvMux", @@ -7438,204 +6563,78 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstTagSetter" + ], "klass": "Codec/Muxer", "long-name": "FLV muxer", - "name": "flvmux", "pad-templates": { "audio": { "caps": "audio/x-adpcm:\n layout: swf\n channels: { (int)1, (int)2 }\n rate: { (int)5512, (int)11025, (int)22050, (int)44100 }\naudio/mpeg:\n mpegversion: 1\n layer: 3\n channels: { (int)1, (int)2 }\n rate: { (int)5512, (int)8000, (int)11025, (int)22050, (int)44100 }\n parsed: true\naudio/mpeg:\n mpegversion: { (int)4, (int)2 }\n stream-format: raw\naudio/x-nellymoser:\n channels: { (int)1, (int)2 }\n rate: { (int)5512, (int)8000, (int)11025, (int)16000, (int)22050, (int)44100 }\naudio/x-raw:\n format: { U8, S16LE }\n layout: interleaved\n channels: { (int)1, (int)2 }\n rate: { (int)5512, (int)11025, (int)22050, (int)44100 }\naudio/x-alaw:\n channels: { (int)1, (int)2 }\n rate: 8000\naudio/x-mulaw:\n channels: { (int)1, (int)2 }\n rate: 8000\naudio/x-speex:\n channels: 1\n rate: 16000\n", "direction": "sink", - "object-type": { - "hierarchy": [ - "GstFlvMuxPad", - "GstAggregatorPad", - "GstPad", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "properties": { - "emit-signals": { - "blurb": "Send signals to signal data consumption", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - } - }, - "signals": { - "buffer-consumed": { - "args": [ - "GstBuffer" - ], - "retval": "void" - } - } - }, - "presence": "request" + "presence": "request", + "type": "GstFlvMuxPad" }, "src": { "caps": "video/x-flv:\n", "direction": "src", - "object-type": { - "hierarchy": [ - "GstAggregatorPad", - "GstPad", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "properties": { - "emit-signals": { - "blurb": "Send signals to signal data consumption", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - } - }, - "signals": { - "buffer-consumed": { - "args": [ - "GstBuffer" - ], - "retval": "void" - } - } - }, - "presence": "always" + "presence": "always", + "type": "GstAggregatorPad" }, "video": { "caps": "video/x-flash-video:\nvideo/x-flash-screen:\nvideo/x-vp6-flash:\nvideo/x-vp6-alpha:\nvideo/x-h264:\n stream-format: avc\n", "direction": "sink", - "object-type": { - "hierarchy": [ - "GstFlvMuxPad", - "GstAggregatorPad", - "GstPad", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "properties": { - "emit-signals": { - "blurb": "Send signals to signal data consumption", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - } - }, - "signals": { - "buffer-consumed": { - "args": [ - "GstBuffer" - ], - "retval": "void" - } - } - }, - "presence": "request" + "presence": "request", + "type": "GstFlvMuxPad" } }, "properties": { "encoder": { "blurb": "The value of encoder in the meta packet.", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "GStreamer 1.17.0.1 FLV muxer", - "type-name": "gchararray", - "writable": true - }, - "latency": { - "blurb": "Additional latency in live mode to allow upstream to take longer to produce buffers for the current position (in nanoseconds)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", + "controllable": false, + "default": "GStreamer 1.18.6 FLV muxer", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, "metadatacreator": { "blurb": "The value of metadatacreator in the meta packet.", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "GStreamer 1.17.0.1 FLV muxer", - "type-name": "gchararray", - "writable": true - }, - "min-upstream-latency": { - "blurb": "When sources with a higher latency are expected to be plugged in dynamically after the aggregator has started playing, this allows overriding the minimum latency reported by the initial source(s). This is only taken into account when larger than the actually reported minimum latency. (nanoseconds)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "start-time": { - "blurb": "Start time to use if start-time-selection=set", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", + "controllable": false, + "default": "GStreamer 1.18.6 FLV muxer", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "start-time-selection": { - "blurb": "Decides which start time is output", + "skip-backwards-streams": { + "blurb": "If set to true, streams that go backwards related to the other stream will have buffers dropped until they reach the correct timestamp", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "zero (0)", - "enum": true, - "type-name": "GstAggregatorStartTimeSelection", - "values": [ - { - "desc": "Start at 0 running time (default)", - "name": "zero", - "value": "0" - }, - { - "desc": "Start at first observed input running time", - "name": "first", - "value": "1" - }, - { - "desc": "Set start time with start-time property", - "name": "set", - "value": "2" - } - ], + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "streamable": { "blurb": "If set to true, the output should be as if it is to be streamed and hence no indexes written or duration written.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, @@ -7644,7 +6643,22 @@ }, "filename": "gstflv", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": { + "GstFlvMuxPad": { + "hierarchy": [ + "GstFlvMuxPad", + "GstAggregatorPad", + "GstPad", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "kind": "object", + "properties": {}, + "signals": {} + } + }, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -7664,7 +6678,6 @@ ], "klass": "Codec/Decoder/Video", "long-name": "FLX video decoder", - "name": "flxdec", "pad-templates": { "sink": { "caps": "video/x-fli:\n", @@ -7677,30 +6690,13 @@ "presence": "always" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, "rank": "primary" } }, "filename": "gstflxdec", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -7720,7 +6716,6 @@ ], "klass": "Codec/Decoder/Image", "long-name": "GdkPixbuf image decoder", - "name": "gdkpixbufdec", "pad-templates": { "sink": { "caps": "image/png:\nimage/x-icon:\napplication/x-navi-animation:\nimage/x-cmu-raster:\nimage/x-sun-raster:\nimage/x-pixmap:\nimage/tiff:\nimage/x-portable-anymap:\nimage/x-portable-bitmap:\nimage/x-portable-graymap:\nimage/x-portable-pixmap:\nimage/bmp:\nimage/x-bmp:\nimage/x-MS-bmp:\nimage/vnd.wap.wbmp:\nimage/x-bitmap:\nimage/x-tga:\nimage/x-pcx:\nimage/svg:\nimage/svg+xml:\n", @@ -7733,28 +6728,10 @@ "presence": "always" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, "rank": "secondary" }, "gdkpixbufoverlay": { - "author": "Tim-Philipp M\u00fcller ", + "author": "Tim-Philipp Müller ", "description": "Overlay an image onto a video stream", "hierarchy": [ "GstGdkPixbufOverlay", @@ -7767,15 +6744,14 @@ ], "klass": "Filter/Effect/Video", "long-name": "GdkPixbuf Overlay", - "name": "gdkpixbufoverlay", "pad-templates": { "sink": { - "caps": "video/x-raw:\n format: { RGBx, RGB, BGR, BGRx, xRGB, xBGR, RGBA, BGRA, ARGB, ABGR, I420, YV12, AYUV, YUY2, UYVY, v308, v210, v216, Y41B, Y42B, Y444, YVYU, NV12, NV21, UYVP, RGB16, BGR16, RGB15, BGR15, UYVP, A420, YUV9, YVU9, IYU1, ARGB64, AYUV64, r210, I420_10LE, I420_10BE, GRAY8, GRAY16_BE, GRAY16_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "caps": "video/x-raw:\n format: { AYUV64, ARGB64, GBRA_12LE, GBRA_12BE, Y412_LE, Y412_BE, A444_10LE, GBRA_10LE, A444_10BE, GBRA_10BE, A422_10LE, A422_10BE, A420_10LE, A420_10BE, RGB10A2_LE, BGR10A2_LE, Y410, GBRA, ABGR, VUYA, BGRA, AYUV, ARGB, RGBA, A420, Y444_16LE, Y444_16BE, v216, P016_LE, P016_BE, Y444_12LE, GBR_12LE, Y444_12BE, GBR_12BE, I422_12LE, I422_12BE, Y212_LE, Y212_BE, I420_12LE, I420_12BE, P012_LE, P012_BE, Y444_10LE, GBR_10LE, Y444_10BE, GBR_10BE, r210, I422_10LE, I422_10BE, NV16_10LE32, Y210, v210, UYVP, I420_10LE, I420_10BE, P010_10LE, NV12_10LE32, NV12_10LE40, P010_10BE, Y444, GBR, NV24, xBGR, BGRx, xRGB, RGBx, BGR, IYU2, v308, RGB, Y42B, NV61, NV16, VYUY, UYVY, YVYU, YUY2, I420, YV12, NV21, NV12, NV12_64Z32, NV12_4L4, NV12_32L32, Y41B, IYU1, YVU9, YUV9, RGB16, BGR16, RGB15, BGR15, RGB8P, GRAY16_LE, GRAY16_BE, GRAY10_LE32, GRAY8 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "video/x-raw:\n format: { RGBx, RGB, BGR, BGRx, xRGB, xBGR, RGBA, BGRA, ARGB, ABGR, I420, YV12, AYUV, YUY2, UYVY, v308, v210, v216, Y41B, Y42B, Y444, YVYU, NV12, NV21, UYVP, RGB16, BGR16, RGB15, BGR15, UYVP, A420, YUV9, YVU9, IYU1, ARGB64, AYUV64, r210, I420_10LE, I420_10BE, GRAY8, GRAY16_BE, GRAY16_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "caps": "video/x-raw:\n format: { AYUV64, ARGB64, GBRA_12LE, GBRA_12BE, Y412_LE, Y412_BE, A444_10LE, GBRA_10LE, A444_10BE, GBRA_10BE, A422_10LE, A422_10BE, A420_10LE, A420_10BE, RGB10A2_LE, BGR10A2_LE, Y410, GBRA, ABGR, VUYA, BGRA, AYUV, ARGB, RGBA, A420, Y444_16LE, Y444_16BE, v216, P016_LE, P016_BE, Y444_12LE, GBR_12LE, Y444_12BE, GBR_12BE, I422_12LE, I422_12BE, Y212_LE, Y212_BE, I420_12LE, I420_12BE, P012_LE, P012_BE, Y444_10LE, GBR_10LE, Y444_10BE, GBR_10BE, r210, I422_10LE, I422_10BE, NV16_10LE32, Y210, v210, UYVP, I420_10LE, I420_10BE, P010_10LE, NV12_10LE32, NV12_10LE40, P010_10BE, Y444, GBR, NV24, xBGR, BGRx, xRGB, RGBx, BGR, IYU2, v308, RGB, Y42B, NV61, NV16, VYUY, UYVY, YVYU, YUY2, I420, YV12, NV21, NV12, NV12_64Z32, NV12_4L4, NV12_32L32, Y41B, IYU1, YVU9, YUV9, RGB16, BGR16, RGB15, BGR15, RGB8P, GRAY16_LE, GRAY16_BE, GRAY10_LE32, GRAY8 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", "direction": "src", "presence": "always" } @@ -7783,159 +6759,170 @@ "properties": { "alpha": { "blurb": "Global alpha of overlay image", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "1", "max": "1", "min": "0", - "type-name": "gdouble", + "mutable": "playing", + "readable": true, + "type": "gdouble", "writable": true }, "coef-x": { "blurb": "Horizontal offset of overlay image in fractions of video image width, from top-left corner of video image (absolute positioning)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "1", "min": "-1", - "type-name": "gdouble", + "mutable": "playing", + "readable": true, + "type": "gdouble", "writable": true }, "coef-y": { "blurb": "Vertical offset of overlay image in fractions of video image height, from top-left corner of video image (absolute positioning)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "1", "min": "-1", - "type-name": "gdouble", + "mutable": "playing", + "readable": true, + "type": "gdouble", "writable": true }, "location": { "blurb": "Location of image file to overlay", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "mutable": "playing", + "readable": true, + "type": "gchararray", "writable": true }, "offset-x": { "blurb": "For positive value, horizontal offset of overlay image in pixels from left of video image. For negative value, horizontal offset of overlay image in pixels from right of video image", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "2147483647", "min": "-2147483648", - "type-name": "gint", + "mutable": "playing", + "readable": true, + "type": "gint", "writable": true }, "offset-y": { "blurb": "For positive value, vertical offset of overlay image in pixels from top of video image. For negative value, vertical offset of overlay image in pixels from bottom of video image", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "2147483647", "min": "-2147483648", - "type-name": "gint", + "mutable": "playing", + "readable": true, + "type": "gint", "writable": true }, "overlay-height": { "blurb": "Height of overlay image in pixels (0 = same as overlay image)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "2147483647", "min": "0", - "type-name": "gint", + "mutable": "playing", + "readable": true, + "type": "gint", "writable": true }, "overlay-width": { "blurb": "Width of overlay image in pixels (0 = same as overlay image)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "2147483647", "min": "0", - "type-name": "gint", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "playing", + "readable": true, + "type": "gint", "writable": true }, "pixbuf": { "blurb": "GdkPixbuf object to render", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GdkPixbuf", + "controllable": true, + "mutable": "playing", + "readable": true, + "type": "GdkPixbuf", "writable": true }, "positioning-mode": { "blurb": "Positioning mode of offset-x and offset-y properties", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "pixels-relative-to-edges (0)", - "enum": true, - "type-name": "GstGdkPixbufPositioningMode", - "values": [ - { - "desc": "pixels-relative-to-edges", - "name": "pixels-relative-to-edges", - "value": "0" - }, - { - "desc": "pixels-absolute", - "name": "pixels-absolute", - "value": "1" - } - ], - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "GstGdkPixbufPositioningMode", "writable": true }, "relative-x": { "blurb": "Horizontal offset of overlay image in fractions of video image width, from top-left corner of video image (in relative positioning)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "1", "min": "-1", - "type-name": "gdouble", + "mutable": "playing", + "readable": true, + "type": "gdouble", "writable": true }, "relative-y": { "blurb": "Vertical offset of overlay image in fractions of video image height, from top-left corner of video image (in relative positioning)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "1", "min": "-1", - "type-name": "gdouble", + "mutable": "playing", + "readable": true, + "type": "gdouble", "writable": true } }, "rank": "none" }, "gdkpixbufsink": { - "author": "Tim-Philipp M\u00fcller ", + "author": "Tim-Philipp Müller ", "description": "Output images as GdkPixbuf objects in bus messages", "hierarchy": [ "GstGdkPixbufSink", @@ -7948,7 +6935,6 @@ ], "klass": "Sink/Video", "long-name": "GdkPixbuf sink", - "name": "gdkpixbufsink", "pad-templates": { "sink": { "caps": "video/x-raw:\n format: RGB\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: RGBA\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", @@ -7957,160 +6943,27 @@ } }, "properties": { - "async": { - "blurb": "Go asynchronously to PAUSED", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "blocksize": { - "blurb": "Size in bytes to pull per buffer (0 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "enable-last-sample": { - "blurb": "Enable the last-sample property", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, "last-pixbuf": { "blurb": "Last GdkPixbuf object rendered", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GdkPixbuf", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GdkPixbuf", "writable": false }, - "last-sample": { - "blurb": "The last sample received in the sink", - "construct": false, - "construct-only": false, - "type-name": "GstSample", - "writable": false - }, - "max-bitrate": { - "blurb": "The maximum bits per second to render (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "max-lateness": { - "blurb": "Maximum number of nanoseconds that a buffer can be late before it is dropped (-1 unlimited)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, "post-messages": { "blurb": "Whether to post messages containing pixbufs on the bus", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", - "writable": true - }, - "processing-deadline": { - "blurb": "Maximum processing deadline in nanoseconds", - "construct": false, - "construct-only": false, - "default": "15000000", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "qos": { - "blurb": "Generate Quality-of-Service events upstream", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "render-delay": { - "blurb": "Additional render delay of the sink in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "show-preroll-frame": { - "blurb": "Whether to render video frames during preroll", - "construct": true, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Sink Statistics", - "construct": false, - "construct-only": false, - "default": "application/x-gst-base-sink-stats, average-rate=(double)0, dropped=(guint64)0, rendered=(guint64)0;", - "type-name": "GstStructure", - "writable": false - }, - "sync": { - "blurb": "Sync on the clock", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "throttle-time": { - "blurb": "The time to keep between rendered buffers (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "ts-offset": { - "blurb": "Timestamp offset in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "-9223372036854775808", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, @@ -8119,7 +6972,24 @@ }, "filename": "gstgdkpixbuf", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": { + "GstGdkPixbufPositioningMode": { + "kind": "enum", + "values": [ + { + "desc": "pixels-relative-to-edges", + "name": "pixels-relative-to-edges", + "value": "0" + }, + { + "desc": "pixels-absolute", + "name": "pixels-absolute", + "value": "1" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -8140,7 +7010,6 @@ ], "klass": "Visualization", "long-name": "GOOM: what a GOOM!", - "name": "goom", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: S16LE\n rate: [ 8000, 96000 ]\n channels: 1\n layout: interleaved\naudio/x-raw:\n format: S16LE\n rate: [ 8000, 96000 ]\n channels: 2\n channel-mask: 0x0000000000000003\n layout: interleaved\n", @@ -8153,101 +7022,14 @@ "presence": "always" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "shade-amount": { - "blurb": "Shading color to use (big-endian ARGB)", - "construct": false, - "construct-only": false, - "default": "657930", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "shader": { - "blurb": "Shader function to apply on each frame", - "construct": false, - "construct-only": false, - "default": "fade (1)", - "enum": true, - "type-name": "GstAudioVisualizerShader", - "values": [ - { - "desc": "GST_AUDIO_VISUALIZER_SHADER_NONE", - "name": "none", - "value": "0" - }, - { - "desc": "GST_AUDIO_VISUALIZER_SHADER_FADE", - "name": "fade", - "value": "1" - }, - { - "desc": "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_UP", - "name": "fade-and-move-up", - "value": "2" - }, - { - "desc": "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_DOWN", - "name": "fade-and-move-down", - "value": "3" - }, - { - "desc": "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_LEFT", - "name": "fade-and-move-left", - "value": "4" - }, - { - "desc": "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_RIGHT", - "name": "fade-and-move-right", - "value": "5" - }, - { - "desc": "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_OUT", - "name": "fade-and-move-horiz-out", - "value": "6" - }, - { - "desc": "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_IN", - "name": "fade-and-move-horiz-in", - "value": "7" - }, - { - "desc": "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_OUT", - "name": "fade-and-move-vert-out", - "value": "8" - }, - { - "desc": "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_IN", - "name": "fade-and-move-vert-in", - "value": "9" - } - ], - "writable": true - } - }, + "properties": {}, "rank": "none" } }, "filename": "gstgoom", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -8268,7 +7050,6 @@ ], "klass": "Visualization", "long-name": "GOOM: what a GOOM! 2k1 edition", - "name": "goom2k1", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: S16LE\n rate: [ 8000, 96000 ]\n channels: 1\n layout: interleaved\naudio/x-raw:\n format: S16LE\n rate: [ 8000, 96000 ]\n channels: 2\n channel-mask: 0x0000000000000003\n layout: interleaved\n", @@ -8281,101 +7062,14 @@ "presence": "always" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "shade-amount": { - "blurb": "Shading color to use (big-endian ARGB)", - "construct": false, - "construct-only": false, - "default": "657930", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "shader": { - "blurb": "Shader function to apply on each frame", - "construct": false, - "construct-only": false, - "default": "fade (1)", - "enum": true, - "type-name": "GstAudioVisualizerShader", - "values": [ - { - "desc": "GST_AUDIO_VISUALIZER_SHADER_NONE", - "name": "none", - "value": "0" - }, - { - "desc": "GST_AUDIO_VISUALIZER_SHADER_FADE", - "name": "fade", - "value": "1" - }, - { - "desc": "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_UP", - "name": "fade-and-move-up", - "value": "2" - }, - { - "desc": "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_DOWN", - "name": "fade-and-move-down", - "value": "3" - }, - { - "desc": "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_LEFT", - "name": "fade-and-move-left", - "value": "4" - }, - { - "desc": "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_RIGHT", - "name": "fade-and-move-right", - "value": "5" - }, - { - "desc": "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_OUT", - "name": "fade-and-move-horiz-out", - "value": "6" - }, - { - "desc": "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_IN", - "name": "fade-and-move-horiz-in", - "value": "7" - }, - { - "desc": "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_OUT", - "name": "fade-and-move-vert-out", - "value": "8" - }, - { - "desc": "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_IN", - "name": "fade-and-move-vert-in", - "value": "9" - } - ], - "writable": true - } - }, + "properties": {}, "rank": "none" } }, "filename": "gstgoom2k1", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -8396,6 +7090,9 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstNavigation" + ], "klass": "Sink/Video", "long-name": "Gtk GL Video Sink", "pad-templates": { @@ -8405,166 +7102,7 @@ "presence": "always" } }, - "properties": { - "async": { - "blurb": "Go asynchronously to PAUSED", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "blocksize": { - "blurb": "Size in bytes to pull per buffer (0 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "enable-last-sample": { - "blurb": "Enable the last-sample property", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "force-aspect-ratio": { - "blurb": "When enabled, scaling will respect original aspect ratio", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "ignore-alpha": { - "blurb": "When enabled, alpha will be ignored and converted to black", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "last-sample": { - "blurb": "The last sample received in the sink", - "construct": false, - "construct-only": false, - "type-name": "GstSample", - "writable": false - }, - "max-bitrate": { - "blurb": "The maximum bits per second to render (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "max-lateness": { - "blurb": "Maximum number of nanoseconds that a buffer can be late before it is dropped (-1 unlimited)", - "construct": false, - "construct-only": false, - "default": "5000000", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "pixel-aspect-ratio": { - "blurb": "The pixel aspect ratio of the device", - "construct": false, - "construct-only": false, - "default": "0/1", - "max": "2147483647/1", - "min": "0/1", - "type-name": "GstFraction", - "writable": true - }, - "processing-deadline": { - "blurb": "Maximum processing deadline in nanoseconds", - "construct": false, - "construct-only": false, - "default": "15000000", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "qos": { - "blurb": "Generate Quality-of-Service events upstream", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "render-delay": { - "blurb": "Additional render delay of the sink in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "show-preroll-frame": { - "blurb": "Whether to render video frames during preroll", - "construct": true, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Sink Statistics", - "construct": false, - "construct-only": false, - "default": "application/x-gst-base-sink-stats, average-rate=(double)0, dropped=(guint64)0, rendered=(guint64)0;", - "type-name": "GstStructure", - "writable": false - }, - "sync": { - "blurb": "Sync on the clock", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "throttle-time": { - "blurb": "The time to keep between rendered buffers (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "ts-offset": { - "blurb": "Timestamp offset in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "-9223372036854775808", - "type-name": "gint64", - "writable": true - }, - "widget": { - "blurb": "The GtkWidget to place in the widget hierarchy (must only be get from the GTK main thread)", - "construct": false, - "construct-only": false, - "type-name": "GtkWidget", - "writable": false - } - }, + "properties": {}, "rank": "none" }, "gtksink": { @@ -8580,6 +7118,9 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstNavigation" + ], "klass": "Sink/Video", "long-name": "Gtk Video Sink", "pad-templates": { @@ -8589,172 +7130,81 @@ "presence": "always" } }, + "properties": {}, + "rank": "none" + } + }, + "filename": "gstgtk", + "license": "LGPL", + "other-types": { + "GstGtkBaseSink": { + "hierarchy": [ + "GstGtkBaseSink", + "GstVideoSink", + "GstBaseSink", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstNavigation" + ], + "kind": "object", "properties": { - "async": { - "blurb": "Go asynchronously to PAUSED", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "blocksize": { - "blurb": "Size in bytes to pull per buffer (0 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "enable-last-sample": { - "blurb": "Enable the last-sample property", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, "force-aspect-ratio": { "blurb": "When enabled, scaling will respect original aspect ratio", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "ignore-alpha": { "blurb": "When enabled, alpha will be ignored and converted to black", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", - "writable": true - }, - "last-sample": { - "blurb": "The last sample received in the sink", - "construct": false, - "construct-only": false, - "type-name": "GstSample", - "writable": false - }, - "max-bitrate": { - "blurb": "The maximum bits per second to render (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "max-lateness": { - "blurb": "Maximum number of nanoseconds that a buffer can be late before it is dropped (-1 unlimited)", - "construct": false, - "construct-only": false, - "default": "5000000", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "pixel-aspect-ratio": { "blurb": "The pixel aspect ratio of the device", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0/1", "max": "2147483647/1", "min": "0/1", - "type-name": "GstFraction", - "writable": true - }, - "processing-deadline": { - "blurb": "Maximum processing deadline in nanoseconds", - "construct": false, - "construct-only": false, - "default": "15000000", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "qos": { - "blurb": "Generate Quality-of-Service events upstream", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "render-delay": { - "blurb": "Additional render delay of the sink in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "show-preroll-frame": { - "blurb": "Whether to render video frames during preroll", - "construct": true, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Sink Statistics", - "construct": false, - "construct-only": false, - "default": "application/x-gst-base-sink-stats, average-rate=(double)0, dropped=(guint64)0, rendered=(guint64)0;", - "type-name": "GstStructure", - "writable": false - }, - "sync": { - "blurb": "Sync on the clock", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "throttle-time": { - "blurb": "The time to keep between rendered buffers (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "ts-offset": { - "blurb": "Timestamp offset in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "-9223372036854775808", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "GstFraction", "writable": true }, "widget": { "blurb": "The GtkWidget to place in the widget hierarchy (must only be get from the GTK main thread)", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GtkWidget", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GtkWidget", "writable": false } - }, - "rank": "none" + } } }, - "filename": "gstgtk", - "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -8774,7 +7224,6 @@ ], "klass": "Codec/Demuxer/Metadata", "long-name": "ICY tag demuxer", - "name": "icydemux", "pad-templates": { "sink": { "caps": "application/x-icy:\nmetadata-interval: [ 0, 2147483647 ]\n", @@ -8787,48 +7236,14 @@ "presence": "sometimes" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, "rank": "primary", - "signals": { - "no-more-pads": { - "args": [], - "retval": "void" - }, - "pad-added": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "pad-removed": { - "args": [ - "GstPad" - ], - "retval": "void" - } - } + "signals": {} } }, "filename": "gsticydemux", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -8849,7 +7264,6 @@ ], "klass": "Codec/Demuxer/Metadata", "long-name": "ID3 tag demuxer", - "name": "id3demux", "pad-templates": { "sink": { "caps": "application/x-id3:\n", @@ -8863,28 +7277,16 @@ } }, "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, "prefer-v1": { "blurb": "Prefer tags from ID3v1 tag at end of file when both ID3v1 and ID3v2 tags are present", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, @@ -8893,7 +7295,8 @@ }, "filename": "gstid3demux", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -8902,7 +7305,7 @@ "description": "Still frame stream generator", "elements": { "imagefreeze": { - "author": "Sebastian Dr\u00f6ge ", + "author": "Sebastian Dröge ", "description": "Generates a still frame stream from an image", "hierarchy": [ "GstImageFreeze", @@ -8913,7 +7316,6 @@ ], "klass": "Filter/Video", "long-name": "Still frame stream generator", - "name": "imagefreeze", "pad-templates": { "sink": { "caps": "video/x-raw(ANY):\n", @@ -8927,30 +7329,42 @@ } }, "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, + "allow-replace": { + "blurb": "Allow replacing the input buffer and always output the latest", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "is-live": { + "blurb": "Whether to output a live video stream", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "num-buffers": { "blurb": "Number of buffers to output before sending EOS (-1 = unlimited)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "-1", "max": "2147483647", "min": "-1", - "type-name": "gint", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true } }, @@ -8959,7 +7373,8 @@ }, "filename": "gstimagefreeze", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -8968,7 +7383,7 @@ "description": "Audio interleaver/deinterleaver", "elements": { "deinterleave": { - "author": "Andy Wingo , Iain , Sebastian Dr\u00f6ge ", + "author": "Andy Wingo , Iain , Sebastian Dröge ", "description": "Splits one interleaved multichannel audio stream into many mono audio streams", "hierarchy": [ "GstDeinterleave", @@ -8979,15 +7394,14 @@ ], "klass": "Filter/Converter/Audio", "long-name": "Audio deinterleaver", - "name": "deinterleave", "pad-templates": { "sink": { - "caps": "audio/x-raw:\n format: { S8, U8, S16LE, S16BE, U16LE, U16BE, S24_32LE, S24_32BE, U24_32LE, U24_32BE, S32LE, S32BE, U32LE, U32BE, S24LE, S24BE, U24LE, U24BE, S20LE, S20BE, U20LE, U20BE, S18LE, S18BE, U18LE, U18BE, F32LE, F32BE, F64LE, F64BE }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: interleaved\n", + "caps": "audio/x-raw:\n format: { F64LE, F64BE, F32LE, F32BE, S32LE, S32BE, U32LE, U32BE, S24_32LE, S24_32BE, U24_32LE, U24_32BE, S24LE, S24BE, U24LE, U24BE, S20LE, S20BE, U20LE, U20BE, S18LE, S18BE, U18LE, U18BE, S16LE, S16BE, U16LE, U16BE, S8, U8 }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: interleaved\n", "direction": "sink", "presence": "always" }, "src_%%u": { - "caps": "audio/x-raw:\n format: { S8, U8, S16LE, S16BE, U16LE, U16BE, S24_32LE, S24_32BE, U24_32LE, U24_32BE, S32LE, S32BE, U32LE, U32BE, S24LE, S24BE, U24LE, U24BE, S20LE, S20BE, U20LE, U20BE, S18LE, S18BE, U18LE, U18BE, F32LE, F32BE, F64LE, F64BE }\n rate: [ 1, 2147483647 ]\n channels: 1\n layout: { (string)non-interleaved, (string)interleaved }\n", + "caps": "audio/x-raw:\n format: { F64LE, F64BE, F32LE, F32BE, S32LE, S32BE, U32LE, U32BE, S24_32LE, S24_32BE, U24_32LE, U24_32BE, S24LE, S24BE, U24LE, U24BE, S20LE, S20BE, U20LE, U20BE, S18LE, S18BE, U18LE, U18BE, S16LE, S16BE, U16LE, U16BE, S8, U8 }\n rate: [ 1, 2147483647 ]\n channels: 1\n layout: { (string)non-interleaved, (string)interleaved }\n", "direction": "src", "presence": "sometimes" } @@ -8995,51 +7409,22 @@ "properties": { "keep-positions": { "blurb": "Keep the original channel positions on the output buffers", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, "rank": "none", - "signals": { - "no-more-pads": { - "args": [], - "retval": "void" - }, - "pad-added": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "pad-removed": { - "args": [ - "GstPad" - ], - "retval": "void" - } - } + "signals": {} }, "interleave": { - "author": "Andy Wingo , Sebastian Dr\u00f6ge ", + "author": "Andy Wingo , Sebastian Dröge ", "description": "Folds many mono channels into one interleaved audio stream", "hierarchy": [ "GstInterleave", @@ -9050,15 +7435,14 @@ ], "klass": "Filter/Converter/Audio", "long-name": "Audio interleaver", - "name": "interleave", "pad-templates": { "sink_%%u": { - "caps": "audio/x-raw:\n rate: [ 1, 2147483647 ]\n channels: 1\n format: { S8, U8, S16LE, S16BE, U16LE, U16BE, S24_32LE, S24_32BE, U24_32LE, U24_32BE, S32LE, S32BE, U32LE, U32BE, S24LE, S24BE, U24LE, U24BE, S20LE, S20BE, U20LE, U20BE, S18LE, S18BE, U18LE, U18BE, F32LE, F32BE, F64LE, F64BE }\n layout: { (string)non-interleaved, (string)interleaved }\n", + "caps": "audio/x-raw:\n rate: [ 1, 2147483647 ]\n channels: 1\n format: { F64LE, F64BE, F32LE, F32BE, S32LE, S32BE, U32LE, U32BE, S24_32LE, S24_32BE, U24_32LE, U24_32BE, S24LE, S24BE, U24LE, U24BE, S20LE, S20BE, U20LE, U20BE, S18LE, S18BE, U18LE, U18BE, S16LE, S16BE, U16LE, U16BE, S8, U8 }\n layout: { (string)non-interleaved, (string)interleaved }\n", "direction": "sink", "presence": "request" }, "src": { - "caps": "audio/x-raw:\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n format: { S8, U8, S16LE, S16BE, U16LE, U16BE, S24_32LE, S24_32BE, U24_32LE, U24_32BE, S32LE, S32BE, U32LE, U32BE, S24LE, S24BE, U24LE, U24BE, S20LE, S20BE, U20LE, U20BE, S18LE, S18BE, U18LE, U18BE, F32LE, F32BE, F64LE, F64BE }\n layout: interleaved\n", + "caps": "audio/x-raw:\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n format: { F64LE, F64BE, F32LE, F32BE, S32LE, S32BE, U32LE, U32BE, S24_32LE, S24_32BE, U24_32LE, U24_32BE, S24LE, S24BE, U24LE, U24BE, S20LE, S20BE, U20LE, U20BE, S18LE, S18BE, U18LE, U18BE, S16LE, S16BE, U16LE, U16BE, S8, U8 }\n layout: interleaved\n", "direction": "src", "presence": "always" } @@ -9066,33 +7450,25 @@ "properties": { "channel-positions": { "blurb": "Channel positions used on the output", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GValueArray", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GValueArray", "writable": true }, "channel-positions-from-input": { "blurb": "Take channel positions from the input", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, @@ -9101,7 +7477,8 @@ }, "filename": "gstinterleave", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -9114,299 +7491,306 @@ "description": "Multiplex audio and video into a 3GPP file", "hierarchy": [ "Gst3GPPMux", + "GstAggregator", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstTagSetter", + "GstTagXmpWriter", + "GstPreset" + ], "klass": "Codec/Muxer", "long-name": "3GPP Muxer", - "name": "3gppmux", "pad-templates": { "audio_%%u": { "caps": "audio/AMR:\n rate: 8000\n channels: [ 1, 2 ]\naudio/AMR-WB:\n rate: 16000\n channels: [ 1, 2 ]\naudio/mpeg:\n mpegversion: 1\n layer: 3\n channels: [ 1, 2 ]\n rate: [ 1, 2147483647 ]\naudio/mpeg:\n mpegversion: 4\n stream-format: raw\n channels: [ 1, 8 ]\n rate: [ 1, 2147483647 ]\naudio/x-ac3:\n channels: [ 1, 6 ]\n rate: [ 1, 2147483647 ]\n", "direction": "sink", - "object-type": { - "hierarchy": [ - "GstQTMuxPad", - "GstPad", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "properties": { - "trak-timescale": { - "blurb": "Timescale to use for this pad's trak (units per second, 0 is automatic)", - "construct": true, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - } - }, - "presence": "request" + "presence": "request", + "type": "GstQTMuxPad" }, "src": { "caps": "video/quicktime:\n variant: 3gpp\n", "direction": "src", - "presence": "always" + "presence": "always", + "type": "GstAggregatorPad" }, "subtitle_%%u": { "caps": "text/x-raw:\n format: utf8\n", "direction": "sink", - "object-type": { - "hierarchy": [ - "GstQTMuxPad", - "GstPad", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "properties": { - "trak-timescale": { - "blurb": "Timescale to use for this pad's trak (units per second, 0 is automatic)", - "construct": true, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - } - }, - "presence": "request" + "presence": "request", + "type": "GstQTMuxPad" }, "video_%%u": { "caps": "video/x-h263:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/mpeg:\n mpegversion: 4\n systemstream: false\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-divx:\n divxversion: 5\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h264:\n stream-format: avc\n alignment: au\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\n", "direction": "sink", - "object-type": { - "hierarchy": [ - "GstQTMuxPad", - "GstPad", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "properties": { - "trak-timescale": { - "blurb": "Timescale to use for this pad's trak (units per second, 0 is automatic)", - "construct": true, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - } - }, - "presence": "request" + "presence": "request", + "type": "GstQTMuxPad" } }, "properties": { "dts-method": { "blurb": "Method to determine DTS time (DEPRECATED)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "reorder (1)", - "enum": true, - "type-name": "GstQTMuxDtsMethods", - "values": [ - { - "desc": "delta/duration", - "name": "dd", - "value": "0" - }, - { - "desc": "reorder", - "name": "reorder", - "value": "1" - }, - { - "desc": "ascending", - "name": "asc", - "value": "2" - } - ], + "mutable": "null", + "readable": true, + "type": "GstQTMuxDtsMethods", "writable": true }, "faststart": { "blurb": "If the file should be formatted for faststart (headers first)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "faststart-file": { "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", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": true + }, + "force-chunks": { + "blurb": "Force multiple chunks to be created even for single-stream files", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "force-create-timecode-trak": { + "blurb": "Create a timecode trak even in unsupported flavors", + "conditionally-available": false, + "construct": true, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "fragment-duration": { "blurb": "Fragment durations in ms (produce a fragmented file if > 0)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "interleave-bytes": { "blurb": "Interleave between streams in bytes", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "interleave-time": { "blurb": "Interleave between streams in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "250000000", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "max-raw-audio-drift": { "blurb": "Maximum allowed drift of raw audio samples vs. timestamps in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "40000000", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "moov-recovery-file": { "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)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, "movie-timescale": { "blurb": "Timescale to use in the movie (units per second, 0 == default)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "presentation-time": { "blurb": "Calculate and include presentation/composition time (in addition to decoding time)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "reserved-bytes-per-sec": { "blurb": "Multiplier for converting reserved-max-duration into bytes of header to reserve, per second, per track", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "550", "max": "10000", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "reserved-duration-remaining": { "blurb": "Reports the approximate amount of remaining moov header space reserved using reserved-max-duration", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": false }, "reserved-max-duration": { "blurb": "When set to a value > 0, reserves space for index tables at the beginning of the file.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "reserved-moov-update-period": { "blurb": "When used with reserved-max-duration, periodically updates the index tables with information muxed so far.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "reserved-prefill": { "blurb": "Prefill samples table of reserved duration", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "start-gap-threshold": { "blurb": "Threshold for creating an edit list for gaps at the start in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "streamable": { "blurb": "If set to true, the output should be as if it is to be streamed and hence no indexes written or duration written. (DEPRECATED, only valid for fragmented MP4)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "trak-timescale": { "blurb": "Timescale to use for the tracks (units per second, 0 is automatic)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true } }, @@ -9417,272 +7801,300 @@ "description": "Multiplex audio and video into a ISML file", "hierarchy": [ "GstISMLMux", + "GstAggregator", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstTagSetter", + "GstTagXmpWriter", + "GstPreset" + ], "klass": "Codec/Muxer", "long-name": "ISML Muxer", - "name": "ismlmux", "pad-templates": { "audio_%%u": { "caps": "audio/mpeg:\n mpegversion: 1\n layer: 3\n channels: [ 1, 2 ]\n rate: [ 1, 2147483647 ]\naudio/mpeg:\n mpegversion: 4\n stream-format: raw\n channels: [ 1, 8 ]\n rate: [ 1, 2147483647 ]\n", "direction": "sink", - "object-type": { - "hierarchy": [ - "GstQTMuxPad", - "GstPad", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "properties": { - "trak-timescale": { - "blurb": "Timescale to use for this pad's trak (units per second, 0 is automatic)", - "construct": true, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - } - }, - "presence": "request" + "presence": "request", + "type": "GstQTMuxPad" }, "src": { "caps": "video/quicktime:\n variant: iso-fragmented\n", "direction": "src", - "presence": "always" + "presence": "always", + "type": "GstAggregatorPad" }, "video_%%u": { "caps": "video/mpeg:\n mpegversion: 4\n systemstream: false\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-divx:\n divxversion: 5\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h264:\n stream-format: avc\n alignment: au\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\n", "direction": "sink", - "object-type": { - "hierarchy": [ - "GstQTMuxPad", - "GstPad", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "properties": { - "trak-timescale": { - "blurb": "Timescale to use for this pad's trak (units per second, 0 is automatic)", - "construct": true, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - } - }, - "presence": "request" + "presence": "request", + "type": "GstQTMuxPad" } }, "properties": { "dts-method": { "blurb": "Method to determine DTS time (DEPRECATED)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "reorder (1)", - "enum": true, - "type-name": "GstQTMuxDtsMethods", - "values": [ - { - "desc": "delta/duration", - "name": "dd", - "value": "0" - }, - { - "desc": "reorder", - "name": "reorder", - "value": "1" - }, - { - "desc": "ascending", - "name": "asc", - "value": "2" - } - ], + "mutable": "null", + "readable": true, + "type": "GstQTMuxDtsMethods", "writable": true }, "faststart": { "blurb": "If the file should be formatted for faststart (headers first)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "faststart-file": { "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", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": true + }, + "force-chunks": { + "blurb": "Force multiple chunks to be created even for single-stream files", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "force-create-timecode-trak": { + "blurb": "Create a timecode trak even in unsupported flavors", + "conditionally-available": false, + "construct": true, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "fragment-duration": { "blurb": "Fragment durations in ms (produce a fragmented file if > 0)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "2000", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "interleave-bytes": { "blurb": "Interleave between streams in bytes", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "interleave-time": { "blurb": "Interleave between streams in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "250000000", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "max-raw-audio-drift": { "blurb": "Maximum allowed drift of raw audio samples vs. timestamps in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "40000000", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "moov-recovery-file": { "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)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, "movie-timescale": { "blurb": "Timescale to use in the movie (units per second, 0 == default)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "presentation-time": { "blurb": "Calculate and include presentation/composition time (in addition to decoding time)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "reserved-bytes-per-sec": { "blurb": "Multiplier for converting reserved-max-duration into bytes of header to reserve, per second, per track", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "550", "max": "10000", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "reserved-duration-remaining": { "blurb": "Reports the approximate amount of remaining moov header space reserved using reserved-max-duration", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": false }, "reserved-max-duration": { "blurb": "When set to a value > 0, reserves space for index tables at the beginning of the file.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "reserved-moov-update-period": { "blurb": "When used with reserved-max-duration, periodically updates the index tables with information muxed so far.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "reserved-prefill": { "blurb": "Prefill samples table of reserved duration", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "start-gap-threshold": { "blurb": "Threshold for creating an edit list for gaps at the start in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "streamable": { "blurb": "If set to true, the output should be as if it is to be streamed and hence no indexes written or duration written.", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "trak-timescale": { "blurb": "Timescale to use for the tracks (units per second, 0 is automatic)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true } }, @@ -9693,272 +8105,300 @@ "description": "Multiplex audio and video into a MJ2 file", "hierarchy": [ "GstMJ2Mux", + "GstAggregator", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstTagSetter", + "GstTagXmpWriter", + "GstPreset" + ], "klass": "Codec/Muxer", "long-name": "MJ2 Muxer", - "name": "mj2mux", "pad-templates": { "audio_%%u": { "caps": "audio/x-raw:\n format: { S16LE, S16BE, S8, U8 }\n layout: interleaved\n channels: [ 1, 2 ]\n rate: [ 1, 2147483647 ]\n", "direction": "sink", - "object-type": { - "hierarchy": [ - "GstQTMuxPad", - "GstPad", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "properties": { - "trak-timescale": { - "blurb": "Timescale to use for this pad's trak (units per second, 0 is automatic)", - "construct": true, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - } - }, - "presence": "request" + "presence": "request", + "type": "GstQTMuxPad" }, "src": { "caps": "video/mj2:\n", "direction": "src", - "presence": "always" + "presence": "always", + "type": "GstAggregatorPad" }, "video_%%u": { "caps": "image/x-j2c:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nimage/x-jpc:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\n", "direction": "sink", - "object-type": { - "hierarchy": [ - "GstQTMuxPad", - "GstPad", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "properties": { - "trak-timescale": { - "blurb": "Timescale to use for this pad's trak (units per second, 0 is automatic)", - "construct": true, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - } - }, - "presence": "request" + "presence": "request", + "type": "GstQTMuxPad" } }, "properties": { "dts-method": { "blurb": "Method to determine DTS time (DEPRECATED)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "reorder (1)", - "enum": true, - "type-name": "GstQTMuxDtsMethods", - "values": [ - { - "desc": "delta/duration", - "name": "dd", - "value": "0" - }, - { - "desc": "reorder", - "name": "reorder", - "value": "1" - }, - { - "desc": "ascending", - "name": "asc", - "value": "2" - } - ], + "mutable": "null", + "readable": true, + "type": "GstQTMuxDtsMethods", "writable": true }, "faststart": { "blurb": "If the file should be formatted for faststart (headers first)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "faststart-file": { "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", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": true + }, + "force-chunks": { + "blurb": "Force multiple chunks to be created even for single-stream files", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "force-create-timecode-trak": { + "blurb": "Create a timecode trak even in unsupported flavors", + "conditionally-available": false, + "construct": true, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "fragment-duration": { "blurb": "Fragment durations in ms (produce a fragmented file if > 0)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "interleave-bytes": { "blurb": "Interleave between streams in bytes", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "interleave-time": { "blurb": "Interleave between streams in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "250000000", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "max-raw-audio-drift": { "blurb": "Maximum allowed drift of raw audio samples vs. timestamps in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "40000000", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "moov-recovery-file": { "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)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, "movie-timescale": { "blurb": "Timescale to use in the movie (units per second, 0 == default)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "presentation-time": { "blurb": "Calculate and include presentation/composition time (in addition to decoding time)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "reserved-bytes-per-sec": { "blurb": "Multiplier for converting reserved-max-duration into bytes of header to reserve, per second, per track", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "550", "max": "10000", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "reserved-duration-remaining": { "blurb": "Reports the approximate amount of remaining moov header space reserved using reserved-max-duration", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": false }, "reserved-max-duration": { "blurb": "When set to a value > 0, reserves space for index tables at the beginning of the file.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "reserved-moov-update-period": { "blurb": "When used with reserved-max-duration, periodically updates the index tables with information muxed so far.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "reserved-prefill": { "blurb": "Prefill samples table of reserved duration", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "start-gap-threshold": { "blurb": "Threshold for creating an edit list for gaps at the start in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "streamable": { "blurb": "If set to true, the output should be as if it is to be streamed and hence no indexes written or duration written. (DEPRECATED, only valid for fragmented MP4)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "trak-timescale": { "blurb": "Timescale to use for the tracks (units per second, 0 is automatic)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true } }, @@ -9969,298 +8409,306 @@ "description": "Multiplex audio and video into a MP4 file", "hierarchy": [ "GstMP4Mux", + "GstAggregator", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstTagSetter", + "GstTagXmpWriter", + "GstPreset" + ], "klass": "Codec/Muxer", "long-name": "MP4 Muxer", - "name": "mp4mux", "pad-templates": { "audio_%%u": { "caps": "audio/mpeg:\n mpegversion: 1\n layer: [ 1, 3 ]\n channels: [ 1, 2 ]\n rate: [ 1, 2147483647 ]\naudio/mpeg:\n mpegversion: 4\n stream-format: raw\n channels: [ 1, 8 ]\n rate: [ 1, 2147483647 ]\naudio/x-ac3:\n channels: [ 1, 6 ]\n rate: [ 1, 2147483647 ]\naudio/x-alac:\n channels: [ 1, 2 ]\n rate: [ 1, 2147483647 ]\naudio/x-opus:\nchannel-mapping-family: [ 0, 255 ]\n channels: [ 1, 8 ]\n rate: [ 1, 2147483647 ]\n", "direction": "sink", - "object-type": { - "hierarchy": [ - "GstQTMuxPad", - "GstPad", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "properties": { - "trak-timescale": { - "blurb": "Timescale to use for this pad's trak (units per second, 0 is automatic)", - "construct": true, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - } - }, - "presence": "request" + "presence": "request", + "type": "GstQTMuxPad" }, "src": { "caps": "video/quicktime:\n variant: iso\n", "direction": "src", - "presence": "always" + "presence": "always", + "type": "GstAggregatorPad" }, "subtitle_%%u": { "caps": "text/x-raw:\n format: utf8\n", "direction": "sink", - "object-type": { - "hierarchy": [ - "GstQTMuxPad", - "GstPad", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "properties": { - "trak-timescale": { - "blurb": "Timescale to use for this pad's trak (units per second, 0 is automatic)", - "construct": true, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - } - }, - "presence": "request" + "presence": "request", + "type": "GstQTMuxPad" }, "video_%%u": { "caps": "video/mpeg:\n mpegversion: 4\n systemstream: false\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-divx:\n divxversion: 5\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h264:\n stream-format: avc\n alignment: au\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h265:\n stream-format: { (string)hvc1, (string)hev1 }\n alignment: au\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-mp4-part:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-av1:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\n", "direction": "sink", - "object-type": { - "hierarchy": [ - "GstQTMuxPad", - "GstPad", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "properties": { - "trak-timescale": { - "blurb": "Timescale to use for this pad's trak (units per second, 0 is automatic)", - "construct": true, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - } - }, - "presence": "request" + "presence": "request", + "type": "GstQTMuxPad" } }, "properties": { "dts-method": { "blurb": "Method to determine DTS time (DEPRECATED)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "reorder (1)", - "enum": true, - "type-name": "GstQTMuxDtsMethods", - "values": [ - { - "desc": "delta/duration", - "name": "dd", - "value": "0" - }, - { - "desc": "reorder", - "name": "reorder", - "value": "1" - }, - { - "desc": "ascending", - "name": "asc", - "value": "2" - } - ], + "mutable": "null", + "readable": true, + "type": "GstQTMuxDtsMethods", "writable": true }, "faststart": { "blurb": "If the file should be formatted for faststart (headers first)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "faststart-file": { "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", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": true + }, + "force-chunks": { + "blurb": "Force multiple chunks to be created even for single-stream files", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "force-create-timecode-trak": { + "blurb": "Create a timecode trak even in unsupported flavors", + "conditionally-available": false, + "construct": true, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "fragment-duration": { "blurb": "Fragment durations in ms (produce a fragmented file if > 0)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "interleave-bytes": { "blurb": "Interleave between streams in bytes", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "interleave-time": { "blurb": "Interleave between streams in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "250000000", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "max-raw-audio-drift": { "blurb": "Maximum allowed drift of raw audio samples vs. timestamps in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "40000000", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "moov-recovery-file": { "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)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, "movie-timescale": { "blurb": "Timescale to use in the movie (units per second, 0 == default)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "presentation-time": { "blurb": "Calculate and include presentation/composition time (in addition to decoding time)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "reserved-bytes-per-sec": { "blurb": "Multiplier for converting reserved-max-duration into bytes of header to reserve, per second, per track", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "550", "max": "10000", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "reserved-duration-remaining": { "blurb": "Reports the approximate amount of remaining moov header space reserved using reserved-max-duration", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": false }, "reserved-max-duration": { "blurb": "When set to a value > 0, reserves space for index tables at the beginning of the file.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "reserved-moov-update-period": { "blurb": "When used with reserved-max-duration, periodically updates the index tables with information muxed so far.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "reserved-prefill": { "blurb": "Prefill samples table of reserved duration", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "start-gap-threshold": { "blurb": "Threshold for creating an edit list for gaps at the start in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "streamable": { "blurb": "If set to true, the output should be as if it is to be streamed and hence no indexes written or duration written. (DEPRECATED, only valid for fragmented MP4)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "trak-timescale": { "blurb": "Timescale to use for the tracks (units per second, 0 is automatic)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true } }, @@ -10278,7 +8726,6 @@ ], "klass": "Codec/Demuxer", "long-name": "QuickTime demuxer", - "name": "qtdemux", "pad-templates": { "audio_%%u": { "caps": "ANY", @@ -10301,43 +8748,8 @@ "presence": "sometimes" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, "rank": "primary", - "signals": { - "no-more-pads": { - "args": [], - "retval": "void" - }, - "pad-added": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "pad-removed": { - "args": [ - "GstPad" - ], - "retval": "void" - } - } + "signals": {} }, "qtmoovrecover": { "author": "Thiago Santos ", @@ -10351,100 +8763,58 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstChildProxy" + ], "klass": "Util", "long-name": "QT Moov Recover", - "name": "qtmoovrecover", "properties": { - "async-handling": { - "blurb": "The bin will handle Asynchronous state changes", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "auto-flush-bus": { - "blurb": "Whether to automatically flush the pipeline's bus when going from READY into NULL state", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, "broken-input": { "blurb": "Path to broken input file. (If qtmux was on faststart mode, this file is the faststart file)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "delay": { - "blurb": "Expected delay needed for elements to spin up to PLAYING in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, "faststart-mode": { "blurb": "If the broken input is from faststart mode", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "fixed-output": { "blurb": "Path to write the fixed file to (used as output)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "latency": { - "blurb": "Latency to configure on the pipeline", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "message-forward": { - "blurb": "Forwards all children messages", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "recovery-input": { - "blurb": "Path to recovery file (used as input)", + "recovery-input": { + "blurb": "Path to recovery file (used as input)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true } }, @@ -10455,324 +8825,312 @@ "description": "Multiplex audio and video into a QuickTime file", "hierarchy": [ "GstQTMux", + "GstAggregator", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstTagSetter", + "GstTagXmpWriter", + "GstPreset" + ], "klass": "Codec/Muxer", "long-name": "QuickTime Muxer", - "name": "qtmux", "pad-templates": { "audio_%%u": { "caps": "audio/x-raw:\n format: { S32LE, S32BE, S24LE, S24BE, S16LE, S16BE, S8, U8 }\n layout: interleaved\n channels: [ 1, 2 ]\n rate: [ 1, 2147483647 ]\naudio/x-raw:\n format: { S32LE, S32BE, S24LE, S24BE, S16LE, S16BE, S8, U8 }\n layout: interleaved\n channel-mask: 0x0000000000000000\n channels: [ 1, 16 ]\n rate: [ 1, 2147483647 ]\naudio/mpeg:\n mpegversion: 1\n layer: [ 1, 3 ]\n channels: [ 1, 2 ]\n rate: [ 1, 2147483647 ]\naudio/mpeg:\n mpegversion: 4\n stream-format: raw\n channels: [ 1, 8 ]\n rate: [ 1, 2147483647 ]\naudio/x-ac3:\n channels: [ 1, 6 ]\n rate: [ 1, 2147483647 ]\naudio/x-adpcm:\n layout: dvi\n block_align: [ 64, 8096 ]\n channels: [ 1, 2 ]\n rate: [ 1, 2147483647 ]\naudio/x-alaw:\n channels: [ 1, 2 ]\n rate: [ 1, 2147483647 ]\naudio/x-mulaw:\n channels: [ 1, 2 ]\n rate: [ 1, 2147483647 ]\naudio/AMR:\n rate: 8000\n channels: [ 1, 2 ]\naudio/AMR-WB:\n rate: 16000\n channels: [ 1, 2 ]\naudio/x-alac:\n channels: [ 1, 2 ]\n rate: [ 1, 2147483647 ]\naudio/x-opus:\nchannel-mapping-family: [ 0, 255 ]\n channels: [ 1, 8 ]\n rate: [ 1, 2147483647 ]\n", "direction": "sink", - "object-type": { - "hierarchy": [ - "GstQTMuxPad", - "GstPad", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "properties": { - "trak-timescale": { - "blurb": "Timescale to use for this pad's trak (units per second, 0 is automatic)", - "construct": true, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - } - }, - "presence": "request" + "presence": "request", + "type": "GstQTMuxPad" }, "caption_%%u": { "caps": "closedcaption/x-cea-608:\n format: s334-1a\nclosedcaption/x-cea-708:\n format: cdp\n", "direction": "sink", - "object-type": { - "hierarchy": [ - "GstQTMuxPad", - "GstPad", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "properties": { - "trak-timescale": { - "blurb": "Timescale to use for this pad's trak (units per second, 0 is automatic)", - "construct": true, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - } - }, - "presence": "request" + "presence": "request", + "type": "GstQTMuxPad" }, "src": { "caps": "video/quicktime:\n variant: apple\nvideo/quicktime:\n", "direction": "src", - "presence": "always" + "presence": "always", + "type": "GstAggregatorPad" }, "subtitle_%%u": { "caps": "text/x-raw:\n format: utf8\n", "direction": "sink", - "object-type": { - "hierarchy": [ - "GstQTMuxPad", - "GstPad", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "properties": { - "trak-timescale": { - "blurb": "Timescale to use for this pad's trak (units per second, 0 is automatic)", - "construct": true, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - } - }, - "presence": "request" + "presence": "request", + "type": "GstQTMuxPad" }, "video_%%u": { "caps": "video/x-raw:\n format: { RGB, UYVY, v210 }\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/mpeg:\n mpegversion: 4\n systemstream: false\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-divx:\n divxversion: 5\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-prores:\n variant: { (string)standard, (string)lt, (string)hq, (string)proxy, (string)4444, (string)4444xq }\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-cineform:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h263:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h264:\n stream-format: avc\n alignment: au\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h265:\n stream-format: { (string)hvc1, (string)hev1 }\n alignment: au\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-svq:\n svqversion: 3\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-dv:\n systemstream: false\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nimage/jpeg:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nimage/png:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-vp8:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-vp9:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-dirac:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-qt-part:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-av1:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\n", "direction": "sink", - "object-type": { - "hierarchy": [ - "GstQTMuxPad", - "GstPad", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "properties": { - "trak-timescale": { - "blurb": "Timescale to use for this pad's trak (units per second, 0 is automatic)", - "construct": true, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - } - }, - "presence": "request" + "presence": "request", + "type": "GstQTMuxPad" } }, "properties": { "dts-method": { "blurb": "Method to determine DTS time (DEPRECATED)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "reorder (1)", - "enum": true, - "type-name": "GstQTMuxDtsMethods", - "values": [ - { - "desc": "delta/duration", - "name": "dd", - "value": "0" - }, - { - "desc": "reorder", - "name": "reorder", - "value": "1" - }, - { - "desc": "ascending", - "name": "asc", - "value": "2" - } - ], + "mutable": "null", + "readable": true, + "type": "GstQTMuxDtsMethods", "writable": true }, "faststart": { "blurb": "If the file should be formatted for faststart (headers first)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "faststart-file": { "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", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": true + }, + "force-chunks": { + "blurb": "Force multiple chunks to be created even for single-stream files", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "force-create-timecode-trak": { + "blurb": "Create a timecode trak even in unsupported flavors", + "conditionally-available": false, + "construct": true, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "fragment-duration": { "blurb": "Fragment durations in ms (produce a fragmented file if > 0)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "interleave-bytes": { "blurb": "Interleave between streams in bytes", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "interleave-time": { "blurb": "Interleave between streams in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "250000000", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "max-raw-audio-drift": { "blurb": "Maximum allowed drift of raw audio samples vs. timestamps in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "40000000", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "moov-recovery-file": { "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)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, "movie-timescale": { "blurb": "Timescale to use in the movie (units per second, 0 == default)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "presentation-time": { "blurb": "Calculate and include presentation/composition time (in addition to decoding time)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "reserved-bytes-per-sec": { "blurb": "Multiplier for converting reserved-max-duration into bytes of header to reserve, per second, per track", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "550", "max": "10000", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "reserved-duration-remaining": { "blurb": "Reports the approximate amount of remaining moov header space reserved using reserved-max-duration", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": false }, "reserved-max-duration": { "blurb": "When set to a value > 0, reserves space for index tables at the beginning of the file.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "reserved-moov-update-period": { "blurb": "When used with reserved-max-duration, periodically updates the index tables with information muxed so far.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "reserved-prefill": { "blurb": "Prefill samples table of reserved duration", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "start-gap-threshold": { "blurb": "Threshold for creating an edit list for gaps at the start in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "streamable": { "blurb": "If set to true, the output should be as if it is to be streamed and hence no indexes written or duration written. (DEPRECATED, only valid for fragmented MP4)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "trak-timescale": { "blurb": "Timescale to use for the tracks (units per second, 0 is automatic)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true } }, @@ -10791,7 +9149,6 @@ ], "klass": "Codec/Depayloader/Network", "long-name": "RTP packet depayloader", - "name": "rtpxqtdepay", "pad-templates": { "sink": { "caps": "application/x-rtp:\n payload: [ 96, 127 ]\n media: { (string)audio, (string)video }\n clock-rate: [ 1, 2147483647 ]\n encoding-name: { (string)X-QT, (string)X-QUICKTIME }\n", @@ -10804,56 +9161,63 @@ "presence": "always" } }, + "properties": {}, + "rank": "marginal" + } + }, + "filename": "gstisomp4", + "license": "LGPL", + "other-types": { + "GstQTMuxDtsMethods": { + "kind": "enum", + "values": [ + { + "desc": "delta/duration", + "name": "dd", + "value": "0" + }, + { + "desc": "reorder", + "name": "reorder", + "value": "1" + }, + { + "desc": "ascending", + "name": "asc", + "value": "2" + } + ] + }, + "GstQTMuxPad": { + "hierarchy": [ + "GstQTMuxPad", + "GstAggregatorPad", + "GstPad", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "kind": "object", "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", + "trak-timescale": { + "blurb": "Timescale to use for this pad's trak (units per second, 0 is automatic)", + "conditionally-available": false, "construct": true, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "0", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false } }, - "rank": "marginal" + "signals": {} } }, - "filename": "gstisomp4", - "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -10875,7 +9239,6 @@ ], "klass": "Sink/Audio", "long-name": "Audio Sink (Jack)", - "name": "jackaudiosink", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: F32LE\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", @@ -10884,546 +9247,172 @@ } }, "properties": { - "alignment-threshold": { - "blurb": "Timestamp alignment threshold in nanoseconds", - "construct": false, - "construct-only": false, - "default": "40000000", - "max": "18446744073709551614", - "min": "1", - "type-name": "guint64", - "writable": true - }, - "async": { - "blurb": "Go asynchronously to PAUSED", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "blocksize": { - "blurb": "Size in bytes to pull per buffer (0 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "buffer-time": { - "blurb": "Size of audio buffer in microseconds, this is the minimum latency that the sink reports", - "construct": false, - "construct-only": false, - "default": "200000", - "max": "9223372036854775807", - "min": "1", - "type-name": "gint64", - "writable": true - }, - "can-activate-pull": { - "blurb": "Allow pull-based scheduling", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, "client": { "blurb": "Handle for jack client", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "JackClient", + "controllable": false, + "mutable": "ready", + "readable": true, + "type": "JackClient", "writable": true }, "client-name": { "blurb": "The client name of the Jack instance (NULL = default)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, "connect": { "blurb": "Specify how the output ports will be connected", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "auto (1)", - "enum": true, - "type-name": "GstJackConnect", - "values": [ - { - "desc": "Don't automatically connect ports to physical ports", - "name": "none", - "value": "0" - }, - { - "desc": "Automatically connect ports to physical ports", - "name": "auto", - "value": "1" - }, - { - "desc": "Automatically connect ports to as many physical ports as possible", - "name": "auto-forced", - "value": "2" - } - ], - "writable": true - }, - "discont-wait": { - "blurb": "Window of time in nanoseconds to wait before creating a discontinuity", - "construct": false, - "construct-only": false, - "default": "1000000000", - "max": "18446744073709551614", - "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "GstJackConnect", "writable": true }, - "drift-tolerance": { - "blurb": "Tolerance for clock drift in microseconds", + "port-pattern": { + "blurb": "A pattern to select which ports to connect to (NULL = first physical ports)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "40000", - "max": "9223372036854775807", - "min": "1", - "type-name": "gint64", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "enable-last-sample": { - "blurb": "Enable the last-sample property", + "server": { + "blurb": "The Jack server to connect to (NULL = default)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "last-sample": { - "blurb": "The last sample received in the sink", - "construct": false, - "construct-only": false, - "type-name": "GstSample", - "writable": false - }, - "latency-time": { - "blurb": "The minimum amount of data to write in each iteration in microseconds", + "transport": { + "blurb": "Jack transport behaviour of the client", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "10000", - "max": "9223372036854775807", - "min": "1", - "type-name": "gint64", + "controllable": false, + "default": "(none)", + "mutable": "null", + "readable": true, + "type": "GstJackTransport", "writable": true - }, - "max-bitrate": { - "blurb": "The maximum bits per second to render (0 = disabled)", + } + }, + "rank": "primary" + }, + "jackaudiosrc": { + "author": "Tristan Matthews ", + "description": "Captures audio from a JACK server", + "hierarchy": [ + "GstJackAudioSrc", + "GstAudioBaseSrc", + "GstPushSrc", + "GstBaseSrc", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Source/Audio", + "long-name": "Audio Source (Jack)", + "pad-templates": { + "src": { + "caps": "audio/x-raw:\n format: F32LE\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "client": { + "blurb": "Handle for jack client", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", + "controllable": false, + "mutable": "ready", + "readable": true, + "type": "JackClient", "writable": true }, - "max-lateness": { - "blurb": "Maximum number of nanoseconds that a buffer can be late before it is dropped (-1 unlimited)", + "client-name": { + "blurb": "The client name of the Jack instance (NULL = default)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, + "controllable": false, "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "connect": { + "blurb": "Specify how the input ports will be connected", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "auto (1)", + "mutable": "null", + "readable": true, + "type": "GstJackConnect", "writable": true }, "port-pattern": { "blurb": "A pattern to select which ports to connect to (NULL = first physical ports)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "processing-deadline": { - "blurb": "Maximum processing deadline in nanoseconds", - "construct": false, - "construct-only": false, - "default": "20000000", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "provide-clock": { - "blurb": "Provide a clock to be used as the global pipeline clock", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "qos": { - "blurb": "Generate Quality-of-Service events upstream", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "render-delay": { - "blurb": "Additional render delay of the sink in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, "server": { "blurb": "The Jack server to connect to (NULL = default)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "slave-method": { - "blurb": "Algorithm used to match the rate of the masterclock", - "construct": false, - "construct-only": false, - "default": "skew (1)", - "enum": true, - "type-name": "GstAudioBaseSinkSlaveMethod", - "values": [ - { - "desc": "GST_AUDIO_BASE_SINK_SLAVE_RESAMPLE", - "name": "resample", - "value": "0" - }, - { - "desc": "GST_AUDIO_BASE_SINK_SLAVE_SKEW", - "name": "skew", - "value": "1" - }, - { - "desc": "GST_AUDIO_BASE_SINK_SLAVE_NONE", - "name": "none", - "value": "2" - }, - { - "desc": "GST_AUDIO_BASE_SINK_SLAVE_CUSTOM", - "name": "custom", - "value": "3" - } - ], - "writable": true - }, - "stats": { - "blurb": "Sink Statistics", - "construct": false, - "construct-only": false, - "default": "application/x-gst-base-sink-stats, average-rate=(double)0, dropped=(guint64)0, rendered=(guint64)0;", - "type-name": "GstStructure", - "writable": false - }, - "sync": { - "blurb": "Sync on the clock", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "throttle-time": { - "blurb": "The time to keep between rendered buffers (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "transport": { - "blurb": "Jack transport behaviour of the client", - "construct": false, - "construct-only": false, - "default": "(none)", - "type-name": "GstJackTransport", - "values": [ - { - "desc": "Start and stop transport with state changes", - "name": "master", - "value": "0x00000001" - }, - { - "desc": "Follow transport state changes", - "name": "slave", - "value": "0x00000002" - } - ], - "writable": true - }, - "ts-offset": { - "blurb": "Timestamp offset in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "-9223372036854775808", - "type-name": "gint64", - "writable": true - } - }, - "rank": "primary" - }, - "jackaudiosrc": { - "author": "Tristan Matthews ", - "description": "Captures audio from a JACK server", - "hierarchy": [ - "GstJackAudioSrc", - "GstAudioBaseSrc", - "GstPushSrc", - "GstBaseSrc", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Source/Audio", - "long-name": "Audio Source (Jack)", - "name": "jackaudiosrc", - "pad-templates": { - "src": { - "caps": "audio/x-raw:\n format: F32LE\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "actual-buffer-time": { - "blurb": "Actual configured size of audio buffer in microseconds", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": false - }, - "actual-latency-time": { - "blurb": "Actual configured audio latency in microseconds", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": false - }, - "blocksize": { - "blurb": "Size in bytes to read per buffer (-1 = default)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "buffer-time": { - "blurb": "Size of audio buffer in microseconds. This is the maximum amount of data that is buffered in the device and the maximum latency that the source reports. This value might be ignored by the element if necessary; see \"actual-buffer-time\"", - "construct": false, - "construct-only": false, - "default": "200000", - "max": "9223372036854775807", - "min": "1", - "type-name": "gint64", - "writable": true - }, - "client": { - "blurb": "Handle for jack client", - "construct": false, - "construct-only": false, - "type-name": "JackClient", - "writable": true - }, - "client-name": { - "blurb": "The client name of the Jack instance (NULL = default)", - "construct": false, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "connect": { - "blurb": "Specify how the input ports will be connected", - "construct": false, - "construct-only": false, - "default": "auto (1)", - "enum": true, - "type-name": "GstJackConnect", - "values": [ - { - "desc": "Don't automatically connect ports to physical ports", - "name": "none", - "value": "0" - }, - { - "desc": "Automatically connect ports to physical ports", - "name": "auto", - "value": "1" - }, - { - "desc": "Automatically connect ports to as many physical ports as possible", - "name": "auto-forced", - "value": "2" - } - ], - "writable": true - }, - "do-timestamp": { - "blurb": "Apply current stream time to buffers", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "latency-time": { - "blurb": "The minimum amount of data to read in each iteration in microseconds. This is the minimum latency that the source reports. This value might be ignored by the element if necessary; see \"actual-latency-time\"", - "construct": false, - "construct-only": false, - "default": "10000", - "max": "9223372036854775807", - "min": "1", - "type-name": "gint64", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "num-buffers": { - "blurb": "Number of buffers to output before sending EOS (-1 = unlimited)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "port-pattern": { - "blurb": "A pattern to select which ports to connect to (NULL = first physical ports)", - "construct": false, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "provide-clock": { - "blurb": "Provide a clock to be used as the global pipeline clock", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "server": { - "blurb": "The Jack server to connect to (NULL = default)", - "construct": false, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "slave-method": { - "blurb": "Algorithm used to match the rate of the masterclock", - "construct": false, - "construct-only": false, - "default": "skew (2)", - "enum": true, - "type-name": "GstAudioBaseSrcSlaveMethod", - "values": [ - { - "desc": "GST_AUDIO_BASE_SRC_SLAVE_RESAMPLE", - "name": "resample", - "value": "0" - }, - { - "desc": "GST_AUDIO_BASE_SRC_SLAVE_RE_TIMESTAMP", - "name": "re-timestamp", - "value": "1" - }, - { - "desc": "GST_AUDIO_BASE_SRC_SLAVE_SKEW", - "name": "skew", - "value": "2" - }, - { - "desc": "GST_AUDIO_BASE_SRC_SLAVE_NONE", - "name": "none", - "value": "3" - } - ], - "writable": true - }, - "transport": { - "blurb": "Jack transport behaviour of the client", + "transport": { + "blurb": "Jack transport behaviour of the client", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "(none)", - "type-name": "GstJackTransport", - "values": [ - { - "desc": "Start and stop transport with state changes", - "name": "master", - "value": "0x00000001" - }, - { - "desc": "Follow transport state changes", - "name": "slave", - "value": "0x00000002" - } - ], - "writable": true - }, - "typefind": { - "blurb": "Run typefind before negotiating (deprecated, non-functional)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "GstJackTransport", "writable": true } }, @@ -11432,7 +9421,44 @@ }, "filename": "gstjack", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": { + "GstJackConnect": { + "kind": "enum", + "values": [ + { + "desc": "Don't automatically connect ports to physical ports", + "name": "none", + "value": "0" + }, + { + "desc": "Automatically connect ports to physical ports", + "name": "auto", + "value": "1" + }, + { + "desc": "Automatically connect ports to as many physical ports as possible", + "name": "auto-forced", + "value": "2" + } + ] + }, + "GstJackTransport": { + "kind": "flags", + "values": [ + { + "desc": "Start and stop transport with state changes", + "name": "master", + "value": "0x00000001" + }, + { + "desc": "Follow transport state changes", + "name": "slave", + "value": "0x00000002" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -11453,7 +9479,6 @@ ], "klass": "Codec/Decoder/Image", "long-name": "JPEG image decoder", - "name": "jpegdec", "pad-templates": { "sink": { "caps": "image/jpeg:\n", @@ -11469,54 +9494,28 @@ "properties": { "idct-method": { "blurb": "The IDCT algorithm to use", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "ifast (1)", - "enum": true, - "type-name": "GstIDCTMethod", - "values": [ - { - "desc": "Slow but accurate integer algorithm", - "name": "islow", - "value": "0" - }, - { - "desc": "Faster, less accurate integer method", - "name": "ifast", - "value": "1" - }, - { - "desc": "Floating-point: accurate, fast on fast HW", - "name": "float", - "value": "2" - } - ], + "mutable": "null", + "readable": true, + "type": "GstIDCTMethod", "writable": true }, "max-errors": { "blurb": "(Deprecated) Error out after receiving N consecutive decoding errors (-1 = never fail, 0 = automatic, 1 = fail on first error)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "2147483647", "min": "-1", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true } }, @@ -11533,9 +9532,11 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstPreset" + ], "klass": "Codec/Encoder/Image", "long-name": "JPEG image encoder", - "name": "jpegenc", "pad-templates": { "sink": { "caps": "video/x-raw:\n format: { I420, YV12, YUY2, UYVY, Y41B, Y42B, YVYU, Y444, NV21, NV12, RGB, BGR, RGBx, xRGB, BGRx, xBGR, GRAY8 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", @@ -11551,70 +9552,40 @@ "properties": { "idct-method": { "blurb": "The IDCT algorithm to use", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "ifast (1)", - "enum": true, - "type-name": "GstIDCTMethod", - "values": [ - { - "desc": "Slow but accurate integer algorithm", - "name": "islow", - "value": "0" - }, - { - "desc": "Faster, less accurate integer method", - "name": "ifast", - "value": "1" - }, - { - "desc": "Floating-point: accurate, fast on fast HW", - "name": "float", - "value": "2" - } - ], - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events from downstream", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "GstIDCTMethod", "writable": true }, "quality": { "blurb": "Quality of encoding", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "85", "max": "100", "min": "0", - "type-name": "gint", + "mutable": "playing", + "readable": true, + "type": "gint", "writable": true }, "snapshot": { "blurb": "Send EOS after encoding a frame, useful for snapshots", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, @@ -11623,7 +9594,29 @@ }, "filename": "gstjpeg", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": { + "GstIDCTMethod": { + "kind": "enum", + "values": [ + { + "desc": "Slow but accurate integer algorithm", + "name": "islow", + "value": "0" + }, + { + "desc": "Faster, less accurate integer method", + "name": "ifast", + "value": "1" + }, + { + "desc": "Floating-point: accurate, fast on fast HW", + "name": "float", + "value": "2" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -11632,7 +9625,7 @@ "description": "Encode MP3s with LAME", "elements": { "lamemp3enc": { - "author": "Sebastian Dr\u00f6ge ", + "author": "Sebastian Dröge ", "description": "High-quality free MP3 encoder", "hierarchy": [ "GstLameMP3Enc", @@ -11642,9 +9635,11 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstPreset" + ], "klass": "Codec/Encoder/Audio", "long-name": "L.A.M.E. mp3 encoder", - "name": "lamemp3enc", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: S16LE\n layout: interleaved\n rate: { (int)8000, (int)11025, (int)12000, (int)16000, (int)22050, (int)24000, (int)32000, (int)44100, (int)48000 }\n channels: 1\naudio/x-raw:\n format: S16LE\n layout: interleaved\n rate: { (int)8000, (int)11025, (int)12000, (int)16000, (int)22050, (int)24000, (int)32000, (int)44100, (int)48000 }\n channels: 2\n channel-mask: 0x0000000000000003\n", @@ -11660,135 +9655,78 @@ "properties": { "bitrate": { "blurb": "Bitrate in kbit/sec (Only valid if target is bitrate, for CBR one of 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256 or 320)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "128", "max": "320", "min": "8", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "cbr": { "blurb": "Enforce constant bitrate encoding (Only valid if target is bitrate)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "encoding-engine-quality": { "blurb": "Quality/speed of the encoding engine, this does not affect the bitrate!", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "standard (1)", - "enum": true, - "type-name": "GstLameMP3EncEncodingEngineQuality", - "values": [ - { - "desc": "Fast", - "name": "fast", - "value": "0" - }, - { - "desc": "Standard", - "name": "standard", - "value": "1" - }, - { - "desc": "High", - "name": "high", - "value": "2" - } - ], - "writable": true - }, - "hard-resync": { - "blurb": "Perform clipping and sample flushing upon discontinuity", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "GstLameMP3EncEncodingEngineQuality", "writable": true }, - "mark-granule": { - "blurb": "Apply granule semantics to buffer metadata (implies perfect-timestamp)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": false - }, "mono": { "blurb": "Enforce mono encoding", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-timestamp": { - "blurb": "Favour perfect timestamps over tracking upstream timestamps", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "quality": { "blurb": "VBR Quality from 0 to 10, 0 being the best (Only valid if target is quality)", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "4", "max": "9.999", "min": "0", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, "target": { "blurb": "Optimize for quality or bitrate", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "quality (0)", - "enum": true, - "type-name": "GstLameMP3EncTarget", - "values": [ - { - "desc": "Quality", - "name": "quality", - "value": "0" - }, - { - "desc": "Bitrate", - "name": "bitrate", - "value": "1" - } - ], - "writable": true - }, - "tolerance": { - "blurb": "Consider discontinuity if timestamp jitter/imperfection exceeds tolerance (ns)", - "construct": false, - "construct-only": false, - "default": "40000000", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "GstLameMP3EncTarget", "writable": true } }, @@ -11797,7 +9735,44 @@ }, "filename": "gstlame", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": { + "GstLameMP3EncEncodingEngineQuality": { + "kind": "enum", + "values": [ + { + "desc": "Fast", + "name": "fast", + "value": "0" + }, + { + "desc": "Standard", + "name": "standard", + "value": "1" + }, + { + "desc": "High", + "name": "high", + "value": "2" + } + ] + }, + "GstLameMP3EncTarget": { + "kind": "enum", + "values": [ + { + "desc": "Quality", + "name": "quality", + "value": "0" + }, + { + "desc": "Bitrate", + "name": "bitrate", + "value": "1" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -11818,7 +9793,6 @@ ], "klass": "Filter/Analyzer/Audio", "long-name": "Level", - "name": "level", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: { S8, S16LE, S32LE, F32LE, F64LE }\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", @@ -11834,72 +9808,68 @@ "properties": { "interval": { "blurb": "Interval of time between message posts (in nanoseconds)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "100000000", "max": "18446744073709551615", "min": "1", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "message": { "blurb": "Post a 'level' message for each passed interval (deprecated, use the post-messages property instead)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "peak-falloff": { "blurb": "Decay rate of decay peak after TTL (in dB/sec)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "10", "max": "1.79769e+308", "min": "0", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, "peak-ttl": { "blurb": "Time To Live of decay peak before it falls back (in nanoseconds)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "300000000", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "post-messages": { "blurb": "Whether to post a 'level' element message on the bus for each passed interval", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, @@ -11908,7 +9878,8 @@ }, "filename": "gstlevel", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -11928,7 +9899,6 @@ ], "klass": "Codec/Demuxer", "long-name": "Matroska demuxer", - "name": "matroskademux", "pad-templates": { "audio_%%u": { "caps": "ANY", @@ -11954,60 +9924,35 @@ "properties": { "max-backtrack-distance": { "blurb": "Maximum backtrack distance in seconds when seeking without and index in pull mode and search for a keyframe (0 = disable backtracking).", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "30", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "max-gap-time": { "blurb": "The demuxer sends out segment events for skipping gaps longer than this (0 = disabled).", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "2000000000", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true } }, "rank": "primary", - "signals": { - "no-more-pads": { - "args": [], - "retval": "void" - }, - "pad-added": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "pad-removed": { - "args": [ - "GstPad" - ], - "retval": "void" - } - } + "signals": {} }, "matroskamux": { "author": "GStreamer maintainers ", @@ -12019,9 +9964,12 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstTagSetter", + "GstTocSetter" + ], "klass": "Codec/Muxer", "long-name": "Matroska muxer", - "name": "matroskamux", "pad-templates": { "audio_%%u": { "caps": "audio/mpeg:\n mpegversion: 1\n layer: [ 1, 3 ]\n channels: [ 1, 2147483647 ]\n rate: [ 1, 2147483647 ]\naudio/mpeg:\n mpegversion: { (int)2, (int)4 }\n stream-format: raw\n channels: [ 1, 2147483647 ]\n rate: [ 1, 2147483647 ]\naudio/x-ac3:\n channels: [ 1, 2147483647 ]\n rate: [ 1, 2147483647 ]\naudio/x-eac3:\n channels: [ 1, 2147483647 ]\n rate: [ 1, 2147483647 ]\naudio/x-dts:\n channels: [ 1, 2147483647 ]\n rate: [ 1, 2147483647 ]\naudio/x-vorbis:\n channels: [ 1, 2147483647 ]\n rate: [ 1, 2147483647 ]\naudio/x-flac:\n channels: [ 1, 2147483647 ]\n rate: [ 1, 2147483647 ]\naudio/x-opus:\naudio/x-speex:\n channels: [ 1, 2147483647 ]\n rate: [ 1, 2147483647 ]\naudio/x-raw:\n format: { U8, S16BE, S16LE, S24BE, S24LE, S32BE, S32LE, F32LE, F64LE }\n layout: interleaved\n channels: [ 1, 2147483647 ]\n rate: [ 1, 2147483647 ]\naudio/x-tta:\n width: { (int)8, (int)16, (int)24 }\n channels: { (int)1, (int)2 }\n rate: [ 8000, 96000 ]\naudio/x-pn-realaudio:\n raversion: { (int)1, (int)2, (int)8 }\n channels: [ 1, 2147483647 ]\n rate: [ 1, 2147483647 ]\naudio/x-wma:\n wmaversion: [ 1, 3 ]\n block_align: [ 0, 65535 ]\n bitrate: [ 0, 524288 ]\n channels: [ 1, 2147483647 ]\n rate: [ 1, 2147483647 ]\naudio/x-alaw:\n channels: { (int)1, (int)2 }\n rate: [ 8000, 192000 ]\naudio/x-mulaw:\n channels: { (int)1, (int)2 }\n rate: [ 8000, 192000 ]\naudio/x-adpcm:\n layout: dvi\n block_align: [ 64, 8192 ]\n channels: { (int)1, (int)2 }\n rate: [ 8000, 96000 ]\naudio/G722:\n channels: 1\n rate: 16000\naudio/x-adpcm:\n layout: g726\n channels: 1\n rate: 8000\n", @@ -12039,100 +9987,127 @@ "presence": "request" }, "video_%%u": { - "caps": "video/mpeg:\n mpegversion: { (int)1, (int)2, (int)4 }\n systemstream: false\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h264:\n stream-format: avc\n alignment: au\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h265:\n stream-format: hvc1\n alignment: au\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-divx:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-huffyuv:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-dv:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h263:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-msmpeg:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nimage/jpeg:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-theora:\nvideo/x-dirac:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-pn-realvideo:\n rmversion: [ 1, 4 ]\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-vp8:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-vp9:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-raw:\n format: { YUY2, I420, YV12, UYVY, AYUV, GRAY8, BGR, RGB }\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-prores:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-wmv:\n wmvversion: [ 1, 3 ]\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-av1:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\n", + "caps": "video/mpeg:\n mpegversion: { (int)1, (int)2, (int)4 }\n systemstream: false\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h264:\n stream-format: avc\n alignment: au\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h265:\n stream-format: hvc1\n alignment: au\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-divx:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-huffyuv:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-dv:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-h263:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-msmpeg:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nimage/jpeg:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-theora:\nvideo/x-dirac:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-pn-realvideo:\n rmversion: [ 1, 4 ]\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-vp8:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-vp9:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-raw:\n format: { YUY2, I420, YV12, UYVY, AYUV, GRAY8, BGR, RGB }\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-prores:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-wmv:\n wmvversion: [ 1, 3 ]\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-av1:\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\nvideo/x-ffv:\n ffversion: 1\n width: [ 16, 2147483647 ]\n height: [ 16, 2147483647 ]\n", "direction": "sink", "presence": "request" } }, "properties": { + "creation-time": { + "blurb": "Date and time of creation. This will be used for the DateUTC field. NULL means that the current time will be used.", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GDateTime", + "writable": true + }, "max-cluster-duration": { "blurb": "A new cluster will be created if its duration exceeds this value. 0 means no maximum duration.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "65535000000", "max": "9223372036854775807", "min": "0", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gint64", "writable": true }, "min-cluster-duration": { "blurb": "Desired cluster duration as nanoseconds. A new cluster will be created irrespective of this property if a force key unit event is received. 0 means create a new cluster for each video keyframe or for each audio buffer in audio only streams.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "500000000", "max": "9223372036854775807", "min": "0", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gint64", "writable": true }, "min-index-interval": { "blurb": "An index entry is created every so many nanoseconds.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "9223372036854775807", "min": "0", - "type-name": "gint64", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gint64", "writable": true }, "offset-to-zero": { "blurb": "Offsets all streams so that the earliest stream starts at 0.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "streamable": { "blurb": "If set to true, the output should be as if it is to be streamed and hence no indexes written or duration written.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "timecodescale": { "blurb": "TimecodeScale used to calculate the Raw Timecode of a Block", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "1000000", "max": "1000000000", "min": "1", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gint64", "writable": true }, "version": { "blurb": "This parameter determines what Matroska features can be used.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "2", "max": "2", "min": "1", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "writing-app": { "blurb": "The name the application that creates the matroska file.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "GStreamer Matroska muxer", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true } }, @@ -12150,7 +10125,6 @@ ], "klass": "Codec/Parser", "long-name": "Matroska parser", - "name": "matroskaparse", "pad-templates": { "sink": { "caps": "audio/x-matroska:\nvideo/x-matroska:\nvideo/x-matroska-3d:\naudio/webm:\nvideo/webm:\n", @@ -12163,24 +10137,6 @@ "presence": "always" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, "rank": "none" }, "webmmux": { @@ -12194,9 +10150,12 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstTagSetter", + "GstTocSetter" + ], "klass": "Codec/Muxer", "long-name": "WebM muxer", - "name": "webmmux", "pad-templates": { "audio_%%u": { "caps": "audio/x-vorbis:\n channels: [ 1, 2147483647 ]\n rate: [ 1, 2147483647 ]\naudio/x-opus:\n channels: [ 1, 2147483647 ]\n rate: [ 1, 2147483647 ]\n", @@ -12219,104 +10178,14 @@ "presence": "request" } }, - "properties": { - "max-cluster-duration": { - "blurb": "A new cluster will be created if its duration exceeds this value. 0 means no maximum duration.", - "construct": false, - "construct-only": false, - "default": "65535000000", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "min-cluster-duration": { - "blurb": "Desired cluster duration as nanoseconds. A new cluster will be created irrespective of this property if a force key unit event is received. 0 means create a new cluster for each video keyframe or for each audio buffer in audio only streams.", - "construct": false, - "construct-only": false, - "default": "500000000", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "min-index-interval": { - "blurb": "An index entry is created every so many nanoseconds.", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "offset-to-zero": { - "blurb": "Offsets all streams so that the earliest stream starts at 0.", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "streamable": { - "blurb": "If set to true, the output should be as if it is to be streamed and hence no indexes written or duration written.", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "timecodescale": { - "blurb": "TimecodeScale used to calculate the Raw Timecode of a Block", - "construct": false, - "construct-only": false, - "default": "1000000", - "max": "1000000000", - "min": "1", - "type-name": "gint64", - "writable": true - }, - "version": { - "blurb": "This parameter determines what Matroska features can be used.", - "construct": false, - "construct-only": false, - "default": "2", - "max": "2", - "min": "1", - "type-name": "gint", - "writable": true - }, - "writing-app": { - "blurb": "The name the application that creates the matroska file.", - "construct": false, - "construct-only": false, - "default": "GStreamer Matroska muxer", - "type-name": "gchararray", - "writable": true - } - }, + "properties": {}, "rank": "primary" } }, "filename": "gstmatroska", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -12336,7 +10205,6 @@ ], "klass": "Visualization", "long-name": "Monoscope", - "name": "monoscope", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: S16LE\n rate: [ 8000, 96000 ]\n channels: 1\n layout: interleaved\n", @@ -12349,30 +10217,13 @@ "presence": "always" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, "rank": "none" } }, "filename": "gstmonoscope", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -12393,7 +10244,6 @@ ], "klass": "Codec/Decoder/Audio", "long-name": "mpg123 mp3 decoder", - "name": "mpg123audiodec", "pad-templates": { "sink": { "caps": "audio/mpeg:\n mpegversion: 1\n layer: [ 1, 3 ]\n rate: { (int)8000, (int)11025, (int)12000, (int)16000, (int)22050, (int)24000, (int)32000, (int)44100, (int)48000 }\n channels: [ 1, 2 ]\n parsed: true\n", @@ -12406,58 +10256,14 @@ "presence": "always" } }, - "properties": { - "min-latency": { - "blurb": "Aggregate output data to a minimum of latency time (ns)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "plc": { - "blurb": "Perform packet loss concealment (if supported)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "tolerance": { - "blurb": "Perfect ts while timestamp jitter/imperfection within tolerance (ns)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - } - }, + "properties": {}, "rank": "marginal" } }, "filename": "gstmpg123", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -12478,7 +10284,6 @@ ], "klass": "Codec/Decoder/Audio", "long-name": "Mu Law audio decoder", - "name": "mulawdec", "pad-templates": { "sink": { "caps": "audio/x-mulaw:\n rate: [ 8000, 192000 ]\n channels: [ 1, 2 ]\n", @@ -12491,52 +10296,7 @@ "presence": "always" } }, - "properties": { - "min-latency": { - "blurb": "Aggregate output data to a minimum of latency time (ns)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "plc": { - "blurb": "Perform packet loss concealment (if supported)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "tolerance": { - "blurb": "Perfect ts while timestamp jitter/imperfection within tolerance (ns)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - } - }, + "properties": {}, "rank": "primary" }, "mulawenc": { @@ -12550,9 +10310,11 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstPreset" + ], "klass": "Codec/Encoder/Audio", "long-name": "Mu Law audio encoder", - "name": "mulawenc", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: S16LE\n layout: interleaved\n rate: [ 8000, 192000 ]\n channels: [ 1, 2 ]\n", @@ -12565,71 +10327,103 @@ "presence": "always" } }, + "properties": {}, + "rank": "primary" + } + }, + "filename": "gstmulaw", + "license": "LGPL", + "other-types": {}, + "package": "GStreamer Good Plug-ins", + "source": "gst-plugins-good", + "tracers": {}, + "url": "Unknown package origin" + }, + "multifile": { + "description": "Reads/Writes buffers from/to sequentially named files", + "elements": { + "imagesequencesrc": { + "author": "Cesar Fabian Orccon Chipana \nThibault Saunier ", + "description": "Create a video stream from a sequence of image files", + "hierarchy": [ + "GstImageSequenceSrc", + "GstPushSrc", + "GstBaseSrc", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstURIHandler" + ], + "klass": "Source/File/Video", + "long-name": "Image Sequence Source", + "pad-templates": { + "src": { + "caps": "ANY", + "direction": "src", + "presence": "always" + } + }, "properties": { - "hard-resync": { - "blurb": "Perform clipping and sample flushing upon discontinuity", + "framerate": { + "blurb": "The output framerate.", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "30/1", + "max": "2147483647/1", + "min": "1/1", + "mutable": "null", + "readable": false, + "type": "GstFraction", "writable": true }, - "mark-granule": { - "blurb": "Apply granule semantics to buffer metadata (implies perfect-timestamp)", + "location": { + "blurb": "Pattern to create file names of input files. File names are created by calling sprintf() with the pattern and the current index.", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": false - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, + "controllable": false, "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "perfect-timestamp": { - "blurb": "Favour perfect timestamps over tracking upstream timestamps", + "start-index": { + "blurb": "Start value of index. The initial value of index can be set either by setting index or start-index. When the end of the loop is reached, the index will be set to the value start-index.", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "0", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "tolerance": { - "blurb": "Consider discontinuity if timestamp jitter/imperfection exceeds tolerance (ns)", + "stop-index": { + "blurb": "Stop value of index. The special value -1 means no stop.", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "40000000", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", + "controllable": false, + "default": "-1", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true } }, - "rank": "primary" - } - }, - "filename": "gstmulaw", - "license": "LGPL", - "package": "GStreamer Good Plug-ins git", - "source": "gst-plugins-good", - "tracers": {}, - "url": "Unknown package origin" - }, - "multifile": { - "description": "Reads/Writes buffers from/to sequentially named files", - "elements": { + "rank": "none" + }, "multifilesink": { "author": "David Schleef ", "description": "Write buffers to a sequentially named set of files", @@ -12643,7 +10437,6 @@ ], "klass": "Sink/File", "long-name": "Multi-File Sink", - "name": "multifilesink", "pad-templates": { "sink": { "caps": "ANY", @@ -12654,240 +10447,106 @@ "properties": { "aggregate-gops": { "blurb": "Whether to aggregate GOPs and process them as a whole without splitting", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", - "writable": true - }, - "async": { - "blurb": "Go asynchronously to PAUSED", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "blocksize": { - "blurb": "Size in bytes to pull per buffer (0 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "enable-last-sample": { - "blurb": "Enable the last-sample property", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "index": { "blurb": "Index to use with location property to create file names. The index is incremented by one for each buffer written.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "2147483647", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "last-sample": { - "blurb": "The last sample received in the sink", - "construct": false, - "construct-only": false, - "type-name": "GstSample", - "writable": false - }, "location": { "blurb": "Location of the file to write", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "%%05d", - "type-name": "gchararray", - "writable": true - }, - "max-bitrate": { - "blurb": "The maximum bits per second to render (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, "max-file-duration": { "blurb": "Maximum file duration before starting a new file in max-duration mode (in nanoseconds)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "18446744073709551615", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "max-file-size": { "blurb": "Maximum file size before starting a new file in max-size mode", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "2147483648", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "max-files": { "blurb": "Maximum number of files to keep on disk. Once the maximum is reached,old files start to be deleted to make room for new ones.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", - "writable": true - }, - "max-lateness": { - "blurb": "Maximum number of nanoseconds that a buffer can be late before it is dropped (-1 unlimited)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "next-file": { "blurb": "When to start a new file", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "buffer (0)", - "enum": true, - "type-name": "GstMultiFileSinkNext", - "values": [ - { - "desc": "New file for each buffer", - "name": "buffer", - "value": "0" - }, - { - "desc": "New file after each discontinuity", - "name": "discont", - "value": "1" - }, - { - "desc": "New file at each key frame (Useful for MPEG-TS segmenting)", - "name": "key-frame", - "value": "2" - }, - { - "desc": "New file after a force key unit event", - "name": "key-unit-event", - "value": "3" - }, - { - "desc": "New file when the configured maximum file size would be exceeded with the next buffer or buffer list", - "name": "max-size", - "value": "4" - }, - { - "desc": "New file when the configured maximum file duration would be exceeded with the next buffer or buffer list", - "name": "max-duration", - "value": "5" - } - ], - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "GstMultiFileSinkNext", "writable": true }, "post-messages": { "blurb": "Post a message for each file with information of the buffer", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", - "writable": true - }, - "processing-deadline": { - "blurb": "Maximum processing deadline in nanoseconds", - "construct": false, - "construct-only": false, - "default": "20000000", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "qos": { - "blurb": "Generate Quality-of-Service events upstream", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "render-delay": { - "blurb": "Additional render delay of the sink in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "stats": { - "blurb": "Sink Statistics", - "construct": false, - "construct-only": false, - "default": "application/x-gst-base-sink-stats, average-rate=(double)0, dropped=(guint64)0, rendered=(guint64)0;", - "type-name": "GstStructure", - "writable": false - }, - "sync": { - "blurb": "Sync on the clock", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "throttle-time": { - "blurb": "The time to keep between rendered buffers (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "ts-offset": { - "blurb": "Timestamp offset in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "-9223372036854775808", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, @@ -12905,9 +10564,11 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstURIHandler" + ], "klass": "Source/File", "long-name": "Multi-File Source", - "name": "multifilesrc", "pad-templates": { "src": { "caps": "ANY", @@ -12916,116 +10577,88 @@ } }, "properties": { - "blocksize": { - "blurb": "Size in bytes to read per buffer (-1 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, "caps": { "blurb": "Caps describing the format of the data.", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstCaps", - "writable": true - }, - "do-timestamp": { - "blurb": "Apply current stream time to buffers", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstCaps", "writable": true }, "index": { "blurb": "Index to use with location property to create file names. The index is incremented by one for each buffer read.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "2147483647", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "location": { "blurb": "Pattern to create file names of input files. File names are created by calling sprintf() with the pattern and the current index.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "%%05d", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, "loop": { "blurb": "Whether to repeat from the beginning when all files have been read.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "num-buffers": { - "blurb": "Number of buffers to output before sending EOS (-1 = unlimited)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "start-index": { "blurb": "Start value of index. The initial value of index can be set either by setting index or start-index. When the end of the loop is reached, the index will be set to the value start-index.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "2147483647", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "stop-index": { "blurb": "Stop value of index. The special value -1 means no stop.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "-1", "max": "2147483647", "min": "-1", - "type-name": "gint", - "writable": true - }, - "typefind": { - "blurb": "Run typefind before negotiating (deprecated, non-functional)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true } }, "rank": "none" }, "splitfilesrc": { - "author": "Tim-Philipp M\u00fcller ", + "author": "Tim-Philipp Müller ", "description": "Read a sequentially named set of files as if it was one large file", "hierarchy": [ "GstSplitFileSrc", @@ -13035,9 +10668,11 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstURIHandler" + ], "klass": "Source/File", "long-name": "Split-File Source", - "name": "splitfilesrc", "pad-templates": { "src": { "caps": "ANY", @@ -13046,64 +10681,16 @@ } }, "properties": { - "blocksize": { - "blurb": "Size in bytes to read per buffer (-1 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "do-timestamp": { - "blurb": "Apply current stream time to buffers", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, "location": { "blurb": "Wildcard pattern to match file names of the input files. If the location is an absolute path or contains directory components, only the base file name part will be considered for pattern matching. The results will be sorted.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "num-buffers": { - "blurb": "Number of buffers to output before sending EOS (-1 = unlimited)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "typefind": { - "blurb": "Run typefind before negotiating (deprecated, non-functional)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true } }, @@ -13120,9 +10707,11 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstChildProxy" + ], "klass": "Generic/Bin/Muxer", "long-name": "Split Muxing Bin", - "name": "splitmuxsink", "pad-templates": { "audio_%%u": { "caps": "ANY", @@ -13153,183 +10742,261 @@ "properties": { "alignment-threshold": { "blurb": "Allow non-reference streams to be that many ns before the reference stream", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "ready", + "readable": true, + "type": "guint64", "writable": true }, "async-finalize": { "blurb": "Finalize each fragment asynchronously and start a new one", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", - "writable": true - }, - "async-handling": { - "blurb": "The bin will handle Asynchronous state changes", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "location": { "blurb": "Format string pattern for the location of the files to write (e.g. video%%05d.mp4)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, "max-files": { "blurb": "Maximum number of files to keep on disk. Once the maximum is reached,old files start to be deleted to make room for new ones.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "max-size-bytes": { "blurb": "Max. amount of data per file (in bytes, 0=disable)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "ready", + "readable": true, + "type": "guint64", "writable": true }, "max-size-time": { "blurb": "Max. amount of time per file (in ns, 0=disable)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "ready", + "readable": true, + "type": "guint64", "writable": true }, "max-size-timecode": { "blurb": "Maximum difference in timecode between first and last frame. Separator is assumed to be \":\" everywhere (e.g. 01:00:00:00). Will only be effective if a timecode track is present.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "message-forward": { - "blurb": "Forwards all children messages", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "ready", + "readable": true, + "type": "gchararray", "writable": true }, "mux-overhead": { "blurb": "Extra size overhead of muxing (0.02 = 2%%)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0.02", "max": "1", "min": "0", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, "muxer": { "blurb": "The muxer element to use (NULL = default mp4mux). Valid only for async-finalize = FALSE", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstElement", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstElement", "writable": true }, "muxer-factory": { "blurb": "The muxer element factory to use (default = mp4mux). Valid only for async-finalize = TRUE", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "mp4mux", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, "muxer-pad-map": { "blurb": "A GstStructure specifies the mapping from splitmuxsink sink pads to muxer pads", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstStructure", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstStructure", "writable": true }, - "muxer-properties": { - "blurb": "The muxer element properties to use. Example: {properties,boolean-prop=true,string-prop=\"hi\"}. Valid only for async-finalize = TRUE", + "muxer-preset": { + "blurb": "The muxer preset to use. Valid only for async-finalize = TRUE", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstStructure", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, + "controllable": false, "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "muxer-properties": { + "blurb": "The muxer element properties to use. Example: {properties,boolean-prop=true,string-prop=\"hi\"}. Valid only for async-finalize = TRUE", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstStructure", "writable": true }, "reset-muxer": { "blurb": "Reset the muxer after each segment. Disabling this will not work for most muxers.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "send-keyframe-requests": { "blurb": "Request a keyframe every max-size-time ns to try splitting at that point. Needs max-size-bytes to be 0 in order to be effective.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "ready", + "readable": true, + "type": "gboolean", "writable": true }, "sink": { "blurb": "The sink element (or element chain) to use (NULL = default filesink). Valid only for async-finalize = FALSE", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstElement", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstElement", "writable": true }, "sink-factory": { "blurb": "The sink element factory to use (default = filesink). Valid only for async-finalize = TRUE", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "filesink", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": true + }, + "sink-preset": { + "blurb": "The sink preset to use. Valid only for async-finalize = TRUE", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, "sink-properties": { "blurb": "The sink element properties to use. Example: {properties,boolean-prop=true,string-prop=\"hi\"}. Valid only for async-finalize = TRUE", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstStructure", + "writable": true + }, + "start-index": { + "blurb": "Start value of fragment index.", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstStructure", + "controllable": false, + "default": "0", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "use-robust-muxing": { "blurb": "Check if muxers support robust muxing via the reserved-max-duration and reserved-duration-remaining properties and use them if so. (Only present on qtmux and mp4mux for now). splitmuxsink may then also create new fragments if the reserved header space is about to overflow. Note that for mp4mux and qtmux, reserved-moov-update-period must be set manually by the app to a non-zero value for robust muxing to have an effect.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, @@ -13337,42 +11004,70 @@ "signals": { "format-location": { "args": [ - "guint" + { + "name": "arg0", + "type": "guint" + } ], - "retval": "gchararray" + "return-type": "gchararray", + "when": "last" }, "format-location-full": { "args": [ - "guint", - "GstSample" + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "GstSample" + } ], - "retval": "gchararray" + "return-type": "gchararray", + "when": "last" }, "muxer-added": { "args": [ - "GstElement" + { + "name": "arg0", + "type": "GstElement" + } ], - "retval": "void" + "return-type": "void", + "when": "last" }, "sink-added": { "args": [ - "GstElement" + { + "name": "arg0", + "type": "GstElement" + } ], - "retval": "void" + "return-type": "void", + "when": "last" }, "split-after": { + "action": true, "args": [], - "retval": "void" + "return-type": "void", + "when": "last" }, "split-at-running-time": { + "action": true, "args": [ - "guint64" + { + "name": "arg0", + "type": "guint64" + } ], - "retval": "void" + "return-type": "void", + "when": "last" }, "split-now": { + "action": true, "args": [], - "retval": "void" + "return-type": "void", + "when": "last" } } }, @@ -13387,9 +11082,12 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstChildProxy", + "GstURIHandler" + ], "klass": "Generic/Bin/Demuxer", "long-name": "Split File Demuxing Bin", - "name": "splitmuxsrc", "pad-templates": { "audio_%%u": { "caps": "ANY", @@ -13413,44 +11111,16 @@ } }, "properties": { - "async-handling": { - "blurb": "The bin will handle Asynchronous state changes", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, "location": { "blurb": "Glob pattern for the location of the files to read", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "message-forward": { - "blurb": "Forwards all children messages", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true } }, @@ -13458,30 +11128,52 @@ "signals": { "format-location": { "args": [], - "retval": "GStrv" - }, - "no-more-pads": { - "args": [], - "retval": "void" - }, - "pad-added": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "pad-removed": { - "args": [ - "GstPad" - ], - "retval": "void" + "return-type": "GStrv", + "when": "last" } } } }, "filename": "gstmultifile", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": { + "GstMultiFileSinkNext": { + "kind": "enum", + "values": [ + { + "desc": "New file for each buffer", + "name": "buffer", + "value": "0" + }, + { + "desc": "New file after each discontinuity", + "name": "discont", + "value": "1" + }, + { + "desc": "New file at each key frame (Useful for MPEG-TS segmenting)", + "name": "key-frame", + "value": "2" + }, + { + "desc": "New file after a force key unit event", + "name": "key-unit-event", + "value": "3" + }, + { + "desc": "New file when the configured maximum file size would be exceeded with the next buffer or buffer list", + "name": "max-size", + "value": "4" + }, + { + "desc": "New file when the configured maximum file duration would be exceeded with the next buffer or buffer list", + "name": "max-duration", + "value": "5" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -13501,7 +11193,6 @@ ], "klass": "Codec/Demuxer", "long-name": "Multipart demuxer", - "name": "multipartdemux", "pad-templates": { "sink": { "caps": "multipart/x-mixed-replace:\n", @@ -13517,56 +11208,31 @@ "properties": { "boundary": { "blurb": "The boundary string separating data, automatic if NULL", + "conditionally-available": false, "construct": true, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, "single-stream": { "blurb": "Assume that there is only one stream whose content-type will not change and emit no-more-pads as soon as the first boundary content is parsed, decoded, and pads are linked", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, "rank": "primary", - "signals": { - "no-more-pads": { - "args": [], - "retval": "void" - }, - "pad-added": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "pad-removed": { - "args": [ - "GstPad" - ], - "retval": "void" - } - } + "signals": {} }, "multipartmux": { "author": "Wim Taymans ", @@ -13580,7 +11246,6 @@ ], "klass": "Codec/Muxer", "long-name": "Multipart muxer", - "name": "multipartmux", "pad-templates": { "sink_%%u": { "caps": "ANY", @@ -13596,26 +11261,14 @@ "properties": { "boundary": { "blurb": "Boundary string", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "ThisRandomString", - "type-name": "gchararray", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true } }, @@ -13624,7 +11277,8 @@ }, "filename": "gstmultipart", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -13646,7 +11300,6 @@ ], "klass": "Filter/Effect/Video", "long-name": "Video navigation test", - "name": "navigationtest", "pad-templates": { "sink": { "caps": "video/x-raw:\n format: I420\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", @@ -13659,38 +11312,14 @@ "presence": "always" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - } - }, + "properties": {}, "rank": "none" } }, "filename": "gstnavigationtest", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -13699,7 +11328,7 @@ "description": "Open Sound System (OSS) version 4 support for GStreamer", "elements": { "oss4sink": { - "author": "Tim-Philipp M\u00fcller ", + "author": "Tim-Philipp Müller ", "description": "Output to a sound card via OSS version 4", "hierarchy": [ "GstOss4Sink", @@ -13711,9 +11340,11 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstStreamVolume" + ], "klass": "Sink/Audio", "long-name": "OSS v4 Audio Sink", - "name": "oss4sink", "pad-templates": { "sink": { "caps": "audio/x-alaw:\n rate: [ 1, 192000 ]\n channels: [ 1, 4096 ]\naudio/x-mulaw:\n rate: [ 1, 192000 ]\n channels: [ 1, 4096 ]\naudio/x-raw:\n format: { S32LE, S32BE, S24_32LE, S24_32BE, S24LE, S16LE, S16BE, U16LE, U16BE, S8, U8 }\n layout: interleaved\n rate: [ 1, 192000 ]\n channels: [ 1, 4096 ]\n", @@ -13722,278 +11353,165 @@ } }, "properties": { - "alignment-threshold": { - "blurb": "Timestamp alignment threshold in nanoseconds", - "construct": false, - "construct-only": false, - "default": "40000000", - "max": "18446744073709551614", - "min": "1", - "type-name": "guint64", - "writable": true - }, - "async": { - "blurb": "Go asynchronously to PAUSED", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "blocksize": { - "blurb": "Size in bytes to pull per buffer (0 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "buffer-time": { - "blurb": "Size of audio buffer in microseconds, this is the minimum latency that the sink reports", - "construct": false, - "construct-only": false, - "default": "200000", - "max": "9223372036854775807", - "min": "1", - "type-name": "gint64", - "writable": true - }, - "can-activate-pull": { - "blurb": "Allow pull-based scheduling", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, "device": { "blurb": "OSS4 device (e.g. /dev/oss/hdaudio0/pcm0 or /dev/dspN) (NULL = use first available playback device)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, "device-name": { "blurb": "Human-readable name of the sound device", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": false }, - "discont-wait": { - "blurb": "Window of time in nanoseconds to wait before creating a discontinuity", - "construct": false, - "construct-only": false, - "default": "1000000000", - "max": "18446744073709551614", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "drift-tolerance": { - "blurb": "Tolerance for clock drift in microseconds", - "construct": false, - "construct-only": false, - "default": "40000", - "max": "9223372036854775807", - "min": "1", - "type-name": "gint64", - "writable": true - }, - "enable-last-sample": { - "blurb": "Enable the last-sample property", + "mute": { + "blurb": "Mute state of this stream", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", - "writable": true - }, - "last-sample": { - "blurb": "The last sample received in the sink", - "construct": false, - "construct-only": false, - "type-name": "GstSample", - "writable": false - }, - "latency-time": { - "blurb": "The minimum amount of data to write in each iteration in microseconds", - "construct": false, - "construct-only": false, - "default": "10000", - "max": "9223372036854775807", - "min": "1", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "max-bitrate": { - "blurb": "The maximum bits per second to render (0 = disabled)", + "volume": { + "blurb": "Linear volume of this stream, 1.0=100%%", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "18446744073709551615", + "controllable": false, + "default": "1", + "max": "10", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true - }, - "max-lateness": { - "blurb": "Maximum number of nanoseconds that a buffer can be late before it is dropped (-1 unlimited)", + } + }, + "rank": "secondary + 1" + }, + "oss4src": { + "author": "Tim-Philipp Müller ", + "description": "Capture from a sound card via OSS version 4", + "hierarchy": [ + "GstOss4Source", + "GstAudioSrc", + "GstAudioBaseSrc", + "GstPushSrc", + "GstBaseSrc", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Source/Audio", + "long-name": "OSS v4 Audio Source", + "pad-templates": { + "src": { + "caps": "audio/x-alaw:\n rate: [ 1, 192000 ]\n channels: [ 1, 4096 ]\naudio/x-mulaw:\n rate: [ 1, 192000 ]\n channels: [ 1, 4096 ]\naudio/x-raw:\n format: { S32LE, S32BE, S24_32LE, S24_32BE, S24LE, S16LE, S16BE, U16LE, U16BE, S8, U8 }\n layout: interleaved\n rate: [ 1, 192000 ]\n channels: [ 1, 4096 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "device": { + "blurb": "OSS4 device (e.g. /dev/oss/hdaudio0/pcm0 or /dev/dspN) (NULL = use first available device)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "mute": { - "blurb": "Mute state of this stream", + "device-name": { + "blurb": "Human-readable name of the sound device", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, + "controllable": false, "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "processing-deadline": { - "blurb": "Maximum processing deadline in nanoseconds", - "construct": false, - "construct-only": false, - "default": "20000000", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "provide-clock": { - "blurb": "Provide a clock to be used as the global pipeline clock", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "qos": { - "blurb": "Generate Quality-of-Service events upstream", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "render-delay": { - "blurb": "Additional render delay of the sink in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "slave-method": { - "blurb": "Algorithm used to match the rate of the masterclock", - "construct": false, - "construct-only": false, - "default": "skew (1)", - "enum": true, - "type-name": "GstAudioBaseSinkSlaveMethod", - "values": [ - { - "desc": "GST_AUDIO_BASE_SINK_SLAVE_RESAMPLE", - "name": "resample", - "value": "0" - }, - { - "desc": "GST_AUDIO_BASE_SINK_SLAVE_SKEW", - "name": "skew", - "value": "1" - }, - { - "desc": "GST_AUDIO_BASE_SINK_SLAVE_NONE", - "name": "none", - "value": "2" - }, - { - "desc": "GST_AUDIO_BASE_SINK_SLAVE_CUSTOM", - "name": "custom", - "value": "3" - } - ], - "writable": true - }, - "stats": { - "blurb": "Sink Statistics", - "construct": false, - "construct-only": false, - "default": "application/x-gst-base-sink-stats, average-rate=(double)0, dropped=(guint64)0, rendered=(guint64)0;", - "type-name": "GstStructure", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": false - }, - "sync": { - "blurb": "Sync on the clock", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "throttle-time": { - "blurb": "The time to keep between rendered buffers (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "ts-offset": { - "blurb": "Timestamp offset in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "-9223372036854775808", - "type-name": "gint64", - "writable": true - }, - "volume": { - "blurb": "Linear volume of this stream, 1.0=100%%", + } + }, + "rank": "secondary + 1" + } + }, + "filename": "gstoss4", + "license": "LGPL", + "other-types": {}, + "package": "GStreamer Good Plug-ins", + "source": "gst-plugins-good", + "tracers": {}, + "url": "Unknown package origin" + }, + "ossaudio": { + "description": "OSS (Open Sound System) support for GStreamer", + "elements": { + "osssink": { + "author": "Erik Walthinsen , Wim Taymans ", + "description": "Output to a sound card via OSS", + "hierarchy": [ + "GstOssSink", + "GstAudioSink", + "GstAudioBaseSink", + "GstBaseSink", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Sink/Audio", + "long-name": "Audio Sink (OSS)", + "pad-templates": { + "sink": { + "caps": "audio/x-raw:\n format: { S16LE, U16LE, S8, U8 }\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: 1\naudio/x-raw:\n format: { S16LE, U16LE, S8, U8 }\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: 2\n channel-mask: 0x0000000000000003\n", + "direction": "sink", + "presence": "always" + } + }, + "properties": { + "device": { + "blurb": "OSS device (usually /dev/dspN)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "1", - "max": "10", - "min": "0", - "type-name": "gdouble", + "controllable": false, + "default": "/dev/dsp", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true } }, - "rank": "secondary + 1" + "rank": "secondary" }, - "oss4src": { - "author": "Tim-Philipp M\u00fcller ", - "description": "Capture from a sound card via OSS version 4", + "osssrc": { + "author": "Erik Walthinsen , Wim Taymans ", + "description": "Capture from a sound card via OSS", "hierarchy": [ - "GstOss4Source", + "GstOssSrc", "GstAudioSrc", "GstAudioBaseSrc", "GstPushSrc", @@ -14004,1918 +11522,2545 @@ "GObject" ], "klass": "Source/Audio", - "long-name": "OSS v4 Audio Source", - "name": "oss4src", + "long-name": "Audio Source (OSS)", "pad-templates": { "src": { - "caps": "audio/x-alaw:\n rate: [ 1, 192000 ]\n channels: [ 1, 4096 ]\naudio/x-mulaw:\n rate: [ 1, 192000 ]\n channels: [ 1, 4096 ]\naudio/x-raw:\n format: { S32LE, S32BE, S24_32LE, S24_32BE, S24LE, S16LE, S16BE, U16LE, U16BE, S8, U8 }\n layout: interleaved\n rate: [ 1, 192000 ]\n channels: [ 1, 4096 ]\n", + "caps": "audio/x-raw:\n format: { S16LE, U16LE, S8, U8 }\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: 1\naudio/x-raw:\n format: { S16LE, U16LE, S8, U8 }\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: 2\n channel-mask: 0x0000000000000003\n", "direction": "src", "presence": "always" } }, "properties": { - "actual-buffer-time": { - "blurb": "Actual configured size of audio buffer in microseconds", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": false - }, - "actual-latency-time": { - "blurb": "Actual configured audio latency in microseconds", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": false - }, - "blocksize": { - "blurb": "Size in bytes to read per buffer (-1 = default)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "buffer-time": { - "blurb": "Size of audio buffer in microseconds. This is the maximum amount of data that is buffered in the device and the maximum latency that the source reports. This value might be ignored by the element if necessary; see \"actual-buffer-time\"", - "construct": false, - "construct-only": false, - "default": "200000", - "max": "9223372036854775807", - "min": "1", - "type-name": "gint64", - "writable": true - }, "device": { - "blurb": "OSS4 device (e.g. /dev/oss/hdaudio0/pcm0 or /dev/dspN) (NULL = use first available device)", + "blurb": "OSS device (usually /dev/dspN)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "NULL", - "type-name": "gchararray", + "controllable": false, + "default": "/dev/dsp", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, "device-name": { "blurb": "Human-readable name of the sound device", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "NULL", - "type-name": "gchararray", + "controllable": false, + "default": "", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": false - }, - "do-timestamp": { - "blurb": "Apply current stream time to buffers", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "latency-time": { - "blurb": "The minimum amount of data to read in each iteration in microseconds. This is the minimum latency that the source reports. This value might be ignored by the element if necessary; see \"actual-latency-time\"", - "construct": false, - "construct-only": false, - "default": "10000", - "max": "9223372036854775807", - "min": "1", - "type-name": "gint64", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "num-buffers": { - "blurb": "Number of buffers to output before sending EOS (-1 = unlimited)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "provide-clock": { - "blurb": "Provide a clock to be used as the global pipeline clock", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "slave-method": { - "blurb": "Algorithm used to match the rate of the masterclock", - "construct": false, - "construct-only": false, - "default": "skew (2)", - "enum": true, - "type-name": "GstAudioBaseSrcSlaveMethod", - "values": [ - { - "desc": "GST_AUDIO_BASE_SRC_SLAVE_RESAMPLE", - "name": "resample", - "value": "0" - }, - { - "desc": "GST_AUDIO_BASE_SRC_SLAVE_RE_TIMESTAMP", - "name": "re-timestamp", - "value": "1" - }, - { - "desc": "GST_AUDIO_BASE_SRC_SLAVE_SKEW", - "name": "skew", - "value": "2" - }, - { - "desc": "GST_AUDIO_BASE_SRC_SLAVE_NONE", - "name": "none", - "value": "3" - } - ], - "writable": true - }, - "typefind": { - "blurb": "Run typefind before negotiating (deprecated, non-functional)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true } }, - "rank": "secondary + 1" + "rank": "secondary" } }, - "filename": "gstoss4", + "filename": "gstossaudio", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" }, - "ossaudio": { - "description": "OSS (Open Sound System) support for GStreamer", + "png": { + "description": "PNG plugin library", "elements": { - "osssink": { - "author": "Erik Walthinsen , Wim Taymans ", - "description": "Output to a sound card via OSS", + "pngdec": { + "author": "Wim Taymans ", + "description": "Decode a png video frame to a raw image", "hierarchy": [ - "GstOssSink", - "GstAudioSink", - "GstAudioBaseSink", - "GstBaseSink", + "GstPngDec", + "GstVideoDecoder", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Sink/Audio", - "long-name": "Audio Sink (OSS)", - "name": "osssink", + "klass": "Codec/Decoder/Image", + "long-name": "PNG image decoder", "pad-templates": { "sink": { - "caps": "audio/x-raw:\n format: { S16LE, U16LE, S8, U8 }\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: 1\naudio/x-raw:\n format: { S16LE, U16LE, S8, U8 }\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: 2\n channel-mask: 0x0000000000000003\n", + "caps": "image/png:\n", "direction": "sink", "presence": "always" + }, + "src": { + "caps": "video/x-raw:\n format: { RGBA, RGB, ARGB64, GRAY8, GRAY16_BE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" } }, - "properties": { - "alignment-threshold": { - "blurb": "Timestamp alignment threshold in nanoseconds", - "construct": false, - "construct-only": false, - "default": "40000000", - "max": "18446744073709551614", - "min": "1", - "type-name": "guint64", - "writable": true - }, - "async": { - "blurb": "Go asynchronously to PAUSED", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true + "properties": {}, + "rank": "primary" + }, + "pngenc": { + "author": "Jeremy SIMON ", + "description": "Encode a video frame to a .png image", + "hierarchy": [ + "GstPngEnc", + "GstVideoEncoder", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstPreset" + ], + "klass": "Codec/Encoder/Image", + "long-name": "PNG image encoder", + "pad-templates": { + "sink": { + "caps": "video/x-raw:\n format: { RGBA, RGB, GRAY8, GRAY16_BE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "sink", + "presence": "always" }, - "blocksize": { - "blurb": "Size in bytes to pull per buffer (0 = default)", + "src": { + "caps": "image/png:\n width: [ 16, 1000000 ]\n height: [ 16, 1000000 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "compression-level": { + "blurb": "PNG compression level", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "4096", - "max": "-1", + "controllable": false, + "default": "6", + "max": "9", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "buffer-time": { - "blurb": "Size of audio buffer in microseconds, this is the minimum latency that the sink reports", + "snapshot": { + "blurb": "Send EOS after encoding a frame, useful for snapshots", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "200000", - "max": "9223372036854775807", - "min": "1", - "type-name": "gint64", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true - }, - "can-activate-pull": { - "blurb": "Allow pull-based scheduling", + } + }, + "rank": "primary" + } + }, + "filename": "gstpng", + "license": "LGPL", + "other-types": {}, + "package": "GStreamer Good Plug-ins", + "source": "gst-plugins-good", + "tracers": {}, + "url": "Unknown package origin" + }, + "pulseaudio": { + "description": "PulseAudio plugin library", + "elements": { + "pulsesink": { + "author": "Lennart Poettering", + "description": "Plays audio to a PulseAudio server", + "hierarchy": [ + "GstPulseSink", + "GstAudioBaseSink", + "GstBaseSink", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstStreamVolume" + ], + "klass": "Sink/Audio", + "long-name": "PulseAudio Audio Sink", + "pad-templates": { + "sink": { + "caps": "audio/x-raw:\n format: { S16LE, S16BE, F32LE, F32BE, S32LE, S32BE, S24LE, S24BE, S24_32LE, S24_32BE, U8 }\n layout: interleaved\n rate: [ 1, 384000 ]\n channels: [ 1, 32 ]\naudio/x-alaw:\n rate: [ 1, 384000 ]\n channels: [ 1, 32 ]\naudio/x-mulaw:\n rate: [ 1, 384000 ]\n channels: [ 1, 32 ]\naudio/x-ac3:\n framed: true\naudio/x-eac3:\n framed: true\naudio/x-dts:\n framed: true\n block-size: { (int)512, (int)1024, (int)2048 }\naudio/mpeg:\n mpegversion: 1\nmpegaudioversion: [ 1, 3 ]\n parsed: true\naudio/mpeg:\n mpegversion: { (int)2, (int)4 }\n framed: true\n stream-format: adts\n", + "direction": "sink", + "presence": "always" + } + }, + "properties": { + "client-name": { + "blurb": "The PulseAudio client name to use", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "gst-hotdoc-plugins-scanner", + "mutable": "ready", + "readable": true, + "type": "gchararray", "writable": true }, - "device": { - "blurb": "OSS device (usually /dev/dspN)", + "current-device": { + "blurb": "The current PulseAudio sink device", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "/dev/dsp", - "type-name": "gchararray", - "writable": true + "controllable": false, + "default": "", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": false }, - "discont-wait": { - "blurb": "Window of time in nanoseconds to wait before creating a discontinuity", + "device": { + "blurb": "The PulseAudio sink device to connect to", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "1000000000", - "max": "18446744073709551614", - "min": "0", - "type-name": "guint64", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "drift-tolerance": { - "blurb": "Tolerance for clock drift in microseconds", + "device-name": { + "blurb": "Human-readable name of the sound device", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "40000", - "max": "9223372036854775807", - "min": "1", - "type-name": "gint64", - "writable": true + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": false }, - "enable-last-sample": { - "blurb": "Enable the last-sample property", + "mute": { + "blurb": "Mute state of this stream", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "last-sample": { - "blurb": "The last sample received in the sink", + "server": { + "blurb": "The PulseAudio server to connect to", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstSample", - "writable": false + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": true }, - "latency-time": { - "blurb": "The minimum amount of data to write in each iteration in microseconds", + "stream-properties": { + "blurb": "list of pulseaudio stream properties", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "10000", - "max": "9223372036854775807", - "min": "1", - "type-name": "gint64", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstStructure", "writable": true }, - "max-bitrate": { - "blurb": "The maximum bits per second to render (0 = disabled)", + "volume": { + "blurb": "Linear volume of this stream, 1.0=100%%", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "18446744073709551615", + "controllable": false, + "default": "1", + "max": "10", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true - }, - "max-lateness": { - "blurb": "Maximum number of nanoseconds that a buffer can be late before it is dropped (-1 unlimited)", + } + }, + "rank": "primary + 10" + }, + "pulsesrc": { + "author": "Lennart Poettering", + "description": "Captures audio from a PulseAudio server", + "hierarchy": [ + "GstPulseSrc", + "GstAudioSrc", + "GstAudioBaseSrc", + "GstPushSrc", + "GstBaseSrc", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstStreamVolume" + ], + "klass": "Source/Audio", + "long-name": "PulseAudio Audio Source", + "pad-templates": { + "src": { + "caps": "audio/x-raw:\n format: { S16LE, S16BE, F32LE, F32BE, S32LE, S32BE, S24LE, S24BE, S24_32LE, S24_32BE, U8 }\n layout: interleaved\n rate: [ 1, 384000 ]\n channels: [ 1, 32 ]\naudio/x-alaw:\n rate: [ 1, 384000 ]\n channels: [ 1, 32 ]\naudio/x-mulaw:\n rate: [ 1, 384000 ]\n channels: [ 1, 32 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "client-name": { + "blurb": "The PulseAudio client_name_to_use", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "default": "gst-hotdoc-plugins-scanner", + "mutable": "ready", + "readable": true, + "type": "gchararray", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "current-device": { + "blurb": "The current PulseAudio source device", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", - "writable": true + "controllable": false, + "default": "", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": false }, - "processing-deadline": { - "blurb": "Maximum processing deadline in nanoseconds", + "device": { + "blurb": "The PulseAudio source device to connect to", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "20000000", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "provide-clock": { - "blurb": "Provide a clock to be used as the global pipeline clock", + "device-name": { + "blurb": "Human-readable name of the sound device", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": false }, - "qos": { - "blurb": "Generate Quality-of-Service events upstream", + "mute": { + "blurb": "Mute state of this stream", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", - "writable": true - }, - "render-delay": { - "blurb": "Additional render delay of the sink in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "slave-method": { - "blurb": "Algorithm used to match the rate of the masterclock", + "server": { + "blurb": "The PulseAudio server to connect to", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "skew (1)", - "enum": true, - "type-name": "GstAudioBaseSinkSlaveMethod", - "values": [ - { - "desc": "GST_AUDIO_BASE_SINK_SLAVE_RESAMPLE", - "name": "resample", - "value": "0" - }, - { - "desc": "GST_AUDIO_BASE_SINK_SLAVE_SKEW", - "name": "skew", - "value": "1" - }, - { - "desc": "GST_AUDIO_BASE_SINK_SLAVE_NONE", - "name": "none", - "value": "2" - }, - { - "desc": "GST_AUDIO_BASE_SINK_SLAVE_CUSTOM", - "name": "custom", - "value": "3" - } - ], + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "stats": { - "blurb": "Sink Statistics", + "source-output-index": { + "blurb": "The index of the PulseAudio source output corresponding to this record stream", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "application/x-gst-base-sink-stats, average-rate=(double)0, dropped=(guint64)0, rendered=(guint64)0;", - "type-name": "GstStructure", + "controllable": false, + "default": "-1", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": false }, - "sync": { - "blurb": "Sync on the clock", + "stream-properties": { + "blurb": "list of pulseaudio stream properties", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstStructure", "writable": true }, - "throttle-time": { - "blurb": "The time to keep between rendered buffers (0 = disabled)", + "volume": { + "blurb": "Linear volume of this stream, 1.0=100%%", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "18446744073709551615", + "controllable": false, + "default": "1", + "max": "10", "min": "0", - "type-name": "guint64", - "writable": true - }, - "ts-offset": { - "blurb": "Timestamp offset in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "-9223372036854775808", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true } }, - "rank": "secondary" - }, - "osssrc": { - "author": "Erik Walthinsen , Wim Taymans ", - "description": "Capture from a sound card via OSS", + "rank": "primary + 10" + } + }, + "filename": "gstpulseaudio", + "license": "LGPL", + "other-types": {}, + "package": "GStreamer Good Plug-ins", + "source": "gst-plugins-good", + "tracers": {}, + "url": "Unknown package origin" + }, + "qmlgl": { + "description": "Qt gl plugin", + "elements": { + "qmlgloverlay": { + "author": "Matthew Waters ", + "description": "A filter that renders a QML scene onto a video stream", "hierarchy": [ - "GstOssSrc", - "GstAudioSrc", - "GstAudioBaseSrc", - "GstPushSrc", - "GstBaseSrc", + "GstQtOverlay", + "GstGLFilter", + "GstGLBaseFilter", + "GstBaseTransform", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Source/Audio", - "long-name": "Audio Source (OSS)", - "name": "osssrc", + "klass": "Filter/QML/Overlay", + "long-name": "Qt Video Overlay", "pad-templates": { + "sink": { + "caps": "video/x-raw(ANY):\n format: RGBA\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n texture-target: 2D\n\nvideo/x-raw(memory:GLMemory):\n format: RGBA\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n texture-target: 2D\n", + "direction": "sink", + "presence": "always" + }, "src": { - "caps": "audio/x-raw:\n format: { S16LE, U16LE, S8, U8 }\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: 1\naudio/x-raw:\n format: { S16LE, U16LE, S8, U8 }\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: 2\n channel-mask: 0x0000000000000003\n", + "caps": "video/x-raw(memory:GLMemory):\n format: RGBA\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n texture-target: 2D\n\nvideo/x-raw(ANY):\n format: RGBA\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n texture-target: 2D\n", "direction": "src", "presence": "always" } }, "properties": { - "actual-buffer-time": { - "blurb": "Actual configured size of audio buffer in microseconds", + "context": { + "blurb": "Get OpenGL context", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstGLContext", "writable": false }, - "actual-latency-time": { - "blurb": "Actual configured audio latency in microseconds", + "qml-scene": { + "blurb": "The contents of the QML scene", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": true + }, + "qos": { + "blurb": "Handle Quality-of-Service events", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "root-item": { + "blurb": "The root QQuickItem from the qml-scene used to render", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "mutable": "null", + "readable": true, + "type": "gpointer", "writable": false }, + "widget": { + "blurb": "The QQuickItem to place the input video in the object hierarchy", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "mutable": "null", + "readable": true, + "type": "gpointer", + "writable": true + } + }, + "rank": "none", + "signals": { + "qml-scene-destroyed": { + "args": [], + "return-type": "void", + "when": "last" + }, + "qml-scene-initialized": { + "args": [], + "return-type": "void", + "when": "last" + } + } + }, + "qmlglsink": { + "author": "Matthew Waters ", + "description": "A video sink that renders to a QQuickItem", + "hierarchy": [ + "GstQtSink", + "GstVideoSink", + "GstBaseSink", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Sink/Video", + "long-name": "Qt Video Sink", + "pad-templates": { + "sink": { + "caps": "video/x-raw(memory:GLMemory):\n format: RGBA\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n texture-target: 2D\n", + "direction": "sink", + "presence": "always" + } + }, + "properties": { + "async": { + "blurb": "Go asynchronously to PAUSED", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, "blocksize": { - "blurb": "Size in bytes to read per buffer (-1 = default)", + "blurb": "Size in bytes to pull per buffer (0 = default)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", + "controllable": false, + "default": "4096", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "buffer-time": { - "blurb": "Size of audio buffer in microseconds. This is the maximum amount of data that is buffered in the device and the maximum latency that the source reports. This value might be ignored by the element if necessary; see \"actual-buffer-time\"", + "enable-last-sample": { + "blurb": "Enable the last-sample property", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "200000", - "max": "9223372036854775807", - "min": "1", - "type-name": "gint64", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "device": { - "blurb": "OSS device (usually /dev/dspN)", + "force-aspect-ratio": { + "blurb": "When enabled, scaling will respect original aspect ratio", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "/dev/dsp", - "type-name": "gchararray", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "device-name": { - "blurb": "Human-readable name of the sound device", + "last-sample": { + "blurb": "The last sample received in the sink", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "", - "type-name": "gchararray", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstSample", "writable": false }, - "do-timestamp": { - "blurb": "Apply current stream time to buffers", + "max-bitrate": { + "blurb": "The maximum bits per second to render (0 = disabled)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "0", + "max": "18446744073709551615", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, - "latency-time": { - "blurb": "The minimum amount of data to read in each iteration in microseconds. This is the minimum latency that the source reports. This value might be ignored by the element if necessary; see \"actual-latency-time\"", + "max-lateness": { + "blurb": "Maximum number of nanoseconds that a buffer can be late before it is dropped (-1 unlimited)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "10000", + "controllable": false, + "default": "5000000", "max": "9223372036854775807", - "min": "1", - "type-name": "gint64", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint64", "writable": true }, - "name": { - "blurb": "The name of the object", - "construct": true, + "pixel-aspect-ratio": { + "blurb": "The pixel aspect ratio of the device", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "default": "0/1", + "max": "2147483647/1", + "min": "0/1", + "mutable": "null", + "readable": true, + "type": "GstFraction", "writable": true }, - "num-buffers": { - "blurb": "Number of buffers to output before sending EOS (-1 = unlimited)", + "processing-deadline": { + "blurb": "Maximum processing time for a buffer in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", + "controllable": false, + "default": "15000000", + "max": "18446744073709551615", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "qos": { + "blurb": "Generate Quality-of-Service events upstream", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "provide-clock": { - "blurb": "Provide a clock to be used as the global pipeline clock", + "render-delay": { + "blurb": "Additional render delay of the sink in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, + "default": "0", + "max": "18446744073709551615", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint64", + "writable": true + }, + "show-preroll-frame": { + "blurb": "Whether to render video frames during preroll", + "conditionally-available": false, + "construct": true, + "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "slave-method": { - "blurb": "Algorithm used to match the rate of the masterclock", + "stats": { + "blurb": "Sink Statistics", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "skew (2)", - "enum": true, - "type-name": "GstAudioBaseSrcSlaveMethod", - "values": [ - { - "desc": "GST_AUDIO_BASE_SRC_SLAVE_RESAMPLE", - "name": "resample", - "value": "0" - }, - { - "desc": "GST_AUDIO_BASE_SRC_SLAVE_RE_TIMESTAMP", - "name": "re-timestamp", - "value": "1" - }, - { - "desc": "GST_AUDIO_BASE_SRC_SLAVE_SKEW", - "name": "skew", - "value": "2" - }, - { - "desc": "GST_AUDIO_BASE_SRC_SLAVE_NONE", - "name": "none", - "value": "3" - } - ], + "controllable": false, + "default": "application/x-gst-base-sink-stats, average-rate=(double)0, dropped=(guint64)0, rendered=(guint64)0;", + "mutable": "null", + "readable": true, + "type": "GstStructure", + "writable": false + }, + "sync": { + "blurb": "Sync on the clock", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "typefind": { - "blurb": "Run typefind before negotiating (deprecated, non-functional)", + "throttle-time": { + "blurb": "The time to keep between rendered buffers (0 = disabled)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "0", + "max": "18446744073709551615", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint64", + "writable": true + }, + "ts-offset": { + "blurb": "Timestamp offset in nanoseconds", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "9223372036854775807", + "min": "-9223372036854775808", + "mutable": "null", + "readable": true, + "type": "gint64", + "writable": true + }, + "widget": { + "blurb": "The QQuickItem to place in the object hierarchy", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "mutable": "null", + "readable": true, + "type": "gpointer", "writable": true } }, - "rank": "secondary" - } - }, - "filename": "gstossaudio", - "license": "LGPL", - "package": "GStreamer Good Plug-ins git", - "source": "gst-plugins-good", - "tracers": {}, - "url": "Unknown package origin" - }, - "png": { - "description": "PNG plugin library", - "elements": { - "pngdec": { - "author": "Wim Taymans ", - "description": "Decode a png video frame to a raw image", + "rank": "none" + }, + "qmlglsrc": { + "author": "Multimedia Team ", + "description": "A video src that captures a window from a QML view", "hierarchy": [ - "GstPngDec", - "GstVideoDecoder", + "GstQtSrc", + "GstPushSrc", + "GstBaseSrc", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Codec/Decoder/Image", - "long-name": "PNG image decoder", - "name": "pngdec", + "klass": "Source/Video", + "long-name": "Qt Video Source", "pad-templates": { - "sink": { - "caps": "image/png:\n", - "direction": "sink", - "presence": "always" - }, "src": { - "caps": "video/x-raw:\n format: { RGBA, RGB, ARGB64, GRAY8, GRAY16_BE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "caps": "video/x-raw(memory:GLMemory):\n format: RGBA\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n texture-target: 2D\n", "direction": "src", "presence": "always" } }, "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, + "blocksize": { + "blurb": "Size in bytes to read per buffer (-1 = default)", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "default": "4096", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "do-timestamp": { + "blurb": "Apply current stream time to buffers", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true - } - }, - "rank": "primary" - }, - "pngenc": { - "author": "Jeremy SIMON ", - "description": "Encode a video frame to a .png image", + }, + "num-buffers": { + "blurb": "Number of buffers to output before sending EOS (-1 = unlimited)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "-1", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + }, + "typefind": { + "blurb": "Run typefind before negotiating (deprecated, non-functional)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "use-default-fbo": { + "blurb": "When set it will not create a new FBO for the QML render thread", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "window": { + "blurb": "The QQuickWindow to place in the object hierarchy", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "mutable": "null", + "readable": true, + "type": "gpointer", + "writable": true + } + }, + "rank": "none" + } + }, + "filename": "gstqmlgl", + "license": "LGPL", + "other-types": {}, + "package": "GStreamer Good Plug-ins", + "source": "gst-plugins-good", + "tracers": {}, + "url": "Unknown package origin" + }, + "replaygain": { + "description": "ReplayGain volume normalization", + "elements": { + "rganalysis": { + "author": "René Stadler ", + "description": "Perform the ReplayGain analysis", "hierarchy": [ - "GstPngEnc", - "GstVideoEncoder", + "GstRgAnalysis", + "GstBaseTransform", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Codec/Encoder/Image", - "long-name": "PNG image encoder", - "name": "pngenc", + "klass": "Filter/Analyzer/Audio", + "long-name": "ReplayGain analysis", "pad-templates": { "sink": { - "caps": "video/x-raw:\n format: { RGBA, RGB, GRAY8, GRAY16_BE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "caps": "audio/x-raw:\n format: { F32LE, S16LE }\n layout: interleaved\n channels: 1\n rate: { (int)8000, (int)11025, (int)12000, (int)16000, (int)22050, (int)24000, (int)32000, (int)44100, (int)48000 }\naudio/x-raw:\n format: { F32LE, S16LE }\n layout: interleaved\n channels: 2\n channel-mask: 0x0000000000000003\n rate: { (int)8000, (int)11025, (int)12000, (int)16000, (int)22050, (int)24000, (int)32000, (int)44100, (int)48000 }\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "image/png:\n width: [ 16, 1000000 ]\n height: [ 16, 1000000 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "caps": "audio/x-raw:\n format: { F32LE, S16LE }\n layout: interleaved\n channels: 1\n rate: { (int)8000, (int)11025, (int)12000, (int)16000, (int)22050, (int)24000, (int)32000, (int)44100, (int)48000 }\naudio/x-raw:\n format: { F32LE, S16LE }\n layout: interleaved\n channels: 2\n channel-mask: 0x0000000000000003\n rate: { (int)8000, (int)11025, (int)12000, (int)16000, (int)22050, (int)24000, (int)32000, (int)44100, (int)48000 }\n", "direction": "src", "presence": "always" } }, "properties": { - "compression-level": { - "blurb": "PNG compression level", + "forced": { + "blurb": "Analyze even if ReplayGain tags exist", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "6", - "max": "9", - "min": "0", - "type-name": "guint", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "name": { - "blurb": "The name of the object", + "message": { + "blurb": "Post statics messages", + "conditionally-available": false, "construct": true, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "num-tracks": { + "blurb": "Number of remaining album tracks", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "0", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "qos": { - "blurb": "Handle Quality-of-Service events from downstream", + "reference-level": { + "blurb": "Reference level [dB]", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "89", + "max": "150", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true + } + }, + "rank": "none" + }, + "rglimiter": { + "author": "René Stadler ", + "description": "Apply signal compression to raw audio data", + "hierarchy": [ + "GstRgLimiter", + "GstBaseTransform", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Filter/Effect/Audio", + "long-name": "ReplayGain limiter", + "pad-templates": { + "sink": { + "caps": "audio/x-raw:\n format: F32LE\n layout: { (string)interleaved, (string)non-interleaved }\n channels: [ 1, 2147483647 ]\n rate: [ 1, 2147483647 ]\n", + "direction": "sink", + "presence": "always" }, - "snapshot": { - "blurb": "Send EOS after encoding a frame, useful for snapshots", + "src": { + "caps": "audio/x-raw:\n format: F32LE\n layout: { (string)interleaved, (string)non-interleaved }\n channels: [ 1, 2147483647 ]\n rate: [ 1, 2147483647 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "enabled": { + "blurb": "Enable processing", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, - "rank": "primary" - } - }, - "filename": "gstpng", - "license": "LGPL", - "package": "GStreamer Good Plug-ins git", - "source": "gst-plugins-good", - "tracers": {}, - "url": "Unknown package origin" - }, - "pulseaudio": { - "description": "PulseAudio plugin library", - "elements": { - "pulsesink": { - "author": "Lennart Poettering", - "description": "Plays audio to a PulseAudio server", + "rank": "none" + }, + "rgvolume": { + "author": "René Stadler ", + "description": "Apply ReplayGain volume adjustment", "hierarchy": [ - "GstPulseSink", - "GstAudioBaseSink", - "GstBaseSink", + "GstRgVolume", + "GstBin", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Sink/Audio", - "long-name": "PulseAudio Audio Sink", - "name": "pulsesink", + "interfaces": [ + "GstChildProxy" + ], + "klass": "Filter/Effect/Audio", + "long-name": "ReplayGain volume", "pad-templates": { "sink": { - "caps": "audio/x-raw:\n format: { S16LE, S16BE, F32LE, F32BE, S32LE, S32BE, S24LE, S24BE, S24_32LE, S24_32BE, U8 }\n layout: interleaved\n rate: [ 1, 384000 ]\n channels: [ 1, 32 ]\naudio/x-alaw:\n rate: [ 1, 384000 ]\n channels: [ 1, 32 ]\naudio/x-mulaw:\n rate: [ 1, 384000 ]\n channels: [ 1, 32 ]\naudio/x-ac3:\n framed: true\naudio/x-eac3:\n framed: true\naudio/x-dts:\n framed: true\n block-size: { (int)512, (int)1024, (int)2048 }\naudio/mpeg:\n mpegversion: 1\nmpegaudioversion: [ 1, 3 ]\n parsed: true\naudio/mpeg:\n mpegversion: { (int)2, (int)4 }\n framed: true\n stream-format: adts\n", + "caps": "audio/x-raw:\n format: { F32LE, S16LE }\n layout: { (string)interleaved, (string)non-interleaved }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", "direction": "sink", "presence": "always" + }, + "src": { + "caps": "audio/x-raw:\n format: { F32LE, S16LE }\n layout: { (string)interleaved, (string)non-interleaved }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", + "direction": "src", + "presence": "always" } }, "properties": { - "alignment-threshold": { - "blurb": "Timestamp alignment threshold in nanoseconds", + "album-mode": { + "blurb": "Prefer album over track gain", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "40000000", - "max": "18446744073709551614", - "min": "1", - "type-name": "guint64", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "async": { - "blurb": "Go asynchronously to PAUSED", + "fallback-gain": { + "blurb": "Gain for streams missing tags [dB]", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "0", + "max": "60", + "min": "-60", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, - "blocksize": { - "blurb": "Size in bytes to pull per buffer (0 = default)", + "headroom": { + "blurb": "Extra headroom [dB]", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "4096", - "max": "-1", + "controllable": false, + "default": "0", + "max": "60", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, - "buffer-time": { - "blurb": "Size of audio buffer in microseconds, this is the minimum latency that the sink reports", + "pre-amp": { + "blurb": "Extra gain [dB]", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "200000", - "max": "9223372036854775807", - "min": "1", - "type-name": "gint64", + "controllable": false, + "default": "0", + "max": "60", + "min": "-60", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, - "can-activate-pull": { - "blurb": "Allow pull-based scheduling", + "result-gain": { + "blurb": "Applied gain [dB]", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true + "controllable": false, + "default": "0", + "max": "120", + "min": "-120", + "mutable": "null", + "readable": true, + "type": "gdouble", + "writable": false }, - "client-name": { - "blurb": "The PulseAudio client name to use", + "target-gain": { + "blurb": "Applicable gain [dB]", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "gst-hotdoc-plugins-scanner", - "type-name": "gchararray", + "controllable": false, + "default": "0", + "max": "120", + "min": "-120", + "mutable": "null", + "readable": true, + "type": "gdouble", + "writable": false + } + }, + "rank": "none" + } + }, + "filename": "gstreplaygain", + "license": "LGPL", + "other-types": {}, + "package": "GStreamer Good Plug-ins", + "source": "gst-plugins-good", + "tracers": {}, + "url": "Unknown package origin" + }, + "rpicamsrc": { + "description": "Raspberry Pi Camera Source", + "elements": { + "rpicamsrc": { + "author": "Jan Schmidt ", + "description": "Raspberry Pi camera module source", + "hierarchy": [ + "GstRpiCamSrc", + "GstPushSrc", + "GstBaseSrc", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstColorBalance", + "GstVideoDirection", + "GstVideoOrientation" + ], + "klass": "Source/Video", + "long-name": "Raspberry Pi Camera Source", + "pad-templates": { + "src": { + "caps": "video/x-h264:\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n stream-format: byte-stream\n alignment: nal\n profile: { (string)constrained-baseline, (string)baseline, (string)main, (string)high }\nimage/jpeg:\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { I420, RGB, BGR, RGBA }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "annotation-mode": { + "blurb": "Flags to control annotation of the output video", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "(none)", + "mutable": "null", + "readable": true, + "type": "GstRpiCamSrcAnnotationMode", "writable": true }, - "current-device": { - "blurb": "The current PulseAudio sink device", + "annotation-text": { + "blurb": "Text string to annotate onto video when annotation-mode flags include 'custom-text'", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "", - "type-name": "gchararray", - "writable": false + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": true }, - "device": { - "blurb": "The PulseAudio sink device to connect to", + "annotation-text-bg-colour": { + "blurb": "Set the annotation text background colour, as the integer corresponding to a VUY value eg 0x8080FF = 8421631, -1 for default", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "NULL", - "type-name": "gchararray", + "controllable": false, + "default": "-1", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "device-name": { - "blurb": "Human-readable name of the sound device", + "annotation-text-colour": { + "blurb": "Set the annotation text colour, as the integer corresponding to a VUY value eg 0x8080FF = 8421631, -1 for default", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": false + "controllable": false, + "default": "-1", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true }, - "discont-wait": { - "blurb": "Window of time in nanoseconds to wait before creating a discontinuity", + "annotation-text-size": { + "blurb": "Set the size of annotation text (in pixels) (0 = Auto)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "1000000000", - "max": "18446744073709551614", + "controllable": false, + "default": "0", + "max": "2147483647", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "drift-tolerance": { - "blurb": "Tolerance for clock drift in microseconds", + "awb-gain-blue": { + "blurb": "Manual AWB Gain for blue channel when awb-mode=off", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "40000", - "max": "9223372036854775807", - "min": "1", - "type-name": "gint64", + "controllable": false, + "default": "0", + "max": "8", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, - "enable-last-sample": { - "blurb": "Enable the last-sample property", + "awb-gain-red": { + "blurb": "Manual AWB Gain for red channel when awb-mode=off", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "0", + "max": "8", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, - "last-sample": { - "blurb": "The last sample received in the sink", + "awb-mode": { + "blurb": "White Balance mode", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstSample", - "writable": false + "controllable": false, + "default": "auto (1)", + "mutable": "null", + "readable": true, + "type": "GstRpiCamSrcAWBMode", + "writable": true }, - "latency-time": { - "blurb": "The minimum amount of data to write in each iteration in microseconds", + "bitrate": { + "blurb": "Bitrate for encoding. 0 for VBR using quantisation-parameter", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "10000", - "max": "9223372036854775807", - "min": "1", - "type-name": "gint64", + "controllable": false, + "default": "17000000", + "max": "25000000", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "max-bitrate": { - "blurb": "The maximum bits per second to render (0 = disabled)", + "brightness": { + "blurb": "Image capture brightness", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "18446744073709551615", + "controllable": false, + "default": "50", + "max": "100", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "max-lateness": { - "blurb": "Maximum number of nanoseconds that a buffer can be late before it is dropped (-1 unlimited)", + "camera-number": { + "blurb": "Which camera to use on a multi-camera system - 0 or 1", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", + "controllable": false, + "default": "0", + "max": "1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "mute": { - "blurb": "Mute state of this stream", + "contrast": { + "blurb": "Image capture contrast", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "0", + "max": "100", + "min": "-100", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "name": { - "blurb": "The name of the object", - "construct": true, + "drc": { + "blurb": "Dynamic Range Control level", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "default": "off (0)", + "mutable": "null", + "readable": true, + "type": "GstRpiCamSrcDRCLevel", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "exposure-compensation": { + "blurb": "Exposure Value compensation", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "0", + "max": "10", + "min": "-10", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "processing-deadline": { - "blurb": "Maximum processing deadline in nanoseconds", + "exposure-mode": { + "blurb": "Camera exposure mode to use", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "20000000", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", + "controllable": false, + "default": "auto (1)", + "mutable": "null", + "readable": true, + "type": "GstRpiCamSrcExposureMode", "writable": true }, - "provide-clock": { - "blurb": "Provide a clock to be used as the global pipeline clock", + "fullscreen": { + "blurb": "Display preview window full screen", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "qos": { - "blurb": "Generate Quality-of-Service events upstream", + "hflip": { + "blurb": "Flip capture horizontally", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "render-delay": { - "blurb": "Additional render delay of the sink in nanoseconds", + "image-effect": { + "blurb": "Visual FX to apply to the image", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", + "controllable": false, + "default": "none (0)", + "mutable": "null", + "readable": true, + "type": "GstRpiCamSrcImageEffect", "writable": true }, - "server": { - "blurb": "The PulseAudio server to connect to", + "inline-headers": { + "blurb": "Set to TRUE to insert SPS/PPS before each IDR packet", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "NULL", - "type-name": "gchararray", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "slave-method": { - "blurb": "Algorithm used to match the rate of the masterclock", + "intra-refresh-type": { + "blurb": "Type of Intra Refresh to use, -1 to disable intra refresh", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "skew (1)", - "enum": true, - "type-name": "GstAudioBaseSinkSlaveMethod", - "values": [ - { - "desc": "GST_AUDIO_BASE_SINK_SLAVE_RESAMPLE", - "name": "resample", - "value": "0" - }, - { - "desc": "GST_AUDIO_BASE_SINK_SLAVE_SKEW", - "name": "skew", - "value": "1" - }, - { - "desc": "GST_AUDIO_BASE_SINK_SLAVE_NONE", - "name": "none", - "value": "2" - }, - { - "desc": "GST_AUDIO_BASE_SINK_SLAVE_CUSTOM", - "name": "custom", - "value": "3" - } - ], + "controllable": false, + "default": "none (-1)", + "mutable": "null", + "readable": true, + "type": "GstRpiCamSrcIntraRefreshType", "writable": true }, - "stats": { - "blurb": "Sink Statistics", + "iso": { + "blurb": "ISO value to use (0 = Auto)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "application/x-gst-base-sink-stats, average-rate=(double)0, dropped=(guint64)0, rendered=(guint64)0;", - "type-name": "GstStructure", - "writable": false + "controllable": false, + "default": "0", + "max": "3200", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true }, - "stream-properties": { - "blurb": "list of pulseaudio stream properties", + "keyframe-interval": { + "blurb": "Interval (in frames) between I frames. -1 = automatic, 0 = single-keyframe", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstStructure", + "controllable": false, + "default": "-1", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "sync": { - "blurb": "Sync on the clock", + "metering-mode": { + "blurb": "Camera exposure metering mode to use", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "average (0)", + "mutable": "null", + "readable": true, + "type": "GstRpiCamSrcExposureMeteringMode", "writable": true }, - "throttle-time": { - "blurb": "The time to keep between rendered buffers (0 = disabled)", + "preview": { + "blurb": "Display preview window overlay", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "ts-offset": { - "blurb": "Timestamp offset in nanoseconds", + "preview-encoded": { + "blurb": "Display encoder output in the preview", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "-9223372036854775808", - "type-name": "gint64", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "volume": { - "blurb": "Linear volume of this stream, 1.0=100%%", + "preview-h": { + "blurb": "Height of the preview window (in pixels)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "1", - "max": "10", + "controllable": false, + "default": "768", + "max": "2048", "min": "0", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true - } - }, - "rank": "primary + 10" - }, - "pulsesrc": { - "author": "Lennart Poettering", - "description": "Captures audio from a PulseAudio server", - "hierarchy": [ - "GstPulseSrc", - "GstAudioSrc", - "GstAudioBaseSrc", - "GstPushSrc", - "GstBaseSrc", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Source/Audio", - "long-name": "PulseAudio Audio Source", - "name": "pulsesrc", - "pad-templates": { - "src": { - "caps": "audio/x-raw:\n format: { S16LE, S16BE, F32LE, F32BE, S32LE, S32BE, S24LE, S24BE, S24_32LE, S24_32BE, U8 }\n layout: interleaved\n rate: [ 1, 384000 ]\n channels: [ 1, 32 ]\naudio/x-alaw:\n rate: [ 1, 384000 ]\n channels: [ 1, 32 ]\naudio/x-mulaw:\n rate: [ 1, 384000 ]\n channels: [ 1, 32 ]\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "actual-buffer-time": { - "blurb": "Actual configured size of audio buffer in microseconds", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": false - }, - "actual-latency-time": { - "blurb": "Actual configured audio latency in microseconds", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": false }, - "blocksize": { - "blurb": "Size in bytes to read per buffer (-1 = default)", + "preview-opacity": { + "blurb": "Opacity to use for the preview window", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "-1", + "controllable": false, + "default": "255", + "max": "255", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "buffer-time": { - "blurb": "Size of audio buffer in microseconds. This is the maximum amount of data that is buffered in the device and the maximum latency that the source reports. This value might be ignored by the element if necessary; see \"actual-buffer-time\"", + "preview-w": { + "blurb": "Width of the preview window (in pixels)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "200000", - "max": "9223372036854775807", - "min": "1", - "type-name": "gint64", + "controllable": false, + "default": "1024", + "max": "2048", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "client-name": { - "blurb": "The PulseAudio client_name_to_use", + "preview-x": { + "blurb": "Start X coordinate of the preview window (in pixels)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "gst-hotdoc-plugins-scanner", - "type-name": "gchararray", + "controllable": false, + "default": "0", + "max": "2048", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "current-device": { - "blurb": "The current PulseAudio source device", - "construct": false, - "construct-only": false, - "default": "", - "type-name": "gchararray", - "writable": false - }, - "device": { - "blurb": "The PulseAudio source device to connect to", + "preview-y": { + "blurb": "Start Y coordinate of the preview window (in pixels)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "NULL", - "type-name": "gchararray", + "controllable": false, + "default": "0", + "max": "2048", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "device-name": { - "blurb": "Human-readable name of the sound device", - "construct": false, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": false - }, - "do-timestamp": { - "blurb": "Apply current stream time to buffers", + "quantisation-parameter": { + "blurb": "Set a Quantisation Parameter approx 10-40 with bitrate=0 for VBR encoding. 0 = off", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "0", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "latency-time": { - "blurb": "The minimum amount of data to read in each iteration in microseconds. This is the minimum latency that the source reports. This value might be ignored by the element if necessary; see \"actual-latency-time\"", + "roi-h": { + "blurb": "Normalised region-of-interest H coord", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "10000", - "max": "9223372036854775807", - "min": "1", - "type-name": "gint64", + "controllable": false, + "default": "1", + "max": "1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, - "mute": { - "blurb": "Mute state of this stream", + "roi-w": { + "blurb": "Normalised region-of-interest W coord", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "1", + "max": "1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, - "name": { - "blurb": "The name of the object", - "construct": true, + "roi-x": { + "blurb": "Normalised region-of-interest X coord", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "default": "0", + "max": "1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, - "num-buffers": { - "blurb": "Number of buffers to output before sending EOS (-1 = unlimited)", + "roi-y": { + "blurb": "Normalised region-of-interest Y coord", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", + "controllable": false, + "default": "0", + "max": "1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "rotation": { + "blurb": "Rotate captured image (0, 90, 180, 270 degrees)", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "0", + "max": "270", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "provide-clock": { - "blurb": "Provide a clock to be used as the global pipeline clock", + "saturation": { + "blurb": "Image capture saturation", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "0", + "max": "100", + "min": "-100", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "server": { - "blurb": "The PulseAudio server to connect to", + "sensor-mode": { + "blurb": "Manually set the camera sensor mode", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "NULL", - "type-name": "gchararray", + "controllable": false, + "default": "automatic (0)", + "mutable": "null", + "readable": true, + "type": "GstRpiCamSrcSensorMode", "writable": true }, - "slave-method": { - "blurb": "Algorithm used to match the rate of the masterclock", + "sharpness": { + "blurb": "Image capture sharpness", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "skew (2)", - "enum": true, - "type-name": "GstAudioBaseSrcSlaveMethod", - "values": [ - { - "desc": "GST_AUDIO_BASE_SRC_SLAVE_RESAMPLE", - "name": "resample", - "value": "0" - }, - { - "desc": "GST_AUDIO_BASE_SRC_SLAVE_RE_TIMESTAMP", - "name": "re-timestamp", - "value": "1" - }, - { - "desc": "GST_AUDIO_BASE_SRC_SLAVE_SKEW", - "name": "skew", - "value": "2" - }, - { - "desc": "GST_AUDIO_BASE_SRC_SLAVE_NONE", - "name": "none", - "value": "3" - } - ], + "controllable": false, + "default": "0", + "max": "100", + "min": "-100", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "source-output-index": { - "blurb": "The index of the PulseAudio source output corresponding to this record stream", + "shutter-speed": { + "blurb": "Set a fixed shutter speed, in microseconds. (0 = Auto)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "-1", - "max": "-1", + "controllable": false, + "default": "0", + "max": "6000000", "min": "0", - "type-name": "guint", - "writable": false + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true }, - "stream-properties": { - "blurb": "list of pulseaudio stream properties", + "use-stc": { + "blurb": "Use the camera STC for timestamping buffers", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstStructure", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "typefind": { - "blurb": "Run typefind before negotiating (deprecated, non-functional)", + "vflip": { + "blurb": "Flip capture vertically", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "volume": { - "blurb": "Linear volume of this stream, 1.0=100%%", + "video-stabilisation": { + "blurb": "Enable or disable video stabilisation", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "1", - "max": "10", - "min": "0", - "type-name": "gdouble", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, - "rank": "primary + 10" + "rank": "none" } }, - "filename": "gstpulseaudio", + "filename": "gstrpicamsrc", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", - "source": "gst-plugins-good", - "tracers": {}, - "url": "Unknown package origin" - }, - "qmlgl": { - "description": "Qt gl plugin", + "other-types": { + "GstRpiCamSrcAWBMode": { + "kind": "enum", + "values": [ + { + "desc": "GST_RPI_CAM_SRC_AWB_MODE_OFF", + "name": "off", + "value": "0" + }, + { + "desc": "GST_RPI_CAM_SRC_AWB_MODE_AUTO", + "name": "auto", + "value": "1" + }, + { + "desc": "GST_RPI_CAM_SRC_AWB_MODE_SUNLIGHT", + "name": "sunlight", + "value": "2" + }, + { + "desc": "GST_RPI_CAM_SRC_AWB_MODE_CLOUDY", + "name": "cloudy", + "value": "3" + }, + { + "desc": "GST_RPI_CAM_SRC_AWB_MODE_SHADE", + "name": "shade", + "value": "4" + }, + { + "desc": "GST_RPI_CAM_SRC_AWB_MODE_TUNGSTEN", + "name": "tungsten", + "value": "5" + }, + { + "desc": "GST_RPI_CAM_SRC_AWB_MODE_FLUORESCENT", + "name": "fluorescent", + "value": "6" + }, + { + "desc": "GST_RPI_CAM_SRC_AWB_MODE_INCANDESCENT", + "name": "incandescent", + "value": "7" + }, + { + "desc": "GST_RPI_CAM_SRC_AWB_MODE_FLASH", + "name": "flash", + "value": "8" + }, + { + "desc": "GST_RPI_CAM_SRC_AWB_MODE_HORIZON", + "name": "horizon", + "value": "9" + } + ] + }, + "GstRpiCamSrcAnnotationMode": { + "kind": "flags", + "values": [ + { + "desc": "GST_RPI_CAM_SRC_ANNOTATION_MODE_CUSTOM_TEXT", + "name": "custom-text", + "value": "0x00000001" + }, + { + "desc": "GST_RPI_CAM_SRC_ANNOTATION_MODE_TEXT", + "name": "text", + "value": "0x00000002" + }, + { + "desc": "GST_RPI_CAM_SRC_ANNOTATION_MODE_DATE", + "name": "date", + "value": "0x00000004" + }, + { + "desc": "GST_RPI_CAM_SRC_ANNOTATION_MODE_TIME", + "name": "time", + "value": "0x00000008" + }, + { + "desc": "GST_RPI_CAM_SRC_ANNOTATION_MODE_SHUTTER_SETTINGS", + "name": "shutter-settings", + "value": "0x00000010" + }, + { + "desc": "GST_RPI_CAM_SRC_ANNOTATION_MODE_CAF_SETTINGS", + "name": "caf-settings", + "value": "0x00000020" + }, + { + "desc": "GST_RPI_CAM_SRC_ANNOTATION_MODE_GAIN_SETTINGS", + "name": "gain-settings", + "value": "0x00000040" + }, + { + "desc": "GST_RPI_CAM_SRC_ANNOTATION_MODE_LENS_SETTINGS", + "name": "lens-settings", + "value": "0x00000080" + }, + { + "desc": "GST_RPI_CAM_SRC_ANNOTATION_MODE_MOTION_SETTINGS", + "name": "motion-settings", + "value": "0x00000100" + }, + { + "desc": "GST_RPI_CAM_SRC_ANNOTATION_MODE_FRAME_NUMBER", + "name": "frame-number", + "value": "0x00000200" + }, + { + "desc": "GST_RPI_CAM_SRC_ANNOTATION_MODE_BLACK_BACKGROUND", + "name": "black-background", + "value": "0x00000400" + } + ] + }, + "GstRpiCamSrcDRCLevel": { + "kind": "enum", + "values": [ + { + "desc": "GST_RPI_CAM_SRC_DRC_LEVEL_OFF", + "name": "off", + "value": "0" + }, + { + "desc": "GST_RPI_CAM_SRC_DRC_LEVEL_LOW", + "name": "low", + "value": "1" + }, + { + "desc": "GST_RPI_CAM_SRC_DRC_LEVEL_MEDIUM", + "name": "medium", + "value": "2" + }, + { + "desc": "GST_RPI_CAM_SRC_DRC_LEVEL_HIGH", + "name": "high", + "value": "3" + } + ] + }, + "GstRpiCamSrcExposureMeteringMode": { + "kind": "enum", + "values": [ + { + "desc": "GST_RPI_CAM_SRC_EXPOSURE_METERING_MODE_AVERAGE", + "name": "average", + "value": "0" + }, + { + "desc": "GST_RPI_CAM_SRC_EXPOSURE_METERING_MODE_SPOT", + "name": "spot", + "value": "1" + }, + { + "desc": "GST_RPI_CAM_SRC_EXPOSURE_METERING_MODE_BACKLIST", + "name": "backlist", + "value": "2" + }, + { + "desc": "GST_RPI_CAM_SRC_EXPOSURE_METERING_MODE_MATRIX", + "name": "matrix", + "value": "3" + } + ] + }, + "GstRpiCamSrcExposureMode": { + "kind": "enum", + "values": [ + { + "desc": "GST_RPI_CAM_SRC_EXPOSURE_MODE_OFF", + "name": "off", + "value": "0" + }, + { + "desc": "GST_RPI_CAM_SRC_EXPOSURE_MODE_AUTO", + "name": "auto", + "value": "1" + }, + { + "desc": "GST_RPI_CAM_SRC_EXPOSURE_MODE_NIGHT", + "name": "night", + "value": "2" + }, + { + "desc": "GST_RPI_CAM_SRC_EXPOSURE_MODE_NIGHTPREVIEW", + "name": "nightpreview", + "value": "3" + }, + { + "desc": "GST_RPI_CAM_SRC_EXPOSURE_MODE_BACKLIGHT", + "name": "backlight", + "value": "4" + }, + { + "desc": "GST_RPI_CAM_SRC_EXPOSURE_MODE_SPOTLIGHT", + "name": "spotlight", + "value": "5" + }, + { + "desc": "GST_RPI_CAM_SRC_EXPOSURE_MODE_SPORTS", + "name": "sports", + "value": "6" + }, + { + "desc": "GST_RPI_CAM_SRC_EXPOSURE_MODE_SNOW", + "name": "snow", + "value": "7" + }, + { + "desc": "GST_RPI_CAM_SRC_EXPOSURE_MODE_BEACH", + "name": "beach", + "value": "8" + }, + { + "desc": "GST_RPI_CAM_SRC_EXPOSURE_MODE_VERYLONG", + "name": "verylong", + "value": "9" + }, + { + "desc": "GST_RPI_CAM_SRC_EXPOSURE_MODE_FIXEDFPS", + "name": "fixedfps", + "value": "10" + }, + { + "desc": "GST_RPI_CAM_SRC_EXPOSURE_MODE_ANTISHAKE", + "name": "antishake", + "value": "11" + }, + { + "desc": "GST_RPI_CAM_SRC_EXPOSURE_MODE_FIREWORKS", + "name": "fireworks", + "value": "12" + } + ] + }, + "GstRpiCamSrcImageEffect": { + "kind": "enum", + "values": [ + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_NONE", + "name": "none", + "value": "0" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_NEGATIVE", + "name": "negative", + "value": "1" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_SOLARIZE", + "name": "solarize", + "value": "2" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_POSTERIZE", + "name": "posterize", + "value": "3" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_WHITEBOARD", + "name": "whiteboard", + "value": "4" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_BLACKBOARD", + "name": "blackboard", + "value": "5" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_SKETCH", + "name": "sketch", + "value": "6" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_DENOISE", + "name": "denoise", + "value": "7" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_EMBOSS", + "name": "emboss", + "value": "8" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_OILPAINT", + "name": "oilpaint", + "value": "9" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_HATCH", + "name": "hatch", + "value": "10" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_GPEN", + "name": "gpen", + "value": "11" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_PASTEL", + "name": "pastel", + "value": "12" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_WATERCOLOUR", + "name": "watercolour", + "value": "13" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_FILM", + "name": "film", + "value": "14" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_BLUR", + "name": "blur", + "value": "15" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_SATURATION", + "name": "saturation", + "value": "16" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_COLOURSWAP", + "name": "colourswap", + "value": "17" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_WASHEDOUT", + "name": "washedout", + "value": "18" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_POSTERISE", + "name": "posterise", + "value": "19" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_COLOURPOINT", + "name": "colourpoint", + "value": "20" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_COLOURBALANCE", + "name": "colourbalance", + "value": "21" + }, + { + "desc": "GST_RPI_CAM_SRC_IMAGEFX_CARTOON", + "name": "cartoon", + "value": "22" + } + ] + }, + "GstRpiCamSrcIntraRefreshType": { + "kind": "enum", + "values": [ + { + "desc": "GST_RPI_CAM_SRC_INTRA_REFRESH_TYPE_NONE", + "name": "none", + "value": "-1" + }, + { + "desc": "GST_RPI_CAM_SRC_INTRA_REFRESH_TYPE_CYCLIC", + "name": "cyclic", + "value": "0" + }, + { + "desc": "GST_RPI_CAM_SRC_INTRA_REFRESH_TYPE_ADAPTIVE", + "name": "adaptive", + "value": "1" + }, + { + "desc": "GST_RPI_CAM_SRC_INTRA_REFRESH_TYPE_BOTH", + "name": "both", + "value": "2" + }, + { + "desc": "GST_RPI_CAM_SRC_INTRA_REFRESH_TYPE_CYCLIC_ROWS", + "name": "cyclic-rows", + "value": "2130706433" + } + ] + }, + "GstRpiCamSrcSensorMode": { + "kind": "enum", + "values": [ + { + "desc": "Automatic", + "name": "automatic", + "value": "0" + }, + { + "desc": "1920x1080 16:9 1-30fps", + "name": "1920x1080", + "value": "1" + }, + { + "desc": "2592x1944 4:3 1-15fps / 3240x2464 15fps w/ v.2 board", + "name": "2592x1944-fast", + "value": "2" + }, + { + "desc": "2592x1944 4:3 0.1666-1fps / 3240x2464 15fps w/ v.2 board", + "name": "2592x1944-slow", + "value": "3" + }, + { + "desc": "1296x972 4:3 1-42fps", + "name": "1296x972", + "value": "4" + }, + { + "desc": "1296x730 16:9 1-49fps", + "name": "1296x730", + "value": "5" + }, + { + "desc": "640x480 4:3 42.1-60fps", + "name": "640x480-slow", + "value": "6" + }, + { + "desc": "640x480 4:3 60.1-90fps", + "name": "640x480-fast", + "value": "7" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", + "source": "gst-plugins-good", + "tracers": {}, + "url": "Unknown package origin" + }, + "rtp": { + "description": "Real-time protocol plugins", "elements": { - "qmlglsink": { - "author": "Matthew Waters ", - "description": "A video sink that renders to a QQuickItem", + "asteriskh263": { + "author": "Neil Stratford ", + "description": "Extracts H263 video from RTP and encodes in Asterisk H263 format", "hierarchy": [ - "GstQtSink", - "GstVideoSink", - "GstBaseSink", + "GstAsteriskh263", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Sink/Video", - "long-name": "Qt Video Sink", + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP Asterisk H263 depayloader", "pad-templates": { "sink": { - "caps": "video/x-raw(memory:GLMemory):\n format: RGBA\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n texture-target: 2D\n", + "caps": "application/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: H263-1998\n", "direction": "sink", "presence": "always" - } - }, - "properties": { - "async": { - "blurb": "Go asynchronously to PAUSED", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "blocksize": { - "blurb": "Size in bytes to pull per buffer (0 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "enable-last-sample": { - "blurb": "Enable the last-sample property", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "force-aspect-ratio": { - "blurb": "When enabled, scaling will respect original aspect ratio", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "last-sample": { - "blurb": "The last sample received in the sink", - "construct": false, - "construct-only": false, - "type-name": "GstSample", - "writable": false - }, - "max-bitrate": { - "blurb": "The maximum bits per second to render (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "max-lateness": { - "blurb": "Maximum number of nanoseconds that a buffer can be late before it is dropped (-1 unlimited)", - "construct": false, - "construct-only": false, - "default": "5000000", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "pixel-aspect-ratio": { - "blurb": "The pixel aspect ratio of the device", - "construct": false, - "construct-only": false, - "default": "0/1", - "max": "2147483647/1", - "min": "0/1", - "type-name": "GstFraction", - "writable": true - }, - "processing-deadline": { - "blurb": "Maximum processing deadline in nanoseconds", - "construct": false, - "construct-only": false, - "default": "15000000", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "qos": { - "blurb": "Generate Quality-of-Service events upstream", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "render-delay": { - "blurb": "Additional render delay of the sink in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "show-preroll-frame": { - "blurb": "Whether to render video frames during preroll", - "construct": true, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Sink Statistics", - "construct": false, - "construct-only": false, - "default": "application/x-gst-base-sink-stats, average-rate=(double)0, dropped=(guint64)0, rendered=(guint64)0;", - "type-name": "GstStructure", - "writable": false - }, - "sync": { - "blurb": "Sync on the clock", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "throttle-time": { - "blurb": "The time to keep between rendered buffers (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "ts-offset": { - "blurb": "Timestamp offset in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "-9223372036854775808", - "type-name": "gint64", - "writable": true }, - "widget": { - "blurb": "The QQuickItem to place in the object hierarchy", - "construct": false, - "construct-only": false, - "type-name": "gpointer", - "writable": true + "src": { + "caps": "application/x-asteriskh263:\n", + "direction": "src", + "presence": "always" } }, "rank": "none" }, - "qmlglsrc": { - "author": "Multimedia Team ", - "description": "A video src that captures a window from a QML view", + "rtpL16depay": { + "author": "Zeeshan Ali ,Wim Taymans ", + "description": "Extracts raw audio from RTP packets", "hierarchy": [ - "GstQtSrc", - "GstPushSrc", - "GstBaseSrc", + "GstRtpL16Depay", + "GstRTPBaseDepayload", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Source/Video", - "long-name": "Qt Video Source", + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP audio depayloader", "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: audio\n clock-rate: [ 1, 2147483647 ]\n encoding-name: L16\napplication/x-rtp:\n media: audio\n payload: { (int)10, (int)11 }\n clock-rate: [ 1, 2147483647 ]\n", + "direction": "sink", + "presence": "always" + }, "src": { - "caps": "video/x-raw(memory:GLMemory):\n format: RGBA\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n texture-target: 2D\n", + "caps": "audio/x-raw:\n format: S16BE\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", "direction": "src", "presence": "always" } }, - "properties": { - "blocksize": { - "blurb": "Size in bytes to read per buffer (-1 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true + "properties": {}, + "rank": "secondary" + }, + "rtpL16pay": { + "author": "Wim Taymans ", + "description": "Payload-encode Raw audio into RTP packets (RFC 3551)", + "hierarchy": [ + "GstRtpL16Pay", + "GstRTPBaseAudioPayload", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP audio payloader", + "pad-templates": { + "sink": { + "caps": "audio/x-raw:\n format: S16BE\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", + "direction": "sink", + "presence": "always" }, - "do-timestamp": { - "blurb": "Apply current stream time to buffers", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true + "src": { + "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: [ 1, 2147483647 ]\n encoding-name: L16\n channels: [ 1, 2147483647 ]\napplication/x-rtp:\n media: audio\n encoding-name: L16\n payload: 10\n clock-rate: 44100\napplication/x-rtp:\n media: audio\n encoding-name: L16\n payload: 11\n clock-rate: 44100\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtpL24depay": { + "author": "Zeeshan Ali ,Wim Taymans ,David Holroyd ", + "description": "Extracts raw 24-bit audio from RTP packets", + "hierarchy": [ + "GstRtpL24Depay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP audio depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: audio\n clock-rate: [ 1, 2147483647 ]\n encoding-name: L24\n", + "direction": "sink", + "presence": "always" }, - "num-buffers": { - "blurb": "Number of buffers to output before sending EOS (-1 = unlimited)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "typefind": { - "blurb": "Run typefind before negotiating (deprecated, non-functional)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "use-default-fbo": { - "blurb": "When set it will not create a new FBO for the QML render thread", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "window": { - "blurb": "The QQuickWindow to place in the object hierarchy", - "construct": false, - "construct-only": false, - "type-name": "gpointer", - "writable": true + "src": { + "caps": "audio/x-raw:\n format: S24BE\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", + "direction": "src", + "presence": "always" } }, - "rank": "none" - } - }, - "filename": "gstqmlgl", - "license": "LGPL", - "package": "GStreamer Good Plug-ins git", - "source": "gst-plugins-good", - "tracers": {}, - "url": "Unknown package origin" - }, - "replaygain": { - "description": "ReplayGain volume normalization", - "elements": { - "rganalysis": { - "author": "Ren\u00e9 Stadler ", - "description": "Perform the ReplayGain analysis", + "properties": {}, + "rank": "secondary" + }, + "rtpL24pay": { + "author": "Wim Taymans ,David Holroyd ", + "description": "Payload-encode Raw 24-bit audio into RTP packets (RFC 3190)", "hierarchy": [ - "GstRgAnalysis", - "GstBaseTransform", + "GstRtpL24Pay", + "GstRTPBaseAudioPayload", + "GstRTPBasePayload", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Filter/Analyzer/Audio", - "long-name": "ReplayGain analysis", - "name": "rganalysis", + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP audio payloader", "pad-templates": { "sink": { - "caps": "audio/x-raw:\n format: { F32LE, S16LE }\n layout: interleaved\n channels: 1\n rate: { (int)8000, (int)11025, (int)12000, (int)16000, (int)22050, (int)24000, (int)32000, (int)44100, (int)48000 }\naudio/x-raw:\n format: { F32LE, S16LE }\n layout: interleaved\n channels: 2\n channel-mask: 0x0000000000000003\n rate: { (int)8000, (int)11025, (int)12000, (int)16000, (int)22050, (int)24000, (int)32000, (int)44100, (int)48000 }\n", + "caps": "audio/x-raw:\n format: S24BE\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "audio/x-raw:\n format: { F32LE, S16LE }\n layout: interleaved\n channels: 1\n rate: { (int)8000, (int)11025, (int)12000, (int)16000, (int)22050, (int)24000, (int)32000, (int)44100, (int)48000 }\naudio/x-raw:\n format: { F32LE, S16LE }\n layout: interleaved\n channels: 2\n channel-mask: 0x0000000000000003\n rate: { (int)8000, (int)11025, (int)12000, (int)16000, (int)22050, (int)24000, (int)32000, (int)44100, (int)48000 }\n", + "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: [ 1, 2147483647 ]\n encoding-name: L24\n channels: [ 1, 2147483647 ]\n", "direction": "src", "presence": "always" } }, - "properties": { - "forced": { - "blurb": "Analyze even if ReplayGain tags exist", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "message": { - "blurb": "Post statics messages", - "construct": true, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "num-tracks": { - "blurb": "Number of remaining album tracks", - "construct": false, - "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true + "properties": {}, + "rank": "secondary" + }, + "rtpL8depay": { + "author": "Zeeshan Ali ,Wim Taymans , GE Intelligent Platforms Embedded Systems, Inc.", + "description": "Extracts raw audio from RTP packets", + "hierarchy": [ + "GstRtpL8Depay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP audio depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: audio\n clock-rate: [ 1, 2147483647 ]\n encoding-name: L8\n", + "direction": "sink", + "presence": "always" }, - "reference-level": { - "blurb": "Reference level [dB]", - "construct": false, - "construct-only": false, - "default": "89", - "max": "150", - "min": "0", - "type-name": "gdouble", - "writable": true + "src": { + "caps": "audio/x-raw:\n format: U8\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", + "direction": "src", + "presence": "always" } }, - "rank": "none" + "properties": {}, + "rank": "secondary" }, - "rglimiter": { - "author": "Ren\u00e9 Stadler ", - "description": "Apply signal compression to raw audio data", + "rtpL8pay": { + "author": "Wim Taymans , GE Intelligent Platforms Embedded Systems, Inc.", + "description": "Payload-encode Raw audio into RTP packets (RFC 3551)", "hierarchy": [ - "GstRgLimiter", - "GstBaseTransform", + "GstRtpL8Pay", + "GstRTPBaseAudioPayload", + "GstRTPBasePayload", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Filter/Effect/Audio", - "long-name": "ReplayGain limiter", - "name": "rglimiter", + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP audio payloader", "pad-templates": { "sink": { - "caps": "audio/x-raw:\n format: F32LE\n layout: { (string)interleaved, (string)non-interleaved }\n channels: [ 1, 2147483647 ]\n rate: [ 1, 2147483647 ]\n", + "caps": "audio/x-raw:\n format: U8\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "audio/x-raw:\n format: F32LE\n layout: { (string)interleaved, (string)non-interleaved }\n channels: [ 1, 2147483647 ]\n rate: [ 1, 2147483647 ]\n", + "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: [ 1, 2147483647 ]\n encoding-name: L8\n channels: [ 1, 2147483647 ]\n", "direction": "src", "presence": "always" } }, - "properties": { - "enabled": { - "blurb": "Enable processing", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true + "properties": {}, + "rank": "secondary" + }, + "rtpac3depay": { + "author": "Wim Taymans ", + "description": "Extracts AC3 audio from RTP packets (RFC 4184)", + "hierarchy": [ + "GstRtpAC3Depay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP AC3 depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: audio\n clock-rate: { (int)32000, (int)44100, (int)48000 }\n encoding-name: AC3\n", + "direction": "sink", + "presence": "always" }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true + "src": { + "caps": "audio/ac3:\n", + "direction": "src", + "presence": "always" } }, - "rank": "none" + "properties": {}, + "rank": "secondary" }, - "rgvolume": { - "author": "Ren\u00e9 Stadler ", - "description": "Apply ReplayGain volume adjustment", + "rtpac3pay": { + "author": "Wim Taymans ", + "description": "Payload AC3 audio as RTP packets (RFC 4184)", "hierarchy": [ - "GstRgVolume", - "GstBin", + "GstRtpAC3Pay", + "GstRTPBasePayload", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Filter/Effect/Audio", - "long-name": "ReplayGain volume", - "name": "rgvolume", + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP AC3 audio payloader", "pad-templates": { "sink": { - "caps": "audio/x-raw:\n format: { F32LE, S16LE }\n layout: { (string)interleaved, (string)non-interleaved }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", + "caps": "audio/ac3:\naudio/x-ac3:\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "audio/x-raw:\n format: { F32LE, S16LE }\n layout: { (string)interleaved, (string)non-interleaved }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", + "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: { (int)32000, (int)44100, (int)48000 }\n encoding-name: AC3\n", "direction": "src", "presence": "always" } }, - "properties": { - "album-mode": { - "blurb": "Prefer album over track gain", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "async-handling": { - "blurb": "The bin will handle Asynchronous state changes", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true + "properties": {}, + "rank": "secondary" + }, + "rtpamrdepay": { + "author": "Wim Taymans ", + "description": "Extracts AMR or AMR-WB audio from RTP packets (RFC 3267)", + "hierarchy": [ + "GstRtpAMRDepay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP AMR depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: audio\n clock-rate: 8000\n encoding-name: AMR\n octet-align: 1\napplication/x-rtp:\n media: audio\n clock-rate: 16000\n encoding-name: AMR-WB\n octet-align: 1\n", + "direction": "sink", + "presence": "always" }, - "fallback-gain": { - "blurb": "Gain for streams missing tags [dB]", - "construct": false, - "construct-only": false, - "default": "0", - "max": "60", - "min": "-60", - "type-name": "gdouble", - "writable": true - }, - "headroom": { - "blurb": "Extra headroom [dB]", - "construct": false, - "construct-only": false, - "default": "0", - "max": "60", - "min": "0", - "type-name": "gdouble", - "writable": true - }, - "message-forward": { - "blurb": "Forwards all children messages", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "pre-amp": { - "blurb": "Extra gain [dB]", - "construct": false, - "construct-only": false, - "default": "0", - "max": "60", - "min": "-60", - "type-name": "gdouble", - "writable": true - }, - "result-gain": { - "blurb": "Applied gain [dB]", - "construct": false, - "construct-only": false, - "default": "0", - "max": "120", - "min": "-120", - "type-name": "gdouble", - "writable": false + "src": { + "caps": "audio/AMR:\n channels: 1\n rate: 8000\naudio/AMR-WB:\n channels: 1\n rate: 16000\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtpamrpay": { + "author": "Wim Taymans ", + "description": "Payload-encode AMR or AMR-WB audio into RTP packets (RFC 3267)", + "hierarchy": [ + "GstRtpAMRPay", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP AMR payloader", + "pad-templates": { + "sink": { + "caps": "audio/AMR:\n channels: 1\n rate: 8000\naudio/AMR-WB:\n channels: 1\n rate: 16000\n", + "direction": "sink", + "presence": "always" }, - "target-gain": { - "blurb": "Applicable gain [dB]", - "construct": false, - "construct-only": false, - "default": "0", - "max": "120", - "min": "-120", - "type-name": "gdouble", - "writable": false + "src": { + "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 8000\n encoding-name: AMR\nencoding-params: 1\n octet-align: 1\n crc: 0\n robust-sorting: 0\n interleaving: 0\n mode-set: [ 0, 7 ]\nmode-change-period: [ 1, 2147483647 ]\nmode-change-neighbor: { (string)0, (string)1 }\n maxptime: [ 20, 2147483647 ]\n ptime: [ 20, 2147483647 ]\napplication/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 16000\n encoding-name: AMR-WB\nencoding-params: 1\n octet-align: 1\n crc: 0\n robust-sorting: 0\n interleaving: 0\n mode-set: [ 0, 7 ]\nmode-change-period: [ 1, 2147483647 ]\nmode-change-neighbor: { (string)0, (string)1 }\n maxptime: [ 20, 2147483647 ]\n ptime: [ 20, 2147483647 ]\n", + "direction": "src", + "presence": "always" } }, - "rank": "none" - } - }, - "filename": "gstreplaygain", - "license": "LGPL", - "package": "GStreamer Good Plug-ins git", - "source": "gst-plugins-good", - "tracers": {}, - "url": "Unknown package origin" - }, - "rtp": { - "description": "Real-time protocol plugins", - "elements": { - "asteriskh263": { - "author": "Neil Stratford ", - "description": "Extracts H263 video from RTP and encodes in Asterisk H263 format", + "properties": {}, + "rank": "secondary" + }, + "rtpbvdepay": { + "author": "Wim Taymans ", + "description": "Extracts BroadcomVoice audio from RTP packets (RFC 4298)", "hierarchy": [ - "GstAsteriskh263", + "GstRTPBVDepay", + "GstRTPBaseDepayload", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP Asterisk H263 depayloader", - "name": "asteriskh263", + "long-name": "RTP BroadcomVoice depayloader", "pad-templates": { "sink": { - "caps": "application/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: H263-1998\n", + "caps": "application/x-rtp:\n media: audio\n clock-rate: 8000\n encoding-name: BV16\napplication/x-rtp:\n media: audio\n clock-rate: 16000\n encoding-name: BV32\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "application/x-asteriskh263:\n", + "caps": "audio/x-bv:\n mode: { (int)16, (int)32 }\n", "direction": "src", "presence": "always" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true + "properties": {}, + "rank": "secondary" + }, + "rtpbvpay": { + "author": "Wim Taymans ", + "description": "Packetize BroadcomVoice audio streams into RTP packets (RFC 4298)", + "hierarchy": [ + "GstRTPBVPay", + "GstRTPBaseAudioPayload", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP BV Payloader", + "pad-templates": { + "sink": { + "caps": "audio/x-bv:\n mode: { (int)16, (int)32 }\n", + "direction": "sink", + "presence": "always" }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true + "src": { + "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 8000\n encoding-name: BV16\napplication/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 16000\n encoding-name: BV32\n", + "direction": "src", + "presence": "always" } }, - "rank": "none" + "properties": {}, + "rank": "secondary" }, - "rtpL16depay": { - "author": "Zeeshan Ali ,Wim Taymans ", - "description": "Extracts raw audio from RTP packets", + "rtpceltdepay": { + "author": "Wim Taymans ", + "description": "Extracts CELT audio from RTP packets", "hierarchy": [ - "GstRtpL16Depay", + "GstRtpCELTDepay", "GstRTPBaseDepayload", "GstElement", "GstObject", @@ -15923,72 +14068,83 @@ "GObject" ], "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP audio depayloader", - "name": "rtpL16depay", + "long-name": "RTP CELT depayloader", "pad-templates": { "sink": { - "caps": "application/x-rtp:\n media: audio\n clock-rate: [ 1, 2147483647 ]\n encoding-name: L16\napplication/x-rtp:\n media: audio\n payload: { (int)10, (int)11 }\n clock-rate: [ 1, 2147483647 ]\n", + "caps": "application/x-rtp:\n media: audio\n clock-rate: [ 32000, 48000 ]\n encoding-name: CELT\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "audio/x-raw:\n format: S16BE\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", + "caps": "audio/x-celt:\n", "direction": "src", "presence": "always" } }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true + "properties": {}, + "rank": "secondary" + }, + "rtpceltpay": { + "author": "Wim Taymans ", + "description": "Payload-encodes CELT audio into a RTP packet", + "hierarchy": [ + "GstRtpCELTPay", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP CELT payloader", + "pad-templates": { + "sink": { + "caps": "audio/x-celt:\n rate: [ 32000, 64000 ]\n channels: [ 1, 2 ]\n frame-size: [ 64, 512 ]\n", + "direction": "sink", + "presence": "always" }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true + "src": { + "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: [ 32000, 48000 ]\n encoding-name: CELT\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtpdvdepay": { + "author": "Marcel Moreaux , Wim Taymans ", + "description": "Depayloads DV from RTP packets (RFC 3189)", + "hierarchy": [ + "GstRTPDVDepay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP DV Depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: { (string)video, (string)audio }\n encoding-name: DV\n clock-rate: 90000\n encode: { (string)SD-VCR/525-60, (string)SD-VCR/625-50, (string)HD-VCR/1125-60, (string)HD-VCR/1250-50, (string)SDL-VCR/525-60, (string)SDL-VCR/625-50, (string)306M/525-60, (string)306M/625-50, (string)314M-25/525-60, (string)314M-25/625-50, (string)314M-50/525-60, (string)314M-50/625-50 }\n", + "direction": "sink", + "presence": "always" }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false + "src": { + "caps": "video/x-dv:\n", + "direction": "src", + "presence": "always" } }, + "properties": {}, "rank": "secondary" }, - "rtpL16pay": { - "author": "Wim Taymans ", - "description": "Payload-encode Raw audio into RTP packets (RFC 3551)", + "rtpdvpay": { + "author": "Marcel Moreaux , Wim Taymans ", + "description": "Payloads DV into RTP packets (RFC 3189)", "hierarchy": [ - "GstRtpL16Pay", - "GstRTPBaseAudioPayload", + "GstRTPDVPay", "GstRTPBasePayload", "GstElement", "GstObject", @@ -15996,185 +14152,40 @@ "GObject" ], "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP audio payloader", - "name": "rtpL16pay", + "long-name": "RTP DV Payloader", "pad-templates": { "sink": { - "caps": "audio/x-raw:\n format: S16BE\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", + "caps": "video/x-dv:\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: [ 1, 2147483647 ]\n encoding-name: L16\n channels: [ 1, 2147483647 ]\napplication/x-rtp:\n media: audio\n encoding-name: L16\n payload: 10\n clock-rate: 44100\napplication/x-rtp:\n media: audio\n encoding-name: L16\n payload: 11\n clock-rate: 44100\n", + "caps": "application/x-rtp:\n media: { (string)video, (string)audio }\n payload: [ 96, 127 ]\n encoding-name: DV\n clock-rate: 90000\n encode: { (string)SD-VCR/525-60, (string)SD-VCR/625-50, (string)HD-VCR/1125-60, (string)HD-VCR/1250-50, (string)SDL-VCR/525-60, (string)SDL-VCR/625-50, (string)306M/525-60, (string)306M/625-50, (string)314M-25/525-60, (string)314M-25/625-50, (string)314M-50/525-60, (string)314M-50/625-50 }\n", "direction": "src", "presence": "always" } }, "properties": { - "buffer-list": { - "blurb": "Use Buffer Lists", + "mode": { + "blurb": "The payload mode of payloading", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", + "controllable": false, + "default": "video (0)", + "mutable": "null", + "readable": true, + "type": "GstDVPayMode", "writable": true } }, "rank": "secondary" }, - "rtpL24depay": { - "author": "Zeeshan Ali ,Wim Taymans ,David Holroyd ", - "description": "Extracts raw 24-bit audio from RTP packets", + "rtpg722depay": { + "author": "Wim Taymans ", + "description": "Extracts G722 audio from RTP packets", "hierarchy": [ - "GstRtpL24Depay", + "GstRtpG722Depay", "GstRTPBaseDepayload", "GstElement", "GstObject", @@ -16183,71 +14194,83 @@ ], "klass": "Codec/Depayloader/Network/RTP", "long-name": "RTP audio depayloader", - "name": "rtpL24depay", "pad-templates": { "sink": { - "caps": "application/x-rtp:\n media: audio\n clock-rate: [ 1, 2147483647 ]\n encoding-name: L24\n", + "caps": "application/x-rtp:\n media: audio\n clock-rate: 8000\n encoding-name: G722\napplication/x-rtp:\n media: audio\n payload: 9\n clock-rate: [ 1, 2147483647 ]\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "audio/x-raw:\n format: S24BE\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", + "caps": "audio/G722:\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", "direction": "src", "presence": "always" } }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true + "properties": {}, + "rank": "secondary" + }, + "rtpg722pay": { + "author": "Wim Taymans ", + "description": "Payload-encode Raw audio into RTP packets (RFC 3551)", + "hierarchy": [ + "GstRtpG722Pay", + "GstRTPBaseAudioPayload", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP audio payloader", + "pad-templates": { + "sink": { + "caps": "audio/G722:\n rate: 16000\n channels: 1\n", + "direction": "sink", + "presence": "always" }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true + "src": { + "caps": "application/x-rtp:\n media: audio\n encoding-name: G722\n payload: 9\nencoding-params: 1\n clock-rate: 8000\napplication/x-rtp:\n media: audio\n encoding-name: G722\n payload: [ 96, 127 ]\nencoding-params: 1\n clock-rate: 8000\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtpg723depay": { + "author": "Wim Taymans ", + "description": "Extracts G.723 audio from RTP packets (RFC 3551)", + "hierarchy": [ + "GstRtpG723Depay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP G.723 depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: audio\n clock-rate: 8000\n encoding-name: G723\napplication/x-rtp:\n media: audio\n payload: 4\n clock-rate: 8000\n", + "direction": "sink", + "presence": "always" }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false + "src": { + "caps": "audio/G723:\n channels: 1\n rate: 8000\n", + "direction": "src", + "presence": "always" } }, + "properties": {}, "rank": "secondary" }, - "rtpL24pay": { - "author": "Wim Taymans ,David Holroyd ", - "description": "Payload-encode Raw 24-bit audio into RTP packets (RFC 3190)", + "rtpg723pay": { + "author": "Wim Taymans ", + "description": "Packetize G.723 audio into RTP packets", "hierarchy": [ - "GstRtpL24Pay", - "GstRTPBaseAudioPayload", + "GstRTPG723Pay", "GstRTPBasePayload", "GstElement", "GstObject", @@ -16255,185 +14278,110 @@ "GObject" ], "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP audio payloader", - "name": "rtpL24pay", + "long-name": "RTP G.723 payloader", "pad-templates": { "sink": { - "caps": "audio/x-raw:\n format: S24BE\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", + "caps": "audio/G723:\n channels: 1\n rate: 8000\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: [ 1, 2147483647 ]\n encoding-name: L24\n channels: [ 1, 2147483647 ]\n", + "caps": "application/x-rtp:\n media: audio\n payload: 4\n clock-rate: 8000\n encoding-name: G723\napplication/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 8000\n encoding-name: G723\n", "direction": "src", "presence": "always" } }, - "properties": { - "buffer-list": { - "blurb": "Use Buffer Lists", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true + "properties": {}, + "rank": "secondary" + }, + "rtpg726depay": { + "author": "Axis Communications ", + "description": "Extracts G.726 audio from RTP packets", + "hierarchy": [ + "GstRtpG726Depay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP G.726 depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: audio\n encoding-name: { (string)G726, (string)G726-16, (string)G726-24, (string)G726-32, (string)G726-40, (string)AAL2-G726-16, (string)AAL2-G726-24, (string)AAL2-G726-32, (string)AAL2-G726-40 }\n clock-rate: 8000\n", + "direction": "sink", + "presence": "always" }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", + "src": { + "caps": "audio/x-adpcm:\n channels: 1\n rate: 8000\n bitrate: { (int)16000, (int)24000, (int)32000, (int)40000 }\n block_align: { (int)2, (int)3, (int)4, (int)5 }\n layout: g726\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "force-aal2": { + "blurb": "Force AAL2 decoding for compatibility with bad payloaders", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true + } + }, + "rank": "secondary" + }, + "rtpg726pay": { + "author": "Axis Communications ", + "description": "Payload-encodes G.726 audio into a RTP packet", + "hierarchy": [ + "GstRtpG726Pay", + "GstRTPBaseAudioPayload", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP G.726 payloader", + "pad-templates": { + "sink": { + "caps": "audio/x-adpcm:\n channels: 1\n rate: 8000\n bitrate: { (int)16000, (int)24000, (int)32000, (int)40000 }\n layout: g726\n", + "direction": "sink", + "presence": "always" }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", + "src": { + "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 8000\n encoding-name: { (string)G726-16, (string)G726-24, (string)G726-32, (string)G726-40, (string)AAL2-G726-16, (string)AAL2-G726-24, (string)AAL2-G726-32, (string)AAL2-G726-40 }\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "force-aal2": { + "blurb": "Force AAL2 encoding for compatibility with bad depayloaders", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, "rank": "secondary" }, - "rtpL8depay": { - "author": "Zeeshan Ali ,Wim Taymans , GE Intelligent Platforms Embedded Systems, Inc.", - "description": "Extracts raw audio from RTP packets", + "rtpg729depay": { + "author": "Laurent Glayal ", + "description": "Extracts G.729 audio from RTP packets (RFC 3551)", "hierarchy": [ - "GstRtpL8Depay", + "GstRtpG729Depay", "GstRTPBaseDepayload", "GstElement", "GstObject", @@ -16441,72 +14389,83 @@ "GObject" ], "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP audio depayloader", - "name": "rtpL8depay", + "long-name": "RTP G.729 depayloader", "pad-templates": { "sink": { - "caps": "application/x-rtp:\n media: audio\n clock-rate: [ 1, 2147483647 ]\n encoding-name: L8\n", + "caps": "application/x-rtp:\n media: audio\n clock-rate: 8000\n encoding-name: G729\napplication/x-rtp:\n media: audio\n payload: 18\n clock-rate: 8000\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "audio/x-raw:\n format: U8\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", + "caps": "audio/G729:\n channels: 1\n rate: 8000\n", "direction": "src", "presence": "always" } }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true + "properties": {}, + "rank": "secondary" + }, + "rtpg729pay": { + "author": "Olivier Crete ", + "description": "Packetize G.729 audio into RTP packets", + "hierarchy": [ + "GstRTPG729Pay", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP G.729 payloader", + "pad-templates": { + "sink": { + "caps": "audio/G729:\n channels: 1\n rate: 8000\n", + "direction": "sink", + "presence": "always" }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true + "src": { + "caps": "application/x-rtp:\n media: audio\n payload: 18\n clock-rate: 8000\n encoding-name: G729\napplication/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 8000\n encoding-name: G729\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtpgsmdepay": { + "author": "Zeeshan Ali ", + "description": "Extracts GSM audio from RTP packets", + "hierarchy": [ + "GstRTPGSMDepay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP GSM depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: audio\n clock-rate: 8000\n encoding-name: GSM\napplication/x-rtp:\n media: audio\n payload: 3\n clock-rate: 8000\n", + "direction": "sink", + "presence": "always" }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false + "src": { + "caps": "audio/x-gsm:\n rate: 8000\n channels: 1\n", + "direction": "src", + "presence": "always" } }, + "properties": {}, "rank": "secondary" }, - "rtpL8pay": { - "author": "Wim Taymans , GE Intelligent Platforms Embedded Systems, Inc.", - "description": "Payload-encode Raw audio into RTP packets (RFC 3551)", + "rtpgsmpay": { + "author": "Zeeshan Ali ", + "description": "Payload-encodes GSM audio into a RTP packet", "hierarchy": [ - "GstRtpL8Pay", - "GstRTPBaseAudioPayload", + "GstRTPGSMPay", "GstRTPBasePayload", "GstElement", "GstObject", @@ -16514,185 +14473,98 @@ "GObject" ], "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP audio payloader", - "name": "rtpL8pay", + "long-name": "RTP GSM payloader", "pad-templates": { "sink": { - "caps": "audio/x-raw:\n format: U8\n layout: interleaved\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", + "caps": "audio/x-gsm:\n rate: 8000\n channels: 1\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: [ 1, 2147483647 ]\n encoding-name: L8\n channels: [ 1, 2147483647 ]\n", + "caps": "application/x-rtp:\n media: audio\n payload: 3\n clock-rate: 8000\n encoding-name: GSM\napplication/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 8000\n encoding-name: GSM\n", "direction": "src", "presence": "always" } }, - "properties": { - "buffer-list": { - "blurb": "Use Buffer Lists", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true + "properties": {}, + "rank": "secondary" + }, + "rtpgstdepay": { + "author": "Wim Taymans ", + "description": "Extracts GStreamer buffers from RTP packets", + "hierarchy": [ + "GstRtpGSTDepay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network", + "long-name": "GStreamer depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: application\n clock-rate: 90000\n encoding-name: X-GST\n", + "direction": "sink", + "presence": "always" }, - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false + "src": { + "caps": "ANY", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "marginal" + }, + "rtpgstpay": { + "author": "Wim Taymans ", + "description": "Payload GStreamer buffers as RTP packets", + "hierarchy": [ + "GstRtpGSTPay", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP GStreamer payloader", + "pad-templates": { + "sink": { + "caps": "ANY", + "direction": "sink", + "presence": "always" }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", + "src": { + "caps": "application/x-rtp:\n media: application\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: X-GST\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "config-interval": { + "blurb": "Interval for sending caps and TAG events in seconds (0 = disabled)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", + "max": "3600", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true } }, - "rank": "secondary" + "rank": "none" }, - "rtpac3depay": { - "author": "Wim Taymans ", - "description": "Extracts AC3 audio from RTP packets (RFC 4184)", + "rtph261depay": { + "author": "Stian Selnes ", + "description": "Extracts H261 video from RTP packets (RFC 4587)", "hierarchy": [ - "GstRtpAC3Depay", + "GstRtpH261Depay", "GstRTPBaseDepayload", "GstElement", "GstObject", @@ -16700,71 +14572,83 @@ "GObject" ], "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP AC3 depayloader", - "name": "rtpac3depay", + "long-name": "RTP H261 depayloader", "pad-templates": { "sink": { - "caps": "application/x-rtp:\n media: audio\n clock-rate: { (int)32000, (int)44100, (int)48000 }\n encoding-name: AC3\n", + "caps": "application/x-rtp:\n media: video\n payload: 31\n clock-rate: 90000\n encoding-name: H261\napplication/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: H261\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "audio/ac3:\n", + "caps": "video/x-h261:\n", "direction": "src", "presence": "always" } }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true + "properties": {}, + "rank": "secondary" + }, + "rtph261pay": { + "author": "Stian Selnes ", + "description": "Payload-encodes H261 video in RTP packets (RFC 4587)", + "hierarchy": [ + "GstRtpH261Pay", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP H261 packet payloader", + "pad-templates": { + "sink": { + "caps": "video/x-h261:\n", + "direction": "sink", + "presence": "always" }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true + "src": { + "caps": "application/x-rtp:\n media: video\n payload: 31\n clock-rate: 90000\n encoding-name: H261\napplication/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: H261\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtph263depay": { + "author": "Philippe Kalaf , Edward Hervey ", + "description": "Extracts H263 video from RTP packets (RFC 2190)", + "hierarchy": [ + "GstRtpH263Depay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP H263 depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: video\n payload: 34\n clock-rate: 90000\napplication/x-rtp:\n media: video\n clock-rate: 90000\n encoding-name: H263\n", + "direction": "sink", + "presence": "always" }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false + "src": { + "caps": "video/x-h263:\n variant: itu\n h263version: h263\n", + "direction": "src", + "presence": "always" } }, + "properties": {}, "rank": "secondary" }, - "rtpac3pay": { - "author": "Wim Taymans ", - "description": "Payload AC3 audio as RTP packets (RFC 4184)", + "rtph263pay": { + "author": "Neil Stratford Dejan Sakelsak ", + "description": "Payload-encodes H263 video in RTP packets (RFC 2190)", "hierarchy": [ - "GstRtpAC3Pay", + "GstRtpH263Pay", "GstRTPBasePayload", "GstElement", "GstObject", @@ -16772,177 +14656,109 @@ "GObject" ], "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP AC3 audio payloader", - "name": "rtpac3pay", + "long-name": "RTP H263 packet payloader", "pad-templates": { "sink": { - "caps": "audio/ac3:\naudio/x-ac3:\n", + "caps": "video/x-h263:\n variant: itu\n h263version: h263\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: { (int)32000, (int)44100, (int)48000 }\n encoding-name: AC3\n", + "caps": "application/x-rtp:\n media: video\n payload: 34\n clock-rate: 90000\n encoding-name: H263\napplication/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: H263\n", "direction": "src", "presence": "always" } }, "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", + "modea-only": { + "blurb": "Disable packetization modes B and C", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true + } + }, + "rank": "secondary" + }, + "rtph263pdepay": { + "author": "Wim Taymans ", + "description": "Extracts H263/+/++ video from RTP packets (RFC 4629)", + "hierarchy": [ + "GstRtpH263PDepay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP H263 depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: video\n clock-rate: [ 1, 2147483647 ]\n encoding-name: H263-1998\napplication/x-rtp:\n media: video\n clock-rate: [ 1, 2147483647 ]\n encoding-name: H263-2000\n", + "direction": "sink", + "presence": "always" }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false + "src": { + "caps": "video/x-h263:\n variant: itu\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtph263ppay": { + "author": "Wim Taymans ", + "description": "Payload-encodes H263/+/++ video in RTP packets (RFC 4629)", + "hierarchy": [ + "GstRtpH263PPay", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP H263 payloader", + "pad-templates": { + "sink": { + "caps": "video/x-h263:\n variant: itu\n", + "direction": "sink", + "presence": "always" }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", + "src": { + "caps": "application/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: H263-1998\napplication/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: H263-2000\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "fragmentation-mode": { + "blurb": "Packet Fragmentation Mode", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", + "controllable": false, + "default": "normal (0)", + "mutable": "null", + "readable": true, + "type": "GstFragmentationMode", "writable": true } }, "rank": "secondary" }, - "rtpamrdepay": { + "rtph264depay": { "author": "Wim Taymans ", - "description": "Extracts AMR or AMR-WB audio from RTP packets (RFC 3267)", + "description": "Extracts H264 video from RTP packets (RFC 3984)", "hierarchy": [ - "GstRtpAMRDepay", + "GstRtpH264Depay", "GstRTPBaseDepayload", "GstElement", "GstObject", @@ -16950,71 +14766,122 @@ "GObject" ], "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP AMR depayloader", - "name": "rtpamrdepay", + "long-name": "RTP H264 depayloader", "pad-templates": { "sink": { - "caps": "application/x-rtp:\n media: audio\n clock-rate: 8000\n encoding-name: AMR\n octet-align: 1\napplication/x-rtp:\n media: audio\n clock-rate: 16000\n encoding-name: AMR-WB\n octet-align: 1\n", + "caps": "application/x-rtp:\n media: video\n clock-rate: 90000\n encoding-name: H264\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "audio/AMR:\n channels: 1\n rate: 8000\naudio/AMR-WB:\n channels: 1\n rate: 16000\n", + "caps": "video/x-h264:\n stream-format: avc\n alignment: au\nvideo/x-h264:\n stream-format: byte-stream\n alignment: { (string)nal, (string)au }\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtph264pay": { + "author": "Laurent Glayal ", + "description": "Payload-encode H264 video into RTP packets (RFC 3984)", + "hierarchy": [ + "GstRtpH264Pay", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP H264 payloader", + "pad-templates": { + "sink": { + "caps": "video/x-h264:\n stream-format: avc\n alignment: au\nvideo/x-h264:\n stream-format: byte-stream\n alignment: { (string)nal, (string)au }\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "application/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: H264\n", "direction": "src", "presence": "always" } }, "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", + "aggregate-mode": { + "blurb": "Bundle suitable SPS/PPS NAL units into STAP-A aggregate packets", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "default": "none (0)", + "mutable": "null", + "readable": true, + "type": "GstRtpH264AggregateMode", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "config-interval": { + "blurb": "Send SPS and PPS Insertion Interval in seconds (sprop parameter sets will be multiplexed in the data stream when detected.) (0 = disabled, -1 = send with every IDR frame)", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "0", + "max": "3600", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", + "sprop-parameter-sets": { + "blurb": "The base64 sprop-parameter-sets to set in out caps (set to NULL to extract from stream)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true + } + }, + "rank": "secondary" + }, + "rtph265depay": { + "author": "Jurgen Slowack ", + "description": "Extracts H265 video from RTP packets (RFC 7798)", + "hierarchy": [ + "GstRtpH265Depay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP H265 depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: video\n clock-rate: 90000\n encoding-name: H265\n", + "direction": "sink", + "presence": "always" }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false + "src": { + "caps": "video/x-h265:\n stream-format: hvc1\n alignment: au\nvideo/x-h265:\n stream-format: byte-stream\n alignment: { (string)nal, (string)au }\n", + "direction": "src", + "presence": "always" } }, + "properties": {}, "rank": "secondary" }, - "rtpamrpay": { - "author": "Wim Taymans ", - "description": "Payload-encode AMR or AMR-WB audio into RTP packets (RFC 3267)", + "rtph265pay": { + "author": "Jurgen Slowack ", + "description": "Payload-encode H265 video into RTP packets (RFC 7798)", "hierarchy": [ - "GstRtpAMRPay", + "GstRtpH265Pay", "GstRTPBasePayload", "GstElement", "GstObject", @@ -17022,177 +14889,54 @@ "GObject" ], "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP AMR payloader", - "name": "rtpamrpay", + "long-name": "RTP H265 payloader", "pad-templates": { "sink": { - "caps": "audio/AMR:\n channels: 1\n rate: 8000\naudio/AMR-WB:\n channels: 1\n rate: 16000\n", + "caps": "video/x-h265:\n stream-format: hvc1\n alignment: au\nvideo/x-h265:\n stream-format: byte-stream\n alignment: { (string)nal, (string)au }\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 8000\n encoding-name: AMR\nencoding-params: 1\n octet-align: 1\n crc: 0\n robust-sorting: 0\n interleaving: 0\n mode-set: [ 0, 7 ]\nmode-change-period: [ 1, 2147483647 ]\nmode-change-neighbor: { (string)0, (string)1 }\n maxptime: [ 20, 2147483647 ]\n ptime: [ 20, 2147483647 ]\napplication/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 16000\n encoding-name: AMR-WB\nencoding-params: 1\n octet-align: 1\n crc: 0\n robust-sorting: 0\n interleaving: 0\n mode-set: [ 0, 7 ]\nmode-change-period: [ 1, 2147483647 ]\nmode-change-neighbor: { (string)0, (string)1 }\n maxptime: [ 20, 2147483647 ]\n ptime: [ 20, 2147483647 ]\n", + "caps": "application/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: H265\n", "direction": "src", "presence": "always" } }, "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", + "aggregate-mode": { + "blurb": "Bundle suitable SPS/PPS NAL units into aggregate packets.", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", + "controllable": false, + "default": "none (0)", + "mutable": "null", + "readable": true, + "type": "GstRtpH265AggregateMode", "writable": true }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", + "config-interval": { + "blurb": "Send VPS, SPS and PPS Insertion Interval in seconds (sprop parameter sets will be multiplexed in the data stream when detected.) (0 = disabled, -1 = send with every IDR frame)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", + "max": "3600", "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true } }, "rank": "secondary" }, - "rtpbvdepay": { - "author": "Wim Taymans ", - "description": "Extracts BroadcomVoice audio from RTP packets (RFC 4298)", + "rtpilbcdepay": { + "author": "Philippe Kalaf ", + "description": "Extracts iLBC audio from RTP packets (RFC 3952)", "hierarchy": [ - "GstRTPBVDepay", + "GstRTPiLBCDepay", "GstRTPBaseDepayload", "GstElement", "GstObject", @@ -17200,71 +14944,40 @@ "GObject" ], "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP BroadcomVoice depayloader", - "name": "rtpbvdepay", + "long-name": "RTP iLBC depayloader", "pad-templates": { "sink": { - "caps": "application/x-rtp:\n media: audio\n clock-rate: 8000\n encoding-name: BV16\napplication/x-rtp:\n media: audio\n clock-rate: 16000\n encoding-name: BV32\n", + "caps": "application/x-rtp:\n media: audio\n clock-rate: 8000\n encoding-name: ILBC\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "audio/x-bv:\n mode: { (int)16, (int)32 }\n", + "caps": "audio/x-iLBC:\n mode: { (int)20, (int)30 }\n", "direction": "src", "presence": "always" } }, "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", + "mode": { + "blurb": "iLBC frame mode", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "30ms (30)", + "mutable": "null", + "readable": true, + "type": "iLBCMode", "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false } }, "rank": "secondary" }, - "rtpbvpay": { - "author": "Wim Taymans ", - "description": "Packetize BroadcomVoice audio streams into RTP packets (RFC 4298)", + "rtpilbcpay": { + "author": "Philippe Kalaf ", + "description": "Packetize iLBC audio streams into RTP packets", "hierarchy": [ - "GstRTPBVPay", + "GstRTPILBCPay", "GstRTPBaseAudioPayload", "GstRTPBasePayload", "GstElement", @@ -17273,185 +14986,224 @@ "GObject" ], "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP BV Payloader", - "name": "rtpbvpay", + "long-name": "RTP iLBC Payloader", "pad-templates": { "sink": { - "caps": "audio/x-bv:\n mode: { (int)16, (int)32 }\n", + "caps": "audio/x-iLBC:\n mode: { (int)20, (int)30 }\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 8000\n encoding-name: BV16\napplication/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 16000\n encoding-name: BV32\n", + "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 8000\n encoding-name: ILBC\n mode: { (string)20, (string)30 }\n", "direction": "src", "presence": "always" } }, - "properties": { - "buffer-list": { - "blurb": "Use Buffer Lists", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true + "properties": {}, + "rank": "secondary" + }, + "rtpj2kdepay": { + "author": "Wim Taymans ", + "description": "Extracts JPEG 2000 video from RTP packets (RFC 5371)", + "hierarchy": [ + "GstRtpJ2KDepay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP JPEG 2000 depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: video\n clock-rate: 90000\n sampling: { (string)RGB, (string)BGR, (string)RGBA, (string)BGRA, (string)YCbCrA, (string)YCbCr-4:4:4, (string)YCbCr-4:2:2, (string)YCbCr-4:2:0, (string)YCbCr-4:1:1, (string)GRAYSCALE }\n encoding-name: JPEG2000\napplication/x-rtp:\n media: video\n clock-rate: 90000\n colorspace: { (string)sRGB, (string)sYUV, (string)GRAY }\n encoding-name: JPEG2000\n", + "direction": "sink", + "presence": "always" }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true + "src": { + "caps": "image/x-jpc:\n colorspace: { (string)sRGB, (string)sYUV, (string)GRAY }\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtpj2kpay": { + "author": "Wim Taymans ", + "description": "Payload-encodes JPEG 2000 pictures into RTP packets (RFC 5371)", + "hierarchy": [ + "GstRtpJ2KPay", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP JPEG 2000 payloader", + "pad-templates": { + "sink": { + "caps": "image/x-jpc:\n sampling: { (string)RGB, (string)BGR, (string)RGBA, (string)BGRA, (string)YCbCrA, (string)YCbCr-4:4:4, (string)YCbCr-4:2:2, (string)YCbCr-4:2:0, (string)YCbCr-4:1:1, (string)GRAYSCALE }\n", + "direction": "sink", + "presence": "always" }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true + "src": { + "caps": "application/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n sampling: { (string)RGB, (string)BGR, (string)RGBA, (string)BGRA, (string)YCbCrA, (string)YCbCr-4:4:4, (string)YCbCr-4:2:2, (string)YCbCr-4:2:0, (string)YCbCr-4:1:1, (string)GRAYSCALE }\n encoding-name: JPEG2000\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtpjpegdepay": { + "author": "Wim Taymans ", + "description": "Extracts JPEG video from RTP packets (RFC 2435)", + "hierarchy": [ + "GstRtpJPEGDepay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP JPEG depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: video\n clock-rate: 90000\n encoding-name: JPEG\napplication/x-rtp:\n media: video\n payload: 26\n clock-rate: 90000\n", + "direction": "sink", + "presence": "always" }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true + "src": { + "caps": "image/jpeg:\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtpjpegpay": { + "author": "Axis Communications ", + "description": "Payload-encodes JPEG pictures into RTP packets (RFC 2435)", + "hierarchy": [ + "GstRtpJPEGPay", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP JPEG payloader", + "pad-templates": { + "sink": { + "caps": "image/jpeg:\nvideo/x-jpeg:\n", + "direction": "sink", + "presence": "always" }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", + "src": { + "caps": "application/x-rtp:\n media: video\n payload: 26\n clock-rate: 90000\n encoding-name: JPEG\n width: [ 1, 65536 ]\n height: [ 1, 65536 ]\napplication/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: JPEG\n width: [ 1, 65536 ]\n height: [ 1, 65536 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "quality": { + "blurb": "Quality factor on JPEG data (unused)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "65535", + "controllable": false, + "default": "255", + "max": "255", "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", + "type": { + "blurb": "Default JPEG Type, overwritten by SOF when present", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "-1", - "max": "-1", + "controllable": false, + "default": "1", + "max": "255", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true + } + }, + "rank": "secondary" + }, + "rtpklvdepay": { + "author": "Tim-Philipp Müller ", + "description": "Extracts KLV (SMPTE ST 336) metadata from RTP packets", + "hierarchy": [ + "GstRtpKlvDepay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP KLV Depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: application\n clock-rate: [ 1, 2147483647 ]\n encoding-name: SMPTE336M\n", + "direction": "sink", + "presence": "always" }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false + "src": { + "caps": "meta/x-klv:\n parsed: true\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtpklvpay": { + "author": "Tim-Philipp Müller ", + "description": "Payloads KLV (SMPTE ST 336) metadata as RTP packets", + "hierarchy": [ + "GstRtpKlvPay", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP KLV Payloader", + "pad-templates": { + "sink": { + "caps": "meta/x-klv:\n parsed: true\n", + "direction": "sink", + "presence": "always" }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true + "src": { + "caps": "application/x-rtp:\n media: application\n clock-rate: [ 1, 2147483647 ]\n encoding-name: SMPTE336M\n", + "direction": "src", + "presence": "always" } }, + "properties": {}, "rank": "secondary" }, - "rtpceltdepay": { + "rtpmp1sdepay": { "author": "Wim Taymans ", - "description": "Extracts CELT audio from RTP packets", + "description": "Extracts MPEG1 System Streams from RTP packets (RFC 3555)", "hierarchy": [ - "GstRtpCELTDepay", + "GstRtpMP1SDepay", "GstRTPBaseDepayload", "GstElement", "GstObject", @@ -17459,71 +15211,70 @@ "GObject" ], "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP CELT depayloader", - "name": "rtpceltdepay", + "long-name": "RTP MPEG1 System Stream depayloader", "pad-templates": { "sink": { - "caps": "application/x-rtp:\n media: audio\n clock-rate: [ 32000, 48000 ]\n encoding-name: CELT\n", + "caps": "application/x-rtp:\n media: other\n clock-rate: [ 1, 2147483647 ]\n encoding-name: MP1S\napplication/x-rtp:\n media: video\n clock-rate: [ 1, 2147483647 ]\n encoding-name: MP1S\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "audio/x-celt:\n", + "caps": "video/mpeg:\n systemstream: true\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtpmp2tdepay": { + "author": "Wim Taymans , Thijs Vermeir ", + "description": "Extracts MPEG2 TS from RTP packets (RFC 2250)", + "hierarchy": [ + "GstRtpMP2TDepay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP MPEG Transport Stream depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: video\n clock-rate: [ 1, 2147483647 ]\n encoding-name: { (string)MP2T, (string)MP2T-ES }\napplication/x-rtp:\n media: video\n payload: 33\n clock-rate: [ 1, 2147483647 ]\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "video/mpegts:\n packetsize: 188\n systemstream: true\n", "direction": "src", "presence": "always" } }, "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", + "skip-first-bytes": { + "blurb": "The amount of bytes that need to be skipped at the beginning of the payload", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "100", - "max": "2147483647", + "controllable": false, + "default": "0", + "max": "-1", "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false } }, "rank": "secondary" }, - "rtpceltpay": { + "rtpmp2tpay": { "author": "Wim Taymans ", - "description": "Payload-encodes CELT audio into a RTP packet", + "description": "Payload-encodes MPEG2 TS into RTP packets (RFC 2250)", "hierarchy": [ - "GstRtpCELTPay", + "GstRTPMP2TPay", "GstRTPBasePayload", "GstElement", "GstObject", @@ -17531,177 +15282,83 @@ "GObject" ], "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP CELT payloader", - "name": "rtpceltpay", + "long-name": "RTP MPEG2 Transport Stream payloader", "pad-templates": { "sink": { - "caps": "audio/x-celt:\n rate: [ 32000, 64000 ]\n channels: [ 1, 2 ]\n frame-size: [ 64, 512 ]\n", + "caps": "video/mpegts:\n packetsize: 188\n systemstream: true\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: [ 32000, 48000 ]\n encoding-name: CELT\n", + "caps": "application/x-rtp:\n media: video\n payload: 33\n clock-rate: 90000\n encoding-name: MP2T\napplication/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: MP2T\n", "direction": "src", "presence": "always" } }, - "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false + "properties": {}, + "rank": "secondary" + }, + "rtpmp4adepay": { + "author": "Nokia Corporation (contact ), Wim Taymans ", + "description": "Extracts MPEG4 audio from RTP packets (RFC 3016)", + "hierarchy": [ + "GstRtpMP4ADepay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP MPEG4 audio depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: audio\n clock-rate: [ 1, 2147483647 ]\n encoding-name: MP4A-LATM\n", + "direction": "sink", + "presence": "always" }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false + "src": { + "caps": "audio/mpeg:\n mpegversion: 4\n framed: { (boolean)false, (boolean)true }\n stream-format: raw\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtpmp4apay": { + "author": "Wim Taymans ", + "description": "Payload MPEG4 audio as RTP packets (RFC 3016)", + "hierarchy": [ + "GstRtpMP4APay", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP MPEG4 audio payloader", + "pad-templates": { + "sink": { + "caps": "audio/mpeg:\n mpegversion: 4\n stream-format: raw\n", + "direction": "sink", + "presence": "always" }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true + "src": { + "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: [ 1, 2147483647 ]\n encoding-name: MP4A-LATM\n", + "direction": "src", + "presence": "always" } }, + "properties": {}, "rank": "secondary" }, - "rtpdvdepay": { - "author": "Marcel Moreaux , Wim Taymans ", - "description": "Depayloads DV from RTP packets (RFC 3189)", + "rtpmp4gdepay": { + "author": "Wim Taymans ", + "description": "Extracts MPEG4 elementary streams from RTP packets (RFC 3640)", "hierarchy": [ - "GstRTPDVDepay", + "GstRtpMP4GDepay", "GstRTPBaseDepayload", "GstElement", "GstObject", @@ -17709,71 +15366,83 @@ "GObject" ], "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP DV Depayloader", - "name": "rtpdvdepay", + "long-name": "RTP MPEG4 ES depayloader", "pad-templates": { "sink": { - "caps": "application/x-rtp:\n media: { (string)video, (string)audio }\n encoding-name: DV\n clock-rate: 90000\n encode: { (string)SD-VCR/525-60, (string)SD-VCR/625-50, (string)HD-VCR/1125-60, (string)HD-VCR/1250-50, (string)SDL-VCR/525-60, (string)SDL-VCR/625-50, (string)306M/525-60, (string)306M/625-50, (string)314M-25/525-60, (string)314M-25/625-50, (string)314M-50/525-60, (string)314M-50/625-50 }\n", + "caps": "application/x-rtp:\n media: { (string)video, (string)audio, (string)application }\n clock-rate: [ 1, 2147483647 ]\n encoding-name: MPEG4-GENERIC\n mode: { (string)generic, (string)CELP-cbr, (string)CELP-vbr, (string)AAC-lbr, (string)AAC-hbr, (string)aac-hbr }\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "video/x-dv:\n", + "caps": "video/mpeg:\n mpegversion: 4\n systemstream: false\naudio/mpeg:\n mpegversion: 4\n stream-format: raw\n", "direction": "src", "presence": "always" } }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true + "properties": {}, + "rank": "secondary" + }, + "rtpmp4gpay": { + "author": "Wim Taymans ", + "description": "Payload MPEG4 elementary streams as RTP packets (RFC 3640)", + "hierarchy": [ + "GstRtpMP4GPay", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP MPEG4 ES payloader", + "pad-templates": { + "sink": { + "caps": "video/mpeg:\n mpegversion: 4\n systemstream: false\naudio/mpeg:\n mpegversion: 4\n stream-format: raw\n", + "direction": "sink", + "presence": "always" }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true + "src": { + "caps": "application/x-rtp:\n media: { (string)video, (string)audio, (string)application }\n payload: [ 96, 127 ]\n clock-rate: [ 1, 2147483647 ]\n encoding-name: MPEG4-GENERIC\n streamtype: { (string)4, (string)5 }\n mode: { (string)generic, (string)CELP-cbr, (string)CELP-vbr, (string)AAC-lbr, (string)AAC-hbr }\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtpmp4vdepay": { + "author": "Wim Taymans ", + "description": "Extracts MPEG4 video from RTP packets (RFC 3016)", + "hierarchy": [ + "GstRtpMP4VDepay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP MPEG4 video depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: video\n clock-rate: [ 1, 2147483647 ]\n encoding-name: MP4V-ES\n", + "direction": "sink", + "presence": "always" }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false + "src": { + "caps": "video/mpeg:\n mpegversion: 4\n systemstream: false\n", + "direction": "src", + "presence": "always" } }, + "properties": {}, "rank": "secondary" }, - "rtpdvpay": { - "author": "Marcel Moreaux , Wim Taymans ", - "description": "Payloads DV into RTP packets (RFC 3189)", + "rtpmp4vpay": { + "author": "Wim Taymans ", + "description": "Payload MPEG-4 video as RTP packets (RFC 3016)", "hierarchy": [ - "GstRTPDVPay", + "GstRtpMP4VPay", "GstRTPBasePayload", "GstElement", "GstObject", @@ -17781,203 +15450,42 @@ "GObject" ], "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP DV Payloader", - "name": "rtpdvpay", + "long-name": "RTP MPEG4 Video payloader", "pad-templates": { "sink": { - "caps": "video/x-dv:\n", + "caps": "video/mpeg:\n mpegversion: 4\n systemstream: false\nvideo/x-divx:\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "application/x-rtp:\n media: { (string)video, (string)audio }\n payload: [ 96, 127 ]\n encoding-name: DV\n clock-rate: 90000\n encode: { (string)SD-VCR/525-60, (string)SD-VCR/625-50, (string)HD-VCR/1125-60, (string)HD-VCR/1250-50, (string)SDL-VCR/525-60, (string)SDL-VCR/625-50, (string)306M/525-60, (string)306M/625-50, (string)314M-25/525-60, (string)314M-25/625-50, (string)314M-50/525-60, (string)314M-50/625-50 }\n", + "caps": "application/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: [ 1, 2147483647 ]\n encoding-name: MP4V-ES\n", "direction": "src", "presence": "always" } }, "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", + "config-interval": { + "blurb": "Send Config Insertion Interval in seconds (configuration headers will be multiplexed in the data stream when detected.) (0 = disabled, -1 = send with every IDR frame)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", + "controllable": false, + "default": "0", + "max": "3600", "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mode": { - "blurb": "The payload mode of payloading", - "construct": false, - "construct-only": false, - "default": "video (0)", - "enum": true, - "type-name": "GstDVPayMode", - "values": [ - { - "desc": "Video only", - "name": "video", - "value": "0" - }, - { - "desc": "Video and Audio bundled", - "name": "bundled", - "value": "1" - }, - { - "desc": "Audio only", - "name": "audio", - "value": "2" - } - ], - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true } }, - "rank": "secondary" + "rank": "secondary + 1" }, - "rtpg722depay": { + "rtpmpadepay": { "author": "Wim Taymans ", - "description": "Extracts G722 audio from RTP packets", + "description": "Extracts MPEG audio from RTP packets (RFC 2038)", "hierarchy": [ - "GstRtpG722Depay", + "GstRtpMPADepay", "GstRTPBaseDepayload", "GstElement", "GstObject", @@ -17985,72 +15493,111 @@ "GObject" ], "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP audio depayloader", - "name": "rtpg722depay", + "long-name": "RTP MPEG audio depayloader", "pad-templates": { "sink": { - "caps": "application/x-rtp:\n media: audio\n clock-rate: 8000\n encoding-name: G722\napplication/x-rtp:\n media: audio\n payload: 9\n clock-rate: [ 1, 2147483647 ]\n", + "caps": "application/x-rtp:\n media: audio\n payload: 14\n clock-rate: 90000\napplication/x-rtp:\n media: audio\n encoding-name: MPA\n clock-rate: [ 1, 2147483647 ]\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "audio/G722:\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n", + "caps": "audio/mpeg:\n mpegversion: 1\n", "direction": "src", "presence": "always" } }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true + "properties": {}, + "rank": "secondary" + }, + "rtpmpapay": { + "author": "Wim Taymans ", + "description": "Payload MPEG audio as RTP packets (RFC 2038)", + "hierarchy": [ + "GstRtpMPAPay", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP MPEG audio payloader", + "pad-templates": { + "sink": { + "caps": "audio/mpeg:\n mpegversion: 1\n", + "direction": "sink", + "presence": "always" }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true + "src": { + "caps": "application/x-rtp:\n media: audio\n payload: 14\n clock-rate: 90000\napplication/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: MPA\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtpmparobustdepay": { + "author": "Mark Nauwelaerts ", + "description": "Extracts MPEG audio from RTP packets (RFC 5219)", + "hierarchy": [ + "GstRtpMPARobustDepay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP MPEG audio depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: audio\n clock-rate: 90000\n encoding-name: MPA-ROBUST\napplication/x-rtp:\n media: audio\n clock-rate: [ 1, 2147483647 ]\n encoding-name: { (string)X-MP3-DRAFT-00, (string)X-MP3-DRAFT-01, (string)X-MP3-DRAFT-02, (string)X-MP3-DRAFT-03, (string)X-MP3-DRAFT-04, (string)X-MP3-DRAFT-05, (string)X-MP3-DRAFT-06 }\n", + "direction": "sink", + "presence": "always" }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false + "src": { + "caps": "audio/mpeg:\n mpegversion: 1\n", + "direction": "src", + "presence": "always" } }, + "properties": {}, "rank": "secondary" }, - "rtpg722pay": { + "rtpmpvdepay": { "author": "Wim Taymans ", - "description": "Payload-encode Raw audio into RTP packets (RFC 3551)", + "description": "Extracts MPEG video from RTP packets (RFC 2250)", "hierarchy": [ - "GstRtpG722Pay", - "GstRTPBaseAudioPayload", + "GstRtpMPVDepay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP MPEG video depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: video\n clock-rate: 90000\n encoding-name: MPV\napplication/x-rtp:\n media: video\n payload: 32\n clock-rate: 90000\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "video/mpeg:\n mpegversion: 2\n systemstream: false\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtpmpvpay": { + "author": "Thijs Vermeir ", + "description": "Payload-encodes MPEG2 ES into RTP packets (RFC 2250)", + "hierarchy": [ + "GstRTPMPVPay", "GstRTPBasePayload", "GstElement", "GstObject", @@ -18058,185 +15605,27 @@ "GObject" ], "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP audio payloader", - "name": "rtpg722pay", + "long-name": "RTP MPEG2 ES video payloader", "pad-templates": { "sink": { - "caps": "audio/G722:\n rate: 16000\n channels: 1\n", + "caps": "video/mpeg:\n mpegversion: 2\n systemstream: false\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "application/x-rtp:\n media: audio\n encoding-name: G722\n payload: 9\nencoding-params: 1\n clock-rate: 8000\napplication/x-rtp:\n media: audio\n encoding-name: G722\n payload: [ 96, 127 ]\nencoding-params: 1\n clock-rate: 8000\n", + "caps": "application/x-rtp:\n media: video\n payload: 32\n clock-rate: 90000\n encoding-name: MPV\napplication/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: MPV\n", "direction": "src", "presence": "always" } }, - "properties": { - "buffer-list": { - "blurb": "Use Buffer Lists", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "9", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)9, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, + "properties": {}, "rank": "secondary" }, - "rtpg723depay": { - "author": "Wim Taymans ", - "description": "Extracts G.723 audio from RTP packets (RFC 3551)", + "rtpopusdepay": { + "author": "Danilo Cesar Lemes de Paula ", + "description": "Extracts Opus audio from RTP packets", "hierarchy": [ - "GstRtpG723Depay", + "GstRTPOpusDepay", "GstRTPBaseDepayload", "GstElement", "GstObject", @@ -18244,71 +15633,84 @@ "GObject" ], "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP G.723 depayloader", - "name": "rtpg723depay", + "long-name": "RTP Opus packet depayloader", "pad-templates": { "sink": { - "caps": "application/x-rtp:\n media: audio\n clock-rate: 8000\n encoding-name: G723\napplication/x-rtp:\n media: audio\n payload: 4\n clock-rate: 8000\n", + "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 48000\n encoding-name: { (string)OPUS, (string)X-GST-OPUS-DRAFT-SPITTKA-00 }\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "audio/G723:\n channels: 1\n rate: 8000\n", + "caps": "audio/x-opus:\nchannel-mapping-family: 0\n", "direction": "src", "presence": "always" } }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true + "properties": {}, + "rank": "primary" + }, + "rtpopuspay": { + "author": "Danilo Cesar Lemes de Paula ", + "description": "Puts Opus audio in RTP packets", + "hierarchy": [ + "GstRtpOPUSPay", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP Opus payloader", + "pad-templates": { + "sink": { + "caps": "audio/x-opus:\nchannel-mapping-family: 0\n", + "direction": "sink", + "presence": "always" }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true + "src": { + "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 48000\nencoding-params: 2\n encoding-name: { (string)OPUS, (string)X-GST-OPUS-DRAFT-SPITTKA-00 }\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "primary" + }, + "rtppcmadepay": { + "author": "Edgard Lima , Zeeshan Ali ", + "description": "Extracts PCMA audio from RTP packets", + "hierarchy": [ + "GstRtpPcmaDepay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP PCMA depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: audio\n payload: 8\n clock-rate: 8000\napplication/x-rtp:\n media: audio\n clock-rate: [ 1, 2147483647 ]\n encoding-name: PCMA\n", + "direction": "sink", + "presence": "always" }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false + "src": { + "caps": "audio/x-alaw:\n channels: 1\n rate: [ 1, 2147483647 ]\n", + "direction": "src", + "presence": "always" } }, + "properties": {}, "rank": "secondary" }, - "rtpg723pay": { - "author": "Wim Taymans ", - "description": "Packetize G.723 audio into RTP packets", + "rtppcmapay": { + "author": "Edgard Lima ", + "description": "Payload-encodes PCMA audio into a RTP packet", "hierarchy": [ - "GstRTPG723Pay", + "GstRtpPcmaPay", + "GstRTPBaseAudioPayload", "GstRTPBasePayload", "GstElement", "GstObject", @@ -18316,452 +15718,362 @@ "GObject" ], "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP G.723 payloader", - "name": "rtpg723pay", + "long-name": "RTP PCMA payloader", "pad-templates": { "sink": { - "caps": "audio/G723:\n channels: 1\n rate: 8000\n", + "caps": "audio/x-alaw:\n channels: 1\n rate: 8000\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "application/x-rtp:\n media: audio\n payload: 4\n clock-rate: 8000\n encoding-name: G723\napplication/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 8000\n encoding-name: G723\n", + "caps": "application/x-rtp:\n media: audio\n payload: 8\n clock-rate: 8000\n encoding-name: PCMA\napplication/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: [ 1, 2147483647 ]\n encoding-name: PCMA\n", "direction": "src", "presence": "always" } }, - "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true + "properties": {}, + "rank": "secondary" + }, + "rtppcmudepay": { + "author": "Edgard Lima , Zeeshan Ali ", + "description": "Extracts PCMU audio from RTP packets", + "hierarchy": [ + "GstRtpPcmuDepay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP PCMU depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: audio\n payload: 0\n clock-rate: 8000\napplication/x-rtp:\n media: audio\n encoding-name: PCMU\n clock-rate: [ 1, 2147483647 ]\n", + "direction": "sink", + "presence": "always" }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true + "src": { + "caps": "audio/x-mulaw:\n channels: 1\n rate: [ 1, 2147483647 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtppcmupay": { + "author": "Edgard Lima ", + "description": "Payload-encodes PCMU audio into a RTP packet", + "hierarchy": [ + "GstRtpPcmuPay", + "GstRTPBaseAudioPayload", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP PCMU payloader", + "pad-templates": { + "sink": { + "caps": "audio/x-mulaw:\n channels: 1\n rate: 8000\n", + "direction": "sink", + "presence": "always" }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "4", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true + "src": { + "caps": "application/x-rtp:\n media: audio\n payload: 0\n clock-rate: 8000\n encoding-name: PCMU\napplication/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: [ 1, 2147483647 ]\n encoding-name: PCMU\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtpqcelpdepay": { + "author": "Wim Taymans ", + "description": "Extracts QCELP (PureVoice) audio from RTP packets (RFC 2658)", + "hierarchy": [ + "GstRtpQCELPDepay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP QCELP depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: audio\n clock-rate: 8000\n encoding-name: QCELP\napplication/x-rtp:\n media: audio\n payload: 12\n clock-rate: 8000\n", + "direction": "sink", + "presence": "always" }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true + "src": { + "caps": "audio/qcelp:\n channels: 1\n rate: 8000\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtpqdm2depay": { + "author": "Edward Hervey ", + "description": "Extracts QDM2 audio from RTP packets (no RFC)", + "hierarchy": [ + "GstRtpQDM2Depay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP QDM2 depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: audio\n encoding-name: X-QDM\n", + "direction": "sink", + "presence": "always" }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false + "src": { + "caps": "audio/x-qdm2:\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtpreddec": { + "author": "Hani Mustafa , Mikhail Fludkov ", + "description": "Decode Redundant Audio Data (RED)", + "hierarchy": [ + "GstRtpRedDec", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "Redundant Audio Data (RED) Decoder", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n", + "direction": "sink", + "presence": "always" }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", + "src": { + "caps": "application/x-rtp:\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "pt": { + "blurb": "Payload type FEC packets", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "-1", - "max": "65535", + "max": "127", "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)4, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", + "received": { + "blurb": "Count of received packets", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true } }, - "rank": "secondary" + "rank": "none" }, - "rtpg726depay": { - "author": "Axis Communications ", - "description": "Extracts G.726 audio from RTP packets", + "rtpredenc": { + "author": "Hani Mustafa , Mikhail Fludkov ", + "description": "Encode Redundant Audio Data (RED)", "hierarchy": [ - "GstRtpG726Depay", - "GstRTPBaseDepayload", + "GstRtpRedEnc", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP G.726 depayloader", - "name": "rtpg726depay", + "klass": "Codec/Payloader/Network/RTP", + "long-name": "Redundant Audio Data (RED) Encoder", "pad-templates": { "sink": { - "caps": "application/x-rtp:\n media: audio\n encoding-name: { (string)G726, (string)G726-16, (string)G726-24, (string)G726-32, (string)G726-40, (string)AAL2-G726-16, (string)AAL2-G726-24, (string)AAL2-G726-32, (string)AAL2-G726-40 }\n clock-rate: 8000\n", + "caps": "application/x-rtp:\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "audio/x-adpcm:\n channels: 1\n rate: 8000\n bitrate: { (int)16000, (int)24000, (int)32000, (int)40000 }\n block_align: { (int)2, (int)3, (int)4, (int)5 }\n layout: g726\n", + "caps": "application/x-rtp:\n", "direction": "src", "presence": "always" } }, "properties": { - "force-aal2": { - "blurb": "Force AAL2 decoding for compatibility with bad payloaders", + "allow-no-red-blocks": { + "blurb": "true - can produce RED packets even without redundant blocks (distance==0) false - RED packets will be produced only if distance>0", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", + "distance": { + "blurb": "Tells which media packet to use as a redundant block (0 - no redundant blocks, 1 to use previous packet, 2 to use the packet before previous, etc.)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "100", - "max": "2147483647", + "controllable": false, + "default": "0", + "max": "-1", "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", + "pt": { + "blurb": "Payload type FEC packets (-1 disable)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "0", + "max": "127", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "stats": { - "blurb": "Various statistics", + "sent": { + "blurb": "Count of sent packets", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", + "controllable": false, + "default": "0", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": false } }, - "rank": "secondary" + "rank": "none" }, - "rtpg726pay": { - "author": "Axis Communications ", - "description": "Payload-encodes G.726 audio into a RTP packet", + "rtpsbcdepay": { + "author": "Arun Raghavan ", + "description": "Extracts SBC audio from RTP packets", "hierarchy": [ - "GstRtpG726Pay", - "GstRTPBaseAudioPayload", - "GstRTPBasePayload", + "GstRtpSbcDepay", + "GstRTPBaseDepayload", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP G.726 payloader", - "name": "rtpg726pay", + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP SBC audio depayloader", "pad-templates": { "sink": { - "caps": "audio/x-adpcm:\n channels: 1\n rate: 8000\n bitrate: { (int)16000, (int)24000, (int)32000, (int)40000 }\n layout: g726\n", + "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: { (int)16000, (int)32000, (int)44100, (int)48000 }\n encoding-name: SBC\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 8000\n encoding-name: { (string)G726-16, (string)G726-24, (string)G726-32, (string)G726-40, (string)AAL2-G726-16, (string)AAL2-G726-24, (string)AAL2-G726-32, (string)AAL2-G726-40 }\n", + "caps": "audio/x-sbc:\n rate: { (int)16000, (int)32000, (int)44100, (int)48000 }\n channels: [ 1, 2 ]\n mode: { (string)mono, (string)dual, (string)stereo, (string)joint }\n blocks: { (int)4, (int)8, (int)12, (int)16 }\n subbands: { (int)4, (int)8 }\nallocation-method: { (string)snr, (string)loudness }\n bitpool: [ 2, 64 ]\n", "direction": "src", "presence": "always" } }, "properties": { - "buffer-list": { - "blurb": "Use Buffer Lists", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "force-aal2": { - "blurb": "Force AAL2 encoding for compatibility with bad depayloaders", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", + "ignore-timestamps": { + "blurb": "Various statistics", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true + } + }, + "rank": "secondary" + }, + "rtpsbcpay": { + "author": "Thiago Sousa Santos ", + "description": "Payload SBC audio as RTP packets", + "hierarchy": [ + "GstRtpSBCPay", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network", + "long-name": "RTP packet payloader", + "pad-templates": { + "sink": { + "caps": "audio/x-sbc:\n rate: { (int)16000, (int)32000, (int)44100, (int)48000 }\n channels: [ 1, 2 ]\n channel-mode: { (string)mono, (string)dual, (string)stereo, (string)joint }\n blocks: { (int)4, (int)8, (int)12, (int)16 }\n subbands: { (int)4, (int)8 }\nallocation-method: { (string)snr, (string)loudness }\n bitpool: [ 2, 64 ]\n", + "direction": "sink", + "presence": "always" }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", + "src": { + "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: { (int)16000, (int)32000, (int)44100, (int)48000 }\n encoding-name: SBC\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "min-frames": { + "blurb": "Minimum quantity of frames to send in one packet (-1 for maximum allowed by the mtu)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", + "max": "2147483647", "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)8000, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true } }, - "rank": "secondary" + "rank": "none" }, - "rtpg729depay": { - "author": "Laurent Glayal ", - "description": "Extracts G.729 audio from RTP packets (RFC 3551)", + "rtpsirendepay": { + "author": "Philippe Kalaf ", + "description": "Extracts Siren audio from RTP packets", "hierarchy": [ - "GstRtpG729Depay", + "GstRTPSirenDepay", "GstRTPBaseDepayload", "GstElement", "GstObject", @@ -18769,71 +16081,84 @@ "GObject" ], "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP G.729 depayloader", - "name": "rtpg729depay", + "long-name": "RTP Siren packet depayloader", "pad-templates": { "sink": { - "caps": "application/x-rtp:\n media: audio\n clock-rate: 8000\n encoding-name: G729\napplication/x-rtp:\n media: audio\n payload: 18\n clock-rate: 8000\n", + "caps": "application/x-rtp:\n media: audio\n clock-rate: 16000\n encoding-name: SIREN\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "audio/G729:\n channels: 1\n rate: 8000\n", + "caps": "audio/x-siren:\n dct-length: 320\n", "direction": "src", "presence": "always" } }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true + "properties": {}, + "rank": "secondary" + }, + "rtpsirenpay": { + "author": "Youness Alaoui ", + "description": "Packetize Siren audio streams into RTP packets", + "hierarchy": [ + "GstRTPSirenPay", + "GstRTPBaseAudioPayload", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP Payloader for Siren Audio", + "pad-templates": { + "sink": { + "caps": "audio/x-siren:\n dct-length: 320\n", + "direction": "sink", + "presence": "always" }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true + "src": { + "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 16000\n encoding-name: SIREN\n bitrate: 16000\n dct-length: 320\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtpspeexdepay": { + "author": "Edgard Lima ", + "description": "Extracts Speex audio from RTP packets", + "hierarchy": [ + "GstRtpSPEEXDepay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP Speex depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: audio\n clock-rate: [ 6000, 48000 ]\n encoding-name: SPEEX\n", + "direction": "sink", + "presence": "always" }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false + "src": { + "caps": "audio/x-speex:\n", + "direction": "src", + "presence": "always" } }, + "properties": {}, "rank": "secondary" }, - "rtpg729pay": { - "author": "Olivier Crete ", - "description": "Packetize G.729 audio into RTP packets", + "rtpspeexpay": { + "author": "Edgard Lima ", + "description": "Payload-encodes Speex audio into a RTP packet", "hierarchy": [ - "GstRTPG729Pay", + "GstRtpSPEEXPay", "GstRTPBasePayload", "GstElement", "GstObject", @@ -18841,177 +16166,134 @@ "GObject" ], "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP G.729 payloader", - "name": "rtpg729pay", + "long-name": "RTP Speex payloader", "pad-templates": { "sink": { - "caps": "audio/G729:\n channels: 1\n rate: 8000\n", + "caps": "audio/x-speex:\n rate: [ 6000, 48000 ]\n channels: 1\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "application/x-rtp:\n media: audio\n payload: 18\n clock-rate: 8000\n encoding-name: G729\napplication/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 8000\n encoding-name: G729\n", + "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: [ 6000, 48000 ]\n encoding-name: SPEEX\nencoding-params: 1\n", "direction": "src", "presence": "always" } }, - "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true + "properties": {}, + "rank": "secondary" + }, + "rtpstorage": { + "author": "Mikhail Fludkov ", + "description": "Helper element for various purposes (ex. recovering from packet loss using RED/FEC). Saves given number of RTP packets. Should be instantiated before jitterbuffer", + "hierarchy": [ + "GstRtpStorage", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Analyzer/RTP", + "long-name": "RTP storage", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n", + "direction": "sink", + "presence": "always" }, - "mtu": { - "blurb": "Maximum size of one packet", + "src": { + "caps": "application/x-rtp:\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "internal-storage": { + "blurb": "Internal RtpStorage object", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GObject", + "writable": false }, - "name": { - "blurb": "The name of the object", + "size-time": { + "blurb": "The amount of data to keep in the storage (in ns, 0-disable)", + "conditionally-available": false, "construct": true, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "18", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, + "controllable": false, "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", + "max": "18446744073709551615", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true + } + }, + "rank": "none" + }, + "rtpstreamdepay": { + "author": "Sebastian Dröge ", + "description": "Depayloads RTP/RTCP packets for streaming protocols according to RFC4571", + "hierarchy": [ + "GstRtpStreamDepay", + "GstBaseParse", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network", + "long-name": "RTP Stream Depayloading", + "pad-templates": { + "sink": { + "caps": "application/x-rtp-stream:\napplication/x-rtcp-stream:\napplication/x-srtp-stream:\napplication/x-srtcp-stream:\n", + "direction": "sink", + "presence": "always" }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)18, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false + "src": { + "caps": "application/x-rtp:\napplication/x-rtcp:\napplication/x-srtp:\napplication/x-srtcp:\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "none" + }, + "rtpstreampay": { + "author": "Sebastian Dröge ", + "description": "Payloads RTP/RTCP packets for streaming protocols according to RFC4571", + "hierarchy": [ + "GstRtpStreamPay", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network", + "long-name": "RTP Stream Payloading", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\napplication/x-rtcp:\napplication/x-srtp:\napplication/x-srtcp:\n", + "direction": "sink", + "presence": "always" }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true + "src": { + "caps": "application/x-rtp-stream:\napplication/x-rtcp-stream:\napplication/x-srtp-stream:\napplication/x-srtcp-stream:\n", + "direction": "src", + "presence": "always" } }, - "rank": "secondary" + "rank": "none" }, - "rtpgsmdepay": { - "author": "Zeeshan Ali ", - "description": "Extracts GSM audio from RTP packets", + "rtpsv3vdepay": { + "author": "Wim Taymans ", + "description": "Extracts SVQ3 video from RTP packets (no RFC)", "hierarchy": [ - "GstRTPGSMDepay", + "GstRtpSV3VDepay", "GstRTPBaseDepayload", "GstElement", "GstObject", @@ -19019,71 +16301,55 @@ "GObject" ], "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP GSM depayloader", - "name": "rtpgsmdepay", + "long-name": "RTP SVQ3 depayloader", "pad-templates": { "sink": { - "caps": "application/x-rtp:\n media: audio\n clock-rate: 8000\n encoding-name: GSM\napplication/x-rtp:\n media: audio\n payload: 3\n clock-rate: 8000\n", + "caps": "application/x-rtp:\n media: video\n clock-rate: 90000\n encoding-name: { (string)X-SV3V-ES, (string)X-SORENSON-VIDEO, (string)X-SORENSONVIDEO, (string)X-SorensonVideo }\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "audio/x-gsm:\n rate: 8000\n channels: 1\n", + "caps": "video/x-svq:\n svqversion: 3\n", "direction": "src", "presence": "always" } }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true + "properties": {}, + "rank": "secondary" + }, + "rtptheoradepay": { + "author": "Wim Taymans ", + "description": "Extracts Theora video from RTP packets (draft-01 of RFC XXXX)", + "hierarchy": [ + "GstRtpTheoraDepay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP Theora depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: video\n clock-rate: 90000\n encoding-name: THEORA\n", + "direction": "sink", + "presence": "always" }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false + "src": { + "caps": "video/x-theora:\n", + "direction": "src", + "presence": "always" } }, + "properties": {}, "rank": "secondary" }, - "rtpgsmpay": { - "author": "Zeeshan Ali ", - "description": "Payload-encodes GSM audio into a RTP packet", + "rtptheorapay": { + "author": "Wim Taymans ", + "description": "Payload-encode Theora video into RTP packets (draft-01 RFC XXXX)", "hierarchy": [ - "GstRTPGSMPay", + "GstRtpTheoraPay", "GstRTPBasePayload", "GstElement", "GstObject", @@ -19091,249 +16357,247 @@ "GObject" ], "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP GSM payloader", - "name": "rtpgsmpay", + "long-name": "RTP Theora payloader", "pad-templates": { "sink": { - "caps": "audio/x-gsm:\n rate: 8000\n channels: 1\n", + "caps": "video/x-theora:\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "application/x-rtp:\n media: audio\n payload: 3\n clock-rate: 8000\n encoding-name: GSM\napplication/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 8000\n encoding-name: GSM\n", + "caps": "application/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: THEORA\n", "direction": "src", "presence": "always" } }, "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", + "config-interval": { + "blurb": "Send Config Insertion Interval in seconds (configuration headers will be multiplexed in the data stream when detected.) (0 = disabled)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", - "max": "9223372036854775807", + "max": "3600", "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true + } + }, + "rank": "secondary" + }, + "rtpulpfecdec": { + "author": "Mikhail Fludkov ", + "description": "Decodes RTP FEC (RFC5109)", + "hierarchy": [ + "GstRtpUlpFecDec", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP FEC Decoder", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n", + "direction": "sink", + "presence": "always" }, + "src": { + "caps": "application/x-rtp:\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { "pt": { - "blurb": "The payload type of the packets", + "blurb": "FEC packets payload type", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "3", + "controllable": false, + "default": "0", "max": "127", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", + "recovered": { + "blurb": "The number of recovered packets", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", - "max": "9223372036854775807", + "max": "-1", "min": "0", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": false + }, + "storage": { + "blurb": "RTP storage", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GObject", "writable": true }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", + "unrecovered": { + "blurb": "The number of unrecovered packets", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", - "max": "65535", + "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": false + } + }, + "rank": "none" + }, + "rtpulpfecenc": { + "author": "Mikhail Fludkov ", + "description": "Encodes RTP FEC (RFC5109)", + "hierarchy": [ + "GstRtpUlpFecEnc", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP FEC Encoder", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n", + "direction": "sink", + "presence": "always" }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, + "src": { + "caps": "application/x-rtp:\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "multipacket": { + "blurb": "Apply FEC on multiple packets", + "conditionally-available": false, + "construct": true, "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, + "percentage": { + "blurb": "FEC overhead percentage for the whole stream", + "conditionally-available": false, + "construct": true, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "0", + "max": "100", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, + "percentage-important": { + "blurb": "FEC overhead percentage for important packets", + "conditionally-available": false, + "construct": true, "construct-only": false, - "default": "-1", - "max": "-1", + "controllable": false, + "default": "0", + "max": "100", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)8000, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)3, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", + "protected": { + "blurb": "Count of protected packets", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": false }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, + "pt": { + "blurb": "The payload type of FEC packets", + "conditionally-available": false, + "construct": true, "construct-only": false, - "default": "-1", - "max": "-1", + "controllable": false, + "default": "255", + "max": "255", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true } }, - "rank": "secondary" + "rank": "none" }, - "rtpgstdepay": { + "rtpvorbisdepay": { "author": "Wim Taymans ", - "description": "Extracts GStreamer buffers from RTP packets", + "description": "Extracts Vorbis Audio from RTP packets (RFC 5215)", "hierarchy": [ - "GstRtpGSTDepay", + "GstRtpVorbisDepay", "GstRTPBaseDepayload", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Codec/Depayloader/Network", - "long-name": "GStreamer depayloader", - "name": "rtpgstdepay", + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP Vorbis depayloader", "pad-templates": { "sink": { - "caps": "application/x-rtp:\n media: application\n clock-rate: 90000\n encoding-name: X-GST\n", + "caps": "application/x-rtp:\n media: audio\n clock-rate: [ 1, 2147483647 ]\n encoding-name: VORBIS\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "ANY", + "caps": "audio/x-vorbis:\n", "direction": "src", "presence": "always" } }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "marginal" + "properties": {}, + "rank": "secondary" }, - "rtpgstpay": { + "rtpvorbispay": { "author": "Wim Taymans ", - "description": "Payload GStreamer buffers as RTP packets", + "description": "Payload-encode Vorbis audio into RTP packets (RFC 5215)", "hierarchy": [ - "GstRtpGSTPay", + "GstRtpVorbisPay", "GstRTPBasePayload", "GstElement", "GstObject", @@ -19341,17280 +16605,9228 @@ "GObject" ], "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP GStreamer payloader", - "name": "rtpgstpay", + "long-name": "RTP Vorbis payloader", "pad-templates": { "sink": { - "caps": "ANY", + "caps": "audio/x-vorbis:\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "application/x-rtp:\n media: application\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: X-GST\n", + "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: [ 1, 2147483647 ]\n encoding-name: VORBIS\n", "direction": "src", "presence": "always" } }, "properties": { "config-interval": { - "blurb": "Interval for sending caps and TAG events in seconds (0 = disabled)", + "blurb": "Send Config Insertion Interval in seconds (configuration headers will be multiplexed in the data stream when detected.) (0 = disabled)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "3600", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true + } + }, + "rank": "secondary" + }, + "rtpvp8depay": { + "author": "Sjoerd Simons ", + "description": "Extracts VP8 video from RTP packets)", + "hierarchy": [ + "GstRtpVP8Depay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP VP8 depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n clock-rate: 90000\n media: video\n encoding-name: { (string)VP8, (string)VP8-DRAFT-IETF-01 }\n", + "direction": "sink", + "presence": "always" }, - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", + "src": { + "caps": "video/x-vp8:\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "wait-for-keyframe": { + "blurb": "Wait for the next keyframe after packet loss", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)90000, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, - "rank": "none" + "rank": "marginal" }, - "rtph261depay": { - "author": "Stian Selnes ", - "description": "Extracts H261 video from RTP packets (RFC 4587)", + "rtpvp8pay": { + "author": "Sjoerd Simons ", + "description": "Puts VP8 video in RTP packets", "hierarchy": [ - "GstRtpH261Depay", - "GstRTPBaseDepayload", + "GstRtpVP8Pay", + "GstRTPBasePayload", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP H261 depayloader", - "name": "rtph261depay", + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP VP8 payloader", "pad-templates": { "sink": { - "caps": "application/x-rtp:\n media: video\n payload: 31\n clock-rate: 90000\n encoding-name: H261\napplication/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: H261\n", + "caps": "video/x-vp8:\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "video/x-h261:\n", + "caps": "application/x-rtp:\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: { (string)VP8, (string)VP8-DRAFT-IETF-01 }\n", "direction": "src", "presence": "always" } }, "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", + "picture-id-mode": { + "blurb": "The picture ID mode for payloading", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "none (0)", + "mutable": "null", + "readable": true, + "type": "GstVP8RTPPayMode", "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false } }, - "rank": "secondary" + "rank": "marginal" }, - "rtph261pay": { + "rtpvp9depay": { "author": "Stian Selnes ", - "description": "Payload-encodes H261 video in RTP packets (RFC 4587)", + "description": "Extracts VP9 video from RTP packets)", "hierarchy": [ - "GstRtpH261Pay", - "GstRTPBasePayload", + "GstRtpVP9Depay", + "GstRTPBaseDepayload", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP H261 packet payloader", - "name": "rtph261pay", + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP VP9 depayloader", "pad-templates": { "sink": { - "caps": "video/x-h261:\n", + "caps": "application/x-rtp:\n clock-rate: 90000\n media: video\n encoding-name: { (string)VP9, (string)VP9-DRAFT-IETF-01 }\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "application/x-rtp:\n media: video\n payload: 31\n clock-rate: 90000\n encoding-name: H261\napplication/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: H261\n", + "caps": "video/x-vp9:\n", "direction": "src", "presence": "always" } }, - "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "31", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)31, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "secondary" - }, - "rtph263depay": { - "author": "Philippe Kalaf , Edward Hervey ", - "description": "Extracts H263 video from RTP packets (RFC 2190)", - "hierarchy": [ - "GstRtpH263Depay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP H263 depayloader", - "name": "rtph263depay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: video\n payload: 34\n clock-rate: 90000\napplication/x-rtp:\n media: video\n clock-rate: 90000\n encoding-name: H263\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "video/x-h263:\n variant: itu\n h263version: h263\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtph263pay": { - "author": "Neil Stratford Dejan Sakelsak ", - "description": "Payload-encodes H263 video in RTP packets (RFC 2190)", - "hierarchy": [ - "GstRtpH263Pay", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP H263 packet payloader", - "name": "rtph263pay", - "pad-templates": { - "sink": { - "caps": "video/x-h263:\n variant: itu\n h263version: h263\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: video\n payload: 34\n clock-rate: 90000\n encoding-name: H263\napplication/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: H263\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "modea-only": { - "blurb": "Disable packetization modes B and C", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "34", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)34, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "secondary" - }, - "rtph263pdepay": { - "author": "Wim Taymans ", - "description": "Extracts H263/+/++ video from RTP packets (RFC 4629)", - "hierarchy": [ - "GstRtpH263PDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP H263 depayloader", - "name": "rtph263pdepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: video\n clock-rate: [ 1, 2147483647 ]\n encoding-name: H263-1998\napplication/x-rtp:\n media: video\n clock-rate: [ 1, 2147483647 ]\n encoding-name: H263-2000\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "video/x-h263:\n variant: itu\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtph263ppay": { - "author": "Wim Taymans ", - "description": "Payload-encodes H263/+/++ video in RTP packets (RFC 4629)", - "hierarchy": [ - "GstRtpH263PPay", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP H263 payloader", - "name": "rtph263ppay", - "pad-templates": { - "sink": { - "caps": "video/x-h263:\n variant: itu\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: H263-1998\napplication/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: H263-2000\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "fragmentation-mode": { - "blurb": "Packet Fragmentation Mode", - "construct": false, - "construct-only": false, - "default": "normal (0)", - "enum": true, - "type-name": "GstFragmentationMode", - "values": [ - { - "desc": "Normal", - "name": "normal", - "value": "0" - }, - { - "desc": "Fragment at sync points", - "name": "sync", - "value": "1" - } - ], - "writable": true - }, - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "secondary" - }, - "rtph264depay": { - "author": "Wim Taymans ", - "description": "Extracts H264 video from RTP packets (RFC 3984)", - "hierarchy": [ - "GstRtpH264Depay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP H264 depayloader", - "name": "rtph264depay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: video\n clock-rate: 90000\n encoding-name: H264\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "video/x-h264:\n stream-format: avc\n alignment: au\nvideo/x-h264:\n stream-format: byte-stream\n alignment: { (string)nal, (string)au }\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtph264pay": { - "author": "Laurent Glayal ", - "description": "Payload-encode H264 video into RTP packets (RFC 3984)", - "hierarchy": [ - "GstRtpH264Pay", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP H264 payloader", - "name": "rtph264pay", - "pad-templates": { - "sink": { - "caps": "video/x-h264:\n stream-format: avc\n alignment: au\nvideo/x-h264:\n stream-format: byte-stream\n alignment: { (string)nal, (string)au }\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: H264\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "aggregate-mode": { - "blurb": "Bundle suitable SPS/PPS NAL units into STAP-A aggregate packets. ", - "construct": false, - "construct-only": false, - "default": "zero-latency (1)", - "enum": true, - "type-name": "GstRtpH264AggregateMode", - "values": [ - { - "desc": "Do not aggregate NAL units", - "name": "none", - "value": "0" - }, - { - "desc": "Aggregate NAL units until a VCL unit is included", - "name": "zero-latency", - "value": "1" - }, - { - "desc": "Aggregate all NAL units with the same timestamp (adds one frame of latency)", - "name": "max-stap", - "value": "2" - } - ], - "writable": true - }, - "config-interval": { - "blurb": "Send SPS and PPS Insertion Interval in seconds (sprop parameter sets will be multiplexed in the data stream when detected.) (0 = disabled, -1 = send with every IDR frame)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "3600", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "sprop-parameter-sets": { - "blurb": "The base64 sprop-parameter-sets to set in out caps (set to NULL to extract from stream)", - "construct": false, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "secondary" - }, - "rtph265depay": { - "author": "Jurgen Slowack ", - "description": "Extracts H265 video from RTP packets (RFC 7798)", - "hierarchy": [ - "GstRtpH265Depay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP H265 depayloader", - "name": "rtph265depay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: video\n clock-rate: 90000\n encoding-name: H265\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "video/x-h265:\n stream-format: hvc1\n alignment: au\nvideo/x-h265:\n stream-format: byte-stream\n alignment: { (string)nal, (string)au }\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtph265pay": { - "author": "Jurgen Slowack ", - "description": "Payload-encode H265 video into RTP packets (RFC 7798)", - "hierarchy": [ - "GstRtpH265Pay", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP H265 payloader", - "name": "rtph265pay", - "pad-templates": { - "sink": { - "caps": "video/x-h265:\n stream-format: hvc1\n alignment: au\nvideo/x-h265:\n stream-format: byte-stream\n alignment: { (string)nal, (string)au }\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: H265\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "aggregate-mode": { - "blurb": "Bundle suitable SPS/PPS NAL units into aggregate packets.", - "construct": false, - "construct-only": false, - "default": "zero-latency (1)", - "enum": true, - "type-name": "GstRtpH265AggregateMode", - "values": [ - { - "desc": "Do not aggregate NAL units", - "name": "none", - "value": "0" - }, - { - "desc": "Aggregate NAL units until a VCL or suffix unit is included", - "name": "zero-latency", - "value": "1" - }, - { - "desc": "Aggregate all NAL units with the same timestamp (adds one frame of latency)", - "name": "max", - "value": "2" - } - ], - "writable": true - }, - "config-interval": { - "blurb": "Send VPS, SPS and PPS Insertion Interval in seconds (sprop parameter sets will be multiplexed in the data stream when detected.) (0 = disabled, -1 = send with every IDR frame)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "3600", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "secondary" - }, - "rtpilbcdepay": { - "author": "Philippe Kalaf ", - "description": "Extracts iLBC audio from RTP packets (RFC 3952)", - "hierarchy": [ - "GstRTPiLBCDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP iLBC depayloader", - "name": "rtpilbcdepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: audio\n clock-rate: 8000\n encoding-name: ILBC\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "audio/x-iLBC:\n mode: { (int)20, (int)30 }\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "mode": { - "blurb": "iLBC frame mode", - "construct": false, - "construct-only": false, - "default": "30ms (30)", - "enum": true, - "type-name": "iLBCMode", - "values": [ - { - "desc": "20ms frames", - "name": "20ms", - "value": "20" - }, - { - "desc": "30ms frames", - "name": "30ms", - "value": "30" - } - ], - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtpilbcpay": { - "author": "Philippe Kalaf ", - "description": "Packetize iLBC audio streams into RTP packets", - "hierarchy": [ - "GstRTPILBCPay", - "GstRTPBaseAudioPayload", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP iLBC Payloader", - "name": "rtpilbcpay", - "pad-templates": { - "sink": { - "caps": "audio/x-iLBC:\n mode: { (int)20, (int)30 }\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 8000\n encoding-name: ILBC\n mode: { (string)20, (string)30 }\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "buffer-list": { - "blurb": "Use Buffer Lists", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)8000, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "secondary" - }, - "rtpj2kdepay": { - "author": "Wim Taymans ", - "description": "Extracts JPEG 2000 video from RTP packets (RFC 5371)", - "hierarchy": [ - "GstRtpJ2KDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP JPEG 2000 depayloader", - "name": "rtpj2kdepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: video\n clock-rate: 90000\n sampling: { (string)RGB, (string)BGR, (string)RGBA, (string)BGRA, (string)YCbCrA, (string)YCbCr-4:4:4, (string)YCbCr-4:2:2, (string)YCbCr-4:2:0, (string)YCbCr-4:1:1, (string)GRAYSCALE }\n encoding-name: JPEG2000\napplication/x-rtp:\n media: video\n clock-rate: 90000\n colorspace: { (string)sRGB, (string)sYUV, (string)GRAY }\n encoding-name: JPEG2000\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "image/x-jpc:\n colorspace: { (string)sRGB, (string)sYUV, (string)GRAY }\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtpj2kpay": { - "author": "Wim Taymans ", - "description": "Payload-encodes JPEG 2000 pictures into RTP packets (RFC 5371)", - "hierarchy": [ - "GstRtpJ2KPay", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP JPEG 2000 payloader", - "name": "rtpj2kpay", - "pad-templates": { - "sink": { - "caps": "image/x-jpc:\n sampling: { (string)RGB, (string)BGR, (string)RGBA, (string)BGRA, (string)YCbCrA, (string)YCbCr-4:4:4, (string)YCbCr-4:2:2, (string)YCbCr-4:2:0, (string)YCbCr-4:1:1, (string)GRAYSCALE }\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n sampling: { (string)RGB, (string)BGR, (string)RGBA, (string)BGRA, (string)YCbCrA, (string)YCbCr-4:4:4, (string)YCbCr-4:2:2, (string)YCbCr-4:2:0, (string)YCbCr-4:1:1, (string)GRAYSCALE }\n encoding-name: JPEG2000\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "secondary" - }, - "rtpjpegdepay": { - "author": "Wim Taymans ", - "description": "Extracts JPEG video from RTP packets (RFC 2435)", - "hierarchy": [ - "GstRtpJPEGDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP JPEG depayloader", - "name": "rtpjpegdepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: video\n clock-rate: 90000\n encoding-name: JPEG\napplication/x-rtp:\n media: video\n payload: 26\n clock-rate: 90000\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "image/jpeg:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtpjpegpay": { - "author": "Axis Communications ", - "description": "Payload-encodes JPEG pictures into RTP packets (RFC 2435)", - "hierarchy": [ - "GstRtpJPEGPay", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP JPEG payloader", - "name": "rtpjpegpay", - "pad-templates": { - "sink": { - "caps": "image/jpeg:\nvideo/x-jpeg:\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: video\n payload: 26\n clock-rate: 90000\n encoding-name: JPEG\n width: [ 1, 65536 ]\n height: [ 1, 65536 ]\napplication/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: JPEG\n width: [ 1, 65536 ]\n height: [ 1, 65536 ]\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "26", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "quality": { - "blurb": "Quality factor on JPEG data (unused)", - "construct": false, - "construct-only": false, - "default": "255", - "max": "255", - "min": "0", - "type-name": "gint", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)26, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "type": { - "blurb": "Default JPEG Type, overwritten by SOF when present", - "construct": false, - "construct-only": false, - "default": "1", - "max": "255", - "min": "0", - "type-name": "gint", - "writable": true - } - }, - "rank": "secondary" - }, - "rtpklvdepay": { - "author": "Tim-Philipp M\u00fcller ", - "description": "Extracts KLV (SMPTE ST 336) metadata from RTP packets", - "hierarchy": [ - "GstRtpKlvDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP KLV Depayloader", - "name": "rtpklvdepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: application\n clock-rate: [ 1, 2147483647 ]\n encoding-name: SMPTE336M\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "meta/x-klv:\n parsed: true\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtpklvpay": { - "author": "Tim-Philipp M\u00fcller ", - "description": "Payloads KLV (SMPTE ST 336) metadata as RTP packets", - "hierarchy": [ - "GstRtpKlvPay", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP KLV Payloader", - "name": "rtpklvpay", - "pad-templates": { - "sink": { - "caps": "meta/x-klv:\n parsed: true\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: application\n clock-rate: [ 1, 2147483647 ]\n encoding-name: SMPTE336M\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "secondary" - }, - "rtpmp1sdepay": { - "author": "Wim Taymans ", - "description": "Extracts MPEG1 System Streams from RTP packets (RFC 3555)", - "hierarchy": [ - "GstRtpMP1SDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP MPEG1 System Stream depayloader", - "name": "rtpmp1sdepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: other\n clock-rate: [ 1, 2147483647 ]\n encoding-name: MP1S\napplication/x-rtp:\n media: video\n clock-rate: [ 1, 2147483647 ]\n encoding-name: MP1S\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "video/mpeg:\n systemstream: true\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtpmp2tdepay": { - "author": "Wim Taymans , Thijs Vermeir ", - "description": "Extracts MPEG2 TS from RTP packets (RFC 2250)", - "hierarchy": [ - "GstRtpMP2TDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP MPEG Transport Stream depayloader", - "name": "rtpmp2tdepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: video\n clock-rate: [ 1, 2147483647 ]\n encoding-name: { (string)MP2T, (string)MP2T-ES }\napplication/x-rtp:\n media: video\n payload: 33\n clock-rate: [ 1, 2147483647 ]\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "video/mpegts:\n packetsize: 188\n systemstream: true\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "skip-first-bytes": { - "blurb": "The amount of bytes that need to be skipped at the beginning of the payload", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtpmp2tpay": { - "author": "Wim Taymans ", - "description": "Payload-encodes MPEG2 TS into RTP packets (RFC 2250)", - "hierarchy": [ - "GstRTPMP2TPay", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP MPEG2 Transport Stream payloader", - "name": "rtpmp2tpay", - "pad-templates": { - "sink": { - "caps": "video/mpegts:\n packetsize: 188\n systemstream: true\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: video\n payload: 33\n clock-rate: 90000\n encoding-name: MP2T\napplication/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: MP2T\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "33", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)90000, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)33, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "secondary" - }, - "rtpmp4adepay": { - "author": "Nokia Corporation (contact ), Wim Taymans ", - "description": "Extracts MPEG4 audio from RTP packets (RFC 3016)", - "hierarchy": [ - "GstRtpMP4ADepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP MPEG4 audio depayloader", - "name": "rtpmp4adepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: audio\n clock-rate: [ 1, 2147483647 ]\n encoding-name: MP4A-LATM\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "audio/mpeg:\n mpegversion: 4\n framed: { (boolean)false, (boolean)true }\n stream-format: raw\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtpmp4apay": { - "author": "Wim Taymans ", - "description": "Payload MPEG4 audio as RTP packets (RFC 3016)", - "hierarchy": [ - "GstRtpMP4APay", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP MPEG4 audio payloader", - "name": "rtpmp4apay", - "pad-templates": { - "sink": { - "caps": "audio/mpeg:\n mpegversion: 4\n stream-format: raw\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: [ 1, 2147483647 ]\n encoding-name: MP4A-LATM\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "secondary" - }, - "rtpmp4gdepay": { - "author": "Wim Taymans ", - "description": "Extracts MPEG4 elementary streams from RTP packets (RFC 3640)", - "hierarchy": [ - "GstRtpMP4GDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP MPEG4 ES depayloader", - "name": "rtpmp4gdepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: { (string)video, (string)audio, (string)application }\n clock-rate: [ 1, 2147483647 ]\n encoding-name: MPEG4-GENERIC\n mode: { (string)generic, (string)CELP-cbr, (string)CELP-vbr, (string)AAC-lbr, (string)AAC-hbr }\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "video/mpeg:\n mpegversion: 4\n systemstream: false\naudio/mpeg:\n mpegversion: 4\n stream-format: raw\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtpmp4gpay": { - "author": "Wim Taymans ", - "description": "Payload MPEG4 elementary streams as RTP packets (RFC 3640)", - "hierarchy": [ - "GstRtpMP4GPay", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP MPEG4 ES payloader", - "name": "rtpmp4gpay", - "pad-templates": { - "sink": { - "caps": "video/mpeg:\n mpegversion: 4\n systemstream: false\naudio/mpeg:\n mpegversion: 4\n stream-format: raw\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: { (string)video, (string)audio, (string)application }\n payload: [ 96, 127 ]\n clock-rate: [ 1, 2147483647 ]\n encoding-name: MPEG4-GENERIC\n streamtype: { (string)4, (string)5 }\n mode: { (string)generic, (string)CELP-cbr, (string)CELP-vbr, (string)AAC-lbr, (string)AAC-hbr }\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "secondary" - }, - "rtpmp4vdepay": { - "author": "Wim Taymans ", - "description": "Extracts MPEG4 video from RTP packets (RFC 3016)", - "hierarchy": [ - "GstRtpMP4VDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP MPEG4 video depayloader", - "name": "rtpmp4vdepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: video\n clock-rate: [ 1, 2147483647 ]\n encoding-name: MP4V-ES\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "video/mpeg:\n mpegversion: 4\n systemstream: false\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtpmp4vpay": { - "author": "Wim Taymans ", - "description": "Payload MPEG-4 video as RTP packets (RFC 3016)", - "hierarchy": [ - "GstRtpMP4VPay", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP MPEG4 Video payloader", - "name": "rtpmp4vpay", - "pad-templates": { - "sink": { - "caps": "video/mpeg:\n mpegversion: 4\n systemstream: false\nvideo/x-divx:\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: [ 1, 2147483647 ]\n encoding-name: MP4V-ES\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "config-interval": { - "blurb": "Send Config Insertion Interval in seconds (configuration headers will be multiplexed in the data stream when detected.) (0 = disabled, -1 = send with every IDR frame)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "3600", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "secondary + 1" - }, - "rtpmpadepay": { - "author": "Wim Taymans ", - "description": "Extracts MPEG audio from RTP packets (RFC 2038)", - "hierarchy": [ - "GstRtpMPADepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP MPEG audio depayloader", - "name": "rtpmpadepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: audio\n payload: 14\n clock-rate: 90000\napplication/x-rtp:\n media: audio\n encoding-name: MPA\n clock-rate: [ 1, 2147483647 ]\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "audio/mpeg:\n mpegversion: 1\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtpmpapay": { - "author": "Wim Taymans ", - "description": "Payload MPEG audio as RTP packets (RFC 2038)", - "hierarchy": [ - "GstRtpMPAPay", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP MPEG audio payloader", - "name": "rtpmpapay", - "pad-templates": { - "sink": { - "caps": "audio/mpeg:\n mpegversion: 1\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: audio\n payload: 14\n clock-rate: 90000\napplication/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: MPA\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "14", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)14, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "secondary" - }, - "rtpmparobustdepay": { - "author": "Mark Nauwelaerts ", - "description": "Extracts MPEG audio from RTP packets (RFC 5219)", - "hierarchy": [ - "GstRtpMPARobustDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP MPEG audio depayloader", - "name": "rtpmparobustdepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: audio\n clock-rate: 90000\n encoding-name: MPA-ROBUST\napplication/x-rtp:\n media: audio\n clock-rate: [ 1, 2147483647 ]\n encoding-name: { (string)X-MP3-DRAFT-00, (string)X-MP3-DRAFT-01, (string)X-MP3-DRAFT-02, (string)X-MP3-DRAFT-03, (string)X-MP3-DRAFT-04, (string)X-MP3-DRAFT-05, (string)X-MP3-DRAFT-06 }\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "audio/mpeg:\n mpegversion: 1\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtpmpvdepay": { - "author": "Wim Taymans ", - "description": "Extracts MPEG video from RTP packets (RFC 2250)", - "hierarchy": [ - "GstRtpMPVDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP MPEG video depayloader", - "name": "rtpmpvdepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: video\n clock-rate: 90000\n encoding-name: MPV\napplication/x-rtp:\n media: video\n payload: 32\n clock-rate: 90000\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "video/mpeg:\n mpegversion: 2\n systemstream: false\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtpmpvpay": { - "author": "Thijs Vermeir ", - "description": "Payload-encodes MPEG2 ES into RTP packets (RFC 2250)", - "hierarchy": [ - "GstRTPMPVPay", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP MPEG2 ES video payloader", - "name": "rtpmpvpay", - "pad-templates": { - "sink": { - "caps": "video/mpeg:\n mpegversion: 2\n systemstream: false\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: video\n payload: 32\n clock-rate: 90000\n encoding-name: MPV\napplication/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: MPV\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "32", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)90000, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)32, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "secondary" - }, - "rtpopusdepay": { - "author": "Danilo Cesar Lemes de Paula ", - "description": "Extracts Opus audio from RTP packets", - "hierarchy": [ - "GstRTPOpusDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP Opus packet depayloader", - "name": "rtpopusdepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 48000\n encoding-name: { (string)OPUS, (string)X-GST-OPUS-DRAFT-SPITTKA-00 }\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "audio/x-opus:\nchannel-mapping-family: 0\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "primary" - }, - "rtpopuspay": { - "author": "Danilo Cesar Lemes de Paula ", - "description": "Puts Opus audio in RTP packets", - "hierarchy": [ - "GstRtpOPUSPay", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP Opus payloader", - "name": "rtpopuspay", - "pad-templates": { - "sink": { - "caps": "audio/x-opus:\n channels: [ 1, 2 ]\nchannel-mapping-family: 0\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 48000\nencoding-params: 2\n encoding-name: { (string)OPUS, (string)X-GST-OPUS-DRAFT-SPITTKA-00 }\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "primary" - }, - "rtppcmadepay": { - "author": "Edgard Lima , Zeeshan Ali ", - "description": "Extracts PCMA audio from RTP packets", - "hierarchy": [ - "GstRtpPcmaDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP PCMA depayloader", - "name": "rtppcmadepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: audio\n payload: 8\n clock-rate: 8000\napplication/x-rtp:\n media: audio\n clock-rate: [ 1, 2147483647 ]\n encoding-name: PCMA\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "audio/x-alaw:\n channels: 1\n rate: [ 1, 2147483647 ]\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtppcmapay": { - "author": "Edgard Lima ", - "description": "Payload-encodes PCMA audio into a RTP packet", - "hierarchy": [ - "GstRtpPcmaPay", - "GstRTPBaseAudioPayload", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP PCMA payloader", - "name": "rtppcmapay", - "pad-templates": { - "sink": { - "caps": "audio/x-alaw:\n channels: 1\n rate: 8000\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: audio\n payload: 8\n clock-rate: 8000\n encoding-name: PCMA\napplication/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: [ 1, 2147483647 ]\n encoding-name: PCMA\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "buffer-list": { - "blurb": "Use Buffer Lists", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "8", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)8000, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)8, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "secondary" - }, - "rtppcmudepay": { - "author": "Edgard Lima , Zeeshan Ali ", - "description": "Extracts PCMU audio from RTP packets", - "hierarchy": [ - "GstRtpPcmuDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP PCMU depayloader", - "name": "rtppcmudepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: audio\n payload: 0\n clock-rate: 8000\napplication/x-rtp:\n media: audio\n encoding-name: PCMU\n clock-rate: [ 1, 2147483647 ]\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "audio/x-mulaw:\n channels: 1\n rate: [ 1, 2147483647 ]\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtppcmupay": { - "author": "Edgard Lima ", - "description": "Payload-encodes PCMU audio into a RTP packet", - "hierarchy": [ - "GstRtpPcmuPay", - "GstRTPBaseAudioPayload", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP PCMU payloader", - "name": "rtppcmupay", - "pad-templates": { - "sink": { - "caps": "audio/x-mulaw:\n channels: 1\n rate: 8000\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: audio\n payload: 0\n clock-rate: 8000\n encoding-name: PCMU\napplication/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: [ 1, 2147483647 ]\n encoding-name: PCMU\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "buffer-list": { - "blurb": "Use Buffer Lists", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "0", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)8000, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)0, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "secondary" - }, - "rtpqcelpdepay": { - "author": "Wim Taymans ", - "description": "Extracts QCELP (PureVoice) audio from RTP packets (RFC 2658)", - "hierarchy": [ - "GstRtpQCELPDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP QCELP depayloader", - "name": "rtpqcelpdepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: audio\n clock-rate: 8000\n encoding-name: QCELP\napplication/x-rtp:\n media: audio\n payload: 12\n clock-rate: 8000\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "audio/qcelp:\n channels: 1\n rate: 8000\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtpqdm2depay": { - "author": "Edward Hervey ", - "description": "Extracts QDM2 audio from RTP packets (no RFC)", - "hierarchy": [ - "GstRtpQDM2Depay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP QDM2 depayloader", - "name": "rtpqdm2depay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: audio\n encoding-name: X-QDM\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "audio/x-qdm2:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtpreddec": { - "author": "Hani Mustafa , Mikhail Fludkov ", - "description": "Decode Redundant Audio Data (RED)", - "hierarchy": [ - "GstRtpRedDec", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "Redundant Audio Data (RED) Decoder", - "name": "rtpreddec", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "pt": { - "blurb": "Payload type FEC packets", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "127", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "received": { - "blurb": "Count of received packets", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - } - }, - "rank": "none" - }, - "rtpredenc": { - "author": "Hani Mustafa , Mikhail Fludkov ", - "description": "Encode Redundant Audio Data (RED)", - "hierarchy": [ - "GstRtpRedEnc", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "Redundant Audio Data (RED) Encoder", - "name": "rtpredenc", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "allow-no-red-blocks": { - "blurb": "true - can produce RED packets even without redundant blocks (distance==0) false - RED packets will be produced only if distance>0", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "distance": { - "blurb": "Tells which media packet to use as a redundant block (0 - no redundant blocks, 1 to use previous packet, 2 to use the packet before previous, etc.)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "pt": { - "blurb": "Payload type FEC packets (-1 disable)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "127", - "min": "0", - "type-name": "gint", - "writable": true - }, - "sent": { - "blurb": "Count of sent packets", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - } - }, - "rank": "none" - }, - "rtpsbcdepay": { - "author": "Arun Raghavan ", - "description": "Extracts SBC audio from RTP packets", - "hierarchy": [ - "GstRtpSbcDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP SBC audio depayloader", - "name": "rtpsbcdepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: { (int)16000, (int)32000, (int)44100, (int)48000 }\n encoding-name: SBC\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "audio/x-sbc:\n rate: { (int)16000, (int)32000, (int)44100, (int)48000 }\n channels: [ 1, 2 ]\n mode: { (string)mono, (string)dual, (string)stereo, (string)joint }\n blocks: { (int)4, (int)8, (int)12, (int)16 }\n subbands: { (int)4, (int)8 }\nallocation-method: { (string)snr, (string)loudness }\n bitpool: [ 2, 64 ]\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "ignore-timestamps": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtpsbcpay": { - "author": "Thiago Sousa Santos ", - "description": "Payload SBC audio as RTP packets", - "hierarchy": [ - "GstRtpSBCPay", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network", - "long-name": "RTP packet payloader", - "name": "rtpsbcpay", - "pad-templates": { - "sink": { - "caps": "audio/x-sbc:\n rate: { (int)16000, (int)32000, (int)44100, (int)48000 }\n channels: [ 1, 2 ]\n channel-mode: { (string)mono, (string)dual, (string)stereo, (string)joint }\n blocks: { (int)4, (int)8, (int)12, (int)16 }\n subbands: { (int)4, (int)8 }\nallocation-method: { (string)snr, (string)loudness }\n bitpool: [ 2, 64 ]\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: { (int)16000, (int)32000, (int)44100, (int)48000 }\n encoding-name: SBC\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-frames": { - "blurb": "Minimum quantity of frames to send in one packet (-1 for maximum allowed by the mtu)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "none" - }, - "rtpsirendepay": { - "author": "Philippe Kalaf ", - "description": "Extracts Siren audio from RTP packets", - "hierarchy": [ - "GstRTPSirenDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP Siren packet depayloader", - "name": "rtpsirendepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: audio\n clock-rate: 16000\n encoding-name: SIREN\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "audio/x-siren:\n dct-length: 320\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtpsirenpay": { - "author": "Youness Alaoui ", - "description": "Packetize Siren audio streams into RTP packets", - "hierarchy": [ - "GstRTPSirenPay", - "GstRTPBaseAudioPayload", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP Payloader for Siren Audio", - "name": "rtpsirenpay", - "pad-templates": { - "sink": { - "caps": "audio/x-siren:\n dct-length: 320\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: 16000\n encoding-name: SIREN\n bitrate: 16000\n dct-length: 320\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "buffer-list": { - "blurb": "Use Buffer Lists", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)16000, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "secondary" - }, - "rtpspeexdepay": { - "author": "Edgard Lima ", - "description": "Extracts Speex audio from RTP packets", - "hierarchy": [ - "GstRtpSPEEXDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP Speex depayloader", - "name": "rtpspeexdepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: audio\n clock-rate: [ 6000, 48000 ]\n encoding-name: SPEEX\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "audio/x-speex:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtpspeexpay": { - "author": "Edgard Lima ", - "description": "Payload-encodes Speex audio into a RTP packet", - "hierarchy": [ - "GstRtpSPEEXPay", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP Speex payloader", - "name": "rtpspeexpay", - "pad-templates": { - "sink": { - "caps": "audio/x-speex:\n rate: [ 6000, 48000 ]\n channels: 1\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: [ 6000, 48000 ]\n encoding-name: SPEEX\nencoding-params: 1\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "110", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)8000, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)110, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "secondary" - }, - "rtpstorage": { - "author": "Mikhail Fludkov ", - "description": "Helper element for various purposes (ex. recovering from packet loss using RED/FEC). Saves given number of RTP packets. Should be instantiated before jitterbuffer", - "hierarchy": [ - "GstRtpStorage", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Analyzer/RTP", - "long-name": "RTP storage", - "name": "rtpstorage", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "internal-storage": { - "blurb": "Internal RtpStorage object", - "construct": false, - "construct-only": false, - "type-name": "GObject", - "writable": false - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "size-time": { - "blurb": "The amount of data to keep in the storage (in ns, 0-disable)", - "construct": true, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - } - }, - "rank": "none" - }, - "rtpstreamdepay": { - "author": "Sebastian Dr\u00f6ge ", - "description": "Depayloads RTP/RTCP packets for streaming protocols according to RFC4571", - "hierarchy": [ - "GstRtpStreamDepay", - "GstBaseParse", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network", - "long-name": "RTP Stream Depayloading", - "name": "rtpstreamdepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp-stream:\napplication/x-rtcp-stream:\napplication/x-srtp-stream:\napplication/x-srtcp-stream:\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\napplication/x-rtcp:\napplication/x-srtp:\napplication/x-srtcp:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "disable-passthrough": { - "blurb": "Force processing (disables passthrough)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, - "rank": "none" - }, - "rtpstreampay": { - "author": "Sebastian Dr\u00f6ge ", - "description": "Payloads RTP/RTCP packets for streaming protocols according to RFC4571", - "hierarchy": [ - "GstRtpStreamPay", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network", - "long-name": "RTP Stream Payloading", - "name": "rtpstreampay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\napplication/x-rtcp:\napplication/x-srtp:\napplication/x-srtcp:\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp-stream:\napplication/x-rtcp-stream:\napplication/x-srtp-stream:\napplication/x-srtcp-stream:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, - "rank": "none" - }, - "rtpsv3vdepay": { - "author": "Wim Taymans ", - "description": "Extracts SVQ3 video from RTP packets (no RFC)", - "hierarchy": [ - "GstRtpSV3VDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP SVQ3 depayloader", - "name": "rtpsv3vdepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: video\n clock-rate: 90000\n encoding-name: { (string)X-SV3V-ES, (string)X-SORENSON-VIDEO, (string)X-SORENSONVIDEO, (string)X-SorensonVideo }\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "video/x-svq:\n svqversion: 3\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtptheoradepay": { - "author": "Wim Taymans ", - "description": "Extracts Theora video from RTP packets (draft-01 of RFC XXXX)", - "hierarchy": [ - "GstRtpTheoraDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP Theora depayloader", - "name": "rtptheoradepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: video\n clock-rate: 90000\n encoding-name: THEORA\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "video/x-theora:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtptheorapay": { - "author": "Wim Taymans ", - "description": "Payload-encode Theora video into RTP packets (draft-01 RFC XXXX)", - "hierarchy": [ - "GstRtpTheoraPay", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP Theora payloader", - "name": "rtptheorapay", - "pad-templates": { - "sink": { - "caps": "video/x-theora:\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: THEORA\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "config-interval": { - "blurb": "Send Config Insertion Interval in seconds (configuration headers will be multiplexed in the data stream when detected.) (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "3600", - "min": "0", - "type-name": "guint", - "writable": true - }, - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "secondary" - }, - "rtpulpfecdec": { - "author": "Mikhail Fludkov ", - "description": "Decodes RTP FEC (RFC5109)", - "hierarchy": [ - "GstRtpUlpFecDec", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP FEC Decoder", - "name": "rtpulpfecdec", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "pt": { - "blurb": "FEC packets payload type", - "construct": false, - "construct-only": false, - "default": "0", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "recovered": { - "blurb": "The number of recovered packets", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "storage": { - "blurb": "RTP storage", - "construct": false, - "construct-only": false, - "type-name": "GObject", - "writable": true - }, - "unrecovered": { - "blurb": "The number of unrecovered packets", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - } - }, - "rank": "none" - }, - "rtpulpfecenc": { - "author": "Mikhail Fludkov ", - "description": "Encodes RTP FEC (RFC5109)", - "hierarchy": [ - "GstRtpUlpFecEnc", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP FEC Encoder", - "name": "rtpulpfecenc", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "multipacket": { - "blurb": "Apply FEC on multiple packets", - "construct": true, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "percentage": { - "blurb": "FEC overhead percentage for the whole stream", - "construct": true, - "construct-only": false, - "default": "0", - "max": "100", - "min": "0", - "type-name": "guint", - "writable": true - }, - "percentage-important": { - "blurb": "FEC overhead percentage for important packets", - "construct": true, - "construct-only": false, - "default": "0", - "max": "100", - "min": "0", - "type-name": "guint", - "writable": true - }, - "protected": { - "blurb": "Count of protected packets", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "pt": { - "blurb": "The payload type of FEC packets", - "construct": true, - "construct-only": false, - "default": "255", - "max": "255", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "none" - }, - "rtpvorbisdepay": { - "author": "Wim Taymans ", - "description": "Extracts Vorbis Audio from RTP packets (RFC 5215)", - "hierarchy": [ - "GstRtpVorbisDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP Vorbis depayloader", - "name": "rtpvorbisdepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: audio\n clock-rate: [ 1, 2147483647 ]\n encoding-name: VORBIS\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "audio/x-vorbis:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtpvorbispay": { - "author": "Wim Taymans ", - "description": "Payload-encode Vorbis audio into RTP packets (RFC 5215)", - "hierarchy": [ - "GstRtpVorbisPay", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP Vorbis payloader", - "name": "rtpvorbispay", - "pad-templates": { - "sink": { - "caps": "audio/x-vorbis:\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: audio\n payload: [ 96, 127 ]\n clock-rate: [ 1, 2147483647 ]\n encoding-name: VORBIS\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "config-interval": { - "blurb": "Send Config Insertion Interval in seconds (configuration headers will be multiplexed in the data stream when detected.) (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "3600", - "min": "0", - "type-name": "guint", - "writable": true - }, - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "secondary" - }, - "rtpvp8depay": { - "author": "Sjoerd Simons ", - "description": "Extracts VP8 video from RTP packets)", - "hierarchy": [ - "GstRtpVP8Depay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP VP8 depayloader", - "name": "rtpvp8depay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n clock-rate: 90000\n media: video\n encoding-name: { (string)VP8, (string)VP8-DRAFT-IETF-01 }\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "video/x-vp8:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "wait-for-keyframe": { - "blurb": "Wait for the next keyframe after packet loss", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - } - }, - "rank": "marginal" - }, - "rtpvp8pay": { - "author": "Sjoerd Simons ", - "description": "Puts VP8 video in RTP packets", - "hierarchy": [ - "GstRtpVP8Pay", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP VP8 payloader", - "name": "rtpvp8pay", - "pad-templates": { - "sink": { - "caps": "video/x-vp8:\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: { (string)VP8, (string)VP8-DRAFT-IETF-01 }\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "picture-id-mode": { - "blurb": "The picture ID mode for payloading", - "construct": false, - "construct-only": false, - "default": "none (0)", - "enum": true, - "type-name": "GstVP8RTPPayMode", - "values": [ - { - "desc": "No Picture ID", - "name": "none", - "value": "0" - }, - { - "desc": "7-bit Picture ID", - "name": "7-bit", - "value": "1" - }, - { - "desc": "15-bit Picture ID", - "name": "15-bit", - "value": "2" - } - ], - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "marginal" - }, - "rtpvp9depay": { - "author": "Stian Selnes ", - "description": "Extracts VP9 video from RTP packets)", - "hierarchy": [ - "GstRtpVP9Depay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP VP9 depayloader", - "name": "rtpvp9depay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n clock-rate: 90000\n media: video\n encoding-name: { (string)VP9, (string)VP9-DRAFT-IETF-01 }\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "video/x-vp9:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "marginal" - }, - "rtpvp9pay": { - "author": "Stian Selnes ", - "description": "Puts VP9 video in RTP packets)", - "hierarchy": [ - "GstRtpVP9Pay", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP VP9 payloader", - "name": "rtpvp9pay", - "pad-templates": { - "sink": { - "caps": "video/x-vp9:\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: { (string)VP9, (string)VP9-DRAFT-IETF-01 }\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "picture-id-mode": { - "blurb": "The picture ID mode for payloading", - "construct": false, - "construct-only": false, - "default": "none (0)", - "enum": true, - "type-name": "GstVP9RTPPayMode", - "values": [ - { - "desc": "No Picture ID", - "name": "none", - "value": "0" - }, - { - "desc": "7-bit Picture ID", - "name": "7-bit", - "value": "1" - }, - { - "desc": "15-bit Picture ID", - "name": "15-bit", - "value": "2" - } - ], - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "marginal" - }, - "rtpvrawdepay": { - "author": "Wim Taymans ", - "description": "Extracts raw video from RTP packets (RFC 4175)", - "hierarchy": [ - "GstRtpVRawDepay", - "GstRTPBaseDepayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Depayloader/Network/RTP", - "long-name": "RTP Raw Video depayloader", - "name": "rtpvrawdepay", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n media: video\n clock-rate: 90000\n encoding-name: RAW\n sampling: { (string)RGB, (string)RGBA, (string)BGR, (string)BGRA, (string)YCbCr-4:4:4, (string)YCbCr-4:2:2, (string)YCbCr-4:2:0, (string)YCbCr-4:1:1 }\n depth: { (string)8, (string)10, (string)12, (string)16 }\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "video/x-raw:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-reorder": { - "blurb": "Max seqnum reorder before assuming sender has restarted", - "construct": false, - "construct-only": false, - "default": "100", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "source-info": { - "blurb": "Add RTP source information as buffer meta", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-depayload-stats, clock_rate=(uint)0, npt-start=(guint64)0, npt-stop=(guint64)18446744073709551615, play-speed=(double)1, play-scale=(double)1, running-time-dts=(guint64)18446744073709551615, running-time-pts=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0;", - "type-name": "GstStructure", - "writable": false - } - }, - "rank": "secondary" - }, - "rtpvrawpay": { - "author": "Wim Taymans ", - "description": "Payload raw video as RTP packets (RFC 4175)", - "hierarchy": [ - "GstRtpVRawPay", - "GstRTPBasePayload", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Payloader/Network/RTP", - "long-name": "RTP Raw Video payloader", - "name": "rtpvrawpay", - "pad-templates": { - "sink": { - "caps": "video/x-raw:\n format: { RGB, RGBA, BGR, BGRA, AYUV, UYVY, I420, Y41B, UYVP }\n width: [ 1, 32767 ]\n height: [ 1, 32767 ]\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: RAW\n sampling: { (string)RGB, (string)RGBA, (string)BGR, (string)BGRA, (string)YCbCr-4:4:4, (string)YCbCr-4:2:2, (string)YCbCr-4:2:0, (string)YCbCr-4:1:1 }\n depth: { (string)8, (string)10, (string)12, (string)16 }\n colorimetry: { (string)BT601-5, (string)BT709-2, (string)SMPTE240M }\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "chunks-per-frame": { - "blurb": "Split and send out each frame in multiple chunks to reduce overhead", - "construct": false, - "construct-only": false, - "default": "10", - "max": "2147483647", - "min": "1", - "type-name": "gint", - "writable": true - }, - "max-ptime": { - "blurb": "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "min-ptime": { - "blurb": "Minimum duration of the packet data in ns (can't go above MTU)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "mtu": { - "blurb": "Maximum size of one packet", - "construct": false, - "construct-only": false, - "default": "1400", - "max": "-1", - "min": "28", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "onvif-no-rate-control": { - "blurb": "Enable ONVIF Rate-Control=no timestamping mode", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-rtptime": { - "blurb": "Generate perfect RTP timestamps when possible", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "pt": { - "blurb": "The payload type of the packets", - "construct": false, - "construct-only": false, - "default": "96", - "max": "127", - "min": "0", - "type-name": "guint", - "writable": true - }, - "ptime-multiple": { - "blurb": "Force buffers to be multiples of this duration in ns (0 disables)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "65535", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "source-info": { - "blurb": "Write CSRC based on buffer meta RTP source information", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-payload-stats, clock-rate=(uint)0, running-time=(guint64)18446744073709551615, seqnum=(uint)0, timestamp=(uint)0, ssrc=(uint)0, pt=(uint)96, seqnum-offset=(uint)0, timestamp-offset=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "timestamp": { - "blurb": "The RTP timestamp of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (default = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - } - }, - "rank": "secondary" - } - }, - "filename": "gstrtp", - "license": "LGPL", - "package": "GStreamer Good Plug-ins git", - "source": "gst-plugins-good", - "tracers": {}, - "url": "Unknown package origin" - }, - "rtpmanager": { - "description": "RTP session management plugin library", - "elements": { - "rtpbin": { - "author": "Wim Taymans ", - "description": "Real-Time Transport Protocol bin", - "hierarchy": [ - "GstRtpBin", - "GstBin", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Filter/Network/RTP", - "long-name": "RTP Bin", - "name": "rtpbin", - "pad-templates": { - "recv_rtcp_sink_%%u": { - "caps": "application/x-rtcp:\napplication/x-srtcp:\n", - "direction": "sink", - "presence": "request" - }, - "recv_rtp_sink_%%u": { - "caps": "application/x-rtp:\napplication/x-srtp:\n", - "direction": "sink", - "presence": "request" - }, - "recv_rtp_src_%%u_%%u_%%u": { - "caps": "application/x-rtp:\n", - "direction": "src", - "presence": "sometimes" - }, - "send_rtcp_src_%%u": { - "caps": "application/x-rtcp:\napplication/x-srtcp:\n", - "direction": "src", - "presence": "request" - }, - "send_rtp_sink_%%u": { - "caps": "application/x-rtp:\n", - "direction": "sink", - "presence": "request" - }, - "send_rtp_src_%%u": { - "caps": "application/x-rtp:\napplication/x-srtp:\n", - "direction": "src", - "presence": "sometimes" - } - }, - "properties": { - "async-handling": { - "blurb": "The bin will handle Asynchronous state changes", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "autoremove": { - "blurb": "Automatically remove timed out sources", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "buffer-mode": { - "blurb": "Control the buffering algorithm in use", - "construct": false, - "construct-only": false, - "default": "slave (1)", - "enum": true, - "type-name": "RTPJitterBufferMode", - "values": [ - { - "desc": "Only use RTP timestamps", - "name": "none", - "value": "0" - }, - { - "desc": "Slave receiver to sender clock", - "name": "slave", - "value": "1" - }, - { - "desc": "Do low/high watermark buffering", - "name": "buffer", - "value": "2" - }, - { - "desc": "Synchronized sender and receiver clocks", - "name": "synced", - "value": "4" - } - ], - "writable": true - }, - "do-lost": { - "blurb": "Send an event downstream when a packet is lost", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "do-retransmission": { - "blurb": "Enable retransmission on all streams", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "do-sync-event": { - "blurb": "Send event downstream when a stream is synchronized to the sender", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "drop-on-latency": { - "blurb": "Tells the jitterbuffer to never exceed the given latency in size", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ignore-pt": { - "blurb": "Do not demultiplex based on PT values", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "latency": { - "blurb": "Default amount of ms to buffer in the jitterbuffers", - "construct": false, - "construct-only": false, - "default": "200", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "max-dropout-time": { - "blurb": "The maximum time (milliseconds) of missing packets tolerated.", - "construct": false, - "construct-only": false, - "default": "60000", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "max-misorder-time": { - "blurb": "The maximum time (milliseconds) of misordered packets tolerated.", - "construct": false, - "construct-only": false, - "default": "2000", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "max-rtcp-rtp-time-diff": { - "blurb": "Maximum amount of time in ms that the RTP time in RTCP SRs is allowed to be ahead (-1 disabled)", - "construct": false, - "construct-only": false, - "default": "1000", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "max-streams": { - "blurb": "The maximum number of streams to create for one session", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "max-ts-offset": { - "blurb": "The maximum absolute value of the time offset in (nanoseconds). Note, if the ntp-sync parameter is set the default value is changed to 0 (no limit)", - "construct": false, - "construct-only": false, - "default": "3000000000", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "max-ts-offset-adjustment": { - "blurb": "The maximum number of nanoseconds per frame that time stamp offsets may be adjusted (0 = no limit).", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "message-forward": { - "blurb": "Forwards all children messages", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "ntp-sync": { - "blurb": "Synchronize received streams to the NTP clock", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ntp-time-source": { - "blurb": "NTP time source for RTCP packets", - "construct": false, - "construct-only": false, - "default": "ntp (0)", - "enum": true, - "type-name": "GstRtpNtpTimeSource", - "values": [ - { - "desc": "NTP time based on realtime clock", - "name": "ntp", - "value": "0" - }, - { - "desc": "UNIX time based on realtime clock", - "name": "unix", - "value": "1" - }, - { - "desc": "Running time based on pipeline clock", - "name": "running-time", - "value": "2" - }, - { - "desc": "Pipeline clock time", - "name": "clock-time", - "value": "3" - } - ], - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "rfc7273-sync": { - "blurb": "Synchronize received streams to the RFC7273 clock (requires clock and offset to be provided)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "rtcp-sync": { - "blurb": "Use of RTCP SR in synchronization", - "construct": false, - "construct-only": false, - "default": "always (0)", - "enum": true, - "type-name": "GstRTCPSync", - "values": [ - { - "desc": "always", - "name": "always", - "value": "0" - }, - { - "desc": "initial", - "name": "initial", - "value": "1" - }, - { - "desc": "rtp-info", - "name": "rtp-info", - "value": "2" - } - ], - "writable": true - }, - "rtcp-sync-interval": { - "blurb": "RTCP SR interval synchronization (ms) (0 = always)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "rtcp-sync-send-time": { - "blurb": "Use send time or capture time for RTCP sync (TRUE = send time, FALSE = capture time)", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "rtp-profile": { - "blurb": "Default RTP profile of newly created sessions", - "construct": false, - "construct-only": false, - "default": "avp (1)", - "enum": true, - "type-name": "GstRTPProfile", - "values": [ - { - "desc": "GST_RTP_PROFILE_UNKNOWN", - "name": "unknown", - "value": "0" - }, - { - "desc": "GST_RTP_PROFILE_AVP", - "name": "avp", - "value": "1" - }, - { - "desc": "GST_RTP_PROFILE_SAVP", - "name": "savp", - "value": "2" - }, - { - "desc": "GST_RTP_PROFILE_AVPF", - "name": "avpf", - "value": "3" - }, - { - "desc": "GST_RTP_PROFILE_SAVPF", - "name": "savpf", - "value": "4" - } - ], - "writable": true - }, - "sdes": { - "blurb": "The SDES items of this session", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-source-sdes, cname=(string)\"user648023474\\@host-e59d5d7e\", tool=(string)GStreamer;", - "hotdoc-fixed-default": true, - "type-name": "GstStructure", - "writable": true - }, - "use-pipeline-clock": { - "blurb": "Use the pipeline running-time to set the NTP time in the RTCP SR messages (DEPRECATED: Use ntp-time-source property)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - } - }, - "rank": "none", - "signals": { - "clear-pt-map": { - "args": [], - "retval": "void" - }, - "get-internal-session": { - "args": [ - "guint" - ], - "retval": "RTPSession" - }, - "get-internal-storage": { - "args": [ - "guint" - ], - "retval": "GObject" - }, - "get-session": { - "args": [ - "guint" - ], - "retval": "GstElement" - }, - "get-storage": { - "args": [ - "guint" - ], - "retval": "GstElement" - }, - "new-jitterbuffer": { - "args": [ - "GstElement", - "guint", - "guint" - ], - "retval": "void" - }, - "new-storage": { - "args": [ - "GstElement", - "guint" - ], - "retval": "void" - }, - "no-more-pads": { - "args": [], - "retval": "void" - }, - "on-bundled-ssrc": { - "args": [ - "guint" - ], - "retval": "guint" - }, - "on-bye-ssrc": { - "args": [ - "guint", - "guint" - ], - "retval": "void" - }, - "on-bye-timeout": { - "args": [ - "guint", - "guint" - ], - "retval": "void" - }, - "on-new-sender-ssrc": { - "args": [ - "guint", - "guint" - ], - "retval": "void" - }, - "on-new-ssrc": { - "args": [ - "guint", - "guint" - ], - "retval": "void" - }, - "on-npt-stop": { - "args": [ - "guint", - "guint" - ], - "retval": "void" - }, - "on-sender-ssrc-active": { - "args": [ - "guint", - "guint" - ], - "retval": "void" - }, - "on-sender-timeout": { - "args": [ - "guint", - "guint" - ], - "retval": "void" - }, - "on-ssrc-active": { - "args": [ - "guint", - "guint" - ], - "retval": "void" - }, - "on-ssrc-collision": { - "args": [ - "guint", - "guint" - ], - "retval": "void" - }, - "on-ssrc-sdes": { - "args": [ - "guint", - "guint" - ], - "retval": "void" - }, - "on-ssrc-validated": { - "args": [ - "guint", - "guint" - ], - "retval": "void" - }, - "on-timeout": { - "args": [ - "guint", - "guint" - ], - "retval": "void" - }, - "pad-added": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "pad-removed": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "payload-type-change": { - "args": [ - "guint", - "guint" - ], - "retval": "void" - }, - "request-aux-receiver": { - "args": [ - "guint" - ], - "retval": "GstElement" - }, - "request-aux-sender": { - "args": [ - "guint" - ], - "retval": "GstElement" - }, - "request-fec-decoder": { - "args": [ - "guint" - ], - "retval": "GstElement" - }, - "request-fec-encoder": { - "args": [ - "guint" - ], - "retval": "GstElement" - }, - "request-jitterbuffer": { - "args": [ - "guint" - ], - "retval": "GstElement" - }, - "request-pt-map": { - "args": [ - "guint", - "guint" - ], - "retval": "GstCaps" - }, - "request-rtcp-decoder": { - "args": [ - "guint" - ], - "retval": "GstElement" - }, - "request-rtcp-encoder": { - "args": [ - "guint" - ], - "retval": "GstElement" - }, - "request-rtp-decoder": { - "args": [ - "guint" - ], - "retval": "GstElement" - }, - "request-rtp-encoder": { - "args": [ - "guint" - ], - "retval": "GstElement" - }, - "reset-sync": { - "args": [], - "retval": "void" - } - } - }, - "rtpdtmfmux": { - "author": "Zeeshan Ali ", - "description": "mixes RTP DTMF streams into other RTP streams", - "hierarchy": [ - "GstRTPDTMFMux", - "GstRTPMux", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Muxer", - "long-name": "RTP muxer", - "name": "rtpdtmfmux", - "pad-templates": { - "priority_sink_%%u": { - "caps": "application/x-rtp:\n", - "direction": "sink", - "presence": "request" - }, - "sink_%%u": { - "caps": "application/x-rtp:\n", - "direction": "sink", - "presence": "request" - }, - "src": { - "caps": "application/x-rtp:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - } - }, - "rank": "none" - }, - "rtpfunnel": { - "author": "Havard Graff ", - "description": "Funnel RTP buffers together for multiplexing", - "hierarchy": [ - "GstRtpFunnel", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "RTP Funneling", - "long-name": "RTP funnel", - "name": "rtpfunnel", - "pad-templates": { - "sink_%%u": { - "caps": "application/x-rtp:\n", - "direction": "sink", - "presence": "request" - }, - "src": { - "caps": "application/x-rtp:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "common-ts-offset": { - "blurb": "Use the same RTP timestamp offset for all sinkpads (-1 = disable)", - "construct": true, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, - "rank": "none" - }, - "rtpjitterbuffer": { - "author": "Philippe Kalaf , Wim Taymans ", - "description": "A buffer that deals with network jitter and other transmission faults", - "hierarchy": [ - "GstRtpJitterBuffer", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Filter/Network/RTP", - "long-name": "RTP packet jitter-buffer", - "name": "rtpjitterbuffer", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n", - "direction": "sink", - "presence": "always" - }, - "sink_rtcp": { - "caps": "application/x-rtcp:\n", - "direction": "sink", - "presence": "request" - }, - "src": { - "caps": "application/x-rtp:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "do-lost": { - "blurb": "Send an event downstream when a packet is lost", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "do-retransmission": { - "blurb": "Send retransmission events upstream when a packet is late", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "drop-on-latency": { - "blurb": "Tells the jitterbuffer to never exceed the given latency in size", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "faststart-min-packets": { - "blurb": "The number of consecutive packets needed to start (set to 0 to disable faststart. The jitterbuffer will by default start after the latency has elapsed)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "latency": { - "blurb": "Amount of ms to buffer", - "construct": false, - "construct-only": false, - "default": "200", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "max-dropout-time": { - "blurb": "The maximum time (milliseconds) of missing packets tolerated.", - "construct": false, - "construct-only": false, - "default": "60000", - "max": "2147483647", - "min": "0", - "type-name": "guint", - "writable": true - }, - "max-misorder-time": { - "blurb": "The maximum time (milliseconds) of misordered packets tolerated.", - "construct": false, - "construct-only": false, - "default": "2000", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "max-rtcp-rtp-time-diff": { - "blurb": "Maximum amount of time in ms that the RTP time in RTCP SRs is allowed to be ahead (-1 disabled)", - "construct": false, - "construct-only": false, - "default": "1000", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "max-ts-offset-adjustment": { - "blurb": "The maximum number of nanoseconds per frame that time stamp offsets may be adjusted (0 = no limit).", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "mode": { - "blurb": "Control the buffering algorithm in use", - "construct": false, - "construct-only": false, - "default": "slave (1)", - "enum": true, - "type-name": "RTPJitterBufferMode", - "values": [ - { - "desc": "Only use RTP timestamps", - "name": "none", - "value": "0" - }, - { - "desc": "Slave receiver to sender clock", - "name": "slave", - "value": "1" - }, - { - "desc": "Do low/high watermark buffering", - "name": "buffer", - "value": "2" - }, - { - "desc": "Synchronized sender and receiver clocks", - "name": "synced", - "value": "4" - } - ], - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "percent": { - "blurb": "The buffer filled percent", - "construct": false, - "construct-only": false, - "default": "0", - "max": "100", - "min": "0", - "type-name": "gint", - "writable": false - }, - "rfc7273-sync": { - "blurb": "Synchronize received streams to the RFC7273 clock (requires clock and offset to be provided)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "rtx-deadline": { - "blurb": "The deadline for a valid RTX request in milliseconds. (-1 automatic)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "rtx-delay": { - "blurb": "Extra time in ms to wait before sending retransmission event (-1 automatic)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "rtx-delay-reorder": { - "blurb": "Sending retransmission event when this much reordering (0 disable)", - "construct": false, - "construct-only": false, - "default": "3", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "rtx-max-retries": { - "blurb": "The maximum number of retries to request a retransmission. (-1 not limited)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "rtx-min-delay": { - "blurb": "Minimum time in ms to wait before sending retransmission event", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "rtx-min-retry-timeout": { - "blurb": "Minimum timeout between sending a transmission event in ms (-1 automatic)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "rtx-next-seqnum": { - "blurb": "Estimate when the next packet should arrive and schedule a retransmission request for it.", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "rtx-retry-period": { - "blurb": "Try to get a retransmission for this many ms (-1 automatic)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "rtx-retry-timeout": { - "blurb": "Retry sending a transmission event after this timeout in ms (-1 automatic)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "rtx-stats-timeout": { - "blurb": "The time to wait for a retransmitted packet after it has been considered lost in order to collect statistics (ms)", - "construct": false, - "construct-only": false, - "default": "1000", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-jitterbuffer-stats, num-pushed=(guint64)0, num-lost=(guint64)0, num-late=(guint64)0, num-duplicates=(guint64)0, avg-jitter=(guint64)0, rtx-count=(guint64)0, rtx-success-count=(guint64)0, rtx-per-packet=(double)0, rtx-rtt=(guint64)0;", - "type-name": "GstStructure", - "writable": false - }, - "ts-offset": { - "blurb": "Adjust buffer timestamps with offset in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "-9223372036854775808", - "type-name": "gint64", - "writable": true - } - }, - "rank": "none", - "signals": { - "clear-pt-map": { - "args": [], - "retval": "void" - }, - "handle-sync": { - "args": [ - "GstStructure" - ], - "retval": "void" - }, - "on-npt-stop": { - "args": [], - "retval": "void" - }, - "request-pt-map": { - "args": [ - "guint" - ], - "retval": "GstCaps" - }, - "set-active": { - "args": [ - "gboolean", - "guint64" - ], - "retval": "guint64" - } - } - }, - "rtpmux": { - "author": "Zeeshan Ali ", - "description": "multiplex N rtp streams into one", - "hierarchy": [ - "GstRTPMux", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Muxer", - "long-name": "RTP muxer", - "name": "rtpmux", - "pad-templates": { - "sink_%%u": { - "caps": "application/x-rtp:\n", - "direction": "sink", - "presence": "request" - }, - "src": { - "caps": "application/x-rtp:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "seqnum": { - "blurb": "The RTP sequence number of the last processed packet", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "seqnum-offset": { - "blurb": "Offset to add to all outgoing seqnum (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "ssrc": { - "blurb": "The SSRC of the packets (default == random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "timestamp-offset": { - "blurb": "Offset to add to all outgoing timestamps (-1 = random)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - } - }, - "rank": "none" - }, - "rtpptdemux": { - "author": "Kai Vehmanen ", - "description": "Parses codec streams transmitted in the same RTP session", - "hierarchy": [ - "GstRtpPtDemux", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Demux/Network/RTP", - "long-name": "RTP Demux", - "name": "rtpptdemux", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n", - "direction": "sink", - "presence": "always" - }, - "src_%%u": { - "caps": "application/x-rtp:\n payload: [ 0, 255 ]\n", - "direction": "src", - "presence": "sometimes" - } - }, - "properties": { - "ignored-payload-types": { - "blurb": "Packets with these payload types will be dropped", - "construct": false, - "construct-only": false, - "type-name": "GstValueArray", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, - "rank": "none", - "signals": { - "clear-pt-map": { - "args": [], - "retval": "void" - }, - "new-payload-type": { - "args": [ - "guint", - "GstPad" - ], - "retval": "void" - }, - "no-more-pads": { - "args": [], - "retval": "void" - }, - "pad-added": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "pad-removed": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "payload-type-change": { - "args": [ - "guint" - ], - "retval": "void" - }, - "request-pt-map": { - "args": [ - "guint" - ], - "retval": "GstCaps" - } - } - }, - "rtprtxqueue": { - "author": "Wim Taymans ", - "description": "Keep RTP packets in a queue for retransmission", - "hierarchy": [ - "GstRTPRtxQueue", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec", - "long-name": "RTP Retransmission Queue", - "name": "rtprtxqueue", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "fulfilled-requests": { - "blurb": "Number of fulfilled retransmission requests", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "max-size-packets": { - "blurb": "Amount of packets to queue (0 = unlimited)", - "construct": false, - "construct-only": false, - "default": "100", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "max-size-time": { - "blurb": "Amount of ms to queue (0 = unlimited)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "requests": { - "blurb": "Total number of retransmission requests", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - } - }, - "rank": "none" - }, - "rtprtxreceive": { - "author": "Julien Isorce ", - "description": "Receive retransmitted RTP packets according to RFC4588", - "hierarchy": [ - "GstRtpRtxReceive", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec", - "long-name": "RTP Retransmission receiver", - "name": "rtprtxreceive", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "num-rtx-assoc-packets": { - "blurb": "Number of retransmission packets correctly associated with retransmission requests", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "num-rtx-packets": { - "blurb": " Number of retransmission packets received", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "num-rtx-requests": { - "blurb": "Number of retransmission events received", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "payload-type-map": { - "blurb": "Map of original payload types to their retransmission payload types", - "construct": false, - "construct-only": false, - "type-name": "GstStructure", - "writable": true - } - }, - "rank": "none" - }, - "rtprtxsend": { - "author": "Julien Isorce ", - "description": "Retransmit RTP packets when needed, according to RFC4588", - "hierarchy": [ - "GstRtpRtxSend", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec", - "long-name": "RTP Retransmission Sender", - "name": "rtprtxsend", - "pad-templates": { - "sink": { - "caps": "application/x-rtp:\n clock-rate: [ 1, 2147483647 ]\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "application/x-rtp:\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "max-size-packets": { - "blurb": "Amount of packets to queue (0 = unlimited)", - "construct": false, - "construct-only": false, - "default": "100", - "max": "32767", - "min": "0", - "type-name": "guint", - "writable": true - }, - "max-size-time": { - "blurb": "Amount of ms to queue (0 = unlimited)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "num-rtx-packets": { - "blurb": " Number of retransmission packets sent", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "num-rtx-requests": { - "blurb": "Number of retransmission events received", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "payload-type-map": { - "blurb": "Map of original payload types to their retransmission payload types", - "construct": false, - "construct-only": false, - "type-name": "GstStructure", - "writable": true - }, - "ssrc-map": { - "blurb": "Map of SSRCs to their retransmission SSRCs for SSRC-multiplexed mode (default = random)", - "construct": false, - "construct-only": false, - "type-name": "GstStructure", - "writable": true - } - }, - "rank": "none" - }, - "rtpsession": { - "author": "Wim Taymans ", - "description": "Implement an RTP session", - "hierarchy": [ - "GstRtpSession", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Filter/Network/RTP", - "long-name": "RTP Session", - "name": "rtpsession", - "pad-templates": { - "recv_rtcp_sink": { - "caps": "application/x-rtcp:\n", - "direction": "sink", - "presence": "request" - }, - "recv_rtp_sink": { - "caps": "application/x-rtp:\n", - "direction": "sink", - "presence": "request" - }, - "recv_rtp_src": { - "caps": "application/x-rtp:\n", - "direction": "src", - "presence": "sometimes" - }, - "send_rtcp_src": { - "caps": "application/x-rtcp:\n", - "direction": "src", - "presence": "request" - }, - "send_rtp_sink": { - "caps": "application/x-rtp:\n", - "direction": "sink", - "presence": "request" - }, - "send_rtp_src": { - "caps": "application/x-rtp:\n", - "direction": "src", - "presence": "sometimes" - }, - "sync_src": { - "caps": "application/x-rtcp:\n", - "direction": "src", - "presence": "sometimes" - } - }, - "properties": { - "bandwidth": { - "blurb": "The bandwidth of the session in bytes per second (0 for auto-discover)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "1.79769e+308", - "min": "0", - "type-name": "gdouble", - "writable": true - }, - "internal-session": { - "blurb": "The internal RTPSession object", - "construct": false, - "construct-only": false, - "type-name": "RTPSession", - "writable": false - }, - "max-dropout-time": { - "blurb": "The maximum time (milliseconds) of missing packets tolerated.", - "construct": false, - "construct-only": false, - "default": "60000", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "max-misorder-time": { - "blurb": "The maximum time (milliseconds) of misordered packets tolerated.", - "construct": false, - "construct-only": false, - "default": "2000", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "ntp-time-source": { - "blurb": "NTP time source for RTCP packets", - "construct": false, - "construct-only": false, - "default": "ntp (0)", - "enum": true, - "type-name": "GstRtpNtpTimeSource", - "values": [ - { - "desc": "NTP time based on realtime clock", - "name": "ntp", - "value": "0" - }, - { - "desc": "UNIX time based on realtime clock", - "name": "unix", - "value": "1" - }, - { - "desc": "Running time based on pipeline clock", - "name": "running-time", - "value": "2" - }, - { - "desc": "Pipeline clock time", - "name": "clock-time", - "value": "3" - } - ], - "writable": true - }, - "num-active-sources": { - "blurb": "The number of active sources in the session", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "num-sources": { - "blurb": "The number of sources in the session", - "construct": false, - "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": false - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "probation": { - "blurb": "Consecutive packet sequence numbers to accept the source", - "construct": false, - "construct-only": false, - "default": "2", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "rtcp-fraction": { - "blurb": "The RTCP bandwidth of the session in bytes per second (or as a real fraction of the RTP bandwidth if < 1.0)", - "construct": false, - "construct-only": false, - "default": "0.05", - "max": "1.79769e+308", - "min": "0", - "type-name": "gdouble", - "writable": true - }, - "rtcp-min-interval": { - "blurb": "Minimum interval between Regular RTCP packet (in ns)", - "construct": false, - "construct-only": false, - "default": "5000000000", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "rtcp-rr-bandwidth": { - "blurb": "The RTCP bandwidth used for receivers in bytes per second (-1 = default)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "rtcp-rs-bandwidth": { - "blurb": "The RTCP bandwidth used for senders in bytes per second (-1 = default)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "rtcp-sync-send-time": { - "blurb": "Use send time or capture time for RTCP sync (TRUE = send time, FALSE = capture time)", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "rtp-profile": { - "blurb": "RTP profile to use", - "construct": false, - "construct-only": false, - "default": "avp (1)", - "enum": true, - "type-name": "GstRTPProfile", - "values": [ - { - "desc": "GST_RTP_PROFILE_UNKNOWN", - "name": "unknown", - "value": "0" - }, - { - "desc": "GST_RTP_PROFILE_AVP", - "name": "avp", - "value": "1" - }, - { - "desc": "GST_RTP_PROFILE_SAVP", - "name": "savp", - "value": "2" - }, - { - "desc": "GST_RTP_PROFILE_AVPF", - "name": "avpf", - "value": "3" - }, - { - "desc": "GST_RTP_PROFILE_SAVPF", - "name": "savpf", - "value": "4" - } - ], - "writable": true - }, - "sdes": { - "blurb": "The SDES items of this session", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-source-sdes, cname=(string)\"user1028847528\\@host-62b02aa8\", tool=(string)GStreamer;", - "hotdoc-fixed-default": true, - "type-name": "GstStructure", - "writable": true - }, - "stats": { - "blurb": "Various statistics", - "construct": false, - "construct-only": false, - "default": "application/x-rtp-session-stats, rtx-drop-count=(uint)0, sent-nack-count=(uint)0, recv-nack-count=(uint)0, source-stats=(GValueArray)< >, rtx-count=(uint)0, recv-rtx-req-count=(uint)0, sent-rtx-req-count=(uint)0;", - "type-name": "GstStructure", - "writable": false - }, - "use-pipeline-clock": { - "blurb": "Use the pipeline running-time to set the NTP time in the RTCP SR messages (DEPRECATED: Use ntp-time-source property)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - } - }, - "rank": "none", - "signals": { - "clear-pt-map": { - "args": [], - "retval": "void" - }, - "no-more-pads": { - "args": [], - "retval": "void" - }, - "on-bye-ssrc": { - "args": [ - "guint" - ], - "retval": "void" - }, - "on-bye-timeout": { - "args": [ - "guint" - ], - "retval": "void" - }, - "on-new-sender-ssrc": { - "args": [ - "guint" - ], - "retval": "void" - }, - "on-new-ssrc": { - "args": [ - "guint" - ], - "retval": "void" - }, - "on-sender-ssrc-active": { - "args": [ - "guint" - ], - "retval": "void" - }, - "on-sender-timeout": { - "args": [ - "guint" - ], - "retval": "void" - }, - "on-ssrc-active": { - "args": [ - "guint" - ], - "retval": "void" - }, - "on-ssrc-collision": { - "args": [ - "guint" - ], - "retval": "void" - }, - "on-ssrc-sdes": { - "args": [ - "guint" - ], - "retval": "void" - }, - "on-ssrc-validated": { - "args": [ - "guint" - ], - "retval": "void" - }, - "on-timeout": { - "args": [ - "guint" - ], - "retval": "void" - }, - "pad-added": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "pad-removed": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "request-pt-map": { - "args": [ - "guint" - ], - "retval": "GstCaps" - } - } - }, - "rtpssrcdemux": { - "author": "Wim Taymans ", - "description": "Splits RTP streams based on the SSRC", - "hierarchy": [ - "GstRtpSsrcDemux", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Demux/Network/RTP", - "long-name": "RTP SSRC Demux", - "name": "rtpssrcdemux", - "pad-templates": { - "rtcp_sink": { - "caps": "application/x-rtcp:\n", - "direction": "sink", - "presence": "always" - }, - "rtcp_src_%%u": { - "caps": "application/x-rtcp:\n", - "direction": "src", - "presence": "sometimes" - }, - "sink": { - "caps": "application/x-rtp:\n", - "direction": "sink", - "presence": "always" - }, - "src_%%u": { - "caps": "application/x-rtp:\n", - "direction": "src", - "presence": "sometimes" - } - }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, - "rank": "none", - "signals": { - "clear-ssrc": { - "args": [ - "guint" - ], - "retval": "void" - }, - "new-ssrc-pad": { - "args": [ - "guint", - "GstPad" - ], - "retval": "void" - }, - "no-more-pads": { - "args": [], - "retval": "void" - }, - "pad-added": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "pad-removed": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "removed-ssrc-pad": { - "args": [ - "guint", - "GstPad" - ], - "retval": "void" - } - } - } - }, - "filename": "gstrtpmanager", - "license": "LGPL", - "package": "GStreamer Good Plug-ins git", - "source": "gst-plugins-good", - "tracers": {}, - "url": "Unknown package origin" - }, - "rtsp": { - "description": "transfer data via RTSP", - "elements": { - "rtpdec": { - "author": "Wim Taymans ", - "description": "Accepts raw RTP and RTCP packets and sends them forward", - "hierarchy": [ - "GstRTPDec", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Parser/Network", - "long-name": "RTP Decoder", - "name": "rtpdec", - "pad-templates": { - "recv_rtcp_sink_%%u": { - "caps": "application/x-rtcp:\n", - "direction": "sink", - "presence": "request" - }, - "recv_rtp_sink_%%u": { - "caps": "application/x-rtp:\n", - "direction": "sink", - "presence": "request" - }, - "recv_rtp_src_%%u_%%u_%%u": { - "caps": "application/x-rtp:\n", - "direction": "src", - "presence": "sometimes" - }, - "rtcp_src_%%u": { - "caps": "application/x-rtcp:\n", - "direction": "src", - "presence": "request" - } - }, - "properties": { - "latency": { - "blurb": "Amount of ms to buffer", - "construct": false, - "construct-only": false, - "default": "200", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, - "rank": "none", - "signals": { - "clear-pt-map": { - "args": [], - "retval": "void" - }, - "no-more-pads": { - "args": [], - "retval": "void" - }, - "on-bye-ssrc": { - "args": [ - "guint", - "guint" - ], - "retval": "void" - }, - "on-bye-timeout": { - "args": [ - "guint", - "guint" - ], - "retval": "void" - }, - "on-new-ssrc": { - "args": [ - "guint", - "guint" - ], - "retval": "void" - }, - "on-ssrc-collision": { - "args": [ - "guint", - "guint" - ], - "retval": "void" - }, - "on-ssrc-validated": { - "args": [ - "guint", - "guint" - ], - "retval": "void" - }, - "on-timeout": { - "args": [ - "guint", - "guint" - ], - "retval": "void" - }, - "pad-added": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "pad-removed": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "request-pt-map": { - "args": [ - "guint", - "guint" - ], - "retval": "GstCaps" - } - } - }, - "rtspsrc": { - "author": "Wim Taymans , Thijs Vermeir , Lutz Mueller ", - "description": "Receive data over the network via RTSP (RFC 2326)", - "hierarchy": [ - "GstRTSPSrc", - "GstBin", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Source/Network", - "long-name": "RTSP packet receiver", - "name": "rtspsrc", - "pad-templates": { - "stream_%%u": { - "caps": "application/x-rtp:\napplication/x-rdt:\n", - "direction": "src", - "presence": "sometimes" - } - }, - "properties": { - "async-handling": { - "blurb": "The bin will handle Asynchronous state changes", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "backchannel": { - "blurb": "The type of backchannel to setup. Default is 'none'.", - "construct": false, - "construct-only": false, - "default": "none (0)", - "enum": true, - "type-name": "GstRTSPBackchannel", - "values": [ - { - "desc": "No backchannel", - "name": "none", - "value": "0" - }, - { - "desc": "ONVIF audio backchannel", - "name": "onvif", - "value": "1" - } - ], - "writable": true - }, - "buffer-mode": { - "blurb": "Control the buffering algorithm in use", - "construct": false, - "construct-only": false, - "default": "auto (3)", - "enum": true, - "type-name": "GstRTSPSrcBufferMode", - "values": [ - { - "desc": "Only use RTP timestamps", - "name": "none", - "value": "0" - }, - { - "desc": "Slave receiver to sender clock", - "name": "slave", - "value": "1" - }, - { - "desc": "Do low/high watermark buffering", - "name": "buffer", - "value": "2" - }, - { - "desc": "Choose mode depending on stream live", - "name": "auto", - "value": "3" - }, - { - "desc": "Synchronized sender and receiver clocks", - "name": "synced", - "value": "4" - } - ], - "writable": true - }, - "connection-speed": { - "blurb": "Network connection speed in kbps (0 = unknown)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "debug": { - "blurb": "Dump request and response messages to stdout(DEPRECATED: Printed all RTSP message to gstreamer log as 'log' level)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "default-rtsp-version": { - "blurb": "The RTSP version that should be tried first when negotiating version.", - "construct": false, - "construct-only": false, - "default": "1-0 (16)", - "enum": true, - "type-name": "GstRTSPVersion", - "values": [ - { - "desc": "GST_RTSP_VERSION_INVALID", - "name": "invalid", - "value": "0" - }, - { - "desc": "GST_RTSP_VERSION_1_0", - "name": "1-0", - "value": "16" - }, - { - "desc": "GST_RTSP_VERSION_1_1", - "name": "1-1", - "value": "17" - }, - { - "desc": "GST_RTSP_VERSION_2_0", - "name": "2-0", - "value": "32" - } - ], - "writable": true - }, - "do-retransmission": { - "blurb": "Ask the server to retransmit lost packets", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "do-rtcp": { - "blurb": "Send RTCP packets, disable for old incompatible server.", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "do-rtsp-keep-alive": { - "blurb": "Send RTSP keep alive packets, disable for old incompatible server.", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "drop-on-latency": { - "blurb": "Tells the jitterbuffer to never exceed the given latency in size", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "is-live": { - "blurb": "Whether to act as a live source", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "latency": { - "blurb": "Amount of ms to buffer", - "construct": false, - "construct-only": false, - "default": "2000", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "location": { - "blurb": "Location of the RTSP url to read", - "construct": false, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "max-rtcp-rtp-time-diff": { - "blurb": "Maximum amount of time in ms that the RTP time in RTCP SRs is allowed to be ahead (-1 disabled)", - "construct": false, - "construct-only": false, - "default": "1000", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "max-ts-offset": { - "blurb": "The maximum absolute value of the time offset in (nanoseconds). Note, if the ntp-sync parameter is set the default value is changed to 0 (no limit)", - "construct": false, - "construct-only": false, - "default": "3000000000", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "max-ts-offset-adjustment": { - "blurb": "The maximum number of nanoseconds per frame that time stamp offsets may be adjusted (0 = no limit).", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "message-forward": { - "blurb": "Forwards all children messages", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "multicast-iface": { - "blurb": "The network interface on which to join the multicast group", - "construct": false, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "nat-method": { - "blurb": "Method to use for traversing firewalls and NAT", - "construct": false, - "construct-only": false, - "default": "dummy (1)", - "enum": true, - "type-name": "GstRTSPNatMethod", - "values": [ - { - "desc": "None", - "name": "none", - "value": "0" - }, - { - "desc": "Send Dummy packets", - "name": "dummy", - "value": "1" - } - ], - "writable": true - }, - "ntp-sync": { - "blurb": "Synchronize received streams to the NTP clock", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "ntp-time-source": { - "blurb": "NTP time source for RTCP packets", - "construct": false, - "construct-only": false, - "default": "ntp (0)", - "enum": true, - "type-name": "GstRTSPSrcNtpTimeSource", - "values": [ - { - "desc": "NTP time based on realtime clock", - "name": "ntp", - "value": "0" - }, - { - "desc": "UNIX time based on realtime clock", - "name": "unix", - "value": "1" - }, - { - "desc": "Running time based on pipeline clock", - "name": "running-time", - "value": "2" - }, - { - "desc": "Pipeline clock time", - "name": "clock-time", - "value": "3" - } - ], - "writable": true - }, - "onvif-mode": { - "blurb": "Act as an ONVIF client", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "onvif-rate-control": { - "blurb": "When in onvif-mode, whether to set Rate-Control to yes or no", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "port-range": { - "blurb": "Client port range that can be used to receive RTP and RTCP data, eg. 3000-3005 (NULL = no restrictions)", - "construct": false, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "probation": { - "blurb": "Consecutive packet sequence numbers to accept the source", - "construct": false, - "construct-only": false, - "default": "2", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "protocols": { - "blurb": "Allowed lower transport protocols", - "construct": false, - "construct-only": false, - "default": "tcp+udp-mcast+udp", - "type-name": "GstRTSPLowerTrans", - "values": [ - { - "desc": "GST_RTSP_LOWER_TRANS_UNKNOWN", - "name": "unknown", - "value": "0x00000000" - }, - { - "desc": "GST_RTSP_LOWER_TRANS_UDP", - "name": "udp", - "value": "0x00000001" - }, - { - "desc": "GST_RTSP_LOWER_TRANS_UDP_MCAST", - "name": "udp-mcast", - "value": "0x00000002" - }, - { - "desc": "GST_RTSP_LOWER_TRANS_TCP", - "name": "tcp", - "value": "0x00000004" - }, - { - "desc": "GST_RTSP_LOWER_TRANS_HTTP", - "name": "http", - "value": "0x00000010" - }, - { - "desc": "GST_RTSP_LOWER_TRANS_TLS", - "name": "tls", - "value": "0x00000020" - } - ], - "writable": true - }, - "proxy": { - "blurb": "Proxy settings for HTTP tunneling. Format: [http://][user:passwd@]host[:port]", - "construct": false, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "proxy-id": { - "blurb": "HTTP proxy URI user id for authentication", - "construct": false, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "proxy-pw": { - "blurb": "HTTP proxy URI user password for authentication", - "construct": false, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "retry": { - "blurb": "Max number of retries when allocating RTP ports.", - "construct": false, - "construct-only": false, - "default": "20", - "max": "65535", - "min": "0", - "type-name": "guint", - "writable": true - }, - "rfc7273-sync": { - "blurb": "Synchronize received streams to the RFC7273 clock (requires clock and offset to be provided)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "rtp-blocksize": { - "blurb": "RTP package size to suggest to server (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "65536", - "min": "0", - "type-name": "guint", - "writable": true - }, - "sdes": { - "blurb": "The SDES items of this session", - "construct": false, - "construct-only": false, - "type-name": "GstStructure", - "writable": true - }, - "short-header": { - "blurb": "Only send the basic RTSP headers for broken encoders", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "tcp-timeout": { - "blurb": "Fail after timeout microseconds on TCP connections (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "20000000", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "teardown-timeout": { - "blurb": "When transitioning PAUSED-READY, allow up to timeout (in nanoseconds) delay in order to send teardown (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "100000000", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "timeout": { - "blurb": "Retry TCP transport after UDP timeout microseconds (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "5000000", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "tls-database": { - "blurb": "TLS database with anchor certificate authorities used to validate the server certificate", - "construct": false, - "construct-only": false, - "type-name": "GTlsDatabase", - "writable": true - }, - "tls-interaction": { - "blurb": "A GTlsInteraction object to prompt the user for password or certificate", - "construct": false, - "construct-only": false, - "type-name": "GTlsInteraction", - "writable": true - }, - "tls-validation-flags": { - "blurb": "TLS certificate validation flags used to validate the server certificate", - "construct": false, - "construct-only": false, - "default": "validate-all", - "type-name": "GTlsCertificateFlags", - "values": [ - { - "desc": "G_TLS_CERTIFICATE_UNKNOWN_CA", - "name": "unknown-ca", - "value": "0x00000001" - }, - { - "desc": "G_TLS_CERTIFICATE_BAD_IDENTITY", - "name": "bad-identity", - "value": "0x00000002" - }, - { - "desc": "G_TLS_CERTIFICATE_NOT_ACTIVATED", - "name": "not-activated", - "value": "0x00000004" - }, - { - "desc": "G_TLS_CERTIFICATE_EXPIRED", - "name": "expired", - "value": "0x00000008" - }, - { - "desc": "G_TLS_CERTIFICATE_REVOKED", - "name": "revoked", - "value": "0x00000010" - }, - { - "desc": "G_TLS_CERTIFICATE_INSECURE", - "name": "insecure", - "value": "0x00000020" - }, - { - "desc": "G_TLS_CERTIFICATE_GENERIC_ERROR", - "name": "generic-error", - "value": "0x00000040" - }, - { - "desc": "G_TLS_CERTIFICATE_VALIDATE_ALL", - "name": "validate-all", - "value": "0x0000007f" - } - ], - "writable": true - }, - "udp-buffer-size": { - "blurb": "Size of the kernel UDP receive buffer in bytes, 0=default", - "construct": false, - "construct-only": false, - "default": "524288", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "udp-reconnect": { - "blurb": "Reconnect to the server if RTSP connection is closed when doing UDP", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "use-pipeline-clock": { - "blurb": "Use the pipeline running-time to set the NTP time in the RTCP SR messages(DEPRECATED: Use ntp-time-source property)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "user-agent": { - "blurb": "The User-Agent string to send to the server", - "construct": false, - "construct-only": false, - "default": "GStreamer/1.17.0.1", - "type-name": "gchararray", - "writable": true - }, - "user-id": { - "blurb": "RTSP location URI user id for authentication", - "construct": false, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "user-pw": { - "blurb": "RTSP location URI user password for authentication", - "construct": false, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": true - } - }, - "rank": "none", - "signals": { - "accept-certificate": { - "args": [ - "GTlsConnection", - "GTlsCertificate", - "GTlsCertificateFlags" - ], - "retval": "gboolean" - }, - "before-send": { - "args": [ - "GstRTSPMessage" - ], - "retval": "gboolean" - }, - "get-parameter": { - "args": [ - "gchararray", - "gchararray", - "GstPromise" - ], - "retval": "gboolean" - }, - "get-parameters": { - "args": [ - "GStrv", - "gchararray", - "GstPromise" - ], - "retval": "gboolean" - }, - "handle-request": { - "args": [ - "gpointer", - "gpointer" - ], - "retval": "void" - }, - "new-manager": { - "args": [ - "GstElement" - ], - "retval": "void" - }, - "no-more-pads": { - "args": [], - "retval": "void" - }, - "on-sdp": { - "args": [ - "GstSDPMessage" - ], - "retval": "void" - }, - "pad-added": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "pad-removed": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "push-backchannel-buffer": { - "args": [ - "guint", - "GstBuffer" - ], - "return-values": [ - { - "desc": "GST_FLOW_CUSTOM_SUCCESS_2", - "name": "custom-success-2", - "value": "102" - }, - { - "desc": "GST_FLOW_CUSTOM_SUCCESS_1", - "name": "custom-success-1", - "value": "101" - }, - { - "desc": "GST_FLOW_CUSTOM_SUCCESS", - "name": "custom-success", - "value": "100" - }, - { - "desc": "GST_FLOW_OK", - "name": "ok", - "value": "0" - }, - { - "desc": "GST_FLOW_NOT_LINKED", - "name": "not-linked", - "value": "-1" - }, - { - "desc": "GST_FLOW_FLUSHING", - "name": "flushing", - "value": "-2" - }, - { - "desc": "GST_FLOW_EOS", - "name": "eos", - "value": "-3" - }, - { - "desc": "GST_FLOW_NOT_NEGOTIATED", - "name": "not-negotiated", - "value": "-4" - }, - { - "desc": "GST_FLOW_ERROR", - "name": "error", - "value": "-5" - }, - { - "desc": "GST_FLOW_NOT_SUPPORTED", - "name": "not-supported", - "value": "-6" - }, - { - "desc": "GST_FLOW_CUSTOM_ERROR", - "name": "custom-error", - "value": "-100" - }, - { - "desc": "GST_FLOW_CUSTOM_ERROR_1", - "name": "custom-error-1", - "value": "-101" - }, - { - "desc": "GST_FLOW_CUSTOM_ERROR_2", - "name": "custom-error-2", - "value": "-102" - } - ], - "retval": "GstFlowReturn" - }, - "request-rtcp-key": { - "args": [ - "guint" - ], - "retval": "GstCaps" - }, - "select-stream": { - "args": [ - "guint", - "GstCaps" - ], - "retval": "gboolean" - }, - "set-parameter": { - "args": [ - "gchararray", - "gchararray", - "gchararray", - "GstPromise" - ], - "retval": "gboolean" - } - } - } - }, - "filename": "gstrtsp", - "license": "LGPL", - "package": "GStreamer Good Plug-ins git", - "source": "gst-plugins-good", - "tracers": {}, - "url": "Unknown package origin" - }, - "shapewipe": { - "description": "Shape Wipe transition filter", - "elements": { - "shapewipe": { - "author": "Sebastian Dr\u00f6ge ", - "description": "Adds a shape wipe transition to a video stream", - "hierarchy": [ - "GstShapeWipe", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Filter/Editor/Video", - "long-name": "Shape Wipe transition filter", - "name": "shapewipe", - "pad-templates": { - "mask_sink": { - "caps": "video/x-raw:\n format: GRAY8\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: 0/1\nvideo/x-raw:\n format: GRAY16_LE\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: 0/1\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "video/x-raw:\n format: { AYUV, ARGB, BGRA, ABGR, RGBA }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", - "direction": "src", - "presence": "always" - }, - "video_sink": { - "caps": "video/x-raw:\n format: { AYUV, ARGB, BGRA, ABGR, RGBA }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", - "direction": "sink", - "presence": "always" - } - }, - "properties": { - "border": { - "blurb": "Border of the mask", - "construct": false, - "construct-only": false, - "default": "0", - "max": "1", - "min": "0", - "type-name": "gfloat", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "position": { - "blurb": "Position of the mask", - "construct": false, - "construct-only": false, - "default": "0", - "max": "1", - "min": "0", - "type-name": "gfloat", - "writable": true - } - }, - "rank": "none" - } - }, - "filename": "gstshapewipe", - "license": "LGPL", - "package": "GStreamer Good Plug-ins git", - "source": "gst-plugins-good", - "tracers": {}, - "url": "Unknown package origin" - }, - "shout2": { - "description": "Sends data to an icecast server using libshout2", - "elements": { - "shout2send": { - "author": "Wim Taymans , Pedro Corte-Real , Zaheer Abbas Merali ", - "description": "Sends data to an icecast server", - "hierarchy": [ - "GstShout2send", - "GstBaseSink", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Sink/Network", - "long-name": "Icecast network sink", - "name": "shout2send", - "pad-templates": { - "sink": { - "caps": "application/ogg:\naudio/ogg:\nvideo/ogg:\naudio/mpeg:\n mpegversion: 1\n layer: [ 1, 3 ]\nvideo/webm:\naudio/webm:\n", - "direction": "sink", - "presence": "always", - "unstable-values": [ - "caps" - ] - } - }, - "properties": { - "async": { - "blurb": "Go asynchronously to PAUSED", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "blocksize": { - "blurb": "Size in bytes to pull per buffer (0 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "description": { - "blurb": "description", - "construct": false, - "construct-only": false, - "default": "", - "type-name": "gchararray", - "writable": true - }, - "enable-last-sample": { - "blurb": "Enable the last-sample property", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "genre": { - "blurb": "genre", - "construct": false, - "construct-only": false, - "default": "", - "type-name": "gchararray", - "writable": true - }, - "ip": { - "blurb": "IP address or hostname", - "construct": false, - "construct-only": false, - "default": "127.0.0.1", - "type-name": "gchararray", - "writable": true - }, - "last-sample": { - "blurb": "The last sample received in the sink", - "construct": false, - "construct-only": false, - "type-name": "GstSample", - "writable": false - }, - "max-bitrate": { - "blurb": "The maximum bits per second to render (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "max-lateness": { - "blurb": "Maximum number of nanoseconds that a buffer can be late before it is dropped (-1 unlimited)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "mount": { - "blurb": "mount", - "construct": false, - "construct-only": false, - "default": "", - "type-name": "gchararray", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "password": { - "blurb": "password", - "construct": false, - "construct-only": false, - "default": "hackme", - "type-name": "gchararray", - "writable": true - }, - "port": { - "blurb": "port", - "construct": false, - "construct-only": false, - "default": "8000", - "max": "65535", - "min": "1", - "type-name": "gint", - "writable": true - }, - "processing-deadline": { - "blurb": "Maximum processing deadline in nanoseconds", - "construct": false, - "construct-only": false, - "default": "20000000", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "protocol": { - "blurb": "Connection Protocol to use", - "construct": false, - "construct-only": false, - "default": "http (3)", - "enum": true, - "type-name": "GstShout2SendProtocol", - "values": [ - { - "desc": "Xaudiocast Protocol (icecast 1.3.x)", - "name": "xaudiocast", - "value": "1" - }, - { - "desc": "Icy Protocol (ShoutCast)", - "name": "icy", - "value": "2" - }, - { - "desc": "Http Protocol (icecast 2.x)", - "name": "http", - "value": "3" - } - ], - "writable": true - }, - "public": { - "blurb": "If the stream should be listed on the server's stream directory", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "qos": { - "blurb": "Generate Quality-of-Service events upstream", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "render-delay": { - "blurb": "Additional render delay of the sink in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "stats": { - "blurb": "Sink Statistics", - "construct": false, - "construct-only": false, - "default": "application/x-gst-base-sink-stats, average-rate=(double)0, dropped=(guint64)0, rendered=(guint64)0;", - "type-name": "GstStructure", - "writable": false - }, - "streamname": { - "blurb": "name of the stream", - "construct": false, - "construct-only": false, - "default": "", - "type-name": "gchararray", - "writable": true - }, - "sync": { - "blurb": "Sync on the clock", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "throttle-time": { - "blurb": "The time to keep between rendered buffers (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "timeout": { - "blurb": "Max amount of time to wait for network activity, in milliseconds", - "construct": false, - "construct-only": false, - "default": "10000", - "max": "-1", - "min": "1", - "type-name": "guint", - "writable": true - }, - "ts-offset": { - "blurb": "Timestamp offset in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "-9223372036854775808", - "type-name": "gint64", - "writable": true - }, - "url": { - "blurb": "the stream's homepage URL", - "construct": false, - "construct-only": false, - "default": "", - "type-name": "gchararray", - "writable": true - }, - "username": { - "blurb": "username", - "construct": false, - "construct-only": false, - "default": "source", - "type-name": "gchararray", - "writable": true - } - }, - "rank": "none", - "signals": { - "connection-problem": { - "args": [ - "gint" - ], - "retval": "void" - } - } - } - }, - "filename": "gstshout2", - "license": "LGPL", - "package": "GStreamer Good Plug-ins git", - "source": "gst-plugins-good", - "tracers": {}, - "url": "Unknown package origin" - }, - "smpte": { - "description": "Apply the standard SMPTE transitions on video images", - "elements": { - "smpte": { - "author": "Wim Taymans ", - "description": "Apply the standard SMPTE transitions on video images", - "hierarchy": [ - "GstSMPTE", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Filter/Editor/Video", - "long-name": "SMPTE transitions", - "name": "smpte", - "pad-templates": { - "sink1": { - "caps": "video/x-raw:\n format: I420\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", - "direction": "sink", - "presence": "always" - }, - "sink2": { - "caps": "video/x-raw:\n format: I420\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "video/x-raw:\n format: I420\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "border": { - "blurb": "The border width of the transition", - "construct": false, - "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "depth": { - "blurb": "Depth of the mask in bits", - "construct": false, - "construct-only": false, - "default": "16", - "max": "24", - "min": "1", - "type-name": "gint", - "writable": true - }, - "duration": { - "blurb": "Duration of the transition effect in nanoseconds", - "construct": false, - "construct-only": false, - "default": "1000000000", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true - }, - "invert": { - "blurb": "Invert transition mask", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "type": { - "blurb": "The type of transition to use", - "construct": false, - "construct-only": false, - "default": "bar-wipe-lr (1)", - "enum": true, - "type-name": "GstSMPTETransitionType", - "values": [ - { - "desc": "A bar moves from left to right", - "name": "bar-wipe-lr", - "value": "1" - }, - { - "desc": "A bar moves from top to bottom", - "name": "bar-wipe-tb", - "value": "2" - }, - { - "desc": "A box expands from the upper-left corner to the lower-right corner", - "name": "box-wipe-tl", - "value": "3" - }, - { - "desc": "A box expands from the upper-right corner to the lower-left corner", - "name": "box-wipe-tr", - "value": "4" - }, - { - "desc": "A box expands from the lower-right corner to the upper-left corner", - "name": "box-wipe-br", - "value": "5" - }, - { - "desc": "A box expands from the lower-left corner to the upper-right corner", - "name": "box-wipe-bl", - "value": "6" - }, - { - "desc": "A box shape expands from each of the four corners toward the center", - "name": "four-box-wipe-ci", - "value": "7" - }, - { - "desc": "A box shape expands from the center of each quadrant toward the corners of each quadrant", - "name": "four-box-wipe-co", - "value": "8" - }, - { - "desc": "A central, vertical line splits and expands toward the left and right edges", - "name": "barndoor-v", - "value": "21" - }, - { - "desc": "A central, horizontal line splits and expands toward the top and bottom edges", - "name": "barndoor-h", - "value": "22" - }, - { - "desc": "A box expands from the top edge's midpoint to the bottom corners", - "name": "box-wipe-tc", - "value": "23" - }, - { - "desc": "A box expands from the right edge's midpoint to the left corners", - "name": "box-wipe-rc", - "value": "24" - }, - { - "desc": "A box expands from the bottom edge's midpoint to the top corners", - "name": "box-wipe-bc", - "value": "25" - }, - { - "desc": "A box expands from the left edge's midpoint to the right corners", - "name": "box-wipe-lc", - "value": "26" - }, - { - "desc": "A diagonal line moves from the upper-left corner to the lower-right corner", - "name": "diagonal-tl", - "value": "41" - }, - { - "desc": "A diagonal line moves from the upper right corner to the lower-left corner", - "name": "diagonal-tr", - "value": "42" - }, - { - "desc": "Two wedge shapes slide in from the top and bottom edges toward the center", - "name": "bowtie-v", - "value": "43" - }, - { - "desc": "Two wedge shapes slide in from the left and right edges toward the center", - "name": "bowtie-h", - "value": "44" - }, - { - "desc": "A diagonal line from the lower-left to upper-right corners splits and expands toward the opposite corners", - "name": "barndoor-dbl", - "value": "45" - }, - { - "desc": "A diagonal line from upper-left to lower-right corners splits and expands toward the opposite corners", - "name": "barndoor-dtl", - "value": "46" - }, - { - "desc": "Four wedge shapes split from the center and retract toward the four edges", - "name": "misc-diagonal-dbd", - "value": "47" - }, - { - "desc": "A diamond connecting the four edge midpoints simultaneously contracts toward the center and expands toward the edges", - "name": "misc-diagonal-dd", - "value": "48" - }, - { - "desc": "A wedge shape moves from top to bottom", - "name": "vee-d", - "value": "61" - }, - { - "desc": "A wedge shape moves from right to left", - "name": "vee-l", - "value": "62" - }, - { - "desc": "A wedge shape moves from bottom to top", - "name": "vee-u", - "value": "63" - }, - { - "desc": "A wedge shape moves from left to right", - "name": "vee-r", - "value": "64" - }, - { - "desc": "A 'V' shape extending from the bottom edge's midpoint to the opposite corners contracts toward the center and expands toward the edges", - "name": "barnvee-d", - "value": "65" - }, - { - "desc": "A 'V' shape extending from the left edge's midpoint to the opposite corners contracts toward the center and expands toward the edges", - "name": "barnvee-l", - "value": "66" - }, - { - "desc": "A 'V' shape extending from the top edge's midpoint to the opposite corners contracts toward the center and expands toward the edges", - "name": "barnvee-u", - "value": "67" - }, - { - "desc": "A 'V' shape extending from the right edge's midpoint to the opposite corners contracts toward the center and expands toward the edges", - "name": "barnvee-r", - "value": "68" - }, - { - "desc": "A rectangle expands from the center.", - "name": "iris-rect", - "value": "101" - }, - { - "desc": "A radial hand sweeps clockwise from the twelve o'clock position", - "name": "clock-cw12", - "value": "201" - }, - { - "desc": "A radial hand sweeps clockwise from the three o'clock position", - "name": "clock-cw3", - "value": "202" - }, - { - "desc": "A radial hand sweeps clockwise from the six o'clock position", - "name": "clock-cw6", - "value": "203" - }, - { - "desc": "A radial hand sweeps clockwise from the nine o'clock position", - "name": "clock-cw9", - "value": "204" - }, - { - "desc": "Two radial hands sweep clockwise from the twelve and six o'clock positions", - "name": "pinwheel-tbv", - "value": "205" - }, - { - "desc": "Two radial hands sweep clockwise from the nine and three o'clock positions", - "name": "pinwheel-tbh", - "value": "206" - }, - { - "desc": "Four radial hands sweep clockwise", - "name": "pinwheel-fb", - "value": "207" - }, - { - "desc": "A fan unfolds from the top edge, the fan axis at the center", - "name": "fan-ct", - "value": "211" - }, - { - "desc": "A fan unfolds from the right edge, the fan axis at the center", - "name": "fan-cr", - "value": "212" - }, - { - "desc": "Two fans, their axes at the center, unfold from the top and bottom", - "name": "doublefan-fov", - "value": "213" - }, - { - "desc": "Two fans, their axes at the center, unfold from the left and right", - "name": "doublefan-foh", - "value": "214" - }, - { - "desc": "A radial hand sweeps clockwise from the top edge's midpoint", - "name": "singlesweep-cwt", - "value": "221" - }, - { - "desc": "A radial hand sweeps clockwise from the right edge's midpoint", - "name": "singlesweep-cwr", - "value": "222" - }, - { - "desc": "A radial hand sweeps clockwise from the bottom edge's midpoint", - "name": "singlesweep-cwb", - "value": "223" - }, - { - "desc": "A radial hand sweeps clockwise from the left edge's midpoint", - "name": "singlesweep-cwl", - "value": "224" - }, - { - "desc": "Two radial hands sweep clockwise and counter-clockwise from the top and bottom edges' midpoints", - "name": "doublesweep-pv", - "value": "225" - }, - { - "desc": "Two radial hands sweep clockwise and counter-clockwise from the left and right edges' midpoints", - "name": "doublesweep-pd", - "value": "226" - }, - { - "desc": "Two radial hands attached at the top and bottom edges' midpoints sweep from right to left", - "name": "doublesweep-ov", - "value": "227" - }, - { - "desc": "Two radial hands attached at the left and right edges' midpoints sweep from top to bottom", - "name": "doublesweep-oh", - "value": "228" - }, - { - "desc": "A fan unfolds from the bottom, the fan axis at the top edge's midpoint", - "name": "fan-t", - "value": "231" - }, - { - "desc": "A fan unfolds from the left, the fan axis at the right edge's midpoint", - "name": "fan-r", - "value": "232" - }, - { - "desc": "A fan unfolds from the top, the fan axis at the bottom edge's midpoint", - "name": "fan-b", - "value": "233" - }, - { - "desc": "A fan unfolds from the right, the fan axis at the left edge's midpoint", - "name": "fan-l", - "value": "234" - }, - { - "desc": "Two fans, their axes at the top and bottom, unfold from the center", - "name": "doublefan-fiv", - "value": "235" - }, - { - "desc": "Two fans, their axes at the left and right, unfold from the center", - "name": "doublefan-fih", - "value": "236" - }, - { - "desc": "A radial hand sweeps clockwise from the upper-left corner", - "name": "singlesweep-cwtl", - "value": "241" - }, - { - "desc": "A radial hand sweeps counter-clockwise from the lower-left corner.", - "name": "singlesweep-cwbl", - "value": "242" - }, - { - "desc": "A radial hand sweeps clockwise from the lower-right corner", - "name": "singlesweep-cwbr", - "value": "243" - }, - { - "desc": "A radial hand sweeps counter-clockwise from the upper-right corner", - "name": "singlesweep-cwtr", - "value": "244" - }, - { - "desc": "Two radial hands attached at the upper-left and lower-right corners sweep down and up", - "name": "doublesweep-pdtl", - "value": "245" - }, - { - "desc": "Two radial hands attached at the lower-left and upper-right corners sweep down and up", - "name": "doublesweep-pdbl", - "value": "246" - }, - { - "desc": "Two radial hands attached at the upper-left and upper-right corners sweep down", - "name": "saloondoor-t", - "value": "251" - }, - { - "desc": "Two radial hands attached at the upper-left and lower-left corners sweep to the right", - "name": "saloondoor-l", - "value": "252" - }, - { - "desc": "Two radial hands attached at the lower-left and lower-right corners sweep up", - "name": "saloondoor-b", - "value": "253" - }, - { - "desc": "Two radial hands attached at the upper-right and lower-right corners sweep to the left", - "name": "saloondoor-r", - "value": "254" - }, - { - "desc": "Two radial hands attached at the midpoints of the top and bottom halves sweep from right to left", - "name": "windshield-r", - "value": "261" - }, - { - "desc": "Two radial hands attached at the midpoints of the left and right halves sweep from top to bottom", - "name": "windshield-u", - "value": "262" - }, - { - "desc": "Two sets of radial hands attached at the midpoints of the top and bottom halves sweep from top to bottom and bottom to top", - "name": "windshield-v", - "value": "263" - }, - { - "desc": "Two sets of radial hands attached at the midpoints of the left and right halves sweep from left to right and right to left", - "name": "windshield-h", - "value": "264" - } - ], - "writable": true - } - }, - "rank": "none" - }, - "smptealpha": { - "author": "Wim Taymans ", - "description": "Apply the standard SMPTE transitions as alpha on video images", - "hierarchy": [ - "GstSMPTEAlpha", - "GstVideoFilter", - "GstBaseTransform", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Filter/Editor/Video", - "long-name": "SMPTE transitions", - "name": "smptealpha", - "pad-templates": { - "sink": { - "caps": "video/x-raw:\n format: I420\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: YV12\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: AYUV\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: ARGB\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: BGRA\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: RGBA\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: ARGB\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "video/x-raw:\n format: AYUV\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: ARGB\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: BGRA\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: RGBA\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: ARGB\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "border": { - "blurb": "The border width of the transition", - "construct": false, - "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "depth": { - "blurb": "Depth of the mask in bits", - "construct": false, - "construct-only": false, - "default": "16", - "max": "24", - "min": "1", - "type-name": "gint", - "writable": true - }, - "invert": { - "blurb": "Invert transition mask", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "position": { - "blurb": "Position of the transition effect", - "construct": false, - "construct-only": false, - "default": "0", - "max": "1", - "min": "0", - "type-name": "gdouble", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "type": { - "blurb": "The type of transition to use", - "construct": false, - "construct-only": false, - "default": "bar-wipe-lr (1)", - "enum": true, - "type-name": "GstSMPTEAlphaTransitionType", - "values": [ - { - "desc": "A bar moves from left to right", - "name": "bar-wipe-lr", - "value": "1" - }, - { - "desc": "A bar moves from top to bottom", - "name": "bar-wipe-tb", - "value": "2" - }, - { - "desc": "A box expands from the upper-left corner to the lower-right corner", - "name": "box-wipe-tl", - "value": "3" - }, - { - "desc": "A box expands from the upper-right corner to the lower-left corner", - "name": "box-wipe-tr", - "value": "4" - }, - { - "desc": "A box expands from the lower-right corner to the upper-left corner", - "name": "box-wipe-br", - "value": "5" - }, - { - "desc": "A box expands from the lower-left corner to the upper-right corner", - "name": "box-wipe-bl", - "value": "6" - }, - { - "desc": "A box shape expands from each of the four corners toward the center", - "name": "four-box-wipe-ci", - "value": "7" - }, - { - "desc": "A box shape expands from the center of each quadrant toward the corners of each quadrant", - "name": "four-box-wipe-co", - "value": "8" - }, - { - "desc": "A central, vertical line splits and expands toward the left and right edges", - "name": "barndoor-v", - "value": "21" - }, - { - "desc": "A central, horizontal line splits and expands toward the top and bottom edges", - "name": "barndoor-h", - "value": "22" - }, - { - "desc": "A box expands from the top edge's midpoint to the bottom corners", - "name": "box-wipe-tc", - "value": "23" - }, - { - "desc": "A box expands from the right edge's midpoint to the left corners", - "name": "box-wipe-rc", - "value": "24" - }, - { - "desc": "A box expands from the bottom edge's midpoint to the top corners", - "name": "box-wipe-bc", - "value": "25" - }, - { - "desc": "A box expands from the left edge's midpoint to the right corners", - "name": "box-wipe-lc", - "value": "26" - }, - { - "desc": "A diagonal line moves from the upper-left corner to the lower-right corner", - "name": "diagonal-tl", - "value": "41" - }, - { - "desc": "A diagonal line moves from the upper right corner to the lower-left corner", - "name": "diagonal-tr", - "value": "42" - }, - { - "desc": "Two wedge shapes slide in from the top and bottom edges toward the center", - "name": "bowtie-v", - "value": "43" - }, - { - "desc": "Two wedge shapes slide in from the left and right edges toward the center", - "name": "bowtie-h", - "value": "44" - }, - { - "desc": "A diagonal line from the lower-left to upper-right corners splits and expands toward the opposite corners", - "name": "barndoor-dbl", - "value": "45" - }, - { - "desc": "A diagonal line from upper-left to lower-right corners splits and expands toward the opposite corners", - "name": "barndoor-dtl", - "value": "46" - }, - { - "desc": "Four wedge shapes split from the center and retract toward the four edges", - "name": "misc-diagonal-dbd", - "value": "47" - }, - { - "desc": "A diamond connecting the four edge midpoints simultaneously contracts toward the center and expands toward the edges", - "name": "misc-diagonal-dd", - "value": "48" - }, - { - "desc": "A wedge shape moves from top to bottom", - "name": "vee-d", - "value": "61" - }, - { - "desc": "A wedge shape moves from right to left", - "name": "vee-l", - "value": "62" - }, - { - "desc": "A wedge shape moves from bottom to top", - "name": "vee-u", - "value": "63" - }, - { - "desc": "A wedge shape moves from left to right", - "name": "vee-r", - "value": "64" - }, - { - "desc": "A 'V' shape extending from the bottom edge's midpoint to the opposite corners contracts toward the center and expands toward the edges", - "name": "barnvee-d", - "value": "65" - }, - { - "desc": "A 'V' shape extending from the left edge's midpoint to the opposite corners contracts toward the center and expands toward the edges", - "name": "barnvee-l", - "value": "66" - }, - { - "desc": "A 'V' shape extending from the top edge's midpoint to the opposite corners contracts toward the center and expands toward the edges", - "name": "barnvee-u", - "value": "67" - }, - { - "desc": "A 'V' shape extending from the right edge's midpoint to the opposite corners contracts toward the center and expands toward the edges", - "name": "barnvee-r", - "value": "68" - }, - { - "desc": "A rectangle expands from the center.", - "name": "iris-rect", - "value": "101" - }, - { - "desc": "A radial hand sweeps clockwise from the twelve o'clock position", - "name": "clock-cw12", - "value": "201" - }, - { - "desc": "A radial hand sweeps clockwise from the three o'clock position", - "name": "clock-cw3", - "value": "202" - }, - { - "desc": "A radial hand sweeps clockwise from the six o'clock position", - "name": "clock-cw6", - "value": "203" - }, - { - "desc": "A radial hand sweeps clockwise from the nine o'clock position", - "name": "clock-cw9", - "value": "204" - }, - { - "desc": "Two radial hands sweep clockwise from the twelve and six o'clock positions", - "name": "pinwheel-tbv", - "value": "205" - }, - { - "desc": "Two radial hands sweep clockwise from the nine and three o'clock positions", - "name": "pinwheel-tbh", - "value": "206" - }, - { - "desc": "Four radial hands sweep clockwise", - "name": "pinwheel-fb", - "value": "207" - }, - { - "desc": "A fan unfolds from the top edge, the fan axis at the center", - "name": "fan-ct", - "value": "211" - }, - { - "desc": "A fan unfolds from the right edge, the fan axis at the center", - "name": "fan-cr", - "value": "212" - }, - { - "desc": "Two fans, their axes at the center, unfold from the top and bottom", - "name": "doublefan-fov", - "value": "213" - }, - { - "desc": "Two fans, their axes at the center, unfold from the left and right", - "name": "doublefan-foh", - "value": "214" - }, - { - "desc": "A radial hand sweeps clockwise from the top edge's midpoint", - "name": "singlesweep-cwt", - "value": "221" - }, - { - "desc": "A radial hand sweeps clockwise from the right edge's midpoint", - "name": "singlesweep-cwr", - "value": "222" - }, - { - "desc": "A radial hand sweeps clockwise from the bottom edge's midpoint", - "name": "singlesweep-cwb", - "value": "223" - }, - { - "desc": "A radial hand sweeps clockwise from the left edge's midpoint", - "name": "singlesweep-cwl", - "value": "224" - }, - { - "desc": "Two radial hands sweep clockwise and counter-clockwise from the top and bottom edges' midpoints", - "name": "doublesweep-pv", - "value": "225" - }, - { - "desc": "Two radial hands sweep clockwise and counter-clockwise from the left and right edges' midpoints", - "name": "doublesweep-pd", - "value": "226" - }, - { - "desc": "Two radial hands attached at the top and bottom edges' midpoints sweep from right to left", - "name": "doublesweep-ov", - "value": "227" - }, - { - "desc": "Two radial hands attached at the left and right edges' midpoints sweep from top to bottom", - "name": "doublesweep-oh", - "value": "228" - }, - { - "desc": "A fan unfolds from the bottom, the fan axis at the top edge's midpoint", - "name": "fan-t", - "value": "231" - }, - { - "desc": "A fan unfolds from the left, the fan axis at the right edge's midpoint", - "name": "fan-r", - "value": "232" - }, - { - "desc": "A fan unfolds from the top, the fan axis at the bottom edge's midpoint", - "name": "fan-b", - "value": "233" - }, - { - "desc": "A fan unfolds from the right, the fan axis at the left edge's midpoint", - "name": "fan-l", - "value": "234" - }, - { - "desc": "Two fans, their axes at the top and bottom, unfold from the center", - "name": "doublefan-fiv", - "value": "235" - }, - { - "desc": "Two fans, their axes at the left and right, unfold from the center", - "name": "doublefan-fih", - "value": "236" - }, - { - "desc": "A radial hand sweeps clockwise from the upper-left corner", - "name": "singlesweep-cwtl", - "value": "241" - }, - { - "desc": "A radial hand sweeps counter-clockwise from the lower-left corner.", - "name": "singlesweep-cwbl", - "value": "242" - }, - { - "desc": "A radial hand sweeps clockwise from the lower-right corner", - "name": "singlesweep-cwbr", - "value": "243" - }, - { - "desc": "A radial hand sweeps counter-clockwise from the upper-right corner", - "name": "singlesweep-cwtr", - "value": "244" - }, - { - "desc": "Two radial hands attached at the upper-left and lower-right corners sweep down and up", - "name": "doublesweep-pdtl", - "value": "245" - }, - { - "desc": "Two radial hands attached at the lower-left and upper-right corners sweep down and up", - "name": "doublesweep-pdbl", - "value": "246" - }, - { - "desc": "Two radial hands attached at the upper-left and upper-right corners sweep down", - "name": "saloondoor-t", - "value": "251" - }, - { - "desc": "Two radial hands attached at the upper-left and lower-left corners sweep to the right", - "name": "saloondoor-l", - "value": "252" - }, - { - "desc": "Two radial hands attached at the lower-left and lower-right corners sweep up", - "name": "saloondoor-b", - "value": "253" - }, - { - "desc": "Two radial hands attached at the upper-right and lower-right corners sweep to the left", - "name": "saloondoor-r", - "value": "254" - }, - { - "desc": "Two radial hands attached at the midpoints of the top and bottom halves sweep from right to left", - "name": "windshield-r", - "value": "261" - }, - { - "desc": "Two radial hands attached at the midpoints of the left and right halves sweep from top to bottom", - "name": "windshield-u", - "value": "262" - }, - { - "desc": "Two sets of radial hands attached at the midpoints of the top and bottom halves sweep from top to bottom and bottom to top", - "name": "windshield-v", - "value": "263" - }, - { - "desc": "Two sets of radial hands attached at the midpoints of the left and right halves sweep from left to right and right to left", - "name": "windshield-h", - "value": "264" - } - ], + "properties": {}, + "rank": "marginal" + }, + "rtpvp9pay": { + "author": "Stian Selnes ", + "description": "Puts VP9 video in RTP packets)", + "hierarchy": [ + "GstRtpVP9Pay", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP VP9 payloader", + "pad-templates": { + "sink": { + "caps": "video/x-vp9:\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "application/x-rtp:\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: { (string)VP9, (string)VP9-DRAFT-IETF-01 }\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "picture-id-mode": { + "blurb": "The picture ID mode for payloading", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "none (0)", + "mutable": "null", + "readable": true, + "type": "GstVP9RTPPayMode", "writable": true } }, - "rank": "none" + "rank": "marginal" + }, + "rtpvrawdepay": { + "author": "Wim Taymans ", + "description": "Extracts raw video from RTP packets (RFC 4175)", + "hierarchy": [ + "GstRtpVRawDepay", + "GstRTPBaseDepayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Depayloader/Network/RTP", + "long-name": "RTP Raw Video depayloader", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n media: video\n clock-rate: 90000\n encoding-name: RAW\n sampling: { (string)RGB, (string)RGBA, (string)BGR, (string)BGRA, (string)YCbCr-4:4:4, (string)YCbCr-4:2:2, (string)YCbCr-4:2:0, (string)YCbCr-4:1:1 }\n depth: { (string)8, (string)10, (string)12, (string)16 }\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "video/x-raw:\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "secondary" + }, + "rtpvrawpay": { + "author": "Wim Taymans ", + "description": "Payload raw video as RTP packets (RFC 4175)", + "hierarchy": [ + "GstRtpVRawPay", + "GstRTPBasePayload", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Payloader/Network/RTP", + "long-name": "RTP Raw Video payloader", + "pad-templates": { + "sink": { + "caps": "video/x-raw:\n format: { RGB, RGBA, BGR, BGRA, AYUV, UYVY, I420, Y41B, UYVP }\n width: [ 1, 32767 ]\n height: [ 1, 32767 ]\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "application/x-rtp:\n media: video\n payload: [ 96, 127 ]\n clock-rate: 90000\n encoding-name: RAW\n sampling: { (string)RGB, (string)RGBA, (string)BGR, (string)BGRA, (string)YCbCr-4:4:4, (string)YCbCr-4:2:2, (string)YCbCr-4:2:0, (string)YCbCr-4:1:1 }\n depth: { (string)8, (string)10, (string)12, (string)16 }\n colorimetry: { (string)BT601-5, (string)BT709-2, (string)SMPTE240M }\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "chunks-per-frame": { + "blurb": "Split and send out each frame in multiple chunks to reduce overhead", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "10", + "max": "2147483647", + "min": "1", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + } + }, + "rank": "secondary" } }, - "filename": "gstsmpte", + "filename": "gstrtp", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": { + "GstDVPayMode": { + "kind": "enum", + "values": [ + { + "desc": "Video only", + "name": "video", + "value": "0" + }, + { + "desc": "Video and Audio bundled", + "name": "bundled", + "value": "1" + }, + { + "desc": "Audio only", + "name": "audio", + "value": "2" + } + ] + }, + "GstFragmentationMode": { + "kind": "enum", + "values": [ + { + "desc": "Normal", + "name": "normal", + "value": "0" + }, + { + "desc": "Fragment at sync points", + "name": "sync", + "value": "1" + } + ] + }, + "GstRtpH264AggregateMode": { + "kind": "enum", + "values": [ + { + "desc": "Do not aggregate NAL units", + "name": "none", + "value": "0" + }, + { + "desc": "Aggregate NAL units until a VCL unit is included", + "name": "zero-latency", + "value": "1" + }, + { + "desc": "Aggregate all NAL units with the same timestamp (adds one frame of latency)", + "name": "max-stap", + "value": "2" + } + ] + }, + "GstRtpH265AggregateMode": { + "kind": "enum", + "values": [ + { + "desc": "Do not aggregate NAL units", + "name": "none", + "value": "0" + }, + { + "desc": "Aggregate NAL units until a VCL or suffix unit is included", + "name": "zero-latency", + "value": "1" + }, + { + "desc": "Aggregate all NAL units with the same timestamp (adds one frame of latency)", + "name": "max", + "value": "2" + } + ] + }, + "GstVP8RTPPayMode": { + "kind": "enum", + "values": [ + { + "desc": "No Picture ID", + "name": "none", + "value": "0" + }, + { + "desc": "7-bit Picture ID", + "name": "7-bit", + "value": "1" + }, + { + "desc": "15-bit Picture ID", + "name": "15-bit", + "value": "2" + } + ] + }, + "GstVP9RTPPayMode": { + "kind": "enum", + "values": [ + { + "desc": "No Picture ID", + "name": "none", + "value": "0" + }, + { + "desc": "7-bit Picture ID", + "name": "7-bit", + "value": "1" + }, + { + "desc": "15-bit Picture ID", + "name": "15-bit", + "value": "2" + } + ] + }, + "iLBCMode": { + "kind": "enum", + "values": [ + { + "desc": "20ms frames", + "name": "20ms", + "value": "20" + }, + { + "desc": "30ms frames", + "name": "30ms", + "value": "30" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" }, - "soup": { - "description": "libsoup HTTP client src/sink", + "rtpmanager": { + "description": "RTP session management plugin library", "elements": { - "souphttpclientsink": { - "author": "David Schleef ", - "description": "Sends streams to HTTP server via PUT", + "rtpbin": { + "author": "Wim Taymans ", + "description": "Real-Time Transport Protocol bin", "hierarchy": [ - "GstSoupHttpClientSink", - "GstBaseSink", + "GstRtpBin", + "GstBin", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Generic", - "long-name": "HTTP client sink", - "name": "souphttpclientsink", + "interfaces": [ + "GstChildProxy" + ], + "klass": "Filter/Network/RTP", + "long-name": "RTP Bin", "pad-templates": { - "sink": { - "caps": "ANY", + "recv_rtcp_sink_%%u": { + "caps": "application/x-rtcp:\napplication/x-srtcp:\n", "direction": "sink", - "presence": "always" + "presence": "request" + }, + "recv_rtp_sink_%%u": { + "caps": "application/x-rtp:\napplication/x-srtp:\n", + "direction": "sink", + "presence": "request" + }, + "recv_rtp_src_%%u_%%u_%%u": { + "caps": "application/x-rtp:\n", + "direction": "src", + "presence": "sometimes" + }, + "send_rtcp_src_%%u": { + "caps": "application/x-rtcp:\napplication/x-srtcp:\n", + "direction": "src", + "presence": "request" + }, + "send_rtp_sink_%%u": { + "caps": "application/x-rtp:\n", + "direction": "sink", + "presence": "request" + }, + "send_rtp_src_%%u": { + "caps": "application/x-rtp:\napplication/x-srtp:\n", + "direction": "src", + "presence": "sometimes" } }, "properties": { - "async": { - "blurb": "Go asynchronously to PAUSED", + "autoremove": { + "blurb": "Automatically remove timed out sources", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "automatic-redirect": { - "blurb": "Automatically follow HTTP redirects (HTTP Status Code 3xx)", + "buffer-mode": { + "blurb": "Control the buffering algorithm in use", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "slave (1)", + "mutable": "null", + "readable": true, + "type": "RTPJitterBufferMode", "writable": true }, - "blocksize": { - "blurb": "Size in bytes to pull per buffer (0 = default)", + "do-lost": { + "blurb": "Send an event downstream when a packet is lost", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "cookies": { - "blurb": "HTTP request cookies", + "do-retransmission": { + "blurb": "Enable retransmission on all streams", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GStrv", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "enable-last-sample": { - "blurb": "Enable the last-sample property", + "do-sync-event": { + "blurb": "Send event downstream when a stream is synchronized to the sender", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "http-log-level": { - "blurb": "Set log level for soup's HTTP session log", + "drop-on-latency": { + "blurb": "Tells the jitterbuffer to never exceed the given latency in size", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "none (0)", - "enum": true, - "type-name": "SoupLoggerLogLevel", - "values": [ - { - "desc": "SOUP_LOGGER_LOG_NONE", - "name": "none", - "value": "0" - }, - { - "desc": "SOUP_LOGGER_LOG_MINIMAL", - "name": "minimal", - "value": "1" - }, - { - "desc": "SOUP_LOGGER_LOG_HEADERS", - "name": "headers", - "value": "2" - }, - { - "desc": "SOUP_LOGGER_LOG_BODY", - "name": "body", - "value": "3" - } - ], + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "last-sample": { - "blurb": "The last sample received in the sink", + "ignore-pt": { + "blurb": "Do not demultiplex based on PT values", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstSample", - "writable": false + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true }, - "location": { - "blurb": "URI to send to", + "latency": { + "blurb": "Default amount of ms to buffer in the jitterbuffers", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "NULL", - "type-name": "gchararray", + "controllable": false, + "default": "200", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "max-bitrate": { - "blurb": "The maximum bits per second to render (0 = disabled)", + "max-dropout-time": { + "blurb": "The maximum time (milliseconds) of missing packets tolerated.", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "18446744073709551615", + "controllable": false, + "default": "60000", + "max": "-1", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "max-lateness": { - "blurb": "Maximum number of nanoseconds that a buffer can be late before it is dropped (-1 unlimited)", + "max-misorder-time": { + "blurb": "The maximum time (milliseconds) of misordered packets tolerated.", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", + "controllable": false, + "default": "2000", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "max-rtcp-rtp-time-diff": { + "blurb": "Maximum amount of time in ms that the RTP time in RTCP SRs is allowed to be ahead (-1 disabled)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "1000", + "max": "2147483647", "min": "-1", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "name": { - "blurb": "The name of the object", - "construct": true, + "max-streams": { + "blurb": "The maximum number of streams to create for one session", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "default": "-1", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "max-ts-offset": { + "blurb": "The maximum absolute value of the time offset in (nanoseconds). Note, if the ntp-sync parameter is set the default value is changed to 0 (no limit)", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "3000000000", + "max": "9223372036854775807", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint64", "writable": true }, - "processing-deadline": { - "blurb": "Maximum processing deadline in nanoseconds", + "max-ts-offset-adjustment": { + "blurb": "The maximum number of nanoseconds per frame that time stamp offsets may be adjusted (0 = no limit).", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "20000000", + "controllable": false, + "default": "0", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, - "proxy": { - "blurb": "HTTP proxy server URI", + "ntp-sync": { + "blurb": "Synchronize received streams to the NTP clock", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "", - "type-name": "gchararray", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "proxy-id": { - "blurb": "user id for proxy authentication", + "ntp-time-source": { + "blurb": "NTP time source for RTCP packets", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "NULL", - "type-name": "gchararray", + "controllable": false, + "default": "ntp (0)", + "mutable": "null", + "readable": true, + "type": "GstRtpNtpTimeSource", "writable": true }, - "proxy-pw": { - "blurb": "user password for proxy authentication", + "rfc7273-sync": { + "blurb": "Synchronize received streams to the RFC7273 clock (requires clock and offset to be provided)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "NULL", - "type-name": "gchararray", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "qos": { - "blurb": "Generate Quality-of-Service events upstream", + "rtcp-sync": { + "blurb": "Use of RTCP SR in synchronization", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "always (0)", + "mutable": "null", + "readable": true, + "type": "GstRTCPSync", "writable": true }, - "render-delay": { - "blurb": "Additional render delay of the sink in nanoseconds", + "rtcp-sync-interval": { + "blurb": "RTCP SR interval synchronization (ms) (0 = always)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", - "max": "18446744073709551615", + "max": "-1", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "retries": { - "blurb": "Maximum number of retries, zero to disable, -1 to retry forever", + "rtcp-sync-send-time": { + "blurb": "Use send time or capture time for RTCP sync (TRUE = send time, FALSE = capture time)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "-1", - "type-name": "gint", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "retry-delay": { - "blurb": "Delay in seconds between retries after a failure", + "rtp-profile": { + "blurb": "Default RTP profile of newly created sessions", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "5", - "max": "2147483647", - "min": "1", - "type-name": "gint", + "controllable": false, + "default": "avp (1)", + "mutable": "null", + "readable": true, + "type": "GstRTPProfile", "writable": true }, - "session": { - "blurb": "SoupSession object to use for communication", + "sdes": { + "blurb": "The SDES items of this session", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "SoupSession", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstStructure", "writable": true }, - "stats": { - "blurb": "Sink Statistics", + "use-pipeline-clock": { + "blurb": "Use the pipeline running-time to set the NTP time in the RTCP SR messages (DEPRECATED: Use ntp-time-source property)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "application/x-gst-base-sink-stats, average-rate=(double)0, dropped=(guint64)0, rendered=(guint64)0;", - "type-name": "GstStructure", - "writable": false + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + } + }, + "rank": "none", + "signals": { + "clear-pt-map": { + "action": true, + "args": [], + "return-type": "void", + "when": "last" + }, + "get-internal-session": { + "action": true, + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "RTPSession", + "when": "last" + }, + "get-internal-storage": { + "action": true, + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "GObject", + "when": "last" + }, + "get-session": { + "action": true, + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "GstElement", + "when": "last" + }, + "get-storage": { + "action": true, + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "GstElement", + "when": "last" + }, + "new-jitterbuffer": { + "args": [ + { + "name": "arg0", + "type": "GstElement" + }, + { + "name": "arg1", + "type": "guint" + }, + { + "name": "arg2", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "new-storage": { + "args": [ + { + "name": "arg0", + "type": "GstElement" + }, + { + "name": "arg1", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-bye-ssrc": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-bye-timeout": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-new-sender-ssrc": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-new-ssrc": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-npt-stop": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-sender-ssrc-active": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-sender-timeout": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-ssrc-active": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-ssrc-collision": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-ssrc-sdes": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-ssrc-validated": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-timeout": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "payload-type-change": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "request-aux-receiver": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "GstElement", + "when": "last" + }, + "request-aux-sender": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "GstElement", + "when": "last" + }, + "request-fec-decoder": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "GstElement", + "when": "last" + }, + "request-fec-encoder": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "GstElement", + "when": "last" + }, + "request-jitterbuffer": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "GstElement", + "when": "last" + }, + "request-pt-map": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + } + ], + "return-type": "GstCaps", + "when": "last" }, - "sync": { - "blurb": "Sync on the clock", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true + "request-rtcp-decoder": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "GstElement", + "when": "last" }, - "throttle-time": { - "blurb": "The time to keep between rendered buffers (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true + "request-rtcp-encoder": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "GstElement", + "when": "last" }, - "ts-offset": { - "blurb": "Timestamp offset in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "-9223372036854775808", - "type-name": "gint64", - "writable": true + "request-rtp-decoder": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "GstElement", + "when": "last" }, - "user-agent": { - "blurb": "Value of the User-Agent HTTP request header field", - "construct": false, - "construct-only": false, - "default": "GStreamer souphttpclientsink ", - "type-name": "gchararray", - "writable": true + "request-rtp-encoder": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "GstElement", + "when": "last" }, - "user-id": { - "blurb": "user id for authentication", - "construct": false, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": true + "reset-sync": { + "action": true, + "args": [], + "return-type": "void", + "when": "last" + } + } + }, + "rtpdtmfmux": { + "author": "Zeeshan Ali ", + "description": "mixes RTP DTMF streams into other RTP streams", + "hierarchy": [ + "GstRTPDTMFMux", + "GstRTPMux", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Muxer", + "long-name": "RTP muxer", + "pad-templates": { + "priority_sink_%%u": { + "caps": "application/x-rtp:\n", + "direction": "sink", + "presence": "request" }, - "user-pw": { - "blurb": "user password for authentication", - "construct": false, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": true + "sink_%%u": { + "caps": "application/x-rtp:\n", + "direction": "sink", + "presence": "request" + }, + "src": { + "caps": "application/x-rtp:\n", + "direction": "src", + "presence": "always" } }, + "properties": {}, "rank": "none" }, - "souphttpsrc": { - "author": "Wouter Cloetens ", - "description": "Receive data as a client over the network via HTTP using SOUP", + "rtpfunnel": { + "author": "Havard Graff ", + "description": "Funnel RTP buffers together for multiplexing", "hierarchy": [ - "GstSoupHTTPSrc", - "GstPushSrc", - "GstBaseSrc", + "GstRtpFunnel", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Source/Network", - "long-name": "HTTP client source", - "name": "souphttpsrc", + "klass": "RTP Funneling", + "long-name": "RTP funnel", "pad-templates": { + "sink_%%u": { + "caps": "application/x-rtp:\n", + "direction": "sink", + "presence": "request" + }, "src": { - "caps": "ANY", + "caps": "application/x-rtp:\n", "direction": "src", "presence": "always" } }, "properties": { - "automatic-redirect": { - "blurb": "Automatically follow HTTP redirects (HTTP Status Code 3xx)", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "blocksize": { - "blurb": "Size in bytes to read per buffer (-1 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "compress": { - "blurb": "Allow compressed content encodings", - "construct": false, + "common-ts-offset": { + "blurb": "Use the same RTP timestamp offset for all sinkpads (-1 = disable)", + "conditionally-available": false, + "construct": true, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "-1", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true + } + }, + "rank": "none" + }, + "rtpjitterbuffer": { + "author": "Philippe Kalaf , Wim Taymans ", + "description": "A buffer that deals with network jitter and other transmission faults", + "hierarchy": [ + "GstRtpJitterBuffer", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Filter/Network/RTP", + "long-name": "RTP packet jitter-buffer", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n", + "direction": "sink", + "presence": "always" }, - "cookies": { - "blurb": "HTTP request cookies", - "construct": false, - "construct-only": false, - "type-name": "GStrv", - "writable": true + "sink_rtcp": { + "caps": "application/x-rtcp:\n", + "direction": "sink", + "presence": "request" }, - "do-timestamp": { - "blurb": "Apply current stream time to buffers", + "src": { + "caps": "application/x-rtp:\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "do-lost": { + "blurb": "Send an event downstream when a packet is lost", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", - "writable": true - }, - "extra-headers": { - "blurb": "Extra headers to append to the HTTP request", - "construct": false, - "construct-only": false, - "type-name": "GstStructure", - "writable": true - }, - "http-log-level": { - "blurb": "Set log level for soup's HTTP session log", - "construct": false, - "construct-only": false, - "default": "headers (2)", - "enum": true, - "type-name": "SoupLoggerLogLevel", - "values": [ - { - "desc": "SOUP_LOGGER_LOG_NONE", - "name": "none", - "value": "0" - }, - { - "desc": "SOUP_LOGGER_LOG_MINIMAL", - "name": "minimal", - "value": "1" - }, - { - "desc": "SOUP_LOGGER_LOG_HEADERS", - "name": "headers", - "value": "2" - }, - { - "desc": "SOUP_LOGGER_LOG_BODY", - "name": "body", - "value": "3" - } - ], - "writable": true - }, - "iradio-mode": { - "blurb": "Enable internet radio mode (ask server to send shoutcast/icecast metadata interleaved with the actual stream data)", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "is-live": { - "blurb": "Act like a live source", + "do-retransmission": { + "blurb": "Send retransmission events upstream when a packet is late", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", - "writable": true - }, - "keep-alive": { - "blurb": "Use HTTP persistent connections", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "location": { - "blurb": "Location to read from", - "construct": false, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "method": { - "blurb": "The HTTP method to use (GET, HEAD, OPTIONS, etc)", - "construct": false, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "num-buffers": { - "blurb": "Number of buffers to output before sending EOS (-1 = unlimited)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "drop-messages-interval": { + "blurb": "Minimal time between posting dropped packet messages", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "proxy": { - "blurb": "HTTP proxy server URI", - "construct": false, - "construct-only": false, - "default": "", - "type-name": "gchararray", + "controllable": false, + "default": "200", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "proxy-id": { - "blurb": "HTTP proxy URI user id for authentication", + "drop-on-latency": { + "blurb": "Tells the jitterbuffer to never exceed the given latency in size", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "NULL", - "type-name": "gchararray", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "proxy-pw": { - "blurb": "HTTP proxy URI user password for authentication", + "faststart-min-packets": { + "blurb": "The number of consecutive packets needed to start (set to 0 to disable faststart. The jitterbuffer will by default start after the latency has elapsed)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "NULL", - "type-name": "gchararray", + "controllable": false, + "default": "0", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "retries": { - "blurb": "Maximum number of retries until giving up (-1=infinite)", + "latency": { + "blurb": "Amount of ms to buffer", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "3", - "max": "2147483647", - "min": "-1", - "type-name": "gint", + "controllable": false, + "default": "200", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "ssl-ca-file": { - "blurb": "Location of a SSL anchor CA file to use", + "max-dropout-time": { + "blurb": "The maximum time (milliseconds) of missing packets tolerated.", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "NULL", - "type-name": "gchararray", + "controllable": false, + "default": "60000", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "ssl-strict": { - "blurb": "Strict SSL certificate checking", + "max-misorder-time": { + "blurb": "The maximum time (milliseconds) of misordered packets tolerated.", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "2000", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "ssl-use-system-ca-file": { - "blurb": "Use system CA file", + "max-rtcp-rtp-time-diff": { + "blurb": "Maximum amount of time in ms that the RTP time in RTCP SRs is allowed to be ahead (-1 disabled)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "1000", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "timeout": { - "blurb": "Value in seconds to timeout a blocking I/O (0 = No timeout).", + "max-ts-offset-adjustment": { + "blurb": "The maximum number of nanoseconds per frame that time stamp offsets may be adjusted (0 = no limit).", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "15", - "max": "3600", + "controllable": false, + "default": "0", + "max": "18446744073709551615", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, - "tls-database": { - "blurb": "TLS database with anchor certificate authorities used to validate the server certificate", + "mode": { + "blurb": "Control the buffering algorithm in use", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GTlsDatabase", + "controllable": false, + "default": "slave (1)", + "mutable": "null", + "readable": true, + "type": "RTPJitterBufferMode", "writable": true }, - "tls-interaction": { - "blurb": "A GTlsInteraction object to be used when the connection or certificate database need to interact with the user.", + "percent": { + "blurb": "The buffer filled percent", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GTlsInteraction", - "writable": true + "controllable": false, + "default": "0", + "max": "100", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": false }, - "typefind": { - "blurb": "Run typefind before negotiating (deprecated, non-functional)", + "post-drop-messages": { + "blurb": "Post a custom message to the bus when a packet is dropped by the jitterbuffer", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "user-agent": { - "blurb": "Value of the User-Agent HTTP request header field", + "rfc7273-sync": { + "blurb": "Synchronize received streams to the RFC7273 clock (requires clock and offset to be provided)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "GStreamer souphttpsrc 1.17.0.1 ", - "type-name": "gchararray", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "user-id": { - "blurb": "HTTP location URI user id for authentication", + "rtx-deadline": { + "blurb": "The deadline for a valid RTX request in milliseconds. (-1 automatic)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "NULL", - "type-name": "gchararray", + "controllable": false, + "default": "-1", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "user-pw": { - "blurb": "HTTP location URI user password for authentication", + "rtx-delay": { + "blurb": "Extra time in ms to wait before sending retransmission event (-1 automatic)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "NULL", - "type-name": "gchararray", + "controllable": false, + "default": "-1", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true - } - }, - "rank": "primary" - } - }, - "filename": "gstsoup", - "license": "LGPL", - "package": "GStreamer Good Plug-ins git", - "source": "gst-plugins-good", - "tracers": {}, - "url": "Unknown package origin" - }, - "spectrum": { - "description": "Run an FFT on the audio signal, output spectrum data", - "elements": { - "spectrum": { - "author": "Erik Walthinsen , Stefan Kost , Sebastian Dr\u00f6ge ", - "description": "Run an FFT on the audio signal, output spectrum data", - "hierarchy": [ - "GstSpectrum", - "GstAudioFilter", - "GstBaseTransform", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Filter/Analyzer/Audio", - "long-name": "Spectrum analyzer", - "name": "spectrum", - "pad-templates": { - "sink": { - "caps": "audio/x-raw:\n format: { S16LE, S24LE, S32LE, F32LE, F64LE }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: interleaved\n", - "direction": "sink", - "presence": "always" }, - "src": { - "caps": "audio/x-raw:\n format: { S16LE, S24LE, S32LE, F32LE, F64LE }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: interleaved\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "bands": { - "blurb": "Number of frequency bands", + "rtx-delay-reorder": { + "blurb": "Sending retransmission event when this much reordering (0 disable)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "128", - "max": "1073741824", - "min": "2", - "type-name": "guint", + "controllable": false, + "default": "3", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "interval": { - "blurb": "Interval of time between message posts (in nanoseconds)", + "rtx-max-retries": { + "blurb": "The maximum number of retries to request a retransmission. (-1 not limited)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "100000000", - "max": "18446744073709551615", - "min": "1", - "type-name": "guint64", + "controllable": false, + "default": "-1", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "message-magnitude": { - "blurb": "Whether to add a 'magnitude' field to the structure of any 'spectrum' element messages posted on the bus", + "rtx-min-delay": { + "blurb": "Minimum time in ms to wait before sending retransmission event", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "0", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "message-phase": { - "blurb": "Whether to add a 'phase' field to the structure of any 'spectrum' element messages posted on the bus", + "rtx-min-retry-timeout": { + "blurb": "Minimum timeout between sending a transmission event in ms (-1 automatic)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "-1", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "multi-channel": { - "blurb": "Send separate results for each channel", + "rtx-next-seqnum": { + "blurb": "Estimate when the next packet should arrive and schedule a retransmission request for it.", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "name": { - "blurb": "The name of the object", - "construct": true, + "rtx-retry-period": { + "blurb": "Try to get a retransmission for this many ms (-1 automatic)", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "default": "-1", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "rtx-retry-timeout": { + "blurb": "Retry sending a transmission event after this timeout in ms (-1 automatic)", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "-1", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "post-messages": { - "blurb": "Whether to post a 'spectrum' element message on the bus for each passed interval", + "rtx-stats-timeout": { + "blurb": "The time to wait for a retransmitted packet after it has been considered lost in order to collect statistics (ms)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "1000", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "qos": { - "blurb": "Handle Quality-of-Service events", + "stats": { + "blurb": "Various statistics", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true + "controllable": false, + "default": "application/x-rtp-jitterbuffer-stats, num-pushed=(guint64)0, num-lost=(guint64)0, num-late=(guint64)0, num-duplicates=(guint64)0, avg-jitter=(guint64)0, rtx-count=(guint64)0, rtx-success-count=(guint64)0, rtx-per-packet=(double)0, rtx-rtt=(guint64)0;", + "mutable": "null", + "readable": true, + "type": "GstStructure", + "writable": false }, - "threshold": { - "blurb": "dB threshold for result. All lower values will be set to this", + "ts-offset": { + "blurb": "Adjust buffer timestamps with offset in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "-60", - "max": "0", - "min": "-2147483648", - "type-name": "gint", + "controllable": false, + "default": "0", + "max": "9223372036854775807", + "min": "-9223372036854775808", + "mutable": "null", + "readable": true, + "type": "gint64", "writable": true } }, - "rank": "none" - } - }, - "filename": "gstspectrum", - "license": "LGPL", - "package": "GStreamer Good Plug-ins git", - "source": "gst-plugins-good", - "tracers": {}, - "url": "Unknown package origin" - }, - "speex": { - "description": "Speex plugin library", - "elements": { - "speexdec": { - "author": "Wim Taymans ", - "description": "decode speex streams to audio", + "rank": "none", + "signals": { + "clear-pt-map": { + "action": true, + "args": [], + "return-type": "void", + "when": "last" + }, + "handle-sync": { + "args": [ + { + "name": "arg0", + "type": "GstStructure" + } + ], + "return-type": "void", + "when": "last" + }, + "on-npt-stop": { + "args": [], + "return-type": "void", + "when": "last" + }, + "request-pt-map": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "GstCaps", + "when": "last" + }, + "set-active": { + "action": true, + "args": [ + { + "name": "arg0", + "type": "gboolean" + }, + { + "name": "arg1", + "type": "guint64" + } + ], + "return-type": "guint64", + "when": "last" + } + } + }, + "rtpmux": { + "author": "Zeeshan Ali ", + "description": "multiplex N rtp streams into one", "hierarchy": [ - "GstSpeexDec", - "GstAudioDecoder", + "GstRTPMux", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Codec/Decoder/Audio", - "long-name": "Speex audio decoder", - "name": "speexdec", + "klass": "Codec/Muxer", + "long-name": "RTP muxer", "pad-templates": { - "sink": { - "caps": "audio/x-speex:\n", + "sink_%%u": { + "caps": "application/x-rtp:\n", "direction": "sink", - "presence": "always" + "presence": "request" }, "src": { - "caps": "audio/x-raw:\n format: S16LE\n layout: interleaved\n rate: [ 6000, 48000 ]\n channels: [ 1, 2 ]\n", + "caps": "application/x-rtp:\n", "direction": "src", "presence": "always" } }, "properties": { - "enh": { - "blurb": "Enable perceptual enhancement", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "min-latency": { - "blurb": "Aggregate output data to a minimum of latency time (ns)", + "seqnum": { + "blurb": "The RTP sequence number of the last processed packet", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", - "max": "9223372036854775807", + "max": "-1", "min": "0", - "type-name": "gint64", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true + "mutable": "null", + "readable": true, + "type": "guint", + "writable": false }, - "parent": { - "blurb": "The parent of the object", + "seqnum-offset": { + "blurb": "Offset to add to all outgoing seqnum (-1 = random)", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "-1", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "plc": { - "blurb": "Perform packet loss concealment (if supported)", + "ssrc": { + "blurb": "The SSRC of the packets (default == random)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "-1", + "max": "-1", + "min": "0", + "mutable": "playing", + "readable": true, + "type": "guint", "writable": true }, - "tolerance": { - "blurb": "Perfect ts while timestamp jitter/imperfection within tolerance (ns)", + "timestamp-offset": { + "blurb": "Offset to add to all outgoing timestamps (-1 = random)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", + "controllable": false, + "default": "-1", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true } }, - "rank": "primary" + "rank": "none" }, - "speexenc": { - "author": "Wim Taymans ", - "description": "Encodes audio in Speex format", + "rtpptdemux": { + "author": "Kai Vehmanen ", + "description": "Parses codec streams transmitted in the same RTP session", "hierarchy": [ - "GstSpeexEnc", - "GstAudioEncoder", + "GstRtpPtDemux", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Codec/Encoder/Audio", - "long-name": "Speex audio encoder", - "name": "speexenc", + "klass": "Demux/Network/RTP", + "long-name": "RTP Demux", "pad-templates": { "sink": { - "caps": "audio/x-raw:\n format: S16LE\n layout: interleaved\n rate: [ 6000, 48000 ]\n channels: 1\naudio/x-raw:\n format: S16LE\n layout: interleaved\n rate: [ 6000, 48000 ]\n channels: 2\n channel-mask: 0x0000000000000003\n", + "caps": "application/x-rtp:\n", "direction": "sink", "presence": "always" }, - "src": { - "caps": "audio/x-speex:\n rate: [ 6000, 48000 ]\n channels: [ 1, 2 ]\n", + "src_%%u": { + "caps": "application/x-rtp:\n payload: [ 0, 255 ]\n", "direction": "src", - "presence": "always" + "presence": "sometimes" } }, "properties": { - "abr": { - "blurb": "Enable average bit-rate (0 = disabled)", - "construct": true, - "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "bitrate": { - "blurb": "Specify an encoding bit-rate (in bps). (0 = automatic)", - "construct": true, - "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "complexity": { - "blurb": "Set encoding complexity", - "construct": true, - "construct-only": false, - "default": "3", - "max": "2147483647", - "min": "0", - "type-name": "gint", - "writable": true - }, - "dtx": { - "blurb": "Enable discontinuous transmission", - "construct": true, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "hard-resync": { - "blurb": "Perform clipping and sample flushing upon discontinuity", + "ignored-payload-types": { + "blurb": "Packets with these payload types will be dropped", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstValueArray", "writable": true + } + }, + "rank": "none", + "signals": { + "clear-pt-map": { + "action": true, + "args": [], + "return-type": "void", + "when": "last" }, - "last-message": { - "blurb": "The last status message", - "construct": false, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": false - }, - "mark-granule": { - "blurb": "Apply granule semantics to buffer metadata (implies perfect-timestamp)", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": false - }, - "mode": { - "blurb": "The encoding mode", - "construct": true, - "construct-only": false, - "default": "auto (0)", - "enum": true, - "type-name": "GstSpeexEncMode", - "values": [ - { - "desc": "Auto", - "name": "auto", - "value": "0" - }, + "new-payload-type": { + "args": [ { - "desc": "Ultra Wide Band", - "name": "uwb", - "value": "1" + "name": "arg0", + "type": "guint" }, { - "desc": "Wide Band", - "name": "wb", - "value": "2" - }, + "name": "arg1", + "type": "GstPad" + } + ], + "return-type": "void", + "when": "last" + }, + "payload-type-change": { + "args": [ { - "desc": "Narrow Band", - "name": "nb", - "value": "3" + "name": "arg0", + "type": "guint" } ], - "writable": true + "return-type": "void", + "when": "last" }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true + "request-pt-map": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "GstCaps", + "when": "last" + } + } + }, + "rtprtxqueue": { + "author": "Wim Taymans ", + "description": "Keep RTP packets in a queue for retransmission", + "hierarchy": [ + "GstRTPRtxQueue", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec", + "long-name": "RTP Retransmission Queue", + "pad-templates": { + "sink": { + "caps": "application/x-rtp:\n", + "direction": "sink", + "presence": "always" }, - "nframes": { - "blurb": "Number of frames per buffer", - "construct": true, + "src": { + "caps": "application/x-rtp:\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "fulfilled-requests": { + "blurb": "Number of fulfilled retransmission requests", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "1", - "max": "2147483647", + "controllable": false, + "default": "0", + "max": "-1", "min": "0", - "type-name": "gint", - "writable": true + "mutable": "null", + "readable": true, + "type": "guint", + "writable": false }, - "parent": { - "blurb": "The parent of the object", + "max-size-packets": { + "blurb": "Amount of packets to queue (0 = unlimited)", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "100", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "perfect-timestamp": { - "blurb": "Favour perfect timestamps over tracking upstream timestamps", + "max-size-time": { + "blurb": "Amount of ms to queue (0 = unlimited)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "quality": { - "blurb": "Encoding quality", - "construct": true, - "construct-only": false, - "default": "8", - "max": "10", + "controllable": false, + "default": "0", + "max": "-1", "min": "0", - "type-name": "gfloat", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "tolerance": { - "blurb": "Consider discontinuity if timestamp jitter/imperfection exceeds tolerance (ns)", + "requests": { + "blurb": "Total number of retransmission requests", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "40000000", - "max": "9223372036854775807", + "controllable": false, + "default": "0", + "max": "-1", "min": "0", - "type-name": "gint64", - "writable": true - }, - "vad": { - "blurb": "Enable voice activity detection", - "construct": true, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "vbr": { - "blurb": "Enable variable bit-rate", - "construct": true, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true + "mutable": "null", + "readable": true, + "type": "guint", + "writable": false } - }, - "rank": "primary" - } - }, - "filename": "gstspeex", - "license": "LGPL", - "package": "GStreamer Good Plug-ins git", - "source": "gst-plugins-good", - "tracers": {}, - "url": "Unknown package origin" - }, - "taglib": { - "description": "Tag writing plug-in based on taglib", - "elements": { - "apev2mux": { - "author": "Sebastian Dr\u00f6ge ", - "description": "Adds an APEv2 header to the beginning of files using taglib", + }, + "rank": "none" + }, + "rtprtxreceive": { + "author": "Julien Isorce ", + "description": "Receive retransmitted RTP packets according to RFC4588", "hierarchy": [ - "GstApev2Mux", - "GstTagMux", + "GstRtpRtxReceive", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Formatter/Metadata", - "long-name": "TagLib-based APEv2 Muxer", - "name": "apev2mux", + "klass": "Codec", + "long-name": "RTP Retransmission receiver", "pad-templates": { "sink": { - "caps": "ANY", + "caps": "application/x-rtp:\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "application/x-apetag:\n", + "caps": "application/x-rtp:\n", "direction": "src", "presence": "always" } }, "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, + "num-rtx-assoc-packets": { + "blurb": "Number of retransmission packets correctly associated with retransmission requests", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true + "controllable": false, + "default": "0", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": false + }, + "num-rtx-packets": { + "blurb": " Number of retransmission packets received", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": false + }, + "num-rtx-requests": { + "blurb": "Number of retransmission events received", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": false }, - "parent": { - "blurb": "The parent of the object", + "payload-type-map": { + "blurb": "Map of original payload types to their retransmission payload types", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstStructure", "writable": true } }, "rank": "none" }, - "id3v2mux": { - "author": "Christophe Fergeau ", - "description": "Adds an ID3v2 header to the beginning of MP3 files using taglib", + "rtprtxsend": { + "author": "Julien Isorce ", + "description": "Retransmit RTP packets when needed, according to RFC4588", "hierarchy": [ - "GstId3v2Mux", - "GstTagMux", + "GstRtpRtxSend", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Formatter/Metadata", - "long-name": "TagLib-based ID3v2 Muxer", - "name": "id3v2mux", + "klass": "Codec", + "long-name": "RTP Retransmission Sender", "pad-templates": { "sink": { - "caps": "ANY", + "caps": "application/x-rtp:\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "application/x-id3:\n", + "caps": "application/x-rtp:\n", "direction": "src", "presence": "always" } }, "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, + "clock-rate-map": { + "blurb": "Map of payload types to their clock rates", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstStructure", + "writable": true + }, + "max-size-packets": { + "blurb": "Amount of packets to queue (0 = unlimited)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "100", + "max": "32767", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "max-size-time": { + "blurb": "Amount of ms to queue (0 = unlimited)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": true + }, + "num-rtx-packets": { + "blurb": " Number of retransmission packets sent", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": false + }, + "num-rtx-requests": { + "blurb": "Number of retransmission events received", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": false + }, + "payload-type-map": { + "blurb": "Map of original payload types to their retransmission payload types", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstStructure", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "ssrc-map": { + "blurb": "Map of SSRCs to their retransmission SSRCs for SSRC-multiplexed mode (default = random)", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "mutable": "null", + "readable": false, + "type": "GstStructure", "writable": true } }, "rank": "none" - } - }, - "filename": "gsttaglib", - "license": "LGPL", - "package": "GStreamer Good Plug-ins git", - "source": "gst-plugins-good", - "tracers": {}, - "url": "Unknown package origin" - }, - "twolame": { - "description": "Encode MP2s with TwoLAME", - "elements": { - "twolamemp2enc": { - "author": "Sebastian Dr\u00f6ge ", - "description": "High-quality free MP2 encoder", + }, + "rtpsession": { + "author": "Wim Taymans ", + "description": "Implement an RTP session", "hierarchy": [ - "GstTwoLame", - "GstAudioEncoder", + "GstRtpSession", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Codec/Encoder/Audio", - "long-name": "TwoLAME mp2 encoder", - "name": "twolamemp2enc", + "klass": "Filter/Network/RTP", + "long-name": "RTP Session", "pad-templates": { - "sink": { - "caps": "audio/x-raw:\n format: { F32LE, S16LE }\n layout: interleaved\n rate: { (int)16000, (int)22050, (int)24000, (int)32000, (int)44100, (int)48000 }\n channels: 1\naudio/x-raw:\n format: { F32LE, S16LE }\n layout: interleaved\n rate: { (int)16000, (int)22050, (int)24000, (int)32000, (int)44100, (int)48000 }\n channels: 2\n channel-mask: 0x0000000000000003\n", + "recv_rtcp_sink": { + "caps": "application/x-rtcp:\n", "direction": "sink", - "presence": "always" + "presence": "request" }, - "src": { - "caps": "audio/mpeg:\n mpegversion: 1\n layer: 2\n rate: { (int)16000, (int)22050, (int)24000, (int)32000, (int)44100, (int)48000 }\n channels: [ 1, 2 ]\n", + "recv_rtp_sink": { + "caps": "application/x-rtp:\n", + "direction": "sink", + "presence": "request" + }, + "recv_rtp_src": { + "caps": "application/x-rtp:\n", "direction": "src", - "presence": "always" + "presence": "sometimes" + }, + "send_rtcp_src": { + "caps": "application/x-rtcp:\n", + "direction": "src", + "presence": "request" + }, + "send_rtp_sink": { + "caps": "application/x-rtp:\n", + "direction": "sink", + "presence": "request" + }, + "send_rtp_src": { + "caps": "application/x-rtp:\n", + "direction": "src", + "presence": "sometimes" + }, + "sync_src": { + "caps": "application/x-rtcp:\n", + "direction": "src", + "presence": "sometimes" } }, "properties": { - "ath-level": { - "blurb": "ATH Level in dB", + "bandwidth": { + "blurb": "The bandwidth of the session in bytes per second (0 for auto-discover)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", - "max": "3.40282e+38", - "min": "-3.40282e+38", - "type-name": "gfloat", - "writable": true - }, - "bitrate": { - "blurb": "Bitrate in kbit/sec (8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 192, 224, 256, 320, 384)", - "construct": false, - "construct-only": false, - "default": "192", - "max": "384", - "min": "8", - "type-name": "gint", - "writable": true - }, - "copyright": { - "blurb": "Mark as copyright", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "max": "1.79769e+308", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, - "emphasis": { - "blurb": "Pre-emphasis to apply to the decoded audio", + "internal-session": { + "blurb": "The internal RTPSession object", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "none (0)", - "enum": true, - "type-name": "GstTwoLameEmphasis", - "values": [ - { - "desc": "No emphasis", - "name": "none", - "value": "0" - }, - { - "desc": "50/15 ms", - "name": "5", - "value": "1" - }, - { - "desc": "CCIT J.17", - "name": "ccit", - "value": "3" - } - ], - "writable": true + "controllable": false, + "mutable": "null", + "readable": true, + "type": "RTPSession", + "writable": false }, - "energy-level-extension": { - "blurb": "Write peak PCM level to each frame", + "max-dropout-time": { + "blurb": "The maximum time (milliseconds) of missing packets tolerated.", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "60000", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "error-protection": { - "blurb": "Adds checksum to every frame", + "max-misorder-time": { + "blurb": "The maximum time (milliseconds) of misordered packets tolerated.", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "2000", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "hard-resync": { - "blurb": "Perform clipping and sample flushing upon discontinuity", + "ntp-time-source": { + "blurb": "NTP time source for RTCP packets", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "ntp (0)", + "mutable": "null", + "readable": true, + "type": "GstRtpNtpTimeSource", "writable": true }, - "mark-granule": { - "blurb": "Apply granule semantics to buffer metadata (implies perfect-timestamp)", + "num-active-sources": { + "blurb": "The number of active sources in the session", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "0", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": false }, - "mode": { - "blurb": "Encoding mode", - "construct": false, - "construct-only": false, - "default": "joint (1)", - "enum": true, - "type-name": "GstTwoLameMode", - "values": [ - { - "desc": "Auto", - "name": "auto", - "value": "-1" - }, - { - "desc": "Stereo", - "name": "stereo", - "value": "0" - }, - { - "desc": "Joint Stereo", - "name": "joint", - "value": "1" - }, - { - "desc": "Dual Channel", - "name": "dual", - "value": "2" - }, - { - "desc": "Mono", - "name": "mono", - "value": "3" - } - ], - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, + "num-sources": { + "blurb": "The number of sources in the session", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true + "controllable": false, + "default": "0", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": false }, - "original": { - "blurb": "Mark as original", + "probation": { + "blurb": "Consecutive packet sequence numbers to accept the source", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "2", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "padding": { - "blurb": "Padding type", + "rtcp-fraction": { + "blurb": "The RTCP bandwidth of the session in bytes per second (or as a real fraction of the RTP bandwidth if < 1.0)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "never (0)", - "enum": true, - "type-name": "GstTwoLamePadding", - "values": [ - { - "desc": "No Padding", - "name": "never", - "value": "0" - }, - { - "desc": "Always Pad", - "name": "always", - "value": "1" - } - ], + "controllable": false, + "default": "0.05", + "max": "1.79769e+308", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "rtcp-min-interval": { + "blurb": "Minimum interval between Regular RTCP packet (in ns)", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "5000000000", + "max": "18446744073709551615", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, - "perfect-timestamp": { - "blurb": "Favour perfect timestamps over tracking upstream timestamps", + "rtcp-rr-bandwidth": { + "blurb": "The RTCP bandwidth used for receivers in bytes per second (-1 = default)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "-1", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "psymodel": { - "blurb": "Psychoacoustic model used to encode the audio", + "rtcp-rs-bandwidth": { + "blurb": "The RTCP bandwidth used for senders in bytes per second (-1 = default)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "3", - "max": "4", + "controllable": false, + "default": "-1", + "max": "2147483647", "min": "-1", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "quick-mode": { - "blurb": "Calculate Psymodel every frames", + "rtcp-sync-send-time": { + "blurb": "Use send time or capture time for RTCP sync (TRUE = send time, FALSE = capture time)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "quick-mode-count": { - "blurb": "Calculate Psymodel every n frames", + "rtp-profile": { + "blurb": "RTP profile to use", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "10", - "max": "2147483647", - "min": "0", - "type-name": "gint", + "controllable": false, + "default": "avp (1)", + "mutable": "null", + "readable": true, + "type": "GstRTPProfile", "writable": true }, - "tolerance": { - "blurb": "Consider discontinuity if timestamp jitter/imperfection exceeds tolerance (ns)", + "sdes": { + "blurb": "The SDES items of this session", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "40000000", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstStructure", "writable": true }, - "vbr": { - "blurb": "Enable variable bitrate mode", + "stats": { + "blurb": "Various statistics", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true + "controllable": false, + "default": "application/x-rtp-session-stats, rtx-drop-count=(uint)0, sent-nack-count=(uint)0, recv-nack-count=(uint)0, source-stats=(GValueArray)< >, rtx-count=(uint)0, recv-rtx-req-count=(uint)0, sent-rtx-req-count=(uint)0;", + "mutable": "null", + "readable": true, + "type": "GstStructure", + "writable": false }, - "vbr-level": { - "blurb": "VBR Level", + "twcc-stats": { + "blurb": "Various statistics from TWCC", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "5", - "max": "10", - "min": "-10", - "type-name": "gfloat", - "writable": true + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstStructure", + "writable": false }, - "vbr-max-bitrate": { - "blurb": "Specify maximum VBR bitrate (0=off, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 192, 224, 256, 320, 384)", + "use-pipeline-clock": { + "blurb": "Use the pipeline running-time to set the NTP time in the RTCP SR messages (DEPRECATED: Use ntp-time-source property)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "384", - "min": "0", - "type-name": "gint", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, - "rank": "primary" - } - }, - "filename": "gsttwolame", - "license": "LGPL", - "package": "GStreamer Good Plug-ins git", - "source": "gst-plugins-good", - "tracers": {}, - "url": "Unknown package origin" - }, - "udp": { - "description": "transfer data via UDP", - "elements": { - "dynudpsink": { - "author": "Philippe Khalaf ", - "description": "Send data over the network via UDP with packet destinations picked up dynamically from meta on the buffers passed", + "rank": "none", + "signals": { + "clear-pt-map": { + "action": true, + "args": [], + "return-type": "void", + "when": "last" + }, + "on-bye-ssrc": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-bye-timeout": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-new-sender-ssrc": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-new-ssrc": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-sender-ssrc-active": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-sender-timeout": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-ssrc-active": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-ssrc-collision": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-ssrc-sdes": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-ssrc-validated": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "on-timeout": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "request-pt-map": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "GstCaps", + "when": "last" + } + } + }, + "rtpssrcdemux": { + "author": "Wim Taymans ", + "description": "Splits RTP streams based on the SSRC", "hierarchy": [ - "GstDynUDPSink", - "GstBaseSink", + "GstRtpSsrcDemux", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Sink/Network", - "long-name": "UDP packet sender", - "name": "dynudpsink", + "klass": "Demux/Network/RTP", + "long-name": "RTP SSRC Demux", "pad-templates": { + "rtcp_sink": { + "caps": "application/x-rtcp:\n", + "direction": "sink", + "presence": "always" + }, + "rtcp_src_%%u": { + "caps": "application/x-rtcp:\n", + "direction": "src", + "presence": "sometimes" + }, "sink": { - "caps": "ANY", + "caps": "application/x-rtp:\n", "direction": "sink", "presence": "always" + }, + "src_%%u": { + "caps": "application/x-rtp:\n", + "direction": "src", + "presence": "sometimes" } }, "properties": { - "async": { - "blurb": "Go asynchronously to PAUSED", + "max-streams": { + "blurb": "The maximum number of streams allowed", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "-1", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true + } + }, + "rank": "none", + "signals": { + "clear-ssrc": { + "action": true, + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" }, - "bind-address": { - "blurb": "Address to bind the socket to", - "construct": false, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": true + "new-ssrc-pad": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "GstPad" + } + ], + "return-type": "void", + "when": "last" }, - "bind-port": { - "blurb": "Port to bind the socket to", + "removed-ssrc-pad": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "GstPad" + } + ], + "return-type": "void", + "when": "last" + } + } + } + }, + "filename": "gstrtpmanager", + "license": "LGPL", + "other-types": { + "GstRTCPSync": { + "kind": "enum", + "values": [ + { + "desc": "always", + "name": "always", + "value": "0" + }, + { + "desc": "initial", + "name": "initial", + "value": "1" + }, + { + "desc": "rtp-info", + "name": "rtp-info", + "value": "2" + } + ] + }, + "GstRtpNtpTimeSource": { + "kind": "enum", + "values": [ + { + "desc": "NTP time based on realtime clock", + "name": "ntp", + "value": "0" + }, + { + "desc": "UNIX time based on realtime clock", + "name": "unix", + "value": "1" + }, + { + "desc": "Running time based on pipeline clock", + "name": "running-time", + "value": "2" + }, + { + "desc": "Pipeline clock time", + "name": "clock-time", + "value": "3" + } + ] + }, + "RTPJitterBufferMode": { + "kind": "enum", + "values": [ + { + "desc": "Only use RTP timestamps", + "name": "none", + "value": "0" + }, + { + "desc": "Slave receiver to sender clock", + "name": "slave", + "value": "1" + }, + { + "desc": "Do low/high watermark buffering", + "name": "buffer", + "value": "2" + }, + { + "desc": "Synchronized sender and receiver clocks", + "name": "synced", + "value": "4" + } + ] + }, + "RTPSession": { + "hierarchy": [ + "RTPSession", + "GObject" + ], + "kind": "object", + "properties": { + "bandwidth": { + "blurb": "The bandwidth of the session in bits per second (0 for auto-discover)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", - "max": "65535", - "min": "0", - "type-name": "gint", - "writable": true - }, - "blocksize": { - "blurb": "Size in bytes to pull per buffer (0 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", + "max": "1.79769e+308", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, - "close-socket": { - "blurb": "Close socket if passed as property on state change", + "disable-sr-timestamp": { + "blurb": "Whether sender reports should be timestamped", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "enable-last-sample": { - "blurb": "Enable the last-sample property", + "favor-new": { + "blurb": "Resolve SSRC conflict in favor of new sources", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "last-sample": { - "blurb": "The last sample received in the sink", + "internal-source": { + "blurb": "The internal source element of the session (deprecated)", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstSample", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "RTPSource", "writable": false }, - "max-bitrate": { - "blurb": "The maximum bits per second to render (0 = disabled)", + "internal-ssrc": { + "blurb": "The internal SSRC used for the session (deprecated)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", - "max": "18446744073709551615", + "max": "-1", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "max-lateness": { - "blurb": "Maximum number of nanoseconds that a buffer can be late before it is dropped (-1 unlimited)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", + "max-dropout-time": { + "blurb": "The maximum time (milliseconds) of missing packets tolerated.", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "60000", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "processing-deadline": { - "blurb": "Maximum processing deadline in nanoseconds", + "max-misorder-time": { + "blurb": "The maximum time (milliseconds) of misordered packets tolerated.", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "20000000", - "max": "18446744073709551615", + "controllable": false, + "default": "2000", + "max": "-1", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "qos": { - "blurb": "Generate Quality-of-Service events upstream", + "num-active-sources": { + "blurb": "The number of active sources in the session", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true + "controllable": false, + "default": "0", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", + "writable": false }, - "render-delay": { - "blurb": "Additional render delay of the sink in nanoseconds", + "num-sources": { + "blurb": "The number of sources in the session", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", - "max": "18446744073709551615", + "max": "-1", "min": "0", - "type-name": "guint64", - "writable": true + "mutable": "null", + "readable": true, + "type": "guint", + "writable": false }, - "socket": { - "blurb": "Socket to use for UDP sending. (NULL == allocate)", + "probation": { + "blurb": "Consecutive packet sequence numbers to accept the source", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GSocket", + "controllable": false, + "default": "2", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "socket-v6": { - "blurb": "Socket to use for UDPv6 sending. (NULL == allocate)", + "rtcp-feedback-retention-window": { + "blurb": "Duration during which RTCP Feedback packets are retained (in ns)", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GSocket", + "controllable": false, + "default": "2000000000", + "max": "18446744073709551615", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, - "stats": { - "blurb": "Sink Statistics", + "rtcp-fraction": { + "blurb": "The fraction of the bandwidth used for RTCP in bits per second (or as a real fraction of the RTP bandwidth if < 1)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "application/x-gst-base-sink-stats, average-rate=(double)0, dropped=(guint64)0, rendered=(guint64)0;", - "type-name": "GstStructure", - "writable": false + "controllable": false, + "default": "0.05", + "max": "1.79769e+308", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gdouble", + "writable": true }, - "sync": { - "blurb": "Sync on the clock", + "rtcp-immediate-feedback-threshold": { + "blurb": "The maximum number of members of a RTP session for which immediate feedback is used (DEPRECATED: has no effect and is not needed)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "3", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "throttle-time": { - "blurb": "The time to keep between rendered buffers (0 = disabled)", + "rtcp-min-interval": { + "blurb": "Minimum interval between Regular RTCP packet (in ns)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", + "controllable": false, + "default": "5000000000", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, - "ts-offset": { - "blurb": "Timestamp offset in nanoseconds", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "-9223372036854775808", - "type-name": "gint64", - "writable": true - } - }, - "rank": "none", - "signals": { - "get-stats": { - "args": [ - "gchararray", - "gint" - ], - "retval": "GstStructure" - } - } - }, - "multiudpsink": { - "author": "Wim Taymans ", - "description": "Send data over the network via UDP to one or multiple recipients which can be added or removed at runtime using action signals", - "hierarchy": [ - "GstMultiUDPSink", - "GstBaseSink", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Sink/Network", - "long-name": "UDP packet sender", - "name": "multiudpsink", - "pad-templates": { - "sink": { - "caps": "ANY", - "direction": "sink", - "presence": "always" - } - }, - "properties": { - "async": { - "blurb": "Go asynchronously to PAUSED", + "rtcp-mtu": { + "blurb": "The maximum size of the RTCP packets", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "1400", + "max": "32767", + "min": "16", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "auto-multicast": { - "blurb": "Automatically join/leave the multicast groups, FALSE means user has to do it himself", + "rtcp-reduced-size": { + "blurb": "Use Reduced Size RTCP for feedback packets", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "bind-address": { - "blurb": "Address to bind the socket to", + "rtcp-rr-bandwidth": { + "blurb": "The RTCP bandwidth used for receivers in bits per second (-1 = default)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "NULL", - "type-name": "gchararray", + "controllable": false, + "default": "-1", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "bind-port": { - "blurb": "Port to bind the socket to", + "rtcp-rs-bandwidth": { + "blurb": "The RTCP bandwidth used for senders in bits per second (-1 = default)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "gint", + "controllable": false, + "default": "-1", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "blocksize": { - "blurb": "Size in bytes to pull per buffer (0 = default)", + "rtp-profile": { + "blurb": "RTP profile to use for this session", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", + "controllable": false, + "default": "avp (1)", + "mutable": "null", + "readable": true, + "type": "GstRTPProfile", "writable": true }, - "buffer-size": { - "blurb": "Size of the kernel send buffer in bytes, 0=default", + "sdes": { + "blurb": "The SDES items of this session", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "0", - "type-name": "gint", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstStructure", "writable": true }, - "bytes-served": { - "blurb": "Total number of bytes sent to all clients", + "sources": { + "blurb": "An array of all known sources in the session", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GValueArray", "writable": false }, - "bytes-to-serve": { - "blurb": "Number of bytes received to serve to clients", + "stats": { + "blurb": "Various statistics", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", + "controllable": false, + "default": "application/x-rtp-session-stats, rtx-drop-count=(uint)0, sent-nack-count=(uint)0, recv-nack-count=(uint)0, source-stats=(GValueArray)< >;", + "mutable": "null", + "readable": true, + "type": "GstStructure", "writable": false + } + }, + "signals": { + "get-source-by-ssrc": { + "action": true, + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "RTPSource", + "when": "last" + }, + "on-app-rtcp": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + }, + { + "name": "arg2", + "type": "gchararray" + }, + { + "name": "arg3", + "type": "GstBuffer" + } + ], + "return-type": "void", + "when": "last" + }, + "on-bye-ssrc": { + "args": [ + { + "name": "arg0", + "type": "RTPSource" + } + ], + "return-type": "void", + "when": "last" + }, + "on-bye-timeout": { + "args": [ + { + "name": "arg0", + "type": "RTPSource" + } + ], + "return-type": "void", + "when": "last" + }, + "on-feedback-rtcp": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + }, + { + "name": "arg2", + "type": "guint" + }, + { + "name": "arg3", + "type": "guint" + }, + { + "name": "arg4", + "type": "GstBuffer" + } + ], + "return-type": "void", + "when": "last" + }, + "on-new-sender-ssrc": { + "args": [ + { + "name": "arg0", + "type": "RTPSource" + } + ], + "return-type": "void", + "when": "last" + }, + "on-new-ssrc": { + "args": [ + { + "name": "arg0", + "type": "RTPSource" + } + ], + "return-type": "void", + "when": "last" + }, + "on-receiving-rtcp": { + "args": [ + { + "name": "arg0", + "type": "GstBuffer" + } + ], + "return-type": "void", + "when": "last" }, - "clients": { - "blurb": "A comma separated list of host:port pairs with destinations", - "construct": false, - "construct-only": false, - "default": "", - "type-name": "gchararray", - "writable": true + "on-sender-ssrc-active": { + "args": [ + { + "name": "arg0", + "type": "RTPSource" + } + ], + "return-type": "void", + "when": "last" }, - "close-socket": { - "blurb": "Close socket if passed as property on state change", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true + "on-sender-timeout": { + "args": [ + { + "name": "arg0", + "type": "RTPSource" + } + ], + "return-type": "void", + "when": "last" }, - "enable-last-sample": { - "blurb": "Enable the last-sample property", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true + "on-sending-nacks": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + }, + { + "name": "arg2", + "type": "GArray" + }, + { + "name": "arg3", + "type": "GstBuffer" + } + ], + "return-type": "guint", + "when": "last" }, - "force-ipv4": { - "blurb": "Forcing the use of an IPv4 socket (DEPRECATED, has no effect anymore)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true + "on-sending-rtcp": { + "args": [ + { + "name": "arg0", + "type": "GstBuffer" + }, + { + "name": "arg1", + "type": "gboolean" + } + ], + "return-type": "gboolean", + "when": "last" }, - "last-sample": { - "blurb": "The last sample received in the sink", - "construct": false, - "construct-only": false, - "type-name": "GstSample", - "writable": false + "on-ssrc-active": { + "args": [ + { + "name": "arg0", + "type": "RTPSource" + } + ], + "return-type": "void", + "when": "last" }, - "loop": { - "blurb": "Used for setting the multicast loop parameter. TRUE = enable, FALSE = disable", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true + "on-ssrc-collision": { + "args": [ + { + "name": "arg0", + "type": "RTPSource" + } + ], + "return-type": "void", + "when": "last" }, - "max-bitrate": { - "blurb": "The maximum bits per second to render (0 = disabled)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true + "on-ssrc-sdes": { + "args": [ + { + "name": "arg0", + "type": "RTPSource" + } + ], + "return-type": "void", + "when": "last" }, - "max-lateness": { - "blurb": "Maximum number of nanoseconds that a buffer can be late before it is dropped (-1 unlimited)", - "construct": false, - "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", - "writable": true + "on-ssrc-validated": { + "args": [ + { + "name": "arg0", + "type": "RTPSource" + } + ], + "return-type": "void", + "when": "last" }, - "multicast-iface": { - "blurb": "The network interface on which to join the multicast group", - "construct": false, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": true + "on-timeout": { + "args": [ + { + "name": "arg0", + "type": "RTPSource" + } + ], + "return-type": "void", + "when": "last" }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true + "send-rtcp": { + "action": true, + "args": [ + { + "name": "arg0", + "type": "guint64" + } + ], + "return-type": "void", + "when": "last" }, - "parent": { - "blurb": "The parent of the object", + "send-rtcp-full": { + "action": true, + "args": [ + { + "name": "arg0", + "type": "guint64" + } + ], + "return-type": "gboolean", + "when": "last" + } + } + }, + "RTPSource": { + "hierarchy": [ + "RTPSource", + "GObject" + ], + "kind": "object", + "properties": { + "disable-rtcp": { + "blurb": "Disable sending RTCP packets for this source", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "processing-deadline": { - "blurb": "Maximum processing deadline in nanoseconds", + "is-csrc": { + "blurb": "If this SSRC is acting as a contributing source", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "20000000", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", - "writable": true + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": false }, - "qos": { - "blurb": "Generate Quality-of-Service events upstream", + "is-sender": { + "blurb": "If this SSRC is a sender", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", - "writable": true + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": false }, - "qos-dscp": { - "blurb": "Quality of Service, differentiated services code point (-1 default)", + "is-validated": { + "blurb": "If this SSRC is validated", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "-1", - "max": "63", - "min": "-1", - "type-name": "gint", - "writable": true + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": false }, - "render-delay": { - "blurb": "Additional render delay of the sink in nanoseconds", + "max-dropout-time": { + "blurb": "The maximum time (milliseconds) of missing packets tolerated.", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "18446744073709551615", + "controllable": false, + "default": "60000", + "max": "-1", "min": "0", - "type-name": "guint64", - "writable": true - }, - "send-duplicates": { - "blurb": "When a distination/port pair is added multiple times, send packets multiple times as well", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "socket": { - "blurb": "Socket to use for UDP sending. (NULL == allocate)", + "max-misorder-time": { + "blurb": "The maximum time (milliseconds) of misordered packets tolerated.", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GSocket", + "controllable": false, + "default": "2000", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "socket-v6": { - "blurb": "Socket to use for UDPv6 sending. (NULL == allocate)", + "probation": { + "blurb": "Consecutive packet sequence numbers to accept the source", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GSocket", + "controllable": false, + "default": "2", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "stats": { - "blurb": "Sink Statistics", + "sdes": { + "blurb": "The SDES information for this source", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "application/x-gst-base-sink-stats, average-rate=(double)0, dropped=(guint64)0, rendered=(guint64)0;", - "type-name": "GstStructure", + "controllable": false, + "default": "application/x-rtp-source-sdes;", + "mutable": "null", + "readable": true, + "type": "GstStructure", "writable": false }, - "sync": { - "blurb": "Sync on the clock", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "throttle-time": { - "blurb": "The time to keep between rendered buffers (0 = disabled)", + "ssrc": { + "blurb": "The SSRC of this source", + "conditionally-available": false, "construct": false, - "construct-only": false, + "construct-only": true, + "controllable": false, "default": "0", - "max": "18446744073709551615", + "max": "-1", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "ts-offset": { - "blurb": "Timestamp offset in nanoseconds", + "stats": { + "blurb": "The stats of this source", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "-9223372036854775808", - "type-name": "gint64", - "writable": true + "controllable": false, + "default": "application/x-rtp-source-stats, ssrc=(uint)0, internal=(boolean)false, validated=(boolean)false, received-bye=(boolean)false, is-csrc=(boolean)false, is-sender=(boolean)false, seqnum-base=(int)-1, clock-rate=(int)-1, octets-sent=(guint64)0, packets-sent=(guint64)0, octets-received=(guint64)0, packets-received=(guint64)0, bytes-received=(guint64)0, bitrate=(guint64)0, packets-lost=(int)0, jitter=(uint)0, sent-pli-count=(uint)0, recv-pli-count=(uint)0, sent-fir-count=(uint)0, recv-fir-count=(uint)0, sent-nack-count=(uint)0, recv-nack-count=(uint)0, recv-packet-rate=(uint)0, have-sr=(boolean)false, sr-ntptime=(guint64)0, sr-rtptime=(uint)0, sr-octet-count=(uint)0, sr-packet-count=(uint)0, sent-rb=(boolean)false, sent-rb-fractionlost=(uint)0, sent-rb-packetslost=(int)0, sent-rb-exthighestseq=(uint)0, sent-rb-jitter=(uint)0, sent-rb-lsr=(uint)0, sent-rb-dlsr=(uint)0, have-rb=(boolean)false, rb-fractionlost=(uint)0, rb-packetslost=(int)0, rb-exthighestseq=(uint)0, rb-jitter=(uint)0, rb-lsr=(uint)0, rb-dlsr=(uint)0, rb-round-trip=(uint)0;", + "mutable": "null", + "readable": true, + "type": "GstStructure", + "writable": false + } + } + } + }, + "package": "GStreamer Good Plug-ins", + "source": "gst-plugins-good", + "tracers": {}, + "url": "Unknown package origin" + }, + "rtsp": { + "description": "transfer data via RTSP", + "elements": { + "rtpdec": { + "author": "Wim Taymans ", + "description": "Accepts raw RTP and RTCP packets and sends them forward", + "hierarchy": [ + "GstRTPDec", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Parser/Network", + "long-name": "RTP Decoder", + "pad-templates": { + "recv_rtcp_sink_%%u": { + "caps": "application/x-rtcp:\n", + "direction": "sink", + "presence": "request" }, - "ttl": { - "blurb": "Used for setting the unicast TTL parameter", - "construct": false, - "construct-only": false, - "default": "64", - "max": "255", - "min": "0", - "type-name": "gint", - "writable": true + "recv_rtp_sink_%%u": { + "caps": "application/x-rtp:\n", + "direction": "sink", + "presence": "request" }, - "ttl-mc": { - "blurb": "Used for setting the multicast TTL parameter", + "recv_rtp_src_%%u_%%u_%%u": { + "caps": "application/x-rtp:\n", + "direction": "src", + "presence": "sometimes" + }, + "rtcp_src_%%u": { + "caps": "application/x-rtcp:\n", + "direction": "src", + "presence": "request" + } + }, + "properties": { + "latency": { + "blurb": "Amount of ms to buffer", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "1", - "max": "255", + "controllable": false, + "default": "200", + "max": "-1", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true - }, - "used-socket": { - "blurb": "Socket currently in use for UDP sending. (NULL == no socket)", - "construct": false, - "construct-only": false, - "type-name": "GSocket", - "writable": false - }, - "used-socket-v6": { - "blurb": "Socket currently in use for UDPv6 sending. (NULL == no socket)", - "construct": false, - "construct-only": false, - "type-name": "GSocket", - "writable": false } }, "rank": "none", "signals": { - "add": { + "clear-pt-map": { + "args": [], + "return-type": "void", + "when": "last" + }, + "on-bye-ssrc": { "args": [ - "gchararray", - "gint" + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + } ], - "retval": "void" + "return-type": "void", + "when": "last" }, - "clear": { - "args": [], - "retval": "void" + "on-bye-timeout": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" }, - "client-added": { + "on-new-ssrc": { "args": [ - "gchararray", - "gint" + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + } ], - "retval": "void" + "return-type": "void", + "when": "last" }, - "client-removed": { + "on-ssrc-collision": { "args": [ - "gchararray", - "gint" + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + } ], - "retval": "void" + "return-type": "void", + "when": "last" }, - "get-stats": { + "on-ssrc-validated": { "args": [ - "gchararray", - "gint" + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + } ], - "retval": "GstStructure" + "return-type": "void", + "when": "last" }, - "remove": { + "on-timeout": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + } + ], + "return-type": "void", + "when": "last" + }, + "request-pt-map": { "args": [ - "gchararray", - "gint" + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "guint" + } ], - "retval": "void" + "return-type": "GstCaps", + "when": "last" } } }, - "udpsink": { - "author": "Wim Taymans ", - "description": "Send data over the network via UDP", + "rtspsrc": { + "author": "Wim Taymans , Thijs Vermeir , Lutz Mueller ", + "description": "Receive data over the network via RTSP (RFC 2326)", "hierarchy": [ - "GstUDPSink", - "GstMultiUDPSink", - "GstBaseSink", + "GstRTSPSrc", + "GstBin", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Sink/Network", - "long-name": "UDP packet sender", - "name": "udpsink", + "interfaces": [ + "GstChildProxy", + "GstURIHandler" + ], + "klass": "Source/Network", + "long-name": "RTSP packet receiver", "pad-templates": { - "sink": { - "caps": "ANY", - "direction": "sink", - "presence": "always" + "stream_%%u": { + "caps": "application/x-rtp:\napplication/x-rdt:\n", + "direction": "src", + "presence": "sometimes" } }, "properties": { - "async": { - "blurb": "Go asynchronously to PAUSED", + "backchannel": { + "blurb": "The type of backchannel to setup. Default is 'none'.", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "none (0)", + "mutable": "null", + "readable": true, + "type": "GstRTSPBackchannel", + "writable": true + }, + "buffer-mode": { + "blurb": "Control the buffering algorithm in use", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "auto (3)", + "mutable": "null", + "readable": true, + "type": "GstRTSPSrcBufferMode", + "writable": true + }, + "connection-speed": { + "blurb": "Network connection speed in kbps (0 = unknown)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "18446744073709551", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint64", + "writable": true + }, + "debug": { + "blurb": "Dump request and response messages to stdout(DEPRECATED: Printed all RTSP message to gstreamer log as 'log' level)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "default-rtsp-version": { + "blurb": "The RTSP version that should be tried first when negotiating version.", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "1-0 (16)", + "mutable": "null", + "readable": true, + "type": "GstRTSPVersion", + "writable": true + }, + "do-retransmission": { + "blurb": "Ask the server to retransmit lost packets", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "auto-multicast": { - "blurb": "Automatically join/leave the multicast groups, FALSE means user has to do it himself", + "do-rtcp": { + "blurb": "Send RTCP packets, disable for old incompatible server.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "bind-address": { - "blurb": "Address to bind the socket to", + "do-rtsp-keep-alive": { + "blurb": "Send RTSP keep alive packets, disable for old incompatible server.", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "NULL", - "type-name": "gchararray", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "bind-port": { - "blurb": "Port to bind the socket to", + "drop-on-latency": { + "blurb": "Tells the jitterbuffer to never exceed the given latency in size", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "65535", - "min": "0", - "type-name": "gint", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "blocksize": { - "blurb": "Size in bytes to pull per buffer (0 = default)", + "is-live": { + "blurb": "Whether to act as a live source", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "4096", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "latency": { + "blurb": "Amount of ms to buffer", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "2000", "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "buffer-size": { - "blurb": "Size of the kernel send buffer in bytes, 0=default", + "location": { + "blurb": "Location of the RTSP url to read", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": true + }, + "max-rtcp-rtp-time-diff": { + "blurb": "Maximum amount of time in ms that the RTP time in RTCP SRs is allowed to be ahead (-1 disabled)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "1000", "max": "2147483647", - "min": "0", - "type-name": "gint", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "bytes-served": { - "blurb": "Total number of bytes sent to all clients", + "max-ts-offset": { + "blurb": "The maximum absolute value of the time offset in (nanoseconds). Note, if the ntp-sync parameter is set the default value is changed to 0 (no limit)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "18446744073709551615", + "controllable": false, + "default": "3000000000", + "max": "9223372036854775807", "min": "0", - "type-name": "guint64", - "writable": false + "mutable": "null", + "readable": true, + "type": "gint64", + "writable": true }, - "bytes-to-serve": { - "blurb": "Number of bytes received to serve to clients", + "max-ts-offset-adjustment": { + "blurb": "The maximum number of nanoseconds per frame that time stamp offsets may be adjusted (0 = no limit).", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", - "writable": false + "mutable": "null", + "readable": true, + "type": "guint64", + "writable": true }, - "clients": { - "blurb": "A comma separated list of host:port pairs with destinations", + "multicast-iface": { + "blurb": "The network interface on which to join the multicast group", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "localhost:5004", - "type-name": "gchararray", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "close-socket": { - "blurb": "Close socket if passed as property on state change", + "nat-method": { + "blurb": "Method to use for traversing firewalls and NAT", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "dummy (1)", + "mutable": "null", + "readable": true, + "type": "GstRTSPNatMethod", "writable": true }, - "enable-last-sample": { - "blurb": "Enable the last-sample property", + "ntp-sync": { + "blurb": "Synchronize received streams to the NTP clock", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "force-ipv4": { - "blurb": "Forcing the use of an IPv4 socket (DEPRECATED, has no effect anymore)", + "ntp-time-source": { + "blurb": "NTP time source for RTCP packets", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "ntp (0)", + "mutable": "null", + "readable": true, + "type": "GstRTSPSrcNtpTimeSource", "writable": true }, - "host": { - "blurb": "The host/IP/Multicast group to send the packets to", + "onvif-mode": { + "blurb": "Act as an ONVIF client", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "localhost", - "type-name": "gchararray", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "last-sample": { - "blurb": "The last sample received in the sink", + "onvif-rate-control": { + "blurb": "When in onvif-mode, whether to set Rate-Control to yes or no", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstSample", - "writable": false + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true }, - "loop": { - "blurb": "Used for setting the multicast loop parameter. TRUE = enable, FALSE = disable", + "port-range": { + "blurb": "Client port range that can be used to receive RTP and RTCP data, eg. 3000-3005 (NULL = no restrictions)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "max-bitrate": { - "blurb": "The maximum bits per second to render (0 = disabled)", + "probation": { + "blurb": "Consecutive packet sequence numbers to accept the source", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "18446744073709551615", + "controllable": false, + "default": "2", + "max": "-1", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "max-lateness": { - "blurb": "Maximum number of nanoseconds that a buffer can be late before it is dropped (-1 unlimited)", + "protocols": { + "blurb": "Allowed lower transport protocols", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "18446744073709551615", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", + "controllable": false, + "default": "tcp+udp-mcast+udp", + "mutable": "null", + "readable": true, + "type": "GstRTSPLowerTrans", "writable": true }, - "multicast-iface": { - "blurb": "The network interface on which to join the multicast group", + "proxy": { + "blurb": "Proxy settings for HTTP tunneling. Format: [http://][user:passwd@]host[:port]", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "name": { - "blurb": "The name of the object", - "construct": true, + "proxy-id": { + "blurb": "HTTP proxy URI user id for authentication", + "conditionally-available": false, + "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "proxy-pw": { + "blurb": "HTTP proxy URI user password for authentication", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "port": { - "blurb": "The port to send the packets to", + "retry": { + "blurb": "Max number of retries when allocating RTP ports.", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "5004", + "controllable": false, + "default": "20", "max": "65535", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "processing-deadline": { - "blurb": "Maximum processing deadline in nanoseconds", + "rfc7273-sync": { + "blurb": "Synchronize received streams to the RFC7273 clock (requires clock and offset to be provided)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "20000000", - "max": "18446744073709551615", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "rtp-blocksize": { + "blurb": "RTP package size to suggest to server (0 = disabled)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "65536", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "qos": { - "blurb": "Generate Quality-of-Service events upstream", + "sdes": { + "blurb": "The SDES items of this session", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstStructure", "writable": true }, - "qos-dscp": { - "blurb": "Quality of Service, differentiated services code point (-1 default)", + "short-header": { + "blurb": "Only send the basic RTSP headers for broken encoders", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "-1", - "max": "63", - "min": "-1", - "type-name": "gint", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "render-delay": { - "blurb": "Additional render delay of the sink in nanoseconds", + "tcp-timeout": { + "blurb": "Fail after timeout microseconds on TCP connections (0 = disabled)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", + "controllable": false, + "default": "20000000", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, - "send-duplicates": { - "blurb": "When a distination/port pair is added multiple times, send packets multiple times as well", + "teardown-timeout": { + "blurb": "When transitioning PAUSED-READY, allow up to timeout (in nanoseconds) delay in order to send teardown (0 = disabled)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "100000000", + "max": "18446744073709551615", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, - "socket": { - "blurb": "Socket to use for UDP sending. (NULL == allocate)", + "timeout": { + "blurb": "Retry TCP transport after UDP timeout microseconds (0 = disabled)", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GSocket", + "controllable": false, + "default": "5000000", + "max": "18446744073709551615", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, - "socket-v6": { - "blurb": "Socket to use for UDPv6 sending. (NULL == allocate)", + "tls-database": { + "blurb": "TLS database with anchor certificate authorities used to validate the server certificate", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GSocket", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GTlsDatabase", "writable": true }, - "stats": { - "blurb": "Sink Statistics", + "tls-interaction": { + "blurb": "A GTlsInteraction object to prompt the user for password or certificate", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "application/x-gst-base-sink-stats, average-rate=(double)0, dropped=(guint64)0, rendered=(guint64)0;", - "type-name": "GstStructure", - "writable": false + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GTlsInteraction", + "writable": true }, - "sync": { - "blurb": "Sync on the clock", + "tls-validation-flags": { + "blurb": "TLS certificate validation flags used to validate the server certificate", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "validate-all", + "mutable": "null", + "readable": true, + "type": "GTlsCertificateFlags", "writable": true }, - "throttle-time": { - "blurb": "The time to keep between rendered buffers (0 = disabled)", + "udp-buffer-size": { + "blurb": "Size of the kernel UDP receive buffer in bytes, 0=default", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "18446744073709551615", + "controllable": false, + "default": "524288", + "max": "2147483647", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "ts-offset": { - "blurb": "Timestamp offset in nanoseconds", + "udp-reconnect": { + "blurb": "Reconnect to the server if RTSP connection is closed when doing UDP", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "-9223372036854775808", - "type-name": "gint64", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "ttl": { - "blurb": "Used for setting the unicast TTL parameter", + "use-pipeline-clock": { + "blurb": "Use the pipeline running-time to set the NTP time in the RTCP SR messages(DEPRECATED: Use ntp-time-source property)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "64", - "max": "255", - "min": "0", - "type-name": "gint", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "ttl-mc": { - "blurb": "Used for setting the multicast TTL parameter", + "user-agent": { + "blurb": "The User-Agent string to send to the server", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "1", - "max": "255", - "min": "0", - "type-name": "gint", + "controllable": false, + "default": "GStreamer/1.18.6", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "used-socket": { - "blurb": "Socket currently in use for UDP sending. (NULL == no socket)", + "user-id": { + "blurb": "RTSP location URI user id for authentication", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GSocket", - "writable": false + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": true }, - "used-socket-v6": { - "blurb": "Socket currently in use for UDPv6 sending. (NULL == no socket)", + "user-pw": { + "blurb": "RTSP location URI user password for authentication", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GSocket", - "writable": false + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": true } }, "rank": "none", "signals": { - "add": { + "accept-certificate": { "args": [ - "gchararray", - "gint" + { + "name": "arg0", + "type": "GTlsConnection" + }, + { + "name": "arg1", + "type": "GTlsCertificate" + }, + { + "name": "arg2", + "type": "GTlsCertificateFlags" + } ], - "retval": "void" + "return-type": "gboolean", + "when": "last" }, - "clear": { - "args": [], - "retval": "void" + "before-send": { + "args": [ + { + "name": "arg0", + "type": "GstRTSPMessage" + } + ], + "return-type": "gboolean", + "when": "last" }, - "client-added": { + "get-parameter": { + "action": true, "args": [ - "gchararray", - "gint" + { + "name": "arg0", + "type": "gchararray" + }, + { + "name": "arg1", + "type": "gchararray" + }, + { + "name": "arg2", + "type": "GstPromise" + } ], - "retval": "void" + "return-type": "gboolean", + "when": "last" }, - "client-removed": { + "get-parameters": { + "action": true, "args": [ - "gchararray", - "gint" + { + "name": "arg0", + "type": "GStrv" + }, + { + "name": "arg1", + "type": "gchararray" + }, + { + "name": "arg2", + "type": "GstPromise" + } ], - "retval": "void" + "return-type": "gboolean", + "when": "last" }, - "get-stats": { + "handle-request": { + "args": [ + { + "name": "arg0", + "type": "gpointer" + }, + { + "name": "arg1", + "type": "gpointer" + } + ], + "return-type": "void" + }, + "new-manager": { + "args": [ + { + "name": "arg0", + "type": "GstElement" + } + ], + "return-type": "void", + "when": "first" + }, + "on-sdp": { + "args": [ + { + "name": "arg0", + "type": "GstSDPMessage" + } + ], + "return-type": "void" + }, + "push-backchannel-buffer": { + "action": true, + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "GstSample" + } + ], + "return-type": "GstFlowReturn", + "when": "last" + }, + "request-rtcp-key": { + "args": [ + { + "name": "arg0", + "type": "guint" + } + ], + "return-type": "GstCaps", + "when": "last" + }, + "select-stream": { + "args": [ + { + "name": "arg0", + "type": "guint" + }, + { + "name": "arg1", + "type": "GstCaps" + } + ], + "return-type": "gboolean", + "when": "last" + }, + "set-parameter": { + "action": true, "args": [ - "gchararray", - "gint" + { + "name": "arg0", + "type": "gchararray" + }, + { + "name": "arg1", + "type": "gchararray" + }, + { + "name": "arg2", + "type": "gchararray" + }, + { + "name": "arg3", + "type": "GstPromise" + } ], - "retval": "GstStructure" + "return-type": "gboolean", + "when": "last" + } + } + } + }, + "filename": "gstrtsp", + "license": "LGPL", + "other-types": { + "GstRTSPBackchannel": { + "kind": "enum", + "values": [ + { + "desc": "No backchannel", + "name": "none", + "value": "0" + }, + { + "desc": "ONVIF audio backchannel", + "name": "onvif", + "value": "1" + } + ] + }, + "GstRTSPNatMethod": { + "kind": "enum", + "values": [ + { + "desc": "None", + "name": "none", + "value": "0" + }, + { + "desc": "Send Dummy packets", + "name": "dummy", + "value": "1" + } + ] + }, + "GstRTSPSrcBufferMode": { + "kind": "enum", + "values": [ + { + "desc": "Only use RTP timestamps", + "name": "none", + "value": "0" + }, + { + "desc": "Slave receiver to sender clock", + "name": "slave", + "value": "1" + }, + { + "desc": "Do low/high watermark buffering", + "name": "buffer", + "value": "2" + }, + { + "desc": "Choose mode depending on stream live", + "name": "auto", + "value": "3" + }, + { + "desc": "Synchronized sender and receiver clocks", + "name": "synced", + "value": "4" + } + ] + }, + "GstRTSPSrcNtpTimeSource": { + "kind": "enum", + "values": [ + { + "desc": "NTP time based on realtime clock", + "name": "ntp", + "value": "0" + }, + { + "desc": "UNIX time based on realtime clock", + "name": "unix", + "value": "1" + }, + { + "desc": "Running time based on pipeline clock", + "name": "running-time", + "value": "2" + }, + { + "desc": "Pipeline clock time", + "name": "clock-time", + "value": "3" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", + "source": "gst-plugins-good", + "tracers": {}, + "url": "Unknown package origin" + }, + "shapewipe": { + "description": "Shape Wipe transition filter", + "elements": { + "shapewipe": { + "author": "Sebastian Dröge ", + "description": "Adds a shape wipe transition to a video stream", + "hierarchy": [ + "GstShapeWipe", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Filter/Editor/Video", + "long-name": "Shape Wipe transition filter", + "pad-templates": { + "mask_sink": { + "caps": "video/x-raw:\n format: GRAY8\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: 0/1\nvideo/x-raw:\n format: GRAY16_LE\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: 0/1\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "video/x-raw:\n format: { AYUV, ARGB, BGRA, ABGR, RGBA }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + }, + "video_sink": { + "caps": "video/x-raw:\n format: { AYUV, ARGB, BGRA, ABGR, RGBA }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "sink", + "presence": "always" + } + }, + "properties": { + "border": { + "blurb": "Border of the mask", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": true, + "default": "0", + "max": "1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gfloat", + "writable": true }, - "remove": { - "args": [ - "gchararray", - "gint" - ], - "retval": "void" + "position": { + "blurb": "Position of the mask", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": true, + "default": "0", + "max": "1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gfloat", + "writable": true } - } - }, - "udpsrc": { - "author": "Wim Taymans , Thijs Vermeir ", - "description": "Receive data over the network via UDP", + }, + "rank": "none" + } + }, + "filename": "gstshapewipe", + "license": "LGPL", + "other-types": {}, + "package": "GStreamer Good Plug-ins", + "source": "gst-plugins-good", + "tracers": {}, + "url": "Unknown package origin" + }, + "shout2": { + "description": "Sends data to an icecast server using libshout2", + "elements": { + "shout2send": { + "author": "Wim Taymans , Pedro Corte-Real , Zaheer Abbas Merali ", + "description": "Sends data to an icecast server", "hierarchy": [ - "GstUDPSrc", - "GstPushSrc", - "GstBaseSrc", + "GstShout2send", + "GstBaseSink", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Source/Network", - "long-name": "UDP packet receiver", - "name": "udpsrc", + "interfaces": [ + "GstTagSetter" + ], + "klass": "Sink/Network", + "long-name": "Icecast network sink", "pad-templates": { - "src": { - "caps": "ANY", - "direction": "src", + "sink": { + "caps": "application/ogg:\naudio/ogg:\nvideo/ogg:\naudio/mpeg:\n mpegversion: 1\n layer: [ 1, 3 ]\nvideo/webm:\naudio/webm:\n", + "direction": "sink", "presence": "always" } }, "properties": { - "address": { - "blurb": "Address to receive packets for. This is equivalent to the multicast-group property for now", + "description": { + "blurb": "description", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0.0.0.0", - "type-name": "gchararray", + "controllable": false, + "default": "", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "auto-multicast": { - "blurb": "Automatically join/leave multicast groups", + "genre": { + "blurb": "genre", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "blocksize": { - "blurb": "Size in bytes to read per buffer (-1 = default)", + "ip": { + "blurb": "IP address or hostname", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", + "controllable": false, + "default": "127.0.0.1", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "buffer-size": { - "blurb": "Size of the kernel receive buffer in bytes, 0=default", + "mount": { + "blurb": "mount", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "0", - "type-name": "gint", + "controllable": false, + "default": "", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "caps": { - "blurb": "The caps of the source pad", + "password": { + "blurb": "password", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstCaps", + "controllable": false, + "default": "hackme", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "close-socket": { - "blurb": "Close socket if passed as property on state change", + "port": { + "blurb": "port", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "8000", + "max": "65535", + "min": "1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "do-timestamp": { - "blurb": "Apply current stream time to buffers", + "protocol": { + "blurb": "Connection Protocol to use", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "http (3)", + "mutable": "null", + "readable": true, + "type": "GstShout2SendProtocol", "writable": true }, - "loop": { - "blurb": "Used for setting the multicast loop parameter. TRUE = enable, FALSE = disable", + "public": { + "blurb": "If the stream should be listed on the server's stream directory", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "mtu": { - "blurb": "Maximum expected packet size. This directly defines the allocationsize of the receive buffer pool.", + "streamname": { + "blurb": "name of the stream", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "1492", - "max": "2147483647", - "min": "0", - "type-name": "guint", + "controllable": false, + "default": "", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "multicast-group": { - "blurb": "The Address of multicast group to join. (DEPRECATED: Use address property instead)", + "timeout": { + "blurb": "Max amount of time to wait for network activity, in milliseconds", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0.0.0.0", - "type-name": "gchararray", + "controllable": false, + "default": "10000", + "max": "-1", + "min": "1", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "multicast-iface": { - "blurb": "The network interface on which to join the multicast group.This allows multiple interfaces separated by comma. (\"eth0,eth1\")", + "url": { + "blurb": "the stream's homepage URL", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "NULL", - "type-name": "gchararray", + "controllable": false, + "default": "", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "name": { - "blurb": "The name of the object", - "construct": true, + "username": { + "blurb": "username", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "default": "source", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true + } + }, + "rank": "none", + "signals": { + "connection-problem": { + "args": [ + { + "name": "arg0", + "type": "gint" + } + ], + "return-type": "void", + "when": "cleanup" + } + } + } + }, + "filename": "gstshout2", + "license": "LGPL", + "other-types": { + "GstShout2SendProtocol": { + "kind": "enum", + "values": [ + { + "desc": "Xaudiocast Protocol (icecast 1.3.x)", + "name": "xaudiocast", + "value": "1" + }, + { + "desc": "Icy Protocol (ShoutCast)", + "name": "icy", + "value": "2" + }, + { + "desc": "Http Protocol (icecast 2.x)", + "name": "http", + "value": "3" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", + "source": "gst-plugins-good", + "tracers": {}, + "url": "Unknown package origin" + }, + "smpte": { + "description": "Apply the standard SMPTE transitions on video images", + "elements": { + "smpte": { + "author": "Wim Taymans ", + "description": "Apply the standard SMPTE transitions on video images", + "hierarchy": [ + "GstSMPTE", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Filter/Editor/Video", + "long-name": "SMPTE transitions", + "pad-templates": { + "sink1": { + "caps": "video/x-raw:\n format: I420\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "sink", + "presence": "always" }, - "num-buffers": { - "blurb": "Number of buffers to output before sending EOS (-1 = unlimited)", + "sink2": { + "caps": "video/x-raw:\n format: I420\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "video/x-raw:\n format: I420\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "border": { + "blurb": "The border width of the transition", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "-1", + "controllable": false, + "default": "0", "max": "2147483647", - "min": "-1", - "type-name": "gint", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "depth": { + "blurb": "Depth of the mask in bits", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "16", + "max": "24", + "min": "1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "port": { - "blurb": "The port to receive the packets from, 0=allocate", + "duration": { + "blurb": "Duration of the transition effect in nanoseconds", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "5004", - "max": "65535", + "controllable": false, + "default": "1000000000", + "max": "18446744073709551615", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, - "retrieve-sender-address": { - "blurb": "Whether to retrieve the sender address and add it to buffers as meta. Disabling this might result in minor performance improvements in certain scenarios", + "invert": { + "blurb": "Invert transition mask", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "reuse": { - "blurb": "Enable reuse of the port", + "type": { + "blurb": "The type of transition to use", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "bar-wipe-lr (1)", + "mutable": "null", + "readable": true, + "type": "GstSMPTETransitionType", "writable": true + } + }, + "rank": "none" + }, + "smptealpha": { + "author": "Wim Taymans ", + "description": "Apply the standard SMPTE transitions as alpha on video images", + "hierarchy": [ + "GstSMPTEAlpha", + "GstVideoFilter", + "GstBaseTransform", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Filter/Editor/Video", + "long-name": "SMPTE transitions", + "pad-templates": { + "sink": { + "caps": "video/x-raw:\n format: I420\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: YV12\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: AYUV\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: ARGB\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: BGRA\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: RGBA\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: ARGB\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "sink", + "presence": "always" }, - "skip-first-bytes": { - "blurb": "number of bytes to skip for each udp packet", + "src": { + "caps": "video/x-raw:\n format: AYUV\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: ARGB\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: BGRA\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: RGBA\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: ARGB\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "border": { + "blurb": "The border width of the transition", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "2147483647", "min": "0", - "type-name": "gint", - "writable": true - }, - "socket": { - "blurb": "Socket to use for UDP reception. (NULL == allocate)", - "construct": false, - "construct-only": false, - "type-name": "GSocket", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "timeout": { - "blurb": "Post a message after timeout nanoseconds (0 = disabled)", + "depth": { + "blurb": "Depth of the mask in bits", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", + "controllable": false, + "default": "16", + "max": "24", + "min": "1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "typefind": { - "blurb": "Run typefind before negotiating (deprecated, non-functional)", + "invert": { + "blurb": "Invert transition mask", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "uri": { - "blurb": "URI in the form of udp://multicast_group:port", + "position": { + "blurb": "Position of the transition effect", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "udp://0.0.0.0:5004", - "type-name": "gchararray", + "controllable": true, + "default": "0", + "max": "1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, - "used-socket": { - "blurb": "Socket currently in use for UDP reception. (NULL = no socket)", + "type": { + "blurb": "The type of transition to use", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GSocket", - "writable": false + "controllable": false, + "default": "bar-wipe-lr (1)", + "mutable": "null", + "readable": true, + "type": "GstSMPTEAlphaTransitionType", + "writable": true } }, "rank": "none" } }, - "filename": "gstudp", + "filename": "gstsmpte", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": { + "GstSMPTEAlphaTransitionType": { + "kind": "enum", + "values": [ + { + "desc": "A bar moves from left to right", + "name": "bar-wipe-lr", + "value": "1" + }, + { + "desc": "A bar moves from top to bottom", + "name": "bar-wipe-tb", + "value": "2" + }, + { + "desc": "A box expands from the upper-left corner to the lower-right corner", + "name": "box-wipe-tl", + "value": "3" + }, + { + "desc": "A box expands from the upper-right corner to the lower-left corner", + "name": "box-wipe-tr", + "value": "4" + }, + { + "desc": "A box expands from the lower-right corner to the upper-left corner", + "name": "box-wipe-br", + "value": "5" + }, + { + "desc": "A box expands from the lower-left corner to the upper-right corner", + "name": "box-wipe-bl", + "value": "6" + }, + { + "desc": "A box shape expands from each of the four corners toward the center", + "name": "four-box-wipe-ci", + "value": "7" + }, + { + "desc": "A box shape expands from the center of each quadrant toward the corners of each quadrant", + "name": "four-box-wipe-co", + "value": "8" + }, + { + "desc": "A central, vertical line splits and expands toward the left and right edges", + "name": "barndoor-v", + "value": "21" + }, + { + "desc": "A central, horizontal line splits and expands toward the top and bottom edges", + "name": "barndoor-h", + "value": "22" + }, + { + "desc": "A box expands from the top edge's midpoint to the bottom corners", + "name": "box-wipe-tc", + "value": "23" + }, + { + "desc": "A box expands from the right edge's midpoint to the left corners", + "name": "box-wipe-rc", + "value": "24" + }, + { + "desc": "A box expands from the bottom edge's midpoint to the top corners", + "name": "box-wipe-bc", + "value": "25" + }, + { + "desc": "A box expands from the left edge's midpoint to the right corners", + "name": "box-wipe-lc", + "value": "26" + }, + { + "desc": "A diagonal line moves from the upper-left corner to the lower-right corner", + "name": "diagonal-tl", + "value": "41" + }, + { + "desc": "A diagonal line moves from the upper right corner to the lower-left corner", + "name": "diagonal-tr", + "value": "42" + }, + { + "desc": "Two wedge shapes slide in from the top and bottom edges toward the center", + "name": "bowtie-v", + "value": "43" + }, + { + "desc": "Two wedge shapes slide in from the left and right edges toward the center", + "name": "bowtie-h", + "value": "44" + }, + { + "desc": "A diagonal line from the lower-left to upper-right corners splits and expands toward the opposite corners", + "name": "barndoor-dbl", + "value": "45" + }, + { + "desc": "A diagonal line from upper-left to lower-right corners splits and expands toward the opposite corners", + "name": "barndoor-dtl", + "value": "46" + }, + { + "desc": "Four wedge shapes split from the center and retract toward the four edges", + "name": "misc-diagonal-dbd", + "value": "47" + }, + { + "desc": "A diamond connecting the four edge midpoints simultaneously contracts toward the center and expands toward the edges", + "name": "misc-diagonal-dd", + "value": "48" + }, + { + "desc": "A wedge shape moves from top to bottom", + "name": "vee-d", + "value": "61" + }, + { + "desc": "A wedge shape moves from right to left", + "name": "vee-l", + "value": "62" + }, + { + "desc": "A wedge shape moves from bottom to top", + "name": "vee-u", + "value": "63" + }, + { + "desc": "A wedge shape moves from left to right", + "name": "vee-r", + "value": "64" + }, + { + "desc": "A 'V' shape extending from the bottom edge's midpoint to the opposite corners contracts toward the center and expands toward the edges", + "name": "barnvee-d", + "value": "65" + }, + { + "desc": "A 'V' shape extending from the left edge's midpoint to the opposite corners contracts toward the center and expands toward the edges", + "name": "barnvee-l", + "value": "66" + }, + { + "desc": "A 'V' shape extending from the top edge's midpoint to the opposite corners contracts toward the center and expands toward the edges", + "name": "barnvee-u", + "value": "67" + }, + { + "desc": "A 'V' shape extending from the right edge's midpoint to the opposite corners contracts toward the center and expands toward the edges", + "name": "barnvee-r", + "value": "68" + }, + { + "desc": "A rectangle expands from the center.", + "name": "iris-rect", + "value": "101" + }, + { + "desc": "A radial hand sweeps clockwise from the twelve o'clock position", + "name": "clock-cw12", + "value": "201" + }, + { + "desc": "A radial hand sweeps clockwise from the three o'clock position", + "name": "clock-cw3", + "value": "202" + }, + { + "desc": "A radial hand sweeps clockwise from the six o'clock position", + "name": "clock-cw6", + "value": "203" + }, + { + "desc": "A radial hand sweeps clockwise from the nine o'clock position", + "name": "clock-cw9", + "value": "204" + }, + { + "desc": "Two radial hands sweep clockwise from the twelve and six o'clock positions", + "name": "pinwheel-tbv", + "value": "205" + }, + { + "desc": "Two radial hands sweep clockwise from the nine and three o'clock positions", + "name": "pinwheel-tbh", + "value": "206" + }, + { + "desc": "Four radial hands sweep clockwise", + "name": "pinwheel-fb", + "value": "207" + }, + { + "desc": "A fan unfolds from the top edge, the fan axis at the center", + "name": "fan-ct", + "value": "211" + }, + { + "desc": "A fan unfolds from the right edge, the fan axis at the center", + "name": "fan-cr", + "value": "212" + }, + { + "desc": "Two fans, their axes at the center, unfold from the top and bottom", + "name": "doublefan-fov", + "value": "213" + }, + { + "desc": "Two fans, their axes at the center, unfold from the left and right", + "name": "doublefan-foh", + "value": "214" + }, + { + "desc": "A radial hand sweeps clockwise from the top edge's midpoint", + "name": "singlesweep-cwt", + "value": "221" + }, + { + "desc": "A radial hand sweeps clockwise from the right edge's midpoint", + "name": "singlesweep-cwr", + "value": "222" + }, + { + "desc": "A radial hand sweeps clockwise from the bottom edge's midpoint", + "name": "singlesweep-cwb", + "value": "223" + }, + { + "desc": "A radial hand sweeps clockwise from the left edge's midpoint", + "name": "singlesweep-cwl", + "value": "224" + }, + { + "desc": "Two radial hands sweep clockwise and counter-clockwise from the top and bottom edges' midpoints", + "name": "doublesweep-pv", + "value": "225" + }, + { + "desc": "Two radial hands sweep clockwise and counter-clockwise from the left and right edges' midpoints", + "name": "doublesweep-pd", + "value": "226" + }, + { + "desc": "Two radial hands attached at the top and bottom edges' midpoints sweep from right to left", + "name": "doublesweep-ov", + "value": "227" + }, + { + "desc": "Two radial hands attached at the left and right edges' midpoints sweep from top to bottom", + "name": "doublesweep-oh", + "value": "228" + }, + { + "desc": "A fan unfolds from the bottom, the fan axis at the top edge's midpoint", + "name": "fan-t", + "value": "231" + }, + { + "desc": "A fan unfolds from the left, the fan axis at the right edge's midpoint", + "name": "fan-r", + "value": "232" + }, + { + "desc": "A fan unfolds from the top, the fan axis at the bottom edge's midpoint", + "name": "fan-b", + "value": "233" + }, + { + "desc": "A fan unfolds from the right, the fan axis at the left edge's midpoint", + "name": "fan-l", + "value": "234" + }, + { + "desc": "Two fans, their axes at the top and bottom, unfold from the center", + "name": "doublefan-fiv", + "value": "235" + }, + { + "desc": "Two fans, their axes at the left and right, unfold from the center", + "name": "doublefan-fih", + "value": "236" + }, + { + "desc": "A radial hand sweeps clockwise from the upper-left corner", + "name": "singlesweep-cwtl", + "value": "241" + }, + { + "desc": "A radial hand sweeps counter-clockwise from the lower-left corner.", + "name": "singlesweep-cwbl", + "value": "242" + }, + { + "desc": "A radial hand sweeps clockwise from the lower-right corner", + "name": "singlesweep-cwbr", + "value": "243" + }, + { + "desc": "A radial hand sweeps counter-clockwise from the upper-right corner", + "name": "singlesweep-cwtr", + "value": "244" + }, + { + "desc": "Two radial hands attached at the upper-left and lower-right corners sweep down and up", + "name": "doublesweep-pdtl", + "value": "245" + }, + { + "desc": "Two radial hands attached at the lower-left and upper-right corners sweep down and up", + "name": "doublesweep-pdbl", + "value": "246" + }, + { + "desc": "Two radial hands attached at the upper-left and upper-right corners sweep down", + "name": "saloondoor-t", + "value": "251" + }, + { + "desc": "Two radial hands attached at the upper-left and lower-left corners sweep to the right", + "name": "saloondoor-l", + "value": "252" + }, + { + "desc": "Two radial hands attached at the lower-left and lower-right corners sweep up", + "name": "saloondoor-b", + "value": "253" + }, + { + "desc": "Two radial hands attached at the upper-right and lower-right corners sweep to the left", + "name": "saloondoor-r", + "value": "254" + }, + { + "desc": "Two radial hands attached at the midpoints of the top and bottom halves sweep from right to left", + "name": "windshield-r", + "value": "261" + }, + { + "desc": "Two radial hands attached at the midpoints of the left and right halves sweep from top to bottom", + "name": "windshield-u", + "value": "262" + }, + { + "desc": "Two sets of radial hands attached at the midpoints of the top and bottom halves sweep from top to bottom and bottom to top", + "name": "windshield-v", + "value": "263" + }, + { + "desc": "Two sets of radial hands attached at the midpoints of the left and right halves sweep from left to right and right to left", + "name": "windshield-h", + "value": "264" + } + ] + }, + "GstSMPTETransitionType": { + "kind": "enum", + "values": [ + { + "desc": "A bar moves from left to right", + "name": "bar-wipe-lr", + "value": "1" + }, + { + "desc": "A bar moves from top to bottom", + "name": "bar-wipe-tb", + "value": "2" + }, + { + "desc": "A box expands from the upper-left corner to the lower-right corner", + "name": "box-wipe-tl", + "value": "3" + }, + { + "desc": "A box expands from the upper-right corner to the lower-left corner", + "name": "box-wipe-tr", + "value": "4" + }, + { + "desc": "A box expands from the lower-right corner to the upper-left corner", + "name": "box-wipe-br", + "value": "5" + }, + { + "desc": "A box expands from the lower-left corner to the upper-right corner", + "name": "box-wipe-bl", + "value": "6" + }, + { + "desc": "A box shape expands from each of the four corners toward the center", + "name": "four-box-wipe-ci", + "value": "7" + }, + { + "desc": "A box shape expands from the center of each quadrant toward the corners of each quadrant", + "name": "four-box-wipe-co", + "value": "8" + }, + { + "desc": "A central, vertical line splits and expands toward the left and right edges", + "name": "barndoor-v", + "value": "21" + }, + { + "desc": "A central, horizontal line splits and expands toward the top and bottom edges", + "name": "barndoor-h", + "value": "22" + }, + { + "desc": "A box expands from the top edge's midpoint to the bottom corners", + "name": "box-wipe-tc", + "value": "23" + }, + { + "desc": "A box expands from the right edge's midpoint to the left corners", + "name": "box-wipe-rc", + "value": "24" + }, + { + "desc": "A box expands from the bottom edge's midpoint to the top corners", + "name": "box-wipe-bc", + "value": "25" + }, + { + "desc": "A box expands from the left edge's midpoint to the right corners", + "name": "box-wipe-lc", + "value": "26" + }, + { + "desc": "A diagonal line moves from the upper-left corner to the lower-right corner", + "name": "diagonal-tl", + "value": "41" + }, + { + "desc": "A diagonal line moves from the upper right corner to the lower-left corner", + "name": "diagonal-tr", + "value": "42" + }, + { + "desc": "Two wedge shapes slide in from the top and bottom edges toward the center", + "name": "bowtie-v", + "value": "43" + }, + { + "desc": "Two wedge shapes slide in from the left and right edges toward the center", + "name": "bowtie-h", + "value": "44" + }, + { + "desc": "A diagonal line from the lower-left to upper-right corners splits and expands toward the opposite corners", + "name": "barndoor-dbl", + "value": "45" + }, + { + "desc": "A diagonal line from upper-left to lower-right corners splits and expands toward the opposite corners", + "name": "barndoor-dtl", + "value": "46" + }, + { + "desc": "Four wedge shapes split from the center and retract toward the four edges", + "name": "misc-diagonal-dbd", + "value": "47" + }, + { + "desc": "A diamond connecting the four edge midpoints simultaneously contracts toward the center and expands toward the edges", + "name": "misc-diagonal-dd", + "value": "48" + }, + { + "desc": "A wedge shape moves from top to bottom", + "name": "vee-d", + "value": "61" + }, + { + "desc": "A wedge shape moves from right to left", + "name": "vee-l", + "value": "62" + }, + { + "desc": "A wedge shape moves from bottom to top", + "name": "vee-u", + "value": "63" + }, + { + "desc": "A wedge shape moves from left to right", + "name": "vee-r", + "value": "64" + }, + { + "desc": "A 'V' shape extending from the bottom edge's midpoint to the opposite corners contracts toward the center and expands toward the edges", + "name": "barnvee-d", + "value": "65" + }, + { + "desc": "A 'V' shape extending from the left edge's midpoint to the opposite corners contracts toward the center and expands toward the edges", + "name": "barnvee-l", + "value": "66" + }, + { + "desc": "A 'V' shape extending from the top edge's midpoint to the opposite corners contracts toward the center and expands toward the edges", + "name": "barnvee-u", + "value": "67" + }, + { + "desc": "A 'V' shape extending from the right edge's midpoint to the opposite corners contracts toward the center and expands toward the edges", + "name": "barnvee-r", + "value": "68" + }, + { + "desc": "A rectangle expands from the center.", + "name": "iris-rect", + "value": "101" + }, + { + "desc": "A radial hand sweeps clockwise from the twelve o'clock position", + "name": "clock-cw12", + "value": "201" + }, + { + "desc": "A radial hand sweeps clockwise from the three o'clock position", + "name": "clock-cw3", + "value": "202" + }, + { + "desc": "A radial hand sweeps clockwise from the six o'clock position", + "name": "clock-cw6", + "value": "203" + }, + { + "desc": "A radial hand sweeps clockwise from the nine o'clock position", + "name": "clock-cw9", + "value": "204" + }, + { + "desc": "Two radial hands sweep clockwise from the twelve and six o'clock positions", + "name": "pinwheel-tbv", + "value": "205" + }, + { + "desc": "Two radial hands sweep clockwise from the nine and three o'clock positions", + "name": "pinwheel-tbh", + "value": "206" + }, + { + "desc": "Four radial hands sweep clockwise", + "name": "pinwheel-fb", + "value": "207" + }, + { + "desc": "A fan unfolds from the top edge, the fan axis at the center", + "name": "fan-ct", + "value": "211" + }, + { + "desc": "A fan unfolds from the right edge, the fan axis at the center", + "name": "fan-cr", + "value": "212" + }, + { + "desc": "Two fans, their axes at the center, unfold from the top and bottom", + "name": "doublefan-fov", + "value": "213" + }, + { + "desc": "Two fans, their axes at the center, unfold from the left and right", + "name": "doublefan-foh", + "value": "214" + }, + { + "desc": "A radial hand sweeps clockwise from the top edge's midpoint", + "name": "singlesweep-cwt", + "value": "221" + }, + { + "desc": "A radial hand sweeps clockwise from the right edge's midpoint", + "name": "singlesweep-cwr", + "value": "222" + }, + { + "desc": "A radial hand sweeps clockwise from the bottom edge's midpoint", + "name": "singlesweep-cwb", + "value": "223" + }, + { + "desc": "A radial hand sweeps clockwise from the left edge's midpoint", + "name": "singlesweep-cwl", + "value": "224" + }, + { + "desc": "Two radial hands sweep clockwise and counter-clockwise from the top and bottom edges' midpoints", + "name": "doublesweep-pv", + "value": "225" + }, + { + "desc": "Two radial hands sweep clockwise and counter-clockwise from the left and right edges' midpoints", + "name": "doublesweep-pd", + "value": "226" + }, + { + "desc": "Two radial hands attached at the top and bottom edges' midpoints sweep from right to left", + "name": "doublesweep-ov", + "value": "227" + }, + { + "desc": "Two radial hands attached at the left and right edges' midpoints sweep from top to bottom", + "name": "doublesweep-oh", + "value": "228" + }, + { + "desc": "A fan unfolds from the bottom, the fan axis at the top edge's midpoint", + "name": "fan-t", + "value": "231" + }, + { + "desc": "A fan unfolds from the left, the fan axis at the right edge's midpoint", + "name": "fan-r", + "value": "232" + }, + { + "desc": "A fan unfolds from the top, the fan axis at the bottom edge's midpoint", + "name": "fan-b", + "value": "233" + }, + { + "desc": "A fan unfolds from the right, the fan axis at the left edge's midpoint", + "name": "fan-l", + "value": "234" + }, + { + "desc": "Two fans, their axes at the top and bottom, unfold from the center", + "name": "doublefan-fiv", + "value": "235" + }, + { + "desc": "Two fans, their axes at the left and right, unfold from the center", + "name": "doublefan-fih", + "value": "236" + }, + { + "desc": "A radial hand sweeps clockwise from the upper-left corner", + "name": "singlesweep-cwtl", + "value": "241" + }, + { + "desc": "A radial hand sweeps counter-clockwise from the lower-left corner.", + "name": "singlesweep-cwbl", + "value": "242" + }, + { + "desc": "A radial hand sweeps clockwise from the lower-right corner", + "name": "singlesweep-cwbr", + "value": "243" + }, + { + "desc": "A radial hand sweeps counter-clockwise from the upper-right corner", + "name": "singlesweep-cwtr", + "value": "244" + }, + { + "desc": "Two radial hands attached at the upper-left and lower-right corners sweep down and up", + "name": "doublesweep-pdtl", + "value": "245" + }, + { + "desc": "Two radial hands attached at the lower-left and upper-right corners sweep down and up", + "name": "doublesweep-pdbl", + "value": "246" + }, + { + "desc": "Two radial hands attached at the upper-left and upper-right corners sweep down", + "name": "saloondoor-t", + "value": "251" + }, + { + "desc": "Two radial hands attached at the upper-left and lower-left corners sweep to the right", + "name": "saloondoor-l", + "value": "252" + }, + { + "desc": "Two radial hands attached at the lower-left and lower-right corners sweep up", + "name": "saloondoor-b", + "value": "253" + }, + { + "desc": "Two radial hands attached at the upper-right and lower-right corners sweep to the left", + "name": "saloondoor-r", + "value": "254" + }, + { + "desc": "Two radial hands attached at the midpoints of the top and bottom halves sweep from right to left", + "name": "windshield-r", + "value": "261" + }, + { + "desc": "Two radial hands attached at the midpoints of the left and right halves sweep from top to bottom", + "name": "windshield-u", + "value": "262" + }, + { + "desc": "Two sets of radial hands attached at the midpoints of the top and bottom halves sweep from top to bottom and bottom to top", + "name": "windshield-v", + "value": "263" + }, + { + "desc": "Two sets of radial hands attached at the midpoints of the left and right halves sweep from left to right and right to left", + "name": "windshield-h", + "value": "264" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" }, - "video4linux2": { - "description": "elements for Video 4 Linux", + "soup": { + "description": "libsoup HTTP client src/sink", "elements": { - "v4l2radio": { - "author": "Alexey Chernov <4ernov@gmail.com>", - "description": "Controls a Video4Linux2 radio device", - "hierarchy": [ - "GstV4l2Radio", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Tuner", - "long-name": "Radio (video4linux2) Tuner", - "name": "v4l2radio", - "properties": { - "device": { - "blurb": "Video4Linux2 radio device location", - "construct": false, - "construct-only": false, - "default": "/dev/radio0", - "type-name": "gchararray", - "writable": true - }, - "frequency": { - "blurb": "Station frequency in Hz", - "construct": false, - "construct-only": false, - "default": "0", - "max": "108000000", - "min": "87500000", - "type-name": "gint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, - "rank": "none" - }, - "v4l2sink": { - "author": "Rob Clark ,", - "description": "Displays frames on a video4linux2 device", + "souphttpclientsink": { + "author": "David Schleef ", + "description": "Sends streams to HTTP server via PUT", "hierarchy": [ - "GstV4l2Sink", - "GstVideoSink", + "GstSoupHttpClientSink", "GstBaseSink", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Sink/Video", - "long-name": "Video (video4linux2) Sink", - "name": "v4l2sink", + "klass": "Generic", + "long-name": "HTTP client sink", "pad-templates": { "sink": { - "caps": "image/jpeg:\nvideo/mpeg:\n mpegversion: 4\n systemstream: false\nvideo/mpeg:\n mpegversion: 2\nvideo/mpegts:\n systemstream: true\nvideo/x-bayer:\n format: { bggr, gbrg, grbg, rggb }\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-dv:\n systemstream: true\nvideo/x-fwht:\nvideo/x-h263:\n variant: itu\nvideo/x-h264:\n stream-format: { (string)byte-stream, (string)avc }\n alignment: au\nvideo/x-h265:\n stream-format: byte-stream\n alignment: au\nvideo/x-pwc1:\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-pwc2:\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { RGB16, BGR, RGB, GRAY8, GRAY16_LE, GRAY16_BE, YVU9, YV12, YUY2, YVYU, UYVY, Y42B, Y41B, YUV9, NV12_64Z32, NV24, NV61, NV16, NV21, NV12, I420, BGRA, BGRx, ARGB, xRGB, BGR15, RGB15 }\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-sonix:\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-vp8:\nvideo/x-vp9:\nvideo/x-wmv:\n wmvversion: 3\n format: WVC1\n", + "caps": "ANY", "direction": "sink", "presence": "always" } }, "properties": { - "async": { - "blurb": "Go asynchronously to PAUSED", + "automatic-redirect": { + "blurb": "Automatically follow HTTP redirects (HTTP Status Code 3xx)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "blocksize": { - "blurb": "Size in bytes to pull per buffer (0 = default)", + "cookies": { + "blurb": "HTTP request cookies", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GStrv", "writable": true }, - "brightness": { - "blurb": "Picture brightness, or more precisely, the black level", + "http-log-level": { + "blurb": "Set log level for soup's HTTP session log", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "-2147483648", - "type-name": "gint", + "controllable": false, + "default": "none (0)", + "mutable": "null", + "readable": true, + "type": "SoupLoggerLogLevel", "writable": true }, - "contrast": { - "blurb": "Picture contrast or luma gain", + "location": { + "blurb": "URI to send to", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "-2147483648", - "type-name": "gint", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "crop-height": { - "blurb": "The height of the video crop; default is equal to negotiated image height", + "proxy": { + "blurb": "HTTP proxy server URI", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", + "controllable": false, + "default": "", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "crop-left": { - "blurb": "The leftmost (x) coordinate of the video crop; top left corner of image is 0,0", + "proxy-id": { + "blurb": "user id for proxy authentication", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "-2147483648", - "type-name": "gint", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "crop-top": { - "blurb": "The topmost (y) coordinate of the video crop; top left corner of image is 0,0", + "proxy-pw": { + "blurb": "user password for proxy authentication", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "-2147483648", - "type-name": "gint", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "crop-width": { - "blurb": "The width of the video crop; default is equal to negotiated image width", + "retries": { + "blurb": "Maximum number of retries, zero to disable, -1 to retry forever", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "device": { - "blurb": "Device location", + "retry-delay": { + "blurb": "Delay in seconds between retries after a failure", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "/dev/video1", - "type-name": "gchararray", + "controllable": false, + "default": "5", + "max": "2147483647", + "min": "1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "device-fd": { - "blurb": "File descriptor of the device", + "session": { + "blurb": "SoupSession object to use for communication", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": false + "controllable": false, + "mutable": "null", + "readable": true, + "type": "SoupSession", + "writable": true }, - "device-name": { - "blurb": "Name of the device", + "user-agent": { + "blurb": "Value of the User-Agent HTTP request header field", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": false + "controllable": false, + "default": "GStreamer souphttpclientsink ", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": true }, - "enable-last-sample": { - "blurb": "Enable the last-sample property", + "user-id": { + "blurb": "user id for authentication", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "extra-controls": { - "blurb": "Extra v4l2 controls (CIDs) for the device", + "user-pw": { + "blurb": "user password for authentication", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstStructure", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true - }, - "flags": { - "blurb": "Device type flags", + } + }, + "rank": "none" + }, + "souphttpsrc": { + "author": "Wouter Cloetens ", + "description": "Receive data as a client over the network via HTTP using SOUP", + "hierarchy": [ + "GstSoupHTTPSrc", + "GstPushSrc", + "GstBaseSrc", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstURIHandler" + ], + "klass": "Source/Network", + "long-name": "HTTP client source", + "pad-templates": { + "src": { + "caps": "ANY", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "automatic-redirect": { + "blurb": "Automatically follow HTTP redirects (HTTP Status Code 3xx)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "(none)", - "type-name": "GstV4l2DeviceTypeFlags", - "values": [ - { - "desc": "Device supports video capture", - "name": "capture", - "value": "0x00000001" - }, - { - "desc": "Device supports video playback", - "name": "output", - "value": "0x00000002" - }, - { - "desc": "Device supports video overlay", - "name": "overlay", - "value": "0x00000004" - }, - { - "desc": "Device supports the VBI capture", - "name": "vbi-capture", - "value": "0x00000010" - }, - { - "desc": "Device supports the VBI output", - "name": "vbi-output", - "value": "0x00000020" - }, - { - "desc": "Device has a tuner or modulator", - "name": "tuner", - "value": "0x00010000" - }, - { - "desc": "Device has audio inputs or outputs", - "name": "audio", - "value": "0x00020000" - } - ], - "writable": false + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true }, - "force-aspect-ratio": { - "blurb": "When enabled, the pixel aspect ratio will be enforced", + "compress": { + "blurb": "Allow compressed content encodings", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "hue": { - "blurb": "Hue or color balance", + "cookies": { + "blurb": "HTTP request cookies", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "-2147483648", - "type-name": "gint", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GStrv", "writable": true }, - "io-mode": { - "blurb": "I/O mode", + "extra-headers": { + "blurb": "Extra headers to append to the HTTP request", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "auto (0)", - "enum": true, - "type-name": "GstV4l2IOMode", - "values": [ - { - "desc": "GST_V4L2_IO_AUTO", - "name": "auto", - "value": "0" - }, - { - "desc": "GST_V4L2_IO_RW", - "name": "rw", - "value": "1" - }, - { - "desc": "GST_V4L2_IO_MMAP", - "name": "mmap", - "value": "2" - }, - { - "desc": "GST_V4L2_IO_USERPTR", - "name": "userptr", - "value": "3" - }, - { - "desc": "GST_V4L2_IO_DMABUF", - "name": "dmabuf", - "value": "4" - }, - { - "desc": "GST_V4L2_IO_DMABUF_IMPORT", - "name": "dmabuf-import", - "value": "5" - } - ], + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstStructure", "writable": true }, - "last-sample": { - "blurb": "The last sample received in the sink", + "http-log-level": { + "blurb": "Set log level for soup's HTTP session log", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstSample", - "writable": false + "controllable": false, + "default": "headers (2)", + "mutable": "null", + "readable": true, + "type": "SoupLoggerLogLevel", + "writable": true }, - "max-bitrate": { - "blurb": "The maximum bits per second to render (0 = disabled)", + "iradio-mode": { + "blurb": "Enable internet radio mode (ask server to send shoutcast/icecast metadata interleaved with the actual stream data)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "max-lateness": { - "blurb": "Maximum number of nanoseconds that a buffer can be late before it is dropped (-1 unlimited)", + "is-live": { + "blurb": "Act like a live source", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "5000000", - "max": "9223372036854775807", - "min": "-1", - "type-name": "gint64", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "name": { - "blurb": "The name of the object", - "construct": true, + "keep-alive": { + "blurb": "Use HTTP persistent connections", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "norm": { - "blurb": "video standard", + "location": { + "blurb": "Location to read from", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "none (0)", - "enum": true, - "type-name": "V4L2_TV_norms", - "values": [ - { - "desc": "none", - "name": "none", - "value": "0" - }, - { - "desc": "NTSC", - "name": "NTSC", - "value": "45056" - }, - { - "desc": "NTSC-M", - "name": "NTSC-M", - "value": "4096" - }, - { - "desc": "NTSC-M-JP", - "name": "NTSC-M-JP", - "value": "8192" - }, - { - "desc": "NTSC-M-KR", - "name": "NTSC-M-KR", - "value": "32768" - }, - { - "desc": "NTSC-443", - "name": "NTSC-443", - "value": "16384" - }, - { - "desc": "PAL", - "name": "PAL", - "value": "255" - }, - { - "desc": "PAL-BG", - "name": "PAL-BG", - "value": "7" - }, - { - "desc": "PAL-B", - "name": "PAL-B", - "value": "1" - }, - { - "desc": "PAL-B1", - "name": "PAL-B1", - "value": "2" - }, - { - "desc": "PAL-G", - "name": "PAL-G", - "value": "4" - }, - { - "desc": "PAL-H", - "name": "PAL-H", - "value": "8" - }, - { - "desc": "PAL-I", - "name": "PAL-I", - "value": "16" - }, - { - "desc": "PAL-DK", - "name": "PAL-DK", - "value": "224" - }, - { - "desc": "PAL-D", - "name": "PAL-D", - "value": "32" - }, - { - "desc": "PAL-D1", - "name": "PAL-D1", - "value": "64" - }, - { - "desc": "PAL-K", - "name": "PAL-K", - "value": "128" - }, - { - "desc": "PAL-M", - "name": "PAL-M", - "value": "256" - }, - { - "desc": "PAL-N", - "name": "PAL-N", - "value": "512" - }, - { - "desc": "PAL-Nc", - "name": "PAL-Nc", - "value": "1024" - }, - { - "desc": "PAL-60", - "name": "PAL-60", - "value": "2048" - }, - { - "desc": "SECAM", - "name": "SECAM", - "value": "16711680" - }, - { - "desc": "SECAM-B", - "name": "SECAM-B", - "value": "65536" - }, - { - "desc": "SECAM-G", - "name": "SECAM-G", - "value": "262144" - }, - { - "desc": "SECAM-H", - "name": "SECAM-H", - "value": "524288" - }, - { - "desc": "SECAM-DK", - "name": "SECAM-DK", - "value": "3276800" - }, - { - "desc": "SECAM-D", - "name": "SECAM-D", - "value": "131072" - }, - { - "desc": "SECAM-K", - "name": "SECAM-K", - "value": "1048576" - }, - { - "desc": "SECAM-K1", - "name": "SECAM-K1", - "value": "2097152" - }, - { - "desc": "SECAM-L", - "name": "SECAM-L", - "value": "4194304" - }, - { - "desc": "SECAM-Lc", - "name": "SECAM-Lc", - "value": "8388608" - } - ], + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "overlay-height": { - "blurb": "The height of the video overlay; default is equal to negotiated image height", + "method": { + "blurb": "The HTTP method to use (GET, HEAD, OPTIONS, etc)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "overlay-left": { - "blurb": "The leftmost (x) coordinate of the video overlay; top left corner of screen is 0,0", + "proxy": { + "blurb": "HTTP proxy server URI", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "-2147483648", - "type-name": "gint", + "controllable": false, + "default": "", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "overlay-top": { - "blurb": "The topmost (y) coordinate of the video overlay; top left corner of screen is 0,0", + "proxy-id": { + "blurb": "HTTP proxy URI user id for authentication", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "-2147483648", - "type-name": "gint", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "overlay-width": { - "blurb": "The width of the video overlay; default is equal to negotiated image width", + "proxy-pw": { + "blurb": "HTTP proxy URI user password for authentication", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "-1", - "min": "0", - "type-name": "guint", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "retries": { + "blurb": "Maximum number of retries until giving up (-1=infinite)", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "3", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "pixel-aspect-ratio": { - "blurb": "Overwrite the pixel aspect ratio of the device", + "ssl-ca-file": { + "blurb": "Location of a SSL anchor CA file to use", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "processing-deadline": { - "blurb": "Maximum processing deadline in nanoseconds", + "ssl-strict": { + "blurb": "Strict SSL certificate checking", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "15000000", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "qos": { - "blurb": "Generate Quality-of-Service events upstream", + "ssl-use-system-ca-file": { + "blurb": "Use system CA file", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "render-delay": { - "blurb": "Additional render delay of the sink in nanoseconds", + "timeout": { + "blurb": "Value in seconds to timeout a blocking I/O (0 = No timeout).", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "18446744073709551615", + "controllable": false, + "default": "15", + "max": "3600", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "saturation": { - "blurb": "Picture color saturation or chroma gain", + "tls-database": { + "blurb": "TLS database with anchor certificate authorities used to validate the server certificate", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "-2147483648", - "type-name": "gint", - "writable": true - }, - "show-preroll-frame": { - "blurb": "Whether to render video frames during preroll", - "construct": true, - "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GTlsDatabase", "writable": true }, - "stats": { - "blurb": "Sink Statistics", + "tls-interaction": { + "blurb": "A GTlsInteraction object to be used when the connection or certificate database need to interact with the user.", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "application/x-gst-base-sink-stats, average-rate=(double)0, dropped=(guint64)0, rendered=(guint64)0;", - "type-name": "GstStructure", - "writable": false + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GTlsInteraction", + "writable": true }, - "sync": { - "blurb": "Sync on the clock", + "user-agent": { + "blurb": "Value of the User-Agent HTTP request header field", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "GStreamer souphttpsrc 1.18.6 ", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "throttle-time": { - "blurb": "The time to keep between rendered buffers (0 = disabled)", + "user-id": { + "blurb": "HTTP location URI user id for authentication", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "18446744073709551615", - "min": "0", - "type-name": "guint64", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "ts-offset": { - "blurb": "Timestamp offset in nanoseconds", + "user-pw": { + "blurb": "HTTP location URI user password for authentication", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "-9223372036854775808", - "type-name": "gint64", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true } }, - "rank": "none" - }, - "v4l2src": { - "author": "Edgard Lima , Stefan Kost ", - "description": "Reads frames from a Video4Linux2 device", + "rank": "primary" + } + }, + "filename": "gstsoup", + "license": "LGPL", + "other-types": {}, + "package": "GStreamer Good Plug-ins", + "source": "gst-plugins-good", + "tracers": {}, + "url": "Unknown package origin" + }, + "spectrum": { + "description": "Run an FFT on the audio signal, output spectrum data", + "elements": { + "spectrum": { + "author": "Erik Walthinsen , Stefan Kost , Sebastian Dröge ", + "description": "Run an FFT on the audio signal, output spectrum data", "hierarchy": [ - "GstV4l2Src", - "GstPushSrc", - "GstBaseSrc", + "GstSpectrum", + "GstAudioFilter", + "GstBaseTransform", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Source/Video", - "long-name": "Video (video4linux2) Source", - "name": "v4l2src", + "klass": "Filter/Analyzer/Audio", + "long-name": "Spectrum analyzer", "pad-templates": { + "sink": { + "caps": "audio/x-raw:\n format: { S16LE, S24LE, S32LE, F32LE, F64LE }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: interleaved\n", + "direction": "sink", + "presence": "always" + }, "src": { - "caps": "image/jpeg:\nvideo/mpeg:\n mpegversion: 4\n systemstream: false\nvideo/mpeg:\n mpegversion: 2\nvideo/mpegts:\n systemstream: true\nvideo/x-bayer:\n format: { bggr, gbrg, grbg, rggb }\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-dv:\n systemstream: true\nvideo/x-fwht:\nvideo/x-h263:\n variant: itu\nvideo/x-h264:\n stream-format: { (string)byte-stream, (string)avc }\n alignment: au\nvideo/x-h265:\n stream-format: byte-stream\n alignment: au\nvideo/x-pwc1:\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-pwc2:\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { RGB16, BGR, RGB, GRAY8, GRAY16_LE, GRAY16_BE, YVU9, YV12, YUY2, YVYU, UYVY, Y42B, Y41B, YUV9, NV12_64Z32, NV24, NV61, NV16, NV21, NV12, I420, BGRA, BGRx, ARGB, xRGB, BGR15, RGB15 }\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-sonix:\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-vp8:\nvideo/x-vp9:\nvideo/x-wmv:\n wmvversion: 3\n format: WVC1\n", + "caps": "audio/x-raw:\n format: { S16LE, S24LE, S32LE, F32LE, F64LE }\n rate: [ 1, 2147483647 ]\n channels: [ 1, 2147483647 ]\n layout: interleaved\n", "direction": "src", "presence": "always" } }, "properties": { - "blocksize": { - "blurb": "Size in bytes to read per buffer (-1 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, - "brightness": { - "blurb": "Picture brightness, or more precisely, the black level", + "bands": { + "blurb": "Number of frequency bands", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "-2147483648", - "type-name": "gint", + "controllable": false, + "default": "128", + "max": "1073741824", + "min": "2", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "contrast": { - "blurb": "Picture contrast or luma gain", + "interval": { + "blurb": "Interval of time between message posts (in nanoseconds)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "-2147483648", - "type-name": "gint", + "controllable": false, + "default": "100000000", + "max": "18446744073709551615", + "min": "1", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, - "device": { - "blurb": "Device location", + "message-magnitude": { + "blurb": "Whether to add a 'magnitude' field to the structure of any 'spectrum' element messages posted on the bus", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "/dev/video0", - "type-name": "gchararray", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "device-fd": { - "blurb": "File descriptor of the device", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": false - }, - "device-name": { - "blurb": "Name of the device", - "construct": false, - "construct-only": false, - "default": "NULL", - "type-name": "gchararray", - "writable": false - }, - "do-timestamp": { - "blurb": "Apply current stream time to buffers", + "message-phase": { + "blurb": "Whether to add a 'phase' field to the structure of any 'spectrum' element messages posted on the bus", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "extra-controls": { - "blurb": "Extra v4l2 controls (CIDs) for the device", + "multi-channel": { + "blurb": "Send separate results for each channel", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstStructure", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "flags": { - "blurb": "Device type flags", - "construct": false, - "construct-only": false, - "default": "(none)", - "type-name": "GstV4l2DeviceTypeFlags", - "values": [ - { - "desc": "Device supports video capture", - "name": "capture", - "value": "0x00000001" - }, - { - "desc": "Device supports video playback", - "name": "output", - "value": "0x00000002" - }, - { - "desc": "Device supports video overlay", - "name": "overlay", - "value": "0x00000004" - }, - { - "desc": "Device supports the VBI capture", - "name": "vbi-capture", - "value": "0x00000010" - }, - { - "desc": "Device supports the VBI output", - "name": "vbi-output", - "value": "0x00000020" - }, - { - "desc": "Device has a tuner or modulator", - "name": "tuner", - "value": "0x00010000" - }, - { - "desc": "Device has audio inputs or outputs", - "name": "audio", - "value": "0x00020000" - } - ], - "writable": false - }, - "force-aspect-ratio": { - "blurb": "When enabled, the pixel aspect ratio will be enforced", + "post-messages": { + "blurb": "Whether to post a 'spectrum' element message on the bus for each passed interval", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "hue": { - "blurb": "Hue or color balance", + "threshold": { + "blurb": "dB threshold for result. All lower values will be set to this", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "2147483647", + "controllable": false, + "default": "-60", + "max": "0", "min": "-2147483648", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true + } + }, + "rank": "none" + } + }, + "filename": "gstspectrum", + "license": "LGPL", + "other-types": {}, + "package": "GStreamer Good Plug-ins", + "source": "gst-plugins-good", + "tracers": {}, + "url": "Unknown package origin" + }, + "speex": { + "description": "Speex plugin library", + "elements": { + "speexdec": { + "author": "Wim Taymans ", + "description": "decode speex streams to audio", + "hierarchy": [ + "GstSpeexDec", + "GstAudioDecoder", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Decoder/Audio", + "long-name": "Speex audio decoder", + "pad-templates": { + "sink": { + "caps": "audio/x-speex:\n", + "direction": "sink", + "presence": "always" }, - "io-mode": { - "blurb": "I/O mode", + "src": { + "caps": "audio/x-raw:\n format: S16LE\n layout: interleaved\n rate: [ 6000, 48000 ]\n channels: [ 1, 2 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "enh": { + "blurb": "Enable perceptual enhancement", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "auto (0)", - "enum": true, - "type-name": "GstV4l2IOMode", - "values": [ - { - "desc": "GST_V4L2_IO_AUTO", - "name": "auto", - "value": "0" - }, - { - "desc": "GST_V4L2_IO_RW", - "name": "rw", - "value": "1" - }, - { - "desc": "GST_V4L2_IO_MMAP", - "name": "mmap", - "value": "2" - }, - { - "desc": "GST_V4L2_IO_USERPTR", - "name": "userptr", - "value": "3" - }, - { - "desc": "GST_V4L2_IO_DMABUF", - "name": "dmabuf", - "value": "4" - }, - { - "desc": "GST_V4L2_IO_DMABUF_IMPORT", - "name": "dmabuf-import", - "value": "5" - } - ], - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true + } + }, + "rank": "primary" + }, + "speexenc": { + "author": "Wim Taymans ", + "description": "Encodes audio in Speex format", + "hierarchy": [ + "GstSpeexEnc", + "GstAudioEncoder", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstPreset", + "GstTagSetter" + ], + "klass": "Codec/Encoder/Audio", + "long-name": "Speex audio encoder", + "pad-templates": { + "sink": { + "caps": "audio/x-raw:\n format: S16LE\n layout: interleaved\n rate: [ 6000, 48000 ]\n channels: 1\naudio/x-raw:\n format: S16LE\n layout: interleaved\n rate: [ 6000, 48000 ]\n channels: 2\n channel-mask: 0x0000000000000003\n", + "direction": "sink", + "presence": "always" }, - "norm": { - "blurb": "video standard", - "construct": false, - "construct-only": false, - "default": "none (0)", - "enum": true, - "type-name": "V4L2_TV_norms", - "values": [ - { - "desc": "none", - "name": "none", - "value": "0" - }, - { - "desc": "NTSC", - "name": "NTSC", - "value": "45056" - }, - { - "desc": "NTSC-M", - "name": "NTSC-M", - "value": "4096" - }, - { - "desc": "NTSC-M-JP", - "name": "NTSC-M-JP", - "value": "8192" - }, - { - "desc": "NTSC-M-KR", - "name": "NTSC-M-KR", - "value": "32768" - }, - { - "desc": "NTSC-443", - "name": "NTSC-443", - "value": "16384" - }, - { - "desc": "PAL", - "name": "PAL", - "value": "255" - }, - { - "desc": "PAL-BG", - "name": "PAL-BG", - "value": "7" - }, - { - "desc": "PAL-B", - "name": "PAL-B", - "value": "1" - }, - { - "desc": "PAL-B1", - "name": "PAL-B1", - "value": "2" - }, - { - "desc": "PAL-G", - "name": "PAL-G", - "value": "4" - }, - { - "desc": "PAL-H", - "name": "PAL-H", - "value": "8" - }, - { - "desc": "PAL-I", - "name": "PAL-I", - "value": "16" - }, - { - "desc": "PAL-DK", - "name": "PAL-DK", - "value": "224" - }, - { - "desc": "PAL-D", - "name": "PAL-D", - "value": "32" - }, - { - "desc": "PAL-D1", - "name": "PAL-D1", - "value": "64" - }, - { - "desc": "PAL-K", - "name": "PAL-K", - "value": "128" - }, - { - "desc": "PAL-M", - "name": "PAL-M", - "value": "256" - }, - { - "desc": "PAL-N", - "name": "PAL-N", - "value": "512" - }, - { - "desc": "PAL-Nc", - "name": "PAL-Nc", - "value": "1024" - }, - { - "desc": "PAL-60", - "name": "PAL-60", - "value": "2048" - }, - { - "desc": "SECAM", - "name": "SECAM", - "value": "16711680" - }, - { - "desc": "SECAM-B", - "name": "SECAM-B", - "value": "65536" - }, - { - "desc": "SECAM-G", - "name": "SECAM-G", - "value": "262144" - }, - { - "desc": "SECAM-H", - "name": "SECAM-H", - "value": "524288" - }, - { - "desc": "SECAM-DK", - "name": "SECAM-DK", - "value": "3276800" - }, - { - "desc": "SECAM-D", - "name": "SECAM-D", - "value": "131072" - }, - { - "desc": "SECAM-K", - "name": "SECAM-K", - "value": "1048576" - }, - { - "desc": "SECAM-K1", - "name": "SECAM-K1", - "value": "2097152" - }, - { - "desc": "SECAM-L", - "name": "SECAM-L", - "value": "4194304" - }, - { - "desc": "SECAM-Lc", - "name": "SECAM-Lc", - "value": "8388608" - } - ], + "src": { + "caps": "audio/x-speex:\n rate: [ 6000, 48000 ]\n channels: [ 1, 2 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "abr": { + "blurb": "Enable average bit-rate (0 = disabled)", + "conditionally-available": false, + "construct": true, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "num-buffers": { - "blurb": "Number of buffers to output before sending EOS (-1 = unlimited)", - "construct": false, + "bitrate": { + "blurb": "Specify an encoding bit-rate (in bps). (0 = automatic)", + "conditionally-available": false, + "construct": true, "construct-only": false, - "default": "-1", + "controllable": false, + "default": "0", "max": "2147483647", - "min": "-1", - "type-name": "gint", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "parent": { - "blurb": "The parent of the object", - "construct": false, + "complexity": { + "blurb": "Set encoding complexity", + "conditionally-available": false, + "construct": true, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "3", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "pixel-aspect-ratio": { - "blurb": "Overwrite the pixel aspect ratio of the device", + "dtx": { + "blurb": "Enable discontinuous transmission", + "conditionally-available": false, + "construct": true, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "last-message": { + "blurb": "The last status message", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": false + }, + "mode": { + "blurb": "The encoding mode", + "conditionally-available": false, + "construct": true, + "construct-only": false, + "controllable": false, + "default": "auto (0)", + "mutable": "null", + "readable": true, + "type": "GstSpeexEncMode", "writable": true }, - "saturation": { - "blurb": "Picture color saturation or chroma gain", - "construct": false, + "nframes": { + "blurb": "Number of frames per buffer", + "conditionally-available": false, + "construct": true, "construct-only": false, - "default": "0", + "controllable": false, + "default": "1", "max": "2147483647", - "min": "-2147483648", - "type-name": "gint", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "typefind": { - "blurb": "Run typefind before negotiating (deprecated, non-functional)", - "construct": false, + "quality": { + "blurb": "Encoding quality", + "conditionally-available": false, + "construct": true, + "construct-only": false, + "controllable": false, + "default": "8", + "max": "10", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gfloat", + "writable": true + }, + "vad": { + "blurb": "Enable voice activity detection", + "conditionally-available": false, + "construct": true, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "vbr": { + "blurb": "Enable variable bit-rate", + "conditionally-available": false, + "construct": true, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, - "rank": "primary", - "signals": { - "prepare-format": { - "args": [ - "gint", - "GstCaps" - ], - "retval": "void" + "rank": "primary" + } + }, + "filename": "gstspeex", + "license": "LGPL", + "other-types": { + "GstSpeexEncMode": { + "kind": "enum", + "values": [ + { + "desc": "Auto", + "name": "auto", + "value": "0" + }, + { + "desc": "Ultra Wide Band", + "name": "uwb", + "value": "1" + }, + { + "desc": "Wide Band", + "name": "wb", + "value": "2" + }, + { + "desc": "Narrow Band", + "name": "nb", + "value": "3" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", + "source": "gst-plugins-good", + "tracers": {}, + "url": "Unknown package origin" + }, + "taglib": { + "description": "Tag writing plug-in based on taglib", + "elements": { + "apev2mux": { + "author": "Sebastian Dröge ", + "description": "Adds an APEv2 header to the beginning of files using taglib", + "hierarchy": [ + "GstApev2Mux", + "GstTagMux", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstTagSetter" + ], + "klass": "Formatter/Metadata", + "long-name": "TagLib-based APEv2 Muxer", + "pad-templates": { + "sink": { + "caps": "ANY", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "application/x-apetag:\n", + "direction": "src", + "presence": "always" } - } + }, + "rank": "none" + }, + "id3v2mux": { + "author": "Christophe Fergeau ", + "description": "Adds an ID3v2 header to the beginning of MP3 files using taglib", + "hierarchy": [ + "GstId3v2Mux", + "GstTagMux", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstTagSetter" + ], + "klass": "Formatter/Metadata", + "long-name": "TagLib-based ID3v2 Muxer", + "pad-templates": { + "sink": { + "caps": "ANY", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "application/x-id3:\n", + "direction": "src", + "presence": "always" + } + }, + "rank": "none" } }, - "filename": "gstvideo4linux2", + "filename": "gsttaglib", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" }, - "videobox": { - "description": "resizes a video by adding borders or cropping", + "twolame": { + "description": "Encode MP2s with TwoLAME", "elements": { - "videobox": { - "author": "Wim Taymans ", - "description": "Resizes a video by adding borders or cropping", + "twolamemp2enc": { + "author": "Sebastian Dröge ", + "description": "High-quality free MP2 encoder", "hierarchy": [ - "GstVideoBox", - "GstVideoFilter", - "GstBaseTransform", + "GstTwoLame", + "GstAudioEncoder", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Filter/Effect/Video", - "long-name": "Video box filter", - "name": "videobox", + "interfaces": [ + "GstPreset" + ], + "klass": "Codec/Encoder/Audio", + "long-name": "TwoLAME mp2 encoder", "pad-templates": { "sink": { - "caps": "video/x-raw:\n format: { AYUV, ARGB, BGRA, ABGR, RGBA, xRGB, BGRx, xBGR, RGBx, RGB, BGR, Y444, Y42B, YUY2, YVYU, UYVY, I420, YV12, Y41B, GRAY8, GRAY16_BE, GRAY16_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "caps": "audio/x-raw:\n format: { F32LE, S16LE }\n layout: interleaved\n rate: { (int)16000, (int)22050, (int)24000, (int)32000, (int)44100, (int)48000 }\n channels: 1\naudio/x-raw:\n format: { F32LE, S16LE }\n layout: interleaved\n rate: { (int)16000, (int)22050, (int)24000, (int)32000, (int)44100, (int)48000 }\n channels: 2\n channel-mask: 0x0000000000000003\n", "direction": "sink", "presence": "always" }, "src": { - "caps": "video/x-raw:\n format: { AYUV, ARGB, BGRA, ABGR, RGBA, xRGB, BGRx, xBGR, RGBx, RGB, BGR, Y444, Y42B, YUY2, YVYU, UYVY, I420, YV12, Y41B, GRAY8, GRAY16_BE, GRAY16_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "caps": "audio/mpeg:\n mpegversion: 1\n layer: 2\n rate: { (int)16000, (int)22050, (int)24000, (int)32000, (int)44100, (int)48000 }\n channels: [ 1, 2 ]\n", "direction": "src", "presence": "always" } }, "properties": { - "alpha": { - "blurb": "Alpha value picture", + "ath-level": { + "blurb": "ATH Level in dB", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "1", - "max": "1", - "min": "0", - "type-name": "gdouble", + "controllable": false, + "default": "0", + "max": "3.40282e+38", + "min": "-3.40282e+38", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, - "autocrop": { - "blurb": "Auto crop", + "bitrate": { + "blurb": "Bitrate in kbit/sec (8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 192, 224, 256, 320, 384)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "192", + "max": "384", + "min": "8", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + }, + "copyright": { + "blurb": "Mark as copyright", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "border-alpha": { - "blurb": "Alpha value of the border", + "emphasis": { + "blurb": "Pre-emphasis to apply to the decoded audio", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "1", - "max": "1", - "min": "0", - "type-name": "gdouble", + "controllable": false, + "default": "none (0)", + "mutable": "null", + "readable": true, + "type": "GstTwoLameEmphasis", "writable": true }, - "bottom": { - "blurb": "Pixels to box at bottom (<0 = add a border)", + "energy-level-extension": { + "blurb": "Write peak PCM level to each frame", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "-2147483648", - "type-name": "gint", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "fill": { - "blurb": "How to fill the borders", + "error-protection": { + "blurb": "Adds checksum to every frame", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "black (0)", - "enum": true, - "type-name": "GstVideoBoxFill", - "values": [ - { - "desc": "Black", - "name": "black", - "value": "0" - }, - { - "desc": "Green", - "name": "green", - "value": "1" - }, - { - "desc": "Blue", - "name": "blue", - "value": "2" - }, - { - "desc": "Red", - "name": "red", - "value": "3" - }, - { - "desc": "Yellow", - "name": "yellow", - "value": "4" - }, - { - "desc": "White", - "name": "white", - "value": "5" - } - ], + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "left": { - "blurb": "Pixels to box at left (<0 = add a border)", + "mode": { + "blurb": "Encoding mode", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "-2147483648", - "type-name": "gint", + "controllable": false, + "default": "joint (1)", + "mutable": "null", + "readable": true, + "type": "GstTwoLameMode", + "writable": true + }, + "original": { + "blurb": "Mark as original", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "padding": { + "blurb": "Padding type", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "never (0)", + "mutable": "null", + "readable": true, + "type": "GstTwoLamePadding", + "writable": true + }, + "psymodel": { + "blurb": "Psychoacoustic model used to encode the audio", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "3", + "max": "4", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "name": { - "blurb": "The name of the object", - "construct": true, + "quick-mode": { + "blurb": "Calculate Psymodel every frames", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "quick-mode-count": { + "blurb": "Calculate Psymodel every n frames", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "10", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "qos": { - "blurb": "Handle Quality-of-Service events", + "vbr": { + "blurb": "Enable variable bitrate mode", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "right": { - "blurb": "Pixels to box at right (<0 = add a border)", + "vbr-level": { + "blurb": "VBR Level", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "-2147483648", - "type-name": "gint", + "controllable": false, + "default": "5", + "max": "10", + "min": "-10", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, - "top": { - "blurb": "Pixels to box at top (<0 = add a border)", + "vbr-max-bitrate": { + "blurb": "Specify maximum VBR bitrate (0=off, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 192, 224, 256, 320, 384)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", - "max": "2147483647", - "min": "-2147483648", - "type-name": "gint", + "max": "384", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true } }, - "rank": "none" + "rank": "primary" } }, - "filename": "gstvideobox", + "filename": "gsttwolame", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": { + "GstTwoLameEmphasis": { + "kind": "enum", + "values": [ + { + "desc": "No emphasis", + "name": "none", + "value": "0" + }, + { + "desc": "50/15 ms", + "name": "5", + "value": "1" + }, + { + "desc": "CCIT J.17", + "name": "ccit", + "value": "3" + } + ] + }, + "GstTwoLameMode": { + "kind": "enum", + "values": [ + { + "desc": "Auto", + "name": "auto", + "value": "-1" + }, + { + "desc": "Stereo", + "name": "stereo", + "value": "0" + }, + { + "desc": "Joint Stereo", + "name": "joint", + "value": "1" + }, + { + "desc": "Dual Channel", + "name": "dual", + "value": "2" + }, + { + "desc": "Mono", + "name": "mono", + "value": "3" + } + ] + }, + "GstTwoLamePadding": { + "kind": "enum", + "values": [ + { + "desc": "No Padding", + "name": "never", + "value": "0" + }, + { + "desc": "Always Pad", + "name": "always", + "value": "1" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" }, - "videocrop": { - "description": "Crops video into a user-defined region", + "udp": { + "description": "transfer data via UDP", "elements": { - "aspectratiocrop": { - "author": "Thijs Vermeir ", - "description": "Crops video into a user-defined aspect-ratio", + "dynudpsink": { + "author": "Philippe Khalaf ", + "description": "Send data over the network via UDP with packet destinations picked up dynamically from meta on the buffers passed", "hierarchy": [ - "GstAspectRatioCrop", - "GstBin", + "GstDynUDPSink", + "GstBaseSink", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Filter/Effect/Video", - "long-name": "aspectratiocrop", - "name": "aspectratiocrop", + "klass": "Sink/Network", + "long-name": "UDP packet sender", "pad-templates": { "sink": { - "caps": "video/x-raw:\n format: { RGBx, xRGB, BGRx, xBGR, RGBA, ARGB, BGRA, ABGR, RGB, BGR, AYUV, YUY2, YVYU, UYVY, I420, YV12, RGB16, RGB15, GRAY8, NV12, NV21, GRAY16_LE, GRAY16_BE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "caps": "ANY", "direction": "sink", "presence": "always" - }, - "src": { - "caps": "video/x-raw:\n format: { RGBx, xRGB, BGRx, xBGR, RGBA, ARGB, BGRA, ABGR, RGB, BGR, AYUV, YUY2, YVYU, UYVY, I420, YV12, RGB16, RGB15, GRAY8, NV12, NV21, GRAY16_LE, GRAY16_BE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", - "direction": "src", - "presence": "always" } }, "properties": { - "aspect-ratio": { - "blurb": "Target aspect-ratio of video", + "bind-address": { + "blurb": "Address to bind the socket to", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0/1", - "max": "2147483647/1", - "min": "0/1", - "type-name": "GstFraction", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "async-handling": { - "blurb": "The bin will handle Asynchronous state changes", + "bind-port": { + "blurb": "Port to bind the socket to", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "0", + "max": "65535", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "message-forward": { - "blurb": "Forwards all children messages", + "close-socket": { + "blurb": "Close socket if passed as property on state change", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "name": { - "blurb": "The name of the object", - "construct": true, + "socket": { + "blurb": "Socket to use for UDP sending. (NULL == allocate)", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GSocket", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "socket-v6": { + "blurb": "Socket to use for UDPv6 sending. (NULL == allocate)", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GSocket", "writable": true } }, - "rank": "none" + "rank": "none", + "signals": { + "get-stats": { + "action": true, + "args": [ + { + "name": "arg0", + "type": "gchararray" + }, + { + "name": "arg1", + "type": "gint" + } + ], + "return-type": "GstStructure", + "when": "last" + } + } }, - "videocrop": { - "author": "Tim-Philipp M\u00fcller ", - "description": "Crops video into a user-defined region", + "multiudpsink": { + "author": "Wim Taymans ", + "description": "Send data over the network via UDP to one or multiple recipients which can be added or removed at runtime using action signals", "hierarchy": [ - "GstVideoCrop", - "GstVideoFilter", - "GstBaseTransform", + "GstMultiUDPSink", + "GstBaseSink", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Filter/Effect/Video", - "long-name": "Crop", - "name": "videocrop", + "klass": "Sink/Network", + "long-name": "UDP packet sender", "pad-templates": { "sink": { - "caps": "video/x-raw:\n format: { RGBx, xRGB, BGRx, xBGR, RGBA, ARGB, BGRA, ABGR, RGB, BGR, AYUV, YUY2, YVYU, UYVY, I420, YV12, RGB16, RGB15, GRAY8, NV12, NV21, GRAY16_LE, GRAY16_BE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "caps": "ANY", "direction": "sink", "presence": "always" - }, - "src": { - "caps": "video/x-raw:\n format: { RGBx, xRGB, BGRx, xBGR, RGBA, ARGB, BGRA, ABGR, RGB, BGR, AYUV, YUY2, YVYU, UYVY, I420, YV12, RGB16, RGB15, GRAY8, NV12, NV21, GRAY16_LE, GRAY16_BE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", - "direction": "src", - "presence": "always" } }, "properties": { - "bottom": { - "blurb": "Pixels to crop at bottom (-1 to auto-crop)", + "auto-multicast": { + "blurb": "Automatically join/leave the multicast groups, FALSE means user has to do it himself", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "bind-address": { + "blurb": "Address to bind the socket to", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": true + }, + "bind-port": { + "blurb": "Port to bind the socket to", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", - "max": "2147483647", - "min": "-1", - "type-name": "gint", + "max": "65535", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "left": { - "blurb": "Pixels to crop at left (-1 to auto-crop)", + "buffer-size": { + "blurb": "Size of the kernel send buffer in bytes, 0=default", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "2147483647", - "min": "-1", - "type-name": "gint", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "name": { - "blurb": "The name of the object", - "construct": true, + "bytes-served": { + "blurb": "Total number of bytes sent to all clients", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "default": "0", + "max": "18446744073709551615", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint64", + "writable": false + }, + "bytes-to-serve": { + "blurb": "Number of bytes received to serve to clients", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "18446744073709551615", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint64", + "writable": false + }, + "clients": { + "blurb": "A comma separated list of host:port pairs with destinations", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "close-socket": { + "blurb": "Close socket if passed as property on state change", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "qos": { - "blurb": "Handle Quality-of-Service events", + "force-ipv4": { + "blurb": "Forcing the use of an IPv4 socket (DEPRECATED, has no effect anymore)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "loop": { + "blurb": "Used for setting the multicast loop parameter. TRUE = enable, FALSE = disable", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "right": { - "blurb": "Pixels to crop at right (-1 to auto-crop)", + "multicast-iface": { + "blurb": "The network interface on which to join the multicast group", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "2147483647", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": true + }, + "qos-dscp": { + "blurb": "Quality of Service, differentiated services code point (-1 default)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "-1", + "max": "63", "min": "-1", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "top": { - "blurb": "Pixels to crop at top (-1 to auto-crop)", + "send-duplicates": { + "blurb": "When a distination/port pair is added multiple times, send packets multiple times as well", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "socket": { + "blurb": "Socket to use for UDP sending. (NULL == allocate)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GSocket", + "writable": true + }, + "socket-v6": { + "blurb": "Socket to use for UDPv6 sending. (NULL == allocate)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GSocket", + "writable": true + }, + "ttl": { + "blurb": "Used for setting the unicast TTL parameter", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "64", + "max": "255", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + }, + "ttl-mc": { + "blurb": "Used for setting the multicast TTL parameter", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "1", + "max": "255", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + }, + "used-socket": { + "blurb": "Socket currently in use for UDP sending. (NULL == no socket)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GSocket", + "writable": false + }, + "used-socket-v6": { + "blurb": "Socket currently in use for UDPv6 sending. (NULL == no socket)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GSocket", + "writable": false } }, - "rank": "none" - } - }, - "filename": "gstvideocrop", - "license": "LGPL", - "package": "GStreamer Good Plug-ins git", - "source": "gst-plugins-good", - "tracers": {}, - "url": "Unknown package origin" - }, - "videofilter": { - "description": "Video filters plugin", - "elements": { - "gamma": { - "author": "Arwed v. Merkatz ", + "description": "Send data over the network via UDP", "hierarchy": [ - "GstGamma", - "GstVideoFilter", - "GstBaseTransform", + "GstUDPSink", + "GstMultiUDPSink", + "GstBaseSink", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Filter/Effect/Video", - "long-name": "Video gamma correction", - "name": "gamma", + "interfaces": [ + "GstURIHandler" + ], + "klass": "Sink/Network", + "long-name": "UDP packet sender", "pad-templates": { "sink": { - "caps": "video/x-raw:\n format: { AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, RGB, BGR, Y42B, NV12, NV21, YUY2, UYVY, YVYU, I420, YV12, IYUV, Y41B }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "caps": "ANY", "direction": "sink", "presence": "always" - }, - "src": { - "caps": "video/x-raw:\n format: { AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, RGB, BGR, Y42B, NV12, NV21, YUY2, UYVY, YVYU, I420, YV12, IYUV, Y41B }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", - "direction": "src", - "presence": "always" } }, "properties": { - "gamma": { - "blurb": "gamma", - "construct": false, - "construct-only": false, - "default": "1", - "max": "10", - "min": "0.01", - "type-name": "gdouble", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", + "host": { + "blurb": "The host/IP/Multicast group to send the packets to", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "localhost", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "qos": { - "blurb": "Handle Quality-of-Service events", + "port": { + "blurb": "The port to send the packets to", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "default": "5004", + "max": "65535", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true } }, - "rank": "none" + "rank": "none", + "signals": {} }, - "videobalance": { - "author": "David Schleef ", - "description": "Adjusts brightness, contrast, hue, saturation on a video stream", + "udpsrc": { + "author": "Wim Taymans , Thijs Vermeir ", + "description": "Receive data over the network via UDP", "hierarchy": [ - "GstVideoBalance", - "GstVideoFilter", - "GstBaseTransform", + "GstUDPSrc", + "GstPushSrc", + "GstBaseSrc", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Filter/Effect/Video", - "long-name": "Video balance", - "name": "videobalance", + "interfaces": [ + "GstURIHandler" + ], + "klass": "Source/Network", + "long-name": "UDP packet receiver", "pad-templates": { - "sink": { - "caps": "video/x-raw:\n format: { AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, RGB, BGR, Y42B, YUY2, UYVY, YVYU, I420, YV12, IYUV, Y41B, NV12, NV21 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(ANY):\n", - "direction": "sink", - "presence": "always" - }, "src": { - "caps": "video/x-raw:\n format: { AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, RGB, BGR, Y42B, YUY2, UYVY, YVYU, I420, YV12, IYUV, Y41B, NV12, NV21 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(ANY):\n", + "caps": "ANY", "direction": "src", "presence": "always" } }, "properties": { - "brightness": { - "blurb": "brightness", + "address": { + "blurb": "Address to receive packets for. This is equivalent to the multicast-group property for now", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "1", - "min": "-1", - "type-name": "gdouble", + "controllable": false, + "default": "0.0.0.0", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "contrast": { - "blurb": "contrast", + "auto-multicast": { + "blurb": "Automatically join/leave multicast groups", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "1", - "max": "2", - "min": "0", - "type-name": "gdouble", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "hue": { - "blurb": "hue", + "buffer-size": { + "blurb": "Size of the kernel receive buffer in bytes, 0=default", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", - "max": "1", - "min": "-1", - "type-name": "gdouble", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "name": { - "blurb": "The name of the object", - "construct": true, + "caps": { + "blurb": "The caps of the source pad", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstCaps", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "close-socket": { + "blurb": "Close socket if passed as property on state change", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "qos": { - "blurb": "Handle Quality-of-Service events", + "loop": { + "blurb": "Used for setting the multicast loop parameter. TRUE = enable, FALSE = disable", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "saturation": { - "blurb": "saturation", + "mtu": { + "blurb": "Maximum expected packet size. This directly defines the allocationsize of the receive buffer pool.", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "1", - "max": "2", + "controllable": false, + "default": "1492", + "max": "2147483647", "min": "0", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true - } - }, - "rank": "none" - }, - "videoflip": { - "author": "David Schleef ", - "description": "Flips and rotates video", - "hierarchy": [ - "GstVideoFlip", - "GstVideoFilter", - "GstBaseTransform", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Filter/Effect/Video", - "long-name": "Video flipper", - "name": "videoflip", - "pad-templates": { - "sink": { - "caps": "video/x-raw:\n format: { AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, RGB, BGR, I420, YV12, IYUV, YUY2, UYVY, YVYU, NV12, NV21, GRAY8, GRAY16_BE, GRAY16_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", - "direction": "sink", - "presence": "always" }, - "src": { - "caps": "video/x-raw:\n format: { AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, RGB, BGR, I420, YV12, IYUV, YUY2, UYVY, YVYU, NV12, NV21, GRAY8, GRAY16_BE, GRAY16_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "method": { - "blurb": "method (deprecated, use video-direction instead)", - "construct": true, + "multicast-group": { + "blurb": "The Address of multicast group to join. (DEPRECATED: Use address property instead)", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "none (0)", - "enum": true, - "type-name": "GstVideoFlipMethod", - "values": [ - { - "desc": "Identity (no rotation)", - "name": "none", - "value": "0" - }, - { - "desc": "Rotate clockwise 90 degrees", - "name": "clockwise", - "value": "1" - }, - { - "desc": "Rotate 180 degrees", - "name": "rotate-180", - "value": "2" - }, - { - "desc": "Rotate counter-clockwise 90 degrees", - "name": "counterclockwise", - "value": "3" - }, - { - "desc": "Flip horizontally", - "name": "horizontal-flip", - "value": "4" - }, - { - "desc": "Flip vertically", - "name": "vertical-flip", - "value": "5" - }, - { - "desc": "Flip across upper left/lower right diagonal", - "name": "upper-left-diagonal", - "value": "6" - }, - { - "desc": "Flip across upper right/lower left diagonal", - "name": "upper-right-diagonal", - "value": "7" - }, - { - "desc": "Select flip method based on image-orientation tag", - "name": "automatic", - "value": "8" - } - ], + "controllable": false, + "default": "0.0.0.0", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "name": { - "blurb": "The name of the object", - "construct": true, + "multicast-iface": { + "blurb": "The network interface on which to join the multicast group.This allows multiple interfaces separated by comma. (\"eth0,eth1\")", + "conditionally-available": false, + "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": true + }, + "port": { + "blurb": "The port to receive the packets from, 0=allocate", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "5004", + "max": "65535", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "retrieve-sender-address": { + "blurb": "Whether to retrieve the sender address and add it to buffers as meta. Disabling this might result in minor performance improvements in certain scenarios", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "qos": { - "blurb": "Handle Quality-of-Service events", + "reuse": { + "blurb": "Enable reuse of the port", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", - "writable": true - }, - "video-direction": { - "blurb": "Video direction: rotation and flipping", - "construct": true, - "construct-only": false, - "default": "identity (0)", - "enum": true, - "type-name": "GstVideoOrientationMethod", - "values": [ - { - "desc": "GST_VIDEO_ORIENTATION_IDENTITY", - "name": "identity", - "value": "0" - }, - { - "desc": "GST_VIDEO_ORIENTATION_90R", - "name": "90r", - "value": "1" - }, - { - "desc": "GST_VIDEO_ORIENTATION_180", - "name": "180", - "value": "2" - }, - { - "desc": "GST_VIDEO_ORIENTATION_90L", - "name": "90l", - "value": "3" - }, - { - "desc": "GST_VIDEO_ORIENTATION_HORIZ", - "name": "horiz", - "value": "4" - }, - { - "desc": "GST_VIDEO_ORIENTATION_VERT", - "name": "vert", - "value": "5" - }, - { - "desc": "GST_VIDEO_ORIENTATION_UL_LR", - "name": "ul-lr", - "value": "6" - }, - { - "desc": "GST_VIDEO_ORIENTATION_UR_LL", - "name": "ur-ll", - "value": "7" - }, - { - "desc": "GST_VIDEO_ORIENTATION_AUTO", - "name": "auto", - "value": "8" - }, - { - "desc": "GST_VIDEO_ORIENTATION_CUSTOM", - "name": "custom", - "value": "9" - } - ], + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true - } - }, - "rank": "none" - }, - "videomedian": { - "author": "Wim Taymans ", - "description": "Apply a median filter to an image", - "hierarchy": [ - "GstVideoMedian", - "GstVideoFilter", - "GstBaseTransform", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Filter/Effect/Video", - "long-name": "Median effect", - "name": "videomedian", - "pad-templates": { - "sink": { - "caps": "video/x-raw:\n format: { I420, YV12 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", - "direction": "sink", - "presence": "always" }, - "src": { - "caps": "video/x-raw:\n format: { I420, YV12 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "filtersize": { - "blurb": "The size of the filter", + "skip-first-bytes": { + "blurb": "number of bytes to skip for each udp packet", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "5 (5)", - "enum": true, - "type-name": "GstVideoMedianSize", - "values": [ - { - "desc": "Median of 5 neighbour pixels", - "name": "5", - "value": "5" - }, - { - "desc": "Median of 9 neighbour pixels", - "name": "9", - "value": "9" - } - ], + "controllable": false, + "default": "0", + "max": "2147483647", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "lum-only": { - "blurb": "Only apply filter on luminance", + "socket": { + "blurb": "Socket to use for UDP reception. (NULL == allocate)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GSocket", "writable": true }, - "name": { - "blurb": "The name of the object", - "construct": true, + "timeout": { + "blurb": "Post a message after timeout nanoseconds (0 = disabled)", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "default": "0", + "max": "18446744073709551615", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "uri": { + "blurb": "URI in the form of udp://multicast_group:port", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "udp://0.0.0.0:5004", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "qos": { - "blurb": "Handle Quality-of-Service events", + "used-socket": { + "blurb": "Socket currently in use for UDP reception. (NULL = no socket)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GSocket", + "writable": false } }, "rank": "none" } }, - "filename": "gstvideofilter", + "filename": "gstudp", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" }, - "videomixer": { - "description": "Video mixer", + "video4linux2": { + "description": "elements for Video 4 Linux", "elements": { - "videomixer": { - "author": "Wim Taymans , Sebastian Dr\u00f6ge ", - "description": "Mix multiple video streams", + "v4l2radio": { + "author": "Alexey Chernov <4ernov@gmail.com>", + "description": "Controls a Video4Linux2 radio device", "hierarchy": [ - "GstVideoMixer2", + "GstV4l2Radio", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Filter/Editor/Video/Compositor", - "long-name": "Video mixer 2", - "name": "videomixer", - "pad-templates": { - "sink_%%u": { - "caps": "video/x-raw:\n format: { AYUV, BGRA, ARGB, RGBA, ABGR, Y444, Y42B, YUY2, UYVY, YVYU, I420, YV12, NV12, NV21, Y41B, RGB, BGR, xRGB, xBGR, RGBx, BGRx }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", - "direction": "sink", - "presence": "request" - }, - "src": { - "caps": "video/x-raw:\n format: { AYUV, BGRA, ARGB, RGBA, ABGR, Y444, Y42B, YUY2, UYVY, YVYU, I420, YV12, NV12, NV21, Y41B, RGB, BGR, xRGB, xBGR, RGBx, BGRx }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", - "direction": "src", - "presence": "always" - } - }, + "interfaces": [ + "GstURIHandler", + "GstTuner" + ], + "klass": "Tuner", + "long-name": "Radio (video4linux2) Tuner", "properties": { - "background": { - "blurb": "Background type", + "device": { + "blurb": "Video4Linux2 radio device location", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "checker (0)", - "enum": true, - "type-name": "GstVideoMixer2Background", - "values": [ - { - "desc": "Checker pattern", - "name": "checker", - "value": "0" - }, - { - "desc": "Black", - "name": "black", - "value": "1" - }, - { - "desc": "White", - "name": "white", - "value": "2" - }, - { - "desc": "Transparent Background to enable further mixing", - "name": "transparent", - "value": "3" - } - ], - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "default": "/dev/radio0", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "frequency": { + "blurb": "Station frequency in Hz", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "0", + "max": "108000000", + "min": "87500000", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true } }, - "rank": "primary" - } - }, - "filename": "gstvideomixer", - "license": "LGPL", - "package": "GStreamer Good Plug-ins git", - "source": "gst-plugins-good", - "tracers": {}, - "url": "Unknown package origin" - }, - "vpx": { - "description": "VP8 plugin", - "elements": { - "vp8dec": { - "author": "David Schleef , Sebastian Dr\u00f6ge ", - "description": "Decode VP8 video streams", + "rank": "none" + }, + "v4l2sink": { + "author": "Rob Clark ,", + "description": "Displays frames on a video4linux2 device", "hierarchy": [ - "GstVP8Dec", - "GstVPXDec", - "GstVideoDecoder", + "GstV4l2Sink", + "GstVideoSink", + "GstBaseSink", "GstElement", "GstObject", "GInitiallyUnowned", "GObject" ], - "klass": "Codec/Decoder/Video", - "long-name": "On2 VP8 Decoder", - "name": "vp8dec", + "interfaces": [ + "GstTuner", + "GstColorBalance", + "GstVideoOrientation" + ], + "klass": "Sink/Video", + "long-name": "Video (video4linux2) Sink", "pad-templates": { "sink": { - "caps": "video/x-vp8:\n", + "caps": "image/jpeg:\nvideo/mpeg:\n mpegversion: 4\n systemstream: false\nvideo/mpeg:\n mpegversion: { (int)1, (int)2 }\nvideo/mpegts:\n systemstream: true\nvideo/x-bayer:\n format: { bggr, gbrg, grbg, rggb }\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-dv:\n systemstream: true\nvideo/x-fwht:\nvideo/x-h263:\n variant: itu\nvideo/x-h264:\n stream-format: { (string)byte-stream, (string)avc }\n alignment: au\nvideo/x-h265:\n stream-format: byte-stream\n alignment: au\nvideo/x-pwc1:\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-pwc2:\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { RGB16, BGR, RGB, ABGR, xBGR, RGBA, RGBx, GRAY8, GRAY16_LE, GRAY16_BE, YVU9, YV12, YUY2, YVYU, UYVY, Y42B, Y41B, YUV9, NV12_64Z32, NV24, NV61, NV16, NV21, NV12, I420, ARGB, xRGB, BGRA, BGRx, BGR15, RGB15 }\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-sonix:\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-vp8:\nvideo/x-vp9:\nvideo/x-wmv:\n wmvversion: 3\n format: WVC1\n\nvideo/x-raw(format:Interlaced):\n format: { RGB16, BGR, RGB, ABGR, xBGR, RGBA, RGBx, GRAY8, GRAY16_LE, GRAY16_BE, YVU9, YV12, YUY2, YVYU, UYVY, Y42B, Y41B, YUV9, NV12_64Z32, NV24, NV61, NV16, NV21, NV12, I420, ARGB, xRGB, BGRA, BGRx, BGR15, RGB15 }\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: alternate\n", "direction": "sink", "presence": "always" - }, - "src": { - "caps": "video/x-raw:\n format: I420\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", - "direction": "src", - "presence": "always" } }, "properties": { - "deblocking-level": { - "blurb": "Deblocking level", + "brightness": { + "blurb": "Picture brightness, or more precisely, the black level", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "4", - "max": "16", + "controllable": true, + "default": "0", + "max": "2147483647", + "min": "-2147483648", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + }, + "contrast": { + "blurb": "Picture contrast or luma gain", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": true, + "default": "0", + "max": "2147483647", + "min": "-2147483648", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + }, + "crop-height": { + "blurb": "The height of the video crop; default is equal to negotiated image height", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "name": { - "blurb": "The name of the object", - "construct": true, + "crop-left": { + "blurb": "The leftmost (x) coordinate of the video crop; top left corner of image is 0,0", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "default": "0", + "max": "2147483647", + "min": "-2147483648", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "noise-level": { - "blurb": "Noise level", + "crop-top": { + "blurb": "The topmost (y) coordinate of the video crop; top left corner of image is 0,0", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", - "max": "16", + "max": "2147483647", + "min": "-2147483648", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + }, + "crop-width": { + "blurb": "The width of the video crop; default is equal to negotiated image width", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0", + "max": "-1", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "device": { + "blurb": "Device location", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": false, + "default": "/dev/video1", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "post-processing": { - "blurb": "Enable post processing", + "device-fd": { + "blurb": "File descriptor of the device", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "-1", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": false + }, + "device-name": { + "blurb": "Name of the device", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": false + }, + "extra-controls": { + "blurb": "Extra v4l2 controls (CIDs) for the device", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstStructure", "writable": true }, - "post-processing-flags": { - "blurb": "Flags to control post processing", + "flags": { + "blurb": "Device type flags", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "mfqe+demacroblock+deblock", - "type-name": "GstVPXDecPostProcessingFlags", - "values": [ - { - "desc": "Deblock", - "name": "deblock", - "value": "0x00000001" - }, - { - "desc": "Demacroblock", - "name": "demacroblock", - "value": "0x00000002" - }, - { - "desc": "Add noise", - "name": "addnoise", - "value": "0x00000004" - }, - { - "desc": "Multi-frame quality enhancement", - "name": "mfqe", - "value": "0x00000008" - } - ], - "writable": true + "controllable": false, + "default": "(none)", + "mutable": "null", + "readable": true, + "type": "GstV4l2DeviceTypeFlags", + "writable": false }, - "threads": { - "blurb": "Maximum number of decoding threads", + "force-aspect-ratio": { + "blurb": "When enabled, the pixel aspect ratio will be enforced", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "16", - "min": "0", - "type-name": "guint", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true - } - }, - "rank": "primary" - }, - "vp8enc": { - "author": "David Schleef , Sebastian Dr\u00f6ge ", - "description": "Encode VP8 video streams", - "hierarchy": [ - "GstVP8Enc", - "GstVPXEnc", - "GstVideoEncoder", - "GstElement", - "GstObject", - "GInitiallyUnowned", - "GObject" - ], - "klass": "Codec/Encoder/Video", - "long-name": "On2 VP8 Encoder", - "name": "vp8enc", - "pad-templates": { - "sink": { - "caps": "video/x-raw:\n format: I420\n width: [ 1, 16383 ]\n height: [ 1, 16383 ]\n framerate: [ 0/1, 2147483647/1 ]\n", - "direction": "sink", - "presence": "always" }, - "src": { - "caps": "video/x-vp8:\n profile: { (string)0, (string)1, (string)2, (string)3 }\n", - "direction": "src", - "presence": "always" - } - }, - "properties": { - "arnr-maxframes": { - "blurb": "AltRef maximum number of frames", + "hue": { + "blurb": "Hue or color balance", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", - "max": "15", - "min": "0", - "type-name": "gint", + "max": "2147483647", + "min": "-2147483648", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "arnr-strength": { - "blurb": "AltRef strength", + "io-mode": { + "blurb": "I/O mode", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "3", - "max": "6", - "min": "0", - "type-name": "gint", + "controllable": false, + "default": "auto (0)", + "mutable": "null", + "readable": true, + "type": "GstV4l2IOMode", "writable": true }, - "arnr-type": { - "blurb": "AltRef type", + "norm": { + "blurb": "video standard", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "3", - "max": "3", - "min": "1", - "type-name": "gint", + "controllable": false, + "default": "none (0)", + "mutable": "null", + "readable": true, + "type": "V4L2_TV_norms", "writable": true }, - "auto-alt-ref": { - "blurb": "Automatically generate AltRef frames", + "overlay-height": { + "blurb": "The height of the video overlay; default is equal to negotiated image height", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": false, + "default": "0", + "max": "-1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "buffer-initial-size": { - "blurb": "Initial client buffer size (ms)", + "overlay-left": { + "blurb": "The leftmost (x) coordinate of the video overlay; top left corner of screen is 0,0", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "4000", + "controllable": false, + "default": "0", "max": "2147483647", - "min": "0", - "type-name": "gint", + "min": "-2147483648", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "buffer-optimal-size": { - "blurb": "Optimal client buffer size (ms)", + "overlay-top": { + "blurb": "The topmost (y) coordinate of the video overlay; top left corner of screen is 0,0", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "5000", + "controllable": false, + "default": "0", "max": "2147483647", - "min": "0", - "type-name": "gint", + "min": "-2147483648", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "buffer-size": { - "blurb": "Client buffer size (ms)", + "overlay-width": { + "blurb": "The width of the video overlay; default is equal to negotiated image width", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "6000", - "max": "2147483647", + "controllable": false, + "default": "0", + "max": "-1", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, - "cpu-used": { - "blurb": "CPU used", + "pixel-aspect-ratio": { + "blurb": "Overwrite the pixel aspect ratio of the device", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "16", - "min": "-16", - "type-name": "gint", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "cq-level": { - "blurb": "Constrained quality level", + "saturation": { + "blurb": "Picture color saturation or chroma gain", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "10", - "max": "63", - "min": "0", - "type-name": "gint", + "controllable": true, + "default": "0", + "max": "2147483647", + "min": "-2147483648", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true - }, - "deadline": { - "blurb": "Deadline per frame (usec, 0=disabled)", + } + }, + "rank": "none" + }, + "v4l2src": { + "author": "Edgard Lima , Stefan Kost ", + "description": "Reads frames from a Video4Linux2 device", + "hierarchy": [ + "GstV4l2Src", + "GstPushSrc", + "GstBaseSrc", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstURIHandler", + "GstTuner", + "GstColorBalance", + "GstVideoOrientation" + ], + "klass": "Source/Video", + "long-name": "Video (video4linux2) Source", + "pad-templates": { + "src": { + "caps": "image/jpeg:\nvideo/mpeg:\n mpegversion: 4\n systemstream: false\nvideo/mpeg:\n mpegversion: { (int)1, (int)2 }\nvideo/mpegts:\n systemstream: true\nvideo/x-bayer:\n format: { bggr, gbrg, grbg, rggb }\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-dv:\n systemstream: true\nvideo/x-fwht:\nvideo/x-h263:\n variant: itu\nvideo/x-h264:\n stream-format: { (string)byte-stream, (string)avc }\n alignment: au\nvideo/x-h265:\n stream-format: byte-stream\n alignment: au\nvideo/x-pwc1:\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-pwc2:\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n format: { RGB16, BGR, RGB, ABGR, xBGR, RGBA, RGBx, GRAY8, GRAY16_LE, GRAY16_BE, YVU9, YV12, YUY2, YVYU, UYVY, Y42B, Y41B, YUV9, NV12_64Z32, NV24, NV61, NV16, NV21, NV12, I420, ARGB, xRGB, BGRA, BGRx, BGR15, RGB15 }\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-sonix:\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\nvideo/x-vp8:\nvideo/x-vp9:\nvideo/x-wmv:\n wmvversion: 3\n format: WVC1\n\nvideo/x-raw(format:Interlaced):\n format: { RGB16, BGR, RGB, ABGR, xBGR, RGBA, RGBx, GRAY8, GRAY16_LE, GRAY16_BE, YVU9, YV12, YUY2, YVYU, UYVY, Y42B, Y41B, YUV9, NV12_64Z32, NV24, NV61, NV16, NV21, NV12, I420, ARGB, xRGB, BGRA, BGRx, BGR15, RGB15 }\n width: [ 1, 32768 ]\n height: [ 1, 32768 ]\n framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: alternate\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "brightness": { + "blurb": "Picture brightness, or more precisely, the black level", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", + "max": "2147483647", + "min": "-2147483648", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "dropframe-threshold": { - "blurb": "Temporal resampling threshold (buf %%)", + "contrast": { + "blurb": "Picture contrast or luma gain", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", - "max": "100", - "min": "0", - "type-name": "gint", + "max": "2147483647", + "min": "-2147483648", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "end-usage": { - "blurb": "Rate control mode", + "device": { + "blurb": "Device location", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "vbr (0)", - "enum": true, - "type-name": "GstVPXEncEndUsage", - "values": [ - { - "desc": "Variable Bit Rate (VBR) mode", - "name": "vbr", - "value": "0" - }, - { - "desc": "Constant Bit Rate (CBR) mode", - "name": "cbr", - "value": "1" - }, - { - "desc": "Constant Quality Mode (CQ) mode", - "name": "cq", - "value": "2" - } - ], + "controllable": false, + "default": "/dev/video0", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "error-resilient": { - "blurb": "Error resilience flags", + "device-fd": { + "blurb": "File descriptor of the device", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "(none)", - "type-name": "GstVPXEncErFlags", - "values": [ - { - "desc": "Default error resilience", - "name": "default", - "value": "0x00000001" - }, - { - "desc": "Allow partitions to be decoded independently", - "name": "partitions", - "value": "0x00000002" - } - ], - "writable": true + "controllable": false, + "default": "-1", + "max": "2147483647", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": false }, - "horizontal-scaling-mode": { - "blurb": "Horizontal scaling mode", + "device-name": { + "blurb": "Name of the device", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "normal (0)", - "enum": true, - "type-name": "GstVPXEncScalingMode", - "values": [ - { - "desc": "Normal", - "name": "normal", - "value": "0" - }, - { - "desc": "4:5", - "name": "4:5", - "value": "1" - }, - { - "desc": "3:5", - "name": "3:5", - "value": "2" - }, - { - "desc": "1:2", - "name": "1:2", - "value": "3" - } - ], - "writable": true + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", + "writable": false }, - "keyframe-max-dist": { - "blurb": "Maximum distance between keyframes (number of frames)", + "extra-controls": { + "blurb": "Extra v4l2 controls (CIDs) for the device", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "128", - "max": "2147483647", - "min": "0", - "type-name": "gint", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GstStructure", "writable": true }, - "keyframe-mode": { - "blurb": "Keyframe placement", + "flags": { + "blurb": "Device type flags", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "auto (1)", - "enum": true, - "type-name": "GstVPXEncKfMode", - "values": [ - { - "desc": "Determine optimal placement automatically", - "name": "auto", - "value": "1" - }, - { - "desc": "Don't automatically place keyframes", - "name": "disabled", - "value": "0" - } - ], - "writable": true + "controllable": false, + "default": "(none)", + "mutable": "null", + "readable": true, + "type": "GstV4l2DeviceTypeFlags", + "writable": false }, - "lag-in-frames": { - "blurb": "Maximum number of frames to lag", + "force-aspect-ratio": { + "blurb": "When enabled, the pixel aspect ratio will be enforced", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "25", - "min": "0", - "type-name": "gint", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "max-intra-bitrate": { - "blurb": "Maximum Intra frame bitrate", + "hue": { + "blurb": "Hue or color balance", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "2147483647", - "min": "0", - "type-name": "gint", + "min": "-2147483648", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "max-quantizer": { - "blurb": "Maximum Quantizer (worst)", + "io-mode": { + "blurb": "I/O mode", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "63", - "max": "63", - "min": "0", - "type-name": "gint", + "controllable": false, + "default": "auto (0)", + "mutable": "null", + "readable": true, + "type": "GstV4l2IOMode", "writable": true }, - "min-quantizer": { - "blurb": "Minimum Quantizer (best)", + "norm": { + "blurb": "video standard", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "4", - "max": "63", - "min": "0", - "type-name": "gint", + "controllable": false, + "default": "none (0)", + "mutable": "null", + "readable": true, + "type": "V4L2_TV_norms", "writable": true }, - "multipass-cache-file": { - "blurb": "Multipass cache file. If stream caps reinited, multiple files will be created: file, file.1, file.2, ... and so on.", + "pixel-aspect-ratio": { + "blurb": "Overwrite the pixel aspect ratio of the device", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "multipass.cache", - "type-name": "gchararray", + "controllable": false, + "default": "NULL", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, - "multipass-mode": { - "blurb": "Multipass encode mode", + "saturation": { + "blurb": "Picture color saturation or chroma gain", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "one-pass (0)", - "enum": true, - "type-name": "GstVPXEncMultipassMode", - "values": [ + "controllable": true, + "default": "0", + "max": "2147483647", + "min": "-2147483648", + "mutable": "null", + "readable": true, + "type": "gint", + "writable": true + } + }, + "rank": "primary", + "signals": { + "prepare-format": { + "args": [ + { + "name": "arg0", + "type": "gint" + }, + { + "name": "arg1", + "type": "GstCaps" + } + ], + "return-type": "void", + "when": "last" + } + } + } + }, + "filename": "gstvideo4linux2", + "license": "LGPL", + "other-types": { + "GstTuner": { + "hierarchy": [ + "GstTuner", + "GInterface" + ], + "kind": "interface", + "signals": { + "channel-changed": { + "args": [ + { + "name": "arg0", + "type": "GstTunerChannel" + } + ], + "return-type": "void", + "when": "last" + }, + "frequency-changed": { + "args": [ { - "desc": "One pass encoding (default)", - "name": "one-pass", - "value": "0" + "name": "arg0", + "type": "GstTunerChannel" }, { - "desc": "First pass of multipass encoding", - "name": "first-pass", - "value": "1" + "name": "arg1", + "type": "gulong" + } + ], + "return-type": "void", + "when": "last" + }, + "norm-changed": { + "args": [ + { + "name": "arg0", + "type": "GstTunerNorm" + } + ], + "return-type": "void", + "when": "last" + }, + "signal-changed": { + "args": [ + { + "name": "arg0", + "type": "GstTunerChannel" }, { - "desc": "Last pass of multipass encoding", - "name": "last-pass", - "value": "2" + "name": "arg1", + "type": "gint" + } + ], + "return-type": "void", + "when": "last" + } + } + }, + "GstTunerChannel": { + "hierarchy": [ + "GstTunerChannel", + "GObject" + ], + "kind": "object", + "signals": { + "frequency-changed": { + "args": [ + { + "name": "arg0", + "type": "gulong" + } + ], + "return-type": "void", + "when": "last" + }, + "signal-changed": { + "args": [ + { + "name": "arg0", + "type": "gint" } ], + "return-type": "void", + "when": "last" + } + } + }, + "GstTunerNorm": { + "hierarchy": [ + "GstTunerNorm", + "GObject" + ], + "kind": "object" + }, + "GstV4l2DeviceTypeFlags": { + "kind": "flags", + "values": [ + { + "desc": "Device supports video capture", + "name": "capture", + "value": "0x00000001" + }, + { + "desc": "Device supports video playback", + "name": "output", + "value": "0x00000002" + }, + { + "desc": "Device supports video overlay", + "name": "overlay", + "value": "0x00000004" + }, + { + "desc": "Device supports the VBI capture", + "name": "vbi-capture", + "value": "0x00000010" + }, + { + "desc": "Device supports the VBI output", + "name": "vbi-output", + "value": "0x00000020" + }, + { + "desc": "Device has a tuner or modulator", + "name": "tuner", + "value": "0x00010000" + }, + { + "desc": "Device has audio inputs or outputs", + "name": "audio", + "value": "0x00020000" + } + ] + }, + "GstV4l2IOMode": { + "kind": "enum", + "values": [ + { + "desc": "GST_V4L2_IO_AUTO", + "name": "auto", + "value": "0" + }, + { + "desc": "GST_V4L2_IO_RW", + "name": "rw", + "value": "1" + }, + { + "desc": "GST_V4L2_IO_MMAP", + "name": "mmap", + "value": "2" + }, + { + "desc": "GST_V4L2_IO_USERPTR", + "name": "userptr", + "value": "3" + }, + { + "desc": "GST_V4L2_IO_DMABUF", + "name": "dmabuf", + "value": "4" + }, + { + "desc": "GST_V4L2_IO_DMABUF_IMPORT", + "name": "dmabuf-import", + "value": "5" + } + ] + }, + "V4L2_TV_norms": { + "kind": "enum", + "values": [ + { + "desc": "none", + "name": "none", + "value": "0" + }, + { + "desc": "NTSC", + "name": "NTSC", + "value": "45056" + }, + { + "desc": "NTSC-M", + "name": "NTSC-M", + "value": "4096" + }, + { + "desc": "NTSC-M-JP", + "name": "NTSC-M-JP", + "value": "8192" + }, + { + "desc": "NTSC-M-KR", + "name": "NTSC-M-KR", + "value": "32768" + }, + { + "desc": "NTSC-443", + "name": "NTSC-443", + "value": "16384" + }, + { + "desc": "PAL", + "name": "PAL", + "value": "255" + }, + { + "desc": "PAL-BG", + "name": "PAL-BG", + "value": "7" + }, + { + "desc": "PAL-B", + "name": "PAL-B", + "value": "1" + }, + { + "desc": "PAL-B1", + "name": "PAL-B1", + "value": "2" + }, + { + "desc": "PAL-G", + "name": "PAL-G", + "value": "4" + }, + { + "desc": "PAL-H", + "name": "PAL-H", + "value": "8" + }, + { + "desc": "PAL-I", + "name": "PAL-I", + "value": "16" + }, + { + "desc": "PAL-DK", + "name": "PAL-DK", + "value": "224" + }, + { + "desc": "PAL-D", + "name": "PAL-D", + "value": "32" + }, + { + "desc": "PAL-D1", + "name": "PAL-D1", + "value": "64" + }, + { + "desc": "PAL-K", + "name": "PAL-K", + "value": "128" + }, + { + "desc": "PAL-M", + "name": "PAL-M", + "value": "256" + }, + { + "desc": "PAL-N", + "name": "PAL-N", + "value": "512" + }, + { + "desc": "PAL-Nc", + "name": "PAL-Nc", + "value": "1024" + }, + { + "desc": "PAL-60", + "name": "PAL-60", + "value": "2048" + }, + { + "desc": "SECAM", + "name": "SECAM", + "value": "16711680" + }, + { + "desc": "SECAM-B", + "name": "SECAM-B", + "value": "65536" + }, + { + "desc": "SECAM-G", + "name": "SECAM-G", + "value": "262144" + }, + { + "desc": "SECAM-H", + "name": "SECAM-H", + "value": "524288" + }, + { + "desc": "SECAM-DK", + "name": "SECAM-DK", + "value": "3276800" + }, + { + "desc": "SECAM-D", + "name": "SECAM-D", + "value": "131072" + }, + { + "desc": "SECAM-K", + "name": "SECAM-K", + "value": "1048576" + }, + { + "desc": "SECAM-K1", + "name": "SECAM-K1", + "value": "2097152" + }, + { + "desc": "SECAM-L", + "name": "SECAM-L", + "value": "4194304" + }, + { + "desc": "SECAM-Lc", + "name": "SECAM-Lc", + "value": "8388608" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", + "source": "gst-plugins-good", + "tracers": {}, + "url": "Unknown package origin" + }, + "videobox": { + "description": "resizes a video by adding borders or cropping", + "elements": { + "videobox": { + "author": "Wim Taymans ", + "description": "Resizes a video by adding borders or cropping", + "hierarchy": [ + "GstVideoBox", + "GstVideoFilter", + "GstBaseTransform", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Filter/Effect/Video", + "long-name": "Video box filter", + "pad-templates": { + "sink": { + "caps": "video/x-raw:\n format: { AYUV, ARGB, BGRA, ABGR, RGBA, xRGB, BGRx, xBGR, RGBx, RGB, BGR, Y444, Y42B, YUY2, YVYU, UYVY, I420, YV12, Y41B, GRAY8, GRAY16_BE, GRAY16_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "video/x-raw:\n format: { AYUV, ARGB, BGRA, ABGR, RGBA, xRGB, BGRx, xBGR, RGBx, RGB, BGR, Y444, Y42B, YUY2, YVYU, UYVY, I420, YV12, Y41B, GRAY8, GRAY16_BE, GRAY16_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "alpha": { + "blurb": "Alpha value picture", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": true, + "default": "1", + "max": "1", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, - "name": { - "blurb": "The name of the object", - "construct": true, + "autocrop": { + "blurb": "Auto crop", + "conditionally-available": false, + "construct": false, "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "controllable": false, + "default": "false", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, - "noise-sensitivity": { - "blurb": "Noise sensisivity (frames to blur)", + "border-alpha": { + "blurb": "Alpha value of the border", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "6", + "controllable": true, + "default": "1", + "max": "1", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, - "overshoot": { - "blurb": "Datarate overshoot (max) target (%%)", + "bottom": { + "blurb": "Pixels to box at bottom (<0 = add a border)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "100", - "max": "1000", - "min": "0", - "type-name": "gint", + "controllable": true, + "default": "0", + "max": "2147483647", + "min": "-2147483648", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "parent": { - "blurb": "The parent of the object", + "fill": { + "blurb": "How to fill the borders", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GstObject", + "controllable": true, + "default": "black (0)", + "mutable": "null", + "readable": true, + "type": "GstVideoBoxFill", "writable": true }, - "qos": { - "blurb": "Handle Quality-of-Service events from downstream", + "left": { + "blurb": "Pixels to box at left (<0 = add a border)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": true, + "default": "0", + "max": "2147483647", + "min": "-2147483648", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "resize-allowed": { - "blurb": "Allow spatial resampling", + "right": { + "blurb": "Pixels to box at right (<0 = add a border)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "false", - "type-name": "gboolean", + "controllable": true, + "default": "0", + "max": "2147483647", + "min": "-2147483648", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, - "resize-down-threshold": { - "blurb": "Downscale threshold (buf %%)", + "top": { + "blurb": "Pixels to box at top (<0 = add a border)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "30", - "max": "100", - "min": "0", - "type-name": "gint", + "controllable": true, + "default": "0", + "max": "2147483647", + "min": "-2147483648", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true + } + }, + "rank": "none" + } + }, + "filename": "gstvideobox", + "license": "LGPL", + "other-types": { + "GstVideoBoxFill": { + "kind": "enum", + "values": [ + { + "desc": "Black", + "name": "black", + "value": "0" + }, + { + "desc": "Green", + "name": "green", + "value": "1" + }, + { + "desc": "Blue", + "name": "blue", + "value": "2" + }, + { + "desc": "Red", + "name": "red", + "value": "3" + }, + { + "desc": "Yellow", + "name": "yellow", + "value": "4" + }, + { + "desc": "White", + "name": "white", + "value": "5" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", + "source": "gst-plugins-good", + "tracers": {}, + "url": "Unknown package origin" + }, + "videocrop": { + "description": "Crops video into a user-defined region", + "elements": { + "aspectratiocrop": { + "author": "Thijs Vermeir ", + "description": "Crops video into a user-defined aspect-ratio", + "hierarchy": [ + "GstAspectRatioCrop", + "GstBin", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstChildProxy" + ], + "klass": "Filter/Effect/Video", + "long-name": "aspectratiocrop", + "pad-templates": { + "sink": { + "caps": "video/x-raw:\n format: { RGBx, xRGB, BGRx, xBGR, RGBA, ARGB, BGRA, ABGR, RGB, BGR, AYUV, YUY2, YVYU, UYVY, I420, YV12, RGB16, RGB15, GRAY8, NV12, NV21, GRAY16_LE, GRAY16_BE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "sink", + "presence": "always" }, - "resize-up-threshold": { - "blurb": "Upscale threshold (buf %%)", + "src": { + "caps": "video/x-raw:\n format: { RGBx, xRGB, BGRx, xBGR, RGBA, ARGB, BGRA, ABGR, RGB, BGR, AYUV, YUY2, YVYU, UYVY, I420, YV12, RGB16, RGB15, GRAY8, NV12, NV21, GRAY16_LE, GRAY16_BE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "aspect-ratio": { + "blurb": "Target aspect-ratio of video", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "60", - "max": "100", - "min": "0", - "type-name": "gint", + "controllable": false, + "default": "0/1", + "max": "2147483647/1", + "min": "0/1", + "mutable": "null", + "readable": true, + "type": "GstFraction", "writable": true + } + }, + "rank": "none" + }, + "videocrop": { + "author": "Tim-Philipp Müller ", + "description": "Crops video into a user-defined region", + "hierarchy": [ + "GstVideoCrop", + "GstVideoFilter", + "GstBaseTransform", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Filter/Effect/Video", + "long-name": "Crop", + "pad-templates": { + "sink": { + "caps": "video/x-raw:\n format: { RGBx, xRGB, BGRx, xBGR, RGBA, ARGB, BGRA, ABGR, RGB, BGR, AYUV, YUY2, Y444, Y42B, Y41B, YVYU, UYVY, I420, YV12, RGB16, RGB15, GRAY8, NV12, NV21, GRAY16_LE, GRAY16_BE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "sink", + "presence": "always" }, - "sharpness": { - "blurb": "Filter sharpness", + "src": { + "caps": "video/x-raw:\n format: { RGBx, xRGB, BGRx, xBGR, RGBA, ARGB, BGRA, ABGR, RGB, BGR, AYUV, YUY2, Y444, Y42B, Y41B, YVYU, UYVY, I420, YV12, RGB16, RGB15, GRAY8, NV12, NV21, GRAY16_LE, GRAY16_BE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "bottom": { + "blurb": "Pixels to crop at bottom (-1 to auto-crop)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", - "max": "7", - "min": "0", - "type-name": "gint", + "max": "2147483647", + "min": "-1", + "mutable": "playing", + "readable": true, + "type": "gint", "writable": true }, - "static-threshold": { - "blurb": "Motion detection threshold", + "left": { + "blurb": "Pixels to crop at left (-1 to auto-crop)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", "max": "2147483647", - "min": "0", - "type-name": "gint", + "min": "-1", + "mutable": "playing", + "readable": true, + "type": "gint", "writable": true }, - "target-bitrate": { - "blurb": "Target bitrate (in bits/sec)", + "right": { + "blurb": "Pixels to crop at right (-1 to auto-crop)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "256000", + "controllable": true, + "default": "0", "max": "2147483647", - "min": "0", - "type-name": "gint", + "min": "-1", + "mutable": "playing", + "readable": true, + "type": "gint", "writable": true }, - "temporal-scalability-layer-id": { - "blurb": "Sequence defining coding layer membership", + "top": { + "blurb": "Pixels to crop at top (-1 to auto-crop)", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GValueArray", + "controllable": true, + "default": "0", + "max": "2147483647", + "min": "-1", + "mutable": "playing", + "readable": true, + "type": "gint", "writable": true + } + }, + "rank": "none" + } + }, + "filename": "gstvideocrop", + "license": "LGPL", + "other-types": {}, + "package": "GStreamer Good Plug-ins", + "source": "gst-plugins-good", + "tracers": {}, + "url": "Unknown package origin" + }, + "videofilter": { + "description": "Video filters plugin", + "elements": { + "gamma": { + "author": "Arwed v. Merkatz ", + "description": "Adjusts brightness, contrast, hue, saturation on a video stream", + "hierarchy": [ + "GstVideoBalance", + "GstVideoFilter", + "GstBaseTransform", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstColorBalance" + ], + "klass": "Filter/Effect/Video", + "long-name": "Video balance", + "pad-templates": { + "sink": { + "caps": "video/x-raw:\n format: { AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, RGB, BGR, Y42B, YUY2, UYVY, YVYU, I420, YV12, IYUV, Y41B, NV12, NV21 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(ANY):\n", + "direction": "sink", + "presence": "always" }, - "temporal-scalability-periodicity": { - "blurb": "Length of sequence that defines layer membership periodicity", + "src": { + "caps": "video/x-raw:\n format: { AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, RGB, BGR, Y42B, YUY2, UYVY, YVYU, I420, YV12, IYUV, Y41B, NV12, NV21 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(ANY):\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "brightness": { + "blurb": "brightness", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": true, "default": "0", - "max": "16", - "min": "0", - "type-name": "gint", - "writable": true - }, - "temporal-scalability-rate-decimator": { - "blurb": "Rate decimation factors for each layer", - "construct": false, - "construct-only": false, - "type-name": "GValueArray", - "writable": true - }, - "temporal-scalability-target-bitrate": { - "blurb": "Target bitrates for coding layers (one per layer, decreasing)", - "construct": false, - "construct-only": false, - "type-name": "GValueArray", + "max": "1", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, - "threads": { - "blurb": "Number of threads to use", + "contrast": { + "blurb": "contrast", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "64", + "controllable": true, + "default": "1", + "max": "2", "min": "0", - "type-name": "gint", - "writable": true - }, - "timebase": { - "blurb": "Fraction of one second that is the shortest interframe time - normally left as zero which will default to the framerate", - "construct": false, - "construct-only": false, - "default": "0/1", - "max": "2147483647/1", - "min": "0/1", - "type-name": "GstFraction", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, - "token-partitions": { - "blurb": "Number of token partitions", + "hue": { + "blurb": "hue", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "1 (0)", - "enum": true, - "type-name": "GstVPXEncTokenPartitions", - "values": [ - { - "desc": "One token partition", - "name": "1", - "value": "0" - }, - { - "desc": "Two token partitions", - "name": "2", - "value": "1" - }, - { - "desc": "Four token partitions", - "name": "4", - "value": "2" - }, - { - "desc": "Eight token partitions", - "name": "8", - "value": "3" - } - ], + "controllable": true, + "default": "0", + "max": "1", + "min": "-1", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, - "tuning": { - "blurb": "Tuning", + "saturation": { + "blurb": "saturation", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "psnr (0)", - "enum": true, - "type-name": "GstVPXEncTuning", - "values": [ - { - "desc": "Tune for PSNR", - "name": "psnr", - "value": "0" - }, - { - "desc": "Tune for SSIM", - "name": "ssim", - "value": "1" - } - ], + "controllable": true, + "default": "1", + "max": "2", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true + } + }, + "rank": "none" + }, + "videoflip": { + "author": "David Schleef ", + "description": "Flips and rotates video", + "hierarchy": [ + "GstVideoFlip", + "GstVideoFilter", + "GstBaseTransform", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstVideoDirection" + ], + "klass": "Filter/Effect/Video", + "long-name": "Video flipper", + "pad-templates": { + "sink": { + "caps": "video/x-raw:\n format: { AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, RGB, BGR, I420, YV12, IYUV, YUY2, UYVY, YVYU, NV12, NV21, GRAY8, GRAY16_BE, GRAY16_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "sink", + "presence": "always" }, - "twopass-vbr-bias": { - "blurb": "CBR/VBR bias (0=CBR, 100=VBR)", - "construct": false, + "src": { + "caps": "video/x-raw:\n format: { AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, xBGR, BGRx, RGB, BGR, I420, YV12, IYUV, YUY2, UYVY, YVYU, NV12, NV21, GRAY8, GRAY16_BE, GRAY16_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "method": { + "blurb": "method (deprecated, use video-direction instead)", + "conditionally-available": false, + "construct": true, "construct-only": false, - "default": "50", - "max": "100", - "min": "0", - "type-name": "gint", + "controllable": true, + "default": "none (0)", + "mutable": "playing", + "readable": true, + "type": "GstVideoFlipMethod", "writable": true + } + }, + "rank": "none" + }, + "videomedian": { + "author": "Wim Taymans ", + "description": "Apply a median filter to an image", + "hierarchy": [ + "GstVideoMedian", + "GstVideoFilter", + "GstBaseTransform", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Filter/Effect/Video", + "long-name": "Median effect", + "pad-templates": { + "sink": { + "caps": "video/x-raw:\n format: { I420, YV12 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "sink", + "presence": "always" }, - "twopass-vbr-maxsection": { - "blurb": "GOP maximum bitrate (%% target)", + "src": { + "caps": "video/x-raw:\n format: { I420, YV12 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "filtersize": { + "blurb": "The size of the filter", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "400", - "max": "2147483647", - "min": "0", - "type-name": "gint", + "controllable": false, + "default": "5 (5)", + "mutable": "null", + "readable": true, + "type": "GstVideoMedianSize", "writable": true }, - "twopass-vbr-minsection": { - "blurb": "GOP minimum bitrate (%% target)", + "lum-only": { + "blurb": "Only apply filter on luminance", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", - "max": "2147483647", - "min": "0", - "type-name": "gint", + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true + } + }, + "rank": "none" + } + }, + "filename": "gstvideofilter", + "license": "LGPL", + "other-types": { + "GstVideoFlipMethod": { + "kind": "enum", + "values": [ + { + "desc": "Identity (no rotation)", + "name": "none", + "value": "0" + }, + { + "desc": "Rotate clockwise 90 degrees", + "name": "clockwise", + "value": "1" + }, + { + "desc": "Rotate 180 degrees", + "name": "rotate-180", + "value": "2" + }, + { + "desc": "Rotate counter-clockwise 90 degrees", + "name": "counterclockwise", + "value": "3" + }, + { + "desc": "Flip horizontally", + "name": "horizontal-flip", + "value": "4" + }, + { + "desc": "Flip vertically", + "name": "vertical-flip", + "value": "5" + }, + { + "desc": "Flip across upper left/lower right diagonal", + "name": "upper-left-diagonal", + "value": "6" + }, + { + "desc": "Flip across upper right/lower left diagonal", + "name": "upper-right-diagonal", + "value": "7" + }, + { + "desc": "Select flip method based on image-orientation tag", + "name": "automatic", + "value": "8" + } + ] + }, + "GstVideoMedianSize": { + "kind": "enum", + "values": [ + { + "desc": "Median of 5 neighbour pixels", + "name": "5", + "value": "5" + }, + { + "desc": "Median of 9 neighbour pixels", + "name": "9", + "value": "9" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", + "source": "gst-plugins-good", + "tracers": {}, + "url": "Unknown package origin" + }, + "videomixer": { + "description": "Video mixer", + "elements": { + "videomixer": { + "author": "Wim Taymans , Sebastian Dröge ", + "description": "Mix multiple video streams", + "hierarchy": [ + "GstVideoMixer2", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstChildProxy" + ], + "klass": "Filter/Editor/Video/Compositor", + "long-name": "Video mixer 2", + "pad-templates": { + "sink_%%u": { + "caps": "video/x-raw:\n format: { AYUV, BGRA, ARGB, RGBA, ABGR, Y444, Y42B, YUY2, UYVY, YVYU, I420, YV12, NV12, NV21, Y41B, RGB, BGR, xRGB, xBGR, RGBx, BGRx }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "sink", + "presence": "request" }, - "undershoot": { - "blurb": "Datarate undershoot (min) target (%%)", + "src": { + "caps": "video/x-raw:\n format: { AYUV, BGRA, ARGB, RGBA, ABGR, Y444, Y42B, YUY2, UYVY, YVYU, I420, YV12, NV12, NV21, Y41B, RGB, BGR, xRGB, xBGR, RGBx, BGRx }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": { + "background": { + "blurb": "Background type", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "100", - "max": "1000", - "min": "0", - "type-name": "gint", + "controllable": false, + "default": "checker (0)", + "mutable": "null", + "readable": true, + "type": "GstVideoMixer2Background", "writable": true + } + }, + "rank": "primary" + } + }, + "filename": "gstvideomixer", + "license": "LGPL", + "other-types": { + "GstVideoMixer2Background": { + "kind": "enum", + "values": [ + { + "desc": "Checker pattern", + "name": "checker", + "value": "0" + }, + { + "desc": "Black", + "name": "black", + "value": "1" + }, + { + "desc": "White", + "name": "white", + "value": "2" + }, + { + "desc": "Transparent Background to enable further mixing", + "name": "transparent", + "value": "3" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", + "source": "gst-plugins-good", + "tracers": {}, + "url": "Unknown package origin" + }, + "vpx": { + "description": "VP8 plugin", + "elements": { + "vp8dec": { + "author": "David Schleef , Sebastian Dröge ", + "description": "Decode VP8 video streams", + "hierarchy": [ + "GstVP8Dec", + "GstVPXDec", + "GstVideoDecoder", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Decoder/Video", + "long-name": "On2 VP8 Decoder", + "pad-templates": { + "sink": { + "caps": "video/x-vp8:\n", + "direction": "sink", + "presence": "always" }, - "vertical-scaling-mode": { - "blurb": "Vertical scaling mode", - "construct": false, - "construct-only": false, - "default": "normal (0)", - "enum": true, - "type-name": "GstVPXEncScalingMode", - "values": [ - { - "desc": "Normal", - "name": "normal", - "value": "0" - }, - { - "desc": "4:5", - "name": "4:5", - "value": "1" - }, - { - "desc": "3:5", - "name": "3:5", - "value": "2" - }, - { - "desc": "1:2", - "name": "1:2", - "value": "3" - } - ], - "writable": true + "src": { + "caps": "video/x-raw:\n format: I420\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "primary" + }, + "vp8enc": { + "author": "David Schleef , Sebastian Dröge ", + "description": "Encode VP8 video streams", + "hierarchy": [ + "GstVP8Enc", + "GstVPXEnc", + "GstVideoEncoder", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstPreset", + "GstTagSetter" + ], + "klass": "Codec/Encoder/Video", + "long-name": "On2 VP8 Encoder", + "pad-templates": { + "sink": { + "caps": "video/x-raw:\n format: I420\n width: [ 1, 16383 ]\n height: [ 1, 16383 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "video/x-vp8:\n profile: { (string)0, (string)1, (string)2, (string)3 }\n", + "direction": "src", + "presence": "always" } }, + "properties": {}, "rank": "primary" }, "vp9dec": { - "author": "David Schleef , Sebastian Dr\u00f6ge ", + "author": "David Schleef , Sebastian Dröge ", "description": "Decode VP9 video streams", "hierarchy": [ "GstVP9Dec", @@ -36627,7 +25839,6 @@ ], "klass": "Codec/Decoder/Video", "long-name": "On2 VP9 Decoder", - "name": "vp9dec", "pad-templates": { "sink": { "caps": "video/x-vp9:\n", @@ -36635,104 +25846,157 @@ "presence": "always" }, "src": { - "caps": "video/x-raw:\n format: { I420, YV12, Y42B, Y444 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "caps": "video/x-raw:\n format: { I420, YV12, Y42B, Y444, GBR }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + } + }, + "properties": {}, + "rank": "primary" + }, + "vp9enc": { + "author": "David Schleef , Sebastian Dröge ", + "description": "Encode VP9 video streams", + "hierarchy": [ + "GstVP9Enc", + "GstVPXEnc", + "GstVideoEncoder", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "interfaces": [ + "GstPreset", + "GstTagSetter" + ], + "klass": "Codec/Encoder/Video", + "long-name": "On2 VP9 Encoder", + "pad-templates": { + "sink": { + "caps": "video/x-raw:\n format: { I420, YV12 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "video/x-vp9:\n profile: { (string)0, (string)1, (string)2, (string)3 }\n", "direction": "src", "presence": "always" } }, + "properties": {}, + "rank": "primary" + } + }, + "filename": "gstvpx", + "license": "LGPL", + "other-types": { + "GstVPXDec": { + "hierarchy": [ + "GstVPXDec", + "GstVideoDecoder", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "kind": "object", "properties": { "deblocking-level": { "blurb": "Deblocking level", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "4", "max": "16", "min": "0", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "noise-level": { "blurb": "Noise level", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "16", "min": "0", - "type-name": "guint", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "post-processing": { "blurb": "Enable post processing", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "post-processing-flags": { "blurb": "Flags to control post processing", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "mfqe+demacroblock+deblock", - "type-name": "GstVPXDecPostProcessingFlags", - "values": [ - { - "desc": "Deblock", - "name": "deblock", - "value": "0x00000001" - }, - { - "desc": "Demacroblock", - "name": "demacroblock", - "value": "0x00000002" - }, - { - "desc": "Add noise", - "name": "addnoise", - "value": "0x00000004" - }, - { - "desc": "Multi-frame quality enhancement", - "name": "mfqe", - "value": "0x00000008" - } - ], + "mutable": "null", + "readable": true, + "type": "GstVPXDecPostProcessingFlags", "writable": true }, "threads": { "blurb": "Maximum number of decoding threads", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "16", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true } - }, - "rank": "primary" + } }, - "vp9enc": { - "author": "David Schleef , Sebastian Dr\u00f6ge ", - "description": "Encode VP9 video streams", + "GstVPXDecPostProcessingFlags": { + "kind": "flags", + "values": [ + { + "desc": "Deblock", + "name": "deblock", + "value": "0x00000001" + }, + { + "desc": "Demacroblock", + "name": "demacroblock", + "value": "0x00000002" + }, + { + "desc": "Add noise", + "name": "addnoise", + "value": "0x00000004" + }, + { + "desc": "Multi-frame quality enhancement", + "name": "mfqe", + "value": "0x00000008" + } + ] + }, + "GstVPXEnc": { "hierarchy": [ - "GstVP9Enc", "GstVPXEnc", "GstVideoEncoder", "GstElement", @@ -36740,605 +26004,750 @@ "GInitiallyUnowned", "GObject" ], - "klass": "Codec/Encoder/Video", - "long-name": "On2 VP9 Encoder", - "name": "vp9enc", - "pad-templates": { - "sink": { - "caps": "video/x-raw:\n format: { I420, YV12 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", - "direction": "sink", - "presence": "always" - }, - "src": { - "caps": "video/x-vp9:\n profile: { (string)0, (string)1, (string)2, (string)3 }\n", - "direction": "src", - "presence": "always" - } - }, + "interfaces": [ + "GstPreset", + "GstTagSetter" + ], + "kind": "object", "properties": { "arnr-maxframes": { "blurb": "AltRef maximum number of frames", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "15", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "arnr-strength": { "blurb": "AltRef strength", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "3", "max": "6", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "arnr-type": { "blurb": "AltRef type", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "3", "max": "3", "min": "1", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "auto-alt-ref": { "blurb": "Automatically generate AltRef frames", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, + "bits-per-pixel": { + "blurb": "Factor to convert number of pixels to bitrate value (only has an effect if target-bitrate=0)", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "0.0434", + "max": "3.40282e+38", + "min": "0", + "mutable": "null", + "readable": true, + "type": "gfloat", "writable": true }, "buffer-initial-size": { "blurb": "Initial client buffer size (ms)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "4000", "max": "2147483647", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "buffer-optimal-size": { "blurb": "Optimal client buffer size (ms)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "5000", "max": "2147483647", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "buffer-size": { "blurb": "Client buffer size (ms)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "6000", "max": "2147483647", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "cpu-used": { "blurb": "CPU used", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "16", "min": "-16", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "cq-level": { "blurb": "Constrained quality level", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "10", "max": "63", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "deadline": { "blurb": "Deadline per frame (usec, 0=disabled)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "9223372036854775807", "min": "0", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "gint64", "writable": true }, "dropframe-threshold": { "blurb": "Temporal resampling threshold (buf %%)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "100", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "end-usage": { "blurb": "Rate control mode", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "vbr (0)", - "enum": true, - "type-name": "GstVPXEncEndUsage", - "values": [ - { - "desc": "Variable Bit Rate (VBR) mode", - "name": "vbr", - "value": "0" - }, - { - "desc": "Constant Bit Rate (CBR) mode", - "name": "cbr", - "value": "1" - }, - { - "desc": "Constant Quality Mode (CQ) mode", - "name": "cq", - "value": "2" - } - ], + "mutable": "null", + "readable": true, + "type": "GstVPXEncEndUsage", "writable": true }, "error-resilient": { "blurb": "Error resilience flags", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "(none)", - "type-name": "GstVPXEncErFlags", - "values": [ - { - "desc": "Default error resilience", - "name": "default", - "value": "0x00000001" - }, - { - "desc": "Allow partitions to be decoded independently", - "name": "partitions", - "value": "0x00000002" - } - ], + "mutable": "null", + "readable": true, + "type": "GstVPXEncErFlags", "writable": true }, "horizontal-scaling-mode": { "blurb": "Horizontal scaling mode", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "normal (0)", - "enum": true, - "type-name": "GstVPXEncScalingMode", - "values": [ - { - "desc": "Normal", - "name": "normal", - "value": "0" - }, - { - "desc": "4:5", - "name": "4:5", - "value": "1" - }, - { - "desc": "3:5", - "name": "3:5", - "value": "2" - }, - { - "desc": "1:2", - "name": "1:2", - "value": "3" - } - ], + "mutable": "null", + "readable": true, + "type": "GstVPXEncScalingMode", "writable": true }, "keyframe-max-dist": { "blurb": "Maximum distance between keyframes (number of frames)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "128", "max": "2147483647", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "keyframe-mode": { "blurb": "Keyframe placement", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "auto (1)", - "enum": true, - "type-name": "GstVPXEncKfMode", - "values": [ - { - "desc": "Determine optimal placement automatically", - "name": "auto", - "value": "1" - }, - { - "desc": "Don't automatically place keyframes", - "name": "disabled", - "value": "0" - } - ], + "controllable": false, + "default": "auto (1)", + "mutable": "null", + "readable": true, + "type": "GstVPXEncKfMode", "writable": true }, "lag-in-frames": { "blurb": "Maximum number of frames to lag", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "25", + "controllable": false, + "default": "0", "max": "25", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "max-intra-bitrate": { "blurb": "Maximum Intra frame bitrate", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "2147483647", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "max-quantizer": { "blurb": "Maximum Quantizer (worst)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "63", "max": "63", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "min-quantizer": { "blurb": "Minimum Quantizer (best)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", + "controllable": false, + "default": "4", "max": "63", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "multipass-cache-file": { "blurb": "Multipass cache file. If stream caps reinited, multiple files will be created: file, file.1, file.2, ... and so on.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "multipass.cache", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, "multipass-mode": { "blurb": "Multipass encode mode", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "one-pass (0)", - "enum": true, - "type-name": "GstVPXEncMultipassMode", - "values": [ - { - "desc": "One pass encoding (default)", - "name": "one-pass", - "value": "0" - }, - { - "desc": "First pass of multipass encoding", - "name": "first-pass", - "value": "1" - }, - { - "desc": "Last pass of multipass encoding", - "name": "last-pass", - "value": "2" - } - ], - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "GstVPXEncMultipassMode", "writable": true }, "noise-sensitivity": { "blurb": "Noise sensisivity (frames to blur)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "6", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "overshoot": { "blurb": "Datarate overshoot (max) target (%%)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "25", + "controllable": false, + "default": "100", "max": "1000", "min": "0", - "type-name": "gint", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events from downstream", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "resize-allowed": { "blurb": "Allow spatial resampling", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "resize-down-threshold": { "blurb": "Downscale threshold (buf %%)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "30", + "controllable": false, + "default": "60", "max": "100", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "resize-up-threshold": { "blurb": "Upscale threshold (buf %%)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "60", + "controllable": false, + "default": "30", "max": "100", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "sharpness": { "blurb": "Filter sharpness", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "7", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "static-threshold": { - "blurb": "Motion detection threshold", + "blurb": "Motion detection threshold. Recommendation is to set 100 for screen/window sharing", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "0", + "controllable": false, + "default": "1", "max": "2147483647", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "target-bitrate": { - "blurb": "Target bitrate (in bits/sec)", + "blurb": "Target bitrate (in bits/sec) (0: auto - bitrate depends on resolution, see \"bits-per-pixel\" property for more info)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "256000", + "controllable": false, + "default": "0", "max": "2147483647", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "temporal-scalability-layer-id": { "blurb": "Sequence defining coding layer membership", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GValueArray", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GValueArray", "writable": true }, "temporal-scalability-number-layers": { "blurb": "Number of coding layers to use", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "1", "max": "5", "min": "1", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "temporal-scalability-periodicity": { "blurb": "Length of sequence that defines layer membership periodicity", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "16", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "temporal-scalability-rate-decimator": { "blurb": "Rate decimation factors for each layer", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GValueArray", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GValueArray", "writable": true }, "temporal-scalability-target-bitrate": { "blurb": "Target bitrates for coding layers (one per layer, decreasing)", + "conditionally-available": false, "construct": false, "construct-only": false, - "type-name": "GValueArray", + "controllable": false, + "mutable": "null", + "readable": true, + "type": "GValueArray", "writable": true }, "threads": { "blurb": "Number of threads to use", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "8", + "controllable": false, + "default": "0", "max": "64", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "timebase": { "blurb": "Fraction of one second that is the shortest interframe time - normally left as zero which will default to the framerate", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0/1", "max": "2147483647/1", "min": "0/1", - "type-name": "GstFraction", + "mutable": "null", + "readable": true, + "type": "GstFraction", "writable": true }, "token-partitions": { "blurb": "Number of token partitions", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "1 (0)", - "enum": true, - "type-name": "GstVPXEncTokenPartitions", - "values": [ - { - "desc": "One token partition", - "name": "1", - "value": "0" - }, - { - "desc": "Two token partitions", - "name": "2", - "value": "1" - }, - { - "desc": "Four token partitions", - "name": "4", - "value": "2" - }, - { - "desc": "Eight token partitions", - "name": "8", - "value": "3" - } - ], + "mutable": "null", + "readable": true, + "type": "GstVPXEncTokenPartitions", "writable": true }, "tuning": { "blurb": "Tuning", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "psnr (0)", - "enum": true, - "type-name": "GstVPXEncTuning", - "values": [ - { - "desc": "Tune for PSNR", - "name": "psnr", - "value": "0" - }, - { - "desc": "Tune for SSIM", - "name": "ssim", - "value": "1" - } - ], + "mutable": "null", + "readable": true, + "type": "GstVPXEncTuning", "writable": true }, "twopass-vbr-bias": { "blurb": "CBR/VBR bias (0=CBR, 100=VBR)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "50", "max": "100", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "twopass-vbr-maxsection": { "blurb": "GOP maximum bitrate (%% target)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "2000", + "controllable": false, + "default": "0", "max": "2147483647", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "twopass-vbr-minsection": { "blurb": "GOP minimum bitrate (%% target)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "2147483647", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "undershoot": { "blurb": "Datarate undershoot (min) target (%%)", + "conditionally-available": false, "construct": false, "construct-only": false, - "default": "25", + "controllable": false, + "default": "100", "max": "1000", "min": "0", - "type-name": "gint", + "mutable": "null", + "readable": true, + "type": "gint", "writable": true }, "vertical-scaling-mode": { "blurb": "Vertical scaling mode", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "normal (0)", - "enum": true, - "type-name": "GstVPXEncScalingMode", - "values": [ - { - "desc": "Normal", - "name": "normal", - "value": "0" - }, - { - "desc": "4:5", - "name": "4:5", - "value": "1" - }, - { - "desc": "3:5", - "name": "3:5", - "value": "2" - }, - { - "desc": "1:2", - "name": "1:2", - "value": "3" - } - ], + "mutable": "null", + "readable": true, + "type": "GstVPXEncScalingMode", "writable": true } - }, - "rank": "primary" + } + }, + "GstVPXEncEndUsage": { + "kind": "enum", + "values": [ + { + "desc": "Variable Bit Rate (VBR) mode", + "name": "vbr", + "value": "0" + }, + { + "desc": "Constant Bit Rate (CBR) mode", + "name": "cbr", + "value": "1" + }, + { + "desc": "Constant Quality Mode (CQ) mode", + "name": "cq", + "value": "2" + } + ] + }, + "GstVPXEncErFlags": { + "kind": "flags", + "values": [ + { + "desc": "Default error resilience", + "name": "default", + "value": "0x00000001" + }, + { + "desc": "Allow partitions to be decoded independently", + "name": "partitions", + "value": "0x00000002" + } + ] + }, + "GstVPXEncKfMode": { + "kind": "enum", + "values": [ + { + "desc": "Determine optimal placement automatically", + "name": "auto", + "value": "1" + }, + { + "desc": "Don't automatically place keyframes", + "name": "disabled", + "value": "0" + } + ] + }, + "GstVPXEncMultipassMode": { + "kind": "enum", + "values": [ + { + "desc": "One pass encoding (default)", + "name": "one-pass", + "value": "0" + }, + { + "desc": "First pass of multipass encoding", + "name": "first-pass", + "value": "1" + }, + { + "desc": "Last pass of multipass encoding", + "name": "last-pass", + "value": "2" + } + ] + }, + "GstVPXEncScalingMode": { + "kind": "enum", + "values": [ + { + "desc": "Normal", + "name": "normal", + "value": "0" + }, + { + "desc": "4:5", + "name": "4:5", + "value": "1" + }, + { + "desc": "3:5", + "name": "3:5", + "value": "2" + }, + { + "desc": "1:2", + "name": "1:2", + "value": "3" + } + ] + }, + "GstVPXEncTokenPartitions": { + "kind": "enum", + "values": [ + { + "desc": "One token partition", + "name": "1", + "value": "0" + }, + { + "desc": "Two token partitions", + "name": "2", + "value": "1" + }, + { + "desc": "Four token partitions", + "name": "4", + "value": "2" + }, + { + "desc": "Eight token partitions", + "name": "8", + "value": "3" + } + ] + }, + "GstVPXEncTuning": { + "kind": "enum", + "values": [ + { + "desc": "Tune for PSNR", + "name": "psnr", + "value": "0" + }, + { + "desc": "Tune for SSIM", + "name": "ssim", + "value": "1" + } + ] } }, - "filename": "gstvpx", - "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -37356,9 +26765,12 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstTagSetter", + "GstTocSetter" + ], "klass": "Codec/Muxer/Audio", "long-name": "WAV audio muxer", - "name": "wavenc", "pad-templates": { "sink": { "caps": "audio/x-raw:\n rate: [ 1, 2147483647 ]\n channels: [ 1, 65535 ]\n format: { S32LE, S24LE, S16LE, U8, F32LE, F64LE }\n layout: interleaved\naudio/x-alaw:\n rate: [ 8000, 192000 ]\n channels: [ 1, 2 ]\naudio/x-mulaw:\n rate: [ 8000, 192000 ]\n channels: [ 1, 2 ]\n", @@ -37371,30 +26783,13 @@ "presence": "always" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - } - }, "rank": "primary" } }, "filename": "gstwavenc", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -37403,7 +26798,7 @@ "description": "Wavpack lossless/lossy audio format handling", "elements": { "wavpackdec": { - "author": "Arwed v. Merkatz , Sebastian Dr\u00f6ge ", + "author": "Arwed v. Merkatz , Sebastian Dröge ", "description": "Decodes Wavpack audio data", "hierarchy": [ "GstWavpackDec", @@ -37415,7 +26810,6 @@ ], "klass": "Codec/Decoder/Audio", "long-name": "Wavpack audio decoder", - "name": "wavpackdec", "pad-templates": { "sink": { "caps": "audio/x-wavpack:\n depth: [ 1, 32 ]\n channels: [ 1, 8 ]\n rate: [ 6000, 192000 ]\n framed: true\n", @@ -37423,61 +26817,16 @@ "presence": "always" }, "src": { - "caps": "audio/x-raw:\n format: S8\n layout: interleaved\n channels: [ 1, 8 ]\n rate: [ 6000, 192000 ]\naudio/x-raw:\n format: S16LE\n layout: interleaved\n channels: [ 1, 8 ]\n rate: [ 6000, 192000 ]\naudio/x-raw:\n format: S32LE\n layout: interleaved\n channels: [ 1, 8 ]\n rate: [ 6000, 192000 ]\n", + "caps": "audio/x-raw:\n format: S8\n layout: interleaved\n channels: [ 1, 8 ]\n rate: [ 6000, 192000 ]\naudio/x-raw:\n format: S16LE\n layout: interleaved\n channels: [ 1, 8 ]\n rate: [ 6000, 192000 ]\naudio/x-raw:\n format: S32LE\n layout: interleaved\n channels: [ 1, 8 ]\n rate: [ 6000, 192000 ]\naudio/x-raw:\n format: F32LE\n layout: interleaved\n channels: [ 1, 8 ]\n rate: [ 6000, 192000 ]\n", "direction": "src", "presence": "always" } }, - "properties": { - "min-latency": { - "blurb": "Aggregate output data to a minimum of latency time (ns)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "plc": { - "blurb": "Perform packet loss concealment (if supported)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - }, - "tolerance": { - "blurb": "Perfect ts while timestamp jitter/imperfection within tolerance (ns)", - "construct": false, - "construct-only": false, - "default": "0", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", - "writable": true - } - }, + "properties": {}, "rank": "primary" }, "wavpackenc": { - "author": "Sebastian Dr\u00f6ge ", + "author": "Sebastian Dröge ", "description": "Encodes audio with the Wavpack lossless/lossy audio codec", "hierarchy": [ "GstWavpackEnc", @@ -37487,9 +26836,11 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstPreset" + ], "klass": "Codec/Encoder/Audio", "long-name": "Wavpack audio encoder", - "name": "wavpackenc", "pad-templates": { "sink": { "caps": "audio/x-raw:\n format: S32LE\n layout: interleaved\n channels: [ 1, 8 ]\n rate: [ 6000, 192000 ]\n", @@ -37510,200 +26861,169 @@ "properties": { "bitrate": { "blurb": "Try to encode with this average bitrate (bits/sec). This enables lossy encoding, values smaller than 24000 disable it again.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "9600000", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "bits-per-sample": { "blurb": "Try to encode with this amount of bits per sample. This enables lossy encoding, values smaller than 2.0 disable it again.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "24", "min": "0", - "type-name": "gdouble", + "mutable": "null", + "readable": true, + "type": "gdouble", "writable": true }, "correction-mode": { "blurb": "Use this mode for the correction stream. Only works in lossy mode!", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "off (0)", - "enum": true, - "type-name": "GstWavpackEncCorrectionMode", - "values": [ - { - "desc": "Create no correction file", - "name": "off", - "value": "0" - }, - { - "desc": "Create correction file", - "name": "on", - "value": "1" - }, - { - "desc": "Create optimized correction file", - "name": "optimized", - "value": "2" - } - ], + "mutable": "null", + "readable": true, + "type": "GstWavpackEncCorrectionMode", "writable": true }, "extra-processing": { "blurb": "Use better but slower filters for better compression/quality.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "6", "min": "0", - "type-name": "guint", - "writable": true - }, - "hard-resync": { - "blurb": "Perform clipping and sample flushing upon discontinuity", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "joint-stereo-mode": { "blurb": "Use this joint-stereo mode.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "auto (0)", - "enum": true, - "type-name": "GstWavpackEncJSMode", - "values": [ - { - "desc": "auto", - "name": "auto", - "value": "0" - }, - { - "desc": "left/right", - "name": "leftright", - "value": "1" - }, - { - "desc": "mid/side", - "name": "midside", - "value": "2" - } - ], + "mutable": "null", + "readable": true, + "type": "GstWavpackEncJSMode", "writable": true }, - "mark-granule": { - "blurb": "Apply granule semantics to buffer metadata (implies perfect-timestamp)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": false - }, "md5": { "blurb": "Store MD5 hash of raw samples within the file.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "mode": { "blurb": "Speed versus compression tradeoff.", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "normal (2)", - "enum": true, - "type-name": "GstWavpackEncMode", - "values": [ - { - "desc": "Fast Compression", - "name": "fast", - "value": "1" - }, - { - "desc": "Normal Compression", - "name": "normal", - "value": "2" - }, - { - "desc": "High Compression", - "name": "high", - "value": "3" - }, - { - "desc": "Very High Compression", - "name": "veryhigh", - "value": "4" - } - ], - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "perfect-timestamp": { - "blurb": "Favour perfect timestamps over tracking upstream timestamps", - "construct": false, - "construct-only": false, - "default": "true", - "type-name": "gboolean", - "writable": true - }, - "tolerance": { - "blurb": "Consider discontinuity if timestamp jitter/imperfection exceeds tolerance (ns)", - "construct": false, - "construct-only": false, - "default": "40000000", - "max": "9223372036854775807", - "min": "0", - "type-name": "gint64", + "mutable": "null", + "readable": true, + "type": "GstWavpackEncMode", "writable": true } }, "rank": "none", - "signals": { - "no-more-pads": { - "args": [], - "retval": "void" - }, - "pad-added": { - "args": [ - "GstPad" - ], - "retval": "void" - }, - "pad-removed": { - "args": [ - "GstPad" - ], - "retval": "void" - } - } + "signals": {} } }, "filename": "gstwavpack", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": { + "GstWavpackEncCorrectionMode": { + "kind": "enum", + "values": [ + { + "desc": "Create no correction file", + "name": "off", + "value": "0" + }, + { + "desc": "Create correction file", + "name": "on", + "value": "1" + }, + { + "desc": "Create optimized correction file", + "name": "optimized", + "value": "2" + } + ] + }, + "GstWavpackEncJSMode": { + "kind": "enum", + "values": [ + { + "desc": "auto", + "name": "auto", + "value": "0" + }, + { + "desc": "left/right", + "name": "leftright", + "value": "1" + }, + { + "desc": "mid/side", + "name": "midside", + "value": "2" + } + ] + }, + "GstWavpackEncMode": { + "kind": "enum", + "values": [ + { + "desc": "Fast Compression", + "name": "fast", + "value": "1" + }, + { + "desc": "Normal Compression", + "name": "normal", + "value": "2" + }, + { + "desc": "High Compression", + "name": "high", + "value": "3" + }, + { + "desc": "Very High Compression", + "name": "veryhigh", + "value": "4" + } + ] + } + }, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -37723,7 +27043,6 @@ ], "klass": "Codec/Demuxer/Audio", "long-name": "WAV audio demuxer", - "name": "wavparse", "pad-templates": { "sink": { "caps": "audio/x-wav:\naudio/x-rf64:\n", @@ -37739,26 +27058,14 @@ "properties": { "ignore-length": { "blurb": "Ignore length from the Wave header", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true } }, @@ -37767,7 +27074,8 @@ }, "filename": "gstwavparse", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -37789,7 +27097,6 @@ ], "klass": "Source/Video", "long-name": "Ximage video source", - "name": "ximagesrc", "pad-templates": { "src": { "caps": "video/x-raw:\n framerate: [ 0/1, 2147483647/1 ]\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\npixel-aspect-ratio: [ 0/1, 2147483647/1 ]\n", @@ -37798,146 +27105,134 @@ } }, "properties": { - "blocksize": { - "blurb": "Size in bytes to read per buffer (-1 = default)", - "construct": false, - "construct-only": false, - "default": "4096", - "max": "-1", - "min": "0", - "type-name": "guint", - "writable": true - }, "display-name": { "blurb": "X Display Name", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", - "writable": true - }, - "do-timestamp": { - "blurb": "Apply current stream time to buffers", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true }, "endx": { "blurb": "X coordinate of bottom right corner of area to be recorded (0 for bottom right of screen)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "2147483647", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "endy": { "blurb": "Y coordinate of bottom right corner of area to be recorded (0 for bottom right of screen)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "2147483647", "min": "0", - "type-name": "guint", - "writable": true - }, - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "num-buffers": { - "blurb": "Number of buffers to output before sending EOS (-1 = unlimited)", - "construct": false, - "construct-only": false, - "default": "-1", - "max": "2147483647", - "min": "-1", - "type-name": "gint", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "remote": { "blurb": "Whether the display is remote", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "show-pointer": { "blurb": "Show mouse pointer (if XFixes extension enabled)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "startx": { "blurb": "X coordinate of top left corner of area to be recorded (0 for top left of screen)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "2147483647", "min": "0", - "type-name": "guint", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "starty": { "blurb": "Y coordinate of top left corner of area to be recorded (0 for top left of screen)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "2147483647", "min": "0", - "type-name": "guint", - "writable": true - }, - "typefind": { - "blurb": "Run typefind before negotiating (deprecated, non-functional)", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "guint", "writable": true }, "use-damage": { "blurb": "Use XDamage (if XDamage extension enabled)", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "true", - "type-name": "gboolean", + "mutable": "null", + "readable": true, + "type": "gboolean", "writable": true }, "xid": { "blurb": "Window XID to capture from", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "0", "max": "18446744073709551615", "min": "0", - "type-name": "guint64", + "mutable": "null", + "readable": true, + "type": "guint64", "writable": true }, "xname": { "blurb": "Window name to capture from", + "conditionally-available": false, "construct": false, "construct-only": false, + "controllable": false, "default": "NULL", - "type-name": "gchararray", + "mutable": "null", + "readable": true, + "type": "gchararray", "writable": true } }, @@ -37946,7 +27241,8 @@ }, "filename": "gstximagesrc", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" @@ -37965,9 +27261,11 @@ "GInitiallyUnowned", "GObject" ], + "interfaces": [ + "GstPreset" + ], "klass": "Codec/Encoder/Video", "long-name": "YUV4MPEG video encoder", - "name": "y4menc", "pad-templates": { "sink": { "caps": "video/x-raw:\n format: { IYUV, I420, Y42B, Y41B, Y444 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", @@ -37980,38 +27278,14 @@ "presence": "always" } }, - "properties": { - "name": { - "blurb": "The name of the object", - "construct": true, - "construct-only": false, - "default": "NULL", - "hotdoc-fixed-default": true, - "type-name": "gchararray", - "writable": true - }, - "parent": { - "blurb": "The parent of the object", - "construct": false, - "construct-only": false, - "type-name": "GstObject", - "writable": true - }, - "qos": { - "blurb": "Handle Quality-of-Service events from downstream", - "construct": false, - "construct-only": false, - "default": "false", - "type-name": "gboolean", - "writable": true - } - }, + "properties": {}, "rank": "primary" } }, "filename": "gsty4menc", "license": "LGPL", - "package": "GStreamer Good Plug-ins git", + "other-types": {}, + "package": "GStreamer Good Plug-ins", "source": "gst-plugins-good", "tracers": {}, "url": "Unknown package origin" diff --git a/docs/meson.build b/docs/meson.build index 7a1daad5cd..bdfcc4a7c2 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -26,6 +26,7 @@ elif plugins_cache_generator.found() command: [plugins_cache_generator, plugins_cache, '@OUTPUT@', '@INPUT@'], input: plugins, output: 'gst_plugins_cache.json', + build_always_stale: true, ) else warning('GStreamer plugin inspector for documentation not found, can\'t update the cache') @@ -37,6 +38,17 @@ if not hotdoc_p.found() subdir_done() endif +hotdoc_req = '>= 0.11.0' +hotdoc_version = run_command(hotdoc_p, '--version').stdout() +if not hotdoc_version.version_compare(hotdoc_req) + if get_option('doc').enabled() + error('Hotdoc version @0@ not found, got @1@'.format(hotdoc_req, hotdoc_version)) + else + message('Hotdoc version @0@ not found, got @1@'.format(hotdoc_req, hotdoc_version)) + subdir_done() + endif +endif + hotdoc = import('hotdoc') foreach extension: required_hotdoc_extensions if not hotdoc.has_extensions(extension) @@ -62,6 +74,8 @@ foreach f: ['gstgdkpixbufplugin.c'] excludes += [join_paths(meson.current_source_dir(), '..', 'ext/gdk_pixbuf/', f)] endforeach +excludes += [join_paths(meson.current_source_dir(), '..', 'sys', 'rpicamsrc', 'Raspi*.[ch]')] + list_plugin_res = run_command(python3, '-c', ''' import sys diff --git a/ext/aalib/gstaasink.c b/ext/aalib/gstaasink.c index 18d361faed..b4d337d7e0 100644 --- a/ext/aalib/gstaasink.c +++ b/ext/aalib/gstaasink.c @@ -225,6 +225,9 @@ gst_aasink_class_init (GstAASinkClass * klass) GST_DEBUG_FUNCPTR (gst_aasink_propose_allocation); gstvideosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_aasink_show_frame); + + gst_type_mark_as_plugin_api (GST_TYPE_AADRIVERS, 0); + gst_type_mark_as_plugin_api (GST_TYPE_AADITHER, 0); } static GstCaps * diff --git a/ext/aalib/gstaasink.h b/ext/aalib/gstaasink.h index 6386c25a02..07239883c5 100644 --- a/ext/aalib/gstaasink.h +++ b/ext/aalib/gstaasink.h @@ -27,24 +27,10 @@ #include -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ +G_BEGIN_DECLS - -#define GST_TYPE_AASINK \ - (gst_aasink_get_type()) -#define GST_AASINK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AASINK,GstAASink)) -#define GST_AASINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AASINK,GstAASinkClass)) -#define GST_IS_AASINK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AASINK)) -#define GST_IS_AASINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AASINK)) - -typedef struct _GstAASink GstAASink; -typedef struct _GstAASinkClass GstAASinkClass; +#define GST_TYPE_AASINK (gst_aasink_get_type()) +G_DECLARE_FINAL_TYPE (GstAASink, gst_aasink, GST, AASINK, GstVideoSink) struct _GstAASink { GstVideoSink parent; @@ -61,15 +47,6 @@ struct _GstAASink { gint aa_driver; }; -struct _GstAASinkClass { - GstVideoSinkClass parent_class; -}; - -GType gst_aasink_get_type(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - +G_END_DECLS #endif /* __GST_AASINKE_H__ */ diff --git a/ext/aalib/gstaatv.c b/ext/aalib/gstaatv.c index 247af83bf5..9f793d50c4 100644 --- a/ext/aalib/gstaatv.c +++ b/ext/aalib/gstaatv.c @@ -619,6 +619,10 @@ gst_aatv_class_init (GstAATvClass * klass) transform_class->transform_caps = GST_DEBUG_FUNCPTR (gst_aatv_transform_caps); videofilter_class->transform_frame = GST_DEBUG_FUNCPTR (gst_aatv_transform_frame); + + gst_type_mark_as_plugin_api (GST_TYPE_AATV_RAIN_MODE, 0); + gst_type_mark_as_plugin_api (GST_TYPE_AADITHER, 0); + gst_type_mark_as_plugin_api (GST_TYPE_AAFONT, 0); } static void diff --git a/ext/aalib/gstaatv.h b/ext/aalib/gstaatv.h index 514ffd9610..07aae0d058 100644 --- a/ext/aalib/gstaatv.h +++ b/ext/aalib/gstaatv.h @@ -27,24 +27,11 @@ #include -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - -#define GST_TYPE_AATV \ - (gst_aatv_get_type()) -#define GST_AATV(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AATV,GstAATv)) -#define GST_AATV_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AATV,GstAATvClass)) -#define GST_IS_AATV(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AATV)) -#define GST_IS_AATV_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AATV)) - - typedef struct _GstAATv GstAATv; - typedef struct _GstAATvClass GstAATvClass; +G_BEGIN_DECLS + +#define GST_TYPE_AATV (gst_aatv_get_type()) +G_DECLARE_FINAL_TYPE (GstAATv, gst_aatv, GST, AATV, GstVideoFilter) + typedef struct _GstAATvDroplet GstAATvDroplet; typedef struct _GstAATvARGB GstAATvARGB; @@ -97,15 +84,7 @@ extern "C" { struct aa_renderparams ascii_parms; }; - struct _GstAATvClass { - GstVideoFilterClass parent_class; - }; - - GType gst_aatv_get_type(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ +G_END_DECLS #endif /* __GST_AASINKE_H__ */ diff --git a/ext/cairo/gstcairooverlay.h b/ext/cairo/gstcairooverlay.h index fe4ac1803b..b342c4b795 100644 --- a/ext/cairo/gstcairooverlay.h +++ b/ext/cairo/gstcairooverlay.h @@ -28,19 +28,9 @@ G_BEGIN_DECLS -#define GST_TYPE_CAIRO_OVERLAY \ - (gst_cairo_overlay_get_type()) -#define GST_CAIRO_OVERLAY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CAIRO_OVERLAY,GstCairoOverlay)) -#define GST_CAIRO_OVERLAY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CAIRO_OVERLAY,GstCairoOverlayClass)) -#define GST_IS_CAIRO_OVERLAY(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CAIRO_OVERLAY)) -#define GST_IS_CAIRO_OVERLAY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CAIRO_OVERLAY)) - -typedef struct _GstCairoOverlay GstCairoOverlay; -typedef struct _GstCairoOverlayClass GstCairoOverlayClass; +#define GST_TYPE_CAIRO_OVERLAY (gst_cairo_overlay_get_type()) +G_DECLARE_FINAL_TYPE (GstCairoOverlay, gst_cairo_overlay, + GST, CAIRO_OVERLAY, GstBaseTransform) struct _GstCairoOverlay { GstBaseTransform parent; @@ -53,12 +43,6 @@ struct _GstCairoOverlay { gboolean attach_compo_to_buffer; }; -struct _GstCairoOverlayClass { - GstBaseTransformClass parent_class; -}; - -GType gst_cairo_overlay_get_type (void); - G_END_DECLS #endif /* __GST_CAIRO_OVERLAY_H__ */ diff --git a/ext/dv/gstdvdec.c b/ext/dv/gstdvdec.c index c9c39bf475..7926ef93b4 100644 --- a/ext/dv/gstdvdec.c +++ b/ext/dv/gstdvdec.c @@ -183,6 +183,8 @@ gst_dvdec_class_init (GstDVDecClass * klass) "Erik Walthinsen ," "Wim Taymans "); GST_DEBUG_CATEGORY_INIT (dvdec_debug, "dvdec", 0, "DV decoding element"); + + gst_type_mark_as_plugin_api (GST_TYPE_DVDEC_QUALITY, 0); } static void diff --git a/ext/dv/gstdvdec.h b/ext/dv/gstdvdec.h index 4031ef051e..49cec968b1 100644 --- a/ext/dv/gstdvdec.h +++ b/ext/dv/gstdvdec.h @@ -30,22 +30,8 @@ G_BEGIN_DECLS - -#define GST_TYPE_DVDEC \ - (gst_dvdec_get_type()) -#define GST_DVDEC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DVDEC,GstDVDec)) -#define GST_DVDEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DVDEC,GstDVDecClass)) -#define GST_IS_DVDEC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DVDEC)) -#define GST_IS_DVDEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DVDEC)) - - -typedef struct _GstDVDec GstDVDec; -typedef struct _GstDVDecClass GstDVDecClass; - +#define GST_TYPE_DVDEC (gst_dvdec_get_type()) +G_DECLARE_FINAL_TYPE (GstDVDec, gst_dvdec, GST, DVDEC, GstElement) struct _GstDVDec { GstElement element; @@ -84,14 +70,6 @@ struct _GstDVDec { gboolean need_segment; }; -struct _GstDVDecClass { - GstElementClass parent_class; -}; - - -GType gst_dvdec_get_type (void); - - G_END_DECLS diff --git a/ext/dv/gstdvdemux.h b/ext/dv/gstdvdemux.h index 95c93206d8..8edb937c82 100644 --- a/ext/dv/gstdvdemux.h +++ b/ext/dv/gstdvdemux.h @@ -27,24 +27,11 @@ G_BEGIN_DECLS -#define GST_TYPE_DVDEMUX \ - (gst_dvdemux_get_type()) -#define GST_DVDEMUX(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DVDEMUX,GstDVDemux)) -#define GST_DVDEMUX_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DVDEMUX,GstDVDemuxClass)) -#define GST_IS_DVDEMUX(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DVDEMUX)) -#define GST_IS_DVDEMUX_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DVDEMUX)) - - -typedef struct _GstDVDemux GstDVDemux; -typedef struct _GstDVDemuxClass GstDVDemuxClass; +#define GST_TYPE_DVDEMUX (gst_dvdemux_get_type()) +G_DECLARE_FINAL_TYPE (GstDVDemux, gst_dvdemux, GST, DVDEMUX, GstElement) typedef gboolean (*GstDVDemuxSeekHandler) (GstDVDemux *demux, GstPad * pad, GstEvent * event); - struct _GstDVDemux { GstElement element; @@ -91,12 +78,6 @@ struct _GstDVDemux { gint16 *audio_buffers[4]; }; -struct _GstDVDemuxClass { - GstElementClass parent_class; -}; - -GType gst_dvdemux_get_type (void); - G_END_DECLS #endif /* __GST_DVDEMUX_H__ */ diff --git a/ext/flac/gstflacdec.h b/ext/flac/gstflacdec.h index c63b300ba9..584e7dfdee 100644 --- a/ext/flac/gstflacdec.h +++ b/ext/flac/gstflacdec.h @@ -31,13 +31,7 @@ G_BEGIN_DECLS #define GST_TYPE_FLAC_DEC gst_flac_dec_get_type() -#define GST_FLAC_DEC(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, GST_TYPE_FLAC_DEC, GstFlacDec) -#define GST_FLAC_DEC_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, GST_TYPE_FLAC_DEC, GstFlacDecClass) -#define GST_IS_FLAC_DEC(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, GST_TYPE_FLAC_DEC) -#define GST_IS_FLAC_DEC_CLASS(klass) G_TYPE_CHECK_CLASS_TYPE(klass, GST_TYPE_FLAC_DEC) - -typedef struct _GstFlacDec GstFlacDec; -typedef struct _GstFlacDecClass GstFlacDecClass; +G_DECLARE_FINAL_TYPE (GstFlacDec, gst_flac_dec, GST, FLAC_DEC, GstAudioDecoder) struct _GstFlacDec { GstAudioDecoder audiodecoder; @@ -63,12 +57,6 @@ struct _GstFlacDec { gint error_count; }; -struct _GstFlacDecClass { - GstAudioDecoderClass audiodecoder; -}; - -GType gst_flac_dec_get_type (void); - G_END_DECLS #endif /* __GST_FLAC_DEC_H__ */ diff --git a/ext/flac/gstflacenc.c b/ext/flac/gstflacenc.c index 4f949054fb..7c0016e434 100644 --- a/ext/flac/gstflacenc.c +++ b/ext/flac/gstflacenc.c @@ -361,6 +361,8 @@ gst_flac_enc_class_init (GstFlacEncClass * klass) base_class->getcaps = GST_DEBUG_FUNCPTR (gst_flac_enc_getcaps); base_class->sink_event = GST_DEBUG_FUNCPTR (gst_flac_enc_sink_event); base_class->sink_query = GST_DEBUG_FUNCPTR (gst_flac_enc_sink_query); + + gst_type_mark_as_plugin_api (GST_TYPE_FLAC_ENC_QUALITY, 0); } static void @@ -809,11 +811,10 @@ gst_flac_enc_getcaps (GstAudioEncoder * enc, GstCaps * filter) } static guint64 -gst_flac_enc_peer_query_total_samples (GstFlacEnc * flacenc, GstPad * pad) +gst_flac_enc_peer_query_total_samples (GstFlacEnc * flacenc, GstPad * pad, + GstAudioInfo * info) { gint64 duration; - GstAudioInfo *info = - gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (flacenc)); GST_DEBUG_OBJECT (flacenc, "querying peer for DEFAULT format duration"); if (gst_pad_peer_query_duration (pad, GST_FORMAT_DEFAULT, &duration) @@ -882,7 +883,7 @@ gst_flac_enc_set_format (GstAudioEncoder * enc, GstAudioInfo * info) flacenc->channel_reorder_map); total_samples = gst_flac_enc_peer_query_total_samples (flacenc, - GST_AUDIO_ENCODER_SINK_PAD (enc)); + GST_AUDIO_ENCODER_SINK_PAD (enc), info); FLAC__stream_encoder_set_bits_per_sample (flacenc->encoder, GST_AUDIO_INFO_DEPTH (info)); diff --git a/ext/flac/gstflacenc.h b/ext/flac/gstflacenc.h index 11aec4e998..1447d5e6fa 100644 --- a/ext/flac/gstflacenc.h +++ b/ext/flac/gstflacenc.h @@ -29,13 +29,7 @@ G_BEGIN_DECLS #define GST_TYPE_FLAC_ENC (gst_flac_enc_get_type()) -#define GST_FLAC_ENC(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, GST_TYPE_FLAC_ENC, GstFlacEnc) -#define GST_FLAC_ENC_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, GST_TYPE_FLAC_ENC, GstFlacEncClass) -#define GST_IS_FLAC_ENC(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, GST_TYPE_FLAC_ENC) -#define GST_IS_FLAC_ENC_CLASS(klass) G_TYPE_CHECK_CLASS_TYPE(klass, GST_TYPE_FLAC_ENC) - -typedef struct _GstFlacEnc GstFlacEnc; -typedef struct _GstFlacEncClass GstFlacEncClass; +G_DECLARE_FINAL_TYPE (GstFlacEnc, gst_flac_enc, GST, FLAC_ENC, GstAudioEncoder) struct _GstFlacEnc { GstAudioEncoder element; @@ -69,12 +63,6 @@ struct _GstFlacEnc { gint channel_reorder_map[8]; }; -struct _GstFlacEncClass { - GstAudioEncoderClass parent_class; -}; - -GType gst_flac_enc_get_type(void); - G_END_DECLS #endif /* __GST_FLAC_ENC_H__ */ diff --git a/ext/flac/gstflactag.h b/ext/flac/gstflactag.h index 106541a051..b360d94c46 100644 --- a/ext/flac/gstflactag.h +++ b/ext/flac/gstflactag.h @@ -28,13 +28,7 @@ #include #define GST_TYPE_FLAC_TAG (gst_flac_tag_get_type()) -#define GST_FLAC_TAG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FLAC_TAG, GstFlacTag)) -#define GST_FLAC_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FLAC_TAG, GstFlacTag)) -#define GST_IS_FLAC_TAG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FLAC_TAG)) -#define GST_IS_FLAC_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FLAC_TAG)) - -typedef struct _GstFlacTag GstFlacTag; -typedef struct _GstFlacTagClass GstFlacTagClass; +G_DECLARE_FINAL_TYPE (GstFlacTag, gst_flac_tag, GST, FLAC_TAG, GstElement) typedef enum { @@ -68,11 +62,4 @@ struct _GstFlacTag gboolean metadata_last_block; }; -struct _GstFlacTagClass -{ - GstElementClass parent_class; -}; - -GType gst_flac_tag_get_type (void); - #endif /* GST_FLAC_TAG_H */ diff --git a/ext/gdk_pixbuf/gstgdkpixbufdec.h b/ext/gdk_pixbuf/gstgdkpixbufdec.h index 4b12f48f0f..63fc6e38dd 100644 --- a/ext/gdk_pixbuf/gstgdkpixbufdec.h +++ b/ext/gdk_pixbuf/gstgdkpixbufdec.h @@ -27,19 +27,9 @@ G_BEGIN_DECLS -#define GST_TYPE_GDK_PIXBUF_DEC \ - (gst_gdk_pixbuf_dec_get_type()) -#define GST_GDK_PIXBUF_DEC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GDK_PIXBUF_DEC,GstGdkPixbufDec)) -#define GST_GDK_PIXBUF_DEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GDK_PIXBUF_DEC,GstGdkPixbufDecClass)) -#define GST_IS_GDK_PIXBUF_DEC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GDK_PIXBUF_DEC)) -#define GST_IS_GDK_PIXBUF_DEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GDK_PIXBUF_DEC)) - -typedef struct _GstGdkPixbufDec GstGdkPixbufDec; -typedef struct _GstGdkPixbufDecClass GstGdkPixbufDecClass; +#define GST_TYPE_GDK_PIXBUF_DEC (gst_gdk_pixbuf_dec_get_type()) +G_DECLARE_FINAL_TYPE (GstGdkPixbufDec, gst_gdk_pixbuf_dec, GST, GDK_PIXBUF_DEC, + GstElement) struct _GstGdkPixbufDec { @@ -58,13 +48,6 @@ struct _GstGdkPixbufDec gboolean packetized; }; -struct _GstGdkPixbufDecClass -{ - GstElementClass parent_class; -}; - -GType gst_gdk_pixbuf_dec_get_type (void); - G_END_DECLS #endif /* __GST_GDK_PIXBUF_DEC_H__ */ diff --git a/ext/gdk_pixbuf/gstgdkpixbufoverlay.c b/ext/gdk_pixbuf/gstgdkpixbufoverlay.c index 8981d9603b..00da3cb593 100644 --- a/ext/gdk_pixbuf/gstgdkpixbufoverlay.c +++ b/ext/gdk_pixbuf/gstgdkpixbufoverlay.c @@ -93,13 +93,6 @@ enum PROP_ALPHA }; -#define VIDEO_FORMATS "{ RGBx, RGB, BGR, BGRx, xRGB, xBGR, " \ - "RGBA, BGRA, ARGB, ABGR, I420, YV12, AYUV, YUY2, UYVY, " \ - "v308, v210, v216, Y41B, Y42B, Y444, YVYU, NV12, NV21, UYVP, " \ - "RGB16, BGR16, RGB15, BGR15, UYVP, A420, YUV9, YVU9, " \ - "IYU1, ARGB64, AYUV64, r210, I420_10LE, I420_10BE, " \ - "GRAY8, GRAY16_BE, GRAY16_LE }" - /* FIXME 2.0: change to absolute positioning */ #define DEFAULT_POSITIONING_MODE \ GST_GDK_PIXBUF_POSITIONING_PIXELS_RELATIVE_TO_EDGES @@ -107,13 +100,15 @@ enum static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (VIDEO_FORMATS)) + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE + (GST_VIDEO_OVERLAY_COMPOSITION_BLEND_FORMATS)) ); static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (VIDEO_FORMATS)) + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE + (GST_VIDEO_OVERLAY_COMPOSITION_BLEND_FORMATS)) ); G_DEFINE_TYPE (GstGdkPixbufOverlay, gst_gdk_pixbuf_overlay, @@ -292,6 +287,8 @@ gst_gdk_pixbuf_overlay_class_init (GstGdkPixbufOverlayClass * klass) "Tim-Philipp Müller "); GST_DEBUG_CATEGORY_INIT (gdkpixbufoverlay_debug, "gdkpixbufoverlay", 0, "debug category for gdkpixbufoverlay element"); + + gst_type_mark_as_plugin_api (GST_TYPE_GDK_PIXBUF_POSITIONING_MODE, 0); } static void diff --git a/ext/gdk_pixbuf/gstgdkpixbufoverlay.h b/ext/gdk_pixbuf/gstgdkpixbufoverlay.h index 8d80b015aa..014f1e6d91 100644 --- a/ext/gdk_pixbuf/gstgdkpixbufoverlay.h +++ b/ext/gdk_pixbuf/gstgdkpixbufoverlay.h @@ -28,14 +28,9 @@ G_BEGIN_DECLS -#define GST_TYPE_GDK_PIXBUF_OVERLAY (gst_gdk_pixbuf_overlay_get_type()) -#define GST_GDK_PIXBUF_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GDK_PIXBUF_OVERLAY,GstGdkPixbufOverlay)) -#define GST_GDK_PIXBUF_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GDK_PIXBUF_OVERLAY,GstGdkPixbufOverlayClass)) -#define GST_IS_GDK_PIXBUF_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GDK_PIXBUF_OVERLAY)) -#define GST_IS_GDK_PIXBUF_OVERLAY_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GDK_PIXBUF_OVERLAY)) - -typedef struct _GstGdkPixbufOverlay GstGdkPixbufOverlay; -typedef struct _GstGdkPixbufOverlayClass GstGdkPixbufOverlayClass; +#define GST_TYPE_GDK_PIXBUF_OVERLAY (gst_gdk_pixbuf_overlay_get_type()) +G_DECLARE_FINAL_TYPE (GstGdkPixbufOverlay, gst_gdk_pixbuf_overlay, + GST, GDK_PIXBUF_OVERLAY, GstVideoFilter) typedef enum { GST_GDK_PIXBUF_POSITIONING_PIXELS_RELATIVE_TO_EDGES, @@ -82,13 +77,6 @@ struct _GstGdkPixbufOverlay gboolean update_composition; }; -struct _GstGdkPixbufOverlayClass -{ - GstVideoFilterClass videofilter_class; -}; - -GType gst_gdk_pixbuf_overlay_get_type (void); - G_END_DECLS #endif diff --git a/ext/gdk_pixbuf/gstgdkpixbufsink.h b/ext/gdk_pixbuf/gstgdkpixbufsink.h index 964437aa1c..65e830832f 100644 --- a/ext/gdk_pixbuf/gstgdkpixbufsink.h +++ b/ext/gdk_pixbuf/gstgdkpixbufsink.h @@ -26,14 +26,9 @@ #include -#define GST_TYPE_GDK_PIXBUF_SINK (gst_gdk_pixbuf_sink_get_type()) -#define GST_GDK_PIXBUF_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GDK_PIXBUF_SINK,GstGdkPixbufSink)) -#define GST_GDK_PIXBUF_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GDK_PIXBUF_SINK,GstGdkPixbufSinkClass)) -#define GST_IS_GDK_PIXBUF_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GDK_PIXBUF_SINK)) -#define GST_IS_GDK_PIXBUF_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GDK_PIXBUF_SINK)) - -typedef struct _GstGdkPixbufSink GstGdkPixbufSink; -typedef struct _GstGdkPixbufSinkClass GstGdkPixbufSinkClass; +#define GST_TYPE_GDK_PIXBUF_SINK (gst_gdk_pixbuf_sink_get_type()) +G_DECLARE_FINAL_TYPE (GstGdkPixbufSink, gst_gdk_pixbuf_sink, + GST, GDK_PIXBUF_SINK, GstVideoSink) /** * GstGdkPixbufSink: @@ -59,17 +54,5 @@ struct _GstGdkPixbufSink GdkPixbuf * last_pixbuf; }; -/** - * GstGdkPixbufSinkClass: - * - * Opaque element class structure. - */ -struct _GstGdkPixbufSinkClass -{ - GstVideoSinkClass basesinkclass; -}; - -GType gst_gdk_pixbuf_sink_get_type (void); - #endif /* GST_GDK_PIXBUF_SINK_H */ diff --git a/ext/gtk/gstgtkbasesink.c b/ext/gtk/gstgtkbasesink.c index 6d4d58edf0..0c48f54d64 100644 --- a/ext/gtk/gstgtkbasesink.c +++ b/ext/gtk/gstgtkbasesink.c @@ -128,6 +128,8 @@ gst_gtk_base_sink_class_init (GstGtkBaseSinkClass * klass) gstbasesink_class->stop = gst_gtk_base_sink_stop; gstvideosink_class->show_frame = gst_gtk_base_sink_show_frame; + + gst_type_mark_as_plugin_api (GST_TYPE_GTK_BASE_SINK, 0); } static void diff --git a/ext/gtk/gstgtkbasesink.h b/ext/gtk/gstgtkbasesink.h index ef8c28495b..6501750366 100644 --- a/ext/gtk/gstgtkbasesink.h +++ b/ext/gtk/gstgtkbasesink.h @@ -89,6 +89,8 @@ struct _GstGtkBaseSinkClass GtkWidget* (*create_widget) (void); }; +G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstGtkBaseSink, gst_object_unref) + G_END_DECLS #endif /* __GST_GTK_BASE_SINK_H__ */ diff --git a/ext/gtk/gstgtkglsink.h b/ext/gtk/gstgtkglsink.h index fbe392a877..8ff935948d 100644 --- a/ext/gtk/gstgtkglsink.h +++ b/ext/gtk/gstgtkglsink.h @@ -30,19 +30,11 @@ #include "gstgtkbasesink.h" -#define GST_TYPE_GTK_GL_SINK (gst_gtk_gl_sink_get_type()) -#define GST_GTK_GL_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GTK_GL_SINK,GstGtkGLSink)) -#define GST_GTK_GL_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GTK_GL_SINK,GstGtkGLSinkClass)) -#define GST_IS_GTK_GL_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GTK_GL_SINK)) -#define GST_IS_GTK_GL_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GTK_GL_SINK)) -#define GST_GTK_GL_SINK_CAST(obj) ((GstGtkGLSink*)(obj)) - G_BEGIN_DECLS -typedef struct _GstGtkGLSink GstGtkGLSink; -typedef struct _GstGtkGLSinkClass GstGtkGLSinkClass; - -GType gst_gtk_gl_sink_get_type (void); +#define GST_TYPE_GTK_GL_SINK (gst_gtk_gl_sink_get_type()) +G_DECLARE_FINAL_TYPE (GstGtkGLSink, gst_gtk_gl_sink, GST, GTK_GL_SINK, + GstGtkBaseSink) /** * GstGtkGLSink: @@ -69,17 +61,6 @@ struct _GstGtkGLSink gulong widget_destroy_sig_handler; }; -/** - * GstGtkGLSinkClass: - * - * The #GstGtkGLSinkClass struct only contains private data - */ -struct _GstGtkGLSinkClass -{ - /* */ - GstGtkBaseSinkClass object_class; -}; - G_END_DECLS #endif /* __GST_GTK_GL_SINK_H__ */ diff --git a/ext/gtk/gstgtksink.h b/ext/gtk/gstgtksink.h index 7dad3b0539..fcc5b973eb 100644 --- a/ext/gtk/gstgtksink.h +++ b/ext/gtk/gstgtksink.h @@ -28,19 +28,10 @@ #include "gstgtkbasesink.h" -#define GST_TYPE_GTK_SINK (gst_gtk_sink_get_type()) -#define GST_GTK_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GTK_SINK,GstGtkSink)) -#define GST_GTK_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GTK_SINK,GstGtkSinkClass)) -#define GST_IS_GTK_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GTK_SINK)) -#define GST_IS_GTK_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GTK_SINK)) -#define GST_GTK_SINK_CAST(obj) ((GstGtkSink*)(obj)) - G_BEGIN_DECLS -typedef struct _GstGtkSink GstGtkSink; -typedef struct _GstGtkSinkClass GstGtkSinkClass; - -GType gst_gtk_sink_get_type (void); +#define GST_TYPE_GTK_SINK (gst_gtk_sink_get_type()) +G_DECLARE_FINAL_TYPE (GstGtkSink, gst_gtk_sink, GST, GTK_SINK, GstGtkBaseSink) /** * GstGtkSink: @@ -53,17 +44,6 @@ struct _GstGtkSink GstGtkBaseSink parent; }; -/** - * GstGtkSinkClass: - * - * The #GstGtkSinkClass struct only contains private data - */ -struct _GstGtkSinkClass -{ - /* */ - GstGtkBaseSinkClass object_class; -}; - G_END_DECLS #endif /* __GST_GTK_SINK_H__ */ diff --git a/ext/gtk/meson.build b/ext/gtk/meson.build index 1d2914b06d..3a30017e75 100644 --- a/ext/gtk/meson.build +++ b/ext/gtk/meson.build @@ -12,14 +12,15 @@ optional_deps = [] gtk_dep = dependency('gtk+-3.0', required : get_option('gtk3')) if gtk_dep.found() - if build_gstgl and gstgl_dep.found() and gtk_dep.version().version_compare('>=3.15.0') + # FIXME: automagic + if have_gstgl and gtk_dep.version().version_compare('>=3.15.0') have_gtk3_gl_windowing = false if gst_gl_have_window_x11 and gst_gl_have_platform_glx # FIXME: automagic gtk_x11_dep = dependency('gtk+-x11-3.0', required : false) if gtk_x11_dep.found() - optional_deps += gtk_x11_dep + optional_deps += [gtk_x11_dep, gstglx11_dep] have_gtk3_gl_windowing = true endif endif @@ -28,7 +29,7 @@ if gtk_dep.found() # FIXME: automagic gtk_wayland_dep = dependency('gtk+-wayland-3.0', required : false) if gtk_wayland_dep.found() - optional_deps += gtk_wayland_dep + optional_deps += [gtk_wayland_dep, gstglegl_dep, gstglwayland_dep] have_gtk3_gl_windowing = true endif endif @@ -38,7 +39,7 @@ if gtk_dep.found() 'gstgtkglsink.c', 'gtkgstglwidget.c', ] - optional_deps += gstgl_dep + optional_deps += [gstgl_dep, gstglproto_dep] gtk_defines += ['-DGST_USE_UNSTABLE_API', '-DHAVE_GTK3_GL'] endif endif diff --git a/ext/jack/gstjack.c b/ext/jack/gstjack.c index ca98dc4059..fdd507d872 100644 --- a/ext/jack/gstjack.c +++ b/ext/jack/gstjack.c @@ -28,7 +28,7 @@ GType gst_jack_connect_get_type (void) { - static volatile gsize jack_connect_type = 0; + static gsize jack_connect_type = 0; if (g_once_init_enter (&jack_connect_type)) { static const GEnumValue jack_connect_enums[] = { @@ -50,7 +50,7 @@ gst_jack_connect_get_type (void) GType gst_jack_transport_get_type (void) { - static volatile gsize type = 0; + static gsize type = 0; if (g_once_init_enter (&type)) { static const GFlagsValue flag_values[] = { @@ -84,7 +84,7 @@ gst_jack_client_free (gpointer jclient) GType gst_jack_client_get_type (void) { - static volatile gsize jack_client_type = 0; + static gsize jack_client_type = 0; if (g_once_init_enter (&jack_client_type)) { /* hackish, but makes it show up nicely in gst-inspect */ diff --git a/ext/jack/gstjackaudiosink.c b/ext/jack/gstjackaudiosink.c index abf7aa58f6..6e8d04ae5b 100644 --- a/ext/jack/gstjackaudiosink.c +++ b/ext/jack/gstjackaudiosink.c @@ -131,7 +131,7 @@ gst_jack_audio_sink_free_channels (GstJackAudioSink * sink) static GType gst_jack_ring_buffer_get_type (void) { - static volatile gsize ringbuffer_type = 0; + static gsize ringbuffer_type = 0; if (g_once_init_enter (&ringbuffer_type)) { static const GTypeInfo ringbuffer_info = { @@ -177,6 +177,9 @@ gst_jack_ring_buffer_class_init (GstJackRingBufferClass * klass) gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_stop); gstringbuffer_class->delay = GST_DEBUG_FUNCPTR (gst_jack_ring_buffer_delay); + + gst_type_mark_as_plugin_api (GST_TYPE_JACK_CONNECT, 0); + gst_type_mark_as_plugin_api (GST_TYPE_JACK_TRANSPORT, 0); } /* this is the callback of jack. This should RT-safe. diff --git a/ext/jack/gstjackaudiosink.h b/ext/jack/gstjackaudiosink.h index f12504c1df..4be821ca57 100644 --- a/ext/jack/gstjackaudiosink.h +++ b/ext/jack/gstjackaudiosink.h @@ -32,15 +32,9 @@ 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; +#define GST_TYPE_JACK_AUDIO_SINK (gst_jack_audio_sink_get_type()) +G_DECLARE_FINAL_TYPE (GstJackAudioSink, gst_jack_audio_sink, + GST, JACK_AUDIO_SINK, GstAudioBaseSink) /** * GstJackAudioSink: @@ -71,12 +65,6 @@ struct _GstJackAudioSink { sample_t **buffers; }; -struct _GstJackAudioSinkClass { - GstAudioBaseSinkClass 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 index 1d2cf82ee6..d43a447a76 100644 --- a/ext/jack/gstjackaudiosrc.c +++ b/ext/jack/gstjackaudiosrc.c @@ -151,7 +151,7 @@ gst_jack_audio_src_free_channels (GstJackAudioSrc * src) static GType gst_jack_ring_buffer_get_type (void) { - static volatile gsize ringbuffer_type = 0; + static gsize ringbuffer_type = 0; if (g_once_init_enter (&ringbuffer_type)) { static const GTypeInfo ringbuffer_info = { sizeof (GstJackRingBufferClass), diff --git a/ext/jack/gstjackaudiosrc.h b/ext/jack/gstjackaudiosrc.h index 63ffe3f754..52209b67a7 100644 --- a/ext/jack/gstjackaudiosrc.h +++ b/ext/jack/gstjackaudiosrc.h @@ -53,15 +53,9 @@ 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; +#define GST_TYPE_JACK_AUDIO_SRC (gst_jack_audio_src_get_type()) +G_DECLARE_FINAL_TYPE (GstJackAudioSrc, gst_jack_audio_src, + GST, JACK_AUDIO_SRC, GstAudioBaseSrc) struct _GstJackAudioSrc { @@ -88,13 +82,6 @@ struct _GstJackAudioSrc sample_t **buffers; }; -struct _GstJackAudioSrcClass -{ - GstAudioBaseSrcClass parent_class; -}; - -GType gst_jack_audio_src_get_type (void); - G_END_DECLS #endif /* __GST_JACK_AUDIO_SRC_H__ */ diff --git a/ext/jpeg/gstjpegdec.c b/ext/jpeg/gstjpegdec.c index 9c6464b6de..cce74afa88 100644 --- a/ext/jpeg/gstjpegdec.c +++ b/ext/jpeg/gstjpegdec.c @@ -181,6 +181,8 @@ gst_jpeg_dec_class_init (GstJpegDecClass * klass) GST_DEBUG_CATEGORY_INIT (jpeg_dec_debug, "jpegdec", 0, "JPEG decoder"); GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE"); + + gst_type_mark_as_plugin_api (GST_TYPE_IDCT_METHOD, 0); } static boolean @@ -866,7 +868,7 @@ gst_jpeg_dec_decode_direct (GstJpegDec * dec, GstVideoFrame * frame, gint lines, v_samp[3]; guchar *base[3], *last[3]; gint stride[3]; - guint height; + guint height, field_height; line[0] = y; line[1] = u; @@ -879,7 +881,12 @@ gst_jpeg_dec_decode_direct (GstJpegDec * dec, GstVideoFrame * frame, if (G_UNLIKELY (v_samp[0] > 2 || v_samp[1] > 2 || v_samp[2] > 2)) goto format_not_supported; - height = GST_VIDEO_FRAME_HEIGHT (frame); + height = field_height = GST_VIDEO_FRAME_HEIGHT (frame); + + /* XXX: division by 2 here might not be a good idea yes. But we are doing this + * already in gst_jpeg_dec_handle_frame() for interlaced jpeg */ + if (num_fields == 2) + field_height /= 2; for (i = 0; i < 3; i++) { base[i] = GST_VIDEO_FRAME_COMP_DATA (frame, i); @@ -894,7 +901,7 @@ gst_jpeg_dec_decode_direct (GstJpegDec * dec, GstVideoFrame * frame, } } - if (height % (v_samp[0] * DCTSIZE) && (dec->scratch_size < stride[0])) { + if (field_height % (v_samp[0] * DCTSIZE) && (dec->scratch_size < stride[0])) { g_free (dec->scratch); dec->scratch = g_malloc (stride[0]); dec->scratch_size = stride[0]; @@ -990,6 +997,9 @@ gst_jpeg_dec_negotiate (GstJpegDec * dec, gint width, gint height, gint clrspc, case JCS_GRAYSCALE: break; default: + /* aka JPEG chroma siting */ + outstate->info.chroma_site = GST_VIDEO_CHROMA_SITE_NONE; + outstate->info.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255; outstate->info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT601; outstate->info.colorimetry.transfer = GST_VIDEO_TRANSFER_UNKNOWN; @@ -1210,6 +1220,8 @@ gst_jpeg_dec_handle_frame (GstVideoDecoder * bdec, GstVideoCodecFrame * frame) data = dec->current_frame_map.data; nbytes = dec->current_frame_map.size; + if (nbytes < 2) + goto need_more_data; has_eoi = ((data[nbytes - 2] == 0xff) && (data[nbytes - 1] == 0xd9)); /* some cameras fail to send an end-of-image marker (EOI), diff --git a/ext/jpeg/gstjpegenc.c b/ext/jpeg/gstjpegenc.c index f2a325f059..5533feb00f 100644 --- a/ext/jpeg/gstjpegenc.c +++ b/ext/jpeg/gstjpegenc.c @@ -280,8 +280,6 @@ gst_jpegenc_term_destination (j_compress_ptr cinfo) } outbuf = gst_buffer_new (); - gst_buffer_copy_into (outbuf, jpegenc->current_frame->input_buffer, - GST_BUFFER_COPY_METADATA, 0, -1); gst_buffer_append_memory (outbuf, jpegenc->output_mem); jpegenc->output_mem = NULL; diff --git a/ext/lame/gstlamemp3enc.c b/ext/lame/gstlamemp3enc.c index 424845e8bf..65a97a3b51 100644 --- a/ext/lame/gstlamemp3enc.c +++ b/ext/lame/gstlamemp3enc.c @@ -273,6 +273,9 @@ gst_lamemp3enc_class_init (GstLameMP3EncClass * klass) g_param_spec_boolean ("mono", "Mono", "Enforce mono encoding", DEFAULT_MONO, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gst_type_mark_as_plugin_api (GST_TYPE_LAMEMP3ENC_TARGET, 0); + gst_type_mark_as_plugin_api (GST_TYPE_LAMEMP3ENC_ENCODING_ENGINE_QUALITY, 0); } static void diff --git a/ext/lame/gstlamemp3enc.h b/ext/lame/gstlamemp3enc.h index 25dbc46f84..ffe0cb23a7 100644 --- a/ext/lame/gstlamemp3enc.h +++ b/ext/lame/gstlamemp3enc.h @@ -31,19 +31,9 @@ G_BEGIN_DECLS #include -#define GST_TYPE_LAMEMP3ENC \ - (gst_lamemp3enc_get_type()) -#define GST_LAMEMP3ENC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_LAMEMP3ENC,GstLameMP3Enc)) -#define GST_LAMEMP3ENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_LAMEMP3ENC,GstLameMP3EncClass)) -#define GST_IS_LAMEMP3ENC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_LAMEMP3ENC)) -#define GST_IS_LAMEMP3ENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_LAMEMP3ENC)) - -typedef struct _GstLameMP3Enc GstLameMP3Enc; -typedef struct _GstLameMP3EncClass GstLameMP3EncClass; +#define GST_TYPE_LAMEMP3ENC (gst_lamemp3enc_get_type()) +G_DECLARE_FINAL_TYPE (GstLameMP3Enc, gst_lamemp3enc, GST, LAMEMP3ENC, + GstAudioEncoder) /** * GstLameMP3Enc: @@ -71,11 +61,6 @@ struct _GstLameMP3Enc { GstAdapter *adapter; }; -struct _GstLameMP3EncClass { - GstAudioEncoderClass parent_class; -}; - -GType gst_lamemp3enc_get_type(void); gboolean gst_lamemp3enc_register (GstPlugin * plugin); G_END_DECLS diff --git a/ext/libcaca/gstcacasink.c b/ext/libcaca/gstcacasink.c index 612ac917d9..b938e1c025 100644 --- a/ext/libcaca/gstcacasink.c +++ b/ext/libcaca/gstcacasink.c @@ -157,6 +157,8 @@ gst_cacasink_class_init (GstCACASinkClass * klass) gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_cacasink_get_times); gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_cacasink_render); gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_cacasink_render); + + gst_type_mark_as_plugin_api (GST_TYPE_CACADITHER, 0); } static void diff --git a/ext/libcaca/gstcacasink.h b/ext/libcaca/gstcacasink.h index 327a6a8a00..53c9d180e3 100644 --- a/ext/libcaca/gstcacasink.h +++ b/ext/libcaca/gstcacasink.h @@ -32,19 +32,8 @@ G_BEGIN_DECLS -#define GST_TYPE_CACASINK \ - (gst_cacasink_get_type()) -#define GST_CACASINK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CACASINK,GstCACASink)) -#define GST_CACASINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CACASINK,GstCACASinkClass)) -#define GST_IS_CACASINK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CACASINK)) -#define GST_IS_CACASINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CACASINK)) - -typedef struct _GstCACASink GstCACASink; -typedef struct _GstCACASinkClass GstCACASinkClass; +#define GST_TYPE_CACASINK (gst_cacasink_get_type()) +G_DECLARE_FINAL_TYPE (GstCACASink, gst_cacasink, GST, CACASINK, GstBaseSink) struct _GstCACASink { GstBaseSink parent; @@ -58,14 +47,6 @@ struct _GstCACASink { struct caca_bitmap *bitmap; }; -struct _GstCACASinkClass { - GstBaseSinkClass parent_class; - - /* signals */ -}; - -GType gst_cacasink_get_type(void); - G_END_DECLS #endif /* __GST_CACASINK_H__ */ diff --git a/ext/libcaca/gstcacatv.c b/ext/libcaca/gstcacatv.c index 0c0a5d1540..0915a076c4 100644 --- a/ext/libcaca/gstcacatv.c +++ b/ext/libcaca/gstcacatv.c @@ -298,6 +298,8 @@ gst_cacatv_class_init (GstCACATvClass * klass) videofilter_class->set_info = GST_DEBUG_FUNCPTR (gst_cacatv_setcaps); transform_class->transform_caps = GST_DEBUG_FUNCPTR (gst_cacatv_transform_caps); + + gst_type_mark_as_plugin_api (GST_TYPE_CACADITHER, 0); } static void diff --git a/ext/libcaca/gstcacatv.h b/ext/libcaca/gstcacatv.h index d24454430c..5a574dc8ab 100644 --- a/ext/libcaca/gstcacatv.h +++ b/ext/libcaca/gstcacatv.h @@ -32,19 +32,8 @@ G_BEGIN_DECLS -#define GST_TYPE_CACATV \ - (gst_cacatv_get_type()) -#define GST_CACATV(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CACATV,GstCACATv)) -#define GST_CACATV_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CACATV,GstCACATvClass)) -#define GST_IS_CACATV(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CACATV)) -#define GST_IS_CACATV_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CACATV)) - -typedef struct _GstCACATv GstCACATv; -typedef struct _GstCACATvClass GstCACATvClass; +#define GST_TYPE_CACATV (gst_cacatv_get_type()) +G_DECLARE_FINAL_TYPE (GstCACATv, gst_cacatv, GST, CACATV, GstVideoFilter) struct _GstCACATv { GstVideoFilter videofilter; @@ -63,14 +52,6 @@ struct _GstCACATv { caca_font_t *font; }; -struct _GstCACATvClass { - GstVideoFilterClass parent_class; - - /* signals */ -}; - -GType gst_cacatv_get_type(void); - G_END_DECLS #endif /* __GST_CACATV_H__ */ diff --git a/ext/libpng/gstpng.h b/ext/libpng/gstpng.h index 1cc8afca74..b94532b921 100644 --- a/ext/libpng/gstpng.h +++ b/ext/libpng/gstpng.h @@ -19,7 +19,5 @@ #include #include -GType gst_pngenc_get_type (void); - extern GstPadTemplate *gst_png_sink_factory (); extern GstPadTemplate *gst_png_src_factory (); diff --git a/ext/libpng/gstpngdec.h b/ext/libpng/gstpngdec.h index a995851bbf..eccdf3e19e 100644 --- a/ext/libpng/gstpngdec.h +++ b/ext/libpng/gstpngdec.h @@ -30,13 +30,7 @@ G_BEGIN_DECLS #define GST_TYPE_PNGDEC (gst_pngdec_get_type()) -#define GST_PNGDEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PNGDEC,GstPngDec)) -#define GST_PNGDEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PNGDEC,GstPngDecClass)) -#define GST_IS_PNGDEC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PNGDEC)) -#define GST_IS_PNGDEC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PNGDEC)) - -typedef struct _GstPngDec GstPngDec; -typedef struct _GstPngDecClass GstPngDecClass; +G_DECLARE_FINAL_TYPE (GstPngDec, gst_pngdec, GST, PNGDEC, GstVideoDecoder) struct _GstPngDec { @@ -59,13 +53,6 @@ struct _GstPngDec gsize read_data; }; -struct _GstPngDecClass -{ - GstVideoDecoderClass parent_class; -}; - -GType gst_pngdec_get_type(void); - G_END_DECLS #endif /* __GST_PNGDEC_H__ */ diff --git a/ext/libpng/gstpngenc.h b/ext/libpng/gstpngenc.h index e71d97c54a..f068d68a83 100644 --- a/ext/libpng/gstpngenc.h +++ b/ext/libpng/gstpngenc.h @@ -27,19 +27,10 @@ #include #include -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ +G_BEGIN_DECLS - -#define GST_TYPE_PNGENC (gst_pngenc_get_type()) -#define GST_PNGENC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PNGENC,GstPngEnc)) -#define GST_PNGENC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PNGENC,GstPngEncClass)) -#define GST_IS_PNGENC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PNGENC)) -#define GST_IS_PNGENC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PNGENC)) - -typedef struct _GstPngEnc GstPngEnc; -typedef struct _GstPngEncClass GstPngEncClass; +#define GST_TYPE_PNGENC (gst_pngenc_get_type()) +G_DECLARE_FINAL_TYPE (GstPngEnc, gst_pngenc, GST, PNGENC, GstVideoEncoder) struct _GstPngEnc { @@ -59,17 +50,6 @@ struct _GstPngEnc gboolean newmedia; }; -struct _GstPngEncClass -{ - GstVideoEncoderClass parent_class; -}; - -GType gst_pngenc_get_type(void); - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - +G_END_DECLS #endif /* __GST_PNGENC_H__ */ diff --git a/ext/mpg123/gstmpg123audiodec.h b/ext/mpg123/gstmpg123audiodec.h index e837a56b0c..f396a25843 100644 --- a/ext/mpg123/gstmpg123audiodec.h +++ b/ext/mpg123/gstmpg123audiodec.h @@ -26,16 +26,9 @@ G_BEGIN_DECLS - -typedef struct _GstMpg123AudioDec GstMpg123AudioDec; -typedef struct _GstMpg123AudioDecClass GstMpg123AudioDecClass; - - -#define GST_TYPE_MPG123_AUDIO_DEC (gst_mpg123_audio_dec_get_type()) -#define GST_MPG123_AUDIO_DEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_MPG123_AUDIO_DEC,GstMpg123AudioDec)) -#define GST_MPG123_AUDIO_DEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_MPG123_AUDIO_DEC,GstMpg123AudioDecClass)) -#define GST_IS_MPG123_AUDIO_DEC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_MPG123_AUDIO_DEC)) -#define GST_IS_MPG123_AUDIO_DEC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_MPG123_AUDIO_DEC)) +#define GST_TYPE_MPG123_AUDIO_DEC (gst_mpg123_audio_dec_get_type()) +G_DECLARE_FINAL_TYPE (GstMpg123AudioDec, gst_mpg123_audio_dec, + GST, MPG123_AUDIO_DEC, GstAudioDecoder) struct _GstMpg123AudioDec { @@ -49,14 +42,6 @@ struct _GstMpg123AudioDec off_t frame_offset; }; - -struct _GstMpg123AudioDecClass -{ - GstAudioDecoderClass parent_class; -}; - -G_GNUC_INTERNAL GType gst_mpg123_audio_dec_get_type (void); - G_END_DECLS #endif diff --git a/ext/pulse/pulsedeviceprovider.c b/ext/pulse/pulsedeviceprovider.c index 4f69bf2ae6..dbc7c10d92 100644 --- a/ext/pulse/pulsedeviceprovider.c +++ b/ext/pulse/pulsedeviceprovider.c @@ -341,8 +341,6 @@ context_subscribe_cb (pa_context * context, pa_subscription_event_type_t type, if (facility == PA_SUBSCRIPTION_EVENT_SERVER || facility != PA_SUBSCRIPTION_EVENT_CHANGE) { pa_context_get_server_info (self->context, get_server_info_cb, self); - - return; } if (facility != PA_SUBSCRIPTION_EVENT_SOURCE && diff --git a/ext/pulse/pulsedeviceprovider.h b/ext/pulse/pulsedeviceprovider.h index 7bcd1bc47c..b2609704ae 100644 --- a/ext/pulse/pulsedeviceprovider.h +++ b/ext/pulse/pulsedeviceprovider.h @@ -34,16 +34,10 @@ G_BEGIN_DECLS -typedef struct _GstPulseDeviceProvider GstPulseDeviceProvider; -typedef struct _GstPulseDeviceProviderClass GstPulseDeviceProviderClass; - -#define GST_TYPE_PULSE_DEVICE_PROVIDER (gst_pulse_device_provider_get_type()) -#define GST_IS_PULSE_DEVICE_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PULSE_DEVICE_PROVIDER)) -#define GST_IS_PULSE_DEVICE_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PULSE_DEVICE_PROVIDER)) -#define GST_PULSE_DEVICE_PROVIDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_PULSE_DEVICE_PROVIDER, GstPulseDeviceProviderClass)) -#define GST_PULSE_DEVICE_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PULSE_DEVICE_PROVIDER, GstPulseDeviceProvider)) -#define GST_PULSE_DEVICE_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEVICE_PROVIDER, GstPulseDeviceProviderClass)) -#define GST_PULSE_DEVICE_PROVIDER_CAST(obj) ((GstPulseDeviceProvider *)(obj)) +#define GST_TYPE_PULSE_DEVICE_PROVIDER (gst_pulse_device_provider_get_type()) +G_DECLARE_FINAL_TYPE (GstPulseDeviceProvider, gst_pulse_device_provider, + GST, PULSE_DEVICE_PROVIDER, GstDeviceProvider) +#define GST_PULSE_DEVICE_PROVIDER_CAST(obj) ((GstPulseDeviceProvider *)(obj)) struct _GstPulseDeviceProvider { GstDeviceProvider parent; @@ -62,23 +56,11 @@ typedef enum { GST_PULSE_DEVICE_TYPE_SINK } GstPulseDeviceType; -struct _GstPulseDeviceProviderClass { - GstDeviceProviderClass parent_class; -}; - -GType gst_pulse_device_provider_get_type (void); - -typedef struct _GstPulseDevice GstPulseDevice; -typedef struct _GstPulseDeviceClass GstPulseDeviceClass; - -#define GST_TYPE_PULSE_DEVICE (gst_pulse_device_get_type()) -#define GST_IS_PULSE_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PULSE_DEVICE)) -#define GST_IS_PULSE_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PULSE_DEVICE)) -#define GST_PULSE_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_PULSE_DEVICE, GstPulseDeviceClass)) -#define GST_PULSE_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PULSE_DEVICE, GstPulseDevice)) -#define GST_PULSE_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEVICE, GstPulseDeviceClass)) -#define GST_PULSE_DEVICE_CAST(obj) ((GstPulseDevice *)(obj)) +#define GST_TYPE_PULSE_DEVICE (gst_pulse_device_get_type()) +G_DECLARE_FINAL_TYPE (GstPulseDevice, gst_pulse_device, GST, PULSE_DEVICE, + GstDevice) +#define GST_PULSE_DEVICE_CAST(obj) ((GstPulseDevice *)(obj)) struct _GstPulseDevice { GstDevice parent; @@ -90,12 +72,6 @@ struct _GstPulseDevice { const gchar *element; }; -struct _GstPulseDeviceClass { - GstDeviceClass parent_class; -}; - -GType gst_pulse_device_get_type (void); - G_END_DECLS #endif /* __GST_PULSE_DEVICE_PROVIDER_H__ */ diff --git a/ext/pulse/pulsesink.h b/ext/pulse/pulsesink.h index de3b932815..51ec86a25a 100644 --- a/ext/pulse/pulsesink.h +++ b/ext/pulse/pulsesink.h @@ -39,21 +39,10 @@ G_BEGIN_DECLS -#define GST_TYPE_PULSESINK \ - (gst_pulsesink_get_type()) -#define GST_PULSESINK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PULSESINK,GstPulseSink)) -#define GST_PULSESINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PULSESINK,GstPulseSinkClass)) -#define GST_IS_PULSESINK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PULSESINK)) -#define GST_IS_PULSESINK_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PULSESINK)) -#define GST_PULSESINK_CAST(obj) \ - ((GstPulseSink *)(obj)) - -typedef struct _GstPulseSink GstPulseSink; -typedef struct _GstPulseSinkClass GstPulseSinkClass; +#define GST_TYPE_PULSESINK (gst_pulsesink_get_type()) +G_DECLARE_FINAL_TYPE (GstPulseSink, gst_pulsesink, GST, PULSESINK, + GstAudioBaseSink) +#define GST_PULSESINK_CAST(obj) ((GstPulseSink *)(obj)) typedef struct _GstPulseDeviceInfo { gchar *description; @@ -83,17 +72,10 @@ struct _GstPulseSink GstStructure *properties; pa_proplist *proplist; - volatile gint format_lost; + gint format_lost; GstClockTime format_lost_time; }; -struct _GstPulseSinkClass -{ - GstAudioBaseSinkClass parent_class; -}; - -GType gst_pulsesink_get_type (void); - #define PULSE_SINK_TEMPLATE_CAPS \ _PULSE_CAPS_PCM \ _PULSE_CAPS_AC3 \ diff --git a/ext/pulse/pulsesrc.h b/ext/pulse/pulsesrc.h index efa7d97edc..c532afb189 100644 --- a/ext/pulse/pulsesrc.h +++ b/ext/pulse/pulsesrc.h @@ -32,21 +32,9 @@ G_BEGIN_DECLS -#define GST_TYPE_PULSESRC \ - (gst_pulsesrc_get_type()) -#define GST_PULSESRC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PULSESRC,GstPulseSrc)) -#define GST_PULSESRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PULSESRC,GstPulseSrcClass)) -#define GST_IS_PULSESRC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PULSESRC)) -#define GST_IS_PULSESRC_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PULSESRC)) -#define GST_PULSESRC_CAST(obj) \ - ((GstPulseSrc *)(obj)) - -typedef struct _GstPulseSrc GstPulseSrc; -typedef struct _GstPulseSrcClass GstPulseSrcClass; +#define GST_TYPE_PULSESRC (gst_pulsesrc_get_type()) +G_DECLARE_FINAL_TYPE (GstPulseSrc, gst_pulsesrc, GST, PULSESRC, GstAudioSrc) +#define GST_PULSESRC_CAST(obj) ((GstPulseSrc *)(obj)) struct _GstPulseSrc { @@ -86,13 +74,6 @@ struct _GstPulseSrc pa_proplist *proplist; }; -struct _GstPulseSrcClass -{ - GstAudioSrcClass parent_class; -}; - -GType gst_pulsesrc_get_type (void); - G_END_DECLS #endif /* __GST_PULSESRC_H__ */ diff --git a/ext/qt/README.md b/ext/qt/README.md index c33eb437ff..7520662709 100644 --- a/ext/qt/README.md +++ b/ext/qt/README.md @@ -48,3 +48,52 @@ make Copy the built plugin to your $GSTREAMER_ROOT/lib/gstreamer-1.0 or link to it directly if it is compiled statically + +# Building for Windows using pre-built gstreamer development package and Qt Creator + +## Step 1 + +Open `qtplugin.pro` in Qt Creator as project and configure it as usual. + +## Step 2 + +Open `qtplugin.pro` in the editor and make sure `GSTREAMER_PATH` +variable in `qmlplugin.pro` is set to the path of your gstreamer SDK installation. This directory +should contain subdirectories `bin`, `include`, `lib` etc. Pay attention to the correct choice +of x86 or x86_64 platform. + +## Step 3 + +Build the project as usual. + +## Step 3 + +Copy the built plugin to your $GSTREAMER_ROOT/lib/gstreamer-1.0 or link to it +directly if it is compiled statically. + +# Building for Windows using pre-built gstreamer development package and Qt on MinGW command line + +## Step 1 + +Launch Qt developer command line from the Start menu. + +## Step 2 + +cd to the directory of the gstqmlgl plugin and make sure `GSTREAMER_PATH` +variable in `qmlplugin.pro` is set to the path of your gstreamer SDK installation. This directory +should contain subdirectories `bin`, `include`, `lib` etc. Pay attention to the correct choice +of x86 or x86_64 platform. + +## Step 3 + +Run the following commands in the gstqmlgl plugin directory: + +``` +qmake +mingw32-make +``` + +## Step 4 + +Copy the built plugin to your $GSTREAMER_ROOT/lib/gstreamer-1.0 or link to it +directly if it is compiled statically. \ No newline at end of file diff --git a/ext/qt/gstplugin.cc b/ext/qt/gstplugin.cc index 79fb18189a..196cf09b35 100644 --- a/ext/qt/gstplugin.cc +++ b/ext/qt/gstplugin.cc @@ -22,6 +22,7 @@ #include "config.h" #endif +#include "gstqtoverlay.h" #include "gstqtsink.h" #include "gstqtsrc.h" #include @@ -33,11 +34,16 @@ plugin_init (GstPlugin * plugin) GST_RANK_NONE, GST_TYPE_QT_SINK)) { return FALSE; } - + if (!gst_element_register (plugin, "qmlglsrc", GST_RANK_NONE, GST_TYPE_QT_SRC)) { return FALSE; } + + if (!gst_element_register (plugin, "qmlgloverlay", + GST_RANK_NONE, GST_TYPE_QT_OVERLAY)) { + return FALSE; + } /* this means the plugin must be loaded before the qml engine is loaded */ qmlRegisterType ("org.freedesktop.gstreamer.GLVideoItem", 1, 0, "GstGLVideoItem"); diff --git a/ext/qt/gstqsgtexture.cc b/ext/qt/gstqsgtexture.cc index 2b314e0eec..00e2ddad0e 100644 --- a/ext/qt/gstqsgtexture.cc +++ b/ext/qt/gstqsgtexture.cc @@ -35,7 +35,7 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); GstQSGTexture::GstQSGTexture () { - static volatile gsize _debug; + static gsize _debug; initializeOpenGLFunctions(); @@ -47,6 +47,7 @@ GstQSGTexture::GstQSGTexture () gst_video_info_init (&this->v_info); this->buffer_ = NULL; + this->buffer_was_bound = FALSE; this->qt_context_ = NULL; this->sync_buffer_ = gst_buffer_new (); this->dummy_tex_id_ = 0; @@ -56,6 +57,7 @@ GstQSGTexture::~GstQSGTexture () { gst_buffer_replace (&this->buffer_, NULL); gst_buffer_replace (&this->sync_buffer_, NULL); + this->buffer_was_bound = FALSE; if (this->dummy_tex_id_ && QOpenGLContext::currentContext ()) { QOpenGLContext::currentContext ()->functions ()->glDeleteTextures (1, &this->dummy_tex_id_); @@ -80,11 +82,26 @@ GstQSGTexture::setBuffer (GstBuffer * buffer) if (!gst_buffer_replace (&this->buffer_, buffer)) return FALSE; + this->buffer_was_bound = FALSE; this->qt_context_ = gst_gl_context_get_current (); return TRUE; } +/* only called from the streaming thread with scene graph thread blocked */ +GstBuffer * +GstQSGTexture::getBuffer (gboolean * was_bound) +{ + GstBuffer *buffer = NULL; + + if (this->buffer_) + buffer = gst_buffer_ref (this->buffer_); + if (was_bound) + *was_bound = this->buffer_was_bound; + + return buffer; +} + /* only called from qt's scene graph render thread */ void GstQSGTexture::bind () @@ -99,8 +116,6 @@ GstQSGTexture::bind () if (!this->qt_context_) return; - gst_gl_context_activate (this->qt_context_, TRUE); - if (!this->buffer_) goto out; if (GST_VIDEO_INFO_FORMAT (&this->v_info) == GST_VIDEO_FORMAT_UNKNOWN) @@ -144,6 +159,8 @@ GstQSGTexture::bind () * to use the dummy texture */ use_dummy_tex = FALSE; + this->buffer_was_bound = TRUE; + out: if (G_UNLIKELY (use_dummy_tex)) { QOpenGLContext *qglcontext = QOpenGLContext::currentContext (); @@ -174,8 +191,6 @@ GstQSGTexture::bind () funcs->glBindTexture (GL_TEXTURE_2D, this->dummy_tex_id_); } - - gst_gl_context_activate (this->qt_context_, FALSE); } /* can be called from any thread */ diff --git a/ext/qt/gstqsgtexture.h b/ext/qt/gstqsgtexture.h index fdabe93a95..ec4a16f575 100644 --- a/ext/qt/gstqsgtexture.h +++ b/ext/qt/gstqsgtexture.h @@ -38,6 +38,7 @@ class GstQSGTexture : public QSGTexture, protected QOpenGLFunctions void setCaps (GstCaps * caps); gboolean setBuffer (GstBuffer * buffer); + GstBuffer * getBuffer (gboolean * was_bound); /* QSGTexture */ void bind (); @@ -48,6 +49,7 @@ class GstQSGTexture : public QSGTexture, protected QOpenGLFunctions private: GstBuffer * buffer_; + gboolean buffer_was_bound; GstBuffer * sync_buffer_; GstGLContext * qt_context_; GstMemory * mem_; diff --git a/ext/qt/gstqtgl.h b/ext/qt/gstqtgl.h index 4d0bb64c11..a1babaad18 100644 --- a/ext/qt/gstqtgl.h +++ b/ext/qt/gstqtgl.h @@ -22,14 +22,7 @@ #include #endif -/* qt uses the same trick as us to typedef GLsync on GLES2 but to a different - * type which confuses the preprocessor. Instead of trying to reconcile the - * two, we instead use the GLsync definition from Qt from above, and ensure - * that we don't typedef GLsync in gstglfuncs.h */ #include -#undef GST_GL_HAVE_GLSYNC -#define GST_GL_HAVE_GLSYNC 1 -#include /* The glext.h guard was renamed in 2018, but some software which * includes their own copy of the GL headers (such as qt) might have @@ -46,6 +39,17 @@ #endif #endif +/* pulls in GLsync, see below */ +#include + +/* qt uses the same trick as us to typedef GLsync on GLES2 but to a different + * type which confuses the preprocessor. Instead of trying to reconcile the + * two, we instead use the GLsync definition from Qt from above, and ensure + * that we don't typedef GLsync in gstglfuncs.h */ +#undef GST_GL_HAVE_GLSYNC +#define GST_GL_HAVE_GLSYNC 1 +#include + #if defined(QT_OPENGL_ES_2) #include #include diff --git a/ext/qt/gstqtglutility.cc b/ext/qt/gstqtglutility.cc index 20e8eaddf0..e139847ae7 100644 --- a/ext/qt/gstqtglutility.cc +++ b/ext/qt/gstqtglutility.cc @@ -28,24 +28,29 @@ #if GST_GL_HAVE_WINDOW_X11 && defined (HAVE_QT_X11) #include #include +#include #endif -#if GST_GL_HAVE_WINDOW_WAYLAND && GST_GL_HAVE_PLATFORM_EGL && defined (HAVE_QT_WAYLAND) -#include +#if GST_GL_HAVE_PLATFORM_EGL && (defined (HAVE_QT_WAYLAND) || defined (HAVE_QT_EGLFS) || defined (HAVE_QT_ANDROID)) +#include +#ifdef HAVE_QT_QPA_HEADER +#include QT_QPA_HEADER +#endif +#include +#include +#endif + +#if GST_GL_HAVE_WINDOW_WAYLAND && defined (HAVE_QT_WAYLAND) #include #endif -#if GST_GL_HAVE_PLATFORM_EGL && (defined (HAVE_QT_EGLFS) || defined (HAVE_QT_ANDROID)) #if GST_GL_HAVE_WINDOW_VIV_FB -#include #include -#else -#include -#include -#ifdef HAVE_QT_QPA_HEADER -#include -#endif #endif + +#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (HAVE_QT_WIN32) +#include +#include #endif #include @@ -53,12 +58,15 @@ #define GST_CAT_DEFAULT qt_gl_utils_debug GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); +G_LOCK_DEFINE_STATIC (display_lock); +static GWeakRef qt_display; + GstGLDisplay * gst_qt_get_gl_display () { GstGLDisplay *display = NULL; QGuiApplication *app = static_cast (QCoreApplication::instance ()); - static volatile gsize _debug; + static gsize _debug; g_assert (app != NULL); @@ -67,6 +75,16 @@ gst_qt_get_gl_display () "Qt gl utility functions"); g_once_init_leave (&_debug, 1); } + + G_LOCK (display_lock); + /* XXX: this assumes that only one display will ever be created by Qt */ + display = static_cast(g_weak_ref_get (&qt_display)); + if (display) { + GST_INFO ("returning previously created display"); + G_UNLOCK (display_lock); + return display; + } + GST_INFO ("QGuiApplication::instance()->platformName() %s", app->platformName().toUtf8().data()); #if GST_GL_HAVE_WINDOW_X11 && defined (HAVE_QT_X11) @@ -145,12 +163,15 @@ gst_qt_get_gl_display () if (!display) display = gst_gl_display_new (); + g_weak_ref_set (&qt_display, display); + G_UNLOCK (display_lock); + return display; } gboolean gst_qt_get_gl_wrapcontext (GstGLDisplay * display, - GstGLContext **wrap_glcontext, GstGLContext **context) + GstGLContext **wrap_glcontext, GstGLContext **context, void * wgl_device) { GstGLPlatform platform = (GstGLPlatform) 0; GstGLAPI gl_api; @@ -159,6 +180,17 @@ gst_qt_get_gl_wrapcontext (GstGLDisplay * display, g_return_val_if_fail (display != NULL && wrap_glcontext != NULL, FALSE); + /* see if we already have a current GL context in GStreamer for this thread */ + { + GstGLContext *current = gst_gl_context_get_current (); + if (current) { + if (current->display == display) { + *wrap_glcontext = static_cast (gst_object_ref (current)); + return TRUE; + } + } + } + #if GST_GL_HAVE_WINDOW_X11 && defined (HAVE_QT_X11) if (GST_IS_GL_DISPLAY_X11 (display)) { #if GST_GL_HAVE_PLATFORM_GLX @@ -216,18 +248,16 @@ gst_qt_get_gl_wrapcontext (GstGLDisplay * display, gst_gl_context_activate(*wrap_glcontext, TRUE); if (!gst_gl_context_fill_info (*wrap_glcontext, &error)) { GST_ERROR ("failed to retrieve qt context info: %s", error->message); - g_object_unref (*wrap_glcontext); + gst_object_unref (*wrap_glcontext); *wrap_glcontext = NULL; return FALSE; } else { gst_gl_display_filter_gl_api (display, gst_gl_context_get_gl_api (*wrap_glcontext)); -#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (HAVE_QT_WIN32) +#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (HAVE_QT_WIN32) g_return_val_if_fail (context != NULL, FALSE); + g_return_val_if_fail (wgl_device != NULL, FALSE); G_STMT_START { - GstGLWindow *window; - HDC device; - /* If there's no wglCreateContextAttribsARB() support, then we would fallback to * wglShareLists() which will fail with ERROR_BUSY (0xaa) if either of the GL * contexts are current in any other thread. @@ -240,21 +270,19 @@ gst_qt_get_gl_wrapcontext (GstGLDisplay * display, * unconditionally. */ *context = gst_gl_context_new (display); - window = gst_gl_context_get_window (*context); - device = (HDC) gst_gl_window_get_display (window); - wglMakeCurrent (device, 0); - gst_object_unref (window); + wglMakeCurrent ((HDC) wgl_device, 0); + if (!gst_gl_context_create (*context, *wrap_glcontext, &error)) { GST_ERROR ("failed to create shared GL context: %s", error->message); - g_object_unref (*context); + gst_object_unref (*context); *context = NULL; - g_object_unref (*wrap_glcontext); + gst_object_unref (*wrap_glcontext); *wrap_glcontext = NULL; - wglMakeCurrent (device, (HGLRC) gl_handle); + wglMakeCurrent ((HDC) wgl_device, (HGLRC) gl_handle); return FALSE; } - wglMakeCurrent (device, (HGLRC) gl_handle); + wglMakeCurrent ((HDC) wgl_device, (HGLRC) gl_handle); } G_STMT_END; #endif gst_gl_context_activate (*wrap_glcontext, FALSE); @@ -262,3 +290,67 @@ gst_qt_get_gl_wrapcontext (GstGLDisplay * display, return TRUE; } + +QVariant +qt_opengl_native_context_from_gst_gl_context (GstGLContext * context) +{ + guintptr handle; + GstGLPlatform platform; + + handle = gst_gl_context_get_gl_context (context); + platform = gst_gl_context_get_gl_platform (context); + +#if GST_GL_HAVE_WINDOW_X11 && defined (HAVE_QT_X11) + if (platform == GST_GL_PLATFORM_GLX) { + GstGLDisplay *display = gst_gl_context_get_display (context); + GstGLWindow *window = gst_gl_context_get_window (context); + Display *xdisplay = (Display *) gst_gl_display_get_handle (display); + Window win = gst_gl_window_get_window_handle (window); + gst_object_unref (window); + gst_object_unref (display); + return QVariant::fromValue(QGLXNativeContext((GLXContext) handle, xdisplay, win)); + } +#endif +#if GST_GL_HAVE_PLATFORM_EGL && (defined (HAVE_QT_WAYLAND) || defined (HAVE_QT_EGLFS) || defined (HAVE_QT_ANDROID)) + if (platform == GST_GL_PLATFORM_EGL) { + EGLDisplay egl_display = EGL_DEFAULT_DISPLAY; + GstGLDisplay *display = gst_gl_context_get_display (context); + GstGLDisplayEGL *display_egl = gst_gl_display_egl_from_gl_display (display); +#if GST_GL_HAVE_WINDOW_WAYLAND && defined (HAVE_QT_WAYLAND) + if (gst_gl_display_get_handle_type (display) == GST_GL_DISPLAY_TYPE_WAYLAND) { +#if 1 + g_warning ("Qt does not support wrapping native OpenGL contexts " + "on wayland. See https://bugreports.qt.io/browse/QTBUG-82528"); + gst_object_unref (display_egl); + gst_object_unref (display); + return QVariant::fromValue(nullptr); +#else + if (display_egl) + egl_display = (EGLDisplay) gst_gl_display_get_handle ((GstGLDisplay *) display_egl); +#endif + } +#endif + gst_object_unref (display_egl); + gst_object_unref (display); + return QVariant::fromValue(QEGLNativeContext((EGLContext) handle, egl_display)); + } +#endif +#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (HAVE_QT_WIN32) + if (platform == GST_GL_PLATFORM_WGL) { + GstGLWindow *window = gst_gl_context_get_window (context); + guintptr hwnd = gst_gl_window_get_window_handle (window); + gst_object_unref (window); + return QVariant::fromValue(QWGLNativeContext((HGLRC) handle, (HWND) hwnd)); + } +#endif + { + gchar *platform_s = gst_gl_platform_to_string (platform); + g_warning ("Unimplemented configuration! This means either:\n" + "1. The qmlgl plugin was built without support for your platform.\n" + "2. The necessary code to convert from a GstGLContext to Qt's " + "native context type for \'%s\' currently does not exist.", + platform_s); + g_free (platform_s); + } + return QVariant::fromValue(nullptr); +} diff --git a/ext/qt/gstqtglutility.h b/ext/qt/gstqtglutility.h index ca9023773a..eca293fe34 100644 --- a/ext/qt/gstqtglutility.h +++ b/ext/qt/gstqtglutility.h @@ -24,11 +24,15 @@ #include #include +#include + G_BEGIN_DECLS GstGLDisplay * gst_qt_get_gl_display (); gboolean gst_qt_get_gl_wrapcontext (GstGLDisplay * display, - GstGLContext **wrap_glcontext, GstGLContext **context); + GstGLContext **wrap_glcontext, GstGLContext **context, void * wgl_device); + +QVariant qt_opengl_native_context_from_gst_gl_context (GstGLContext * context); G_END_DECLS #endif /* __QT_GL_UTILS_H__ */ diff --git a/ext/qt/gstqtoverlay.cc b/ext/qt/gstqtoverlay.cc new file mode 100644 index 0000000000..26c2a01c5f --- /dev/null +++ b/ext/qt/gstqtoverlay.cc @@ -0,0 +1,428 @@ +/* + * GStreamer + * Copyright (C) 2020 Matthew Waters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/** + * SECTION:gstqtoverlay + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstqtoverlay.h" +#include "qtglrenderer.h" +#include "gstqtglutility.h" + +#include + +#include + +#define GST_CAT_DEFAULT gst_debug_qt_gl_overlay +GST_DEBUG_CATEGORY (GST_CAT_DEFAULT); + +static void gst_qt_overlay_finalize (GObject * object); +static void gst_qt_overlay_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * param_spec); +static void gst_qt_overlay_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * param_spec); + +static gboolean gst_qt_overlay_gl_start (GstGLBaseFilter * bfilter); +static void gst_qt_overlay_gl_stop (GstGLBaseFilter * bfilter); +static gboolean gst_qt_overlay_gl_set_caps (GstGLBaseFilter * bfilter, + GstCaps * in_caps, GstCaps * out_caps); + +static GstFlowReturn gst_qt_overlay_prepare_output_buffer (GstBaseTransform * btrans, + GstBuffer * buffer, GstBuffer ** outbuf); +static GstFlowReturn gst_qt_overlay_transform (GstBaseTransform * btrans, + GstBuffer * inbuf, GstBuffer * outbuf); + +static GstStateChangeReturn gst_qt_overlay_change_state (GstElement * element, + GstStateChange transition); + +enum +{ + PROP_0, + PROP_WIDGET, + PROP_QML_SCENE, + PROP_ROOT_ITEM, +}; + +enum +{ + SIGNAL_0, + SIGNAL_QML_SCENE_INITIALIZED, + SIGNAL_QML_SCENE_DESTROYED, + LAST_SIGNAL +}; + +static guint gst_qt_overlay_signals[LAST_SIGNAL] = { 0 }; + +#define gst_qt_overlay_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstQtOverlay, gst_qt_overlay, + GST_TYPE_GL_FILTER, GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, + "qtoverlay", 0, "Qt Video Overlay")); + +static void +gst_qt_overlay_class_init (GstQtOverlayClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseTransformClass *btrans_class; + GstGLBaseFilterClass *glbasefilter_class; + GstGLFilterClass *glfilter_class; + GstElementClass *element_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + glbasefilter_class = (GstGLBaseFilterClass *) klass; + glfilter_class = (GstGLFilterClass *) klass; + btrans_class = (GstBaseTransformClass *) klass; + element_class = (GstElementClass *) klass; + + gobject_class->set_property = gst_qt_overlay_set_property; + gobject_class->get_property = gst_qt_overlay_get_property; + gobject_class->finalize = gst_qt_overlay_finalize; + + gst_element_class_set_metadata (gstelement_class, "Qt Video Overlay", + "Filter/QML/Overlay", "A filter that renders a QML scene onto a video stream", + "Matthew Waters "); + + g_object_class_install_property (gobject_class, PROP_QML_SCENE, + g_param_spec_string ("qml-scene", "QML Scene", + "The contents of the QML scene", NULL, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property (gobject_class, PROP_WIDGET, + g_param_spec_pointer ("widget", "QQuickItem", + "The QQuickItem to place the input video in the object hierarchy", + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property (gobject_class, PROP_ROOT_ITEM, + g_param_spec_pointer ("root-item", "QQuickItem", + "The root QQuickItem from the qml-scene used to render", + (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS))); + + /** + * GstQmlGLOverlay::qml-scene-initialized + * @element: the #GstQmlGLOverlay + * @user_data: user provided data + */ + gst_qt_overlay_signals[SIGNAL_QML_SCENE_INITIALIZED] = + g_signal_new ("qml-scene-initialized", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); + + /** + * GstQmlGLOverlay::qml-scene-destroyed + * @element: the #GstQmlGLOverlay + * @user_data: user provided data + */ + gst_qt_overlay_signals[SIGNAL_QML_SCENE_DESTROYED] = + g_signal_new ("qml-scene-destroyed", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); + + gst_gl_filter_add_rgba_pad_templates (glfilter_class); + + btrans_class->prepare_output_buffer = gst_qt_overlay_prepare_output_buffer; + btrans_class->transform = gst_qt_overlay_transform; + + glbasefilter_class->gl_start = gst_qt_overlay_gl_start; + glbasefilter_class->gl_stop = gst_qt_overlay_gl_stop; + glbasefilter_class->gl_set_caps = gst_qt_overlay_gl_set_caps; + + element_class->change_state = gst_qt_overlay_change_state; +} + +static void +gst_qt_overlay_init (GstQtOverlay * qt_overlay) +{ + qt_overlay->widget = QSharedPointer(); +} + +static void +gst_qt_overlay_finalize (GObject * object) +{ + GstQtOverlay *qt_overlay = GST_QT_OVERLAY (object); + + qt_overlay->widget.clear(); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_qt_overlay_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstQtOverlay *qt_overlay = GST_QT_OVERLAY (object); + + switch (prop_id) { + case PROP_WIDGET: { + QtGLVideoItem *qt_item = static_cast (g_value_get_pointer (value)); + if (qt_item) + qt_overlay->widget = qt_item->getInterface(); + else + qt_overlay->widget.clear(); + break; + } + case PROP_QML_SCENE: + g_free (qt_overlay->qml_scene); + qt_overlay->qml_scene = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_qt_overlay_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstQtOverlay *qt_overlay = GST_QT_OVERLAY (object); + + switch (prop_id) { + case PROP_WIDGET: + /* This is not really safe - the app needs to be + * sure the widget is going to be kept alive or + * this can crash */ + if (qt_overlay->widget) + g_value_set_pointer (value, qt_overlay->widget->videoItem()); + else + g_value_set_pointer (value, NULL); + break; + case PROP_QML_SCENE: + g_value_set_string (value, qt_overlay->qml_scene); + break; + case PROP_ROOT_ITEM: + GST_OBJECT_LOCK (qt_overlay); + if (qt_overlay->renderer) { + QQuickItem *root = qt_overlay->renderer->rootItem(); + if (root) + g_value_set_pointer (value, root); + else + g_value_set_pointer (value, NULL); + } else { + g_value_set_pointer (value, NULL); + } + GST_OBJECT_UNLOCK (qt_overlay); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_qt_overlay_gl_start (GstGLBaseFilter * bfilter) +{ + GstQtOverlay *qt_overlay = GST_QT_OVERLAY (bfilter); + QQuickItem *root; + GError *error = NULL; + + GST_TRACE_OBJECT (bfilter, "using scene:\n%s", qt_overlay->qml_scene); + + if (!qt_overlay->qml_scene || g_strcmp0 (qt_overlay->qml_scene, "") == 0) { + GST_ELEMENT_ERROR (bfilter, RESOURCE, NOT_FOUND, ("qml-scene property not set"), (NULL)); + return FALSE; + } + + if (!GST_GL_BASE_FILTER_CLASS (parent_class)->gl_start (bfilter)) + return FALSE; + + GST_OBJECT_LOCK (bfilter); + qt_overlay->renderer = new GstQuickRenderer; + if (!qt_overlay->renderer->init (bfilter->context, &error)) { + GST_ELEMENT_ERROR (GST_ELEMENT (bfilter), RESOURCE, NOT_FOUND, + ("%s", error->message), (NULL)); + delete qt_overlay->renderer; + qt_overlay->renderer = NULL; + GST_OBJECT_UNLOCK (bfilter); + return FALSE; + } + + /* FIXME: Qml may do async loading and we need to propagate qml errors in that case as well */ + if (!qt_overlay->renderer->setQmlScene (qt_overlay->qml_scene, &error)) { + GST_ELEMENT_ERROR (GST_ELEMENT (bfilter), RESOURCE, NOT_FOUND, + ("%s", error->message), (NULL)); + goto fail_renderer; + return FALSE; + } + + root = qt_overlay->renderer->rootItem(); + if (!root) { + GST_ELEMENT_ERROR (GST_ELEMENT (bfilter), RESOURCE, NOT_FOUND, + ("Qml scene does not have a root item"), (NULL)); + goto fail_renderer; + } + GST_OBJECT_UNLOCK (bfilter); + + g_object_notify (G_OBJECT (qt_overlay), "root-item"); + g_signal_emit (qt_overlay, gst_qt_overlay_signals[SIGNAL_QML_SCENE_INITIALIZED], 0); + + return TRUE; + +fail_renderer: + { + qt_overlay->renderer->cleanup(); + delete qt_overlay->renderer; + qt_overlay->renderer = NULL; + GST_OBJECT_UNLOCK (bfilter); + return FALSE; + } +} + +static void +gst_qt_overlay_gl_stop (GstGLBaseFilter * bfilter) +{ + GstQtOverlay *qt_overlay = GST_QT_OVERLAY (bfilter); + GstQuickRenderer *renderer = NULL; + + /* notify before actually destroying anything */ + GST_OBJECT_LOCK (qt_overlay); + if (qt_overlay->renderer) + renderer = qt_overlay->renderer; + qt_overlay->renderer = NULL; + GST_OBJECT_UNLOCK (qt_overlay); + + g_signal_emit (qt_overlay, gst_qt_overlay_signals[SIGNAL_QML_SCENE_DESTROYED], 0); + g_object_notify (G_OBJECT (qt_overlay), "root-item"); + + if (qt_overlay->widget) + qt_overlay->widget->setBuffer (NULL); + + if (renderer) { + renderer->cleanup(); + delete renderer; + } + + GST_GL_BASE_FILTER_CLASS (parent_class)->gl_stop (bfilter); +} + +static gboolean +gst_qt_overlay_gl_set_caps (GstGLBaseFilter * bfilter, GstCaps * in_caps, + GstCaps * out_caps) +{ + GstGLFilter *filter = GST_GL_FILTER (bfilter); + GstQtOverlay *qt_overlay = GST_QT_OVERLAY (bfilter); + + if (!GST_GL_BASE_FILTER_CLASS (parent_class)->gl_set_caps (bfilter, in_caps, out_caps)) + return FALSE; + + qt_overlay->renderer->setSize (GST_VIDEO_INFO_WIDTH (&filter->out_info), + GST_VIDEO_INFO_HEIGHT (&filter->out_info)); + + return TRUE; +} + +static GstFlowReturn +gst_qt_overlay_prepare_output_buffer (GstBaseTransform * btrans, + GstBuffer * buffer, GstBuffer ** outbuf) +{ + GstBaseTransformClass *bclass = GST_BASE_TRANSFORM_GET_CLASS (btrans); + GstGLBaseFilter *bfilter = GST_GL_BASE_FILTER (btrans); + GstGLFilter *filter = GST_GL_FILTER (btrans); + GstQtOverlay *qt_overlay = GST_QT_OVERLAY (btrans); + GstGLMemory *out_mem; + GstGLSyncMeta *sync_meta; + + if (qt_overlay->widget) { + qt_overlay->widget->setCaps (bfilter->in_caps); + qt_overlay->widget->setBuffer (buffer); + } + + /* XXX: is this the correct ts to drive the animation */ + out_mem = qt_overlay->renderer->generateOutput (GST_BUFFER_PTS (buffer)); + if (!out_mem) { + GST_ERROR_OBJECT (qt_overlay, "Failed to generate output"); + return GST_FLOW_ERROR; + } + + *outbuf = gst_buffer_new (); + gst_buffer_append_memory (*outbuf, (GstMemory *) out_mem); + gst_buffer_add_video_meta (*outbuf, (GstVideoFrameFlags) 0, + GST_VIDEO_INFO_FORMAT (&filter->out_info), + GST_VIDEO_INFO_WIDTH (&filter->in_info), + GST_VIDEO_INFO_HEIGHT (&filter->out_info)); + + sync_meta = gst_buffer_add_gl_sync_meta (bfilter->context, *outbuf); + gst_gl_sync_meta_set_sync_point (sync_meta, bfilter->context); + + bclass->copy_metadata (btrans, buffer, *outbuf); + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_qt_overlay_transform (GstBaseTransform * btrans, GstBuffer * inbuf, + GstBuffer * outbuf) +{ + return GST_FLOW_OK; +} + +static GstStateChangeReturn +gst_qt_overlay_change_state (GstElement * element, + GstStateChange transition) +{ + GstQtOverlay *qt_overlay = GST_QT_OVERLAY (element); + GstGLBaseFilter *filter = GST_GL_BASE_FILTER (element); + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + + GST_DEBUG_OBJECT (filter, "changing state: %s => %s", + gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)), + gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition))); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: { + QGuiApplication *app; + GstGLDisplay *display = NULL; + + app = static_cast (QCoreApplication::instance ()); + if (!app) { + GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND, + ("%s", "Failed to connect to Qt"), + ("%s", "Could not retrieve QGuiApplication instance")); + return GST_STATE_CHANGE_FAILURE; + } + + display = gst_qt_get_gl_display (); + + if (display != filter->display) + /* always propagate. The application may need to choose between window + * system display connections */ + gst_gl_element_propagate_display_context (GST_ELEMENT (qt_overlay), display); + gst_object_unref (display); + break; + } + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + if (ret == GST_STATE_CHANGE_FAILURE) + return ret; + + switch (transition) { + default: + break; + } + + return ret; + +} diff --git a/ext/qt/gstqtoverlay.h b/ext/qt/gstqtoverlay.h new file mode 100644 index 0000000000..f6ffbfb692 --- /dev/null +++ b/ext/qt/gstqtoverlay.h @@ -0,0 +1,77 @@ +/* + * GStreamer + * Copyright (C) 2020 Matthew Waters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_QT_OVERLAY_H__ +#define __GST_QT_OVERLAY_H__ + +#include +#include +#include +#include "qtglrenderer.h" +#include "qtitem.h" + +typedef struct _GstQtOverlay GstQtOverlay; +typedef struct _GstQtOverlayClass GstQtOverlayClass; +typedef struct _GstQtOverlayPrivate GstQtOverlayPrivate; + +G_BEGIN_DECLS + +GType gst_qt_overlay_get_type (void); +#define GST_TYPE_QT_OVERLAY (gst_qt_overlay_get_type()) +#define GST_QT_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_QT_OVERLAY,GstQtOverlay)) +#define GST_QT_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_QT_OVERLAY,GstQtOverlayClass)) +#define GST_IS_QT_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_QT_OVERLAY)) +#define GST_IS_QT_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_QT_OVERLAY)) +#define GST_QT_OVERLAY_CAST(obj) ((GstQtOverlay*)(obj)) + +/** + * GstQtOverlay: + * + * Opaque #GstQtOverlay object + */ +struct _GstQtOverlay +{ + /* */ + GstGLFilter parent; + + gchar *qml_scene; + QQuickItem *root_item; + + GstQuickRenderer *renderer; + + QSharedPointer widget; +}; + +/** + * GstQtOverlayClass: + * + * The #GstQtOverlayClass struct only contains private data + */ +struct _GstQtOverlayClass +{ + /* */ + GstGLFilterClass parent_class; +}; + +GstQtOverlay * gst_qt_overlay_new (void); + +G_END_DECLS + +#endif /* __GST_QT_OVERLAY_H__ */ diff --git a/ext/qt/gstqtsink.cc b/ext/qt/gstqtsink.cc index 2a4ad7ccc6..b447c2416b 100644 --- a/ext/qt/gstqtsink.cc +++ b/ext/qt/gstqtsink.cc @@ -320,6 +320,13 @@ gst_qt_sink_change_state (GstElement * element, GstStateChange transition) (NULL)); return GST_STATE_CHANGE_FAILURE; } + + GST_OBJECT_LOCK (qt_sink->display); + gst_gl_display_add_context (qt_sink->display, qt_sink->context); + GST_OBJECT_UNLOCK (qt_sink->display); + + gst_gl_element_propagate_display_context (GST_ELEMENT (qt_sink), qt_sink->display); + break; case GST_STATE_CHANGE_READY_TO_PAUSED: break; diff --git a/ext/qt/gstqtsink.h b/ext/qt/gstqtsink.h index 3ee20b7d5d..5bd85f34a1 100644 --- a/ext/qt/gstqtsink.h +++ b/ext/qt/gstqtsink.h @@ -27,19 +27,13 @@ #include #include "qtitem.h" -typedef struct _GstQtSink GstQtSink; -typedef struct _GstQtSinkClass GstQtSinkClass; typedef struct _GstQtSinkPrivate GstQtSinkPrivate; G_BEGIN_DECLS -GType gst_qt_sink_get_type (void); -#define GST_TYPE_QT_SINK (gst_qt_sink_get_type()) -#define GST_QT_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_QT_SINK,GstQtSink)) -#define GST_QT_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_QT_SINK,GstQtSinkClass)) -#define GST_IS_QT_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_QT_SINK)) -#define GST_IS_QT_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_QT_SINK)) -#define GST_QT_SINK_CAST(obj) ((GstQtSink*)(obj)) +#define GST_TYPE_QT_SINK (gst_qt_sink_get_type()) +G_DECLARE_FINAL_TYPE (GstQtSink, gst_qt_sink, GST, QT_SINK, GstVideoSink) +#define GST_QT_SINK_CAST(obj) ((GstQtSink*)(obj)) /** * GstQtSink: @@ -61,17 +55,6 @@ struct _GstQtSink QSharedPointer widget; }; -/** - * GstQtSinkClass: - * - * The #GstQtSinkClass struct only contains private data - */ -struct _GstQtSinkClass -{ - /* */ - GstVideoSinkClass object_class; -}; - GstQtSink * gst_qt_sink_new (void); G_END_DECLS diff --git a/ext/qt/gstqtsrc.h b/ext/qt/gstqtsrc.h index d84544224a..d563d995c5 100644 --- a/ext/qt/gstqtsrc.h +++ b/ext/qt/gstqtsrc.h @@ -27,18 +27,11 @@ #include #include "qtwindow.h" -typedef struct _GstQtSrc GstQtSrc; -typedef struct _GstQtSrcClass GstQtSrcClass; - G_BEGIN_DECLS -GType gst_qt_src_get_type (void); -#define GST_TYPE_QT_SRC (gst_qt_src_get_type()) -#define GST_QT_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_QT_SRC,GstQtSrc)) -#define GST_QT_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_QT_SRC,GstQtSrcClass)) -#define GST_IS_QT_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_QT_SRC)) -#define GST_IS_QT_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_QT_SRC)) -#define GST_QT_SRC_CAST(obj) ((GstQtSrc*)(obj)) +#define GST_TYPE_QT_SRC (gst_qt_src_get_type()) +G_DECLARE_FINAL_TYPE (GstQtSrc, gst_qt_src, GST, QT_SRC, GstPushSrc) +#define GST_QT_SRC_CAST(obj) ((GstQtSrc*)(obj)) /** * GstQtSrc: @@ -64,17 +57,6 @@ struct _GstQtSrc gboolean pending_image_orientation; }; -/** - * GstQtSrcClass: - * - * The #GstQtSrcClass struct only contains private data - */ -struct _GstQtSrcClass -{ - /* */ - GstPushSrcClass object_class; -}; - G_END_DECLS #endif /* __GST_QT_SRC_H__ */ diff --git a/ext/qt/meson.build b/ext/qt/meson.build index badcae2b9a..90e967ed13 100644 --- a/ext/qt/meson.build +++ b/ext/qt/meson.build @@ -2,8 +2,10 @@ sources = [ 'gstplugin.cc', 'gstqsgtexture.cc', 'gstqtglutility.cc', + 'gstqtoverlay.cc', 'gstqtsink.cc', 'gstqtsrc.cc', + 'qtglrenderer.cc', 'qtitem.cc', 'qtwindow.cc', ] @@ -12,157 +14,151 @@ moc_headers = [ 'qtitem.h', 'qtwindow.h', 'gstqsgtexture.h', + 'qtglrenderer.h', ] -# FIXME: -Dqt5=enabled is silently ignored if a c++ compiler is not found -if have_cxx and build_gstgl - qt5_mod = import('qt5') - qt5qml_dep = dependency('qt5', modules : ['Core', 'Gui', 'Qml', 'Quick'], - required: get_option('qt5'), static: host_machine.system() == 'ios') - - # On Linux, distros often have the Qt5 pkg-config files and moc in separate - # packages, so the user may not have both installed. Check for moc and ensure - # that it's installed. - # We don't do this check on other OSes because they need to be able to simply - # point the `QMAKE` env var to `qmake` to build against a particular Qt5. - if host_system == 'linux' - moc = find_program('moc-qt5', 'moc', required : get_option('qt5')) - else - # We only check if `moc` was found, and then discard it, so we can fake it. - # This is also a good unit test of the fact that we *don't* use it. - moc = declare_dependency() +# Define a not-found dependency so this variable is always defined when we're +# deciding whether to build the qt5 examples +qt5qml_dep = dependency('', required: false) +qt5_option = get_option('qt5') + +if qt5_option.disabled() + subdir_done() +endif + +if not have_gstgl + if qt5_option.enabled() + error('qt5 qmlglsink plugin is enabled, but gstreamer-gl-1.0 was not found') endif - if qt5qml_dep.found() and moc.found() - optional_deps = [] - qt_defines = [] - have_qpa_include = false - have_qt_windowing = false - - # Attempt to find the QPA header either through pkg-config (preferred) or qmake - # This semi-matches what meson does internally with the qt5 module - # FIXME Add a way to get some of this information out of the qt5 module - if not have_qpa_include - # FIXME: automagic - qt5core_dep = dependency('Qt5Core', required: false) - if qt5core_dep.found() and qt5core_dep.type_name() == 'pkgconfig' - qt_version = qt5core_dep.version() - qt_include_dir = qt5core_dep.get_pkgconfig_variable('includedir') - qpa_include_path = join_paths(qt_include_dir, 'QtGui', qt_version, 'QtGui') - if cxx.has_header('qpa/qplatformnativeinterface.h', - dependencies : qt5core_dep, - args : '-I' + qpa_include_path) - qt_defines += '-DHAVE_QT_QPA_HEADER' - qt_defines += '-I' + qpa_include_path - have_qpa_include = true - message('Found QPA header using pkg-config') - endif - endif - endif - if not have_qpa_include - qmake = find_program('qmake-qt5', 'qmake') - if qmake.found() - qt_version = run_command(qmake, '-query', 'QT_VERSION').stdout().strip() - qt_include_dir = run_command(qmake, '-query', 'QT_INSTALL_HEADERS').stdout().strip() - qpa_include_path = join_paths(qt_include_dir, 'QtGui', qt_version, 'QtGui') - if cxx.has_header('qpa/qplatformnativeinterface.h', - args : '-I' + qpa_include_path) - qt_defines += '-DHAVE_QT_QPA_HEADER' - qt_defines += '-I' + qpa_include_path - have_qpa_include = true - message('Found QPA header using qmake') - endif - endif - endif + subdir_done() +endif - # Try to come up with all the platform/winsys combinations that will work +if not add_languages('cpp', native: false, required: qt5_option) + subdir_done() +endif - if gst_gl_have_window_x11 and gst_gl_have_platform_glx - # FIXME: automagic - qt5x11extras = dependency('qt5', modules : ['X11Extras'], required : false) - if qt5x11extras.found() - optional_deps += qt5x11extras - qt_defines += ['-DHAVE_QT_X11'] - have_qt_windowing = true - endif - endif +qt5_mod = import('qt5') +qt5qml_dep = dependency('qt5', modules : ['Core', 'Gui', 'Qml', 'Quick'], + required: qt5_option, static: host_machine.system() == 'ios') - if gst_gl_have_platform_egl - # Embedded linux (e.g. i.MX6) with or without windowing support - qt_defines += ['-DHAVE_QT_EGLFS'] - egl_dep = dependency('egl', required : false) - optional_deps += egl_dep - have_qt_windowing = true - if have_qpa_include - # Wayland windowing - if gst_gl_have_window_wayland - # FIXME: automagic - qt5waylandextras = dependency('qt5', modules : ['WaylandClient'], required : false) - if qt5waylandextras.found() - optional_deps += qt5waylandextras - qt_defines += ['-DHAVE_QT_WAYLAND'] - have_qt_windowing = true - endif - endif - # Android windowing - if gst_gl_have_window_android - # FIXME: automagic - qt5androidextras = dependency('qt5', modules : ['AndroidExtras'], required : false) - # for gl functions in QtGui/qopenglfunctions.h - # FIXME: automagic - glesv2_dep = cc.find_library('GLESv2', required : false) - if glesv2_dep.found() and qt5androidextras.found() - optional_deps += [qt5androidextras, glesv2_dep] - qt_defines += ['-DHAVE_QT_ANDROID'] - have_qt_windowing = true - # Needed for C++11 support in Cerbero. People building with Android - # in some other way need to add the necessary bits themselves. - optional_deps += dependency('gnustl', required : false) - endif - endif - endif - endif +# On Linux, distros often have the Qt5 pkg-config files and moc in separate +# packages, so the user may not have both installed. Check for moc and ensure +# that it's installed. +# We don't do this check on other OSes because they need to be able to simply +# point the `QMAKE` env var to `qmake` to build against a particular Qt5. +if host_system == 'linux' and not meson.is_cross_build() + moc = find_program('moc-qt5', 'moc', required : qt5_option) +else + # We only check if `moc` was found, and then discard it, so we can fake it. + # This is also a good unit test of the fact that we *don't* use it. + moc = declare_dependency() +endif + +if not qt5qml_dep.found() or not moc.found() + subdir_done() +endif - if gst_gl_have_platform_wgl and gst_gl_have_window_win32 - # for wglMakeCurrent() +optional_deps = [] +qt_defines = [] +have_qpa_include = false +have_qt_windowing = false + +# Look for the QPA platform native interface header +qpa_header_path = join_paths(qt5qml_dep.version(), 'QtGui') +qpa_header = join_paths(qpa_header_path, 'qpa/qplatformnativeinterface.h') +if cxx.has_header(qpa_header, dependencies : qt5qml_dep) + qt_defines += '-DHAVE_QT_QPA_HEADER' + qt_defines += '-DQT_QPA_HEADER=' + '<@0@>'.format(qpa_header) + have_qpa_include = true + message('Found QtGui QPA header in ' + qpa_header_path) +endif + +# Try to come up with all the platform/winsys combinations that will work + +if gst_gl_have_window_x11 and gst_gl_have_platform_glx + # FIXME: automagic + qt5x11extras = dependency('qt5', modules : ['X11Extras'], required : false) + if qt5x11extras.found() + optional_deps += [qt5x11extras, gstglx11_dep] + qt_defines += ['-DHAVE_QT_X11'] + have_qt_windowing = true + endif +endif + +if gst_gl_have_platform_egl + # Embedded linux (e.g. i.MX6) with or without windowing support + qt_defines += ['-DHAVE_QT_EGLFS'] + optional_deps += gstglegl_dep + have_qt_windowing = true + if have_qpa_include + # Wayland windowing + if gst_gl_have_window_wayland # FIXME: automagic - opengl32_dep = cc.find_library('opengl32', required : false) - if opengl32_dep.found() - qt_defines += ['-DHAVE_QT_WIN32'] - optional_deps += opengl32_dep + qt5waylandextras = dependency('qt5', modules : ['WaylandClient'], required : false) + if qt5waylandextras.found() + optional_deps += [qt5waylandextras, gstglwayland_dep] + qt_defines += ['-DHAVE_QT_WAYLAND'] have_qt_windowing = true endif endif - - if gst_gl_have_window_cocoa and gst_gl_have_platform_cgl + # Android windowing + if gst_gl_have_window_android + # FIXME: automagic + qt5androidextras = dependency('qt5', modules : ['AndroidExtras'], required : false) + # for gl functions in QtGui/qopenglfunctions.h # FIXME: automagic - qt5macextras = dependency('qt5', modules : ['MacExtras'], required : false) - if qt5macextras.found() - qt_defines += ['-DHAVE_QT_MAC'] - optional_deps += qt5macextras + glesv2_dep = cc.find_library('GLESv2', required : false) + if glesv2_dep.found() and qt5androidextras.found() + optional_deps += [qt5androidextras, glesv2_dep] + qt_defines += ['-DHAVE_QT_ANDROID'] have_qt_windowing = true + # Needed for C++11 support in Cerbero. People building with Android + # in some other way need to add the necessary bits themselves. + optional_deps += dependency('gnustl', required : false) endif endif + endif +endif - if gst_gl_have_window_eagl and gst_gl_have_platform_eagl - if host_machine.system() == 'ios' - qt_defines += ['-DHAVE_QT_IOS'] - have_qt_windowing = true - endif - endif +if gst_gl_have_platform_wgl and gst_gl_have_window_win32 + # for wglMakeCurrent() + # FIXME: automagic + opengl32_dep = cc.find_library('opengl32', required : false) + if opengl32_dep.found() + qt_defines += ['-DHAVE_QT_WIN32'] + optional_deps += opengl32_dep + have_qt_windowing = true + endif +endif - if have_qt_windowing - # Build it! - moc_files = qt5_mod.preprocess(moc_headers : moc_headers) - gstqmlgl = library('gstqmlgl', sources, moc_files, - cpp_args : gst_plugins_good_args + qt_defines, - link_args : noseh_link_args, - include_directories: [configinc, libsinc], - dependencies : [glib_deps, gst_dep, gstvideo_dep, gstgl_dep, qt5qml_dep, optional_deps], - override_options : ['cpp_std=c++11'], - install: true, - install_dir : plugins_install_dir) - pkgconfig.generate(gstqmlgl, install_dir : plugins_pkgconfig_install_dir) - plugins += [gstqmlgl] - endif +if gst_gl_have_window_cocoa and gst_gl_have_platform_cgl + # FIXME: automagic + qt5macextras = dependency('qt5', modules : ['MacExtras'], required : false) + if qt5macextras.found() + qt_defines += ['-DHAVE_QT_MAC'] + optional_deps += qt5macextras + have_qt_windowing = true endif endif + +if gst_gl_have_window_eagl and gst_gl_have_platform_eagl + if host_machine.system() == 'ios' + qt_defines += ['-DHAVE_QT_IOS'] + have_qt_windowing = true + endif +endif + +if have_qt_windowing + # Build it! + moc_files = qt5_mod.preprocess(moc_headers : moc_headers) + gstqmlgl = library('gstqmlgl', sources, moc_files, + cpp_args : gst_plugins_good_args + qt_defines, + link_args : noseh_link_args, + include_directories: [configinc, libsinc], + dependencies : [glib_deps, gst_dep, gstvideo_dep, gstgl_dep, gstglproto_dep, qt5qml_dep, optional_deps], + override_options : ['cpp_std=c++11'], + install: true, + install_dir : plugins_install_dir) + pkgconfig.generate(gstqmlgl, install_dir : plugins_pkgconfig_install_dir) + plugins += [gstqmlgl] +endif diff --git a/ext/qt/qtglrenderer.cc b/ext/qt/qtglrenderer.cc new file mode 100644 index 0000000000..52965fd0bd --- /dev/null +++ b/ext/qt/qtglrenderer.cc @@ -0,0 +1,765 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "qtglrenderer.h" +#include "gstqtglutility.h" + +#define GST_CAT_DEFAULT gst_qt_gl_renderer_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +static void +init_debug (void) +{ + static gsize _debug; + + if (g_once_init_enter (&_debug)) { + GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "qtglrenderer", 0, + "Qt OpenGL Renderer"); + g_once_init_leave (&_debug, 1); + } +} + +/* Needs to be based on QWindow otherwise (at least) windows and nvidia + * proprietary on linux does not work + * We also need to override the size handling to get the correct output size + */ +class GstBackingSurface : public QWindow +{ +public: + GstBackingSurface(); + ~GstBackingSurface(); + + void setSize (int width, int height); + QSize size() const override; + +private: + QSize m_size; +}; + +GstBackingSurface::GstBackingSurface() + : m_size(QSize()) +{ + /* we do OpenGL things so need an OpenGL surface */ + setSurfaceType(QSurface::OpenGLSurface); +} + +GstBackingSurface::~GstBackingSurface() +{ +} + +QSize GstBackingSurface::size () const +{ + return m_size; +} + +void GstBackingSurface::setSize (int width, int height) +{ + m_size = QSize (width, height); +} + +class GstAnimationDriver : public QAnimationDriver +{ +public: + GstAnimationDriver(); + + void setNextTime(qint64 ms); + void advance() override; + qint64 elapsed() const override; +private: + qint64 m_elapsed; + qint64 m_next; +}; + +GstAnimationDriver::GstAnimationDriver() + : m_elapsed(0), + m_next(0) +{ +} + +void GstAnimationDriver::advance() +{ + m_elapsed = m_next; + advanceAnimation(); +} + +qint64 GstAnimationDriver::elapsed() const +{ + return m_elapsed; +} + +void GstAnimationDriver::setNextTime(qint64 ms) +{ + m_next = ms; +} + +typedef enum +{ + STATE_ERROR = -1, + STATE_NEW = 0, + STATE_WAITING_FOR_WINDOW, + STATE_WINDOW_CREATED, + STATE_READY, +} SharedRenderDataState; + +struct SharedRenderData +{ + int refcount; + SharedRenderDataState state; + GMutex lock; + GCond cond; + GstAnimationDriver *m_animationDriver; + QOpenGLContext *m_context; + GstBackingSurface *m_surface; + QThread *m_renderThread; +}; + +static struct SharedRenderData * +shared_render_data_new (void) +{ + struct SharedRenderData *ret = g_new0 (struct SharedRenderData, 1); + + g_atomic_int_set (&ret->refcount, 1); + g_mutex_init (&ret->lock); + + return ret; +} + +static void +shared_render_data_free (struct SharedRenderData * data) +{ + GST_DEBUG ("%p freeing shared render data", data); + + g_mutex_clear (&data->lock); + + if (data->m_animationDriver) { + data->m_animationDriver->uninstall(); + delete data->m_animationDriver; + } + data->m_animationDriver = nullptr; + if (data->m_context) + delete data->m_context; + data->m_context = nullptr; + if (data->m_surface) + delete data->m_surface; + data->m_surface = nullptr; +} + +static struct SharedRenderData * +shared_render_data_ref (struct SharedRenderData * data) +{ + GST_TRACE ("%p reffing shared render data", data); + g_atomic_int_inc (&data->refcount); + return data; +} + +static void +shared_render_data_unref (struct SharedRenderData * data) +{ + GST_TRACE ("%p unreffing shared render data", data); + if (g_atomic_int_dec_and_test (&data->refcount)) + shared_render_data_free (data); +} + +void +GstQuickRenderer::deactivateContext () +{ +} + +void +GstQuickRenderer::activateContext () +{ +} + +struct FBOUserData +{ + GstGLContext * context; + QOpenGLFramebufferObject * fbo; +}; + +static void +delete_cxx_gl_context (GstGLContext * context, struct FBOUserData * data) +{ + GST_TRACE ("freeing Qfbo %p", data->fbo); + delete data->fbo; +} + +static void +notify_fbo_delete (struct FBOUserData * data) +{ + gst_gl_context_thread_add (data->context, + (GstGLContextThreadFunc) delete_cxx_gl_context, data); + gst_object_unref (data->context); + g_free (data); +} + +GstQuickRenderer::GstQuickRenderer() + : gl_context(NULL), + m_fbo(nullptr), + m_quickWindow(nullptr), + m_renderControl(nullptr), + m_qmlEngine(nullptr), + m_qmlComponent(nullptr), + m_rootItem(nullptr), + gl_allocator(NULL), + gl_params(NULL), + gl_mem(NULL), + m_sharedRenderData(NULL) +{ + init_debug (); +} + +static gpointer +dup_shared_render_data (gpointer data, gpointer user_data) +{ + struct SharedRenderData *render_data = (struct SharedRenderData *) data; + + if (render_data) + return shared_render_data_ref (render_data); + + return NULL; +} + +class CreateSurfaceEvent : public QEvent +{ +public: + CreateSurfaceEvent (CreateSurfaceWorker * worker) + : QEvent(CreateSurfaceEvent::type()) + { + m_worker = worker; + } + + ~CreateSurfaceEvent() + { + GST_TRACE ("%p destroying create surface event", this); + delete m_worker; + } + + static QEvent::Type type() + { + if (customEventType == QEvent::None) { + int generatedType = QEvent::registerEventType(); + customEventType = static_cast(generatedType); + } + return customEventType; + } + +private: + static QEvent::Type customEventType; + CreateSurfaceWorker *m_worker; +}; + +QEvent::Type CreateSurfaceEvent::customEventType = QEvent::None; + + +CreateSurfaceWorker::CreateSurfaceWorker (struct SharedRenderData * rdata) +{ + m_sharedRenderData = shared_render_data_ref (rdata); +} + +CreateSurfaceWorker::~CreateSurfaceWorker () +{ + shared_render_data_unref (m_sharedRenderData); +} + +bool CreateSurfaceWorker::event(QEvent * ev) +{ + if (ev->type() == CreateSurfaceEvent::type()) { + GST_TRACE ("%p creating surface", m_sharedRenderData); + /* create the window surface in the main thread */ + g_mutex_lock (&m_sharedRenderData->lock); + m_sharedRenderData->m_surface = new GstBackingSurface; + m_sharedRenderData->m_surface->create(); + m_sharedRenderData->m_surface->moveToThread (m_sharedRenderData->m_renderThread); + GST_TRACE ("%p created surface %p", m_sharedRenderData, + m_sharedRenderData->m_surface); + g_cond_broadcast (&m_sharedRenderData->cond); + g_mutex_unlock (&m_sharedRenderData->lock); + } + + return QObject::event(ev); +} + +bool GstQuickRenderer::init (GstGLContext * context, GError ** error) +{ + g_return_val_if_fail (GST_IS_GL_CONTEXT (context), false); + g_return_val_if_fail (gst_gl_context_get_current () == context, false); + + QVariant qt_native_context = qt_opengl_native_context_from_gst_gl_context (context); + + if (qt_native_context.isNull()) { + g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_NOT_FOUND, + "Could not convert from the provided GstGLContext to a Qt " + "native context"); + return false; + } + + struct SharedRenderData *render_data = NULL, *old_render_data; + do { + if (render_data) + shared_render_data_unref (render_data); + + old_render_data = render_data = (struct SharedRenderData *) + g_object_dup_data (G_OBJECT (context), + "qt.gl.render.shared.data", dup_shared_render_data, NULL); + if (!render_data) + render_data = shared_render_data_new (); + } while (old_render_data != render_data + && !g_object_replace_data (G_OBJECT (context), + "qt.gl.render.shared.data", old_render_data, render_data, + NULL, NULL)); + m_sharedRenderData = render_data; + GST_TRACE ("%p retrieved shared render data %p", this, m_sharedRenderData); + + g_mutex_lock (&m_sharedRenderData->lock); + if (m_sharedRenderData->state == STATE_ERROR) { + g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_NOT_FOUND, + "In an error state from a previous attempt"); + g_mutex_unlock (&m_sharedRenderData->lock); + return false; + } + + if (m_sharedRenderData->state != STATE_READY) { + /* this state handling and locking is so that two qtglrenderer's will + * not attempt to create an OpenGL context without freeing the previous + * OpenGL context and cause a leak. It also only allows one + * CreateSurfaceEvent() to be posted to the main thread + * (QCoreApplication::instance()->thread()) while still allowing + * multiple waiters to wait for the window to be created */ + if (m_sharedRenderData->state == STATE_NEW) { + QCoreApplication *app = QCoreApplication::instance (); + + if (!app) { + g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_NOT_FOUND, + "Could not retrieve QCoreApplication instance"); + m_sharedRenderData->state = STATE_ERROR; + g_mutex_unlock (&m_sharedRenderData->lock); + return false; + } + + m_sharedRenderData->m_renderThread = QThread::currentThread(); + m_sharedRenderData->m_context = new QOpenGLContext; + GST_TRACE ("%p new QOpenGLContext %p", this, m_sharedRenderData->m_context); + m_sharedRenderData->m_context->setNativeHandle(qt_native_context); + + CreateSurfaceWorker *w = new CreateSurfaceWorker (m_sharedRenderData); + GST_TRACE ("%p posting create surface event to main thread with " + "worker %p", this, w); + w->moveToThread (app->thread()); + app->postEvent (w, new CreateSurfaceEvent (w)); + m_sharedRenderData->state = STATE_WAITING_FOR_WINDOW; + } + + if (m_sharedRenderData->state == STATE_WAITING_FOR_WINDOW) { + gint64 end_time = g_get_monotonic_time () + 5 * G_TIME_SPAN_SECOND; + while (!m_sharedRenderData->m_surface) { + /* XXX: This might deadlock with the main thread if the + * QCoreApplication is not running and will not be able to + * execute. We only wait for 5 seconds until a better + * approach can be found here */ + if (!g_cond_wait_until (&m_sharedRenderData->cond, + &m_sharedRenderData->lock, end_time)) { + g_set_error (error, GST_RESOURCE_ERROR, + GST_RESOURCE_ERROR_NOT_FOUND, + "Could not create Qt window within 5 seconds"); + m_sharedRenderData->state = STATE_ERROR; + g_mutex_unlock (&m_sharedRenderData->lock); + return false; + } + } + + GST_TRACE ("%p surface successfully created", this); + m_sharedRenderData->state = STATE_WINDOW_CREATED; + } + + if (m_sharedRenderData->state == STATE_WINDOW_CREATED) { + /* Qt does some things that may require the OpenGL context current + * in ->create() so that it has the necessry information to create + * the QOpenGLContext from the native handle. This may fail if the + * OpenGL context is already current in another thread so we need + * to deactivate the context from GStreamer's thread before asking + * Qt to create the QOpenGLContext with ->create(). + */ + gst_gl_context_activate (context, FALSE); + m_sharedRenderData->m_context->create(); + m_sharedRenderData->m_context->doneCurrent(); + + if (!m_sharedRenderData->m_context->makeCurrent(m_sharedRenderData->m_surface)) { + g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_NOT_FOUND, + "Could not make Qt OpenGL context current"); + /* try to keep the same OpenGL context state */ + gst_gl_context_activate (context, TRUE); + m_sharedRenderData->state = STATE_ERROR; + g_mutex_unlock (&m_sharedRenderData->lock); + return false; + } + + if (!gst_gl_context_activate (context, TRUE)) { + g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_NOT_FOUND, + "Could not make OpenGL context current again"); + m_sharedRenderData->state = STATE_ERROR; + g_mutex_unlock (&m_sharedRenderData->lock); + return false; + } + m_sharedRenderData->state = STATE_READY; + } + } + + m_renderControl = new QQuickRenderControl(); + /* Create a QQuickWindow that is associated with our render control. Note that this + * window never gets created or shown, meaning that it will never get an underlying + * native (platform) window. + */ + m_quickWindow = new QQuickWindow(m_renderControl); + /* after QQuickWindow creation as QQuickRenderControl requires it */ + m_renderControl->prepareThread (m_sharedRenderData->m_renderThread); + g_mutex_unlock (&m_sharedRenderData->lock); + + /* Create a QML engine. */ + m_qmlEngine = new QQmlEngine; + if (!m_qmlEngine->incubationController()) + m_qmlEngine->setIncubationController(m_quickWindow->incubationController()); + + gl_context = static_cast(gst_object_ref (context)); + gl_allocator = (GstGLBaseMemoryAllocator *) gst_gl_memory_allocator_get_default (gl_context); + gl_params = (GstGLAllocationParams *) + gst_gl_video_allocation_params_new_wrapped_texture (gl_context, + NULL, &this->v_info, 0, NULL, GST_GL_TEXTURE_TARGET_2D, GST_GL_RGBA8, + 0, NULL, (GDestroyNotify) notify_fbo_delete); + + /* This is a gross hack relying on the internals of Qt and GStreamer + * however it's the only way to remove this warning on shutdown of all + * resources. + * + * GLib-CRITICAL **: 17:35:24.988: g_main_context_pop_thread_default: assertion 'g_queue_peek_head (stack) == context' failed + * + * The reason is that libgstgl has a GMainContext that it pushes as the + * thread default context. Then later, Qt pushes a thread default main + * context. The detruction order of the GMainContext's is reversed as + * GStreamer will explicitly pop the thread default main context however + * Qt pops when the thread is about to be destroyed. GMainContext is + * unhappy with the ordering of the pops. + */ + GMainContext *gst_main_context = g_main_context_ref_thread_default (); + + /* make Qt allocate and push a thread-default GMainContext if it is + * going to */ + QEventLoop loop; + if (loop.processEvents()) + GST_LOG ("pending QEvents processed"); + + GMainContext *qt_main_context = g_main_context_ref_thread_default (); + + if (qt_main_context == gst_main_context) { + g_main_context_unref (qt_main_context); + g_main_context_unref (gst_main_context); + } else { + /* We flip the order of the GMainContext's so that the destruction + * order can be preserved. */ + g_main_context_pop_thread_default (qt_main_context); + g_main_context_pop_thread_default (gst_main_context); + g_main_context_push_thread_default (qt_main_context); + g_main_context_push_thread_default (gst_main_context); + g_main_context_unref (qt_main_context); + g_main_context_unref (gst_main_context); + } + + return true; +} + +GstQuickRenderer::~GstQuickRenderer() +{ + gst_gl_allocation_params_free (gl_params); + gst_clear_object (&gl_allocator); +} + +void GstQuickRenderer::stopGL () +{ + GST_DEBUG ("%p stop QOpenGLContext curent: %p stored: %p", this, + QOpenGLContext::currentContext(), m_sharedRenderData->m_context); + g_assert (QOpenGLContext::currentContext() == m_sharedRenderData->m_context); + + if (m_renderControl) + m_renderControl->invalidate(); + + if (m_fbo) + delete m_fbo; + m_fbo = nullptr; + + QEventLoop loop; + if (loop.processEvents()) + GST_LOG ("%p pending QEvents processed", this); + + if (m_sharedRenderData) + shared_render_data_unref (m_sharedRenderData); + m_sharedRenderData = NULL; + + /* XXX: reset the OpenGL context and drawable as Qt may have clobbered it. + * Fixes any attempt to access OpenGL after shutting down qmlgloverlay. */ + gst_gl_context_activate (gl_context, FALSE); + gst_gl_context_activate (gl_context, TRUE); +} + +void GstQuickRenderer::cleanup() +{ + if (gl_context) + gst_gl_context_thread_add (gl_context, + (GstGLContextThreadFunc) GstQuickRenderer::stop_c, this); + + /* Delete the render control first since it will free the scenegraph resources. + * Destroy the QQuickWindow only afterwards. */ + if (m_renderControl) + delete m_renderControl; + m_renderControl = nullptr; + + if (m_qmlComponent) + delete m_qmlComponent; + m_qmlComponent = nullptr; + if (m_quickWindow) + delete m_quickWindow; + m_quickWindow = nullptr; + if (m_qmlEngine) + delete m_qmlEngine; + m_qmlEngine = nullptr; + if (m_rootItem) + delete m_rootItem; + m_rootItem = nullptr; + + gst_clear_object (&gl_context); +} + +void GstQuickRenderer::ensureFbo() +{ + if (m_fbo && m_fbo->size() != m_sharedRenderData->m_surface->size()) { + GST_INFO ("%p removing old framebuffer created with size %ix%i", + this, m_fbo->size().width(), m_fbo->size().height()); + delete m_fbo; + m_fbo = nullptr; + } + + if (!m_fbo) { + m_fbo = new QOpenGLFramebufferObject(m_sharedRenderData->m_surface->size(), + QOpenGLFramebufferObject::CombinedDepthStencil); + m_quickWindow->setRenderTarget(m_fbo); + GST_DEBUG ("%p new framebuffer created with size %ix%i", this, + m_fbo->size().width(), m_fbo->size().height()); + } +} + +void +GstQuickRenderer::renderGstGL () +{ + const GstGLFuncs *gl = gl_context->gl_vtable; + + GST_TRACE ("%p current QOpenGLContext %p", this, + QOpenGLContext::currentContext()); + m_quickWindow->resetOpenGLState(); + + m_sharedRenderData->m_animationDriver->advance(); + + QEventLoop loop; + if (loop.processEvents()) + GST_LOG ("pending QEvents processed"); + + loop.exit(); + + ensureFbo(); + + /* Synchronization and rendering happens here on the render thread. */ + if (m_renderControl->sync()) + GST_LOG ("sync successful"); + + /* Meanwhile on this thread continue with the actual rendering. */ + m_renderControl->render(); + + GST_DEBUG ("wrapping Qfbo %p with texture %u", m_fbo, m_fbo->texture()); + struct FBOUserData *data = g_new0 (struct FBOUserData, 1); + data->context = (GstGLContext *) gst_object_ref (gl_context); + data->fbo = m_fbo; + gl_params->user_data = static_cast (data); + gl_params->gl_handle = GINT_TO_POINTER (m_fbo->texture()); + gl_mem = (GstGLMemory *) gst_gl_base_memory_alloc (gl_allocator, gl_params); + + m_fbo = nullptr; + + m_quickWindow->resetOpenGLState (); + /* Qt doesn't seem to reset this, breaking glimagesink */ + if (gl->DrawBuffer) + gl->DrawBuffer (GL_BACK); +} + +GstGLMemory *GstQuickRenderer::generateOutput(GstClockTime input_ns) +{ + m_sharedRenderData->m_animationDriver->setNextTime(input_ns / GST_MSECOND); + + /* run an event loop to update any changed values for rendering */ + QEventLoop loop; + if (loop.processEvents()) + GST_LOG ("pending QEvents processed"); + + GST_LOG ("generating output for time %" GST_TIME_FORMAT " ms: %" + G_GUINT64_FORMAT, GST_TIME_ARGS (input_ns), input_ns / GST_MSECOND); + + m_quickWindow->update(); + + /* Polishing happens on the gui thread. */ + m_renderControl->polishItems(); + + /* TODO: an async version could be used where */ + gst_gl_context_thread_add (gl_context, + (GstGLContextThreadFunc) GstQuickRenderer::render_gst_gl_c, this); + + GstGLMemory *tmp = gl_mem; + gl_mem = NULL; + + return tmp; +} + +void GstQuickRenderer::initializeGstGL () +{ + GST_TRACE ("current QOpenGLContext %p", QOpenGLContext::currentContext()); + if (!m_sharedRenderData->m_context->makeCurrent(m_sharedRenderData->m_surface)) { + m_errorString = "Failed to make Qt's wrapped OpenGL context current"; + return; + } + GST_INFO ("current QOpenGLContext %p", QOpenGLContext::currentContext()); + + /* XXX: Avoid an assertion inside QSGDefaultRenderContext::initialize() + * from an unused (in this scenario) property when using multiple + * QQuickRenderControl's with the same QOpenGLContext. + * + * First noticed with Qt 5.15. Idea from: + * https://forum.qt.io/topic/55888/is-it-impossible-that-2-qquickrendercontrol-use-same-qopenglcontext/2 + * + * ASSERT: "!m_gl->property(QSG_RENDERCONTEXT_PROPERTY).isValid()" in file /path/to/qt5/qtdeclarative/src/quick/scenegraph/qsgdefaultrendercontext.cpp, line 121 + */ + m_sharedRenderData->m_context->setProperty("_q_sgrendercontext", QVariant()); + + m_renderControl->initialize(m_sharedRenderData->m_context); + + /* 1. QAnimationDriver's are thread-specific + * 2. QAnimationDriver controls the 'animation time' that the Qml scene is + * rendered at + */ + /* FIXME: what happens with multiple qmlgloverlay elements? Do we need a + * shared animation driver? */ + g_mutex_lock (&m_sharedRenderData->lock); + if (m_sharedRenderData->m_animationDriver == nullptr) { + m_sharedRenderData->m_animationDriver = new GstAnimationDriver; + m_sharedRenderData->m_animationDriver->install(); + } + g_mutex_unlock (&m_sharedRenderData->lock); + /* XXX: reset the OpenGL context drawable as Qt may have clobbered it. + * Fixes glimagesink output where Qt replaces the Surface to use in its + * own MakeCurrent call. Qt does this on it's OpenGL initialisation + * the the rendering engine. */ + gst_gl_context_activate (gl_context, FALSE); + gst_gl_context_activate (gl_context, TRUE); +} + +void GstQuickRenderer::initializeQml() +{ + disconnect(m_qmlComponent, &QQmlComponent::statusChanged, this, + &GstQuickRenderer::initializeQml); + + if (m_qmlComponent->isError()) { + const QList errorList = m_qmlComponent->errors(); + for (const QQmlError &error : errorList) + m_errorString += error.toString(); + return; + } + + QObject *rootObject = m_qmlComponent->create(); + if (m_qmlComponent->isError()) { + const QList errorList = m_qmlComponent->errors(); + for (const QQmlError &error : errorList) + m_errorString += error.toString(); + delete rootObject; + return; + } + + m_rootItem = qobject_cast(rootObject); + if (!m_rootItem) { + m_errorString += "root QML item is not a QQuickItem"; + delete rootObject; + return; + } + + /* The root item is ready. Associate it with the window. */ + m_rootItem->setParentItem(m_quickWindow->contentItem()); + + /* Update item and rendering related geometries. */ + updateSizes(); + + /* Initialize the render control and our OpenGL resources. */ + gst_gl_context_thread_add (gl_context, + (GstGLContextThreadFunc) GstQuickRenderer::initialize_gst_gl_c, this); +} + +void GstQuickRenderer::updateSizes() +{ + GstBackingSurface *surface = + static_cast(m_sharedRenderData->m_surface); + /* Behave like SizeRootObjectToView. */ + QSize size = surface->size(); + + m_rootItem->setWidth(size.width()); + m_rootItem->setHeight(size.height()); + + m_quickWindow->setGeometry(0, 0, size.width(), size.height()); + + gst_video_info_set_format (&v_info, GST_VIDEO_FORMAT_RGBA, size.width(), + size.height()); + GstGLVideoAllocationParams *params = (GstGLVideoAllocationParams *) (gl_params); + gst_video_info_set_format (params->v_info, GST_VIDEO_FORMAT_RGBA, size.width(), + size.height()); +} + +void GstQuickRenderer::setSize(int w, int h) +{ + static_cast(m_sharedRenderData->m_surface)->setSize(w, h); + updateSizes(); +} + +bool GstQuickRenderer::setQmlScene (const gchar * scene, GError ** error) +{ + /* replacing the scene is not supported */ + g_return_val_if_fail (m_qmlComponent == NULL, false); + + m_errorString = ""; + + m_qmlComponent = new QQmlComponent(m_qmlEngine); + /* XXX: do we need to provide a propper base name? */ + m_qmlComponent->setData(QByteArray (scene), QUrl("")); + if (m_qmlComponent->isLoading()) + /* TODO: handle async properly */ + connect(m_qmlComponent, &QQmlComponent::statusChanged, this, + &GstQuickRenderer::initializeQml); + else + initializeQml(); + + if (m_errorString != "") { + QByteArray string = m_errorString.toUtf8(); + g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_SETTINGS, + "%s", string.constData()); + return FALSE; + } + + return TRUE; +} + +QQuickItem * GstQuickRenderer::rootItem() const +{ + return m_rootItem; +} diff --git a/ext/qt/qtglrenderer.h b/ext/qt/qtglrenderer.h new file mode 100644 index 0000000000..b271b0bee4 --- /dev/null +++ b/ext/qt/qtglrenderer.h @@ -0,0 +1,123 @@ +/* + * GStreamer + * Copyright (C) 2020 Matthew Waters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __QT_QUICK_RENDER_H__ +#define __QT_QUICK_RENDER_H__ + +#include +#include + +#include + +QT_FORWARD_DECLARE_CLASS(QOpenGLContext) +QT_FORWARD_DECLARE_CLASS(QOpenGLFramebufferObject) +QT_FORWARD_DECLARE_CLASS(QQuickRenderControl) +QT_FORWARD_DECLARE_CLASS(QQuickWindow) +QT_FORWARD_DECLARE_CLASS(QQmlEngine) +QT_FORWARD_DECLARE_CLASS(QQmlComponent) +QT_FORWARD_DECLARE_CLASS(QQuickItem) +QT_FORWARD_DECLARE_CLASS(GstAnimationDriver) +QT_FORWARD_DECLARE_CLASS(GstBackingSurface) + +class GstQuickRenderer : public QObject +{ + Q_OBJECT + +public: + GstQuickRenderer(); + ~GstQuickRenderer(); + + /* initialize the GStreamer/Qt integration. On failure returns false + * and fills @error. + * Must be called with @context not wrapped and current in the current + * thread */ + bool init (GstGLContext * context, GError ** error); + + /* set the qml scene. returns false and fills @error on failure */ + bool setQmlScene (const gchar * scene, GError ** error); + + void setSize(int w, int h); + + GstGLMemory *generateOutput(GstClockTime input_ns); + + /* cleanup any resources. Any use of this object after calling this + * function may result in undefined behaviour */ + void cleanup(); + + /* retrieve the rootItem from the qml scene. Only valid after + * setQmlScene() has been successfully called */ + QQuickItem *rootItem() const; + +private slots: + void initializeQml(); + +private: + void init(); + void ensureFbo(); + + void updateSizes(); + + static void render_gst_gl_c (GstGLContext * context, GstQuickRenderer * self) { self->renderGstGL (); } + void renderGstGL (); + + static void initialize_gst_gl_c (GstGLContext * context, GstQuickRenderer * self) { self->initializeGstGL (); } + void initializeGstGL (); + + static void stop_c (GstGLContext * context, GstQuickRenderer * self) { self->stopGL (); } + void stopGL (); + + static void activate_context_c (GstGLContext * context, GstQuickRenderer * self) { self->activateContext (); } + void activateContext (); + + static void deactivate_context_c (GstGLContext * context, GstQuickRenderer * self) { self->deactivateContext (); } + void deactivateContext (); + + GstGLContext *gl_context; + QOpenGLFramebufferObject *m_fbo; + QQuickWindow *m_quickWindow; + QQuickRenderControl *m_renderControl; + QQmlEngine *m_qmlEngine; + QQmlComponent *m_qmlComponent; + QQuickItem *m_rootItem; + + GstGLBaseMemoryAllocator *gl_allocator; + GstGLAllocationParams *gl_params; + GstVideoInfo v_info; + GstGLMemory *gl_mem; + + QString m_errorString; + struct SharedRenderData *m_sharedRenderData; +}; + +class CreateSurfaceWorker : public QObject +{ + Q_OBJECT + +public: + CreateSurfaceWorker (struct SharedRenderData * rdata); + ~CreateSurfaceWorker (); + + bool event(QEvent *ev) override; + +private: + struct SharedRenderData *m_sharedRenderData; +}; + +#endif /* __QT_QUICK_RENDER_H__ */ diff --git a/ext/qt/qtitem.cc b/ext/qt/qtitem.cc index 65b883eab8..8b7539885d 100644 --- a/ext/qt/qtitem.cc +++ b/ext/qt/qtitem.cc @@ -31,10 +31,15 @@ #include #include +#include #include #include #include +#ifdef HAVE_QT_QPA_HEADER +#include +#endif + /** * SECTION:gtkgstglwidget * @short_description: a #GtkGLArea that renders GStreamer video #GstBuffers @@ -78,6 +83,14 @@ struct _QtGLVideoItemPrivate QOpenGLContext *qt_context; GstGLContext *other_context; GstGLContext *context; + + /* buffers with textures that were bound by QML */ + GQueue bound_buffers; + /* buffers that were previously bound but in the meantime a new one was + * bound so this one is most likely not used anymore + * FIXME: Ideally we would use fences for this but there seems to be no + * way to reliably "try wait" on a fence */ + GQueue potentially_unbound_buffers; }; class InitializeSceneGraph : public QRunnable @@ -87,7 +100,7 @@ class InitializeSceneGraph : public QRunnable void run(); private: - QtGLVideoItem *item_; + QPointer item_; }; InitializeSceneGraph::InitializeSceneGraph(QtGLVideoItem *item) : @@ -97,12 +110,13 @@ InitializeSceneGraph::InitializeSceneGraph(QtGLVideoItem *item) : void InitializeSceneGraph::run() { - item_->onSceneGraphInitialized(); + if(item_) + item_->onSceneGraphInitialized(); } QtGLVideoItem::QtGLVideoItem() { - static volatile gsize _debug; + static gsize _debug; if (g_once_init_enter (&_debug)) { GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "qtglwidget", 0, "Qt GL Widget"); @@ -131,11 +145,13 @@ QtGLVideoItem::QtGLVideoItem() QtGLVideoItem::~QtGLVideoItem() { + GstBuffer *tmp_buffer; + /* Before destroying the priv info, make sure * no qmlglsink's will call in again, and that * any ongoing calls are done by invalidating the proxy * pointer */ - GST_INFO ("Destroying QtGLVideoItem and invalidating the proxy"); + GST_INFO ("%p Destroying QtGLVideoItem and invalidating the proxy %p", this, proxy.data()); proxy->invalidateRef(); proxy.clear(); @@ -146,6 +162,19 @@ QtGLVideoItem::~QtGLVideoItem() gst_object_unref(this->priv->other_context); if (this->priv->display) gst_object_unref(this->priv->display); + + while ((tmp_buffer = (GstBuffer*) g_queue_pop_head (&this->priv->potentially_unbound_buffers))) { + GST_TRACE ("old buffer %p should be unbound now, unreffing", tmp_buffer); + gst_buffer_unref (tmp_buffer); + } + while ((tmp_buffer = (GstBuffer*) g_queue_pop_head (&this->priv->bound_buffers))) { + GST_TRACE ("old buffer %p should be unbound now, unreffing", tmp_buffer); + gst_buffer_unref (tmp_buffer); + } + + gst_buffer_replace (&this->priv->buffer, NULL); + + gst_caps_replace (&this->priv->caps, NULL); g_free (this->priv); this->priv = NULL; } @@ -188,6 +217,9 @@ QSGNode * QtGLVideoItem::updatePaintNode(QSGNode * oldNode, UpdatePaintNodeData * updatePaintNodeData) { + GstBuffer *old_buffer; + gboolean was_bound = FALSE; + if (!m_openGlContextInitialized) { return oldNode; } @@ -197,7 +229,9 @@ QtGLVideoItem::updatePaintNode(QSGNode * oldNode, GstQSGTexture *tex; g_mutex_lock (&this->priv->lock); - gst_gl_context_activate (this->priv->other_context, TRUE); + + if (gst_gl_context_get_current() == NULL) + gst_gl_context_activate (this->priv->other_context, TRUE); GST_TRACE ("%p updatePaintNode", this); @@ -213,6 +247,38 @@ QtGLVideoItem::updatePaintNode(QSGNode * oldNode, } tex = static_cast (texNode->texture()); + + if ((old_buffer = tex->getBuffer(&was_bound))) { + if (old_buffer == this->priv->buffer) { + /* same buffer */ + gst_buffer_unref (old_buffer); + } else if (!was_bound) { + GST_TRACE ("old buffer %p was not bound yet, unreffing", old_buffer); + gst_buffer_unref (old_buffer); + } else { + GstBuffer *tmp_buffer; + + GST_TRACE ("old buffer %p was bound, queueing up for later", old_buffer); + /* Unref all buffers that were previously not bound anymore. At least + * one more buffer was bound in the meantime so this one is most likely + * not in use anymore. */ + while ((tmp_buffer = (GstBuffer*) g_queue_pop_head (&this->priv->potentially_unbound_buffers))) { + GST_TRACE ("old buffer %p should be unbound now, unreffing", tmp_buffer); + gst_buffer_unref (tmp_buffer); + } + + /* Move previous bound buffers to the next queue. We now know that + * another buffer was bound in the meantime and will free them on + * the next iteration above. */ + while ((tmp_buffer = (GstBuffer*) g_queue_pop_head (&this->priv->bound_buffers))) { + GST_TRACE ("old buffer %p is potentially unbound now", tmp_buffer); + g_queue_push_tail (&this->priv->potentially_unbound_buffers, tmp_buffer); + } + g_queue_push_tail (&this->priv->bound_buffers, old_buffer); + } + old_buffer = NULL; + } + tex->setCaps (this->priv->caps); tex->setBuffer (this->priv->buffer); texNode->markDirty(QSGNode::DirtyMaterial); @@ -236,7 +302,6 @@ QtGLVideoItem::updatePaintNode(QSGNode * oldNode, texNode->setRect (QRectF (result.x, result.y, result.w, result.h)); - gst_gl_context_activate (this->priv->other_context, FALSE); g_mutex_unlock (&this->priv->lock); return texNode; @@ -245,12 +310,23 @@ QtGLVideoItem::updatePaintNode(QSGNode * oldNode, static void _reset (QtGLVideoItem * qt_item) { + GstBuffer *tmp_buffer; + gst_buffer_replace (&qt_item->priv->buffer, NULL); gst_caps_replace (&qt_item->priv->caps, NULL); qt_item->priv->negotiated = FALSE; qt_item->priv->initted = FALSE; + + while ((tmp_buffer = (GstBuffer*) g_queue_pop_head (&qt_item->priv->potentially_unbound_buffers))) { + GST_TRACE ("old buffer %p should be unbound now, unreffing", tmp_buffer); + gst_buffer_unref (tmp_buffer); + } + while ((tmp_buffer = (GstBuffer*) g_queue_pop_head (&qt_item->priv->bound_buffers))) { + GST_TRACE ("old buffer %p should be unbound now, unreffing", tmp_buffer); + gst_buffer_unref (tmp_buffer); + } } void @@ -258,11 +334,13 @@ QtGLVideoItemInterface::setBuffer (GstBuffer * buffer) { QMutexLocker locker(&lock); - if (qt_item == NULL) + if (qt_item == NULL) { + GST_WARNING ("%p actual item is NULL. setBuffer call ignored", this); return; + } if (!qt_item->priv->negotiated) { - GST_WARNING ("Got buffer on unnegotiated QtGLVideoItem. Dropping"); + GST_WARNING ("%p Got buffer on unnegotiated QtGLVideoItem. Dropping", this); return; } @@ -278,6 +356,16 @@ QtGLVideoItemInterface::setBuffer (GstBuffer * buffer) void QtGLVideoItem::onSceneGraphInitialized () { + if (this->window() == NULL) + return; + + void* wgl_device = nullptr; + +#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (HAVE_QT_WIN32) && defined (HAVE_QT_QPA_HEADER) + HWND hWnd = nullptr; + QWindow* window = this->window(); +#endif + GST_DEBUG ("scene graph initialization with Qt GL context %p", this->window()->openglContext ()); @@ -290,8 +378,29 @@ QtGLVideoItem::onSceneGraphInitialized () return; } +#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (HAVE_QT_WIN32) && defined (HAVE_QT_QPA_HEADER) + if (window && window->handle()) { + QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface(); + hWnd = static_cast(pni->nativeResourceForWindow(QByteArrayLiteral("handle"), window)); + + if (hWnd != nullptr) { + wgl_device = GetWindowDC(hWnd); + } + } +#endif + m_openGlContextInitialized = gst_qt_get_gl_wrapcontext (this->priv->display, - &this->priv->other_context, &this->priv->context); + &this->priv->other_context, &this->priv->context, wgl_device); + +#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (HAVE_QT_WIN32) && defined (HAVE_QT_QPA_HEADER) + if (wgl_device != nullptr) { + ReleaseDC(hWnd, static_cast(wgl_device)); + wgl_device = nullptr; + } + + hWnd = nullptr; + window = nullptr; +#endif GST_DEBUG ("%p created wrapped GL context %" GST_PTR_FORMAT, this, this->priv->other_context); @@ -305,6 +414,10 @@ QtGLVideoItem::onSceneGraphInvalidated () GST_FIXME ("%p scene graph invalidated", this); } +/** + * Retrieve and populate the GL context information from the current + * OpenGL context. + */ gboolean QtGLVideoItemInterface::initWinSys () { @@ -405,27 +518,28 @@ _calculate_par (QtGLVideoItem * widget, GstVideoInfo * info) if (!ok) return FALSE; - GST_LOG ("PAR: %u/%u DAR:%u/%u", par_n, par_d, display_par_n, display_par_d); + GST_LOG ("%p PAR: %u/%u DAR:%u/%u", widget, par_n, par_d, display_par_n, + display_par_d); if (height % display_ratio_den == 0) { - GST_DEBUG ("keeping video height"); + GST_DEBUG ("%p keeping video height", widget); widget->priv->display_width = (guint) gst_util_uint64_scale_int (height, display_ratio_num, display_ratio_den); widget->priv->display_height = height; } else if (width % display_ratio_num == 0) { - GST_DEBUG ("keeping video width"); + GST_DEBUG ("%p keeping video width", widget); widget->priv->display_width = width; widget->priv->display_height = (guint) gst_util_uint64_scale_int (width, display_ratio_den, display_ratio_num); } else { - GST_DEBUG ("approximating while keeping video height"); + GST_DEBUG ("%p approximating while keeping video height", widget); widget->priv->display_width = (guint) gst_util_uint64_scale_int (height, display_ratio_num, display_ratio_den); widget->priv->display_height = height; } - GST_DEBUG ("scaling to %dx%d", widget->priv->display_width, + GST_DEBUG ("%p scaling to %dx%d", widget, widget->priv->display_width, widget->priv->display_height); return TRUE; @@ -491,7 +605,7 @@ QtGLVideoItemInterface::getContext () } GstGLDisplay * -QtGLVideoItemInterface::getDisplay() +QtGLVideoItemInterface::getDisplay() { QMutexLocker locker(&lock); diff --git a/ext/qt/qtplugin.pro b/ext/qt/qtplugin.pro index a4a63d5c03..5d6e40dd96 100644 --- a/ext/qt/qtplugin.pro +++ b/ext/qt/qtplugin.pro @@ -2,14 +2,65 @@ TEMPLATE = lib TARGET = gstqmlgl -QT += qml quick gui +QT += qml quick gui-private -QT_CONFIG -= no-pkg-config -CONFIG += link_pkgconfig debug -PKGCONFIG = \ - gstreamer-1.0 \ - gstreamer-video-1.0 \ - gstreamer-gl-1.0 +win32:!defined(packagesExist, test) { + # Change this to your gstreamer SDK installation path + GSTREAMER_PATH=C:/gstreamer/1.0/x86 + + # pkgconfig dependencies: gstreamer-1.0, gstreamer-video-1.0, gstreamer-gl-1.0 + + GSTREAMER_1_0_INCLUDEPATH = $${GSTREAMER_PATH}/include/gstreamer-1.0 + win32-g++:GSTREAMER_1_0_LIBS = -L$${GSTREAMER_PATH}/lib -lgstreamer-1.0 + win32-msvc:GSTREAMER_1_0_LIBS = /LIBPATH:$${GSTREAMER_PATH}/lib gstreamer-1.0.lib + + GSTREAMER_VIDEO_1_0_INCLUDEPATH = $${GSTREAMER_PATH}/include/gstreamer-1.0 + win32-g++:GSTREAMER_VIDEO_1_0_LIBS = -L$${GSTREAMER_PATH}/lib -lgstvideo-1.0 + win32-msvc:GSTREAMER_VIDEO_1_0_LIBS = /LIBPATH:$${GSTREAMER_PATH}/lib gstvideo-1.0.lib + + GSTREAMER_GL_1_0_INCLUDEPATH = $${GSTREAMER_PATH}/include \ + $${GSTREAMER_PATH}/lib/gstreamer-1.0/include + win32-g++:GSTREAMER_GL_1_0_LIBS = -L$${GSTREAMER_PATH}/lib -lgstgl-1.0 + win32-msvc:GSTREAMER_GL_1_0_LIBS = /LIBPATH:$${GSTREAMER_PATH}/lib gstgl-1.0.lib + + # Extra dependencies: + # glib-2.0, gobject-2.0 (required by gstreamer-1.0) + # gstreamer-base-1.0 (required by gstreamer-video-1.0) + + GLIB_2_0_INCLUDEPATH = $${GSTREAMER_PATH}/include/glib-2.0 \ + $${GSTREAMER_PATH}/lib/glib-2.0/include + win32-g++:GLIB_2_0_LIBS = -L$${GSTREAMER_PATH}/lib -lglib-2.0 -lintl + win32-msvc:GLIB_2_0_LIBS = /LIBPATH:$${GSTREAMER_PATH}/lib glib-2.0.lib intl.lib + + GOBJECT_2_0_INCLUDEPATH = $${GSTREAMER_PATH}/include + win32-g++:GOBJECT_2_0_LIBS = -L$${GSTREAMER_PATH}/lib -lgobject-2.0 + win32-msvc:GOBJECT_2_0_LIBS = /LIBPATH:$${GSTREAMER_PATH}/lib gobject-2.0.lib + + GSTREAMER_BASE_1_0_INCLUDEPATH = $${GSTREAMER_PATH}/include/gstreamer-1.0 + win32-g++:GSTREAMER_BASE_1_0_LIBS = -L$${GSTREAMER_PATH}/lib -lgstbase-1.0 + win32-msvc:GSTREAMER_BASE_1_0_LIBS = /LIBPATH:$${GSTREAMER_PATH}/lib gstbase-1.0.lib + + INCLUDEPATH += $${GSTREAMER_1_0_INCLUDEPATH} \ + $${GSTREAMER_VIDEO_1_0_INCLUDEPATH} \ + $${GSTREAMER_GL_1_0_INCLUDEPATH} \ + $${GLIB_2_0_INCLUDEPATH} \ + $${GOBJECT_2_0_INCLUDEPATH} \ + $${GSTREAMER_BASE_1_0_INCLUDEPATH} + + LIBS += $${GSTREAMER_1_0_LIBS} \ + $${GSTREAMER_VIDEO_1_0_LIBS} \ + $${GSTREAMER_GL_1_0_LIBS} \ + $${GLIB_2_0_LIBS} \ + $${GOBJECT_2_0_LIBS} \ + $${GSTREAMER_BASE_1_0_LIBS} +} else { + QT_CONFIG -= no-pkg-config + CONFIG += link_pkgconfig debug + PKGCONFIG = \ + gstreamer-1.0 \ + gstreamer-video-1.0 \ + gstreamer-gl-1.0 +} android { CONFIG += static @@ -18,17 +69,22 @@ android { } android:DEFINES += HAVE_QT_ANDROID -win32:DEFINES += HAVE_QT_WIN32 +win32:DEFINES += HAVE_QT_WIN32 HAVE_QT_QPA_HEADER macx:DEFINES += HAVE_QT_MAC -versionAtLeast(QT_VERSION, "5.5"):win32-msvc: LIBS += opengl32.lib +versionAtLeast(QT_VERSION, "5.5") { + win32-msvc: LIBS += opengl32.lib user32.lib + win32-g++: LIBS += -lopengl32 +} SOURCES += \ gstplugin.cc \ gstqtglutility.cc \ gstqsgtexture.cc \ + gstqtoverlay.cc \ gstqtsink.cc \ gstqtsrc.cc \ + qtglrenderer.cc \ qtwindow.cc \ qtitem.cc @@ -36,7 +92,9 @@ HEADERS += \ gstqsgtexture.h \ gstqtgl.h \ gstqtglutility.h \ + gstqtoverlay.h \ gstqtsink.h \ gstqtsrc.h \ + qtglrenderer.h \ qtwindow.h \ qtitem.h diff --git a/ext/qt/qtwindow.cc b/ext/qt/qtwindow.cc index 9360c3337f..2f88aa9848 100644 --- a/ext/qt/qtwindow.cc +++ b/ext/qt/qtwindow.cc @@ -36,6 +36,10 @@ #include #include +#ifdef HAVE_QT_QPA_HEADER +#include +#endif + /* compatibility definitions... */ #ifndef GL_READ_FRAMEBUFFER #define GL_READ_FRAMEBUFFER 0x8CA8 @@ -103,7 +107,7 @@ QtGLWindow::QtGLWindow ( QWindow * parent, QQuickWindow *src ) : QQuickWindow( parent ), source (src) { QGuiApplication *app = static_cast (QCoreApplication::instance ()); - static volatile gsize _debug; + static gsize _debug; g_assert (app != NULL); @@ -152,7 +156,7 @@ QtGLWindow::beforeRendering() g_mutex_lock (&this->priv->lock); - static volatile gsize once = 0; + static gsize once = 0; if (g_once_init_enter(&once)) { this->priv->start = QDateTime::currentDateTime().toMSecsSinceEpoch(); g_once_init_leave(&once,1); @@ -289,11 +293,35 @@ QtGLWindow::aboutToQuit() void QtGLWindow::onSceneGraphInitialized() { + void* wgl_device = nullptr; + +#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (HAVE_QT_WIN32) && defined (HAVE_QT_QPA_HEADER) + HWND hWnd = nullptr; +#endif + GST_DEBUG ("scene graph initialization with Qt GL context %p", this->source->openglContext ()); +#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (HAVE_QT_WIN32) && defined (HAVE_QT_QPA_HEADER) + if (handle()) { + QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface(); + hWnd = static_cast(pni->nativeResourceForWindow(QByteArrayLiteral("handle"), this)); + + if (hWnd != nullptr) { + wgl_device = GetWindowDC(hWnd); + } + } +#endif + this->priv->initted = gst_qt_get_gl_wrapcontext (this->priv->display, - &this->priv->other_context, NULL); + &this->priv->other_context, NULL, wgl_device); + +#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (HAVE_QT_WIN32) && defined (HAVE_QT_QPA_HEADER) + if (wgl_device != nullptr) { + ReleaseDC(hWnd, static_cast(wgl_device)); + wgl_device = nullptr; + } +#endif if (this->priv->initted && this->priv->other_context) { const GstGLFuncs *gl; diff --git a/ext/raw1394/gst1394clock.h b/ext/raw1394/gst1394clock.h index 411251e2d6..3e4912bf1c 100644 --- a/ext/raw1394/gst1394clock.h +++ b/ext/raw1394/gst1394clock.h @@ -31,21 +31,10 @@ G_BEGIN_DECLS -#define GST_TYPE_1394_CLOCK \ - (gst_1394_clock_get_type()) -#define GST_1394_CLOCK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_1394_CLOCK,Gst1394Clock)) -#define GST_1394_CLOCK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_1394_CLOCK,Gst1394ClockClass)) -#define GST_IS_1394_CLOCK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_1394_CLOCK)) -#define GST_IS_1394_CLOCK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_1394_CLOCK)) -#define GST_1394_CLOCK_CAST(obj) \ - ((Gst1394Clock*)(obj)) - -typedef struct _Gst1394Clock Gst1394Clock; -typedef struct _Gst1394ClockClass Gst1394ClockClass; +#define GST_TYPE_1394_CLOCK (gst_1394_clock_get_type()) +G_DECLARE_FINAL_TYPE (Gst1394Clock, gst_1394_clock, GST, 1394_CLOCK, + GstSystemClock) +#define GST_1394_CLOCK_CAST(obj) ((Gst1394Clock*)(obj)) /** * Gst1394Clock: @@ -62,11 +51,6 @@ struct _Gst1394Clock { guint32 cycle_timer_hi; }; -struct _Gst1394ClockClass { - GstSystemClockClass parent_class; -}; - -GType gst_1394_clock_get_type (void); Gst1394Clock* gst_1394_clock_new (const gchar *name); void gst_1394_clock_set_handle (Gst1394Clock *clock, raw1394handle_t handle); diff --git a/ext/raw1394/gstdv1394src.c b/ext/raw1394/gstdv1394src.c index 7ca9cd978a..2c0e8d6035 100644 --- a/ext/raw1394/gstdv1394src.c +++ b/ext/raw1394/gstdv1394src.c @@ -171,8 +171,7 @@ gst_dv1394src_class_init (GstDV1394SrcClass * klass) gst_dv1394src_signals[SIGNAL_FRAME_DROPPED] = g_signal_new ("frame-dropped", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDV1394SrcClass, frame_dropped), - NULL, NULL, NULL, G_TYPE_NONE, 0); + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PORT, g_param_spec_int ("port", "Port", "Port number (-1 automatic)", diff --git a/ext/raw1394/gstdv1394src.h b/ext/raw1394/gstdv1394src.h index 14a0178442..891d1fff74 100644 --- a/ext/raw1394/gstdv1394src.h +++ b/ext/raw1394/gstdv1394src.h @@ -33,19 +33,8 @@ G_BEGIN_DECLS -#define GST_TYPE_DV1394SRC \ - (gst_dv1394src_get_type()) -#define GST_DV1394SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DV1394SRC,GstDV1394Src)) -#define GST_DV1394SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DV1394SRC,GstDV1394SrcClass)) -#define GST_IS_DV1394SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DV1394SRC)) -#define GST_IS_DV1394SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DV1394SRC)) - -typedef struct _GstDV1394Src GstDV1394Src; -typedef struct _GstDV1394SrcClass GstDV1394SrcClass; +#define GST_TYPE_DV1394SRC (gst_dv1394src_get_type()) +G_DECLARE_FINAL_TYPE (GstDV1394Src, gst_dv1394src, GST, DV1394SRC, GstPushSrc) struct _GstDV1394Src { GstPushSrc element; @@ -87,15 +76,6 @@ struct _GstDV1394Src { Gst1394Clock *provided_clock; }; -struct _GstDV1394SrcClass { - GstPushSrcClass parent_class; - - /* signal */ - void (*frame_dropped) (GstElement *elem); -}; - -GType gst_dv1394src_get_type(void); - G_END_DECLS #endif /* __GST_GST1394_H__ */ diff --git a/ext/raw1394/gsthdv1394src.h b/ext/raw1394/gsthdv1394src.h index 6ae863c899..46dd0e6c09 100644 --- a/ext/raw1394/gsthdv1394src.h +++ b/ext/raw1394/gsthdv1394src.h @@ -32,19 +32,9 @@ G_BEGIN_DECLS -#define GST_TYPE_HDV1394SRC \ - (gst_hdv1394src_get_type()) -#define GST_HDV1394SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_HDV1394SRC,GstHDV1394Src)) -#define GST_HDV1394SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_HDV1394SRC,GstHDV1394SrcClass)) -#define GST_IS_HDV1394SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_HDV1394SRC)) -#define GST_IS_HDV1394SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_HDV1394SRC)) - -typedef struct _GstHDV1394Src GstHDV1394Src; -typedef struct _GstHDV1394SrcClass GstHDV1394SrcClass; +#define GST_TYPE_HDV1394SRC (gst_hdv1394src_get_type()) +G_DECLARE_FINAL_TYPE (GstHDV1394Src, gst_hdv1394src, GST, HDV1394SRC, + GstPushSrc) struct _GstHDV1394Src { GstPushSrc element; @@ -74,12 +64,6 @@ struct _GstHDV1394Src { iec61883_mpeg2_t iec61883mpeg2; }; -struct _GstHDV1394SrcClass { - GstPushSrcClass parent_class; -}; - -GType gst_hdv1394src_get_type(void); - G_END_DECLS #endif /* __GST_GST1394_H__ */ diff --git a/ext/shout2/gstshout2.c b/ext/shout2/gstshout2.c index adfaccf7a5..955897926f 100644 --- a/ext/shout2/gstshout2.c +++ b/ext/shout2/gstshout2.c @@ -94,11 +94,18 @@ enum #else #define WEBM_CAPS "" #endif + +#define SHOUT2SEND_BASIC_CAPS "application/ogg; audio/ogg; video/ogg; "\ + "audio/mpeg, mpegversion = (int) 1, layer = (int) [ 1, 3 ]" + +#define SHOUT2SEND_DOC_CAPS SHOUT2SEND_BASIC_CAPS "; video/webm; audio/webm" + +#define SHOUT2SEND_CAPS SHOUT2SEND_BASIC_CAPS WEBM_CAPS + static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/ogg; audio/ogg; video/ogg; " - "audio/mpeg, mpegversion = (int) 1, layer = (int) [ 1, 3 ]" WEBM_CAPS)); + GST_STATIC_CAPS (SHOUT2SEND_CAPS)); static void gst_shout2send_finalize (GstShout2send * shout2send); @@ -151,6 +158,8 @@ gst_shout2send_class_init (GstShout2sendClass * klass) GObjectClass *gobject_class; GstElementClass *gstelement_class; GstBaseSinkClass *gstbasesink_class; + GstPadTemplate *tmpl; + GstCaps *doc_caps; gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; @@ -220,8 +229,7 @@ gst_shout2send_class_init (GstShout2sendClass * klass) /* signals */ gst_shout2send_signals[SIGNAL_CONNECTION_PROBLEM] = g_signal_new ("connection-problem", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_CLEANUP, G_STRUCT_OFFSET (GstShout2sendClass, - connection_problem), NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT); + G_SIGNAL_RUN_CLEANUP, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT); gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_shout2send_start); gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_shout2send_stop); @@ -232,7 +240,13 @@ gst_shout2send_class_init (GstShout2sendClass * klass) gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_shout2send_event); gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_shout2send_setcaps); - gst_element_class_add_static_pad_template (gstelement_class, &sink_template); + tmpl = gst_static_pad_template_get (&sink_template); + gst_element_class_add_pad_template (gstelement_class, tmpl); + + /* our caps depend on the libshout2 version */ + doc_caps = gst_caps_from_string (SHOUT2SEND_DOC_CAPS); + gst_pad_template_set_documentation_caps (tmpl, doc_caps); + gst_clear_caps (&doc_caps); gst_element_class_set_static_metadata (gstelement_class, "Icecast network sink", @@ -242,6 +256,8 @@ gst_shout2send_class_init (GstShout2sendClass * klass) "Zaheer Abbas Merali "); GST_DEBUG_CATEGORY_INIT (shout2_debug, "shout2", 0, "shout2send element"); + + gst_type_mark_as_plugin_api (GST_TYPE_SHOUT_PROTOCOL, 0); } static void @@ -551,7 +567,13 @@ gst_shout2send_connect (GstShout2send * sink) ret = shout_open (sink->conn); /* wait for connection or timeout */ +#ifdef SHOUTERR_RETRY + /* starting with libshout 2.4.2, shout_open() has broken API + ABI and + * can also return SHOUTERR_RETRY (a new define) to mean "try again" */ + while (ret == SHOUTERR_BUSY || ret == SHOUTERR_RETRY) { +#else while (ret == SHOUTERR_BUSY) { +#endif if (gst_util_get_timestamp () - start_ts > sink->timeout * GST_MSECOND) { goto connection_timeout; } diff --git a/ext/shout2/gstshout2.h b/ext/shout2/gstshout2.h index 408716692d..92a97a7399 100644 --- a/ext/shout2/gstshout2.h +++ b/ext/shout2/gstshout2.h @@ -35,8 +35,10 @@ typedef enum { } GstShout2SendProtocol; -/* Definition of structure storing data for this element. */ -typedef struct _GstShout2send GstShout2send; +#define GST_TYPE_SHOUT2SEND (gst_shout2send_get_type()) +G_DECLARE_FINAL_TYPE (GstShout2send, gst_shout2send, GST, SHOUT2SEND, + GstBaseSink) + struct _GstShout2send { GstBaseSink parent; @@ -72,33 +74,6 @@ struct _GstShout2send { GstTagList* tags; }; - - -/* Standard definition defining a class for this element. */ -typedef struct _GstShout2sendClass GstShout2sendClass; -struct _GstShout2sendClass { - GstBaseSinkClass parent_class; - - /* signal callbacks */ - void (*connection_problem) (GstElement *element,guint errno); -}; - -/* Standard macros for defining types for this element. */ -#define GST_TYPE_SHOUT2SEND \ - (gst_shout2send_get_type()) -#define GST_SHOUT2SEND(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SHOUT2SEND,GstShout2send)) -#define GST_SHOUT2SEND_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SHOUT2SEND,GstShout2sendClass)) -#define GST_IS_SHOUT2SEND(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SHOUT2SEND)) -#define GST_IS_SHOUT2SEND_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SHOUT2SEND)) - -/* Standard function returning type information. */ -GType gst_shout2send_get_type(void); - - G_END_DECLS #endif /* __GST_SHOUT2SEND_H__ */ diff --git a/ext/soup/gstsouphttpclientsink.h b/ext/soup/gstsouphttpclientsink.h index 29c4500169..a98302c55f 100644 --- a/ext/soup/gstsouphttpclientsink.h +++ b/ext/soup/gstsouphttpclientsink.h @@ -25,14 +25,9 @@ G_BEGIN_DECLS -#define GST_TYPE_SOUP_HTTP_CLIENT_SINK (gst_soup_http_client_sink_get_type()) -#define GST_SOUP_HTTP_CLIENT_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SOUP_HTTP_CLIENT_SINK,GstSoupHttpClientSink)) -#define GST_SOUP_HTTP_CLIENT_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SOUP_HTTP_CLIENT_SINK,GstSoupHttpClientSinkClass)) -#define GST_IS_SOUP_HTTP_CLIENT_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SOUP_HTTP_CLIENT_SINK)) -#define GST_IS_SOUP_HTTP_CLIENT_SINK_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SOUP_HTTP_CLIENT_SINK)) - -typedef struct _GstSoupHttpClientSink GstSoupHttpClientSink; -typedef struct _GstSoupHttpClientSinkClass GstSoupHttpClientSinkClass; +#define GST_TYPE_SOUP_HTTP_CLIENT_SINK (gst_soup_http_client_sink_get_type()) +G_DECLARE_FINAL_TYPE (GstSoupHttpClientSink, gst_soup_http_client_sink, + GST, SOUP_HTTP_CLIENT_SINK, GstBaseSink) struct _GstSoupHttpClientSink { @@ -73,13 +68,6 @@ struct _GstSoupHttpClientSink gint retries; }; -struct _GstSoupHttpClientSinkClass -{ - GstBaseSinkClass base_souphttpsink_class; -}; - -GType gst_soup_http_client_sink_get_type (void); - G_END_DECLS #endif diff --git a/ext/soup/gstsouphttpsrc.c b/ext/soup/gstsouphttpsrc.c index 2d4c712784..ab3155efeb 100644 --- a/ext/soup/gstsouphttpsrc.c +++ b/ext/soup/gstsouphttpsrc.c @@ -919,6 +919,7 @@ gst_soup_http_src_session_open (GstSoupHTTPSrc * src) if (!src->session) { GstQuery *query; gboolean can_share = (src->timeout == DEFAULT_TIMEOUT) + && (src->cookies == NULL) && (src->ssl_strict == DEFAULT_SSL_STRICT) && (src->tls_interaction == NULL) && (src->proxy == NULL) && (src->tls_database == DEFAULT_TLS_DATABASE) @@ -1172,8 +1173,9 @@ gst_soup_http_src_got_headers (GstSoupHTTPSrc * src, SoupMessage * msg) gst_event_unref (http_headers_event); /* Parse Content-Length. */ - if (soup_message_headers_get_encoding (msg->response_headers) == - SOUP_ENCODING_CONTENT_LENGTH) { + if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code) && + (soup_message_headers_get_encoding (msg->response_headers) == + SOUP_ENCODING_CONTENT_LENGTH)) { newsize = src->request_position + soup_message_headers_get_content_length (msg->response_headers); if (!src->have_size || (src->content_size != newsize)) { @@ -1415,7 +1417,8 @@ gst_soup_http_src_parse_status (SoupMessage * msg, GstSoupHTTPSrc * src) * a body message, requests that go beyond the content limits will result * in an error. Here we convert those to EOS */ if (msg->status_code == SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE && - src->have_body && !src->have_size) { + src->have_body && (!src->have_size || + (src->request_position >= src->content_size))) { GST_DEBUG_OBJECT (src, "Requested range out of limits and received full " "body, returning EOS"); return GST_FLOW_EOS; @@ -1502,10 +1505,14 @@ gst_soup_http_src_build_message (GstSoupHTTPSrc * src, const gchar * method) soup_message_headers_append (src->msg->request_headers, "Cookie", *cookie); } + + soup_message_disable_feature (src->msg, SOUP_TYPE_COOKIE_JAR); } - if (!src->compress) - soup_message_disable_feature (src->msg, SOUP_TYPE_CONTENT_DECODER); + if (!src->compress) { + soup_message_headers_append (src->msg->request_headers, "Accept-Encoding", + "identity"); + } soup_message_set_flags (src->msg, SOUP_MESSAGE_OVERWRITE_CHUNKS | (src->automatic_redirect ? 0 : SOUP_MESSAGE_NO_REDIRECT)); diff --git a/ext/speex/gstspeexdec.c b/ext/speex/gstspeexdec.c index ca2dfdb313..3c29ec7ac2 100644 --- a/ext/speex/gstspeexdec.c +++ b/ext/speex/gstspeexdec.c @@ -132,7 +132,7 @@ gst_speex_dec_reset (GstSpeexDec * dec) dec->frame_size = 0; dec->frame_duration = 0; dec->mode = NULL; - free (dec->header); + speex_header_free (dec->header); dec->header = NULL; speex_bits_destroy (&dec->bits); speex_bits_set_bit_buffer (&dec->bits, NULL, 0); diff --git a/ext/speex/gstspeexdec.h b/ext/speex/gstspeexdec.h index 5e1e17173a..4a2033e8c3 100644 --- a/ext/speex/gstspeexdec.h +++ b/ext/speex/gstspeexdec.h @@ -31,19 +31,9 @@ G_BEGIN_DECLS -#define GST_TYPE_SPEEX_DEC \ - (gst_speex_dec_get_type()) -#define GST_SPEEX_DEC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPEEX_DEC,GstSpeexDec)) -#define GST_SPEEX_DEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPEEX_DEC,GstSpeexDecClass)) -#define GST_IS_SPEEX_DEC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPEEX_DEC)) -#define GST_IS_SPEEX_DEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPEEX_DEC)) - -typedef struct _GstSpeexDec GstSpeexDec; -typedef struct _GstSpeexDecClass GstSpeexDecClass; +#define GST_TYPE_SPEEX_DEC (gst_speex_dec_get_type()) +G_DECLARE_FINAL_TYPE (GstSpeexDec, gst_speex_dec, GST, SPEEX_DEC, + GstAudioDecoder) struct _GstSpeexDec { GstAudioDecoder element; @@ -65,12 +55,6 @@ struct _GstSpeexDec { GstBuffer *vorbiscomment; }; -struct _GstSpeexDecClass { - GstAudioDecoderClass parent_class; -}; - -GType gst_speex_dec_get_type (void); - G_END_DECLS #endif /* __GST_SPEEX_DEC_H__ */ diff --git a/ext/speex/gstspeexenc.c b/ext/speex/gstspeexenc.c index 52faa6e720..dc39d0adf6 100644 --- a/ext/speex/gstspeexenc.c +++ b/ext/speex/gstspeexenc.c @@ -217,6 +217,8 @@ gst_speex_enc_class_init (GstSpeexEncClass * klass) "Encodes audio in Speex format", "Wim Taymans "); GST_DEBUG_CATEGORY_INIT (speexenc_debug, "speexenc", 0, "Speex encoder"); + + gst_type_mark_as_plugin_api (GST_TYPE_SPEEX_ENC_MODE, 0); } static void @@ -718,7 +720,8 @@ gst_speex_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf) /* create header buffer */ data = (guint8 *) speex_header_to_packet (&enc->header, &data_len); - buf1 = gst_buffer_new_wrapped (data, data_len); + buf1 = gst_buffer_new_wrapped_full (0, + data, data_len, 0, data_len, data, (GDestroyNotify) speex_header_free); GST_BUFFER_OFFSET_END (buf1) = 0; GST_BUFFER_OFFSET (buf1) = 0; diff --git a/ext/speex/gstspeexenc.h b/ext/speex/gstspeexenc.h index 29fcc72a12..0ab2d5564a 100644 --- a/ext/speex/gstspeexenc.h +++ b/ext/speex/gstspeexenc.h @@ -30,16 +30,9 @@ G_BEGIN_DECLS -#define GST_TYPE_SPEEX_ENC \ - (gst_speex_enc_get_type()) -#define GST_SPEEX_ENC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPEEX_ENC,GstSpeexEnc)) -#define GST_SPEEX_ENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPEEX_ENC,GstSpeexEncClass)) -#define GST_IS_SPEEX_ENC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPEEX_ENC)) -#define GST_IS_SPEEX_ENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPEEX_ENC)) +#define GST_TYPE_SPEEX_ENC (gst_speex_enc_get_type()) +G_DECLARE_FINAL_TYPE (GstSpeexEnc, gst_speex_enc, GST, SPEEX_ENC, + GstAudioEncoder) typedef enum { @@ -49,9 +42,6 @@ typedef enum GST_SPEEX_ENC_MODE_NB } GstSpeexMode; -typedef struct _GstSpeexEnc GstSpeexEnc; -typedef struct _GstSpeexEncClass GstSpeexEncClass; - struct _GstSpeexEnc { GstAudioEncoder element; @@ -87,12 +77,6 @@ struct _GstSpeexEnc { gint comment_len; }; -struct _GstSpeexEncClass { - GstAudioEncoderClass parent_class; -}; - -GType gst_speex_enc_get_type (void); - G_END_DECLS #endif /* __GST_SPEEXENC_H__ */ diff --git a/ext/taglib/gstapev2mux.h b/ext/taglib/gstapev2mux.h index 8eceb57142..785a1c21b9 100644 --- a/ext/taglib/gstapev2mux.h +++ b/ext/taglib/gstapev2mux.h @@ -26,30 +26,13 @@ G_BEGIN_DECLS -typedef struct _GstApev2Mux GstApev2Mux; -typedef struct _GstApev2MuxClass GstApev2MuxClass; +#define GST_TYPE_APEV2_MUX (gst_apev2_mux_get_type()) +G_DECLARE_FINAL_TYPE (GstApev2Mux, gst_apev2_mux, GST, APEV2_MUX, GstTagMux) struct _GstApev2Mux { GstTagMux tagmux; }; -struct _GstApev2MuxClass { - GstTagMuxClass tagmux_class; -}; - -#define GST_TYPE_APEV2_MUX \ - (gst_apev2_mux_get_type()) -#define GST_APEV2_MUX(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_APEV2_MUX,GstApev2Mux)) -#define GST_APEV2_MUX_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_APEV2_MUX,GstApev2MuxClass)) -#define GST_IS_APEV2_MUX(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_APEV2_MUX)) -#define GST_IS_APEV2_MUX_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_APEV2_MUX)) - -GType gst_apev2_mux_get_type (void); - G_END_DECLS #endif /* GST_APEV2_MUX_H */ diff --git a/ext/taglib/gstid3v2mux.h b/ext/taglib/gstid3v2mux.h index 36c748fc4b..ca2ad6e1dc 100644 --- a/ext/taglib/gstid3v2mux.h +++ b/ext/taglib/gstid3v2mux.h @@ -25,30 +25,13 @@ G_BEGIN_DECLS -typedef struct _GstId3v2Mux GstId3v2Mux; -typedef struct _GstId3v2MuxClass GstId3v2MuxClass; +#define GST_TYPE_ID3V2_MUX (gst_id3v2_mux_get_type()) +G_DECLARE_FINAL_TYPE (GstId3v2Mux, gst_id3v2_mux, GST, ID3V2_MUX, GstTagMux) struct _GstId3v2Mux { GstTagMux tagmux; }; -struct _GstId3v2MuxClass { - GstTagMuxClass tagmux_class; -}; - -#define GST_TYPE_ID3V2_MUX \ - (gst_id3v2_mux_get_type()) -#define GST_ID3V2_MUX(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ID3V2_MUX,GstId3v2Mux)) -#define GST_ID3V2_MUX_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ID3V2_MUX,GstId3v2MuxClass)) -#define GST_IS_ID3V2_MUX(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ID3V2_MUX)) -#define GST_IS_ID3V2_MUX_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ID3V2_MUX)) - -GType gst_id3v2_mux_get_type (void); - G_END_DECLS #endif /* GST_ID3V2_MUX_H */ diff --git a/ext/taglib/meson.build b/ext/taglib/meson.build index 18b9e31ae2..dcea2c58e8 100644 --- a/ext/taglib/meson.build +++ b/ext/taglib/meson.build @@ -6,7 +6,7 @@ taglib_sources = [ taglib_dep = dependency('taglib', version : '>= 1.5', required : get_option('taglib')) -if taglib_dep.found() and add_languages('cpp') +if taglib_dep.found() and add_languages('cpp', native: false, required: get_option('taglib')) extra_args = [] cxx = meson.get_compiler('cpp') if cxx.has_argument('-fvisibility=hidden') diff --git a/ext/twolame/gsttwolamemp2enc.c b/ext/twolame/gsttwolamemp2enc.c index 09e7a6c06c..57572109c8 100644 --- a/ext/twolame/gsttwolamemp2enc.c +++ b/ext/twolame/gsttwolamemp2enc.c @@ -335,6 +335,10 @@ gst_two_lame_class_init (GstTwoLameClass * klass) "TwoLAME mp2 encoder", "Codec/Encoder/Audio", "High-quality free MP2 encoder", "Sebastian Dröge "); + + gst_type_mark_as_plugin_api (GST_TYPE_TWO_LAME_MODE, 0); + gst_type_mark_as_plugin_api (GST_TYPE_TWO_LAME_PADDING, 0); + gst_type_mark_as_plugin_api (GST_TYPE_TWO_LAME_EMPHASIS, 0); } static gboolean diff --git a/ext/twolame/gsttwolamemp2enc.h b/ext/twolame/gsttwolamemp2enc.h index 72a6beaec8..2a02ca6bd0 100644 --- a/ext/twolame/gsttwolamemp2enc.h +++ b/ext/twolame/gsttwolamemp2enc.h @@ -30,19 +30,8 @@ G_BEGIN_DECLS #include -#define GST_TYPE_TWO_LAME \ - (gst_two_lame_get_type()) -#define GST_TWO_LAME(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TWO_LAME,GstTwoLame)) -#define GST_TWO_LAME_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TWO_LAME,GstTwoLameClass)) -#define GST_IS_TWO_LAME(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TWO_LAME)) -#define GST_IS_TWO_LAME_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TWO_LAME)) - -typedef struct _GstTwoLame GstTwoLame; -typedef struct _GstTwoLameClass GstTwoLameClass; +#define GST_TYPE_TWO_LAME (gst_two_lame_get_type()) +G_DECLARE_FINAL_TYPE (GstTwoLame, gst_two_lame, GST, TWO_LAME, GstAudioEncoder) /** * GstTwoLame: @@ -76,12 +65,6 @@ struct _GstTwoLame { twolame_options *glopts; }; -struct _GstTwoLameClass { - GstAudioEncoderClass parent_class; -}; - -GType gst_two_lame_get_type(void); - G_END_DECLS diff --git a/ext/vpx/gstvp8dec.h b/ext/vpx/gstvp8dec.h index fc3b16135c..4b75ceefc1 100644 --- a/ext/vpx/gstvp8dec.h +++ b/ext/vpx/gstvp8dec.h @@ -44,32 +44,14 @@ G_BEGIN_DECLS -#define GST_TYPE_VP8_DEC \ - (gst_vp8_dec_get_type()) -#define GST_VP8_DEC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VP8_DEC,GstVP8Dec)) -#define GST_VP8_DEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VP8_DEC,GstVP8DecClass)) -#define GST_IS_VP8_DEC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VP8_DEC)) -#define GST_IS_VP8_DEC_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VP8_DEC)) - -typedef struct _GstVP8Dec GstVP8Dec; -typedef struct _GstVP8DecClass GstVP8DecClass; +#define GST_TYPE_VP8_DEC (gst_vp8_dec_get_type()) +G_DECLARE_FINAL_TYPE (GstVP8Dec, gst_vp8_dec, GST, VP8_DEC, GstVPXDec) struct _GstVP8Dec { GstVPXDec base_vpx_decoder; }; -struct _GstVP8DecClass -{ - GstVPXDecClass base_vpx_class; -}; - -GType gst_vp8_dec_get_type (void); - G_END_DECLS #endif diff --git a/ext/vpx/gstvp8enc.c b/ext/vpx/gstvp8enc.c index 1e93adae02..8bc56f980c 100644 --- a/ext/vpx/gstvp8enc.c +++ b/ext/vpx/gstvp8enc.c @@ -29,10 +29,10 @@ * [Google](http://www.google.com/). It's the successor of On2 VP3, which was * the base of the Theora video codec. * - * To control the quality of the encoding, the #GstVP8Enc:target-bitrate, - * #GstVP8Enc:min-quantizer, #GstVP8Enc:max-quantizer or #GstVP8Enc:cq-level + * To control the quality of the encoding, the #GstVPXEnc:target-bitrate, + * #GstVPXEnc:min-quantizer, #GstVPXEnc:max-quantizer or #GstVPXEnc:cq-level * properties can be used. Which one is used depends on the mode selected by - * the #GstVP8Enc:end-usage property. + * the #GstVPXEnc:end-usage property. * See [Encoder Parameters](http://www.webmproject.org/docs/encoder-parameters/) * for explanation, examples for useful encoding parameters and more details * on the encoding parameters. diff --git a/ext/vpx/gstvp8enc.h b/ext/vpx/gstvp8enc.h index 47319e2791..f1275a44fe 100644 --- a/ext/vpx/gstvp8enc.h +++ b/ext/vpx/gstvp8enc.h @@ -38,19 +38,8 @@ G_BEGIN_DECLS -#define GST_TYPE_VP8_ENC \ - (gst_vp8_enc_get_type()) -#define GST_VP8_ENC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VP8_ENC,GstVP8Enc)) -#define GST_VP8_ENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VP8_ENC,GstVP8EncClass)) -#define GST_IS_VP8_ENC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VP8_ENC)) -#define GST_IS_VP8_ENC_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VP8_ENC)) - -typedef struct _GstVP8Enc GstVP8Enc; -typedef struct _GstVP8EncClass GstVP8EncClass; +#define GST_TYPE_VP8_ENC (gst_vp8_enc_get_type()) +G_DECLARE_FINAL_TYPE (GstVP8Enc, gst_vp8_enc, GST, VP8_ENC, GstVPXEnc) struct _GstVP8Enc { @@ -59,13 +48,6 @@ struct _GstVP8Enc int keyframe_distance; }; -struct _GstVP8EncClass -{ - GstVPXEncClass base_vpxenc_class; -}; - -GType gst_vp8_enc_get_type (void); - G_END_DECLS #endif diff --git a/ext/vpx/gstvp9dec.h b/ext/vpx/gstvp9dec.h index 41332f3cdf..bffc0135c3 100644 --- a/ext/vpx/gstvp9dec.h +++ b/ext/vpx/gstvp9dec.h @@ -44,32 +44,14 @@ G_BEGIN_DECLS -#define GST_TYPE_VP9_DEC \ - (gst_vp9_dec_get_type()) -#define GST_VP9_DEC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VP9_DEC,GstVP9Dec)) -#define GST_VP9_DEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VP9_DEC,GstVP9DecClass)) -#define GST_IS_VP9_DEC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VP9_DEC)) -#define GST_IS_VP9_DEC_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VP9_DEC)) - -typedef struct _GstVP9Dec GstVP9Dec; -typedef struct _GstVP9DecClass GstVP9DecClass; +#define GST_TYPE_VP9_DEC (gst_vp9_dec_get_type()) +G_DECLARE_FINAL_TYPE (GstVP9Dec, gst_vp9_dec, GST, VP9_DEC, GstVPXDec) struct _GstVP9Dec { GstVPXDec base_vpx_decoder; }; -struct _GstVP9DecClass -{ - GstVPXDecClass base_vpx_class; -}; - -GType gst_vp9_dec_get_type (void); - G_END_DECLS #endif diff --git a/ext/vpx/gstvp9enc.c b/ext/vpx/gstvp9enc.c index 3628564769..1705b06024 100644 --- a/ext/vpx/gstvp9enc.c +++ b/ext/vpx/gstvp9enc.c @@ -29,10 +29,10 @@ * [Google](http://www.google.com/). It's the successor of On2 VP3, which was * the base of the Theora video codec. * - * To control the quality of the encoding, the #GstVP9Enc:target-bitrate, - * #GstVP9Enc:min-quantizer, #GstVP9Enc:max-quantizer or #GstVP9Enc:cq-level + * To control the quality of the encoding, the #GstVPXEnc:target-bitrate, + * #GstVPXEnc:min-quantizer, #GstVPXEnc:max-quantizer or #GstVPXEnc:cq-level * properties can be used. Which one is used depends on the mode selected by - * the #GstVP9Enc:end-usage property. + * the #GstVPXEnc:end-usage property. * See [Encoder Parameters](http://www.webmproject.org/docs/encoder-parameters/) * for explanation, examples for useful encoding parameters and more details * on the encoding parameters. @@ -101,6 +101,8 @@ static GstFlowReturn gst_vp9_enc_handle_invisible_frame_buffer (GstVPXEnc * enc, static void gst_vp9_enc_set_frame_user_data (GstVPXEnc * enc, GstVideoCodecFrame * frame, vpx_image_t * image); +#define DEFAULT_BITS_PER_PIXEL 0.0289 + static void gst_vp9_enc_class_init (GstVP9EncClass * klass) { @@ -152,6 +154,7 @@ gst_vp9_enc_init (GstVP9Enc * gst_vp9_enc) } else { gst_vpx_enc->have_default_config = TRUE; } + gst_vpx_enc->bits_per_pixel = DEFAULT_BITS_PER_PIXEL; } static vpx_codec_iface_t * diff --git a/ext/vpx/gstvp9enc.h b/ext/vpx/gstvp9enc.h index 843372b730..a61a2f91aa 100644 --- a/ext/vpx/gstvp9enc.h +++ b/ext/vpx/gstvp9enc.h @@ -38,32 +38,14 @@ G_BEGIN_DECLS -#define GST_TYPE_VP9_ENC \ - (gst_vp9_enc_get_type()) -#define GST_VP9_ENC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VP9_ENC,GstVP9Enc)) -#define GST_VP9_ENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VP9_ENC,GstVP9EncClass)) -#define GST_IS_VP9_ENC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VP9_ENC)) -#define GST_IS_VP9_ENC_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VP9_ENC)) - -typedef struct _GstVP9Enc GstVP9Enc; -typedef struct _GstVP9EncClass GstVP9EncClass; +#define GST_TYPE_VP9_ENC (gst_vp9_enc_get_type()) +G_DECLARE_FINAL_TYPE (GstVP9Enc, gst_vp9_enc, GST, VP9_ENC, GstVPXEnc) struct _GstVP9Enc { GstVPXEnc base_vpx_encoder; }; -struct _GstVP9EncClass -{ - GstVPXEncClass base_vpxenc_class; -}; - -GType gst_vp9_enc_get_type (void); - G_END_DECLS #endif diff --git a/ext/vpx/gstvpxdec.c b/ext/vpx/gstvpxdec.c index 3eafb7f10b..74cc3c9702 100644 --- a/ext/vpx/gstvpxdec.c +++ b/ext/vpx/gstvpxdec.c @@ -79,7 +79,7 @@ gst_vpx_dec_post_processing_flags_get_type (void) {C_FLAGS (VP8_MFQE), "Multi-frame quality enhancement", "mfqe"}, {0, NULL, NULL} }; - static volatile GType id = 0; + static GType id = 0; if (g_once_init_enter ((gsize *) & id)) { GType _id; @@ -188,6 +188,9 @@ gst_vpx_dec_class_init (GstVPXDecClass * klass) GST_DEBUG_FUNCPTR (gst_vpx_dec_default_frame_format); GST_DEBUG_CATEGORY_INIT (gst_vpxdec_debug, "vpxdec", 0, "VPX Decoder"); + + gst_type_mark_as_plugin_api (GST_VPX_DEC_TYPE_POST_PROCESSING_FLAGS, 0); + gst_type_mark_as_plugin_api (GST_TYPE_VPX_DEC, 0); } static void @@ -586,6 +589,14 @@ gst_vpx_dec_open_codec (GstVPXDec * dec, GstVideoCodecFrame * frame) GST_WARNING_OBJECT (dec, "No keyframe, skipping"); return GST_FLOW_CUSTOM_SUCCESS_1; } + if (stream_info.w == 0 || stream_info.h == 0) { + /* For VP8 it's possible to signal width or height to be 0, but it does + * not make sense to do so. For VP9 it's impossible. Hence, we most likely + * have a corrupt stream if width or height is 0. */ + GST_INFO_OBJECT (dec, "Invalid resolution %d x %d", stream_info.w, + stream_info.h); + return GST_FLOW_CUSTOM_SUCCESS_1; + } gst_vpx_dec_set_stream_info (dec, &stream_info); gst_vpx_dec_set_default_format (dec, GST_VIDEO_FORMAT_I420, stream_info.w, diff --git a/ext/vpx/gstvpxdec.h b/ext/vpx/gstvpxdec.h index 6852f860ac..36b3c272e9 100644 --- a/ext/vpx/gstvpxdec.h +++ b/ext/vpx/gstvpxdec.h @@ -106,6 +106,8 @@ struct _GstVPXDecClass GType gst_vpx_dec_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstVPXDec, gst_object_unref) + G_END_DECLS #endif diff --git a/ext/vpx/gstvpxenc.c b/ext/vpx/gstvpxenc.c index 88cfe22c6e..4b3b4f7708 100644 --- a/ext/vpx/gstvpxenc.c +++ b/ext/vpx/gstvpxenc.c @@ -47,7 +47,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_vpxenc_debug); #define DEFAULT_PROFILE 0 #define DEFAULT_RC_END_USAGE VPX_VBR -#define DEFAULT_RC_TARGET_BITRATE 256000 +#define DEFAULT_RC_TARGET_BITRATE 0 #define DEFAULT_RC_MIN_QUANTIZER 4 #define DEFAULT_RC_MAX_QUANTIZER 63 @@ -102,6 +102,8 @@ GST_DEBUG_CATEGORY_STATIC (gst_vpxenc_debug); #define DEFAULT_TIMEBASE_N 0 #define DEFAULT_TIMEBASE_D 1 +#define DEFAULT_BITS_PER_PIXEL 0.0434 + enum { PROP_0, @@ -148,7 +150,8 @@ enum PROP_TUNING, PROP_CQ_LEVEL, PROP_MAX_INTRA_BITRATE_PCT, - PROP_TIMEBASE + PROP_TIMEBASE, + PROP_BITS_PER_PIXEL }; @@ -162,7 +165,7 @@ gst_vpx_enc_end_usage_get_type (void) {VPX_CQ, "Constant Quality Mode (CQ) mode", "cq"}, {0, NULL, NULL} }; - static volatile GType id = 0; + static GType id = 0; if (g_once_init_enter ((gsize *) & id)) { GType _id; @@ -185,7 +188,7 @@ gst_vpx_enc_multipass_mode_get_type (void) {VPX_RC_LAST_PASS, "Last pass of multipass encoding", "last-pass"}, {0, NULL, NULL} }; - static volatile GType id = 0; + static GType id = 0; if (g_once_init_enter ((gsize *) & id)) { GType _id; @@ -207,7 +210,7 @@ gst_vpx_enc_kf_mode_get_type (void) {VPX_KF_DISABLED, "Don't automatically place keyframes", "disabled"}, {0, NULL, NULL} }; - static volatile GType id = 0; + static GType id = 0; if (g_once_init_enter ((gsize *) & id)) { GType _id; @@ -229,7 +232,7 @@ gst_vpx_enc_tuning_get_type (void) {VP8_TUNE_SSIM, "Tune for SSIM", "ssim"}, {0, NULL, NULL} }; - static volatile GType id = 0; + static GType id = 0; if (g_once_init_enter ((gsize *) & id)) { GType _id; @@ -253,7 +256,7 @@ gst_vpx_enc_scaling_mode_get_type (void) {VP8E_ONETWO, "1:2", "1:2"}, {0, NULL, NULL} }; - static volatile GType id = 0; + static GType id = 0; if (g_once_init_enter ((gsize *) & id)) { GType _id; @@ -277,7 +280,7 @@ gst_vpx_enc_token_partitions_get_type (void) {VP8_EIGHT_TOKENPARTITION, "Eight token partitions", "8"}, {0, NULL, NULL} }; - static volatile GType id = 0; + static GType id = 0; if (g_once_init_enter ((gsize *) & id)) { GType _id; @@ -300,7 +303,7 @@ gst_vpx_enc_er_flags_get_type (void) "Allow partitions to be decoded independently", "partitions"}, {0, NULL, NULL} }; - static volatile GType id = 0; + static GType id = 0; if (g_once_init_enter ((gsize *) & id)) { GType _id; @@ -336,7 +339,8 @@ static gboolean gst_vpx_enc_propose_allocation (GstVideoEncoder * encoder, #define parent_class gst_vpx_enc_parent_class G_DEFINE_TYPE_WITH_CODE (GstVPXEnc, gst_vpx_enc, GST_TYPE_VIDEO_ENCODER, G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL); - G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL);); + G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL); + ); static void gst_vpx_enc_class_init (GstVPXEncClass * klass) @@ -364,117 +368,137 @@ gst_vpx_enc_class_init (GstVPXEncClass * klass) g_param_spec_enum ("end-usage", "Rate control mode", "Rate control mode", GST_VPX_ENC_END_USAGE_TYPE, DEFAULT_RC_END_USAGE, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_RC_TARGET_BITRATE, g_param_spec_int ("target-bitrate", "Target bitrate", - "Target bitrate (in bits/sec)", + "Target bitrate (in bits/sec) (0: auto - bitrate depends on " + "resolution, see \"bits-per-pixel\" property for more info)", 0, G_MAXINT, DEFAULT_RC_TARGET_BITRATE, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_RC_MIN_QUANTIZER, g_param_spec_int ("min-quantizer", "Minimum Quantizer", "Minimum Quantizer (best)", 0, 63, DEFAULT_RC_MIN_QUANTIZER, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_RC_MAX_QUANTIZER, g_param_spec_int ("max-quantizer", "Maximum Quantizer", "Maximum Quantizer (worst)", 0, 63, DEFAULT_RC_MAX_QUANTIZER, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_RC_DROPFRAME_THRESH, g_param_spec_int ("dropframe-threshold", "Drop Frame Threshold", "Temporal resampling threshold (buf %)", 0, 100, DEFAULT_RC_DROPFRAME_THRESH, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_RC_RESIZE_ALLOWED, g_param_spec_boolean ("resize-allowed", "Resize Allowed", "Allow spatial resampling", DEFAULT_RC_RESIZE_ALLOWED, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_RC_RESIZE_UP_THRESH, g_param_spec_int ("resize-up-threshold", "Resize Up Threshold", "Upscale threshold (buf %)", 0, 100, DEFAULT_RC_RESIZE_UP_THRESH, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_RC_RESIZE_DOWN_THRESH, g_param_spec_int ("resize-down-threshold", "Resize Down Threshold", "Downscale threshold (buf %)", 0, 100, DEFAULT_RC_RESIZE_DOWN_THRESH, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_RC_UNDERSHOOT_PCT, g_param_spec_int ("undershoot", "Undershoot PCT", "Datarate undershoot (min) target (%)", 0, 1000, DEFAULT_RC_UNDERSHOOT_PCT, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_RC_OVERSHOOT_PCT, g_param_spec_int ("overshoot", "Overshoot PCT", "Datarate overshoot (max) target (%)", 0, 1000, DEFAULT_RC_OVERSHOOT_PCT, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_RC_BUF_SZ, g_param_spec_int ("buffer-size", "Buffer size", "Client buffer size (ms)", 0, G_MAXINT, DEFAULT_RC_BUF_SZ, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_RC_BUF_INITIAL_SZ, g_param_spec_int ("buffer-initial-size", "Buffer initial size", "Initial client buffer size (ms)", 0, G_MAXINT, DEFAULT_RC_BUF_INITIAL_SZ, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_RC_BUF_OPTIMAL_SZ, g_param_spec_int ("buffer-optimal-size", "Buffer optimal size", "Optimal client buffer size (ms)", 0, G_MAXINT, DEFAULT_RC_BUF_OPTIMAL_SZ, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_RC_2PASS_VBR_BIAS_PCT, g_param_spec_int ("twopass-vbr-bias", "2-pass VBR bias", "CBR/VBR bias (0=CBR, 100=VBR)", 0, 100, DEFAULT_RC_2PASS_VBR_BIAS_PCT, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_RC_2PASS_VBR_MINSECTION_PCT, g_param_spec_int ("twopass-vbr-minsection", "2-pass GOP min bitrate", "GOP minimum bitrate (% target)", 0, G_MAXINT, DEFAULT_RC_2PASS_VBR_MINSECTION_PCT, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_RC_2PASS_VBR_MAXSECTION_PCT, g_param_spec_int ("twopass-vbr-maxsection", "2-pass GOP max bitrate", "GOP maximum bitrate (% target)", 0, G_MAXINT, DEFAULT_RC_2PASS_VBR_MINSECTION_PCT, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_KF_MODE, g_param_spec_enum ("keyframe-mode", "Keyframe Mode", "Keyframe placement", GST_VPX_ENC_KF_MODE_TYPE, DEFAULT_KF_MODE, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_KF_MAX_DIST, g_param_spec_int ("keyframe-max-dist", "Keyframe max distance", "Maximum distance between keyframes (number of frames)", 0, G_MAXINT, DEFAULT_KF_MAX_DIST, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_MULTIPASS_MODE, g_param_spec_enum ("multipass-mode", "Multipass Mode", "Multipass encode mode", GST_VPX_ENC_MULTIPASS_MODE_TYPE, DEFAULT_MULTIPASS_MODE, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_MULTIPASS_CACHE_FILE, g_param_spec_string ("multipass-cache-file", "Multipass Cache File", @@ -488,7 +512,8 @@ gst_vpx_enc_class_init (GstVPXEncClass * klass) g_param_spec_int ("temporal-scalability-number-layers", "Number of coding layers", "Number of coding layers to use", 1, 5, DEFAULT_TS_NUMBER_LAYERS, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_TS_TARGET_BITRATE, g_param_spec_value_array ("temporal-scalability-target-bitrate", @@ -496,8 +521,10 @@ gst_vpx_enc_class_init (GstVPXEncClass * klass) "Target bitrates for coding layers (one per layer, decreasing)", g_param_spec_int ("target-bitrate", "Target bitrate", "Target bitrate", 0, G_MAXINT, DEFAULT_RC_TARGET_BITRATE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS), - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT), + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT)); g_object_class_install_property (gobject_class, PROP_TS_RATE_DECIMATOR, g_param_spec_value_array ("temporal-scalability-rate-decimator", @@ -505,140 +532,180 @@ gst_vpx_enc_class_init (GstVPXEncClass * klass) "Rate decimation factors for each layer", g_param_spec_int ("rate-decimator", "Rate decimator", "Rate decimator", 0, 1000000000, 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS), - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT), + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT)); g_object_class_install_property (gobject_class, PROP_TS_PERIODICITY, g_param_spec_int ("temporal-scalability-periodicity", "Coding layer periodicity", "Length of sequence that defines layer membership periodicity", 0, 16, DEFAULT_TS_PERIODICITY, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_TS_LAYER_ID, g_param_spec_value_array ("temporal-scalability-layer-id", "Coding layer identification", "Sequence defining coding layer membership", g_param_spec_int ("layer-id", "Layer ID", "Layer ID", 0, 4, 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS), - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT), + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT)); g_object_class_install_property (gobject_class, PROP_LAG_IN_FRAMES, g_param_spec_int ("lag-in-frames", "Lag in frames", "Maximum number of frames to lag", 0, 25, DEFAULT_LAG_IN_FRAMES, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_ERROR_RESILIENT, g_param_spec_flags ("error-resilient", "Error resilient", "Error resilience flags", GST_VPX_ENC_ER_FLAGS_TYPE, DEFAULT_ERROR_RESILIENT, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_THREADS, g_param_spec_int ("threads", "Threads", "Number of threads to use", 0, 64, DEFAULT_THREADS, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_DEADLINE, g_param_spec_int64 ("deadline", "Deadline", "Deadline per frame (usec, 0=disabled)", 0, G_MAXINT64, DEFAULT_DEADLINE, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_H_SCALING_MODE, g_param_spec_enum ("horizontal-scaling-mode", "Horizontal scaling mode", "Horizontal scaling mode", GST_VPX_ENC_SCALING_MODE_TYPE, DEFAULT_H_SCALING_MODE, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_V_SCALING_MODE, g_param_spec_enum ("vertical-scaling-mode", "Vertical scaling mode", "Vertical scaling mode", GST_VPX_ENC_SCALING_MODE_TYPE, DEFAULT_V_SCALING_MODE, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_CPU_USED, g_param_spec_int ("cpu-used", "CPU used", "CPU used", -16, 16, DEFAULT_CPU_USED, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_ENABLE_AUTO_ALT_REF, g_param_spec_boolean ("auto-alt-ref", "Auto alt reference frames", "Automatically generate AltRef frames", DEFAULT_ENABLE_AUTO_ALT_REF, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_NOISE_SENSITIVITY, g_param_spec_int ("noise-sensitivity", "Noise sensitivity", "Noise sensisivity (frames to blur)", 0, 6, DEFAULT_NOISE_SENSITIVITY, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_SHARPNESS, g_param_spec_int ("sharpness", "Sharpness", "Filter sharpness", 0, 7, DEFAULT_SHARPNESS, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_STATIC_THRESHOLD, g_param_spec_int ("static-threshold", "Static Threshold", "Motion detection threshold. Recommendation is to set 100 for " "screen/window sharing", 0, G_MAXINT, DEFAULT_STATIC_THRESHOLD, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_TOKEN_PARTITIONS, g_param_spec_enum ("token-partitions", "Token partitions", "Number of token partitions", GST_VPX_ENC_TOKEN_PARTITIONS_TYPE, DEFAULT_TOKEN_PARTITIONS, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_ARNR_MAXFRAMES, g_param_spec_int ("arnr-maxframes", "AltRef max frames", "AltRef maximum number of frames", 0, 15, DEFAULT_ARNR_MAXFRAMES, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_ARNR_STRENGTH, g_param_spec_int ("arnr-strength", "AltRef strength", "AltRef strength", 0, 6, DEFAULT_ARNR_STRENGTH, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_ARNR_TYPE, g_param_spec_int ("arnr-type", "AltRef type", "AltRef type", 1, 3, DEFAULT_ARNR_TYPE, (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - G_PARAM_DEPRECATED))); + G_PARAM_DEPRECATED | GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_TUNING, g_param_spec_enum ("tuning", "Tuning", "Tuning", GST_VPX_ENC_TUNING_TYPE, DEFAULT_TUNING, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_CQ_LEVEL, g_param_spec_int ("cq-level", "Constrained quality level", "Constrained quality level", 0, 63, DEFAULT_CQ_LEVEL, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_MAX_INTRA_BITRATE_PCT, g_param_spec_int ("max-intra-bitrate", "Max Intra bitrate", "Maximum Intra frame bitrate", 0, G_MAXINT, DEFAULT_MAX_INTRA_BITRATE_PCT, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); g_object_class_install_property (gobject_class, PROP_TIMEBASE, gst_param_spec_fraction ("timebase", "Shortest interframe time", "Fraction of one second that is the shortest interframe time - normally left as zero which will default to the framerate", 0, 1, G_MAXINT, 1, DEFAULT_TIMEBASE_N, DEFAULT_TIMEBASE_D, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT)); + + g_object_class_install_property (gobject_class, PROP_BITS_PER_PIXEL, + g_param_spec_float ("bits-per-pixel", "Bits per pixel", + "Factor to convert number of pixels to bitrate value " + "(only has an effect if target-bitrate=0)", + 0.0, G_MAXFLOAT, DEFAULT_BITS_PER_PIXEL, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT))); GST_DEBUG_CATEGORY_INIT (gst_vpxenc_debug, "vpxenc", 0, "VPX Encoder"); + + gst_type_mark_as_plugin_api (GST_VPX_ENC_END_USAGE_TYPE, 0); + gst_type_mark_as_plugin_api (GST_VPX_ENC_MULTIPASS_MODE_TYPE, 0); + gst_type_mark_as_plugin_api (GST_VPX_ENC_KF_MODE_TYPE, 0); + gst_type_mark_as_plugin_api (GST_VPX_ENC_TUNING_TYPE, 0); + gst_type_mark_as_plugin_api (GST_VPX_ENC_SCALING_MODE_TYPE, 0); + gst_type_mark_as_plugin_api (GST_VPX_ENC_TOKEN_PARTITIONS_TYPE, 0); + gst_type_mark_as_plugin_api (GST_VPX_ENC_ER_FLAGS_TYPE, 0); + gst_type_mark_as_plugin_api (GST_TYPE_VPX_ENC, 0); } static void @@ -649,7 +716,7 @@ gst_vpx_enc_init (GstVPXEnc * gst_vpx_enc) gst_vpx_enc->cfg.rc_end_usage = DEFAULT_RC_END_USAGE; gst_vpx_enc->cfg.rc_target_bitrate = DEFAULT_RC_TARGET_BITRATE / 1000; - gst_vpx_enc->rc_target_bitrate_set = FALSE; + gst_vpx_enc->rc_target_bitrate_auto = DEFAULT_RC_TARGET_BITRATE == 0; gst_vpx_enc->cfg.rc_min_quantizer = DEFAULT_RC_MIN_QUANTIZER; gst_vpx_enc->cfg.rc_max_quantizer = DEFAULT_RC_MAX_QUANTIZER; gst_vpx_enc->cfg.rc_dropframe_thresh = DEFAULT_RC_DROPFRAME_THRESH; @@ -697,6 +764,7 @@ gst_vpx_enc_init (GstVPXEnc * gst_vpx_enc) gst_vpx_enc->max_intra_bitrate_pct = DEFAULT_MAX_INTRA_BITRATE_PCT; gst_vpx_enc->timebase_n = DEFAULT_TIMEBASE_N; gst_vpx_enc->timebase_d = DEFAULT_TIMEBASE_D; + gst_vpx_enc->bits_per_pixel = DEFAULT_BITS_PER_PIXEL; gst_vpx_enc->cfg.g_profile = DEFAULT_PROFILE; @@ -726,6 +794,42 @@ gst_vpx_enc_finalize (GObject * object) G_OBJECT_CLASS (parent_class)->finalize (object); } +static void +gst_vpx_enc_set_auto_bitrate (GstVPXEnc * encoder) +{ + if (encoder->input_state != NULL) { + guint size; + guint pixels_per_sec; + guint target_bitrate; + guint fps_n, fps_d; + + if (GST_VIDEO_INFO_FPS_N (&encoder->input_state->info) != 0) { + fps_n = GST_VIDEO_INFO_FPS_N (&encoder->input_state->info); + fps_d = GST_VIDEO_INFO_FPS_D (&encoder->input_state->info); + } else { + /* otherwise assume 30 frames per second as a fallback */ + fps_n = 30; + fps_d = 1; + } + + size = + GST_VIDEO_INFO_WIDTH (&encoder->input_state->info) * + GST_VIDEO_INFO_HEIGHT (&encoder->input_state->info); + pixels_per_sec = size * fps_n / fps_d; + target_bitrate = pixels_per_sec * encoder->bits_per_pixel; + + GST_DEBUG_OBJECT (encoder, + "Setting autobitrate for %ux%ux @ %u/%ufps %.4f = %ubps", + GST_VIDEO_INFO_WIDTH (&encoder->input_state->info), + GST_VIDEO_INFO_HEIGHT (&encoder->input_state->info), + GST_VIDEO_INFO_FPS_N (&encoder->input_state->info), + GST_VIDEO_INFO_FPS_D (&encoder->input_state->info), + encoder->bits_per_pixel, target_bitrate); + + encoder->cfg.rc_target_bitrate = target_bitrate / 1000; + } +} + static void gst_vpx_enc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) @@ -745,8 +849,13 @@ gst_vpx_enc_set_property (GObject * object, guint prop_id, global = TRUE; break; case PROP_RC_TARGET_BITRATE: - gst_vpx_enc->cfg.rc_target_bitrate = g_value_get_int (value) / 1000; - gst_vpx_enc->rc_target_bitrate_set = TRUE; + if (g_value_get_int (value) == 0) { + gst_vpx_enc_set_auto_bitrate (gst_vpx_enc); + gst_vpx_enc->rc_target_bitrate_auto = TRUE; + } else { + gst_vpx_enc->cfg.rc_target_bitrate = g_value_get_int (value) / 1000; + gst_vpx_enc->rc_target_bitrate_auto = FALSE; + } global = TRUE; break; case PROP_RC_MIN_QUANTIZER: @@ -1089,6 +1198,13 @@ gst_vpx_enc_set_property (GObject * object, guint prop_id, gst_vpx_enc->timebase_n = gst_value_get_fraction_numerator (value); gst_vpx_enc->timebase_d = gst_value_get_fraction_denominator (value); break; + case PROP_BITS_PER_PIXEL: + gst_vpx_enc->bits_per_pixel = g_value_get_float (value); + if (gst_vpx_enc->rc_target_bitrate_auto) { + gst_vpx_enc_set_auto_bitrate (gst_vpx_enc); + global = TRUE; + } + break; default: break; } @@ -1310,6 +1426,9 @@ gst_vpx_enc_get_property (GObject * object, guint prop_id, GValue * value, gst_value_set_fraction (value, gst_vpx_enc->timebase_n, gst_vpx_enc->timebase_d); break; + case PROP_BITS_PER_PIXEL: + g_value_set_float (value, gst_vpx_enc->bits_per_pixel); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1444,14 +1563,6 @@ gst_vpx_enc_set_format (GstVideoEncoder * video_encoder, } encoder->cfg.g_profile = gst_vpx_enc_get_downstream_profile (encoder); - - /* Scale default bitrate to our size */ - if (!encoder->rc_target_bitrate_set) - encoder->cfg.rc_target_bitrate = - gst_util_uint64_scale (DEFAULT_RC_TARGET_BITRATE, - GST_VIDEO_INFO_WIDTH (info) * GST_VIDEO_INFO_HEIGHT (info), - 320 * 240 * 1000); - encoder->cfg.g_w = GST_VIDEO_INFO_WIDTH (info); encoder->cfg.g_h = GST_VIDEO_INFO_HEIGHT (info); @@ -1633,6 +1744,10 @@ gst_vpx_enc_set_format (GstVideoEncoder * video_encoder, gst_video_codec_state_unref (encoder->input_state); encoder->input_state = gst_video_codec_state_ref (state); + /* Scale default bitrate to our size */ + if (encoder->rc_target_bitrate_auto) + gst_vpx_enc_set_auto_bitrate (encoder); + /* prepare cached image buffer setup */ image = &encoder->image; memset (image, 0, sizeof (*image)); diff --git a/ext/vpx/gstvpxenc.h b/ext/vpx/gstvpxenc.h index fb0192768b..fbf5476ba0 100644 --- a/ext/vpx/gstvpxenc.h +++ b/ext/vpx/gstvpxenc.h @@ -68,7 +68,7 @@ struct _GstVPXEnc /* properties */ vpx_codec_enc_cfg_t cfg; gboolean have_default_config; - gboolean rc_target_bitrate_set; + gboolean rc_target_bitrate_auto; gint n_ts_target_bitrate; gint n_ts_rate_decimator; gint n_ts_layer_id; @@ -100,6 +100,9 @@ struct _GstVPXEnc unsigned int timebase_n; unsigned int timebase_d; + /* Bits per Pixel */ + gfloat bits_per_pixel; + /* state */ gboolean inited; @@ -133,6 +136,8 @@ struct _GstVPXEncClass GType gst_vpx_enc_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstVPXEnc, gst_object_unref) + G_END_DECLS #endif diff --git a/ext/wavpack/gstwavpackdec.c b/ext/wavpack/gstwavpackdec.c index a87774a1b8..9fc32d8350 100644 --- a/ext/wavpack/gstwavpackdec.c +++ b/ext/wavpack/gstwavpackdec.c @@ -82,6 +82,10 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", "audio/x-raw, " "format = (string) " GST_AUDIO_NE (S32) ", " "layout = (string) interleaved, " + "channels = (int) [ 1, 8 ], " "rate = (int) [ 6000, 192000 ]; " + "audio/x-raw, " + "format = (string) " GST_AUDIO_NE (F32) ", " + "layout = (string) interleaved, " "channels = (int) [ 1, 8 ], " "rate = (int) [ 6000, 192000 ]") ); @@ -131,6 +135,7 @@ gst_wavpack_dec_reset (GstWavpackDec * dec) dec->channel_mask = 0; dec->sample_rate = 0; dec->depth = 0; + dec->mode_float = FALSE; } static void @@ -208,7 +213,9 @@ gst_wavpack_dec_negotiate (GstWavpackDec * dec) break; case 24: case 32: - fmt = _GST_AUDIO_FORMAT_NE (S32); + fmt = + dec->mode_float ? _GST_AUDIO_FORMAT_NE (F32) : + _GST_AUDIO_FORMAT_NE (S32); dec->width = 32; break; default: @@ -277,7 +284,8 @@ gst_wavpack_dec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buf) WavpackHeader wph; int32_t decoded, unpacked_size; gboolean format_changed; - gint width, depth, i, j, max; + gint width, depth, i, j, max, wavpack_mode; + gboolean mode_float; gint32 *dec_data = NULL; guint8 *out_data; GstMapInfo map, omap; @@ -323,10 +331,14 @@ gst_wavpack_dec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buf) g_assert (dec->context != NULL); + wavpack_mode = WavpackGetMode (dec->context); + mode_float = (wavpack_mode & MODE_FLOAT) == MODE_FLOAT; + format_changed = (dec->sample_rate != WavpackGetSampleRate (dec->context)) || (dec->channels != WavpackGetNumChannels (dec->context)) || (dec->depth != WavpackGetBytesPerSample (dec->context) * 8) || + (dec->mode_float != mode_float) || (dec->channel_mask != WavpackGetChannelMask (dec->context)); if (!gst_pad_has_current_caps (GST_AUDIO_DECODER_SRC_PAD (dec)) || @@ -336,6 +348,7 @@ gst_wavpack_dec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buf) dec->sample_rate = WavpackGetSampleRate (dec->context); dec->channels = WavpackGetNumChannels (dec->context); dec->depth = WavpackGetBytesPerSample (dec->context) * 8; + dec->mode_float = mode_float; channel_mask = WavpackGetChannelMask (dec->context); if (channel_mask == 0) diff --git a/ext/wavpack/gstwavpackdec.h b/ext/wavpack/gstwavpackdec.h index 8a002b4bf6..726e5c2232 100644 --- a/ext/wavpack/gstwavpackdec.h +++ b/ext/wavpack/gstwavpackdec.h @@ -31,18 +31,10 @@ #include "gstwavpackstreamreader.h" G_BEGIN_DECLS -#define GST_TYPE_WAVPACK_DEC \ - (gst_wavpack_dec_get_type()) -#define GST_WAVPACK_DEC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WAVPACK_DEC,GstWavpackDec)) -#define GST_WAVPACK_DEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WAVPACK_DEC,GstWavpackDecClass)) -#define GST_IS_WAVPACK_DEC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WAVPACK_DEC)) -#define GST_IS_WAVPACK_DEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WAVPACK_DEC)) -typedef struct _GstWavpackDec GstWavpackDec; -typedef struct _GstWavpackDecClass GstWavpackDecClass; + +#define GST_TYPE_WAVPACK_DEC (gst_wavpack_dec_get_type()) +G_DECLARE_FINAL_TYPE (GstWavpackDec, gst_wavpack_dec, GST, WAVPACK_DEC, + GstAudioDecoder) struct _GstWavpackDec { @@ -60,18 +52,12 @@ struct _GstWavpackDec gint width; gint channels; gint channel_mask; + gboolean mode_float; gint channel_reorder_map[64]; }; -struct _GstWavpackDecClass -{ - GstAudioDecoderClass parent; -}; - -GType gst_wavpack_dec_get_type (void); - gboolean gst_wavpack_dec_plugin_init (GstPlugin * plugin); G_END_DECLS diff --git a/ext/wavpack/gstwavpackenc.c b/ext/wavpack/gstwavpackenc.c index 3f05175726..7c38aaea87 100644 --- a/ext/wavpack/gstwavpackenc.c +++ b/ext/wavpack/gstwavpackenc.c @@ -263,6 +263,10 @@ gst_wavpack_enc_class_init (GstWavpackEncClass * klass) "Use this joint-stereo mode.", GST_TYPE_WAVPACK_ENC_JOINT_STEREO_MODE, GST_WAVPACK_JS_MODE_AUTO, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gst_type_mark_as_plugin_api (GST_TYPE_WAVPACK_ENC_MODE, 0); + gst_type_mark_as_plugin_api (GST_TYPE_WAVPACK_ENC_CORRECTION_MODE, 0); + gst_type_mark_as_plugin_api (GST_TYPE_WAVPACK_ENC_JOINT_STEREO_MODE, 0); } static void diff --git a/ext/wavpack/gstwavpackenc.h b/ext/wavpack/gstwavpackenc.h index 26a5b1128b..5a6ed0a19a 100644 --- a/ext/wavpack/gstwavpackenc.h +++ b/ext/wavpack/gstwavpackenc.h @@ -28,18 +28,10 @@ #include G_BEGIN_DECLS -#define GST_TYPE_WAVPACK_ENC \ - (gst_wavpack_enc_get_type()) -#define GST_WAVPACK_ENC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WAVPACK_ENC,GstWavpackEnc)) -#define GST_WAVPACK_ENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WAVPACK_ENC,GstWavpackEnc)) -#define GST_IS_WAVPACK_ENC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WAVPACK_ENC)) -#define GST_IS_WAVPACK_ENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WAVPACK_ENC)) -typedef struct _GstWavpackEnc GstWavpackEnc; -typedef struct _GstWavpackEncClass GstWavpackEncClass; + +#define GST_TYPE_WAVPACK_ENC (gst_wavpack_enc_get_type()) +G_DECLARE_FINAL_TYPE (GstWavpackEnc, gst_wavpack_enc, GST, WAVPACK_ENC, + GstAudioEncoder) typedef struct { @@ -48,7 +40,6 @@ typedef struct gboolean passthrough; } GstWavpackEncWriteID; - struct _GstWavpackEnc { GstAudioEncoder element; @@ -92,13 +83,6 @@ struct _GstWavpackEnc GstClockTime next_ts; }; -struct _GstWavpackEncClass -{ - GstAudioEncoderClass parent; -}; - -GType gst_wavpack_enc_get_type (void); - gboolean gst_wavpack_enc_plugin_init (GstPlugin * plugin); G_END_DECLS diff --git a/gst-plugins-good.doap b/gst-plugins-good.doap index 576f4f20c1..b44f9cb327 100644 --- a/gst-plugins-good.doap +++ b/gst-plugins-good.doap @@ -18,7 +18,7 @@ quality code and correct functionality, under our preferred license (LGPL for the plug-in code, LGPL or LGPL-compatible for the supporting library). - + C @@ -32,6 +32,106 @@ the plug-in code, LGPL or LGPL-compatible for the supporting library). + + + 1.18.6 + 1.18 + + 2022-02-02 + + + + + + + 1.18.5 + 1.18 + + 2021-09-08 + + + + + + + 1.18.4 + 1.18 + + 2021-03-15 + + + + + + + 1.18.3 + 1.18 + + 2021-01-13 + + + + + + + 1.18.2 + 1.18 + + 2020-12-06 + + + + + + + 1.18.1 + 1.18 + + 2020-10-26 + + + + + + + 1.18.0 + master + + 2020-09-08 + + + + + + + 1.17.90 + master + + 2020-08-20 + + + + + + + 1.17.2 + master + + 2020-07-03 + + + + + + + 1.17.1 + master + + 2020-06-19 + + + + 1.16.0 diff --git a/gst/alpha/gstalpha.c b/gst/alpha/gstalpha.c index 4a37b01e85..e3fc649a69 100644 --- a/gst/alpha/gstalpha.c +++ b/gst/alpha/gstalpha.c @@ -286,6 +286,8 @@ gst_alpha_class_init (GstAlphaClass * klass) vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_alpha_set_info); vfilter_class->transform_frame = GST_DEBUG_FUNCPTR (gst_alpha_transform_frame); + + gst_type_mark_as_plugin_api (GST_TYPE_ALPHA_METHOD, 0); } static void diff --git a/gst/audiofx/audioamplify.c b/gst/audiofx/audioamplify.c index f96093a8f0..13bcab86fe 100644 --- a/gst/audiofx/audioamplify.c +++ b/gst/audiofx/audioamplify.c @@ -303,6 +303,8 @@ gst_audio_amplify_class_init (GstAudioAmplifyClass * klass) GST_AUDIO_FILTER_CLASS (klass)->setup = GST_DEBUG_FUNCPTR (gst_audio_amplify_setup); + + gst_type_mark_as_plugin_api (GST_TYPE_AUDIO_AMPLIFY_CLIPPING_METHOD, 0); } static void diff --git a/gst/audiofx/audiochebband.c b/gst/audiofx/audiochebband.c index 0751963ee6..02686a6186 100644 --- a/gst/audiofx/audiochebband.c +++ b/gst/audiofx/audiochebband.c @@ -191,6 +191,8 @@ gst_audio_cheb_band_class_init (GstAudioChebBandClass * klass) "Sebastian Dröge "); filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_cheb_band_setup); + + gst_type_mark_as_plugin_api (GST_TYPE_AUDIO_CHEBYSHEV_FREQ_BAND_MODE, 0); } static void diff --git a/gst/audiofx/audiocheblimit.c b/gst/audiofx/audiocheblimit.c index c02b62e5af..0f7e8dc86a 100644 --- a/gst/audiofx/audiocheblimit.c +++ b/gst/audiofx/audiocheblimit.c @@ -183,6 +183,8 @@ gst_audio_cheb_limit_class_init (GstAudioChebLimitClass * klass) "Sebastian Dröge "); filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_cheb_limit_setup); + + gst_type_mark_as_plugin_api (GST_TYPE_AUDIO_CHEBYSHEV_FREQ_LIMIT_MODE, 0); } static void diff --git a/gst/audiofx/audiodynamic.c b/gst/audiofx/audiodynamic.c index 99e43543cb..07cb215d1a 100644 --- a/gst/audiofx/audiodynamic.c +++ b/gst/audiofx/audiodynamic.c @@ -254,6 +254,9 @@ gst_audio_dynamic_class_init (GstAudioDynamicClass * klass) GST_BASE_TRANSFORM_CLASS (klass)->transform_ip = GST_DEBUG_FUNCPTR (gst_audio_dynamic_transform_ip); GST_BASE_TRANSFORM_CLASS (klass)->transform_ip_on_passthrough = FALSE; + + gst_type_mark_as_plugin_api (GST_TYPE_AUDIO_DYNAMIC_CHARACTERISTICS, 0); + gst_type_mark_as_plugin_api (GST_TYPE_AUDIO_DYNAMIC_MODE, 0); } static void diff --git a/gst/audiofx/audiofxbasefirfilter.c b/gst/audiofx/audiofxbasefirfilter.c index 02ad61a956..e28cb64aca 100644 --- a/gst/audiofx/audiofxbasefirfilter.c +++ b/gst/audiofx/audiofxbasefirfilter.c @@ -584,6 +584,8 @@ gst_audio_fx_base_fir_filter_class_init (GstAudioFXBaseFIRFilterClass * klass) trans_class->transform_size = GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_transform_size); filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_setup); + + gst_type_mark_as_plugin_api (GST_TYPE_AUDIO_FX_BASE_FIR_FILTER, 0); } static void diff --git a/gst/audiofx/audiofxbaseiirfilter.c b/gst/audiofx/audiofxbaseiirfilter.c index 93553e8fe9..72ee3e8431 100644 --- a/gst/audiofx/audiofxbaseiirfilter.c +++ b/gst/audiofx/audiofxbaseiirfilter.c @@ -118,6 +118,8 @@ gst_audio_fx_base_iir_filter_class_init (GstAudioFXBaseIIRFilterClass * klass) GST_DEBUG_FUNCPTR (gst_audio_fx_base_iir_filter_transform_ip); trans_class->transform_ip_on_passthrough = FALSE; trans_class->stop = GST_DEBUG_FUNCPTR (gst_audio_fx_base_iir_filter_stop); + + gst_type_mark_as_plugin_api (GST_TYPE_AUDIO_FX_BASE_IIR_FILTER, 0); } static void diff --git a/gst/audiofx/audiopanorama.c b/gst/audiofx/audiopanorama.c index fe1f2a1cf3..31544e3893 100644 --- a/gst/audiofx/audiopanorama.c +++ b/gst/audiofx/audiopanorama.c @@ -210,6 +210,8 @@ gst_audio_panorama_class_init (GstAudioPanoramaClass * klass) GST_DEBUG_FUNCPTR (gst_audio_panorama_set_caps); GST_BASE_TRANSFORM_CLASS (klass)->transform = GST_DEBUG_FUNCPTR (gst_audio_panorama_transform); + + gst_type_mark_as_plugin_api (GST_TYPE_AUDIO_PANORAMA_METHOD, 0); } static void diff --git a/gst/audiofx/audiowsincband.c b/gst/audiofx/audiowsincband.c index 6159bb8cb8..305673926c 100644 --- a/gst/audiofx/audiowsincband.c +++ b/gst/audiofx/audiowsincband.c @@ -205,6 +205,9 @@ gst_audio_wsincband_class_init (GstAudioWSincBandClass * klass) "Sebastian Dröge "); filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_wsincband_setup); + + gst_type_mark_as_plugin_api (GST_TYPE_AUDIO_WSINC_BAND_MODE, 0); + gst_type_mark_as_plugin_api (GST_TYPE_AUDIO_WSINC_BAND_WINDOW, 0); } static void diff --git a/gst/audiofx/audiowsinclimit.c b/gst/audiofx/audiowsinclimit.c index 54bb903320..95c62be381 100644 --- a/gst/audiofx/audiowsinclimit.c +++ b/gst/audiofx/audiowsinclimit.c @@ -201,6 +201,9 @@ gst_audio_wsinclimit_class_init (GstAudioWSincLimitClass * klass) "Sebastian Dröge "); filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_wsinclimit_setup); + + gst_type_mark_as_plugin_api (GST_TYPE_AUDIO_WSINC_LIMIT_MODE, 0); + gst_type_mark_as_plugin_api (GST_TYPE_AUDIO_WSINC_LIMIT_WINDOW, 0); } static void diff --git a/gst/audiofx/meson.build b/gst/audiofx/meson.build index d0375a76f3..1711cb6670 100644 --- a/gst/audiofx/meson.build +++ b/gst/audiofx/meson.build @@ -28,6 +28,7 @@ if have_orcc input : orcsrc + '.orc', output : orcsrc + '.c', command : orcc_args + ['--implementation', '-o', '@OUTPUT@', '@INPUT@']) + orc_targets += {'name': orcsrc, 'orc-source': files(orcsrc + '.orc'), 'header': orc_h, 'source': orc_c} else orc_h = configure_file(input : orcsrc + '-dist.h', output : orcsrc + '.h', diff --git a/gst/audioparsers/gstaacparse.c b/gst/audioparsers/gstaacparse.c index 3b10462e49..2b54a5315e 100644 --- a/gst/audioparsers/gstaacparse.c +++ b/gst/audioparsers/gstaacparse.c @@ -173,7 +173,7 @@ static gboolean gst_aac_parse_set_src_caps (GstAacParse * aacparse, GstCaps * sink_caps) { GstStructure *s; - GstCaps *src_caps = NULL, *allowed; + GstCaps *src_caps = NULL, *peercaps; gboolean res = FALSE; const gchar *stream_format; guint8 codec_data[2]; @@ -226,8 +226,8 @@ gst_aac_parse_set_src_caps (GstAacParse * aacparse, GstCaps * sink_caps) if (stream_format) gst_structure_set (s, "stream-format", G_TYPE_STRING, stream_format, NULL); - allowed = gst_pad_get_allowed_caps (GST_BASE_PARSE (aacparse)->srcpad); - if (allowed && !gst_caps_can_intersect (src_caps, allowed)) { + peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (aacparse), NULL); + if (peercaps && !gst_caps_can_intersect (src_caps, peercaps)) { GST_DEBUG_OBJECT (GST_BASE_PARSE (aacparse)->srcpad, "Caps can not intersect"); if (aacparse->header_type == DSPAAC_HEADER_ADTS) { @@ -235,7 +235,7 @@ gst_aac_parse_set_src_caps (GstAacParse * aacparse, GstCaps * sink_caps) "Input is ADTS, trying raw"); gst_caps_set_simple (src_caps, "stream-format", G_TYPE_STRING, "raw", NULL); - if (gst_caps_can_intersect (src_caps, allowed)) { + if (gst_caps_can_intersect (src_caps, peercaps)) { GstBuffer *codec_data_buffer; GST_DEBUG_OBJECT (GST_BASE_PARSE (aacparse)->srcpad, @@ -255,15 +255,15 @@ gst_aac_parse_set_src_caps (GstAacParse * aacparse, GstCaps * sink_caps) "Input is raw, trying ADTS"); gst_caps_set_simple (src_caps, "stream-format", G_TYPE_STRING, "adts", NULL); - if (gst_caps_can_intersect (src_caps, allowed)) { + if (gst_caps_can_intersect (src_caps, peercaps)) { GST_DEBUG_OBJECT (GST_BASE_PARSE (aacparse)->srcpad, "Caps can intersect, we will prepend ADTS headers"); aacparse->output_header_type = DSPAAC_HEADER_ADTS; } } } - if (allowed) - gst_caps_unref (allowed); + if (peercaps) + gst_caps_unref (peercaps); aacparse->last_parsed_channels = 0; aacparse->last_parsed_sample_rate = 0; diff --git a/gst/audioparsers/gstac3parse.h b/gst/audioparsers/gstac3parse.h index 0e7af5acd7..81e2104d5e 100644 --- a/gst/audioparsers/gstac3parse.h +++ b/gst/audioparsers/gstac3parse.h @@ -62,7 +62,7 @@ struct _GstAc3Parse { gint blocks; gboolean eac; gboolean sent_codec_tag; - volatile gint align; + gint align; GstPadChainFunction baseparse_chainfunc; }; diff --git a/gst/audioparsers/gstflacparse.c b/gst/audioparsers/gstflacparse.c index c2a09ffcf5..5004d45d21 100644 --- a/gst/audioparsers/gstflacparse.c +++ b/gst/audioparsers/gstflacparse.c @@ -183,7 +183,7 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", ); static GstBuffer *gst_flac_parse_generate_vorbiscomment (GstFlacParse * - flacparse); + flacparse, gboolean is_last); static inline void gst_flac_parse_reset_buffer_time_and_offset (GstBuffer * buffer); @@ -1243,6 +1243,7 @@ gst_flac_parse_handle_headers (GstFlacParse * flacparse) GstCaps *caps; GList *l; GstFlowReturn res = GST_FLOW_OK; + gboolean is_streaminfo_last = FALSE; caps = gst_caps_new_simple ("audio/x-flac", "channels", G_TYPE_INT, flacparse->channels, @@ -1264,6 +1265,7 @@ gst_flac_parse_handle_headers (GstFlacParse * flacparse) marker = header; } else if (map.size > 1 && (map.data[0] & 0x7f) == 0) { streaminfo = header; + is_streaminfo_last = (map.data[0] & 0x80) != 0; } else if (map.size > 1 && (map.data[0] & 0x7f) == 4) { vorbiscomment = header; } @@ -1276,8 +1278,11 @@ gst_flac_parse_handle_headers (GstFlacParse * flacparse) if (vorbiscomment == NULL && streaminfo != NULL) { GST_DEBUG_OBJECT (flacparse, "missing vorbiscomment header; generating dummy"); - vorbiscomment = gst_flac_parse_generate_vorbiscomment (flacparse); - flacparse->headers = g_list_insert (flacparse->headers, vorbiscomment, + /* this vorbiscomment header is inserted after streaminfo and inherits its last-metadata-block flag */ + vorbiscomment = + gst_flac_parse_generate_vorbiscomment (flacparse, is_streaminfo_last); + flacparse->headers = + g_list_insert (flacparse->headers, vorbiscomment, g_list_index (flacparse->headers, streaminfo) + 1); } @@ -1312,6 +1317,8 @@ gst_flac_parse_handle_headers (GstFlacParse * flacparse) writemap.data[8] = (num & 0x00FF) >> 0; memcpy (writemap.data + 9, "fLaC", 4); memcpy (writemap.data + 13, sinfomap.data, sinfomap.size); + /* clear the last-metadata-block flag because a VORBISCOMMENT always follows */ + writemap.data[13] = 0x00; /* is_last = 0; type = 0; */ _value_array_append_buffer (&array, buf); gst_buffer_unmap (streaminfo, &sinfomap); @@ -1319,14 +1326,10 @@ gst_flac_parse_handle_headers (GstFlacParse * flacparse) gst_buffer_unref (buf); } - /* add VORBISCOMMENT header */ - _value_array_append_buffer (&array, vorbiscomment); - - /* add other headers, if there are any */ + /* add other headers, including VORBISCOMMENT */ for (l = flacparse->headers; l; l = l->next) { if (GST_BUFFER_CAST (l->data) != marker && - GST_BUFFER_CAST (l->data) != streaminfo && - GST_BUFFER_CAST (l->data) != vorbiscomment) { + GST_BUFFER_CAST (l->data) != streaminfo) { _value_array_append_buffer (&array, GST_BUFFER_CAST (l->data)); } } @@ -1368,7 +1371,8 @@ gst_flac_parse_handle_headers (GstFlacParse * flacparse) /* empty vorbiscomment */ static GstBuffer * -gst_flac_parse_generate_vorbiscomment (GstFlacParse * flacparse) +gst_flac_parse_generate_vorbiscomment (GstFlacParse * flacparse, + gboolean is_last) { GstTagList *taglist = gst_tag_list_new_empty (); guchar header[4]; @@ -1376,7 +1380,7 @@ gst_flac_parse_generate_vorbiscomment (GstFlacParse * flacparse) GstBuffer *vorbiscomment; GstMapInfo map; - header[0] = 0x84; /* is_last = 1; type = 4; */ + header[0] = (is_last ? 0x80 : 0x00) | 0x04; /* is_last may vary; type = 4; */ vorbiscomment = gst_tag_list_to_vorbiscomment_buffer (taglist, header, @@ -1475,7 +1479,7 @@ gst_flac_parse_generate_headers (GstFlacParse * flacparse) flacparse->headers = g_list_append (flacparse->headers, streaminfo); flacparse->headers = g_list_append (flacparse->headers, - gst_flac_parse_generate_vorbiscomment (flacparse)); + gst_flac_parse_generate_vorbiscomment (flacparse, TRUE)); return TRUE; } diff --git a/gst/audioparsers/gstmpegaudioparse.c b/gst/audioparsers/gstmpegaudioparse.c index b570b1aac0..f4cb1ccd24 100644 --- a/gst/audioparsers/gstmpegaudioparse.c +++ b/gst/audioparsers/gstmpegaudioparse.c @@ -199,6 +199,7 @@ gst_mpeg_audio_parse_reset (GstMpegAudioParse * mp3parse) mp3parse->freerate = 0; mp3parse->hdr_bitrate = 0; + mp3parse->bitrate_is_constant = TRUE; mp3parse->xing_flags = 0; mp3parse->xing_bitrate = 0; @@ -755,6 +756,9 @@ gst_mpeg_audio_parse_handle_frame (GstBaseParse * parse, (version == 1) ? 10 : 30, 2); } + if (mp3parse->hdr_bitrate && mp3parse->hdr_bitrate != bitrate) { + mp3parse->bitrate_is_constant = FALSE; + } mp3parse->hdr_bitrate = bitrate; /* For first frame; check for seek tables and output a codec tag */ @@ -1227,6 +1231,14 @@ gst_mpeg_audio_parse_time_to_bytepos (GstMpegAudioParse * mp3parse, return TRUE; } + /* If we have had a constant bit rate (so far), use it directly, as it + * may give slightly more accurate results than the base class. */ + if (mp3parse->bitrate_is_constant && mp3parse->hdr_bitrate) { + *bytepos = gst_util_uint64_scale (ts, mp3parse->hdr_bitrate, + 8 * GST_SECOND); + return TRUE; + } + return FALSE; } @@ -1292,6 +1304,14 @@ gst_mpeg_audio_parse_bytepos_to_time (GstMpegAudioParse * mp3parse, return TRUE; } + /* If we have had a constant bit rate (so far), use it directly, as it + * may give slightly more accurate results than the base class. */ + if (mp3parse->bitrate_is_constant && mp3parse->hdr_bitrate) { + *ts = gst_util_uint64_scale (bytepos, 8 * GST_SECOND, + mp3parse->hdr_bitrate); + return TRUE; + } + return FALSE; } diff --git a/gst/audioparsers/gstmpegaudioparse.h b/gst/audioparsers/gstmpegaudioparse.h index 5e576beae5..e7fa8099fb 100644 --- a/gst/audioparsers/gstmpegaudioparse.h +++ b/gst/audioparsers/gstmpegaudioparse.h @@ -69,6 +69,7 @@ struct _GstMpegAudioParse { /* Bitrate from non-vbr headers */ guint32 hdr_bitrate; + gboolean bitrate_is_constant; /* Xing info */ guint32 xing_flags; diff --git a/gst/auparse/gstauparse.c b/gst/auparse/gstauparse.c index 78d100ab4c..8fbab097a9 100644 --- a/gst/auparse/gstauparse.c +++ b/gst/auparse/gstauparse.c @@ -417,9 +417,9 @@ gst_au_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) GstFlowReturn ret = GST_FLOW_OK; GstAuParse *auparse; gint avail, sendnow = 0; - gint64 timestamp; - gint64 duration; - gint64 offset; + gint64 timestamp = 0; + gint64 duration = 0; + gint64 offset = 0; auparse = GST_AU_PARSE (parent); diff --git a/gst/autodetect/gstautodetect.c b/gst/autodetect/gstautodetect.c index 8c6da12780..d6224fa89f 100644 --- a/gst/autodetect/gstautodetect.c +++ b/gst/autodetect/gstautodetect.c @@ -84,12 +84,15 @@ gst_auto_detect_class_init (GstAutoDetectClass * klass) g_object_class_install_property (gobject_class, PROP_CAPS, g_param_spec_boxed ("filter-caps", "Filter caps", "Filter sink candidates using these caps.", GST_TYPE_CAPS, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT)); g_object_class_install_property (gobject_class, PROP_SYNC, g_param_spec_boolean ("sync", "Sync", "Sync on the clock", DEFAULT_SYNC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gst_type_mark_as_plugin_api (GST_TYPE_AUTO_DETECT, 0); } static void diff --git a/gst/avi/gstavidemux.c b/gst/avi/gstavidemux.c index 712b436bfd..bd0e79518a 100644 --- a/gst/avi/gstavidemux.c +++ b/gst/avi/gstavidemux.c @@ -1965,37 +1965,36 @@ gst_avi_demux_check_caps (GstAviDemux * avi, GstAviStream * stream, gst_structure_remove_field (s, "palette_data"); return caps; } - } else if (!gst_structure_has_name (s, "video/x-h264")) { - return caps; - } - - GST_DEBUG_OBJECT (avi, "checking caps %" GST_PTR_FORMAT, caps); - - /* some muxers put invalid bytestream stuff in h264 extra data */ - val = gst_structure_get_value (s, "codec_data"); - if (val && (buf = gst_value_get_buffer (val))) { - guint8 *data; - gint size; - GstMapInfo map; - - gst_buffer_map (buf, &map, GST_MAP_READ); - data = map.data; - size = map.size; - if (size >= 4) { - guint32 h = GST_READ_UINT32_BE (data); - gst_buffer_unmap (buf, &map); - if (h == 0x01) { - /* can hardly be valid AVC codec data */ - GST_DEBUG_OBJECT (avi, - "discarding invalid codec_data containing byte-stream"); - /* so do not pretend to downstream that it is packetized avc */ - gst_structure_remove_field (s, "codec_data"); - /* ... but rather properly parsed bytestream */ - gst_structure_set (s, "stream-format", G_TYPE_STRING, "byte-stream", - "alignment", G_TYPE_STRING, "au", NULL); + } else if (gst_structure_has_name (s, "video/x-h264")) { + GST_DEBUG_OBJECT (avi, "checking caps %" GST_PTR_FORMAT, caps); + + /* some muxers put invalid bytestream stuff in h264 extra data */ + val = gst_structure_get_value (s, "codec_data"); + if (val && (buf = gst_value_get_buffer (val))) { + guint8 *data; + gint size; + GstMapInfo map; + + gst_buffer_map (buf, &map, GST_MAP_READ); + data = map.data; + size = map.size; + if (size >= 4) { + guint32 h = GST_READ_UINT32_BE (data); + + gst_buffer_unmap (buf, &map); + if (h == 0x01 || (h >> 8) == 0x01) { + /* can hardly be valid AVC codec data */ + GST_DEBUG_OBJECT (avi, + "discarding invalid codec_data containing byte-stream"); + /* so do not pretend to downstream that it is packetized avc */ + gst_structure_remove_field (s, "codec_data"); + /* ... but rather properly parsed bytestream */ + gst_structure_set (s, "stream-format", G_TYPE_STRING, "byte-stream", + "alignment", G_TYPE_STRING, "au", NULL); + } + } else { + gst_buffer_unmap (buf, &map); } - } else { - gst_buffer_unmap (buf, &map); } } @@ -2227,7 +2226,8 @@ gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf) } break; case GST_RIFF_TAG_strn: - g_free (stream->name); + { + gchar *stream_name = NULL; gst_buffer_map (sub, &map, GST_MAP_READ); @@ -2237,12 +2237,16 @@ gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf) map.data, map.size); if (gst_tag_list_get_string (avi->globaltags, GST_TAG_TITLE, - &stream->name)) - GST_DEBUG_OBJECT (avi, "stream name: %s", stream->name); + &stream_name)) { + GST_DEBUG_OBJECT (avi, "stream name: %s", stream_name); + g_free (stream->name); + stream->name = stream_name; + } gst_buffer_unmap (sub, &map); gst_buffer_unref (sub); sub = NULL; + } break; case GST_RIFF_IDIT: gst_avi_demux_parse_idit (avi, sub); diff --git a/gst/deinterlace/gstdeinterlace.c b/gst/deinterlace/gstdeinterlace.c index 653ecb759d..abacf18658 100644 --- a/gst/deinterlace/gstdeinterlace.c +++ b/gst/deinterlace/gstdeinterlace.c @@ -40,6 +40,7 @@ #include "gstdeinterlace.h" #include "tvtime/plugins.h" +#include "yadif.h" #include @@ -157,6 +158,7 @@ static const GEnumValue methods_types[] = { "weavetff"}, {GST_DEINTERLACE_WEAVE_BFF, "Progressive: Bottom Field First (Do Not Use)", "weavebff"}, + {GST_DEINTERLACE_YADIF, "YADIF Adaptive Deinterlacer", "yadif"}, {0, NULL, NULL}, }; @@ -301,7 +303,7 @@ static void gst_deinterlace_get_property (GObject * self, guint prop_id, static GstCaps *gst_deinterlace_getcaps (GstDeinterlace * self, GstPad * pad, GstCaps * filter); static gboolean gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, - GstCaps * caps); + GstCaps * caps, gboolean force); static gboolean gst_deinterlace_sink_event (GstPad * pad, GstObject * parent, GstEvent * event); static gboolean gst_deinterlace_sink_query (GstPad * pad, GstObject * parent, @@ -368,7 +370,8 @@ static const struct gst_deinterlace_method_scaler_bob_get_type}, { gst_deinterlace_method_weave_get_type}, { gst_deinterlace_method_weave_tff_get_type}, { - gst_deinterlace_method_weave_bff_get_type} + gst_deinterlace_method_weave_bff_get_type}, { + gst_deinterlace_method_yadif_get_type} }; static void @@ -394,9 +397,9 @@ gst_deinterlace_set_method (GstDeinterlace * self, GstDeinterlaceMethods method) #if 0 gst_child_proxy_child_removed (GST_OBJECT (self), GST_OBJECT (self->method)); +#endif gst_object_unparent (GST_OBJECT (self->method)); self->method = NULL; -#endif } method_type = @@ -538,6 +541,7 @@ gst_deinterlace_class_init (GstDeinterlaceClass * klass) * * weave Weave. Bad quality, do not use. * * weavetff Progressive: Top Field First. Bad quality, do not use. * * weavebff Progressive: Bottom Field First. Bad quality, do not use. + * * yadif YADIF Adaptive. */ g_object_class_install_property (gobject_class, PROP_METHOD, g_param_spec_enum ("method", @@ -613,6 +617,12 @@ gst_deinterlace_class_init (GstDeinterlaceClass * klass) element_class->change_state = GST_DEBUG_FUNCPTR (gst_deinterlace_change_state); + + gst_type_mark_as_plugin_api (GST_TYPE_DEINTERLACE_METHODS, 0); + gst_type_mark_as_plugin_api (GST_TYPE_DEINTERLACE_FIELDS, 0); + gst_type_mark_as_plugin_api (GST_TYPE_DEINTERLACE_FIELD_LAYOUT, 0); + gst_type_mark_as_plugin_api (GST_TYPE_DEINTERLACE_MODES, 0); + gst_type_mark_as_plugin_api (GST_TYPE_DEINTERLACE_LOCKING, 0); } #if 0 @@ -668,6 +678,7 @@ gst_deinterlace_init (GstDeinterlace * self) self->mode = DEFAULT_MODE; self->user_set_method_id = DEFAULT_METHOD; gst_video_info_init (&self->vinfo); + gst_video_info_init (&self->vinfo_out); gst_deinterlace_set_method (self, self->user_set_method_id); self->fields = DEFAULT_FIELDS; self->user_set_fields = DEFAULT_FIELDS; @@ -830,6 +841,7 @@ gst_deinterlace_reset (GstDeinterlace * self) GST_DEBUG_OBJECT (self, "Resetting internal state"); gst_video_info_init (&self->vinfo); + gst_video_info_init (&self->vinfo_out); self->passthrough = FALSE; @@ -1054,6 +1066,7 @@ gst_deinterlace_get_buffer_state (GstDeinterlace * self, GstVideoFrame * frame, #define MODE_TO_STRING(m) ((m) == GST_VIDEO_INTERLACE_MODE_MIXED ? "MIXED" : \ (m) == GST_VIDEO_INTERLACE_MODE_INTERLEAVED ? "I" : \ + (m) == GST_VIDEO_INTERLACE_MODE_ALTERNATE ? "A" : \ (m) == GST_VIDEO_INTERLACE_MODE_FIELDS ? "FIELDS" : "P") static void @@ -1079,8 +1092,12 @@ gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer) onefield = GST_VIDEO_FRAME_IS_ONEFIELD (frame); fields_to_push = (onefield) ? 1 : 2; - g_return_if_fail (self->history_count < - GST_DEINTERLACE_MAX_FIELD_HISTORY - fields_to_push); + if (G_UNLIKELY (self->history_count >= + GST_DEINTERLACE_MAX_FIELD_HISTORY - fields_to_push)) { + GST_WARNING_OBJECT (self, "history count exceeded limit"); + gst_video_frame_unmap_and_free (frame); + return; + } gst_deinterlace_get_buffer_state (self, frame, &buf_state, &interlacing_mode); @@ -1598,7 +1615,8 @@ gst_deinterlace_output_frame (GstDeinterlace * self, gboolean flushing) /* setcaps on sink and src pads */ sinkcaps = gst_pad_get_current_caps (self->sinkpad); - if (!sinkcaps || !gst_deinterlace_setcaps (self, self->sinkpad, sinkcaps)) { + if (!sinkcaps + || !gst_deinterlace_setcaps (self, self->sinkpad, sinkcaps, FALSE)) { if (sinkcaps) gst_caps_unref (sinkcaps); return GST_FLOW_NOT_NEGOTIATED; @@ -1866,7 +1884,7 @@ gst_deinterlace_output_frame (GstDeinterlace * self, gboolean flushing) /* map the frame so the deinterlace methods can write the data to the * correct memory locations */ outframe = - gst_video_frame_new_and_map (&self->vinfo, outbuf, GST_MAP_WRITE); + gst_video_frame_new_and_map (&self->vinfo_out, outbuf, GST_MAP_WRITE); /* do magic calculus */ gst_deinterlace_method_deinterlace_frame (self->method, @@ -2027,7 +2045,7 @@ gst_deinterlace_output_frame (GstDeinterlace * self, gboolean flushing) /* map the frame so the deinterlace methods can write the data to the * correct memory locations */ outframe = - gst_video_frame_new_and_map (&self->vinfo, outbuf, GST_MAP_WRITE); + gst_video_frame_new_and_map (&self->vinfo_out, outbuf, GST_MAP_WRITE); /* do magic calculus */ gst_deinterlace_method_deinterlace_frame (self->method, @@ -2145,11 +2163,16 @@ gst_deinterlace_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) GST_OBJECT_LOCK (self); if (self->reconfigure || gst_pad_check_reconfigure (self->srcpad)) { GstCaps *caps; + gboolean force_reconfigure = FALSE; - if ((gint) self->new_fields != -1) + if ((gint) self->new_fields != -1) { + force_reconfigure |= (self->user_set_fields != self->new_fields); self->user_set_fields = self->new_fields; - if ((gint) self->new_mode != -1) + } + if ((gint) self->new_mode != -1) { + force_reconfigure |= (self->mode != self->new_mode); self->mode = self->new_mode; + } self->new_mode = -1; self->new_fields = -1; @@ -2157,7 +2180,8 @@ gst_deinterlace_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) GST_OBJECT_UNLOCK (self); caps = gst_pad_get_current_caps (self->sinkpad); if (caps != NULL) { - if (!gst_deinterlace_setcaps (self, self->sinkpad, caps)) { + if (!gst_deinterlace_setcaps (self, self->sinkpad, caps, + force_reconfigure)) { gst_pad_mark_reconfigure (self->srcpad); gst_caps_unref (caps); if (GST_PAD_IS_FLUSHING (self->srcpad)) @@ -2396,6 +2420,22 @@ gst_deinterlace_caps_double_framerate (GstCaps * caps, gboolean half) return caps; } +static GstCaps * +dup_caps_with_alternate (GstCaps * caps) +{ + GstCaps *with_alternate; + GstCapsFeatures *features; + + with_alternate = gst_caps_copy (caps); + features = gst_caps_features_new (GST_CAPS_FEATURE_FORMAT_INTERLACED, NULL); + gst_caps_set_features_simple (with_alternate, features); + + gst_caps_set_simple (with_alternate, "interlace-mode", G_TYPE_STRING, + "alternate", NULL); + + return with_alternate; +} + static GstCaps * gst_deinterlace_getcaps (GstDeinterlace * self, GstPad * pad, GstCaps * filter) { @@ -2484,11 +2524,18 @@ gst_deinterlace_getcaps (GstDeinterlace * self, GstPad * pad, GstCaps * filter) for (len = gst_caps_get_size (tmp2); len > 0; len--) { GstStructure *s = gst_caps_get_structure (tmp2, len - 1); - if (pad == self->sinkpad) + /* Drop fields which can be converted by us. + * Specifically "field-order" here. + * "field-order" with "progressive" and/or + * unspecified "interlace-mode" would cause negotiation issue */ + gst_structure_remove_field (s, "field-order"); + + if (pad == self->sinkpad) { gst_structure_remove_field (s, "interlace-mode"); - else + } else { gst_structure_set (s, "interlace-mode", G_TYPE_STRING, "progressive", NULL); + } } if (self->user_set_fields == GST_DEINTERLACE_ALL) { @@ -2516,6 +2563,17 @@ gst_deinterlace_getcaps (GstDeinterlace * self, GstPad * pad, GstCaps * filter) gst_caps_unref (caps); caps = NULL; + if (pad == self->sinkpad) { + GstCaps *can_deinterlace; + + tmp = gst_static_caps_get (&deinterlace_caps); + can_deinterlace = gst_caps_intersect (ret, tmp); + gst_caps_unref (tmp); + + ret = gst_caps_merge (ret, dup_caps_with_alternate (can_deinterlace)); + gst_caps_unref (can_deinterlace); + } + done: if (filter) { @@ -2614,8 +2672,12 @@ gst_deinterlace_do_bufferpool (GstDeinterlace * self, GstCaps * outcaps) if (gst_query_get_n_allocation_pools (query) > 0) gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max); else { + GstVideoInfo out_info; + + gst_video_info_from_caps (&out_info, outcaps); + pool = NULL; - size = GST_VIDEO_INFO_SIZE (&self->vinfo); + size = GST_VIDEO_INFO_SIZE (&out_info); min = MAX ((gst_deinterlace_method_get_fields_required (self->method) + 1) / 2 + 1, 4); @@ -2645,16 +2707,19 @@ gst_deinterlace_do_bufferpool (GstDeinterlace * self, GstCaps * outcaps) static gboolean -gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps) +gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps, + gboolean force) { - GstCaps *srccaps = NULL; + GstCaps *srccaps = NULL, *caps_no_feat = NULL; GstVideoInterlaceMode interlacing_mode; gint fps_n, fps_d; GstCaps *peercaps, *current_caps; gst_pad_check_reconfigure (self->srcpad); - if ((current_caps = gst_pad_get_current_caps (pad))) { + /* If the force flag is set, always re-check the downstream caps, + * and reconfigure as the deinterlace mode has changed */ + if (!force && (current_caps = gst_pad_get_current_caps (pad))) { if (gst_caps_is_equal (caps, current_caps)) { GST_DEBUG_OBJECT (pad, "Got same caps again, returning"); gst_caps_unref (current_caps); @@ -2701,6 +2766,26 @@ gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps) if (!gst_video_info_from_caps (&self->vinfo, caps)) goto invalid_caps; + gst_video_info_set_interlaced_format (&self->vinfo_out, + GST_VIDEO_INFO_FORMAT (&self->vinfo), + GST_VIDEO_INTERLACE_MODE_PROGRESSIVE, + GST_VIDEO_INFO_WIDTH (&self->vinfo), + GST_VIDEO_INFO_HEIGHT (&self->vinfo)); + + if (GST_VIDEO_INFO_INTERLACE_MODE (&self->vinfo) == + GST_VIDEO_INTERLACE_MODE_ALTERNATE) { + /* alternate interlace mode uses a caps feature, remove it when interesecting caps + * and setting the src pad caps. */ + GstCapsFeatures *features; + + caps_no_feat = gst_caps_copy (caps); + + features = gst_caps_get_features (caps_no_feat, 0); + gst_caps_features_remove (features, GST_CAPS_FEATURE_FORMAT_INTERLACED); + } else { + caps_no_feat = gst_caps_ref (caps); + } + fps_n = GST_VIDEO_INFO_FPS_N (&self->vinfo); fps_d = GST_VIDEO_INFO_FPS_D (&self->vinfo); @@ -2711,7 +2796,7 @@ gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps) } else if (self->mode == GST_DEINTERLACE_MODE_INTERLACED) { GstCaps *tmp = gst_static_caps_get (&deinterlace_caps); - if (!gst_caps_can_intersect (caps, tmp)) { + if (!gst_caps_can_intersect (caps_no_feat, tmp)) { gst_caps_unref (tmp); GST_ERROR_OBJECT (self, "Unsupported caps for mode=interlaced"); goto invalid_caps; @@ -2728,7 +2813,7 @@ gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps) GST_DEBUG_OBJECT (self, "Passthrough because mode=auto and progressive caps"); self->passthrough = TRUE; - } else if (gst_caps_can_intersect (caps, tmp)) { + } else if (gst_caps_can_intersect (caps_no_feat, tmp)) { if (peercaps) { GstCaps *allowed_caps; GstCaps *tmp2; @@ -2788,7 +2873,7 @@ gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps) if (!self->passthrough) { if (self->pattern_lock) { - srccaps = gst_caps_copy (caps); + srccaps = gst_caps_copy (caps_no_feat); if (self->pattern != -1 && G_UNLIKELY (!gst_util_fraction_multiply (fps_n, fps_d, telecine_patterns[self->pattern].ratio_n, @@ -2801,17 +2886,17 @@ gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps) || self->low_latency == 0) { /* in high latency pattern locking mode if we don't have a pattern lock, * the sink pad caps are the best we know */ - srccaps = gst_caps_copy (caps); + srccaps = gst_caps_copy (caps_no_feat); } else if (self->low_latency > 0 && interlacing_mode == GST_VIDEO_INTERLACE_MODE_MIXED && self->pattern == -1) { /* for initial buffers of a telecine pattern, until there is a lock we * we output naïvely adjusted timestamps in low-latency pattern locking * mode */ - srccaps = gst_caps_copy (caps); + srccaps = gst_caps_copy (caps_no_feat); gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, 0, 1, NULL); } else if (self->user_set_fields == GST_DEINTERLACE_FIELDS_AUTO) { - srccaps = gst_caps_copy (caps); + srccaps = gst_caps_copy (caps_no_feat); if (peercaps) { gboolean can_be_tf = FALSE; @@ -2849,7 +2934,7 @@ gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps) } } else { self->fields = self->user_set_fields; - srccaps = gst_caps_copy (caps); + srccaps = gst_caps_copy (caps_no_feat); if (self->fields == GST_DEINTERLACE_ALL) srccaps = gst_deinterlace_caps_double_framerate (srccaps, FALSE); } @@ -2858,10 +2943,15 @@ gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps) gst_caps_set_simple (srccaps, "interlace-mode", G_TYPE_STRING, "progressive", NULL); + { + GstStructure *s = gst_caps_get_structure (srccaps, 0); + gst_structure_remove_field (s, "field-order"); + } + gst_deinterlace_set_method (self, self->method_id); gst_deinterlace_method_setup (self->method, &self->vinfo); } else { - srccaps = gst_caps_ref (caps); + srccaps = gst_caps_ref (caps_no_feat); } if (fps_n != 0) { @@ -2882,6 +2972,7 @@ gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps) if (peercaps) gst_caps_unref (peercaps); gst_caps_unref (srccaps); + g_clear_pointer (&caps_no_feat, gst_caps_unref); return TRUE; @@ -2889,6 +2980,7 @@ gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps) { if (peercaps) gst_caps_unref (peercaps); + g_clear_pointer (&caps_no_feat, gst_caps_unref); GST_ERROR_OBJECT (pad, "Invalid caps: %" GST_PTR_FORMAT, caps); gst_pad_mark_reconfigure (self->srcpad); return FALSE; @@ -2899,6 +2991,7 @@ gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps) if (peercaps) gst_caps_unref (peercaps); gst_caps_unref (srccaps); + g_clear_pointer (&caps_no_feat, gst_caps_unref); gst_pad_mark_reconfigure (self->srcpad); return FALSE; } @@ -2908,6 +3001,7 @@ gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps) if (peercaps) gst_caps_unref (peercaps); gst_caps_unref (srccaps); + g_clear_pointer (&caps_no_feat, gst_caps_unref); gst_pad_mark_reconfigure (self->srcpad); return FALSE; } @@ -2928,7 +3022,7 @@ gst_deinterlace_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) GstCaps *caps = NULL; gst_event_parse_caps (event, &caps); - res = gst_deinterlace_setcaps (self, pad, caps); + res = gst_deinterlace_setcaps (self, pad, caps, FALSE); gst_event_unref (event); break; } diff --git a/gst/deinterlace/gstdeinterlace.h b/gst/deinterlace/gstdeinterlace.h index b87fce2e6c..65b438a459 100644 --- a/gst/deinterlace/gstdeinterlace.h +++ b/gst/deinterlace/gstdeinterlace.h @@ -56,7 +56,8 @@ typedef enum GST_DEINTERLACE_SCALER_BOB, GST_DEINTERLACE_WEAVE, GST_DEINTERLACE_WEAVE_TFF, - GST_DEINTERLACE_WEAVE_BFF + GST_DEINTERLACE_WEAVE_BFF, + GST_DEINTERLACE_YADIF } GstDeinterlaceMethods; typedef enum @@ -136,6 +137,7 @@ struct _GstDeinterlace GstDeinterlaceMethod *method; GstVideoInfo vinfo; + GstVideoInfo vinfo_out; GstBufferPool *pool; GstAllocator *allocator; GstAllocationParams params; diff --git a/gst/deinterlace/gstdeinterlacemethod.c b/gst/deinterlace/gstdeinterlacemethod.c index 93e77e7f09..ab5732381b 100644 --- a/gst/deinterlace/gstdeinterlacemethod.c +++ b/gst/deinterlace/gstdeinterlacemethod.c @@ -268,10 +268,14 @@ gst_deinterlace_simple_method_supported (GstDeinterlaceMethodClass * mklass, && klass->copy_scanline_ayuv != NULL); case GST_VIDEO_FORMAT_NV12: return (klass->interpolate_scanline_nv12 != NULL - && klass->copy_scanline_nv12 != NULL); + && klass->copy_scanline_nv12 != NULL + && klass->interpolate_scanline_planar_y != NULL + && klass->copy_scanline_planar_y != NULL); case GST_VIDEO_FORMAT_NV21: return (klass->interpolate_scanline_nv21 != NULL - && klass->copy_scanline_nv21 != NULL); + && klass->copy_scanline_nv21 != NULL + && klass->interpolate_scanline_planar_y != NULL + && klass->copy_scanline_planar_y != NULL); case GST_VIDEO_FORMAT_I420: case GST_VIDEO_FORMAT_YV12: case GST_VIDEO_FORMAT_Y444: @@ -304,6 +308,49 @@ gst_deinterlace_simple_method_copy_scanline_packed (GstDeinterlaceSimpleMethod * memcpy (out, scanlines->m0, stride); } +typedef struct +{ + const GstDeinterlaceField *history; + guint history_count; + gint cur_field_idx; +} LinesGetter; + +#define CLAMP_LOW(i) (((i)<0) ? (i+2) : (i)) +#define CLAMP_HI(i) (((i)>=(frame_height)) ? (i-2) : (i)) + +static guint8 * +get_line (LinesGetter * lg, gint field_offset, guint plane, gint line, + gint line_offset) +{ + const GstVideoFrame *frame; + gint idx, frame_height; + guint8 *data; + + idx = lg->cur_field_idx + field_offset; + if (idx < 0 || idx >= lg->history_count) + return NULL; + + frame = lg->history[idx].frame; + g_assert (frame); + + if (GST_VIDEO_FRAME_FLAG_IS_SET (frame, GST_VIDEO_FRAME_FLAG_TOP_FIELD) || + GST_VIDEO_FRAME_FLAG_IS_SET (frame, GST_VIDEO_FRAME_FLAG_BOTTOM_FIELD)) { + /* Alternate frame containing a single field, adjust the line index */ + line /= 2; + if (line_offset != 1) + line_offset /= 2; + } + + frame_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, plane); + line += line_offset; + + data = GST_VIDEO_FRAME_PLANE_DATA ((frame), plane); + data += CLAMP_HI (CLAMP_LOW (line)) * GST_VIDEO_FRAME_PLANE_STRIDE ((frame), + plane); + + return data; +} + static void gst_deinterlace_simple_method_deinterlace_frame_packed (GstDeinterlaceMethod * method, const GstDeinterlaceField * history, guint history_count, @@ -317,6 +364,7 @@ gst_deinterlace_simple_method_deinterlace_frame_packed (GstDeinterlaceMethod * guint cur_field_flags; gint i; gint frame_height, frame_width; + LinesGetter lg = { history, history_count, cur_field_idx }; GstVideoFrame *framep, *frame0, *frame1, *frame2; g_assert (self->interpolate_scanline_packed != NULL); @@ -333,7 +381,7 @@ gst_deinterlace_simple_method_deinterlace_frame_packed (GstDeinterlaceMethod * if (framep) frame_width = MIN (frame_width, GST_VIDEO_FRAME_PLANE_STRIDE (framep, 0)); - g_assert (dm_class->fields_required <= 4); + g_assert (dm_class->fields_required <= 5); frame1 = (cur_field_idx + 1 < @@ -347,11 +395,8 @@ gst_deinterlace_simple_method_deinterlace_frame_packed (GstDeinterlaceMethod * if (frame2) frame_width = MIN (frame_width, GST_VIDEO_FRAME_PLANE_STRIDE (frame2, 0)); -#define CLAMP_LOW(i) (((i)<0) ? (i+2) : (i)) -#define CLAMP_HI(i) (((i)>=(frame_height)) ? (i-2) : (i)) -#define LINE(x,i) (((guint8*)GST_VIDEO_FRAME_PLANE_DATA((x),0)) + CLAMP_HI(CLAMP_LOW(i)) * \ +#define LINE(x,i) (((guint8*)GST_VIDEO_FRAME_PLANE_DATA((x),0)) + i * \ GST_VIDEO_FRAME_PLANE_STRIDE((x),0)) -#define LINE2(x,i) ((x) ? LINE(x,i) : NULL) for (i = 0; i < frame_height; i++) { memset (&scanlines, 0, sizeof (scanlines)); @@ -359,43 +404,45 @@ gst_deinterlace_simple_method_deinterlace_frame_packed (GstDeinterlaceMethod * if (!((i & 1) ^ scanlines.bottom_field)) { /* copying */ - scanlines.tp = LINE2 (framep, i - 1); - scanlines.bp = LINE2 (framep, i + 1); + scanlines.tp = get_line (&lg, -1, 0, i, -1); + scanlines.bp = get_line (&lg, -1, 0, i, 1); - scanlines.tt0 = LINE2 (frame0, (i - 2 >= 0) ? i - 2 : i); - scanlines.m0 = LINE2 (frame0, i); - scanlines.bb0 = LINE2 (frame0, (i + 2 < frame_height ? i + 2 : i)); + scanlines.tt0 = get_line (&lg, 0, 0, i, -2); + scanlines.m0 = get_line (&lg, 0, 0, i, 0); + scanlines.bb0 = get_line (&lg, 0, 0, i, 2); - scanlines.t1 = LINE2 (frame1, i - 1); - scanlines.b1 = LINE2 (frame1, i + 1); + scanlines.t1 = get_line (&lg, 1, 0, i, -1); + scanlines.b1 = get_line (&lg, 1, 0, i, 1); - scanlines.tt2 = LINE2 (frame2, (i - 2 >= 0) ? i - 2 : i); - scanlines.m2 = LINE2 (frame2, i); - scanlines.bb2 = LINE2 (frame2, (i + 2 < frame_height ? i + 2 : i)); + scanlines.tt2 = get_line (&lg, 2, 0, i, -2); + scanlines.m2 = get_line (&lg, 2, 0, i, 0); + scanlines.bb2 = get_line (&lg, 2, 0, i, 2); self->copy_scanline_packed (self, LINE (outframe, i), &scanlines, frame_width); } else { /* interpolating */ - scanlines.ttp = LINE2 (framep, (i - 2 >= 0) ? i - 2 : i); - scanlines.mp = LINE2 (framep, i); - scanlines.bbp = LINE2 (framep, (i + 2 < frame_height ? i + 2 : i)); + scanlines.tp2 = get_line (&lg, -2, 0, i, -1); + scanlines.bp2 = get_line (&lg, -2, 0, i, 1); - scanlines.t0 = LINE2 (frame0, i - 1); - scanlines.b0 = LINE2 (frame0, i + 1); + scanlines.ttp = get_line (&lg, -1, 0, i, -2); + scanlines.mp = get_line (&lg, -1, 0, i, 0); + scanlines.bbp = get_line (&lg, -1, 0, i, 2); - scanlines.tt1 = LINE2 (frame1, (i - 2 >= 0) ? i - 2 : i); - scanlines.m1 = LINE2 (frame1, i); - scanlines.bb1 = LINE2 (frame1, (i + 2 < frame_height ? i + 2 : i)); + scanlines.t0 = get_line (&lg, 0, 0, i, -1); + scanlines.b0 = get_line (&lg, 0, 0, i, 1); - scanlines.t2 = LINE2 (frame2, i - 1); - scanlines.b2 = LINE2 (frame2, i + 1); + scanlines.tt1 = get_line (&lg, 1, 0, i, -2); + scanlines.m1 = get_line (&lg, 1, 0, i, 0); + scanlines.bb1 = get_line (&lg, 1, 0, i, 2); + + scanlines.t2 = get_line (&lg, 2, 0, i, -1); + scanlines.b2 = get_line (&lg, 2, 0, i, 1); self->interpolate_scanline_packed (self, LINE (outframe, i), &scanlines, frame_width); } #undef LINE -#undef LINE2 } } @@ -450,8 +497,7 @@ gst_deinterlace_simple_method_copy_scanline_planar_v (GstDeinterlaceSimpleMethod static void gst_deinterlace_simple_method_deinterlace_frame_planar_plane (GstDeinterlaceSimpleMethod * self, GstVideoFrame * dest, - const GstVideoFrame * frame0, const GstVideoFrame * frame1, - const GstVideoFrame * frame2, const GstVideoFrame * framep, + LinesGetter * lg, guint cur_field_flags, gint plane, GstDeinterlaceSimpleMethodFunction copy_scanline, GstDeinterlaceSimpleMethodFunction interpolate_scanline) @@ -467,9 +513,8 @@ static void g_assert (interpolate_scanline != NULL); g_assert (copy_scanline != NULL); -#define LINE(x,i) (((guint8*)GST_VIDEO_FRAME_PLANE_DATA((x),plane)) + CLAMP_HI(CLAMP_LOW(i)) * \ +#define LINE(x,i) (((guint8*)GST_VIDEO_FRAME_PLANE_DATA((x),plane)) + i * \ GST_VIDEO_FRAME_PLANE_STRIDE((x),plane)) -#define LINE2(x,i) ((x) ? LINE(x,i) : NULL) for (i = 0; i < frame_height; i++) { memset (&scanlines, 0, sizeof (scanlines)); @@ -477,41 +522,43 @@ static void if (!((i & 1) ^ scanlines.bottom_field)) { /* copying */ - scanlines.tp = LINE2 (framep, i - 1); - scanlines.bp = LINE2 (framep, i + 1); + scanlines.tp = get_line (lg, -1, plane, i, -1); + scanlines.bp = get_line (lg, -1, plane, i, 1); - scanlines.tt0 = LINE2 (frame0, (i - 2 >= 0) ? i - 2 : i); - scanlines.m0 = LINE2 (frame0, i); - scanlines.bb0 = LINE2 (frame0, (i + 2 < frame_height ? i + 2 : i)); + scanlines.tt0 = get_line (lg, 0, plane, i, -2); + scanlines.m0 = get_line (lg, 0, plane, i, 0); + scanlines.bb0 = get_line (lg, 0, plane, i, 2); - scanlines.t1 = LINE2 (frame1, i - 1); - scanlines.b1 = LINE2 (frame1, i + 1); + scanlines.t1 = get_line (lg, 1, plane, i, -1); + scanlines.b1 = get_line (lg, 1, plane, i, 1); - scanlines.tt2 = LINE2 (frame2, (i - 2 >= 0) ? i - 2 : i); - scanlines.m2 = LINE2 (frame2, i); - scanlines.bb2 = LINE2 (frame2, (i + 2 < frame_height ? i + 2 : i)); + scanlines.tt2 = get_line (lg, 2, plane, i, -2); + scanlines.m2 = get_line (lg, 2, plane, i, 0); + scanlines.bb2 = get_line (lg, 2, plane, i, 2); copy_scanline (self, LINE (dest, i), &scanlines, frame_width); } else { /* interpolating */ - scanlines.ttp = LINE2 (framep, (i - 2 >= 0) ? i - 2 : i); - scanlines.mp = LINE2 (framep, i); - scanlines.bbp = LINE2 (framep, (i + 2 < frame_height ? i + 2 : i)); + scanlines.tp2 = get_line (lg, -2, plane, i, -1); + scanlines.bp2 = get_line (lg, -2, plane, i, 1); + + scanlines.ttp = get_line (lg, -1, plane, i, -2); + scanlines.mp = get_line (lg, -1, plane, i, 0); + scanlines.bbp = get_line (lg, -1, plane, i, 2); - scanlines.t0 = LINE2 (frame0, i - 1); - scanlines.b0 = LINE2 (frame0, i + 1); + scanlines.t0 = get_line (lg, 0, plane, i, -1); + scanlines.b0 = get_line (lg, 0, plane, i, 1); - scanlines.tt1 = LINE2 (frame1, (i - 2 >= 0) ? i - 2 : i); - scanlines.m1 = LINE2 (frame1, i); - scanlines.bb1 = LINE2 (frame1, (i + 2 < frame_height ? i + 2 : i)); + scanlines.tt1 = get_line (lg, 1, plane, i, -2); + scanlines.m1 = get_line (lg, 1, plane, i, 0); + scanlines.bb1 = get_line (lg, 1, plane, i, 2); - scanlines.t2 = LINE2 (frame2, i - 1); - scanlines.b2 = LINE2 (frame2, i + 1); + scanlines.t2 = get_line (lg, 2, plane, i, -1); + scanlines.b2 = get_line (lg, 2, plane, i, 1); interpolate_scanline (self, LINE (dest, i), &scanlines, frame_width); } #undef LINE -#undef LINE2 } } @@ -524,11 +571,11 @@ gst_deinterlace_simple_method_deinterlace_frame_planar (GstDeinterlaceMethod * #ifndef G_DISABLE_ASSERT GstDeinterlaceMethodClass *dm_class = GST_DEINTERLACE_METHOD_GET_CLASS (self); #endif - const GstVideoFrame *frame0, *frame1, *frame2, *framep; guint cur_field_flags = history[cur_field_idx].flags; gint i; GstDeinterlaceSimpleMethodFunction copy_scanline; GstDeinterlaceSimpleMethodFunction interpolate_scanline; + LinesGetter lg = { history, history_count, cur_field_idx }; g_assert (self->interpolate_scanline_planar[0] != NULL); g_assert (self->interpolate_scanline_planar[1] != NULL); @@ -536,27 +583,14 @@ gst_deinterlace_simple_method_deinterlace_frame_planar (GstDeinterlaceMethod * g_assert (self->copy_scanline_planar[0] != NULL); g_assert (self->copy_scanline_planar[1] != NULL); g_assert (self->copy_scanline_planar[2] != NULL); + g_assert (dm_class->fields_required <= 5); for (i = 0; i < 3; i++) { copy_scanline = self->copy_scanline_planar[i]; interpolate_scanline = self->interpolate_scanline_planar[i]; - framep = (cur_field_idx > 0 ? history[cur_field_idx - 1].frame : NULL); - - frame0 = history[cur_field_idx].frame; - - g_assert (dm_class->fields_required <= 4); - - frame1 = - (cur_field_idx + 1 < - history_count ? history[cur_field_idx + 1].frame : NULL); - frame2 = - (cur_field_idx + 2 < - history_count ? history[cur_field_idx + 2].frame : NULL); - gst_deinterlace_simple_method_deinterlace_frame_planar_plane (self, - outframe, frame0, frame1, frame2, framep, cur_field_flags, i, - copy_scanline, interpolate_scanline); + outframe, &lg, cur_field_flags, i, copy_scanline, interpolate_scanline); } } @@ -569,31 +603,23 @@ gst_deinterlace_simple_method_deinterlace_frame_nv12 (GstDeinterlaceMethod * #ifndef G_DISABLE_ASSERT GstDeinterlaceMethodClass *dm_class = GST_DEINTERLACE_METHOD_GET_CLASS (self); #endif - const GstVideoFrame *frame0, *frame1, *frame2, *framep; guint cur_field_flags = history[cur_field_idx].flags; - gint i; + LinesGetter lg = { history, history_count, cur_field_idx, }; + /* Y plane is at position 0 */ g_assert (self->interpolate_scanline_packed != NULL); g_assert (self->copy_scanline_packed != NULL); - - for (i = 0; i < 2; i++) { - framep = (cur_field_idx > 0 ? history[cur_field_idx - 1].frame : NULL); - - frame0 = history[cur_field_idx].frame; - - g_assert (dm_class->fields_required <= 4); - - frame1 = - (cur_field_idx + 1 < - history_count ? history[cur_field_idx + 1].frame : NULL); - frame2 = - (cur_field_idx + 2 < - history_count ? history[cur_field_idx + 2].frame : NULL); - - gst_deinterlace_simple_method_deinterlace_frame_planar_plane (self, - outframe, frame0, frame1, frame2, framep, cur_field_flags, i, - self->copy_scanline_packed, self->interpolate_scanline_packed); - } + g_assert (self->interpolate_scanline_planar[0] != NULL); + g_assert (self->copy_scanline_planar[0] != NULL); + g_assert (dm_class->fields_required <= 5); + + /* Y plane first, then UV/VU plane */ + gst_deinterlace_simple_method_deinterlace_frame_planar_plane (self, + outframe, &lg, cur_field_flags, 0, + self->copy_scanline_planar[0], self->interpolate_scanline_planar[0]); + gst_deinterlace_simple_method_deinterlace_frame_planar_plane (self, + outframe, &lg, cur_field_flags, 1, + self->copy_scanline_packed, self->interpolate_scanline_packed); } static void @@ -668,10 +694,16 @@ gst_deinterlace_simple_method_setup (GstDeinterlaceMethod * method, case GST_VIDEO_FORMAT_NV12: self->interpolate_scanline_packed = klass->interpolate_scanline_nv12; self->copy_scanline_packed = klass->copy_scanline_nv12; + self->interpolate_scanline_planar[0] = + klass->interpolate_scanline_planar_y; + self->copy_scanline_planar[0] = klass->copy_scanline_planar_y; break; case GST_VIDEO_FORMAT_NV21: self->interpolate_scanline_packed = klass->interpolate_scanline_nv21; self->copy_scanline_packed = klass->copy_scanline_nv21; + self->interpolate_scanline_planar[0] = + klass->interpolate_scanline_planar_y; + self->copy_scanline_planar[0] = klass->copy_scanline_planar_y; break; case GST_VIDEO_FORMAT_I420: case GST_VIDEO_FORMAT_YV12: diff --git a/gst/deinterlace/gstdeinterlacemethod.h b/gst/deinterlace/gstdeinterlacemethod.h index e967f2c8ff..6c421c1e7b 100644 --- a/gst/deinterlace/gstdeinterlacemethod.h +++ b/gst/deinterlace/gstdeinterlacemethod.h @@ -135,19 +135,20 @@ struct _GstDeinterlaceScanlineData { const guint8 *tt0, *t0, *m0, *b0, *bb0; const guint8 *tt1, *t1, *m1, *b1, *bb1; const guint8 *tt2, *t2, *m2, *b2, *bb2; + const guint8 *tp2, *bp2; gboolean bottom_field; }; /* * For interpolate_scanline the input is: * - * | t-3 t-2 t-1 t t+1 - * | Field 3 | Field 2 | Field 1 | Field 0 | Field -1 - * | TT3 | | TT1 | | TTp - * | | T2 | | T0 | - * | M3 | | M1 | | Mp - * | | B2 | | B0 | - * | BB3 | | BB1 | | BBp + * | t-3 t-2 t-1 t t+1 t+2 + * | Field 3 | Field 2 | Field 1 | Field 0 | Field -1 | Field -2 + * | TT3 | | TT1 | | TTp | + * | | T2 | | T0 | | Tp2 + * | M3 | | M1 | | Mp | + * | | B2 | | B0 | | Bp2 + * | BB3 | | BB1 | | BBp | * * For copy_scanline the input is: * diff --git a/gst/deinterlace/meson.build b/gst/deinterlace/meson.build index 4a36d8ee2a..5eae029ebb 100644 --- a/gst/deinterlace/meson.build +++ b/gst/deinterlace/meson.build @@ -10,7 +10,8 @@ interlace_sources = [ 'tvtime/weave.c', 'tvtime/linear.c', 'tvtime/linearblend.c', - 'tvtime/scalerbob.c' + 'tvtime/scalerbob.c', + 'yadif.c' ] orcsrc = 'tvtime' @@ -23,6 +24,7 @@ if have_orcc input : orcsrc + '.orc', output : orcsrc + '.c', command : orcc_args + ['--implementation', '-o', '@OUTPUT@', '@INPUT@']) + orc_targets += {'name': orcsrc, 'orc-source': files(orcsrc + '.orc'), 'header': orc_h, 'source': orc_c} else orc_h = configure_file(input : orcsrc + '-dist.h', output : orcsrc + '.h', @@ -32,8 +34,64 @@ else copy : true) endif +asm_gen_objs = [] +if have_nasm and host_cpu == 'x86_64' + if host_system == 'windows' + outputname = '@PLAINNAME@.obj' + else + outputname = '@PLAINNAME@.o' + endif + + if get_option('b_staticpic') + asm_pic_def = '-DPIC' + else + asm_pic_def = '-UPIC' + endif + + # Assembly has to be told when the symbols have to be prefixed with _ + # Note that symbols_have_underscore_prefix does not work properly on macos + # if the compiler -g flag is used. See: + # https://github.com/mesonbuild/meson/issues/5482 + if ['darwin', 'ios'].contains(host_system) + asm_prefix_def = '-DPREFIX' + elif cc.symbols_have_underscore_prefix() + asm_prefix_def = '-DPREFIX' + else + asm_prefix_def = '-UPREFIX' + endif + + asm_arch_def = '-DARCH_X86_64=1' + if host_system == 'windows' + asm_outformat = 'win64' + elif ['darwin', 'ios'].contains(host_system) + asm_outformat = 'macho64' + elif host_system.endswith('bsd') + asm_outformat = 'aoutb' + else + asm_outformat = 'elf64' + endif + asm_x = files('x86/yadif.asm') + + asm_stackalign_def = '-DSTACK_ALIGNMENT=64' + asm_incdir = 'x86' + + message('Nasm configured on x86-64') + asm_gen = generator(nasm, + output: outputname, + arguments: ['-I@CURRENT_SOURCE_DIR@', + '-I@CURRENT_SOURCE_DIR@/@0@/'.format(asm_incdir), + asm_arch_def, + asm_stackalign_def, + asm_pic_def, + asm_prefix_def, + '-f', asm_outformat, + '-o', '@OUTPUT@', + '@INPUT@']) + asm_gen_objs = asm_gen.process(asm_x) +endif + gstdeinterlace = library('gstdeinterlace', - interlace_sources, orc_c, orc_h, + interlace_sources, asm_gen_objs, orc_c, orc_h, c_args : gst_plugins_good_args, include_directories : [configinc], dependencies : [orc_dep, gstbase_dep, gstvideo_dep], diff --git a/gst/deinterlace/tvtime/greedy.c b/gst/deinterlace/tvtime/greedy.c index 804ce8b4f4..5a01cc6f3c 100644 --- a/gst/deinterlace/tvtime/greedy.c +++ b/gst/deinterlace/tvtime/greedy.c @@ -203,6 +203,10 @@ gst_deinterlace_method_greedy_l_class_init (GstDeinterlaceMethodGreedyLClass * deinterlace_greedy_interpolate_scanline_orc; dism_class->interpolate_scanline_uyvy = deinterlace_greedy_interpolate_scanline_orc; + dism_class->interpolate_scanline_nv12 = + deinterlace_greedy_interpolate_scanline_orc; + dism_class->interpolate_scanline_nv21 = + deinterlace_greedy_interpolate_scanline_orc; dism_class->interpolate_scanline_argb = deinterlace_greedy_interpolate_scanline_orc; dism_class->interpolate_scanline_abgr = diff --git a/gst/deinterlace/x86/x86inc.asm b/gst/deinterlace/x86/x86inc.asm new file mode 100644 index 0000000000..7404bfed36 --- /dev/null +++ b/gst/deinterlace/x86/x86inc.asm @@ -0,0 +1,1701 @@ +;***************************************************************************** +;* x86inc.asm: x264asm abstraction layer +;***************************************************************************** +;* Copyright (C) 2005-2018 x264 project +;* +;* Authors: Loren Merritt +;* Henrik Gramner +;* Anton Mitrofanov +;* Fiona Glaser +;* +;* Permission to use, copy, modify, and/or distribute this software for any +;* purpose with or without fee is hereby granted, provided that the above +;* copyright notice and this permission notice appear in all copies. +;* +;* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +;* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +;* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +;* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +;* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +;* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +;* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +;***************************************************************************** + +; This is a header file for the x264ASM assembly language, which uses +; NASM/YASM syntax combined with a large number of macros to provide easy +; abstraction between different calling conventions (x86_32, win64, linux64). +; It also has various other useful features to simplify writing the kind of +; DSP functions that are most often used in x264. + +; Unlike the rest of x264, this file is available under an ISC license, as it +; has significant usefulness outside of x264 and we want it to be available +; to the largest audience possible. Of course, if you modify it for your own +; purposes to add a new feature, we strongly encourage contributing a patch +; as this feature might be useful for others as well. Send patches or ideas +; to x264-devel@videolan.org . + +%ifndef private_prefix + %define private_prefix gst +%endif + +%ifndef public_prefix + %define public_prefix private_prefix +%endif + +%ifndef STACK_ALIGNMENT + %if ARCH_X86_64 + %define STACK_ALIGNMENT 16 + %else + %define STACK_ALIGNMENT 4 + %endif +%endif + +%define WIN64 0 +%define UNIX64 0 +%if ARCH_X86_64 + %ifidn __OUTPUT_FORMAT__,win32 + %define WIN64 1 + %elifidn __OUTPUT_FORMAT__,win64 + %define WIN64 1 + %elifidn __OUTPUT_FORMAT__,x64 + %define WIN64 1 + %else + %define UNIX64 1 + %endif +%endif + +; Only 1 for yasm. Workaround here. +%define HAVE_CPUNOP 0 + +%define FORMAT_ELF 0 +%ifidn __OUTPUT_FORMAT__,elf + %define FORMAT_ELF 1 +%elifidn __OUTPUT_FORMAT__,elf32 + %define FORMAT_ELF 1 +%elifidn __OUTPUT_FORMAT__,elf64 + %define FORMAT_ELF 1 +%endif + +%ifdef PREFIX + %define mangle(x) _ %+ x +%else + %define mangle(x) x +%endif + +; aout does not support align= +; NOTE: This section is out of sync with x264, in order to +; keep supporting OS/2. +%macro SECTION_RODATA 0-1 16 + %ifidn __OUTPUT_FORMAT__,aout + SECTION .text + %elifidn __OUTPUT_FORMAT__,coff + SECTION .text + %elifidn __OUTPUT_FORMAT__,win32 + SECTION .rdata align=%1 + %elif WIN64 + SECTION .rdata align=%1 + %else + SECTION .rodata align=%1 + %endif +%endmacro + +%if WIN64 + %define PIC +%elif ARCH_X86_64 == 0 +; x86_32 doesn't require PIC. +; Some distros prefer shared objects to be PIC, but nothing breaks if +; the code contains a few textrels, so we'll skip that complexity. + %undef PIC +%endif +%ifdef PIC + default rel +%endif + +%macro CPUNOP 1 + %if HAVE_CPUNOP + CPU %1 + %endif +%endmacro + +; Macros to eliminate most code duplication between x86_32 and x86_64: +; Currently this works only for leaf functions which load all their arguments +; into registers at the start, and make no other use of the stack. Luckily that +; covers most of x264's asm. + +; PROLOGUE: +; %1 = number of arguments. loads them from stack if needed. +; %2 = number of registers used. pushes callee-saved regs if needed. +; %3 = number of xmm registers used. pushes callee-saved xmm regs if needed. +; %4 = (optional) stack size to be allocated. The stack will be aligned before +; allocating the specified stack size. If the required stack alignment is +; larger than the known stack alignment the stack will be manually aligned +; and an extra register will be allocated to hold the original stack +; pointer (to not invalidate r0m etc.). To prevent the use of an extra +; register as stack pointer, request a negative stack size. +; %4+/%5+ = list of names to define to registers +; PROLOGUE can also be invoked by adding the same options to cglobal + +; e.g. +; cglobal foo, 2,3,7,0x40, dst, src, tmp +; declares a function (foo) that automatically loads two arguments (dst and +; src) into registers, uses one additional register (tmp) plus 7 vector +; registers (m0-m6) and allocates 0x40 bytes of stack space. + +; TODO Some functions can use some args directly from the stack. If they're the +; last args then you can just not declare them, but if they're in the middle +; we need more flexible macro. + +; RET: +; Pops anything that was pushed by PROLOGUE, and returns. + +; REP_RET: +; Use this instead of RET if it's a branch target. + +; registers: +; rN and rNq are the native-size register holding function argument N +; rNd, rNw, rNb are dword, word, and byte size +; rNh is the high 8 bits of the word size +; rNm is the original location of arg N (a register or on the stack), dword +; rNmp is native size + +%macro DECLARE_REG 2-3 + %define r%1q %2 + %define r%1d %2d + %define r%1w %2w + %define r%1b %2b + %define r%1h %2h + %define %2q %2 + %if %0 == 2 + %define r%1m %2d + %define r%1mp %2 + %elif ARCH_X86_64 ; memory + %define r%1m [rstk + stack_offset + %3] + %define r%1mp qword r %+ %1 %+ m + %else + %define r%1m [rstk + stack_offset + %3] + %define r%1mp dword r %+ %1 %+ m + %endif + %define r%1 %2 +%endmacro + +%macro DECLARE_REG_SIZE 3 + %define r%1q r%1 + %define e%1q r%1 + %define r%1d e%1 + %define e%1d e%1 + %define r%1w %1 + %define e%1w %1 + %define r%1h %3 + %define e%1h %3 + %define r%1b %2 + %define e%1b %2 + %if ARCH_X86_64 == 0 + %define r%1 e%1 + %endif +%endmacro + +DECLARE_REG_SIZE ax, al, ah +DECLARE_REG_SIZE bx, bl, bh +DECLARE_REG_SIZE cx, cl, ch +DECLARE_REG_SIZE dx, dl, dh +DECLARE_REG_SIZE si, sil, null +DECLARE_REG_SIZE di, dil, null +DECLARE_REG_SIZE bp, bpl, null + +; t# defines for when per-arch register allocation is more complex than just function arguments + +%macro DECLARE_REG_TMP 1-* + %assign %%i 0 + %rep %0 + CAT_XDEFINE t, %%i, r%1 + %assign %%i %%i+1 + %rotate 1 + %endrep +%endmacro + +%macro DECLARE_REG_TMP_SIZE 0-* + %rep %0 + %define t%1q t%1 %+ q + %define t%1d t%1 %+ d + %define t%1w t%1 %+ w + %define t%1h t%1 %+ h + %define t%1b t%1 %+ b + %rotate 1 + %endrep +%endmacro + +DECLARE_REG_TMP_SIZE 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 + +%if ARCH_X86_64 + %define gprsize 8 +%else + %define gprsize 4 +%endif + +%macro PUSH 1 + push %1 + %ifidn rstk, rsp + %assign stack_offset stack_offset+gprsize + %endif +%endmacro + +%macro POP 1 + pop %1 + %ifidn rstk, rsp + %assign stack_offset stack_offset-gprsize + %endif +%endmacro + +%macro PUSH_IF_USED 1-* + %rep %0 + %if %1 < regs_used + PUSH r%1 + %endif + %rotate 1 + %endrep +%endmacro + +%macro POP_IF_USED 1-* + %rep %0 + %if %1 < regs_used + pop r%1 + %endif + %rotate 1 + %endrep +%endmacro + +%macro LOAD_IF_USED 1-* + %rep %0 + %if %1 < num_args + mov r%1, r %+ %1 %+ mp + %endif + %rotate 1 + %endrep +%endmacro + +%macro SUB 2 + sub %1, %2 + %ifidn %1, rstk + %assign stack_offset stack_offset+(%2) + %endif +%endmacro + +%macro ADD 2 + add %1, %2 + %ifidn %1, rstk + %assign stack_offset stack_offset-(%2) + %endif +%endmacro + +%macro movifnidn 2 + %ifnidn %1, %2 + mov %1, %2 + %endif +%endmacro + +%macro movsxdifnidn 2 + %ifnidn %1, %2 + movsxd %1, %2 + %endif +%endmacro + +%macro ASSERT 1 + %if (%1) == 0 + %error assertion ``%1'' failed + %endif +%endmacro + +%macro DEFINE_ARGS 0-* + %ifdef n_arg_names + %assign %%i 0 + %rep n_arg_names + CAT_UNDEF arg_name %+ %%i, q + CAT_UNDEF arg_name %+ %%i, d + CAT_UNDEF arg_name %+ %%i, w + CAT_UNDEF arg_name %+ %%i, h + CAT_UNDEF arg_name %+ %%i, b + CAT_UNDEF arg_name %+ %%i, m + CAT_UNDEF arg_name %+ %%i, mp + CAT_UNDEF arg_name, %%i + %assign %%i %%i+1 + %endrep + %endif + + %xdefine %%stack_offset stack_offset + %undef stack_offset ; so that the current value of stack_offset doesn't get baked in by xdefine + %assign %%i 0 + %rep %0 + %xdefine %1q r %+ %%i %+ q + %xdefine %1d r %+ %%i %+ d + %xdefine %1w r %+ %%i %+ w + %xdefine %1h r %+ %%i %+ h + %xdefine %1b r %+ %%i %+ b + %xdefine %1m r %+ %%i %+ m + %xdefine %1mp r %+ %%i %+ mp + CAT_XDEFINE arg_name, %%i, %1 + %assign %%i %%i+1 + %rotate 1 + %endrep + %xdefine stack_offset %%stack_offset + %assign n_arg_names %0 +%endmacro + +%define required_stack_alignment ((mmsize + 15) & ~15) +%define vzeroupper_required (mmsize > 16 && (ARCH_X86_64 == 0 || xmm_regs_used > 16 || notcpuflag(avx512))) +%define high_mm_regs (16*cpuflag(avx512)) + +%macro ALLOC_STACK 1-2 0 ; stack_size, n_xmm_regs (for win64 only) + %ifnum %1 + %if %1 != 0 + %assign %%pad 0 + %assign stack_size %1 + %if stack_size < 0 + %assign stack_size -stack_size + %endif + %if WIN64 + %assign %%pad %%pad + 32 ; shadow space + %if mmsize != 8 + %assign xmm_regs_used %2 + %if xmm_regs_used > 8 + %assign %%pad %%pad + (xmm_regs_used-8)*16 ; callee-saved xmm registers + %endif + %endif + %endif + %if required_stack_alignment <= STACK_ALIGNMENT + ; maintain the current stack alignment + %assign stack_size_padded stack_size + %%pad + ((-%%pad-stack_offset-gprsize) & (STACK_ALIGNMENT-1)) + SUB rsp, stack_size_padded + %else + %assign %%reg_num (regs_used - 1) + %xdefine rstk r %+ %%reg_num + ; align stack, and save original stack location directly above + ; it, i.e. in [rsp+stack_size_padded], so we can restore the + ; stack in a single instruction (i.e. mov rsp, rstk or mov + ; rsp, [rsp+stack_size_padded]) + %if %1 < 0 ; need to store rsp on stack + %xdefine rstkm [rsp + stack_size + %%pad] + %assign %%pad %%pad + gprsize + %else ; can keep rsp in rstk during whole function + %xdefine rstkm rstk + %endif + %assign stack_size_padded stack_size + ((%%pad + required_stack_alignment-1) & ~(required_stack_alignment-1)) + mov rstk, rsp + and rsp, ~(required_stack_alignment-1) + sub rsp, stack_size_padded + movifnidn rstkm, rstk + %endif + WIN64_PUSH_XMM + %endif + %endif +%endmacro + +%macro SETUP_STACK_POINTER 1 + %ifnum %1 + %if %1 != 0 && required_stack_alignment > STACK_ALIGNMENT + %if %1 > 0 + ; Reserve an additional register for storing the original stack pointer, but avoid using + ; eax/rax for this purpose since it can potentially get overwritten as a return value. + %assign regs_used (regs_used + 1) + %if ARCH_X86_64 && regs_used == 7 + %assign regs_used 8 + %elif ARCH_X86_64 == 0 && regs_used == 1 + %assign regs_used 2 + %endif + %endif + %if ARCH_X86_64 && regs_used < 5 + UNIX64 * 3 + ; Ensure that we don't clobber any registers containing arguments. For UNIX64 we also preserve r6 (rax) + ; since it's used as a hidden argument in vararg functions to specify the number of vector registers used. + %assign regs_used 5 + UNIX64 * 3 + %endif + %endif + %endif +%endmacro + +%macro DEFINE_ARGS_INTERNAL 3+ + %ifnum %2 + DEFINE_ARGS %3 + %elif %1 == 4 + DEFINE_ARGS %2 + %elif %1 > 4 + DEFINE_ARGS %2, %3 + %endif +%endmacro + +%if WIN64 ; Windows x64 ;================================================= + +DECLARE_REG 0, rcx +DECLARE_REG 1, rdx +DECLARE_REG 2, R8 +DECLARE_REG 3, R9 +DECLARE_REG 4, R10, 40 +DECLARE_REG 5, R11, 48 +DECLARE_REG 6, rax, 56 +DECLARE_REG 7, rdi, 64 +DECLARE_REG 8, rsi, 72 +DECLARE_REG 9, rbx, 80 +DECLARE_REG 10, rbp, 88 +DECLARE_REG 11, R14, 96 +DECLARE_REG 12, R15, 104 +DECLARE_REG 13, R12, 112 +DECLARE_REG 14, R13, 120 + +%macro PROLOGUE 2-5+ 0 ; #args, #regs, #xmm_regs, [stack_size,] arg_names... + %assign num_args %1 + %assign regs_used %2 + ASSERT regs_used >= num_args + SETUP_STACK_POINTER %4 + ASSERT regs_used <= 15 + PUSH_IF_USED 7, 8, 9, 10, 11, 12, 13, 14 + ALLOC_STACK %4, %3 + %if mmsize != 8 && stack_size == 0 + WIN64_SPILL_XMM %3 + %endif + LOAD_IF_USED 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 + DEFINE_ARGS_INTERNAL %0, %4, %5 +%endmacro + +%macro WIN64_PUSH_XMM 0 + ; Use the shadow space to store XMM6 and XMM7, the rest needs stack space allocated. + %if xmm_regs_used > 6 + high_mm_regs + movaps [rstk + stack_offset + 8], xmm6 + %endif + %if xmm_regs_used > 7 + high_mm_regs + movaps [rstk + stack_offset + 24], xmm7 + %endif + %assign %%xmm_regs_on_stack xmm_regs_used - high_mm_regs - 8 + %if %%xmm_regs_on_stack > 0 + %assign %%i 8 + %rep %%xmm_regs_on_stack + movaps [rsp + (%%i-8)*16 + stack_size + 32], xmm %+ %%i + %assign %%i %%i+1 + %endrep + %endif +%endmacro + +%macro WIN64_SPILL_XMM 1 + %assign xmm_regs_used %1 + ASSERT xmm_regs_used <= 16 + high_mm_regs + %assign %%xmm_regs_on_stack xmm_regs_used - high_mm_regs - 8 + %if %%xmm_regs_on_stack > 0 + ; Allocate stack space for callee-saved xmm registers plus shadow space and align the stack. + %assign %%pad %%xmm_regs_on_stack*16 + 32 + %assign stack_size_padded %%pad + ((-%%pad-stack_offset-gprsize) & (STACK_ALIGNMENT-1)) + SUB rsp, stack_size_padded + %endif + WIN64_PUSH_XMM +%endmacro + +%macro WIN64_RESTORE_XMM_INTERNAL 0 + %assign %%pad_size 0 + %assign %%xmm_regs_on_stack xmm_regs_used - high_mm_regs - 8 + %if %%xmm_regs_on_stack > 0 + %assign %%i xmm_regs_used - high_mm_regs + %rep %%xmm_regs_on_stack + %assign %%i %%i-1 + movaps xmm %+ %%i, [rsp + (%%i-8)*16 + stack_size + 32] + %endrep + %endif + %if stack_size_padded > 0 + %if stack_size > 0 && required_stack_alignment > STACK_ALIGNMENT + mov rsp, rstkm + %else + add rsp, stack_size_padded + %assign %%pad_size stack_size_padded + %endif + %endif + %if xmm_regs_used > 7 + high_mm_regs + movaps xmm7, [rsp + stack_offset - %%pad_size + 24] + %endif + %if xmm_regs_used > 6 + high_mm_regs + movaps xmm6, [rsp + stack_offset - %%pad_size + 8] + %endif +%endmacro + +%macro WIN64_RESTORE_XMM 0 + WIN64_RESTORE_XMM_INTERNAL + %assign stack_offset (stack_offset-stack_size_padded) + %assign stack_size_padded 0 + %assign xmm_regs_used 0 +%endmacro + +%define has_epilogue regs_used > 7 || stack_size > 0 || vzeroupper_required || xmm_regs_used > 6+high_mm_regs + +%macro RET 0 + WIN64_RESTORE_XMM_INTERNAL + POP_IF_USED 14, 13, 12, 11, 10, 9, 8, 7 + %if vzeroupper_required + vzeroupper + %endif + AUTO_REP_RET +%endmacro + +%elif ARCH_X86_64 ; *nix x64 ;============================================= + +DECLARE_REG 0, rdi +DECLARE_REG 1, rsi +DECLARE_REG 2, rdx +DECLARE_REG 3, rcx +DECLARE_REG 4, R8 +DECLARE_REG 5, R9 +DECLARE_REG 6, rax, 8 +DECLARE_REG 7, R10, 16 +DECLARE_REG 8, R11, 24 +DECLARE_REG 9, rbx, 32 +DECLARE_REG 10, rbp, 40 +DECLARE_REG 11, R14, 48 +DECLARE_REG 12, R15, 56 +DECLARE_REG 13, R12, 64 +DECLARE_REG 14, R13, 72 + +%macro PROLOGUE 2-5+ 0 ; #args, #regs, #xmm_regs, [stack_size,] arg_names... + %assign num_args %1 + %assign regs_used %2 + %assign xmm_regs_used %3 + ASSERT regs_used >= num_args + SETUP_STACK_POINTER %4 + ASSERT regs_used <= 15 + PUSH_IF_USED 9, 10, 11, 12, 13, 14 + ALLOC_STACK %4 + LOAD_IF_USED 6, 7, 8, 9, 10, 11, 12, 13, 14 + DEFINE_ARGS_INTERNAL %0, %4, %5 +%endmacro + +%define has_epilogue regs_used > 9 || stack_size > 0 || vzeroupper_required + +%macro RET 0 + %if stack_size_padded > 0 + %if required_stack_alignment > STACK_ALIGNMENT + mov rsp, rstkm + %else + add rsp, stack_size_padded + %endif + %endif + POP_IF_USED 14, 13, 12, 11, 10, 9 + %if vzeroupper_required + vzeroupper + %endif + AUTO_REP_RET +%endmacro + +%else ; X86_32 ;============================================================== + +DECLARE_REG 0, eax, 4 +DECLARE_REG 1, ecx, 8 +DECLARE_REG 2, edx, 12 +DECLARE_REG 3, ebx, 16 +DECLARE_REG 4, esi, 20 +DECLARE_REG 5, edi, 24 +DECLARE_REG 6, ebp, 28 +%define rsp esp + +%macro DECLARE_ARG 1-* + %rep %0 + %define r%1m [rstk + stack_offset + 4*%1 + 4] + %define r%1mp dword r%1m + %rotate 1 + %endrep +%endmacro + +DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14 + +%macro PROLOGUE 2-5+ ; #args, #regs, #xmm_regs, [stack_size,] arg_names... + %assign num_args %1 + %assign regs_used %2 + ASSERT regs_used >= num_args + %if num_args > 7 + %assign num_args 7 + %endif + %if regs_used > 7 + %assign regs_used 7 + %endif + SETUP_STACK_POINTER %4 + ASSERT regs_used <= 7 + PUSH_IF_USED 3, 4, 5, 6 + ALLOC_STACK %4 + LOAD_IF_USED 0, 1, 2, 3, 4, 5, 6 + DEFINE_ARGS_INTERNAL %0, %4, %5 +%endmacro + +%define has_epilogue regs_used > 3 || stack_size > 0 || vzeroupper_required + +%macro RET 0 + %if stack_size_padded > 0 + %if required_stack_alignment > STACK_ALIGNMENT + mov rsp, rstkm + %else + add rsp, stack_size_padded + %endif + %endif + POP_IF_USED 6, 5, 4, 3 + %if vzeroupper_required + vzeroupper + %endif + AUTO_REP_RET +%endmacro + +%endif ;====================================================================== + +%if WIN64 == 0 + %macro WIN64_SPILL_XMM 1 + %endmacro + %macro WIN64_RESTORE_XMM 0 + %endmacro + %macro WIN64_PUSH_XMM 0 + %endmacro +%endif + +; On AMD cpus <=K10, an ordinary ret is slow if it immediately follows either +; a branch or a branch target. So switch to a 2-byte form of ret in that case. +; We can automatically detect "follows a branch", but not a branch target. +; (SSSE3 is a sufficient condition to know that your cpu doesn't have this problem.) +%macro REP_RET 0 + %if has_epilogue || cpuflag(ssse3) + RET + %else + rep ret + %endif + annotate_function_size +%endmacro + +%define last_branch_adr $$ +%macro AUTO_REP_RET 0 + %if notcpuflag(ssse3) + times ((last_branch_adr-$)>>31)+1 rep ; times 1 iff $ == last_branch_adr. + %endif + ret + annotate_function_size +%endmacro + +%macro BRANCH_INSTR 0-* + %rep %0 + %macro %1 1-2 %1 + %2 %1 + %if notcpuflag(ssse3) + %%branch_instr equ $ + %xdefine last_branch_adr %%branch_instr + %endif + %endmacro + %rotate 1 + %endrep +%endmacro + +BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, jna, jnae, jb, jbe, jnb, jnbe, jc, jnc, js, jns, jo, jno, jp, jnp + +%macro TAIL_CALL 2 ; callee, is_nonadjacent + %if has_epilogue + call %1 + RET + %elif %2 + jmp %1 + %endif + annotate_function_size +%endmacro + +;============================================================================= +; arch-independent part +;============================================================================= + +%assign function_align 16 + +; Begin a function. +; Applies any symbol mangling needed for C linkage, and sets up a define such that +; subsequent uses of the function name automatically refer to the mangled version. +; Appends cpuflags to the function name if cpuflags has been specified. +; The "" empty default parameter is a workaround for nasm, which fails if SUFFIX +; is empty and we call cglobal_internal with just %1 %+ SUFFIX (without %2). +%macro cglobal 1-2+ "" ; name, [PROLOGUE args] + cglobal_internal 1, %1 %+ SUFFIX, %2 +%endmacro +%macro cvisible 1-2+ "" ; name, [PROLOGUE args] + cglobal_internal 0, %1 %+ SUFFIX, %2 +%endmacro +%macro cglobal_internal 2-3+ + annotate_function_size + %if %1 + %xdefine %%FUNCTION_PREFIX private_prefix + %xdefine %%VISIBILITY hidden + %else + %xdefine %%FUNCTION_PREFIX public_prefix + %xdefine %%VISIBILITY + %endif + %ifndef cglobaled_%2 + %xdefine %2 mangle(%%FUNCTION_PREFIX %+ _ %+ %2) + %xdefine %2.skip_prologue %2 %+ .skip_prologue + CAT_XDEFINE cglobaled_, %2, 1 + %endif + %xdefine current_function %2 + %xdefine current_function_section __SECT__ + %if FORMAT_ELF + global %2:function %%VISIBILITY + %else + global %2 + %endif + align function_align + %2: + RESET_MM_PERMUTATION ; needed for x86-64, also makes disassembly somewhat nicer + %xdefine rstk rsp ; copy of the original stack pointer, used when greater alignment than the known stack alignment is required + %assign stack_offset 0 ; stack pointer offset relative to the return address + %assign stack_size 0 ; amount of stack space that can be freely used inside a function + %assign stack_size_padded 0 ; total amount of allocated stack space, including space for callee-saved xmm registers on WIN64 and alignment padding + %assign xmm_regs_used 0 ; number of XMM registers requested, used for dealing with callee-saved registers on WIN64 and vzeroupper + %ifnidn %3, "" + PROLOGUE %3 + %endif +%endmacro + +; Create a global symbol from a local label with the correct name mangling and type +%macro cglobal_label 1 + %if FORMAT_ELF + global current_function %+ %1:function hidden + %else + global current_function %+ %1 + %endif + %1: +%endmacro + +%macro cextern 1 + %xdefine %1 mangle(private_prefix %+ _ %+ %1) + CAT_XDEFINE cglobaled_, %1, 1 + extern %1 +%endmacro + +; like cextern, but without the prefix +%macro cextern_naked 1 + %ifdef PREFIX + %xdefine %1 mangle(%1) + %endif + CAT_XDEFINE cglobaled_, %1, 1 + extern %1 +%endmacro + +%macro const 1-2+ + %xdefine %1 mangle(private_prefix %+ _ %+ %1) + %if FORMAT_ELF + global %1:data hidden + %else + global %1 + %endif + %1: %2 +%endmacro + +; This is needed for ELF, otherwise the GNU linker assumes the stack is executable by default. +%if FORMAT_ELF + [SECTION .note.GNU-stack noalloc noexec nowrite progbits] +%endif + +; Tell debuggers how large the function was. +; This may be invoked multiple times per function; we rely on later instances overriding earlier ones. +; This is invoked by RET and similar macros, and also cglobal does it for the previous function, +; but if the last function in a source file doesn't use any of the standard macros for its epilogue, +; then its size might be unspecified. +%macro annotate_function_size 0 + %ifdef __YASM_VER__ + %ifdef current_function + %if FORMAT_ELF + current_function_section + %%ecf equ $ + size current_function %%ecf - current_function + __SECT__ + %endif + %endif + %endif +%endmacro + +; cpuflags + +%assign cpuflags_mmx (1<<0) +%assign cpuflags_mmx2 (1<<1) | cpuflags_mmx +%assign cpuflags_3dnow (1<<2) | cpuflags_mmx +%assign cpuflags_3dnowext (1<<3) | cpuflags_3dnow +%assign cpuflags_sse (1<<4) | cpuflags_mmx2 +%assign cpuflags_sse2 (1<<5) | cpuflags_sse +%assign cpuflags_sse2slow (1<<6) | cpuflags_sse2 +%assign cpuflags_lzcnt (1<<7) | cpuflags_sse2 +%assign cpuflags_sse3 (1<<8) | cpuflags_sse2 +%assign cpuflags_ssse3 (1<<9) | cpuflags_sse3 +%assign cpuflags_sse4 (1<<10)| cpuflags_ssse3 +%assign cpuflags_sse42 (1<<11)| cpuflags_sse4 +%assign cpuflags_aesni (1<<12)| cpuflags_sse42 +%assign cpuflags_avx (1<<13)| cpuflags_sse42 +%assign cpuflags_xop (1<<14)| cpuflags_avx +%assign cpuflags_fma4 (1<<15)| cpuflags_avx +%assign cpuflags_fma3 (1<<16)| cpuflags_avx +%assign cpuflags_bmi1 (1<<17)| cpuflags_avx|cpuflags_lzcnt +%assign cpuflags_bmi2 (1<<18)| cpuflags_bmi1 +%assign cpuflags_avx2 (1<<19)| cpuflags_fma3|cpuflags_bmi2 +%assign cpuflags_avx512 (1<<20)| cpuflags_avx2 ; F, CD, BW, DQ, VL + +%assign cpuflags_cache32 (1<<21) +%assign cpuflags_cache64 (1<<22) +%assign cpuflags_aligned (1<<23) ; not a cpu feature, but a function variant +%assign cpuflags_atom (1<<24) + +; Returns a boolean value expressing whether or not the specified cpuflag is enabled. +%define cpuflag(x) (((((cpuflags & (cpuflags_ %+ x)) ^ (cpuflags_ %+ x)) - 1) >> 31) & 1) +%define notcpuflag(x) (cpuflag(x) ^ 1) + +; Takes an arbitrary number of cpuflags from the above list. +; All subsequent functions (up to the next INIT_CPUFLAGS) is built for the specified cpu. +; You shouldn't need to invoke this macro directly, it's a subroutine for INIT_MMX &co. +%macro INIT_CPUFLAGS 0-* + %xdefine SUFFIX + %undef cpuname + %assign cpuflags 0 + + %if %0 >= 1 + %rep %0 + %ifdef cpuname + %xdefine cpuname cpuname %+ _%1 + %else + %xdefine cpuname %1 + %endif + %assign cpuflags cpuflags | cpuflags_%1 + %rotate 1 + %endrep + %xdefine SUFFIX _ %+ cpuname + + %if cpuflag(avx) + %assign avx_enabled 1 + %endif + %if (mmsize == 16 && notcpuflag(sse2)) || (mmsize == 32 && notcpuflag(avx2)) + %define mova movaps + %define movu movups + %define movnta movntps + %endif + %if cpuflag(aligned) + %define movu mova + %elif cpuflag(sse3) && notcpuflag(ssse3) + %define movu lddqu + %endif + %endif + + %if ARCH_X86_64 || cpuflag(sse2) + CPUNOP amdnop + %else + CPUNOP basicnop + %endif +%endmacro + +; Merge mmx, sse*, and avx* +; m# is a simd register of the currently selected size +; xm# is the corresponding xmm register if mmsize >= 16, otherwise the same as m# +; ym# is the corresponding ymm register if mmsize >= 32, otherwise the same as m# +; zm# is the corresponding zmm register if mmsize >= 64, otherwise the same as m# +; (All 4 remain in sync through SWAP.) + +%macro CAT_XDEFINE 3 + %xdefine %1%2 %3 +%endmacro + +%macro CAT_UNDEF 2 + %undef %1%2 +%endmacro + +%macro DEFINE_MMREGS 1 ; mmtype + %assign %%prev_mmregs 0 + %ifdef num_mmregs + %assign %%prev_mmregs num_mmregs + %endif + + %assign num_mmregs 8 + %if ARCH_X86_64 && mmsize >= 16 + %assign num_mmregs 16 + %if cpuflag(avx512) || mmsize == 64 + %assign num_mmregs 32 + %endif + %endif + + %assign %%i 0 + %rep num_mmregs + CAT_XDEFINE m, %%i, %1 %+ %%i + CAT_XDEFINE nn%1, %%i, %%i + %assign %%i %%i+1 + %endrep + %if %%prev_mmregs > num_mmregs + %rep %%prev_mmregs - num_mmregs + CAT_UNDEF m, %%i + CAT_UNDEF nn %+ mmtype, %%i + %assign %%i %%i+1 + %endrep + %endif + %xdefine mmtype %1 +%endmacro + +; Prefer registers 16-31 over 0-15 to avoid having to use vzeroupper +%macro AVX512_MM_PERMUTATION 0-1 0 ; start_reg + %if ARCH_X86_64 && cpuflag(avx512) + %assign %%i %1 + %rep 16-%1 + %assign %%i_high %%i+16 + SWAP %%i, %%i_high + %assign %%i %%i+1 + %endrep + %endif +%endmacro + +%macro INIT_MMX 0-1+ + %assign avx_enabled 0 + %define RESET_MM_PERMUTATION INIT_MMX %1 + %define mmsize 8 + %define mova movq + %define movu movq + %define movh movd + %define movnta movntq + INIT_CPUFLAGS %1 + DEFINE_MMREGS mm +%endmacro + +%macro INIT_XMM 0-1+ + %assign avx_enabled 0 + %define RESET_MM_PERMUTATION INIT_XMM %1 + %define mmsize 16 + %define mova movdqa + %define movu movdqu + %define movh movq + %define movnta movntdq + INIT_CPUFLAGS %1 + DEFINE_MMREGS xmm + %if WIN64 + AVX512_MM_PERMUTATION 6 ; Swap callee-saved registers with volatile registers + %endif +%endmacro + +%macro INIT_YMM 0-1+ + %assign avx_enabled 1 + %define RESET_MM_PERMUTATION INIT_YMM %1 + %define mmsize 32 + %define mova movdqa + %define movu movdqu + %undef movh + %define movnta movntdq + INIT_CPUFLAGS %1 + DEFINE_MMREGS ymm + AVX512_MM_PERMUTATION +%endmacro + +%macro INIT_ZMM 0-1+ + %assign avx_enabled 1 + %define RESET_MM_PERMUTATION INIT_ZMM %1 + %define mmsize 64 + %define mova movdqa + %define movu movdqu + %undef movh + %define movnta movntdq + INIT_CPUFLAGS %1 + DEFINE_MMREGS zmm + AVX512_MM_PERMUTATION +%endmacro + +INIT_XMM + +%macro DECLARE_MMCAST 1 + %define mmmm%1 mm%1 + %define mmxmm%1 mm%1 + %define mmymm%1 mm%1 + %define mmzmm%1 mm%1 + %define xmmmm%1 mm%1 + %define xmmxmm%1 xmm%1 + %define xmmymm%1 xmm%1 + %define xmmzmm%1 xmm%1 + %define ymmmm%1 mm%1 + %define ymmxmm%1 xmm%1 + %define ymmymm%1 ymm%1 + %define ymmzmm%1 ymm%1 + %define zmmmm%1 mm%1 + %define zmmxmm%1 xmm%1 + %define zmmymm%1 ymm%1 + %define zmmzmm%1 zmm%1 + %define xm%1 xmm %+ m%1 + %define ym%1 ymm %+ m%1 + %define zm%1 zmm %+ m%1 +%endmacro + +%assign i 0 +%rep 32 + DECLARE_MMCAST i + %assign i i+1 +%endrep + +; I often want to use macros that permute their arguments. e.g. there's no +; efficient way to implement butterfly or transpose or dct without swapping some +; arguments. +; +; I would like to not have to manually keep track of the permutations: +; If I insert a permutation in the middle of a function, it should automatically +; change everything that follows. For more complex macros I may also have multiple +; implementations, e.g. the SSE2 and SSSE3 versions may have different permutations. +; +; Hence these macros. Insert a PERMUTE or some SWAPs at the end of a macro that +; permutes its arguments. It's equivalent to exchanging the contents of the +; registers, except that this way you exchange the register names instead, so it +; doesn't cost any cycles. + +%macro PERMUTE 2-* ; takes a list of pairs to swap + %rep %0/2 + %xdefine %%tmp%2 m%2 + %rotate 2 + %endrep + %rep %0/2 + %xdefine m%1 %%tmp%2 + CAT_XDEFINE nn, m%1, %1 + %rotate 2 + %endrep +%endmacro + +%macro SWAP 2+ ; swaps a single chain (sometimes more concise than pairs) + %ifnum %1 ; SWAP 0, 1, ... + SWAP_INTERNAL_NUM %1, %2 + %else ; SWAP m0, m1, ... + SWAP_INTERNAL_NAME %1, %2 + %endif +%endmacro + +%macro SWAP_INTERNAL_NUM 2-* + %rep %0-1 + %xdefine %%tmp m%1 + %xdefine m%1 m%2 + %xdefine m%2 %%tmp + CAT_XDEFINE nn, m%1, %1 + CAT_XDEFINE nn, m%2, %2 + %rotate 1 + %endrep +%endmacro + +%macro SWAP_INTERNAL_NAME 2-* + %xdefine %%args nn %+ %1 + %rep %0-1 + %xdefine %%args %%args, nn %+ %2 + %rotate 1 + %endrep + SWAP_INTERNAL_NUM %%args +%endmacro + +; If SAVE_MM_PERMUTATION is placed at the end of a function, then any later +; calls to that function will automatically load the permutation, so values can +; be returned in mmregs. +%macro SAVE_MM_PERMUTATION 0-1 + %if %0 + %xdefine %%f %1_m + %else + %xdefine %%f current_function %+ _m + %endif + %assign %%i 0 + %rep num_mmregs + CAT_XDEFINE %%f, %%i, m %+ %%i + %assign %%i %%i+1 + %endrep +%endmacro + +%macro LOAD_MM_PERMUTATION 1 ; name to load from + %ifdef %1_m0 + %assign %%i 0 + %rep num_mmregs + CAT_XDEFINE m, %%i, %1_m %+ %%i + CAT_XDEFINE nn, m %+ %%i, %%i + %assign %%i %%i+1 + %endrep + %endif +%endmacro + +; Append cpuflags to the callee's name iff the appended name is known and the plain name isn't +%macro call 1 + %ifid %1 + call_internal %1 %+ SUFFIX, %1 + %else + call %1 + %endif +%endmacro +%macro call_internal 2 + %xdefine %%i %2 + %ifndef cglobaled_%2 + %ifdef cglobaled_%1 + %xdefine %%i %1 + %endif + %endif + call %%i + LOAD_MM_PERMUTATION %%i +%endmacro + +; Substitutions that reduce instruction size but are functionally equivalent +%macro add 2 + %ifnum %2 + %if %2==128 + sub %1, -128 + %else + add %1, %2 + %endif + %else + add %1, %2 + %endif +%endmacro + +%macro sub 2 + %ifnum %2 + %if %2==128 + add %1, -128 + %else + sub %1, %2 + %endif + %else + sub %1, %2 + %endif +%endmacro + +;============================================================================= +; AVX abstraction layer +;============================================================================= + +%assign i 0 +%rep 32 + %if i < 8 + CAT_XDEFINE sizeofmm, i, 8 + CAT_XDEFINE regnumofmm, i, i + %endif + CAT_XDEFINE sizeofxmm, i, 16 + CAT_XDEFINE sizeofymm, i, 32 + CAT_XDEFINE sizeofzmm, i, 64 + CAT_XDEFINE regnumofxmm, i, i + CAT_XDEFINE regnumofymm, i, i + CAT_XDEFINE regnumofzmm, i, i + %assign i i+1 +%endrep +%undef i + +%macro CHECK_AVX_INSTR_EMU 3-* + %xdefine %%opcode %1 + %xdefine %%dst %2 + %rep %0-2 + %ifidn %%dst, %3 + %error non-avx emulation of ``%%opcode'' is not supported + %endif + %rotate 1 + %endrep +%endmacro + +;%1 == instruction +;%2 == minimal instruction set +;%3 == 1 if float, 0 if int +;%4 == 1 if 4-operand emulation, 0 if 3-operand emulation, 255 otherwise (no emulation) +;%5 == 1 if commutative (i.e. doesn't matter which src arg is which), 0 if not +;%6+: operands +%macro RUN_AVX_INSTR 6-9+ + %ifnum sizeof%7 + %assign __sizeofreg sizeof%7 + %elifnum sizeof%6 + %assign __sizeofreg sizeof%6 + %else + %assign __sizeofreg mmsize + %endif + %assign __emulate_avx 0 + %if avx_enabled && __sizeofreg >= 16 + %xdefine __instr v%1 + %else + %xdefine __instr %1 + %if %0 >= 8+%4 + %assign __emulate_avx 1 + %endif + %endif + %ifnidn %2, fnord + %ifdef cpuname + %if notcpuflag(%2) + %error use of ``%1'' %2 instruction in cpuname function: current_function + %elif cpuflags_%2 < cpuflags_sse && notcpuflag(sse2) && __sizeofreg > 8 + %error use of ``%1'' sse2 instruction in cpuname function: current_function + %endif + %endif + %endif + + %if __emulate_avx + %xdefine __src1 %7 + %xdefine __src2 %8 + %if %5 && %4 == 0 + %ifnidn %6, %7 + %ifidn %6, %8 + %xdefine __src1 %8 + %xdefine __src2 %7 + %elifnnum sizeof%8 + ; 3-operand AVX instructions with a memory arg can only have it in src2, + ; whereas SSE emulation prefers to have it in src1 (i.e. the mov). + ; So, if the instruction is commutative with a memory arg, swap them. + %xdefine __src1 %8 + %xdefine __src2 %7 + %endif + %endif + %endif + %ifnidn %6, __src1 + %if %0 >= 9 + CHECK_AVX_INSTR_EMU {%1 %6, %7, %8, %9}, %6, __src2, %9 + %else + CHECK_AVX_INSTR_EMU {%1 %6, %7, %8}, %6, __src2 + %endif + %if __sizeofreg == 8 + MOVQ %6, __src1 + %elif %3 + MOVAPS %6, __src1 + %else + MOVDQA %6, __src1 + %endif + %endif + %if %0 >= 9 + %1 %6, __src2, %9 + %else + %1 %6, __src2 + %endif + %elif %0 >= 9 + __instr %6, %7, %8, %9 + %elif %0 == 8 + __instr %6, %7, %8 + %elif %0 == 7 + __instr %6, %7 + %else + __instr %6 + %endif +%endmacro + +;%1 == instruction +;%2 == minimal instruction set +;%3 == 1 if float, 0 if int +;%4 == 1 if 4-operand emulation, 0 if 3-operand emulation, 255 otherwise (no emulation) +;%5 == 1 if commutative (i.e. doesn't matter which src arg is which), 0 if not +%macro AVX_INSTR 1-5 fnord, 0, 255, 0 + %macro %1 1-10 fnord, fnord, fnord, fnord, %1, %2, %3, %4, %5 + %ifidn %2, fnord + RUN_AVX_INSTR %6, %7, %8, %9, %10, %1 + %elifidn %3, fnord + RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2 + %elifidn %4, fnord + RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2, %3 + %elifidn %5, fnord + RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2, %3, %4 + %else + RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2, %3, %4, %5 + %endif + %endmacro +%endmacro + +; Instructions with both VEX/EVEX and legacy encodings +; Non-destructive instructions are written without parameters +AVX_INSTR addpd, sse2, 1, 0, 1 +AVX_INSTR addps, sse, 1, 0, 1 +AVX_INSTR addsd, sse2, 1, 0, 0 +AVX_INSTR addss, sse, 1, 0, 0 +AVX_INSTR addsubpd, sse3, 1, 0, 0 +AVX_INSTR addsubps, sse3, 1, 0, 0 +AVX_INSTR aesdec, aesni, 0, 0, 0 +AVX_INSTR aesdeclast, aesni, 0, 0, 0 +AVX_INSTR aesenc, aesni, 0, 0, 0 +AVX_INSTR aesenclast, aesni, 0, 0, 0 +AVX_INSTR aesimc, aesni +AVX_INSTR aeskeygenassist, aesni +AVX_INSTR andnpd, sse2, 1, 0, 0 +AVX_INSTR andnps, sse, 1, 0, 0 +AVX_INSTR andpd, sse2, 1, 0, 1 +AVX_INSTR andps, sse, 1, 0, 1 +AVX_INSTR blendpd, sse4, 1, 1, 0 +AVX_INSTR blendps, sse4, 1, 1, 0 +AVX_INSTR blendvpd, sse4 ; can't be emulated +AVX_INSTR blendvps, sse4 ; can't be emulated +AVX_INSTR cmpeqpd, sse2, 1, 0, 1 +AVX_INSTR cmpeqps, sse, 1, 0, 1 +AVX_INSTR cmpeqsd, sse2, 1, 0, 0 +AVX_INSTR cmpeqss, sse, 1, 0, 0 +AVX_INSTR cmplepd, sse2, 1, 0, 0 +AVX_INSTR cmpleps, sse, 1, 0, 0 +AVX_INSTR cmplesd, sse2, 1, 0, 0 +AVX_INSTR cmpless, sse, 1, 0, 0 +AVX_INSTR cmpltpd, sse2, 1, 0, 0 +AVX_INSTR cmpltps, sse, 1, 0, 0 +AVX_INSTR cmpltsd, sse2, 1, 0, 0 +AVX_INSTR cmpltss, sse, 1, 0, 0 +AVX_INSTR cmpneqpd, sse2, 1, 0, 1 +AVX_INSTR cmpneqps, sse, 1, 0, 1 +AVX_INSTR cmpneqsd, sse2, 1, 0, 0 +AVX_INSTR cmpneqss, sse, 1, 0, 0 +AVX_INSTR cmpnlepd, sse2, 1, 0, 0 +AVX_INSTR cmpnleps, sse, 1, 0, 0 +AVX_INSTR cmpnlesd, sse2, 1, 0, 0 +AVX_INSTR cmpnless, sse, 1, 0, 0 +AVX_INSTR cmpnltpd, sse2, 1, 0, 0 +AVX_INSTR cmpnltps, sse, 1, 0, 0 +AVX_INSTR cmpnltsd, sse2, 1, 0, 0 +AVX_INSTR cmpnltss, sse, 1, 0, 0 +AVX_INSTR cmpordpd, sse2 1, 0, 1 +AVX_INSTR cmpordps, sse 1, 0, 1 +AVX_INSTR cmpordsd, sse2 1, 0, 0 +AVX_INSTR cmpordss, sse 1, 0, 0 +AVX_INSTR cmppd, sse2, 1, 1, 0 +AVX_INSTR cmpps, sse, 1, 1, 0 +AVX_INSTR cmpsd, sse2, 1, 1, 0 +AVX_INSTR cmpss, sse, 1, 1, 0 +AVX_INSTR cmpunordpd, sse2, 1, 0, 1 +AVX_INSTR cmpunordps, sse, 1, 0, 1 +AVX_INSTR cmpunordsd, sse2, 1, 0, 0 +AVX_INSTR cmpunordss, sse, 1, 0, 0 +AVX_INSTR comisd, sse2 +AVX_INSTR comiss, sse +AVX_INSTR cvtdq2pd, sse2 +AVX_INSTR cvtdq2ps, sse2 +AVX_INSTR cvtpd2dq, sse2 +AVX_INSTR cvtpd2ps, sse2 +AVX_INSTR cvtps2dq, sse2 +AVX_INSTR cvtps2pd, sse2 +AVX_INSTR cvtsd2si, sse2 +AVX_INSTR cvtsd2ss, sse2, 1, 0, 0 +AVX_INSTR cvtsi2sd, sse2, 1, 0, 0 +AVX_INSTR cvtsi2ss, sse, 1, 0, 0 +AVX_INSTR cvtss2sd, sse2, 1, 0, 0 +AVX_INSTR cvtss2si, sse +AVX_INSTR cvttpd2dq, sse2 +AVX_INSTR cvttps2dq, sse2 +AVX_INSTR cvttsd2si, sse2 +AVX_INSTR cvttss2si, sse +AVX_INSTR divpd, sse2, 1, 0, 0 +AVX_INSTR divps, sse, 1, 0, 0 +AVX_INSTR divsd, sse2, 1, 0, 0 +AVX_INSTR divss, sse, 1, 0, 0 +AVX_INSTR dppd, sse4, 1, 1, 0 +AVX_INSTR dpps, sse4, 1, 1, 0 +AVX_INSTR extractps, sse4 +AVX_INSTR haddpd, sse3, 1, 0, 0 +AVX_INSTR haddps, sse3, 1, 0, 0 +AVX_INSTR hsubpd, sse3, 1, 0, 0 +AVX_INSTR hsubps, sse3, 1, 0, 0 +AVX_INSTR insertps, sse4, 1, 1, 0 +AVX_INSTR lddqu, sse3 +AVX_INSTR ldmxcsr, sse +AVX_INSTR maskmovdqu, sse2 +AVX_INSTR maxpd, sse2, 1, 0, 1 +AVX_INSTR maxps, sse, 1, 0, 1 +AVX_INSTR maxsd, sse2, 1, 0, 0 +AVX_INSTR maxss, sse, 1, 0, 0 +AVX_INSTR minpd, sse2, 1, 0, 1 +AVX_INSTR minps, sse, 1, 0, 1 +AVX_INSTR minsd, sse2, 1, 0, 0 +AVX_INSTR minss, sse, 1, 0, 0 +AVX_INSTR movapd, sse2 +AVX_INSTR movaps, sse +AVX_INSTR movd, mmx +AVX_INSTR movddup, sse3 +AVX_INSTR movdqa, sse2 +AVX_INSTR movdqu, sse2 +AVX_INSTR movhlps, sse, 1, 0, 0 +AVX_INSTR movhpd, sse2, 1, 0, 0 +AVX_INSTR movhps, sse, 1, 0, 0 +AVX_INSTR movlhps, sse, 1, 0, 0 +AVX_INSTR movlpd, sse2, 1, 0, 0 +AVX_INSTR movlps, sse, 1, 0, 0 +AVX_INSTR movmskpd, sse2 +AVX_INSTR movmskps, sse +AVX_INSTR movntdq, sse2 +AVX_INSTR movntdqa, sse4 +AVX_INSTR movntpd, sse2 +AVX_INSTR movntps, sse +AVX_INSTR movq, mmx +AVX_INSTR movsd, sse2, 1, 0, 0 +AVX_INSTR movshdup, sse3 +AVX_INSTR movsldup, sse3 +AVX_INSTR movss, sse, 1, 0, 0 +AVX_INSTR movupd, sse2 +AVX_INSTR movups, sse +AVX_INSTR mpsadbw, sse4, 0, 1, 0 +AVX_INSTR mulpd, sse2, 1, 0, 1 +AVX_INSTR mulps, sse, 1, 0, 1 +AVX_INSTR mulsd, sse2, 1, 0, 0 +AVX_INSTR mulss, sse, 1, 0, 0 +AVX_INSTR orpd, sse2, 1, 0, 1 +AVX_INSTR orps, sse, 1, 0, 1 +AVX_INSTR pabsb, ssse3 +AVX_INSTR pabsd, ssse3 +AVX_INSTR pabsw, ssse3 +AVX_INSTR packsswb, mmx, 0, 0, 0 +AVX_INSTR packssdw, mmx, 0, 0, 0 +AVX_INSTR packuswb, mmx, 0, 0, 0 +AVX_INSTR packusdw, sse4, 0, 0, 0 +AVX_INSTR paddb, mmx, 0, 0, 1 +AVX_INSTR paddw, mmx, 0, 0, 1 +AVX_INSTR paddd, mmx, 0, 0, 1 +AVX_INSTR paddq, sse2, 0, 0, 1 +AVX_INSTR paddsb, mmx, 0, 0, 1 +AVX_INSTR paddsw, mmx, 0, 0, 1 +AVX_INSTR paddusb, mmx, 0, 0, 1 +AVX_INSTR paddusw, mmx, 0, 0, 1 +AVX_INSTR palignr, ssse3, 0, 1, 0 +AVX_INSTR pand, mmx, 0, 0, 1 +AVX_INSTR pandn, mmx, 0, 0, 0 +AVX_INSTR pavgb, mmx2, 0, 0, 1 +AVX_INSTR pavgw, mmx2, 0, 0, 1 +AVX_INSTR pblendvb, sse4 ; can't be emulated +AVX_INSTR pblendw, sse4, 0, 1, 0 +AVX_INSTR pclmulqdq, fnord, 0, 1, 0 +AVX_INSTR pclmulhqhqdq, fnord, 0, 0, 0 +AVX_INSTR pclmulhqlqdq, fnord, 0, 0, 0 +AVX_INSTR pclmullqhqdq, fnord, 0, 0, 0 +AVX_INSTR pclmullqlqdq, fnord, 0, 0, 0 +AVX_INSTR pcmpestri, sse42 +AVX_INSTR pcmpestrm, sse42 +AVX_INSTR pcmpistri, sse42 +AVX_INSTR pcmpistrm, sse42 +AVX_INSTR pcmpeqb, mmx, 0, 0, 1 +AVX_INSTR pcmpeqw, mmx, 0, 0, 1 +AVX_INSTR pcmpeqd, mmx, 0, 0, 1 +AVX_INSTR pcmpeqq, sse4, 0, 0, 1 +AVX_INSTR pcmpgtb, mmx, 0, 0, 0 +AVX_INSTR pcmpgtw, mmx, 0, 0, 0 +AVX_INSTR pcmpgtd, mmx, 0, 0, 0 +AVX_INSTR pcmpgtq, sse42, 0, 0, 0 +AVX_INSTR pextrb, sse4 +AVX_INSTR pextrd, sse4 +AVX_INSTR pextrq, sse4 +AVX_INSTR pextrw, mmx2 +AVX_INSTR phaddw, ssse3, 0, 0, 0 +AVX_INSTR phaddd, ssse3, 0, 0, 0 +AVX_INSTR phaddsw, ssse3, 0, 0, 0 +AVX_INSTR phminposuw, sse4 +AVX_INSTR phsubw, ssse3, 0, 0, 0 +AVX_INSTR phsubd, ssse3, 0, 0, 0 +AVX_INSTR phsubsw, ssse3, 0, 0, 0 +AVX_INSTR pinsrb, sse4, 0, 1, 0 +AVX_INSTR pinsrd, sse4, 0, 1, 0 +AVX_INSTR pinsrq, sse4, 0, 1, 0 +AVX_INSTR pinsrw, mmx2, 0, 1, 0 +AVX_INSTR pmaddwd, mmx, 0, 0, 1 +AVX_INSTR pmaddubsw, ssse3, 0, 0, 0 +AVX_INSTR pmaxsb, sse4, 0, 0, 1 +AVX_INSTR pmaxsw, mmx2, 0, 0, 1 +AVX_INSTR pmaxsd, sse4, 0, 0, 1 +AVX_INSTR pmaxub, mmx2, 0, 0, 1 +AVX_INSTR pmaxuw, sse4, 0, 0, 1 +AVX_INSTR pmaxud, sse4, 0, 0, 1 +AVX_INSTR pminsb, sse4, 0, 0, 1 +AVX_INSTR pminsw, mmx2, 0, 0, 1 +AVX_INSTR pminsd, sse4, 0, 0, 1 +AVX_INSTR pminub, mmx2, 0, 0, 1 +AVX_INSTR pminuw, sse4, 0, 0, 1 +AVX_INSTR pminud, sse4, 0, 0, 1 +AVX_INSTR pmovmskb, mmx2 +AVX_INSTR pmovsxbw, sse4 +AVX_INSTR pmovsxbd, sse4 +AVX_INSTR pmovsxbq, sse4 +AVX_INSTR pmovsxwd, sse4 +AVX_INSTR pmovsxwq, sse4 +AVX_INSTR pmovsxdq, sse4 +AVX_INSTR pmovzxbw, sse4 +AVX_INSTR pmovzxbd, sse4 +AVX_INSTR pmovzxbq, sse4 +AVX_INSTR pmovzxwd, sse4 +AVX_INSTR pmovzxwq, sse4 +AVX_INSTR pmovzxdq, sse4 +AVX_INSTR pmuldq, sse4, 0, 0, 1 +AVX_INSTR pmulhrsw, ssse3, 0, 0, 1 +AVX_INSTR pmulhuw, mmx2, 0, 0, 1 +AVX_INSTR pmulhw, mmx, 0, 0, 1 +AVX_INSTR pmullw, mmx, 0, 0, 1 +AVX_INSTR pmulld, sse4, 0, 0, 1 +AVX_INSTR pmuludq, sse2, 0, 0, 1 +AVX_INSTR por, mmx, 0, 0, 1 +AVX_INSTR psadbw, mmx2, 0, 0, 1 +AVX_INSTR pshufb, ssse3, 0, 0, 0 +AVX_INSTR pshufd, sse2 +AVX_INSTR pshufhw, sse2 +AVX_INSTR pshuflw, sse2 +AVX_INSTR psignb, ssse3, 0, 0, 0 +AVX_INSTR psignw, ssse3, 0, 0, 0 +AVX_INSTR psignd, ssse3, 0, 0, 0 +AVX_INSTR psllw, mmx, 0, 0, 0 +AVX_INSTR pslld, mmx, 0, 0, 0 +AVX_INSTR psllq, mmx, 0, 0, 0 +AVX_INSTR pslldq, sse2, 0, 0, 0 +AVX_INSTR psraw, mmx, 0, 0, 0 +AVX_INSTR psrad, mmx, 0, 0, 0 +AVX_INSTR psrlw, mmx, 0, 0, 0 +AVX_INSTR psrld, mmx, 0, 0, 0 +AVX_INSTR psrlq, mmx, 0, 0, 0 +AVX_INSTR psrldq, sse2, 0, 0, 0 +AVX_INSTR psubb, mmx, 0, 0, 0 +AVX_INSTR psubw, mmx, 0, 0, 0 +AVX_INSTR psubd, mmx, 0, 0, 0 +AVX_INSTR psubq, sse2, 0, 0, 0 +AVX_INSTR psubsb, mmx, 0, 0, 0 +AVX_INSTR psubsw, mmx, 0, 0, 0 +AVX_INSTR psubusb, mmx, 0, 0, 0 +AVX_INSTR psubusw, mmx, 0, 0, 0 +AVX_INSTR ptest, sse4 +AVX_INSTR punpckhbw, mmx, 0, 0, 0 +AVX_INSTR punpckhwd, mmx, 0, 0, 0 +AVX_INSTR punpckhdq, mmx, 0, 0, 0 +AVX_INSTR punpckhqdq, sse2, 0, 0, 0 +AVX_INSTR punpcklbw, mmx, 0, 0, 0 +AVX_INSTR punpcklwd, mmx, 0, 0, 0 +AVX_INSTR punpckldq, mmx, 0, 0, 0 +AVX_INSTR punpcklqdq, sse2, 0, 0, 0 +AVX_INSTR pxor, mmx, 0, 0, 1 +AVX_INSTR rcpps, sse +AVX_INSTR rcpss, sse, 1, 0, 0 +AVX_INSTR roundpd, sse4 +AVX_INSTR roundps, sse4 +AVX_INSTR roundsd, sse4, 1, 1, 0 +AVX_INSTR roundss, sse4, 1, 1, 0 +AVX_INSTR rsqrtps, sse +AVX_INSTR rsqrtss, sse, 1, 0, 0 +AVX_INSTR shufpd, sse2, 1, 1, 0 +AVX_INSTR shufps, sse, 1, 1, 0 +AVX_INSTR sqrtpd, sse2 +AVX_INSTR sqrtps, sse +AVX_INSTR sqrtsd, sse2, 1, 0, 0 +AVX_INSTR sqrtss, sse, 1, 0, 0 +AVX_INSTR stmxcsr, sse +AVX_INSTR subpd, sse2, 1, 0, 0 +AVX_INSTR subps, sse, 1, 0, 0 +AVX_INSTR subsd, sse2, 1, 0, 0 +AVX_INSTR subss, sse, 1, 0, 0 +AVX_INSTR ucomisd, sse2 +AVX_INSTR ucomiss, sse +AVX_INSTR unpckhpd, sse2, 1, 0, 0 +AVX_INSTR unpckhps, sse, 1, 0, 0 +AVX_INSTR unpcklpd, sse2, 1, 0, 0 +AVX_INSTR unpcklps, sse, 1, 0, 0 +AVX_INSTR xorpd, sse2, 1, 0, 1 +AVX_INSTR xorps, sse, 1, 0, 1 + +; 3DNow instructions, for sharing code between AVX, SSE and 3DN +AVX_INSTR pfadd, 3dnow, 1, 0, 1 +AVX_INSTR pfsub, 3dnow, 1, 0, 0 +AVX_INSTR pfmul, 3dnow, 1, 0, 1 + +; base-4 constants for shuffles +%assign i 0 +%rep 256 + %assign j ((i>>6)&3)*1000 + ((i>>4)&3)*100 + ((i>>2)&3)*10 + (i&3) + %if j < 10 + CAT_XDEFINE q000, j, i + %elif j < 100 + CAT_XDEFINE q00, j, i + %elif j < 1000 + CAT_XDEFINE q0, j, i + %else + CAT_XDEFINE q, j, i + %endif + %assign i i+1 +%endrep +%undef i +%undef j + +%macro FMA_INSTR 3 + %macro %1 4-7 %1, %2, %3 + %if cpuflag(xop) + v%5 %1, %2, %3, %4 + %elifnidn %1, %4 + %6 %1, %2, %3 + %7 %1, %4 + %else + %error non-xop emulation of ``%5 %1, %2, %3, %4'' is not supported + %endif + %endmacro +%endmacro + +FMA_INSTR pmacsww, pmullw, paddw +FMA_INSTR pmacsdd, pmulld, paddd ; sse4 emulation +FMA_INSTR pmacsdql, pmuldq, paddq ; sse4 emulation +FMA_INSTR pmadcswd, pmaddwd, paddd + +; tzcnt is equivalent to "rep bsf" and is backwards-compatible with bsf. +; This lets us use tzcnt without bumping the yasm version requirement yet. +%define tzcnt rep bsf + +; Macros for consolidating FMA3 and FMA4 using 4-operand (dst, src1, src2, src3) syntax. +; FMA3 is only possible if dst is the same as one of the src registers. +; Either src2 or src3 can be a memory operand. +%macro FMA4_INSTR 2-* + %push fma4_instr + %xdefine %$prefix %1 + %rep %0 - 1 + %macro %$prefix%2 4-6 %$prefix, %2 + %if notcpuflag(fma3) && notcpuflag(fma4) + %error use of ``%5%6'' fma instruction in cpuname function: current_function + %elif cpuflag(fma4) + v%5%6 %1, %2, %3, %4 + %elifidn %1, %2 + ; If %3 or %4 is a memory operand it needs to be encoded as the last operand. + %ifnum sizeof%3 + v%{5}213%6 %2, %3, %4 + %else + v%{5}132%6 %2, %4, %3 + %endif + %elifidn %1, %3 + v%{5}213%6 %3, %2, %4 + %elifidn %1, %4 + v%{5}231%6 %4, %2, %3 + %else + %error fma3 emulation of ``%5%6 %1, %2, %3, %4'' is not supported + %endif + %endmacro + %rotate 1 + %endrep + %pop +%endmacro + +FMA4_INSTR fmadd, pd, ps, sd, ss +FMA4_INSTR fmaddsub, pd, ps +FMA4_INSTR fmsub, pd, ps, sd, ss +FMA4_INSTR fmsubadd, pd, ps +FMA4_INSTR fnmadd, pd, ps, sd, ss +FMA4_INSTR fnmsub, pd, ps, sd, ss + +; Macros for converting VEX instructions to equivalent EVEX ones. +%macro EVEX_INSTR 2-3 0 ; vex, evex, prefer_evex + %macro %1 2-7 fnord, fnord, %1, %2, %3 + %ifidn %3, fnord + %define %%args %1, %2 + %elifidn %4, fnord + %define %%args %1, %2, %3 + %else + %define %%args %1, %2, %3, %4 + %endif + %assign %%evex_required cpuflag(avx512) & %7 + %ifnum regnumof%1 + %if regnumof%1 >= 16 || sizeof%1 > 32 + %assign %%evex_required 1 + %endif + %endif + %ifnum regnumof%2 + %if regnumof%2 >= 16 || sizeof%2 > 32 + %assign %%evex_required 1 + %endif + %endif + %if %%evex_required + %6 %%args + %else + %5 %%args ; Prefer VEX over EVEX due to shorter instruction length + %endif + %endmacro +%endmacro + +EVEX_INSTR vbroadcastf128, vbroadcastf32x4 +EVEX_INSTR vbroadcasti128, vbroadcasti32x4 +EVEX_INSTR vextractf128, vextractf32x4 +EVEX_INSTR vextracti128, vextracti32x4 +EVEX_INSTR vinsertf128, vinsertf32x4 +EVEX_INSTR vinserti128, vinserti32x4 +EVEX_INSTR vmovdqa, vmovdqa32 +EVEX_INSTR vmovdqu, vmovdqu32 +EVEX_INSTR vpand, vpandd +EVEX_INSTR vpandn, vpandnd +EVEX_INSTR vpor, vpord +EVEX_INSTR vpxor, vpxord +EVEX_INSTR vrcpps, vrcp14ps, 1 ; EVEX versions have higher precision +EVEX_INSTR vrcpss, vrcp14ss, 1 +EVEX_INSTR vrsqrtps, vrsqrt14ps, 1 +EVEX_INSTR vrsqrtss, vrsqrt14ss, 1 + +; workaround: vpbroadcastq is broken in x86_32 due to a yasm bug (fixed in 1.3.0) +%ifdef __YASM_VER__ + %if __YASM_VERSION_ID__ < 0x01030000 && ARCH_X86_64 == 0 + %macro vpbroadcastq 2 + %if sizeof%1 == 16 + movddup %1, %2 + %else + vbroadcastsd %1, %2 + %endif + %endmacro + %endif +%endif diff --git a/gst/deinterlace/x86/yadif.asm b/gst/deinterlace/x86/yadif.asm new file mode 100644 index 0000000000..08734bd395 --- /dev/null +++ b/gst/deinterlace/x86/yadif.asm @@ -0,0 +1,410 @@ +;***************************************************************************** +;* x86-optimized functions for yadif filter +;* Copyright (C) 2020 Vivia Nikolaidou +;* +;* Based on libav's vf_yadif.asm file +;* Copyright (C) 2006 Michael Niedermayer +;* Copyright (c) 2013 Daniel Kang +;* +;* 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 "x86inc.asm" + +SECTION_RODATA + +; 16 bytes of value 1 +pb_1: times 16 db 1 +; 8 words of value 1 +pw_1: times 8 dw 1 + +SECTION .text + +%macro ABS1 2 +%if cpuflag(ssse3) + pabsw %1, %1 +%elif cpuflag(mmxext) ; a, tmp + pxor %2, %2 + psubw %2, %1 + pmaxsw %1, %2 +%else ; a, tmp + pxor %2, %2 + pcmpgtw %2, %1 + pxor %1, %2 + psubw %1, %2 +%endif +%endmacro + +%macro CHECK 2 +; %1 = 1+j, %2 = 1-j + ; m2 = t0[x+1+j] + movu m2, [tzeroq+%1] + ; m3 = b0[x+1-j] + movu m3, [bzeroq+%2] + ; m4 = t0[x+1+j] + mova m4, m2 + ; m5 = t0[x+1+j] + mova m5, m2 + ; m4 = xor(t0[x+1+j], b0[x+1-j] + pxor m4, m3 + pavgb m5, m3 + ; round down to 0 + pand m4, [pb_1] + ; m5 = rounded down average of the whole thing + psubusb m5, m4 + ; shift by 1 quadword to prepare for spatial_pred + psrldq m5, 1 + ; m7 = 0 + ; Interleave low-order bytes with 0 + ; so one pixel doesn't spill into the next one + punpcklbw m5, m7 + ; m4 = t0[x+1+j] (reset) + mova m4, m2 + ; m2 = t0[x+1+j] - b0[x+1-j] + psubusb m2, m3 + ; m3 = -m2 + psubusb m3, m4 + ; m2 = FFABS(t0[x+1+j] - b0[x+1-j]); + pmaxub m2, m3 + ; m3 = FFABS(t0[x+1+j] - b0[x+1-j]); + mova m3, m2 + ; m4 = FFABS(FFABS(t0[x+1+j] - b0[x+1-j]); + mova m4, m2 + ; m3 = FFABS(t0[x+j] - b0[x-j]) + psrldq m3, 1 + ; m4 = FFABS(t0[x-1+j] - b0[x-1-j]) + psrldq m4, 2 + ; prevent pixel spilling for all of them + punpcklbw m2, m7 + punpcklbw m3, m7 + punpcklbw m4, m7 + paddw m2, m3 + ; m2 = score + paddw m2, m4 +%endmacro + +%macro CHECK1 0 +; m0 was spatial_score +; m1 was spatial_pred + mova m3, m0 + ; compare for greater than + ; each word will be 1111 or 0000 + pcmpgtw m3, m2 + ; if (score < spatial_score) spatial_score = score; + pminsw m0, m2 + ; m6 = the mask + mova m6, m3 + ; m5 = becomes 0 if it should change + pand m5, m3 + ; nand: m3 = becomes 0 if it should not change + pandn m3, m1 + ; m3 = put them together in an OR + por m3, m5 + ; and put it in spatial_pred + mova m1, m3 +%endmacro + +%macro CHECK2 0 +; m6 was the mask from CHECK1 (we don't change it) + paddw m6, [pw_1] + ; shift words left while shifting in 14 0s (16 - j) + ; essentially to not recalculate the mask! + psllw m6, 14 + ; add it to score + paddsw m2, m6 + ; same as CHECK1 + mova m3, m0 + pcmpgtw m3, m2 + pminsw m0, m2 + pand m5, m3 + pandn m3, m1 + por m3, m5 + mova m1, m3 +%endmacro + +%macro LOAD 2 + movh %1, %2 + punpcklbw %1, m7 +%endmacro + +%macro FILTER_HEAD 0 + ; m7 = 0 + pxor m7, m7 + ; m0 = c + LOAD m0, [tzeroq] + ; m1 = e + LOAD m1, [bzeroq] + ; m3 = mp + LOAD m3, [mpq] + ; m2 = m1 + LOAD m2, [moneq] + ; m4 = mp + mova m4, m3 + ; m3 = m1 + mp + paddw m3, m2 + ; m3 = d + psraw m3, 1 + ; rsp + 0 = d + mova [rsp+ 0], m3 + ; m2 = m1 - mp + psubw m2, m4 + ; m2 = temporal_diff0 (m4 is temporary) + ABS1 m2, m4 + ; m3 = t2 + LOAD m3, [ttwoq] + ; m4 = b2 + LOAD m4, [btwoq] + ; m3 = t2 - c + psubw m3, m0 + ; m4 = b2 - e + psubw m4, m1 + ; m3 = ABS(t2 - c) + ABS1 m3, m5 + ; m4 = ABS(b2 - e) + ABS1 m4, m5 + paddw m3, m4 + psrlw m2, 1 + ; m3 = temporal_diff1 + psrlw m3, 1 + ; m2 = left part of diff + pmaxsw m2, m3 + ; m3 = tp2 + LOAD m3, [tptwoq] + ; m4 = bp2 + LOAD m4, [bptwoq] + psubw m3, m0 + psubw m4, m1 + ABS1 m3, m5 + ABS1 m4, m5 + paddw m3, m4 + ; m3 = temporal_diff2 + psrlw m3, 1 + ; m2 = diff (for real) + pmaxsw m2, m3 + ; rsp + 16 = diff + mova [rsp+16], m2 + + ; m1 = e + c + paddw m1, m0 + ; m0 = 2c + paddw m0, m0 + ; m0 = c - e + psubw m0, m1 + ; m1 = spatial_pred + psrlw m1, 1 + ; m0 = FFABS(c-e) + ABS1 m0, m2 + + ; m2 = t0[x-1] + ; if it's unpacked it should contain 4 bytes + movu m2, [tzeroq-1] + ; m3 = b0[x-1] + movu m3, [bzeroq-1] + ; m4 = t0[x-1] + mova m4, m2 + ; m2 = t0[x-1]-b0[x-1] unsigned packed + psubusb m2, m3 + ; m3 = m3 - m4 = b0[x-1]-t0[x-1] = -m2 unsigned packed + psubusb m3, m4 + ; m2 = max(m2, -m2) = abs(t0[x-1]-b0[x-1]) + pmaxub m2, m3 +%if mmsize == 16 + ; m3 = m2 >> 2quadwords + ; pixel jump: go from x-1 to x+1 + mova m3, m2 + psrldq m3, 2 +%else + pshufw m3, m2, q0021 +%endif + ; m7 = 0 + ; unpack and interleave low-order bytes + ; to prevent pixel spilling when adding + punpcklbw m2, m7 + punpcklbw m3, m7 + paddw m0, m2 + paddw m0, m3 + ; m0 = spatial_score + psubw m0, [pw_1] + + CHECK -2, 0 + CHECK1 + CHECK -3, 1 + CHECK2 + CHECK 0, -2 + CHECK1 + CHECK 1, -3 + CHECK2 + ; now m0 = spatial_score, m1 = spatial_pred + + ; m6 = diff + mova m6, [rsp+16] +%endmacro + +%macro FILTER_TAIL 0 + ; m2 = d + mova m2, [rsp] + ; m3 = d + mova m3, m2 + ; m2 = d - diff + psubw m2, m6 + ; m3 = d + diff + paddw m3, m6 + ; m1 = max(spatial_pred, d-diff) + pmaxsw m1, m2 + ; m1 = min(d + diff, max(spatial_pred, d-diff)) + ; m1 = spatial_pred + pminsw m1, m3 + ; Converts 8 signed word integers into 16 unsigned byte integers with saturation + packuswb m1, m1 + + ; dst = spatial_pred + movh [dstq], m1 + ; half the register size + add dstq, mmsize/2 + add tzeroq, mmsize/2 + add bzeroq, mmsize/2 + add moneq, mmsize/2 + add mpq, mmsize/2 + add ttwoq, mmsize/2 + add btwoq, mmsize/2 + add tptwoq, mmsize/2 + add bptwoq, mmsize/2 + add ttoneq, mmsize/2 + add ttpq, mmsize/2 + add bboneq, mmsize/2 + add bbpq, mmsize/2 +%endmacro + +%macro FILTER_MODE0 0 +.loop0: + FILTER_HEAD + ; m2 = tt1 + LOAD m2, [ttoneq] + ; m4 = ttp + LOAD m4, [ttpq] + ; m3 = bb1 + LOAD m3, [bboneq] + ; m5 = bbp + LOAD m5, [bbpq] + paddw m2, m4 + paddw m3, m5 + ; m2 = b + psrlw m2, 1 + ; m3 = f + psrlw m3, 1 + ; m4 = c + LOAD m4, [tzeroq] + ; m5 = d + mova m5, [rsp] + ; m7 = e + LOAD m7, [bzeroq] + ; m2 = b - c + psubw m2, m4 + ; m3 = f - e + psubw m3, m7 + ; m0 = d + mova m0, m5 + ; m5 = d - c + psubw m5, m4 + ; m0 = d - e + psubw m0, m7 + ; m4 = b - c + mova m4, m2 + ; m2 = FFMIN(b-c, f-e) + pminsw m2, m3 + ; m3 = FFMAX(f-e, b-c) + pmaxsw m3, m4 + ; m2 = FFMAX(d-c, FFMIN(b-c, f-e)) + pmaxsw m2, m5 + ; m3 = FFMIN(d-c, FFMAX(f-e, b-c)) + pminsw m3, m5 + ; m2 = max + pmaxsw m2, m0 + ; m3 = min + pminsw m3, m0 + ; m4 = 0 + pxor m4, m4 + ; m6 = MAX(diff, min) + pmaxsw m6, m3 + ; m4 = -max + psubw m4, m2 + ; m6 = diff + pmaxsw m6, m4 + + FILTER_TAIL + ; r13m = w + sub DWORD r13m, mmsize/2 + jg .loop0 +%endmacro + +%macro FILTER_MODE2 0 +.loop2: + FILTER_HEAD + FILTER_TAIL + ; r13m = w + sub DWORD r13m, mmsize/2 + jg .loop2 +%endmacro + +%macro YADIF_ADD3 0 + ; start 3 pixels later + add dstq, 3 + add tzeroq, 3 + add bzeroq, 3 + add moneq, 3 + add mpq, 3 + add ttwoq, 3 + add btwoq, 3 + add tptwoq, 3 + add bptwoq, 3 + add ttoneq, 3 + add ttpq, 3 + add bboneq, 3 + add bbpq, 3 +%endmacro + +; cglobal foo, 2,3,7,0x40, dst, src, tmp +; declares a function (foo) that automatically loads two arguments (dst and +; src) into registers, uses one additional register (tmp) plus 7 vector +; registers (m0-m6) and allocates 0x40 bytes of stack space. +%macro YADIF_MODE0 0 +cglobal yadif_filter_line_mode0, 13, 14, 8, 80, dst, tzero, bzero, mone, mp, \ + ttwo, btwo, tptwo, bptwo, ttone, \ + ttp, bbone, bbp, w + + YADIF_ADD3 + FILTER_MODE0 + RET +%endmacro + +%macro YADIF_MODE2 0 +cglobal yadif_filter_line_mode2, 13, 14, 8, 80, dst, tzero, bzero, mone, mp, \ + ttwo, btwo, tptwo, bptwo, ttone, \ + ttp, bbone, bbp, w + + YADIF_ADD3 + FILTER_MODE2 + RET +%endmacro + +; declares two functions for ssse3, and two for sse2 +INIT_XMM ssse3 +YADIF_MODE0 +YADIF_MODE2 +INIT_XMM sse2 +YADIF_MODE0 +YADIF_MODE2 diff --git a/gst/deinterlace/yadif.c b/gst/deinterlace/yadif.c new file mode 100644 index 0000000000..3692e157a3 --- /dev/null +++ b/gst/deinterlace/yadif.c @@ -0,0 +1,486 @@ +/* + * GStreamer + * Copyright (C) 2019 Jan Schmidt + * + * Portions of this file extracted from libav + * Copyright (C) 2006 Michael Niedermayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include +#ifdef HAVE_ORC +#include +#include +#endif +#include "gstdeinterlacemethod.h" +#include "yadif.h" + +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) || defined(__clang__) +#define ALWAYS_INLINE __attribute__((always_inline)) inline +#elif defined(_MSC_VER) +#define ALWAYS_INLINE __forceinline +#else +#define ALWAYS_INLINE inline +#endif +#ifndef ORC_RESTRICT +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define ORC_RESTRICT restrict +#elif defined(__GNUC__) && __GNUC__ >= 4 +#define ORC_RESTRICT __restrict__ +#else +#define ORC_RESTRICT +#endif +#endif + +#define GST_TYPE_DEINTERLACE_METHOD_YADIF (gst_deinterlace_method_yadif_get_type ()) +#define GST_IS_DEINTERLACE_METHOD_YADIF(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_YADIF)) +#define GST_IS_DEINTERLACE_METHOD_YADIF_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_YADIF)) +#define GST_DEINTERLACE_METHOD_YADIF_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_YADIF, GstDeinterlaceMethodYadifClass)) +#define GST_DEINTERLACE_METHOD_YADIF(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_YADIF, GstDeinterlaceMethodYadif)) +#define GST_DEINTERLACE_METHOD_YADIF_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_YADIF, GstDeinterlaceMethodYadifClass)) +#define GST_DEINTERLACE_METHOD_YADIF_CAST(obj) ((GstDeinterlaceMethodYadif*)(obj)) + +typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodYadif; +typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodYadifClass; + +G_DEFINE_TYPE (GstDeinterlaceMethodYadif, + gst_deinterlace_method_yadif, GST_TYPE_DEINTERLACE_SIMPLE_METHOD); + +static void +filter_scanline_yadif (GstDeinterlaceSimpleMethod * self, + guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size, + int colors, int y_alternates_every); + +static void +filter_scanline_yadif_planar (GstDeinterlaceSimpleMethod * self, + guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size); + +static void +filter_scanline_yadif_semiplanar (GstDeinterlaceSimpleMethod * self, + guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size); + +static void +filter_scanline_yadif_packed_4 (GstDeinterlaceSimpleMethod * self, + guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size); + +static void +filter_scanline_yadif_packed_yvyu (GstDeinterlaceSimpleMethod * self, + guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size); + +static void +filter_scanline_yadif_packed_uyvy (GstDeinterlaceSimpleMethod * self, + guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size); + +static void +filter_scanline_yadif_packed_3 (GstDeinterlaceSimpleMethod * self, + guint8 * out, const GstDeinterlaceScanlineData * scanlines, guint size); + +static void +filter_line_c_planar_mode0 (void *ORC_RESTRICT dst, + const void *ORC_RESTRICT tzero, const void *ORC_RESTRICT bzero, + const void *ORC_RESTRICT mone, const void *ORC_RESTRICT mp, + const void *ORC_RESTRICT ttwo, const void *ORC_RESTRICT btwo, + const void *ORC_RESTRICT tptwo, const void *ORC_RESTRICT bptwo, + const void *ORC_RESTRICT ttone, const void *ORC_RESTRICT ttp, + const void *ORC_RESTRICT bbone, const void *ORC_RESTRICT bbp, int w); + +static void +filter_line_c_planar_mode2 (void *ORC_RESTRICT dst, + const void *ORC_RESTRICT tzero, const void *ORC_RESTRICT bzero, + const void *ORC_RESTRICT mone, const void *ORC_RESTRICT mp, + const void *ORC_RESTRICT ttwo, const void *ORC_RESTRICT btwo, + const void *ORC_RESTRICT tptwo, const void *ORC_RESTRICT bptwo, + const void *ORC_RESTRICT ttone, const void *ORC_RESTRICT ttp, + const void *ORC_RESTRICT bbone, const void *ORC_RESTRICT bbp, int w); + +static void (*filter_mode2) (void *ORC_RESTRICT dst, + const void *ORC_RESTRICT tzero, const void *ORC_RESTRICT bzero, + const void *ORC_RESTRICT mone, const void *ORC_RESTRICT mp, + const void *ORC_RESTRICT ttwo, const void *ORC_RESTRICT btwo, + const void *ORC_RESTRICT tptwo, const void *ORC_RESTRICT bptwo, + const void *ORC_RESTRICT ttone, const void *ORC_RESTRICT ttp, + const void *ORC_RESTRICT bbone, const void *ORC_RESTRICT bbp, int w); + +static void (*filter_mode0) (void *ORC_RESTRICT dst, + const void *ORC_RESTRICT tzero, const void *ORC_RESTRICT bzero, + const void *ORC_RESTRICT mone, const void *ORC_RESTRICT mp, + const void *ORC_RESTRICT ttwo, const void *ORC_RESTRICT btwo, + const void *ORC_RESTRICT tptwo, const void *ORC_RESTRICT bptwo, + const void *ORC_RESTRICT ttone, const void *ORC_RESTRICT ttp, + const void *ORC_RESTRICT bbone, const void *ORC_RESTRICT bbp, int w); + + +static void +copy_scanline (GstDeinterlaceSimpleMethod * self, guint8 * out, + const GstDeinterlaceScanlineData * scanlines, guint size) +{ + memcpy (out, scanlines->m0, size); +} + +static void + gst_deinterlace_method_yadif_class_init + (GstDeinterlaceMethodYadifClass * klass) +{ + GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass; + GstDeinterlaceSimpleMethodClass *dism_class = + (GstDeinterlaceSimpleMethodClass *) klass; + + dim_class->name = "YADIF Adaptive Deinterlacer"; + dim_class->nick = "yadif"; + dim_class->fields_required = 5; + dim_class->latency = 2; + + dism_class->copy_scanline_planar_y = copy_scanline; + dism_class->copy_scanline_planar_u = copy_scanline; + dism_class->copy_scanline_planar_v = copy_scanline; + dism_class->copy_scanline_yuy2 = copy_scanline; + dism_class->copy_scanline_yvyu = copy_scanline; + dism_class->copy_scanline_uyvy = copy_scanline; + dism_class->copy_scanline_ayuv = copy_scanline; + dism_class->copy_scanline_argb = copy_scanline; + dism_class->copy_scanline_abgr = copy_scanline; + dism_class->copy_scanline_rgba = copy_scanline; + dism_class->copy_scanline_bgra = copy_scanline; + dism_class->copy_scanline_rgb = copy_scanline; + dism_class->copy_scanline_bgr = copy_scanline; + dism_class->copy_scanline_nv12 = copy_scanline; + dism_class->copy_scanline_nv21 = copy_scanline; + + dism_class->interpolate_scanline_planar_y = filter_scanline_yadif_planar; + dism_class->interpolate_scanline_planar_u = filter_scanline_yadif_planar; + dism_class->interpolate_scanline_planar_v = filter_scanline_yadif_planar; + dism_class->interpolate_scanline_yuy2 = filter_scanline_yadif_packed_yvyu; + dism_class->interpolate_scanline_yvyu = filter_scanline_yadif_packed_yvyu; + dism_class->interpolate_scanline_uyvy = filter_scanline_yadif_packed_uyvy; + dism_class->interpolate_scanline_ayuv = filter_scanline_yadif_packed_4; + dism_class->interpolate_scanline_argb = filter_scanline_yadif_packed_4; + dism_class->interpolate_scanline_abgr = filter_scanline_yadif_packed_4; + dism_class->interpolate_scanline_rgba = filter_scanline_yadif_packed_4; + dism_class->interpolate_scanline_bgra = filter_scanline_yadif_packed_4; + dism_class->interpolate_scanline_rgb = filter_scanline_yadif_packed_3; + dism_class->interpolate_scanline_bgr = filter_scanline_yadif_packed_3; + dism_class->interpolate_scanline_nv12 = filter_scanline_yadif_semiplanar; + dism_class->interpolate_scanline_nv21 = filter_scanline_yadif_semiplanar; +} + +#define FFABS(a) ABS(a) +#define FFMIN(a,b) MIN(a,b) +#define FFMAX(a,b) MAX(a,b) +#define FFMAX3(a,b,c) FFMAX(FFMAX(a,b),c) +#define FFMIN3(a,b,c) FFMIN(FFMIN(a,b),c) + +#define CHECK(j1, j2, j3)\ + { int score = FFABS(stzero[x - j1] - sbzero[x - j2])\ + + FFABS(stzero[x + j3] - sbzero[x - j3])\ + + FFABS(stzero[x + j1] - sbzero[x + j2]);\ + if (score < spatial_score) {\ + spatial_score= score;\ + spatial_pred= (stzero[x + j3] + sbzero[x - j3])>>1;\ + +/* The is_not_edge argument here controls when the code will enter a branch + * which reads up to and including x-3 and x+3. */ + +#define FILTER(start, end, is_not_edge) \ + for (x = start; x < end; x++) { \ + int c = stzero[x]; \ + int d = (smone[x] + smp[x])>>1; \ + int e = sbzero[x]; \ + int temporal_diff0 = FFABS(smone[x] - smp[x]); \ + int temporal_diff1 =(FFABS(sttwo[x] - c) + FFABS(sbtwo[x] - e) )>>1; \ + int temporal_diff2 =(FFABS(stptwo[x] - c) + FFABS(sbptwo[x] - e) )>>1; \ + int diff = FFMAX3(temporal_diff0 >> 1, temporal_diff1, temporal_diff2); \ + int spatial_pred = (c+e) >> 1; \ + int colors2 = colors; \ + if ((y_alternates_every == 1 && (x%2 == 0)) || \ + (y_alternates_every == 2 && (x%2 == 1))) \ + colors2 = 2; \ + \ + if (is_not_edge) {\ + int spatial_score = FFABS(stzero[x-colors2] - sbzero[x-colors2]) + FFABS(c-e) \ + + FFABS(stzero[x+colors2] - sbzero[x+colors2]); \ + int twice_colors2 = colors2 << 1; \ + int minus_colors2 = -colors2; \ + int thrice_colors2 = colors2 * 3; \ + int minus2_colors2 = colors2 * -2; \ + CHECK(0, twice_colors2, minus_colors2) \ + CHECK(-colors2, thrice_colors2, minus2_colors2) }} }} \ + CHECK(twice_colors2, 0, colors2) \ + CHECK(thrice_colors2, minus_colors2, twice_colors2) }} }} \ + }\ + \ + if (!(mode&2)) { \ + int b = (sttone[x] + sttp[x])>>1; \ + int f = (sbbone[x] + sbbp[x])>>1; \ + int max = FFMAX3(d - e, d - c, FFMIN(b - c, f - e)); \ + int min = FFMIN3(d - e, d - c, FFMAX(b - c, f - e)); \ + \ + diff = FFMAX3(diff, min, -max); \ + } \ + \ + if (spatial_pred > d + diff) \ + spatial_pred = d + diff; \ + else if (spatial_pred < d - diff) \ + spatial_pred = d - diff; \ + \ + sdst[x] = spatial_pred; \ + \ + } + +ALWAYS_INLINE static void +filter_line_c (guint8 * sdst, const guint8 * stzero, const guint8 * sbzero, + const guint8 * smone, const guint8 * smp, const guint8 * sttwo, + const guint8 * sbtwo, const guint8 * stptwo, const guint8 * sbptwo, + const guint8 * sttone, const guint8 * sttp, const guint8 * sbbone, + const guint8 * sbbp, int w, int colors, int y_alternates_every, int start, + int end, int mode) +{ + int x; + + /* The function is called for processing the middle + * pixels of each line, excluding 3 at each end. + * This allows the FILTER macro to be + * called so that it processes all the pixels normally. A constant value of + * true for is_not_edge lets the compiler ignore the if statement. */ + FILTER (start, end, 1) +} + +#define MAX_ALIGN 8 + +ALWAYS_INLINE static void +filter_line_c_planar (void *ORC_RESTRICT dst, const void *ORC_RESTRICT tzero, + const void *ORC_RESTRICT bzero, const void *ORC_RESTRICT mone, + const void *ORC_RESTRICT mp, const void *ORC_RESTRICT ttwo, + const void *ORC_RESTRICT btwo, const void *ORC_RESTRICT tptwo, + const void *ORC_RESTRICT bptwo, const void *ORC_RESTRICT ttone, + const void *ORC_RESTRICT ttp, const void *ORC_RESTRICT bbone, + const void *ORC_RESTRICT bbp, int w, int mode) +{ + int x; + const int start = 0; + const int colors = 1; + const int y_alternates_every = 0; + /* hardcode colors = 1, bpp = 1 */ + const int end = w; + guint8 *sdst = (guint8 *) dst + 3; + guint8 *stzero = (guint8 *) tzero + 3; + guint8 *sbzero = (guint8 *) bzero + 3; + guint8 *smone = (guint8 *) mone + 3; + guint8 *smp = (guint8 *) mp + 3; + guint8 *sttwo = (guint8 *) ttwo + 3; + guint8 *sbtwo = (guint8 *) btwo + 3; + guint8 *stptwo = (guint8 *) tptwo + 3; + guint8 *sbptwo = (guint8 *) bptwo + 3; + guint8 *sttone = (guint8 *) ttone + 3; + guint8 *sttp = (guint8 *) ttp + 3; + guint8 *sbbone = (guint8 *) bbone + 3; + guint8 *sbbp = (guint8 *) bbp + 3; + /* The function is called for processing the middle + * pixels of each line, excluding 3 at each end. + * This allows the FILTER macro to be + * called so that it processes all the pixels normally. A constant value of + * true for is_not_edge lets the compiler ignore the if statement. */ + FILTER (start, end, 1) +} + +ALWAYS_INLINE G_GNUC_UNUSED static void +filter_line_c_planar_mode0 (void *ORC_RESTRICT dst, + const void *ORC_RESTRICT tzero, const void *ORC_RESTRICT bzero, + const void *ORC_RESTRICT mone, const void *ORC_RESTRICT mp, + const void *ORC_RESTRICT ttwo, const void *ORC_RESTRICT btwo, + const void *ORC_RESTRICT tptwo, const void *ORC_RESTRICT bptwo, + const void *ORC_RESTRICT ttone, const void *ORC_RESTRICT ttp, + const void *ORC_RESTRICT bbone, const void *ORC_RESTRICT bbp, int w) +{ + filter_line_c_planar (dst, tzero, bzero, mone, mp, ttwo, btwo, tptwo, bptwo, + ttone, ttp, bbone, bbp, w, 0); +} + +ALWAYS_INLINE G_GNUC_UNUSED static void +filter_line_c_planar_mode2 (void *ORC_RESTRICT dst, + const void *ORC_RESTRICT tzero, const void *ORC_RESTRICT bzero, + const void *ORC_RESTRICT mone, const void *ORC_RESTRICT mp, + const void *ORC_RESTRICT ttwo, const void *ORC_RESTRICT btwo, + const void *ORC_RESTRICT tptwo, const void *ORC_RESTRICT bptwo, + const void *ORC_RESTRICT ttone, const void *ORC_RESTRICT ttp, + const void *ORC_RESTRICT bbone, const void *ORC_RESTRICT bbp, int w) +{ + filter_line_c_planar (dst, tzero, bzero, mone, mp, ttwo, btwo, tptwo, bptwo, + ttone, ttp, bbone, bbp, w, 2); +} + +ALWAYS_INLINE static void +filter_edges (guint8 * sdst, const guint8 * stzero, const guint8 * sbzero, + const guint8 * smone, const guint8 * smp, const guint8 * sttwo, + const guint8 * sbtwo, const guint8 * stptwo, const guint8 * sbptwo, + const guint8 * sttone, const guint8 * sttp, const guint8 * sbbone, + const guint8 * sbbp, int w, int colors, int y_alternates_every, + int mode, const int bpp) +{ + int x; + const int edge = colors * (MAX_ALIGN / bpp); + const int border = 3 * colors; + + /* Only edge pixels need to be processed here. A constant value of false + * for is_not_edge should let the compiler ignore the whole branch. */ + FILTER (0, border, 0) + FILTER (w - edge, w - border, 1) + FILTER (w - border, w, 0) +} + +static void +filter_scanline_yadif_semiplanar (GstDeinterlaceSimpleMethod * self, + guint8 * out, const GstDeinterlaceScanlineData * s_orig, guint size) +{ + filter_scanline_yadif (self, out, s_orig, size, 2, 0); +} + +static void +filter_scanline_yadif_packed_3 (GstDeinterlaceSimpleMethod * self, + guint8 * out, const GstDeinterlaceScanlineData * s_orig, guint size) +{ + filter_scanline_yadif (self, out, s_orig, size, 3, 0); +} + +static void +filter_scanline_yadif_packed_4 (GstDeinterlaceSimpleMethod * self, + guint8 * out, const GstDeinterlaceScanlineData * s_orig, guint size) +{ + filter_scanline_yadif (self, out, s_orig, size, 4, 0); +} + +static void +filter_scanline_yadif_packed_yvyu (GstDeinterlaceSimpleMethod * self, + guint8 * out, const GstDeinterlaceScanlineData * s_orig, guint size) +{ + filter_scanline_yadif (self, out, s_orig, size, 4, 1); +} + +static void +filter_scanline_yadif_packed_uyvy (GstDeinterlaceSimpleMethod * self, + guint8 * out, const GstDeinterlaceScanlineData * s_orig, guint size) +{ + filter_scanline_yadif (self, out, s_orig, size, 4, 2); +} + +ALWAYS_INLINE static void +filter_scanline_yadif (GstDeinterlaceSimpleMethod * self, + guint8 * out, const GstDeinterlaceScanlineData * s_orig, guint size, + int colors, int y_alternates_every) +{ + guint8 *dst = out; + const int bpp = 1; // Hard code 8-bit atm + int w = size / bpp; + int edge = colors * MAX_ALIGN / bpp; + GstDeinterlaceScanlineData s = *s_orig; + + int mode = (s.tt1 == NULL || s.bb1 == NULL || s.ttp == NULL + || s.bbp == NULL) ? 2 : 0; + + /* When starting up, some data might not yet be available, so use the current frame */ + if (s.m1 == NULL) + s.m1 = s.mp; + if (s.tt1 == NULL) + s.tt1 = s.ttp; + if (s.bb1 == NULL) + s.bb1 = s.bbp; + if (s.t2 == NULL) + s.t2 = s.tp2; + if (s.b2 == NULL) + s.b2 = s.bp2; + + filter_edges (dst, s.t0, s.b0, s.m1, s.mp, s.t2, s.b2, s.tp2, s.bp2, s.tt1, + s.ttp, s.bb1, s.bbp, w, colors, y_alternates_every, mode, bpp); + filter_line_c (dst, s.t0, s.b0, s.m1, s.mp, s.t2, s.b2, s.tp2, s.bp2, s.tt1, + s.ttp, s.bb1, s.bbp, w, colors, y_alternates_every, colors * 3, w - edge, + mode); +} + +ALWAYS_INLINE static void +filter_scanline_yadif_planar (GstDeinterlaceSimpleMethod * self, + guint8 * out, const GstDeinterlaceScanlineData * s_orig, guint size) +{ + guint8 *dst = out; + const int bpp = 1; // Hard code 8-bit atm + int w = size / bpp; + int edge = MAX_ALIGN / bpp; + GstDeinterlaceScanlineData s = *s_orig; + + int mode = (s.tt1 == NULL || s.bb1 == NULL || s.ttp == NULL + || s.bbp == NULL) ? 2 : 0; + + /* When starting up, some data might not yet be available, so use the current frame */ + if (s.m1 == NULL) + s.m1 = s.mp; + if (s.tt1 == NULL) + s.tt1 = s.ttp; + if (s.bb1 == NULL) + s.bb1 = s.bbp; + if (s.t2 == NULL) + s.t2 = s.tp2; + if (s.b2 == NULL) + s.b2 = s.bp2; + + filter_edges (dst, s.t0, s.b0, s.m1, s.mp, s.t2, s.b2, s.tp2, s.bp2, s.tt1, + s.ttp, s.bb1, s.bbp, w, 1, 0, mode, bpp); + if (mode == 0) + filter_mode0 (dst, (void *) s.t0, (void *) s.b0, (void *) s.m1, + (void *) s.mp, (void *) s.t2, (void *) s.b2, (void *) s.tp2, + (void *) s.bp2, (void *) s.tt1, (void *) s.ttp, (void *) s.bb1, + (void *) s.bbp, w - edge); + else + filter_mode2 (dst, (void *) s.t0, (void *) s.b0, (void *) s.m1, + (void *) s.mp, (void *) s.t2, (void *) s.b2, (void *) s.tp2, + (void *) s.bp2, (void *) s.tt1, (void *) s.ttp, (void *) s.bb1, + (void *) s.bbp, w - edge); +} + +static void +gst_deinterlace_method_yadif_init (GstDeinterlaceMethodYadif * self) +{ +#if (defined __x86_64__ || defined _M_X64) && defined HAVE_NASM + if ( +# if defined HAVE_ORC + orc_sse_get_cpu_flags () & ORC_TARGET_SSE_SSSE3 +# elif defined __SSSE3__ + TRUE +# else + FALSE +# endif + ) { + GST_DEBUG ("SSSE3 optimization enabled"); + filter_mode0 = gst_yadif_filter_line_mode0_ssse3; + filter_mode2 = gst_yadif_filter_line_mode2_ssse3; + } else { + GST_DEBUG ("SSE2 optimization enabled"); + filter_mode0 = gst_yadif_filter_line_mode0_sse2; + filter_mode2 = gst_yadif_filter_line_mode2_sse2; + } +#else + { + GST_DEBUG ("SSE optimization disabled"); + filter_mode0 = filter_line_c_planar_mode0; + filter_mode2 = filter_line_c_planar_mode2; + } +#endif +} diff --git a/gst/deinterlace/yadif.h b/gst/deinterlace/yadif.h new file mode 100644 index 0000000000..444c1d00ef --- /dev/null +++ b/gst/deinterlace/yadif.h @@ -0,0 +1,48 @@ +/* + * GStreamer + * Copyright (C) 2019 Jan Schmidt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __YADIF_H__ +#define __YADIF_H__ + +#define GST_TYPE_DEINTERLACE_YADIF (gst_deinterlace_method_yadif_get_type ()) + +GType gst_deinterlace_method_yadif_get_type (void); + +void +gst_yadif_filter_line_mode0_sse2 (void *dst, const void *tzero, const void *bzero, + const void *mone, const void *mp, const void *ttwo, const void *btwo, const void *tptwo, const void *bptwo, + const void *ttone, const void *ttp, const void *bbone, const void *bbp, int w); + +void +gst_yadif_filter_line_mode2_sse2 (void *dst, const void *tzero, const void *bzero, + const void *mone, const void *mp, const void *ttwo, const void *btwo, const void *tptwo, const void *bptwo, + const void *ttone, const void *ttp, const void *bbone, const void *bbp, int w); + +void +gst_yadif_filter_line_mode0_ssse3 (void *dst, const void *tzero, const void *bzero, + const void *mone, const void *mp, const void *ttwo, const void *btwo, const void *tptwo, const void *bptwo, + const void *ttone, const void *ttp, const void *bbone, const void *bbp, int w); + +void +gst_yadif_filter_line_mode2_ssse3 (void *dst, const void *tzero, const void *bzero, + const void *mone, const void *mp, const void *ttwo, const void *btwo, const void *tptwo, const void *bptwo, + const void *ttone, const void *ttp, const void *bbone, const void *bbp, int w); + +#endif diff --git a/gst/effectv/gstop.c b/gst/effectv/gstop.c index ec636b38ef..498b89a7a7 100644 --- a/gst/effectv/gstop.c +++ b/gst/effectv/gstop.c @@ -407,6 +407,8 @@ gst_optv_class_init (GstOpTVClass * klass) vfilter_class->transform_frame = GST_DEBUG_FUNCPTR (gst_optv_transform_frame); initPalette (); + + gst_type_mark_as_plugin_api (GST_TYPE_OPTV_MODE, 0); } static void diff --git a/gst/effectv/gstradioac.c b/gst/effectv/gstradioac.c index a36a5b9a79..0d674008d0 100644 --- a/gst/effectv/gstradioac.c +++ b/gst/effectv/gstradioac.c @@ -610,6 +610,9 @@ gst_radioactv_class_init (GstRadioacTVClass * klass) GST_DEBUG_FUNCPTR (gst_radioactv_transform_frame); makePalette (); + + gst_type_mark_as_plugin_api (GST_TYPE_RADIOACTV_MODE, 0); + gst_type_mark_as_plugin_api (GST_TYPE_RADIOACTV_COLOR, 0); } static void diff --git a/gst/effectv/gstripple.c b/gst/effectv/gstripple.c index 577c7d6fbe..2b15d03689 100644 --- a/gst/effectv/gstripple.c +++ b/gst/effectv/gstripple.c @@ -598,6 +598,8 @@ gst_rippletv_class_init (GstRippleTVClass * klass) GST_DEBUG_FUNCPTR (gst_rippletv_transform_frame); setTable (); + + gst_type_mark_as_plugin_api (GST_TYPE_RIPPLETV_MODE, 0); } static void diff --git a/gst/equalizer/gstiirequalizer.c b/gst/equalizer/gstiirequalizer.c index 210296b73a..e78d77959d 100644 --- a/gst/equalizer/gstiirequalizer.c +++ b/gst/equalizer/gstiirequalizer.c @@ -272,6 +272,8 @@ gst_iir_equalizer_band_class_init (GstIirEqualizerBandClass * klass) "Filter type", GST_TYPE_IIR_EQUALIZER_BAND_TYPE, BAND_TYPE_PEAK, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE)); + + gst_type_mark_as_plugin_api (GST_TYPE_IIR_EQUALIZER, 0); } static void diff --git a/gst/flv/gstflvdemux.c b/gst/flv/gstflvdemux.c index 9342ca1d0d..09f935d332 100644 --- a/gst/flv/gstflvdemux.c +++ b/gst/flv/gstflvdemux.c @@ -107,6 +107,8 @@ static gboolean flv_demux_handle_seek_push (GstFlvDemux * demux, static gboolean gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event, gboolean seeking); +static gboolean gst_flv_demux_sink_query (GstPad * pad, GstObject * parent, + GstQuery * query); static gboolean gst_flv_demux_query (GstPad * pad, GstObject * parent, GstQuery * query); static gboolean gst_flv_demux_src_event (GstPad * pad, GstObject * parent, @@ -202,7 +204,8 @@ FLV_GET_STRING (GstByteReader * reader) } memcpy (string, str, string_size); - if (!g_utf8_validate (string, string_size, NULL)) { + /* Check utf-8 validity if it's not an empty string */ + if (string[0] && !g_utf8_validate (string, string_size, NULL)) { g_free (string); return NULL; } @@ -371,11 +374,13 @@ gst_flv_demux_parse_metadata_item (GstFlvDemux * demux, GstByteReader * reader, } else if (!strcmp (tag_name, "framerate")) { demux->framerate = d; } else if (!strcmp (tag_name, "audiodatarate")) { + demux->audio_bitrate = (guint) (d * 1024); gst_tag_list_add (demux->audio_tags, GST_TAG_MERGE_REPLACE, - GST_TAG_NOMINAL_BITRATE, (guint) (d * 1024), NULL); + GST_TAG_NOMINAL_BITRATE, demux->audio_bitrate, NULL); } else if (!strcmp (tag_name, "videodatarate")) { + demux->video_bitrate = (guint) (d * 1024); gst_tag_list_add (demux->video_tags, GST_TAG_MERGE_REPLACE, - GST_TAG_NOMINAL_BITRATE, (guint) (d * 1024), NULL); + GST_TAG_NOMINAL_BITRATE, demux->video_bitrate, NULL); } else { GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name); } @@ -402,6 +407,11 @@ gst_flv_demux_parse_metadata_item (GstFlvDemux * demux, GstByteReader * reader, s = FLV_GET_STRING (reader); if (s == NULL) goto error; + if (!strcmp (s, "")) { + /* Not strictly an error, just an empty string */ + g_free (s); + break; + } GST_DEBUG_OBJECT (demux, "%s => (string) %s", tag_name, s); @@ -1018,6 +1028,51 @@ gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 dts, gboolean discont, return ret; } +static void +gst_flv_demux_sync_streams (GstFlvDemux * demux) +{ + /* Check if the audio or video stream are more than 3s behind the other + * stream, and if so send a gap event accordingly */ + + if (demux->audio_pad && GST_CLOCK_TIME_IS_VALID (demux->segment.position) && + demux->last_audio_pts * GST_MSECOND + demux->audio_time_offset + + 3 * GST_SECOND < demux->segment.position) { + GstEvent *event; + guint64 start = + demux->last_audio_pts * GST_MSECOND + demux->audio_time_offset; + guint64 stop = demux->segment.position - 3 * GST_SECOND; + + GST_DEBUG_OBJECT (demux, + "Synchronizing audio stream with video stream by advancing time from %" + GST_TIME_FORMAT " to %" GST_TIME_FORMAT, GST_TIME_ARGS (start), + GST_TIME_ARGS (stop)); + + demux->last_audio_pts = (stop - demux->audio_time_offset) / GST_MSECOND; + + event = gst_event_new_gap (start, stop - start); + gst_pad_push_event (demux->audio_pad, event); + } + + if (demux->video_pad && GST_CLOCK_TIME_IS_VALID (demux->segment.position) && + demux->last_video_dts * GST_MSECOND + demux->video_time_offset + + 3 * GST_SECOND < demux->segment.position) { + GstEvent *event; + guint64 start = + demux->last_video_dts * GST_MSECOND + demux->video_time_offset; + guint64 stop = demux->segment.position - 3 * GST_SECOND; + + GST_DEBUG_OBJECT (demux, + "Synchronizing video stream with audio stream by advancing time from %" + GST_TIME_FORMAT " to %" GST_TIME_FORMAT, GST_TIME_ARGS (start), + GST_TIME_ARGS (stop)); + + demux->last_video_dts = (stop - demux->video_time_offset) / GST_MSECOND; + + event = gst_event_new_gap (start, stop - start); + gst_pad_push_event (demux->video_pad, event); + } +} + static GstFlowReturn gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer) { @@ -1315,6 +1370,10 @@ gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer) ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, demux->audio_pad, ret); + if (ret == GST_FLOW_OK) { + gst_flv_demux_sync_streams (demux); + } + beach: gst_buffer_unmap (buffer, &map); @@ -1630,7 +1689,7 @@ gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer) /* Check if caps have changed */ if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) { - GST_ERROR_OBJECT (demux, "video settings have changed, changing caps"); + GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps"); if (codec_tag != demux->video_codec_tag) gst_buffer_replace (&demux->video_codec_data, NULL); @@ -1750,6 +1809,10 @@ gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer) ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, demux->video_pad, ret); + if (ret == GST_FLOW_OK) { + gst_flv_demux_sync_streams (demux); + } + beach: gst_buffer_unmap (buffer, &map); return ret; @@ -2049,6 +2112,9 @@ gst_flv_demux_cleanup (GstFlvDemux * demux) demux->filepositions = NULL; } + demux->video_bitrate = 0; + demux->audio_bitrate = 0; + gst_flv_demux_clear_tags (demux); } @@ -3276,6 +3342,54 @@ gst_flv_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) return ret; } +static gboolean +gst_flv_demux_sink_query (GstPad * pad, GstObject * parent, GstQuery * query) +{ + GstFlvDemux *demux; + gboolean ret = FALSE; + + demux = GST_FLV_DEMUX (parent); + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_BITRATE: + { + guint total_bitrate = 0; + + if (demux->audio_pad) { + if (!demux->audio_bitrate) { + GST_DEBUG_OBJECT (demux, + "Have audio pad but no audio bitrate, can't answer BITRATE query"); + break; + } + total_bitrate = demux->audio_bitrate; + } + if (demux->video_pad) { + if (!demux->video_bitrate) { + GST_DEBUG_OBJECT (demux, + "Have video pad but no video bitrate, can't answer BITRATE query"); + break; + } + total_bitrate += demux->video_bitrate; + } + + GST_DEBUG_OBJECT (demux, + "bitrate query. total_bitrate:%" G_GUINT32_FORMAT, total_bitrate); + + if (total_bitrate) { + /* Padding of 2kbit/s for container overhead */ + gst_query_set_bitrate (query, total_bitrate + 2048); + ret = TRUE; + } + break; + } + default: + ret = gst_pad_query_default (pad, parent, query); + break; + } + + return ret; +} + static gboolean gst_flv_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event) { @@ -3640,7 +3754,7 @@ gst_flv_demux_init (GstFlvDemux * demux) { demux->sinkpad = gst_pad_new_from_static_template (&flv_sink_template, "sink"); - + GST_PAD_SET_ACCEPT_TEMPLATE (demux->sinkpad); gst_pad_set_event_function (demux->sinkpad, GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event)); gst_pad_set_chain_function (demux->sinkpad, @@ -3649,6 +3763,8 @@ gst_flv_demux_init (GstFlvDemux * demux) GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate)); gst_pad_set_activatemode_function (demux->sinkpad, GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_mode)); + gst_pad_set_query_function (demux->sinkpad, + GST_DEBUG_FUNCPTR (gst_flv_demux_sink_query)); gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad); diff --git a/gst/flv/gstflvdemux.h b/gst/flv/gstflvdemux.h index 4eb1791760..28a42a89bc 100644 --- a/gst/flv/gstflvdemux.h +++ b/gst/flv/gstflvdemux.h @@ -101,11 +101,11 @@ struct _GstFlvDemux guint64 audio_offset; gboolean audio_need_discont; gboolean audio_need_segment; - gboolean audio_linked; GstBuffer * audio_codec_data; GstClockTime audio_start; guint32 last_audio_pts; GstClockTime audio_time_offset; + guint32 audio_bitrate; /* Video infos */ guint32 w; @@ -116,13 +116,13 @@ struct _GstFlvDemux guint64 video_offset; gboolean video_need_discont; gboolean video_need_segment; - gboolean video_linked; gboolean got_par; GstBuffer * video_codec_data; GstClockTime video_start; guint32 last_video_dts; GstClockTime video_time_offset; gdouble framerate; + guint32 video_bitrate; gboolean random_access; gboolean need_header; diff --git a/gst/flv/gstflvmux.c b/gst/flv/gstflvmux.c index 8f9d64d4e2..8742ac36e5 100644 --- a/gst/flv/gstflvmux.c +++ b/gst/flv/gstflvmux.c @@ -54,12 +54,14 @@ enum PROP_0, PROP_STREAMABLE, PROP_METADATACREATOR, - PROP_ENCODER + PROP_ENCODER, + PROP_SKIP_BACKWARDS_STREAMS, }; #define DEFAULT_STREAMABLE FALSE #define MAX_INDEX_ENTRIES 128 #define DEFAULT_METADATACREATOR "GStreamer " PACKAGE_VERSION " FLV muxer" +#define DEFAULT_SKIP_BACKWARDS_STREAMS FALSE static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, @@ -131,19 +133,63 @@ static GstFlowReturn gst_flv_mux_rewrite_header (GstFlvMux * mux); static gboolean gst_flv_mux_are_all_pads_eos (GstFlvMux * mux); static GstFlowReturn gst_flv_mux_update_src_caps (GstAggregator * aggregator, GstCaps * caps, GstCaps ** ret); +static guint64 gst_flv_mux_query_upstream_duration (GstFlvMux * mux); +static GstClockTime gst_flv_mux_segment_to_running_time (const GstSegment * + segment, GstClockTime t); static GstFlowReturn gst_flv_mux_pad_flush (GstAggregatorPad * pad, GstAggregator * aggregator) { GstFlvMuxPad *flvpad = GST_FLV_MUX_PAD (pad); - flvpad->last_timestamp = 0; + flvpad->last_timestamp = GST_CLOCK_TIME_NONE; flvpad->pts = GST_CLOCK_STIME_NONE; flvpad->dts = GST_CLOCK_STIME_NONE; return GST_FLOW_OK; } +static gboolean +gst_flv_mux_skip_buffer (GstAggregatorPad * apad, GstAggregator * aggregator, + GstBuffer * buffer) +{ + GstFlvMuxPad *fpad = GST_FLV_MUX_PAD_CAST (apad); + GstFlvMux *mux = GST_FLV_MUX_CAST (aggregator); + GstClockTime t; + + if (!mux->skip_backwards_streams) + return FALSE; + + if (fpad->drop_deltas) { + if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) { + GST_INFO_OBJECT (fpad, "Waiting for keyframe, dropping %" GST_PTR_FORMAT, + buffer); + return TRUE; + } else { + /* drop-deltas is set and the buffer isn't delta, drop flag */ + fpad->drop_deltas = FALSE; + } + } + + if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS_OR_PTS (buffer))) { + t = gst_flv_mux_segment_to_running_time (&apad->segment, + GST_BUFFER_DTS_OR_PTS (buffer)); + + if (t < (GST_MSECOND * mux->last_dts)) { + GST_WARNING_OBJECT (fpad, + "Timestamp %" GST_TIME_FORMAT " going backwards from last used %" + GST_TIME_FORMAT ", dropping %" GST_PTR_FORMAT, + GST_TIME_ARGS (t), GST_TIME_ARGS (GST_MSECOND * mux->last_dts), + buffer); + /* Look for non-delta buffer */ + fpad->drop_deltas = TRUE; + return TRUE; + } + } + + return FALSE; +} + static void gst_flv_mux_pad_class_init (GstFlvMuxPadClass * klass) { @@ -153,6 +199,8 @@ gst_flv_mux_pad_class_init (GstFlvMuxPadClass * klass) gobject_class->finalize = gst_flv_mux_pad_finalize; aggregatorpad_class->flush = GST_DEBUG_FUNCPTR (gst_flv_mux_pad_flush); + aggregatorpad_class->skip_buffer = + GST_DEBUG_FUNCPTR (gst_flv_mux_skip_buffer); } static void @@ -235,6 +283,12 @@ gst_flv_mux_class_init (GstFlvMuxClass * klass) g_param_spec_string ("encoder", "encoder", "The value of encoder in the meta packet.", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_SKIP_BACKWARDS_STREAMS, + g_param_spec_boolean ("skip-backwards-streams", "Skip backwards streams", + "If set to true, streams that go backwards related to the other stream " + "will have buffers dropped until they reach the correct timestamp", + DEFAULT_SKIP_BACKWARDS_STREAMS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); gstaggregator_class->create_new_pad = GST_DEBUG_FUNCPTR (gst_flv_mux_create_new_pad); @@ -261,6 +315,8 @@ gst_flv_mux_class_init (GstFlvMuxClass * klass) "Sebastian Dröge "); GST_DEBUG_CATEGORY_INIT (flvmux_debug, "flvmux", 0, "FLV muxer"); + + gst_type_mark_as_plugin_api (GST_TYPE_FLV_MUX_PAD, 0); } static void @@ -661,6 +717,7 @@ gst_flv_mux_reset_pad (GstFlvMuxPad * pad) pad->width = G_MAXUINT; pad->channels = G_MAXUINT; pad->info_changed = FALSE; + pad->drop_deltas = FALSE; gst_flv_mux_pad_flush (GST_AGGREGATOR_PAD_CAST (pad), NULL); } @@ -676,8 +733,10 @@ gst_flv_mux_create_new_pad (GstAggregator * agg, const gchar *name = NULL; gboolean video; - if (mux->state != GST_FLV_MUX_STATE_HEADER) { - GST_WARNING_OBJECT (mux, "Can't request pads after writing header"); + if (mux->state != GST_FLV_MUX_STATE_HEADER && !mux->streamable) { + GST_ELEMENT_WARNING (mux, STREAM, MUX, + ("Requested a late stream in a non-streamable file"), + ("Stream added after file started and therefore won't be playable")); return NULL; } @@ -722,9 +781,10 @@ static void gst_flv_mux_release_pad (GstElement * element, GstPad * pad) { GstFlvMux *mux = GST_FLV_MUX (element); - GstFlvMuxPad *flvpad = GST_FLV_MUX_PAD (pad); + GstFlvMuxPad *flvpad = GST_FLV_MUX_PAD (gst_object_ref (pad)); + + GST_ELEMENT_CLASS (gst_flv_mux_parent_class)->release_pad (element, pad); - gst_pad_set_active (pad, FALSE); gst_flv_mux_reset_pad (flvpad); if (flvpad == mux->video_pad) { @@ -735,7 +795,7 @@ gst_flv_mux_release_pad (GstElement * element, GstPad * pad) GST_WARNING_OBJECT (pad, "Pad is not known audio or video pad"); } - gst_element_remove_pad (element, pad); + gst_object_unref (flvpad); } static GstFlowReturn @@ -833,7 +893,7 @@ gst_flv_mux_create_metadata (GstFlvMux * mux) const GstTagList *tags; GstBuffer *script_tag, *tmp; GstMapInfo map; - guint32 dts; + guint64 dts; guint8 *data; gint i, n_tags, tags_written = 0; @@ -846,9 +906,16 @@ gst_flv_mux_create_metadata (GstFlvMux * mux) dts -= mux->first_timestamp / GST_MSECOND; } - GST_DEBUG_OBJECT (mux, "Creating metadata, dts %i, tags = %" GST_PTR_FORMAT, + GST_DEBUG_OBJECT (mux, + "Creating metadata, dts %" G_GUINT64_FORMAT ", tags = %" GST_PTR_FORMAT, dts, tags); + if (dts > G_MAXUINT32) { + GST_LOG_OBJECT (mux, + "Detected rollover, timestamp will be truncated (previous:%" + G_GUINT64_FORMAT ", new:%u)", dts, (guint32) dts); + } + /* FIXME perhaps some bytewriter'ing here ... */ _gst_buffer_new_and_alloc (11, &script_tag, &data); @@ -939,20 +1006,7 @@ gst_flv_mux_create_metadata (GstFlvMux * mux) } if (!mux->streamable && mux->duration == GST_CLOCK_TIME_NONE) { - GList *l; - guint64 dur; - - for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) { - GstFlvMuxPad *pad = GST_FLV_MUX_PAD (l->data); - - if (gst_pad_peer_query_duration (GST_PAD (pad), GST_FORMAT_TIME, - (gint64 *) & dur) && dur != GST_CLOCK_TIME_NONE) { - if (mux->duration == GST_CLOCK_TIME_NONE) - mux->duration = dur; - else - mux->duration = MAX (dur, mux->duration); - } - } + mux->duration = gst_flv_mux_query_upstream_duration (mux); } if (!mux->streamable && mux->duration != GST_CLOCK_TIME_NONE) { @@ -1134,7 +1188,6 @@ gst_flv_mux_create_metadata (GstFlvMux * mux) data[2] = 9; /* end marker */ script_tag = gst_buffer_append (script_tag, tmp); - _gst_buffer_new_and_alloc (4, &tmp, &data); GST_WRITE_UINT32_BE (data, gst_buffer_get_size (script_tag)); script_tag = gst_buffer_append (script_tag, tmp); @@ -1158,15 +1211,32 @@ gst_flv_mux_buffer_to_tag_internal (GstFlvMux * mux, GstBuffer * buffer, GstBuffer *tag; GstMapInfo map; guint size; - guint32 pts, dts, cts; + guint64 pts, dts, cts; guint8 *data, *bdata = NULL; gsize bsize = 0; - if (!GST_CLOCK_STIME_IS_VALID (pad->dts)) { - pts = dts = pad->last_timestamp / GST_MSECOND; - } else { + if (GST_CLOCK_STIME_IS_VALID (pad->dts)) { pts = pad->pts / GST_MSECOND; dts = pad->dts / GST_MSECOND; + GST_LOG_OBJECT (mux, + "Pad %s: Created dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT + " from rounding %" GST_TIME_FORMAT ", %" GST_TIME_FORMAT, + GST_PAD_NAME (pad), GST_TIME_ARGS (dts * GST_MSECOND), + GST_TIME_ARGS (pts * GST_MSECOND), GST_TIME_ARGS (pad->dts), + GST_TIME_ARGS (pad->pts)); + } else if (GST_CLOCK_TIME_IS_VALID (pad->last_timestamp)) { + pts = dts = pad->last_timestamp / GST_MSECOND; + GST_DEBUG_OBJECT (mux, + "Pad %s: Created dts and pts %" GST_TIME_FORMAT + " from rounding last pad timestamp %" GST_TIME_FORMAT, + GST_PAD_NAME (pad), GST_TIME_ARGS (pts * GST_MSECOND), + GST_TIME_ARGS (pad->last_timestamp)); + } else { + pts = dts = mux->last_dts; + GST_DEBUG_OBJECT (mux, + "Pad %s: Created dts and pts %" GST_TIME_FORMAT + " from last mux timestamp", + GST_PAD_NAME (pad), GST_TIME_ARGS (pts * GST_MSECOND)); } /* We prevent backwards timestamps because they confuse librtmp, @@ -1181,7 +1251,6 @@ gst_flv_mux_buffer_to_tag_internal (GstFlvMux * mux, GstBuffer * buffer, } mux->last_dts = dts; - /* Be safe in case TS are buggy */ if (pts > dts) cts = pts - dts; @@ -1194,7 +1263,15 @@ gst_flv_mux_buffer_to_tag_internal (GstFlvMux * mux, GstBuffer * buffer, pts = dts + cts; } - GST_LOG_OBJECT (mux, "got pts %i dts %i cts %i", pts, dts, cts); + GST_LOG_OBJECT (mux, + "got pts %" G_GUINT64_FORMAT " dts %" G_GUINT64_FORMAT " cts %" + G_GUINT64_FORMAT, pts, dts, cts); + + if (dts > G_MAXUINT32) { + GST_LOG_OBJECT (mux, + "Detected rollover, timestamp will be truncated (previous:%" + G_GUINT64_FORMAT ", new:%u)", dts, (guint32) dts); + } if (buffer != NULL) { gst_buffer_map (buffer, &map, GST_MAP_READ); @@ -1227,7 +1304,6 @@ gst_flv_mux_buffer_to_tag_internal (GstFlvMux * mux, GstBuffer * buffer, data[2] = ((size - 11 - 4) >> 8) & 0xff; data[3] = ((size - 11 - 4) >> 0) & 0xff; - GST_WRITE_UINT24_BE (data + 4, dts); data[7] = (((guint) dts) >> 24) & 0xff; @@ -1264,7 +1340,7 @@ gst_flv_mux_buffer_to_tag_internal (GstFlvMux * mux, GstBuffer * buffer, data[11] |= (pad->width << 1) & 0x02; data[11] |= (pad->channels << 0) & 0x01; - GST_DEBUG_OBJECT (mux, "Creating byte %02x with " + GST_LOG_OBJECT (mux, "Creating byte %02x with " "codec:%d, rate:%d, width:%d, channels:%d", data[11], pad->codec, pad->rate, pad->width, pad->channels); @@ -1371,6 +1447,7 @@ gst_flv_mux_prepare_src_caps (GstFlvMux * mux, GstBuffer ** header_buf, video_codec_data = NULL; audio_codec_data = NULL; + GST_OBJECT_LOCK (mux); for (l = GST_ELEMENT_CAST (mux)->sinkpads; l != NULL; l = l->next) { GstFlvMuxPad *pad = l->data; @@ -1391,6 +1468,7 @@ gst_flv_mux_prepare_src_caps (GstFlvMux * mux, GstBuffer ** header_buf, gst_flv_mux_codec_data_buffer_to_tag (mux, pad->codec_data, pad); } } + GST_OBJECT_UNLOCK (mux); /* mark buffers that will go in the streamheader */ GST_BUFFER_FLAG_SET (header, GST_BUFFER_FLAG_HEADER); @@ -1600,7 +1678,6 @@ gst_flv_mux_write_buffer (GstFlvMux * mux, GstFlvMuxPad * pad, if (ret == GST_FLOW_OK && GST_CLOCK_TIME_IS_VALID (dts)) pad->last_timestamp = dts; - return ret; } @@ -1613,6 +1690,7 @@ gst_flv_mux_determine_duration (GstFlvMux * mux) GST_DEBUG_OBJECT (mux, "trying to determine the duration " "from pad timestamps"); + GST_OBJECT_LOCK (mux); for (l = GST_ELEMENT_CAST (mux)->sinkpads; l != NULL; l = l->next) { GstFlvMuxPad *pad = GST_FLV_MUX_PAD (l->data); @@ -1623,21 +1701,59 @@ gst_flv_mux_determine_duration (GstFlvMux * mux) duration = MAX (duration, pad->last_timestamp); } } + GST_OBJECT_UNLOCK (mux); return duration; } +struct DurationData +{ + GstClockTime duration; +}; + +static gboolean +duration_query_cb (GstElement * element, GstPad * pad, + struct DurationData *data) +{ + guint64 dur; + + if (gst_pad_peer_query_duration (GST_PAD (pad), GST_FORMAT_TIME, + (gint64 *) & dur) && dur != GST_CLOCK_TIME_NONE) { + if (data->duration == GST_CLOCK_TIME_NONE) + data->duration = dur; + else + data->duration = MAX (dur, data->duration); + } + + return TRUE; +} + +static guint64 +gst_flv_mux_query_upstream_duration (GstFlvMux * mux) +{ + struct DurationData cb_data = { GST_CLOCK_TIME_NONE }; + + gst_element_foreach_sink_pad (GST_ELEMENT (mux), + (GstElementForeachPadFunc) (duration_query_cb), &cb_data); + + return cb_data.duration; +} + static gboolean gst_flv_mux_are_all_pads_eos (GstFlvMux * mux) { GList *l; + GST_OBJECT_LOCK (mux); for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) { GstFlvMuxPad *pad = GST_FLV_MUX_PAD (l->data); - if (!gst_aggregator_pad_is_eos (GST_AGGREGATOR_PAD (pad))) + if (!gst_aggregator_pad_is_eos (GST_AGGREGATOR_PAD (pad))) { + GST_OBJECT_UNLOCK (mux); return FALSE; + } } + GST_OBJECT_UNLOCK (mux); return TRUE; } @@ -1792,38 +1908,77 @@ gst_flv_mux_rewrite_header (GstFlvMux * mux) return gst_flv_mux_push (mux, rewrite); } +/* Returns NULL, or a reference to the pad with the + * buffer with lowest running time */ static GstFlvMuxPad * -gst_flv_mux_find_best_pad (GstAggregator * aggregator, GstClockTime * ts) +gst_flv_mux_find_best_pad (GstAggregator * aggregator, GstClockTime * ts, + gboolean timeout) { - GstAggregatorPad *apad; - GstFlvMuxPad *pad, *best = NULL; - GList *l; - GstBuffer *buffer; + GstFlvMuxPad *best = NULL; GstClockTime best_ts = GST_CLOCK_TIME_NONE; + GstIterator *pads; + GValue padptr = { 0, }; + gboolean done = FALSE; + + pads = gst_element_iterate_sink_pads (GST_ELEMENT (aggregator)); + + while (!done) { + switch (gst_iterator_next (pads, &padptr)) { + case GST_ITERATOR_OK:{ + GstAggregatorPad *apad = g_value_get_object (&padptr); + GstClockTime t = GST_CLOCK_TIME_NONE; + GstBuffer *buffer; + + buffer = gst_aggregator_pad_peek_buffer (apad); + if (!buffer) { + if (!timeout && !GST_PAD_IS_EOS (apad)) { + gst_object_replace ((GstObject **) & best, NULL); + best_ts = GST_CLOCK_TIME_NONE; + done = TRUE; + } + break; + } - for (l = GST_ELEMENT_CAST (aggregator)->sinkpads; l; l = l->next) { - apad = GST_AGGREGATOR_PAD (l->data); - pad = GST_FLV_MUX_PAD (l->data); - buffer = gst_aggregator_pad_peek_buffer (GST_AGGREGATOR_PAD (pad)); - if (!buffer) - continue; - if (best_ts == GST_CLOCK_TIME_NONE) { - best = pad; - best_ts = gst_flv_mux_segment_to_running_time (&apad->segment, - GST_BUFFER_DTS_OR_PTS (buffer)); - } else if (GST_BUFFER_DTS_OR_PTS (buffer) != GST_CLOCK_TIME_NONE) { - gint64 t = gst_flv_mux_segment_to_running_time (&apad->segment, - GST_BUFFER_DTS_OR_PTS (buffer)); - if (t < best_ts) { - best = pad; - best_ts = t; + if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS_OR_PTS (buffer))) { + t = gst_flv_mux_segment_to_running_time (&apad->segment, + GST_BUFFER_DTS_OR_PTS (buffer)); + } + + if (!GST_CLOCK_TIME_IS_VALID (best_ts) || + (GST_CLOCK_TIME_IS_VALID (t) && t < best_ts)) { + gst_object_replace ((GstObject **) & best, GST_OBJECT (apad)); + best_ts = t; + } + gst_buffer_unref (buffer); + break; } + case GST_ITERATOR_DONE: + done = TRUE; + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (pads); + /* Clear the best pad and start again. It might have disappeared */ + gst_object_replace ((GstObject **) & best, NULL); + best_ts = GST_CLOCK_TIME_NONE; + break; + case GST_ITERATOR_ERROR: + /* This can't happen if the parameters to gst_iterator_next() are valid */ + g_assert_not_reached (); + break; } - gst_buffer_unref (buffer); + g_value_reset (&padptr); } - GST_DEBUG_OBJECT (aggregator, - "Best pad found with %" GST_TIME_FORMAT ": %" GST_PTR_FORMAT, - GST_TIME_ARGS (best_ts), best); + g_value_unset (&padptr); + gst_iterator_free (pads); + + if (best) { + GST_DEBUG_OBJECT (aggregator, + "Best pad found with TS %" GST_TIME_FORMAT ": %" GST_PTR_FORMAT, + GST_TIME_ARGS (best_ts), best); + } else { + GST_DEBUG_OBJECT (aggregator, "Best pad not found"); + } + if (ts) *ts = best_ts; return best; @@ -1846,12 +2001,21 @@ gst_flv_mux_aggregate (GstAggregator * aggregator, gboolean timeout) return GST_FLOW_ERROR; } + best = gst_flv_mux_find_best_pad (aggregator, &ts, timeout); + if (!best) { + if (!gst_flv_mux_are_all_pads_eos (mux)) + return GST_AGGREGATOR_FLOW_NEED_DATA; + else + return GST_FLOW_OK; + } + ret = gst_flv_mux_write_header (mux); - if (ret != GST_FLOW_OK) + if (ret != GST_FLOW_OK) { + gst_object_unref (best); return ret; - mux->state = GST_FLV_MUX_STATE_DATA; + } - best = gst_flv_mux_find_best_pad (aggregator, &ts); + mux->state = GST_FLV_MUX_STATE_DATA; if (!mux->streamable || mux->first_timestamp == GST_CLOCK_STIME_NONE) { if (best && GST_CLOCK_STIME_IS_VALID (ts)) @@ -1860,7 +2024,16 @@ gst_flv_mux_aggregate (GstAggregator * aggregator, gboolean timeout) mux->first_timestamp = 0; } } else { - best = gst_flv_mux_find_best_pad (aggregator, &ts); + best = gst_flv_mux_find_best_pad (aggregator, &ts, timeout); + } + + if (best) { + buffer = gst_aggregator_pad_pop_buffer (GST_AGGREGATOR_PAD (best)); + if (!buffer) { + /* We might have gotten a flush event after we picked the pad */ + gst_object_unref (best); + return GST_AGGREGATOR_FLOW_NEED_DATA; + } } if (mux->new_tags && mux->streamable) { @@ -1871,8 +2044,6 @@ gst_flv_mux_aggregate (GstAggregator * aggregator, gboolean timeout) } if (best) { - buffer = gst_aggregator_pad_pop_buffer (GST_AGGREGATOR_PAD (best)); - g_assert (buffer); best->dts = gst_flv_mux_segment_to_running_time (&GST_AGGREGATOR_PAD (best)->segment, GST_BUFFER_DTS_OR_PTS (buffer)); @@ -1891,6 +2062,8 @@ gst_flv_mux_aggregate (GstAggregator * aggregator, gboolean timeout) GST_STIME_FORMAT, GST_TIME_ARGS (best->pts), GST_STIME_ARGS (best->dts)); } else { + if (!gst_flv_mux_are_all_pads_eos (mux)) + return GST_AGGREGATOR_FLOW_NEED_DATA; best_time = GST_CLOCK_STIME_NONE; } @@ -1904,11 +2077,14 @@ gst_flv_mux_aggregate (GstAggregator * aggregator, gboolean timeout) gst_buffer_unref (buffer); buffer = NULL; } + gst_object_unref (best); best = NULL; } if (best) { - return gst_flv_mux_write_buffer (mux, best, buffer); + GstFlowReturn ret = gst_flv_mux_write_buffer (mux, best, buffer); + gst_object_unref (best); + return ret; } else { if (gst_flv_mux_are_all_pads_eos (mux)) { gst_flv_mux_write_eos (mux); @@ -1935,6 +2111,9 @@ gst_flv_mux_get_property (GObject * object, case PROP_ENCODER: g_value_set_string (value, mux->encoder); break; + case PROP_SKIP_BACKWARDS_STREAMS: + g_value_set_boolean (value, mux->skip_backwards_streams); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1975,6 +2154,9 @@ gst_flv_mux_set_property (GObject * object, mux->encoder = g_value_dup_string (value); } break; + case PROP_SKIP_BACKWARDS_STREAMS: + mux->skip_backwards_streams = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/gst/flv/gstflvmux.h b/gst/flv/gstflvmux.h index 45de460b39..8e350b2351 100644 --- a/gst/flv/gstflvmux.h +++ b/gst/flv/gstflvmux.h @@ -70,6 +70,7 @@ struct _GstFlvMuxPad gint64 dts; gboolean info_changed; + gboolean drop_deltas; }; struct _GstFlvMuxPadClass { @@ -94,6 +95,7 @@ struct _GstFlvMux { gboolean streamable; gchar *metadatacreator; gchar *encoder; + gboolean skip_backwards_streams; GstTagList *tags; gboolean new_tags; diff --git a/gst/imagefreeze/gstimagefreeze.c b/gst/imagefreeze/gstimagefreeze.c index 424ca0c432..e47a2a6b33 100644 --- a/gst/imagefreeze/gstimagefreeze.c +++ b/gst/imagefreeze/gstimagefreeze.c @@ -1,6 +1,7 @@ /* GStreamer * Copyright (c) 2005 Edward Hervey * Copyright (C) 2010 Sebastian Dröge + * Copyright (C) 2020 Sebastian Dröge * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -47,12 +48,14 @@ #define DEFAULT_NUM_BUFFERS -1 #define DEFAULT_ALLOW_REPLACE FALSE +#define DEFAULT_IS_LIVE FALSE enum { PROP_0, PROP_NUM_BUFFERS, PROP_ALLOW_REPLACE, + PROP_IS_LIVE, }; static void gst_image_freeze_finalize (GObject * object); @@ -61,6 +64,7 @@ static void gst_image_freeze_reset (GstImageFreeze * self); static GstStateChangeReturn gst_image_freeze_change_state (GstElement * element, GstStateChange transition); +static GstClock *gst_image_freeze_provide_clock (GstElement * element); static void gst_image_freeze_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); @@ -72,8 +76,8 @@ static gboolean gst_image_freeze_sink_event (GstPad * pad, GstObject * parent, GstEvent * event); static gboolean gst_image_freeze_sink_setcaps (GstImageFreeze * self, GstCaps * caps); -static GstCaps *gst_image_freeze_sink_getcaps (GstImageFreeze * self, - GstCaps * filter); +static GstCaps *gst_image_freeze_query_caps (GstImageFreeze * self, + GstPad * pad, GstCaps * filter); static gboolean gst_image_freeze_sink_query (GstPad * pad, GstObject * parent, GstQuery * query); static void gst_image_freeze_src_loop (GstPad * pad); @@ -119,8 +123,24 @@ gst_image_freeze_class_init (GstImageFreezeClass * klass) "Allow replacing the input buffer and always output the latest", DEFAULT_ALLOW_REPLACE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstImageFreeze:is-live + * + * Selects whether the output stream should be a non-live stream based on + * the segment configured via a %GST_EVENT_SEEK, or whether the output + * stream should be a live stream with the negotiated framerate. + * + * Since: 1.18 + */ + g_object_class_install_property (gobject_class, PROP_IS_LIVE, + g_param_spec_boolean ("is-live", "Is Live", + "Whether to output a live video stream", + DEFAULT_IS_LIVE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_image_freeze_change_state); + gstelement_class->provide_clock = + GST_DEBUG_FUNCPTR (gst_image_freeze_provide_clock); gst_element_class_set_static_metadata (gstelement_class, "Still frame stream generator", @@ -156,9 +176,11 @@ gst_image_freeze_init (GstImageFreeze * self) gst_element_add_pad (GST_ELEMENT (self), self->srcpad); g_mutex_init (&self->lock); + g_cond_init (&self->blocked_cond); self->num_buffers = DEFAULT_NUM_BUFFERS; self->allow_replace = DEFAULT_ALLOW_REPLACE; + self->is_live = DEFAULT_IS_LIVE; gst_image_freeze_reset (self); } @@ -173,6 +195,7 @@ gst_image_freeze_finalize (GObject * object) gst_image_freeze_reset (self); g_mutex_clear (&self->lock); + g_cond_clear (&self->blocked_cond); G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -186,19 +209,17 @@ gst_image_freeze_reset (GstImageFreeze * self) gst_buffer_replace (&self->buffer, NULL); gst_caps_replace (&self->buffer_caps, NULL); gst_caps_replace (&self->current_caps, NULL); - self->buffer_caps_updated = FALSE; self->num_buffers_left = self->num_buffers; gst_segment_init (&self->segment, GST_FORMAT_TIME); self->need_segment = TRUE; + self->flushing = TRUE; self->negotiated_framerate = FALSE; self->fps_n = self->fps_d = 0; self->offset = 0; self->seqnum = 0; g_mutex_unlock (&self->lock); - - g_atomic_int_set (&self->seeking, 0); } static gboolean @@ -221,9 +242,9 @@ gst_image_freeze_sink_setcaps (GstImageFreeze * self, GstCaps * caps) gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL); GST_DEBUG_OBJECT (pad, "Setting caps %" GST_PTR_FORMAT, caps); - ret = gst_pad_set_caps (self->srcpad, caps); + gst_pad_set_caps (self->srcpad, caps); gst_caps_unref (caps); - return ret; + return TRUE; } /* Else negotiate a framerate with downstream */ @@ -261,23 +282,24 @@ gst_image_freeze_sink_setcaps (GstImageFreeze * self, GstCaps * caps) for (i = 0; i < n; i++) { GstCaps *candidate = gst_caps_new_empty (); GstStructure *s = gst_structure_copy (gst_caps_get_structure (caps, i)); + GstCapsFeatures *f = + gst_caps_features_copy (gst_caps_get_features (caps, i)); - gst_caps_append_structure (candidate, s); + gst_caps_append_structure_full (candidate, s, f); if (gst_structure_has_field_typed (s, "framerate", GST_TYPE_FRACTION) || gst_structure_fixate_field_nearest_fraction (s, "framerate", 25, 1)) { gst_structure_get_fraction (s, "framerate", &fps_n, &fps_d); if (fps_d != 0) { - if (gst_pad_set_caps (self->srcpad, candidate)) { - g_mutex_lock (&self->lock); - self->fps_n = fps_n; - self->fps_d = fps_d; - g_mutex_unlock (&self->lock); - self->negotiated_framerate = TRUE; - GST_DEBUG_OBJECT (pad, "Setting caps %" GST_PTR_FORMAT, candidate); - ret = TRUE; - gst_caps_unref (candidate); - break; - } + gst_pad_set_caps (self->srcpad, candidate); + g_mutex_lock (&self->lock); + self->fps_n = fps_n; + self->fps_d = fps_d; + g_mutex_unlock (&self->lock); + self->negotiated_framerate = TRUE; + GST_DEBUG_OBJECT (pad, "Setting caps %" GST_PTR_FORMAT, candidate); + ret = TRUE; + gst_caps_unref (candidate); + break; } else { GST_WARNING_OBJECT (pad, "Invalid caps with framerate %d/%d", fps_n, fps_d); @@ -311,25 +333,26 @@ gst_image_freeze_remove_fps (GstImageFreeze * self, GstCaps * caps) } static GstCaps * -gst_image_freeze_sink_getcaps (GstImageFreeze * self, GstCaps * filter) +gst_image_freeze_query_caps (GstImageFreeze * self, GstPad * pad, + GstCaps * filter) { GstCaps *ret, *tmp, *templ; - GstPad *pad; + GstPad *otherpad; - pad = self->sinkpad; + otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad; if (filter) { filter = gst_caps_copy (filter); gst_image_freeze_remove_fps (self, filter); } templ = gst_pad_get_pad_template_caps (pad); - tmp = gst_pad_peer_query_caps (self->srcpad, filter); + tmp = gst_pad_peer_query_caps (otherpad, filter); if (tmp) { - GST_LOG_OBJECT (self, "peer caps %" GST_PTR_FORMAT, tmp); + GST_LOG_OBJECT (otherpad, "peer caps %" GST_PTR_FORMAT, tmp); ret = gst_caps_intersect (tmp, templ); gst_caps_unref (tmp); } else { - GST_LOG_OBJECT (self, "going to copy"); + GST_LOG_OBJECT (otherpad, "going to copy"); ret = gst_caps_copy (templ); } if (templ) @@ -360,7 +383,7 @@ gst_image_freeze_sink_query (GstPad * pad, GstObject * parent, GstQuery * query) GstCaps *caps; gst_query_parse_caps (query, &caps); - caps = gst_image_freeze_sink_getcaps (self, caps); + caps = gst_image_freeze_query_caps (self, pad, caps); gst_query_set_caps_result (query, caps); gst_caps_unref (caps); ret = TRUE; @@ -532,21 +555,44 @@ gst_image_freeze_src_query (GstPad * pad, GstObject * parent, GstQuery * query) gboolean seekable; gst_query_parse_seeking (query, &format, NULL, NULL, NULL); - seekable = (format == GST_FORMAT_TIME || format == GST_FORMAT_DEFAULT); + seekable = !self->is_live && (format == GST_FORMAT_TIME + || format == GST_FORMAT_DEFAULT); gst_query_set_seeking (query, format, seekable, (seekable ? 0 : -1), -1); ret = TRUE; break; } case GST_QUERY_LATENCY: - /* This will only return an accurate latency for the first buffer since - * all further buffers outputted by us are just copies of that one, and - * the latency is 0 in that case. However, latency changes are not - * straightforward, so let's do the conservative fix for now. */ - ret = gst_pad_query_default (pad, parent, query); + if (self->is_live) { + /* If we run live, we output the buffer without any latency but allow + * for at most one frame of latency. If downstream takes longer to + * consume out frame we would skip ahead */ + if (self->fps_n > 0 && self->fps_d > 0) + gst_query_set_latency (query, TRUE, 0, + gst_util_uint64_scale_ceil (GST_SECOND, self->fps_d, + self->fps_n)); + else + gst_query_set_latency (query, TRUE, 0, GST_CLOCK_TIME_NONE); + } else { + /* If we don't run live, even if upstream is live, we never output any + * buffers with latency but immediately generate buffers as fast as we + * can according to the negotiated framerate */ + gst_query_set_latency (query, FALSE, 0, GST_CLOCK_TIME_NONE); + } + ret = TRUE; break; + case GST_QUERY_CAPS: + { + GstCaps *caps; + gst_query_parse_caps (query, &caps); + caps = gst_image_freeze_query_caps (self, pad, caps); + gst_query_set_caps_result (query, caps); + gst_caps_unref (caps); + ret = TRUE; + break; + } default: - ret = FALSE; + ret = gst_pad_query_default (pad, parent, query); break; } @@ -592,7 +638,10 @@ gst_image_freeze_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) gst_image_freeze_reset (self); /* fall through */ default: - ret = gst_pad_push_event (self->srcpad, event); + ret = gst_pad_push_event (self->srcpad, gst_event_ref (event)); + if (GST_EVENT_IS_STICKY (event)) + ret = TRUE; + gst_event_unref (event); break; } @@ -627,6 +676,13 @@ gst_image_freeze_src_event (GstPad * pad, GstObject * parent, GstEvent * event) gboolean flush; guint32 seqnum; + if (self->is_live) { + GST_ERROR_OBJECT (pad, "Can't seek in live mode"); + ret = FALSE; + gst_event_unref (event); + break; + } + seqnum = gst_event_get_seqnum (event); gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, &stop_type, &stop); @@ -658,7 +714,10 @@ gst_image_freeze_src_event (GstPad * pad, GstObject * parent, GstEvent * event) if (flush) { GstEvent *e; - g_atomic_int_set (&self->seeking, 1); + g_mutex_lock (&self->lock); + self->flushing = TRUE; + g_mutex_unlock (&self->lock); + e = gst_event_new_flush_start (); gst_event_set_seqnum (e, seqnum); gst_pad_push_event (self->srcpad, e); @@ -676,6 +735,7 @@ gst_image_freeze_src_event (GstPad * pad, GstObject * parent, GstEvent * event) last_stop = self->segment.position; start_task = self->buffer != NULL; + self->flushing = FALSE; g_mutex_unlock (&self->lock); if (flush) { @@ -684,7 +744,6 @@ gst_image_freeze_src_event (GstPad * pad, GstObject * parent, GstEvent * event) e = gst_event_new_flush_stop (TRUE); gst_event_set_seqnum (e, seqnum); gst_pad_push_event (self->srcpad, e); - g_atomic_int_set (&self->seeking, 0); } if (flags & GST_SEEK_FLAG_SEGMENT) { @@ -714,8 +773,18 @@ gst_image_freeze_src_event (GstPad * pad, GstObject * parent, GstEvent * event) break; } case GST_EVENT_FLUSH_START: + g_mutex_lock (&self->lock); + self->flushing = TRUE; + g_mutex_unlock (&self->lock); + ret = gst_pad_push_event (self->sinkpad, event); + break; + case GST_EVENT_FLUSH_STOP: gst_image_freeze_reset (self); - /* fall through */ + g_mutex_lock (&self->lock); + self->flushing = FALSE; + g_mutex_unlock (&self->lock); + ret = gst_pad_push_event (self->sinkpad, event); + break; default: ret = gst_pad_push_event (self->sinkpad, event); break; @@ -739,6 +808,9 @@ gst_image_freeze_set_property (GObject * object, guint prop_id, case PROP_ALLOW_REPLACE: self->allow_replace = g_value_get_boolean (value); break; + case PROP_IS_LIVE: + self->is_live = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -760,6 +832,9 @@ gst_image_freeze_get_property (GObject * object, guint prop_id, GValue * value, case PROP_ALLOW_REPLACE: g_value_set_boolean (value, self->allow_replace); break; + case PROP_IS_LIVE: + g_value_set_boolean (value, self->is_live); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -788,8 +863,9 @@ gst_image_freeze_sink_chain (GstPad * pad, GstObject * parent, } gst_buffer_replace (&self->buffer, buffer); - self->buffer_caps_updated = !self->buffer_caps - || !gst_caps_is_equal (self->buffer_caps, self->current_caps); + if (!self->buffer_caps + || !gst_caps_is_equal (self->buffer_caps, self->current_caps)) + gst_pad_mark_reconfigure (self->srcpad); gst_caps_replace (&self->buffer_caps, self->current_caps); gst_buffer_unref (buffer); @@ -813,35 +889,53 @@ gst_image_freeze_src_loop (GstPad * pad) gboolean first = FALSE; g_mutex_lock (&self->lock); - if (!self->buffer) { + if (self->flushing) { + GST_DEBUG_OBJECT (pad, "Flushing"); + flow_ret = GST_FLOW_FLUSHING; + g_mutex_unlock (&self->lock); + goto pause_task; + } else if (!self->buffer) { GST_ERROR_OBJECT (pad, "Have no buffer yet"); flow_ret = GST_FLOW_ERROR; g_mutex_unlock (&self->lock); goto pause_task; } + g_assert (self->buffer); + + /* Take a new reference of the buffer here so we're guaranteed to have one + * in all the following code even if it disappears while we temporarily + * unlock the mutex */ + buffer = gst_buffer_ref (self->buffer); + + if (gst_pad_check_reconfigure (self->srcpad)) { + GstCaps *buffer_caps = gst_caps_ref (self->buffer_caps); + g_mutex_unlock (&self->lock); + if (!gst_image_freeze_sink_setcaps (self, buffer_caps)) { + gst_caps_unref (buffer_caps); + gst_buffer_unref (buffer); + gst_pad_mark_reconfigure (self->srcpad); + flow_ret = GST_FLOW_NOT_NEGOTIATED; + goto pause_task; + } + gst_caps_unref (buffer_caps); + g_mutex_lock (&self->lock); + } + /* normally we don't count buffers */ if (G_UNLIKELY (self->num_buffers_left >= 0)) { GST_DEBUG_OBJECT (pad, "Buffers left %d", self->num_buffers_left); if (self->num_buffers_left == 0) { flow_ret = GST_FLOW_EOS; + gst_buffer_unref (buffer); g_mutex_unlock (&self->lock); goto pause_task; } else { self->num_buffers_left--; } } - buffer = gst_buffer_copy (self->buffer); - - if (self->buffer_caps_updated) { - GstCaps *buffer_caps = gst_caps_ref (self->buffer_caps); - self->buffer_caps_updated = FALSE; - g_mutex_unlock (&self->lock); - gst_image_freeze_sink_setcaps (self, buffer_caps); - gst_caps_unref (buffer_caps); - } else { - g_mutex_unlock (&self->lock); - } + buffer = gst_buffer_make_writable (buffer); + g_mutex_unlock (&self->lock); if (self->need_segment) { GstEvent *e; @@ -873,16 +967,102 @@ gst_image_freeze_src_loop (GstPad * pad) g_mutex_lock (&self->lock); offset = self->offset; + if (self->is_live) { + GstClockTime base_time, clock_time; + GstClockTimeDiff jitter; + GstClockReturn clock_ret; + GstClock *clock; + + clock = gst_element_get_clock (GST_ELEMENT (self)); + + /* Wait until the element went to PLAYING or flushing */ + while ((!clock || self->blocked) && !self->flushing) { + g_cond_wait (&self->blocked_cond, &self->lock); + gst_clear_object (&clock); + clock = gst_element_get_clock (GST_ELEMENT (self)); + } - if (self->fps_n != 0) { - timestamp = - gst_util_uint64_scale (offset, self->fps_d * GST_SECOND, self->fps_n); - timestamp_end = - gst_util_uint64_scale (offset + 1, self->fps_d * GST_SECOND, - self->fps_n); + if (self->flushing) { + g_mutex_unlock (&self->lock); + gst_buffer_unref (buffer); + flow_ret = GST_FLOW_FLUSHING; + gst_clear_object (&clock); + goto pause_task; + } + + /* Wait on the clock until the time for our current frame is reached */ + base_time = gst_element_get_base_time (GST_ELEMENT (self)); + if (self->fps_n != 0) { + clock_time = + base_time + gst_util_uint64_scale (offset, self->fps_d * GST_SECOND, + self->fps_n); + } else { + clock_time = base_time; + } + + self->clock_id = gst_clock_new_single_shot_id (clock, clock_time); + g_mutex_unlock (&self->lock); + GST_TRACE_OBJECT (self, + "Waiting for %" GST_TIME_FORMAT ", now %" GST_TIME_FORMAT, + GST_TIME_ARGS (clock_time), GST_TIME_ARGS (gst_clock_get_time (clock))); + clock_ret = gst_clock_id_wait (self->clock_id, &jitter); + GST_TRACE_OBJECT (self, + "Waited for %" GST_TIME_FORMAT ", clock ret %d, jitter %" + GST_STIME_FORMAT, GST_TIME_ARGS (clock_time), clock_ret, + GST_STIME_ARGS (jitter)); + g_mutex_lock (&self->lock); + gst_clock_id_unref (self->clock_id); + self->clock_id = NULL; + gst_object_unref (clock); + + if (self->flushing || clock_ret == GST_CLOCK_UNSCHEDULED) { + g_mutex_unlock (&self->lock); + gst_buffer_unref (buffer); + flow_ret = GST_FLOW_FLUSHING; + goto pause_task; + } + + /* If we were late, adjust our offset and jump ahead if needed */ + if (self->fps_n != 0) { + if (jitter > 0) { + guint64 new_offset = + gst_util_uint64_scale (clock_time + jitter - base_time, self->fps_n, + self->fps_d * GST_SECOND); + + if (new_offset != offset) { + GST_INFO_OBJECT (self, + "Late by %" GST_TIME_FORMAT ", old offset %" G_GUINT64_FORMAT + ", new offset %" G_GUINT64_FORMAT, GST_TIME_ARGS (jitter), offset, + new_offset); + self->offset = offset = new_offset; + } + } + + timestamp = + gst_util_uint64_scale (offset, self->fps_d * GST_SECOND, self->fps_n); + timestamp_end = + gst_util_uint64_scale (offset + 1, self->fps_d * GST_SECOND, + self->fps_n); + } else { + /* If we have no framerate then we output a single frame now */ + if (jitter > 0) + timestamp = jitter; + else + timestamp = 0; + + timestamp_end = GST_CLOCK_TIME_NONE; + } } else { - timestamp = self->segment.start; - timestamp_end = GST_CLOCK_TIME_NONE; + if (self->fps_n != 0) { + timestamp = + gst_util_uint64_scale (offset, self->fps_d * GST_SECOND, self->fps_n); + timestamp_end = + gst_util_uint64_scale (offset + 1, self->fps_d * GST_SECOND, + self->fps_n); + } else { + timestamp = self->segment.start; + timestamp_end = GST_CLOCK_TIME_NONE; + } } eos = (self->fps_n == 0 && offset > 0) || @@ -991,14 +1171,36 @@ gst_image_freeze_change_state (GstElement * element, GstStateChange transition) { GstImageFreeze *self = GST_IMAGE_FREEZE (element); GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + gboolean no_preroll = FALSE; switch (transition) { case GST_STATE_CHANGE_READY_TO_PAUSED: gst_image_freeze_reset (self); + g_mutex_lock (&self->lock); + self->flushing = FALSE; + self->blocked = TRUE; + g_mutex_unlock (&self->lock); + if (self->is_live) + no_preroll = TRUE; + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + g_mutex_lock (&self->lock); + self->blocked = FALSE; + g_cond_signal (&self->blocked_cond); + g_mutex_unlock (&self->lock); break; case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_pad_stop_task (self->srcpad); + g_mutex_lock (&self->lock); + self->flushing = TRUE; + if (self->clock_id) { + GST_DEBUG_OBJECT (self, "unlock clock wait"); + gst_clock_id_unschedule (self->clock_id); + } + self->blocked = FALSE; + g_cond_signal (&self->blocked_cond); + g_mutex_unlock (&self->lock); gst_image_freeze_reset (self); + gst_pad_stop_task (self->srcpad); break; default: break; @@ -1008,13 +1210,30 @@ gst_image_freeze_change_state (GstElement * element, GstStateChange transition) ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); switch (transition) { + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + g_mutex_lock (&self->lock); + self->blocked = TRUE; + g_mutex_unlock (&self->lock); + if (self->is_live) + no_preroll = TRUE; + break; default: break; } + if (no_preroll && ret == GST_STATE_CHANGE_SUCCESS) + ret = GST_STATE_CHANGE_NO_PREROLL; + return ret; } +/* FIXME: GStreamer 2.0 */ +static GstClock * +gst_image_freeze_provide_clock (GstElement * element) +{ + return gst_system_clock_obtain (); +} + static gboolean plugin_init (GstPlugin * plugin) { diff --git a/gst/imagefreeze/gstimagefreeze.h b/gst/imagefreeze/gstimagefreeze.h index 779c676f19..d23feaa973 100644 --- a/gst/imagefreeze/gstimagefreeze.h +++ b/gst/imagefreeze/gstimagefreeze.h @@ -50,7 +50,6 @@ struct _GstImageFreeze GMutex lock; GstBuffer *buffer; GstCaps *buffer_caps, *current_caps; - gboolean buffer_caps_updated; gboolean negotiated_framerate; gint fps_n, fps_d; @@ -64,11 +63,14 @@ struct _GstImageFreeze gboolean allow_replace; + gboolean is_live; + gboolean blocked; + GCond blocked_cond; + GstClockID clock_id; + guint64 offset; - /* TRUE if currently doing a flushing seek, protected - * by srcpad's stream lock */ - gint seeking; + gboolean flushing; }; struct _GstImageFreezeClass diff --git a/gst/isomp4/atoms.c b/gst/isomp4/atoms.c index e1441d468c..8dd493e15e 100644 --- a/gst/isomp4/atoms.c +++ b/gst/isomp4/atoms.c @@ -54,10 +54,11 @@ * Creates a new AtomsContext for the given flavor. */ AtomsContext * -atoms_context_new (AtomsTreeFlavor flavor) +atoms_context_new (AtomsTreeFlavor flavor, gboolean force_create_timecode_trak) { AtomsContext *context = g_new0 (AtomsContext, 1); context->flavor = flavor; + context->force_create_timecode_trak = force_create_timecode_trak; return context; } @@ -493,6 +494,34 @@ atom_gmhd_free (AtomGMHD * gmhd) g_free (gmhd); } +static void +atom_nmhd_init (AtomNMHD * nmhd) +{ + atom_header_set (&nmhd->header, FOURCC_nmhd, 0, 0); + nmhd->flags = 0; +} + +static void +atom_nmhd_clear (AtomNMHD * nmhd) +{ + atom_clear (&nmhd->header); +} + +static AtomNMHD * +atom_nmhd_new (void) +{ + AtomNMHD *nmhd = g_new0 (AtomNMHD, 1); + atom_nmhd_init (nmhd); + return nmhd; +} + +static void +atom_nmhd_free (AtomNMHD * nmhd) +{ + atom_nmhd_clear (nmhd); + g_free (nmhd); +} + static void atom_sample_entry_init (SampleTableEntry * se, guint32 type) { @@ -735,6 +764,8 @@ atom_ctts_free (AtomCTTS * ctts) g_free (ctts); } +/* svmi is specified in ISO 23000-11 (Stereoscopic video application format) + * MPEG-A */ static void atom_svmi_init (AtomSVMI * svmi) { @@ -819,6 +850,9 @@ atom_co64_init (AtomSTCO64 * co64) guint8 flags[3] = { 0, 0, 0 }; atom_full_init (&co64->header, FOURCC_stco, 0, 0, 0, flags); + + co64->chunk_offset = 0; + co64->max_offset = 0; atom_array_init (&co64->entries, 256); } @@ -1129,6 +1163,10 @@ atom_minf_clear_handlers (AtomMINF * minf) atom_gmhd_free (minf->gmhd); minf->gmhd = NULL; } + if (minf->nmhd) { + atom_nmhd_free (minf->nmhd); + minf->nmhd = NULL; + } } static void @@ -1955,6 +1993,21 @@ atom_gmhd_copy_data (AtomGMHD * gmhd, guint8 ** buffer, guint64 * size, return original_offset - *offset; } +static guint64 +atom_nmhd_copy_data (AtomNMHD * nmhd, guint8 ** buffer, guint64 * size, + guint64 * offset) +{ + guint64 original_offset = *offset; + + if (!atom_copy_data (&nmhd->header, buffer, size, offset)) { + return 0; + } + prop_copy_uint32 (nmhd->flags, buffer, size, offset); + + atom_write_size (buffer, size, offset, original_offset); + return original_offset - *offset; +} + static gboolean atom_url_same_file_flag (AtomURL * url) { @@ -2368,7 +2421,17 @@ atom_stco64_copy_data (AtomSTCO64 * stco64, guint8 ** buffer, guint64 * size, { guint64 original_offset = *offset; guint i; - gboolean trunc_to_32 = stco64->header.header.type == FOURCC_stco; + + /* If any (mdat-relative) offset will by over 32-bits when converted to an + * absolute file offset then we need to write a 64-bit co64 atom, otherwise + * we can write a smaller stco 32-bit table */ + gboolean write_stco64 = + (stco64->max_offset + stco64->chunk_offset) > G_MAXUINT32; + + if (write_stco64) + stco64->header.header.type = FOURCC_co64; + else + stco64->header.header.type = FOURCC_stco; if (!atom_full_copy_data (&stco64->header, buffer, size, offset)) { return 0; @@ -2384,10 +2447,10 @@ atom_stco64_copy_data (AtomSTCO64 * stco64, guint8 ** buffer, guint64 * size, guint64 value = atom_array_index (&stco64->entries, i) + stco64->chunk_offset; - if (trunc_to_32) { - prop_copy_uint32 ((guint32) value, buffer, size, offset); - } else { + if (write_stco64) { prop_copy_uint64 (value, buffer, size, offset); + } else { + prop_copy_uint32 ((guint32) value, buffer, size, offset); } } @@ -2620,6 +2683,10 @@ atom_minf_copy_data (AtomMINF * minf, guint8 ** buffer, guint64 * size, if (!atom_gmhd_copy_data (minf->gmhd, buffer, size, offset)) { return 0; } + } else if (minf->nmhd) { + if (!atom_nmhd_copy_data (minf->nmhd, buffer, size, offset)) { + return 0; + } } if (minf->hdlr) { @@ -3109,8 +3176,8 @@ atom_stco64_add_entry (AtomSTCO64 * stco64, guint64 entry) return FALSE; atom_array_append (&stco64->entries, entry, 256); - if (entry > G_MAXUINT32) - stco64->header.header.type = FOURCC_co64; + if (entry > stco64->max_offset) + stco64->max_offset = entry; return TRUE; } @@ -4076,24 +4143,36 @@ atom_trak_set_timecode_type (AtomTRAK * trak, AtomsContext * context, guint32 trak_timescale, GstVideoTimeCode * tc) { SampleTableEntryTMCD *ste; - AtomGMHD *gmhd = trak->mdia.minf.gmhd; - if (context->flavor != ATOMS_TREE_FLAVOR_MOV) { + if (context->flavor != ATOMS_TREE_FLAVOR_MOV && + !context->force_create_timecode_trak) { return NULL; } - ste = atom_trak_add_timecode_entry (trak, context, trak_timescale, tc); - - gmhd = atom_gmhd_new (); - gmhd->gmin.graphics_mode = 0x0040; - gmhd->gmin.opcolor[0] = 0x8000; - gmhd->gmin.opcolor[1] = 0x8000; - gmhd->gmin.opcolor[2] = 0x8000; - gmhd->tmcd = atom_tmcd_new (); - gmhd->tmcd->tcmi.text_size = 12; - gmhd->tmcd->tcmi.font_name = g_strdup ("Chicago"); /* Pascal string */ - trak->mdia.minf.gmhd = gmhd; + if (context->flavor == ATOMS_TREE_FLAVOR_MOV) { + AtomGMHD *gmhd = trak->mdia.minf.gmhd; + + gmhd = atom_gmhd_new (); + gmhd->gmin.graphics_mode = 0x0040; + gmhd->gmin.opcolor[0] = 0x8000; + gmhd->gmin.opcolor[1] = 0x8000; + gmhd->gmin.opcolor[2] = 0x8000; + gmhd->tmcd = atom_tmcd_new (); + gmhd->tmcd->tcmi.text_size = 12; + gmhd->tmcd->tcmi.font_name = g_strdup ("Chicago"); /* Pascal string */ + + trak->mdia.minf.gmhd = gmhd; + } else if (context->force_create_timecode_trak) { + AtomNMHD *nmhd = trak->mdia.minf.nmhd; + /* MOV files use GMHD, other files use NMHD */ + + nmhd = atom_nmhd_new (); + trak->mdia.minf.nmhd = nmhd; + } else { + return NULL; + } + ste = atom_trak_add_timecode_entry (trak, context, trak_timescale, tc); trak->is_video = FALSE; trak->is_h264 = FALSE; @@ -4194,7 +4273,8 @@ build_colr_extension (const GstVideoColorimetry * colorimetry, gboolean is_mp4) guint16 matrix; primaries = gst_video_color_primaries_to_iso (colorimetry->primaries); - transfer_function = gst_video_color_transfer_to_iso (colorimetry->transfer); + transfer_function = + gst_video_transfer_function_to_iso (colorimetry->transfer); matrix = gst_video_color_matrix_to_iso (colorimetry->matrix); atom_data_alloc_mem (atom_data, 10 + (is_mp4 ? 1 : 0)); diff --git a/gst/isomp4/atoms.h b/gst/isomp4/atoms.h index de93e22fda..d176d8e168 100644 --- a/gst/isomp4/atoms.h +++ b/gst/isomp4/atoms.h @@ -103,9 +103,10 @@ typedef enum _AtomsTreeFlavor typedef struct _AtomsContext { AtomsTreeFlavor flavor; + gboolean force_create_timecode_trak; } AtomsContext; -AtomsContext* atoms_context_new (AtomsTreeFlavor flavor); +AtomsContext* atoms_context_new (AtomsTreeFlavor flavor, gboolean force_create_timecode_trak); void atoms_context_free (AtomsContext *context); #define METADATA_DATA_FLAG 0x0 @@ -325,6 +326,12 @@ typedef struct _AtomGMHD } AtomGMHD; +typedef struct _AtomNMHD +{ + Atom header; + guint32 flags; +} AtomNMHD; + typedef struct _AtomURL { AtomFull header; @@ -541,13 +548,17 @@ typedef struct _AtomTREF /* * used for both STCO and CO64 - * if used as STCO, entries should be truncated to use only 32bits + * The table will be written out as STCO automatically when + * the offsets being written will fit in a 32-bit table, + * otherwise it is written as CO64 */ typedef struct _AtomSTCO64 { AtomFull header; /* Global offset to add to entries when serialising */ guint32 chunk_offset; + /* Maximum offset stored in the table */ + guint64 max_offset; ATOM_ARRAY (guint64) entries; } AtomSTCO64; @@ -600,6 +611,7 @@ typedef struct _AtomMINF AtomSMHD *smhd; AtomHMHD *hmhd; AtomGMHD *gmhd; + AtomNMHD *nmhd; AtomHDLR *hdlr; AtomDINF dinf; diff --git a/gst/isomp4/fourcc.h b/gst/isomp4/fourcc.h index 6c425e6f98..7952d8e3a0 100644 --- a/gst/isomp4/fourcc.h +++ b/gst/isomp4/fourcc.h @@ -130,6 +130,11 @@ G_BEGIN_DECLS #define FOURCC_dvc_ GST_MAKE_FOURCC('d','v','c',' ') #define FOURCC_dv5p GST_MAKE_FOURCC('d','v','5','p') #define FOURCC_dv5n GST_MAKE_FOURCC('d','v','5','n') +#define FOURCC_dva1 GST_MAKE_FOURCC('d','v','a','1') +#define FOURCC_dvav GST_MAKE_FOURCC('d','v','a','v') +#define FOURCC_dvh1 GST_MAKE_FOURCC('d','v','h','1') +#define FOURCC_dvhe GST_MAKE_FOURCC('d','v','h','e') +#define FOURCC_dvcC GST_MAKE_FOURCC('d','v','c','C') #define FOURCC_edts GST_MAKE_FOURCC('e','d','t','s') #define FOURCC_elst GST_MAKE_FOURCC('e','l','s','t') #define FOURCC_enda GST_MAKE_FOURCC('e','n','d','a') @@ -156,7 +161,11 @@ G_BEGIN_DECLS #define FOURCC_ilst GST_MAKE_FOURCC('i','l','s','t') #define FOURCC_ima4 GST_MAKE_FOURCC('i','m','a','4') #define FOURCC_imap GST_MAKE_FOURCC('i','m','a','p') +#define FOURCC_s16l GST_MAKE_FOURCC('s','1','6','l') #define FOURCC_in24 GST_MAKE_FOURCC('i','n','2','4') +#define FOURCC_in32 GST_MAKE_FOURCC('i','n','3','2') +#define FOURCC_fl64 GST_MAKE_FOURCC('f','l','6','4') +#define FOURCC_fl32 GST_MAKE_FOURCC('f','l','3','2') #define FOURCC_jp2c GST_MAKE_FOURCC('j','p','2','c') #define FOURCC_jpeg GST_MAKE_FOURCC('j','p','e','g') #define FOURCC_keyw GST_MAKE_FOURCC('k','e','y','w') @@ -173,6 +182,7 @@ G_BEGIN_DECLS #define FOURCC_mhlr GST_MAKE_FOURCC('m','h','l','r') #define FOURCC_minf GST_MAKE_FOURCC('m','i','n','f') #define FOURCC_moov GST_MAKE_FOURCC('m','o','o','v') +#define FOURCC_mp3_ GST_MAKE_FOURCC('m','p','3',' ') #define FOURCC_mp4a GST_MAKE_FOURCC('m','p','4','a') #define FOURCC_mp4s GST_MAKE_FOURCC('m','p','4','s') #define FOURCC_mp4s GST_MAKE_FOURCC('m','p','4','s') @@ -180,6 +190,7 @@ G_BEGIN_DECLS #define FOURCC_name GST_MAKE_FOURCC('n','a','m','e') #define FOURCC_nclc GST_MAKE_FOURCC('n','c','l','c') #define FOURCC_nclx GST_MAKE_FOURCC('n','c','l','x') +#define FOURCC_nmhd GST_MAKE_FOURCC('n','m','h','d') #define FOURCC_opus GST_MAKE_FOURCC('O','p','u','s') #define FOURCC_dops GST_MAKE_FOURCC('d','O','p','s') #define FOURCC_pasp GST_MAKE_FOURCC('p','a','s','p') @@ -259,6 +270,7 @@ G_BEGIN_DECLS #define FOURCC_vmhd GST_MAKE_FOURCC('v','m','h','d') #define FOURCC_vp08 GST_MAKE_FOURCC('v','p','0','8') #define FOURCC_vp09 GST_MAKE_FOURCC('v','p','0','9') +#define FOURCC_vpcC GST_MAKE_FOURCC('v','p','c','C') #define FOURCC_xvid GST_MAKE_FOURCC('x','v','i','d') #define FOURCC_wave GST_MAKE_FOURCC('w','a','v','e') #define FOURCC_wide GST_MAKE_FOURCC('w','i','d','e') diff --git a/gst/isomp4/gstqtmux.c b/gst/isomp4/gstqtmux.c index 21ccba194b..9631b09b30 100644 --- a/gst/isomp4/gstqtmux.c +++ b/gst/isomp4/gstqtmux.c @@ -366,8 +366,10 @@ enum PROP_DO_CTTS, PROP_INTERLEAVE_BYTES, PROP_INTERLEAVE_TIME, + PROP_FORCE_CHUNKS, PROP_MAX_RAW_AUDIO_DRIFT, PROP_START_GAP_THRESHOLD, + PROP_FORCE_CREATE_TIMECODE_TRAK, }; /* some spare for header size as well */ @@ -390,8 +392,10 @@ enum #define DEFAULT_RESERVED_PREFILL FALSE #define DEFAULT_INTERLEAVE_BYTES 0 #define DEFAULT_INTERLEAVE_TIME 250*GST_MSECOND +#define DEFAULT_FORCE_CHUNKS (FALSE) #define DEFAULT_MAX_RAW_AUDIO_DRIFT 40 * GST_MSECOND #define DEFAULT_START_GAP_THRESHOLD 0 +#define DEFAULT_FORCE_CREATE_TIMECODE_TRAK FALSE static void gst_qt_mux_finalize (GObject * object); @@ -409,6 +413,8 @@ static void gst_qt_mux_release_pad (GstElement * element, GstPad * pad); /* event */ static gboolean gst_qt_mux_sink_event (GstAggregator * agg, GstAggregatorPad * agg_pad, GstEvent * event); +static GstFlowReturn gst_qt_mux_sink_event_pre_queue (GstAggregator * self, + GstAggregatorPad * aggpad, GstEvent * event); /* aggregator */ static GstAggregatorPad *gst_qt_mux_create_new_pad (GstAggregator * self, @@ -453,7 +459,7 @@ gst_qt_mux_base_init (gpointer g_class) longname = g_strdup_printf ("%s Muxer", params->prop->long_name); description = g_strdup_printf ("Multiplex audio and video into a %s file", params->prop->long_name); - gst_element_class_set_static_metadata (element_class, longname, + gst_element_class_set_metadata (element_class, longname, "Codec/Muxer", description, "Thiago Sousa Santos "); g_free (longname); @@ -623,6 +629,10 @@ gst_qt_mux_class_init (GstQTMuxClass * klass) "Interleave between streams in nanoseconds", 0, G_MAXUINT64, DEFAULT_INTERLEAVE_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_FORCE_CHUNKS, + g_param_spec_boolean ("force-chunks", "Force Chunks", + "Force multiple chunks to be created even for single-stream files", + DEFAULT_FORCE_CHUNKS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_MAX_RAW_AUDIO_DRIFT, g_param_spec_uint64 ("max-raw-audio-drift", "Max Raw Audio Drift", "Maximum allowed drift of raw audio samples vs. timestamps in nanoseconds", @@ -633,17 +643,28 @@ gst_qt_mux_class_init (GstQTMuxClass * klass) "Threshold for creating an edit list for gaps at the start in nanoseconds", 0, G_MAXUINT64, DEFAULT_START_GAP_THRESHOLD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, + PROP_FORCE_CREATE_TIMECODE_TRAK, + g_param_spec_boolean ("force-create-timecode-trak", + "Force Create Timecode Trak", + "Create a timecode trak even in unsupported flavors", + DEFAULT_FORCE_CREATE_TIMECODE_TRAK, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR (gst_qt_mux_request_new_pad); gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_qt_mux_release_pad); gstagg_class->sink_event = gst_qt_mux_sink_event; + gstagg_class->sink_event_pre_queue = gst_qt_mux_sink_event_pre_queue; gstagg_class->aggregate = gst_qt_mux_aggregate; gstagg_class->clip = gst_qt_mux_clip_running_time; gstagg_class->start = gst_qt_mux_start; gstagg_class->stop = gst_qt_mux_stop; gstagg_class->create_new_pad = gst_qt_mux_create_new_pad; + + gst_type_mark_as_plugin_api (GST_TYPE_QT_MUX_PAD, 0); + gst_type_mark_as_plugin_api (GST_TYPE_QT_MUX_DTS_METHOD, 0); } static void @@ -850,12 +871,15 @@ gst_qt_mux_init (GstQTMux * qtmux, GstQTMuxClass * qtmux_klass) DEFAULT_RESERVED_BYTES_PER_SEC_PER_TRAK; qtmux->interleave_bytes = DEFAULT_INTERLEAVE_BYTES; qtmux->interleave_time = DEFAULT_INTERLEAVE_TIME; + qtmux->force_chunks = DEFAULT_FORCE_CHUNKS; qtmux->max_raw_audio_drift = DEFAULT_MAX_RAW_AUDIO_DRIFT; qtmux->start_gap_threshold = DEFAULT_START_GAP_THRESHOLD; + qtmux->force_create_timecode_trak = DEFAULT_FORCE_CREATE_TIMECODE_TRAK; /* always need this */ qtmux->context = - atoms_context_new (gst_qt_mux_map_format_to_flavor (qtmux_klass->format)); + atoms_context_new (gst_qt_mux_map_format_to_flavor (qtmux_klass->format), + qtmux->force_create_timecode_trak); /* internals to initial state */ gst_qt_mux_reset (qtmux, TRUE); @@ -2416,6 +2440,7 @@ gst_qt_mux_downstream_is_seekable (GstQTMux * qtmux) return seekable; } +/* Must be called with object lock */ static void gst_qt_mux_prepare_moov_recovery (GstQTMux * qtmux) { @@ -2436,21 +2461,17 @@ gst_qt_mux_prepare_moov_recovery (GstQTMux * qtmux) gst_qt_mux_prepare_ftyp (qtmux, &ftyp, &prefix); - GST_OBJECT_LOCK (qtmux); if (!atoms_recov_write_headers (qtmux->moov_recov_file, ftyp, prefix, qtmux->moov, qtmux->timescale, g_list_length (GST_ELEMENT (qtmux)->sinkpads))) { GST_WARNING_OBJECT (qtmux, "Failed to write moov recovery file " "headers"); - GST_OBJECT_UNLOCK (qtmux); goto fail; } - GST_OBJECT_UNLOCK (qtmux); atom_ftyp_free (ftyp); if (prefix) gst_buffer_unref (prefix); - GST_OBJECT_LOCK (qtmux); for (l = GST_ELEMENT_CAST (qtmux)->sinkpads; l; l = l->next) { GstQTMuxPad *qpad = (GstQTMuxPad *) l->data; /* write info for each stream */ @@ -2461,7 +2482,6 @@ gst_qt_mux_prepare_moov_recovery (GstQTMux * qtmux) break; } } - GST_OBJECT_UNLOCK (qtmux); return; @@ -2508,8 +2528,10 @@ prefill_get_sample_size (GstQTMux * qtmux, GstQTMuxPad * qpad) return 525000; } else if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 1080) { return 1050000; - } else { + } else if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 2160) { return 4150000; + } else { + return 16600000; } break; case FOURCC_apcn: @@ -2521,8 +2543,10 @@ prefill_get_sample_size (GstQTMux * qtmux, GstQTMuxPad * qpad) return 350000; } else if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 1080) { return 700000; - } else { + } else if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 2160) { return 2800000; + } else { + return 11200000; } break; case FOURCC_apcs: @@ -2534,8 +2558,10 @@ prefill_get_sample_size (GstQTMux * qtmux, GstQTMuxPad * qpad) return 250000; } else if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 1080) { return 500000; - } else { + } else if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 2160) { return 2800000; + } else { + return 11200000; } break; case FOURCC_apco: @@ -2547,8 +2573,10 @@ prefill_get_sample_size (GstQTMux * qtmux, GstQTMuxPad * qpad) return 150000; } else if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 1080) { return 250000; - } else { + } else if (((SampleTableEntryMP4V *) qpad->trak_ste)->height <= 2160) { return 900000; + } else { + return 3600000; } break; case FOURCC_c608: @@ -2695,6 +2723,7 @@ prefill_raw_audio_prepare_buf_func (GstQTMuxPad * qtpad, GstBuffer * buf, return buf; } +/* Must be called with object lock */ static void find_video_sample_duration (GstQTMux * qtmux, guint * dur_n, guint * dur_d) { @@ -2702,7 +2731,6 @@ find_video_sample_duration (GstQTMux * qtmux, guint * dur_n, guint * dur_d) /* Find the (first) video track and assume that we have to output * in that size */ - GST_OBJECT_LOCK (qtmux); for (l = GST_ELEMENT_CAST (qtmux)->sinkpads; l; l = l->next) { GstQTMuxPad *tmp_qpad = (GstQTMuxPad *) l->data; @@ -2712,7 +2740,6 @@ find_video_sample_duration (GstQTMux * qtmux, guint * dur_n, guint * dur_d) break; } } - GST_OBJECT_UNLOCK (qtmux); if (l == NULL) { GST_INFO_OBJECT (qtmux, @@ -2851,7 +2878,8 @@ gst_qt_mux_prefill_samples (GstQTMux * qtmux) } GST_OBJECT_UNLOCK (qtmux); - if (qtmux_klass->format == GST_QT_MUX_FORMAT_QT) { + if (qtmux_klass->format == GST_QT_MUX_FORMAT_QT || + qtmux->force_create_timecode_trak) { /* For the first sample check/update timecode as needed. We do that before * all actual samples as the code in gst_qt_mux_add_buffer() does it with * initial buffer directly, not with last_buf */ @@ -3016,6 +3044,11 @@ gst_qt_mux_start_file (GstQTMux * qtmux) } else if (qtmux->fast_start) { qtmux->mux_mode = GST_QT_MUX_MODE_FAST_START; } else if (reserved_max_duration != GST_CLOCK_TIME_NONE) { + if (reserved_max_duration == 0) { + GST_ELEMENT_ERROR (qtmux, STREAM, MUX, + ("reserved-max-duration of 0 is not allowed"), (NULL)); + return GST_FLOW_ERROR; + } if (qtmux->reserved_prefill) qtmux->mux_mode = GST_QT_MUX_MODE_ROBUST_RECORDING_PREFILL; else @@ -3340,6 +3373,7 @@ gst_qt_mux_start_file (GstQTMux * qtmux) gst_aggregator_update_segment (GST_AGGREGATOR (qtmux), &segment); } + GST_OBJECT_LOCK (qtmux); qtmux->current_chunk_size = 0; qtmux->current_chunk_duration = 0; qtmux->current_chunk_offset = -1; @@ -3347,7 +3381,6 @@ gst_qt_mux_start_file (GstQTMux * qtmux) qtmux->current_pad = NULL; qtmux->longest_chunk = GST_CLOCK_TIME_NONE; - GST_OBJECT_LOCK (qtmux); for (l = GST_ELEMENT_CAST (qtmux)->sinkpads; l; l = l->next) { GstQTMuxPad *qtpad = (GstQTMuxPad *) l->data; @@ -3644,7 +3677,8 @@ gst_qt_mux_update_timecode (GstQTMux * qtmux, GstQTMuxPad * qtpad) guint64 offset = qtpad->tc_pos; GstQTMuxClass *qtmux_klass = (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux)); - if (qtmux_klass->format != GST_QT_MUX_FORMAT_QT) + if (qtmux_klass->format != GST_QT_MUX_FORMAT_QT && + !qtmux->force_create_timecode_trak) return GST_FLOW_OK; g_assert (qtpad->tc_pos != -1); @@ -4480,7 +4514,8 @@ gst_qt_mux_check_and_update_timecode (GstQTMux * qtmux, GstQTMuxPad * pad, if (!pad->trak->is_video) return ret; - if (qtmux_klass->format != GST_QT_MUX_FORMAT_QT) + if (qtmux_klass->format != GST_QT_MUX_FORMAT_QT && + !qtmux->force_create_timecode_trak) return ret; if (buf == NULL || (pad->tc_trak != NULL && pad->tc_pos == -1)) @@ -5067,6 +5102,12 @@ find_best_pad (GstQTMux * qtmux) /* Find the exact offset where the next sample of this track is supposed * to be written at */ block_idx = current_block_idx = prefill_get_block_index (qtmux, qtpad); + if (!qtpad->samples || block_idx >= qtpad->samples->len) { + GST_ELEMENT_ERROR (qtmux, RESOURCE, SETTINGS, + ("Failed to create samples in prefill mode"), (NULL)); + return NULL; + } + sample_entry = &g_array_index (qtpad->samples, TrakBufferEntryInfo, block_idx); while (block_idx > 0) { @@ -5121,10 +5162,13 @@ find_best_pad (GstQTMux * qtmux) } } else { GST_OBJECT_LOCK (qtmux); - if (GST_ELEMENT (qtmux)->sinkpads->next) { + if (GST_ELEMENT (qtmux)->sinkpads->next || qtmux->force_chunks) { /* Only switch pads if we have more than one, otherwise * we can just put everything into a single chunk and save - * a few bytes of offsets + * a few bytes of offsets. + * + * Various applications and the Apple ProRes spec require chunking even + * in case of single stream files. */ if (qtmux->current_pad) GST_DEBUG_OBJECT (qtmux, "Switching from pad %s:%s", @@ -5285,6 +5329,10 @@ gst_qt_mux_can_renegotiate (GstQTMux * qtmux, GstPad * pad, GstCaps * caps) * the old caps are a subset of the new one (this means upstream * added more info to the caps, as both should be 'fixed' caps) */ current_caps = gst_pad_get_current_caps (pad); + + if (!current_caps) + return TRUE; + g_assert (caps != NULL); if (!gst_qtmux_caps_is_subset_full (qtmux, current_caps, caps)) { @@ -5292,14 +5340,12 @@ gst_qt_mux_can_renegotiate (GstQTMux * qtmux, GstPad * pad, GstCaps * caps) GST_WARNING_OBJECT (qtmux, "pad %s refused renegotiation to %" GST_PTR_FORMAT, GST_PAD_NAME (pad), caps); - gst_object_unref (qtmux); return FALSE; } GST_DEBUG_OBJECT (qtmux, "pad %s accepted renegotiation to %" GST_PTR_FORMAT " from %" GST_PTR_FORMAT, GST_PAD_NAME (pad), caps, current_caps); - gst_object_unref (qtmux); gst_caps_unref (current_caps); return TRUE; @@ -5323,9 +5369,6 @@ gst_qt_mux_audio_sink_set_caps (GstQTMuxPad * qtpad, GstCaps * caps) const gchar *stream_format; guint32 timescale; - if (qtpad->fourcc) - return gst_qt_mux_can_renegotiate (qtmux, pad, caps); - GST_DEBUG_OBJECT (qtmux, "%s:%s, caps=%" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME (pad), caps); @@ -5673,9 +5716,6 @@ gst_qt_mux_video_sink_set_caps (GstQTMuxPad * qtpad, GstCaps * caps) int par_num, par_den; const gchar *multiview_mode; - if (qtpad->fourcc) - return gst_qt_mux_can_renegotiate (qtmux, pad, caps); - GST_DEBUG_OBJECT (qtmux, "%s:%s, caps=%" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME (pad), caps); @@ -5732,6 +5772,9 @@ gst_qt_mux_video_sink_set_caps (GstQTMuxPad * qtpad, GstCaps * caps) gst_structure_get_flagset (structure, "multiview-flags", (guint *) & flags, NULL); switch (mode) { + case GST_VIDEO_MULTIVIEW_MODE_MONO: + /* Nothing to do for mono, just don't warn about it */ + break; case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE: qtpad->trak->mdia.minf.stbl.svmi = atom_svmi_new (0, @@ -6168,7 +6211,7 @@ gst_qt_mux_video_sink_set_caps (GstQTMuxPad * qtpad, GstCaps * caps) mp4v->horizontal_resolution = 72 << 16; mp4v->vertical_resolution = 72 << 16; mp4v->depth = (entry.fourcc == FOURCC_ap4h - || entry.fourcc == FOURCC_ap4x) ? 32 : 24; + || entry.fourcc == FOURCC_ap4x) ? (depth > 0 ? depth : 32) : 24; /* Set compressor name, required by some software */ switch (entry.fourcc) { @@ -6218,9 +6261,6 @@ gst_qt_mux_subtitle_sink_set_caps (GstQTMuxPad * qtpad, GstCaps * caps) GstStructure *structure; SubtitleSampleEntry entry = { 0, }; - if (qtpad->fourcc) - return gst_qt_mux_can_renegotiate (qtmux, pad, caps); - GST_DEBUG_OBJECT (qtmux, "%s:%s, caps=%" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME (pad), caps); @@ -6272,9 +6312,6 @@ gst_qt_mux_caption_sink_set_caps (GstQTMuxPad * qtpad, GstCaps * caps) guint32 fourcc_entry; guint32 timescale; - if (qtpad->fourcc) - return gst_qt_mux_can_renegotiate (qtmux, pad, caps); - GST_DEBUG_OBJECT (qtmux, "%s:%s, caps=%" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME (pad), caps); @@ -6326,6 +6363,34 @@ gst_qt_mux_caption_sink_set_caps (GstQTMuxPad * qtpad, GstCaps * caps) } } +static GstFlowReturn +gst_qt_mux_sink_event_pre_queue (GstAggregator * agg, + GstAggregatorPad * agg_pad, GstEvent * event) +{ + GstAggregatorClass *agg_class = GST_AGGREGATOR_CLASS (parent_class); + GstQTMux *qtmux; + GstFlowReturn ret = GST_FLOW_OK; + + qtmux = GST_QT_MUX_CAST (agg); + + if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) { + GstCaps *caps; + + gst_event_parse_caps (event, &caps); + if (!gst_qt_mux_can_renegotiate (qtmux, GST_PAD (agg_pad), caps)) { + gst_event_unref (event); + event = NULL; + ret = GST_FLOW_NOT_NEGOTIATED; + } + } + + if (event != NULL) + ret = agg_class->sink_event_pre_queue (agg, agg_pad, event); + + return ret; +} + + static gboolean gst_qt_mux_sink_event (GstAggregator * agg, GstAggregatorPad * agg_pad, GstEvent * event) @@ -6417,18 +6482,25 @@ static void gst_qt_mux_release_pad (GstElement * element, GstPad * pad) { GstQTMux *mux = GST_QT_MUX_CAST (element); + GstQTMuxPad *muxpad = GST_QT_MUX_PAD_CAST (pad); GST_DEBUG_OBJECT (element, "Releasing %s:%s", GST_DEBUG_PAD_NAME (pad)); - gst_element_remove_pad (element, pad); + /* Take a ref to the pad so we can clean it up after removing it from the element */ + pad = gst_object_ref (pad); + /* Do aggregate level cleanup */ + GST_ELEMENT_CLASS (parent_class)->release_pad (element, pad); + + GST_OBJECT_LOCK (mux); if (mux->current_pad && GST_PAD (mux->current_pad) == pad) { mux->current_pad = NULL; mux->current_chunk_size = 0; mux->current_chunk_duration = 0; } - GST_OBJECT_LOCK (mux); + gst_qt_mux_pad_reset (muxpad); + if (GST_ELEMENT (mux)->sinkpads == NULL) { /* No more outstanding request pads, reset our counters */ mux->video_pads = 0; @@ -6436,6 +6508,8 @@ gst_qt_mux_release_pad (GstElement * element, GstPad * pad) mux->subtitle_pads = 0; } GST_OBJECT_UNLOCK (mux); + + gst_object_unref (pad); } static GstAggregatorPad * @@ -6503,9 +6577,12 @@ gst_qt_mux_request_new_pad (GstElement * element, g_free (name); /* set up pad */ + GST_OBJECT_LOCK (qtmux); gst_qt_mux_pad_reset (qtpad); qtpad->trak = atom_trak_new (qtmux->context); + atom_moov_add_trak (qtmux->moov, qtpad->trak); + GST_OBJECT_UNLOCK (qtmux); /* set up pad functions */ qtpad->set_caps = setcaps_func; @@ -6605,12 +6682,18 @@ gst_qt_mux_get_property (GObject * object, case PROP_INTERLEAVE_TIME: g_value_set_uint64 (value, qtmux->interleave_time); break; + case PROP_FORCE_CHUNKS: + g_value_set_boolean (value, qtmux->force_chunks); + break; case PROP_MAX_RAW_AUDIO_DRIFT: g_value_set_uint64 (value, qtmux->max_raw_audio_drift); break; case PROP_START_GAP_THRESHOLD: g_value_set_uint64 (value, qtmux->start_gap_threshold); break; + case PROP_FORCE_CREATE_TIMECODE_TRAK: + g_value_set_boolean (value, qtmux->force_create_timecode_trak); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -6699,12 +6782,20 @@ gst_qt_mux_set_property (GObject * object, qtmux->interleave_time = g_value_get_uint64 (value); qtmux->interleave_time_set = TRUE; break; + case PROP_FORCE_CHUNKS: + qtmux->force_chunks = g_value_get_boolean (value); + break; case PROP_MAX_RAW_AUDIO_DRIFT: qtmux->max_raw_audio_drift = g_value_get_uint64 (value); break; case PROP_START_GAP_THRESHOLD: qtmux->start_gap_threshold = g_value_get_uint64 (value); break; + case PROP_FORCE_CREATE_TIMECODE_TRAK: + qtmux->force_create_timecode_trak = g_value_get_boolean (value); + qtmux->context->force_create_timecode_trak = + qtmux->force_create_timecode_trak; + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/gst/isomp4/gstqtmux.h b/gst/isomp4/gstqtmux.h index d18871babe..4c635c9341 100644 --- a/gst/isomp4/gstqtmux.h +++ b/gst/isomp4/gstqtmux.h @@ -289,6 +289,7 @@ struct _GstQTMux guint64 interleave_bytes; GstClockTime interleave_time; gboolean interleave_bytes_set, interleave_time_set; + gboolean force_chunks; GstClockTime max_raw_audio_drift; @@ -313,6 +314,8 @@ struct _GstQTMux GstClockTime start_gap_threshold; + gboolean force_create_timecode_trak; + /* for request pad naming */ guint video_pads, audio_pads, subtitle_pads, caption_pads; }; diff --git a/gst/isomp4/meson.build b/gst/isomp4/meson.build index 656eed38e6..17a83620b2 100644 --- a/gst/isomp4/meson.build +++ b/gst/isomp4/meson.build @@ -5,6 +5,8 @@ mp4_sources = [ 'qtdemux_types.c', 'qtdemux_dump.c', 'qtdemux_lang.c', + 'qtdemux_tags.c', + 'qtdemux_tree.c', 'gstisoff.c', 'gstqtmux.c', 'gstqtmoovrecover.c', diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c index 086bd92c1e..a0df29f0db 100644 --- a/gst/isomp4/qtdemux.c +++ b/gst/isomp4/qtdemux.c @@ -53,9 +53,9 @@ #include "gst/gst-i18n-plugin.h" #include +#include #include #include -#include #include #include @@ -67,8 +67,9 @@ #include "qtdemux_lang.h" #include "qtdemux.h" #include "qtpalette.h" +#include "qtdemux_tags.h" +#include "qtdemux_tree.h" -#include #include #include @@ -104,24 +105,13 @@ #define QTDEMUX_NTH_OLD_STREAM(demux,idx) \ QTDEMUX_STREAM(g_ptr_array_index((demux)->old_streams,idx)) +#define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index])) + GST_DEBUG_CATEGORY (qtdemux_debug); #define GST_CAT_DEFAULT qtdemux_debug -typedef struct _QtDemuxSegment QtDemuxSegment; -typedef struct _QtDemuxSample QtDemuxSample; - typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo; -struct _QtDemuxSample -{ - guint32 size; - gint32 pts_offset; /* Add this value to timestamp to get the pts */ - guint64 offset; - guint64 timestamp; /* DTS In mov time */ - guint32 duration; /* In mov time */ - gboolean keyframe; /* TRUE when this packet is a keyframe */ -}; - /* Macros for converting to/from timescale */ #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale)) #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND)) @@ -227,237 +217,13 @@ struct _QtDemuxSegment #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE) /* Used with fragmented MP4 files (mfra atom) */ -typedef struct +struct _QtDemuxRandomAccessEntry { GstClockTime ts; guint64 moof_offset; -} QtDemuxRandomAccessEntry; - -typedef struct _QtDemuxStreamStsdEntry -{ - GstCaps *caps; - guint32 fourcc; - gboolean sparse; - - /* video info */ - gint width; - gint height; - gint par_w; - gint par_h; - /* Numerator/denominator framerate */ - gint fps_n; - gint fps_d; - GstVideoColorimetry colorimetry; - guint16 bits_per_sample; - guint16 color_table_id; - GstMemory *rgb8_palette; - guint interlace_mode; - guint field_order; - - /* audio info */ - gdouble rate; - gint n_channels; - guint samples_per_packet; - guint samples_per_frame; - guint bytes_per_packet; - guint bytes_per_sample; - guint bytes_per_frame; - guint compression; - - /* if we use chunks or samples */ - gboolean sampled; - guint padding; - -} QtDemuxStreamStsdEntry; - -#define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index])) - -struct _QtDemuxStream -{ - GstPad *pad; - - GstQTDemux *demux; - gchar *stream_id; - - QtDemuxStreamStsdEntry *stsd_entries; - guint stsd_entries_length; - guint cur_stsd_entry_index; - - /* stream type */ - guint32 subtype; - - gboolean new_caps; /* If TRUE, caps need to be generated (by - * calling _configure_stream()) This happens - * for MSS and fragmented streams */ - - gboolean new_stream; /* signals that a stream_start is required */ - gboolean on_keyframe; /* if this stream last pushed buffer was a - * keyframe. This is important to identify - * where to stop pushing buffers after a - * segment stop time */ - - /* if the stream has a redirect URI in its headers, we store it here */ - gchar *redirect_uri; - - /* track id */ - guint track_id; - - /* duration/scale */ - guint64 duration; /* in timescale units */ - guint32 timescale; - - /* language */ - gchar lang_id[4]; /* ISO 639-2T language code */ - - /* our samples */ - guint32 n_samples; - QtDemuxSample *samples; - gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */ - guint32 n_samples_moof; /* sample count in a moof */ - guint64 duration_moof; /* duration in timescale of a moof, used for figure out - * the framerate of fragmented format stream */ - guint64 duration_last_moof; - - guint32 offset_in_sample; /* Offset in the current sample, used for - * streams which have got exceedingly big - * sample size (such as 24s of raw audio). - * Only used when max_buffer_size is non-NULL */ - guint32 max_buffer_size; /* Maximum allowed size for output buffers. - * Currently only set for raw audio streams*/ - - /* video info */ - /* aspect ratio */ - gint display_width; - gint display_height; - - /* allocation */ - gboolean use_allocator; - GstAllocator *allocator; - GstAllocationParams params; - - gsize alignment; - - /* when a discontinuity is pending */ - gboolean discont; - - /* list of buffers to push first */ - GSList *buffers; - - /* if we need to clip this buffer. This is only needed for uncompressed - * data */ - gboolean need_clip; - - /* buffer needs some custom processing, e.g. subtitles */ - gboolean need_process; - /* buffer needs potentially be split, e.g. CEA608 subtitles */ - gboolean need_split; - - /* current position */ - guint32 segment_index; - guint32 sample_index; - GstClockTime time_position; /* in gst time */ - guint64 accumulated_base; - - /* the Gst segment we are processing out, used for clipping */ - GstSegment segment; - - /* quicktime segments */ - guint32 n_segments; - QtDemuxSegment *segments; - gboolean dummy_segment; - guint32 from_sample; - guint32 to_sample; - - gboolean sent_eos; - GstTagList *stream_tags; - gboolean send_global_tags; - - GstEvent *pending_event; - - GstByteReader stco; - GstByteReader stsz; - GstByteReader stsc; - GstByteReader stts; - GstByteReader stss; - GstByteReader stps; - GstByteReader ctts; - - gboolean chunks_are_samples; /* TRUE means treat chunks as samples */ - gint64 stbl_index; - /* stco */ - guint co_size; - GstByteReader co_chunk; - guint32 first_chunk; - guint32 current_chunk; - guint32 last_chunk; - guint32 samples_per_chunk; - guint32 stsd_sample_description_id; - guint32 stco_sample_index; - /* stsz */ - guint32 sample_size; /* 0 means variable sizes are stored in stsz */ - /* stsc */ - guint32 stsc_index; - guint32 n_samples_per_chunk; - guint32 stsc_chunk_index; - guint32 stsc_sample_index; - guint64 chunk_offset; - /* stts */ - guint32 stts_index; - guint32 stts_samples; - guint32 n_sample_times; - guint32 stts_sample_index; - guint64 stts_time; - guint32 stts_duration; - /* stss */ - gboolean stss_present; - guint32 n_sample_syncs; - guint32 stss_index; - /* stps */ - gboolean stps_present; - guint32 n_sample_partial_syncs; - guint32 stps_index; - QtDemuxRandomAccessEntry *ra_entries; - guint n_ra_entries; - - const QtDemuxRandomAccessEntry *pending_seek; - - /* ctts */ - gboolean ctts_present; - guint32 n_composition_times; - guint32 ctts_index; - guint32 ctts_sample_index; - guint32 ctts_count; - gint32 ctts_soffset; - - /* cslg */ - guint32 cslg_shift; - - /* fragmented */ - gboolean parsed_trex; - guint32 def_sample_description_index; /* index is 1-based */ - guint32 def_sample_duration; - guint32 def_sample_size; - guint32 def_sample_flags; - - gboolean disabled; - - /* stereoscopic video streams */ - GstVideoMultiviewMode multiview_mode; - GstVideoMultiviewFlags multiview_flags; - - /* protected streams */ - gboolean protected; - guint32 protection_scheme_type; - guint32 protection_scheme_version; - gpointer protection_scheme_info; /* specific to the protection scheme */ - GQueue protection_scheme_event_queue; - - /* KEY_UNITS trickmode with an interval */ - GstClockTime last_keyframe_dts; - - gint ref_count; /* atomic */ }; + /* Contains properties and cryptographic info for a set of samples from a * track protected using Common Encryption (cenc) */ struct _QtDemuxCencSampleSetInfo @@ -485,13 +251,6 @@ qt_demux_state_string (enum QtDemuxState state) } } -static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc); -static GNode *qtdemux_tree_get_child_by_type_full (GNode * node, - guint32 fourcc, GstByteReader * parser); -static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc); -static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node, - guint32 fourcc, GstByteReader * parser); - static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux); static void gst_qtdemux_check_send_pending_segment (GstQTDemux * demux); @@ -569,8 +328,6 @@ static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux, static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer, guint length); static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux); -static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, - GNode * udta); static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds, @@ -1493,6 +1250,31 @@ gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event) &cur_type, &cur, &stop_type, &stop); seqnum = gst_event_get_seqnum (event); + /* Directly send the instant-rate-change event here before taking the + * stream-lock so that it can be applied as soon as possible */ + if (flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE) { + GstEvent *ev; + + /* instant rate change only supported if direction does not change. All + * other requirements are already checked before creating the seek event + * but let's double-check here to be sure */ + if ((qtdemux->segment.rate > 0 && rate < 0) || + (qtdemux->segment.rate < 0 && rate > 0) || + cur_type != GST_SEEK_TYPE_NONE || + stop_type != GST_SEEK_TYPE_NONE || (flags & GST_SEEK_FLAG_FLUSH)) { + GST_ERROR_OBJECT (qtdemux, + "Instant rate change seeks only supported in the " + "same direction, without flushing and position change"); + return FALSE; + } + + ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate, + (GstSegmentFlags) flags); + gst_event_set_seqnum (ev, seqnum); + gst_qtdemux_push_event (qtdemux, ev); + return TRUE; + } + /* only forward streaming and seeking is possible */ if (rate <= 0) goto unsupported_seek; @@ -1655,12 +1437,12 @@ gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment, static gboolean gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event) { - gdouble rate; + gdouble rate = 1.0; GstFormat format; GstSeekFlags flags; GstSeekType cur_type, stop_type; gint64 cur, stop; - gboolean flush; + gboolean flush, instant_rate_change; gboolean update; GstSegment seeksegment; guint32 seqnum = GST_SEQNUM_INVALID; @@ -1681,7 +1463,33 @@ gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event) GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format)); - flush = flags & GST_SEEK_FLAG_FLUSH; + flush = ! !(flags & GST_SEEK_FLAG_FLUSH); + instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE); + + /* Directly send the instant-rate-change event here before taking the + * stream-lock so that it can be applied as soon as possible */ + if (instant_rate_change) { + GstEvent *ev; + + /* instant rate change only supported if direction does not change. All + * other requirements are already checked before creating the seek event + * but let's double-check here to be sure */ + if ((qtdemux->segment.rate > 0 && rate < 0) || + (qtdemux->segment.rate < 0 && rate > 0) || + cur_type != GST_SEEK_TYPE_NONE || + stop_type != GST_SEEK_TYPE_NONE || flush) { + GST_ERROR_OBJECT (qtdemux, + "Instant rate change seeks only supported in the " + "same direction, without flushing and position change"); + return FALSE; + } + + ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate, + (GstSegmentFlags) flags); + gst_event_set_seqnum (ev, seqnum); + gst_qtdemux_push_event (qtdemux, ev); + return TRUE; + } /* stop streaming, either by flushing or by pausing the task */ if (flush) { @@ -1790,6 +1598,9 @@ gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent, break; case GST_EVENT_SEEK: { + GstSeekFlags flags = 0; + gboolean instant_rate_change; + #ifndef GST_DISABLE_GST_DEBUG GstClockTime ts = gst_util_get_timestamp (); #endif @@ -1797,6 +1608,9 @@ gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent, qtdemux->received_seek = TRUE; + gst_event_parse_seek (event, NULL, NULL, &flags, NULL, NULL, NULL, NULL); + instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE); + if (seqnum == qtdemux->segment_seqnum) { GST_LOG_OBJECT (pad, "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum); @@ -1815,16 +1629,17 @@ gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent, &qtdemux->trickmode_interval); /* Build complete index for seeking; - * if not a fragmented file at least */ - if (!qtdemux->fragmented) + * if not a fragmented file at least and we're really doing a seek, + * not just an instant-rate-change */ + if (!qtdemux->fragmented && !instant_rate_change) { if (!qtdemux_ensure_index (qtdemux)) goto index_failed; + } #ifndef GST_DISABLE_GST_DEBUG ts = gst_util_get_timestamp () - ts; GST_INFO_OBJECT (qtdemux, "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts)); #endif - } if (qtdemux->pullbased) { res = gst_qtdemux_do_seek (qtdemux, pad, event); } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) { @@ -1840,6 +1655,7 @@ gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent, res = FALSE; } gst_event_unref (event); + } break; default: upstream: @@ -2109,6 +1925,16 @@ gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps) &CUR_STREAM (stream)->n_channels); gst_structure_get_int (structure, "rate", &rate); CUR_STREAM (stream)->rate = rate; + } else if (gst_structure_has_name (structure, "application/x-cenc")) { + if (gst_structure_has_field (structure, "original-media-type")) { + const gchar *media_type = + gst_structure_get_string (structure, "original-media-type"); + if (g_str_has_prefix (media_type, "video")) { + stream->subtype = FOURCC_vide; + } else if (g_str_has_prefix (media_type, "audio")) { + stream->subtype = FOURCC_soun; + } + } } } gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps); @@ -2825,27 +2651,6 @@ qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length) } } -static void -qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist, - GstTagList * xmptaglist) -{ - /* Strip out bogus fields */ - if (xmptaglist) { - if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) { - gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC); - gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC); - } else { - gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT); - } - - GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist); - - /* prioritize native tags using _KEEP mode */ - gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP); - gst_tag_list_unref (xmptaglist); - } -} - static void qtdemux_update_default_sample_encryption_settings (GstQTDemux * qtdemux, QtDemuxCencSampleSetInfo * info, guint32 is_encrypted, guint8 iv_size, @@ -6314,6 +6119,7 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux) GstClockTime duration = 0; gboolean keyframe = FALSE; guint sample_size = 0; + guint num_samples = 1; gboolean empty = 0; guint size; gint i; @@ -6457,14 +6263,58 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux) if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS)) goto next; - if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) { - size = sample_size; - } else { + if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) { GST_DEBUG_OBJECT (qtdemux, "size %d larger than stream max_buffer_size %d, trimming", sample_size, stream->max_buffer_size); size = MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size); + } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0 + && sample_size < stream->min_buffer_size) { + guint start_sample_index = stream->sample_index; + guint accumulated_size = sample_size; + guint64 expected_next_offset = offset + sample_size; + + GST_DEBUG_OBJECT (qtdemux, + "size %d smaller than stream min_buffer_size %d, combining with the next", + sample_size, stream->min_buffer_size); + + while (stream->sample_index < stream->to_sample + && stream->sample_index + 1 < stream->n_samples) { + const QtDemuxSample *next_sample; + + /* Increment temporarily */ + stream->sample_index++; + + /* Failed to parse sample so let's go back to the previous one that was + * still successful */ + if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) { + stream->sample_index--; + break; + } + + next_sample = &stream->samples[stream->sample_index]; + + /* Not contiguous with the previous sample so let's go back to the + * previous one that was still successful */ + if (next_sample->offset != expected_next_offset) { + stream->sample_index--; + break; + } + + accumulated_size += next_sample->size; + expected_next_offset += next_sample->size; + if (accumulated_size >= stream->min_buffer_size) + break; + } + + num_samples = stream->sample_index + 1 - start_sample_index; + stream->sample_index = start_sample_index; + GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once", + num_samples, accumulated_size); + size = accumulated_size; + } else { + size = sample_size; } if (qtdemux->cenc_aux_info_offset > 0) { @@ -6506,6 +6356,7 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux) if (G_UNLIKELY (ret != GST_FLOW_OK)) goto beach; + /* Update for both splitting and combining of samples */ if (size != sample_size) { pts += gst_util_uint64_scale_int (GST_SECOND, stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame, @@ -6522,7 +6373,7 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux) ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf, dts, pts, duration, keyframe, min_time, offset); - if (size != sample_size) { + if (size < sample_size) { QtDemuxSample *sample = &stream->samples[stream->sample_index]; QtDemuxSegment *segment = &stream->segments[stream->segment_index]; @@ -6540,6 +6391,10 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux) * decode the first sample of the segment. */ stream->time_position = segment->time; } + } else if (size > sample_size) { + /* Increase to the last sample we already pulled so that advancing + * below brings us to the next sample we need to pull */ + stream->sample_index += num_samples - 1; } /* combine flows */ @@ -8073,6 +7928,8 @@ qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer, case FOURCC_H265: case FOURCC_hvc1: case FOURCC_hev1: + case FOURCC_dvh1: + case FOURCC_dvhe: case FOURCC_mjp2: case FOURCC_encv: { @@ -8228,92 +8085,6 @@ qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer, } } -static GNode * -qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc) -{ - GNode *child; - guint8 *buffer; - guint32 child_fourcc; - - for (child = g_node_first_child (node); child; - child = g_node_next_sibling (child)) { - buffer = (guint8 *) child->data; - - child_fourcc = QT_FOURCC (buffer + 4); - - if (G_UNLIKELY (child_fourcc == fourcc)) { - return child; - } - } - return NULL; -} - -static GNode * -qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc, - GstByteReader * parser) -{ - GNode *child; - guint8 *buffer; - guint32 child_fourcc, child_len; - - for (child = g_node_first_child (node); child; - child = g_node_next_sibling (child)) { - buffer = (guint8 *) child->data; - - child_len = QT_UINT32 (buffer); - child_fourcc = QT_FOURCC (buffer + 4); - - if (G_UNLIKELY (child_fourcc == fourcc)) { - if (G_UNLIKELY (child_len < (4 + 4))) - return NULL; - /* FIXME: must verify if atom length < parent atom length */ - gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4)); - return child; - } - } - return NULL; -} - -static GNode * -qtdemux_tree_get_child_by_index (GNode * node, guint index) -{ - return g_node_nth_child (node, index); -} - -static GNode * -qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc, - GstByteReader * parser) -{ - GNode *child; - guint8 *buffer; - guint32 child_fourcc, child_len; - - for (child = g_node_next_sibling (node); child; - child = g_node_next_sibling (child)) { - buffer = (guint8 *) child->data; - - child_fourcc = QT_FOURCC (buffer + 4); - - if (child_fourcc == fourcc) { - if (parser) { - child_len = QT_UINT32 (buffer); - if (G_UNLIKELY (child_len < (4 + 4))) - return NULL; - /* FIXME: must verify if atom length < parent atom length */ - gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4)); - } - return child; - } - } - return NULL; -} - -static GNode * -qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc) -{ - return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL); -} - static void qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux) { @@ -9122,6 +8893,133 @@ qtdemux_add_fragmented_samples (GstQTDemux * qtdemux) } } +static void +qtdemux_merge_sample_table (GstQTDemux * qtdemux, QtDemuxStream * stream) +{ + guint i; + guint32 num_chunks; + gint32 stts_duration; + GstByteWriter stsc, stts, stsz; + + /* Each sample has a different size, which we don't support for merging */ + if (stream->sample_size == 0) { + GST_DEBUG_OBJECT (qtdemux, + "Not all samples have the same size, not merging"); + return; + } + + /* The stream has a ctts table, we don't support that */ + if (stream->ctts_present) { + GST_DEBUG_OBJECT (qtdemux, "Have ctts, not merging"); + return; + } + + /* If there's a sync sample table also ignore this stream */ + if (stream->stps_present || stream->stss_present) { + GST_DEBUG_OBJECT (qtdemux, "Have stss/stps, not merging"); + return; + } + + /* If chunks are considered samples already ignore this stream */ + if (stream->chunks_are_samples) { + GST_DEBUG_OBJECT (qtdemux, "Chunks are samples, not merging"); + return; + } + + /* Require that all samples have the same duration */ + if (stream->n_sample_times > 1) { + GST_DEBUG_OBJECT (qtdemux, "Not all samples have the same duration"); + return; + } + + /* Parse the stts to get the sample duration and number of samples */ + gst_byte_reader_skip_unchecked (&stream->stts, 4); + stts_duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts); + + /* Parse the number of chunks from the stco manually because the + * reader is already behind that */ + num_chunks = GST_READ_UINT32_BE (stream->stco.data + 4); + + GST_DEBUG_OBJECT (qtdemux, "sample_duration %d, num_chunks %u", stts_duration, + num_chunks); + + /* Now parse stsc, convert chunks into single samples and generate a + * new stsc, stts and stsz from this information */ + gst_byte_writer_init (&stsc); + gst_byte_writer_init (&stts); + gst_byte_writer_init (&stsz); + + /* Note: we skip fourccs, size, version, flags and other fields of the new + * atoms as the byte readers with them are already behind that position + * anyway and only update the values of those inside the stream directly. + */ + stream->n_sample_times = 0; + stream->n_samples = 0; + for (i = 0; i < stream->n_samples_per_chunk; i++) { + guint j; + guint32 first_chunk, last_chunk, samples_per_chunk, sample_description_id; + + first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc); + samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc); + sample_description_id = + gst_byte_reader_get_uint32_be_unchecked (&stream->stsc); + + if (i == stream->n_samples_per_chunk - 1) { + /* +1 because first_chunk is 1-based */ + last_chunk = num_chunks + 1; + } else { + last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc); + } + + GST_DEBUG_OBJECT (qtdemux, + "Merging first_chunk: %u, last_chunk: %u, samples_per_chunk: %u, sample_description_id: %u", + first_chunk, last_chunk, samples_per_chunk, sample_description_id); + + gst_byte_writer_put_uint32_be (&stsc, first_chunk); + /* One sample in this chunk */ + gst_byte_writer_put_uint32_be (&stsc, 1); + gst_byte_writer_put_uint32_be (&stsc, sample_description_id); + + /* For each chunk write a stts and stsz entry now */ + gst_byte_writer_put_uint32_be (&stts, last_chunk - first_chunk); + gst_byte_writer_put_uint32_be (&stts, stts_duration * samples_per_chunk); + for (j = first_chunk; j < last_chunk; j++) { + gst_byte_writer_put_uint32_be (&stsz, + stream->sample_size * samples_per_chunk); + } + + stream->n_sample_times += 1; + stream->n_samples += last_chunk - first_chunk; + } + + g_assert_cmpint (stream->n_samples, ==, num_chunks); + + GST_DEBUG_OBJECT (qtdemux, "Have %u samples and %u sample times", + stream->n_samples, stream->n_sample_times); + + /* We don't have a fixed sample size anymore */ + stream->sample_size = 0; + + /* Free old data for the atoms */ + g_free ((gpointer) stream->stsz.data); + stream->stsz.data = NULL; + g_free ((gpointer) stream->stsc.data); + stream->stsc.data = NULL; + g_free ((gpointer) stream->stts.data); + stream->stts.data = NULL; + + /* Store new data and replace byte readers */ + stream->stsz.size = gst_byte_writer_get_size (&stsz); + stream->stsz.data = gst_byte_writer_reset_and_get_data (&stsz); + gst_byte_reader_init (&stream->stsz, stream->stsz.data, stream->stsz.size); + stream->stts.size = gst_byte_writer_get_size (&stts); + stream->stts.data = gst_byte_writer_reset_and_get_data (&stts); + gst_byte_reader_init (&stream->stts, stream->stts.data, stream->stts.size); + stream->stsc.size = gst_byte_writer_get_size (&stsc); + stream->stsc.data = gst_byte_writer_reset_and_get_data (&stsc); + gst_byte_reader_init (&stream->stsc, stream->stsc.data, stream->stsc.size); +} + /* initialise bytereaders for stbl sub-atoms */ static gboolean qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl) @@ -9270,26 +9168,6 @@ qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl) } } - GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)", - stream->n_samples, (guint) sizeof (QtDemuxSample), - stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0)); - - if (stream->n_samples >= - QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) { - GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would " - "be larger than %uMB (broken file?)", stream->n_samples, - QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20); - return FALSE; - } - - g_assert (stream->samples == NULL); - stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples); - if (!stream->samples) { - GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples", - stream->n_samples); - return FALSE; - } - /* composition time-to-sample */ if ((stream->ctts_present = ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts, @@ -9342,7 +9220,7 @@ qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl) stream->cslg_shift = 0; stream->ctts_present = FALSE; - return TRUE; + goto done; } if (offset < cslg_least) @@ -9363,6 +9241,35 @@ qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl) stream->cslg_shift = 0; } + /* For raw audio streams especially we might want to merge the samples + * to not output one audio sample per buffer. We're doing this here + * before allocating the sample tables so that from this point onwards + * the number of container samples are static */ + if (stream->min_buffer_size > 0) { + qtdemux_merge_sample_table (qtdemux, stream); + } + +done: + GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)", + stream->n_samples, (guint) sizeof (QtDemuxSample), + stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0)); + + if (stream->n_samples >= + QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) { + GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would " + "be larger than %uMB (broken file?)", stream->n_samples, + QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20); + return FALSE; + } + + g_assert (stream->samples == NULL); + stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples); + if (!stream->samples) { + GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples", + stream->n_samples); + return FALSE; + } + return TRUE; corrupt_file: @@ -10477,48 +10384,116 @@ qtdemux_track_id_compare_func (QtDemuxStream ** stream1, return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id; } -/* parse the traks. - * With each track we associate a new QtDemuxStream that contains all the info - * about the trak. - * traks that do not decode to something (like strm traks) will not have a pad. - */ static gboolean -qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) +qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream, + GNode * stbl) { - GstByteReader tkhd; - int offset; - GNode *mdia; - GNode *mdhd; - GNode *hdlr; - GNode *minf; - GNode *stbl; - GNode *stsd; - GNode *mp4a; - GNode *mp4v; - GNode *esds; - GNode *tref; - GNode *udta; GNode *svmi; - QtDemuxStream *stream = NULL; - const guint8 *stsd_data; - const guint8 *stsd_entry_data; - guint remaining_stsd_len; - guint stsd_entry_count; - guint stsd_index; - guint16 lang_code; /* quicktime lang code or packed iso code */ - guint32 version; - guint32 tkhd_flags = 0; - guint8 tkhd_version = 0; - guint32 w = 0, h = 0; - guint value_size, stsd_len, len; - guint32 track_id; - guint32 dummy; + /*parse svmi header if existing */ + svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi); + if (svmi) { + guint len = QT_UINT32 ((guint8 *) svmi->data); + guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8); + if (!version) { + GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE; + GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE; + guint8 frame_type, frame_layout; + guint32 stereo_mono_change_count; - GST_DEBUG_OBJECT (qtdemux, "parse_trak"); + if (len < 18) + return FALSE; - if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd) - || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version) + /* MPEG-A stereo video */ + if (qtdemux->major_brand == FOURCC_ss02) + flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO; + + frame_type = QT_UINT8 ((guint8 *) svmi->data + 12); + frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01; + stereo_mono_change_count = QT_UINT32 ((guint8 *) svmi->data + 14); + + switch (frame_type) { + case 0: + mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE; + break; + case 1: + mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED; + break; + case 2: + mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME; + break; + case 3: + /* mode 3 is primary/secondary view sequence, ie + * left/right views in separate tracks. See section 7.2 + * of ISO/IEC 23000-11:2009 */ + /* In the future this might be supported using related + * streams, like an enhancement track - if files like this + * ever exist */ + GST_FIXME_OBJECT (qtdemux, + "Implement stereo video in separate streams"); + } + + if ((frame_layout & 0x1) == 0) + flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST; + + GST_LOG_OBJECT (qtdemux, + "StereoVideo: composition type: %u, is_left_first: %u", + frame_type, frame_layout); + + if (stereo_mono_change_count > 1) { + GST_FIXME_OBJECT (qtdemux, + "Mixed-mono flags are not yet supported in qtdemux."); + } + + stream->multiview_mode = mode; + stream->multiview_flags = flags; + } + } + + return TRUE; +} + +/* parse the traks. + * With each track we associate a new QtDemuxStream that contains all the info + * about the trak. + * traks that do not decode to something (like strm traks) will not have a pad. + */ +static gboolean +qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) +{ + GstByteReader tkhd; + int offset; + GNode *mdia; + GNode *mdhd; + GNode *hdlr; + GNode *minf; + GNode *stbl; + GNode *stsd; + GNode *mp4a; + GNode *mp4v; + GNode *esds; + GNode *tref; + GNode *udta; + + QtDemuxStream *stream = NULL; + const guint8 *stsd_data; + const guint8 *stsd_entry_data; + guint remaining_stsd_len; + guint stsd_entry_count; + guint stsd_index; + guint16 lang_code; /* quicktime lang code or packed iso code */ + guint32 version; + guint32 tkhd_flags = 0; + guint8 tkhd_version = 0; + guint32 w = 0, h = 0; + guint value_size, stsd_len, len; + guint32 track_id; + guint32 dummy; + + GST_DEBUG_OBJECT (qtdemux, "parse_trak"); + + if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd) + || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version) || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags)) goto corrupt_file; @@ -10650,50 +10625,9 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl))) goto corrupt_file; - /*parse svmi header if existing */ - svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi); - if (svmi) { - len = QT_UINT32 ((guint8 *) svmi->data); - version = QT_UINT32 ((guint8 *) svmi->data + 8); - if (!version) { - GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE; - GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE; - guint8 frame_type, frame_layout; - - /* MPEG-A stereo video */ - if (qtdemux->major_brand == FOURCC_ss02) - flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO; - - frame_type = QT_UINT8 ((guint8 *) svmi->data + 12); - frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01; - switch (frame_type) { - case 0: - mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE; - break; - case 1: - mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED; - break; - case 2: - mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME; - break; - case 3: - /* mode 3 is primary/secondary view sequence, ie - * left/right views in separate tracks. See section 7.2 - * of ISO/IEC 23000-11:2009 */ - GST_FIXME_OBJECT (qtdemux, - "Implement stereo video in separate streams"); - } - - if ((frame_layout & 0x1) == 0) - flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST; - - GST_LOG_OBJECT (qtdemux, - "StereoVideo: composition type: %u, is_left_first: %u", - frame_type, frame_layout); - stream->multiview_mode = mode; - stream->multiview_flags = flags; - } - } + /* Parse out svmi (and later st3d/sv3d) atoms */ + if (!qtdemux_parse_stereo_svmi_atom (qtdemux, stream, stbl)) + goto corrupt_file; /* parse rest of tkhd */ if (stream->subtype == FOURCC_vide) { @@ -10732,6 +10666,12 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) } stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12); + /* each stsd entry must contain at least 8 bytes */ + if (stream->stsd_entries_length == 0 + || stream->stsd_entries_length > stsd_len / 8) { + stream->stsd_entries_length = 0; + goto corrupt_file; + } stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count); GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len); GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count); @@ -11002,7 +10942,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) CUR_STREAM (stream)->colorimetry.primaries = gst_video_color_primaries_from_iso (primaries); CUR_STREAM (stream)->colorimetry.transfer = - gst_video_color_transfer_from_iso (transfer_function); + gst_video_transfer_function_from_iso (transfer_function); CUR_STREAM (stream)->colorimetry.matrix = gst_video_color_matrix_from_iso (matrix); CUR_STREAM (stream)->colorimetry.range = @@ -11136,6 +11076,8 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) case FOURCC_H265: case FOURCC_hvc1: case FOURCC_hev1: + case FOURCC_dvh1: + case FOURCC_dvhe: { gint len = QT_UINT32 (stsd_entry_data) - 0x56; const guint8 *hevc_data = stsd_entry_data + 0x56; @@ -11670,6 +11612,156 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) break; } + + /* TODO: Need to parse vpcC for VP8 codec too. + * Note that VPCodecConfigurationBox (vpcC) is defined for + * vp08, vp09, and vp10 fourcc. */ + case FOURCC_vp09: + { + gint len = QT_UINT32 (stsd_entry_data) - 0x56; + const guint8 *vpcc_data = stsd_entry_data + 0x56; + + /* find vpcC */ + while (len >= 0x8) { + gint size; + + if (QT_UINT32 (vpcc_data) <= len) + size = QT_UINT32 (vpcc_data) - 0x8; + else + size = len - 0x8; + + if (size < 1) + /* No real data, so break out */ + break; + + switch (QT_FOURCC (vpcc_data + 0x4)) { + case FOURCC_vpcC: + { + const gchar *profile_str = NULL; + const gchar *chroma_format_str = NULL; + guint8 profile; + guint8 bitdepth; + guint8 chroma_format; + GstVideoColorimetry cinfo; + + /* parse, if found */ + GST_DEBUG_OBJECT (qtdemux, + "found vp codec_data in stsd of size %d", size); + + /* the meaning of "size" is length of the atom body, excluding + * atom length and fourcc fields */ + if (size < 12) + break; + + /* Content is: + * 4 bytes: atom length + * 4 bytes: fourcc + * 1 byte: version + * 3 bytes: flags + * 1 byte: profile + * 1 byte: level + * 4 bits: bitDepth + * 3 bits: chromaSubsampling + * 1 bit: videoFullRangeFlag + * 1 byte: colourPrimaries + * 1 byte: transferCharacteristics + * 1 byte: matrixCoefficients + * 2 bytes: codecIntializationDataSize (should be zero for vp8 and vp9) + * rest: codecIntializationData (not used for vp8 and vp9) + */ + + if (vpcc_data[8] != 1) { + GST_WARNING_OBJECT (qtdemux, + "unknown vpcC version %d", vpcc_data[8]); + break; + } + + profile = vpcc_data[12]; + switch (profile) { + case 0: + profile_str = "0"; + break; + case 1: + profile_str = "1"; + break; + case 2: + profile_str = "2"; + break; + case 3: + profile_str = "3"; + break; + default: + break; + } + + if (profile_str) { + gst_caps_set_simple (entry->caps, + "profile", G_TYPE_STRING, profile_str, NULL); + } + + /* skip level, the VP9 spec v0.6 defines only one level atm, + * but webm spec define various ones. Add level to caps + * if we really need it then */ + + bitdepth = (vpcc_data[14] & 0xf0) >> 4; + if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) { + gst_caps_set_simple (entry->caps, + "bit-depth-luma", G_TYPE_UINT, bitdepth, + "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL); + } + + chroma_format = (vpcc_data[14] & 0xe) >> 1; + switch (chroma_format) { + case 0: + case 1: + chroma_format_str = "4:2:0"; + break; + case 2: + chroma_format_str = "4:2:2"; + break; + case 3: + chroma_format_str = "4:4:4"; + break; + default: + break; + } + + if (chroma_format_str) { + gst_caps_set_simple (entry->caps, + "chroma-format", G_TYPE_STRING, chroma_format_str, + NULL); + } + + if ((vpcc_data[14] & 0x1) != 0) + cinfo.range = GST_VIDEO_COLOR_RANGE_0_255; + else + cinfo.range = GST_VIDEO_COLOR_RANGE_16_235; + cinfo.primaries = + gst_video_color_primaries_from_iso (vpcc_data[15]); + cinfo.transfer = + gst_video_transfer_function_from_iso (vpcc_data[16]); + cinfo.matrix = + gst_video_color_matrix_from_iso (vpcc_data[17]); + + if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN && + cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN && + cinfo.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) { + /* set this only if all values are known, otherwise this + * might overwrite valid ones parsed from other color box */ + CUR_STREAM (stream)->colorimetry = cinfo; + } + break; + } + default: + break; + } + + len -= size + 8; + vpcc_data += size + 8; + } + + break; + } default: break; } @@ -11822,6 +11914,63 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) entry->bytes_per_sample = 2; entry->samples_per_frame = 160 * entry->n_channels; break; + } + /* fix up any invalid header information from above */ + case FOURCC_twos: + case FOURCC_sowt: + case FOURCC_raw_: + case FOURCC_lpcm: + /* Sometimes these are set to 0 in the sound sample descriptions so + * let's try to infer useful values from the other information we + * have available */ + if (entry->bytes_per_sample == 0) + entry->bytes_per_sample = + entry->bytes_per_frame / entry->n_channels; + if (entry->bytes_per_sample == 0) + entry->bytes_per_sample = samplesize / 8; + + if (entry->bytes_per_frame == 0) + entry->bytes_per_frame = + entry->bytes_per_sample * entry->n_channels; + + if (entry->bytes_per_packet == 0) + entry->bytes_per_packet = entry->bytes_per_sample; + + if (entry->samples_per_frame == 0) + entry->samples_per_frame = entry->n_channels; + + if (entry->samples_per_packet == 0) + entry->samples_per_packet = entry->samples_per_frame; + + break; + case FOURCC_in24: + case FOURCC_in32: + case FOURCC_fl32: + case FOURCC_fl64: + case FOURCC_s16l:{ + switch (fourcc) { + case FOURCC_in24: + entry->bytes_per_sample = 3; + break; + case FOURCC_in32: + case FOURCC_fl32: + entry->bytes_per_sample = 4; + break; + case FOURCC_fl64: + entry->bytes_per_sample = 8; + break; + case FOURCC_s16l: + entry->bytes_per_sample = 2; + break; + default: + g_assert_not_reached (); + break; + } + entry->samples_per_frame = entry->n_channels; + entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample; + entry->samples_per_packet = entry->samples_per_frame; + entry->bytes_per_packet = entry->bytes_per_sample; + break; } default: break; @@ -11835,23 +11984,44 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) switch (fourcc) { case FOURCC_in24: + case FOURCC_in32: + case FOURCC_fl32: + case FOURCC_fl64: { GNode *enda; - GNode *in24; + GNode *fmt; - in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24); + fmt = qtdemux_tree_get_child_by_type (stsd, fourcc); - enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda); + enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda); if (!enda) { - wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave); + wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave); if (wave) enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda); } if (enda) { int enda_value = QT_UINT16 ((guint8 *) enda->data + 8); + const gchar *format_str; + + switch (fourcc) { + case FOURCC_in24: + format_str = (enda_value) ? "S24LE" : "S24BE"; + break; + case FOURCC_in32: + format_str = (enda_value) ? "S32LE" : "S32BE"; + break; + case FOURCC_fl32: + format_str = (enda_value) ? "F32LE" : "F32BE"; + break; + case FOURCC_fl64: + format_str = (enda_value) ? "F64LE" : "F64BE"; + break; + default: + g_assert_not_reached (); + break; + } gst_caps_set_simple (entry->caps, - "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", - NULL); + "format", G_TYPE_STRING, format_str, NULL); } break; } @@ -12214,6 +12384,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) entry->bytes_per_frame = QT_UINT32 (alac_data + 12); entry->n_channels = QT_UINT8 (alac_data + 21); entry->rate = QT_UINT32 (alac_data + 32); + samplesize = QT_UINT8 (alac_data + 16 + 1); } } gst_caps_set_simple (entry->caps, @@ -12353,36 +12524,55 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) { /* mp4a atom withtout ESDS; Attempt to build codec data from atom */ gint len = QT_UINT32 (stsd_entry_data); + guint16 sound_version = 0; + /* FIXME: Can this be determined somehow? There doesn't seem to be + * anything in mp4a atom that specifis compression */ + gint profile = 2; + guint16 channels = entry->n_channels; + guint32 time_scale = (guint32) entry->rate; + gint sample_rate_index = -1; if (len >= 34) { - guint16 sound_version = QT_UINT16 (stsd_entry_data + 16); + sound_version = QT_UINT16 (stsd_entry_data + 16); if (sound_version == 1) { - guint16 channels = QT_UINT16 (stsd_entry_data + 24); - guint32 time_scale = QT_UINT32 (stsd_entry_data + 30); - guint8 codec_data[2]; - GstBuffer *buf; - gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */ - - gint sample_rate_index = - gst_codec_utils_aac_get_index_from_sample_rate (time_scale); - - /* build AAC codec data */ - codec_data[0] = profile << 3; - codec_data[0] |= ((sample_rate_index >> 1) & 0x7); - codec_data[1] = (sample_rate_index & 0x01) << 7; - codec_data[1] |= (channels & 0xF) << 3; - - buf = gst_buffer_new_and_alloc (2); - gst_buffer_fill (buf, 0, codec_data, 2); - gst_caps_set_simple (entry->caps, - "codec_data", GST_TYPE_BUFFER, buf, NULL); - gst_buffer_unref (buf); + channels = QT_UINT16 (stsd_entry_data + 24); + time_scale = QT_UINT32 (stsd_entry_data + 30); + } else { + GST_FIXME_OBJECT (qtdemux, "Unhandled mp4a atom version %d", + sound_version); } + } else { + GST_DEBUG_OBJECT (qtdemux, "Too small stsd entry data len %d", + len); + } + + sample_rate_index = + gst_codec_utils_aac_get_index_from_sample_rate (time_scale); + if (sample_rate_index >= 0 && channels > 0) { + guint8 codec_data[2]; + GstBuffer *buf; + + /* build AAC codec data */ + codec_data[0] = profile << 3; + codec_data[0] |= ((sample_rate_index >> 1) & 0x7); + codec_data[1] = (sample_rate_index & 0x01) << 7; + codec_data[1] |= (channels & 0xF) << 3; + + buf = gst_buffer_new_and_alloc (2); + gst_buffer_fill (buf, 0, codec_data, 2); + gst_caps_set_simple (entry->caps, + "codec_data", GST_TYPE_BUFFER, buf, NULL); + gst_buffer_unref (buf); } break; } case FOURCC_lpcm: + case FOURCC_in24: + case FOURCC_in32: + case FOURCC_fl32: + case FOURCC_fl64: + case FOURCC_s16l: /* Fully handled elsewhere */ break; default: @@ -12781,8 +12971,9 @@ qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux, newstream->pad = oldstream->pad; oldstream->pad = NULL; - /* unset new_stream to prevent stream-start event */ - newstream->new_stream = FALSE; + /* unset new_stream to prevent stream-start event, unless we are EOS in which + * case we need to force one through */ + newstream->new_stream = GST_PAD_IS_EOS (newstream->pad); return gst_qtdemux_configure_stream (qtdemux, newstream); } @@ -12956,992 +13147,29 @@ qtdemux_expose_streams (GstQTDemux * qtdemux) return GST_FLOW_OK; } -/* check if major or compatible brand is 3GP */ -static inline gboolean -qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major) +typedef struct { - if (major) { - return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) == - FOURCC_3g__); - } else if (qtdemux->comp_brands != NULL) { - GstMapInfo map; - guint8 *data; - gsize size; - gboolean res = FALSE; - - gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ); - data = map.data; - size = map.size; - while (size >= 4) { - res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) == - FOURCC_3g__); - data += 4; - size -= 4; - } - gst_buffer_unmap (qtdemux->comp_brands, &map); - return res; - } else { - return FALSE; - } -} + GstStructure *structure; /* helper for sort function */ + gchar *location; + guint min_req_bitrate; + guint min_req_qt_version; +} GstQtReference; -/* check if tag is a spec'ed 3GP tag keyword storing a string */ -static inline gboolean -qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc) +static gint +qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b) { - return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl - || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth - || fourcc == FOURCC_albm; + GstQtReference *ref_a = (GstQtReference *) a; + GstQtReference *ref_b = (GstQtReference *) b; + + if (ref_b->min_req_qt_version != ref_a->min_req_qt_version) + return ref_b->min_req_qt_version - ref_a->min_req_qt_version; + + /* known bitrates go before unknown; higher bitrates go first */ + return ref_b->min_req_bitrate - ref_a->min_req_bitrate; } -static void -qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist, - const char *tag, const char *dummy, GNode * node) -{ - const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL }; - int offset; - char *name; - gchar *data; - gdouble longitude, latitude, altitude; - gint len; - - len = QT_UINT32 (node->data); - if (len <= 14) - goto short_read; - - data = node->data; - offset = 14; - - /* TODO: language code skipped */ - - name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars); - - if (!name) { - /* do not alarm in trivial case, but bail out otherwise */ - if (*(data + offset) != 0) { - GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, " - "giving up", tag); - } - } else { - gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_GEO_LOCATION_NAME, name, NULL); - offset += strlen (name); - g_free (name); - } - - if (len < offset + 2 + 4 + 4 + 4) - goto short_read; - - /* +1 +1 = skip null-terminator and location role byte */ - offset += 1 + 1; - /* table in spec says unsigned, semantics say negative has meaning ... */ - longitude = QT_SFP32 (data + offset); - - offset += 4; - latitude = QT_SFP32 (data + offset); - - offset += 4; - altitude = QT_SFP32 (data + offset); - - /* one invalid means all are invalid */ - if (longitude >= -180.0 && longitude <= 180.0 && - latitude >= -90.0 && latitude <= 90.0) { - gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_GEO_LOCATION_LATITUDE, latitude, - GST_TAG_GEO_LOCATION_LONGITUDE, longitude, - GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL); - } - - /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */ - - return; - - /* ERRORS */ -short_read: - { - GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location"); - return; - } -} - - -static void -qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist, - const char *tag, const char *dummy, GNode * node) -{ - guint16 y; - GDate *date; - gint len; - - len = QT_UINT32 (node->data); - if (len < 14) - return; - - y = QT_UINT16 ((guint8 *) node->data + 12); - if (y == 0) { - GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y); - return; - } - GST_DEBUG_OBJECT (qtdemux, "year: %u", y); - - date = g_date_new_dmy (1, 1, y); - gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL); - g_date_free (date); -} - -static void -qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist, - const char *tag, const char *dummy, GNode * node) -{ - int offset; - char *tag_str = NULL; - guint8 *entity; - guint16 table; - gint len; - - len = QT_UINT32 (node->data); - if (len <= 20) - goto short_read; - - offset = 12; - entity = (guint8 *) node->data + offset; - if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) { - GST_DEBUG_OBJECT (qtdemux, - "classification info: %c%c%c%c invalid classification entity", - entity[0], entity[1], entity[2], entity[3]); - return; - } - - offset += 4; - table = QT_UINT16 ((guint8 *) node->data + offset); - - /* Language code skipped */ - - offset += 4; - - /* Tag format: "XXXX://Y[YYYY]/classification info string" - * XXXX: classification entity, fixed length 4 chars. - * Y[YYYY]: classification table, max 5 chars. - */ - tag_str = g_strdup_printf ("----://%u/%s", - table, (char *) node->data + offset); - - /* memcpy To be sure we're preserving byte order */ - memcpy (tag_str, entity, 4); - GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str); - - gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL); - - g_free (tag_str); - - return; - - /* ERRORS */ -short_read: - { - GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification"); - return; - } -} - -static gboolean -qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist, - const char *tag, const char *dummy, GNode * node) -{ - const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL }; - GNode *data; - char *s; - int len; - guint32 type; - int offset; - gboolean ret = TRUE; - const gchar *charset = NULL; - - data = qtdemux_tree_get_child_by_type (node, FOURCC_data); - if (data) { - len = QT_UINT32 (data->data); - type = QT_UINT32 ((guint8 *) data->data + 8); - if (type == 0x00000001 && len > 16) { - s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16, - env_vars); - if (s) { - GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s)); - gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL); - g_free (s); - } else { - GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag); - } - } - } else { - len = QT_UINT32 (node->data); - type = QT_UINT32 ((guint8 *) node->data + 4); - if ((type >> 24) == 0xa9 && len > 8 + 4) { - gint str_len; - gint lang_code; - - /* Type starts with the (C) symbol, so the next data is a list - * of (string size(16), language code(16), string) */ - - str_len = QT_UINT16 ((guint8 *) node->data + 8); - lang_code = QT_UINT16 ((guint8 *) node->data + 10); - - /* the string + fourcc + size + 2 16bit fields, - * means that there are more tags in this atom */ - if (len > str_len + 8 + 4) { - /* TODO how to represent the same tag in different languages? */ - GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple " - "text alternatives, reading only first one"); - } - - offset = 12; - len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */ - GST_DEBUG_OBJECT (qtdemux, "found international text tag"); - - if (lang_code < 0x800) { /* MAC encoded string */ - charset = "mac"; - } - } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux, - QT_FOURCC ((guint8 *) node->data + 4))) { - guint32 type = QT_UINT32 ((guint8 *) node->data + 8); - - /* we go for 3GP style encoding if major brands claims so, - * or if no hope for data be ok UTF-8, and compatible 3GP brand present */ - if (qtdemux_is_brand_3gp (qtdemux, TRUE) || - (qtdemux_is_brand_3gp (qtdemux, FALSE) && - ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) { - offset = 14; - /* 16-bit Language code is ignored here as well */ - GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag"); - } else { - goto normal; - } - } else { - normal: - offset = 8; - GST_DEBUG_OBJECT (qtdemux, "found normal text tag"); - ret = FALSE; /* may have to fallback */ - } - if (charset) { - GError *err = NULL; - - s = g_convert ((gchar *) node->data + offset, len - offset, "utf8", - charset, NULL, NULL, &err); - if (err) { - GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:" - " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code, - err->message); - g_error_free (err); - } - } else { - s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset, - len - offset, env_vars); - } - if (s) { - GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s)); - gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL); - g_free (s); - ret = TRUE; - } else { - GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag); - } - } - return ret; -} - -static void -qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist, - const char *tag, const char *dummy, GNode * node) -{ - qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node); -} - -static void -qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist, - const char *tag, const char *dummy, GNode * node) -{ - const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL }; - guint8 *data; - char *s, *t, *k = NULL; - int len; - int offset; - int count; - - /* first try normal string tag if major brand not 3GP */ - if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) { - if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) { - /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand; - * let's try it 3gpp way after minor safety check */ - data = node->data; - if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE)) - return; - } else - return; - } - - GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag"); - - data = node->data; - - len = QT_UINT32 (data); - if (len < 15) - goto short_read; - - count = QT_UINT8 (data + 14); - offset = 15; - for (; count; count--) { - gint slen; - - if (offset + 1 > len) - goto short_read; - slen = QT_UINT8 (data + offset); - offset += 1; - if (offset + slen > len) - goto short_read; - s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset, - slen, env_vars); - if (s) { - GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s)); - if (k) { - t = g_strjoin (",", k, s, NULL); - g_free (s); - g_free (k); - k = t; - } else { - k = s; - } - } else { - GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8"); - } - offset += slen; - } - -done: - if (k) { - GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k)); - gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL); - } - g_free (k); - - return; - - /* ERRORS */ -short_read: - { - GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords"); - goto done; - } -} - -static void -qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist, - const char *tag1, const char *tag2, GNode * node) -{ - GNode *data; - int len; - int type; - int n1, n2; - - data = qtdemux_tree_get_child_by_type (node, FOURCC_data); - if (data) { - len = QT_UINT32 (data->data); - type = QT_UINT32 ((guint8 *) data->data + 8); - if (type == 0x00000000 && len >= 22) { - n1 = QT_UINT16 ((guint8 *) data->data + 18); - n2 = QT_UINT16 ((guint8 *) data->data + 20); - if (n1 > 0) { - GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1); - gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL); - } - if (n2 > 0) { - GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2); - gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL); - } - } - } -} - -static void -qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist, - const char *tag1, const char *dummy, GNode * node) -{ - GNode *data; - int len; - int type; - int n1; - - data = qtdemux_tree_get_child_by_type (node, FOURCC_data); - if (data) { - len = QT_UINT32 (data->data); - type = QT_UINT32 ((guint8 *) data->data + 8); - GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len); - /* some files wrongly have a type 0x0f=15, but it should be 0x15 */ - if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) { - n1 = QT_UINT16 ((guint8 *) data->data + 16); - if (n1) { - /* do not add bpm=0 */ - GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1); - gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1, - NULL); - } - } - } -} - -static void -qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist, - const char *tag1, const char *dummy, GNode * node) -{ - GNode *data; - int len; - int type; - guint32 num; - - data = qtdemux_tree_get_child_by_type (node, FOURCC_data); - if (data) { - len = QT_UINT32 (data->data); - type = QT_UINT32 ((guint8 *) data->data + 8); - GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len); - /* some files wrongly have a type 0x0f=15, but it should be 0x15 */ - if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) { - num = QT_UINT32 ((guint8 *) data->data + 16); - if (num) { - /* do not add num=0 */ - GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num); - gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL); - } - } - } -} - -static void -qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist, - const char *tag1, const char *dummy, GNode * node) -{ - GNode *data; - int len; - int type; - GstSample *sample; - - data = qtdemux_tree_get_child_by_type (node, FOURCC_data); - if (data) { - len = QT_UINT32 (data->data); - type = QT_UINT32 ((guint8 *) data->data + 8); - GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len); - if ((type == 0x0000000d || type == 0x0000000e) && len > 16) { - GstTagImageType image_type; - - if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0) - image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER; - else - image_type = GST_TAG_IMAGE_TYPE_NONE; - - if ((sample = - gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16, - len - 16, image_type))) { - GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16); - gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL); - gst_sample_unref (sample); - } - } - } -} - -static void -qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist, - const char *tag, const char *dummy, GNode * node) -{ - GNode *data; - GstDateTime *datetime = NULL; - char *s; - int len; - int type; - - data = qtdemux_tree_get_child_by_type (node, FOURCC_data); - if (data) { - len = QT_UINT32 (data->data); - type = QT_UINT32 ((guint8 *) data->data + 8); - if (type == 0x00000001 && len > 16) { - guint y, m = 1, d = 1; - gint ret; - - s = g_strndup ((char *) data->data + 16, len - 16); - GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s); - datetime = gst_date_time_new_from_iso8601_string (s); - if (datetime != NULL) { - gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_DATE_TIME, - datetime, NULL); - gst_date_time_unref (datetime); - } - - ret = sscanf (s, "%u-%u-%u", &y, &m, &d); - if (ret >= 1 && y > 1500 && y < 3000) { - GDate *date; - - date = g_date_new_dmy (d, m, y); - gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL); - g_date_free (date); - } else { - GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s); - } - g_free (s); - } - } -} - -static void -qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist, - const char *tag, const char *dummy, GNode * node) -{ - GNode *data; - - data = qtdemux_tree_get_child_by_type (node, FOURCC_data); - - /* re-route to normal string tag if major brand says so - * or no data atom and compatible brand suggests so */ - if (qtdemux_is_brand_3gp (qtdemux, TRUE) || - (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) { - qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node); - return; - } - - if (data) { - guint len, type, n; - - len = QT_UINT32 (data->data); - type = QT_UINT32 ((guint8 *) data->data + 8); - if (type == 0x00000000 && len >= 18) { - n = QT_UINT16 ((guint8 *) data->data + 16); - if (n > 0) { - const gchar *genre; - - genre = gst_tag_id3_genre_get (n - 1); - if (genre != NULL) { - GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre); - gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL); - } - } - } - } -} - -static void -qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist, - const gchar * tag, guint8 * data, guint32 datasize) -{ - gdouble value; - gchar *datacopy; - - /* make a copy to have \0 at the end */ - datacopy = g_strndup ((gchar *) data, datasize); - - /* convert the str to double */ - if (sscanf (datacopy, "%lf", &value) == 1) { - GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy); - gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL); - } else { - GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s", - datacopy); - } - g_free (datacopy); -} - - -static void -qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist, - const char *tag, const char *tag_bis, GNode * node) -{ - GNode *mean; - GNode *name; - GNode *data; - guint32 meansize; - guint32 namesize; - guint32 datatype; - guint32 datasize; - const gchar *meanstr; - const gchar *namestr; - - /* checking the whole ---- atom size for consistency */ - if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) { - GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring"); - return; - } - - mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean); - if (!mean) { - GST_WARNING_OBJECT (demux, "No 'mean' atom found"); - return; - } - - meansize = QT_UINT32 (mean->data); - if (meansize <= 12) { - GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag"); - return; - } - meanstr = ((gchar *) mean->data) + 12; - meansize -= 12; - - name = qtdemux_tree_get_child_by_type (node, FOURCC_name); - if (!name) { - GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag"); - return; - } - - namesize = QT_UINT32 (name->data); - if (namesize <= 12) { - GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag"); - return; - } - namestr = ((gchar *) name->data) + 12; - namesize -= 12; - - /* - * Data atom is: - * uint32 - size - * uint32 - name - * uint8 - version - * uint24 - data type - * uint32 - all 0 - * rest - the data - */ - data = qtdemux_tree_get_child_by_type (node, FOURCC_data); - if (!data) { - GST_WARNING_OBJECT (demux, "No data atom in this tag"); - return; - } - datasize = QT_UINT32 (data->data); - if (datasize <= 16) { - GST_WARNING_OBJECT (demux, "Data atom too small"); - return; - } - datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF; - - if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) || - (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) { - static const struct - { - const gchar name[28]; - const gchar tag[28]; - } tags[] = { - { - "replaygain_track_gain", GST_TAG_TRACK_GAIN}, { - "replaygain_track_peak", GST_TAG_TRACK_PEAK}, { - "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, { - "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, { - "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, { - "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, { - "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, { - "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID} - }; - int i; - - for (i = 0; i < G_N_ELEMENTS (tags); ++i) { - if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) { - switch (gst_tag_get_type (tags[i].tag)) { - case G_TYPE_DOUBLE: - qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag, - ((guint8 *) data->data) + 16, datasize - 16); - break; - case G_TYPE_STRING: - qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node); - break; - default: - /* not reached */ - break; - } - break; - } - } - if (i == G_N_ELEMENTS (tags)) - goto unknown_tag; - } else { - goto unknown_tag; - } - - return; - -/* errors */ -unknown_tag: -#ifndef GST_DISABLE_GST_DEBUG - { - gchar *namestr_dbg; - gchar *meanstr_dbg; - - meanstr_dbg = g_strndup (meanstr, meansize); - namestr_dbg = g_strndup (namestr, namesize); - - GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, " - "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype); - - g_free (namestr_dbg); - g_free (meanstr_dbg); - } -#endif - return; -} - -static void -qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag, - const char *tag_bis, GNode * node) -{ - guint8 *data; - GstBuffer *buf; - guint len; - GstTagList *id32_taglist = NULL; - - GST_LOG_OBJECT (demux, "parsing ID32"); - - data = node->data; - len = GST_READ_UINT32_BE (data); - - /* need at least full box and language tag */ - if (len < 12 + 2) - return; - - buf = gst_buffer_new_allocate (NULL, len - 14, NULL); - gst_buffer_fill (buf, 0, data + 14, len - 14); - - id32_taglist = gst_tag_list_from_id3v2_tag (buf); - if (id32_taglist) { - GST_LOG_OBJECT (demux, "parsing ok"); - gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP); - gst_tag_list_unref (id32_taglist); - } else { - GST_LOG_OBJECT (demux, "parsing failed"); - } - - gst_buffer_unref (buf); -} - -typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist, - const char *tag, const char *tag_bis, GNode * node); - -/* unmapped tags -FOURCC_pcst -> if media is a podcast -> bool -FOURCC_cpil -> if media is part of a compilation -> bool -FOURCC_pgap -> if media is part of a gapless context -> bool -FOURCC_tven -> the tv episode id e.g. S01E23 -> str -*/ - -static const struct -{ - guint32 fourcc; - const gchar *gst_tag; - const gchar *gst_tag_bis; - const GstQTDemuxAddTagFunc func; -} add_funcs[] = { - { - FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, { - FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, { - FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, { - FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, { - FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, { - FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, { - FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, { - FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, { - FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, { - FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, { - FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, { - FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, { - FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, { - FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, { - FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, { - FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, { - FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, { - FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, { - FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, { - FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, { - FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, { - FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, { - FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT, - qtdemux_tag_add_num}, { - FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT, - qtdemux_tag_add_num}, { - FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, { - FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, { - FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, { - FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, { - FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, { - FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, { - FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, { - FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, { - FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, { - FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, { - FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, { - FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, { - FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, { - FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, { - FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, { - FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, { - FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, { - FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL, - qtdemux_tag_add_classification}, { - FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, { - FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, { - FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, { - - /* This is a special case, some tags are stored in this - * 'reverse dns naming', according to: - * http://atomicparsley.sourceforge.net/mpeg-4files.html and - * bug #614471 - */ - FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, { - /* see http://www.mp4ra.org/specs.html for ID32 in meta box */ - FOURCC_ID32, "", NULL, qtdemux_tag_add_id32} -}; - -struct _GstQtDemuxTagList -{ - GstQTDemux *demux; - GstTagList *taglist; -}; -typedef struct _GstQtDemuxTagList GstQtDemuxTagList; - -static void -qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist) -{ - gint len; - guint8 *data; - GstBuffer *buf; - gchar *media_type; - const gchar *style; - GstSample *sample; - GstStructure *s; - guint i; - guint8 ndata[4]; - GstQTDemux *demux = qtdemuxtaglist->demux; - GstTagList *taglist = qtdemuxtaglist->taglist; - - data = node->data; - len = QT_UINT32 (data); - buf = gst_buffer_new_and_alloc (len); - gst_buffer_fill (buf, 0, data, len); - - /* heuristic to determine style of tag */ - if (QT_FOURCC (data + 4) == FOURCC_____ || - (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data)) - style = "itunes"; - else if (demux->major_brand == FOURCC_qt__) - style = "quicktime"; - /* fall back to assuming iso/3gp tag style */ - else - style = "iso"; - - /* sanitize the name for the caps. */ - for (i = 0; i < 4; i++) { - guint8 d = data[4 + i]; - if (g_ascii_isalnum (d)) - ndata[i] = g_ascii_tolower (d); - else - ndata[i] = '_'; - } - - media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag", - ndata[0], ndata[1], ndata[2], ndata[3]); - GST_DEBUG_OBJECT (demux, "media type %s", media_type); - - s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL); - sample = gst_sample_new (buf, NULL, NULL, s); - gst_buffer_unref (buf); - g_free (media_type); - - GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT, - len, s); - - gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, - GST_QT_DEMUX_PRIVATE_TAG, sample, NULL); - - gst_sample_unref (sample); -} - -static void -qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta) -{ - GNode *meta; - GNode *ilst; - GNode *xmp_; - GNode *node; - gint i; - GstQtDemuxTagList demuxtaglist; - - demuxtaglist.demux = qtdemux; - demuxtaglist.taglist = taglist; - - meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta); - if (meta != NULL) { - ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst); - if (ilst == NULL) { - GST_LOG_OBJECT (qtdemux, "no ilst"); - return; - } - } else { - ilst = udta; - GST_LOG_OBJECT (qtdemux, "no meta so using udta itself"); - } - - i = 0; - while (i < G_N_ELEMENTS (add_funcs)) { - node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc); - if (node) { - gint len; - - len = QT_UINT32 (node->data); - if (len < 12) { - GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (add_funcs[i].fourcc)); - } else { - add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag, - add_funcs[i].gst_tag_bis, node); - } - g_node_destroy (node); - } else { - i++; - } - } - - /* parsed nodes have been removed, pass along remainder as blob */ - g_node_children_foreach (ilst, G_TRAVERSE_ALL, - (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist); - - /* parse up XMP_ node if existing */ - xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_); - if (xmp_ != NULL) { - GstBuffer *buf; - GstTagList *xmptaglist; - - buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8, - QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL); - xmptaglist = gst_tag_list_from_xmp_buffer (buf); - gst_buffer_unref (buf); - - qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist); - } else { - GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found"); - } -} - -typedef struct -{ - GstStructure *structure; /* helper for sort function */ - gchar *location; - guint min_req_bitrate; - guint min_req_qt_version; -} GstQtReference; - -static gint -qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b) -{ - GstQtReference *ref_a = (GstQtReference *) a; - GstQtReference *ref_b = (GstQtReference *) b; - - if (ref_b->min_req_qt_version != ref_a->min_req_qt_version) - return ref_b->min_req_qt_version - ref_a->min_req_qt_version; - - /* known bitrates go before unknown; higher bitrates go first */ - return ref_b->min_req_bitrate - ref_a->min_req_bitrate; -} - -/* sort the redirects and post a message for the application. - */ +/* sort the redirects and post a message for the application. + */ static void qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references) { @@ -14968,12 +14196,14 @@ qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, break; case FOURCC_H264: case FOURCC_avc1: + case FOURCC_dva1: _codec ("H.264 / AVC"); caps = gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING, "avc", "alignment", G_TYPE_STRING, "au", NULL); break; case FOURCC_avc3: + case FOURCC_dvav: _codec ("H.264 / AVC"); caps = gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING, "avc3", @@ -14981,12 +14211,14 @@ qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, break; case FOURCC_H265: case FOURCC_hvc1: + case FOURCC_dvh1: _codec ("H.265 / HEVC"); caps = gst_caps_new_simple ("video/x-h265", "stream-format", G_TYPE_STRING, "hvc1", "alignment", G_TYPE_STRING, "au", NULL); break; case FOURCC_hev1: + case FOURCC_dvhe: _codec ("H.265 / HEVC"); caps = gst_caps_new_simple ("video/x-h265", "stream-format", G_TYPE_STRING, "hev1", @@ -15111,12 +14343,24 @@ qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, caps = gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "4444", NULL); + + /* 24 bits per sample = an alpha channel is coded but image is always opaque */ + if (entry->bits_per_sample > 0) { + gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample, + NULL); + } break; case FOURCC_ap4x: _codec ("Apple ProRes 4444 XQ"); caps = gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "4444xq", NULL); + + /* 24 bits per sample = an alpha channel is coded but image is always opaque */ + if (entry->bits_per_sample > 0) { + gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample, + NULL); + } break; case FOURCC_cfhd: _codec ("GoPro CineForm"); @@ -15216,15 +14460,19 @@ qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, stream->alignment = round_up_pow2 (stream->alignment); break; } - case GST_MAKE_FOURCC ('f', 'l', '6', '4'): + case FOURCC_fl64: _codec ("Raw 64-bit floating-point audio"); + /* we assume BIG ENDIAN, an enda box will tell us to change this to little + * endian later */ caps = gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING, "F64BE", "layout", G_TYPE_STRING, "interleaved", NULL); stream->alignment = 8; break; - case GST_MAKE_FOURCC ('f', 'l', '3', '2'): + case FOURCC_fl32: _codec ("Raw 32-bit floating-point audio"); + /* we assume BIG ENDIAN, an enda box will tell us to change this to little + * endian later */ caps = gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING, "F32BE", "layout", G_TYPE_STRING, "interleaved", NULL); @@ -15239,14 +14487,16 @@ qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, "layout", G_TYPE_STRING, "interleaved", NULL); stream->alignment = 4; break; - case GST_MAKE_FOURCC ('i', 'n', '3', '2'): + case FOURCC_in32: _codec ("Raw 32-bit PCM audio"); + /* we assume BIG ENDIAN, an enda box will tell us to change this to little + * endian later */ caps = gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING, "S32BE", "layout", G_TYPE_STRING, "interleaved", NULL); stream->alignment = 4; break; - case GST_MAKE_FOURCC ('s', '1', '6', 'l'): + case FOURCC_s16l: _codec ("Raw 16-bit PCM audio"); caps = gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING, "S16LE", @@ -15285,6 +14535,7 @@ qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, case 0x6d730055: /* MPEG layer 3, CBR only (pre QT4.1) */ case FOURCC__mp3: + case FOURCC_mp3_: _codec ("MPEG-1 layer 3"); /* MPEG layer 3, CBR & VBR (QT4.1 and later) */ caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3, @@ -15467,6 +14718,12 @@ qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, } break; } + case GST_MAKE_FOURCC ('a', 'c', '-', '4'): + { + _codec ("AC4"); + caps = gst_caps_new_empty_simple ("audio/x-ac4"); + break; + } case GST_MAKE_FOURCC ('q', 't', 'v', 'r'): /* ? */ default: @@ -15490,8 +14747,10 @@ qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, name = gst_structure_get_name (s); if (g_str_has_prefix (name, "audio/x-raw")) { stream->need_clip = TRUE; + stream->min_buffer_size = 1024 * entry->bytes_per_frame; stream->max_buffer_size = 4096 * entry->bytes_per_frame; - GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size); + GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size, + stream->max_buffer_size); } return caps; } diff --git a/gst/isomp4/qtdemux.h b/gst/isomp4/qtdemux.h index c5e85c7211..81fb9d242c 100644 --- a/gst/isomp4/qtdemux.h +++ b/gst/isomp4/qtdemux.h @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include "gstisoff.h" G_BEGIN_DECLS @@ -48,6 +50,10 @@ G_BEGIN_DECLS typedef struct _GstQTDemux GstQTDemux; typedef struct _GstQTDemuxClass GstQTDemuxClass; typedef struct _QtDemuxStream QtDemuxStream; +typedef struct _QtDemuxSample QtDemuxSample; +typedef struct _QtDemuxSegment QtDemuxSegment; +typedef struct _QtDemuxRandomAccessEntry QtDemuxRandomAccessEntry; +typedef struct _QtDemuxStreamStsdEntry QtDemuxStreamStsdEntry; enum QtDemuxState { @@ -261,6 +267,241 @@ struct _GstQTDemuxClass { GType gst_qtdemux_get_type (void); +struct _QtDemuxStreamStsdEntry +{ + GstCaps *caps; + guint32 fourcc; + gboolean sparse; + + /* video info */ + gint width; + gint height; + gint par_w; + gint par_h; + /* Numerator/denominator framerate */ + gint fps_n; + gint fps_d; + GstVideoColorimetry colorimetry; + guint16 bits_per_sample; + guint16 color_table_id; + GstMemory *rgb8_palette; + guint interlace_mode; + guint field_order; + + /* audio info */ + gdouble rate; + gint n_channels; + guint samples_per_packet; + guint samples_per_frame; + guint bytes_per_packet; + guint bytes_per_sample; + guint bytes_per_frame; + guint compression; + + /* if we use chunks or samples */ + gboolean sampled; + guint padding; + +}; + +struct _QtDemuxSample +{ + guint32 size; + gint32 pts_offset; /* Add this value to timestamp to get the pts */ + guint64 offset; + guint64 timestamp; /* DTS In mov time */ + guint32 duration; /* In mov time */ + gboolean keyframe; /* TRUE when this packet is a keyframe */ +}; + +struct _QtDemuxStream +{ + GstPad *pad; + + GstQTDemux *demux; + gchar *stream_id; + + QtDemuxStreamStsdEntry *stsd_entries; + guint stsd_entries_length; + guint cur_stsd_entry_index; + + /* stream type */ + guint32 subtype; + + gboolean new_caps; /* If TRUE, caps need to be generated (by + * calling _configure_stream()) This happens + * for MSS and fragmented streams */ + + gboolean new_stream; /* signals that a stream_start is required */ + gboolean on_keyframe; /* if this stream last pushed buffer was a + * keyframe. This is important to identify + * where to stop pushing buffers after a + * segment stop time */ + + /* if the stream has a redirect URI in its headers, we store it here */ + gchar *redirect_uri; + + /* track id */ + guint track_id; + + /* duration/scale */ + guint64 duration; /* in timescale units */ + guint32 timescale; + + /* language */ + gchar lang_id[4]; /* ISO 639-2T language code */ + + /* our samples */ + guint32 n_samples; + QtDemuxSample *samples; + gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */ + guint32 n_samples_moof; /* sample count in a moof */ + guint64 duration_moof; /* duration in timescale of a moof, used for figure out + * the framerate of fragmented format stream */ + guint64 duration_last_moof; + + guint32 offset_in_sample; /* Offset in the current sample, used for + * streams which have got exceedingly big + * sample size (such as 24s of raw audio). + * Only used when max_buffer_size is non-NULL */ + guint32 min_buffer_size; /* Minimum allowed size for output buffers. + * Currently only set for raw audio streams*/ + guint32 max_buffer_size; /* Maximum allowed size for output buffers. + * Currently only set for raw audio streams*/ + + /* video info */ + /* aspect ratio */ + gint display_width; + gint display_height; + + /* allocation */ + gboolean use_allocator; + GstAllocator *allocator; + GstAllocationParams params; + + gsize alignment; + + /* when a discontinuity is pending */ + gboolean discont; + + /* list of buffers to push first */ + GSList *buffers; + + /* if we need to clip this buffer. This is only needed for uncompressed + * data */ + gboolean need_clip; + + /* buffer needs some custom processing, e.g. subtitles */ + gboolean need_process; + /* buffer needs potentially be split, e.g. CEA608 subtitles */ + gboolean need_split; + + /* current position */ + guint32 segment_index; + guint32 sample_index; + GstClockTime time_position; /* in gst time */ + guint64 accumulated_base; + + /* the Gst segment we are processing out, used for clipping */ + GstSegment segment; + + /* quicktime segments */ + guint32 n_segments; + QtDemuxSegment *segments; + gboolean dummy_segment; + guint32 from_sample; + guint32 to_sample; + + gboolean sent_eos; + GstTagList *stream_tags; + gboolean send_global_tags; + + GstEvent *pending_event; + + GstByteReader stco; + GstByteReader stsz; + GstByteReader stsc; + GstByteReader stts; + GstByteReader stss; + GstByteReader stps; + GstByteReader ctts; + + gboolean chunks_are_samples; /* TRUE means treat chunks as samples */ + gint64 stbl_index; + /* stco */ + guint co_size; + GstByteReader co_chunk; + guint32 first_chunk; + guint32 current_chunk; + guint32 last_chunk; + guint32 samples_per_chunk; + guint32 stsd_sample_description_id; + guint32 stco_sample_index; + /* stsz */ + guint32 sample_size; /* 0 means variable sizes are stored in stsz */ + /* stsc */ + guint32 stsc_index; + guint32 n_samples_per_chunk; + guint32 stsc_chunk_index; + guint32 stsc_sample_index; + guint64 chunk_offset; + /* stts */ + guint32 stts_index; + guint32 stts_samples; + guint32 n_sample_times; + guint32 stts_sample_index; + guint64 stts_time; + guint32 stts_duration; + /* stss */ + gboolean stss_present; + guint32 n_sample_syncs; + guint32 stss_index; + /* stps */ + gboolean stps_present; + guint32 n_sample_partial_syncs; + guint32 stps_index; + QtDemuxRandomAccessEntry *ra_entries; + guint n_ra_entries; + + const QtDemuxRandomAccessEntry *pending_seek; + + /* ctts */ + gboolean ctts_present; + guint32 n_composition_times; + guint32 ctts_index; + guint32 ctts_sample_index; + guint32 ctts_count; + gint32 ctts_soffset; + + /* cslg */ + guint32 cslg_shift; + + /* fragmented */ + gboolean parsed_trex; + guint32 def_sample_description_index; /* index is 1-based */ + guint32 def_sample_duration; + guint32 def_sample_size; + guint32 def_sample_flags; + + gboolean disabled; + + /* stereoscopic video streams */ + GstVideoMultiviewMode multiview_mode; + GstVideoMultiviewFlags multiview_flags; + + /* protected streams */ + gboolean protected; + guint32 protection_scheme_type; + guint32 protection_scheme_version; + gpointer protection_scheme_info; /* specific to the protection scheme */ + GQueue protection_scheme_event_queue; + + /* KEY_UNITS trickmode with an interval */ + GstClockTime last_keyframe_dts; + + gint ref_count; /* atomic */ +}; + G_END_DECLS #endif /* __GST_QTDEMUX_H__ */ diff --git a/gst/isomp4/qtdemux_tags.c b/gst/isomp4/qtdemux_tags.c new file mode 100644 index 0000000000..f2b384d692 --- /dev/null +++ b/gst/isomp4/qtdemux_tags.c @@ -0,0 +1,1034 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * Copyright (C) <2003> David A. Schleef + * Copyright (C) <2006> Wim Taymans + * Copyright (C) <2007> Julien Moutte + * Copyright (C) <2009> Tim-Philipp Müller + * Copyright (C) <2009> STEricsson + * Copyright (C) <2013> Sreerenj Balachandran + * Copyright (C) <2013> Intel Corporation + * Copyright (C) <2014> Centricular Ltd + * Copyright (C) <2015> YouView TV Ltd. + * Copyright (C) <2016> British Broadcasting Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/* Parsing functions for various MP4 standard extension atom groups */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "qtdemux_tags.h" +#include "qtdemux_tree.h" +#include "qtdemux_types.h" +#include "fourcc.h" + +static GstBuffer * +_gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func) +{ + return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY, + mem, size, 0, size, mem, free_func); +} + +/* check if major or compatible brand is 3GP */ +static inline gboolean +qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major) +{ + if (major) { + return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) == + FOURCC_3g__); + } else if (qtdemux->comp_brands != NULL) { + GstMapInfo map; + guint8 *data; + gsize size; + gboolean res = FALSE; + + gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ); + data = map.data; + size = map.size; + while (size >= 4) { + res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) == + FOURCC_3g__); + data += 4; + size -= 4; + } + gst_buffer_unmap (qtdemux->comp_brands, &map); + return res; + } else { + return FALSE; + } +} + +/* check if tag is a spec'ed 3GP tag keyword storing a string */ +static inline gboolean +qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc) +{ + return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl + || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth + || fourcc == FOURCC_albm; +} + +static void +qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist, + const char *tag, const char *dummy, GNode * node) +{ + const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL }; + int offset; + char *name; + gchar *data; + gdouble longitude, latitude, altitude; + gint len; + + len = QT_UINT32 (node->data); + if (len <= 14) + goto short_read; + + data = node->data; + offset = 14; + + /* TODO: language code skipped */ + + name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars); + + if (!name) { + /* do not alarm in trivial case, but bail out otherwise */ + if (*(data + offset) != 0) { + GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, " + "giving up", tag); + } + } else { + gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, + GST_TAG_GEO_LOCATION_NAME, name, NULL); + offset += strlen (name); + g_free (name); + } + + if (len < offset + 2 + 4 + 4 + 4) + goto short_read; + + /* +1 +1 = skip null-terminator and location role byte */ + offset += 1 + 1; + /* table in spec says unsigned, semantics say negative has meaning ... */ + longitude = QT_SFP32 (data + offset); + + offset += 4; + latitude = QT_SFP32 (data + offset); + + offset += 4; + altitude = QT_SFP32 (data + offset); + + /* one invalid means all are invalid */ + if (longitude >= -180.0 && longitude <= 180.0 && + latitude >= -90.0 && latitude <= 90.0) { + gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, + GST_TAG_GEO_LOCATION_LATITUDE, latitude, + GST_TAG_GEO_LOCATION_LONGITUDE, longitude, + GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL); + } + + /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */ + + return; + + /* ERRORS */ +short_read: + { + GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location"); + return; + } +} + + +static void +qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist, + const char *tag, const char *dummy, GNode * node) +{ + guint16 y; + GDate *date; + gint len; + + len = QT_UINT32 (node->data); + if (len < 14) + return; + + y = QT_UINT16 ((guint8 *) node->data + 12); + if (y == 0) { + GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y); + return; + } + GST_DEBUG_OBJECT (qtdemux, "year: %u", y); + + date = g_date_new_dmy (1, 1, y); + gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL); + g_date_free (date); +} + +static void +qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist, + const char *tag, const char *dummy, GNode * node) +{ + int offset; + char *tag_str = NULL; + guint8 *entity; + guint16 table; + gint len; + + len = QT_UINT32 (node->data); + if (len <= 20) + goto short_read; + + offset = 12; + entity = (guint8 *) node->data + offset; + if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) { + GST_DEBUG_OBJECT (qtdemux, + "classification info: %c%c%c%c invalid classification entity", + entity[0], entity[1], entity[2], entity[3]); + return; + } + + offset += 4; + table = QT_UINT16 ((guint8 *) node->data + offset); + + /* Language code skipped */ + + offset += 4; + + /* Tag format: "XXXX://Y[YYYY]/classification info string" + * XXXX: classification entity, fixed length 4 chars. + * Y[YYYY]: classification table, max 5 chars. + */ + tag_str = g_strdup_printf ("----://%u/%s", + table, (char *) node->data + offset); + + /* memcpy To be sure we're preserving byte order */ + memcpy (tag_str, entity, 4); + GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str); + + gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL); + + g_free (tag_str); + + return; + + /* ERRORS */ +short_read: + { + GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification"); + return; + } +} + +static gboolean +qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist, + const char *tag, const char *dummy, GNode * node) +{ + const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL }; + GNode *data; + char *s; + int len; + guint32 type; + int offset; + gboolean ret = TRUE; + const gchar *charset = NULL; + + data = qtdemux_tree_get_child_by_type (node, FOURCC_data); + if (data) { + len = QT_UINT32 (data->data); + type = QT_UINT32 ((guint8 *) data->data + 8); + if (type == 0x00000001 && len > 16) { + s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16, + env_vars); + if (s) { + GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s)); + gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL); + g_free (s); + } else { + GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag); + } + } + } else { + len = QT_UINT32 (node->data); + type = QT_UINT32 ((guint8 *) node->data + 4); + if ((type >> 24) == 0xa9 && len > 8 + 4) { + gint str_len; + gint lang_code; + + /* Type starts with the (C) symbol, so the next data is a list + * of (string size(16), language code(16), string) */ + + str_len = QT_UINT16 ((guint8 *) node->data + 8); + lang_code = QT_UINT16 ((guint8 *) node->data + 10); + + /* the string + fourcc + size + 2 16bit fields, + * means that there are more tags in this atom */ + if (len > str_len + 8 + 4) { + /* TODO how to represent the same tag in different languages? */ + GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple " + "text alternatives, reading only first one"); + } + + offset = 12; + len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */ + GST_DEBUG_OBJECT (qtdemux, "found international text tag"); + + if (lang_code < 0x800) { /* MAC encoded string */ + charset = "mac"; + } + } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux, + QT_FOURCC ((guint8 *) node->data + 4))) { + guint32 type = QT_UINT32 ((guint8 *) node->data + 8); + + /* we go for 3GP style encoding if major brands claims so, + * or if no hope for data be ok UTF-8, and compatible 3GP brand present */ + if (qtdemux_is_brand_3gp (qtdemux, TRUE) || + (qtdemux_is_brand_3gp (qtdemux, FALSE) && + ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) { + offset = 14; + /* 16-bit Language code is ignored here as well */ + GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag"); + } else { + goto normal; + } + } else { + normal: + offset = 8; + GST_DEBUG_OBJECT (qtdemux, "found normal text tag"); + ret = FALSE; /* may have to fallback */ + } + if (charset) { + GError *err = NULL; + + s = g_convert ((gchar *) node->data + offset, len - offset, "utf8", + charset, NULL, NULL, &err); + if (err) { + GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:" + " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code, + err->message); + g_error_free (err); + } + } else { + s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset, + len - offset, env_vars); + } + if (s) { + GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s)); + gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL); + g_free (s); + ret = TRUE; + } else { + GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag); + } + } + return ret; +} + +static void +qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist, + const char *tag, const char *dummy, GNode * node) +{ + qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node); +} + +static void +qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist, + const char *tag, const char *dummy, GNode * node) +{ + const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL }; + guint8 *data; + char *s, *t, *k = NULL; + int len; + int offset; + int count; + + /* first try normal string tag if major brand not 3GP */ + if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) { + if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) { + /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand; + * let's try it 3gpp way after minor safety check */ + data = node->data; + if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE)) + return; + } else + return; + } + + GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag"); + + data = node->data; + + len = QT_UINT32 (data); + if (len < 15) + goto short_read; + + count = QT_UINT8 (data + 14); + offset = 15; + for (; count; count--) { + gint slen; + + if (offset + 1 > len) + goto short_read; + slen = QT_UINT8 (data + offset); + offset += 1; + if (offset + slen > len) + goto short_read; + s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset, + slen, env_vars); + if (s) { + GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s)); + if (k) { + t = g_strjoin (",", k, s, NULL); + g_free (s); + g_free (k); + k = t; + } else { + k = s; + } + } else { + GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8"); + } + offset += slen; + } + +done: + if (k) { + GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k)); + gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL); + } + g_free (k); + + return; + + /* ERRORS */ +short_read: + { + GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords"); + goto done; + } +} + +static void +qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist, + const char *tag1, const char *tag2, GNode * node) +{ + GNode *data; + int len; + int type; + int n1, n2; + + data = qtdemux_tree_get_child_by_type (node, FOURCC_data); + if (data) { + len = QT_UINT32 (data->data); + type = QT_UINT32 ((guint8 *) data->data + 8); + if (type == 0x00000000 && len >= 22) { + n1 = QT_UINT16 ((guint8 *) data->data + 18); + n2 = QT_UINT16 ((guint8 *) data->data + 20); + if (n1 > 0) { + GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1); + gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL); + } + if (n2 > 0) { + GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2); + gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL); + } + } + } +} + +static void +qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist, + const char *tag1, const char *dummy, GNode * node) +{ + GNode *data; + int len; + int type; + int n1; + + data = qtdemux_tree_get_child_by_type (node, FOURCC_data); + if (data) { + len = QT_UINT32 (data->data); + type = QT_UINT32 ((guint8 *) data->data + 8); + GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len); + /* some files wrongly have a type 0x0f=15, but it should be 0x15 */ + if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) { + n1 = QT_UINT16 ((guint8 *) data->data + 16); + if (n1) { + /* do not add bpm=0 */ + GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1); + gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1, + NULL); + } + } + } +} + +static void +qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist, + const char *tag1, const char *dummy, GNode * node) +{ + GNode *data; + int len; + int type; + guint32 num; + + data = qtdemux_tree_get_child_by_type (node, FOURCC_data); + if (data) { + len = QT_UINT32 (data->data); + type = QT_UINT32 ((guint8 *) data->data + 8); + GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len); + /* some files wrongly have a type 0x0f=15, but it should be 0x15 */ + if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) { + num = QT_UINT32 ((guint8 *) data->data + 16); + if (num) { + /* do not add num=0 */ + GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num); + gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL); + } + } + } +} + +static void +qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist, + const char *tag1, const char *dummy, GNode * node) +{ + GNode *data; + int len; + int type; + GstSample *sample; + + data = qtdemux_tree_get_child_by_type (node, FOURCC_data); + if (data) { + len = QT_UINT32 (data->data); + type = QT_UINT32 ((guint8 *) data->data + 8); + GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len); + if ((type == 0x0000000d || type == 0x0000000e) && len > 16) { + GstTagImageType image_type; + + if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0) + image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER; + else + image_type = GST_TAG_IMAGE_TYPE_NONE; + + if ((sample = + gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16, + len - 16, image_type))) { + GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16); + gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL); + gst_sample_unref (sample); + } + } + } +} + +static void +qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist, + const char *tag, const char *dummy, GNode * node) +{ + GNode *data; + GstDateTime *datetime = NULL; + char *s; + int len; + int type; + + data = qtdemux_tree_get_child_by_type (node, FOURCC_data); + if (data) { + len = QT_UINT32 (data->data); + type = QT_UINT32 ((guint8 *) data->data + 8); + if (type == 0x00000001 && len > 16) { + guint y, m = 1, d = 1; + gint ret; + + s = g_strndup ((char *) data->data + 16, len - 16); + GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s); + datetime = gst_date_time_new_from_iso8601_string (s); + if (datetime != NULL) { + gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_DATE_TIME, + datetime, NULL); + gst_date_time_unref (datetime); + } + + ret = sscanf (s, "%u-%u-%u", &y, &m, &d); + if (ret >= 1 && y > 1500 && y < 3000) { + GDate *date; + + date = g_date_new_dmy (d, m, y); + gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL); + g_date_free (date); + } else { + GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s); + } + g_free (s); + } + } +} + +static void +qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist, + const char *tag, const char *dummy, GNode * node) +{ + GNode *data; + + data = qtdemux_tree_get_child_by_type (node, FOURCC_data); + + /* re-route to normal string tag if major brand says so + * or no data atom and compatible brand suggests so */ + if (qtdemux_is_brand_3gp (qtdemux, TRUE) || + (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) { + qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node); + return; + } + + if (data) { + guint len, type, n; + + len = QT_UINT32 (data->data); + type = QT_UINT32 ((guint8 *) data->data + 8); + if (type == 0x00000000 && len >= 18) { + n = QT_UINT16 ((guint8 *) data->data + 16); + if (n > 0) { + const gchar *genre; + + genre = gst_tag_id3_genre_get (n - 1); + if (genre != NULL) { + GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre); + gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL); + } + } + } + } +} + +static void +qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist, + const gchar * tag, guint8 * data, guint32 datasize) +{ + gdouble value; + gchar *datacopy; + + /* make a copy to have \0 at the end */ + datacopy = g_strndup ((gchar *) data, datasize); + + /* convert the str to double */ + if (sscanf (datacopy, "%lf", &value) == 1) { + GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy); + gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL); + } else { + GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s", + datacopy); + } + g_free (datacopy); +} + + +static void +qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist, + const char *tag, const char *tag_bis, GNode * node) +{ + GNode *mean; + GNode *name; + GNode *data; + guint32 meansize; + guint32 namesize; + guint32 datatype; + guint32 datasize; + const gchar *meanstr; + const gchar *namestr; + + /* checking the whole ---- atom size for consistency */ + if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) { + GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring"); + return; + } + + mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean); + if (!mean) { + GST_WARNING_OBJECT (demux, "No 'mean' atom found"); + return; + } + + meansize = QT_UINT32 (mean->data); + if (meansize <= 12) { + GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag"); + return; + } + meanstr = ((gchar *) mean->data) + 12; + meansize -= 12; + + name = qtdemux_tree_get_child_by_type (node, FOURCC_name); + if (!name) { + GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag"); + return; + } + + namesize = QT_UINT32 (name->data); + if (namesize <= 12) { + GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag"); + return; + } + namestr = ((gchar *) name->data) + 12; + namesize -= 12; + + /* + * Data atom is: + * uint32 - size + * uint32 - name + * uint8 - version + * uint24 - data type + * uint32 - all 0 + * rest - the data + */ + data = qtdemux_tree_get_child_by_type (node, FOURCC_data); + if (!data) { + GST_WARNING_OBJECT (demux, "No data atom in this tag"); + return; + } + datasize = QT_UINT32 (data->data); + if (datasize <= 16) { + GST_WARNING_OBJECT (demux, "Data atom too small"); + return; + } + datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF; + + if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) || + (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) { + static const struct + { + const gchar name[28]; + const gchar tag[28]; + } tags[] = { + { + "replaygain_track_gain", GST_TAG_TRACK_GAIN}, { + "replaygain_track_peak", GST_TAG_TRACK_PEAK}, { + "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, { + "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, { + "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, { + "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, { + "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, { + "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID} + }; + int i; + + for (i = 0; i < G_N_ELEMENTS (tags); ++i) { + if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) { + switch (gst_tag_get_type (tags[i].tag)) { + case G_TYPE_DOUBLE: + qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag, + ((guint8 *) data->data) + 16, datasize - 16); + break; + case G_TYPE_STRING: + qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node); + break; + default: + /* not reached */ + break; + } + break; + } + } + if (i == G_N_ELEMENTS (tags)) + goto unknown_tag; + } else { + goto unknown_tag; + } + + return; + +/* errors */ +unknown_tag: +#ifndef GST_DISABLE_GST_DEBUG + { + gchar *namestr_dbg; + gchar *meanstr_dbg; + + meanstr_dbg = g_strndup (meanstr, meansize); + namestr_dbg = g_strndup (namestr, namesize); + + GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, " + "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype); + + g_free (namestr_dbg); + g_free (meanstr_dbg); + } +#endif + return; +} + +static void +qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag, + const char *tag_bis, GNode * node) +{ + guint8 *data; + GstBuffer *buf; + guint len; + GstTagList *id32_taglist = NULL; + + GST_LOG_OBJECT (demux, "parsing ID32"); + + data = node->data; + len = GST_READ_UINT32_BE (data); + + /* need at least full box and language tag */ + if (len < 12 + 2) + return; + + buf = gst_buffer_new_allocate (NULL, len - 14, NULL); + gst_buffer_fill (buf, 0, data + 14, len - 14); + + id32_taglist = gst_tag_list_from_id3v2_tag (buf); + if (id32_taglist) { + GST_LOG_OBJECT (demux, "parsing ok"); + gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP); + gst_tag_list_unref (id32_taglist); + } else { + GST_LOG_OBJECT (demux, "parsing failed"); + } + + gst_buffer_unref (buf); +} + +typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist, + const char *tag, const char *tag_bis, GNode * node); + +/* unmapped tags +FOURCC_pcst -> if media is a podcast -> bool +FOURCC_cpil -> if media is part of a compilation -> bool +FOURCC_pgap -> if media is part of a gapless context -> bool +FOURCC_tven -> the tv episode id e.g. S01E23 -> str +*/ + +static const struct +{ + guint32 fourcc; + const gchar *gst_tag; + const gchar *gst_tag_bis; + const GstQTDemuxAddTagFunc func; +} add_funcs[] = { + { + FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, { + FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, { + FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, { + FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, { + FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, { + FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, { + FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, { + FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, { + FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, { + FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, { + FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, { + FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, { + FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, { + FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, { + FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, { + FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, { + FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, { + FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, { + FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, { + FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, { + FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, { + FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, { + FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT, + qtdemux_tag_add_num}, { + FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT, + qtdemux_tag_add_num}, { + FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, { + FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, { + FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, { + FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, { + FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, { + FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, { + FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, { + FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, { + FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, { + FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, { + FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, { + FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, { + FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, { + FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, { + FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, { + FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, { + FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, { + FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL, + qtdemux_tag_add_classification}, { + FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, { + FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, { + FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, { + + /* This is a special case, some tags are stored in this + * 'reverse dns naming', according to: + * http://atomicparsley.sourceforge.net/mpeg-4files.html and + * bug #614471 + */ + FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, { + /* see http://www.mp4ra.org/specs.html for ID32 in meta box */ + FOURCC_ID32, "", NULL, qtdemux_tag_add_id32} +}; + +struct _GstQtDemuxTagList +{ + GstQTDemux *demux; + GstTagList *taglist; +}; +typedef struct _GstQtDemuxTagList GstQtDemuxTagList; + +static void +qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist) +{ + gint len; + guint8 *data; + GstBuffer *buf; + gchar *media_type; + const gchar *style; + GstSample *sample; + GstStructure *s; + guint i; + guint8 ndata[4]; + GstQTDemux *demux = qtdemuxtaglist->demux; + GstTagList *taglist = qtdemuxtaglist->taglist; + + data = node->data; + len = QT_UINT32 (data); + buf = gst_buffer_new_and_alloc (len); + gst_buffer_fill (buf, 0, data, len); + + /* heuristic to determine style of tag */ + if (QT_FOURCC (data + 4) == FOURCC_____ || + (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data)) + style = "itunes"; + else if (demux->major_brand == FOURCC_qt__) + style = "quicktime"; + /* fall back to assuming iso/3gp tag style */ + else + style = "iso"; + + /* sanitize the name for the caps. */ + for (i = 0; i < 4; i++) { + guint8 d = data[4 + i]; + if (g_ascii_isalnum (d)) + ndata[i] = g_ascii_tolower (d); + else + ndata[i] = '_'; + } + + media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag", + ndata[0], ndata[1], ndata[2], ndata[3]); + GST_DEBUG_OBJECT (demux, "media type %s", media_type); + + s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL); + sample = gst_sample_new (buf, NULL, NULL, s); + gst_buffer_unref (buf); + g_free (media_type); + + GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT, + len, s); + + gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, + GST_QT_DEMUX_PRIVATE_TAG, sample, NULL); + + gst_sample_unref (sample); +} + +void +qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta) +{ + GNode *meta; + GNode *ilst; + GNode *xmp_; + GNode *node; + gint i; + GstQtDemuxTagList demuxtaglist; + + demuxtaglist.demux = qtdemux; + demuxtaglist.taglist = taglist; + + meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta); + if (meta != NULL) { + ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst); + if (ilst == NULL) { + GST_LOG_OBJECT (qtdemux, "no ilst"); + return; + } + } else { + ilst = udta; + GST_LOG_OBJECT (qtdemux, "no meta so using udta itself"); + } + + i = 0; + while (i < G_N_ELEMENTS (add_funcs)) { + node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc); + if (node) { + gint len; + + len = QT_UINT32 (node->data); + if (len < 12) { + GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (add_funcs[i].fourcc)); + } else { + add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag, + add_funcs[i].gst_tag_bis, node); + } + g_node_destroy (node); + } else { + i++; + } + } + + /* parsed nodes have been removed, pass along remainder as blob */ + g_node_children_foreach (ilst, G_TRAVERSE_ALL, + (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist); + + /* parse up XMP_ node if existing */ + xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_); + if (xmp_ != NULL) { + GstBuffer *buf; + GstTagList *xmptaglist; + + buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8, + QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL); + xmptaglist = gst_tag_list_from_xmp_buffer (buf); + gst_buffer_unref (buf); + + qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist); + } else { + GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found"); + } +} + +void +qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist, + GstTagList * xmptaglist) +{ + /* Strip out bogus fields */ + if (xmptaglist) { + if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) { + gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC); + gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC); + } else { + gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT); + } + + GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist); + + /* prioritize native tags using _KEEP mode */ + gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP); + gst_tag_list_unref (xmptaglist); + } +} diff --git a/gst/isomp4/qtdemux_tags.h b/gst/isomp4/qtdemux_tags.h new file mode 100644 index 0000000000..a55e993394 --- /dev/null +++ b/gst/isomp4/qtdemux_tags.h @@ -0,0 +1,30 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __QTDEMUX_TAGS_H__ +#define __QTDEMUX_TAGS_H__ + +#include +#include "qtdemux.h" + +void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta); +void qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist, + GstTagList * xmptaglist); + +#endif diff --git a/gst/isomp4/qtdemux_tree.c b/gst/isomp4/qtdemux_tree.c new file mode 100644 index 0000000000..e27dc45a39 --- /dev/null +++ b/gst/isomp4/qtdemux_tree.c @@ -0,0 +1,122 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * Copyright (C) <2003> David A. Schleef + * Copyright (C) <2006> Wim Taymans + * Copyright (C) <2007> Julien Moutte + * Copyright (C) <2009> Tim-Philipp Müller + * Copyright (C) <2009> STEricsson + * Copyright (C) <2013> Sreerenj Balachandran + * Copyright (C) <2013> Intel Corporation + * Copyright (C) <2014> Centricular Ltd + * Copyright (C) <2015> YouView TV Ltd. + * Copyright (C) <2016> British Broadcasting Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "qtdemux_tree.h" +#include "qtdemux_types.h" +#include "fourcc.h" + +GNode * +qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc) +{ + GNode *child; + guint8 *buffer; + guint32 child_fourcc; + + for (child = g_node_first_child (node); child; + child = g_node_next_sibling (child)) { + buffer = (guint8 *) child->data; + + child_fourcc = QT_FOURCC (buffer + 4); + + if (G_UNLIKELY (child_fourcc == fourcc)) { + return child; + } + } + return NULL; +} + +GNode * +qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc, + GstByteReader * parser) +{ + GNode *child; + guint8 *buffer; + guint32 child_fourcc, child_len; + + for (child = g_node_first_child (node); child; + child = g_node_next_sibling (child)) { + buffer = (guint8 *) child->data; + + child_len = QT_UINT32 (buffer); + child_fourcc = QT_FOURCC (buffer + 4); + + if (G_UNLIKELY (child_fourcc == fourcc)) { + if (G_UNLIKELY (child_len < (4 + 4))) + return NULL; + /* FIXME: must verify if atom length < parent atom length */ + gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4)); + return child; + } + } + return NULL; +} + +GNode * +qtdemux_tree_get_child_by_index (GNode * node, guint index) +{ + return g_node_nth_child (node, index); +} + +GNode * +qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc, + GstByteReader * parser) +{ + GNode *child; + guint8 *buffer; + guint32 child_fourcc, child_len; + + for (child = g_node_next_sibling (node); child; + child = g_node_next_sibling (child)) { + buffer = (guint8 *) child->data; + + child_fourcc = QT_FOURCC (buffer + 4); + + if (child_fourcc == fourcc) { + if (parser) { + child_len = QT_UINT32 (buffer); + if (G_UNLIKELY (child_len < (4 + 4))) + return NULL; + /* FIXME: must verify if atom length < parent atom length */ + gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4)); + } + return child; + } + } + return NULL; +} + +GNode * +qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc) +{ + return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL); +} diff --git a/gst/isomp4/qtdemux_tree.h b/gst/isomp4/qtdemux_tree.h new file mode 100644 index 0000000000..14381815ae --- /dev/null +++ b/gst/isomp4/qtdemux_tree.h @@ -0,0 +1,47 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * Copyright (C) <2003> David A. Schleef + * Copyright (C) <2006> Wim Taymans + * Copyright (C) <2007> Julien Moutte + * Copyright (C) <2009> Tim-Philipp Müller + * Copyright (C) <2009> STEricsson + * Copyright (C) <2013> Sreerenj Balachandran + * Copyright (C) <2013> Intel Corporation + * Copyright (C) <2014> Centricular Ltd + * Copyright (C) <2015> YouView TV Ltd. + * Copyright (C) <2016> British Broadcasting Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include +#include + +#ifndef __QTDEMUX_TREE_H__ +#define __QTDEMUX_TREE_H__ + +G_BEGIN_DECLS + +GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc); +GNode *qtdemux_tree_get_child_by_type_full (GNode * node, + guint32 fourcc, GstByteReader * parser); +GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc); +GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node, + guint32 fourcc, GstByteReader * parser); +GNode *qtdemux_tree_get_child_by_index (GNode * node, guint index); + +G_END_DECLS + +#endif diff --git a/gst/isomp4/qtdemux_types.c b/gst/isomp4/qtdemux_types.c index 9ab2e7e3e3..9852429ba5 100644 --- a/gst/isomp4/qtdemux_types.c +++ b/gst/isomp4/qtdemux_types.c @@ -186,10 +186,15 @@ static const QtNodeType qt_node_types[] = { {FOURCC_avcC, "AV codec configuration container", 0}, {FOURCC_avc1, "AV codec configuration v1", 0}, {FOURCC_avc3, "AV codec configuration v3", 0}, + {FOURCC_dva1, "AVC-based Dolby Vision derived from avc1", 0}, + {FOURCC_dvav, "AVC-based Dolby Vision derived from avc3", 0}, {FOURCC_mp4s, "VOBSUB codec configuration", 0}, {FOURCC_hvc1, "HEVC codec configuration", 0}, {FOURCC_hev1, "HEVC codec configuration", 0}, {FOURCC_hvcC, "HEVC codec configuration container", 0}, + {FOURCC_dvhe, "HEVC-based Dolby Vision codec derived from hev1 ", 0}, + {FOURCC_dvh1, "HEVC-based Dolby Vision codec derived from hvc1 ", 0}, + {FOURCC_dvcC, "HEVC-based Dolby Vision codec configuration container", 0}, {FOURCC_tfdt, "Track fragment decode time", 0, qtdemux_dump_tfdt}, {FOURCC_chap, "Chapter Reference"}, {FOURCC_btrt, "Bitrate information", 0}, diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c index 5a6b2487ee..fea2fd9c87 100644 --- a/gst/matroska/matroska-demux.c +++ b/gst/matroska/matroska-demux.c @@ -473,8 +473,8 @@ gst_matroska_demux_parse_mastering_metadata (GstMatroskaDemux * demux, guint32 id; gdouble num; /* Precision defined by HEVC specification */ - const guint chroma_den = 50000; - const guint luma_den = 10000; + const guint chroma_scale = 50000; + const guint luma_scale = 10000; gst_video_mastering_display_info_init (&minfo); @@ -504,7 +504,7 @@ gst_matroska_demux_parse_mastering_metadata (GstMatroskaDemux * demux, * 1000 cd/m^2 is generally used value on HDR. Just check guint range here. * See https://www.webmproject.org/docs/container/#LuminanceMax */ - if (num < 0 || num > (gdouble) (G_MAXUINT32 / luma_den)) { + if (num < 0 || num > (gdouble) (G_MAXUINT32 / luma_scale)) { GST_WARNING_OBJECT (demux, "0x%x has invalid value %f", id, num); goto beach; } @@ -512,44 +512,34 @@ gst_matroska_demux_parse_mastering_metadata (GstMatroskaDemux * demux, switch (id) { case GST_MATROSKA_ID_PRIMARYRCHROMATICITYX: - minfo.Rx_n = (guint) round (num * chroma_den); - minfo.Rx_d = chroma_den; + minfo.display_primaries[0].x = (guint16) (num * chroma_scale); break; case GST_MATROSKA_ID_PRIMARYRCHROMATICITYY: - minfo.Ry_n = (guint) round (num * chroma_den); - minfo.Ry_d = chroma_den; + minfo.display_primaries[0].y = (guint16) (num * chroma_scale); break; case GST_MATROSKA_ID_PRIMARYGCHROMATICITYX: - minfo.Gx_n = (guint) round (num * chroma_den); - minfo.Gx_d = chroma_den; + minfo.display_primaries[1].x = (guint16) (num * chroma_scale); break; case GST_MATROSKA_ID_PRIMARYGCHROMATICITYY: - minfo.Gy_n = (guint) round (num * chroma_den); - minfo.Gy_d = chroma_den; + minfo.display_primaries[1].y = (guint16) (num * chroma_scale); break; case GST_MATROSKA_ID_PRIMARYBCHROMATICITYX: - minfo.Bx_n = (guint) round (num * chroma_den); - minfo.Bx_d = chroma_den; + minfo.display_primaries[2].x = (guint16) (num * chroma_scale); break; case GST_MATROSKA_ID_PRIMARYBCHROMATICITYY: - minfo.By_n = (guint) round (num * chroma_den); - minfo.By_d = chroma_den; + minfo.display_primaries[2].y = (guint16) (num * chroma_scale); break; case GST_MATROSKA_ID_WHITEPOINTCHROMATICITYX: - minfo.Wx_n = (guint) round (num * chroma_den); - minfo.Wx_d = chroma_den; + minfo.white_point.x = (guint16) (num * chroma_scale); break; case GST_MATROSKA_ID_WHITEPOINTCHROMATICITYY: - minfo.Wy_n = (guint) round (num * chroma_den); - minfo.Wy_d = chroma_den; + minfo.white_point.y = (guint16) (num * chroma_scale); break; case GST_MATROSKA_ID_LUMINANCEMAX: - minfo.max_luma_n = (guint) round (num * luma_den); - minfo.max_luma_d = luma_den; + minfo.max_display_mastering_luminance = (guint32) (num * luma_scale); break; case GST_MATROSKA_ID_LUMINANCEMIN: - minfo.min_luma_n = (guint) round (num * luma_den); - minfo.min_luma_d = luma_den; + minfo.min_display_mastering_luminance = (guint32) (num * luma_scale); break; default: GST_FIXME_OBJECT (demux, @@ -626,7 +616,8 @@ gst_matroska_demux_parse_colour (GstMatroskaDemux * demux, GstEbmlRead * ebml, if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) goto beach; - colorimetry.transfer = gst_video_color_transfer_from_iso ((guint) num); + colorimetry.transfer = + gst_video_transfer_function_from_iso ((guint) num); break; } @@ -650,12 +641,11 @@ gst_matroska_demux_parse_colour (GstMatroskaDemux * demux, GstEbmlRead * ebml, case GST_MATROSKA_ID_MAXCLL:{ if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) goto beach; - if (num >= G_MAXUINT32) { + if (num > G_MAXUINT16) { GST_WARNING_OBJECT (demux, "Too large maxCLL value %" G_GUINT64_FORMAT, num); } else { - video_context->content_light_level.maxCLL_n = num; - video_context->content_light_level.maxCLL_d = 1; + video_context->content_light_level.max_content_light_level = num; } break; } @@ -663,12 +653,12 @@ gst_matroska_demux_parse_colour (GstMatroskaDemux * demux, GstEbmlRead * ebml, case GST_MATROSKA_ID_MAXFALL:{ if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK) goto beach; - if (num >= G_MAXUINT32) { + if (num >= G_MAXUINT16) { GST_WARNING_OBJECT (demux, "Too large maxFALL value %" G_GUINT64_FORMAT, num); } else { - video_context->content_light_level.maxFALL_n = num; - video_context->content_light_level.maxFALL_d = 1; + video_context->content_light_level.max_frame_average_light_level = + num; } break; } @@ -702,6 +692,8 @@ gst_matroska_demux_parse_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml, DEBUG_ELEMENT_START (demux, ebml, "TrackEntry"); + *dest_context = NULL; + /* start with the master */ if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) { DEBUG_ELEMENT_STOP (demux, ebml, "TrackEntry", ret); @@ -2741,7 +2733,8 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux, GstSeekFlags flags; GstSeekType cur_type, stop_type; GstFormat format; - gboolean flush, keyunit, before, after, accurate, snap_next; + gboolean flush, keyunit, instant_rate_change, before, after, accurate, + snap_next; gdouble rate; gint64 cur, stop; GstMatroskaTrackContext *track = NULL; @@ -2769,6 +2762,40 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux, return FALSE; } + GST_DEBUG_OBJECT (demux, "configuring seek"); + + flush = ! !(flags & GST_SEEK_FLAG_FLUSH); + keyunit = ! !(flags & GST_SEEK_FLAG_KEY_UNIT); + after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER); + before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE); + accurate = ! !(flags & GST_SEEK_FLAG_ACCURATE); + instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE); + + /* Directly send the instant-rate-change event here before taking the + * stream-lock so that it can be applied as soon as possible */ + if (instant_rate_change) { + GstEvent *ev; + + /* instant rate change only supported if direction does not change. All + * other requirements are already checked before creating the seek event + * but let's double-check here to be sure */ + if ((rate > 0 && demux->common.segment.rate < 0) || + (rate < 0 && demux->common.segment.rate > 0) || + cur_type != GST_SEEK_TYPE_NONE || + stop_type != GST_SEEK_TYPE_NONE || flush) { + GST_ERROR_OBJECT (demux, + "Instant rate change seeks only supported in the " + "same direction, without flushing and position change"); + return FALSE; + } + + ev = gst_event_new_instant_rate_change (rate / + demux->common.segment.rate, (GstSegmentFlags) flags); + gst_event_set_seqnum (ev, seqnum); + gst_matroska_demux_send_event (demux, ev); + return TRUE; + } + /* copy segment, we need this because we still need the old * segment when we close the current segment. */ memcpy (&seeksegment, &demux->common.segment, sizeof (GstSegment)); @@ -2781,7 +2808,6 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux, seeksegment.duration = GST_CLOCK_TIME_NONE; } - GST_DEBUG_OBJECT (demux, "configuring seek"); /* Subtract stream_start_time so we always seek on a segment * in stream time */ if (GST_CLOCK_TIME_IS_VALID (demux->stream_start_time)) { @@ -2793,8 +2819,11 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux, seeksegment.stop = seeksegment.duration; } - gst_segment_do_seek (&seeksegment, rate, format, flags, - cur_type, cur, stop_type, stop, &update); + if (!gst_segment_do_seek (&seeksegment, rate, format, flags, + cur_type, cur, stop_type, stop, &update)) { + GST_WARNING_OBJECT (demux, "gst_segment_do_seek() failed."); + return FALSE; + } /* Restore the clip timestamp offset */ if (GST_CLOCK_TIME_IS_VALID (demux->stream_start_time)) { @@ -2810,12 +2839,6 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux, * would be determined again when parsing, but anyway ... */ seeksegment.duration = demux->common.segment.duration; - flush = ! !(flags & GST_SEEK_FLAG_FLUSH); - keyunit = ! !(flags & GST_SEEK_FLAG_KEY_UNIT); - after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER); - before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE); - accurate = ! !(flags & GST_SEEK_FLAG_ACCURATE); - /* always do full update if flushing, * otherwise problems might arise downstream with missing keyframes etc */ update = update || flush; @@ -3034,6 +3057,35 @@ gst_matroska_demux_handle_seek_push (GstMatroskaDemux * demux, GstPad * pad, gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur, &stop_type, &stop); + /* Directly send the instant-rate-change event here before taking the + * stream-lock so that it can be applied as soon as possible */ + if (flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE) { + guint32 seqnum; + GstEvent *ev; + + /* instant rate change only supported if direction does not change. All + * other requirements are already checked before creating the seek event + * but let's double-check here to be sure */ + if ((rate > 0 && demux->common.segment.rate < 0) || + (rate < 0 && demux->common.segment.rate > 0) || + cur_type != GST_SEEK_TYPE_NONE || + stop_type != GST_SEEK_TYPE_NONE || (flags & GST_SEEK_FLAG_FLUSH)) { + GST_ERROR_OBJECT (demux, + "Instant rate change seeks only supported in the " + "same direction, without flushing and position change"); + return FALSE; + } + + seqnum = gst_event_get_seqnum (event); + ev = gst_event_new_instant_rate_change (rate / demux->common.segment.rate, + (GstSegmentFlags) flags); + gst_event_set_seqnum (ev, seqnum); + gst_matroska_demux_send_event (demux, ev); + return TRUE; + } + + + /* sanity checks */ /* we can only seek on time */ @@ -3799,6 +3851,12 @@ gst_matroska_demux_add_wvpk_header (GstElement * element, guint32 block_samples, tmp; gsize size = gst_buffer_get_size (*buf); + if (size < 4) { + GST_ERROR_OBJECT (element, "Too small wavpack buffer"); + gst_buffer_unmap (*buf, &map); + return GST_FLOW_ERROR; + } + gst_buffer_extract (*buf, 0, &tmp, sizeof (guint32)); block_samples = GUINT32_FROM_LE (tmp); /* we need to reconstruct the header of the wavpack block */ @@ -3806,10 +3864,10 @@ gst_matroska_demux_add_wvpk_header (GstElement * element, /* -20 because ck_size is the size of the wavpack block -8 * and lace_size is the size of the wavpack block + 12 * (the three guint32 of the header that already are in the buffer) */ - wvh.ck_size = size + sizeof (Wavpack4Header) - 20; + wvh.ck_size = size + WAVPACK4_HEADER_SIZE - 20; /* block_samples, flags and crc are already in the buffer */ - newbuf = gst_buffer_new_allocate (NULL, sizeof (Wavpack4Header) - 12, NULL); + newbuf = gst_buffer_new_allocate (NULL, WAVPACK4_HEADER_SIZE - 12, NULL); gst_buffer_map (newbuf, &outmap, GST_MAP_WRITE); data = outmap.data; @@ -3834,9 +3892,11 @@ gst_matroska_demux_add_wvpk_header (GstElement * element, audiocontext->wvpk_block_index += block_samples; } else { guint8 *outdata = NULL; - guint outpos = 0; - gsize buf_size, size, out_size = 0; + gsize buf_size, size; guint32 block_samples, flags, crc, blocksize; + GstAdapter *adapter; + + adapter = gst_adapter_new (); gst_buffer_map (*buf, &map, GST_MAP_READ); buf_data = map.data; @@ -3845,6 +3905,7 @@ gst_matroska_demux_add_wvpk_header (GstElement * element, if (buf_size < 4) { GST_ERROR_OBJECT (element, "Too small wavpack buffer"); gst_buffer_unmap (*buf, &map); + g_object_unref (adapter); return GST_FLOW_ERROR; } @@ -3866,59 +3927,57 @@ gst_matroska_demux_add_wvpk_header (GstElement * element, data += 4; size -= 4; - if (blocksize == 0 || size < blocksize) - break; - - g_assert ((newbuf == NULL) == (outdata == NULL)); + if (blocksize == 0 || size < blocksize) { + GST_ERROR_OBJECT (element, "Too small wavpack buffer"); + gst_buffer_unmap (*buf, &map); + g_object_unref (adapter); + return GST_FLOW_ERROR; + } - if (newbuf == NULL) { - out_size = sizeof (Wavpack4Header) + blocksize; - newbuf = gst_buffer_new_allocate (NULL, out_size, NULL); + g_assert (newbuf == NULL); - gst_buffer_copy_into (newbuf, *buf, - GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_FLAGS, 0, -1); + newbuf = + gst_buffer_new_allocate (NULL, WAVPACK4_HEADER_SIZE + blocksize, + NULL); + gst_buffer_map (newbuf, &outmap, GST_MAP_WRITE); + outdata = outmap.data; + + outdata[0] = 'w'; + outdata[1] = 'v'; + outdata[2] = 'p'; + outdata[3] = 'k'; + outdata += 4; + + GST_WRITE_UINT32_LE (outdata, blocksize + WAVPACK4_HEADER_SIZE - 8); + GST_WRITE_UINT16_LE (outdata + 4, wvh.version); + GST_WRITE_UINT8 (outdata + 6, wvh.track_no); + GST_WRITE_UINT8 (outdata + 7, wvh.index_no); + GST_WRITE_UINT32_LE (outdata + 8, wvh.total_samples); + GST_WRITE_UINT32_LE (outdata + 12, wvh.block_index); + GST_WRITE_UINT32_LE (outdata + 16, block_samples); + GST_WRITE_UINT32_LE (outdata + 20, flags); + GST_WRITE_UINT32_LE (outdata + 24, crc); + outdata += 28; + + memcpy (outdata, data, blocksize); - outpos = 0; - gst_buffer_map (newbuf, &outmap, GST_MAP_WRITE); - outdata = outmap.data; - } else { - gst_buffer_unmap (newbuf, &outmap); - out_size += sizeof (Wavpack4Header) + blocksize; - gst_buffer_set_size (newbuf, out_size); - gst_buffer_map (newbuf, &outmap, GST_MAP_WRITE); - outdata = outmap.data; - } + gst_buffer_unmap (newbuf, &outmap); + gst_adapter_push (adapter, newbuf); + newbuf = NULL; - outdata[outpos] = 'w'; - outdata[outpos + 1] = 'v'; - outdata[outpos + 2] = 'p'; - outdata[outpos + 3] = 'k'; - outpos += 4; - - GST_WRITE_UINT32_LE (outdata + outpos, - blocksize + sizeof (Wavpack4Header) - 8); - GST_WRITE_UINT16_LE (outdata + outpos + 4, wvh.version); - GST_WRITE_UINT8 (outdata + outpos + 6, wvh.track_no); - GST_WRITE_UINT8 (outdata + outpos + 7, wvh.index_no); - GST_WRITE_UINT32_LE (outdata + outpos + 8, wvh.total_samples); - GST_WRITE_UINT32_LE (outdata + outpos + 12, wvh.block_index); - GST_WRITE_UINT32_LE (outdata + outpos + 16, block_samples); - GST_WRITE_UINT32_LE (outdata + outpos + 20, flags); - GST_WRITE_UINT32_LE (outdata + outpos + 24, crc); - outpos += 28; - - memmove (outdata + outpos, data, blocksize); - outpos += blocksize; data += blocksize; size -= blocksize; } gst_buffer_unmap (*buf, &map); - gst_buffer_unref (*buf); - if (newbuf) - gst_buffer_unmap (newbuf, &outmap); + newbuf = gst_adapter_take_buffer (adapter, gst_adapter_available (adapter)); + g_object_unref (adapter); + gst_buffer_copy_into (newbuf, *buf, + GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_FLAGS, 0, -1); + gst_buffer_unref (*buf); *buf = newbuf; + audiocontext->wvpk_block_index += block_samples; } @@ -6372,6 +6431,19 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext * GST_WARNING ("No AV1 codec data found!"); } *codec_name = g_strdup_printf ("AOM AV1"); + } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_FFV1)) { + caps = + gst_caps_new_simple ("video/x-ffv", "ffvversion", G_TYPE_INT, 1, NULL); + if (data) { + GstBuffer *priv; + + priv = gst_buffer_new_wrapped (g_memdup (data, size), size); + gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, priv, NULL); + gst_buffer_unref (priv); + } else { + GST_WARNING ("No FFV1 codec data found!"); + } + *codec_name = g_strdup_printf ("FFMpeg v1"); } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_PRORES)) { guint32 fourcc; const gchar *variant, *variant_descr = ""; @@ -6536,8 +6608,8 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext * } } - if (videocontext->content_light_level.maxCLL_n && - videocontext->content_light_level.maxFALL_n) { + if (videocontext->content_light_level.max_content_light_level && + videocontext->content_light_level.max_frame_average_light_level) { if (!gst_video_content_light_level_add_to_caps (&videocontext->content_light_level, caps)) { GST_WARNING ("couldn't set content light level to caps"); diff --git a/gst/matroska/matroska-ids.h b/gst/matroska/matroska-ids.h index 429213f778..e84ef1ab01 100644 --- a/gst/matroska/matroska-ids.h +++ b/gst/matroska/matroska-ids.h @@ -379,6 +379,7 @@ #define GST_MATROSKA_CODEC_ID_VIDEO_AV1 "V_AV1" #define GST_MATROSKA_CODEC_ID_VIDEO_MPEGH_HEVC "V_MPEGH/ISO/HEVC" #define GST_MATROSKA_CODEC_ID_VIDEO_PRORES "V_PRORES" +#define GST_MATROSKA_CODEC_ID_VIDEO_FFV1 "V_FFV1" #define GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1 "A_MPEG/L1" #define GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2 "A_MPEG/L2" @@ -688,6 +689,8 @@ typedef struct _Wavpack4Header { guint32 crc; /* crc for actual decoded data */ } Wavpack4Header; +#define WAVPACK4_HEADER_SIZE (32) + typedef enum { GST_MATROSKA_TRACK_ENCODING_SCOPE_FRAME = (1<<0), GST_MATROSKA_TRACK_ENCODING_SCOPE_CODEC_DATA = (1<<1), diff --git a/gst/matroska/matroska-mux.c b/gst/matroska/matroska-mux.c index b82dccd75a..70f15b2b07 100644 --- a/gst/matroska/matroska-mux.c +++ b/gst/matroska/matroska-mux.c @@ -143,7 +143,8 @@ static GstStaticPadTemplate videosink_templ = "video/x-prores, " COMMON_VIDEO_CAPS "; " "video/x-wmv, " "wmvversion = (int) [ 1, 3 ], " COMMON_VIDEO_CAPS "; " - "video/x-av1, " COMMON_VIDEO_CAPS) + "video/x-av1, " COMMON_VIDEO_CAPS ";" + "video/x-ffv, ffversion = (int) 1, " COMMON_VIDEO_CAPS) ); #define COMMON_AUDIO_CAPS \ @@ -970,13 +971,19 @@ gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps) if ((old_caps = gst_pad_get_current_caps (pad))) { if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER - && !gst_caps_is_equal (caps, old_caps)) { + && !gst_caps_is_subset (caps, old_caps)) { GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL), - ("Caps changes are not supported by Matroska")); + ("Caps changes are not supported by Matroska\nCurrent: `%" + GST_PTR_FORMAT "`\nNew: `%" GST_PTR_FORMAT "`", old_caps, caps)); gst_caps_unref (old_caps); goto refuse_caps; } gst_caps_unref (old_caps); + } else if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER) { + GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL), + ("Caps on pad %" GST_PTR_FORMAT + " arrived late. Headers were already written", pad)); + goto refuse_caps; } /* find context */ @@ -1246,6 +1253,12 @@ gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps) if (codec_buf != NULL) gst_buffer_extract_dup (codec_buf, 0, gst_buffer_get_size (codec_buf), &context->codec_priv, &context->codec_priv_size); + } else if (!strcmp (mimetype, "video/x-ffv")) { + gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_FFV1); + gst_matroska_mux_free_codec_priv (context); + if (codec_buf != NULL) + gst_buffer_extract_dup (codec_buf, 0, gst_buffer_get_size (codec_buf), + &context->codec_priv, &context->codec_priv_size); } else if (!strcmp (mimetype, "video/mpeg")) { gint mpegversion; @@ -1834,6 +1847,11 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps) goto refuse_caps; } gst_caps_unref (old_caps); + } else if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER) { + GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL), + ("Caps on pad %" GST_PTR_FORMAT + " arrived late. Headers were already written", pad)); + goto refuse_caps; } /* find context */ @@ -2252,6 +2270,7 @@ gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps) GstMatroskaTrackSubtitleContext *scontext; GstMatroskaMux *mux; GstMatroskaPad *collect_pad; + GstCollectData *data; const gchar *mimetype; GstStructure *structure; const GValue *value = NULL; @@ -2270,11 +2289,18 @@ gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps) goto refuse_caps; } gst_caps_unref (old_caps); + } else if (mux->state >= GST_MATROSKA_MUX_STATE_HEADER) { + GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL), + ("Caps on pad %" GST_PTR_FORMAT + " arrived late. Headers were already written", pad)); + goto refuse_caps; } /* find context */ collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad); g_assert (collect_pad); + data = (GstCollectData *) (collect_pad); + context = collect_pad->track; g_assert (context); g_assert (context->type == GST_MATROSKA_TRACK_TYPE_SUBTITLE); @@ -2350,6 +2376,13 @@ gst_matroska_mux_subtitle_pad_setcaps (GstPad * pad, GstCaps * caps) GST_DEBUG_OBJECT (pad, "codec_id %s, codec data size %" G_GSIZE_FORMAT, GST_STR_NULL (context->codec_id), context->codec_priv_size); + /* This pad is sparse. Now that we have caps on it, we can tell collectpads + * not to actually wait for data when muxing */ + GST_COLLECT_PADS_STREAM_LOCK (mux->collect); + GST_COLLECT_PADS_STATE_UNSET (data, GST_COLLECT_PADS_STATE_LOCKED); + gst_collect_pads_set_waiting (mux->collect, data, FALSE); + GST_COLLECT_PADS_STREAM_UNLOCK (mux->collect); + exit: return ret; @@ -2387,7 +2420,6 @@ gst_matroska_mux_request_new_pad (GstElement * element, GstMatroskaCapsFunc capsfunc = NULL; GstMatroskaTrackContext *context = NULL; gint pad_id; - gboolean locked = TRUE; const gchar *id = NULL; if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) { @@ -2434,7 +2466,6 @@ gst_matroska_mux_request_new_pad (GstElement * element, context->name = g_strdup ("Subtitle"); /* setcaps may only provide proper one a lot later */ id = "S_SUB_UNKNOWN"; - locked = FALSE; } else { GST_WARNING_OBJECT (mux, "This is not our template!"); return NULL; @@ -2447,7 +2478,7 @@ gst_matroska_mux_request_new_pad (GstElement * element, collect_pad = (GstMatroskaPad *) gst_collect_pads_add_pad (mux->collect, GST_PAD (newpad), sizeof (GstMatroskaPad), - (GstCollectDataDestroyNotify) gst_matroska_pad_free, locked); + (GstCollectDataDestroyNotify) gst_matroska_pad_free, TRUE); collect_pad->mux = mux; collect_pad->track = context; @@ -2532,6 +2563,8 @@ gst_matroska_mux_write_mastering_metadata (GstMatroskaMux * mux, guint64 master; GstVideoMasteringDisplayInfo *minfo = &videocontext->mastering_display_info; gdouble value; + const gdouble chroma_scale = 50000; + const gdouble luma_scale = 50000; if (!videocontext->mastering_display_info_present) return; @@ -2539,34 +2572,34 @@ gst_matroska_mux_write_mastering_metadata (GstMatroskaMux * mux, master = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_MASTERINGMETADATA); - gst_util_fraction_to_double (minfo->Rx_n, minfo->Rx_d, &value); + value = (gdouble) minfo->display_primaries[0].x / chroma_scale; gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYRCHROMATICITYX, value); - gst_util_fraction_to_double (minfo->Ry_n, minfo->Ry_d, &value); + value = (gdouble) minfo->display_primaries[0].y / chroma_scale; gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYRCHROMATICITYY, value); - gst_util_fraction_to_double (minfo->Gx_n, minfo->Gx_d, &value); + value = (gdouble) minfo->display_primaries[1].x / chroma_scale; gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYGCHROMATICITYX, value); - gst_util_fraction_to_double (minfo->Gy_n, minfo->Gy_d, &value); + value = (gdouble) minfo->display_primaries[1].y / chroma_scale; gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYGCHROMATICITYY, value); - gst_util_fraction_to_double (minfo->Bx_n, minfo->Bx_d, &value); + value = (gdouble) minfo->display_primaries[2].x / chroma_scale; gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYBCHROMATICITYX, value); - gst_util_fraction_to_double (minfo->By_n, minfo->By_d, &value); + value = (gdouble) minfo->display_primaries[2].y / chroma_scale; gst_ebml_write_float (ebml, GST_MATROSKA_ID_PRIMARYBCHROMATICITYY, value); - gst_util_fraction_to_double (minfo->Wx_n, minfo->Wx_d, &value); + value = (gdouble) minfo->white_point.x / chroma_scale; gst_ebml_write_float (ebml, GST_MATROSKA_ID_WHITEPOINTCHROMATICITYX, value); - gst_util_fraction_to_double (minfo->Wy_n, minfo->Wy_d, &value); + value = (gdouble) minfo->white_point.y / chroma_scale; gst_ebml_write_float (ebml, GST_MATROSKA_ID_WHITEPOINTCHROMATICITYY, value); - gst_util_fraction_to_double (minfo->max_luma_n, minfo->max_luma_d, &value); + value = (gdouble) minfo->max_display_mastering_luminance / luma_scale; gst_ebml_write_float (ebml, GST_MATROSKA_ID_LUMINANCEMAX, value); - gst_util_fraction_to_double (minfo->min_luma_n, minfo->min_luma_d, &value); + value = (gdouble) minfo->min_display_mastering_luminance / luma_scale; gst_ebml_write_float (ebml, GST_MATROSKA_ID_LUMINANCEMIN, value); gst_ebml_write_master_finish (ebml, master); @@ -2599,7 +2632,7 @@ gst_matroska_mux_write_colour (GstMatroskaMux * mux, matrix_id = gst_video_color_matrix_to_iso (videocontext->colorimetry.matrix); transfer_id = - gst_video_color_transfer_to_iso (videocontext->colorimetry.transfer); + gst_video_transfer_function_to_iso (videocontext->colorimetry.transfer); primaries_id = gst_video_color_primaries_to_iso (videocontext->colorimetry.primaries); @@ -2609,16 +2642,12 @@ gst_matroska_mux_write_colour (GstMatroskaMux * mux, gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOTRANSFERCHARACTERISTICS, transfer_id); gst_ebml_write_uint (ebml, GST_MATROSKA_ID_VIDEOPRIMARIES, primaries_id); - if (videocontext->content_light_level.maxCLL_n && - videocontext->content_light_level.maxFALL_n) { - gdouble maxCLL = 0, maxFALL = 0; - - gst_util_fraction_to_double (videocontext->content_light_level.maxCLL_n, - videocontext->content_light_level.maxCLL_d, &maxCLL); - gst_util_fraction_to_double (videocontext->content_light_level.maxFALL_n, - videocontext->content_light_level.maxFALL_d, &maxFALL); - gst_ebml_write_uint (ebml, GST_MATROSKA_ID_MAXCLL, (guint) maxCLL); - gst_ebml_write_uint (ebml, GST_MATROSKA_ID_MAXFALL, (guint) maxFALL); + if (videocontext->content_light_level.max_content_light_level && + videocontext->content_light_level.max_frame_average_light_level) { + gst_ebml_write_uint (ebml, GST_MATROSKA_ID_MAXCLL, + videocontext->content_light_level.max_content_light_level); + gst_ebml_write_uint (ebml, GST_MATROSKA_ID_MAXFALL, + videocontext->content_light_level.max_frame_average_light_level); } gst_matroska_mux_write_mastering_metadata (mux, videocontext); @@ -2781,6 +2810,8 @@ gst_matroska_mux_track_header (GstMatroskaMux * mux, break; } + GST_DEBUG_OBJECT (mux, "Wrote track header. Codec %s", context->codec_id); + gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CODECID, context->codec_id); if (context->codec_priv) gst_ebml_write_binary (ebml, GST_MATROSKA_ID_CODECPRIVATE, @@ -3798,6 +3829,7 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad, GstBuffer *hdr; guint64 blockgroup; gboolean write_duration; + guint64 cluster_time_scaled; gint16 relative_timestamp; gint64 relative_timestamp64; guint64 block_duration, duration_diff = 0; @@ -3910,6 +3942,8 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad, gst_pad_push_event (mux->srcpad, mux->force_key_unit_event); mux->force_key_unit_event = NULL; } + cluster_time_scaled = + gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale); mux->prev_cluster_size = ebml->pos - mux->cluster_pos; mux->cluster_pos = ebml->pos; @@ -3917,25 +3951,44 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad, mux->cluster = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER); gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE, - gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale)); + cluster_time_scaled); GST_LOG_OBJECT (mux, "cluster timestamp %" G_GUINT64_FORMAT, gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale)); gst_ebml_write_flush_cache (ebml, is_video_keyframe || is_audio_only, buffer_timestamp); - mux->cluster_time = buffer_timestamp; gst_ebml_write_uint (ebml, GST_MATROSKA_ID_PREVSIZE, mux->prev_cluster_size); + /* cluster_time needs to be identical in value to what's stored in the + * matroska so we need to have it with the same precision as what's + * possible with the set timecodescale rather than just using the + * buffer_timestamp. + * If this is not done the rounding of relative_timestamp will be + * incorrect and possibly making the timestamps get out of order if tw + * buffers arrive at the same millisecond (assuming default timecodescale + * of 1ms) */ + mux->cluster_time = + gst_util_uint64_scale (cluster_time_scaled, mux->time_scale, 1); } } else { /* first cluster */ - + cluster_time_scaled = + gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale); mux->cluster_pos = ebml->pos; gst_ebml_write_set_cache (ebml, 0x20); mux->cluster = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CLUSTER); gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CLUSTERTIMECODE, - gst_util_uint64_scale (buffer_timestamp, 1, mux->time_scale)); + cluster_time_scaled); gst_ebml_write_flush_cache (ebml, TRUE, buffer_timestamp); - mux->cluster_time = buffer_timestamp; + /* cluster_time needs to be identical in value to what's stored in the + * matroska so we need to have it with the same precision as what's + * possible with the set timecodescale rather than just using the + * buffer_timestamp. + * If this is not done the rounding of relative_timestamp will be + * incorrect and possibly making the timestamps get out of order if tw + * buffers arrive at the same millisecond (assuming default timecodescale + * of 1ms) */ + mux->cluster_time = + gst_util_uint64_scale (cluster_time_scaled, mux->time_scale, 1); } /* We currently write index entries for all video tracks or for the audio diff --git a/gst/multifile/gstimagesequencesrc.c b/gst/multifile/gstimagesequencesrc.c new file mode 100644 index 0000000000..9d4d06c2eb --- /dev/null +++ b/gst/multifile/gstimagesequencesrc.c @@ -0,0 +1,657 @@ +/* GStreamer + * Copyright (C) 2006 David A. Schleef ds@schleef.org + * Copyright (C) 2019 Cesar Fabian Orccon Chipana + * Copyright (C) 2020 Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, + * Boston, MA 02110-1335, USA. + */ + +/** + * SECTION:element-imagesequencesrc + * + * Stream image sequences from image files. + * + * ``` + * gst-launch-1.0 imagesequencesrc location=image-%05d.jpg start-index=1 stop-index=50 framerate=24/1 ! decodebin ! videoconvert ! autovideosink + * ``` + * + * This elements implements the #GstURIHandler interface meaning that you can use it with playbin, + * (make sure to quote the URI for the filename pattern, like: `%2505d` instead of the `%05d` you would use + * when dealing with the location). + * + * Note that you can pass the #imagesequencesrc:framerate, #imagesequencesrc:start-index and #imagesequencesrc:stop-index + * properties directly in the URI using its 'query' component, for example: + * + * ``` + * gst-launch-1.0 playbin uri="imagesequence://path/to/image-%2505d.jpeg?start-index=0&framerate=30/1" + * ``` + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "gstimagesequencesrc.h" + +#define LOCK(self) (g_rec_mutex_lock (&self->fields_lock)) +#define UNLOCK(self) (g_rec_mutex_unlock (&self->fields_lock)) + +static GstFlowReturn gst_image_sequence_src_create (GstPushSrc * src, + GstBuffer ** buffer); + + +static void gst_image_sequence_src_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec); +static void gst_image_sequence_src_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec); +static GstCaps *gst_image_sequence_src_getcaps (GstBaseSrc * src, + GstCaps * filter); +static gboolean gst_image_sequence_src_query (GstBaseSrc * src, + GstQuery * query); +static void gst_image_sequence_src_set_caps (GstImageSequenceSrc * self, + GstCaps * caps); +static void gst_image_sequence_src_set_duration (GstImageSequenceSrc * self); +static gint gst_image_sequence_src_count_frames (GstImageSequenceSrc * self, + gboolean can_read); + + +static GstStaticPadTemplate gst_image_sequence_src_pad_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +GST_DEBUG_CATEGORY_STATIC (gst_image_sequence_src_debug); +#define GST_CAT_DEFAULT gst_image_sequence_src_debug + +enum +{ + PROP_0, + PROP_LOCATION, + PROP_START_INDEX, + PROP_STOP_INDEX, + PROP_FRAMERATE +}; + +#define DEFAULT_LOCATION "%05d" +#define DEFAULT_START_INDEX 0 +#define DEFAULT_STOP_INDEX -1 +#define DEFAULT_FRAMERATE 30 + +/* Call with LOCK taken */ +static gboolean +gst_image_sequence_src_set_location (GstImageSequenceSrc * self, + const gchar * location) +{ + g_free (self->path); + if (location != NULL) + self->path = g_strdup (location); + else + self->path = NULL; + + return TRUE; +} + +/*** GSTURIHANDLER INTERFACE *************************************************/ + +static GstURIType +gst_image_sequence_src_uri_get_type (GType type) +{ + return GST_URI_SRC; +} + +static const gchar *const * +gst_image_sequence_src_uri_get_protocols (GType type) +{ + static const gchar *protocols[] = { "imagesequence", NULL }; + + return protocols; +} + +static gchar * +gst_image_sequence_src_uri_get_uri (GstURIHandler * handler) +{ + GstImageSequenceSrc *self = GST_IMAGE_SEQUENCE_SRC (handler); + gchar *uri = NULL; + + LOCK (self); + if (self->uri) + uri = gst_uri_to_string (self->uri); + else if (self->path) + uri = gst_uri_construct ("imagesequence", self->path); + UNLOCK (self); + + return uri; +} + +static gboolean +gst_image_sequence_src_uri_set_uri (GstURIHandler * handler, const gchar * uri, + GError ** err) +{ + gchar *hostname = NULL, *location = NULL, *tmp; + gboolean ret = FALSE; + GstImageSequenceSrc *self = GST_IMAGE_SEQUENCE_SRC (handler); + GstUri *ruri = gst_uri_from_string (uri); + GHashTable *query = NULL; + + if (!ruri) { + g_set_error (err, GST_URI_ERROR, GST_URI_ERROR_BAD_URI, + "imagesequencesrc URI is invalid: '%s'", uri); + goto beach; + } + + + LOCK (self); + g_clear_pointer (&self->uri, gst_uri_unref); + self->uri = ruri; + tmp = gst_filename_to_uri (gst_uri_get_path (ruri), err); + location = g_filename_from_uri (tmp, &hostname, err); + g_free (tmp); + query = gst_uri_get_query_table (ruri); + if (!location || (err != NULL && *err != NULL)) { + GST_WARNING_OBJECT (self, "Invalid URI '%s' for imagesequencesrc: %s", uri, + (err != NULL && *err != NULL) ? (*err)->message : "unknown error"); + goto beach; + } + + if (hostname && strcmp (hostname, "localhost")) { + /* Only 'localhost' is permitted */ + GST_WARNING_OBJECT (self, "Invalid hostname '%s' for filesrc", hostname); + g_set_error (err, GST_URI_ERROR, GST_URI_ERROR_BAD_URI, + "File URI with invalid hostname '%s'", hostname); + goto beach; + } +#ifdef G_OS_WIN32 + /* Unfortunately, g_filename_from_uri() doesn't handle some UNC paths + * correctly on windows, it leaves them with an extra backslash + * at the start if they're of the mozilla-style file://///host/path/file + * form. Correct this. + */ + if (location[0] == '\\' && location[1] == '\\' && location[2] == '\\') + memmove (location, location + 1, strlen (location + 1) + 1); +#endif + + ret = gst_image_sequence_src_set_location (self, location); + + if (query) { + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init (&iter, query); + while (g_hash_table_iter_next (&iter, &key, &value)) { + GST_INFO_OBJECT (self, "Setting property from URI: %s=%s", (gchar *) key, + (gchar *) value); + gst_util_set_object_arg (G_OBJECT (self), key, value); + } + } + +beach: + UNLOCK (self); + + g_free (location); + g_free (hostname); + g_clear_pointer (&query, g_hash_table_unref); + + return ret; +} + +static void +gst_image_sequence_src_uri_handler_init (gpointer g_iface, gpointer iface_data) +{ + GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; + + iface->get_type = gst_image_sequence_src_uri_get_type; + iface->get_protocols = gst_image_sequence_src_uri_get_protocols; + iface->get_uri = gst_image_sequence_src_uri_get_uri; + iface->set_uri = gst_image_sequence_src_uri_set_uri; +} + +#define gst_image_sequence_src_parent_class parent_class +#define _do_init \ + G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER, gst_image_sequence_src_uri_handler_init); \ + GST_DEBUG_CATEGORY_INIT (gst_image_sequence_src_debug, "imagesequencesrc", \ + 0, "imagesequencesrc element"); +G_DEFINE_TYPE_WITH_CODE (GstImageSequenceSrc, gst_image_sequence_src, + GST_TYPE_PUSH_SRC, _do_init); + +static gboolean +is_seekable (GstBaseSrc * src) +{ + GstImageSequenceSrc *self = GST_IMAGE_SEQUENCE_SRC (src); + + if ((self->n_frames != 0) && (self->fps_n) && (self->fps_d)) + return TRUE; + return FALSE; +} + + +static gboolean +do_seek (GstBaseSrc * bsrc, GstSegment * segment) +{ + GstImageSequenceSrc *self; + + self = GST_IMAGE_SEQUENCE_SRC (bsrc); + + self->reverse = segment->rate < 0; + if (self->reverse) { + segment->time = segment->start; + } + + self->index = + self->start_index + + segment->position * self->fps_n / (self->fps_d * GST_SECOND); + + return TRUE; +} + +static void +gst_image_sequence_src_finalize (GObject * object) +{ + GstImageSequenceSrc *self = GST_IMAGE_SEQUENCE_SRC (object); + + g_clear_pointer (&self->path, g_free); + g_rec_mutex_clear (&self->fields_lock); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_image_sequence_src_dispose (GObject * object) +{ + GstImageSequenceSrc *self = GST_IMAGE_SEQUENCE_SRC (object); + + gst_clear_caps (&self->caps); + g_clear_pointer (&self->uri, gst_uri_unref); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_image_sequence_src_class_init (GstImageSequenceSrcClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); + GstPushSrcClass *gstpushsrc_class = GST_PUSH_SRC_CLASS (klass); + GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass); + + gobject_class->set_property = gst_image_sequence_src_set_property; + gobject_class->get_property = gst_image_sequence_src_get_property; + + + g_object_class_install_property (gobject_class, PROP_LOCATION, + g_param_spec_string ("location", "File Location", + "Pattern to create file names of input files. File names are " + "created by calling sprintf() with the pattern and the current " + "index.", DEFAULT_LOCATION, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_START_INDEX, + g_param_spec_int ("start-index", "Start Index", + "Start value of index. The initial value of index can be set " + "either by setting index or start-index. When the end of the loop " + "is reached, the index will be set to the value start-index.", + 0, INT_MAX, DEFAULT_START_INDEX, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_STOP_INDEX, + g_param_spec_int ("stop-index", "Stop Index", + "Stop value of index. The special value -1 means no stop.", + -1, INT_MAX, DEFAULT_STOP_INDEX, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_FRAMERATE, + gst_param_spec_fraction ("framerate", "Framerate", + "The output framerate.", + 1, 1, G_MAXINT, 1, DEFAULT_FRAMERATE, 1, + G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)); + + gobject_class->finalize = gst_image_sequence_src_finalize; + gobject_class->dispose = gst_image_sequence_src_dispose; + + gstbasesrc_class->get_caps = gst_image_sequence_src_getcaps; + gstbasesrc_class->query = gst_image_sequence_src_query; + gstbasesrc_class->is_seekable = is_seekable; + gstbasesrc_class->do_seek = do_seek; + + gstpushsrc_class->create = gst_image_sequence_src_create; + + gst_element_class_add_static_pad_template (gstelement_class, + &gst_image_sequence_src_pad_template); + gst_element_class_set_static_metadata (gstelement_class, + "Image Sequence Source", "Source/File/Video", + "Create a video stream from a sequence of image files", + "Cesar Fabian Orccon Chipana \n" + "Thibault Saunier "); +} + +static void +gst_image_sequence_src_init (GstImageSequenceSrc * self) +{ + GstBaseSrc *bsrc; + + GST_DEBUG_CATEGORY_INIT (gst_image_sequence_src_debug, "imagesequencesrc", 0, + "imagesequencesrc element"); + + bsrc = GST_BASE_SRC (self); + gst_base_src_set_format (bsrc, GST_FORMAT_TIME); + + g_rec_mutex_init (&self->fields_lock); + self->start_index = DEFAULT_START_INDEX; + self->index = 0; + self->stop_index = DEFAULT_STOP_INDEX; + self->path = NULL; + self->caps = NULL; + self->n_frames = 0; + self->fps_n = 30; + self->fps_d = 1; +} + +static GstCaps * +gst_image_sequence_src_getcaps (GstBaseSrc * src, GstCaps * filter) +{ + GstImageSequenceSrc *self = GST_IMAGE_SEQUENCE_SRC (src); + + GST_DEBUG_OBJECT (self, "returning %" GST_PTR_FORMAT, self->caps); + + if (filter) { + if (self->caps) + return gst_caps_intersect_full (filter, self->caps, + GST_CAPS_INTERSECT_FIRST); + else + return gst_caps_ref (filter); + } + + return gst_caps_new_any (); +} + +static gboolean +gst_image_sequence_src_query (GstBaseSrc * bsrc, GstQuery * query) +{ + gboolean ret; + GstImageSequenceSrc *self; + + self = GST_IMAGE_SEQUENCE_SRC (bsrc); + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_DURATION: + { + GstFormat format; + + gst_query_parse_duration (query, &format, NULL); + + switch (format) { + case GST_FORMAT_TIME: + LOCK (self); + if (self->n_frames <= 0) { + gst_image_sequence_src_count_frames (self, FALSE); + gst_image_sequence_src_set_duration (self); + } + + if (self->n_frames > 0) + gst_query_set_duration (query, format, self->duration); + UNLOCK (self); + + ret = TRUE; + break; + default: + ret = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query); + } + break; + } + default: + ret = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query); + break; + } + + return ret; +} + +static void +gst_image_sequence_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstImageSequenceSrc *self = GST_IMAGE_SEQUENCE_SRC (object); + + LOCK (self); + switch (prop_id) { + case PROP_LOCATION: + gst_image_sequence_src_set_location (self, g_value_get_string (value)); + break; + case PROP_START_INDEX: + self->start_index = g_value_get_int (value); + gst_image_sequence_src_count_frames (self, FALSE); + break; + case PROP_STOP_INDEX: + self->stop_index = g_value_get_int (value); + gst_image_sequence_src_count_frames (self, FALSE); + break; + case PROP_FRAMERATE: + self->fps_n = gst_value_get_fraction_numerator (value); + self->fps_d = gst_value_get_fraction_denominator (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + UNLOCK (self); +} + +static void +gst_image_sequence_src_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstImageSequenceSrc *self = GST_IMAGE_SEQUENCE_SRC (object); + + LOCK (self); + switch (prop_id) { + case PROP_LOCATION: + g_value_set_string (value, self->path); + break; + case PROP_START_INDEX: + g_value_set_int (value, self->start_index); + break; + case PROP_STOP_INDEX: + g_value_set_int (value, self->stop_index); + break; + case PROP_FRAMERATE: + self->fps_n = gst_value_get_fraction_numerator (value); + self->fps_d = gst_value_get_fraction_denominator (value); + GST_DEBUG_OBJECT (self, "Set (framerate) property to (%d/%d)", + self->fps_n, self->fps_d); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + UNLOCK (self); +} + +/* Call with LOCK */ +static gint +gst_image_sequence_src_count_frames (GstImageSequenceSrc * self, + gboolean can_read) +{ + if (can_read && self->stop_index < 0 && self->path) { + gint i; + + for (i = self->start_index;; i++) { + gchar *filename = g_strdup_printf (self->path, i); + + if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) { + i--; + g_free (filename); + break; + } + + g_free (filename); + } + if (i > self->start_index) + self->stop_index = i; + } + + if (self->stop_index >= self->start_index) + self->n_frames = self->stop_index - self->start_index + 1; + return self->n_frames; +} + +static void +gst_image_sequence_src_set_caps (GstImageSequenceSrc * self, GstCaps * caps) +{ + GstCaps *new_caps; + + g_assert (caps != NULL); + new_caps = gst_caps_copy (caps); + + if (self->n_frames > 0) { + GValue fps = G_VALUE_INIT; + g_value_init (&fps, GST_TYPE_FRACTION); + gst_value_set_fraction (&fps, self->fps_n, self->fps_d); + gst_caps_set_value (new_caps, "framerate", &fps); + g_value_unset (&fps); + } + + gst_caps_replace (&self->caps, new_caps); + gst_pad_set_caps (GST_BASE_SRC_PAD (self), new_caps); + + GST_DEBUG_OBJECT (self, "Setting new caps: %" GST_PTR_FORMAT, new_caps); +} + +/* Call with LOCK */ +static void +gst_image_sequence_src_set_duration (GstImageSequenceSrc * self) +{ + GstClockTime old_duration = self->duration; + + if (self->n_frames <= 0) + return; + + /* Calculate duration */ + self->duration = + gst_util_uint64_scale (GST_SECOND * self->n_frames, self->fps_d, + self->fps_n); + + if (self->duration != old_duration) { + UNLOCK (self); + gst_element_post_message (GST_ELEMENT (self), + gst_message_new_duration_changed (GST_OBJECT (self))); + LOCK (self); + } +} + +/* Call with LOCK */ +static gchar * +gst_image_sequence_src_get_filename (GstImageSequenceSrc * self) +{ + gchar *filename; + + GST_DEBUG ("Reading filename at index %d.", self->index); + filename = g_strdup_printf (self->path, self->index); + + return filename; +} + +static GstFlowReturn +gst_image_sequence_src_create (GstPushSrc * src, GstBuffer ** buffer) +{ + GstImageSequenceSrc *self; + gsize size; + gchar *data; + gchar *filename; + GstBuffer *buf; + gboolean ret; + GError *error = NULL; + gint fps_n, fps_d, start_index, stop_index; + + self = GST_IMAGE_SEQUENCE_SRC (src); + + LOCK (self); + start_index = self->start_index; + stop_index = self->stop_index; + if (self->index > stop_index && stop_index > 0) { + UNLOCK (self); + + return GST_FLOW_EOS; + } + + if (self->index < self->start_index) + self->index = self->start_index; + + g_assert (start_index <= self->index && + (self->index <= stop_index || stop_index <= 0)); + + filename = gst_image_sequence_src_get_filename (self); + fps_n = self->fps_n; + fps_d = self->fps_d; + UNLOCK (self); + + if (!filename) + goto handle_error; + + ret = g_file_get_contents (filename, &data, &size, &error); + if (!ret) + goto handle_error; + + buf = gst_buffer_new_wrapped_full (0, data, size, 0, size, NULL, g_free); + + if (!self->caps) { + GstCaps *caps; + caps = gst_type_find_helper_for_buffer (NULL, buf, NULL); + if (!caps) { + GST_ELEMENT_ERROR (self, STREAM, TYPE_NOT_FOUND, (NULL), + ("Could not determine image type.")); + + return GST_FLOW_NOT_SUPPORTED; + } + + LOCK (self); + gst_image_sequence_src_count_frames (self, TRUE); + gst_image_sequence_src_set_duration (self); + UNLOCK (self); + + gst_image_sequence_src_set_caps (self, caps); + gst_caps_unref (caps); + } + + GST_BUFFER_PTS (buf) = + gst_util_uint64_scale_ceil ((self->index - start_index) * GST_SECOND, + fps_d, fps_n); + GST_BUFFER_DURATION (buf) = gst_util_uint64_scale (GST_SECOND, fps_d, fps_n); + GST_BUFFER_OFFSET (buf) = self->index - start_index; + GST_LOG_OBJECT (self, "index: %d, %s - %" GST_PTR_FORMAT, self->index, + filename, buf); + + g_free (filename); + *buffer = buf; + + self->index += self->reverse ? -1 : 1; + return GST_FLOW_OK; + +handle_error: + { + if (error != NULL) { + GST_ELEMENT_ERROR (self, RESOURCE, READ, + ("Error while reading from file \"%s\".", filename), + ("%s", error->message)); + g_error_free (error); + } else { + GST_ELEMENT_ERROR (self, RESOURCE, READ, + ("Error while reading from file \"%s\".", filename), + ("%s", g_strerror (errno))); + } + g_free (filename); + return GST_FLOW_ERROR; + } +} diff --git a/gst/multifile/gstimagesequencesrc.h b/gst/multifile/gstimagesequencesrc.h new file mode 100644 index 0000000000..f2d9db228b --- /dev/null +++ b/gst/multifile/gstimagesequencesrc.h @@ -0,0 +1,55 @@ +/* GStreamer + * Copyright (C) 2019 Cesar Fabian Orccon Chipana + * Copyright (C) 2020 Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, + * Boston, MA 02110-1335, USA. + */ + +#ifndef __GST_IMAGESEQUENCESRC_H__ +#define __GST_IMAGESEQUENCESRC_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_IMAGE_SEQUENCE_SRC (gst_image_sequence_src_get_type()) +G_DECLARE_FINAL_TYPE(GstImageSequenceSrc, gst_image_sequence_src, GST, IMAGE_SEQUENCE_SRC, GstPushSrc) + +struct _GstImageSequenceSrc +{ + GstPushSrc parent; + + GRecMutex fields_lock; + gchar* path; + GstUri *uri; + gint start_index; + gint stop_index; + gint index; + gint n_frames; + + guint64 duration; + gboolean reverse; + + GstCaps *caps; + + gint fps_n, fps_d; +}; + + +G_END_DECLS + +#endif /* __GST_IMAGESEQUENCESRC_H__ */ diff --git a/gst/multifile/gstmultifile.c b/gst/multifile/gstmultifile.c index 6cbb655f5d..1d22f69907 100644 --- a/gst/multifile/gstmultifile.c +++ b/gst/multifile/gstmultifile.c @@ -33,6 +33,7 @@ #include "gstsplitfilesrc.h" #include "gstsplitmuxsink.h" #include "gstsplitmuxsrc.h" +#include "gstimagesequencesrc.h" static gboolean plugin_init (GstPlugin * plugin) @@ -43,6 +44,8 @@ plugin_init (GstPlugin * plugin) gst_multi_file_sink_get_type ()); gst_element_register (plugin, "splitfilesrc", GST_RANK_NONE, gst_split_file_src_get_type ()); + gst_element_register (plugin, "imagesequencesrc", GST_RANK_NONE, + gst_image_sequence_src_get_type ()); if (!register_splitmuxsink (plugin)) return FALSE; diff --git a/gst/multifile/gstmultifilesink.c b/gst/multifile/gstmultifilesink.c index 224cf33e15..c555a0baac 100644 --- a/gst/multifile/gstmultifilesink.c +++ b/gst/multifile/gstmultifilesink.c @@ -274,6 +274,8 @@ gst_multi_file_sink_class_init (GstMultiFileSinkClass * klass) "Sink/File", "Write buffers to a sequentially named set of files", "David Schleef "); + + gst_type_mark_as_plugin_api (GST_TYPE_MULTI_FILE_SINK_NEXT, 0); } static void diff --git a/gst/multifile/gstmultifilesrc.c b/gst/multifile/gstmultifilesrc.c index d25f8bf737..4627a357fe 100644 --- a/gst/multifile/gstmultifilesrc.c +++ b/gst/multifile/gstmultifilesrc.c @@ -342,6 +342,7 @@ gst_multi_file_src_set_property (GObject * object, guint prop_id, src->fps_n = -1; src->fps_d = -1; } + gst_caps_unref (new_caps); } break; case PROP_LOOP: diff --git a/gst/multifile/gstsplitmuxpartreader.c b/gst/multifile/gstsplitmuxpartreader.c index 4859dd8f5a..77a1745c7f 100644 --- a/gst/multifile/gstsplitmuxpartreader.c +++ b/gst/multifile/gstsplitmuxpartreader.c @@ -37,6 +37,9 @@ GST_DEBUG_CATEGORY_STATIC (splitmux_part_debug); #define SPLITMUX_PART_TYPE_LOCK(p) g_mutex_lock(&(p)->type_lock) #define SPLITMUX_PART_TYPE_UNLOCK(p) g_mutex_unlock(&(p)->type_lock) +#define SPLITMUX_PART_MSG_LOCK(p) g_mutex_lock(&(p)->msg_lock) +#define SPLITMUX_PART_MSG_UNLOCK(p) g_mutex_unlock(&(p)->msg_lock) + typedef struct _GstSplitMuxPartPad { GstPad parent; @@ -149,6 +152,9 @@ handle_buffer_measuring (GstSplitMuxPartReader * reader, /* Adjust buffer timestamps */ offset = reader->start_offset + part_pad->segment.base; offset -= part_pad->initial_ts_offset; + /* We don't add the ts_offset here, because we + * want to measure the logical length of the stream, + * not to generate output timestamps */ /* Update the stored max duration on the pad, * always preferring making DTS contiguous @@ -159,8 +165,8 @@ handle_buffer_measuring (GstSplitMuxPartReader * reader, ts = GST_BUFFER_PTS (buf) + offset; GST_DEBUG_OBJECT (reader, "Pad %" GST_PTR_FORMAT - " incoming PTS %" GST_TIME_FORMAT - " DTS %" GST_TIME_FORMAT " offset by %" GST_STIME_FORMAT + " incoming DTS %" GST_TIME_FORMAT + " PTS %" GST_TIME_FORMAT " offset by %" GST_STIME_FORMAT " to %" GST_STIME_FORMAT, part_pad, GST_TIME_ARGS (GST_BUFFER_DTS (buf)), GST_TIME_ARGS (GST_BUFFER_PTS (buf)), @@ -228,6 +234,7 @@ splitmux_part_pad_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) /* Adjust buffer timestamps */ offset = reader->start_offset + part_pad->segment.base; offset -= part_pad->initial_ts_offset; + offset += reader->ts_offset; if (GST_BUFFER_PTS_IS_VALID (buf)) GST_BUFFER_PTS (buf) += offset; @@ -356,21 +363,22 @@ splitmux_part_pad_event (GstPad * pad, GstObject * parent, GstEvent * event) goto wrong_segment; /* Adjust segment */ - /* Adjust start/stop so the overall file is 0 + start_offset based */ + /* Adjust start/stop so the overall file is 0 + start_offset based, + * adding a fixed offset so that DTS is never negative */ if (seg->stop != -1) { seg->stop -= seg->start; - seg->stop += seg->time + reader->start_offset; + seg->stop += seg->time + reader->start_offset + reader->ts_offset; } - seg->start = seg->time + reader->start_offset; + seg->start = seg->time + reader->start_offset + reader->ts_offset; seg->time += reader->start_offset; seg->position += reader->start_offset; - GST_LOG_OBJECT (pad, "Adjusted segment now %" GST_PTR_FORMAT, event); - /* Replace event */ gst_event_unref (event); event = gst_event_new_segment (seg); + GST_LOG_OBJECT (pad, "Adjusted segment now %" GST_PTR_FORMAT, event); + if (reader->prep_state != PART_STATE_PREPARING_COLLECT_STREAMS && reader->prep_state != PART_STATE_PREPARING_MEASURE_STREAMS) break; /* Only do further stuff with segments during initial measuring */ @@ -631,6 +639,7 @@ gst_splitmux_part_reader_init (GstSplitMuxPartReader * reader) g_cond_init (&reader->inactive_cond); g_mutex_init (&reader->lock); g_mutex_init (&reader->type_lock); + g_mutex_init (&reader->msg_lock); /* FIXME: Create elements on a state change */ reader->src = gst_element_factory_make ("filesrc", NULL); @@ -678,6 +687,7 @@ splitmux_part_reader_finalize (GObject * object) g_cond_clear (&reader->inactive_cond); g_mutex_clear (&reader->lock); g_mutex_clear (&reader->type_lock); + g_mutex_clear (&reader->msg_lock); g_free (reader->path); @@ -689,12 +699,12 @@ do_async_start (GstSplitMuxPartReader * reader) { GstMessage *message; - GST_STATE_LOCK (reader); + SPLITMUX_PART_MSG_LOCK (reader); reader->async_pending = TRUE; message = gst_message_new_async_start (GST_OBJECT_CAST (reader)); GST_BIN_CLASS (parent_class)->handle_message (GST_BIN_CAST (reader), message); - GST_STATE_UNLOCK (reader); + SPLITMUX_PART_MSG_UNLOCK (reader); } static void @@ -702,7 +712,7 @@ do_async_done (GstSplitMuxPartReader * reader) { GstMessage *message; - GST_STATE_LOCK (reader); + SPLITMUX_PART_MSG_LOCK (reader); if (reader->async_pending) { message = gst_message_new_async_done (GST_OBJECT_CAST (reader), @@ -712,7 +722,7 @@ do_async_done (GstSplitMuxPartReader * reader) reader->async_pending = FALSE; } - GST_STATE_UNLOCK (reader); + SPLITMUX_PART_MSG_UNLOCK (reader); } static void @@ -1246,12 +1256,13 @@ gst_splitmux_part_reader_get_end_offset (GstSplitMuxPartReader * reader) void gst_splitmux_part_reader_set_start_offset (GstSplitMuxPartReader * reader, - GstClockTime offset) + GstClockTime time_offset, GstClockTime ts_offset) { SPLITMUX_PART_LOCK (reader); - reader->start_offset = offset; - GST_INFO_OBJECT (reader, "TS offset now %" GST_TIME_FORMAT, - GST_TIME_ARGS (offset)); + reader->start_offset = time_offset; + reader->ts_offset = ts_offset; + GST_INFO_OBJECT (reader, "Time offset now %" GST_TIME_FORMAT, + GST_TIME_ARGS (time_offset)); SPLITMUX_PART_UNLOCK (reader); } diff --git a/gst/multifile/gstsplitmuxpartreader.h b/gst/multifile/gstsplitmuxpartreader.h index b1d24560e2..78ecc6eb5a 100644 --- a/gst/multifile/gstsplitmuxpartreader.h +++ b/gst/multifile/gstsplitmuxpartreader.h @@ -73,12 +73,14 @@ struct _GstSplitMuxPartReader GstClockTime duration; GstClockTime start_offset; + GstClockTime ts_offset; GList *pads; GCond inactive_cond; GMutex lock; GMutex type_lock; + GMutex msg_lock; GstSplitMuxPartReaderPadCb get_pad_cb; gpointer cb_data; @@ -107,7 +109,7 @@ void gst_splitmux_part_reader_deactivate (GstSplitMuxPartReader *part); gboolean gst_splitmux_part_reader_is_active (GstSplitMuxPartReader *part); gboolean gst_splitmux_part_reader_src_query (GstSplitMuxPartReader *part, GstPad *src_pad, GstQuery * query); -void gst_splitmux_part_reader_set_start_offset (GstSplitMuxPartReader *part, GstClockTime offset); +void gst_splitmux_part_reader_set_start_offset (GstSplitMuxPartReader *part, GstClockTime time_offset, GstClockTime ts_offset); GstClockTime gst_splitmux_part_reader_get_start_offset (GstSplitMuxPartReader *part); GstClockTime gst_splitmux_part_reader_get_end_offset (GstSplitMuxPartReader *part); GstClockTime gst_splitmux_part_reader_get_duration (GstSplitMuxPartReader * reader); diff --git a/gst/multifile/gstsplitmuxsink.c b/gst/multifile/gstsplitmuxsink.c index 2d643d923f..d8e86c0862 100644 --- a/gst/multifile/gstsplitmuxsink.c +++ b/gst/multifile/gstsplitmuxsink.c @@ -80,6 +80,9 @@ GST_DEBUG_CATEGORY_STATIC (splitmux_debug); #define GST_CAT_DEFAULT splitmux_debug +#define GST_SPLITMUX_STATE_LOCK(s) g_mutex_lock(&(s)->state_lock) +#define GST_SPLITMUX_STATE_UNLOCK(s) g_mutex_unlock(&(s)->state_lock) + #define GST_SPLITMUX_LOCK(s) g_mutex_lock(&(s)->lock) #define GST_SPLITMUX_UNLOCK(s) g_mutex_unlock(&(s)->lock) #define GST_SPLITMUX_WAIT_INPUT(s) g_cond_wait (&(s)->input_cond, &(s)->lock) @@ -111,8 +114,10 @@ enum PROP_RESET_MUXER, PROP_ASYNC_FINALIZE, PROP_MUXER_FACTORY, + PROP_MUXER_PRESET, PROP_MUXER_PROPERTIES, PROP_SINK_FACTORY, + PROP_SINK_PRESET, PROP_SINK_PROPERTIES, PROP_MUXERPAD_MAP }; @@ -234,6 +239,7 @@ static GstElement *create_element (GstSplitMuxSink * splitmux, const gchar * factory, const gchar * name, gboolean locked); static void do_async_done (GstSplitMuxSink * splitmux); +static void gst_splitmux_reset_timecode (GstSplitMuxSink * splitmux); static MqStreamBuf * mq_stream_buf_new (void) @@ -309,24 +315,30 @@ gst_splitmux_sink_class_init (GstSplitMuxSinkClass * klass) g_object_class_install_property (gobject_class, PROP_MAX_SIZE_TIME, g_param_spec_uint64 ("max-size-time", "Max. size (ns)", "Max. amount of time per file (in ns, 0=disable)", 0, G_MAXUINT64, - DEFAULT_MAX_SIZE_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + DEFAULT_MAX_SIZE_TIME, + G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_MAX_SIZE_BYTES, g_param_spec_uint64 ("max-size-bytes", "Max. size bytes", "Max. amount of data per file (in bytes, 0=disable)", 0, G_MAXUINT64, - DEFAULT_MAX_SIZE_BYTES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + DEFAULT_MAX_SIZE_BYTES, + G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_MAX_SIZE_TIMECODE, g_param_spec_string ("max-size-timecode", "Maximum timecode difference", "Maximum difference in timecode between first and last frame. " "Separator is assumed to be \":\" everywhere (e.g. 01:00:00:00). " - "Will only be effective if a timecode track is present.", - NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + "Will only be effective if a timecode track is present.", NULL, + G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_SEND_KEYFRAME_REQUESTS, g_param_spec_boolean ("send-keyframe-requests", "Request keyframes at max-size-time", "Request a keyframe every max-size-time ns to try splitting at that point. " "Needs max-size-bytes to be 0 in order to be effective.", DEFAULT_SEND_KEYFRAME_REQUESTS, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_MAX_FILES, g_param_spec_uint ("max-files", "Max files", "Maximum number of files to keep on disk. Once the maximum is reached," @@ -336,9 +348,9 @@ gst_splitmux_sink_class_init (GstSplitMuxSinkClass * klass) g_object_class_install_property (gobject_class, PROP_ALIGNMENT_THRESHOLD, g_param_spec_uint64 ("alignment-threshold", "Alignment threshold (ns)", "Allow non-reference streams to be that many ns before the reference" - " stream", - 0, G_MAXUINT64, DEFAULT_ALIGNMENT_THRESHOLD, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + " stream", 0, G_MAXUINT64, DEFAULT_ALIGNMENT_THRESHOLD, + G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_MUXER, g_param_spec_object ("muxer", "Muxer", @@ -379,6 +391,19 @@ gst_splitmux_sink_class_init (GstSplitMuxSinkClass * klass) "The muxer element factory to use (default = mp4mux). " "Valid only for async-finalize = TRUE", "mp4mux", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstSplitMuxSink:muxer-preset + * + * An optional #GstPreset name to use for the muxer. This only has an effect + * in `async-finalize=TRUE` mode. + * + * Since: 1.18 + */ + g_object_class_install_property (gobject_class, PROP_MUXER_PRESET, + g_param_spec_string ("muxer-preset", "Muxer preset", + "The muxer preset to use. " + "Valid only for async-finalize = TRUE", + NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_MUXER_PROPERTIES, g_param_spec_boxed ("muxer-properties", "Muxer properties", "The muxer element properties to use. " @@ -390,6 +415,19 @@ gst_splitmux_sink_class_init (GstSplitMuxSinkClass * klass) "The sink element factory to use (default = filesink). " "Valid only for async-finalize = TRUE", "filesink", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstSplitMuxSink:sink-preset + * + * An optional #GstPreset name to use for the sink. This only has an effect + * in `async-finalize=TRUE` mode. + * + * Since: 1.18 + */ + g_object_class_install_property (gobject_class, PROP_SINK_PRESET, + g_param_spec_string ("sink-preset", "Sink preset", + "The sink preset to use. " + "Valid only for async-finalize = TRUE", + NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_SINK_PROPERTIES, g_param_spec_boxed ("sink-properties", "Sink properties", "The sink element properties to use. " @@ -427,7 +465,10 @@ gst_splitmux_sink_class_init (GstSplitMuxSinkClass * klass) * @splitmux: the #GstSplitMuxSink * @fragment_id: the sequence number of the file to be created * - * Returns: the location to be used for the next output file + * Returns: the location to be used for the next output file. This must be + * a newly-allocated string which will be freed with g_free() by the + * splitmuxsink element when it no longer needs it, so use g_strdup() or + * g_strdup_printf() or similar functions to allocate it. */ signals[SIGNAL_FORMAT_LOCATION] = g_signal_new ("format-location", G_TYPE_FROM_CLASS (klass), @@ -440,7 +481,12 @@ gst_splitmux_sink_class_init (GstSplitMuxSinkClass * klass) * @first_sample: A #GstSample containing the first buffer * from the reference stream in the new file * - * Returns: the location to be used for the next output file + * Returns: the location to be used for the next output file. This must be + * a newly-allocated string which will be freed with g_free() by the + * splitmuxsink element when it no longer needs it, so use g_strdup() or + * g_strdup_printf() or similar functions to allocate it. + * + * Since: 1.12 */ signals[SIGNAL_FORMAT_LOCATION_FULL] = g_signal_new ("format-location-full", G_TYPE_FROM_CLASS (klass), @@ -534,6 +580,7 @@ static void gst_splitmux_sink_init (GstSplitMuxSink * splitmux) { g_mutex_init (&splitmux->lock); + g_mutex_init (&splitmux->state_lock); g_cond_init (&splitmux->input_cond); g_cond_init (&splitmux->output_cond); g_queue_init (&splitmux->out_cmd_q); @@ -543,12 +590,12 @@ gst_splitmux_sink_init (GstSplitMuxSink * splitmux) splitmux->threshold_bytes = DEFAULT_MAX_SIZE_BYTES; splitmux->max_files = DEFAULT_MAX_FILES; splitmux->send_keyframe_requests = DEFAULT_SEND_KEYFRAME_REQUESTS; - splitmux->next_max_tc_time = GST_CLOCK_TIME_NONE; splitmux->alignment_threshold = DEFAULT_ALIGNMENT_THRESHOLD; splitmux->use_robust_muxing = DEFAULT_USE_ROBUST_MUXING; splitmux->reset_muxer = DEFAULT_RESET_MUXER; splitmux->threshold_timecode_str = NULL; + gst_splitmux_reset_timecode (splitmux); splitmux->async_finalize = DEFAULT_ASYNC_FINALIZE; splitmux->muxer_factory = g_strdup (DEFAULT_MUXER); @@ -560,10 +607,11 @@ gst_splitmux_sink_init (GstSplitMuxSink * splitmux) splitmux->split_requested = FALSE; splitmux->do_split_next_gop = FALSE; splitmux->times_to_split = gst_queue_array_new_for_struct (8, 8); + splitmux->next_fku_time = GST_CLOCK_TIME_NONE; } static void -gst_splitmux_reset (GstSplitMuxSink * splitmux) +gst_splitmux_reset_elements (GstSplitMuxSink * splitmux) { if (splitmux->muxer) { gst_element_set_locked_state (splitmux->muxer, TRUE); @@ -579,6 +627,15 @@ gst_splitmux_reset (GstSplitMuxSink * splitmux) splitmux->sink = splitmux->active_sink = splitmux->muxer = NULL; } +static void +gst_splitmux_reset_timecode (GstSplitMuxSink * splitmux) +{ + g_clear_pointer (&splitmux->in_tc, gst_video_time_code_free); + g_clear_pointer (&splitmux->fragment_start_tc, gst_video_time_code_free); + g_clear_pointer (&splitmux->gop_start_tc, gst_video_time_code_free); + splitmux->next_fragment_start_tc_time = GST_CLOCK_TIME_NONE; +} + static void gst_splitmux_sink_dispose (GObject * object) { @@ -597,6 +654,7 @@ gst_splitmux_sink_finalize (GObject * object) g_cond_clear (&splitmux->input_cond); g_cond_clear (&splitmux->output_cond); g_mutex_clear (&splitmux->lock); + g_mutex_clear (&splitmux->state_lock); g_queue_foreach (&splitmux->out_cmd_q, (GFunc) out_cmd_buf_free, NULL); g_queue_clear (&splitmux->out_cmd_q); @@ -610,15 +668,21 @@ gst_splitmux_sink_finalize (GObject * object) if (splitmux->muxer_factory) g_free (splitmux->muxer_factory); + if (splitmux->muxer_preset) + g_free (splitmux->muxer_preset); if (splitmux->muxer_properties) gst_structure_free (splitmux->muxer_properties); if (splitmux->sink_factory) g_free (splitmux->sink_factory); + if (splitmux->sink_preset) + g_free (splitmux->sink_preset); if (splitmux->sink_properties) gst_structure_free (splitmux->sink_properties); if (splitmux->threshold_timecode_str) g_free (splitmux->threshold_timecode_str); + if (splitmux->tc_interval) + gst_video_time_code_interval_free (splitmux->tc_interval); if (splitmux->times_to_split) gst_queue_array_free (splitmux->times_to_split); @@ -629,6 +693,7 @@ gst_splitmux_sink_finalize (GObject * object) * because the dispose will have freed all request pads though */ g_list_foreach (splitmux->contexts, (GFunc) mq_stream_ctx_free, NULL); g_list_free (splitmux->contexts); + gst_splitmux_reset_timecode (splitmux); G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -699,7 +764,24 @@ gst_splitmux_sink_set_property (GObject * object, guint prop_id, break; case PROP_MAX_SIZE_TIMECODE: GST_OBJECT_LOCK (splitmux); + g_free (splitmux->threshold_timecode_str); + /* will be calculated later */ + g_clear_pointer (&splitmux->tc_interval, + gst_video_time_code_interval_free); + gst_splitmux_reset_timecode (splitmux); + splitmux->threshold_timecode_str = g_value_dup_string (value); + if (splitmux->threshold_timecode_str) { + splitmux->tc_interval = + gst_video_time_code_interval_new_from_string + (splitmux->threshold_timecode_str); + if (!splitmux->tc_interval) { + g_warning ("Wrong timecode string %s", + splitmux->threshold_timecode_str); + g_free (splitmux->threshold_timecode_str); + splitmux->threshold_timecode_str = NULL; + } + } GST_OBJECT_UNLOCK (splitmux); break; case PROP_SEND_KEYFRAME_REQUESTS: @@ -762,6 +844,13 @@ gst_splitmux_sink_set_property (GObject * object, guint prop_id, splitmux->muxer_factory = g_value_dup_string (value); GST_OBJECT_UNLOCK (splitmux); break; + case PROP_MUXER_PRESET: + GST_OBJECT_LOCK (splitmux); + if (splitmux->muxer_preset) + g_free (splitmux->muxer_preset); + splitmux->muxer_preset = g_value_dup_string (value); + GST_OBJECT_UNLOCK (splitmux); + break; case PROP_MUXER_PROPERTIES: GST_OBJECT_LOCK (splitmux); if (splitmux->muxer_properties) @@ -780,6 +869,13 @@ gst_splitmux_sink_set_property (GObject * object, guint prop_id, splitmux->sink_factory = g_value_dup_string (value); GST_OBJECT_UNLOCK (splitmux); break; + case PROP_SINK_PRESET: + GST_OBJECT_LOCK (splitmux); + if (splitmux->sink_preset) + g_free (splitmux->sink_preset); + splitmux->sink_preset = g_value_dup_string (value); + GST_OBJECT_UNLOCK (splitmux); + break; case PROP_SINK_PROPERTIES: GST_OBJECT_LOCK (splitmux); if (splitmux->sink_properties) @@ -893,6 +989,11 @@ gst_splitmux_sink_get_property (GObject * object, guint prop_id, g_value_set_string (value, splitmux->muxer_factory); GST_OBJECT_UNLOCK (splitmux); break; + case PROP_MUXER_PRESET: + GST_OBJECT_LOCK (splitmux); + g_value_set_string (value, splitmux->muxer_preset); + GST_OBJECT_UNLOCK (splitmux); + break; case PROP_MUXER_PROPERTIES: GST_OBJECT_LOCK (splitmux); gst_value_set_structure (value, splitmux->muxer_properties); @@ -903,6 +1004,11 @@ gst_splitmux_sink_get_property (GObject * object, guint prop_id, g_value_set_string (value, splitmux->sink_factory); GST_OBJECT_UNLOCK (splitmux); break; + case PROP_SINK_PRESET: + GST_OBJECT_LOCK (splitmux); + g_value_set_string (value, splitmux->sink_preset); + GST_OBJECT_UNLOCK (splitmux); + break; case PROP_SINK_PROPERTIES: GST_OBJECT_LOCK (splitmux); gst_value_set_structure (value, splitmux->sink_properties); @@ -936,6 +1042,16 @@ my_segment_to_running_time (GstSegment * segment, GstClockTime val) return res; } +static void +mq_stream_ctx_reset (MqStreamCtx * ctx) +{ + gst_segment_init (&ctx->in_segment, GST_FORMAT_UNDEFINED); + gst_segment_init (&ctx->out_segment, GST_FORMAT_UNDEFINED); + ctx->in_running_time = ctx->out_running_time = GST_CLOCK_STIME_NONE; + g_queue_foreach (&ctx->queued_bufs, (GFunc) mq_stream_buf_free, NULL); + g_queue_clear (&ctx->queued_bufs); +} + static MqStreamCtx * mq_stream_ctx_new (GstSplitMuxSink * splitmux) { @@ -943,10 +1059,9 @@ mq_stream_ctx_new (GstSplitMuxSink * splitmux) ctx = g_new0 (MqStreamCtx, 1); ctx->splitmux = splitmux; - gst_segment_init (&ctx->in_segment, GST_FORMAT_UNDEFINED); - gst_segment_init (&ctx->out_segment, GST_FORMAT_UNDEFINED); - ctx->in_running_time = ctx->out_running_time = GST_CLOCK_STIME_NONE; g_queue_init (&ctx->queued_bufs); + mq_stream_ctx_reset (ctx); + return ctx; } @@ -966,7 +1081,6 @@ mq_stream_ctx_free (MqStreamCtx * ctx) } gst_object_unref (ctx->q); } - gst_buffer_replace (&ctx->prev_in_keyframe, NULL); gst_object_unref (ctx->sinkpad); gst_object_unref (ctx->srcpad); g_queue_foreach (&ctx->queued_bufs, (GFunc) mq_stream_buf_free, NULL); @@ -994,6 +1108,9 @@ send_fragment_opened_closed_msg (GstSplitMuxSink * splitmux, gboolean opened, "location") != NULL) g_object_get (sink, "location", &location, NULL); + GST_DEBUG_OBJECT (splitmux, + "Sending %s message. Running time %" GST_TIME_FORMAT " location %s", + msg_name, GST_TIME_ARGS (running_time), GST_STR_NULL (location)); /* If it's in the middle of a teardown, the reference_ctc might have become * NULL */ @@ -1069,16 +1186,15 @@ eos_context_async (MqStreamCtx * ctx, GstSplitMuxSink * splitmux) helper->pad = sinkpad; /* Takes the reference */ ctx->out_eos_async_done = TRUE; - /* HACK: Here, we explicitly unset the SINK flag on the target sink element - * that's about to be asynchronously disposed, so that it no longer - * participates in GstBin EOS logic. This fixes a race where if - * splitmuxsink really reaches EOS before an asynchronous background - * element has finished, then the bin won't actually send EOS to the - * pipeline. Even after finishing and removing the old element, the - * bin doesn't re-check EOS status on removing a SINK element. This - * should be fixed in core, making this hack unnecessary. */ - GST_OBJECT_FLAG_UNSET (splitmux->active_sink, GST_ELEMENT_FLAG_SINK); + /* There used to be a bug here, where we had to explicitly remove + * the SINK flag so that GstBin would ignore it for EOS purposes. + * That fixed a race where if splitmuxsink really reaches EOS + * before an asynchronous background element has finished, then + * the bin wouldn't actually send EOS to the pipeline. Even after + * finishing and removing the old element, the bin didn't re-check + * EOS status on removing a SINK element. That bug was fixed + * in core. */ GST_DEBUG_OBJECT (splitmux, "scheduled EOS to pad %" GST_PTR_FORMAT " ctx %p", sinkpad, ctx); @@ -1154,6 +1270,7 @@ complete_or_wait_on_out (GstSplitMuxSink * splitmux, MqStreamCtx * ctx) continue; case SPLITMUX_OUTPUT_STATE_ENDING_FILE: + case SPLITMUX_OUTPUT_STATE_ENDING_STREAM: /* We've reached the max out running_time to get here, so end this file now */ if (ctx->out_eos == FALSE) { if (splitmux->async_finalize) { @@ -1204,8 +1321,13 @@ complete_or_wait_on_out (GstSplitMuxSink * splitmux, MqStreamCtx * ctx) grow_blocked_queues (splitmux); if (cmd->start_new_fragment) { - GST_DEBUG_OBJECT (splitmux, "Got cmd to start new fragment"); - splitmux->output_state = SPLITMUX_OUTPUT_STATE_ENDING_FILE; + if (splitmux->muxed_out_bytes > 0) { + GST_DEBUG_OBJECT (splitmux, "Got cmd to start new fragment"); + splitmux->output_state = SPLITMUX_OUTPUT_STATE_ENDING_FILE; + } else { + GST_DEBUG_OBJECT (splitmux, + "Got cmd to start new fragment, but fragment is empty - ignoring."); + } } else { GST_DEBUG_OBJECT (splitmux, "Got new output cmd for time %" GST_STIME_FORMAT, @@ -1222,7 +1344,7 @@ complete_or_wait_on_out (GstSplitMuxSink * splitmux, MqStreamCtx * ctx) } else { GST_SPLITMUX_WAIT_OUTPUT (splitmux); } - } while (splitmux->output_state == + } while (!ctx->flushing && splitmux->output_state == SPLITMUX_OUTPUT_STATE_AWAITING_COMMAND); /* loop and re-check the state */ continue; @@ -1249,29 +1371,29 @@ complete_or_wait_on_out (GstSplitMuxSink * splitmux, MqStreamCtx * ctx) static GstClockTime calculate_next_max_timecode (GstSplitMuxSink * splitmux, - const GstVideoTimeCode * cur_tc) + const GstVideoTimeCode * cur_tc, GstClockTime running_time, + GstVideoTimeCode ** next_tc) { GstVideoTimeCode *target_tc; - GstVideoTimeCodeInterval *tc_inter; GstClockTime cur_tc_time, target_tc_time, next_max_tc_time; - if (cur_tc == NULL || splitmux->threshold_timecode_str == NULL) + if (cur_tc == NULL || splitmux->tc_interval == NULL) return GST_CLOCK_TIME_NONE; - tc_inter = - gst_video_time_code_interval_new_from_string - (splitmux->threshold_timecode_str); - target_tc = gst_video_time_code_add_interval (cur_tc, tc_inter); - gst_video_time_code_interval_free (tc_inter); + target_tc = gst_video_time_code_add_interval (cur_tc, splitmux->tc_interval); + if (!target_tc) { + GST_ELEMENT_ERROR (splitmux, + STREAM, FAILED, (NULL), ("Couldn't calculate target timecode")); + return GST_CLOCK_TIME_NONE; + } /* Convert to ns */ target_tc_time = gst_video_time_code_nsec_since_daily_jam (target_tc); cur_tc_time = gst_video_time_code_nsec_since_daily_jam (cur_tc); - /* Add fragment_start_time, accounting for wraparound */ + /* Add running_time, accounting for wraparound. */ if (target_tc_time >= cur_tc_time) { - next_max_tc_time = - target_tc_time - cur_tc_time + splitmux->fragment_start_time; + next_max_tc_time = target_tc_time - cur_tc_time + running_time; } else { GstClockTime day_in_ns = 24 * 60 * 60 * GST_SECOND; @@ -1295,37 +1417,53 @@ calculate_next_max_timecode (GstSplitMuxSink * splitmux, cur_tc->config.fps_n); gst_video_time_code_free (tc_for_offset); } - next_max_tc_time = - day_in_ns - cur_tc_time + target_tc_time + - splitmux->fragment_start_time; + next_max_tc_time = day_in_ns - cur_tc_time + target_tc_time + running_time; } GST_INFO_OBJECT (splitmux, "Next max TC time: %" GST_TIME_FORMAT " from ref TC: %" GST_TIME_FORMAT, GST_TIME_ARGS (next_max_tc_time), GST_TIME_ARGS (cur_tc_time)); - gst_video_time_code_free (target_tc); + if (next_tc) + *next_tc = target_tc; + else + gst_video_time_code_free (target_tc); return next_max_tc_time; } static gboolean -request_next_keyframe (GstSplitMuxSink * splitmux, GstBuffer * buffer) +request_next_keyframe (GstSplitMuxSink * splitmux, GstBuffer * buffer, + GstClockTime running_time) { GstEvent *ev; GstClockTime target_time; gboolean timecode_based = FALSE; + GstClockTime max_tc_time = GST_CLOCK_TIME_NONE; + GstClockTime next_max_tc_time = GST_CLOCK_TIME_NONE; + GstClockTime next_fku_time = GST_CLOCK_TIME_NONE; + GstClockTime tc_rounding_error = 5 * GST_USECOND; - splitmux->next_max_tc_time = GST_CLOCK_TIME_NONE; - if (splitmux->threshold_timecode_str) { - GstVideoTimeCodeMeta *tc_meta; + if (!splitmux->send_keyframe_requests) + return TRUE; - if (buffer != NULL) { - tc_meta = gst_buffer_get_video_time_code_meta (buffer); - if (tc_meta) { - splitmux->next_max_tc_time = - calculate_next_max_timecode (splitmux, &tc_meta->tc); - timecode_based = (splitmux->next_max_tc_time != GST_CLOCK_TIME_NONE); + if (splitmux->tc_interval) { + if (splitmux->in_tc && gst_video_time_code_is_valid (splitmux->in_tc)) { + GstVideoTimeCode *next_tc = NULL; + max_tc_time = + calculate_next_max_timecode (splitmux, splitmux->in_tc, + running_time, &next_tc); + + /* calculate the next expected keyframe time to prevent too early fku + * event */ + if (GST_CLOCK_TIME_IS_VALID (max_tc_time) && next_tc) { + next_max_tc_time = + calculate_next_max_timecode (splitmux, next_tc, max_tc_time, NULL); } + if (next_tc) + gst_video_time_code_free (next_tc); + + timecode_based = GST_CLOCK_TIME_IS_VALID (max_tc_time) && + GST_CLOCK_TIME_IS_VALID (next_max_tc_time); } else { /* This can happen in the presence of GAP events that trigger * a new fragment start */ @@ -1334,20 +1472,79 @@ request_next_keyframe (GstSplitMuxSink * splitmux, GstBuffer * buffer) } } - if (splitmux->send_keyframe_requests == FALSE - || (splitmux->threshold_time == 0 && !timecode_based) + if ((splitmux->threshold_time == 0 && !timecode_based) || splitmux->threshold_bytes != 0) return TRUE; if (timecode_based) { /* We might have rounding errors: aim slightly earlier */ - target_time = splitmux->next_max_tc_time - 5 * GST_USECOND; + if (max_tc_time >= tc_rounding_error) { + target_time = max_tc_time - tc_rounding_error; + } else { + /* unreliable target time */ + GST_DEBUG_OBJECT (splitmux, "tc time %" GST_TIME_FORMAT + " is smaller than allowed rounding error, set it to zero", + GST_TIME_ARGS (max_tc_time)); + target_time = 0; + } + + if (next_max_tc_time >= tc_rounding_error) { + next_fku_time = next_max_tc_time - tc_rounding_error; + } else { + /* unreliable target time */ + GST_DEBUG_OBJECT (splitmux, "next tc time %" GST_TIME_FORMAT + " is smaller than allowed rounding error, set it to zero", + GST_TIME_ARGS (next_max_tc_time)); + next_fku_time = 0; + } } else { - target_time = splitmux->fragment_start_time + splitmux->threshold_time; + target_time = running_time + splitmux->threshold_time; } + + if (GST_CLOCK_TIME_IS_VALID (splitmux->next_fku_time)) { + GstClockTime allowed_time = splitmux->next_fku_time; + + if (timecode_based) { + if (allowed_time >= tc_rounding_error) { + allowed_time -= tc_rounding_error; + } else { + /* unreliable next force key unit time */ + GST_DEBUG_OBJECT (splitmux, "expected next force key unit time %" + GST_TIME_FORMAT + " is smaller than allowed rounding error, set it to zero", + GST_TIME_ARGS (splitmux->next_fku_time)); + allowed_time = 0; + } + } + + if (target_time < allowed_time) { + GST_LOG_OBJECT (splitmux, "Target time %" GST_TIME_FORMAT + " is smaller than expected next keyframe time %" GST_TIME_FORMAT + ", rounding error compensated next keyframe time %" GST_TIME_FORMAT, + GST_TIME_ARGS (target_time), + GST_TIME_ARGS (splitmux->next_fku_time), + GST_TIME_ARGS (allowed_time)); + + return TRUE; + } else if (allowed_time != splitmux->next_fku_time && + target_time < splitmux->next_fku_time) { + GST_DEBUG_OBJECT (splitmux, "Target time %" GST_TIME_FORMAT + " is smaller than expected next keyframe time %" GST_TIME_FORMAT + ", but the difference is smaller than allowed rounding error", + GST_TIME_ARGS (target_time), GST_TIME_ARGS (splitmux->next_fku_time)); + } + } + + if (!timecode_based) { + next_fku_time = target_time + splitmux->threshold_time; + } + + splitmux->next_fku_time = next_fku_time; + ev = gst_video_event_new_upstream_force_key_unit (target_time, TRUE, 0); - GST_INFO_OBJECT (splitmux, "Requesting next keyframe at %" GST_TIME_FORMAT, - GST_TIME_ARGS (target_time)); + GST_INFO_OBJECT (splitmux, "Requesting keyframe at %" GST_TIME_FORMAT + ", the next expected keyframe is %" GST_TIME_FORMAT, + GST_TIME_ARGS (target_time), GST_TIME_ARGS (next_fku_time)); return gst_pad_push_event (splitmux->reference_ctx->sinkpad, ev); } @@ -1367,7 +1564,7 @@ handle_mq_output (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx) if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM || info->type & GST_PAD_PROBE_TYPE_EVENT_FLUSH) { GstEvent *event = gst_pad_probe_info_get_event (info); - gboolean locked = FALSE; + gboolean locked = FALSE, wait = !ctx->is_reference; GST_LOG_OBJECT (pad, "Event %" GST_PTR_FORMAT, event); @@ -1381,13 +1578,19 @@ handle_mq_output (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx) gst_segment_init (&ctx->out_segment, GST_FORMAT_UNDEFINED); g_queue_foreach (&ctx->queued_bufs, (GFunc) mq_stream_buf_free, NULL); g_queue_clear (&ctx->queued_bufs); + g_queue_clear (&ctx->queued_bufs); + /* If this is the reference context, we just threw away any queued keyframes */ + if (ctx->is_reference) + splitmux->queued_keyframes = 0; ctx->flushing = FALSE; + wait = FALSE; break; case GST_EVENT_FLUSH_START: GST_SPLITMUX_LOCK (splitmux); locked = TRUE; GST_LOG_OBJECT (pad, "Flush start"); ctx->flushing = TRUE; + GST_SPLITMUX_BROADCAST_INPUT (splitmux); GST_SPLITMUX_BROADCAST_OUTPUT (splitmux); break; case GST_EVENT_EOS: @@ -1396,6 +1599,12 @@ handle_mq_output (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx) if (splitmux->output_state == SPLITMUX_OUTPUT_STATE_STOPPED) goto beach; ctx->out_eos = TRUE; + + if (ctx == splitmux->reference_ctx) { + splitmux->output_state = SPLITMUX_OUTPUT_STATE_ENDING_STREAM; + GST_SPLITMUX_BROADCAST_OUTPUT (splitmux); + } + GST_INFO_OBJECT (splitmux, "Have EOS event at pad %" GST_PTR_FORMAT " ctx %p", pad, ctx); break; @@ -1503,7 +1712,7 @@ handle_mq_output (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx) * until the muxer / sink are ready for it */ if (!locked) GST_SPLITMUX_LOCK (splitmux); - if (!ctx->is_reference) + if (wait) complete_or_wait_on_out (splitmux, ctx); GST_SPLITMUX_UNLOCK (splitmux); @@ -1710,7 +1919,14 @@ start_next_fragment (GstSplitMuxSink * splitmux, MqStreamCtx * ctx) sink = gst_object_ref (splitmux->active_sink); GST_SPLITMUX_UNLOCK (splitmux); - GST_STATE_LOCK (splitmux); + GST_SPLITMUX_STATE_LOCK (splitmux); + + if (splitmux->shutdown) { + GST_DEBUG_OBJECT (splitmux, + "Shutdown requested. Aborting fragment switch."); + GST_SPLITMUX_STATE_UNLOCK (splitmux); + return; + } if (splitmux->async_finalize) { if (splitmux->muxed_out_bytes > 0 @@ -1727,6 +1943,9 @@ start_next_fragment (GstSplitMuxSink * splitmux, MqStreamCtx * ctx) create_element (splitmux, splitmux->sink_factory, newname, TRUE)) == NULL) goto fail; + if (splitmux->sink_preset && GST_IS_PRESET (splitmux->sink)) + gst_preset_load_preset (GST_PRESET (splitmux->sink), + splitmux->sink_preset); if (splitmux->sink_properties) gst_structure_foreach (splitmux->sink_properties, _set_property_from_structure, splitmux->sink); @@ -1744,6 +1963,9 @@ start_next_fragment (GstSplitMuxSink * splitmux, MqStreamCtx * ctx) * failures, so let's try and turn that off */ g_object_set (splitmux->sink, "async", FALSE, NULL); } + if (splitmux->muxer_preset && GST_IS_PRESET (splitmux->muxer)) + gst_preset_load_preset (GST_PRESET (splitmux->muxer), + splitmux->muxer_preset); if (splitmux->muxer_properties) gst_structure_foreach (splitmux->muxer_properties, _set_property_from_structure, splitmux->muxer); @@ -1802,9 +2024,7 @@ start_next_fragment (GstSplitMuxSink * splitmux, MqStreamCtx * ctx) } GST_SPLITMUX_LOCK (splitmux); - if (splitmux->muxed_out_bytes > 0 - || splitmux->fragment_id == splitmux->start_index) - set_next_filename (splitmux, ctx); + set_next_filename (splitmux, ctx); splitmux->muxed_out_bytes = 0; GST_SPLITMUX_UNLOCK (splitmux); @@ -1817,7 +2037,7 @@ start_next_fragment (GstSplitMuxSink * splitmux, MqStreamCtx * ctx) gst_object_unref (muxer); GST_SPLITMUX_LOCK (splitmux); - GST_STATE_UNLOCK (splitmux); + GST_SPLITMUX_STATE_UNLOCK (splitmux); splitmux->switching_fragment = FALSE; do_async_done (splitmux); @@ -1835,7 +2055,7 @@ start_next_fragment (GstSplitMuxSink * splitmux, MqStreamCtx * ctx) return; fail: - GST_STATE_UNLOCK (splitmux); + GST_SPLITMUX_STATE_UNLOCK (splitmux); GST_ELEMENT_ERROR (splitmux, RESOURCE, SETTINGS, ("Could not create the new muxer/sink"), NULL); } @@ -1888,7 +2108,12 @@ bus_handler (GstBin * bin, GstMessage * message) GST_SPLITMUX_UNLOCK (splitmux); return; } - } else if (splitmux->output_state == SPLITMUX_OUTPUT_STATE_ENDING_FILE) { + } else if (splitmux->output_state == SPLITMUX_OUTPUT_STATE_ENDING_STREAM) { + GST_DEBUG_OBJECT (splitmux, + "Passing EOS message. Output state %d max_out_running_time %" + GST_STIME_FORMAT, splitmux->output_state, + GST_STIME_ARGS (splitmux->max_out_running_time)); + } else { GST_DEBUG_OBJECT (splitmux, "Caught EOS at end of fragment, dropping"); splitmux->output_state = SPLITMUX_OUTPUT_STATE_START_NEXT_FILE; GST_SPLITMUX_BROADCAST_OUTPUT (splitmux); @@ -1896,11 +2121,6 @@ bus_handler (GstBin * bin, GstMessage * message) gst_message_unref (message); GST_SPLITMUX_UNLOCK (splitmux); return; - } else { - GST_DEBUG_OBJECT (splitmux, - "Passing EOS message. Output state %d max_out_running_time %" - GST_STIME_FORMAT, splitmux->output_state, - GST_STIME_ARGS (splitmux->max_out_running_time)); } GST_SPLITMUX_UNLOCK (splitmux); break; @@ -1990,9 +2210,14 @@ need_new_fragment (GstSplitMuxSink * splitmux, && splitmux->muxer_has_reserved_props; GST_OBJECT_UNLOCK (splitmux); - /* Have we muxed anything into the new file at all? */ - if (splitmux->fragment_total_bytes <= 0) + /* Have we muxed at least one thing from the reference + * stream into the file? If not, no other streams can have + * either */ + if (splitmux->fragment_reference_bytes <= 0) { + GST_TRACE_OBJECT (splitmux, + "Not ready to split - nothing muxed on the reference stream"); return FALSE; + } /* User told us to split now */ if (g_atomic_int_get (&(splitmux->do_split_next_gop)) == TRUE) { @@ -2001,7 +2226,7 @@ need_new_fragment (GstSplitMuxSink * splitmux, } /* User told us to split at this running time */ - if (splitmux->reference_ctx->in_running_time > time_to_split) { + if (splitmux->gop_start_time >= time_to_split) { GST_OBJECT_LOCK (splitmux); /* Dequeue running time */ gst_queue_array_pop_head_struct (splitmux->times_to_split); @@ -2009,12 +2234,16 @@ need_new_fragment (GstSplitMuxSink * splitmux, ptr_to_time = gst_queue_array_peek_head_struct (splitmux->times_to_split); while (ptr_to_time) { time_to_split = *ptr_to_time; - if (splitmux->reference_ctx->in_running_time <= time_to_split) { + if (splitmux->gop_start_time < time_to_split) { break; } gst_queue_array_pop_head_struct (splitmux->times_to_split); ptr_to_time = gst_queue_array_peek_head_struct (splitmux->times_to_split); } + GST_TRACE_OBJECT (splitmux, + "GOP start time %" GST_STIME_FORMAT " is after requested split point %" + GST_STIME_FORMAT, GST_STIME_ARGS (splitmux->gop_start_time), + GST_STIME_ARGS (time_to_split)); GST_OBJECT_UNLOCK (splitmux); return TRUE; } @@ -2032,14 +2261,16 @@ need_new_fragment (GstSplitMuxSink * splitmux, return TRUE; /* Would overrun time limit */ } - /* Timecode-based threshold accounts for possible rounding errors: - * 5us should be bigger than all possible rounding errors but nowhere near - * big enough to skip to another frame */ - if (splitmux->next_max_tc_time != GST_CLOCK_TIME_NONE && + if (splitmux->tc_interval && + GST_CLOCK_TIME_IS_VALID (splitmux->next_fragment_start_tc_time) && splitmux->reference_ctx->in_running_time > - splitmux->next_max_tc_time + 5 * GST_USECOND) { - GST_TRACE_OBJECT (splitmux, "Splitting at timecode mark"); - return TRUE; /* Timecode threshold */ + splitmux->next_fragment_start_tc_time + 5 * GST_USECOND) { + GST_TRACE_OBJECT (splitmux, + "in running time %" GST_STIME_FORMAT " overruns time limit %" + GST_TIME_FORMAT, + GST_STIME_ARGS (splitmux->reference_ctx->in_running_time), + GST_TIME_ARGS (splitmux->next_fragment_start_tc_time)); + return TRUE; } if (check_robust_muxing) { @@ -2066,6 +2297,26 @@ need_new_fragment (GstSplitMuxSink * splitmux, return FALSE; } +/* probably we want to add this API? */ +static void +video_time_code_replace (GstVideoTimeCode ** old_tc, GstVideoTimeCode * new_tc) +{ + GstVideoTimeCode *timecode = NULL; + + g_return_if_fail (old_tc != NULL); + + if (*old_tc == new_tc) + return; + + if (new_tc) + timecode = gst_video_time_code_copy (new_tc); + + if (*old_tc) + gst_video_time_code_free (*old_tc); + + *old_tc = timecode; +} + /* Called with splitmux lock held */ /* Called when entering ProcessingCompleteGop state * Assess if mq contents overflowed the current file @@ -2101,9 +2352,18 @@ handle_gathered_gop (GstSplitMuxSink * splitmux) splitmux->reference_ctx->in_running_time - splitmux->gop_start_time; GST_LOG_OBJECT (splitmux, " queued_bytes %" G_GUINT64_FORMAT, queued_bytes); + GST_LOG_OBJECT (splitmux, "mq at TS %" GST_STIME_FORMAT + " bytes %" G_GUINT64_FORMAT " in running time %" GST_STIME_FORMAT + " gop start time %" GST_STIME_FORMAT, + GST_STIME_ARGS (queued_time), queued_bytes, + GST_STIME_ARGS (splitmux->reference_ctx->in_running_time), + GST_STIME_ARGS (splitmux->gop_start_time)); + + if (queued_gop_time < 0) + goto error_gop_duration; - g_assert (queued_gop_time >= 0); - g_assert (queued_time >= splitmux->fragment_start_time); + if (queued_time < splitmux->fragment_start_time) + goto error_queued_time; queued_time -= splitmux->fragment_start_time; if (queued_time < queued_gop_time) @@ -2112,15 +2372,6 @@ handle_gathered_gop (GstSplitMuxSink * splitmux) /* Expand queued bytes estimate by muxer overhead */ queued_bytes += (queued_bytes * splitmux->mux_overhead); - GST_LOG_OBJECT (splitmux, "mq at TS %" GST_STIME_FORMAT - " bytes %" G_GUINT64_FORMAT, GST_STIME_ARGS (queued_time), queued_bytes); - if (splitmux->next_max_tc_time != GST_CLOCK_TIME_NONE) { - GST_LOG_OBJECT (splitmux, - "timecode mq TS %" GST_TIME_FORMAT " vs target %" GST_TIME_FORMAT, - GST_TIME_ARGS (splitmux->reference_ctx->in_running_time), - GST_TIME_ARGS (splitmux->next_max_tc_time + 5 * GST_USECOND)); - } - /* Check for overrun - have we output at least one byte and overrun * either threshold? */ if (need_new_fragment (splitmux, queued_time, queued_gop_time, queued_bytes)) { @@ -2145,19 +2396,29 @@ handle_gathered_gop (GstSplitMuxSink * splitmux) new_out_ts = splitmux->reference_ctx->in_running_time; splitmux->fragment_start_time = splitmux->gop_start_time; splitmux->fragment_total_bytes = 0; - - if (request_next_keyframe (splitmux, - splitmux->reference_ctx->prev_in_keyframe) == FALSE) { - GST_WARNING_OBJECT (splitmux, - "Could not request a keyframe. Files may not split at the exact location they should"); + splitmux->fragment_reference_bytes = 0; + + if (splitmux->tc_interval) { + video_time_code_replace (&splitmux->fragment_start_tc, + splitmux->gop_start_tc); + splitmux->next_fragment_start_tc_time = + calculate_next_max_timecode (splitmux, splitmux->fragment_start_tc, + splitmux->fragment_start_time, NULL); + if (!GST_CLOCK_TIME_IS_VALID (splitmux->next_fragment_start_tc_time)) { + GST_WARNING_OBJECT (splitmux, + "Couldn't calculate next fragment start time for timecode mode"); + /* shouldn't happen, but reset all and try again with next buffers */ + gst_splitmux_reset_timecode (splitmux); + } } - gst_buffer_replace (&splitmux->reference_ctx->prev_in_keyframe, NULL); } /* And set up to collect the next GOP */ if (!splitmux->reference_ctx->in_eos) { splitmux->input_state = SPLITMUX_INPUT_STATE_COLLECTING_GOP_START; splitmux->gop_start_time = new_out_ts; + if (splitmux->tc_interval) + video_time_code_replace (&splitmux->gop_start_tc, splitmux->in_tc); } else { /* This is probably already the current state, but just in case: */ splitmux->input_state = SPLITMUX_INPUT_STATE_FINISHING_UP; @@ -2170,6 +2431,7 @@ handle_gathered_gop (GstSplitMuxSink * splitmux) /* Now either way - either there was no overflow, or we requested a new fragment: release this GOP */ splitmux->fragment_total_bytes += splitmux->gop_total_bytes; + splitmux->fragment_reference_bytes += splitmux->gop_reference_bytes; if (splitmux->gop_total_bytes > 0) { GST_LOG_OBJECT (splitmux, @@ -2189,6 +2451,21 @@ handle_gathered_gop (GstSplitMuxSink * splitmux) } splitmux->gop_total_bytes = 0; + splitmux->gop_reference_bytes = 0; + return; + +error_gop_duration: + GST_ELEMENT_ERROR (splitmux, + STREAM, FAILED, ("Timestamping error on input streams"), + ("Queued GOP time is negative %" GST_STIME_FORMAT, + GST_STIME_ARGS (queued_gop_time))); + return; +error_queued_time: + GST_ELEMENT_ERROR (splitmux, + STREAM, FAILED, ("Timestamping error on input streams"), + ("Queued time is negative. Input went backwards. queued_time - %" + GST_STIME_FORMAT, GST_STIME_ARGS (queued_time))); + return; } /* Called with splitmux lock held */ @@ -2228,64 +2505,69 @@ check_completed_gop (GstSplitMuxSink * splitmux, MqStreamCtx * ctx) return; } - if (splitmux->input_state == SPLITMUX_INPUT_STATE_WAITING_GOP_COLLECT) { - gboolean ready = TRUE; - - /* Iterate each pad, and check that the input running time is at least - * up to the reference running time, and if so handle the collected GOP */ - GST_LOG_OBJECT (splitmux, "Checking GOP collected, Max in running time %" - GST_STIME_FORMAT " ctx %p", - GST_STIME_ARGS (splitmux->max_in_running_time), ctx); - for (cur = g_list_first (splitmux->contexts); cur != NULL; - cur = g_list_next (cur)) { - MqStreamCtx *tmpctx = (MqStreamCtx *) (cur->data); - - GST_LOG_OBJECT (splitmux, - "Context %p sink pad %" GST_PTR_FORMAT " @ TS %" GST_STIME_FORMAT - " EOS %d", tmpctx, tmpctx->sinkpad, - GST_STIME_ARGS (tmpctx->in_running_time), tmpctx->in_eos); + do { + if (splitmux->input_state == SPLITMUX_INPUT_STATE_WAITING_GOP_COLLECT) { + gboolean ready = TRUE; + + /* Iterate each pad, and check that the input running time is at least + * up to the reference running time, and if so handle the collected GOP */ + GST_LOG_OBJECT (splitmux, "Checking GOP collected, Max in running time %" + GST_STIME_FORMAT " ctx %p", + GST_STIME_ARGS (splitmux->max_in_running_time), ctx); + for (cur = g_list_first (splitmux->contexts); cur != NULL; + cur = g_list_next (cur)) { + MqStreamCtx *tmpctx = (MqStreamCtx *) (cur->data); - if (splitmux->max_in_running_time != GST_CLOCK_STIME_NONE && - tmpctx->in_running_time < splitmux->max_in_running_time && - !tmpctx->in_eos) { GST_LOG_OBJECT (splitmux, - "Context %p sink pad %" GST_PTR_FORMAT " not ready. We'll sleep", - tmpctx, tmpctx->sinkpad); - ready = FALSE; - break; + "Context %p sink pad %" GST_PTR_FORMAT " @ TS %" GST_STIME_FORMAT + " EOS %d", tmpctx, tmpctx->sinkpad, + GST_STIME_ARGS (tmpctx->in_running_time), tmpctx->in_eos); + + if (splitmux->max_in_running_time != GST_CLOCK_STIME_NONE && + tmpctx->in_running_time < splitmux->max_in_running_time && + !tmpctx->in_eos) { + GST_LOG_OBJECT (splitmux, + "Context %p sink pad %" GST_PTR_FORMAT " not ready. We'll sleep", + tmpctx, tmpctx->sinkpad); + ready = FALSE; + break; + } } - } - if (ready) { - GST_DEBUG_OBJECT (splitmux, - "Collected GOP is complete. Processing (ctx %p)", ctx); - /* All pads have a complete GOP, release it into the multiqueue */ - handle_gathered_gop (splitmux); - - /* The user has requested a split, we can split now that the previous GOP - * has been collected to the correct location */ - if (g_atomic_int_compare_and_exchange (&(splitmux->split_requested), TRUE, - FALSE)) { - g_atomic_int_set (&(splitmux->do_split_next_gop), TRUE); + if (ready) { + GST_DEBUG_OBJECT (splitmux, + "Collected GOP is complete. Processing (ctx %p)", ctx); + /* All pads have a complete GOP, release it into the multiqueue */ + handle_gathered_gop (splitmux); + + /* The user has requested a split, we can split now that the previous GOP + * has been collected to the correct location */ + if (g_atomic_int_compare_and_exchange (&(splitmux->split_requested), + TRUE, FALSE)) { + g_atomic_int_set (&(splitmux->do_split_next_gop), TRUE); + } } } - } - - /* If upstream reached EOS we are not expecting more data, no need to wait - * here. */ - if (ctx->in_eos) - return; - /* Some pad is not yet ready, or GOP is being pushed - * either way, sleep and wait to get woken */ - while (splitmux->input_state == SPLITMUX_INPUT_STATE_WAITING_GOP_COLLECT && - !ctx->flushing && - (ctx->in_running_time >= splitmux->max_in_running_time) && - (splitmux->max_in_running_time != GST_CLOCK_STIME_NONE)) { + /* If upstream reached EOS we are not expecting more data, no need to wait + * here. */ + if (ctx->in_eos) + return; - GST_LOG_OBJECT (splitmux, "Sleeping for GOP collection (ctx %p)", ctx); - GST_SPLITMUX_WAIT_INPUT (splitmux); - GST_LOG_OBJECT (splitmux, "Done waiting for complete GOP (ctx %p)", ctx); - } + if (splitmux->input_state == SPLITMUX_INPUT_STATE_WAITING_GOP_COLLECT && + !ctx->flushing && + (ctx->in_running_time >= splitmux->max_in_running_time) && + (splitmux->max_in_running_time != GST_CLOCK_STIME_NONE)) { + /* Some pad is not yet ready, or GOP is being pushed + * either way, sleep and wait to get woken */ + GST_LOG_OBJECT (splitmux, "Sleeping for GOP collection (ctx %p)", ctx); + GST_SPLITMUX_WAIT_INPUT (splitmux); + GST_LOG_OBJECT (splitmux, "Done waiting for complete GOP (ctx %p)", ctx); + } else { + /* This pad is not ready or the state changed - break out and get another + * buffer / event */ + break; + } + } while (splitmux->input_state == SPLITMUX_INPUT_STATE_WAITING_GOP_COLLECT); } static GstPadProbeReturn @@ -2432,23 +2714,47 @@ handle_mq_input (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx) buf_info->buf_size = gst_buffer_get_size (buf); buf_info->duration = GST_BUFFER_DURATION (buf); - /* initialize fragment_start_time */ - if (ctx->is_reference - && splitmux->fragment_start_time == GST_CLOCK_STIME_NONE) { - splitmux->gop_start_time = splitmux->fragment_start_time = buf_info->run_ts; - GST_LOG_OBJECT (splitmux, "Mux start time now %" GST_STIME_FORMAT, - GST_STIME_ARGS (splitmux->fragment_start_time)); - gst_buffer_replace (&ctx->prev_in_keyframe, buf); - - /* Also take this as the first start time when starting up, - * so that we start counting overflow from the first frame */ - if (!GST_CLOCK_STIME_IS_VALID (splitmux->max_in_running_time)) - splitmux->max_in_running_time = splitmux->fragment_start_time; - if (request_next_keyframe (splitmux, ctx->prev_in_keyframe) == FALSE) { + if (ctx->is_reference) { + /* initialize fragment_start_time */ + if (splitmux->fragment_start_time == GST_CLOCK_STIME_NONE) { + splitmux->gop_start_time = splitmux->fragment_start_time = + buf_info->run_ts; + GST_LOG_OBJECT (splitmux, "Mux start time now %" GST_STIME_FORMAT, + GST_STIME_ARGS (splitmux->fragment_start_time)); + + /* Also take this as the first start time when starting up, + * so that we start counting overflow from the first frame */ + if (!GST_CLOCK_STIME_IS_VALID (splitmux->max_in_running_time)) + splitmux->max_in_running_time = splitmux->fragment_start_time; + } + + if (splitmux->tc_interval) { + GstVideoTimeCodeMeta *tc_meta = gst_buffer_get_video_time_code_meta (buf); + if (tc_meta) { + video_time_code_replace (&splitmux->in_tc, &tc_meta->tc); + + if (!splitmux->fragment_start_tc) { + /* also initialize fragment_start_tc */ + video_time_code_replace (&splitmux->gop_start_tc, &tc_meta->tc); + video_time_code_replace (&splitmux->fragment_start_tc, &tc_meta->tc); + + splitmux->next_fragment_start_tc_time = + calculate_next_max_timecode (splitmux, splitmux->in_tc, + ctx->in_running_time, NULL); + GST_DEBUG_OBJECT (splitmux, "Initialize next fragment start tc time %" + GST_TIME_FORMAT, + GST_TIME_ARGS (splitmux->next_fragment_start_tc_time)); + } + } + } + + /* Check whether we need to request next keyframe depending on + * current running time */ + if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) && + request_next_keyframe (splitmux, buf, ctx->in_running_time) == FALSE) { GST_WARNING_OBJECT (splitmux, "Could not request a keyframe. Files may not split at the exact location they should"); } - gst_buffer_replace (&splitmux->reference_ctx->prev_in_keyframe, NULL); } GST_DEBUG_OBJECT (pad, "Buf TS %" GST_STIME_FORMAT @@ -2462,7 +2768,12 @@ handle_mq_input (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx) switch (splitmux->input_state) { case SPLITMUX_INPUT_STATE_COLLECTING_GOP_START: - if (ctx->is_reference) { + if (ctx->is_releasing) { + /* The pad belonging to this context is being released */ + GST_WARNING_OBJECT (pad, "Pad is being released while the muxer is " + "running. Data might not drain correctly"); + loop_again = FALSE; + } else if (ctx->is_reference) { /* This is the reference context. If it's a keyframe, * it marks the start of a new GOP and we should wait in * check_completed_gop before continuing, but either way @@ -2490,8 +2801,6 @@ handle_mq_input (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx) /* Wake up other input pads to collect this GOP */ GST_SPLITMUX_BROADCAST_INPUT (splitmux); check_completed_gop (splitmux, ctx); - /* Store this new keyframe to remember the start of GOP */ - gst_buffer_replace (&ctx->prev_in_keyframe, buf); } else { /* Pass this buffer if the reference ctx is far enough ahead */ if (ctx->in_running_time < splitmux->max_in_running_time) { @@ -2551,6 +2860,9 @@ handle_mq_input (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx) /* Update total input byte counter for overflow detect */ splitmux->gop_total_bytes += buf_info->buf_size; + if (ctx->is_reference) { + splitmux->gop_reference_bytes += buf_info->buf_size; + } /* Now add this buffer to the queue just before returning */ g_queue_push_head (&ctx->queued_bufs, buf_info); @@ -2913,12 +3225,21 @@ gst_splitmux_sink_release_pad (GstElement * element, GstPad * pad) /* Remove the context from our consideration */ splitmux->contexts = g_list_remove (splitmux->contexts, ctx); - if (ctx->sink_pad_block_id) + GST_SPLITMUX_UNLOCK (splitmux); + + if (ctx->sink_pad_block_id) { gst_pad_remove_probe (ctx->sinkpad, ctx->sink_pad_block_id); + gst_pad_send_event (ctx->sinkpad, gst_event_new_flush_start ()); + } if (ctx->src_pad_block_id) gst_pad_remove_probe (ctx->srcpad, ctx->src_pad_block_id); + GST_SPLITMUX_LOCK (splitmux); + + ctx->is_releasing = TRUE; + GST_SPLITMUX_BROADCAST_INPUT (splitmux); + /* Can release the context now */ mq_stream_ctx_free (ctx); if (ctx == splitmux->reference_ctx) @@ -2939,7 +3260,11 @@ gst_splitmux_sink_release_pad (GstElement * element, GstPad * pad) /* Reset the internal elements only after all request pads are released */ if (splitmux->contexts == NULL) - gst_splitmux_reset (splitmux); + gst_splitmux_reset_elements (splitmux); + + /* Wake up other input streams to check if the completion conditions have + * changed */ + GST_SPLITMUX_BROADCAST_INPUT (splitmux); fail: GST_SPLITMUX_UNLOCK (splitmux); @@ -2986,13 +3311,18 @@ create_muxer (GstSplitMuxSink * splitmux) if ((!splitmux->async_finalize && provided_muxer == NULL) || (splitmux->async_finalize && splitmux->muxer_factory == NULL)) { if ((splitmux->muxer = - create_element (splitmux, DEFAULT_MUXER, "muxer", FALSE)) == NULL) + create_element (splitmux, + splitmux->muxer_factory ? splitmux-> + muxer_factory : DEFAULT_MUXER, "muxer", FALSE)) == NULL) goto fail; } else if (splitmux->async_finalize) { if ((splitmux->muxer = create_element (splitmux, splitmux->muxer_factory, "muxer", FALSE)) == NULL) goto fail; + if (splitmux->muxer_preset && GST_IS_PRESET (splitmux->muxer)) + gst_preset_load_preset (GST_PRESET (splitmux->muxer), + splitmux->muxer_preset); if (splitmux->muxer_properties) gst_structure_foreach (splitmux->muxer_properties, _set_property_from_structure, splitmux->muxer); @@ -3087,6 +3417,9 @@ create_sink (GstSplitMuxSink * splitmux) create_element (splitmux, splitmux->sink_factory, "sink", TRUE)) == NULL) goto fail; + if (splitmux->sink_preset && GST_IS_PRESET (splitmux->sink)) + gst_preset_load_preset (GST_PRESET (splitmux->sink), + splitmux->sink_preset); if (splitmux->sink_properties) gst_structure_foreach (splitmux->sink_properties, _set_property_from_structure, splitmux->sink); @@ -3225,6 +3558,33 @@ do_async_done (GstSplitMuxSink * splitmux) splitmux->need_async_start = FALSE; } +static void +gst_splitmux_sink_reset (GstSplitMuxSink * splitmux) +{ + splitmux->max_in_running_time = GST_CLOCK_STIME_NONE; + splitmux->gop_start_time = splitmux->fragment_start_time = + GST_CLOCK_STIME_NONE; + splitmux->max_out_running_time = 0; + splitmux->fragment_total_bytes = 0; + splitmux->fragment_reference_bytes = 0; + splitmux->gop_total_bytes = 0; + splitmux->gop_reference_bytes = 0; + splitmux->muxed_out_bytes = 0; + splitmux->ready_for_output = FALSE; + + g_atomic_int_set (&(splitmux->split_requested), FALSE); + g_atomic_int_set (&(splitmux->do_split_next_gop), FALSE); + + splitmux->next_fku_time = GST_CLOCK_TIME_NONE; + gst_queue_array_clear (splitmux->times_to_split); + + g_list_foreach (splitmux->contexts, (GFunc) mq_stream_ctx_reset, NULL); + splitmux->queued_keyframes = 0; + + g_queue_foreach (&splitmux->out_cmd_q, (GFunc) out_cmd_buf_free, NULL); + g_queue_clear (&splitmux->out_cmd_q); +} + static GstStateChangeReturn gst_splitmux_sink_change_state (GstElement * element, GstStateChange transition) { @@ -3247,23 +3607,30 @@ gst_splitmux_sink_change_state (GstElement * element, GstStateChange transition) } case GST_STATE_CHANGE_READY_TO_PAUSED:{ GST_SPLITMUX_LOCK (splitmux); + /* Make sure contexts and tracking times are cleared, in case we're being reused */ + gst_splitmux_sink_reset (splitmux); /* Start by collecting one input on each pad */ splitmux->input_state = SPLITMUX_INPUT_STATE_COLLECTING_GOP_START; splitmux->output_state = SPLITMUX_OUTPUT_STATE_START_NEXT_FILE; - splitmux->max_in_running_time = GST_CLOCK_STIME_NONE; - splitmux->gop_start_time = splitmux->fragment_start_time = - GST_CLOCK_STIME_NONE; - splitmux->muxed_out_bytes = 0; - splitmux->ready_for_output = FALSE; + GST_SPLITMUX_UNLOCK (splitmux); + + GST_SPLITMUX_STATE_LOCK (splitmux); + splitmux->shutdown = FALSE; + GST_SPLITMUX_STATE_UNLOCK (splitmux); break; } case GST_STATE_CHANGE_PAUSED_TO_READY: g_atomic_int_set (&(splitmux->split_requested), FALSE); g_atomic_int_set (&(splitmux->do_split_next_gop), FALSE); + case GST_STATE_CHANGE_READY_TO_NULL: + GST_SPLITMUX_STATE_LOCK (splitmux); + splitmux->shutdown = TRUE; + GST_SPLITMUX_STATE_UNLOCK (splitmux); + GST_SPLITMUX_LOCK (splitmux); - gst_queue_array_clear (splitmux->times_to_split); + gst_splitmux_sink_reset (splitmux); splitmux->output_state = SPLITMUX_OUTPUT_STATE_STOPPED; splitmux->input_state = SPLITMUX_INPUT_STATE_STOPPED; /* Wake up any blocked threads */ @@ -3303,7 +3670,7 @@ gst_splitmux_sink_change_state (GstElement * element, GstStateChange transition) splitmux->fragment_id = 0; /* Reset internal elements only if no pad contexts are using them */ if (splitmux->contexts == NULL) - gst_splitmux_reset (splitmux); + gst_splitmux_reset_elements (splitmux); do_async_done (splitmux); GST_SPLITMUX_UNLOCK (splitmux); break; @@ -3315,7 +3682,7 @@ gst_splitmux_sink_change_state (GstElement * element, GstStateChange transition) if (transition == GST_STATE_CHANGE_NULL_TO_READY && ret == GST_STATE_CHANGE_FAILURE) { /* Cleanup elements on failed transition out of NULL */ - gst_splitmux_reset (splitmux); + gst_splitmux_reset_elements (splitmux); GST_SPLITMUX_LOCK (splitmux); do_async_done (splitmux); GST_SPLITMUX_UNLOCK (splitmux); diff --git a/gst/multifile/gstsplitmuxsink.h b/gst/multifile/gstsplitmuxsink.h index 77e79a7fc5..dc12182f55 100644 --- a/gst/multifile/gstsplitmuxsink.h +++ b/gst/multifile/gstsplitmuxsink.h @@ -50,6 +50,7 @@ typedef enum _SplitMuxOutputState SPLITMUX_OUTPUT_STATE_AWAITING_COMMAND, /* Waiting first command packet from input */ SPLITMUX_OUTPUT_STATE_OUTPUT_GOP, /* Outputting a collected GOP */ SPLITMUX_OUTPUT_STATE_ENDING_FILE, /* Finishing the current fragment */ + SPLITMUX_OUTPUT_STATE_ENDING_STREAM, /* Finishing up the entire stream due to input EOS */ SPLITMUX_OUTPUT_STATE_START_NEXT_FILE /* Restarting after ENDING_FILE */ } SplitMuxOutputState; @@ -84,6 +85,7 @@ typedef struct _MqStreamCtx gboolean out_eos_async_done; gboolean need_unblock; gboolean caps_change; + gboolean is_releasing; GstSegment in_segment; GstSegment out_segment; @@ -91,8 +93,6 @@ typedef struct _MqStreamCtx GstClockTimeDiff in_running_time; GstClockTimeDiff out_running_time; - GstBuffer *prev_in_keyframe; /* store keyframe for each GOP */ - GstElement *q; GQueue queued_bufs; @@ -107,7 +107,11 @@ struct _GstSplitMuxSink { GstBin parent; + GMutex state_lock; + gboolean shutdown; + GMutex lock; + GCond input_cond; GCond output_cond; @@ -118,8 +122,11 @@ struct _GstSplitMuxSink guint max_files; gboolean send_keyframe_requests; gchar *threshold_timecode_str; - GstClockTime next_max_tc_time; + /* created from threshold_timecode_str */ + GstVideoTimeCodeInterval *tc_interval; GstClockTime alignment_threshold; + /* expected running time of next force keyframe unit event */ + GstClockTime next_fku_time; gboolean reset_muxer; @@ -143,13 +150,28 @@ struct _GstSplitMuxSink /* Number of bytes sent to the * current fragment */ guint64 fragment_total_bytes; + /* Number of bytes for the reference + * stream in this fragment */ + guint64 fragment_reference_bytes; + /* Number of bytes we've collected into * the GOP that's being collected */ guint64 gop_total_bytes; + /* Number of bytes from the reference context + * that we've collected into the current GOP */ + guint64 gop_reference_bytes; /* Start time of the current fragment */ GstClockTimeDiff fragment_start_time; /* Start time of the current GOP */ GstClockTimeDiff gop_start_time; + /* The last timecode we have */ + GstVideoTimeCode *in_tc; + /* Start timecode of the current fragment */ + GstVideoTimeCode *fragment_start_tc; + /* Start timecode of the current GOP */ + GstVideoTimeCode *gop_start_tc; + /* expected running time of next fragment in timecode mode */ + GstClockTime next_fragment_start_tc_time; GQueue out_cmd_q; /* Queue of commands for output thread */ @@ -179,8 +201,10 @@ struct _GstSplitMuxSink /* Async finalize options */ gboolean async_finalize; gchar *muxer_factory; + gchar *muxer_preset; GstStructure *muxer_properties; gchar *sink_factory; + gchar *sink_preset; GstStructure *sink_properties; GstStructure *muxerpad_map; diff --git a/gst/multifile/gstsplitmuxsrc.c b/gst/multifile/gstsplitmuxsrc.c index a9cfa56296..d8569eb4a7 100644 --- a/gst/multifile/gstsplitmuxsrc.c +++ b/gst/multifile/gstsplitmuxsrc.c @@ -55,6 +55,8 @@ GST_DEBUG_CATEGORY (splitmux_debug); #define GST_CAT_DEFAULT splitmux_debug +#define FIXED_TS_OFFSET (1000*GST_SECOND) + enum { PROP_0, @@ -329,13 +331,13 @@ do_async_start (GstSplitMuxSrc * splitmux) { GstMessage *message; - GST_STATE_LOCK (splitmux); + SPLITMUX_SRC_MSG_LOCK (splitmux); splitmux->async_pending = TRUE; message = gst_message_new_async_start (GST_OBJECT_CAST (splitmux)); GST_BIN_CLASS (parent_class)->handle_message (GST_BIN_CAST (splitmux), message); - GST_STATE_UNLOCK (splitmux); + SPLITMUX_SRC_MSG_UNLOCK (splitmux); } static void @@ -343,7 +345,7 @@ do_async_done (GstSplitMuxSrc * splitmux) { GstMessage *message; - GST_STATE_LOCK (splitmux); + SPLITMUX_SRC_MSG_LOCK (splitmux); if (splitmux->async_pending) { message = gst_message_new_async_done (GST_OBJECT_CAST (splitmux), @@ -353,7 +355,7 @@ do_async_done (GstSplitMuxSrc * splitmux) splitmux->async_pending = FALSE; } - GST_STATE_UNLOCK (splitmux); + SPLITMUX_SRC_MSG_UNLOCK (splitmux); } static GstStateChangeReturn @@ -406,10 +408,14 @@ gst_splitmux_src_change_state (GstElement * element, GstStateChange transition) static void gst_splitmux_src_activate_first_part (GstSplitMuxSrc * splitmux) { - if (!gst_splitmux_src_activate_part (splitmux, 0, GST_SEEK_FLAG_NONE)) { - GST_ELEMENT_ERROR (splitmux, RESOURCE, OPEN_READ, (NULL), - ("Failed to activate first part for playback")); + SPLITMUX_SRC_LOCK (splitmux); + if (splitmux->running) { + if (!gst_splitmux_src_activate_part (splitmux, 0, GST_SEEK_FLAG_NONE)) { + GST_ELEMENT_ERROR (splitmux, RESOURCE, OPEN_READ, (NULL), + ("Failed to activate first part for playback")); + } } + SPLITMUX_SRC_UNLOCK (splitmux); } static GstBusSyncReply @@ -642,14 +648,14 @@ gst_splitmux_handle_event (GstSplitMuxSrc * splitmux, * seg or play_segment */ if (splitmux->play_segment.rate > 0.0) { if (splitmux->play_segment.stop != -1) - seg.stop = splitmux->play_segment.stop; + seg.stop = splitmux->play_segment.stop + FIXED_TS_OFFSET; else seg.stop = splitpad->segment.stop; } else { /* Reverse playback from stop time to start time */ /* See if an end point was requested in the seek */ if (splitmux->play_segment.start != -1) { - seg.start = splitmux->play_segment.start; + seg.start = splitmux->play_segment.start + FIXED_TS_OFFSET; seg.time = splitmux->play_segment.time; } else { seg.start = splitpad->segment.start; @@ -745,7 +751,11 @@ gst_splitmux_pad_loop (GstPad * pad) GST_OBJECT_LOCK (splitpad); if (splitpad->part_pad == NULL) { + GST_DEBUG_OBJECT (splitmux, + "Pausing task because part reader is not present"); GST_OBJECT_UNLOCK (splitpad); + gst_pad_pause_task (pad); + gst_object_unref (splitmux); return; } part_pad = gst_object_ref (splitpad->part_pad); @@ -858,7 +868,7 @@ gst_splitmux_src_prepare_next_part (GstSplitMuxSrc * splitmux) splitmux->parts[idx]->path, idx); gst_splitmux_part_reader_set_start_offset (splitmux->parts[idx], - splitmux->end_offset); + splitmux->end_offset, FIXED_TS_OFFSET); if (!gst_splitmux_part_reader_prepare (splitmux->parts[idx])) { GST_WARNING_OBJECT (splitmux, "Failed to prepare file part %s. Cannot play past there.", @@ -885,6 +895,14 @@ gst_splitmux_src_start (GstSplitMuxSrc * splitmux) gchar **files; guint i; + SPLITMUX_SRC_LOCK (splitmux); + if (splitmux->running) { + /* splitmux is still running / stopping. We can't start again yet */ + SPLITMUX_SRC_UNLOCK (splitmux); + return FALSE; + } + SPLITMUX_SRC_UNLOCK (splitmux); + GST_DEBUG_OBJECT (splitmux, "Starting"); g_signal_emit (splitmux, signals[SIGNAL_FORMAT_LOCATION], 0, &files); @@ -975,10 +993,13 @@ gst_splitmux_src_stop (GstSplitMuxSrc * splitmux) SPLITMUX_SRC_LOCK (splitmux); if (!splitmux->running) goto out; - + splitmux->running = FALSE; GST_DEBUG_OBJECT (splitmux, "Stopping"); - /* Stop and destroy all parts */ + SPLITMUX_SRC_UNLOCK (splitmux); + + /* Stop and destroy all parts. We don't need the lock here, + * because all parts were created in _start() */ for (i = 0; i < splitmux->num_created_parts; i++) { if (splitmux->parts[i] == NULL) continue; @@ -986,6 +1007,7 @@ gst_splitmux_src_stop (GstSplitMuxSrc * splitmux) g_object_unref (splitmux->parts[i]); splitmux->parts[i] = NULL; } + SPLITMUX_SRC_LOCK (splitmux); SPLITMUX_SRC_PADS_WLOCK (splitmux); pads_list = splitmux->pads; @@ -1006,7 +1028,6 @@ gst_splitmux_src_stop (GstSplitMuxSrc * splitmux) splitmux->num_parts = 0; splitmux->num_prepared_parts = 0; splitmux->num_created_parts = 0; - splitmux->running = FALSE; splitmux->total_duration = GST_CLOCK_TIME_NONE; /* Reset playback segment */ gst_segment_init (&splitmux->play_segment, GST_FORMAT_TIME); diff --git a/gst/multifile/gstsplitmuxsrc.h b/gst/multifile/gstsplitmuxsrc.h index 4c8f95cc0c..8bb84a7a4a 100644 --- a/gst/multifile/gstsplitmuxsrc.h +++ b/gst/multifile/gstsplitmuxsrc.h @@ -44,6 +44,7 @@ struct _GstSplitMuxSrc GstBin parent; GMutex lock; + GMutex msg_lock; gboolean running; gchar *location; /* OBJECT_LOCK */ @@ -108,6 +109,9 @@ gboolean register_splitmuxsrc (GstPlugin * plugin); #define SPLITMUX_SRC_LOCK(s) g_mutex_lock(&(s)->lock) #define SPLITMUX_SRC_UNLOCK(s) g_mutex_unlock(&(s)->lock) +#define SPLITMUX_SRC_MSG_LOCK(s) g_mutex_lock(&(s)->msg_lock) +#define SPLITMUX_SRC_MSG_UNLOCK(s) g_mutex_unlock(&(s)->msg_lock) + #define SPLITMUX_SRC_PADS_WLOCK(s) g_rw_lock_writer_lock(&(s)->pads_rwlock) #define SPLITMUX_SRC_PADS_WUNLOCK(s) g_rw_lock_writer_unlock(&(s)->pads_rwlock) #define SPLITMUX_SRC_PADS_RLOCK(s) g_rw_lock_reader_lock(&(s)->pads_rwlock) diff --git a/gst/multifile/meson.build b/gst/multifile/meson.build index 2ced699568..b7215f301b 100644 --- a/gst/multifile/meson.build +++ b/gst/multifile/meson.build @@ -8,6 +8,7 @@ multifile_sources = [ 'gstsplitmuxsrc.c', 'gstsplitutils.c', 'patternspec.c', + 'gstimagesequencesrc.c', ] gstmultifile = library('gstmultifile', diff --git a/gst/rtp/gstbuffermemory.c b/gst/rtp/gstbuffermemory.c new file mode 100644 index 0000000000..d6fd6477f3 --- /dev/null +++ b/gst/rtp/gstbuffermemory.c @@ -0,0 +1,120 @@ +/* GStreamer + * Copyright (C) 2020 Ognyan Tonchev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "gstbuffermemory.h" + +gboolean +gst_buffer_memory_map (GstBuffer * buffer, GstBufferMemoryMap * map) +{ + GstMemory *mem; + + g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE); + g_return_val_if_fail (map != NULL, FALSE); + + if (gst_buffer_n_memory (buffer) == 0) { + GST_DEBUG ("no memory blocks in buffer"); + return FALSE; + } + + mem = gst_buffer_get_memory (buffer, 0); + + if (!gst_memory_map (mem, &map->map, GST_MAP_READ)) { + GST_ERROR ("failed to map memory"); + gst_memory_unref (mem); + return FALSE; + } + + map->buf = buffer; + map->mem = mem; + map->data = map->map.data; + map->size = map->map.size; + map->index = 0; + map->total_size = gst_buffer_get_size (buffer); + map->offset = 0; + + return TRUE; +} + +static gboolean +buffer_memory_map_next (GstBufferMemoryMap * map) +{ + if (!map->mem) + return FALSE; + + gst_memory_unmap (map->mem, &map->map); + gst_memory_unref (map->mem); + map->mem = NULL; + map->data = NULL; + map->size = 0; + + map->index++; + + if (map->index >= gst_buffer_n_memory (map->buf)) { + GST_DEBUG ("no more memory blocks in buffer"); + return FALSE; + } + + map->mem = gst_buffer_get_memory (map->buf, map->index); + + if (!gst_memory_map (map->mem, &map->map, GST_MAP_READ)) { + GST_ERROR ("failed to map memory"); + gst_memory_unref (map->mem); + map->mem = NULL; + return FALSE; + } + + map->data = map->map.data; + map->size = map->map.size; + + return TRUE; +} + +gboolean +gst_buffer_memory_advance_bytes (GstBufferMemoryMap * map, gsize size) +{ + gsize offset = size; + + g_return_val_if_fail (map != NULL, FALSE); + + map->offset += size; + + while (offset >= map->size) { + offset -= map->size; + GST_DEBUG ("switching memory"); + if (!buffer_memory_map_next (map)) + return FALSE; + } + + map->data += offset; + map->size -= offset; + + return TRUE; +} + +void +gst_buffer_memory_unmap (GstBufferMemoryMap * map) +{ + g_return_if_fail (map != NULL); + + if (map->mem) { + gst_memory_unmap (map->mem, &map->map); + gst_memory_unref (map->mem); + map->mem = NULL; + } +} diff --git a/gst/rtp/gstbuffermemory.h b/gst/rtp/gstbuffermemory.h new file mode 100644 index 0000000000..3b78429898 --- /dev/null +++ b/gst/rtp/gstbuffermemory.h @@ -0,0 +1,66 @@ +/* GStreamer + * Copyright (C) 2020 Ognyan Tonchev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_BUFFER_MEMORY_H__ +#define __GST_BUFFER_MEMORY_H__ + +#include + +G_BEGIN_DECLS + +struct _GstBufferMemoryMap +{ + /* private datas */ + + GstBuffer *buf; + GstMemory *mem; + GstMapInfo map; + guint index; + gsize total_size; + + /* public datas */ + + /* data of the currently mapped memory */ + const guint8 *data; + guint offset; + + /* size of the currently mapped memory */ + gsize size; + + /* When advancing through the data with gst_buffer_memory_advance_bytes () + * the data field is also advanced and the size field decreased with the + * corresponding number of bytes. If all the bytes from the currently mapped + * GstMemory have been consumed then a new GstMemory will be mapped and data + * and size fileds will be updated. + * */ +}; +typedef struct _GstBufferMemoryMap GstBufferMemoryMap; + +G_GNUC_INTERNAL +gboolean gst_buffer_memory_map (GstBuffer * buffer, GstBufferMemoryMap * map); + +G_GNUC_INTERNAL +gboolean gst_buffer_memory_advance_bytes (GstBufferMemoryMap * map, gsize size); + +G_GNUC_INTERNAL +void gst_buffer_memory_unmap (GstBufferMemoryMap * map); + +G_END_DECLS + +#endif /* __GST_BUFFER_MEMORY_H__ */ diff --git a/gst/rtp/gstrtp.c b/gst/rtp/gstrtp.c index b0ab05527d..b2a6706e17 100644 --- a/gst/rtp/gstrtp.c +++ b/gst/rtp/gstrtp.c @@ -117,8 +117,6 @@ #include "gstrtpreddec.h" #include "gstrtpulpfecdec.h" #include "gstrtpulpfecenc.h" -#include "gstrtpreddec.h" -#include "gstrtpredenc.h" #include "gstrtpstorage.h" static gboolean @@ -411,14 +409,6 @@ plugin_init (GstPlugin * plugin) GST_TYPE_RTP_ULPFEC_ENC)) return FALSE; - if (!gst_element_register (plugin, "rtpreddec", GST_RANK_NONE, - GST_TYPE_RTP_RED_DEC)) - return FALSE; - - if (!gst_element_register (plugin, "rtpredenc", GST_RANK_NONE, - GST_TYPE_RTP_RED_ENC)) - return FALSE; - if (!gst_element_register (plugin, "rtpstorage", GST_RANK_NONE, GST_TYPE_RTP_STORAGE)) return FALSE; diff --git a/gst/rtp/gstrtpL16depay.c b/gst/rtp/gstrtpL16depay.c index a249921d0e..f054a24801 100644 --- a/gst/rtp/gstrtpL16depay.c +++ b/gst/rtp/gstrtpL16depay.c @@ -209,6 +209,7 @@ gst_rtp_L16_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps) GST_STR_NULL (channel_order), channels)); /* create default NONE layout */ gst_rtp_channels_create_default (channels, info->position); + info->flags |= GST_AUDIO_FLAG_UNPOSITIONED; } srccaps = gst_audio_info_to_caps (info); @@ -279,12 +280,14 @@ gst_rtp_L16_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) { GST_ELEMENT_WARNING (rtpL16depay, STREAM, DECODE, ("Wrong Payload Size."), (NULL)); + gst_buffer_unref (outbuf); return NULL; } reorder_failed: { GST_ELEMENT_ERROR (rtpL16depay, STREAM, DECODE, ("Channel reordering failed."), (NULL)); + gst_buffer_unref (outbuf); return NULL; } } diff --git a/gst/rtp/gstrtpL24depay.c b/gst/rtp/gstrtpL24depay.c index b37b06312f..448dac022b 100644 --- a/gst/rtp/gstrtpL24depay.c +++ b/gst/rtp/gstrtpL24depay.c @@ -187,6 +187,7 @@ gst_rtp_L24_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps) GST_STR_NULL (channel_order), channels)); /* create default NONE layout */ gst_rtp_channels_create_default (channels, info->position); + info->flags |= GST_AUDIO_FLAG_UNPOSITIONED; } srccaps = gst_audio_info_to_caps (info); diff --git a/gst/rtp/gstrtpL8depay.c b/gst/rtp/gstrtpL8depay.c index 026f308cbb..121a749af9 100644 --- a/gst/rtp/gstrtpL8depay.c +++ b/gst/rtp/gstrtpL8depay.c @@ -186,6 +186,7 @@ gst_rtp_L8_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps) GST_STR_NULL (channel_order), channels)); /* create default NONE layout */ gst_rtp_channels_create_default (channels, info->position); + info->flags |= GST_AUDIO_FLAG_UNPOSITIONED; } srccaps = gst_audio_info_to_caps (info); diff --git a/gst/rtp/gstrtpac3pay.c b/gst/rtp/gstrtpac3pay.c index 8c5c2350db..1feccedf4a 100644 --- a/gst/rtp/gstrtpac3pay.c +++ b/gst/rtp/gstrtpac3pay.c @@ -274,7 +274,9 @@ gst_rtp_ac3_pay_flush (GstRtpAC3Pay * rtpac3pay) payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0); /* create buffer to hold the payload */ - outbuf = gst_rtp_buffer_new_allocate (2, 0, 0); + outbuf = + gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD + (rtpac3pay), 2, 0, 0); if (FT == 0) { /* check if it all fits */ diff --git a/gst/rtp/gstrtpamrpay.c b/gst/rtp/gstrtpamrpay.c index 7921d97132..828a7189f9 100644 --- a/gst/rtp/gstrtpamrpay.c +++ b/gst/rtp/gstrtpamrpay.c @@ -312,7 +312,9 @@ gst_rtp_amr_pay_handle_buffer (GstRTPBasePayload * basepayload, goto too_big; /* now alloc output buffer */ - outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0); + outbuf = + gst_rtp_base_payload_allocate_output_buffer (basepayload, payload_len, 0, + 0); gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); diff --git a/gst/rtp/gstrtpceltpay.c b/gst/rtp/gstrtpceltpay.c index c4988977ed..a29d23b170 100644 --- a/gst/rtp/gstrtpceltpay.c +++ b/gst/rtp/gstrtpceltpay.c @@ -332,7 +332,9 @@ gst_rtp_celt_pay_flush_queued (GstRtpCELTPay * rtpceltpay) payload_len, GST_TIME_ARGS (rtpceltpay->qduration)); /* get a big enough packet for the sizes + payloads */ - outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0); + outbuf = + gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD + (rtpceltpay), payload_len, 0, 0); GST_BUFFER_DURATION (outbuf) = duration; diff --git a/gst/rtp/gstrtpdvpay.c b/gst/rtp/gstrtpdvpay.c index 440880638d..540d685662 100644 --- a/gst/rtp/gstrtpdvpay.c +++ b/gst/rtp/gstrtpdvpay.c @@ -132,6 +132,8 @@ gst_rtp_dv_pay_class_init (GstRTPDVPayClass * klass) gstrtpbasepayload_class->set_caps = gst_rtp_dv_pay_setcaps; gstrtpbasepayload_class->handle_buffer = gst_rtp_dv_pay_handle_buffer; + + gst_type_mark_as_plugin_api (GST_TYPE_DV_PAY_MODE, 0); } static void diff --git a/gst/rtp/gstrtpg723pay.c b/gst/rtp/gstrtpg723pay.c index cb6dff52a1..18e294a3f7 100644 --- a/gst/rtp/gstrtpg723pay.c +++ b/gst/rtp/gstrtpg723pay.c @@ -144,8 +144,9 @@ gst_rtp_g723_pay_flush (GstRTPG723Pay * pay) avail = gst_adapter_available (pay->adapter); - outbuf = gst_rtp_buffer_new_allocate (0, 0, 0); - + outbuf = + gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD (pay), + 0, 0, 0); gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); GST_BUFFER_PTS (outbuf) = pay->timestamp; diff --git a/gst/rtp/gstrtpg729pay.c b/gst/rtp/gstrtpg729pay.c index 378fa64e09..78097805e3 100644 --- a/gst/rtp/gstrtpg729pay.c +++ b/gst/rtp/gstrtpg729pay.c @@ -167,7 +167,9 @@ gst_rtp_g729_pay_push (GstRTPG729Pay * rtpg729pay, GstBuffer * buf) payload_len, GST_TIME_ARGS (rtpg729pay->next_ts)); /* create buffer to hold the payload */ - outbuf = gst_rtp_buffer_new_allocate (0, 0, 0); + outbuf = + gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD + (rtpg729pay), 0, 0, 0); gst_rtp_buffer_map (outbuf, GST_MAP_READWRITE, &rtp); diff --git a/gst/rtp/gstrtpgsmpay.c b/gst/rtp/gstrtpgsmpay.c index aa239a8b06..25fa0fa0a2 100644 --- a/gst/rtp/gstrtpgsmpay.c +++ b/gst/rtp/gstrtpgsmpay.c @@ -145,7 +145,7 @@ gst_rtp_gsm_pay_handle_buffer (GstRTPBasePayload * basepayload, if (payload_len > GST_RTP_BASE_PAYLOAD_MTU (rtpgsmpay)) goto too_big; - outbuf = gst_rtp_buffer_new_allocate (0, 0, 0); + outbuf = gst_rtp_base_payload_allocate_output_buffer (basepayload, 0, 0, 0); /* copy timestamp and duration */ GST_BUFFER_PTS (outbuf) = timestamp; diff --git a/gst/rtp/gstrtpgstpay.c b/gst/rtp/gstrtpgstpay.c index a0f42e32e1..15b281bd73 100644 --- a/gst/rtp/gstrtpgstpay.c +++ b/gst/rtp/gstrtpgstpay.c @@ -299,7 +299,9 @@ gst_rtp_gst_pay_create_from_adapter (GstRtpGSTPay * rtpgstpay, payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0); /* create buffer to hold the header */ - outbuf = gst_rtp_buffer_new_allocate (8, 0, 0); + outbuf = + gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD + (rtpgstpay), 8, 0, 0); gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); payload = gst_rtp_buffer_get_payload (&rtp); diff --git a/gst/rtp/gstrtph263ppay.c b/gst/rtp/gstrtph263ppay.c index 9b3ebb522c..3b1ee0512e 100644 --- a/gst/rtp/gstrtph263ppay.c +++ b/gst/rtp/gstrtph263ppay.c @@ -151,6 +151,8 @@ gst_rtp_h263p_pay_class_init (GstRtpH263PPayClass * klass) GST_DEBUG_CATEGORY_INIT (rtph263ppay_debug, "rtph263ppay", 0, "rtph263ppay (RFC 4629)"); + + gst_type_mark_as_plugin_api (GST_TYPE_FRAGMENTATION_MODE, 0); } static void diff --git a/gst/rtp/gstrtph264depay.c b/gst/rtp/gstrtph264depay.c index 854cb7cf4c..cc92c9a149 100644 --- a/gst/rtp/gstrtph264depay.c +++ b/gst/rtp/gstrtph264depay.c @@ -1035,6 +1035,7 @@ gst_rtp_h264_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) gst_adapter_clear (rtph264depay->adapter); rtph264depay->wait_start = TRUE; rtph264depay->current_fu_type = 0; + rtph264depay->last_fu_seqnum = 0; } { @@ -1194,6 +1195,7 @@ gst_rtp_h264_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) rtph264depay->current_fu_type = nal_unit_type; rtph264depay->fu_timestamp = timestamp; + rtph264depay->last_fu_seqnum = gst_rtp_buffer_get_seq (rtp); rtph264depay->wait_start = FALSE; @@ -1221,6 +1223,25 @@ gst_rtp_h264_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) /* and assemble in the adapter */ gst_adapter_push (rtph264depay->adapter, outbuf); } else { + if (rtph264depay->current_fu_type == 0) { + /* previous FU packet missing start bit? */ + GST_WARNING_OBJECT (rtph264depay, "missing FU start bit on an " + "earlier packet. Dropping."); + gst_adapter_clear (rtph264depay->adapter); + return NULL; + } + if (gst_rtp_buffer_compare_seqnum (rtph264depay->last_fu_seqnum, + gst_rtp_buffer_get_seq (rtp)) != 1) { + /* jump in sequence numbers within an FU is cause for discarding */ + GST_WARNING_OBJECT (rtph264depay, "Jump in sequence numbers from " + "%u to %u within Fragmentation Unit. Data was lost, dropping " + "stored.", rtph264depay->last_fu_seqnum, + gst_rtp_buffer_get_seq (rtp)); + gst_adapter_clear (rtph264depay->adapter); + return NULL; + } + rtph264depay->last_fu_seqnum = gst_rtp_buffer_get_seq (rtp); + /* strip off FU indicator and FU header bytes */ payload += 2; payload_len -= 2; diff --git a/gst/rtp/gstrtph264depay.h b/gst/rtp/gstrtph264depay.h index ba413125a6..2cb2167a4f 100644 --- a/gst/rtp/gstrtph264depay.h +++ b/gst/rtp/gstrtph264depay.h @@ -59,6 +59,7 @@ struct _GstRtpH264Depay /* Work around broken payloaders wrt. FU-A & FU-B */ guint8 current_fu_type; + guint16 last_fu_seqnum; GstClockTime fu_timestamp; gboolean fu_marker; diff --git a/gst/rtp/gstrtph264pay.c b/gst/rtp/gstrtph264pay.c index b5d3e6ab71..67353283eb 100644 --- a/gst/rtp/gstrtph264pay.c +++ b/gst/rtp/gstrtph264pay.c @@ -33,6 +33,7 @@ #include "gstrtph264pay.h" #include "gstrtputils.h" +#include "gstbuffermemory.h" #define IDR_TYPE_ID 5 @@ -98,7 +99,7 @@ GST_STATIC_PAD_TEMPLATE ("src", #define DEFAULT_SPROP_PARAMETER_SETS NULL #define DEFAULT_CONFIG_INTERVAL 0 -#define DEFAULT_AGGREGATE_MODE GST_RTP_H264_AGGREGATE_ZERO_LATENCY +#define DEFAULT_AGGREGATE_MODE GST_RTP_H264_AGGREGATE_NONE enum { @@ -166,12 +167,25 @@ gst_rtp_h264_pay_class_init (GstRtpH264PayClass * klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) ); + /** + * GstRtpH264Pay:aggregate-mode + * + * Bundle suitable SPS/PPS NAL units into STAP-A aggregate packets. + * + * This can potentially reduce RTP packetization overhead but not all + * RTP implementations handle it correctly. + * + * For best compatibility, it is recommended to set this to "none" (the + * default) for RTSP and for WebRTC to "zero-latency". + * + * Since: 1.18 + */ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_AGGREGATE_MODE, g_param_spec_enum ("aggregate-mode", "Attempt to use aggregate packets", "Bundle suitable SPS/PPS NAL units into STAP-A " - "aggregate packets. ", + "aggregate packets", GST_TYPE_RTP_H264_AGGREGATE_MODE, DEFAULT_AGGREGATE_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) ); @@ -198,6 +212,8 @@ gst_rtp_h264_pay_class_init (GstRtpH264PayClass * klass) GST_DEBUG_CATEGORY_INIT (rtph264pay_debug, "rtph264pay", 0, "H264 RTP Payloader"); + + gst_type_mark_as_plugin_api (GST_TYPE_RTP_H264_AGGREGATE_MODE, 0); } static void @@ -1342,7 +1358,6 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload, GstFlowReturn ret; gsize size; guint nal_len, i; - GstMapInfo map; const guint8 *data; GstClockTime dts, pts; GArray *nal_queue; @@ -1364,16 +1379,6 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload, /* In AVC mode, there is no adapter, so nothing to drain */ if (draining) return GST_FLOW_OK; - gst_buffer_map (buffer, &map, GST_MAP_READ); - data = map.data; - size = map.size; - pts = GST_BUFFER_PTS (buffer); - dts = GST_BUFFER_DTS (buffer); - rtph264pay->delta_unit = GST_BUFFER_FLAG_IS_SET (buffer, - GST_BUFFER_FLAG_DELTA_UNIT); - rtph264pay->discont = GST_BUFFER_IS_DISCONT (buffer); - marker = GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_MARKER); - GST_DEBUG_OBJECT (basepayload, "got %" G_GSIZE_FORMAT " bytes", size); } else { if (buffer) { if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) { @@ -1417,29 +1422,43 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload, /* now loop over all NAL units and put them in a packet */ if (avc) { + GstBufferMemoryMap memory; + gsize remaining_buffer_size; guint nal_length_size; gsize offset = 0; + gst_buffer_memory_map (buffer, &memory); + remaining_buffer_size = gst_buffer_get_size (buffer); + + pts = GST_BUFFER_PTS (buffer); + dts = GST_BUFFER_DTS (buffer); + rtph264pay->delta_unit = GST_BUFFER_FLAG_IS_SET (buffer, + GST_BUFFER_FLAG_DELTA_UNIT); + rtph264pay->discont = GST_BUFFER_IS_DISCONT (buffer); + marker = GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_MARKER); + GST_DEBUG_OBJECT (basepayload, "got %" G_GSIZE_FORMAT " bytes", + remaining_buffer_size); + nal_length_size = rtph264pay->nal_length_size; - while (size > nal_length_size) { + while (remaining_buffer_size > nal_length_size) { gint i; gboolean end_of_au = FALSE; nal_len = 0; for (i = 0; i < nal_length_size; i++) { - nal_len = ((nal_len << 8) + data[i]); + nal_len = (nal_len << 8) + *memory.data; + if (!gst_buffer_memory_advance_bytes (&memory, 1)) + break; } - /* skip the length bytes, make sure we don't run past the buffer size */ - data += nal_length_size; offset += nal_length_size; - size -= nal_length_size; + remaining_buffer_size -= nal_length_size; - if (size >= nal_len) { + if (remaining_buffer_size >= nal_len) { GST_DEBUG_OBJECT (basepayload, "got NAL of size %u", nal_len); } else { - nal_len = size; + nal_len = remaining_buffer_size; GST_DEBUG_OBJECT (basepayload, "got incomplete NAL of size %u", nal_len); } @@ -1447,7 +1466,7 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload, /* If we're at the end of the buffer, then we're at the end of the * access unit */ - if (size - nal_len <= nal_length_size) { + if (remaining_buffer_size - nal_len <= nal_length_size) { if (rtph264pay->alignment == GST_H264_ALIGNMENT_AU || marker) end_of_au = TRUE; } @@ -1469,10 +1488,19 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload, if (ret != GST_FLOW_OK) break; - data += nal_len; + /* Skip current nal. If it is split over multiple GstMemory + * advance_bytes () will switch to the correct GstMemory. The payloader + * does not access those bytes directly but uses gst_buffer_copy_region () + * to create a sub-buffer referencing the nal instead */ + if (!gst_buffer_memory_advance_bytes (&memory, nal_len)) + break; + offset += nal_len; - size -= nal_len; + remaining_buffer_size -= nal_len; } + + gst_buffer_memory_unmap (&memory); + gst_buffer_unref (buffer); } else { guint next; gboolean update = FALSE; @@ -1638,10 +1666,7 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload, done: - if (avc) { - gst_buffer_unmap (buffer, &map); - gst_buffer_unref (buffer); - } else { + if (!avc) { gst_adapter_unmap (rtph264pay->adapter); } diff --git a/gst/rtp/gstrtph265depay.c b/gst/rtp/gstrtph265depay.c index 384c6bf65f..46553f0e1d 100644 --- a/gst/rtp/gstrtph265depay.c +++ b/gst/rtp/gstrtph265depay.c @@ -384,7 +384,7 @@ gst_rtp_h265_depay_set_output_caps (GstRtpH265Depay * rtph265depay, static gboolean gst_rtp_h265_set_src_caps (GstRtpH265Depay * rtph265depay) { - gboolean res, update_caps; + gboolean res; GstCaps *old_caps; GstCaps *srccaps; GstPad *srcpad; @@ -594,36 +594,9 @@ gst_rtp_h265_set_src_caps (GstRtpH265Depay * rtph265depay) } srcpad = GST_RTP_BASE_DEPAYLOAD_SRCPAD (rtph265depay); - old_caps = gst_pad_get_current_caps (srcpad); - if (old_caps != NULL) { - /* Only update the caps if they are not equal. For - * AVC we don't update caps if only the codec_data - * changes. This is the same behaviour as in h264parse - * and gstrtph264depay - */ - if (rtph265depay->byte_stream) { - update_caps = !gst_caps_is_equal (srccaps, old_caps); - } else { - GstCaps *tmp_caps = gst_caps_copy (srccaps); - GstStructure *old_s, *tmp_s; - - old_s = gst_caps_get_structure (old_caps, 0); - tmp_s = gst_caps_get_structure (tmp_caps, 0); - if (gst_structure_has_field (old_s, "codec_data")) - gst_structure_set_value (tmp_s, "codec_data", - gst_structure_get_value (old_s, "codec_data")); - - update_caps = !gst_caps_is_equal (old_caps, tmp_caps); - gst_caps_unref (tmp_caps); - } - gst_caps_unref (old_caps); - } else { - update_caps = TRUE; - } - - if (update_caps) { + if (old_caps == NULL || !gst_caps_is_equal (srccaps, old_caps)) { res = gst_rtp_h265_depay_set_output_caps (rtph265depay, srccaps); } else { res = TRUE; @@ -1259,6 +1232,7 @@ gst_rtp_h265_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) gst_adapter_clear (rtph265depay->adapter); rtph265depay->wait_start = TRUE; rtph265depay->current_fu_type = 0; + rtph265depay->last_fu_seqnum = 0; } { @@ -1456,6 +1430,7 @@ gst_rtp_h265_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) rtph265depay->current_fu_type = nal_unit_type; rtph265depay->fu_timestamp = timestamp; + rtph265depay->last_fu_seqnum = gst_rtp_buffer_get_seq (rtp); rtph265depay->wait_start = FALSE; @@ -1493,6 +1468,24 @@ gst_rtp_h265_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) /* and assemble in the adapter */ gst_adapter_push (rtph265depay->adapter, outbuf); } else { + if (rtph265depay->current_fu_type == 0) { + /* previous FU packet missing start bit? */ + GST_WARNING_OBJECT (rtph265depay, "missing FU start bit on an " + "earlier packet. Dropping."); + gst_adapter_clear (rtph265depay->adapter); + return NULL; + } + if (gst_rtp_buffer_compare_seqnum (rtph265depay->last_fu_seqnum, + gst_rtp_buffer_get_seq (rtp)) != 1) { + /* jump in sequence numbers within an FU is cause for discarding */ + GST_WARNING_OBJECT (rtph265depay, "Jump in sequence numbers from " + "%u to %u within Fragmentation Unit. Data was lost, dropping " + "stored.", rtph265depay->last_fu_seqnum, + gst_rtp_buffer_get_seq (rtp)); + gst_adapter_clear (rtph265depay->adapter); + return NULL; + } + rtph265depay->last_fu_seqnum = gst_rtp_buffer_get_seq (rtp); GST_DEBUG_OBJECT (rtph265depay, "Following part of Fragmentation Unit"); diff --git a/gst/rtp/gstrtph265depay.h b/gst/rtp/gstrtph265depay.h index cf1769454a..b3b55ee7b2 100644 --- a/gst/rtp/gstrtph265depay.h +++ b/gst/rtp/gstrtph265depay.h @@ -73,6 +73,7 @@ struct _GstRtpH265Depay /* Work around broken payloaders wrt. Fragmentation Units */ guint8 current_fu_type; + guint16 last_fu_seqnum; GstClockTime fu_timestamp; gboolean fu_marker; diff --git a/gst/rtp/gstrtph265pay.c b/gst/rtp/gstrtph265pay.c index d5285f0510..3793ad613c 100644 --- a/gst/rtp/gstrtph265pay.c +++ b/gst/rtp/gstrtph265pay.c @@ -34,6 +34,7 @@ #include "gstrtph265pay.h" #include "gstrtputils.h" +#include "gstbuffermemory.h" #define AP_TYPE_ID 48 #define FU_TYPE_ID 49 @@ -132,7 +133,7 @@ GST_STATIC_PAD_TEMPLATE ("src", ); #define DEFAULT_CONFIG_INTERVAL 0 -#define DEFAULT_AGGREGATE_MODE GST_RTP_H265_AGGREGATE_ZERO_LATENCY +#define DEFAULT_AGGREGATE_MODE GST_RTP_H265_AGGREGATE_NONE enum { @@ -191,6 +192,19 @@ gst_rtp_h265_pay_class_init (GstRtpH265PayClass * klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) ); + /** + * GstRtpH265Pay:aggregate-mode + * + * Bundle suitable SPS/PPS NAL units into STAP-A aggregate packets. + * + * This can potentially reduce RTP packetization overhead but not all + * RTP implementations handle it correctly. + * + * For best compatibility, it is recommended to set this to "none" (the + * default) for RTSP and for WebRTC to "zero-latency". + * + * Since: 1.18 + */ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_AGGREGATE_MODE, g_param_spec_enum ("aggregate-mode", @@ -222,6 +236,8 @@ gst_rtp_h265_pay_class_init (GstRtpH265PayClass * klass) GST_DEBUG_CATEGORY_INIT (rtph265pay_debug, "rtph265pay", 0, "H265 RTP Payloader"); + + gst_type_mark_as_plugin_api (GST_TYPE_RTP_H265_AGGREGATE_MODE, 0); } static void @@ -1424,7 +1440,6 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload, GstFlowReturn ret; gsize size; guint nal_len, i; - GstMapInfo map; const guint8 *data; GstClockTime dts, pts; GArray *nal_queue; @@ -1446,13 +1461,6 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload, /* In hevc mode, there is no adapter, so nothing to drain */ if (draining) return GST_FLOW_OK; - gst_buffer_map (buffer, &map, GST_MAP_READ); - data = map.data; - size = map.size; - pts = GST_BUFFER_PTS (buffer); - dts = GST_BUFFER_DTS (buffer); - marker = GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_MARKER); - GST_DEBUG_OBJECT (basepayload, "got %" G_GSIZE_FORMAT " bytes", size); } else { if (buffer) { if (gst_adapter_available (rtph265pay->adapter) == 0) @@ -1478,6 +1486,8 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload, /* now loop over all NAL units and put them in a packet */ if (hevc) { + GstBufferMemoryMap memory; + gsize remaining_buffer_size; guint nal_length_size; gsize offset = 0; GPtrArray *paybufs; @@ -1485,23 +1495,32 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload, paybufs = g_ptr_array_new (); nal_length_size = rtph265pay->nal_length_size; - while (size > nal_length_size) { + gst_buffer_memory_map (buffer, &memory); + remaining_buffer_size = gst_buffer_get_size (buffer); + + pts = GST_BUFFER_PTS (buffer); + dts = GST_BUFFER_DTS (buffer); + marker = GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_MARKER); + GST_DEBUG_OBJECT (basepayload, "got %" G_GSIZE_FORMAT " bytes", + remaining_buffer_size); + + while (remaining_buffer_size > nal_length_size) { gint i; nal_len = 0; for (i = 0; i < nal_length_size; i++) { - nal_len = ((nal_len << 8) + data[i]); + nal_len = (nal_len << 8) + *memory.data; + if (!gst_buffer_memory_advance_bytes (&memory, 1)) + break; } - /* skip the length bytes, make sure we don't run past the buffer size */ - data += nal_length_size; offset += nal_length_size; - size -= nal_length_size; + remaining_buffer_size -= nal_length_size; - if (size >= nal_len) { + if (remaining_buffer_size >= nal_len) { GST_DEBUG_OBJECT (basepayload, "got NAL of size %u", nal_len); } else { - nal_len = size; + nal_len = remaining_buffer_size; GST_DEBUG_OBJECT (basepayload, "got incomplete NAL of size %u", nal_len); } @@ -1514,7 +1533,7 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload, * access unit */ GST_BUFFER_FLAG_UNSET (paybuf, GST_BUFFER_FLAG_MARKER); - if (size - nal_len <= nal_length_size) { + if (remaining_buffer_size - nal_len <= nal_length_size) { if (rtph265pay->alignment == GST_H265_ALIGNMENT_AU || marker) GST_BUFFER_FLAG_SET (paybuf, GST_BUFFER_FLAG_MARKER); } @@ -1525,11 +1544,19 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload, discont = FALSE; } - data += nal_len; + /* Skip current nal. If it is split over multiple GstMemory + * advance_bytes () will switch to the correct GstMemory. The payloader + * does not access those bytes directly but uses gst_buffer_copy_region () + * to create a sub-buffer referencing the nal instead */ + if (!gst_buffer_memory_advance_bytes (&memory, nal_len)) + break; offset += nal_len; - size -= nal_len; + remaining_buffer_size -= nal_len; } ret = gst_rtp_h265_pay_payload_nal (basepayload, paybufs, dts, pts); + + gst_buffer_memory_unmap (&memory); + gst_buffer_unref (buffer); } else { guint next; gboolean update = FALSE; @@ -1658,10 +1685,7 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload, } done: - if (hevc) { - gst_buffer_unmap (buffer, &map); - gst_buffer_unref (buffer); - } else { + if (!hevc) { gst_adapter_unmap (rtph265pay->adapter); } diff --git a/gst/rtp/gstrtpilbcdepay.c b/gst/rtp/gstrtpilbcdepay.c index 26de4837d5..0b020afd79 100644 --- a/gst/rtp/gstrtpilbcdepay.c +++ b/gst/rtp/gstrtpilbcdepay.c @@ -124,6 +124,8 @@ gst_rtp_ilbc_depay_class_init (GstRTPiLBCDepayClass * klass) gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_ilbc_depay_process; gstrtpbasedepayload_class->set_caps = gst_rtp_ilbc_depay_setcaps; + + gst_type_mark_as_plugin_api (GST_TYPE_ILBC_MODE, 0); } static void diff --git a/gst/rtp/gstrtpjpegpay.c b/gst/rtp/gstrtpjpegpay.c index 1b5aecffd0..7ba1f51eb6 100644 --- a/gst/rtp/gstrtpjpegpay.c +++ b/gst/rtp/gstrtpjpegpay.c @@ -43,6 +43,7 @@ #include "gstrtpjpegpay.h" #include "gstrtputils.h" +#include "gstbuffermemory.h" static GstStaticPadTemplate gst_rtp_jpeg_pay_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", @@ -383,45 +384,76 @@ gst_rtp_jpeg_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps) } } +/* + * get uint16 value from current position in mapped memory. + * the memory offset will be increased with 2. + */ static guint -gst_rtp_jpeg_pay_header_size (const guint8 * data, guint offset) +parse_mem_inc_offset_guint16 (GstBufferMemoryMap * memory) { - return data[offset] << 8 | data[offset + 1]; + guint data; + + g_return_val_if_fail (memory->total_size > (memory->offset + 1), 0); + + data = ((guint) * memory->data) << 8; + gst_buffer_memory_advance_bytes (memory, 1); + data = data | (*memory->data); + gst_buffer_memory_advance_bytes (memory, 1); + + return data; } +/* + * get uint8 value from current position in mapped memory. + * the memory offset will be increased with 1. + */ static guint -gst_rtp_jpeg_pay_read_quant_table (const guint8 * data, guint size, - guint offset, RtpQuantTable tables[]) +parse_mem_inc_offset_guint8 (GstBufferMemoryMap * memory) +{ + guint data; + + g_return_val_if_fail (memory->total_size > memory->offset, 0); + + data = (*memory->data); + gst_buffer_memory_advance_bytes (memory, 1); + + return data; +} + +static void +gst_rtp_jpeg_pay_read_quant_table (GstBufferMemoryMap * memory, + RtpQuantTable tables[]) { guint quant_size, tab_size; guint8 prec; guint8 id; - if (offset + 2 > size) + if (memory->total_size <= (memory->offset + 1)) goto too_small; - quant_size = gst_rtp_jpeg_pay_header_size (data, offset); + quant_size = parse_mem_inc_offset_guint16 (memory); if (quant_size < 2) goto small_quant_size; /* clamp to available data */ - if (offset + quant_size > size) - quant_size = size - offset; + if (memory->offset + quant_size > memory->total_size) + quant_size = memory->total_size - memory->offset; - offset += 2; quant_size -= 2; while (quant_size > 0) { + guint8 data; /* not enough to read the id */ - if (offset + 1 > size) + if (memory->offset + 1 > memory->total_size) break; - id = data[offset] & 0x0f; + data = parse_mem_inc_offset_guint8 (memory); + id = data & 0x0f; if (id == 15) /* invalid id received - corrupt data */ goto invalid_id; - prec = (data[offset] & 0xf0) >> 4; + prec = (data & 0xf0) >> 4; if (prec) tab_size = 128; else @@ -434,25 +466,26 @@ gst_rtp_jpeg_pay_read_quant_table (const guint8 * data, guint size, GST_LOG ("read quant table %d, tab_size %d, prec %02x", id, tab_size, prec); tables[id].size = tab_size; - tables[id].data = &data[offset + 1]; + tables[id].data = memory->data; - tab_size += 1; - quant_size -= tab_size; - offset += tab_size; + quant_size -= (tab_size + 1); + if (!gst_buffer_memory_advance_bytes (memory, tab_size)) { + goto too_small; + } } done: - return offset + quant_size; + return; /* ERRORS */ too_small: { GST_WARNING ("not enough data"); - return size; + return; } small_quant_size: { GST_WARNING ("quant_size too small (%u < 2)", quant_size); - return size; + return; } invalid_id: { @@ -468,38 +501,31 @@ gst_rtp_jpeg_pay_read_quant_table (const guint8 * data, guint size, } static gboolean -gst_rtp_jpeg_pay_read_sof (GstRtpJPEGPay * pay, const guint8 * data, - guint size, guint * offset, CompInfo info[], RtpQuantTable tables[], - gulong tables_elements) +gst_rtp_jpeg_pay_read_sof (GstRtpJPEGPay * pay, GstBufferMemoryMap * memory, + CompInfo info[], RtpQuantTable tables[], gulong tables_elements) { guint sof_size, off; guint width, height, infolen; CompInfo elem; gint i, j; - off = *offset; + off = memory->offset; /* we need at least 17 bytes for the SOF */ - if (off + 17 > size) + if (off + 17 > memory->total_size) goto wrong_size; - sof_size = gst_rtp_jpeg_pay_header_size (data, off); + sof_size = parse_mem_inc_offset_guint16 (memory); if (sof_size < 17) goto wrong_length; - *offset += sof_size; - - /* skip size */ - off += 2; - /* precision should be 8 */ - if (data[off++] != 8) + if (parse_mem_inc_offset_guint8 (memory) != 8) goto bad_precision; /* read dimensions */ - height = data[off] << 8 | data[off + 1]; - width = data[off + 2] << 8 | data[off + 3]; - off += 4; + height = parse_mem_inc_offset_guint16 (memory); + width = parse_mem_inc_offset_guint16 (memory); GST_LOG_OBJECT (pay, "got dimensions %ux%u", height, width); @@ -525,14 +551,14 @@ gst_rtp_jpeg_pay_read_sof (GstRtpJPEGPay * pay, const guint8 * data, } /* we only support 3 components */ - if (data[off++] != 3) + if (parse_mem_inc_offset_guint8 (memory) != 3) goto bad_components; infolen = 0; for (i = 0; i < 3; i++) { - elem.id = data[off++]; - elem.samp = data[off++]; - elem.qt = data[off++]; + elem.id = parse_mem_inc_offset_guint8 (memory); + elem.samp = parse_mem_inc_offset_guint8 (memory); + elem.qt = parse_mem_inc_offset_guint8 (memory); GST_LOG_OBJECT (pay, "got comp %d, samp %02x, qt %d", elem.id, elem.samp, elem.qt); /* insertion sort from the last element to the first */ @@ -565,7 +591,8 @@ gst_rtp_jpeg_pay_read_sof (GstRtpJPEGPay * pay, const guint8 * data, wrong_size: { GST_ELEMENT_WARNING (pay, STREAM, FORMAT, - ("Wrong size %u (needed %u).", size, off + 17), (NULL)); + ("Wrong size %u (needed %u).", (guint) memory->total_size, off + 17), + (NULL)); return FALSE; } wrong_length: @@ -600,57 +627,81 @@ gst_rtp_jpeg_pay_read_sof (GstRtpJPEGPay * pay, const guint8 * data, } static gboolean -gst_rtp_jpeg_pay_read_dri (GstRtpJPEGPay * pay, const guint8 * data, - guint size, guint * offset, RtpRestartMarkerHeader * dri) +gst_rtp_jpeg_pay_read_dri (GstRtpJPEGPay * pay, GstBufferMemoryMap * memory, + RtpRestartMarkerHeader * dri) { - guint dri_size, off; - - off = *offset; + guint dri_size, restart_interval; /* we need at least 4 bytes for the DRI */ - if (off + 4 > size) + if (memory->offset + 4 > memory->total_size) goto wrong_size; - dri_size = gst_rtp_jpeg_pay_header_size (data, off); + dri_size = parse_mem_inc_offset_guint16 (memory); if (dri_size < 4) goto wrong_length; - *offset += dri_size; - off += 2; - - dri->restart_interval = g_htons ((data[off] << 8) | (data[off + 1])); + restart_interval = parse_mem_inc_offset_guint16 (memory); + dri->restart_interval = g_htons (restart_interval); dri->restart_count = g_htons (0xFFFF); + if (!gst_buffer_memory_advance_bytes (memory, dri_size - 4)) { + goto wrong_size; + } return dri->restart_interval > 0; wrong_size: { GST_WARNING ("not enough data for DRI"); - *offset = size; return FALSE; } wrong_length: { GST_WARNING ("DRI size too small (%u)", dri_size); - *offset += dri_size; + /* offset got incremented by two when dri_size was parsed. */ + if (dri_size > 2) + gst_buffer_memory_advance_bytes (memory, dri_size - 2); return FALSE; } } +static void +gst_rtp_jpeg_pay_skipping_marker (GstBufferMemoryMap * memory) +{ + guint skip; + + if (G_UNLIKELY (((memory->offset + 1) >= memory->total_size))) { + goto wrong_size; + } + skip = parse_mem_inc_offset_guint16 (memory); + + if (G_UNLIKELY (((skip - 2 + memory->offset) > memory->total_size))) { + goto wrong_size; + } + if (skip > 2) { + gst_buffer_memory_advance_bytes (memory, skip - 2); + } + return; + +wrong_size: + { + GST_WARNING ("not enough data"); + } +} + static RtpJpegMarker -gst_rtp_jpeg_pay_scan_marker (const guint8 * data, guint size, guint * offset) +gst_rtp_jpeg_pay_scan_marker (GstBufferMemoryMap * memory) { - while ((data[(*offset)++] != JPEG_MARKER) && ((*offset) < size)); + guint8 marker = parse_mem_inc_offset_guint8 (memory); + + while (marker != JPEG_MARKER && ((memory->offset) < memory->total_size)) { + marker = parse_mem_inc_offset_guint8 (memory); + } - if (G_UNLIKELY ((*offset) >= size)) { + if (G_UNLIKELY ((memory->offset) >= memory->total_size)) { GST_LOG ("found EOI marker"); return JPEG_MARKER_EOI; } else { - guint8 marker; - - marker = data[*offset]; - GST_LOG ("found 0x%02x marker at offset %u", marker, *offset); - (*offset)++; + marker = parse_mem_inc_offset_guint8 (memory); return marker; } } @@ -670,9 +721,6 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload, RtpQuantTable tables[15] = { {0, NULL}, }; CompInfo info[3] = { {0,}, }; guint quant_data_size; - GstMapInfo map; - guint8 *data; - gsize size; guint mtu, max_payload_size; guint bytes_left; guint jpeg_header_size = 0; @@ -682,19 +730,19 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload, gint i; GstBufferList *list = NULL; gboolean discont; + GstBufferMemoryMap memory; pay = GST_RTP_JPEG_PAY (basepayload); mtu = GST_RTP_BASE_PAYLOAD_MTU (pay); - gst_buffer_map (buffer, &map, GST_MAP_READ); - data = map.data; - size = map.size; + gst_buffer_memory_map (buffer, &memory); + timestamp = GST_BUFFER_PTS (buffer); - offset = 0; discont = GST_BUFFER_IS_DISCONT (buffer); GST_LOG_OBJECT (pay, "got buffer size %" G_GSIZE_FORMAT - " , timestamp %" GST_TIME_FORMAT, size, GST_TIME_ARGS (timestamp)); + " , timestamp %" GST_TIME_FORMAT, memory.total_size, + GST_TIME_ARGS (timestamp)); /* parse the jpeg header for 'start of scan' and read quant tables if needed */ sos_found = FALSE; @@ -702,33 +750,36 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload, sof_found = FALSE; dri_found = FALSE; - while (!sos_found && (offset < size)) { + while (!sos_found && (memory.offset < memory.total_size)) { gint marker; - GST_LOG_OBJECT (pay, "checking from offset %u", offset); - switch ((marker = gst_rtp_jpeg_pay_scan_marker (data, size, &offset))) { + GST_LOG_OBJECT (pay, "checking from offset %u", memory.offset); + marker = gst_rtp_jpeg_pay_scan_marker (&memory); + switch (marker) { case JPEG_MARKER_JFIF: case JPEG_MARKER_CMT: case JPEG_MARKER_DHT: case JPEG_MARKER_H264: GST_LOG_OBJECT (pay, "skipping marker"); - offset += gst_rtp_jpeg_pay_header_size (data, offset); + gst_rtp_jpeg_pay_skipping_marker (&memory); break; case JPEG_MARKER_SOF: - if (!gst_rtp_jpeg_pay_read_sof (pay, data, size, &offset, info, tables, + if (!gst_rtp_jpeg_pay_read_sof (pay, &memory, info, tables, G_N_ELEMENTS (tables))) goto invalid_format; sof_found = TRUE; break; case JPEG_MARKER_DQT: GST_LOG ("DQT found"); - offset = gst_rtp_jpeg_pay_read_quant_table (data, size, offset, tables); + gst_rtp_jpeg_pay_read_quant_table (&memory, tables); dqt_found = TRUE; break; case JPEG_MARKER_SOS: sos_found = TRUE; GST_LOG_OBJECT (pay, "SOS found"); - jpeg_header_size = offset + gst_rtp_jpeg_pay_header_size (data, offset); + jpeg_header_size = memory.offset; + /* Do not re-combine into single statement with previous line! */ + jpeg_header_size += parse_mem_inc_offset_guint16 (&memory); break; case JPEG_MARKER_EOI: GST_WARNING_OBJECT (pay, "EOI reached before SOS!"); @@ -738,8 +789,7 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload, break; case JPEG_MARKER_DRI: GST_LOG_OBJECT (pay, "DRI found"); - if (gst_rtp_jpeg_pay_read_dri (pay, data, size, &offset, - &restart_marker_header)) + if (gst_rtp_jpeg_pay_read_dri (pay, &memory, &restart_marker_header)) dri_found = TRUE; break; default: @@ -747,8 +797,9 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload, (marker >= JPEG_MARKER_JPG0 && marker <= JPEG_MARKER_JPG13) || (marker >= JPEG_MARKER_APP0 && marker <= JPEG_MARKER_APP15)) { GST_LOG_OBJECT (pay, "skipping marker"); - offset += gst_rtp_jpeg_pay_header_size (data, offset); + gst_rtp_jpeg_pay_skipping_marker (&memory); } else { + /* no need to do anything, gst_rtp_jpeg_pay_scan_marker will go on */ GST_FIXME_OBJECT (pay, "unhandled marker 0x%02x", marker); } break; @@ -765,8 +816,6 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload, GST_LOG_OBJECT (pay, "header size %u", jpeg_header_size); - size -= jpeg_header_size; - data += jpeg_header_size; offset = 0; if (dri_found) @@ -778,7 +827,6 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload, jpeg_header.q = pay->quant; jpeg_header.width = pay->width; jpeg_header.height = pay->height; - /* collect the quant headers sizes */ quant_header.mbz = 0; quant_header.precision = 0; @@ -809,7 +857,9 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload, GST_LOG_OBJECT (pay, "quant_data size %u", quant_data_size); - bytes_left = sizeof (jpeg_header) + quant_data_size + size; + bytes_left = + sizeof (jpeg_header) + quant_data_size + memory.total_size - + jpeg_header_size; if (dri_found) bytes_left += sizeof (restart_marker_header); @@ -912,14 +962,12 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload, bytes_left -= payload_size; offset += payload_size; - data += payload_size; } while (!frame_done); - /* push the whole buffer list at once */ ret = gst_rtp_base_payload_push_list (basepayload, list); - gst_buffer_unmap (buffer, &map); + gst_buffer_memory_unmap (&memory); gst_buffer_unref (buffer); return ret; @@ -928,28 +976,28 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload, unsupported_jpeg: { GST_ELEMENT_WARNING (pay, STREAM, FORMAT, ("Unsupported JPEG"), (NULL)); - gst_buffer_unmap (buffer, &map); + gst_buffer_memory_unmap (&memory); gst_buffer_unref (buffer); return GST_FLOW_OK; } no_dimension: { GST_ELEMENT_WARNING (pay, STREAM, FORMAT, ("No size given"), (NULL)); - gst_buffer_unmap (buffer, &map); + gst_buffer_memory_unmap (&memory); gst_buffer_unref (buffer); return GST_FLOW_OK; } invalid_format: { /* error was posted */ - gst_buffer_unmap (buffer, &map); + gst_buffer_memory_unmap (&memory); gst_buffer_unref (buffer); return GST_FLOW_OK; } invalid_quant: { GST_ELEMENT_WARNING (pay, STREAM, FORMAT, ("Invalid quant tables"), (NULL)); - gst_buffer_unmap (buffer, &map); + gst_buffer_memory_unmap (&memory); gst_buffer_unref (buffer); return GST_FLOW_OK; } diff --git a/gst/rtp/gstrtpmp2tpay.c b/gst/rtp/gstrtpmp2tpay.c index 12f948ed8b..8dac50b9a9 100644 --- a/gst/rtp/gstrtpmp2tpay.c +++ b/gst/rtp/gstrtpmp2tpay.c @@ -152,7 +152,9 @@ gst_rtp_mp2t_pay_flush (GstRTPMP2TPay * rtpmp2tpay) break; /* create buffer to hold the payload */ - outbuf = gst_rtp_buffer_new_allocate (0, 0, 0); + outbuf = + gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD + (rtpmp2tpay), 0, 0, 0); /* get payload */ paybuf = gst_adapter_take_buffer_fast (rtpmp2tpay->adapter, payload_len); diff --git a/gst/rtp/gstrtpmp4apay.c b/gst/rtp/gstrtpmp4apay.c index 2f01b21b59..ab1eeb55a3 100644 --- a/gst/rtp/gstrtpmp4apay.c +++ b/gst/rtp/gstrtpmp4apay.c @@ -408,7 +408,8 @@ gst_rtp_mp4a_pay_handle_buffer (GstRTPBasePayload * basepayload, packet_len, payload_len); /* create buffer to hold the payload. */ - outbuf = gst_rtp_buffer_new_allocate (header_len, 0, 0); + outbuf = gst_rtp_base_payload_allocate_output_buffer (basepayload, + header_len, 0, 0); /* copy payload */ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); diff --git a/gst/rtp/gstrtpmp4gdepay.c b/gst/rtp/gstrtpmp4gdepay.c index 5c4b454080..a734be065f 100644 --- a/gst/rtp/gstrtpmp4gdepay.c +++ b/gst/rtp/gstrtpmp4gdepay.c @@ -53,7 +53,7 @@ GST_STATIC_PAD_TEMPLATE ("sink", /* "streamtype = (string) { \"4\", \"5\" }, " Not set by Wowza 4 = video, 5 = audio */ /* "profile-level-id = (string) [1,MAX], " */ /* "config = (string) [1,MAX]" */ - "mode = (string) { \"generic\", \"CELP-cbr\", \"CELP-vbr\", \"AAC-lbr\", \"AAC-hbr\" } " + "mode = (string) { \"generic\", \"CELP-cbr\", \"CELP-vbr\", \"AAC-lbr\", \"AAC-hbr\", \"aac-hbr\" } " /* Optional general parameters */ /* "objecttype = (string) [1,MAX], " */ /* "constantsize = (string) [1,MAX], " *//* constant size of each AU */ diff --git a/gst/rtp/gstrtpmp4gpay.c b/gst/rtp/gstrtpmp4gpay.c index 1f64b24c35..532e2de25c 100644 --- a/gst/rtp/gstrtpmp4gpay.c +++ b/gst/rtp/gstrtpmp4gpay.c @@ -487,8 +487,9 @@ gst_rtp_mp4g_pay_flush (GstRtpMP4GPay * rtpmp4gpay) packet_len, payload_len); /* create buffer to hold the payload, also make room for the 4 header bytes. */ - outbuf = gst_rtp_buffer_new_allocate (4, 0, 0); - + outbuf = + gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD + (rtpmp4gpay), 4, 0, 0); gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); /* copy payload */ diff --git a/gst/rtp/gstrtpmpapay.c b/gst/rtp/gstrtpmpapay.c index 09fa8a8433..62639f7127 100644 --- a/gst/rtp/gstrtpmpapay.c +++ b/gst/rtp/gstrtpmpapay.c @@ -213,7 +213,9 @@ gst_rtp_mpa_pay_flush (GstRtpMPAPay * rtpmpapay) payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0); /* create buffer to hold the payload */ - outbuf = gst_rtp_buffer_new_allocate (4, 0, 0); + outbuf = + gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD + (rtpmpapay), 4, 0, 0); gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); diff --git a/gst/rtp/gstrtpopuspay.c b/gst/rtp/gstrtpopuspay.c index 3831a11147..871a18248e 100644 --- a/gst/rtp/gstrtpopuspay.c +++ b/gst/rtp/gstrtpopuspay.c @@ -39,8 +39,7 @@ static GstStaticPadTemplate gst_rtp_opus_pay_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS - ("audio/x-opus, channels = (int) [1, 2], channel-mapping-family = (int) 0") + GST_STATIC_CAPS ("audio/x-opus, channel-mapping-family = (int) 0") ); static GstStaticPadTemplate gst_rtp_opus_pay_src_template = diff --git a/gst/rtp/gstrtpsbcpay.c b/gst/rtp/gstrtpsbcpay.c index 1d2cbd4095..f2cf849ec8 100644 --- a/gst/rtp/gstrtpsbcpay.c +++ b/gst/rtp/gstrtpsbcpay.c @@ -198,7 +198,9 @@ gst_rtp_sbc_pay_flush_buffers (GstRtpSBCPay * sbcpay) if (payload_length == 0) /* Nothing to send */ return GST_FLOW_OK; - outbuf = gst_rtp_buffer_new_allocate (RTP_SBC_PAYLOAD_HEADER_SIZE, 0, 0); + outbuf = + gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD + (sbcpay), RTP_SBC_PAYLOAD_HEADER_SIZE, 0, 0); /* get payload */ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); diff --git a/gst/rtp/gstrtpspeexpay.c b/gst/rtp/gstrtpspeexpay.c index 7816bd63cd..6f086b0103 100644 --- a/gst/rtp/gstrtpspeexpay.c +++ b/gst/rtp/gstrtpspeexpay.c @@ -279,8 +279,8 @@ gst_rtp_speex_pay_handle_buffer (GstRTPBasePayload * basepayload, duration = GST_BUFFER_DURATION (buffer); /* FIXME, only one SPEEX frame per RTP packet for now */ + outbuf = gst_rtp_base_payload_allocate_output_buffer (basepayload, 0, 0, 0); - outbuf = gst_rtp_buffer_new_allocate (0, 0, 0); /* FIXME, assert for now */ g_assert (gst_buffer_get_size (buffer) <= GST_RTP_BASE_PAYLOAD_MTU (rtpspeexpay)); diff --git a/gst/rtp/gstrtputils.c b/gst/rtp/gstrtputils.c index 044d1b30a1..4d86fb2208 100644 --- a/gst/rtp/gstrtputils.c +++ b/gst/rtp/gstrtputils.c @@ -39,8 +39,9 @@ foreach_metadata_copy (GstBuffer * inbuf, GstMeta ** meta, gpointer user_data) const GstMetaInfo *info = (*meta)->info; const gchar *const *tags = gst_meta_api_type_get_tags (info->api); - if (!tags || (copy_tag != 0 && g_strv_length ((gchar **) tags) == 1 - && gst_meta_api_type_has_tag (info->api, copy_tag))) { + if (info->transform_func && (!tags || !tags[0] || (copy_tag != 0 + && g_strv_length ((gchar **) tags) == 1 + && gst_meta_api_type_has_tag (info->api, copy_tag)))) { GstMetaTransformCopy copy_data = { FALSE, 0, -1 }; GST_DEBUG_OBJECT (element, "copy metadata %s", g_type_name (info->api)); /* simply copy then */ @@ -93,7 +94,8 @@ foreach_metadata_drop (GstBuffer * inbuf, GstMeta ** meta, gpointer user_data) const GstMetaInfo *info = (*meta)->info; const gchar *const *tags = gst_meta_api_type_get_tags (info->api); - if (!tags || (keep_tag != 0 && g_strv_length ((gchar **) tags) == 1 + if (!tags || !tags[0] || (keep_tag != 0 + && g_strv_length ((gchar **) tags) == 1 && gst_meta_api_type_has_tag (info->api, keep_tag))) { GST_DEBUG_OBJECT (element, "keeping metadata %s", g_type_name (info->api)); } else { diff --git a/gst/rtp/gstrtpvorbispay.c b/gst/rtp/gstrtpvorbispay.c index 9220f372c2..8a3c249c0f 100644 --- a/gst/rtp/gstrtpvorbispay.c +++ b/gst/rtp/gstrtpvorbispay.c @@ -270,14 +270,18 @@ static void gst_rtp_vorbis_pay_init_packet (GstRtpVorbisPay * rtpvorbispay, guint8 VDT, GstClockTime timestamp) { + guint len; + GST_LOG_OBJECT (rtpvorbispay, "starting new packet, VDT: %d", VDT); gst_rtp_vorbis_pay_clear_packet (rtpvorbispay); /* new packet allocate max packet size */ - rtpvorbispay->packet = - gst_rtp_buffer_new_allocate_len (GST_RTP_BASE_PAYLOAD_MTU + len = gst_rtp_buffer_calc_payload_len (GST_RTP_BASE_PAYLOAD_MTU (rtpvorbispay), 0, 0); + rtpvorbispay->packet = + gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD + (rtpvorbispay), len, 0, 0); gst_rtp_vorbis_pay_reset_packet (rtpvorbispay, VDT); GST_BUFFER_PTS (rtpvorbispay->packet) = timestamp; diff --git a/gst/rtp/gstrtpvp8pay.c b/gst/rtp/gstrtpvp8pay.c index 17a7788c11..4d6d20f7f6 100644 --- a/gst/rtp/gstrtpvp8pay.c +++ b/gst/rtp/gstrtpvp8pay.c @@ -134,6 +134,8 @@ gst_rtp_vp8_pay_class_init (GstRtpVP8PayClass * gst_rtp_vp8_pay_class) GST_DEBUG_CATEGORY_INIT (gst_rtp_vp8_pay_debug, "rtpvp8pay", 0, "VP8 Video RTP Payloader"); + + gst_type_mark_as_plugin_api (GST_TYPE_RTP_VP8_PAY_PICTURE_ID_MODE, 0); } static void @@ -531,6 +533,7 @@ gst_rtp_vp8_pay_set_caps (GstRTPBasePayload * payload, GstCaps * caps) if (!gst_value_can_intersect (&default_value, value)) encoding_name = "VP8-DRAFT-IETF-01"; } + gst_caps_unref (src_caps); } gst_rtp_base_payload_set_options (payload, "video", TRUE, diff --git a/gst/rtp/gstrtpvp9pay.c b/gst/rtp/gstrtpvp9pay.c index fd1676588f..ce79c64632 100644 --- a/gst/rtp/gstrtpvp9pay.c +++ b/gst/rtp/gstrtpvp9pay.c @@ -135,6 +135,8 @@ gst_rtp_vp9_pay_class_init (GstRtpVP9PayClass * gst_rtp_vp9_pay_class) GST_DEBUG_CATEGORY_INIT (gst_rtp_vp9_pay_debug, "rtpvp9pay", 0, "VP9 Video RTP Payloader"); + + gst_type_mark_as_plugin_api (GST_TYPE_RTP_VP9_PAY_PICTURE_ID_MODE, 0); } static void @@ -546,6 +548,7 @@ gst_rtp_vp9_pay_set_caps (GstRTPBasePayload * payload, GstCaps * caps) if (!gst_value_can_intersect (&default_value, value)) encoding_name = "VP9-DRAFT-IETF-01"; } + gst_caps_unref (src_caps); } gst_rtp_base_payload_set_options (payload, "video", TRUE, diff --git a/gst/rtp/meson.build b/gst/rtp/meson.build index 5bfdc3be7c..d57a195aeb 100644 --- a/gst/rtp/meson.build +++ b/gst/rtp/meson.build @@ -1,6 +1,7 @@ rtp_sources = [ 'dboolhuff.c', 'fnv1hash.c', + 'gstbuffermemory.c', 'gstrtp.c', 'gstrtpchannels.c', 'gstrtpac3depay.c', diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c index 1bb521a6e1..1fb98ffc71 100644 --- a/gst/rtpmanager/gstrtpbin.c +++ b/gst/rtpmanager/gstrtpbin.c @@ -701,6 +701,7 @@ create_session (GstRtpBin * rtpbin, gint id) /* configure SDES items */ GST_OBJECT_LOCK (rtpbin); + g_object_set (demux, "max-streams", rtpbin->max_streams, NULL); g_object_set (session, "sdes", rtpbin->sdes, "rtp-profile", rtpbin->rtp_profile, "rtcp-sync-send-time", rtpbin->rtcp_sync_send_time, NULL); @@ -858,6 +859,7 @@ free_session (GstRtpBinSession * sess, GstRtpBin * bin) g_slist_foreach (sess->elements, (GFunc) remove_bin_element, bin); g_slist_free (sess->elements); + sess->elements = NULL; g_slist_foreach (sess->streams, (GFunc) free_stream, bin); g_slist_free (sess->streams); @@ -1782,26 +1784,19 @@ create_stream (GstRtpBinSession * session, guint32 ssrc) if (g_object_class_find_property (jb_class, "max-dropout-time")) g_object_set (buffer, "max-dropout-time", rtpbin->max_dropout_time, NULL); if (g_object_class_find_property (jb_class, "max-misorder-time")) - g_object_set (buffer, "max-dropout-time", rtpbin->max_misorder_time, NULL); + g_object_set (buffer, "max-misorder-time", rtpbin->max_misorder_time, NULL); if (g_object_class_find_property (jb_class, "rfc7273-sync")) g_object_set (buffer, "rfc7273-sync", rtpbin->rfc7273_sync, NULL); if (g_object_class_find_property (jb_class, "max-ts-offset-adjustment")) g_object_set (buffer, "max-ts-offset-adjustment", rtpbin->max_ts_offset_adjustment, NULL); - /* need to sink the jitterbufer or otherwise signal handlers from bindings will - * take ownership of it and we don't own it anymore */ - gst_object_ref_sink (buffer); g_signal_emit (rtpbin, gst_rtp_bin_signals[SIGNAL_NEW_JITTERBUFFER], 0, buffer, session->id, ssrc); if (!rtpbin->ignore_pt) gst_bin_add (GST_BIN_CAST (rtpbin), demux); - /* unref the jitterbuffer again, the bin has a reference now and - * we don't need it anymore */ - gst_object_unref (buffer); - /* link stuff */ if (demux) gst_element_link_pads_full (buffer, "src", demux, "sink", @@ -1855,6 +1850,7 @@ create_stream (GstRtpBinSession * session, guint32 ssrc) static void free_stream (GstRtpBinStream * stream, GstRtpBin * bin) { + GstRtpBinSession *sess = stream->session; GSList *clients, *next_client; GST_DEBUG_OBJECT (bin, "freeing stream %p", stream); @@ -1881,7 +1877,10 @@ free_stream (GstRtpBinStream * stream, GstRtpBin * bin) if (stream->buffer_ntpstop_sig) g_signal_handler_disconnect (stream->buffer, stream->buffer_ntpstop_sig); + sess->elements = g_slist_remove (sess->elements, stream->buffer); + remove_bin_element (stream->buffer, bin); gst_object_unref (stream->buffer); + if (stream->demux) gst_bin_remove (GST_BIN_CAST (bin), stream->demux); @@ -2685,6 +2684,8 @@ gst_rtp_bin_class_init (GstRtpBinClass * klass) GST_DEBUG_FUNCPTR (gst_rtp_bin_request_jitterbuffer); GST_DEBUG_CATEGORY_INIT (gst_rtp_bin_debug, "rtpbin", 0, "RTP bin"); + + gst_type_mark_as_plugin_api (GST_RTP_BIN_RTCP_SYNC_TYPE, 0); } static void @@ -3216,7 +3217,7 @@ gst_rtp_bin_handle_message (GstBin * bin, GstMessage * message) streams = g_slist_next (streams)) { GstRtpBinStream *stream = (GstRtpBinStream *) streams->data; GstElement *element = stream->buffer; - guint64 last_out; + guint64 last_out = -1; if (g_signal_lookup ("set-active", G_OBJECT_TYPE (element)) != 0) { g_signal_emit_by_name (element, "set-active", active, offset, @@ -3888,7 +3889,8 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name) /* ERRORS */ no_name: { - g_warning ("rtpbin: invalid name given"); + g_warning ("rtpbin: cannot find session id for pad: %s", + GST_STR_NULL (name)); return NULL; } create_error: @@ -4063,7 +4065,8 @@ create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ, /* ERRORS */ no_name: { - g_warning ("rtpbin: invalid name given"); + g_warning ("rtpbin: cannot find session id for pad: %s", + GST_STR_NULL (name)); return NULL; } create_error: @@ -4392,7 +4395,8 @@ create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name) /* ERRORS */ no_name: { - g_warning ("rtpbin: invalid name given"); + g_warning ("rtpbin: cannot find session id for pad: %s", + GST_STR_NULL (name)); return NULL; } create_error: @@ -4546,7 +4550,8 @@ create_send_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ, /* ERRORS */ no_name: { - g_warning ("rtpbin: invalid name given"); + g_warning ("rtpbin: cannot find session id for pad: %s", + GST_STR_NULL (name)); return NULL; } create_error: diff --git a/gst/rtpmanager/gstrtpfunnel.c b/gst/rtpmanager/gstrtpfunnel.c index 155875bd50..7638b34973 100644 --- a/gst/rtpmanager/gstrtpfunnel.c +++ b/gst/rtpmanager/gstrtpfunnel.c @@ -20,15 +20,63 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ + + /** + * SECTION:element-rtpfunnel + * @title: rtpfunnel + * @see_also: rtpbasepaylaoder, rtpsession + * + * RTP funnel is basically like a normal funnel with a few added + * functionalities to support bundling. + * + * Bundle is the concept of sending multiple streams in a single RTP session. + * These can be both audio and video streams, and several of both. + * One of the advantages with bundling is that you can get away with fewer + * ports for sending and receiving media. Also the RTCP traffic gets more + * compact if you can report on multiple streams in a single sender/receiver + * report. + * + * One of the reasons for a specialized RTP funnel is that some messages + * coming upstream want to find their way back to the right stream, + * and a normal funnel can't know which of its sinkpads it should send + * these messages to. The RTP funnel achieves this by keeping track of the + * SSRC of each stream on its sinkpad, and then uses the fact that upstream + * events are tagged inside rtpbin with the appropriate SSRC, so that upon + * receiving such an event, the RTP funnel can do a simple lookup for the + * right pad to forward the event to. + * + * A good example here is the KeyUnit event. If several video encoders are + * being bundled together using the RTP funnel, and one of the decoders on + * the receiving side asks for a KeyUnit, typically a RTCP PLI message will + * be sent from the receiver to the sender, and this will be transformed into + * a GstForceKeyUnit event inside GstRTPSession, and sent upstream. The + * RTP funnel can than make sure that this event hits the right encoder based + * on the SSRC embedded in the event. + * + * Another feature of the RTP funnel is that it will mux together TWCC + * (Transport-Wide Congestion Control) sequence-numbers. The point being that + * it should increment "transport-wide", meaning potentially several + * bundled streams. Note that not *all* streams being bundled needs to be + * affected by this. As an example Google WebRTC will use bundle with audio + * and video, but will only use TWCC sequence-numbers for the video-stream(s). + * + */ + #ifdef HAVE_CONFIG_H #include "config.h" #endif +#include + #include "gstrtpfunnel.h" GST_DEBUG_CATEGORY_STATIC (gst_rtp_funnel_debug); #define GST_CAT_DEFAULT gst_rtp_funnel_debug +#define TWCC_EXTMAP_STR "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01" + +/**************** GstRTPFunnelPad ****************/ + struct _GstRtpFunnelPadClass { GstPadClass class; @@ -38,30 +86,31 @@ struct _GstRtpFunnelPad { GstPad pad; guint32 ssrc; + gboolean has_twcc; }; -enum -{ - PROP_0, - PROP_COMMON_TS_OFFSET, -}; - -#define DEFAULT_COMMON_TS_OFFSET -1 - G_DEFINE_TYPE (GstRtpFunnelPad, gst_rtp_funnel_pad, GST_TYPE_PAD); static void -gst_rtp_funnel_pad_class_init (GstRtpFunnelPadClass * klass) +gst_rtp_funnel_pad_class_init (G_GNUC_UNUSED GstRtpFunnelPadClass * klass) { - (void) klass; } static void -gst_rtp_funnel_pad_init (GstRtpFunnelPad * pad) +gst_rtp_funnel_pad_init (G_GNUC_UNUSED GstRtpFunnelPad * pad) { - (void) pad; } +/**************** GstRTPFunnel ****************/ + +enum +{ + PROP_0, + PROP_COMMON_TS_OFFSET, +}; + +#define DEFAULT_COMMON_TS_OFFSET -1 + struct _GstRtpFunnelClass { GstElementClass class; @@ -72,12 +121,16 @@ struct _GstRtpFunnel GstElement element; GstPad *srcpad; - GstCaps *srccaps; + GstCaps *srccaps; /* protected by OBJECT_LOCK */ gboolean send_sticky_events; - GHashTable *ssrc_to_pad; + GHashTable *ssrc_to_pad; /* protected by OBJECT_LOCK */ /* The last pad data was chained on */ GstPad *current_pad; + guint8 twcc_ext_id; /* the negotiated twcc extmap id */ + guint16 twcc_seqnum; /* our internal twcc seqnum */ + guint twcc_pads; /* numer of sinkpads with negotiated twcc */ + /* properties */ gint common_ts_offset; }; @@ -102,7 +155,8 @@ static void gst_rtp_funnel_send_sticky (GstRtpFunnel * funnel, GstPad * pad) { GstEvent *stream_start; - GstEvent *caps; + GstCaps *caps; + GstEvent *caps_ev; if (!funnel->send_sticky_events) goto done; @@ -113,8 +167,15 @@ gst_rtp_funnel_send_sticky (GstRtpFunnel * funnel, GstPad * pad) goto done; } - caps = gst_event_new_caps (funnel->srccaps); - if (caps && !gst_pad_push_event (funnel->srcpad, caps)) { + /* We modify these caps in our sink pad event handlers, so make sure to + * send a copy downstream so that we can keep our internal caps writable */ + GST_OBJECT_LOCK (funnel); + caps = gst_caps_copy (funnel->srccaps); + GST_OBJECT_UNLOCK (funnel); + + caps_ev = gst_event_new_caps (caps); + gst_caps_unref (caps); + if (caps_ev && !gst_pad_push_event (funnel->srcpad, caps_ev)) { GST_ERROR_OBJECT (funnel, "Could not push caps"); goto done; } @@ -146,6 +207,43 @@ gst_rtp_funnel_forward_segment (GstRtpFunnel * funnel, GstPad * pad) return; } +static void +gst_rtp_funnel_set_twcc_seqnum (GstRtpFunnel * funnel, + GstPad * pad, GstBuffer ** buf) +{ + GstRtpFunnelPad *fpad = GST_RTP_FUNNEL_PAD_CAST (pad); + GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; + + if (!funnel->twcc_ext_id || !fpad->has_twcc) + return; + + *buf = gst_buffer_make_writable (*buf); + + if (gst_rtp_buffer_map (*buf, GST_MAP_READWRITE, &rtp)) { + gpointer data; + + /* if there already is a twcc-seqnum inside the packet */ + if (gst_rtp_buffer_get_extension_onebyte_header (&rtp, funnel->twcc_ext_id, + 0, &data, NULL)) { + + /* with only one pad, we read the twcc-seqnum instead of writing it */ + if (funnel->twcc_pads == 1) { + funnel->twcc_seqnum = GST_READ_UINT16_BE (data); + } else { + GST_WRITE_UINT16_BE (data, funnel->twcc_seqnum); + } + } else { + guint16 seq_be; + GST_WRITE_UINT16_BE (&seq_be, funnel->twcc_seqnum); + gst_rtp_buffer_add_extension_onebyte_header (&rtp, funnel->twcc_ext_id, + &seq_be, 2); + } + } + gst_rtp_buffer_unmap (&rtp); + + funnel->twcc_seqnum++; +} + static GstFlowReturn gst_rtp_funnel_sink_chain_object (GstPad * pad, GstRtpFunnel * funnel, gboolean is_list, GstMiniObject * obj) @@ -159,11 +257,13 @@ gst_rtp_funnel_sink_chain_object (GstPad * pad, GstRtpFunnel * funnel, gst_rtp_funnel_send_sticky (funnel, pad); gst_rtp_funnel_forward_segment (funnel, pad); - if (is_list) + if (is_list) { res = gst_pad_push_list (funnel->srcpad, GST_BUFFER_LIST_CAST (obj)); - else - res = gst_pad_push (funnel->srcpad, GST_BUFFER_CAST (obj)); - + } else { + GstBuffer *buf = GST_BUFFER_CAST (obj); + gst_rtp_funnel_set_twcc_seqnum (funnel, pad, &buf); + res = gst_pad_push (funnel->srcpad, buf); + } GST_PAD_STREAM_UNLOCK (funnel->srcpad); return res; @@ -188,10 +288,59 @@ gst_rtp_funnel_sink_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) GST_MINI_OBJECT_CAST (buffer)); } +static void +gst_rtp_funnel_set_twcc_ext_id (GstRtpFunnel * funnel, guint8 twcc_ext_id) +{ + gchar *name; + + if (funnel->twcc_ext_id == twcc_ext_id) + return; + + name = g_strdup_printf ("extmap-%u", twcc_ext_id); + + GST_OBJECT_LOCK (funnel); + gst_caps_set_simple (funnel->srccaps, name, G_TYPE_STRING, TWCC_EXTMAP_STR, + NULL); + GST_OBJECT_UNLOCK (funnel); + + g_free (name); + + /* make sure we update the sticky with the new caps */ + funnel->send_sticky_events = TRUE; + + GST_INFO_OBJECT (funnel, "Setting twcc-ext-id to %u", twcc_ext_id); + funnel->twcc_ext_id = twcc_ext_id; +} + +static guint8 +_get_extmap_id_for_attribute (const GstStructure * s, const gchar * ext_name) +{ + guint i; + guint8 extmap_id = 0; + guint n_fields = gst_structure_n_fields (s); + + for (i = 0; i < n_fields; i++) { + const gchar *field_name = gst_structure_nth_field_name (s, i); + if (g_str_has_prefix (field_name, "extmap-")) { + const gchar *str = gst_structure_get_string (s, field_name); + if (str && g_strcmp0 (str, ext_name) == 0) { + gint64 id = g_ascii_strtoll (field_name + 7, NULL, 10); + if (id > 0 && id < 15) { + extmap_id = id; + break; + } + } + } + } + return extmap_id; +} + static gboolean gst_rtp_funnel_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstRtpFunnel *funnel = GST_RTP_FUNNEL_CAST (parent); + GstRtpFunnelPad *fpad = GST_RTP_FUNNEL_PAD_CAST (pad); + gboolean forward = TRUE; gboolean ret = TRUE; @@ -207,23 +356,32 @@ gst_rtp_funnel_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) GstCaps *caps; GstStructure *s; guint ssrc; + guint8 ext_id; + gst_event_parse_caps (event, &caps); + GST_OBJECT_LOCK (funnel); if (!gst_caps_can_intersect (funnel->srccaps, caps)) { GST_ERROR_OBJECT (funnel, "Can't intersect with caps %" GST_PTR_FORMAT, caps); g_assert_not_reached (); } + GST_OBJECT_UNLOCK (funnel); s = gst_caps_get_structure (caps, 0); if (gst_structure_get_uint (s, "ssrc", &ssrc)) { - GstRtpFunnelPad *fpad = GST_RTP_FUNNEL_PAD_CAST (pad); fpad->ssrc = ssrc; GST_DEBUG_OBJECT (pad, "Got ssrc: %u", ssrc); GST_OBJECT_LOCK (funnel); g_hash_table_insert (funnel->ssrc_to_pad, GUINT_TO_POINTER (ssrc), pad); GST_OBJECT_UNLOCK (funnel); } + ext_id = _get_extmap_id_for_attribute (s, TWCC_EXTMAP_STR); + if (ext_id > 0) { + fpad->has_twcc = TRUE; + funnel->twcc_pads++; + gst_rtp_funnel_set_twcc_ext_id (funnel, ext_id); + } forward = FALSE; break; @@ -245,8 +403,7 @@ static gboolean gst_rtp_funnel_sink_query (GstPad * pad, GstObject * parent, GstQuery * query) { GstRtpFunnel *funnel = GST_RTP_FUNNEL_CAST (parent); - gboolean res = FALSE; - (void) funnel; + gboolean res = TRUE; switch (GST_QUERY_TYPE (query)) { case GST_QUERY_CAPS: @@ -256,12 +413,14 @@ gst_rtp_funnel_sink_query (GstPad * pad, GstObject * parent, GstQuery * query) gst_query_parse_caps (query, &filter_caps); + GST_OBJECT_LOCK (funnel); if (filter_caps) { new_caps = gst_caps_intersect_full (funnel->srccaps, filter_caps, GST_CAPS_INTERSECT_FIRST); } else { new_caps = gst_caps_copy (funnel->srccaps); } + GST_OBJECT_UNLOCK (funnel); if (funnel->common_ts_offset >= 0) gst_caps_set_simple (new_caps, "timestamp-offset", G_TYPE_UINT, @@ -271,7 +430,25 @@ gst_rtp_funnel_sink_query (GstPad * pad, GstObject * parent, GstQuery * query) GST_DEBUG_OBJECT (pad, "Answering caps-query with caps: %" GST_PTR_FORMAT, new_caps); gst_caps_unref (new_caps); - res = TRUE; + break; + } + case GST_QUERY_ACCEPT_CAPS: + { + GstCaps *caps; + gboolean result; + + gst_query_parse_accept_caps (query, &caps); + + GST_OBJECT_LOCK (funnel); + result = gst_caps_is_subset (caps, funnel->srccaps); + if (!result) { + GST_ERROR_OBJECT (pad, + "caps: %" GST_PTR_FORMAT " were not compatible with: %" + GST_PTR_FORMAT, caps, funnel->srccaps); + } + GST_OBJECT_UNLOCK (funnel); + + gst_query_set_accept_caps_result (query, result); break; } default: diff --git a/gst/rtpmanager/gstrtpjitterbuffer.c b/gst/rtpmanager/gstrtpjitterbuffer.c index 8cf2774adc..5bd15b3f47 100644 --- a/gst/rtpmanager/gstrtpjitterbuffer.c +++ b/gst/rtpmanager/gstrtpjitterbuffer.c @@ -234,6 +234,8 @@ enum } G_STMT_END #define JBUF_WAIT_EVENT(priv,label) G_STMT_START { \ + if (G_UNLIKELY (priv->srcresult != GST_FLOW_OK)) \ + goto label; \ GST_DEBUG ("waiting event"); \ (priv)->waiting_event = TRUE; \ g_cond_wait (&(priv)->jbuf_event, &(priv)->jbuf_lock); \ @@ -250,6 +252,8 @@ enum } G_STMT_END #define JBUF_WAIT_QUERY(priv,label) G_STMT_START { \ + if (G_UNLIKELY (priv->srcresult != GST_FLOW_OK)) \ + goto label; \ GST_DEBUG ("waiting query"); \ (priv)->waiting_query = TRUE; \ g_cond_wait (&(priv)->jbuf_query, &(priv)->jbuf_lock); \ @@ -269,6 +273,18 @@ enum #define GST_BUFFER_IS_RETRANSMISSION(buffer) \ GST_BUFFER_FLAG_IS_SET (buffer, GST_RTP_BUFFER_FLAG_RETRANSMISSION) +#if !GLIB_CHECK_VERSION(2, 60, 0) +#define g_queue_clear_full queue_clear_full +static void +queue_clear_full (GQueue * queue, GDestroyNotify free_func) +{ + gpointer data; + + while ((data = g_queue_pop_head (queue)) != NULL) + free_func (data); +} +#endif + struct _GstRtpJitterBufferPrivate { GstPad *sinkpad, *srcpad; @@ -276,9 +292,9 @@ struct _GstRtpJitterBufferPrivate RTPJitterBuffer *jbuf; GMutex jbuf_lock; - gboolean waiting_queue; + guint waiting_queue; GCond jbuf_queue; - gboolean waiting_timer; + guint waiting_timer; GCond jbuf_timer; gboolean waiting_event; GCond jbuf_event; @@ -399,13 +415,11 @@ struct _GstRtpJitterBufferPrivate GstClockTime last_drop_msg_timestamp; /* accumulators; reset every time a drop message is posted */ guint num_too_late; - guint num_already_lost; guint num_drop_on_latency; }; typedef enum { REASON_TOO_LATE, - REASON_ALREADY_LOST, REASON_DROP_ON_LATENCY } DropMessageReason; @@ -594,11 +608,9 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass) * * * #guint `seqnum`: Seqnum of dropped packet. * * #guint64 `timestamp`: PTS timestamp of dropped packet. - * * #gstring `reason`: Reason for dropping the packet. + * * #GString `reason`: Reason for dropping the packet. * * #guint `num-too-late`: Number of packets arriving too late since * last drop message. - * * #guint `num-already-lost`: Number of packets already considered lost - * since drop message. * * #guint `num-drop-on-latency`: Number of packets dropped due to the * drop-on-latency property since last drop message. * @@ -723,7 +735,7 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass) -1, G_MAXINT, DEFAULT_RTX_DELAY_REORDER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * GstRtpJitterBuffer::rtx-retry-timeout: + * GstRtpJitterBuffer:rtx-retry-timeout: * * When no packet has been received after sending a retransmission event * for this time, retry sending a retransmission event. @@ -739,7 +751,7 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass) "ms (-1 automatic)", -1, G_MAXINT, DEFAULT_RTX_RETRY_TIMEOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * GstRtpJitterBuffer::rtx-min-retry-timeout: + * GstRtpJitterBuffer:rtx-min-retry-timeout: * * The minimum amount of time between retry timeouts. When * GstRtpJitterBuffer::rtx-retry-timeout is -1, this value ensures a @@ -801,7 +813,7 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass) "(-1 automatic)", -1, G_MAXINT, DEFAULT_RTX_DEADLINE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * GstRtpJitterBuffer::rtx-stats-timeout: + * GstRtpJitterBuffer:rtx-stats-timeout: * * The time to wait for a retransmitted packet after it has been * considered lost in order to collect RTX statistics. @@ -836,6 +848,7 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass) * * #guint64 `num-lost`: the number of packets considered lost. * * #guint64 `num-late`: the number of packets arriving too late. * * #guint64 `num-duplicates`: the number of duplicate packets. + * * #guint64 `avg-jitter`: the average jitter in nanoseconds. * * #guint64 `rtx-count`: the number of retransmissions requested. * * #guint64 `rtx-success-count`: the number of successful retransmissions. * * #gdouble `rtx-per-packet`: average number of RTX per packet. @@ -981,6 +994,8 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass) GST_DEBUG_CATEGORY_INIT (rtpjitterbuffer_debug, "rtpjitterbuffer", 0, "RTP Jitter Buffer"); GST_DEBUG_REGISTER_FUNCPTR (gst_rtp_jitter_buffer_chain_rtcp); + + gst_type_mark_as_plugin_api (RTP_TYPE_JITTER_BUFFER_MODE, 0); } static void @@ -1022,7 +1037,6 @@ gst_rtp_jitter_buffer_init (GstRtpJitterBuffer * jitterbuffer) priv->avg_jitter = 0; priv->last_drop_msg_timestamp = GST_CLOCK_TIME_NONE; priv->num_too_late = 0; - priv->num_already_lost = 0; priv->num_drop_on_latency = 0; priv->segment_seqnum = GST_SEQNUM_INVALID; priv->timers = rtp_timer_queue_new (); @@ -1072,20 +1086,6 @@ gst_rtp_jitter_buffer_init (GstRtpJitterBuffer * jitterbuffer) GST_OBJECT_FLAG_SET (jitterbuffer, GST_ELEMENT_FLAG_PROVIDE_CLOCK); } -#define IS_DROPABLE(it) (((it)->type == ITEM_TYPE_BUFFER) || ((it)->type == ITEM_TYPE_LOST)) - -#define ITEM_TYPE_BUFFER 0 -#define ITEM_TYPE_LOST 1 -#define ITEM_TYPE_EVENT 2 -#define ITEM_TYPE_QUERY 3 - -static inline RTPJitterBufferItem * -alloc_event_item (GstEvent * event) -{ - return rtp_jitter_buffer_alloc_item (event, ITEM_TYPE_EVENT, -1, -1, -1, 0, - -1, (GDestroyNotify) gst_mini_object_unref); -} - static void free_item_and_retain_sticky_events (RTPJitterBufferItem * item, gpointer user_data) @@ -1372,6 +1372,24 @@ gst_rtp_jitter_buffer_getcaps (GstPad * pad, GstCaps * filter) return caps; } +/* g_ascii_string_to_unsigned is available since 2.54. Get rid of this wrapper + * when we bump the version in 1.18 */ +#if !GLIB_CHECK_VERSION(2,54,0) +#define g_ascii_string_to_unsigned _gst_jitter_buffer_ascii_string_to_unsigned +static gboolean +_gst_jitter_buffer_ascii_string_to_unsigned (const gchar * str, guint base, + guint64 min, guint64 max, guint64 * out_num, GError ** error) +{ + gchar *endptr = NULL; + *out_num = g_ascii_strtoull (str, &endptr, base); + if (errno) + return FALSE; + if (endptr == str) + return FALSE; + return TRUE; +} +#endif + /* * Must be called with JBUF_LOCK held */ @@ -1519,8 +1537,9 @@ gst_jitter_buffer_sink_parse_caps (GstRtpJitterBuffer * jitterbuffer, if ((mediaclk = gst_structure_get_string (caps_struct, "a-mediaclk"))) { GST_DEBUG_OBJECT (jitterbuffer, "Got media clock %s", mediaclk); - if (!g_str_has_prefix (mediaclk, "direct=") - || sscanf (mediaclk, "direct=%" G_GUINT64_FORMAT, &clock_offset) != 1) + if (!g_str_has_prefix (mediaclk, "direct=") || + !g_ascii_string_to_unsigned (&mediaclk[7], 10, 0, G_MAXUINT64, + &clock_offset, NULL)) GST_FIXME_OBJECT (jitterbuffer, "Unsupported media clock"); if (strstr (mediaclk, "rate=") != NULL) { GST_FIXME_OBJECT (jitterbuffer, "Rate property not supported"); @@ -1600,7 +1619,6 @@ gst_rtp_jitter_buffer_flush_stop (GstRtpJitterBuffer * jitterbuffer) priv->segment_seqnum = GST_SEQNUM_INVALID; priv->last_drop_msg_timestamp = GST_CLOCK_TIME_NONE; priv->num_too_late = 0; - priv->num_already_lost = 0; priv->num_drop_on_latency = 0; GST_DEBUG_OBJECT (jitterbuffer, "flush and reset jitterbuffer"); rtp_jitter_buffer_flush (priv->jbuf, NULL, NULL); @@ -1779,7 +1797,6 @@ static gboolean queue_event (GstRtpJitterBuffer * jitterbuffer, GstEvent * event) { GstRtpJitterBufferPrivate *priv = jitterbuffer->priv; - RTPJitterBufferItem *item; gboolean head; switch (GST_EVENT_TYPE (event)) { @@ -1819,10 +1836,8 @@ queue_event (GstRtpJitterBuffer * jitterbuffer, GstEvent * event) break; } - GST_DEBUG_OBJECT (jitterbuffer, "adding event"); - item = alloc_event_item (event); - rtp_jitter_buffer_insert (priv->jbuf, item, &head, NULL); + head = rtp_jitter_buffer_append_event (priv->jbuf, event); if (head || priv->eos) JBUF_SIGNAL_EVENT (priv); @@ -2028,9 +2043,6 @@ new_drop_message (GstRtpJitterBuffer * jitterbuffer, guint seqnum, if (reason == REASON_TOO_LATE) { priv->num_too_late++; reason_str = "too-late"; - } else if (reason == REASON_ALREADY_LOST) { - priv->num_already_lost++; - reason_str = "already-lost"; } else if (reason == REASON_DROP_ON_LATENCY) { priv->num_drop_on_latency++; reason_str = "drop-on-latency"; @@ -2049,12 +2061,10 @@ new_drop_message (GstRtpJitterBuffer * jitterbuffer, guint seqnum, "timestamp", GST_TYPE_CLOCK_TIME, timestamp, "reason", G_TYPE_STRING, reason_str, "num-too-late", G_TYPE_UINT, priv->num_too_late, - "num-already-lost", G_TYPE_UINT, priv->num_already_lost, "num-drop-on-latency", G_TYPE_UINT, priv->num_drop_on_latency, NULL); priv->last_drop_msg_timestamp = current_time; priv->num_too_late = 0; - priv->num_already_lost = 0; priv->num_drop_on_latency = 0; drop_msg = gst_message_new_element (GST_OBJECT (jitterbuffer), s); } @@ -2078,6 +2088,27 @@ get_pts_timeout (const RtpTimer * timer) return timer->timeout - timer->offset; } +static inline gboolean +safe_add (guint64 * res, guint64 val, gint64 offset) +{ + if (val <= G_MAXINT64) { + gint64 tmp = (gint64) val + offset; + if (tmp >= 0) { + *res = tmp; + return TRUE; + } + return FALSE; + } + /* From here, val > G_MAXINT64 */ + + /* Negative value */ + if (offset < 0 && val < -offset) + return FALSE; + + *res = val + offset; + return TRUE; +} + static void update_timer_offsets (GstRtpJitterBuffer * jitterbuffer) { @@ -2087,8 +2118,15 @@ update_timer_offsets (GstRtpJitterBuffer * jitterbuffer) while (test) { if (test->type != RTP_TIMER_EXPECTED) { - test->timeout = get_pts_timeout (test) + new_offset; - test->offset = new_offset; + GstClockTime pts = get_pts_timeout (test); + if (safe_add (&test->timeout, pts, new_offset)) { + test->offset = new_offset; + } else { + GST_DEBUG_OBJECT (jitterbuffer, + "Invalidating timeout (pts lower than new offset)"); + test->timeout = GST_CLOCK_TIME_NONE; + test->offset = 0; + } /* as we apply the offset on all timers, the order of timers won't * change and we can skip updating the timer queue */ } @@ -2136,7 +2174,8 @@ apply_offset (GstRtpJitterBuffer * jitterbuffer, GstClockTime timestamp) return -1; /* apply the timestamp offset, this is used for inter stream sync */ - timestamp += priv->ts_offset; + if (!safe_add (×tamp, timestamp, priv->ts_offset)) + timestamp = 0; /* add the offset, this is used when buffering */ timestamp += priv->out_offset; @@ -2220,33 +2259,6 @@ get_rtx_delay (GstRtpJitterBufferPrivate * priv) return delay; } -/* Check if packet with seqnum is already considered definitely lost by being - * part of a "lost timer" for multiple packets */ -static gboolean -already_lost (GstRtpJitterBuffer * jitterbuffer, GstClockTime pts, - guint16 seqnum) -{ - GstRtpJitterBufferPrivate *priv = jitterbuffer->priv; - RtpTimer *test; - - test = rtp_timer_queue_peek_earliest (priv->timers); - while (test && get_pts_timeout (test) <= pts) { - gint gap = gst_rtp_buffer_compare_seqnum (test->seqnum, seqnum); - - if (test->num > 1 && test->type == RTP_TIMER_LOST && gap >= 0 && - gap < test->num) { - GST_DEBUG_OBJECT (jitterbuffer, - "seqnum #%d already considered definitely lost (#%d->#%d)", - seqnum, test->seqnum, (test->seqnum + test->num - 1) & 0xffff); - return TRUE; - } - - test = rtp_timer_get_next (test); - } - - return FALSE; -} - /* we just received a packet with seqnum and dts. * * First check for old seqnum that we are still expecting. If the gap with the @@ -2400,6 +2412,52 @@ calculate_packet_spacing (GstRtpJitterBuffer * jitterbuffer, guint32 rtptime, } } +static void +insert_lost_event (GstRtpJitterBuffer * jitterbuffer, + guint16 seqnum, guint lost_packets, GstClockTime timestamp, + GstClockTime duration, guint num_rtx_retry) +{ + GstRtpJitterBufferPrivate *priv = jitterbuffer->priv; + GstEvent *event = NULL; + guint next_in_seqnum; + + /* we had a gap and thus we lost some packets. Create an event for this. */ + if (lost_packets > 1) + GST_DEBUG_OBJECT (jitterbuffer, "Packets #%d -> #%d lost", seqnum, + seqnum + lost_packets - 1); + else + GST_DEBUG_OBJECT (jitterbuffer, "Packet #%d lost", seqnum); + + priv->num_lost += lost_packets; + priv->num_rtx_failed += num_rtx_retry; + + next_in_seqnum = (seqnum + lost_packets) & 0xffff; + + /* we now only accept seqnum bigger than this */ + if (gst_rtp_buffer_compare_seqnum (priv->next_in_seqnum, next_in_seqnum) > 0) { + priv->next_in_seqnum = next_in_seqnum; + priv->last_in_pts = timestamp; + } + + /* Avoid creating events if we don't need it. Note that we still need to create + * the lost *ITEM* since it will be used to notify the outgoing thread of + * lost items (so that we can set discont flags and such) */ + if (priv->do_lost) { + /* create packet lost event */ + if (duration == GST_CLOCK_TIME_NONE && priv->packet_spacing > 0) + duration = priv->packet_spacing; + event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, + gst_structure_new ("GstRTPPacketLost", + "seqnum", G_TYPE_UINT, (guint) seqnum, + "timestamp", G_TYPE_UINT64, timestamp, + "duration", G_TYPE_UINT64, duration, + "retry", G_TYPE_UINT, num_rtx_retry, NULL)); + } + if (rtp_jitter_buffer_append_lost_event (priv->jbuf, + event, seqnum, lost_packets)) + JBUF_SIGNAL_EVENT (priv); +} + static void calculate_expected (GstRtpJitterBuffer * jitterbuffer, guint32 expected, guint16 seqnum, GstClockTime pts, gint gap) @@ -2407,10 +2465,11 @@ calculate_expected (GstRtpJitterBuffer * jitterbuffer, guint32 expected, GstRtpJitterBufferPrivate *priv = jitterbuffer->priv; GstClockTime duration, expected_pts; gboolean equidistant = priv->equidistant > 0; + GstClockTime last_in_pts = priv->last_in_pts; GST_DEBUG_OBJECT (jitterbuffer, "pts %" GST_TIME_FORMAT ", last %" GST_TIME_FORMAT, - GST_TIME_ARGS (pts), GST_TIME_ARGS (priv->last_in_pts)); + GST_TIME_ARGS (pts), GST_TIME_ARGS (last_in_pts)); if (pts == GST_CLOCK_TIME_NONE) { GST_WARNING_OBJECT (jitterbuffer, "Have no PTS"); @@ -2420,8 +2479,8 @@ calculate_expected (GstRtpJitterBuffer * jitterbuffer, guint32 expected, if (equidistant) { GstClockTime total_duration; /* the total duration spanned by the missing packets */ - if (pts >= priv->last_in_pts) - total_duration = pts - priv->last_in_pts; + if (pts >= last_in_pts) + total_duration = pts - last_in_pts; else total_duration = 0; @@ -2458,18 +2517,30 @@ calculate_expected (GstRtpJitterBuffer * jitterbuffer, guint32 expected, GST_TIME_ARGS (priv->latency_ns), lost_packets, GST_TIME_ARGS (gap_time)); - /* this timer will fire immediately and the lost event will be pushed from - * the timer thread */ + /* this multi-lost-packet event will be inserted directly into the packet-queue + for immediate processing */ if (lost_packets > 0) { - rtp_timer_queue_set_lost (priv->timers, expected, lost_packets, - priv->last_in_pts + duration, gap_time, - timeout_offset (jitterbuffer)); + RtpTimer *timer; + GstClockTime timestamp = + apply_offset (jitterbuffer, last_in_pts + duration); + insert_lost_event (jitterbuffer, expected, lost_packets, timestamp, + gap_time, 0); + + timer = rtp_timer_queue_find (priv->timers, expected); + if (timer && timer->type == RTP_TIMER_EXPECTED) { + if (timer->queued) + rtp_timer_queue_unschedule (priv->timers, timer); + GST_DEBUG_OBJECT (jitterbuffer, "removing timer for seqnum #%u", + expected); + rtp_timer_free (timer); + } + expected += lost_packets; - priv->last_in_pts += gap_time; + last_in_pts += gap_time; } } - expected_pts = priv->last_in_pts + duration; + expected_pts = last_in_pts + duration; } else { /* If we cannot assume equidistant packet spacing, the only thing we now * for sure is that the missing packets have expected pts not later than @@ -2507,7 +2578,7 @@ calculate_expected (GstRtpJitterBuffer * jitterbuffer, guint32 expected, } } else { while (gst_rtp_buffer_compare_seqnum (expected, seqnum) > 0) { - rtp_timer_queue_set_lost (priv->timers, expected, 0, expected_pts, + rtp_timer_queue_set_lost (priv->timers, expected, expected_pts, duration, timeout_offset (jitterbuffer)); expected_pts += duration; expected++; @@ -2700,7 +2771,6 @@ gst_rtp_jitter_buffer_reset (GstRtpJitterBuffer * jitterbuffer, GstFlowReturn ret = GST_FLOW_OK; GList *events = NULL, *l; GList *buffers; - gboolean head; GST_DEBUG_OBJECT (jitterbuffer, "flush and reset jitterbuffer"); rtp_jitter_buffer_flush (priv->jbuf, @@ -2729,10 +2799,7 @@ gst_rtp_jitter_buffer_reset (GstRtpJitterBuffer * jitterbuffer, */ events = g_list_reverse (events); for (l = events; l; l = l->next) { - RTPJitterBufferItem *item; - - item = alloc_event_item (l->data); - rtp_jitter_buffer_insert (priv->jbuf, item, &head, NULL); + rtp_jitter_buffer_append_event (priv->jbuf, l->data); } g_list_free (events); @@ -2808,16 +2875,17 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent, GstClockTime dts, pts; guint64 latency_ts; gboolean head; + gboolean duplicate; gint percent = -1; guint8 pt; GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; gboolean do_next_seqnum = FALSE; - RTPJitterBufferItem *item; GstMessage *msg = NULL; GstMessage *drop_msg = NULL; gboolean estimated_dts = FALSE; gint32 packet_rate, max_dropout, max_misorder; RtpTimer *timer = NULL; + gboolean is_rtx; jitterbuffer = GST_RTP_JITTER_BUFFER_CAST (parent); @@ -2831,6 +2899,8 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent, rtptime = gst_rtp_buffer_get_timestamp (&rtp); gst_rtp_buffer_unmap (&rtp); + is_rtx = GST_BUFFER_IS_RETRANSMISSION (buffer); + /* make sure we have PTS and DTS set */ pts = GST_BUFFER_PTS (buffer); dts = GST_BUFFER_DTS (buffer); @@ -2862,8 +2932,7 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent, GST_DEBUG_OBJECT (jitterbuffer, "Received packet #%d at time %" GST_TIME_FORMAT ", discont %d, rtx %d", - seqnum, GST_TIME_ARGS (dts), GST_BUFFER_IS_DISCONT (buffer), - GST_BUFFER_IS_RETRANSMISSION (buffer)); + seqnum, GST_TIME_ARGS (dts), GST_BUFFER_IS_DISCONT (buffer), is_rtx); JBUF_LOCK_CHECK (priv, out_flushing); @@ -2901,7 +2970,7 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent, if (G_UNLIKELY (priv->eos)) goto have_eos; - if (!GST_BUFFER_IS_RETRANSMISSION (buffer)) + if (!is_rtx) calculate_jitter (jitterbuffer, dts, rtptime); if (priv->seqnum_base != -1) { @@ -2925,20 +2994,23 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent, expected = priv->next_in_seqnum; - packet_rate = - gst_rtp_packet_rate_ctx_update (&priv->packet_rate_ctx, seqnum, rtptime); + /* don't update packet-rate based on RTX, as those arrive highly unregularly */ + if (!is_rtx) { + packet_rate = gst_rtp_packet_rate_ctx_update (&priv->packet_rate_ctx, + seqnum, rtptime); + GST_TRACE_OBJECT (jitterbuffer, "updated packet_rate: %d", packet_rate); + } max_dropout = gst_rtp_packet_rate_ctx_get_max_dropout (&priv->packet_rate_ctx, priv->max_dropout_time); max_misorder = gst_rtp_packet_rate_ctx_get_max_misorder (&priv->packet_rate_ctx, priv->max_misorder_time); - GST_TRACE_OBJECT (jitterbuffer, - "packet_rate: %d, max_dropout: %d, max_misorder: %d", packet_rate, + GST_TRACE_OBJECT (jitterbuffer, "max_dropout: %d, max_misorder: %d", max_dropout, max_misorder); timer = rtp_timer_queue_find (priv->timers, seqnum); - if (GST_BUFFER_IS_RETRANSMISSION (buffer)) { + if (is_rtx) { if (G_UNLIKELY (!priv->do_retransmission)) goto unsolicited_rtx; @@ -2994,12 +3066,13 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent, * next packet */ GST_WARNING_OBJECT (jitterbuffer, "%d pending timers > %d - resetting", rtp_timer_queue_length (priv->timers), max_dropout); - gst_buffer_unref (buffer); + g_queue_insert_sorted (&priv->gap_packets, buffer, + (GCompareDataFunc) compare_buffer_seqnum, NULL); return gst_rtp_jitter_buffer_reset (jitterbuffer, pad, parent, seqnum); } /* Special handling of large gaps */ - if ((gap != -1 && gap < -max_misorder) || (gap >= max_dropout)) { + if (!is_rtx && ((gap != -1 && gap < -max_misorder) || (gap >= max_dropout))) { gboolean reset = handle_big_gap_buffer (jitterbuffer, buffer, pt, seqnum, gap, max_dropout, max_misorder); if (reset) { @@ -3021,7 +3094,7 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent, pts = rtp_jitter_buffer_calculate_pts (priv->jbuf, dts, estimated_dts, rtptime, gst_element_get_base_time (GST_ELEMENT_CAST (jitterbuffer)), - gap, GST_BUFFER_IS_RETRANSMISSION (buffer)); + gap, is_rtx); if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts))) { /* A valid timestamp cannot be calculated, discard packet */ @@ -3056,7 +3129,7 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent, priv->next_in_seqnum = (seqnum + 1) & 0xffff; } - if (GST_BUFFER_IS_RETRANSMISSION (buffer)) + if (is_rtx) timer->num_rtx_received++; /* At 2^15, we would detect a seqnum rollover too early, therefore @@ -3089,7 +3162,7 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent, /* priv->last_popped_seqnum >= seqnum, we're too late. */ if (G_UNLIKELY (gap <= 0)) { if (priv->do_retransmission) { - if (GST_BUFFER_IS_RETRANSMISSION (buffer) && timer) { + if (is_rtx && timer) { update_rtx_stats (jitterbuffer, timer, dts, FALSE); /* Only count the retranmitted packet too late if it has been * considered lost. If the original packet arrived before the @@ -3102,9 +3175,6 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent, } } - if (already_lost (jitterbuffer, pts, seqnum)) - goto already_lost; - /* let's drop oldest packet if the queue is already full and drop-on-latency * is set. We can only do this when there actually is a latency. When no * latency is set, we just pump it in the queue and let the other end push it @@ -3140,20 +3210,15 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent, * later. The code above always sets dts to pts or the other way around if * any of those is valid in the buffer, so we know that if we estimated the * dts that both are unknown */ - if (estimated_dts) - item = rtp_jitter_buffer_alloc_item (buffer, ITEM_TYPE_BUFFER, - GST_CLOCK_TIME_NONE, pts, seqnum, 1, rtptime, - (GDestroyNotify) gst_mini_object_unref); - else - item = rtp_jitter_buffer_alloc_item (buffer, ITEM_TYPE_BUFFER, dts, pts, - seqnum, 1, rtptime, (GDestroyNotify) gst_mini_object_unref); + head = rtp_jitter_buffer_append_buffer (priv->jbuf, buffer, + estimated_dts ? GST_CLOCK_TIME_NONE : dts, pts, seqnum, rtptime, + &duplicate, &percent); /* now insert the packet into the queue in sorted order. This function returns * FALSE if a packet with the same seqnum was already in the queue, meaning we * have a duplicate. */ - if (G_UNLIKELY (!rtp_jitter_buffer_insert (priv->jbuf, item, &head, - &percent))) { - if (GST_BUFFER_IS_RETRANSMISSION (buffer) && timer) + if (G_UNLIKELY (duplicate)) { + if (is_rtx && timer) update_rtx_stats (jitterbuffer, timer, dts, FALSE); goto duplicate; } @@ -3163,8 +3228,7 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent, head = TRUE; /* update timers */ - update_timers (jitterbuffer, seqnum, dts, pts, do_next_seqnum, - GST_BUFFER_IS_RETRANSMISSION (buffer), timer); + update_timers (jitterbuffer, seqnum, dts, pts, do_next_seqnum, is_rtx, timer); /* we had an unhandled SR, handle it now */ if (priv->last_sr) @@ -3234,24 +3298,11 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent, gst_buffer_unref (buffer); goto finished; } -already_lost: - { - GST_DEBUG_OBJECT (jitterbuffer, "Packet #%d too late as it was already " - "considered lost", seqnum); - priv->num_late++; - if (priv->post_drop_messages) { - drop_msg = - new_drop_message (jitterbuffer, seqnum, pts, REASON_ALREADY_LOST); - } - gst_buffer_unref (buffer); - goto finished; - } duplicate: { GST_DEBUG_OBJECT (jitterbuffer, "Duplicate packet #%d detected, dropping", seqnum); priv->num_duplicates++; - rtp_jitter_buffer_free_item (item); goto finished; } rtx_duplicate: @@ -3273,7 +3324,7 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent, { GST_DEBUG_OBJECT (jitterbuffer, "cannot calculate a valid pts for #%d (rtx: %d), discard", - seqnum, GST_BUFFER_IS_RETRANSMISSION (buffer)); + seqnum, is_rtx); gst_buffer_unref (buffer); goto finished; } @@ -3766,7 +3817,7 @@ update_rtx_stats (GstRtpJitterBuffer * jitterbuffer, const RtpTimer * timer, /* the timeout for when we expected a packet expired */ static gboolean do_expected_timeout (GstRtpJitterBuffer * jitterbuffer, RtpTimer * timer, - GstClockTime now) + GstClockTime now, GQueue * events) { GstRtpJitterBufferPrivate *priv = jitterbuffer->priv; GstEvent *event; @@ -3804,6 +3855,7 @@ do_expected_timeout (GstRtpJitterBuffer * jitterbuffer, RtpTimer * timer, "deadline", G_TYPE_UINT, rtx_deadline_ms, "packet-spacing", G_TYPE_UINT64, priv->packet_spacing, "avg-rtt", G_TYPE_UINT, avg_rtx_rtt_ms, NULL)); + g_queue_push_tail (events, event); GST_DEBUG_OBJECT (jitterbuffer, "Request RTX: %" GST_PTR_FORMAT, event); priv->num_rtx_requests++; @@ -3841,10 +3893,6 @@ do_expected_timeout (GstRtpJitterBuffer * jitterbuffer, RtpTimer * timer, rtp_timer_queue_update_timer (priv->timers, timer, timer->seqnum, timer->rtx_base + timer->rtx_retry, timer->rtx_delay, offset, FALSE); - JBUF_UNLOCK (priv); - gst_pad_push_event (priv->sinkpad, event); - JBUF_LOCK (priv); - return FALSE; } @@ -3854,55 +3902,11 @@ do_lost_timeout (GstRtpJitterBuffer * jitterbuffer, RtpTimer * timer, GstClockTime now) { GstRtpJitterBufferPrivate *priv = jitterbuffer->priv; - guint seqnum, lost_packets, num_rtx_retry, next_in_seqnum; - gboolean head; - GstEvent *event = NULL; - RTPJitterBufferItem *item; - - seqnum = timer->seqnum; - lost_packets = MAX (timer->num, 1); - num_rtx_retry = timer->num_rtx_retry; - - /* we had a gap and thus we lost some packets. Create an event for this. */ - if (lost_packets > 1) - GST_DEBUG_OBJECT (jitterbuffer, "Packets #%d -> #%d lost", seqnum, - seqnum + lost_packets - 1); - else - GST_DEBUG_OBJECT (jitterbuffer, "Packet #%d lost", seqnum); + GstClockTime timestamp; - priv->num_lost += lost_packets; - priv->num_rtx_failed += num_rtx_retry; - - next_in_seqnum = (seqnum + lost_packets) & 0xffff; - - /* we now only accept seqnum bigger than this */ - if (gst_rtp_buffer_compare_seqnum (priv->next_in_seqnum, next_in_seqnum) > 0) { - priv->next_in_seqnum = next_in_seqnum; - priv->last_in_pts = apply_offset (jitterbuffer, get_pts_timeout (timer)); - } - - /* Avoid creating events if we don't need it. Note that we still need to create - * the lost *ITEM* since it will be used to notify the outgoing thread of - * lost items (so that we can set discont flags and such) */ - if (priv->do_lost) { - GstClockTime duration, timestamp; - /* create packet lost event */ - timestamp = apply_offset (jitterbuffer, get_pts_timeout (timer)); - duration = timer->duration; - if (duration == GST_CLOCK_TIME_NONE && priv->packet_spacing > 0) - duration = priv->packet_spacing; - event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, - gst_structure_new ("GstRTPPacketLost", - "seqnum", G_TYPE_UINT, (guint) seqnum, - "timestamp", G_TYPE_UINT64, timestamp, - "duration", G_TYPE_UINT64, duration, - "retry", G_TYPE_UINT, num_rtx_retry, NULL)); - } - item = rtp_jitter_buffer_alloc_item (event, ITEM_TYPE_LOST, -1, -1, seqnum, - lost_packets, -1, (GDestroyNotify) gst_mini_object_unref); - if (!rtp_jitter_buffer_insert (priv->jbuf, item, &head, NULL)) - /* Duplicate */ - rtp_jitter_buffer_free_item (item); + timestamp = apply_offset (jitterbuffer, get_pts_timeout (timer)); + insert_lost_event (jitterbuffer, timer->seqnum, 1, timestamp, + timer->duration, timer->num_rtx_retry); if (GST_CLOCK_TIME_IS_VALID (timer->rtx_last)) { /* Store info to update stats if the packet arrives too late */ @@ -3913,9 +3917,6 @@ do_lost_timeout (GstRtpJitterBuffer * jitterbuffer, RtpTimer * timer, rtp_timer_free (timer); } - if (head) - JBUF_SIGNAL_EVENT (priv); - return TRUE; } @@ -3961,13 +3962,13 @@ do_deadline_timeout (GstRtpJitterBuffer * jitterbuffer, RtpTimer * timer, static gboolean do_timeout (GstRtpJitterBuffer * jitterbuffer, RtpTimer * timer, - GstClockTime now) + GstClockTime now, GQueue * events) { gboolean removed = FALSE; switch (timer->type) { case RTP_TIMER_EXPECTED: - removed = do_expected_timeout (jitterbuffer, timer, now); + removed = do_expected_timeout (jitterbuffer, timer, now, events); break; case RTP_TIMER_LOST: removed = do_lost_timeout (jitterbuffer, timer, now); @@ -3982,6 +3983,35 @@ do_timeout (GstRtpJitterBuffer * jitterbuffer, RtpTimer * timer, return removed; } +static void +push_rtx_events_unlocked (GstRtpJitterBuffer * jitterbuffer, GQueue * events) +{ + GstRtpJitterBufferPrivate *priv = jitterbuffer->priv; + GstEvent *event; + + while ((event = (GstEvent *) g_queue_pop_head (events))) + gst_pad_push_event (priv->sinkpad, event); +} + +/* called with JBUF lock + * + * Pushes all events in @events queue. + * + * Returns: %TRUE if the timer thread is not longer running + */ +static void +push_rtx_events (GstRtpJitterBuffer * jitterbuffer, GQueue * events) +{ + GstRtpJitterBufferPrivate *priv = jitterbuffer->priv; + + if (events->length == 0) + return; + + JBUF_UNLOCK (priv); + push_rtx_events_unlocked (jitterbuffer, events); + JBUF_LOCK (priv); +} + /* called when we need to wait for the next timeout. * * We loop over the array of recorded timeouts and wait for the earliest one. @@ -3998,7 +4028,7 @@ wait_next_timeout (GstRtpJitterBuffer * jitterbuffer) JBUF_LOCK (priv); while (priv->timer_running) { RtpTimer *timer = NULL; - GQueue timers = G_QUEUE_INIT; + GQueue events = G_QUEUE_INIT; /* don't produce data in paused */ while (priv->blocked) { @@ -4031,25 +4061,8 @@ wait_next_timeout (GstRtpJitterBuffer * jitterbuffer) rtp_timer_queue_remove_until (priv->rtx_stats_timers, now); /* Iterate expired "normal" timers */ - while ((timer = rtp_timer_queue_pop_until (priv->timers, now))) { - do { - if (timer->type == RTP_TIMER_LOST) { - GST_DEBUG_OBJECT (jitterbuffer, "Weeding out expired lost timers"); - do_lost_timeout (jitterbuffer, timer, now); - } else { - g_queue_push_tail_link (&timers, (GList *) timer); - } - } while ((timer = rtp_timer_queue_pop_until (priv->timers, now))); - - /* execute the remaining timers */ - while ((timer = (RtpTimer *) g_queue_pop_head_link (&timers))) - do_timeout (jitterbuffer, timer, now); - - /* do_expected_timeout(), called by do_timeout will drop the - * JBUF_LOCK, so we need to check if we are still running */ - if (!priv->timer_running) - goto stopping; - } + while ((timer = rtp_timer_queue_pop_until (priv->timers, now))) + do_timeout (jitterbuffer, timer, now, &events); timer = rtp_timer_queue_peek_earliest (priv->timers); if (timer) { @@ -4070,6 +4083,7 @@ wait_next_timeout (GstRtpJitterBuffer * jitterbuffer) /* let's just push if there is no clock */ GST_DEBUG_OBJECT (jitterbuffer, "No clock, timeout right away"); now = timer->timeout; + push_rtx_events (jitterbuffer, &events); continue; } @@ -4091,18 +4105,21 @@ wait_next_timeout (GstRtpJitterBuffer * jitterbuffer) /* release the lock so that the other end can push stuff or unlock */ JBUF_UNLOCK (priv); + push_rtx_events_unlocked (jitterbuffer, &events); + ret = gst_clock_id_wait (id, &clock_jitter); JBUF_LOCK (priv); if (!priv->timer_running) { + g_queue_clear_full (&events, (GDestroyNotify) gst_event_unref); gst_clock_id_unref (id); priv->clock_id = NULL; break; } if (ret != GST_CLOCK_UNSCHEDULED) { - now = timer->timeout + MAX (clock_jitter, 0); + now = priv->timer_timeout + MAX (clock_jitter, 0); GST_DEBUG_OBJECT (jitterbuffer, "sync done, %d, #%d, %" GST_STIME_FORMAT, ret, priv->timer_seqnum, GST_STIME_ARGS (clock_jitter)); @@ -4114,6 +4131,8 @@ wait_next_timeout (GstRtpJitterBuffer * jitterbuffer) gst_clock_id_unref (id); priv->clock_id = NULL; } else { + push_rtx_events_unlocked (jitterbuffer, &events); + /* when draining the timers, the pusher thread will reuse our * condition to wait for completion. Signal that thread before * sleeping again here */ @@ -4148,9 +4167,9 @@ gst_rtp_jitter_buffer_loop (GstRtpJitterBuffer * jitterbuffer) JBUF_LOCK_CHECK (priv, flushing); do { result = handle_next_buffer (jitterbuffer); - JBUF_SIGNAL_QUEUE (priv); if (G_LIKELY (result == GST_FLOW_WAIT)) { /* now wait for the next event */ + JBUF_SIGNAL_QUEUE (priv); JBUF_WAIT_EVENT (priv, flushing); result = GST_FLOW_OK; } @@ -4380,17 +4399,11 @@ gst_rtp_jitter_buffer_sink_query (GstPad * pad, GstObject * parent, } default: if (GST_QUERY_IS_SERIALIZED (query)) { - RTPJitterBufferItem *item; - gboolean head; - JBUF_LOCK_CHECK (priv, out_flushing); if (rtp_jitter_buffer_get_mode (priv->jbuf) != RTP_JITTER_BUFFER_MODE_BUFFER) { GST_DEBUG_OBJECT (jitterbuffer, "adding serialized query"); - item = rtp_jitter_buffer_alloc_item (query, ITEM_TYPE_QUERY, -1, -1, - -1, 0, -1, NULL); - rtp_jitter_buffer_insert (priv->jbuf, item, &head, NULL); - if (head) + if (rtp_jitter_buffer_append_query (priv->jbuf, query)) JBUF_SIGNAL_EVENT (priv); JBUF_WAIT_QUERY (priv, out_flushing); res = priv->last_query; diff --git a/gst/rtpmanager/gstrtpptdemux.c b/gst/rtpmanager/gstrtpptdemux.c index 397141b7b8..56ce75161b 100644 --- a/gst/rtpmanager/gstrtpptdemux.c +++ b/gst/rtpmanager/gstrtpptdemux.c @@ -313,10 +313,11 @@ gst_rtp_pt_demux_finalize (GObject * object) static GstCaps * gst_rtp_pt_demux_get_caps (GstRtpPtDemux * rtpdemux, guint pt) { - GstCaps *caps; + guint32 ssrc = 0; + gboolean have_ssrc = FALSE; + GstCaps *caps, *sink_caps; GValue ret = { 0 }; GValue args[2] = { {0}, {0} }; - GstCaps *sink_caps; /* figure out the caps */ g_value_init (&args[0], GST_TYPE_ELEMENT); @@ -333,30 +334,26 @@ gst_rtp_pt_demux_get_caps (GstRtpPtDemux * rtpdemux, guint pt) g_value_unset (&args[0]); g_value_unset (&args[1]); caps = g_value_dup_boxed (&ret); - g_value_unset (&ret); - sink_caps = gst_pad_get_current_caps (rtpdemux->sink); + g_value_unset (&ret); - if (sink_caps) { - if (caps == NULL) { - caps = gst_caps_ref (sink_caps); - } else { - GstStructure *s1; - GstStructure *s2; - guint ssrc; - - caps = gst_caps_make_writable (caps); - s1 = gst_caps_get_structure (sink_caps, 0); - s2 = gst_caps_get_structure (caps, 0); - - gst_structure_get_uint (s1, "ssrc", &ssrc); - gst_structure_set (s2, "ssrc", G_TYPE_UINT, ssrc, NULL); - } - + if (caps == NULL) { + caps = sink_caps; + } else if (sink_caps) { + have_ssrc = + gst_structure_get_uint (gst_caps_get_structure (sink_caps, 0), "ssrc", + &ssrc); gst_caps_unref (sink_caps); } - GST_DEBUG ("pt %d, got caps %" GST_PTR_FORMAT, pt, caps); + if (caps != NULL) { + caps = gst_caps_make_writable (caps); + gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL); + if (have_ssrc) + gst_caps_set_simple (caps, "ssrc", G_TYPE_UINT, ssrc, NULL); + } + + GST_DEBUG_OBJECT (rtpdemux, "pt %d, got caps %" GST_PTR_FORMAT, pt, caps); return caps; } @@ -367,7 +364,7 @@ gst_rtp_pt_demux_clear_pt_map (GstRtpPtDemux * rtpdemux) GSList *walk; GST_OBJECT_LOCK (rtpdemux); - GST_DEBUG ("clearing pt map"); + GST_DEBUG_OBJECT (rtpdemux, "clearing pt map"); for (walk = rtpdemux->srcpads; walk; walk = g_slist_next (walk)) { GstRtpPtDemuxPad *pad = walk->data; @@ -489,7 +486,7 @@ gst_rtp_pt_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) g_free (padname); gst_pad_set_event_function (srcpad, gst_rtp_pt_demux_src_event); - GST_DEBUG ("Adding pt=%d to the list.", pt); + GST_DEBUG_OBJECT (rtpdemux, "Adding pt=%d to the list.", pt); rtpdemuxpad = g_slice_new0 (GstRtpPtDemuxPad); rtpdemuxpad->pt = pt; rtpdemuxpad->newcaps = FALSE; @@ -501,14 +498,11 @@ gst_rtp_pt_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) gst_pad_set_active (srcpad, TRUE); - /* First push the stream-start event, it must always come first */ gst_pad_push_event (srcpad, gst_pad_get_sticky_event (rtpdemux->sink, GST_EVENT_STREAM_START, 0)); /* Then caps event is sent */ - caps = gst_caps_make_writable (caps); - gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL); gst_pad_set_caps (srcpad, caps); gst_caps_unref (caps); @@ -518,7 +512,7 @@ gst_rtp_pt_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) gst_element_add_pad (GST_ELEMENT_CAST (rtpdemux), srcpad); - GST_DEBUG ("emitting new-payload-type for pt %d", pt); + GST_DEBUG_OBJECT (rtpdemux, "emitting new-payload-type for pt %d", pt); g_signal_emit (G_OBJECT (rtpdemux), gst_rtp_pt_demux_signals[SIGNAL_NEW_PAYLOAD_TYPE], 0, pt, srcpad); } @@ -528,21 +522,20 @@ gst_rtp_pt_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) /* our own signal with an extra flag that this is the only pad */ rtpdemux->last_pt = pt; - GST_DEBUG ("emitting payload-type-changed for pt %d", emit_pt); + GST_DEBUG_OBJECT (rtpdemux, "emitting payload-type-changed for pt %d", + emit_pt); g_signal_emit (G_OBJECT (rtpdemux), gst_rtp_pt_demux_signals[SIGNAL_PAYLOAD_TYPE_CHANGE], 0, emit_pt); } while (need_caps_for_pt (rtpdemux, pt)) { - GST_DEBUG ("need new caps for %d", pt); + GST_DEBUG_OBJECT (rtpdemux, "need new caps for %d", pt); caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt); if (!caps) goto no_caps; clear_newcaps_for_pt (rtpdemux, pt); - caps = gst_caps_make_writable (caps); - gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL); gst_pad_set_caps (srcpad, caps); gst_caps_unref (caps); } @@ -749,8 +742,8 @@ gst_rtp_pt_demux_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - case GST_STATE_CHANGE_PAUSED_TO_READY: break; + case GST_STATE_CHANGE_PAUSED_TO_READY: case GST_STATE_CHANGE_READY_TO_NULL: gst_rtp_pt_demux_release (ptdemux); break; diff --git a/gst/rtpmanager/gstrtpsession.c b/gst/rtpmanager/gstrtpsession.c index ce5694de1b..0b9fc3d5d2 100644 --- a/gst/rtpmanager/gstrtpsession.c +++ b/gst/rtpmanager/gstrtpsession.c @@ -115,6 +115,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_rtp_session_debug); #define GST_CAT_DEFAULT gst_rtp_session_debug +#define GST_TYPE_RTP_NTP_TIME_SOURCE (gst_rtp_ntp_time_source_get_type ()) GType gst_rtp_ntp_time_source_get_type (void) { @@ -239,6 +240,7 @@ enum PROP_MAX_DROPOUT_TIME, PROP_MAX_MISORDER_TIME, PROP_STATS, + PROP_TWCC_STATS, PROP_RTP_PROFILE, PROP_NTP_TIME_SOURCE, PROP_RTCP_SYNC_SEND_TIME @@ -277,6 +279,8 @@ struct _GstRtpSessionPrivate guint recv_rtx_req_count; guint sent_rtx_req_count; + GstStructure *last_twcc_stats; + /* * This is the list of processed packets in the receive path when upstream * pushed a buffer list. @@ -302,6 +306,8 @@ static GstClockTime gst_rtp_session_request_time (RTPSession * session, gpointer user_data); static void gst_rtp_session_notify_nack (RTPSession * sess, guint16 seqnum, guint16 blp, guint32 ssrc, gpointer user_data); +static void gst_rtp_session_notify_twcc (RTPSession * sess, + GstStructure * twcc_packets, GstStructure * twcc_stats, gpointer user_data); static void gst_rtp_session_reconfigure (RTPSession * sess, gpointer user_data); static void gst_rtp_session_notify_early_rtcp (RTPSession * sess, gpointer user_data); @@ -326,6 +332,7 @@ static RTPSessionCallbacks callbacks = { gst_rtp_session_request_key_unit, gst_rtp_session_request_time, gst_rtp_session_notify_nack, + gst_rtp_session_notify_twcc, gst_rtp_session_reconfigure, gst_rtp_session_notify_early_rtcp }; @@ -729,22 +736,22 @@ gst_rtp_session_class_init (GstRtpSessionClass * klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * GstRtpSession::stats: + * GstRtpSession:stats: * - * Various session statistics. This property returns a GstStructure - * with name application/x-rtp-session-stats with the following fields: + * Various session statistics. This property returns a #GstStructure + * with name `application/x-rtp-session-stats` with the following fields: * - * "recv-rtx-req-count G_TYPE_UINT The number of retransmission event + * * "recv-rtx-req-count" G_TYPE_UINT The number of retransmission events * received from downstream (in receiver mode) (Since 1.16) - * "sent-rtx-req-count" G_TYPE_UINT The number of retransmission event + * * "sent-rtx-req-count" G_TYPE_UINT The number of retransmission events * sent downstream (in sender mode) (Since 1.16) - * "rtx-count" G_TYPE_UINT DEPRECATED Since 1.16, same as + * * "rtx-count" G_TYPE_UINT DEPRECATED Since 1.16, same as * "recv-rtx-req-count". - * "rtx-drop-count" G_TYPE_UINT The number of retransmission events + * * "rtx-drop-count" G_TYPE_UINT The number of retransmission events * dropped (due to bandwidth constraints) - * "sent-nack-count" G_TYPE_UINT Number of NACKs sent - * "recv-nack-count" G_TYPE_UINT Number of NACKs received - * "source-stats" G_TYPE_BOXED GValueArray of #RTPSource::stats for all + * * "sent-nack-count" G_TYPE_UINT Number of NACKs sent + * * "recv-nack-count" G_TYPE_UINT Number of NACKs received + * * "source-stats" G_TYPE_BOXED GValueArray of #RTPSource:stats for all * RTP sources (Since 1.8) * * Since: 1.4 @@ -754,6 +761,30 @@ gst_rtp_session_class_init (GstRtpSessionClass * klass) "Various statistics", GST_TYPE_STRUCTURE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + /** + * GstRtpSession:twcc-stats: + * + * Various statistics derived from TWCC. This property returns a GstStructure + * with name RTPTWCCStats with the following fields: + * + * "bitrate-sent" G_TYPE_UINT The actual sent bitrate of TWCC packets + * "bitrate-recv" G_TYPE_UINT The estimated bitrate for the receiver. + * "packets-sent" G_TYPE_UINT Number of packets sent + * "packets-recv" G_TYPE_UINT Number of packets reported recevied + * "packet-loss-pct" G_TYPE_DOUBLE Packetloss percentage, based on + * packets reported as lost from the recevier. + * "avg-delta-of-delta", G_TYPE_INT64 In nanoseconds, a moving window + * average of the difference in inter-packet spacing between + * sender and receiver. A sudden increase in this number can indicate + * network congestion. + * + * Since: 1.18 + */ + g_object_class_install_property (gobject_class, PROP_TWCC_STATS, + g_param_spec_boxed ("twcc-stats", "TWCC Statistics", + "Various statistics from TWCC", GST_TYPE_STRUCTURE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_RTP_PROFILE, g_param_spec_enum ("rtp-profile", "RTP Profile", "RTP profile to use", GST_TYPE_RTP_PROFILE, DEFAULT_RTP_PROFILE, @@ -762,7 +793,7 @@ gst_rtp_session_class_init (GstRtpSessionClass * klass) g_object_class_install_property (gobject_class, PROP_NTP_TIME_SOURCE, g_param_spec_enum ("ntp-time-source", "NTP Time Source", "NTP time source for RTCP packets", - gst_rtp_ntp_time_source_get_type (), DEFAULT_NTP_TIME_SOURCE, + GST_TYPE_RTP_NTP_TIME_SOURCE, DEFAULT_NTP_TIME_SOURCE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_RTCP_SYNC_SEND_TIME, @@ -812,6 +843,9 @@ gst_rtp_session_class_init (GstRtpSessionClass * klass) GST_DEBUG_REGISTER_FUNCPTR (gst_rtp_session_chain_send_rtp); GST_DEBUG_REGISTER_FUNCPTR (gst_rtp_session_chain_send_rtp_list); + gst_type_mark_as_plugin_api (GST_TYPE_RTP_NTP_TIME_SOURCE, 0); + gst_type_mark_as_plugin_api (RTP_TYPE_SESSION, 0); + gst_type_mark_as_plugin_api (RTP_TYPE_SOURCE, 0); } static void @@ -880,6 +914,8 @@ gst_rtp_session_finalize (GObject * object) g_cond_clear (&rtpsession->priv->cond); g_object_unref (rtpsession->priv->sysclock); g_object_unref (rtpsession->priv->session); + if (rtpsession->priv->last_twcc_stats) + gst_structure_free (rtpsession->priv->last_twcc_stats); G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -1004,6 +1040,11 @@ gst_rtp_session_get_property (GObject * object, guint prop_id, case PROP_STATS: g_value_take_boxed (value, gst_rtp_session_create_stats (rtpsession)); break; + case PROP_TWCC_STATS: + GST_RTP_SESSION_LOCK (rtpsession); + g_value_set_boxed (value, priv->last_twcc_stats); + GST_RTP_SESSION_UNLOCK (rtpsession); + break; case PROP_RTP_PROFILE: g_object_get_property (G_OBJECT (priv->session), "rtp-profile", value); break; @@ -1200,7 +1241,7 @@ start_rtcp_thread (GstRtpSession * rtpsession) g_thread_join (rtpsession->priv->thread); /* only create a new thread if the old one was stopped. Otherwise we can * just reuse the currently running one. */ - rtpsession->priv->thread = g_thread_try_new ("rtpsession-rtcp-thread", + rtpsession->priv->thread = g_thread_try_new ("rtpsession-rtcp", (GThreadFunc) rtcp_thread, rtpsession, &error); rtpsession->priv->thread_stopped = FALSE; } @@ -1563,12 +1604,15 @@ gst_rtp_session_cache_caps (GstRtpSession * rtpsession, GstCaps * caps) GST_DEBUG_OBJECT (rtpsession, "parsing caps"); s = gst_caps_get_structure (caps, 0); + if (!gst_structure_get_int (s, "payload", &payload)) return; if (g_hash_table_lookup (priv->ptmap, GINT_TO_POINTER (payload))) return; + rtp_session_update_recv_caps_structure (rtpsession->priv->session, s); + g_hash_table_insert (priv->ptmap, GINT_TO_POINTER (payload), gst_caps_ref (caps)); } @@ -2801,6 +2845,31 @@ gst_rtp_session_notify_nack (RTPSession * sess, guint16 seqnum, } } +static void +gst_rtp_session_notify_twcc (RTPSession * sess, + GstStructure * twcc_packets, GstStructure * twcc_stats, gpointer user_data) +{ + GstRtpSession *rtpsession = GST_RTP_SESSION (user_data); + GstEvent *event; + GstPad *send_rtp_sink; + + GST_RTP_SESSION_LOCK (rtpsession); + if ((send_rtp_sink = rtpsession->send_rtp_sink)) + gst_object_ref (send_rtp_sink); + if (rtpsession->priv->last_twcc_stats) + gst_structure_free (rtpsession->priv->last_twcc_stats); + rtpsession->priv->last_twcc_stats = twcc_stats; + GST_RTP_SESSION_UNLOCK (rtpsession); + + if (send_rtp_sink) { + event = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, twcc_packets); + gst_pad_push_event (send_rtp_sink, event); + gst_object_unref (send_rtp_sink); + } + + g_object_notify (G_OBJECT (rtpsession), "twcc-stats"); +} + static void gst_rtp_session_reconfigure (RTPSession * sess, gpointer user_data) { diff --git a/gst/rtpmanager/gstrtpssrcdemux.c b/gst/rtpmanager/gstrtpssrcdemux.c index a70fbf33ef..96d53490d9 100644 --- a/gst/rtpmanager/gstrtpssrcdemux.c +++ b/gst/rtpmanager/gstrtpssrcdemux.c @@ -89,6 +89,13 @@ typedef enum RTCP_PAD } PadType; +#define DEFAULT_MAX_STREAMS G_MAXUINT +enum +{ + PROP_0, + PROP_MAX_STREAMS +}; + /* signals */ enum { @@ -273,6 +280,7 @@ find_or_create_demux_pad_for_ssrc (GstRtpSsrcDemux * demux, guint32 ssrc, gchar *padname; GstRtpSsrcDemuxPad *demuxpad; GstPad *retpad; + guint num_streams; INTERNAL_STREAM_LOCK (demux); @@ -281,6 +289,13 @@ find_or_create_demux_pad_for_ssrc (GstRtpSsrcDemux * demux, guint32 ssrc, INTERNAL_STREAM_UNLOCK (demux); return retpad; } + /* We create 2 src pads per ssrc (RTP & RTCP). Checking if we are allowed + to create 2 more pads */ + num_streams = (GST_ELEMENT_CAST (demux)->numsrcpads) >> 1; + if (num_streams >= demux->max_streams) { + INTERNAL_STREAM_UNLOCK (demux); + return NULL; + } GST_DEBUG_OBJECT (demux, "creating new pad for SSRC %08x", ssrc); @@ -347,6 +362,40 @@ find_or_create_demux_pad_for_ssrc (GstRtpSsrcDemux * demux, guint32 ssrc, return retpad; } +static void +gst_rtp_ssrc_demux_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstRtpSsrcDemux *demux; + + demux = GST_RTP_SSRC_DEMUX (object); + switch (prop_id) { + case PROP_MAX_STREAMS: + demux->max_streams = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_rtp_ssrc_demux_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstRtpSsrcDemux *demux; + + demux = GST_RTP_SSRC_DEMUX (object); + switch (prop_id) { + case PROP_MAX_STREAMS: + g_value_set_uint (value, demux->max_streams); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static void gst_rtp_ssrc_demux_class_init (GstRtpSsrcDemuxClass * klass) { @@ -360,6 +409,14 @@ gst_rtp_ssrc_demux_class_init (GstRtpSsrcDemuxClass * klass) gobject_klass->dispose = gst_rtp_ssrc_demux_dispose; gobject_klass->finalize = gst_rtp_ssrc_demux_finalize; + gobject_klass->set_property = gst_rtp_ssrc_demux_set_property; + gobject_klass->get_property = gst_rtp_ssrc_demux_get_property; + + g_object_class_install_property (gobject_klass, PROP_MAX_STREAMS, + g_param_spec_uint ("max-streams", "Max Streams", + "The maximum number of streams allowed", + 0, G_MAXUINT, DEFAULT_MAX_STREAMS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * GstRtpSsrcDemux::new-ssrc-pad: @@ -451,6 +508,8 @@ gst_rtp_ssrc_demux_init (GstRtpSsrcDemux * demux) gst_rtp_ssrc_demux_iterate_internal_links_sink); gst_element_add_pad (GST_ELEMENT_CAST (demux), demux->rtcp_sink); + demux->max_streams = DEFAULT_MAX_STREAMS; + g_rec_mutex_init (&demux->padlock); } @@ -636,18 +695,17 @@ gst_rtp_ssrc_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) /* ERRORS */ invalid_payload: { - /* this is fatal and should be filtered earlier */ - GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL), - ("Dropping invalid RTP payload")); + GST_DEBUG_OBJECT (demux, "Dropping invalid RTP packet"); gst_buffer_unref (buf); - return GST_FLOW_ERROR; + return GST_FLOW_OK; } create_failed: { - GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL), - ("Could not create new pad")); gst_buffer_unref (buf); - return GST_FLOW_ERROR; + GST_WARNING_OBJECT (demux, + "Dropping buffer SSRC %08x. " + "Max streams number reached (%u)", ssrc, demux->max_streams); + return GST_FLOW_OK; } } @@ -686,6 +744,8 @@ gst_rtp_ssrc_demux_rtcp_chain (GstPad * pad, GstObject * parent, ssrc = gst_rtcp_packet_rr_get_ssrc (&packet); break; case GST_RTCP_TYPE_APP: + ssrc = gst_rtcp_packet_app_get_ssrc (&packet); + break; case GST_RTCP_TYPE_RTPFB: case GST_RTCP_TYPE_PSFB: ssrc = gst_rtcp_packet_fb_get_sender_ssrc (&packet); @@ -724,11 +784,9 @@ gst_rtp_ssrc_demux_rtcp_chain (GstPad * pad, GstObject * parent, /* ERRORS */ invalid_rtcp: { - /* this is fatal and should be filtered earlier */ - GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL), - ("Dropping invalid RTCP packet")); + GST_DEBUG_OBJECT (demux, "Dropping invalid RTCP packet"); gst_buffer_unref (buf); - return GST_FLOW_ERROR; + return GST_FLOW_OK; } unexpected_rtcp: { @@ -738,10 +796,11 @@ gst_rtp_ssrc_demux_rtcp_chain (GstPad * pad, GstObject * parent, } create_failed: { - GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL), - ("Could not create new pad")); gst_buffer_unref (buf); - return GST_FLOW_ERROR; + GST_WARNING_OBJECT (demux, + "Dropping buffer SSRC %08x. " + "Max streams number reached (%u)", ssrc, demux->max_streams); + return GST_FLOW_OK; } } @@ -934,9 +993,9 @@ gst_rtp_ssrc_demux_change_state (GstElement * element, case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: + case GST_STATE_CHANGE_READY_TO_NULL: gst_rtp_ssrc_demux_reset (demux); break; - case GST_STATE_CHANGE_READY_TO_NULL: default: break; } diff --git a/gst/rtpmanager/gstrtpssrcdemux.h b/gst/rtpmanager/gstrtpssrcdemux.h index 82df4449e8..3bb210c8e1 100644 --- a/gst/rtpmanager/gstrtpssrcdemux.h +++ b/gst/rtpmanager/gstrtpssrcdemux.h @@ -41,6 +41,7 @@ struct _GstRtpSsrcDemux GRecMutex padlock; GSList *srcpads; + guint max_streams; }; struct _GstRtpSsrcDemuxClass diff --git a/gst/rtpmanager/meson.build b/gst/rtpmanager/meson.build index 221c8e3e5f..118a1e1ea8 100644 --- a/gst/rtpmanager/meson.build +++ b/gst/rtpmanager/meson.build @@ -14,6 +14,7 @@ rtpmanager_sources = [ 'rtpsource.c', 'rtpstats.c', 'rtptimerqueue.c', + 'rtptwcc.c', 'gstrtpsession.c', 'gstrtpfunnel.c', ] diff --git a/gst/rtpmanager/rtpjitterbuffer.c b/gst/rtpmanager/rtpjitterbuffer.c index 0b25fcb52a..aef5cbc352 100644 --- a/gst/rtpmanager/rtpjitterbuffer.c +++ b/gst/rtpmanager/rtpjitterbuffer.c @@ -87,7 +87,7 @@ rtp_jitter_buffer_init (RTPJitterBuffer * jbuf) { g_mutex_init (&jbuf->clock_lock); - jbuf->packets = g_queue_new (); + g_queue_init (&jbuf->packets); jbuf->mode = RTP_JITTER_BUFFER_MODE_SLAVE; rtp_jitter_buffer_reset_skew (jbuf); @@ -112,7 +112,10 @@ rtp_jitter_buffer_finalize (GObject * object) if (jbuf->pipeline_clock) gst_object_unref (jbuf->pipeline_clock); - g_queue_free (jbuf->packets); + /* We cannot use g_queue_clear() as it would pass the wrong size to + * g_slice_free() which may lead to data corruption in the slice allocator. + */ + rtp_jitter_buffer_flush (jbuf, NULL, NULL); g_mutex_clear (&jbuf->clock_lock); @@ -385,7 +388,7 @@ get_buffer_level (RTPJitterBuffer * jbuf) guint64 level; /* first buffer with timestamp */ - high_buf = (RTPJitterBufferItem *) g_queue_peek_tail_link (jbuf->packets); + high_buf = (RTPJitterBufferItem *) g_queue_peek_tail_link (&jbuf->packets); while (high_buf) { if (high_buf->dts != -1 || high_buf->pts != -1) break; @@ -393,7 +396,7 @@ get_buffer_level (RTPJitterBuffer * jbuf) high_buf = (RTPJitterBufferItem *) g_list_previous (high_buf); } - low_buf = (RTPJitterBufferItem *) g_queue_peek_head_link (jbuf->packets); + low_buf = (RTPJitterBufferItem *) g_queue_peek_head_link (&jbuf->packets); while (low_buf) { if (low_buf->dts != -1 || low_buf->pts != -1) break; @@ -678,7 +681,7 @@ calculate_skew (RTPJitterBuffer * jbuf, guint64 ext_rtptime, static void queue_do_insert (RTPJitterBuffer * jbuf, GList * list, GList * item) { - GQueue *queue = jbuf->packets; + GQueue *queue = &jbuf->packets; /* It's more likely that the packet was inserted at the tail of the queue */ if (G_LIKELY (list)) { @@ -916,8 +919,14 @@ rtp_jitter_buffer_calculate_pts (RTPJitterBuffer * jbuf, GstClockTime dts, else pts = 0; - GST_DEBUG ("RFC7273 clock time %" GST_TIME_FORMAT ", out %" GST_TIME_FORMAT, - GST_TIME_ARGS (rtpsystime), GST_TIME_ARGS (pts)); + GST_DEBUG ("RFC7273 clock time %" GST_TIME_FORMAT ", ntptime %" + GST_TIME_FORMAT ", ntprtptime %" G_GUINT64_FORMAT ", rtptime %" + G_GUINT32_FORMAT ", base_time %" GST_TIME_FORMAT ", internal %" + GST_TIME_FORMAT ", external %" GST_TIME_FORMAT ", out %" + GST_TIME_FORMAT, GST_TIME_ARGS (rtpsystime), GST_TIME_ARGS (ntptime), + ntprtptime, rtptime, GST_TIME_ARGS (base_time), + GST_TIME_ARGS (internal), GST_TIME_ARGS (external), + GST_TIME_ARGS (pts)); } else { /* If we used the RFC7273 clock before and not anymore, * we need to resync it later again */ @@ -989,7 +998,7 @@ rtp_jitter_buffer_calculate_pts (RTPJitterBuffer * jbuf, GstClockTime dts, * * Returns: %FALSE if a packet with the same number already existed. */ -gboolean +static gboolean rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, RTPJitterBufferItem * item, gboolean * head, gint * percent) { @@ -999,7 +1008,7 @@ rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, RTPJitterBufferItem * item, g_return_val_if_fail (jbuf != NULL, FALSE); g_return_val_if_fail (item != NULL, FALSE); - list = jbuf->packets->tail; + list = jbuf->packets.tail; /* no seqnum, simply append then */ if (item->seqnum == -1) @@ -1067,10 +1076,156 @@ rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, RTPJitterBufferItem * item, GST_DEBUG ("duplicate packet %d found", (gint) seqnum); if (G_LIKELY (head)) *head = FALSE; + if (percent) + *percent = -1; return FALSE; } } +/** + * rtp_jitter_buffer_alloc_item: + * @data: The data stored in this item + * @type: User specific item type + * @dts: Decoding Timestamp + * @pts: Presentation Timestamp + * @seqnum: Sequence number + * @count: Number of packet this item represent + * @rtptime: The RTP specific timestamp + * @free_data: A function to free @data (optional) + * + * Create an item that can then be stored in the jitter buffer. + * + * Returns: a newly allocated RTPJitterbufferItem + */ +static RTPJitterBufferItem * +rtp_jitter_buffer_alloc_item (gpointer data, guint type, GstClockTime dts, + GstClockTime pts, guint seqnum, guint count, guint rtptime, + GDestroyNotify free_data) +{ + RTPJitterBufferItem *item; + + item = g_slice_new (RTPJitterBufferItem); + item->data = data; + item->next = NULL; + item->prev = NULL; + item->type = type; + item->dts = dts; + item->pts = pts; + item->seqnum = seqnum; + item->count = count; + item->rtptime = rtptime; + item->free_data = free_data; + + return item; +} + +static inline RTPJitterBufferItem * +alloc_event_item (GstEvent * event) +{ + return rtp_jitter_buffer_alloc_item (event, ITEM_TYPE_EVENT, -1, -1, -1, 0, + -1, (GDestroyNotify) gst_mini_object_unref); +} + +/** + * rtp_jitter_buffer_append_event: + * @jbuf: an #RTPJitterBuffer + * @event: an #GstEvent to insert + + * Inserts @event into the packet queue of @jbuf. + * + * Returns: %TRUE if the event is at the head of the queue + */ +gboolean +rtp_jitter_buffer_append_event (RTPJitterBuffer * jbuf, GstEvent * event) +{ + RTPJitterBufferItem *item = alloc_event_item (event); + gboolean head; + rtp_jitter_buffer_insert (jbuf, item, &head, NULL); + return head; +} + +/** + * rtp_jitter_buffer_append_query: + * @jbuf: an #RTPJitterBuffer + * @query: an #GstQuery to insert + + * Inserts @query into the packet queue of @jbuf. + * + * Returns: %TRUE if the query is at the head of the queue + */ +gboolean +rtp_jitter_buffer_append_query (RTPJitterBuffer * jbuf, GstQuery * query) +{ + RTPJitterBufferItem *item = + rtp_jitter_buffer_alloc_item (query, ITEM_TYPE_QUERY, -1, -1, -1, 0, -1, + NULL); + gboolean head; + rtp_jitter_buffer_insert (jbuf, item, &head, NULL); + return head; +} + +/** + * rtp_jitter_buffer_append_lost_event: + * @jbuf: an #RTPJitterBuffer + * @event: an #GstEvent to insert + * @seqnum: Sequence number + * @lost_packets: Number of lost packet this item represent + + * Inserts @event into the packet queue of @jbuf. + * + * Returns: %TRUE if the event is at the head of the queue + */ +gboolean +rtp_jitter_buffer_append_lost_event (RTPJitterBuffer * jbuf, GstEvent * event, + guint16 seqnum, guint lost_packets) +{ + RTPJitterBufferItem *item = rtp_jitter_buffer_alloc_item (event, + ITEM_TYPE_LOST, -1, -1, seqnum, lost_packets, -1, + (GDestroyNotify) gst_mini_object_unref); + gboolean head; + + if (!rtp_jitter_buffer_insert (jbuf, item, &head, NULL)) { + /* Duplicate */ + rtp_jitter_buffer_free_item (item); + head = FALSE; + } + + return head; +} + +/** + * rtp_jitter_buffer_append_buffer: + * @jbuf: an #RTPJitterBuffer + * @buf: an #GstBuffer to insert + * @seqnum: Sequence number + * @duplicate: TRUE when the packet inserted is a duplicate + * @percent: the buffering percent after insertion + * + * Inserts @buf into the packet queue of @jbuf. + * + * Returns: %TRUE if the buffer is at the head of the queue + */ +gboolean +rtp_jitter_buffer_append_buffer (RTPJitterBuffer * jbuf, GstBuffer * buf, + GstClockTime dts, GstClockTime pts, guint16 seqnum, guint rtptime, + gboolean * duplicate, gint * percent) +{ + RTPJitterBufferItem *item = rtp_jitter_buffer_alloc_item (buf, + ITEM_TYPE_BUFFER, dts, pts, seqnum, 1, rtptime, + (GDestroyNotify) gst_mini_object_unref); + gboolean head; + gboolean inserted; + + inserted = rtp_jitter_buffer_insert (jbuf, item, &head, percent); + if (!inserted) + rtp_jitter_buffer_free_item (item); + + if (duplicate) + *duplicate = !inserted; + + return head; +} + /** * rtp_jitter_buffer_pop: * @jbuf: an #RTPJitterBuffer @@ -1090,7 +1245,7 @@ rtp_jitter_buffer_pop (RTPJitterBuffer * jbuf, gint * percent) g_return_val_if_fail (jbuf != NULL, NULL); - queue = jbuf->packets; + queue = &jbuf->packets; item = queue->head; if (item) { @@ -1131,7 +1286,7 @@ rtp_jitter_buffer_peek (RTPJitterBuffer * jbuf) { g_return_val_if_fail (jbuf != NULL, NULL); - return (RTPJitterBufferItem *) jbuf->packets->head; + return (RTPJitterBufferItem *) jbuf->packets.head; } /** @@ -1153,7 +1308,7 @@ rtp_jitter_buffer_flush (RTPJitterBuffer * jbuf, GFunc free_func, if (free_func == NULL) free_func = (GFunc) rtp_jitter_buffer_free_item; - while ((item = g_queue_pop_head_link (jbuf->packets))) + while ((item = g_queue_pop_head_link (&jbuf->packets))) free_func ((RTPJitterBufferItem *) item, user_data); } @@ -1225,7 +1380,7 @@ rtp_jitter_buffer_num_packets (RTPJitterBuffer * jbuf) { g_return_val_if_fail (jbuf != NULL, 0); - return jbuf->packets->length; + return jbuf->packets.length; } /** @@ -1246,8 +1401,8 @@ rtp_jitter_buffer_get_ts_diff (RTPJitterBuffer * jbuf) g_return_val_if_fail (jbuf != NULL, 0); - high_buf = (RTPJitterBufferItem *) g_queue_peek_tail_link (jbuf->packets); - low_buf = (RTPJitterBufferItem *) g_queue_peek_head_link (jbuf->packets); + high_buf = (RTPJitterBufferItem *) g_queue_peek_tail_link (&jbuf->packets); + low_buf = (RTPJitterBufferItem *) g_queue_peek_head_link (&jbuf->packets); if (!high_buf || !low_buf || high_buf == low_buf) return 0; @@ -1283,8 +1438,8 @@ rtp_jitter_buffer_get_seqnum_diff (RTPJitterBuffer * jbuf) g_return_val_if_fail (jbuf != NULL, 0); - high_buf = (RTPJitterBufferItem *) g_queue_peek_tail_link (jbuf->packets); - low_buf = (RTPJitterBufferItem *) g_queue_peek_head_link (jbuf->packets); + high_buf = (RTPJitterBufferItem *) g_queue_peek_tail_link (&jbuf->packets); + low_buf = (RTPJitterBufferItem *) g_queue_peek_head_link (&jbuf->packets); while (high_buf && high_buf->seqnum == -1) high_buf = (RTPJitterBufferItem *) high_buf->prev; @@ -1383,42 +1538,6 @@ rtp_jitter_buffer_is_full (RTPJitterBuffer * jbuf) rtp_jitter_buffer_num_packets (jbuf) > 10000; } -/** - * rtp_jitter_buffer_alloc_item: - * @data: The data stored in this item - * @type: User specific item type - * @dts: Decoding Timestamp - * @pts: Presentation Timestamp - * @seqnum: Sequence number - * @count: Number of packet this item represent - * @rtptime: The RTP specific timestamp - * @free_data: A function to free @data (optional) - * - * Create an item that can then be stored in the jitter buffer. - * - * Returns: a newly allocated RTPJitterbufferItem - */ -RTPJitterBufferItem * -rtp_jitter_buffer_alloc_item (gpointer data, guint type, GstClockTime dts, - GstClockTime pts, guint seqnum, guint count, guint rtptime, - GDestroyNotify free_data) -{ - RTPJitterBufferItem *item; - - item = g_slice_new (RTPJitterBufferItem); - item->data = data; - item->next = NULL; - item->prev = NULL; - item->type = type; - item->dts = dts; - item->pts = pts; - item->seqnum = seqnum; - item->count = count; - item->rtptime = rtptime; - item->free_data = free_data; - - return item; -} /** * rtp_jitter_buffer_free_item: diff --git a/gst/rtpmanager/rtpjitterbuffer.h b/gst/rtpmanager/rtpjitterbuffer.h index 0957f90c33..8accee4b40 100644 --- a/gst/rtpmanager/rtpjitterbuffer.h +++ b/gst/rtpmanager/rtpjitterbuffer.h @@ -73,7 +73,7 @@ GType rtp_jitter_buffer_mode_get_type (void); struct _RTPJitterBuffer { GObject object; - GQueue *packets; + GQueue packets; RTPJitterBufferMode mode; @@ -116,6 +116,12 @@ struct _RTPJitterBufferClass { GObjectClass parent_class; }; +#define IS_DROPABLE(it) (((it)->type == ITEM_TYPE_BUFFER) || ((it)->type == ITEM_TYPE_LOST)) +#define ITEM_TYPE_BUFFER 0 +#define ITEM_TYPE_LOST 1 +#define ITEM_TYPE_EVENT 2 +#define ITEM_TYPE_QUERY 3 + /** * RTPJitterBufferItem: * @data: the data of the item @@ -174,9 +180,14 @@ void rtp_jitter_buffer_set_rfc7273_sync (RTPJitterBuffer *jbuf, void rtp_jitter_buffer_reset_skew (RTPJitterBuffer *jbuf); -gboolean rtp_jitter_buffer_insert (RTPJitterBuffer *jbuf, - RTPJitterBufferItem *item, - gboolean *head, gint *percent); +gboolean rtp_jitter_buffer_append_event (RTPJitterBuffer * jbuf, GstEvent * event); +gboolean rtp_jitter_buffer_append_query (RTPJitterBuffer * jbuf, GstQuery * query); +gboolean rtp_jitter_buffer_append_lost_event (RTPJitterBuffer * jbuf, GstEvent * event, + guint16 seqnum, guint lost_packets); +gboolean rtp_jitter_buffer_append_buffer (RTPJitterBuffer * jbuf, GstBuffer * buf, + GstClockTime dts, GstClockTime pts, + guint16 seqnum, guint rtptime, + gboolean * duplicate, gint * percent); void rtp_jitter_buffer_disable_buffering (RTPJitterBuffer *jbuf, gboolean disabled); @@ -205,9 +216,6 @@ gboolean rtp_jitter_buffer_can_fast_start (RTPJitterBuffer * jbuf gboolean rtp_jitter_buffer_is_full (RTPJitterBuffer * jbuf); -RTPJitterBufferItem * rtp_jitter_buffer_alloc_item (gpointer data, guint type, GstClockTime dts, - GstClockTime pts, guint seqnum, guint count, - guint rtptime, GDestroyNotify free_data); void rtp_jitter_buffer_free_item (RTPJitterBufferItem * item); #endif /* __RTP_JITTER_BUFFER_H__ */ diff --git a/gst/rtpmanager/rtpsession.c b/gst/rtpmanager/rtpsession.c index bfd96ca8ff..dcfb1d796f 100644 --- a/gst/rtpmanager/rtpsession.c +++ b/gst/rtpmanager/rtpsession.c @@ -22,6 +22,7 @@ #define GLIB_DISABLE_DEPRECATION_WARNINGS #include +#include #include #include @@ -30,7 +31,7 @@ #include "rtpsession.h" -GST_DEBUG_CATEGORY_STATIC (rtp_session_debug); +GST_DEBUG_CATEGORY (rtp_session_debug); #define GST_CAT_DEFAULT rtp_session_debug /* signals and args */ @@ -115,6 +116,8 @@ enum (avg) = ((val) + (15 * (avg))) >> 4; +#define TWCC_EXTMAP_STR "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01" + /* GObject vmethods */ static void rtp_session_finalize (GObject * object); static void rtp_session_set_property (GObject * object, guint prop_id, @@ -449,7 +452,9 @@ rtp_session_class_init (RTPSessionClass * klass) g_object_class_install_property (gobject_class, PROP_INTERNAL_SSRC, g_param_spec_uint ("internal-ssrc", "Internal SSRC", "The internal SSRC used for the session (deprecated)", - 0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_DOC_SHOW_DEFAULT)); g_object_class_install_property (gobject_class, PROP_INTERNAL_SOURCE, g_param_spec_object ("internal-source", "Internal Source", @@ -503,12 +508,13 @@ rtp_session_class_init (RTPSessionClass * klass) DEFAULT_NUM_ACTIVE_SOURCES, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** - * RTPSource::sources + * RTPSource:sources * * Get a GValue Array of all sources in the session. * * ## Getting the #RTPSources of a session - * |[ + * + * ``` C * { * GValueArray *arr; * GValue *val; @@ -524,7 +530,7 @@ rtp_session_class_init (RTPSessionClass * klass) * } * g_value_array_free (arr); * } - * ]| + * ``` */ g_object_class_install_property (gobject_class, PROP_SOURCES, g_param_spec_boxed ("sources", "Sources", @@ -578,16 +584,16 @@ rtp_session_class_init (RTPSessionClass * klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * RTPSession::stats: + * RTPSession:stats: * * Various session statistics. This property returns a GstStructure * with name application/x-rtp-session-stats with the following fields: * - * "rtx-drop-count" G_TYPE_UINT The number of retransmission events + * * "rtx-drop-count" G_TYPE_UINT The number of retransmission events * dropped (due to bandwidth constraints) - * "sent-nack-count" G_TYPE_UINT Number of NACKs sent - * "recv-nack-count" G_TYPE_UINT Number of NACKs received - * "source-stats" G_TYPE_BOXED GValueArray of #RTPSource::stats for all + * * "sent-nack-count" G_TYPE_UINT Number of NACKs sent + * * "recv-nack-count" G_TYPE_UINT Number of NACKs received + * * "source-stats" G_TYPE_BOXED GValueArray of #RTPSource:stats for all * RTP sources (Since 1.8) * * Since: 1.4 @@ -609,7 +615,7 @@ rtp_session_class_init (RTPSessionClass * klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * RTPSession::disable-sr-timestamp: + * RTPSession:disable-sr-timestamp: * * Whether sender reports should be timestamped. * @@ -706,6 +712,9 @@ rtp_session_init (RTPSession * sess) sess->timestamp_sender_reports = !DEFAULT_RTCP_DISABLE_SR_TIMESTAMP; sess->is_doing_ptp = TRUE; + + sess->twcc = rtp_twcc_manager_new (sess->mtu); + sess->twcc_stats = rtp_twcc_stats_new (); } static void @@ -727,6 +736,9 @@ rtp_session_finalize (GObject * object) for (i = 0; i < 1; i++) g_hash_table_destroy (sess->ssrcs[i]); + g_object_unref (sess->twcc); + rtp_twcc_stats_free (sess->twcc_stats); + g_mutex_clear (&sess->lock); G_OBJECT_CLASS (rtp_session_parent_class)->finalize (object); @@ -847,6 +859,7 @@ rtp_session_set_property (GObject * object, guint prop_id, break; case PROP_RTCP_MTU: sess->mtu = g_value_get_uint (value); + rtp_twcc_manager_set_mtu (sess->twcc, sess->mtu); break; case PROP_SDES: rtp_session_set_sdes_struct (sess, g_value_get_boxed (value)); @@ -1206,6 +1219,10 @@ rtp_session_set_callbacks (RTPSession * sess, RTPSessionCallbacks * callbacks, sess->callbacks.notify_nack = callbacks->notify_nack; sess->notify_nack_user_data = user_data; } + if (callbacks->notify_twcc) { + sess->callbacks.notify_twcc = callbacks->notify_twcc; + sess->notify_twcc_user_data = user_data; + } if (callbacks->reconfigure) { sess->callbacks.reconfigure = callbacks->reconfigure; sess->reconfigure_user_data = user_data; @@ -2067,10 +2084,15 @@ update_packet (GstBuffer ** buffer, guint idx, RTPPacketInfo * pinfo) pinfo->seqnum = gst_rtp_buffer_get_seq (&rtp); pinfo->pt = gst_rtp_buffer_get_payload_type (&rtp); pinfo->rtptime = gst_rtp_buffer_get_timestamp (&rtp); + pinfo->marker = gst_rtp_buffer_get_marker (&rtp); /* copy available csrc */ pinfo->csrc_count = gst_rtp_buffer_get_csrc_count (&rtp); for (i = 0; i < pinfo->csrc_count; i++) pinfo->csrcs[i] = gst_rtp_buffer_get_csrc (&rtp, i); + + /* RTP header extensions */ + pinfo->header_ext = gst_rtp_buffer_get_extension_bytes (&rtp, + &pinfo->header_ext_bit_pattern); } gst_rtp_buffer_unmap (&rtp); } @@ -2119,6 +2141,7 @@ update_packet_info (RTPSession * sess, RTPPacketInfo * pinfo, pinfo->bytes = 0; pinfo->payload_len = 0; pinfo->packets = 0; + pinfo->marker = FALSE; if (is_list) { GstBufferList *list = GST_BUFFER_LIST_CAST (data); @@ -2129,6 +2152,7 @@ update_packet_info (RTPSession * sess, RTPPacketInfo * pinfo, GstBuffer *buffer = GST_BUFFER_CAST (data); res = update_packet (&buffer, 0, pinfo); } + return res; } @@ -2141,6 +2165,24 @@ clean_packet_info (RTPPacketInfo * pinfo) gst_mini_object_unref (pinfo->data); pinfo->data = NULL; } + if (pinfo->header_ext) + g_bytes_unref (pinfo->header_ext); +} + +static gint32 +packet_info_get_twcc_seqnum (RTPPacketInfo * pinfo, guint8 ext_id) +{ + gint32 val = -1; + gpointer data; + guint size; + + if (pinfo->header_ext && + gst_rtp_buffer_get_extension_onebyte_header_from_bytes (pinfo->header_ext, + pinfo->header_ext_bit_pattern, ext_id, 0, &data, &size)) { + if (size == 2) + val = GST_READ_UINT16_BE (data); + } + return val; } static gboolean @@ -2165,6 +2207,30 @@ source_update_active (RTPSession * sess, RTPSource * source, return TRUE; } +static void +process_twcc_packet (RTPSession * sess, RTPPacketInfo * pinfo) +{ + gint32 twcc_seqnum; + + if (sess->twcc_recv_ext_id == 0) + return; + + twcc_seqnum = packet_info_get_twcc_seqnum (pinfo, sess->twcc_recv_ext_id); + if (twcc_seqnum == -1) + return; + + if (rtp_twcc_manager_recv_packet (sess->twcc, twcc_seqnum, pinfo)) { + RTP_SESSION_UNLOCK (sess); + + /* TODO: find a better rational for this number, and possibly tune it based + on factors like framerate / bandwidth etc */ + if (!rtp_session_send_rtcp (sess, 100 * GST_MSECOND)) { + GST_INFO ("Could not schedule TWCC straight away"); + } + RTP_SESSION_LOCK (sess); + } +} + static gboolean source_update_sender (RTPSession * sess, RTPSource * source, gboolean prevsender) @@ -2244,6 +2310,7 @@ rtp_session_process_rtp (RTPSession * sess, GstBuffer * buffer, /* let source process the packet */ result = rtp_source_process_rtp (source, &pinfo); + process_twcc_packet (sess, &pinfo); /* source became active */ if (source_update_active (sess, source, prevactive)) @@ -2801,6 +2868,35 @@ rtp_session_process_nack (RTPSession * sess, guint32 sender_ssrc, } } +static void +rtp_session_process_twcc (RTPSession * sess, guint32 sender_ssrc, + guint32 media_ssrc, guint8 * fci_data, guint fci_length) +{ + GArray *twcc_packets; + GstStructure *twcc_packets_s; + GstStructure *twcc_stats_s; + + twcc_packets = rtp_twcc_manager_parse_fci (sess->twcc, + fci_data, fci_length * sizeof (guint32)); + if (twcc_packets == NULL) + return; + + twcc_packets_s = rtp_twcc_stats_get_packets_structure (twcc_packets); + twcc_stats_s = + rtp_twcc_stats_process_packets (sess->twcc_stats, twcc_packets); + + GST_DEBUG_OBJECT (sess, "Parsed TWCC: %" GST_PTR_FORMAT, twcc_packets_s); + GST_INFO_OBJECT (sess, "Current TWCC stats %" GST_PTR_FORMAT, twcc_stats_s); + + g_array_unref (twcc_packets); + + RTP_SESSION_UNLOCK (sess); + if (sess->callbacks.notify_twcc) + sess->callbacks.notify_twcc (sess, twcc_packets_s, twcc_stats_s, + sess->notify_twcc_user_data); + RTP_SESSION_LOCK (sess); +} + static void rtp_session_process_feedback (RTPSession * sess, GstRTCPPacket * packet, RTPPacketInfo * pinfo, GstClockTime current_time) @@ -2862,7 +2958,9 @@ rtp_session_process_feedback (RTPSession * sess, GstRTCPPacket * packet, if ((src && src->internal) || /* PSFB FIR puts the media ssrc inside the FCI */ - (type == GST_RTCP_TYPE_PSFB && fbtype == GST_RTCP_PSFB_TYPE_FIR)) { + (type == GST_RTCP_TYPE_PSFB && fbtype == GST_RTCP_PSFB_TYPE_FIR) || + /* TWCC is for all sources, so a single media-ssrc is not enough */ + (type == GST_RTCP_TYPE_RTPFB && fbtype == GST_RTCP_RTPFB_TYPE_TWCC)) { switch (type) { case GST_RTCP_TYPE_PSFB: switch (fbtype) { @@ -2890,6 +2988,10 @@ rtp_session_process_feedback (RTPSession * sess, GstRTCPPacket * packet, rtp_session_process_nack (sess, sender_ssrc, media_ssrc, fci_data, fci_length, current_time); break; + case GST_RTCP_RTPFB_TYPE_TWCC: + rtp_session_process_twcc (sess, sender_ssrc, media_ssrc, + fci_data, fci_length); + break; default: break; } @@ -3021,6 +3123,29 @@ rtp_session_process_rtcp (RTPSession * sess, GstBuffer * buffer, } } +static guint8 +_get_extmap_id_for_attribute (const GstStructure * s, const gchar * ext_name) +{ + guint i; + guint8 extmap_id = 0; + guint n_fields = gst_structure_n_fields (s); + + for (i = 0; i < n_fields; i++) { + const gchar *field_name = gst_structure_nth_field_name (s, i); + if (g_str_has_prefix (field_name, "extmap-")) { + const gchar *str = gst_structure_get_string (s, field_name); + if (str && g_strcmp0 (str, ext_name) == 0) { + gint64 id = g_ascii_strtoll (field_name + 7, NULL, 10); + if (id > 0 && id < 15) { + extmap_id = id; + break; + } + } + } + } + return extmap_id; +} + /** * rtp_session_update_send_caps: * @sess: an #RTPSession @@ -3075,8 +3200,30 @@ rtp_session_update_send_caps (RTPSession * sess, GstCaps * caps) } else { sess->internal_ssrc_from_caps_or_property = FALSE; } + + sess->twcc_send_ext_id = _get_extmap_id_for_attribute (s, TWCC_EXTMAP_STR); + if (sess->twcc_send_ext_id > 0) { + GST_INFO ("TWCC enabled for send using extension id: %u", + sess->twcc_send_ext_id); + } +} + +static void +send_twcc_packet (RTPSession * sess, RTPPacketInfo * pinfo) +{ + gint32 twcc_seqnum; + + if (sess->twcc_send_ext_id == 0) + return; + + twcc_seqnum = packet_info_get_twcc_seqnum (pinfo, sess->twcc_send_ext_id); + if (twcc_seqnum == -1) + return; + + rtp_twcc_manager_send_packet (sess->twcc, twcc_seqnum, pinfo); } + /** * rtp_session_send_rtp: * @sess: an #RTPSession @@ -3111,6 +3258,8 @@ rtp_session_send_rtp (RTPSession * sess, gpointer data, gboolean is_list, current_time, running_time, -1)) goto invalid_packet; + send_twcc_packet (sess, &pinfo); + source = obtain_internal_source (sess, pinfo.ssrc, &created, current_time); if (created) on_new_sender_ssrc (sess, source); @@ -3168,7 +3317,7 @@ rtp_session_send_rtp (RTPSession * sess, gpointer data, gboolean is_list, collision: { g_object_unref (source); - gst_mini_object_unref (GST_MINI_OBJECT_CAST (data)); + clean_packet_info (&pinfo); RTP_SESSION_UNLOCK (sess); GST_WARNING ("non-internal source with same ssrc %08x, drop packet", pinfo.ssrc); @@ -4114,6 +4263,37 @@ remove_closing_sources (const gchar * key, RTPSource * source, return FALSE; } +static void +generate_twcc (const gchar * key, RTPSource * source, ReportData * data) +{ + RTPSession *sess = data->sess; + GstBuffer *buf; + + /* only generate RTCP for active internal sources */ + if (!source->internal || source->sent_bye) + return; + + /* ignore other sources when we do the timeout after a scheduled BYE */ + if (sess->scheduled_bye && !source->marked_bye) + return; + + /* skip if RTCP is disabled */ + if (source->disable_rtcp) { + GST_DEBUG ("source %08x has RTCP disabled", source->ssrc); + return; + } + + while ((buf = rtp_twcc_manager_get_feedback (sess->twcc, source->ssrc))) { + ReportOutput *output = g_slice_new (ReportOutput); + output->source = g_object_ref (source); + output->is_bye = FALSE; + output->buffer = buf; + /* queue the RTCP packet to push later */ + g_queue_push_tail (&data->output, output); + } +} + + static void generate_rtcp (const gchar * key, RTPSource * source, ReportData * data) { @@ -4338,6 +4518,9 @@ rtp_session_on_timeout (RTPSession * sess, GstClockTime current_time, g_hash_table_foreach (sess->ssrcs[sess->mask_idx], (GHFunc) generate_rtcp, &data); + g_hash_table_foreach (sess->ssrcs[sess->mask_idx], + (GHFunc) generate_twcc, &data); + /* update the generation for all the sources that have been reported */ g_hash_table_foreach (sess->ssrcs[sess->mask_idx], (GHFunc) update_generation, &data); @@ -4721,3 +4904,22 @@ rtp_session_request_nack (RTPSession * sess, guint32 ssrc, guint16 seqnum, return FALSE; } } + +/** + * rtp_session_update_recv_caps_structure: + * @sess: an #RTPSession + * @s: a #GstStructure from a #GstCaps + * + * Update the caps of the receiver in the rtp session. + */ +void +rtp_session_update_recv_caps_structure (RTPSession * sess, + const GstStructure * s) +{ + guint8 ext_id = _get_extmap_id_for_attribute (s, TWCC_EXTMAP_STR); + if (ext_id > 0) { + sess->twcc_recv_ext_id = ext_id; + GST_INFO ("TWCC enabled for recv using extension id: %u", + sess->twcc_recv_ext_id); + } +} diff --git a/gst/rtpmanager/rtpsession.h b/gst/rtpmanager/rtpsession.h index 6aa28ca2e0..949fcc49b8 100644 --- a/gst/rtpmanager/rtpsession.h +++ b/gst/rtpmanager/rtpsession.h @@ -23,6 +23,7 @@ #include #include "rtpsource.h" +#include "rtptwcc.h" typedef struct _RTPSession RTPSession; typedef struct _RTPSessionClass RTPSessionClass; @@ -156,6 +157,15 @@ typedef GstClockTime (*RTPSessionRequestTime) (RTPSession *sess, typedef void (*RTPSessionNotifyNACK) (RTPSession *sess, guint16 seqnum, guint16 blp, guint32 ssrc, gpointer user_data); +/** + * RTPSessionNotifyTWCC: + * @user_data: user data specified when registering + * + * Notifies of Transport-wide congestion control packets and stats. + */ +typedef void (*RTPSessionNotifyTWCC) (RTPSession *sess, + GstStructure * twcc_packets, GstStructure * twcc_stats, gpointer user_data); + /** * RTPSessionReconfigure: * @sess: an #RTPSession @@ -186,6 +196,7 @@ typedef void (*RTPSessionNotifyEarlyRTCP) (RTPSession *sess, * @RTPSessionRequestKeyUnit: callback for requesting a new key unit * @RTPSessionRequestTime: callback for requesting the current time * @RTPSessionNotifyNACK: callback for notifying NACK + * @RTPSessionNotifyTWCC: callback for notifying TWCC * @RTPSessionReconfigure: callback for requesting reconfiguration * @RTPSessionNotifyEarlyRTCP: callback for notifying early RTCP * @@ -203,6 +214,7 @@ typedef struct { RTPSessionRequestKeyUnit request_key_unit; RTPSessionRequestTime request_time; RTPSessionNotifyNACK notify_nack; + RTPSessionNotifyTWCC notify_twcc; RTPSessionReconfigure reconfigure; RTPSessionNotifyEarlyRTCP notify_early_rtcp; } RTPSessionCallbacks; @@ -280,6 +292,7 @@ struct _RTPSession { gpointer request_key_unit_user_data; gpointer request_time_user_data; gpointer notify_nack_user_data; + gpointer notify_twcc_user_data; gpointer reconfigure_user_data; gpointer notify_early_rtcp_user_data; @@ -295,6 +308,12 @@ struct _RTPSession { GList *conflicting_addresses; gboolean timestamp_sender_reports; + + /* Transport-wide cc-extension */ + RTPTWCCManager *twcc; + RTPTWCCStats *twcc_stats; + guint8 twcc_recv_ext_id; + guint8 twcc_send_ext_id; }; /** @@ -418,5 +437,7 @@ gboolean rtp_session_request_nack (RTPSession * sess, guint16 seqnum, GstClockTime max_delay); +void rtp_session_update_recv_caps_structure (RTPSession * sess, const GstStructure * s); + #endif /* __RTP_SESSION_H__ */ diff --git a/gst/rtpmanager/rtpsource.c b/gst/rtpmanager/rtpsource.c index ac4b89d1ce..12aa125499 100644 --- a/gst/rtpmanager/rtpsource.c +++ b/gst/rtpmanager/rtpsource.c @@ -105,7 +105,7 @@ rtp_source_class_init (RTPSourceClass * klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** - * RTPSource::sdes + * RTPSource:sdes * * The current SDES items of the source. Returns a structure with name * application/x-rtp-source-sdes and may contain the following fields: @@ -127,7 +127,7 @@ rtp_source_class_init (RTPSourceClass * klass) GST_TYPE_STRUCTURE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** - * RTPSource::stats + * RTPSource:stats * * This property returns a GstStructure named application/x-rtp-source-stats with * fields useful for statistics and diagnostics. @@ -144,77 +144,77 @@ rtp_source_class_init (RTPSourceClass * klass) * * The following fields are always present. * - * "ssrc" G_TYPE_UINT the SSRC of this source - * "internal" G_TYPE_BOOLEAN this source is a source of the session - * "validated" G_TYPE_BOOLEAN the source is validated - * "received-bye" G_TYPE_BOOLEAN we received a BYE from this source - * "is-csrc" G_TYPE_BOOLEAN this source was found as CSRC - * "is-sender" G_TYPE_BOOLEAN this source is a sender - * "seqnum-base" G_TYPE_INT first seqnum if known - * "clock-rate" G_TYPE_INT the clock rate of the media + * * "ssrc" G_TYPE_UINT the SSRC of this source + * * "internal" G_TYPE_BOOLEAN this source is a source of the session + * * "validated" G_TYPE_BOOLEAN the source is validated + * * "received-bye" G_TYPE_BOOLEAN we received a BYE from this source + * * "is-csrc" G_TYPE_BOOLEAN this source was found as CSRC + * * "is-sender" G_TYPE_BOOLEAN this source is a sender + * * "seqnum-base" G_TYPE_INT first seqnum if known + * * "clock-rate" G_TYPE_INT the clock rate of the media * * The following fields are only present when known. * - * "rtp-from" G_TYPE_STRING where we received the last RTP packet from - * "rtcp-from" G_TYPE_STRING where we received the last RTCP packet from + * * "rtp-from" G_TYPE_STRING where we received the last RTP packet from + * * "rtcp-from" G_TYPE_STRING where we received the last RTCP packet from * * The following fields make sense for internal sources and will only increase * when "is-sender" is TRUE. * - * "octets-sent" G_TYPE_UINT64 number of payload bytes we sent - * "packets-sent" G_TYPE_UINT64 number of packets we sent + * * "octets-sent" G_TYPE_UINT64 number of payload bytes we sent + * * "packets-sent" G_TYPE_UINT64 number of packets we sent * * The following fields make sense for non-internal sources and will only * increase when "is-sender" is TRUE. * - * "octets-received" G_TYPE_UINT64 total number of payload bytes received - * "packets-received" G_TYPE_UINT64 total number of packets received - * "bytes-received" G_TYPE_UINT64 total number of bytes received including lower level headers overhead + * * "octets-received" G_TYPE_UINT64 total number of payload bytes received + * * "packets-received" G_TYPE_UINT64 total number of packets received + * * "bytes-received" G_TYPE_UINT64 total number of bytes received including lower level headers overhead * * Following fields are updated when "is-sender" is TRUE. * - * "bitrate" G_TYPE_UINT64 bitrate in bits per second - * "jitter" G_TYPE_UINT estimated jitter (in clock rate units) - * "packets-lost" G_TYPE_INT estimated amount of packets lost + * * "bitrate" G_TYPE_UINT64 bitrate in bits per second + * * "jitter" G_TYPE_UINT estimated jitter (in clock rate units) + * * "packets-lost" G_TYPE_INT estimated amount of packets lost * * The last SR report this source sent. This only updates when "is-sender" is * TRUE. * - * "have-sr" G_TYPE_BOOLEAN the source has sent SR - * "sr-ntptime" G_TYPE_UINT64 NTP time of SR (in NTP Timestamp Format, 32.32 fixed point) - * "sr-rtptime" G_TYPE_UINT RTP time of SR (in clock rate units) - * "sr-octet-count" G_TYPE_UINT the number of bytes in the SR - * "sr-packet-count" G_TYPE_UINT the number of packets in the SR + * * "have-sr" G_TYPE_BOOLEAN the source has sent SR + * * "sr-ntptime" G_TYPE_UINT64 NTP time of SR (in NTP Timestamp Format, 32.32 fixed point) + * * "sr-rtptime" G_TYPE_UINT RTP time of SR (in clock rate units) + * * "sr-octet-count" G_TYPE_UINT the number of bytes in the SR + * * "sr-packet-count" G_TYPE_UINT the number of packets in the SR * * The following fields are only present for non-internal sources and * represent the content of the last RB packet that was sent to this source. * These values are only updated when the source is sending. * - * "sent-rb" G_TYPE_BOOLEAN we have sent an RB - * "sent-rb-fractionlost" G_TYPE_UINT calculated lost 8-bit fraction - * "sent-rb-packetslost" G_TYPE_INT lost packets - * "sent-rb-exthighestseq" G_TYPE_UINT last seen seqnum - * "sent-rb-jitter" G_TYPE_UINT jitter (in clock rate units) - * "sent-rb-lsr" G_TYPE_UINT last SR time (seconds in NTP Short Format, 16.16 fixed point) - * "sent-rb-dlsr" G_TYPE_UINT delay since last SR (seconds in NTP Short Format, 16.16 fixed point) + * * "sent-rb" G_TYPE_BOOLEAN we have sent an RB + * * "sent-rb-fractionlost" G_TYPE_UINT calculated lost 8-bit fraction + * * "sent-rb-packetslost" G_TYPE_INT lost packets + * * "sent-rb-exthighestseq" G_TYPE_UINT last seen seqnum + * * "sent-rb-jitter" G_TYPE_UINT jitter (in clock rate units) + * * "sent-rb-lsr" G_TYPE_UINT last SR time (seconds in NTP Short Format, 16.16 fixed point) + * * "sent-rb-dlsr" G_TYPE_UINT delay since last SR (seconds in NTP Short Format, 16.16 fixed point) * * The following fields are only present for non-internal sources and * represents the last RB that this source sent. This is only updated * when the source is receiving data and sending RB blocks. * - * "have-rb" G_TYPE_BOOLEAN the source has sent RB - * "rb-fractionlost" G_TYPE_UINT lost 8-bit fraction - * "rb-packetslost" G_TYPE_INT lost packets - * "rb-exthighestseq" G_TYPE_UINT highest received seqnum - * "rb-jitter" G_TYPE_UINT reception jitter (in clock rate units) - * "rb-lsr" G_TYPE_UINT last SR time (seconds in NTP Short Format, 16.16 fixed point) - * "rb-dlsr" G_TYPE_UINT delay since last SR (seconds in NTP Short Format, 16.16 fixed point) + * * "have-rb" G_TYPE_BOOLEAN the source has sent RB + * * "rb-fractionlost" G_TYPE_UINT lost 8-bit fraction + * * "rb-packetslost" G_TYPE_INT lost packets + * * "rb-exthighestseq" G_TYPE_UINT highest received seqnum + * * "rb-jitter" G_TYPE_UINT reception jitter (in clock rate units) + * * "rb-lsr" G_TYPE_UINT last SR time (seconds in NTP Short Format, 16.16 fixed point) + * * "rb-dlsr" G_TYPE_UINT delay since last SR (seconds in NTP Short Format, 16.16 fixed point) * * The round trip of this source is calculated from the last RB * values and the reception time of the last RB packet. It is only present for * non-internal sources. * - * "rb-round-trip" G_TYPE_UINT the round-trip time (seconds in NTP Short Format, 16.16 fixed point) + * * "rb-round-trip" G_TYPE_UINT the round-trip time (seconds in NTP Short Format, 16.16 fixed point) * */ g_object_class_install_property (gobject_class, PROP_STATS, @@ -241,7 +241,7 @@ rtp_source_class_init (RTPSourceClass * klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * RTPSession::disable-rtcp: + * RTPSource:disable-rtcp: * * Allow disabling the sending of RTCP packets for this source. */ @@ -426,7 +426,9 @@ rtp_source_create_stats (RTPSource * src) "sent-fir-count", G_TYPE_UINT, src->stats.sent_fir_count, "recv-fir-count", G_TYPE_UINT, src->stats.recv_fir_count, "sent-nack-count", G_TYPE_UINT, src->stats.sent_nack_count, - "recv-nack-count", G_TYPE_UINT, src->stats.recv_nack_count, NULL); + "recv-nack-count", G_TYPE_UINT, src->stats.recv_nack_count, + "recv-packet-rate", G_TYPE_UINT, + gst_rtp_packet_rate_ctx_get (&src->packet_rate_ctx), NULL); /* get the last SR. */ have_sr = rtp_source_get_last_sr (src, &time, &ntptime, &rtptime, @@ -918,8 +920,8 @@ push_packet (RTPSource * src, GstBuffer * buffer) return ret; } -static gint -get_clock_rate (RTPSource * src, guint8 payload) +static void +fetch_clock_rate_from_payload (RTPSource * src, guint8 payload) { if (src->payload == -1) { /* first payload received, nothing was in the caps, lock on to this payload */ @@ -944,7 +946,6 @@ get_clock_rate (RTPSource * src, guint8 payload) src->clock_rate = clock_rate; gst_rtp_packet_rate_ctx_reset (&src->packet_rate_ctx, clock_rate); } - return src->clock_rate; } /* Jitter is the variation in the delay of received packets in a flow. It is @@ -958,26 +959,23 @@ calculate_jitter (RTPSource * src, RTPPacketInfo * pinfo) GstClockTime running_time; guint32 rtparrival, transit, rtptime; gint32 diff; - gint clock_rate; - guint8 pt; /* get arrival time */ if ((running_time = pinfo->running_time) == GST_CLOCK_TIME_NONE) goto no_time; - pt = pinfo->pt; + GST_LOG ("SSRC %08x got payload %d", src->ssrc, pinfo->pt); - GST_LOG ("SSRC %08x got payload %d", src->ssrc, pt); - - /* get clockrate */ - if ((clock_rate = get_clock_rate (src, pt)) == -1) + /* check if clock-rate is valid */ + if (src->clock_rate == -1) goto no_clock_rate; rtptime = pinfo->rtptime; /* convert arrival time to RTP timestamp units, truncate to 32 bits, we don't * care about the absolute value, just the difference. */ - rtparrival = gst_util_uint64_scale_int (running_time, clock_rate, GST_SECOND); + rtparrival = + gst_util_uint64_scale_int (running_time, src->clock_rate, GST_SECOND); /* transit time is difference with RTP timestamp */ transit = rtparrival - rtptime; @@ -1000,7 +998,7 @@ calculate_jitter (RTPSource * src, RTPPacketInfo * pinfo) src->stats.last_rtptime = rtparrival; GST_LOG ("rtparrival %u, rtptime %u, clock-rate %d, diff %d, jitter: %f", - rtparrival, rtptime, clock_rate, diff, (src->stats.jitter) / 16.0); + rtparrival, rtptime, src->clock_rate, diff, (src->stats.jitter) / 16.0); return; @@ -1012,7 +1010,7 @@ calculate_jitter (RTPSource * src, RTPPacketInfo * pinfo) } no_clock_rate: { - GST_WARNING ("cannot get clock-rate for pt %d", pt); + GST_WARNING ("cannot get clock-rate for pt %d", pinfo->pt); return; } } @@ -1263,6 +1261,8 @@ rtp_source_process_rtp (RTPSource * src, RTPPacketInfo * pinfo) g_return_val_if_fail (RTP_IS_SOURCE (src), GST_FLOW_ERROR); g_return_val_if_fail (pinfo != NULL, GST_FLOW_ERROR); + fetch_clock_rate_from_payload (src, pinfo->pt); + if (!update_receiver_stats (src, pinfo, TRUE)) return GST_FLOW_OK; @@ -1551,7 +1551,7 @@ rtp_source_get_new_sr (RTPSource * src, guint64 ntpnstime, if (src->clock_rate == -1 && src->pt_set) { GST_INFO ("no clock-rate, getting for pt %u and SSRC %u", src->pt, src->ssrc); - get_clock_rate (src, src->pt); + fetch_clock_rate_from_payload (src, src->pt); } if (src->clock_rate != -1) { diff --git a/gst/rtpmanager/rtpstats.c b/gst/rtpmanager/rtpstats.c index 27063ee9ce..45fff37058 100644 --- a/gst/rtpmanager/rtpstats.c +++ b/gst/rtpmanager/rtpstats.c @@ -19,7 +19,10 @@ * Boston, MA 02110-1301, USA. */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #include "rtpstats.h" +#include "rtptwcc.h" void gst_rtp_packet_rate_ctx_reset (RTPPacketRateCtx * ctx, gint32 clock_rate) @@ -37,6 +40,7 @@ gst_rtp_packet_rate_ctx_update (RTPPacketRateCtx * ctx, guint16 seqnum, guint64 new_ts, diff_ts; gint diff_seqnum; gint32 new_packet_rate; + gint32 base; if (ctx->clock_rate <= 0) { return ctx->avg_packet_rate; @@ -47,13 +51,21 @@ gst_rtp_packet_rate_ctx_update (RTPPacketRateCtx * ctx, guint16 seqnum, if (!ctx->probed) { ctx->probed = TRUE; - goto done; + goto done_but_save; } diff_seqnum = gst_rtp_buffer_compare_seqnum (ctx->last_seqnum, seqnum); - if (diff_seqnum <= 0 || new_ts <= ctx->last_ts || diff_seqnum > 1) { + /* Ignore seqnums that are over 15,000 away from the latest one, it's close + * to 2^14 but far enough to avoid any risk of computing error. + */ + if (diff_seqnum > 15000) + goto done_but_save; + + /* Ignore any packet that is in the past, we're only interested in newer + * packets to compute the packet rate. + */ + if (diff_seqnum <= 0 || new_ts <= ctx->last_ts) goto done; - } diff_ts = new_ts - ctx->last_ts; diff_ts = gst_util_uint64_scale_int (diff_ts, GST_SECOND, ctx->clock_rate); @@ -65,16 +77,25 @@ gst_rtp_packet_rate_ctx_update (RTPPacketRateCtx * ctx, guint16 seqnum, * This is useful for bursty cases, where a lot of packets are close * to each other and should allow a higher reorder/dropout there. * Round up the new average. + * We do it on different rates depending on the packet rate, so it's not too + * jumpy. */ - if (ctx->avg_packet_rate > new_packet_rate) { - ctx->avg_packet_rate = (7 * ctx->avg_packet_rate + new_packet_rate + 7) / 8; - } else { - ctx->avg_packet_rate = (ctx->avg_packet_rate + new_packet_rate + 1) / 2; - } + if (ctx->avg_packet_rate > new_packet_rate) + base = MAX (ctx->avg_packet_rate / 3, 8); /* about 333 ms */ + else + base = MAX (ctx->avg_packet_rate / 15, 2); /* about 66 ms */ + + diff_seqnum = MIN (diff_seqnum, base - 1); + + ctx->avg_packet_rate = (((base - diff_seqnum) * ctx->avg_packet_rate) + + (new_packet_rate * diff_seqnum)) / base; + + +done_but_save: -done: ctx->last_seqnum = seqnum; ctx->last_ts = new_ts; +done: return ctx->avg_packet_rate; } @@ -427,3 +448,232 @@ __g_socket_address_to_string (GSocketAddress * addr) return ret; } + +static void +_append_structure_to_value_array (GValueArray * array, GstStructure * s) +{ + GValue *val; + g_value_array_append (array, NULL); + val = g_value_array_get_nth (array, array->n_values - 1); + g_value_init (val, GST_TYPE_STRUCTURE); + g_value_take_boxed (val, s); +} + +static void +_structure_take_value_array (GstStructure * s, + const gchar * field_name, GValueArray * array) +{ + GValue value = G_VALUE_INIT; + g_value_init (&value, G_TYPE_VALUE_ARRAY); + g_value_take_boxed (&value, array); + gst_structure_take_value (s, field_name, &value); + g_value_unset (&value); +} + +GstStructure * +rtp_twcc_stats_get_packets_structure (GArray * twcc_packets) +{ + GstStructure *ret = gst_structure_new_empty ("RTPTWCCPackets"); + GValueArray *array = g_value_array_new (0); + guint i; + + for (i = 0; i < twcc_packets->len; i++) { + RTPTWCCPacket *pkt = &g_array_index (twcc_packets, RTPTWCCPacket, i); + + GstStructure *pkt_s = gst_structure_new ("RTPTWCCPacket", + "seqnum", G_TYPE_UINT, pkt->seqnum, + "local-ts", G_TYPE_UINT64, pkt->local_ts, + "remote-ts", G_TYPE_UINT64, pkt->remote_ts, + "size", G_TYPE_UINT, pkt->size, + "lost", G_TYPE_BOOLEAN, pkt->status == RTP_TWCC_PACKET_STATUS_NOT_RECV, + NULL); + _append_structure_to_value_array (array, pkt_s); + } + + _structure_take_value_array (ret, "packets", array); + return ret; +} + +static void +rtp_twcc_stats_calculate_stats (RTPTWCCStats * stats, GArray * twcc_packets) +{ + guint packets_recv = 0; + guint i; + + for (i = 0; i < twcc_packets->len; i++) { + RTPTWCCPacket *pkt = &g_array_index (twcc_packets, RTPTWCCPacket, i); + + if (pkt->status != RTP_TWCC_PACKET_STATUS_NOT_RECV) + packets_recv++; + + if (GST_CLOCK_TIME_IS_VALID (pkt->local_ts) && + GST_CLOCK_TIME_IS_VALID (stats->last_local_ts)) { + pkt->local_delta = GST_CLOCK_DIFF (stats->last_local_ts, pkt->local_ts); + } + + if (GST_CLOCK_TIME_IS_VALID (pkt->remote_ts) && + GST_CLOCK_TIME_IS_VALID (stats->last_remote_ts)) { + pkt->remote_delta = + GST_CLOCK_DIFF (stats->last_remote_ts, pkt->remote_ts); + } + + if (GST_CLOCK_STIME_IS_VALID (pkt->local_delta) && + GST_CLOCK_STIME_IS_VALID (pkt->remote_delta)) { + pkt->delta_delta = pkt->remote_delta - pkt->local_delta; + } + + stats->last_local_ts = pkt->local_ts; + stats->last_remote_ts = pkt->remote_ts; + } + + stats->packets_sent = twcc_packets->len; + stats->packets_recv = packets_recv; +} + +static gint +_get_window_start_index (RTPTWCCStats * stats, GstClockTime duration, + GstClockTime * local_duration, GstClockTime * remote_duration) +{ + RTPTWCCPacket *last = NULL; + guint i; + + if (stats->packets->len < 2) + return -1; + + for (i = 0; i < stats->packets->len; i++) { + guint start_index = stats->packets->len - 1 - i; + RTPTWCCPacket *pkt = + &g_array_index (stats->packets, RTPTWCCPacket, start_index); + if (GST_CLOCK_TIME_IS_VALID (pkt->local_ts) + && GST_CLOCK_TIME_IS_VALID (pkt->remote_ts)) { + /* first find the last valid packet */ + if (last == NULL) { + last = pkt; + } else { + /* and then get the duration in local ts */ + GstClockTimeDiff ld = GST_CLOCK_DIFF (pkt->local_ts, last->local_ts); + if (ld >= duration) { + *local_duration = ld; + *remote_duration = GST_CLOCK_DIFF (pkt->remote_ts, last->remote_ts); + return start_index; + } + } + } + } + + return -1; +} + +static void +rtp_twcc_stats_calculate_windowed_stats (RTPTWCCStats * stats) +{ + guint i; + gint start_idx; + guint bits_sent = 0; + guint bits_recv = 0; + guint packets_sent = 0; + guint packets_recv = 0; + guint packets_lost; + GstClockTimeDiff delta_delta_sum = 0; + guint delta_delta_count = 0; + GstClockTime local_duration; + GstClockTime remote_duration; + + start_idx = _get_window_start_index (stats, stats->window_size, + &local_duration, &remote_duration); + if (start_idx == -1) { + return; + } + + /* remove the old packets */ + if (start_idx > 0) + g_array_remove_range (stats->packets, 0, start_idx); + + packets_sent = stats->packets->len - 1; + + for (i = 0; i < packets_sent; i++) { + RTPTWCCPacket *pkt = &g_array_index (stats->packets, RTPTWCCPacket, i); + + if (GST_CLOCK_TIME_IS_VALID (pkt->local_ts)) { + bits_sent += pkt->size * 8; + } + + if (GST_CLOCK_TIME_IS_VALID (pkt->remote_ts)) { + bits_recv += pkt->size * 8; + packets_recv++; + } + + if (GST_CLOCK_STIME_IS_VALID (pkt->delta_delta)) { + delta_delta_sum += pkt->delta_delta; + delta_delta_count++; + } + } + + packets_lost = packets_sent - packets_recv; + stats->packet_loss_pct = (packets_lost * 100) / (gfloat) packets_sent; + + if (delta_delta_count) { + GstClockTimeDiff avg_delta_of_delta = delta_delta_sum / delta_delta_count; + if (GST_CLOCK_STIME_IS_VALID (stats->avg_delta_of_delta)) { + stats->avg_delta_of_delta_change = + (avg_delta_of_delta - + stats->avg_delta_of_delta) / (250 * GST_USECOND); + } + stats->avg_delta_of_delta = avg_delta_of_delta; + } + + if (local_duration > 0) + stats->bitrate_sent = + gst_util_uint64_scale (bits_sent, GST_SECOND, local_duration); + if (remote_duration > 0) + stats->bitrate_recv = + gst_util_uint64_scale (bits_recv, GST_SECOND, remote_duration); + + GST_DEBUG ("Got stats: bits_sent: %u, bits_recv: %u, packets_sent = %u, " + "packets_recv: %u, packetlost_pct = %f, sent_bitrate = %u, " + "recv_bitrate = %u, delta-delta-avg = %" GST_STIME_FORMAT ", " + "delta-delta-change: %f", bits_sent, bits_recv, stats->packets_sent, + packets_recv, stats->packet_loss_pct, stats->bitrate_sent, + stats->bitrate_recv, GST_STIME_ARGS (stats->avg_delta_of_delta), + stats->avg_delta_of_delta_change); +} + +RTPTWCCStats * +rtp_twcc_stats_new (void) +{ + RTPTWCCStats *stats = g_new0 (RTPTWCCStats, 1); + stats->packets = g_array_new (FALSE, FALSE, sizeof (RTPTWCCPacket)); + stats->last_local_ts = GST_CLOCK_TIME_NONE; + stats->last_remote_ts = GST_CLOCK_TIME_NONE; + stats->avg_delta_of_delta = GST_CLOCK_STIME_NONE; + stats->window_size = 300 * GST_MSECOND; /* FIXME: could be configurable? */ + return stats; +} + +void +rtp_twcc_stats_free (RTPTWCCStats * stats) +{ + g_array_unref (stats->packets); + g_free (stats); +} + +static GstStructure * +rtp_twcc_stats_get_stats_structure (RTPTWCCStats * stats) +{ + return gst_structure_new ("RTPTWCCStats", + "bitrate-sent", G_TYPE_UINT, stats->bitrate_sent, + "bitrate-recv", G_TYPE_UINT, stats->bitrate_recv, + "packets-sent", G_TYPE_UINT, stats->packets_sent, + "packets-recv", G_TYPE_UINT, stats->packets_recv, + "packet-loss-pct", G_TYPE_DOUBLE, stats->packet_loss_pct, + "avg-delta-of-delta", G_TYPE_INT64, stats->avg_delta_of_delta, NULL); +} + +GstStructure * +rtp_twcc_stats_process_packets (RTPTWCCStats * stats, GArray * twcc_packets) +{ + rtp_twcc_stats_calculate_stats (stats, twcc_packets); + g_array_append_vals (stats->packets, twcc_packets->data, twcc_packets->len); + rtp_twcc_stats_calculate_windowed_stats (stats); + return rtp_twcc_stats_get_stats_structure (stats); +} diff --git a/gst/rtpmanager/rtpstats.h b/gst/rtpmanager/rtpstats.h index bd3a54efed..776651f444 100644 --- a/gst/rtpmanager/rtpstats.h +++ b/gst/rtpmanager/rtpstats.h @@ -77,6 +77,10 @@ typedef struct { * @seqnum: the seqnum of the packet * @pt: the payload type of the packet * @rtptime: the RTP time of the packet + * @marker: the marker bit + * + * @tw_seqnum_ext_id: the extension-header ID for transport-wide seqnums + * @tw_seqnum: the transport-wide seqnum of the packet * * Structure holding information about the packet. */ @@ -97,8 +101,11 @@ typedef struct { guint16 seqnum; guint8 pt; guint32 rtptime; + gboolean marker; guint32 csrc_count; guint32 csrcs[16]; + GBytes *header_ext; + guint16 header_ext_bit_pattern; } RTPPacketInfo; /** @@ -245,6 +252,27 @@ typedef struct { guint nacks_received; } RTPSessionStats; +/** + * RTPTWCCStats: + * + * Stats kept for a session and used to produce TWCC stats. + */ +typedef struct { + GArray *packets; + GstClockTime window_size; + GstClockTime last_local_ts; + GstClockTime last_remote_ts; + + guint bitrate_sent; + guint bitrate_recv; + guint packets_sent; + guint packets_recv; + gfloat packet_loss_pct; + GstClockTimeDiff avg_delta_of_delta; + gfloat avg_delta_of_delta_change; +} RTPTWCCStats; + + void rtp_stats_init_defaults (RTPSessionStats *stats); void rtp_stats_set_bandwidths (RTPSessionStats *stats, @@ -264,4 +292,10 @@ void rtp_stats_set_min_interval (RTPSessionStats *stats, gboolean __g_socket_address_equal (GSocketAddress *a, GSocketAddress *b); gchar * __g_socket_address_to_string (GSocketAddress * addr); +RTPTWCCStats * rtp_twcc_stats_new (void); +void rtp_twcc_stats_free (RTPTWCCStats * stats); +GstStructure * rtp_twcc_stats_process_packets (RTPTWCCStats * stats, + GArray * twcc_packets); +GstStructure * rtp_twcc_stats_get_packets_structure (GArray * twcc_packets); + #endif /* __RTP_STATS_H__ */ diff --git a/gst/rtpmanager/rtptimerqueue.c b/gst/rtpmanager/rtptimerqueue.c index 1c8cad3b4a..446a70ea54 100644 --- a/gst/rtpmanager/rtptimerqueue.c +++ b/gst/rtpmanager/rtptimerqueue.c @@ -18,6 +18,7 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ +#include #include @@ -390,22 +391,25 @@ rtp_timer_queue_new (void) /** * rtp_timer_queue_insert: * @queue: the #RtpTimerQueue object - * @timer: the #RtpTimer to insert + * @timer: (transfer full): the #RtpTimer to insert * * Insert a timer into the queue. Earliest timer are at the head and then * timer are sorted by seqnum (smaller seqnum first). This function is o(n) * but it is expected that most timers added are schedule later, in which case * the insertion will be faster. * - * Returns: %FLASE is a timer with the same seqnum already existed + * Returns: %FALSE if a timer with the same seqnum already existed */ gboolean rtp_timer_queue_insert (RtpTimerQueue * queue, RtpTimer * timer) { g_return_val_if_fail (timer->queued == FALSE, FALSE); - if (rtp_timer_queue_find (queue, timer->seqnum)) + if (rtp_timer_queue_find (queue, timer->seqnum)) { + rtp_timer_free (timer); + GST_WARNING ("Timer queue collision, freeing duplicate."); return FALSE; + } if (timer->timeout == -1) rtp_timer_queue_insert_head (queue, timer); @@ -554,7 +558,6 @@ rtp_timer_queue_remove_all (RtpTimerQueue * queue) * @queue: the #RtpTimerQueue * @type: the #RtpTimerType * @senum: the timer seqnum - * @num: the number of seqnum in the range (partially supported) * @timeout: the timer timeout * @delay: the additional delay (will be added to @timeout) * @duration: the duration of the event related to the timer @@ -566,7 +569,7 @@ rtp_timer_queue_remove_all (RtpTimerQueue * queue) */ void rtp_timer_queue_set_timer (RtpTimerQueue * queue, RtpTimerType type, - guint16 seqnum, guint num, GstClockTime timeout, GstClockTime delay, + guint16 seqnum, GstClockTime timeout, GstClockTime delay, GstClockTime duration, GstClockTimeDiff offset) { RtpTimer *timer; @@ -590,7 +593,6 @@ rtp_timer_queue_set_timer (RtpTimerQueue * queue, RtpTimerType type, timer->type = type; timer->seqnum = seqnum; - timer->num = num; if (timeout == -1) timer->timeout = -1; @@ -622,7 +624,7 @@ void rtp_timer_queue_set_expected (RtpTimerQueue * queue, guint16 seqnum, GstClockTime timeout, GstClockTime delay, GstClockTime duration) { - rtp_timer_queue_set_timer (queue, RTP_TIMER_EXPECTED, seqnum, 0, timeout, + rtp_timer_queue_set_timer (queue, RTP_TIMER_EXPECTED, seqnum, timeout, delay, duration, 0); } @@ -630,7 +632,6 @@ rtp_timer_queue_set_expected (RtpTimerQueue * queue, guint16 seqnum, * rtp_timer_queue_set_lost: * @queue: the #RtpTimerQueue * @senum: the timer seqnum - * @num: the number of seqnum in the range (partially supported) * @timeout: the timer timeout * @duration: the duration of the event related to the timer * @offset: offset that can be used to convert the timeout to timestamp @@ -640,10 +641,9 @@ rtp_timer_queue_set_expected (RtpTimerQueue * queue, guint16 seqnum, */ void rtp_timer_queue_set_lost (RtpTimerQueue * queue, guint16 seqnum, - guint num, GstClockTime timeout, GstClockTime duration, - GstClockTimeDiff offset) + GstClockTime timeout, GstClockTime duration, GstClockTimeDiff offset) { - rtp_timer_queue_set_timer (queue, RTP_TIMER_LOST, seqnum, num, timeout, 0, + rtp_timer_queue_set_timer (queue, RTP_TIMER_LOST, seqnum, timeout, 0, duration, offset); } @@ -661,8 +661,7 @@ void rtp_timer_queue_set_eos (RtpTimerQueue * queue, GstClockTime timeout, GstClockTimeDiff offset) { - rtp_timer_queue_set_timer (queue, RTP_TIMER_EOS, -1, 0, timeout, 0, 0, - offset); + rtp_timer_queue_set_timer (queue, RTP_TIMER_EOS, -1, timeout, 0, 0, offset); } /** @@ -680,7 +679,7 @@ void rtp_timer_queue_set_deadline (RtpTimerQueue * queue, guint16 seqnum, GstClockTime timeout, GstClockTimeDiff offset) { - rtp_timer_queue_set_timer (queue, RTP_TIMER_DEADLINE, seqnum, 0, timeout, 0, + rtp_timer_queue_set_timer (queue, RTP_TIMER_DEADLINE, seqnum, timeout, 0, 0, offset); } diff --git a/gst/rtpmanager/rtptimerqueue.h b/gst/rtpmanager/rtptimerqueue.h index b172125497..969cbd37ff 100644 --- a/gst/rtpmanager/rtptimerqueue.h +++ b/gst/rtpmanager/rtptimerqueue.h @@ -60,7 +60,6 @@ typedef struct gboolean queued; guint16 seqnum; - guint num; RtpTimerType type; GstClockTime timeout; GstClockTimeDiff offset; @@ -107,14 +106,14 @@ void rtp_timer_queue_remove_until (RtpTimerQueue * queue, GstClockTim void rtp_timer_queue_remove_all (RtpTimerQueue * queue); void rtp_timer_queue_set_timer (RtpTimerQueue * queue, RtpTimerType type, - guint16 seqnum, guint num, GstClockTime timeout, + guint16 seqnum, GstClockTime timeout, GstClockTime delay, GstClockTime duration, GstClockTimeDiff offset); void rtp_timer_queue_set_expected (RtpTimerQueue * queue, guint16 seqnum, GstClockTime timeout, GstClockTime delay, GstClockTime duration); void rtp_timer_queue_set_lost (RtpTimerQueue * queue, guint16 seqnum, - guint num, GstClockTime timeout, + GstClockTime timeout, GstClockTime duration, GstClockTimeDiff offset); void rtp_timer_queue_set_eos (RtpTimerQueue * queue, GstClockTime timeout, GstClockTimeDiff offset); diff --git a/gst/rtpmanager/rtptwcc.c b/gst/rtpmanager/rtptwcc.c new file mode 100644 index 0000000000..f5b5351bfd --- /dev/null +++ b/gst/rtpmanager/rtptwcc.c @@ -0,0 +1,909 @@ +/* GStreamer + * Copyright (C) 2019 Pexip (http://pexip.com/) + * @author: Havard Graff + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include "rtptwcc.h" +#include +#include +#include + +GST_DEBUG_CATEGORY_EXTERN (rtp_session_debug); +#define GST_CAT_DEFAULT rtp_session_debug + +#define REF_TIME_UNIT (64 * GST_MSECOND) +#define DELTA_UNIT (250 * GST_USECOND) +#define MAX_TS_DELTA (0xff * DELTA_UNIT) + +typedef enum +{ + RTP_TWCC_CHUNK_TYPE_RUN_LENGTH = 0, + RTP_TWCC_CHUNK_TYPE_STATUS_VECTOR = 1, +} RTPTWCCChunkType; + +typedef struct +{ + guint8 base_seqnum[2]; + guint8 packet_count[2]; + guint8 base_time[3]; + guint8 fb_pkt_count[1]; +} RTPTWCCHeader; + +typedef struct +{ + GstClockTime ts; + guint16 seqnum; + + gint64 delta; + RTPTWCCPacketStatus status; + guint16 missing_run; + guint equal_run; +} RecvPacket; + +typedef struct +{ + GstClockTime ts; + GstClockTime socket_ts; + GstClockTime remote_ts; + guint16 seqnum; + guint size; + gboolean lost; +} SentPacket; + +struct _RTPTWCCManager +{ + GObject object; + + guint mtu; + guint max_packets_per_rtcp; + GArray *recv_packets; + + guint8 fb_pkt_count; + gint32 last_seqnum; + + GArray *sent_packets; + GArray *parsed_packets; + GQueue *rtcp_buffers; + + guint64 recv_sender_ssrc; + guint64 recv_media_ssrc; + + guint16 expected_recv_seqnum; + + gboolean first_fci_parse; + guint16 expected_parsed_seqnum; + guint8 expected_parsed_fb_pkt_count; +}; + +G_DEFINE_TYPE (RTPTWCCManager, rtp_twcc_manager, G_TYPE_OBJECT); + +static void +rtp_twcc_manager_init (RTPTWCCManager * twcc) +{ + twcc->recv_packets = g_array_new (FALSE, FALSE, sizeof (RecvPacket)); + twcc->sent_packets = g_array_new (FALSE, FALSE, sizeof (SentPacket)); + twcc->parsed_packets = g_array_new (FALSE, FALSE, sizeof (RecvPacket)); + + twcc->rtcp_buffers = g_queue_new (); + + twcc->last_seqnum = -1; + twcc->recv_media_ssrc = -1; + twcc->recv_sender_ssrc = -1; + + twcc->first_fci_parse = TRUE; +} + +static void +rtp_twcc_manager_finalize (GObject * object) +{ + RTPTWCCManager *twcc = RTP_TWCC_MANAGER_CAST (object); + + g_array_unref (twcc->recv_packets); + g_array_unref (twcc->sent_packets); + g_array_unref (twcc->parsed_packets); + g_queue_free_full (twcc->rtcp_buffers, (GDestroyNotify) gst_buffer_unref); + + G_OBJECT_CLASS (rtp_twcc_manager_parent_class)->finalize (object); +} + +static void +rtp_twcc_manager_class_init (RTPTWCCManagerClass * klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + gobject_class->finalize = rtp_twcc_manager_finalize; +} + +RTPTWCCManager * +rtp_twcc_manager_new (guint mtu) +{ + RTPTWCCManager *twcc = g_object_new (RTP_TYPE_TWCC_MANAGER, NULL); + + rtp_twcc_manager_set_mtu (twcc, mtu); + + return twcc; +} + +static void +recv_packet_init (RecvPacket * packet, guint16 seqnum, RTPPacketInfo * pinfo) +{ + memset (packet, 0, sizeof (RecvPacket)); + packet->seqnum = seqnum; + packet->ts = pinfo->running_time; +} + +void +rtp_twcc_manager_set_mtu (RTPTWCCManager * twcc, guint mtu) +{ + twcc->mtu = mtu; + + /* the absolute worst case is that 7 packets uses + header (4 * 4 * 4) 32 bytes) and + packet_chunk 2 bytes + + recv_deltas (2 * 7) 14 bytes */ + twcc->max_packets_per_rtcp = ((twcc->mtu - 32) * 7) / (2 + 14); +} + +static gint +_twcc_seqnum_sort (gconstpointer a, gconstpointer b) +{ + gint32 seqa = ((RecvPacket *) a)->seqnum; + gint32 seqb = ((RecvPacket *) b)->seqnum; + gint res = seqa - seqb; + if (res < -65000) + res = 1; + if (res > 65000) + res = -1; + return res; +} + +static void +rtp_twcc_write_recv_deltas (guint8 * fci_data, GArray * twcc_packets) +{ + guint i; + for (i = 0; i < twcc_packets->len; i++) { + RecvPacket *pkt = &g_array_index (twcc_packets, RecvPacket, i); + + if (pkt->status == RTP_TWCC_PACKET_STATUS_SMALL_DELTA) { + GST_WRITE_UINT8 (fci_data, pkt->delta); + fci_data += 1; + } else if (pkt->status == RTP_TWCC_PACKET_STATUS_LARGE_NEGATIVE_DELTA) { + GST_WRITE_UINT16_BE (fci_data, pkt->delta); + fci_data += 2; + } + } +} + +static void +rtp_twcc_write_run_length_chunk (GArray * packet_chunks, + RTPTWCCPacketStatus status, guint run_length) +{ + guint written = 0; + while (written < run_length) { + GstBitWriter writer; + guint16 data = 0; + guint len = MIN (run_length - written, 8191); + + GST_LOG ("Writing a run-lenght of %u with status %u", len, status); + + gst_bit_writer_init_with_data (&writer, (guint8 *) & data, 2, FALSE); + gst_bit_writer_put_bits_uint8 (&writer, RTP_TWCC_CHUNK_TYPE_RUN_LENGTH, 1); + gst_bit_writer_put_bits_uint8 (&writer, status, 2); + gst_bit_writer_put_bits_uint16 (&writer, len, 13); + g_array_append_val (packet_chunks, data); + written += len; + } +} + +typedef struct +{ + GArray *packet_chunks; + GstBitWriter writer; + guint16 data; + guint symbol_size; +} ChunkBitWriter; + +static void +chunk_bit_writer_reset (ChunkBitWriter * writer) +{ + writer->data = 0; + gst_bit_writer_init_with_data (&writer->writer, + (guint8 *) & writer->data, 2, FALSE); + + gst_bit_writer_put_bits_uint8 (&writer->writer, + RTP_TWCC_CHUNK_TYPE_STATUS_VECTOR, 1); + /* 1 for 2-bit symbol-size, 0 for 1-bit */ + gst_bit_writer_put_bits_uint8 (&writer->writer, writer->symbol_size - 1, 1); +} + +static void +chunk_bit_writer_configure (ChunkBitWriter * writer, guint symbol_size) +{ + writer->symbol_size = symbol_size; + chunk_bit_writer_reset (writer); +} + +static gboolean +chunk_bit_writer_is_empty (ChunkBitWriter * writer) +{ + return writer->writer.bit_size == 2; +} + +static gboolean +chunk_bit_writer_is_full (ChunkBitWriter * writer) +{ + return writer->writer.bit_size == 16; +} + +static guint +chunk_bit_writer_get_available_slots (ChunkBitWriter * writer) +{ + return (16 - writer->writer.bit_size) / writer->symbol_size; +} + +static guint +chunk_bit_writer_get_total_slots (ChunkBitWriter * writer) +{ + return 14 / writer->symbol_size; +} + +static void +chunk_bit_writer_flush (ChunkBitWriter * writer) +{ + /* don't append a chunk if no bits have been written */ + if (!chunk_bit_writer_is_empty (writer)) { + g_array_append_val (writer->packet_chunks, writer->data); + chunk_bit_writer_reset (writer); + } +} + +static void +chunk_bit_writer_init (ChunkBitWriter * writer, + GArray * packet_chunks, guint symbol_size) +{ + writer->packet_chunks = packet_chunks; + chunk_bit_writer_configure (writer, symbol_size); +} + +static void +chunk_bit_writer_write (ChunkBitWriter * writer, RTPTWCCPacketStatus status) +{ + gst_bit_writer_put_bits_uint8 (&writer->writer, status, writer->symbol_size); + if (chunk_bit_writer_is_full (writer)) { + chunk_bit_writer_flush (writer); + } +} + +static void +rtp_twcc_write_status_vector_chunk (ChunkBitWriter * writer, RecvPacket * pkt) +{ + if (pkt->missing_run > 0) { + guint available = chunk_bit_writer_get_available_slots (writer); + guint total = chunk_bit_writer_get_total_slots (writer); + guint i; + + if (pkt->missing_run > (available + total)) { + /* here it is better to finish up the current status-chunk and then + go for run-length */ + for (i = 0; i < available; i++) { + chunk_bit_writer_write (writer, RTP_TWCC_PACKET_STATUS_NOT_RECV); + } + rtp_twcc_write_run_length_chunk (writer->packet_chunks, + RTP_TWCC_PACKET_STATUS_NOT_RECV, pkt->missing_run - available); + } else { + for (i = 0; i < pkt->missing_run; i++) { + chunk_bit_writer_write (writer, RTP_TWCC_PACKET_STATUS_NOT_RECV); + } + } + } + + chunk_bit_writer_write (writer, pkt->status); +} + +typedef struct +{ + RecvPacket *equal; +} RunLengthHelper; + +static void +run_lenght_helper_update (RunLengthHelper * rlh, RecvPacket * pkt) +{ + /* for missing packets we reset */ + if (pkt->missing_run > 0) { + rlh->equal = NULL; + } + + /* all status equal run */ + if (rlh->equal == NULL) { + rlh->equal = pkt; + rlh->equal->equal_run = 0; + } + + if (rlh->equal->status == pkt->status) { + rlh->equal->equal_run++; + } else { + rlh->equal = pkt; + rlh->equal->equal_run = 1; + } +} + +static void +rtp_twcc_write_chunks (GArray * packet_chunks, + GArray * twcc_packets, guint symbol_size) +{ + ChunkBitWriter writer; + guint i; + guint bits_per_chunks = 7 * symbol_size; + + chunk_bit_writer_init (&writer, packet_chunks, symbol_size); + + for (i = 0; i < twcc_packets->len; i++) { + RecvPacket *pkt = &g_array_index (twcc_packets, RecvPacket, i); + guint remaining_packets = twcc_packets->len - i; + + /* we can only start a run-length chunk if the status-chunk is + completed */ + if (chunk_bit_writer_is_empty (&writer)) { + /* first write in any preceeding gaps, we use run-length + if it would take up more than one chunk (14/7) */ + if (pkt->missing_run > bits_per_chunks) { + rtp_twcc_write_run_length_chunk (packet_chunks, + RTP_TWCC_PACKET_STATUS_NOT_RECV, pkt->missing_run); + } + + /* we have a run of the same status, write a run-length chunk and skip + to the next point */ + if (pkt->missing_run == 0 && + (pkt->equal_run > bits_per_chunks || + pkt->equal_run == remaining_packets)) { + rtp_twcc_write_run_length_chunk (packet_chunks, + pkt->status, pkt->equal_run); + i += pkt->equal_run - 1; + continue; + } + } + + GST_LOG ("i=%u: Writing a %u-bit vector of status: %u", + i, symbol_size, pkt->status); + rtp_twcc_write_status_vector_chunk (&writer, pkt); + } + chunk_bit_writer_flush (&writer); +} + +static void +rtp_twcc_manager_add_fci (RTPTWCCManager * twcc, GstRTCPPacket * packet) +{ + RecvPacket *first, *last, *prev; + guint16 packet_count; + GstClockTime base_time; + GstClockTime ts_rounded; + guint i; + GArray *packet_chunks = g_array_new (FALSE, FALSE, 2); + RTPTWCCHeader header; + guint header_size = sizeof (RTPTWCCHeader); + guint packet_chunks_size; + guint recv_deltas_size = 0; + guint16 fci_length; + guint16 fci_chunks; + guint8 *fci_data; + guint8 *fci_data_ptr; + RunLengthHelper rlh = { NULL }; + guint symbol_size = 1; + GstClockTimeDiff delta_ts; + gint64 delta_ts_rounded; + + g_array_sort (twcc->recv_packets, _twcc_seqnum_sort); + + /* get first and last packet */ + first = &g_array_index (twcc->recv_packets, RecvPacket, 0); + last = + &g_array_index (twcc->recv_packets, RecvPacket, + twcc->recv_packets->len - 1); + + packet_count = last->seqnum - first->seqnum + 1; + base_time = first->ts / REF_TIME_UNIT; + + GST_WRITE_UINT16_BE (header.base_seqnum, first->seqnum); + GST_WRITE_UINT16_BE (header.packet_count, packet_count); + GST_WRITE_UINT24_BE (header.base_time, base_time); + GST_WRITE_UINT8 (header.fb_pkt_count, twcc->fb_pkt_count); + + base_time *= REF_TIME_UNIT; + ts_rounded = base_time; + + GST_DEBUG ("Created TWCC feedback: base_seqnum: #%u, packet_count: %u, " + "base_time %" GST_TIME_FORMAT " fb_pkt_count: %u", + first->seqnum, packet_count, GST_TIME_ARGS (base_time), + twcc->fb_pkt_count); + + twcc->fb_pkt_count++; + twcc->expected_recv_seqnum = first->seqnum + packet_count; + + /* calculate all deltas and check for gaps etc */ + prev = first; + for (i = 0; i < twcc->recv_packets->len; i++) { + RecvPacket *pkt = &g_array_index (twcc->recv_packets, RecvPacket, i); + if (i != 0) { + pkt->missing_run = pkt->seqnum - prev->seqnum - 1; + } + + delta_ts = GST_CLOCK_DIFF (ts_rounded, pkt->ts); + pkt->delta = delta_ts / DELTA_UNIT; + delta_ts_rounded = pkt->delta * DELTA_UNIT; + ts_rounded += delta_ts_rounded; + + if (delta_ts_rounded < 0 || delta_ts_rounded > MAX_TS_DELTA) { + pkt->status = RTP_TWCC_PACKET_STATUS_LARGE_NEGATIVE_DELTA; + recv_deltas_size += 2; + symbol_size = 2; + } else { + pkt->status = RTP_TWCC_PACKET_STATUS_SMALL_DELTA; + recv_deltas_size += 1; + } + run_lenght_helper_update (&rlh, pkt); + + GST_LOG ("pkt: #%u, ts: %" GST_TIME_FORMAT + " ts_rounded: %" GST_TIME_FORMAT + " delta_ts: %" GST_STIME_FORMAT + " delta_ts_rounded: %" GST_STIME_FORMAT + " missing_run: %u, status: %u", pkt->seqnum, + GST_TIME_ARGS (pkt->ts), GST_TIME_ARGS (ts_rounded), + GST_STIME_ARGS (delta_ts), GST_STIME_ARGS (delta_ts_rounded), + pkt->missing_run, pkt->status); + prev = pkt; + } + + rtp_twcc_write_chunks (packet_chunks, twcc->recv_packets, symbol_size); + + packet_chunks_size = packet_chunks->len * 2; + fci_length = header_size + packet_chunks_size + recv_deltas_size; + fci_chunks = (fci_length - 1) / sizeof (guint32) + 1; + + if (!gst_rtcp_packet_fb_set_fci_length (packet, fci_chunks)) { + GST_ERROR ("Could not fit: %u packets", packet_count); + g_assert_not_reached (); + } + + fci_data = gst_rtcp_packet_fb_get_fci (packet); + fci_data_ptr = fci_data; + + memcpy (fci_data_ptr, &header, header_size); + fci_data_ptr += header_size; + + memcpy (fci_data_ptr, packet_chunks->data, packet_chunks_size); + fci_data_ptr += packet_chunks_size; + + rtp_twcc_write_recv_deltas (fci_data_ptr, twcc->recv_packets); + + GST_MEMDUMP ("twcc-header:", (guint8 *) & header, header_size); + GST_MEMDUMP ("packet-chunks:", (guint8 *) packet_chunks->data, + packet_chunks_size); + GST_MEMDUMP ("full fci:", fci_data, fci_length); + + g_array_unref (packet_chunks); + g_array_set_size (twcc->recv_packets, 0); +} + +static void +rtp_twcc_manager_create_feedback (RTPTWCCManager * twcc) +{ + GstBuffer *buf; + GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT; + GstRTCPPacket packet; + + buf = gst_rtcp_buffer_new (twcc->mtu); + + gst_rtcp_buffer_map (buf, GST_MAP_READWRITE, &rtcp); + + gst_rtcp_buffer_add_packet (&rtcp, GST_RTCP_TYPE_RTPFB, &packet); + + gst_rtcp_packet_fb_set_type (&packet, GST_RTCP_RTPFB_TYPE_TWCC); + if (twcc->recv_sender_ssrc != 1) + gst_rtcp_packet_fb_set_sender_ssrc (&packet, twcc->recv_sender_ssrc); + gst_rtcp_packet_fb_set_media_ssrc (&packet, twcc->recv_media_ssrc); + + rtp_twcc_manager_add_fci (twcc, &packet); + + gst_rtcp_buffer_unmap (&rtcp); + + g_queue_push_tail (twcc->rtcp_buffers, buf); +} + +/* we have calculated a (very pessimistic) max-packets per RTCP feedback, + so this is to make sure we don't exceed that */ +static gboolean +_exceeds_max_packets (RTPTWCCManager * twcc, guint16 seqnum) +{ + RecvPacket *first, *last; + guint16 packet_count; + + if (twcc->recv_packets->len == 0) + return FALSE; + + /* find the delta betwen first stored packet and this seqnum */ + first = &g_array_index (twcc->recv_packets, RecvPacket, 0); + packet_count = seqnum - first->seqnum + 1; + if (packet_count > twcc->max_packets_per_rtcp) + return TRUE; + + /* then find the delta between last stored packet and this seqnum */ + last = + &g_array_index (twcc->recv_packets, RecvPacket, + twcc->recv_packets->len - 1); + packet_count = seqnum - (last->seqnum + 1); + if (packet_count > twcc->max_packets_per_rtcp) + return TRUE; + + return FALSE; +} + +/* in this case we could have lost the packet with the marker bit, + so with a large (30) amount of packets, lost packets and still no marker, + we send a feedback anyway */ +static gboolean +_many_packets_some_lost (RTPTWCCManager * twcc, guint16 seqnum) +{ + RecvPacket *first; + guint16 packet_count; + guint received_packets = twcc->recv_packets->len; + if (received_packets == 0) + return FALSE; + + first = &g_array_index (twcc->recv_packets, RecvPacket, 0); + packet_count = seqnum - first->seqnum + 1; + /* packet-count larger than recevied-packets means we have lost packets */ + if (packet_count >= 30 && packet_count > received_packets) + return TRUE; + + return FALSE; +} + +gboolean +rtp_twcc_manager_recv_packet (RTPTWCCManager * twcc, + guint16 seqnum, RTPPacketInfo * pinfo) +{ + gboolean send_feedback = FALSE; + RecvPacket packet; + gint32 diff; + + /* if this packet would exceed the capacity of our MTU, we create a feedback + with the current packets, and start over with this one */ + if (_exceeds_max_packets (twcc, seqnum)) { + GST_INFO ("twcc-seqnum: %u would overflow max packets: %u, create feedback" + " with current packets", seqnum, twcc->max_packets_per_rtcp); + rtp_twcc_manager_create_feedback (twcc); + send_feedback = TRUE; + } + + /* we can have multiple ssrcs here, so just pick the first one */ + if (twcc->recv_media_ssrc == -1) + twcc->recv_media_ssrc = pinfo->ssrc; + + /* check if we are reordered, and treat it as lost if we already sent + a feedback msg with a higher seqnum. If the diff is huge, treat + it as a restart of a stream */ + diff = (gint32) seqnum - (gint32) twcc->expected_recv_seqnum; + if (twcc->fb_pkt_count > 0 && diff < 0 && diff > -1000) { + GST_INFO ("Received out of order packet (%u after %u), treating as lost", + seqnum, twcc->expected_recv_seqnum); + return FALSE; + } + + /* store the packet for Transport-wide RTCP feedback message */ + recv_packet_init (&packet, seqnum, pinfo); + g_array_append_val (twcc->recv_packets, packet); + twcc->last_seqnum = seqnum; + GST_LOG ("Receive: twcc-seqnum: %u, marker: %d, ts: %" GST_TIME_FORMAT, + seqnum, pinfo->marker, GST_TIME_ARGS (pinfo->running_time)); + + if (pinfo->marker || _many_packets_some_lost (twcc, seqnum)) { + rtp_twcc_manager_create_feedback (twcc); + send_feedback = TRUE; + } + + return send_feedback; +} + +static void +_change_rtcp_fb_sender_ssrc (GstBuffer * buf, guint32 sender_ssrc) +{ + GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT; + GstRTCPPacket packet; + gst_rtcp_buffer_map (buf, GST_MAP_READWRITE, &rtcp); + gst_rtcp_buffer_get_first_packet (&rtcp, &packet); + gst_rtcp_packet_fb_set_sender_ssrc (&packet, sender_ssrc); + gst_rtcp_buffer_unmap (&rtcp); +} + +GstBuffer * +rtp_twcc_manager_get_feedback (RTPTWCCManager * twcc, guint sender_ssrc) +{ + GstBuffer *buf; + buf = g_queue_pop_head (twcc->rtcp_buffers); + + if (buf && twcc->recv_sender_ssrc != sender_ssrc) { + _change_rtcp_fb_sender_ssrc (buf, sender_ssrc); + twcc->recv_sender_ssrc = sender_ssrc; + } + + return buf; +} + +static void +sent_packet_init (SentPacket * packet, guint16 seqnum, RTPPacketInfo * pinfo) +{ + packet->seqnum = seqnum; + packet->ts = pinfo->running_time; + packet->size = pinfo->payload_len; + packet->remote_ts = GST_CLOCK_TIME_NONE; + packet->socket_ts = GST_CLOCK_TIME_NONE; + packet->lost = FALSE; +} + +void +rtp_twcc_manager_send_packet (RTPTWCCManager * twcc, + guint16 seqnum, RTPPacketInfo * pinfo) +{ + SentPacket packet; + sent_packet_init (&packet, seqnum, pinfo); + g_array_append_val (twcc->sent_packets, packet); + + GST_LOG ("Send: twcc-seqnum: %u, marker: %d, ts: %" GST_TIME_FORMAT, + seqnum, pinfo->marker, GST_TIME_ARGS (pinfo->running_time)); +} + +void +rtp_twcc_manager_set_send_packet_ts (RTPTWCCManager * twcc, + guint packet_id, GstClockTime ts) +{ + SentPacket *pkt = NULL; + pkt = &g_array_index (twcc->sent_packets, SentPacket, packet_id); + if (pkt) { + pkt->socket_ts = ts; + GST_DEBUG ("assigning: pkt-id: %u to packet: %u", packet_id, pkt->seqnum); + } +} + +static void +_add_twcc_packet (GArray * twcc_packets, guint16 seqnum, guint status) +{ + RTPTWCCPacket packet; + memset (&packet, 0, sizeof (RTPTWCCPacket)); + packet.local_ts = GST_CLOCK_TIME_NONE; + packet.remote_ts = GST_CLOCK_TIME_NONE; + packet.local_delta = GST_CLOCK_STIME_NONE; + packet.remote_delta = GST_CLOCK_STIME_NONE; + packet.delta_delta = GST_CLOCK_STIME_NONE; + packet.seqnum = seqnum; + packet.status = status; + g_array_append_val (twcc_packets, packet); +} + +static guint +_parse_run_length_chunk (GstBitReader * reader, GArray * twcc_packets, + guint16 seqnum_offset, guint remaining_packets) +{ + guint run_length; + guint8 status_code; + guint i; + + gst_bit_reader_get_bits_uint8 (reader, &status_code, 2); + + run_length = *(guint16 *) reader->data & ~0xE0; /* mask out the 3 last bits */ + run_length = MIN (remaining_packets, GST_READ_UINT16_BE (&run_length)); + + for (i = 0; i < run_length; i++) { + _add_twcc_packet (twcc_packets, seqnum_offset + i, status_code); + } + + return run_length; +} + +static guint +_parse_status_vector_chunk (GstBitReader * reader, GArray * twcc_packets, + guint16 seqnum_offset, guint remaining_packets) +{ + guint8 symbol_size; + guint num_bits; + guint i; + + gst_bit_reader_get_bits_uint8 (reader, &symbol_size, 1); + symbol_size += 1; + num_bits = MIN (remaining_packets, 14 / symbol_size); + + for (i = 0; i < num_bits; i++) { + guint8 status_code; + if (gst_bit_reader_get_bits_uint8 (reader, &status_code, symbol_size)) + _add_twcc_packet (twcc_packets, seqnum_offset + i, status_code); + } + + return num_bits; +} + +/* Remove all locally stored packets that has been reported + back to us */ +static void +_prune_sent_packets (RTPTWCCManager * twcc, GArray * twcc_packets) +{ + SentPacket *first; + RTPTWCCPacket *last; + guint16 last_idx; + + if (twcc_packets->len == 0 || twcc->sent_packets->len == 0) + return; + + first = &g_array_index (twcc->sent_packets, SentPacket, 0); + last = &g_array_index (twcc_packets, RTPTWCCPacket, twcc_packets->len - 1); + + last_idx = last->seqnum - first->seqnum; + + if (last_idx < twcc->sent_packets->len) + g_array_remove_range (twcc->sent_packets, 0, last_idx); +} + +static void +_check_for_lost_packets (RTPTWCCManager * twcc, GArray * twcc_packets, + guint16 base_seqnum, guint16 packet_count, guint8 fb_pkt_count) +{ + guint packets_lost; + guint i; + + /* first packet */ + if (twcc->first_fci_parse) { + twcc->first_fci_parse = FALSE; + goto done; + } + + /* we have gone backwards, don't reset the expectations, + but process the packet nonetheless */ + if (fb_pkt_count < twcc->expected_parsed_fb_pkt_count) { + GST_WARNING ("feedback packet count going backwards (%u < %u)", + fb_pkt_count, twcc->expected_parsed_fb_pkt_count); + return; + } + + /* we have jumped forwards, reset expectations, but don't trigger + lost packets in case the missing fb-packet(s) arrive later */ + if (fb_pkt_count > twcc->expected_parsed_fb_pkt_count) { + GST_WARNING ("feedback packet count jumped ahead (%u > %u)", + fb_pkt_count, twcc->expected_parsed_fb_pkt_count); + goto done; + } + + packets_lost = base_seqnum - twcc->expected_parsed_seqnum; + for (i = 0; i < packets_lost; i++) { + _add_twcc_packet (twcc_packets, twcc->expected_parsed_seqnum + i, + RTP_TWCC_PACKET_STATUS_NOT_RECV); + } + +done: + twcc->expected_parsed_seqnum = base_seqnum + packet_count; + twcc->expected_parsed_fb_pkt_count = fb_pkt_count + 1; + return; +} + +GArray * +rtp_twcc_manager_parse_fci (RTPTWCCManager * twcc, + guint8 * fci_data, guint fci_length) +{ + GArray *twcc_packets; + guint16 base_seqnum; + guint16 packet_count; + GstClockTime base_time; + GstClockTime ts_rounded; + guint8 fb_pkt_count; + guint packets_parsed = 0; + guint fci_parsed; + guint i; + SentPacket *first_sent_pkt = NULL; + + if (fci_length < 10) { + GST_WARNING ("Malformed TWCC RTCP feedback packet"); + return NULL; + } + + base_seqnum = GST_READ_UINT16_BE (&fci_data[0]); + packet_count = GST_READ_UINT16_BE (&fci_data[2]); + base_time = GST_READ_UINT24_BE (&fci_data[4]) * REF_TIME_UNIT; + fb_pkt_count = fci_data[7]; + + GST_DEBUG ("Parsed TWCC feedback: base_seqnum: #%u, packet_count: %u, " + "base_time %" GST_TIME_FORMAT " fb_pkt_count: %u", + base_seqnum, packet_count, GST_TIME_ARGS (base_time), fb_pkt_count); + + twcc_packets = g_array_sized_new (FALSE, FALSE, + sizeof (RTPTWCCPacket), packet_count); + + _check_for_lost_packets (twcc, twcc_packets, + base_seqnum, packet_count, fb_pkt_count); + + fci_parsed = 8; + while (packets_parsed < packet_count && (fci_parsed + 1) < fci_length) { + GstBitReader reader = GST_BIT_READER_INIT (&fci_data[fci_parsed], 2); + guint8 chunk_type; + guint seqnum_offset = base_seqnum + packets_parsed; + guint remaining_packets = packet_count - packets_parsed; + + gst_bit_reader_get_bits_uint8 (&reader, &chunk_type, 1); + + if (chunk_type == RTP_TWCC_CHUNK_TYPE_RUN_LENGTH) { + packets_parsed += _parse_run_length_chunk (&reader, + twcc_packets, seqnum_offset, remaining_packets); + } else { + packets_parsed += _parse_status_vector_chunk (&reader, + twcc_packets, seqnum_offset, remaining_packets); + } + fci_parsed += 2; + } + + if (twcc->sent_packets->len > 0) + first_sent_pkt = &g_array_index (twcc->sent_packets, SentPacket, 0); + + ts_rounded = base_time; + for (i = 0; i < twcc_packets->len; i++) { + RTPTWCCPacket *pkt = &g_array_index (twcc_packets, RTPTWCCPacket, i); + gint16 delta = 0; + GstClockTimeDiff delta_ts; + + if (pkt->status == RTP_TWCC_PACKET_STATUS_SMALL_DELTA) { + delta = fci_data[fci_parsed]; + fci_parsed += 1; + } else if (pkt->status == RTP_TWCC_PACKET_STATUS_LARGE_NEGATIVE_DELTA) { + delta = GST_READ_UINT16_BE (&fci_data[fci_parsed]); + fci_parsed += 2; + } + + if (fci_parsed > fci_length) { + GST_WARNING ("Malformed TWCC RTCP feedback packet"); + g_array_set_size (twcc_packets, 0); + break; + } + + if (pkt->status != RTP_TWCC_PACKET_STATUS_NOT_RECV) { + delta_ts = delta * DELTA_UNIT; + ts_rounded += delta_ts; + pkt->remote_ts = ts_rounded; + + GST_LOG ("pkt: #%u, remote_ts: %" GST_TIME_FORMAT + " delta_ts: %" GST_STIME_FORMAT + " status: %u", pkt->seqnum, + GST_TIME_ARGS (pkt->remote_ts), GST_STIME_ARGS (delta_ts), + pkt->status); + } + + if (first_sent_pkt) { + SentPacket *found = NULL; + guint16 sent_idx = pkt->seqnum - first_sent_pkt->seqnum; + if (sent_idx < twcc->sent_packets->len) + found = &g_array_index (twcc->sent_packets, SentPacket, sent_idx); + if (found && found->seqnum == pkt->seqnum) { + if (GST_CLOCK_TIME_IS_VALID (found->socket_ts)) { + pkt->local_ts = found->socket_ts; + } else { + pkt->local_ts = found->ts; + } + pkt->size = found->size; + + GST_LOG ("matching pkt: #%u with local_ts: %" GST_TIME_FORMAT + " size: %u", pkt->seqnum, GST_TIME_ARGS (pkt->local_ts), pkt->size); + } + } + } + + _prune_sent_packets (twcc, twcc_packets); + + return twcc_packets; +} diff --git a/gst/rtpmanager/rtptwcc.h b/gst/rtpmanager/rtptwcc.h new file mode 100644 index 0000000000..50da704778 --- /dev/null +++ b/gst/rtpmanager/rtptwcc.h @@ -0,0 +1,72 @@ +/* GStreamer + * Copyright (C) 2019 Pexip (http://pexip.com/) + * @author: Havard Graff + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __RTP_TWCC_H__ +#define __RTP_TWCC_H__ + +#include +#include +#include "rtpstats.h" + +typedef struct _RTPTWCCPacket RTPTWCCPacket; +typedef enum _RTPTWCCPacketStatus RTPTWCCPacketStatus; + +G_DECLARE_FINAL_TYPE (RTPTWCCManager, rtp_twcc_manager, RTP, TWCC_MANAGER, GObject) +#define RTP_TYPE_TWCC_MANAGER (rtp_twcc_manager_get_type()) +#define RTP_TWCC_MANAGER_CAST(obj) ((RTPTWCCManager *)(obj)) + +enum _RTPTWCCPacketStatus +{ + RTP_TWCC_PACKET_STATUS_NOT_RECV = 0, + RTP_TWCC_PACKET_STATUS_SMALL_DELTA = 1, + RTP_TWCC_PACKET_STATUS_LARGE_NEGATIVE_DELTA = 2, +}; + +struct _RTPTWCCPacket +{ + GstClockTime local_ts; + GstClockTime remote_ts; + GstClockTimeDiff local_delta; + GstClockTimeDiff remote_delta; + GstClockTimeDiff delta_delta; + RTPTWCCPacketStatus status; + guint16 seqnum; + guint size; +}; + +RTPTWCCManager * rtp_twcc_manager_new (guint mtu); + +void rtp_twcc_manager_set_mtu (RTPTWCCManager * twcc, guint mtu); + +gboolean rtp_twcc_manager_recv_packet (RTPTWCCManager * twcc, + guint16 seqnum, RTPPacketInfo * pinfo); + +void rtp_twcc_manager_send_packet (RTPTWCCManager * twcc, + guint16 seqnum, RTPPacketInfo * pinfo); +void rtp_twcc_manager_set_send_packet_ts (RTPTWCCManager * twcc, + guint packet_id, GstClockTime ts); + +GstBuffer * rtp_twcc_manager_get_feedback (RTPTWCCManager * twcc, + guint32 sender_ssrc); + +GArray * rtp_twcc_manager_parse_fci (RTPTWCCManager * twcc, + guint8 * fci_data, guint fci_length); + +#endif /* __RTP_TWCC_H__ */ diff --git a/gst/rtsp/gstrtspsrc.c b/gst/rtsp/gstrtspsrc.c index 41de44dd32..35405bd9bc 100644 --- a/gst/rtsp/gstrtspsrc.c +++ b/gst/rtsp/gstrtspsrc.c @@ -85,6 +85,14 @@ * ]| Establish a connection to an RTSP server and send the raw RTP packets to a * fakesink. * + * NOTE: rtspsrc will send a PAUSE command to the server if you set the + * element to the PAUSED state, and will send a PLAY command if you set it to + * the PLAYING state. + * + * Unfortunately, going to the NULL state involves going through PAUSED, so + * rtspsrc does not know the difference and will send a PAUSE when you wanted + * a TEARDOWN. The workaround is to hook into the `before-send` signal and + * return FALSE in this case. */ #ifdef HAVE_CONFIG_H @@ -152,6 +160,23 @@ enum _GstRtspSrcRtcpSyncMode RTCP_SYNC_RTP }; +#define GST_TYPE_RTSP_SRC_TIMEOUT_CAUSE (gst_rtsp_src_timeout_cause_get_type()) +static GType +gst_rtsp_src_timeout_cause_get_type (void) +{ + static GType timeout_cause_type = 0; + static const GEnumValue timeout_causes[] = { + {GST_RTSP_SRC_TIMEOUT_CAUSE_RTCP, "timeout triggered by RTCP", "RTCP"}, + {0, NULL, NULL}, + }; + + if (!timeout_cause_type) { + timeout_cause_type = + g_enum_register_static ("GstRTSPSrcTimeoutCause", timeout_causes); + } + return timeout_cause_type; +} + enum _GstRtspSrcBufferMode { BUFFER_MODE_NONE, @@ -1052,7 +1077,7 @@ gst_rtspsrc_class_init (GstRTSPSrcClass * klass) */ gst_rtspsrc_signals[SIGNAL_SELECT_STREAM] = g_signal_new_class_handler ("select-stream", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_CLEANUP, + G_SIGNAL_RUN_LAST, (GCallback) default_select_stream, select_stream_accum, NULL, NULL, G_TYPE_BOOLEAN, 2, G_TYPE_UINT, GST_TYPE_CAPS); /** @@ -1067,8 +1092,7 @@ gst_rtspsrc_class_init (GstRTSPSrcClass * klass) */ gst_rtspsrc_signals[SIGNAL_NEW_MANAGER] = g_signal_new_class_handler ("new-manager", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_CLEANUP, 0, NULL, NULL, NULL, - G_TYPE_NONE, 1, GST_TYPE_ELEMENT); + 0, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_ELEMENT); /** * GstRTSPSrc::request-rtcp-key: @@ -1083,7 +1107,7 @@ gst_rtspsrc_class_init (GstRTSPSrcClass * klass) */ gst_rtspsrc_signals[SIGNAL_REQUEST_RTCP_KEY] = g_signal_new ("request-rtcp-key", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, GST_TYPE_CAPS, 1, G_TYPE_UINT); + 0, 0, NULL, NULL, NULL, GST_TYPE_CAPS, 1, G_TYPE_UINT); /** * GstRTSPSrc::accept-certificate: @@ -1106,8 +1130,8 @@ gst_rtspsrc_class_init (GstRTSPSrcClass * klass) G_TYPE_BOOLEAN, 3, G_TYPE_TLS_CONNECTION, G_TYPE_TLS_CERTIFICATE, G_TYPE_TLS_CERTIFICATE_FLAGS); - /* - * GstRTSPSrc::before-send + /** + * GstRTSPSrc::before-send: * @rtspsrc: a #GstRTSPSrc * @num: the stream number * @@ -1124,14 +1148,14 @@ gst_rtspsrc_class_init (GstRTSPSrcClass * klass) */ gst_rtspsrc_signals[SIGNAL_BEFORE_SEND] = g_signal_new_class_handler ("before-send", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_CLEANUP, + G_SIGNAL_RUN_LAST, (GCallback) default_before_send, before_send_accum, NULL, NULL, G_TYPE_BOOLEAN, 1, GST_TYPE_RTSP_MESSAGE | G_SIGNAL_TYPE_STATIC_SCOPE); /** * GstRTSPSrc::push-backchannel-buffer: * @rtspsrc: a #GstRTSPSrc - * @buffer: RTP buffer to send back + * @sample: RTP sample to send back * * */ @@ -1139,7 +1163,7 @@ gst_rtspsrc_class_init (GstRTSPSrcClass * klass) g_signal_new ("push-backchannel-buffer", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstRTSPSrcClass, push_backchannel_buffer), NULL, NULL, NULL, - GST_TYPE_FLOW_RETURN, 2, G_TYPE_UINT, GST_TYPE_BUFFER); + GST_TYPE_FLOW_RETURN, 2, G_TYPE_UINT, GST_TYPE_SAMPLE); /** * GstRTSPSrc::get-parameter: @@ -1217,6 +1241,12 @@ gst_rtspsrc_class_init (GstRTSPSrcClass * klass) klass->set_parameter = GST_DEBUG_FUNCPTR (set_parameter); gst_rtsp_ext_list_init (); + + gst_type_mark_as_plugin_api (GST_TYPE_RTSP_SRC_TIMEOUT_CAUSE, 0); + gst_type_mark_as_plugin_api (GST_TYPE_RTSP_SRC_BUFFER_MODE, 0); + gst_type_mark_as_plugin_api (GST_TYPE_RTSP_SRC_NTP_TIME_SOURCE, 0); + gst_type_mark_as_plugin_api (GST_TYPE_RTSP_BACKCHANNEL, 0); + gst_type_mark_as_plugin_api (GST_TYPE_RTSP_NAT_METHOD, 0); } static gboolean @@ -1394,6 +1424,8 @@ gst_rtspsrc_init (GstRTSPSrc * src) src->onvif_mode = DEFAULT_ONVIF_MODE; src->onvif_rate_control = DEFAULT_ONVIF_RATE_CONTROL; src->is_live = DEFAULT_IS_LIVE; + src->seek_seqnum = GST_SEQNUM_INVALID; + src->group_id = GST_GROUP_ID_INVALID; /* get a list of all extensions */ src->extensions = gst_rtsp_ext_list_get (); @@ -1417,6 +1449,8 @@ gst_rtspsrc_init (GstRTSPSrc * src) g_mutex_init (&src->conninfo.recv_lock); g_cond_init (&src->cmd_cond); + g_mutex_init (&src->group_lock); + GST_OBJECT_FLAG_SET (src, GST_ELEMENT_FLAG_SOURCE); gst_bin_set_suppressed_flags (GST_BIN (src), GST_ELEMENT_FLAG_SOURCE | GST_ELEMENT_FLAG_SINK); @@ -1432,15 +1466,6 @@ free_param_data (ParameterRequest * req) g_free (req); } -static void -free_param_queue (gpointer data) -{ - ParameterRequest *req = data; - - gst_promise_expire (req->promise); - free_param_data (req); -} - static void gst_rtspsrc_finalize (GObject * object) { @@ -1481,6 +1506,8 @@ gst_rtspsrc_finalize (GObject * object) g_mutex_clear (&rtspsrc->conninfo.recv_lock); g_cond_clear (&rtspsrc->cmd_cond); + g_mutex_clear (&rtspsrc->group_lock); + G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -2416,6 +2443,7 @@ static void gst_rtspsrc_cleanup (GstRTSPSrc * src) { GList *walk; + ParameterRequest *req; GST_DEBUG_OBJECT (src, "cleanup"); @@ -2465,9 +2493,10 @@ gst_rtspsrc_cleanup (GstRTSPSrc * src) GST_OBJECT_LOCK (src); /* free parameter requests queue */ - if (!g_queue_is_empty (&src->set_get_param_q)) - g_queue_free_full (&src->set_get_param_q, free_param_queue); - + while ((req = g_queue_pop_head (&src->set_get_param_q))) { + gst_promise_expire (req->promise); + free_param_data (req); + } GST_OBJECT_UNLOCK (src); } @@ -2836,21 +2865,15 @@ gst_rtspsrc_perform_seek (GstRTSPSrc * src, GstEvent * event) /* copy segment, we need this because we still need the old * segment when we close the current segment. */ - memcpy (&seeksegment, &src->segment, sizeof (GstSegment)); + seeksegment = src->segment; /* configure the seek parameters in the seeksegment. We will then have the * right values in the segment to perform the seek */ GST_DEBUG_OBJECT (src, "configuring seek"); - seeksegment.duration = GST_CLOCK_TIME_NONE; rate_change_same_direction = (rate * seeksegment.rate) > 0; gst_segment_do_seek (&seeksegment, rate, format, flags, cur_type, cur, stop_type, stop, &update); - /* figure out the last position we need to play. If it's configured (stop != - * -1), use that, else we play until the total duration of the file */ - if ((stop = seeksegment.stop) == -1) - stop = seeksegment.duration; - /* if we were playing, pause first */ playing = (src->state == GST_RTSP_STATE_PLAYING); if (playing) { @@ -2865,6 +2888,11 @@ gst_rtspsrc_perform_seek (GstRTSPSrc * src, GstEvent * event) /* PLAY will add the range header now. */ src->need_range = TRUE; + /* If an accurate seek was requested, we want to clip the segment we + * output in ONVIF mode to the requested bounds */ + src->clip_out_segment = ! !(flags & GST_SEEK_FLAG_ACCURATE); + src->seek_seqnum = gst_event_get_seqnum (event); + /* prepare for streaming again */ if (flush) { /* if we started flush, we stop now */ @@ -2873,7 +2901,7 @@ gst_rtspsrc_perform_seek (GstRTSPSrc * src, GstEvent * event) } /* now we did the seek and can activate the new segment values */ - memcpy (&src->segment, &seeksegment, sizeof (GstSegment)); + src->segment = seeksegment; /* if we're doing a segment seek, post a SEGMENT_START message */ if (src->segment.flags & GST_SEEK_FLAG_SEGMENT) { @@ -2882,10 +2910,6 @@ gst_rtspsrc_perform_seek (GstRTSPSrc * src, GstEvent * event) src->segment.format, src->segment.position)); } - /* now create the newsegment */ - GST_DEBUG_OBJECT (src, "Creating newsegment from %" G_GINT64_FORMAT - " to %" G_GINT64_FORMAT, src->segment.position, stop); - /* mark discont when needed */ if (!(rate_change_only && rate_change_same_direction)) { GST_DEBUG_OBJECT (src, "mark DISCONT, we did a seek to another position"); @@ -2917,10 +2941,6 @@ gst_rtspsrc_perform_seek (GstRTSPSrc * src, GstEvent * event) seek_style = "Next"; } - /* If an accurate seek was requested, we want to clip the segment we - * output in ONVIF mode to the requested bounds */ - src->clip_out_segment = ! !(flags & GST_SEEK_FLAG_ACCURATE); - if (playing) gst_rtspsrc_play (src, &seeksegment, FALSE, seek_style); @@ -2961,7 +2981,15 @@ gst_rtspsrc_handle_src_event (GstPad * pad, GstObject * parent, switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: - res = gst_rtspsrc_perform_seek (src, event); + { + guint32 seqnum = gst_event_get_seqnum (event); + if (seqnum == src->seek_seqnum) { + GST_LOG_OBJECT (pad, "Drop duplicated SEEK event seqnum %" + G_GUINT32_FORMAT, seqnum); + } else { + res = gst_rtspsrc_perform_seek (src, event); + } + } forward = FALSE; break; case GST_EVENT_QOS: @@ -2987,27 +3015,53 @@ gst_rtspsrc_handle_src_event (GstPad * pad, GstObject * parent, return res; } +static void +gst_rtspsrc_stream_start_event_add_group_id (GstRTSPSrc * src, GstEvent * event) +{ + g_mutex_lock (&src->group_lock); + + if (src->group_id == GST_GROUP_ID_INVALID) + src->group_id = gst_util_group_id_next (); + + g_mutex_unlock (&src->group_lock); + + gst_event_set_group_id (event, src->group_id); +} + static gboolean gst_rtspsrc_handle_src_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstRTSPStream *stream; + GstRTSPSrc *self = GST_RTSPSRC (GST_OBJECT_PARENT (parent)); stream = gst_pad_get_element_private (pad); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_STREAM_START:{ - const gchar *upstream_id; + GChecksum *cs; + gchar *uri; gchar *stream_id; - gst_event_parse_stream_start (event, &upstream_id); - stream_id = g_strdup_printf ("%s/%s", upstream_id, stream->stream_id); + cs = g_checksum_new (G_CHECKSUM_SHA256); + uri = self->conninfo.location; + g_checksum_update (cs, (const guchar *) uri, strlen (uri)); + stream_id = + g_strdup_printf ("%s/%s", g_checksum_get_string (cs), + stream->stream_id); + + g_checksum_free (cs); gst_event_unref (event); event = gst_event_new_stream_start (stream_id); + gst_rtspsrc_stream_start_event_add_group_id (self, event); g_free (stream_id); break; } + case GST_EVENT_SEGMENT: + if (self->seek_seqnum != GST_SEQNUM_INVALID) + GST_EVENT_SEQNUM (event) = self->seek_seqnum; + break; default: break; } @@ -3045,7 +3099,7 @@ gst_rtspsrc_handle_internal_src_query (GstPad * pad, GstObject * parent, GstQuery * query) { GstRTSPSrc *src; - gboolean res = TRUE; + gboolean res = FALSE; src = GST_RTSPSRC_CAST (gst_pad_get_element_private (pad)); @@ -3067,9 +3121,9 @@ gst_rtspsrc_handle_internal_src_query (GstPad * pad, GstObject * parent, switch (format) { case GST_FORMAT_TIME: gst_query_set_duration (query, format, src->segment.duration); + res = TRUE; break; default: - res = FALSE; break; } break; @@ -3079,6 +3133,7 @@ gst_rtspsrc_handle_internal_src_query (GstPad * pad, GstObject * parent, /* we are live with a min latency of 0 and unlimited max latency, this * result will be updated by the session manager if there is any. */ gst_query_set_latency (query, src->is_live, 0, -1); + res = TRUE; break; } default: @@ -3124,8 +3179,7 @@ gst_rtspsrc_handle_src_query (GstPad * pad, GstObject * parent, gst_query_parse_seeking (query, &format, NULL, NULL, NULL); if (format == GST_FORMAT_TIME) { - gboolean seekable = - src->cur_protocols != GST_RTSP_LOWER_TRANS_UDP_MCAST; + gboolean seekable = TRUE; GstClockTime start = 0, duration = src->segment.duration; /* seeking without duration is unlikely */ @@ -3142,7 +3196,9 @@ gst_rtspsrc_handle_src_query (GstPad * pad, GstObject * parent, } } - GST_LOG_OBJECT (src, "seekable : %d", seekable); + GST_LOG_OBJECT (src, "seekable: %d, duration: %" GST_TIME_FORMAT + ", src->seekable: %f", seekable, + GST_TIME_ARGS (src->segment.duration), src->seekable); gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, start, duration); @@ -3546,8 +3602,8 @@ on_timeout (GObject * session, GObject * source, GstRTSPStream * stream) /* timeout, post element message */ gst_element_post_message (GST_ELEMENT_CAST (src), gst_message_new_element (GST_OBJECT_CAST (src), - gst_structure_new ("GstRTSPSrcTimeout", - "cause", G_TYPE_ENUM, GST_RTSP_SRC_TIMEOUT_CAUSE_RTCP, + gst_structure_new ("GstRTSPSrcTimeout", "cause", + GST_TYPE_RTSP_SRC_TIMEOUT_CAUSE, GST_RTSP_SRC_TIMEOUT_CAUSE_RTCP, "stream-number", G_TYPE_INT, stream->id, "ssrc", G_TYPE_UINT, stream->ssrc, NULL))); @@ -5382,7 +5438,6 @@ gst_rtspsrc_handle_data (GstRTSPSrc * src, GstRTSPMessage * message) GChecksum *cs; gchar *uri; GList *streams; - guint group_id = gst_util_group_id_next (); /* generate an SHA256 sum of the URI */ cs = g_checksum_new (G_CHECKSUM_SHA256); @@ -5400,8 +5455,10 @@ gst_rtspsrc_handle_data (GstRTSPSrc * src, GstRTSPMessage * message) stream_id = g_strdup_printf ("%s/%d", g_checksum_get_string (cs), ostream->id); + event = gst_event_new_stream_start (stream_id); - gst_event_set_group_id (event, group_id); + + gst_rtspsrc_stream_start_event_add_group_id (src, event); g_free (stream_id); gst_rtspsrc_stream_push_event (src, ostream, event); @@ -5557,16 +5614,8 @@ gst_rtspsrc_loop_interleaved (GstRTSPSrc * src) GstRTSPMessage message = { 0 }; GstRTSPResult res; GstFlowReturn ret = GST_FLOW_OK; - gint64 timeout; while (TRUE) { - /* get the next timeout interval */ - timeout = gst_rtsp_connection_next_timeout_usec (src->conninfo.connection); - - GST_DEBUG_OBJECT (src, "doing receive with timeout %" G_GINT64_FORMAT - " seconds, %" G_GINT64_FORMAT " usec", timeout / G_USEC_PER_SEC, - timeout % G_USEC_PER_SEC); - gst_rtsp_message_unset (&message); /* protect the connection with the connection lock so that we can see when @@ -6333,7 +6382,10 @@ gst_rtsp_src_receive_response (GstRTSPSrc * src, GstRTSPConnInfo * conninfo, { GstRTSPStatusCode thecode; gchar *content_base = NULL; - GstRTSPResult res = gst_rtspsrc_connection_receive (src, conninfo, response, + GstRTSPResult res; + +next: + res = gst_rtspsrc_connection_receive (src, conninfo, response, src->tcp_timeout); if (res < 0) @@ -6350,7 +6402,7 @@ gst_rtsp_src_receive_response (GstRTSPSrc * src, GstRTSPConnInfo * conninfo, goto handle_request_failed; /* Not a response, receive next message */ - return gst_rtsp_src_receive_response (src, conninfo, response, code); + goto next; case GST_RTSP_MESSAGE_RESPONSE: /* ok, a response is good */ GST_DEBUG_OBJECT (src, "received response message"); @@ -6361,13 +6413,13 @@ gst_rtsp_src_receive_response (GstRTSPSrc * src, GstRTSPConnInfo * conninfo, gst_rtspsrc_handle_data (src, response); /* Not a response, receive next message */ - return gst_rtsp_src_receive_response (src, conninfo, response, code); + goto next; default: GST_WARNING_OBJECT (src, "ignoring unknown message type %d", response->type); /* Not a response, receive next message */ - return gst_rtsp_src_receive_response (src, conninfo, response, code); + goto next; } thecode = response->type_data.response.code; @@ -6474,6 +6526,10 @@ gst_rtspsrc_try_send (GstRTSPSrc * src, GstRTSPConnInfo * conninfo, goto again; } } + + if (res < 0) + goto receive_error; + gst_rtsp_ext_list_after_send (src->extensions, request, response); return res; @@ -6491,6 +6547,20 @@ gst_rtspsrc_try_send (GstRTSPSrc * src, GstRTSPConnInfo * conninfo, g_free (str); return res; } + +receive_error: + { + gchar *str = gst_rtsp_strresult (res); + + if (res != GST_RTSP_EINTR) { + GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), + ("Could not receive message. (%s)", str)); + } else { + GST_WARNING_OBJECT (src, "receive interrupted"); + } + g_free (str); + return res; + } } /** @@ -7631,6 +7701,12 @@ gst_rtspsrc_parse_range (GstRTSPSrc * src, const gchar * range, * don't update duration in that case */ if (update_duration && seconds != -1) { segment->duration = seconds; + GST_DEBUG_OBJECT (src, "set duration from range as %" GST_TIME_FORMAT, + GST_TIME_ARGS (seconds)); + } else { + GST_DEBUG_OBJECT (src, "not updating existing duration %" GST_TIME_FORMAT + " from range %" GST_TIME_FORMAT, GST_TIME_ARGS (segment->duration), + GST_TIME_ARGS (seconds)); } if (segment->rate > 0.0) @@ -8378,10 +8454,20 @@ gen_range_header (GstRTSPSrc * src, GstSegment * segment) g_date_time_unref (prime_epoch); } else { range.unit = GST_RTSP_RANGE_NPT; - range.min.type = GST_RTSP_TIME_SECONDS; - range.min.seconds = begin_seconds; - range.max.type = GST_RTSP_TIME_SECONDS; - range.max.seconds = end_seconds; + + if (src->range && src->range->min.type == GST_RTSP_TIME_NOW) { + range.min.type = GST_RTSP_TIME_NOW; + } else { + range.min.type = GST_RTSP_TIME_SECONDS; + range.min.seconds = begin_seconds; + } + + if (src->range && src->range->max.type == GST_RTSP_TIME_END) { + range.max.type = GST_RTSP_TIME_END; + } else { + range.max.type = GST_RTSP_TIME_SECONDS; + range.max.seconds = end_seconds; + } } /* Don't set end bounds when not required to */ @@ -8667,7 +8753,7 @@ gst_rtspsrc_play (GstRTSPSrc * src, GstSegment * segment, gboolean async, break; } - memcpy (&src->out_segment, segment, sizeof (GstSegment)); + src->out_segment = *segment; if (src->clip_out_segment) { /* Only clip the output segment when the server has answered with valid @@ -8888,6 +8974,7 @@ gst_rtspsrc_handle_message (GstBin * bin, GstMessage * message) rtspsrc = GST_RTSPSRC (bin); switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_STREAM_START: case GST_MESSAGE_EOS: gst_message_unref (message); break; @@ -8976,7 +9063,9 @@ gst_rtspsrc_thread (GstRTSPSrc * src) src->pending_cmd = CMD_LOOP; } else { ParameterRequest *next_req; - req = g_queue_pop_head (&src->set_get_param_q); + if (cmd == CMD_GET_PARAMETER || cmd == CMD_SET_PARAMETER) { + req = g_queue_pop_head (&src->set_get_param_q); + } next_req = g_queue_peek_head (&src->set_get_param_q); src->pending_cmd = next_req ? next_req->cmd : CMD_LOOP; } @@ -9136,6 +9225,7 @@ gst_rtspsrc_change_state (GstElement * element, GstStateChange transition) } break; case GST_STATE_CHANGE_PAUSED_TO_READY: + rtspsrc->group_id = GST_GROUP_ID_INVALID; break; default: break; @@ -9168,6 +9258,7 @@ gst_rtspsrc_change_state (GstElement * element, GstStateChange transition) ret = GST_STATE_CHANGE_SUCCESS; break; case GST_STATE_CHANGE_PAUSED_TO_READY: + rtspsrc->seek_seqnum = GST_SEQNUM_INVALID; gst_rtspsrc_loop_send_cmd_and_wait (rtspsrc, CMD_CLOSE, CMD_ALL, rtspsrc->teardown_timeout); ret = GST_STATE_CHANGE_SUCCESS; @@ -9369,6 +9460,8 @@ gst_rtspsrc_get_parameter (GstRTSPSrc * src, ParameterRequest * req) GST_DEBUG_OBJECT (src, "creating server get_parameter"); + g_assert (req); + if ((res = gst_rtspsrc_ensure_open (src, FALSE)) < 0) goto open_failed; @@ -9486,6 +9579,8 @@ gst_rtspsrc_set_parameter (GstRTSPSrc * src, ParameterRequest * req) GST_DEBUG_OBJECT (src, "creating server set_parameter"); + g_assert (req); + if ((res = gst_rtspsrc_ensure_open (src, FALSE)) < 0) goto open_failed; diff --git a/gst/rtsp/gstrtspsrc.h b/gst/rtsp/gstrtspsrc.h index cf42ab6e66..469d2dace7 100644 --- a/gst/rtsp/gstrtspsrc.h +++ b/gst/rtsp/gstrtspsrc.h @@ -268,7 +268,7 @@ struct _GstRTSPSrc { gboolean do_retransmission; gint ntp_time_source; gchar *user_agent; - GstClockTime max_rtcp_rtp_time_diff; + gint max_rtcp_rtp_time_diff; gboolean rfc7273_sync; guint64 max_ts_offset_adjustment; gint64 max_ts_offset; @@ -303,6 +303,7 @@ struct _GstRTSPSrc { * between any two random access points * */ gfloat seekable; + guint32 seek_seqnum; GstClockTime last_pos; /* session management */ @@ -323,6 +324,9 @@ struct _GstRTSPSrc { GstRTSPVersion version; GstEvent *initial_seek; + + guint group_id; + GMutex group_lock; }; struct _GstRTSPSrcClass { diff --git a/gst/smpte/gstsmpte.c b/gst/smpte/gstsmpte.c index f7f8c7321f..54c077ee36 100644 --- a/gst/smpte/gstsmpte.c +++ b/gst/smpte/gstsmpte.c @@ -199,6 +199,8 @@ gst_smpte_class_init (GstSMPTEClass * klass) "Filter/Editor/Video", "Apply the standard SMPTE transitions on video images", "Wim Taymans "); + + gst_type_mark_as_plugin_api (GST_TYPE_SMPTE_TRANSITION_TYPE, 0); } /* wht yel cya grn mag red blu blk -I Q */ diff --git a/gst/smpte/gstsmptealpha.c b/gst/smpte/gstsmptealpha.c index ee830ce239..3d7fe1171e 100644 --- a/gst/smpte/gstsmptealpha.c +++ b/gst/smpte/gstsmptealpha.c @@ -212,6 +212,8 @@ gst_smpte_alpha_class_init (GstSMPTEAlphaClass * klass) "Filter/Editor/Video", "Apply the standard SMPTE transitions as alpha on video images", "Wim Taymans "); + + gst_type_mark_as_plugin_api (GST_TYPE_SMPTE_TRANSITION_TYPE, 0); } static gboolean diff --git a/gst/udp/gstmultiudpsink.c b/gst/udp/gstmultiudpsink.c index 3cece6a1f9..30ca4b7a9c 100644 --- a/gst/udp/gstmultiudpsink.c +++ b/gst/udp/gstmultiudpsink.c @@ -41,6 +41,8 @@ #include #endif +#include + #include "gst/net/net.h" #include "gst/glib-compat-private.h" @@ -1338,10 +1340,9 @@ gst_multiudpsink_start (GstBaseSink * bsink) } #ifdef SO_SNDBUF { - socklen_t len; - gint sndsize, ret; + gint sndsize; + GError *opt_err = NULL; - len = sizeof (sndsize); if (sink->buffer_size != 0) { sndsize = sink->buffer_size; @@ -1351,24 +1352,22 @@ gst_multiudpsink_start (GstBaseSink * bsink) * Linux. */ if (sink->used_socket) { - ret = - setsockopt (g_socket_get_fd (sink->used_socket), SOL_SOCKET, - SO_SNDBUF, (void *) &sndsize, len); - if (ret != 0) { + if (!g_socket_set_option (sink->used_socket, SOL_SOCKET, SO_SNDBUF, + sndsize, &opt_err)) { GST_ELEMENT_WARNING (sink, RESOURCE, SETTINGS, (NULL), - ("Could not create a buffer of requested %d bytes, %d: %s", - sndsize, ret, g_strerror (errno))); + ("Could not create a buffer of requested %d bytes (%s)", + sndsize, opt_err->message)); + g_clear_error (&opt_err); } } if (sink->used_socket_v6) { - ret = - setsockopt (g_socket_get_fd (sink->used_socket_v6), SOL_SOCKET, - SO_SNDBUF, (void *) &sndsize, len); - if (ret != 0) { + if (!g_socket_set_option (sink->used_socket_v6, SOL_SOCKET, SO_SNDBUF, + sndsize, &opt_err)) { GST_ELEMENT_WARNING (sink, RESOURCE, SETTINGS, (NULL), - ("Could not create a buffer of requested %d bytes, %d: %s", - sndsize, ret, g_strerror (errno))); + ("Could not create a buffer of requested %d bytes (%s)", + sndsize, opt_err->message)); + g_clear_error (&opt_err); } } } @@ -1377,23 +1376,21 @@ gst_multiudpsink_start (GstBaseSink * bsink) * value we set because the kernel allocates extra memory for metadata. * The default on Linux is about 100K (which is about 50K without metadata) */ if (sink->used_socket) { - ret = - getsockopt (g_socket_get_fd (sink->used_socket), SOL_SOCKET, - SO_SNDBUF, (void *) &sndsize, &len); - if (ret == 0) + if (g_socket_get_option (sink->used_socket, SOL_SOCKET, SO_SNDBUF, + &sndsize, NULL)) { GST_DEBUG_OBJECT (sink, "have UDP buffer of %d bytes", sndsize); - else + } else { GST_DEBUG_OBJECT (sink, "could not get UDP buffer size"); + } } if (sink->used_socket_v6) { - ret = - getsockopt (g_socket_get_fd (sink->used_socket_v6), SOL_SOCKET, - SO_SNDBUF, (void *) &sndsize, &len); - if (ret == 0) + if (g_socket_get_option (sink->used_socket_v6, SOL_SOCKET, SO_SNDBUF, + &sndsize, NULL)) { GST_DEBUG_OBJECT (sink, "have UDPv6 buffer of %d bytes", sndsize); - else + } else { GST_DEBUG_OBJECT (sink, "could not get UDPv6 buffer size"); + } } } #endif diff --git a/gst/udp/gstudpsrc.c b/gst/udp/gstudpsrc.c index 6aab24a692..42477456c6 100644 --- a/gst/udp/gstudpsrc.c +++ b/gst/udp/gstudpsrc.c @@ -68,7 +68,7 @@ * If the #GstUDPSrc:timeout property is set to a value bigger than 0, udpsrc * will generate an element message named `GstUDPSrcTimeout` * if no data was received in the given timeout. - * + * * The message's structure contains one field: * * * #guint64 `timeout`: the timeout in microseconds that expired when waiting for data. @@ -1019,6 +1019,7 @@ gst_udpsrc_fill (GstPushSrc * psrc, GstBuffer * outbuf) { gst_buffer_unmap (outbuf, &info); gst_memory_unmap (udpsrc->extra_mem, &extra_info); + g_clear_object (&saddr); if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_BUSY) || g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { g_clear_error (&err); @@ -1032,6 +1033,7 @@ gst_udpsrc_fill (GstPushSrc * psrc, GstBuffer * outbuf) } skip_error: { + g_clear_object (&saddr); GST_ELEMENT_ERROR (udpsrc, STREAM, DECODE, (NULL), ("UDP buffer to small to skip header")); return GST_FLOW_ERROR; diff --git a/gst/videobox/gstvideobox.c b/gst/videobox/gstvideobox.c index 58df1ee507..0e69c7c136 100644 --- a/gst/videobox/gstvideobox.c +++ b/gst/videobox/gstvideobox.c @@ -147,7 +147,7 @@ fill_ayuv (GstVideoBoxFill fill_type, guint b_alpha, width = GST_VIDEO_FRAME_WIDTH (frame); height = GST_VIDEO_FRAME_HEIGHT (frame); - b_alpha = CLAMP (b_alpha, 0, 255); + b_alpha = MIN (b_alpha, 255); if (sdtv) empty_pixel = GUINT32_FROM_BE ((b_alpha << 24) | @@ -1695,7 +1695,7 @@ copy_i420_ayuv (guint i_alpha, GstVideoFrame * dest_frame, srcU = srcU + (src_y / 2) * src_strideU + src_x / 2; srcV = srcV + (src_y / 2) * src_strideV + src_x / 2; - i_alpha = CLAMP (i_alpha, 0, 255); + i_alpha = MIN (i_alpha, 255); if (src_sdtv != dest_sdtv) { gint i, j, uv_idx; @@ -1779,7 +1779,7 @@ fill_rgb32 (GstVideoBoxFill fill_type, guint b_alpha, p[2] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 1); p[3] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 2); - b_alpha = CLAMP (b_alpha, 0, 255); + b_alpha = MIN (b_alpha, 255); if (GST_VIDEO_FRAME_N_COMPONENTS (frame) == 4) { empty_pixel = GUINT32_FROM_LE ((b_alpha << (p[0] * 8)) | @@ -1886,7 +1886,7 @@ copy_rgb32 (guint i_alpha, GstVideoFrame * dest_frame, } } else if (out_alpha && !packed_in) { w *= 4; - i_alpha = CLAMP (i_alpha, 0, 255); + i_alpha = MIN (i_alpha, 255); for (i = 0; i < h; i++) { for (j = 0; j < w; j += 4) { @@ -1899,7 +1899,7 @@ copy_rgb32 (guint i_alpha, GstVideoFrame * dest_frame, src += src_stride; } } else if (out_alpha && packed_in) { - i_alpha = CLAMP (i_alpha, 0, 255); + i_alpha = MIN (i_alpha, 255); for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { @@ -1995,7 +1995,7 @@ copy_rgb32_ayuv (guint i_alpha, GstVideoFrame * dest_frame, } } else if (!packed_in) { w *= 4; - i_alpha = CLAMP (i_alpha, 0, 255); + i_alpha = MIN (i_alpha, 255); for (i = 0; i < h; i++) { for (j = 0; j < w; j += 4) { @@ -2017,7 +2017,7 @@ copy_rgb32_ayuv (guint i_alpha, GstVideoFrame * dest_frame, src += src_stride; } } else { - i_alpha = CLAMP (i_alpha, 0, 255); + i_alpha = MIN (i_alpha, 255); for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { @@ -2533,6 +2533,8 @@ gst_video_box_class_init (GstVideoBoxClass * klass) &gst_video_box_sink_template); gst_element_class_add_static_pad_template (element_class, &gst_video_box_src_template); + + gst_type_mark_as_plugin_api (GST_TYPE_VIDEO_BOX_FILL, 0); } static void diff --git a/gst/videobox/meson.build b/gst/videobox/meson.build index 8c8e074bcb..1511c30661 100644 --- a/gst/videobox/meson.build +++ b/gst/videobox/meson.build @@ -8,6 +8,7 @@ if have_orcc input : orcsrc + '.orc', output : orcsrc + '.c', command : orcc_args + ['--implementation', '-o', '@OUTPUT@', '@INPUT@']) + orc_targets += {'name': orcsrc, 'orc-source': files(orcsrc + '.orc'), 'header': orc_h, 'source': orc_c} else orc_h = configure_file(input : orcsrc + '-dist.h', output : orcsrc + '.h', diff --git a/gst/videocrop/gstvideocrop.c b/gst/videocrop/gstvideocrop.c index 4722ec797d..9ad5df7d18 100644 --- a/gst/videocrop/gstvideocrop.c +++ b/gst/videocrop/gstvideocrop.c @@ -80,9 +80,9 @@ enum /* we support the same caps as aspectratiocrop (sync changes) */ #define VIDEO_CROP_CAPS \ GST_VIDEO_CAPS_MAKE ("{ RGBx, xRGB, BGRx, xBGR, " \ - "RGBA, ARGB, BGRA, ABGR, RGB, BGR, AYUV, YUY2, " \ - "YVYU, UYVY, I420, YV12, RGB16, RGB15, GRAY8, " \ - "NV12, NV21, GRAY16_LE, GRAY16_BE }") + "RGBA, ARGB, BGRA, ABGR, RGB, BGR, AYUV, YUY2, Y444, " \ + "Y42B, Y41B, YVYU, UYVY, I420, YV12, RGB16, RGB15, " \ + "GRAY8, NV12, NV21, GRAY16_LE, GRAY16_BE }") static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, @@ -331,52 +331,48 @@ static void gst_video_crop_transform_planar (GstVideoCrop * vcrop, GstVideoFrame * in_frame, GstVideoFrame * out_frame, gint x, gint y) { - gint width, height; + const GstVideoFormatInfo *format_info; gint crop_top, crop_left; - guint8 *y_out, *u_out, *v_out; - guint8 *y_in, *u_in, *v_in; - guint i, dx; + guint p; - width = GST_VIDEO_FRAME_WIDTH (out_frame); - height = GST_VIDEO_FRAME_HEIGHT (out_frame); + format_info = in_frame->info.finfo; crop_left = vcrop->crop_left + x; crop_top = vcrop->crop_top + y; - /* Y plane */ - y_in = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0); - y_out = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0); - - y_in += (crop_top * GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0)) + crop_left; - dx = width; - - for (i = 0; i < height; ++i) { - memcpy (y_out, y_in, dx); - y_in += GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0); - y_out += GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0); - } - - /* U + V planes */ - u_in = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 1); - u_out = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 1); - - u_in += (crop_top / 2) * GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 1); - u_in += crop_left / 2; - - v_in = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 2); - v_out = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 2); - - v_in += (crop_top / 2) * GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 2); - v_in += crop_left / 2; - - dx = GST_ROUND_UP_2 (width) / 2; + for (p = 0; p < GST_VIDEO_FRAME_N_PLANES (in_frame); ++p) { + guint8 *plane_in, *plane_out; + guint sub_w_factor, sub_h_factor; + guint subsampled_crop_left, subsampled_crop_top; + guint copy_width; + gint i; - for (i = 0; i < GST_ROUND_UP_2 (height) / 2; ++i) { - memcpy (u_out, u_in, dx); - memcpy (v_out, v_in, dx); - u_in += GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 1); - u_out += GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 1); - v_in += GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 2); - v_out += GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 2); + /* plane */ + plane_in = GST_VIDEO_FRAME_PLANE_DATA (in_frame, p); + plane_out = GST_VIDEO_FRAME_PLANE_DATA (out_frame, p); + + /* apply crop top/left + * crop_top and crop_left have to be rounded down to the corresponding + * subsampling factor, since, e.g.: the first line in a subsampled plane + * describes 2 lines in the actual image. A crop_top of 1 thus should + * not shift the pointer of the input plane. */ + sub_w_factor = 1 << GST_VIDEO_FORMAT_INFO_W_SUB (format_info, p); + sub_h_factor = 1 << GST_VIDEO_FORMAT_INFO_H_SUB (format_info, p); + subsampled_crop_left = GST_ROUND_DOWN_N ((guint) crop_left, sub_w_factor); + subsampled_crop_top = GST_ROUND_DOWN_N ((guint) crop_top, sub_h_factor); + + plane_in += + GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (format_info, p, + subsampled_crop_top) * GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, p); + plane_in += + GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (format_info, p, + subsampled_crop_left); + copy_width = (guint) GST_VIDEO_FRAME_COMP_WIDTH (out_frame, p); + + for (i = 0; i < GST_VIDEO_FRAME_COMP_HEIGHT (out_frame, p); ++i) { + memcpy (plane_out, plane_in, copy_width); + plane_in += GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, p); + plane_out += GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, p); + } } } @@ -634,7 +630,7 @@ gst_video_crop_transform_dimension_value (const GValue * src_val, for (i = 0; i < gst_value_list_get_size (src_val); ++i) { const GValue *list_val; - GValue newval = { 0, }; + GValue newval = G_VALUE_INIT; list_val = gst_value_list_get_value (src_val, i); if (gst_video_crop_transform_dimension_value (list_val, delta, &newval, @@ -695,8 +691,7 @@ gst_video_crop_transform_caps (GstBaseTransform * trans, for (i = 0; i < gst_caps_get_size (caps); ++i) { const GValue *v; GstStructure *structure, *new_structure; - GValue w_val = { 0, }, h_val = { - 0,}; + GValue w_val = G_VALUE_INIT, h_val = G_VALUE_INIT; structure = gst_caps_get_structure (caps, i); @@ -813,6 +808,9 @@ gst_video_crop_set_info (GstVideoFilter * vfilter, GstCaps * in, break; case GST_VIDEO_FORMAT_I420: case GST_VIDEO_FORMAT_YV12: + case GST_VIDEO_FORMAT_Y444: + case GST_VIDEO_FORMAT_Y42B: + case GST_VIDEO_FORMAT_Y41B: crop->packing = VIDEO_CROP_PIXEL_FORMAT_PLANAR; break; case GST_VIDEO_FORMAT_NV12: diff --git a/gst/videocrop/gstvideocrop.h b/gst/videocrop/gstvideocrop.h index f654e8483d..4082b99592 100644 --- a/gst/videocrop/gstvideocrop.h +++ b/gst/videocrop/gstvideocrop.h @@ -38,7 +38,7 @@ G_BEGIN_DECLS typedef enum { VIDEO_CROP_PIXEL_FORMAT_PACKED_SIMPLE = 0, /* RGBx, AYUV */ VIDEO_CROP_PIXEL_FORMAT_PACKED_COMPLEX, /* UYVY, YVYU */ - VIDEO_CROP_PIXEL_FORMAT_PLANAR, /* I420, YV12 */ + VIDEO_CROP_PIXEL_FORMAT_PLANAR, /* I420, YV12, Y444 */ VIDEO_CROP_PIXEL_FORMAT_SEMI_PLANAR /* NV12, NV21 */ } VideoCropPixelFormat; diff --git a/gst/videofilter/gstvideoflip.c b/gst/videofilter/gstvideoflip.c index 1c2612662f..f20e4edafc 100644 --- a/gst/videofilter/gstvideoflip.c +++ b/gst/videofilter/gstvideoflip.c @@ -135,6 +135,26 @@ gst_video_flip_transform_caps (GstBaseTransform * trans, ret = gst_caps_copy (caps); + GST_OBJECT_LOCK (videoflip); + + if (videoflip->change_configuring_method) { + GEnumValue *configuring_method_enum, *method_enum; + GEnumClass *enum_class = + g_type_class_ref (GST_TYPE_VIDEO_ORIENTATION_METHOD); + + configuring_method_enum = + g_enum_get_value (enum_class, videoflip->configuring_method); + method_enum = g_enum_get_value (enum_class, videoflip->proposed_method); + GST_LOG_OBJECT (videoflip, + "Changing configuring method from %s to proposed %s", + configuring_method_enum ? configuring_method_enum->value_nick : "(nil)", + method_enum ? method_enum->value_nick : "(nil)"); + g_type_class_unref (enum_class); + + videoflip->configuring_method = videoflip->proposed_method; + } + videoflip->change_configuring_method = FALSE; + for (i = 0; i < gst_caps_get_size (ret); i++) { GstStructure *structure = gst_caps_get_structure (ret, i); gint par_n, par_d; @@ -142,7 +162,7 @@ gst_video_flip_transform_caps (GstBaseTransform * trans, if (gst_structure_get_int (structure, "width", &width) && gst_structure_get_int (structure, "height", &height)) { - switch (videoflip->active_method) { + switch (videoflip->configuring_method) { case GST_VIDEO_ORIENTATION_90R: case GST_VIDEO_ORIENTATION_90L: case GST_VIDEO_ORIENTATION_UL_LR: @@ -177,6 +197,7 @@ gst_video_flip_transform_caps (GstBaseTransform * trans, } } } + GST_OBJECT_UNLOCK (videoflip); GST_DEBUG_OBJECT (videoflip, "transformed %" GST_PTR_FORMAT " to %" GST_PTR_FORMAT, caps, ret); @@ -435,7 +456,7 @@ gst_video_flip_planar_yuv (GstVideoFlip * videoflip, GstVideoFrame * dest, } break; case GST_VIDEO_ORIENTATION_IDENTITY: - g_assert_not_reached (); + gst_video_frame_copy (dest, src); break; default: g_assert_not_reached (); @@ -634,7 +655,7 @@ gst_video_flip_semi_planar_yuv (GstVideoFlip * videoflip, GstVideoFrame * dest, } break; case GST_VIDEO_ORIENTATION_IDENTITY: - g_assert_not_reached (); + gst_video_frame_copy (dest, src); break; default: g_assert_not_reached (); @@ -735,7 +756,7 @@ gst_video_flip_packed_simple (GstVideoFlip * videoflip, GstVideoFrame * dest, } break; case GST_VIDEO_ORIENTATION_IDENTITY: - g_assert_not_reached (); + gst_video_frame_copy (dest, src); break; default: g_assert_not_reached (); @@ -951,7 +972,7 @@ gst_video_flip_y422 (GstVideoFlip * videoflip, GstVideoFrame * dest, } break; case GST_VIDEO_ORIENTATION_IDENTITY: - g_assert_not_reached (); + gst_video_frame_copy (dest, src); break; default: g_assert_not_reached (); @@ -959,13 +980,51 @@ gst_video_flip_y422 (GstVideoFlip * videoflip, GstVideoFrame * dest, } } +static void +gst_video_flip_configure_process (GstVideoFlip * vf) +{ + switch (vf->v_format) { + case GST_VIDEO_FORMAT_I420: + case GST_VIDEO_FORMAT_YV12: + case GST_VIDEO_FORMAT_Y444: + vf->process = gst_video_flip_planar_yuv; + break; + case GST_VIDEO_FORMAT_YUY2: + case GST_VIDEO_FORMAT_UYVY: + case GST_VIDEO_FORMAT_YVYU: + vf->process = gst_video_flip_y422; + break; + case GST_VIDEO_FORMAT_AYUV: + case GST_VIDEO_FORMAT_ARGB: + case GST_VIDEO_FORMAT_ABGR: + case GST_VIDEO_FORMAT_RGBA: + case GST_VIDEO_FORMAT_BGRA: + case GST_VIDEO_FORMAT_xRGB: + case GST_VIDEO_FORMAT_xBGR: + case GST_VIDEO_FORMAT_RGBx: + case GST_VIDEO_FORMAT_BGRx: + case GST_VIDEO_FORMAT_RGB: + case GST_VIDEO_FORMAT_BGR: + case GST_VIDEO_FORMAT_GRAY8: + case GST_VIDEO_FORMAT_GRAY16_BE: + case GST_VIDEO_FORMAT_GRAY16_LE: + vf->process = gst_video_flip_packed_simple; + break; + case GST_VIDEO_FORMAT_NV12: + case GST_VIDEO_FORMAT_NV21: + vf->process = gst_video_flip_semi_planar_yuv; + break; + default: + break; + } +} static gboolean gst_video_flip_set_info (GstVideoFilter * vfilter, GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info) { GstVideoFlip *vf = GST_VIDEO_FLIP (vfilter); - gboolean ret = FALSE; + gboolean ret = FALSE, need_reconfigure = FALSE; vf->process = NULL; @@ -973,7 +1032,8 @@ gst_video_flip_set_info (GstVideoFilter * vfilter, GstCaps * incaps, goto invalid_caps; /* Check that they are correct */ - switch (vf->active_method) { + GST_OBJECT_LOCK (vf); + switch (vf->configuring_method) { case GST_VIDEO_ORIENTATION_90R: case GST_VIDEO_ORIENTATION_90L: case GST_VIDEO_ORIENTATION_UL_LR: @@ -987,8 +1047,6 @@ gst_video_flip_set_info (GstVideoFilter * vfilter, GstCaps * incaps, } break; case GST_VIDEO_ORIENTATION_IDENTITY: - - break; case GST_VIDEO_ORIENTATION_180: case GST_VIDEO_ORIENTATION_HORIZ: case GST_VIDEO_ORIENTATION_VERT: @@ -1007,42 +1065,32 @@ gst_video_flip_set_info (GstVideoFilter * vfilter, GstCaps * incaps, ret = TRUE; - switch (GST_VIDEO_INFO_FORMAT (in_info)) { - case GST_VIDEO_FORMAT_I420: - case GST_VIDEO_FORMAT_YV12: - case GST_VIDEO_FORMAT_Y444: - vf->process = gst_video_flip_planar_yuv; - break; - case GST_VIDEO_FORMAT_YUY2: - case GST_VIDEO_FORMAT_UYVY: - case GST_VIDEO_FORMAT_YVYU: - vf->process = gst_video_flip_y422; - break; - case GST_VIDEO_FORMAT_AYUV: - case GST_VIDEO_FORMAT_ARGB: - case GST_VIDEO_FORMAT_ABGR: - case GST_VIDEO_FORMAT_RGBA: - case GST_VIDEO_FORMAT_BGRA: - case GST_VIDEO_FORMAT_xRGB: - case GST_VIDEO_FORMAT_xBGR: - case GST_VIDEO_FORMAT_RGBx: - case GST_VIDEO_FORMAT_BGRx: - case GST_VIDEO_FORMAT_RGB: - case GST_VIDEO_FORMAT_BGR: - case GST_VIDEO_FORMAT_GRAY8: - case GST_VIDEO_FORMAT_GRAY16_BE: - case GST_VIDEO_FORMAT_GRAY16_LE: - vf->process = gst_video_flip_packed_simple; - break; - case GST_VIDEO_FORMAT_NV12: - case GST_VIDEO_FORMAT_NV21: - vf->process = gst_video_flip_semi_planar_yuv; - break; - default: - break; + { + GEnumValue *active_method_enum, *method_enum; + GEnumClass *enum_class = + g_type_class_ref (GST_TYPE_VIDEO_ORIENTATION_METHOD); + + active_method_enum = g_enum_get_value (enum_class, vf->active_method); + method_enum = g_enum_get_value (enum_class, vf->configuring_method); + GST_LOG_OBJECT (vf, "Changing active method from %s to configuring %s", + active_method_enum ? active_method_enum->value_nick : "(nil)", + method_enum ? method_enum->value_nick : "(nil)"); + g_type_class_unref (enum_class); } + vf->active_method = vf->configuring_method; + vf->change_configuring_method = TRUE; + if (vf->active_method != vf->proposed_method) + need_reconfigure = TRUE; + + vf->v_format = GST_VIDEO_INFO_FORMAT (in_info); + gst_video_flip_configure_process (vf); beach: + GST_OBJECT_UNLOCK (vf); + if (need_reconfigure) { + gst_base_transform_reconfigure_src (GST_BASE_TRANSFORM (vf)); + } + return ret && (vf->process != NULL); invalid_caps: @@ -1075,7 +1123,7 @@ gst_video_flip_set_method (GstVideoFlip * videoflip, else method = videoflip->method; - if (method != videoflip->active_method) { + if (method != videoflip->proposed_method) { GEnumValue *active_method_enum, *method_enum; GstBaseTransform *btrans = GST_BASE_TRANSFORM (videoflip); GEnumClass *enum_class = @@ -1084,12 +1132,12 @@ gst_video_flip_set_method (GstVideoFlip * videoflip, active_method_enum = g_enum_get_value (enum_class, videoflip->active_method); method_enum = g_enum_get_value (enum_class, method); - GST_DEBUG_OBJECT (videoflip, "Changing method from %s to %s", + GST_LOG_OBJECT (videoflip, "Changing method from %s to %s", active_method_enum ? active_method_enum->value_nick : "(nil)", method_enum ? method_enum->value_nick : "(nil)"); g_type_class_unref (enum_class); - videoflip->active_method = method; + videoflip->proposed_method = method; GST_OBJECT_UNLOCK (videoflip); @@ -1123,26 +1171,46 @@ gst_video_flip_transform_frame (GstVideoFilter * vfilter, GstVideoFrame * in_frame, GstVideoFrame * out_frame) { GEnumClass *enum_class; + GstVideoOrientationMethod active, proposed; GEnumValue *active_method_enum; GstVideoFlip *videoflip = GST_VIDEO_FLIP (vfilter); + GST_OBJECT_LOCK (videoflip); if (G_UNLIKELY (videoflip->process == NULL)) goto not_negotiated; + if (videoflip->configuring_method != videoflip->active_method) { + videoflip->active_method = videoflip->configuring_method; + gst_video_flip_configure_process (videoflip); + } + enum_class = g_type_class_ref (GST_TYPE_VIDEO_ORIENTATION_METHOD); active_method_enum = g_enum_get_value (enum_class, videoflip->active_method); - GST_LOG_OBJECT (videoflip, "videoflip: flipping (%s)", - active_method_enum ? active_method_enum->value_nick : "(nil)"); + GST_LOG_OBJECT (videoflip, + "videoflip: flipping (%s), input %ux%u output %ux%u", + active_method_enum ? active_method_enum->value_nick : "(nil)", + GST_VIDEO_FRAME_WIDTH (in_frame), GST_VIDEO_FRAME_HEIGHT (in_frame), + GST_VIDEO_FRAME_WIDTH (out_frame), GST_VIDEO_FRAME_HEIGHT (out_frame)); g_type_class_unref (enum_class); - GST_OBJECT_LOCK (videoflip); videoflip->process (videoflip, out_frame, in_frame); + + proposed = videoflip->proposed_method; + active = videoflip->active_method; + videoflip->change_configuring_method = TRUE; GST_OBJECT_UNLOCK (videoflip); + if (proposed != active) { + gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (videoflip), + proposed == GST_VIDEO_ORIENTATION_IDENTITY); + gst_base_transform_reconfigure_src (GST_BASE_TRANSFORM (videoflip)); + } + return GST_FLOW_OK; not_negotiated: { + GST_OBJECT_UNLOCK (videoflip); GST_ERROR_OBJECT (videoflip, "Not negotiated yet"); return GST_FLOW_NOT_NEGOTIATED; } @@ -1168,6 +1236,7 @@ gst_video_flip_src_event (GstBaseTransform * trans, GstEvent * event) if (gst_structure_get_double (structure, "pointer_x", &x) && gst_structure_get_double (structure, "pointer_y", &y)) { GST_DEBUG_OBJECT (vf, "converting %fx%f", x, y); + GST_OBJECT_LOCK (vf); switch (vf->active_method) { case GST_VIDEO_ORIENTATION_90R: new_x = y; @@ -1202,6 +1271,7 @@ gst_video_flip_src_event (GstBaseTransform * trans, GstEvent * event) new_y = y; break; } + GST_OBJECT_UNLOCK (vf); GST_DEBUG_OBJECT (vf, "to %fx%f", new_x, new_y); gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, new_x, "pointer_y", G_TYPE_DOUBLE, new_y, NULL); @@ -1301,6 +1371,7 @@ gst_video_flip_class_init (GstVideoFlipClass * klass) GstElementClass *gstelement_class = (GstElementClass *) klass; GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass; GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass; + GParamSpec *pspec; GST_DEBUG_CATEGORY_INIT (video_flip_debug, "videoflip", 0, "videoflip"); @@ -1311,10 +1382,14 @@ gst_video_flip_class_init (GstVideoFlipClass * klass) g_param_spec_enum ("method", "method", "method (deprecated, use video-direction instead)", GST_TYPE_VIDEO_FLIP_METHOD, PROP_METHOD_DEFAULT, - GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_CONSTRUCT | - G_PARAM_STATIC_STRINGS)); + GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); g_object_class_override_property (gobject_class, PROP_VIDEO_DIRECTION, "video-direction"); + /* override the overriden property's flags to include the mutable in playing + * flag */ + pspec = g_object_class_find_property (gobject_class, "video-direction"); + pspec->flags |= GST_PARAM_MUTABLE_PLAYING; gst_element_class_set_static_metadata (gstelement_class, "Video flipper", "Filter/Effect/Video", @@ -1335,6 +1410,8 @@ gst_video_flip_class_init (GstVideoFlipClass * klass) vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_video_flip_set_info); vfilter_class->transform_frame = GST_DEBUG_FUNCPTR (gst_video_flip_transform_frame); + + gst_type_mark_as_plugin_api (GST_TYPE_VIDEO_FLIP_METHOD, 0); } static void @@ -1343,4 +1420,6 @@ gst_video_flip_init (GstVideoFlip * videoflip) /* AUTO is not valid for active method, this is just to ensure we setup the * method in gst_video_flip_set_method() */ videoflip->active_method = GST_VIDEO_ORIENTATION_AUTO; + videoflip->proposed_method = GST_VIDEO_ORIENTATION_IDENTITY; + videoflip->configuring_method = GST_VIDEO_ORIENTATION_IDENTITY; } diff --git a/gst/videofilter/gstvideoflip.h b/gst/videofilter/gstvideoflip.h index 0fca8e93e3..a82bbc4799 100644 --- a/gst/videofilter/gstvideoflip.h +++ b/gst/videofilter/gstvideoflip.h @@ -75,8 +75,13 @@ struct _GstVideoFlip { GstVideoFilter videofilter; /* < private > */ + GstVideoFormat v_format; + GstVideoOrientationMethod method; GstVideoOrientationMethod tag_method; + GstVideoOrientationMethod proposed_method; + gboolean change_configuring_method; + GstVideoOrientationMethod configuring_method; GstVideoOrientationMethod active_method; void (*process) (GstVideoFlip *videoflip, GstVideoFrame *dest, const GstVideoFrame *src); }; diff --git a/gst/videofilter/gstvideomedian.c b/gst/videofilter/gstvideomedian.c index 042cd23b1c..663872682b 100644 --- a/gst/videofilter/gstvideomedian.c +++ b/gst/videofilter/gstvideomedian.c @@ -119,6 +119,8 @@ gst_video_median_class_init (GstVideoMedianClass * klass) vfilter_class->transform_frame = GST_DEBUG_FUNCPTR (gst_video_median_transform_frame); + + gst_type_mark_as_plugin_api (GST_TYPE_VIDEO_MEDIAN_SIZE, 0); } void diff --git a/gst/videomixer/meson.build b/gst/videomixer/meson.build index b0f1c425c4..2e1cb77743 100644 --- a/gst/videomixer/meson.build +++ b/gst/videomixer/meson.build @@ -13,6 +13,7 @@ if have_orcc input : orcsrc + '.orc', output : orcsrc + '.c', command : orcc_args + ['--implementation', '-o', '@OUTPUT@', '@INPUT@']) + orc_targets += {'name': orcsrc, 'orc-source': files(orcsrc + '.orc'), 'header': orc_h, 'source': orc_c} else orc_h = configure_file(input : orcsrc + '-dist.h', output : orcsrc + '.h', diff --git a/gst/videomixer/videomixer2.c b/gst/videomixer/videomixer2.c index 69a0a0fb3b..d225abbbf8 100644 --- a/gst/videomixer/videomixer2.c +++ b/gst/videomixer/videomixer2.c @@ -258,6 +258,7 @@ gst_videomixer2_update_src_caps (GstVideoMixer2 * mix) tmp = gst_caps_intersect (caps, peercaps); gst_caps_unref (caps); gst_caps_unref (peercaps); + peercaps = NULL; caps = tmp; if (gst_caps_is_empty (caps)) { GST_DEBUG_OBJECT (mix, "empty caps"); @@ -277,6 +278,8 @@ gst_videomixer2_update_src_caps (GstVideoMixer2 * mix) gst_structure_get_int (s, "height", &info.height); gst_structure_get_fraction (s, "fraction", &info.fps_n, &info.fps_d); } + if (peercaps) + gst_caps_unref (peercaps); gst_caps_unref (caps); caps = gst_video_info_to_caps (&info); @@ -2232,6 +2235,8 @@ gst_videomixer2_class_init (GstVideoMixer2Class * klass) /* Register the pad class */ g_type_class_ref (GST_TYPE_VIDEO_MIXER2_PAD); + + gst_type_mark_as_plugin_api (GST_TYPE_VIDEO_MIXER2_BACKGROUND, 0); } static void diff --git a/gst/wavenc/gstwavenc.c b/gst/wavenc/gstwavenc.c index 938820e22d..ddfa7953c4 100644 --- a/gst/wavenc/gstwavenc.c +++ b/gst/wavenc/gstwavenc.c @@ -546,6 +546,7 @@ gst_wavparse_tags_foreach (const GstTagList * tags, const gchar * tag, 0, NULL} }; gint n; + size_t size; gchar *str = NULL; GstByteWriter *bw = data; for (n = 0; rifftags[n].fcc != 0; n++) { @@ -563,9 +564,15 @@ gst_wavparse_tags_foreach (const GstTagList * tags, const gchar * tag, gst_tag_list_get_string (tags, tag, &str); } if (str) { + /* get string length including null termination */ + size = strlen (str) + 1; gst_byte_writer_put_uint32_le (bw, rifftags[n].fcc); - gst_byte_writer_put_uint32_le (bw, GST_ROUND_UP_2 (strlen (str))); - gst_byte_writer_put_string (bw, str); + gst_byte_writer_put_uint32_le (bw, GST_ROUND_UP_2 (size)); + gst_byte_writer_put_data (bw, (const guint8 *) str, size); + /* add padding if needed */ + if (GST_ROUND_UP_2 (size) > size) { + gst_byte_writer_put_uint8 (bw, 0); + } g_free (str); str = NULL; break; diff --git a/gst/wavparse/gstwavparse.c b/gst/wavparse/gstwavparse.c index a09720658b..7d4d753f47 100644 --- a/gst/wavparse/gstwavparse.c +++ b/gst/wavparse/gstwavparse.c @@ -832,9 +832,8 @@ gst_wavparse_labl_chunk (GstWavParse * wav, const guint8 * data, guint32 size) labl = g_new0 (GstWavParseLabl, 1); /* parse data */ - data += 8; labl->cue_point_id = GST_READ_UINT32_LE (data); - labl->text = g_memdup (data + 4, size - 4); + labl->text = g_strndup ((const gchar *) data + 4, size - 4); wav->labls = g_list_append (wav->labls, labl); @@ -862,9 +861,8 @@ gst_wavparse_note_chunk (GstWavParse * wav, const guint8 * data, guint32 size) note = g_new0 (GstWavParseNote, 1); /* parse data */ - data += 8; note->cue_point_id = GST_READ_UINT32_LE (data); - note->text = g_memdup (data + 4, size - 4); + note->text = g_strndup ((const gchar *) data + 4, size - 4); wav->notes = g_list_append (wav->notes, note); @@ -926,17 +924,17 @@ gst_wavparse_adtl_chunk (GstWavParse * wav, const guint8 * data, guint32 size) ltag = GST_READ_UINT32_LE (data + offset); lsize = GST_READ_UINT32_LE (data + offset + 4); - if (lsize + 8 > size) { + if (lsize > (G_MAXUINT - 8) || lsize + 8 > size) { GST_WARNING_OBJECT (wav, "Invalid adtl size: %u + 8 > %u", lsize, size); return FALSE; } switch (ltag) { case GST_RIFF_TAG_labl: - gst_wavparse_labl_chunk (wav, data + offset, size); + gst_wavparse_labl_chunk (wav, data + offset + 8, lsize); break; case GST_RIFF_TAG_note: - gst_wavparse_note_chunk (wav, data + offset, size); + gst_wavparse_note_chunk (wav, data + offset + 8, lsize); break; default: GST_WARNING_OBJECT (wav, "Unknowm adtl %" GST_FOURCC_FORMAT, diff --git a/meson.build b/meson.build index 28df2fcd2f..c122d0e001 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-plugins-good', 'c', - version : '1.17.0.1', + version : '1.18.6', meson_version : '>= 0.48', default_options : [ 'warning_level=1', 'buildtype=debugoptimized' ]) @@ -16,8 +16,7 @@ else endif gst_version_is_dev = gst_version_minor % 2 == 1 and gst_version_micro < 90 -# FIXME: automagic -have_cxx = add_languages('cpp', required : false) +have_cxx = add_languages('cpp', native: false, required: false) glib_req = '>= 2.44.0' orc_req = '>= 0.4.17' @@ -272,10 +271,14 @@ gstvideo_dep = dependency('gstreamer-video-1.0', version : gst_req, # FIXME: automagic gstgl_dep = dependency('gstreamer-gl-1.0', version : gst_req, fallback : ['gst-plugins-base', 'gstgl_dep'], required: false) +gstglproto_dep = dependency('', required : false) +gstglx11_dep = dependency('', required : false) +gstglwayland_dep = dependency('', required : false) +gstglegl_dep = dependency('', required : false) -build_gstgl = gstgl_dep.found() # FIXME: add option? +have_gstgl = gstgl_dep.found() -if build_gstgl +if have_gstgl if gstgl_dep.type_name() == 'pkgconfig' gst_gl_apis = gstgl_dep.get_pkgconfig_variable('gl_apis').split() gst_gl_winsys = gstgl_dep.get_pkgconfig_variable('gl_winsys').split() @@ -302,6 +305,25 @@ if build_gstgl foreach api : ['gl', 'gles2'] set_variable('gst_gl_have_api_@0@'.format(api), gst_gl_apis.contains(api)) endforeach + + gstglproto_dep = dependency('gstreamer-gl-prototypes-1.0', version : gst_req, + fallback : ['gst-plugins-base', 'gstglproto_dep'], required: true) + # Behind specific checks because meson fails at optional dependencies with a + # fallback to the same subproject. On the first failure, meson will never + # check the system again even if the fallback never existed. + # Last checked with meson 0.54.3 + if gst_gl_have_window_x11 + gstglx11_dep = dependency('gstreamer-gl-x11-1.0', version : gst_req, + fallback : ['gst-plugins-base', 'gstglx11_dep'], required: true) + endif + if gst_gl_have_window_wayland + gstglwayland_dep = dependency('gstreamer-gl-wayland-1.0', version : gst_req, + fallback : ['gst-plugins-base', 'gstglwayland_dep'], required: true) + endif + if gst_gl_have_platform_egl + gstglegl_dep = dependency('gstreamer-gl-egl-1.0', version : gst_req, + fallback : ['gst-plugins-base', 'gstglegl_dep'], required: true) + endif endif zlib_dep = dependency('zlib', required : false) @@ -323,6 +345,7 @@ libsinc = include_directories('gst-libs') have_orcc = false orcc_args = [] +orc_targets = [] # Used by various libraries/elements that use Orc code orc_dep = dependency('orc-0.4', version : orc_req, required : get_option('orc'), fallback : ['orc', 'orc_dep']) @@ -336,6 +359,46 @@ else cdata.set('DISABLE_ORC', 1) endif +have_nasm = false +# FIXME: nasm path needs testing on non-Linux, esp. Windows +host_cpu = host_machine.cpu_family() +if host_cpu == 'x86_64' + if cc.get_define('__ILP32__') == '1' + message('Nasm disabled on x32') + else + asm_option = get_option('asm') + nasm = find_program('nasm', native: true, required: asm_option) + if nasm.found() + # We can't use the version: kwarg for find_program because old versions + # of nasm don't support --version + ret = run_command(nasm, '-v') + if ret.returncode() == 0 + nasm_version = ret.stdout().strip().split()[2] + nasm_req = '>=2.13' + if nasm_version.version_compare(nasm_req) + message('nasm found on x86-64') + cdata.set('HAVE_NASM', 1) + have_nasm = true + else + if asm_option.enabled() + error('asm option is enabled, and nasm @0@ was found, but @1@ is required'.format(nasm_version, nasm_req)) + endif + message('nasm @0@ was found, but @1@ is required'.format(nasm_version, nasm_req)) + endif + else + if asm_option.enabled() + error('asm option is enabled, but nasm is not usable: @0@\n@1@'.format(ret.stdout(), ret.stderr())) + endif + message('nasm was found, but it\'s not usable') + endif + # Unset nasm to not be 'found' + if not have_nasm + nasm = disabler() + endif + endif + endif +endif + # Disable compiler warnings for unused variables and args if gst debug system is disabled if gst_dep.type_name() == 'internal' gst_debug_disabled = not subproject('gstreamer').get_variable('gst_debug') @@ -373,12 +436,66 @@ subdir('ext') subdir('tests') subdir('docs') +if have_orcc and orc_targets.length() > 0 + update_orc_dist_files = find_program('scripts/update-orc-dist-files.py') + + orc_update_targets = [] + foreach t : orc_targets + orc_name = t.get('name') + orc_file = t.get('orc-source') + header = t.get('header') + source = t.get('source') + # alias_target() only works with build targets, so can't use run_target() here + orc_update_targets += [ + custom_target('update-orc-@0@'.format(orc_name), + input: [header, source], + command: [update_orc_dist_files, orc_file, header, source], + output: ['@0@-dist.c'.format(orc_name)]) # not entirely true + ] + endforeach + + if meson.version().version_compare('>= 0.52') + update_orc_dist_target = alias_target('update-orc-dist', orc_update_targets) + endif +endif + # xgettext is optional (on Windows for instance) if find_program('xgettext', required : get_option('nls')).found() cdata.set('ENABLE_NLS', 1) subdir('po') endif +subdir('scripts') + +# Set release date +if gst_version_nano == 0 + extract_release_date = find_program('scripts/extract-release-date-from-doap-file.py') + run_result = run_command(extract_release_date, gst_version, files('gst-plugins-good.doap')) + if run_result.returncode() == 0 + release_date = run_result.stdout().strip() + cdata.set_quoted('GST_PACKAGE_RELEASE_DATETIME', release_date) + message('Package release date: ' + release_date) + else + # Error out if our release can't be found in the .doap file + error(run_result.stderr()) + endif +endif + configure_file(output : 'config.h', configuration : cdata) run_command(python3, '-c', 'import shutil; shutil.copy("hooks/pre-commit.hook", ".git/hooks/pre-commit")') + +if meson.version().version_compare('>= 0.54') + plugin_names = [] + foreach plugin: plugins + # FIXME: Use str.subtring() when we can depend on Meson 0.56 + split = plugin.name().split('gst') + if split.length() == 2 + plugin_names += [split[1]] + else + warning('Need substring API in meson >= 0.56 to properly parse plugin name: ' + plugin.name()) + plugin_names += [plugin.name()] + endif + endforeach + summary({'Plugins':plugin_names}, list_sep: ', ') +endif diff --git a/meson_options.txt b/meson_options.txt index 2153286595..5c96f65425 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -74,6 +74,11 @@ option('vpx', type : 'feature', value : 'auto', description : 'VP8 and VP9 video option('waveform', type : 'feature', value : 'auto', description : 'Windows waveform audio sink plugin') option('wavpack', type : 'feature', value : 'auto', description : 'Wavpack audio codec plugin') +# rpicamsrc plugin options +option('rpicamsrc', type : 'feature', value : 'auto', description : 'Raspberry Pi camera module plugin') +option('rpi-header-dir', type : 'string', value : '/opt/vc/include', description : 'Directory where VideoCore/MMAL headers and bcm_host.h can be found') +option('rpi-lib-dir', type : 'string', value : '/opt/vc/lib', description : 'Directory where VideoCore/MMAL libraries can be found') + # ximagesrc plugin options option('ximagesrc', type : 'feature', value : 'auto', description : 'X11 ximagesrc plugin') option('ximagesrc-xshm', type : 'feature', value : 'auto', description : 'X11 ximagesrc plugin (XSHM support)') @@ -97,6 +102,7 @@ option('glib-asserts', type : 'feature', value : 'enabled', yield : true, description: 'Enable GLib assertion (auto = enabled for development, disabled for stable releases)') option('glib-checks', type : 'feature', value : 'enabled', yield : true, description: 'Enable GLib checks such as API guards (auto = enabled for development, disabled for stable releases)') +option('asm', type : 'feature', value : 'auto', yield : true) # Common options option('package-name', type : 'string', yield : true, diff --git a/po/POTFILES b/po/POTFILES index d99dfde4e2..0b87b3f7e5 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -20,6 +20,7 @@ sys/oss4/oss4-source.c sys/oss/gstosssink.c sys/oss/gstosssrc.c sys/osxaudio/gstosxaudioringbuffer.c +sys/rpicamsrc/gstrpicamsrcdeviceprovider.c sys/v4l2/gstv4l2bufferpool.c sys/v4l2/gstv4l2object.c sys/v4l2/gstv4l2radio.c diff --git a/scripts/dist-translations.py b/scripts/dist-translations.py new file mode 100755 index 0000000000..65148d6ecd --- /dev/null +++ b/scripts/dist-translations.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2020 Tim-Philipp Müller +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. + +import os +import subprocess +import shutil +import tempfile + +if __name__ == "__main__": + dist_root = os.environ['MESON_DIST_ROOT'] + build_root = os.environ['MESON_BUILD_ROOT'] + source_root = os.environ['MESON_SOURCE_ROOT'] + pwd = os.environ['PWD'] + tmpdir = tempfile.gettempdir() + + module = os.path.basename(os.path.normpath(source_root)) + + # Generate pot file + print('Generating pot file ...') + subprocess.run(['ninja', '-C', build_root, module + '-1.0-pot'], check=True) + + # Dist pot file in tarball + print('Copying pot file into dist staging directory ...') + pot_src = os.path.join(source_root, 'po', module + '-1.0.pot') + dist_po_dir = os.path.join(dist_root, 'po') + shutil.copy2(pot_src, dist_po_dir) diff --git a/scripts/extract-release-date-from-doap-file.py b/scripts/extract-release-date-from-doap-file.py new file mode 100755 index 0000000000..f09b60e9d0 --- /dev/null +++ b/scripts/extract-release-date-from-doap-file.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +# +# extract-release-date-from-doap-file.py VERSION DOAP-FILE +# +# Extract release date for the given release version from a DOAP file +# +# Copyright (C) 2020 Tim-Philipp Müller +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. + +import sys +import xml.etree.ElementTree as ET + +if len(sys.argv) != 3: + sys.exit('Usage: {} VERSION DOAP-FILE'.format(sys.argv[0])) + +release_version = sys.argv[1] +doap_fn = sys.argv[2] + +tree = ET.parse(doap_fn) +root = tree.getroot() + +namespaces = {'doap': 'http://usefulinc.com/ns/doap#'} + +for v in root.findall('doap:release/doap:Version', namespaces=namespaces): + if v.findtext('doap:revision', namespaces=namespaces) == release_version: + release_date = v.findtext('doap:created', namespaces=namespaces) + if release_date: + print(release_date) + sys.exit(0) + +sys.exit('Could not find a release with version {} in {}'.format(release_version, doap_fn)) diff --git a/scripts/meson.build b/scripts/meson.build new file mode 100644 index 0000000000..f5d9106271 --- /dev/null +++ b/scripts/meson.build @@ -0,0 +1,4 @@ +# dist scripts +if not meson.is_subproject() + meson.add_dist_script('dist-translations.py') +endif diff --git a/scripts/update-orc-dist-files.py b/scripts/update-orc-dist-files.py new file mode 100755 index 0000000000..592d04e6e7 --- /dev/null +++ b/scripts/update-orc-dist-files.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +# +# update-orc-dist-files.py ORC-FILE GENERATED-HEADER GENERATED-SOURCE +# +# Copies generated orc .c and .h files into source dir as -dist.[ch] backups, +# based on location of passed .orc file. +# +# Copyright (C) 2020 Tim-Philipp Müller +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. + +import shutil +import subprocess +import sys + +assert(len(sys.argv) == 4) + +orc_file = sys.argv[1] +gen_header = sys.argv[2] +gen_source = sys.argv[3] + +# split off .orc suffix +assert(orc_file.endswith('.orc')) +orc_src_base = sys.argv[1][:-4] + +# figure out names of disted backup files +dist_h = orc_src_base + "-dist.h" +dist_c = orc_src_base + "-dist.c" + +# copy generated files from build dir into source dir +shutil.copyfile(gen_header, dist_h) +shutil.copyfile(gen_source, dist_c) + +# run gst-indent on the .c files (twice, because gnu indent) +subprocess.run(['gst-indent', dist_c]) +subprocess.run(['gst-indent', dist_c]) diff --git a/sys/meson.build b/sys/meson.build index c5c8d640eb..d3370152e4 100644 --- a/sys/meson.build +++ b/sys/meson.build @@ -3,6 +3,7 @@ subdir('oss') subdir('oss4') subdir('osxaudio') subdir('osxvideo') +subdir('rpicamsrc') subdir('v4l2') subdir('waveform') subdir('ximage') diff --git a/sys/osxvideo/meson.build b/sys/osxvideo/meson.build index 28ff76724f..4a96fdc282 100644 --- a/sys/osxvideo/meson.build +++ b/sys/osxvideo/meson.build @@ -7,7 +7,7 @@ endif osxvideo_opengl_dep = dependency('appleframeworks', modules : ['OpenGL'], required : get_option('osxvideo')) osxvideo_cocoa_dep = dependency('appleframeworks', modules : ['Cocoa'], required : get_option('osxvideo')) -have_objc = add_languages('objc', required : get_option('osxvideo')) +have_objc = add_languages('objc', native: false, required: get_option('osxvideo')) if have_objc and osxvideo_opengl_dep.found() and osxvideo_cocoa_dep.found() diff --git a/sys/rpicamsrc/RaspiCLI.c b/sys/rpicamsrc/RaspiCLI.c new file mode 100644 index 0000000000..7314248334 --- /dev/null +++ b/sys/rpicamsrc/RaspiCLI.c @@ -0,0 +1,157 @@ +/* *INDENT-OFF* */ +/* +Copyright (c) 2013, Broadcom Europe Ltd +Copyright (c) 2013, James Hughes +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * \file RaspiCLI.c + * Code for handling command line parameters + * + * \date 4th March 2013 + * \Author: James Hughes + * + * Description + * + * Some functions/structures for command line parameter parsing + * + */ +#include +#include +#include +#include + +#include "interface/vcos/vcos.h" + +#include "RaspiCLI.h" + + +/** + * Convert a string from command line to a comand_id from the list + * + * @param commands Array of command to check + * @param num_command Number of commands in the array + * @param arg String to search for in the list + * @param num_parameters Returns the number of parameters used by the command + * + * @return command ID if found, -1 if not found + * + */ +int raspicli_get_command_id(const COMMAND_LIST *commands, const int num_commands, const char *arg, int *num_parameters) +{ + int command_id = -1; + int j; + + vcos_assert(commands); + vcos_assert(num_parameters); + vcos_assert(arg); + + if (!commands || !num_parameters || !arg) + return -1; + + for (j = 0; j < num_commands; j++) + { + if (!strcmp(arg, commands[j].command) || + !strcmp(arg, commands[j].abbrev)) + { + // match + command_id = commands[j].id; + *num_parameters = commands[j].num_parameters; + break; + } + } + + return command_id; +} + + +/** + * Display the list of commands in help format + * + * @param commands Array of command to check + * @param num_command Number of commands in the arry + * + * + */ +void raspicli_display_help(const COMMAND_LIST *commands, const int num_commands) +{ + int i; + + vcos_assert(commands); + + if (!commands) + return; + + for (i = 0; i < num_commands; i++) + { + fprintf(stderr, "-%s, -%s\t: %s\n", commands[i].abbrev, + commands[i].command, commands[i].help); + } +} + + +/** + * Function to take a string, a mapping, and return the int equivalent + * @param str Incoming string to match + * @param map Mapping data + * @param num_refs The number of items in the mapping data + * @return The integer match for the string, or -1 if no match + */ +int raspicli_map_xref(const char *str, const XREF_T *map, int num_refs) +{ + int i; + + for (i=0;i +Portions: +Copyright (c) 2013, Broadcom Europe Ltd +Copyright (c) 2013, James Hughes +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#include + +#include "interface/vcos/vcos.h" + +#include "interface/vmcs_host/vc_vchi_gencmd.h" +#include "interface/mmal/mmal.h" +#include "interface/mmal/mmal_logging.h" +#include "interface/mmal/util/mmal_util.h" +#include "interface/mmal/util/mmal_util_params.h" +#include "interface/mmal/util/mmal_default_components.h" +#include "RaspiCamControl.h" +#include "RaspiCapture.h" + +#if 0 +/// Structure to cross reference exposure strings against the MMAL parameter equivalent +static XREF_T exposure_map[] = +{ + {"auto", MMAL_PARAM_EXPOSUREMODE_AUTO}, + {"night", MMAL_PARAM_EXPOSUREMODE_NIGHT}, + {"nightpreview", MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW}, + {"backlight", MMAL_PARAM_EXPOSUREMODE_BACKLIGHT}, + {"spotlight", MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT}, + {"sports", MMAL_PARAM_EXPOSUREMODE_SPORTS}, + {"snow", MMAL_PARAM_EXPOSUREMODE_SNOW}, + {"beach", MMAL_PARAM_EXPOSUREMODE_BEACH}, + {"verylong", MMAL_PARAM_EXPOSUREMODE_VERYLONG}, + {"fixedfps", MMAL_PARAM_EXPOSUREMODE_FIXEDFPS}, + {"antishake", MMAL_PARAM_EXPOSUREMODE_ANTISHAKE}, + {"fireworks", MMAL_PARAM_EXPOSUREMODE_FIREWORKS} +}; + +static const int exposure_map_size = sizeof(exposure_map) / sizeof(exposure_map[0]); + +/// Structure to cross reference awb strings against the MMAL parameter equivalent +static XREF_T awb_map[] = +{ + {"off", MMAL_PARAM_AWBMODE_OFF}, + {"auto", MMAL_PARAM_AWBMODE_AUTO}, + {"sun", MMAL_PARAM_AWBMODE_SUNLIGHT}, + {"cloud", MMAL_PARAM_AWBMODE_CLOUDY}, + {"shade", MMAL_PARAM_AWBMODE_SHADE}, + {"tungsten", MMAL_PARAM_AWBMODE_TUNGSTEN}, + {"fluorescent", MMAL_PARAM_AWBMODE_FLUORESCENT}, + {"incandescent", MMAL_PARAM_AWBMODE_INCANDESCENT}, + {"flash", MMAL_PARAM_AWBMODE_FLASH}, + {"horizon", MMAL_PARAM_AWBMODE_HORIZON} +}; + +static const int awb_map_size = sizeof(awb_map) / sizeof(awb_map[0]); + +/// Structure to cross reference image effect against the MMAL parameter equivalent +static XREF_T imagefx_map[] = +{ + {"none", MMAL_PARAM_IMAGEFX_NONE}, + {"negative", MMAL_PARAM_IMAGEFX_NEGATIVE}, + {"solarise", MMAL_PARAM_IMAGEFX_SOLARIZE}, + {"sketch", MMAL_PARAM_IMAGEFX_SKETCH}, + {"denoise", MMAL_PARAM_IMAGEFX_DENOISE}, + {"emboss", MMAL_PARAM_IMAGEFX_EMBOSS}, + {"oilpaint", MMAL_PARAM_IMAGEFX_OILPAINT}, + {"hatch", MMAL_PARAM_IMAGEFX_HATCH}, + {"gpen", MMAL_PARAM_IMAGEFX_GPEN}, + {"pastel", MMAL_PARAM_IMAGEFX_PASTEL}, + {"watercolour", MMAL_PARAM_IMAGEFX_WATERCOLOUR}, + {"film", MMAL_PARAM_IMAGEFX_FILM}, + {"blur", MMAL_PARAM_IMAGEFX_BLUR}, + {"saturation", MMAL_PARAM_IMAGEFX_SATURATION}, + {"colourswap", MMAL_PARAM_IMAGEFX_COLOURSWAP}, + {"washedout", MMAL_PARAM_IMAGEFX_WASHEDOUT}, + {"posterise", MMAL_PARAM_IMAGEFX_POSTERISE}, + {"colourpoint", MMAL_PARAM_IMAGEFX_COLOURPOINT}, + {"colourbalance", MMAL_PARAM_IMAGEFX_COLOURBALANCE}, + {"cartoon", MMAL_PARAM_IMAGEFX_CARTOON} + }; + +static const int imagefx_map_size = sizeof(imagefx_map) / sizeof(imagefx_map[0]); + +static XREF_T metering_mode_map[] = +{ + {"average", MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE}, + {"spot", MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT}, + {"backlit", MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT}, + {"matrix", MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX} +}; + +static const int metering_mode_map_size = sizeof(metering_mode_map)/sizeof(metering_mode_map[0]); + +static XREF_T drc_mode_map[] = +{ + {"off", MMAL_PARAMETER_DRC_STRENGTH_OFF}, + {"low", MMAL_PARAMETER_DRC_STRENGTH_LOW}, + {"med", MMAL_PARAMETER_DRC_STRENGTH_MEDIUM}, + {"high", MMAL_PARAMETER_DRC_STRENGTH_HIGH} +}; + +static const int drc_mode_map_size = sizeof(drc_mode_map)/sizeof(drc_mode_map[0]); + +static XREF_T stereo_mode_map[] = +{ + {"off", MMAL_STEREOSCOPIC_MODE_NONE}, + {"sbs", MMAL_STEREOSCOPIC_MODE_SIDE_BY_SIDE}, + {"tb", MMAL_STEREOSCOPIC_MODE_TOP_BOTTOM}, +}; + +static const int stereo_mode_map_size = sizeof(stereo_mode_map)/sizeof(stereo_mode_map[0]); + + +#define CommandSharpness 0 +#define CommandContrast 1 +#define CommandBrightness 2 +#define CommandSaturation 3 +#define CommandISO 4 +#define CommandVideoStab 5 +#define CommandEVComp 6 +#define CommandExposure 7 +#define CommandAWB 8 +#define CommandImageFX 9 +#define CommandColourFX 10 +#define CommandMeterMode 11 +#define CommandRotation 12 +#define CommandHFlip 13 +#define CommandVFlip 14 +#define CommandROI 15 +#define CommandShutterSpeed 16 +#define CommandAwbGains 17 +#define CommandDRCLevel 18 +#define CommandStatsPass 19 +#define CommandAnnotate 20 +#define CommandStereoMode 21 +#define CommandStereoDecimate 22 +#define CommandStereoSwap 23 +#define CommandAnnotateExtras 24 + +static COMMAND_LIST cmdline_commands[] = +{ + {CommandSharpness, "-sharpness", "sh", "Set image sharpness (-100 to 100)", 1}, + {CommandContrast, "-contrast", "co", "Set image contrast (-100 to 100)", 1}, + {CommandBrightness, "-brightness","br", "Set image brightness (0 to 100)", 1}, + {CommandSaturation, "-saturation","sa", "Set image saturation (-100 to 100)", 1}, + {CommandISO, "-ISO", "ISO","Set capture ISO", 1}, + {CommandVideoStab, "-vstab", "vs", "Turn on video stabilisation", 0}, + {CommandEVComp, "-ev", "ev", "Set EV compensation", 1}, + {CommandExposure, "-exposure", "ex", "Set exposure mode (see Notes)", 1}, + {CommandAWB, "-awb", "awb","Set AWB mode (see Notes)", 1}, + {CommandImageFX, "-imxfx", "ifx","Set image effect (see Notes)", 1}, + {CommandColourFX, "-colfx", "cfx","Set colour effect (U:V)", 1}, + {CommandMeterMode, "-metering", "mm", "Set metering mode (see Notes)", 1}, + {CommandRotation, "-rotation", "rot","Set image rotation (0-359)", 1}, + {CommandHFlip, "-hflip", "hf", "Set horizontal flip", 0}, + {CommandVFlip, "-vflip", "vf", "Set vertical flip", 0}, + {CommandROI, "-roi", "roi","Set region of interest (x,y,w,d as normalised coordinates [0.0-1.0])", 1}, + {CommandShutterSpeed,"-shutter", "ss", "Set shutter speed in microseconds", 1}, + {CommandAwbGains, "-awbgains", "awbg", "Set AWB gains - AWB mode must be off", 1}, + {CommandDRCLevel, "-drc", "drc", "Set DRC Level", 1}, + {CommandStatsPass, "-stats", "st", "Force recomputation of statistics on stills capture pass"}, + {CommandAnnotate, "-annotate", "a", "Enable/Set annotate flags or text", 1}, + {CommandStereoMode, "-stereo", "3d", "Select stereoscopic mode", 1}, + {CommandStereoDecimate,"-decimate","dec", "Half width/height of stereo image"}, + {CommandStereoSwap, "-3dswap", "3dswap", "Swap camera order for stereoscopic"}, + {CommandAnnotateExtras,"-annotateex","ae", "Set extra annotation parameters (text size, text colour(hex YUV), bg colour(hex YUV))", 2}, +}; + +static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]); + +static const int exposure_map_size = 1; +static const int awb_map_size = 1; +static const int metering_mode_map_size = 1; + +#define parameter_reset -99999 + +/** + * Update the passed in parameter according to the rest of the parameters + * passed in. + * + * + * @return 0 if reached end of cycle for this parameter, !0 otherwise + */ +static int update_cycle_parameter(int *option, int min, int max, int increment) +{ + vcos_assert(option); + if (!option) + return 0; + + if (*option == parameter_reset) + *option = min - increment; + + *option += increment; + + if (*option > max) + { + *option = parameter_reset; + return 0; + } + else + return 1; +} +#endif + + +/** + * Test/Demo code to cycle through a bunch of camera settings + * This code is pretty hacky so please don't complain!! + * It only does stuff that should have a visual impact (hence demo!) + * This will override any user supplied parameters + * + * Each call of this function will move on to the next setting + * + * @param camera Pointer to the camera to change settings on. + * @return 0 if reached end of complete sequence, !0 otherwise + */ + +int raspicamcontrol_cycle_test(MMAL_COMPONENT_T *camera) +{ + return 1; +} +#if 0 + static int parameter = 0; + static int parameter_option = parameter_reset; // which value the parameter currently has + + vcos_assert(camera); + + // We are going to cycle through all the relevant entries in the parameter block + // and send options to the camera. + if (parameter == 0) + { + // sharpness + if (update_cycle_parameter(¶meter_option, -100, 100, 10)) + raspicamcontrol_set_sharpness(camera, parameter_option); + else + { + raspicamcontrol_set_sharpness(camera, 0); + parameter++; + } + } + else + if (parameter == 1) + { + // contrast + if (update_cycle_parameter(¶meter_option, -100, 100, 10)) + raspicamcontrol_set_contrast(camera, parameter_option); + else + { + raspicamcontrol_set_contrast(camera, 0); + parameter++; + } + } + else + if (parameter == 2) + { + // brightness + if (update_cycle_parameter(¶meter_option, 0, 100, 10)) + raspicamcontrol_set_brightness(camera, parameter_option); + else + { + raspicamcontrol_set_brightness(camera, 50); + parameter++; + } + } + else + if (parameter == 3) + { + // contrast + if (update_cycle_parameter(¶meter_option, -100, 100, 10)) + raspicamcontrol_set_saturation(camera, parameter_option); + else + { + parameter++; + raspicamcontrol_set_saturation(camera, 0); + } + } + else + if (parameter == 4) + { + // EV + if (update_cycle_parameter(¶meter_option, -10, 10, 4)) + raspicamcontrol_set_exposure_compensation(camera, parameter_option); + else + { + raspicamcontrol_set_exposure_compensation(camera, 0); + parameter++; + } + } + else + if (parameter == 5) + { + // MMAL_PARAM_EXPOSUREMODE_T + if (update_cycle_parameter(¶meter_option, 0, exposure_map_size, 1)) + raspicamcontrol_set_exposure_mode(camera, exposure_map[parameter_option].mmal_mode); + else + { + raspicamcontrol_set_exposure_mode(camera, MMAL_PARAM_EXPOSUREMODE_AUTO); + parameter++; + } + } + else + if (parameter == 6) + { + // MMAL_PARAM_AWB_T + if (update_cycle_parameter(¶meter_option, 0, awb_map_size, 1)) + raspicamcontrol_set_awb_mode(camera, awb_map[parameter_option].mmal_mode); + else + { + raspicamcontrol_set_awb_mode(camera, MMAL_PARAM_AWBMODE_AUTO); + parameter++; + } + } + if (parameter == 7) + { + // MMAL_PARAM_IMAGEFX_T + if (update_cycle_parameter(¶meter_option, 0, imagefx_map_size, 1)) + raspicamcontrol_set_imageFX(camera, imagefx_map[parameter_option].mmal_mode); + else + { + raspicamcontrol_set_imageFX(camera, MMAL_PARAM_IMAGEFX_NONE); + parameter++; + } + } + if (parameter == 8) + { + MMAL_PARAM_COLOURFX_T colfx = {0,0,0}; + switch (parameter_option) + { + case parameter_reset : + parameter_option = 1; + colfx.u = 128; + colfx.v = 128; + break; + case 1 : + parameter_option = 2; + colfx.u = 100; + colfx.v = 200; + break; + case 2 : + parameter_option = parameter_reset; + colfx.enable = 0; + parameter++; + break; + } + raspicamcontrol_set_colourFX(camera, &colfx); + } + + // Orientation + if (parameter == 9) + { + switch (parameter_option) + { + case parameter_reset: + raspicamcontrol_set_rotation(camera, 90); + parameter_option = 1; + break; + + case 1 : + raspicamcontrol_set_rotation(camera, 180); + parameter_option = 2; + break; + + case 2 : + raspicamcontrol_set_rotation(camera, 270); + parameter_option = 3; + break; + + case 3 : + { + raspicamcontrol_set_rotation(camera, 0); + raspicamcontrol_set_flips(camera, 1,0); + parameter_option = 4; + break; + } + case 4 : + { + raspicamcontrol_set_flips(camera, 0,1); + parameter_option = 5; + break; + } + case 5 : + { + raspicamcontrol_set_flips(camera, 1, 1); + parameter_option = 6; + break; + } + case 6 : + { + raspicamcontrol_set_flips(camera, 0, 0); + parameter_option = parameter_reset; + parameter++; + break; + } + } + } + + if (parameter == 10) + { + parameter = 1; + return 0; + } + + return 1; +} +#endif + + +#if 0 +/** + * Parse a possible command pair - command and parameter + * @param arg1 Command + * @param arg2 Parameter (could be NULL) + * @return How many parameters were used, 0,1,2 + */ +int raspicamcontrol_parse_cmdline(RASPICAM_CAMERA_PARAMETERS *params, const char *arg1, const char *arg2) +{ + int command_id, used = 0, num_parameters; + + if (!arg1) + return 0; + + command_id = raspicli_get_command_id(cmdline_commands, cmdline_commands_size, arg1, &num_parameters); + + // If invalid command, or we are missing a parameter, drop out + if (command_id==-1 || (command_id != -1 && num_parameters > 0 && arg2 == NULL)) + return 0; + + switch (command_id) + { + case CommandSharpness : // sharpness - needs single number parameter + sscanf(arg2, "%d", ¶ms->sharpness); + used = 2; + break; + + case CommandContrast : // contrast - needs single number parameter + sscanf(arg2, "%d", ¶ms->contrast); + used = 2; + break; + + case CommandBrightness : // brightness - needs single number parameter + sscanf(arg2, "%d", ¶ms->brightness); + used = 2; + break; + + case CommandSaturation : // saturation - needs single number parameter + sscanf(arg2, "%d", ¶ms->saturation); + used = 2; + break; + + case CommandISO : // ISO - needs single number parameter + sscanf(arg2, "%d", ¶ms->ISO); + used = 2; + break; + + case CommandVideoStab : // video stabilisation - if here, its on + params->videoStabilisation = 1; + used = 1; + break; + + case CommandEVComp : // EV - needs single number parameter + sscanf(arg2, "%d", ¶ms->exposureCompensation); + used = 2; + break; + + case CommandExposure : // exposure mode - needs string + params->exposureMode = exposure_mode_from_string(arg2); + used = 2; + break; + + case CommandAWB : // AWB mode - needs single number parameter + params->awbMode = awb_mode_from_string(arg2); + used = 2; + break; + + case CommandImageFX : // Image FX - needs string + params->imageEffect = imagefx_mode_from_string(arg2); + used = 2; + break; + + case CommandColourFX : // Colour FX - needs string "u:v" + sscanf(arg2, "%d:%d", ¶ms->colourEffects.u, ¶ms->colourEffects.u); + params->colourEffects.enable = 1; + used = 2; + break; + + case CommandMeterMode: + params->exposureMeterMode = metering_mode_from_string(arg2); + used = 2; + break; + + case CommandRotation : // Rotation - degree + sscanf(arg2, "%d", ¶ms->rotation); + used = 2; + break; + + case CommandHFlip : + params->hflip = 1; + used = 1; + break; + + case CommandVFlip : + params->vflip = 1; + used = 1; + break; + + case CommandROI : + { + double x,y,w,h; + int args; + + args = sscanf(arg2, "%lf,%lf,%lf,%lf", &x,&y,&w,&h); + + if (args != 4 || x > 1.0 || y > 1.0 || w > 1.0 || h > 1.0) + { + return 0; + } + + // Make sure we stay within bounds + if (x + w > 1.0) + w = 1 - x; + + if (y + h > 1.0) + h = 1 - y; + + params->roi.x = x; + params->roi.y = y; + params->roi.w = w; + params->roi.h = h; + + used = 2; + break; + } + + case CommandShutterSpeed : // Shutter speed needs single number parameter + { + sscanf(arg2, "%d", ¶ms->shutter_speed); + used = 2; + break; + } + + case CommandAwbGains : + { + double r,b; + int args; + + args = sscanf(arg2, "%lf,%lf", &r,&b); + + if (args != 2 || r > 8.0 || b > 8.0) + { + return 0; + } + + params->awb_gains_r = r; + params->awb_gains_b = b; + + used = 2; + break; + } + + case CommandDRCLevel: + { + params->drc_level = drc_mode_from_string(arg2); + used = 2; + break; + } + + case CommandStatsPass: + { + params->stats_pass = MMAL_TRUE; + used = 1; + break; + } + + case CommandAnnotate: + { + // If parameter is a number, assume its a bitmask, otherwise a string + if (isdigit(*arg2)) + { + sscanf(arg2, "%u", ¶ms->enable_annotate); + } + else + { + params->enable_annotate = ANNOTATE_USER_TEXT; + //copy string char by char and replace "\n" with newline character + unsigned char c; + char const *s = arg2; + char *t = ¶ms->annotate_string[0]; + int n=0; + while ((c = *s++) && n < MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3-1) + { + if (c == '\\' && *s) + { + switch (c = *s++) + { + case 'n': + c = '\n'; + break; + + default: + c = '\\'; + s--; + break; + } + } + *(t++) = c; + n++; + } + *t='\0'; + + //params->annotate_string[MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3-1] = '\0'; + } + used=2; + break; + } + + case CommandAnnotateExtras: + { + // 3 parameters - text size (6-80), text colour (Hex VVUUYY) and background colour (Hex VVUUYY) + sscanf(arg2, "%u,%X,%X", ¶ms->annotate_text_size, + ¶ms->annotate_text_colour, + ¶ms->annotate_bg_colour); + used=2; + break; + } + + case CommandStereoMode: + { + params->stereo_mode.mode = stereo_mode_from_string(arg2); + used = 2; + break; + } + + case CommandStereoDecimate: + { + params->stereo_mode.decimate = MMAL_TRUE; + used = 1; + break; + } + + case CommandStereoSwap: + { + params->stereo_mode.swap_eyes = MMAL_TRUE; + used = 1; + break; + } + + } + + return used; +} + +/** + * Display help for command line options + */ +void raspicamcontrol_display_help() +{ + int i; + + fprintf(stderr, "\nImage parameter commands\n\n"); + + raspicli_display_help(cmdline_commands, cmdline_commands_size); + + fprintf(stderr, "\n\nNotes\n\nExposure mode options :\n%s", exposure_map[0].mode ); + + for (i=1;iexposureMode, exposure_map, exposure_map_size); + //const char *awb_mode = raspicli_unmap_xref(params->awbMode, awb_map, awb_map_size); + //const char *image_effect = raspicli_unmap_xref(params->imageEffect, imagefx_map, imagefx_map_size); + //const char *metering_mode = raspicli_unmap_xref(params->exposureMeterMode, metering_mode_map, metering_mode_map_size); + + fprintf(stderr, "Sharpness %d, Contrast %d, Brightness %d\n", params->sharpness, params->contrast, params->brightness); + fprintf(stderr, "Saturation %d, ISO %d, Video Stabilisation %s, Exposure compensation %d\n", params->saturation, params->ISO, params->videoStabilisation ? "Yes": "No", params->exposureCompensation); + //fprintf(stderr, "Exposure Mode '%s', AWB Mode '%s', Image Effect '%s'\n", exp_mode, awb_mode, image_effect); + fprintf(stderr, "Exposure Mode '%d', AWB Mode '%d', Image Effect '%d'\n", params->exposureMode, params->awbMode, params->imageEffect); + //fprintf(stderr, "Metering Mode '%s', Colour Effect Enabled %s with U = %d, V = %d\n", metering_mode, params->colourEffects.enable ? "Yes":"No", params->colourEffects.u, params->colourEffects.v); + fprintf(stderr, "Rotation %d, hflip %s, vflip %s\n", params->rotation, params->hflip ? "Yes":"No",params->vflip ? "Yes":"No"); + fprintf(stderr, "ROI x %lf, y %f, w %f h %f\n", params->roi.x, params->roi.y, params->roi.w, params->roi.h); +} + +/** + * Convert a MMAL status return value to a simple boolean of success + * ALso displays a fault if code is not success + * + * @param status The error code to convert + * @return 0 if status is sucess, 1 otherwise + */ +int mmal_status_to_int(MMAL_STATUS_T status) +{ + if (status == MMAL_SUCCESS) + return 0; + else + { + switch (status) + { + case MMAL_ENOMEM : vcos_log_error("Out of memory"); break; + case MMAL_ENOSPC : vcos_log_error("Out of resources (other than memory)"); break; + case MMAL_EINVAL: vcos_log_error("Argument is invalid"); break; + case MMAL_ENOSYS : vcos_log_error("Function not implemented"); break; + case MMAL_ENOENT : vcos_log_error("No such file or directory"); break; + case MMAL_ENXIO : vcos_log_error("No such device or address"); break; + case MMAL_EIO : vcos_log_error("I/O error"); break; + case MMAL_ESPIPE : vcos_log_error("Illegal seek"); break; + case MMAL_ECORRUPT : vcos_log_error("Data is corrupt \attention FIXME: not POSIX"); break; + case MMAL_ENOTREADY :vcos_log_error("Component is not ready \attention FIXME: not POSIX"); break; + case MMAL_ECONFIG : vcos_log_error("Component is not configured \attention FIXME: not POSIX"); break; + case MMAL_EISCONN : vcos_log_error("Port is already connected "); break; + case MMAL_ENOTCONN : vcos_log_error("Port is disconnected"); break; + case MMAL_EAGAIN : vcos_log_error("Resource temporarily unavailable. Try again later"); break; + case MMAL_EFAULT : vcos_log_error("Bad address"); break; + default : vcos_log_error("Unknown status error"); break; + } + + return 1; + } +} + +/** + * Give the supplied parameter block a set of default values + * @params Pointer to parameter block + */ +void raspicamcontrol_set_defaults(RASPICAM_CAMERA_PARAMETERS *params) +{ + vcos_assert(params); + + params->sharpness = 0; + params->contrast = 0; + params->brightness = 50; + params->saturation = 0; + params->ISO = 0; // 0 = auto + params->videoStabilisation = 0; + params->exposureCompensation = 0; + params->exposureMode = MMAL_PARAM_EXPOSUREMODE_AUTO; + params->exposureMeterMode = MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE; + params->awbMode = MMAL_PARAM_AWBMODE_AUTO; + params->imageEffect = MMAL_PARAM_IMAGEFX_NONE; + params->colourEffects.enable = 0; + params->colourEffects.u = 128; + params->colourEffects.v = 128; + params->rotation = 0; + params->hflip = params->vflip = 0; + params->roi.x = params->roi.y = 0.0; + params->roi.w = params->roi.h = 1.0; + params->shutter_speed = 0; // 0 = auto + params->awb_gains_r = 0; // Only have any function if AWB OFF is used. + params->awb_gains_b = 0; + params->drc_level = MMAL_PARAMETER_DRC_STRENGTH_OFF; + params->stats_pass = MMAL_FALSE; + params->enable_annotate = 0; + params->annotate_string[0] = '\0'; + params->annotate_text_size = 0; //Use firmware default + params->annotate_text_colour = -1; //Use firmware default + params->annotate_bg_colour = -1; //Use firmware default + params->stereo_mode.mode = MMAL_STEREOSCOPIC_MODE_NONE; + params->stereo_mode.decimate = MMAL_FALSE; + params->stereo_mode.swap_eyes = MMAL_FALSE; +} + +/** + * Get all the current camera parameters from specified camera component + * @param camera Pointer to camera component + * @param params Pointer to parameter block to accept settings + * @return 0 if successful, non-zero if unsuccessful + */ +int raspicamcontrol_get_all_parameters(MMAL_COMPONENT_T *camera, RASPICAM_CAMERA_PARAMETERS *params) +{ + vcos_assert(camera); + vcos_assert(params); + + if (!camera || !params) + return 1; + +/* TODO : Write these get functions + params->sharpness = raspicamcontrol_get_sharpness(camera); + params->contrast = raspicamcontrol_get_contrast(camera); + params->brightness = raspicamcontrol_get_brightness(camera); + params->saturation = raspicamcontrol_get_saturation(camera); + params->ISO = raspicamcontrol_get_ISO(camera); + params->videoStabilisation = raspicamcontrol_get_video_stabilisation(camera); + params->exposureCompensation = raspicamcontrol_get_exposure_compensation(camera); + params->exposureMode = raspicamcontrol_get_exposure_mode(camera); + params->awbMode = raspicamcontrol_get_awb_mode(camera); + params->imageEffect = raspicamcontrol_get_image_effect(camera); + params->colourEffects = raspicamcontrol_get_colour_effect(camera); + params->thumbnailConfig = raspicamcontrol_get_thumbnail_config(camera); +*/ + return 0; +} + +/** + * Set the specified camera to all the specified settings + * @param camera Pointer to camera component + * @param params Pointer to parameter block containing parameters + * @return 0 if successful, none-zero if unsuccessful. + */ +int raspicamcontrol_set_all_parameters(MMAL_COMPONENT_T *camera, const RASPICAM_CAMERA_PARAMETERS *params) +{ + int result; + + result = raspicamcontrol_set_saturation(camera, params->saturation); + result += raspicamcontrol_set_sharpness(camera, params->sharpness); + result += raspicamcontrol_set_contrast(camera, params->contrast); + result += raspicamcontrol_set_brightness(camera, params->brightness); + result += raspicamcontrol_set_ISO(camera, params->ISO); + result += raspicamcontrol_set_video_stabilisation(camera, params->videoStabilisation); + result += raspicamcontrol_set_exposure_compensation(camera, params->exposureCompensation); + result += raspicamcontrol_set_exposure_mode(camera, params->exposureMode); + result += raspicamcontrol_set_metering_mode(camera, params->exposureMeterMode); + result += raspicamcontrol_set_awb_mode(camera, params->awbMode); + result += raspicamcontrol_set_awb_gains(camera, params->awb_gains_r, params->awb_gains_b); + result += raspicamcontrol_set_imageFX(camera, params->imageEffect); + result += raspicamcontrol_set_colourFX(camera, ¶ms->colourEffects); + //result += raspicamcontrol_set_thumbnail_parameters(camera, ¶ms->thumbnailConfig); TODO Not working for some reason + result += raspicamcontrol_set_rotation(camera, params->rotation); + result += raspicamcontrol_set_flips(camera, params->hflip, params->vflip); + result += raspicamcontrol_set_ROI(camera, params->roi); + result += raspicamcontrol_set_shutter_speed(camera, params->shutter_speed); + result += raspicamcontrol_set_DRC(camera, params->drc_level); + result += raspicamcontrol_set_stats_pass(camera, params->stats_pass); + result += raspicamcontrol_set_annotate(camera, params->enable_annotate, params->annotate_string, + params->annotate_text_size, + params->annotate_text_colour, + params->annotate_bg_colour); + + return result; +} + +/** + * Adjust the saturation level for images + * @param camera Pointer to camera component + * @param saturation Value to adjust, -100 to 100 + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_saturation(MMAL_COMPONENT_T *camera, int saturation) +{ + int ret = 0; + + if (!camera) + return 1; + + if (saturation >= -100 && saturation <= 100) + { + MMAL_RATIONAL_T value = {saturation, 100}; + ret = mmal_status_to_int(mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_SATURATION, value)); + } + else + { + vcos_log_error("Invalid saturation value"); + ret = 1; + } + + return ret; +} + +/** + * Set the sharpness of the image + * @param camera Pointer to camera component + * @param sharpness Sharpness adjustment -100 to 100 + */ +int raspicamcontrol_set_sharpness(MMAL_COMPONENT_T *camera, int sharpness) +{ + int ret = 0; + + if (!camera) + return 1; + + if (sharpness >= -100 && sharpness <= 100) + { + MMAL_RATIONAL_T value = {sharpness, 100}; + ret = mmal_status_to_int(mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_SHARPNESS, value)); + } + else + { + vcos_log_error("Invalid sharpness value"); + ret = 1; + } + + return ret; +} + +/** + * Set the contrast adjustment for the image + * @param camera Pointer to camera component + * @param contrast Contrast adjustment -100 to 100 + * @return + */ +int raspicamcontrol_set_contrast(MMAL_COMPONENT_T *camera, int contrast) +{ + int ret = 0; + + if (!camera) + return 1; + + if (contrast >= -100 && contrast <= 100) + { + MMAL_RATIONAL_T value = {contrast, 100}; + ret = mmal_status_to_int(mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_CONTRAST, value)); + } + else + { + vcos_log_error("Invalid contrast value"); + ret = 1; + } + + return ret; +} + +/** + * Adjust the brightness level for images + * @param camera Pointer to camera component + * @param brightness Value to adjust, 0 to 100 + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_brightness(MMAL_COMPONENT_T *camera, int brightness) +{ + int ret = 0; + + if (!camera) + return 1; + + if (brightness >= 0 && brightness <= 100) + { + MMAL_RATIONAL_T value = {brightness, 100}; + ret = mmal_status_to_int(mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_BRIGHTNESS, value)); + } + else + { + vcos_log_error("Invalid brightness value"); + ret = 1; + } + + return ret; +} + +/** + * Adjust the ISO used for images + * @param camera Pointer to camera component + * @param ISO Value to set TODO : + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_ISO(MMAL_COMPONENT_T *camera, int ISO) +{ + if (!camera) + return 1; + + return mmal_status_to_int(mmal_port_parameter_set_uint32(camera->control, MMAL_PARAMETER_ISO, ISO)); +} + +/** + * Adjust the metering mode for images + * @param camera Pointer to camera component + * @param saturation Value from following + * - MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE, + * - MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT, + * - MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT, + * - MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_metering_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_EXPOSUREMETERINGMODE_T m_mode ) +{ + MMAL_PARAMETER_EXPOSUREMETERINGMODE_T meter_mode = {{MMAL_PARAMETER_EXP_METERING_MODE,sizeof(meter_mode)}, + m_mode}; + if (!camera) + return 1; + + return mmal_status_to_int(mmal_port_parameter_set(camera->control, &meter_mode.hdr)); +} + + +/** + * Set the video stabilisation flag. Only used in video mode + * @param camera Pointer to camera component + * @param saturation Flag 0 off 1 on + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_video_stabilisation(MMAL_COMPONENT_T *camera, int vstabilisation) +{ + if (!camera) + return 1; + + return mmal_status_to_int(mmal_port_parameter_set_boolean(camera->control, MMAL_PARAMETER_VIDEO_STABILISATION, vstabilisation)); +} + +/** + * Adjust the exposure compensation for images (EV) + * @param camera Pointer to camera component + * @param exp_comp Value to adjust, -10 to +10 + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_exposure_compensation(MMAL_COMPONENT_T *camera, int exp_comp) +{ + if (!camera) + return 1; + + return mmal_status_to_int(mmal_port_parameter_set_int32(camera->control, MMAL_PARAMETER_EXPOSURE_COMP , exp_comp)); +} + + +/** + * Set exposure mode for images + * @param camera Pointer to camera component + * @param mode Exposure mode to set from + * - MMAL_PARAM_EXPOSUREMODE_OFF, + * - MMAL_PARAM_EXPOSUREMODE_AUTO, + * - MMAL_PARAM_EXPOSUREMODE_NIGHT, + * - MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW, + * - MMAL_PARAM_EXPOSUREMODE_BACKLIGHT, + * - MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT, + * - MMAL_PARAM_EXPOSUREMODE_SPORTS, + * - MMAL_PARAM_EXPOSUREMODE_SNOW, + * - MMAL_PARAM_EXPOSUREMODE_BEACH, + * - MMAL_PARAM_EXPOSUREMODE_VERYLONG, + * - MMAL_PARAM_EXPOSUREMODE_FIXEDFPS, + * - MMAL_PARAM_EXPOSUREMODE_ANTISHAKE, + * - MMAL_PARAM_EXPOSUREMODE_FIREWORKS, + * + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_exposure_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_EXPOSUREMODE_T mode) +{ + MMAL_PARAMETER_EXPOSUREMODE_T exp_mode = {{MMAL_PARAMETER_EXPOSURE_MODE,sizeof(exp_mode)}, mode}; + + if (!camera) + return 1; + + return mmal_status_to_int(mmal_port_parameter_set(camera->control, &exp_mode.hdr)); +} + + +/** + * Set the aWB (auto white balance) mode for images + * @param camera Pointer to camera component + * @param awb_mode Value to set from + * - MMAL_PARAM_AWBMODE_OFF, + * - MMAL_PARAM_AWBMODE_AUTO, + * - MMAL_PARAM_AWBMODE_SUNLIGHT, + * - MMAL_PARAM_AWBMODE_CLOUDY, + * - MMAL_PARAM_AWBMODE_SHADE, + * - MMAL_PARAM_AWBMODE_TUNGSTEN, + * - MMAL_PARAM_AWBMODE_FLUORESCENT, + * - MMAL_PARAM_AWBMODE_INCANDESCENT, + * - MMAL_PARAM_AWBMODE_FLASH, + * - MMAL_PARAM_AWBMODE_HORIZON, + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_awb_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_AWBMODE_T awb_mode) +{ + MMAL_PARAMETER_AWBMODE_T param = {{MMAL_PARAMETER_AWB_MODE,sizeof(param)}, awb_mode}; + + if (!camera) + return 1; + + return mmal_status_to_int(mmal_port_parameter_set(camera->control, ¶m.hdr)); +} + +int raspicamcontrol_set_awb_gains(MMAL_COMPONENT_T *camera, float r_gain, float b_gain) +{ + MMAL_PARAMETER_AWB_GAINS_T param = {{MMAL_PARAMETER_CUSTOM_AWB_GAINS,sizeof(param)}, {0,0}, {0,0}}; + + if (!camera) + return 1; + + if (!r_gain || !b_gain) + return 0; + + param.r_gain.num = (unsigned int)(r_gain * 65536); + param.b_gain.num = (unsigned int)(b_gain * 65536); + param.r_gain.den = param.b_gain.den = 65536; + return mmal_status_to_int(mmal_port_parameter_set(camera->control, ¶m.hdr)); +} + +/** + * Set the image effect for the images + * @param camera Pointer to camera component + * @param imageFX Value from + * - MMAL_PARAM_IMAGEFX_NONE, + * - MMAL_PARAM_IMAGEFX_NEGATIVE, + * - MMAL_PARAM_IMAGEFX_SOLARIZE, + * - MMAL_PARAM_IMAGEFX_POSTERIZE, + * - MMAL_PARAM_IMAGEFX_WHITEBOARD, + * - MMAL_PARAM_IMAGEFX_BLACKBOARD, + * - MMAL_PARAM_IMAGEFX_SKETCH, + * - MMAL_PARAM_IMAGEFX_DENOISE, + * - MMAL_PARAM_IMAGEFX_EMBOSS, + * - MMAL_PARAM_IMAGEFX_OILPAINT, + * - MMAL_PARAM_IMAGEFX_HATCH, + * - MMAL_PARAM_IMAGEFX_GPEN, + * - MMAL_PARAM_IMAGEFX_PASTEL, + * - MMAL_PARAM_IMAGEFX_WATERCOLOUR, + * - MMAL_PARAM_IMAGEFX_FILM, + * - MMAL_PARAM_IMAGEFX_BLUR, + * - MMAL_PARAM_IMAGEFX_SATURATION, + * - MMAL_PARAM_IMAGEFX_COLOURSWAP, + * - MMAL_PARAM_IMAGEFX_WASHEDOUT, + * - MMAL_PARAM_IMAGEFX_POSTERISE, + * - MMAL_PARAM_IMAGEFX_COLOURPOINT, + * - MMAL_PARAM_IMAGEFX_COLOURBALANCE, + * - MMAL_PARAM_IMAGEFX_CARTOON, + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_imageFX(MMAL_COMPONENT_T *camera, MMAL_PARAM_IMAGEFX_T imageFX) +{ + MMAL_PARAMETER_IMAGEFX_T imgFX = {{MMAL_PARAMETER_IMAGE_EFFECT,sizeof(imgFX)}, imageFX}; + + if (!camera) + return 1; + + return mmal_status_to_int(mmal_port_parameter_set(camera->control, &imgFX.hdr)); +} + +/* TODO :what to do with the image effects parameters? + MMAL_PARAMETER_IMAGEFX_PARAMETERS_T imfx_param = {{MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,sizeof(imfx_param)}, + imageFX, 0, {0}}; +mmal_port_parameter_set(camera->control, &imfx_param.hdr); + */ + +/** + * Set the colour effect for images (Set UV component) + * @param camera Pointer to camera component + * @param colourFX Contains enable state and U and V numbers to set (e.g. 128,128 = Black and white) + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_colourFX(MMAL_COMPONENT_T *camera, const MMAL_PARAM_COLOURFX_T *colourFX) +{ + MMAL_PARAMETER_COLOURFX_T colfx = {{MMAL_PARAMETER_COLOUR_EFFECT,sizeof(colfx)}, 0, 0, 0}; + + if (!camera) + return 1; + + colfx.enable = colourFX->enable; + colfx.u = colourFX->u; + colfx.v = colourFX->v; + + return mmal_status_to_int(mmal_port_parameter_set(camera->control, &colfx.hdr)); + +} + + +/** + * Set the rotation of the image + * @param camera Pointer to camera component + * @param rotation Degree of rotation (any number, but will be converted to 0,90,180 or 270 only) + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_rotation(MMAL_COMPONENT_T *camera, int rotation) +{ + int ret; + int my_rotation = ((rotation % 360 ) / 90) * 90; + + ret = mmal_port_parameter_set_int32(camera->output[0], MMAL_PARAMETER_ROTATION, my_rotation); + mmal_port_parameter_set_int32(camera->output[1], MMAL_PARAMETER_ROTATION, my_rotation); + mmal_port_parameter_set_int32(camera->output[2], MMAL_PARAMETER_ROTATION, my_rotation); + + return ret; +} + +/** + * Set the flips state of the image + * @param camera Pointer to camera component + * @param hflip If true, horizontally flip the image + * @param vflip If true, vertically flip the image + * + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_flips(MMAL_COMPONENT_T *camera, int hflip, int vflip) +{ + MMAL_PARAMETER_MIRROR_T mirror = {{MMAL_PARAMETER_MIRROR, sizeof(MMAL_PARAMETER_MIRROR_T)}, MMAL_PARAM_MIRROR_NONE}; + + if (hflip && vflip) + mirror.value = MMAL_PARAM_MIRROR_BOTH; + else + if (hflip) + mirror.value = MMAL_PARAM_MIRROR_HORIZONTAL; + else + if (vflip) + mirror.value = MMAL_PARAM_MIRROR_VERTICAL; + + mmal_port_parameter_set(camera->output[0], &mirror.hdr); + mmal_port_parameter_set(camera->output[1], &mirror.hdr); + return mmal_port_parameter_set(camera->output[2], &mirror.hdr); +} + +/** + * Set the ROI of the sensor to use for captures/preview + * @param camera Pointer to camera component + * @param rect Normalised coordinates of ROI rectangle + * + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_ROI(MMAL_COMPONENT_T *camera, PARAM_FLOAT_RECT_T rect) +{ + MMAL_PARAMETER_INPUT_CROP_T crop = {{MMAL_PARAMETER_INPUT_CROP, sizeof(MMAL_PARAMETER_INPUT_CROP_T)}}; + + crop.rect.x = (65536 * rect.x); + crop.rect.y = (65536 * rect.y); + crop.rect.width = (65536 * rect.w); + crop.rect.height = (65536 * rect.h); + + return mmal_port_parameter_set(camera->control, &crop.hdr); +} + +/** + * Adjust the exposure time used for images + * @param camera Pointer to camera component + * @param shutter speed in microseconds + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_shutter_speed(MMAL_COMPONENT_T *camera, int speed) +{ + if (!camera) + return 1; + + return mmal_status_to_int(mmal_port_parameter_set_uint32(camera->control, MMAL_PARAMETER_SHUTTER_SPEED, speed)); +} + +/** + * Adjust the Dynamic range compression level + * @param camera Pointer to camera component + * @param strength Strength of DRC to apply + * MMAL_PARAMETER_DRC_STRENGTH_OFF + * MMAL_PARAMETER_DRC_STRENGTH_LOW + * MMAL_PARAMETER_DRC_STRENGTH_MEDIUM + * MMAL_PARAMETER_DRC_STRENGTH_HIGH + * + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_DRC(MMAL_COMPONENT_T *camera, MMAL_PARAMETER_DRC_STRENGTH_T strength) +{ + MMAL_PARAMETER_DRC_T drc = {{MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION, sizeof(MMAL_PARAMETER_DRC_T)}, strength}; + + if (!camera) + return 1; + + return mmal_status_to_int(mmal_port_parameter_set(camera->control, &drc.hdr)); +} + +int raspicamcontrol_set_stats_pass(MMAL_COMPONENT_T *camera, int stats_pass) +{ + if (!camera) + return 1; + + return mmal_status_to_int(mmal_port_parameter_set_boolean(camera->control, MMAL_PARAMETER_CAPTURE_STATS_PASS, stats_pass)); +} + + +/** + * Set the annotate data + * @param camera Pointer to camera component + * @param Bitmask of required annotation data. 0 for off. + * @param If set, a pointer to text string to use instead of bitmask, max length 32 characters + * + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_annotate(MMAL_COMPONENT_T *camera, const int settings, const char *string, + const int text_size, const int text_colour, const int bg_colour) +{ + MMAL_PARAMETER_CAMERA_ANNOTATE_V3_T annotate = + {{MMAL_PARAMETER_ANNOTATE, sizeof(MMAL_PARAMETER_CAMERA_ANNOTATE_V3_T)}}; + + if (settings) + { + time_t t = time(NULL); + struct tm tm = *localtime(&t); + char tmp[MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3]; + + annotate.enable = 1; + + if (settings & (ANNOTATE_APP_TEXT | ANNOTATE_USER_TEXT)) + { + strncpy(annotate.text, string, MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3); + annotate.text[MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3-1] = '\0'; + } + + if (settings & ANNOTATE_TIME_TEXT) + { + strftime(tmp, 32, "%X ", &tm ); + strncat(annotate.text, tmp, MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3 - strlen(annotate.text) - 1); + } + + if (settings & ANNOTATE_DATE_TEXT) + { + strftime(tmp, 32, "%x", &tm ); + strncat(annotate.text, tmp, MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3 - strlen(annotate.text) - 1); + } + + if (settings & ANNOTATE_SHUTTER_SETTINGS) + annotate.show_shutter = MMAL_TRUE; + + if (settings & ANNOTATE_GAIN_SETTINGS) + annotate.show_analog_gain = MMAL_TRUE; + + if (settings & ANNOTATE_LENS_SETTINGS) + annotate.show_lens = MMAL_TRUE; + + if (settings & ANNOTATE_CAF_SETTINGS) + annotate.show_caf = MMAL_TRUE; + + if (settings & ANNOTATE_MOTION_SETTINGS) + annotate.show_motion = MMAL_TRUE; + + if (settings & ANNOTATE_FRAME_NUMBER) + annotate.show_frame_num = MMAL_TRUE; + + if (settings & ANNOTATE_BLACK_BACKGROUND) + annotate.enable_text_background = MMAL_TRUE; + + annotate.text_size = text_size; + + if (text_colour != -1) + { + annotate.custom_text_colour = MMAL_TRUE; + annotate.custom_text_Y = text_colour&0xff; + annotate.custom_text_U = (text_colour>>8)&0xff; + annotate.custom_text_V = (text_colour>>16)&0xff; + } + else + annotate.custom_text_colour = MMAL_FALSE; + + if (bg_colour != -1) + { + annotate.custom_background_colour = MMAL_TRUE; + annotate.custom_background_Y = bg_colour&0xff; + annotate.custom_background_U = (bg_colour>>8)&0xff; + annotate.custom_background_V = (bg_colour>>16)&0xff; + } + else + annotate.custom_background_colour = MMAL_FALSE; + } + else + annotate.enable = 0; + + return mmal_status_to_int(mmal_port_parameter_set(camera->control, &annotate.hdr)); +} + +int raspicamcontrol_set_stereo_mode(MMAL_PORT_T *port, MMAL_PARAMETER_STEREOSCOPIC_MODE_T *stereo_mode) +{ + MMAL_PARAMETER_STEREOSCOPIC_MODE_T stereo = { {MMAL_PARAMETER_STEREOSCOPIC_MODE, sizeof(stereo)}, + MMAL_STEREOSCOPIC_MODE_NONE, MMAL_FALSE, MMAL_FALSE }; + if (stereo_mode->mode != MMAL_STEREOSCOPIC_MODE_NONE) + { + stereo.mode = stereo_mode->mode; + stereo.decimate = stereo_mode->decimate; + stereo.swap_eyes = stereo_mode->swap_eyes; + } + return mmal_status_to_int(mmal_port_parameter_set(port, &stereo.hdr)); +} + +/** + * Asked GPU how much memory it has allocated + * + * @return amount of memory in MB + */ +static int raspicamcontrol_get_mem_gpu(void) +{ + char response[80] = ""; + int gpu_mem = 0; + if (vc_gencmd(response, sizeof response, "get_mem gpu") == 0) + vc_gencmd_number_property(response, "gpu", &gpu_mem); + return gpu_mem; +} + +/** + * Ask GPU about its camera abilities + * @param supported None-zero if software supports the camera + * @param detected None-zero if a camera has been detected + */ +void raspicamcontrol_get_camera(int *supported, int *detected) +{ + char response[80] = ""; + if (vc_gencmd(response, sizeof response, "get_camera") == 0) + { + if (supported) + vc_gencmd_number_property(response, "supported", supported); + if (detected) + vc_gencmd_number_property(response, "detected", detected); + } +} + +/** + * Check to see if camera is supported, and we have allocated enough meooryAsk GPU about its camera abilities + * @param supported None-zero if software supports the camera + * @param detected None-zero if a camera has been detected + */ +void raspicamcontrol_check_configuration(int min_gpu_mem) +{ + int gpu_mem = raspicamcontrol_get_mem_gpu(); + int supported = 0, detected = 0; + raspicamcontrol_get_camera(&supported, &detected); + if (!supported) + vcos_log_error("Camera is not enabled in this build. Try running \"sudo raspi-config\" and ensure that \"camera\" has been enabled\n"); + else if (gpu_mem < min_gpu_mem) + vcos_log_error("Only %dM of gpu_mem is configured. Try running \"sudo raspi-config\" and ensure that \"memory_split\" has a value of %d or greater\n", gpu_mem, min_gpu_mem); + else if (!detected) + vcos_log_error("Camera is not detected. Please check carefully the camera module is installed correctly\n"); + else + vcos_log_error("Failed to run camera app. Please check for firmware updates\n"); +} +/* *INDENT-ON* */ diff --git a/sys/rpicamsrc/RaspiCamControl.h b/sys/rpicamsrc/RaspiCamControl.h new file mode 100644 index 0000000000..83e9eddf15 --- /dev/null +++ b/sys/rpicamsrc/RaspiCamControl.h @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2013-2015 Jan Schmidt +Portions: +Copyright (c) 2013, Broadcom Europe Ltd +Copyright (c) 2013, James Hughes +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef RASPICAMCONTROL_H_ +#define RASPICAMCONTROL_H_ + +/* Various parameters + * + * Exposure Mode + * MMAL_PARAM_EXPOSUREMODE_OFF, + MMAL_PARAM_EXPOSUREMODE_AUTO, + MMAL_PARAM_EXPOSUREMODE_NIGHT, + MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW, + MMAL_PARAM_EXPOSUREMODE_BACKLIGHT, + MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT, + MMAL_PARAM_EXPOSUREMODE_SPORTS, + MMAL_PARAM_EXPOSUREMODE_SNOW, + MMAL_PARAM_EXPOSUREMODE_BEACH, + MMAL_PARAM_EXPOSUREMODE_VERYLONG, + MMAL_PARAM_EXPOSUREMODE_FIXEDFPS, + MMAL_PARAM_EXPOSUREMODE_ANTISHAKE, + MMAL_PARAM_EXPOSUREMODE_FIREWORKS, + * + * AWB Mode + * MMAL_PARAM_AWBMODE_OFF, + MMAL_PARAM_AWBMODE_AUTO, + MMAL_PARAM_AWBMODE_SUNLIGHT, + MMAL_PARAM_AWBMODE_CLOUDY, + MMAL_PARAM_AWBMODE_SHADE, + MMAL_PARAM_AWBMODE_TUNGSTEN, + MMAL_PARAM_AWBMODE_FLUORESCENT, + MMAL_PARAM_AWBMODE_INCANDESCENT, + MMAL_PARAM_AWBMODE_FLASH, + MMAL_PARAM_AWBMODE_HORIZON, + * + * Image FX + MMAL_PARAM_IMAGEFX_NONE, + MMAL_PARAM_IMAGEFX_NEGATIVE, + MMAL_PARAM_IMAGEFX_SOLARIZE, + MMAL_PARAM_IMAGEFX_POSTERIZE, + MMAL_PARAM_IMAGEFX_WHITEBOARD, + MMAL_PARAM_IMAGEFX_BLACKBOARD, + MMAL_PARAM_IMAGEFX_SKETCH, + MMAL_PARAM_IMAGEFX_DENOISE, + MMAL_PARAM_IMAGEFX_EMBOSS, + MMAL_PARAM_IMAGEFX_OILPAINT, + MMAL_PARAM_IMAGEFX_HATCH, + MMAL_PARAM_IMAGEFX_GPEN, + MMAL_PARAM_IMAGEFX_PASTEL, + MMAL_PARAM_IMAGEFX_WATERCOLOUR, + MMAL_PARAM_IMAGEFX_FILM, + MMAL_PARAM_IMAGEFX_BLUR, + MMAL_PARAM_IMAGEFX_SATURATION, + MMAL_PARAM_IMAGEFX_COLOURSWAP, + MMAL_PARAM_IMAGEFX_WASHEDOUT, + MMAL_PARAM_IMAGEFX_POSTERISE, + MMAL_PARAM_IMAGEFX_COLOURPOINT, + MMAL_PARAM_IMAGEFX_COLOURBALANCE, + MMAL_PARAM_IMAGEFX_CARTOON, + + */ + +/// Annotate bitmask options +/// Supplied by user on command line +#define ANNOTATE_USER_TEXT 1 +/// Supplied by app using this module +#define ANNOTATE_APP_TEXT 2 +/// Insert current date +#define ANNOTATE_DATE_TEXT 4 +// Insert current time +#define ANNOTATE_TIME_TEXT 8 + +#define ANNOTATE_SHUTTER_SETTINGS 16 +#define ANNOTATE_CAF_SETTINGS 32 +#define ANNOTATE_GAIN_SETTINGS 64 +#define ANNOTATE_LENS_SETTINGS 128 +#define ANNOTATE_MOTION_SETTINGS 256 +#define ANNOTATE_FRAME_NUMBER 512 +#define ANNOTATE_BLACK_BACKGROUND 1024 + + +// There isn't actually a MMAL structure for the following, so make one +typedef struct +{ + int enable; /// Turn colourFX on or off + int u,v; /// U and V to use +} MMAL_PARAM_COLOURFX_T; + +typedef struct +{ + int enable; + int width,height; + int quality; +} MMAL_PARAM_THUMBNAIL_CONFIG_T; + +typedef struct +{ + double x; + double y; + double w; + double h; +} PARAM_FLOAT_RECT_T; + +/// struct contain camera settings +typedef struct +{ + int sharpness; /// -100 to 100 + int contrast; /// -100 to 100 + int brightness; /// 0 to 100 + int saturation; /// -100 to 100 + int ISO; /// TODO : what range? + int videoStabilisation; /// 0 or 1 (false or true) + int exposureCompensation; /// -10 to +10 ? + MMAL_PARAM_EXPOSUREMODE_T exposureMode; + MMAL_PARAM_EXPOSUREMETERINGMODE_T exposureMeterMode; + MMAL_PARAM_AWBMODE_T awbMode; + MMAL_PARAM_IMAGEFX_T imageEffect; + MMAL_PARAMETER_IMAGEFX_PARAMETERS_T imageEffectsParameters; + MMAL_PARAM_COLOURFX_T colourEffects; + int rotation; /// 0-359 + int hflip; /// 0 or 1 + int vflip; /// 0 or 1 + PARAM_FLOAT_RECT_T roi; /// region of interest to use on the sensor. Normalised [0,1] values in the rect + int shutter_speed; /// 0 = auto, otherwise the shutter speed in ms + float awb_gains_r; /// AWB red gain + float awb_gains_b; /// AWB blue gain + MMAL_PARAMETER_DRC_STRENGTH_T drc_level; // Strength of Dynamic Range compression to apply + MMAL_BOOL_T stats_pass; /// Stills capture statistics pass on/off + int enable_annotate; /// Flag to enable the annotate, 0 = disabled, otherwise a bitmask of what needs to be displayed + char annotate_string[MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V2]; /// String to use for annotate - overrides certain bitmask settings + int annotate_text_size; // Text size for annotation + int annotate_text_colour; // Text colour for annotation + int annotate_bg_colour; // Background colour for annotation + MMAL_PARAMETER_STEREOSCOPIC_MODE_T stereo_mode; +} RASPICAM_CAMERA_PARAMETERS; + + +void raspicamcontrol_check_configuration(int min_gpu_mem); + +int raspicamcontrol_parse_cmdline(RASPICAM_CAMERA_PARAMETERS *params, const char *arg1, const char *arg2); +void raspicamcontrol_display_help(); +int raspicamcontrol_cycle_test(MMAL_COMPONENT_T *camera); + +int raspicamcontrol_set_all_parameters(MMAL_COMPONENT_T *camera, const RASPICAM_CAMERA_PARAMETERS *params); +int raspicamcontrol_get_all_parameters(MMAL_COMPONENT_T *camera, RASPICAM_CAMERA_PARAMETERS *params); +void raspicamcontrol_dump_parameters(const RASPICAM_CAMERA_PARAMETERS *params); + +void raspicamcontrol_set_defaults(RASPICAM_CAMERA_PARAMETERS *params); + +void raspicamcontrol_check_configuration(int min_gpu_mem); +void raspicamcontrol_get_camera(int *supported, int *detected); + +// Individual setting functions +int raspicamcontrol_set_saturation(MMAL_COMPONENT_T *camera, int saturation); +int raspicamcontrol_set_sharpness(MMAL_COMPONENT_T *camera, int sharpness); +int raspicamcontrol_set_contrast(MMAL_COMPONENT_T *camera, int contrast); +int raspicamcontrol_set_brightness(MMAL_COMPONENT_T *camera, int brightness); +int raspicamcontrol_set_ISO(MMAL_COMPONENT_T *camera, int ISO); +int raspicamcontrol_set_metering_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_EXPOSUREMETERINGMODE_T mode); +int raspicamcontrol_set_video_stabilisation(MMAL_COMPONENT_T *camera, int vstabilisation); +int raspicamcontrol_set_exposure_compensation(MMAL_COMPONENT_T *camera, int exp_comp); +int raspicamcontrol_set_exposure_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_EXPOSUREMODE_T mode); +int raspicamcontrol_set_awb_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_AWBMODE_T awb_mode); +int raspicamcontrol_set_awb_gains(MMAL_COMPONENT_T *camera, float r_gain, float b_gain); +int raspicamcontrol_set_imageFX(MMAL_COMPONENT_T *camera, MMAL_PARAM_IMAGEFX_T imageFX); +int raspicamcontrol_set_colourFX(MMAL_COMPONENT_T *camera, const MMAL_PARAM_COLOURFX_T *colourFX); +int raspicamcontrol_set_rotation(MMAL_COMPONENT_T *camera, int rotation); +int raspicamcontrol_set_flips(MMAL_COMPONENT_T *camera, int hflip, int vflip); +int raspicamcontrol_set_ROI(MMAL_COMPONENT_T *camera, PARAM_FLOAT_RECT_T rect); +int raspicamcontrol_set_shutter_speed(MMAL_COMPONENT_T *camera, int speed_ms); +int raspicamcontrol_set_DRC(MMAL_COMPONENT_T *camera, MMAL_PARAMETER_DRC_STRENGTH_T strength); +int raspicamcontrol_set_stats_pass(MMAL_COMPONENT_T *camera, int stats_pass); +int raspicamcontrol_set_annotate(MMAL_COMPONENT_T *camera, const int bitmask, const char *string, + const int text_size, const int text_colour, const int bg_colour); +int raspicamcontrol_set_stereo_mode(MMAL_PORT_T *port, MMAL_PARAMETER_STEREOSCOPIC_MODE_T *stereo_mode); + +//Individual getting functions +int raspicamcontrol_get_saturation(MMAL_COMPONENT_T *camera); +int raspicamcontrol_get_sharpness(MMAL_COMPONENT_T *camera); +int raspicamcontrol_get_contrast(MMAL_COMPONENT_T *camera); +int raspicamcontrol_get_brightness(MMAL_COMPONENT_T *camera); +int raspicamcontrol_get_ISO(MMAL_COMPONENT_T *camera); +MMAL_PARAM_EXPOSUREMETERINGMODE_T raspicamcontrol_get_metering_mode(MMAL_COMPONENT_T *camera); +int raspicamcontrol_get_video_stabilisation(MMAL_COMPONENT_T *camera); +int raspicamcontrol_get_exposure_compensation(MMAL_COMPONENT_T *camera); +MMAL_PARAM_THUMBNAIL_CONFIG_T raspicamcontrol_get_thumbnail_parameters(MMAL_COMPONENT_T *camera); +MMAL_PARAM_EXPOSUREMODE_T raspicamcontrol_get_exposure_mode(MMAL_COMPONENT_T *camera); +MMAL_PARAM_AWBMODE_T raspicamcontrol_get_awb_mode(MMAL_COMPONENT_T *camera); +MMAL_PARAM_IMAGEFX_T raspicamcontrol_get_imageFX(MMAL_COMPONENT_T *camera); +MMAL_PARAM_COLOURFX_T raspicamcontrol_get_colourFX(MMAL_COMPONENT_T *camera); + + +#endif /* RASPICAMCONTROL_H_ */ diff --git a/sys/rpicamsrc/RaspiCapture.c b/sys/rpicamsrc/RaspiCapture.c new file mode 100644 index 0000000000..8a58e52a76 --- /dev/null +++ b/sys/rpicamsrc/RaspiCapture.c @@ -0,0 +1,2040 @@ +/* *INDENT-OFF* */ +/* + * Copyright (c) 2013-2016 Jan Schmidt +Portions: +Copyright (c) 2013, Broadcom Europe Ltd +Copyright (c) 2013, James Hughes +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * \file RaspiCapture.c + * + * Modification of the RaspiVid command line capture program for GStreamer + * use. + * + * \date 28th Feb 2013, 11 Oct 2013, 5 Mar 2015 + * \Author: James Hughes, Jan Schmidt + * + * Description + * + * 3 components are created; camera, preview and video encoder. + * Camera component has three ports, preview, video and stills. + * This program connects preview and stills to the preview and video + * encoder. Using mmal we don't need to worry about buffers between these + * components, but we do need to handle buffers from the encoder, which + * are simply written straight to the file in the requisite buffer callback. + * + * We use the RaspiCamControl code to handle the specific camera settings. + * We use the RaspiPreview code to handle the (generic) preview window + */ + +// We use some GNU extensions (basename, asprintf) +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#include + +#include "bcm_host.h" +#include "interface/vcos/vcos.h" + +#include "interface/mmal/mmal.h" +#include "interface/mmal/mmal_logging.h" +#include "interface/mmal/mmal_buffer.h" +#include "interface/mmal/util/mmal_util.h" +#include "interface/mmal/util/mmal_util_params.h" +#include "interface/mmal/util/mmal_default_components.h" +#include "interface/mmal/util/mmal_connection.h" + +#include "RaspiCapture.h" +#include "RaspiCamControl.h" +#include "RaspiPreview.h" +#include "RaspiCLI.h" + +#include + +// Standard port setting for the camera component +#define MMAL_CAMERA_PREVIEW_PORT 0 +#define MMAL_CAMERA_VIDEO_PORT 1 +#define MMAL_CAMERA_CAPTURE_PORT 2 + +// Video format information +// 0 implies variable +#define VIDEO_FRAME_RATE_NUM 30 +#define VIDEO_FRAME_RATE_DEN 1 + +/// Video render needs at least 2 buffers. +#define VIDEO_OUTPUT_BUFFERS_NUM 3 + +// Max bitrate we allow for recording +const int MAX_BITRATE = 25000000; // 25Mbits/s + +/// Interval at which we check for an failure abort during capture +const int ABORT_INTERVAL = 100; // ms + + +int mmal_status_to_int(MMAL_STATUS_T status); + +/** Struct used to pass information in encoder port userdata to callback + */ +typedef struct +{ + RASPIVID_STATE *state; /// pointer to our state in case required in callback + int abort; /// Set to 1 in callback if an error occurs to attempt to abort the capture +} PORT_USERDATA; + +struct RASPIVID_STATE_T +{ + RASPIVID_CONFIG config; + + FILE *output_file; + + MMAL_COMPONENT_T *camera_component; /// Pointer to the camera component + MMAL_COMPONENT_T *encoder_component; /// Pointer to the encoder component + MMAL_CONNECTION_T *preview_connection; /// Pointer to the connection from camera to preview + MMAL_CONNECTION_T *encoder_connection; /// Pointer to the connection from camera to encoder + + MMAL_PORT_T *camera_video_port; + MMAL_PORT_T *camera_still_port; + MMAL_PORT_T *encoder_output_port; + + MMAL_POOL_T *encoder_pool; /// Pointer to the pool of buffers used by encoder output port + + PORT_USERDATA callback_data; + + MMAL_QUEUE_T *encoded_buffer_q; + + int64_t base_time; + int64_t last_second; + + RASPIPREVIEW_STATE preview_state; +}; + + +/// Structure to cross reference H264 profile strings against the MMAL parameter equivalent +static XREF_T profile_map[] = +{ + {"baseline", MMAL_VIDEO_PROFILE_H264_BASELINE}, + {"main", MMAL_VIDEO_PROFILE_H264_MAIN}, + {"high", MMAL_VIDEO_PROFILE_H264_HIGH}, +// {"constrained", MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE} // Does anyone need this? +}; + +static int profile_map_size = sizeof(profile_map) / sizeof(profile_map[0]); + +#if 0 +static XREF_T initial_map[] = +{ + {"record", 0}, + {"pause", 1}, +}; + +static int initial_map_size = sizeof(initial_map) / sizeof(initial_map[0]); +#endif + +static XREF_T intra_refresh_map[] = +{ + {"cyclic", MMAL_VIDEO_INTRA_REFRESH_CYCLIC}, + {"adaptive", MMAL_VIDEO_INTRA_REFRESH_ADAPTIVE}, + {"both", MMAL_VIDEO_INTRA_REFRESH_BOTH}, + {"cyclicrows", MMAL_VIDEO_INTRA_REFRESH_CYCLIC_MROWS}, +// {"random", MMAL_VIDEO_INTRA_REFRESH_PSEUDO_RAND} Cannot use random, crashes the encoder. No idea why. +}; + +static int intra_refresh_map_size = sizeof(intra_refresh_map) / sizeof(intra_refresh_map[0]); + +#if 0 + +static void display_valid_parameters(char *app_name); + +/// Command ID's and Structure defining our command line options +#define CommandHelp 0 +#define CommandWidth 1 +#define CommandHeight 2 +#define CommandBitrate 3 +#define CommandOutput 4 +#define CommandVerbose 5 +#define CommandTimeout 6 +#define CommandDemoMode 7 +#define CommandFramerate 8 +#define CommandPreviewEnc 9 +#define CommandIntraPeriod 10 +#define CommandProfile 11 +#define CommandTimed 12 +#define CommandSignal 13 +#define CommandKeypress 14 +#define CommandInitialState 15 +#define CommandQP 16 +#define CommandInlineHeaders 17 +#define CommandSegmentFile 18 +#define CommandSegmentWrap 19 +#define CommandSegmentStart 20 +#define CommandSplitWait 21 +#define CommandCircular 22 +#define CommandIMV 23 +#define CommandCamSelect 24 +#define CommandSettings 25 +#define CommandSensorMode 26 +#define CommandIntraRefreshType 27 + +static COMMAND_LIST cmdline_commands[] = +{ + { CommandHelp, "-help", "?", "This help information", 0 }, + { CommandWidth, "-width", "w", "Set image width . Default 1920", 1 }, + { CommandHeight, "-height", "h", "Set image height . Default 1080", 1 }, + { CommandBitrate, "-bitrate", "b", "Set bitrate. Use bits per second (e.g. 10MBits/s would be -b 10000000)", 1 }, + { CommandOutput, "-output", "o", "Output filename (to write to stdout, use '-o -')", 1 }, + { CommandVerbose, "-verbose", "v", "Output verbose information during run", 0 }, + { CommandTimeout, "-timeout", "t", "Time (in ms) to capture for. If not specified, set to 5s. Zero to disable", 1 }, + { CommandDemoMode, "-demo", "d", "Run a demo mode (cycle through range of camera options, no capture)", 1}, + { CommandFramerate, "-framerate", "fps","Specify the frames per second to record", 1}, + { CommandPreviewEnc, "-penc", "e", "Display preview image *after* encoding (shows compression artifacts)", 0}, + { CommandIntraPeriod, "-intra", "g", "Specify the intra refresh period (key frame rate/GoP size). Zero to produce an initial I-frame and then just P-frames.", 1}, + { CommandProfile, "-profile", "pf", "Specify H264 profile to use for encoding", 1}, + { CommandTimed, "-timed", "td", "Cycle between capture and pause. -cycle on,off where on is record time and off is pause time in ms", 0}, + { CommandSignal, "-signal", "s", "Cycle between capture and pause on Signal", 0}, + { CommandKeypress, "-keypress", "k", "Cycle between capture and pause on ENTER", 0}, + { CommandInitialState, "-initial", "i", "Initial state. Use 'record' or 'pause'. Default 'record'", 1}, + { CommandQP, "-qp", "qp", "Quantisation parameter. Use approximately 10-40. Default 0 (off)", 1}, + { CommandInlineHeaders, "-inline", "ih", "Insert inline headers (SPS, PPS) to stream", 0}, + { CommandSegmentFile, "-segment", "sg", "Segment output file in to multiple files at specified interval ", 1}, + { CommandSegmentWrap, "-wrap", "wr", "In segment mode, wrap any numbered filename back to 1 when reach number", 1}, + { CommandSegmentStart, "-start", "sn", "In segment mode, start with specified segment number", 1}, + { CommandSplitWait, "-split", "sp", "In wait mode, create new output file for each start event", 0}, + { CommandCircular, "-circular", "c", "Run encoded data through circular buffer until triggered then save", 0}, + { CommandIMV, "-vectors", "x", "Output filename for inline motion vectors", 1 }, + { CommandCamSelect, "-camselect", "cs", "Select camera . Default 0", 1 }, + { CommandSettings, "-settings", "set","Retrieve camera settings and write to stdout", 0}, + { CommandSensorMode, "-mode", "md", "Force sensor mode. 0=auto. See docs for other modes available", 1}, + { CommandIntraRefreshType,"-irefresh", "if", "Set intra refresh type", 1}, +}; + +static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]); +#endif + +static void dump_state(RASPIVID_STATE *state); + +/** + * Assign a default set of parameters to the state passed in + * + * @param state Pointer to state structure to assign defaults to + */ +void raspicapture_default_config(RASPIVID_CONFIG *config) +{ + if (!config) + { + vcos_assert(0); + return; + } + + // Default everything to zero + memset(config, 0, sizeof(RASPIVID_CONFIG)); + + // Now set anything non-zero + config->timeout = 5000; // 5s delay before take image + config->width = 1920; // Default to 1080p + config->height = 1080; + config->bitrate = 17000000; // This is a decent default bitrate for 1080p + config->fps_n = VIDEO_FRAME_RATE_NUM; + config->fps_d = VIDEO_FRAME_RATE_DEN; + config->intraperiod = -1; // Not set + config->quantisationParameter = 0; + config->demoMode = 0; + config->demoInterval = 250; // ms + config->immutableInput = 1; + config->profile = MMAL_VIDEO_PROFILE_H264_HIGH; + config->encoding = MMAL_ENCODING_H264; + + config->bInlineHeaders = 0; + + config->inlineMotionVectors = 0; + + config->cameraNum = 0; + config->settings = 0; + config->sensor_mode = 0; + + config->intra_refresh_type = -1; + + // Setup preview window defaults + raspipreview_set_defaults(&config->preview_parameters); + + // Set up the camera_parameters to default + raspicamcontrol_set_defaults(&config->camera_parameters); + +} + + +/** + * Dump image state parameters to printf. Used for debugging + * + * @param state Pointer to state structure to assign defaults to + */ +static void dump_state(RASPIVID_STATE *state) +{ + RASPIVID_CONFIG *config; + + if (!state) + { + vcos_assert(0); + return; + } + + config = &state->config; + + fprintf(stderr, "Width %d, Height %d\n", config->width, config->height); + fprintf(stderr, "bitrate %d, framerate %d/%d, time delay %d\n", + config->bitrate, config->fps_n, config->fps_d, config->timeout); + //fprintf(stderr, "H264 Profile %s\n", raspicli_unmap_xref(config->profile, profile_map, profile_map_size)); + + raspipreview_dump_parameters(&config->preview_parameters); + raspicamcontrol_dump_parameters(&config->camera_parameters); +} + +#if 0 +/** + * Parse the incoming command line and put resulting parameters in to the state + * + * @param argc Number of arguments in command line + * @param argv Array of pointers to strings from command line + * @param state Pointer to state structure to assign any discovered parameters to + * @return Non-0 if failed for some reason, 0 otherwise + */ +static int parse_cmdline(int argc, const char **argv, RASPIVID_STATE *state) +{ + // Parse the command line arguments. + // We are looking for -- or - + + int valid = 1; + int i; + + for (i = 1; i < argc && valid; i++) + { + int command_id, num_parameters; + + if (!argv[i]) + continue; + + if (argv[i][0] != '-') + { + valid = 0; + continue; + } + + // Assume parameter is valid until proven otherwise + valid = 1; + + command_id = raspicli_get_command_id(cmdline_commands, cmdline_commands_size, &argv[i][1], &num_parameters); + + // If we found a command but are missing a parameter, continue (and we will drop out of the loop) + if (command_id != -1 && num_parameters > 0 && (i + 1 >= argc) ) + continue; + + // We are now dealing with a command line option + switch (command_id) + { + case CommandHelp: + display_valid_parameters(basename(argv[0])); + return -1; + + case CommandWidth: // Width > 0 + if (sscanf(argv[i + 1], "%u", &state->width) != 1) + valid = 0; + else + i++; + break; + + case CommandHeight: // Height > 0 + if (sscanf(argv[i + 1], "%u", &state->height) != 1) + valid = 0; + else + i++; + break; + + case CommandBitrate: // 1-100 + if (sscanf(argv[i + 1], "%u", &state->bitrate) == 1) + { + if (state->bitrate > MAX_BITRATE) + { + state->bitrate = MAX_BITRATE; + } + i++; + } + else + valid = 0; + + break; + + case CommandOutput: // output filename + { + int len = strlen(argv[i + 1]); + if (len) + { + state->filename = malloc(len + 1); + vcos_assert(state->filename); + if (state->filename) + strncpy(state->filename, argv[i + 1], len+1); + i++; + } + else + valid = 0; + break; + } + + case CommandVerbose: // display lots of data during run + state->verbose = 1; + break; + + case CommandTimeout: // Time to run viewfinder/capture + { + if (sscanf(argv[i + 1], "%u", &state->timeout) == 1) + { + // Ensure that if previously selected a waitMethod we dont overwrite it + if (state->timeout == 0 && state->waitMethod == WAIT_METHOD_NONE) + state->waitMethod = WAIT_METHOD_FOREVER; + + i++; + } + else + valid = 0; + break; + } + + case CommandDemoMode: // Run in demo mode - no capture + { + // Demo mode might have a timing parameter + // so check if a) we have another parameter, b) its not the start of the next option + if (i + 1 < argc && argv[i+1][0] != '-') + { + if (sscanf(argv[i + 1], "%u", &state->demoInterval) == 1) + { + // TODO : What limits do we need for timeout? + if (state->demoInterval == 0) + state->demoInterval = 250; // ms + + state->demoMode = 1; + i++; + } + else + valid = 0; + } + else + { + state->demoMode = 1; + } + + break; + } + + case CommandFramerate: // fps to record + { + if (sscanf(argv[i + 1], "%u", &state->framerate) == 1) + { + // TODO : What limits do we need for fps 1 - 30 - 120?? + i++; + } + else + valid = 0; + break; + } + + case CommandPreviewEnc: + state->immutableInput = 0; + break; + + case CommandIntraPeriod: // key frame rate + { + if (sscanf(argv[i + 1], "%u", &state->intraperiod) == 1) + i++; + else + valid = 0; + break; + } + + case CommandQP: // quantisation parameter + { + if (sscanf(argv[i + 1], "%u", &state->quantisationParameter) == 1) + i++; + else + valid = 0; + break; + } + + case CommandProfile: // H264 profile + { + state->profile = raspicli_map_xref(argv[i + 1], profile_map, profile_map_size); + + if( state->profile == -1) + state->profile = MMAL_VIDEO_PROFILE_H264_HIGH; + + i++; + break; + } + + case CommandInlineHeaders: // H264 inline headers + { + state->bInlineHeaders = 1; + break; + } + + case CommandTimed: + { + if (sscanf(argv[i + 1], "%u,%u", &state->onTime, &state->offTime) == 2) + { + i++; + + if (state->onTime < 1000) + state->onTime = 1000; + + if (state->offTime < 1000) + state->offTime = 1000; + + state->waitMethod = WAIT_METHOD_TIMED; + } + else + valid = 0; + break; + } + + case CommandKeypress: + state->waitMethod = WAIT_METHOD_KEYPRESS; + break; + + case CommandSignal: + state->waitMethod = WAIT_METHOD_SIGNAL; + // Reenable the signal + signal(SIGUSR1, signal_handler); + break; + + case CommandInitialState: + { + state->bCapturing = raspicli_map_xref(argv[i + 1], initial_map, initial_map_size); + + if( state->bCapturing == -1) + state->bCapturing = 0; + + i++; + break; + } + + case CommandSegmentFile: // Segment file in to chunks of specified time + { + if (sscanf(argv[i + 1], "%u", &state->segmentSize) == 1) + { + // Must enable inline headers for this to work + state->bInlineHeaders = 1; + i++; + } + else + valid = 0; + break; + } + + case CommandSegmentWrap: // segment wrap value + { + if (sscanf(argv[i + 1], "%u", &state->segmentWrap) == 1) + i++; + else + valid = 0; + break; + } + + case CommandSegmentStart: // initial segment number + { + if((sscanf(argv[i + 1], "%u", &state->segmentNumber) == 1) && (!state->segmentWrap || (state->segmentNumber <= state->segmentWrap))) + i++; + else + valid = 0; + break; + } + + case CommandSplitWait: // split files on restart + { + // Must enable inline headers for this to work + state->bInlineHeaders = 1; + state->splitWait = 1; + break; + } + + case CommandCircular: + { + state->bCircularBuffer = 1; + break; + } + + case CommandIMV: // output filename + { + state->inlineMotionVectors = 1; + int len = strlen(argv[i + 1]); + if (len) + { + state->imv_filename = malloc(len + 1); + vcos_assert(state->imv_filename); + if (state->imv_filename) + strncpy(state->imv_filename, argv[i + 1], len+1); + i++; + } + else + valid = 0; + break; + } + case CommandCamSelect: //Select camera input port + { + if (sscanf(argv[i + 1], "%u", &state->cameraNum) == 1) + { + i++; + } + else + valid = 0; + break; + } + + case CommandSettings: + state->settings = 1; + break; + + case CommandSensorMode: + { + if (sscanf(argv[i + 1], "%u", &state->sensor_mode) == 1) + { + i++; + } + else + valid = 0; + break; + } + + case CommandIntraRefreshType: + { + state->config.intra_refresh_type = raspicli_map_xref(argv[i + 1], intra_refresh_map, intra_refresh_map_size); + i++; + break; + } + + default: + { + // Try parsing for any image specific parameters + // result indicates how many parameters were used up, 0,1,2 + // but we adjust by -1 as we have used one already + const char *second_arg = (i + 1 < argc) ? argv[i + 1] : NULL; + int parms_used = (raspicamcontrol_parse_cmdline(&state->camera_parameters, &argv[i][1], second_arg)); + + // Still unused, try preview options + if (!parms_used) + parms_used = raspipreview_parse_cmdline(&state->preview_parameters, &argv[i][1], second_arg); + + + // If no parms were used, this must be a bad parameters + if (!parms_used) + valid = 0; + else + i += parms_used - 1; + + break; + } + } + } + + if (!valid) + { + fprintf(stderr, "Invalid command line option (%s)\n", argv[i-1]); + return 1; + } + + // Always disable verbose if output going to stdout + if (state->filename && state->filename[0] == '-') + { + state->verbose = 0; + } + + return 0; +} + +/** + * Display usage information for the application to stdout + * + * @param app_name String to display as the application name + */ +static void display_valid_parameters(char *app_name) +{ + int i; + + fprintf(stderr, "Display camera output to display, and optionally saves an H264 capture at requested bitrate\n\n"); + fprintf(stderr, "\nusage: %s [options]\n\n", app_name); + + fprintf(stderr, "Image parameter commands\n\n"); + + raspicli_display_help(cmdline_commands, cmdline_commands_size); + + // Profile options + fprintf(stderr, "\n\nH264 Profile options :\n%s", profile_map[0].mode ); + + for (i=1;icmd == MMAL_EVENT_PARAMETER_CHANGED) + { + MMAL_EVENT_PARAMETER_CHANGED_T *param = (MMAL_EVENT_PARAMETER_CHANGED_T *)buffer->data; + switch (param->hdr.id) { + case MMAL_PARAMETER_CAMERA_SETTINGS: + { + MMAL_PARAMETER_CAMERA_SETTINGS_T *settings = (MMAL_PARAMETER_CAMERA_SETTINGS_T*)param; + vcos_log_error("Exposure now %u, analog gain %u/%u, digital gain %u/%u", + settings->exposure, + settings->analog_gain.num, settings->analog_gain.den, + settings->digital_gain.num, settings->digital_gain.den); + vcos_log_error("AWB R=%u/%u, B=%u/%u", + settings->awb_red_gain.num, settings->awb_red_gain.den, + settings->awb_blue_gain.num, settings->awb_blue_gain.den + ); + } + break; + } + } + else if (buffer->cmd == MMAL_EVENT_ERROR) { + vcos_log_error("Camera control callback got an error"); + } else { + vcos_log_error("Received unexpected camera control callback event, 0x%08x", buffer->cmd); + } + + mmal_buffer_header_release(buffer); +} + +#if 0 +/** + * Open a file based on the settings in state + * + * @param state Pointer to state + */ +static FILE *open_filename(RASPIVID_STATE *pState) +{ + FILE *new_handle = NULL; + char *tempname = NULL, *filename = NULL; + + if (pState->segmentSize || pState->splitWait) + { + // Create a new filename string + asprintf(&tempname, pState->filename, pState->segmentNumber); + filename = tempname; + } + else + { + filename = pState->filename; + } + + if (filename) + new_handle = fopen(filename, "wb"); + + if (pState->verbose) + { + if (new_handle) + fprintf(stderr, "Opening output file \"%s\"\n", filename); + else + fprintf(stderr, "Failed to open new file \"%s\"\n", filename); + } + + if (tempname) + free(tempname); + + return new_handle; +} + +/** + * Open a file based on the settings in state + * + * This time for the imv output file + * + * @param state Pointer to state + */ +static FILE *open_imv_filename(RASPIVID_STATE *pState) +{ + FILE *new_handle = NULL; + char *tempname = NULL, *filename = NULL; + + if (pState->segmentSize || pState->splitWait) + { + // Create a new filename string + asprintf(&tempname, pState->imv_filename, pState->segmentNumber); + filename = tempname; + } + else + { + filename = pState->imv_filename; + } + + if (filename) + new_handle = fopen(filename, "wb"); + + if (pState->verbose) + { + if (new_handle) + fprintf(stderr, "Opening imv output file \"%s\"\n", filename); + else + fprintf(stderr, "Failed to open new imv file \"%s\"\n", filename); + } + + if (tempname) + free(tempname); + + return new_handle; +} +#endif + +/** + * Update any annotation data specific to the video. + * This simply passes on the setting from cli, or + * if application defined annotate requested, updates + * with the H264 parameters + * + * @param state Pointer to state control struct + * + */ +static void update_annotation_data(RASPIVID_STATE *state) +{ + RASPIVID_CONFIG *config = &state->config; + + // So, if we have asked for a application supplied string, set it to the H264 parameters + if (config->camera_parameters.enable_annotate & ANNOTATE_APP_TEXT) + { + char *text; + const char *refresh = raspicli_unmap_xref(config->intra_refresh_type, intra_refresh_map, intra_refresh_map_size); + + asprintf(&text, "%dk,%ff,%s,%d,%s", + config->bitrate / 1000, ((float)(config->fps_n) / config->fps_d), + refresh ? refresh : "(none)", + config->intraperiod, + raspicli_unmap_xref(config->profile, profile_map, profile_map_size)); + + raspicamcontrol_set_annotate(state->camera_component, config->camera_parameters.enable_annotate, text, + config->camera_parameters.annotate_text_size, + config->camera_parameters.annotate_text_colour, + config->camera_parameters.annotate_bg_colour); + + free(text); + } + else + { + raspicamcontrol_set_annotate(state->camera_component, config->camera_parameters.enable_annotate, + config->camera_parameters.annotate_string, + config->camera_parameters.annotate_text_size, + config->camera_parameters.annotate_text_colour, + config->camera_parameters.annotate_bg_colour); + } +} + + + +/** + * buffer header callback function for encoder + * + * Callback will dump buffer data to the specific file + * + * @param port Pointer to port from which callback originated + * @param buffer mmal buffer header pointer + */ +static void encoder_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) +{ + PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata; + RASPIVID_STATE *state = pData->state; + int64_t current_time; + + // All our segment times based on the receipt of the first encoder callback + if (state->base_time == -1) + state->base_time = vcos_getmicrosecs64()/1000; + + if (pData == NULL) + { + vcos_log_error("Received a encoder buffer callback with no state"); + // release buffer back to the pool + mmal_buffer_header_release(buffer); + return; + } + + current_time = vcos_getmicrosecs64()/1000; + if (state->base_time == -1) + state->base_time = current_time; + + // See if the second count has changed and we need to update any annotation + if (current_time/1000 != state->last_second) + { + update_annotation_data(state); + state->last_second = current_time/1000; + } + + /* Send buffer to GStreamer element for pushing to the pipeline */ + mmal_queue_put(state->encoded_buffer_q, buffer); +} + +GstFlowReturn +raspi_capture_fill_buffer(RASPIVID_STATE *state, GstBuffer **bufp, + GstClock *clock, GstClockTime base_time) +{ + RASPIVID_CONFIG *config = &state->config; + GstBuffer *buf; + MMAL_BUFFER_HEADER_T *buffer; + GstFlowReturn ret = GST_FLOW_ERROR; + /* No timestamps if no clockm or invalid PTS */ + GstClockTime gst_pts = GST_CLOCK_TIME_NONE; + + do { + buffer = mmal_queue_timedwait(state->encoded_buffer_q, 500); + // Work around a bug where mmal_queue_timedwait() might return + // immediately if the internal timeout time aligns exactly + // with a 1 second rollover boundary by checking errno. + if (errno == EINVAL) { + GST_WARNING ("Retrying mmal_queue_timedwait() due to spurious failure."); + continue; + } + } while (0); + + if (G_UNLIKELY(buffer == NULL)) { + return GST_FLOW_ERROR_TIMEOUT; + } + + if (G_LIKELY (config->useSTC && clock)) { + MMAL_PARAMETER_INT64_T param; + GstClockTime runtime; + + runtime = gst_clock_get_time (clock) - base_time; + + param.hdr.id = MMAL_PARAMETER_SYSTEM_TIME; + param.hdr.size = sizeof(param); + param.value = -1; + + mmal_port_parameter_get(state->encoder_output_port, ¶m.hdr); + + if (buffer->pts != -1 && param.value != -1 && param.value >= buffer->pts) { + /* Convert microsecond RPi TS to GStreamer clock: */ + GstClockTime offset = (param.value - buffer->pts) * 1000; + if (runtime >= offset) + gst_pts = runtime - offset; + } + GST_LOG ("Buf %05u bytes FLAGS 0x%05x (uS) PTS %" G_GINT64_FORMAT + " DTS %" G_GINT64_FORMAT " STC %" G_GINT64_FORMAT + " (latency %" G_GINT64_FORMAT "uS) TS %" GST_TIME_FORMAT, + buffer->length, buffer->flags, buffer->pts, buffer->dts, param.value, + param.value - buffer->pts, GST_TIME_ARGS (gst_pts)); + } + else { + GST_LOG ("use-stc=false. Not applying STC to buffer"); + } + + mmal_buffer_header_mem_lock(buffer); + buf = gst_buffer_new_allocate(NULL, buffer->length, NULL); + if (buf) { + if (config->useSTC) + GST_BUFFER_DTS(buf) = GST_BUFFER_PTS(buf) = gst_pts; + /* FIXME: Can we avoid copies and give MMAL our own buffers to fill? */ + gst_buffer_fill(buf, 0, buffer->data + buffer->offset, buffer->length); + + if ((buffer->flags & MMAL_BUFFER_HEADER_FLAG_CONFIG)) + GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER); + else if ((buffer->flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)) + GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT); + else + GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT); + + /* NAL_END is bogus and can't be trusted */ + if ((buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END)) + ret = GST_FLOW_OK; + else + ret = GST_FLOW_KEEP_ACCUMULATING; + } + + mmal_buffer_header_mem_unlock(buffer); + + *bufp = buf; + // release buffer back to the pool + mmal_buffer_header_release(buffer); + + // and send one back to the port (if still open) + if (state->encoder_output_port->is_enabled) + { + MMAL_STATUS_T status = MMAL_SUCCESS; + + buffer = mmal_queue_get(state->encoder_pool->queue); + if (buffer) + status = mmal_port_send_buffer(state->encoder_output_port, buffer); + + if (!buffer || status != MMAL_SUCCESS) { + vcos_log_error("Unable to return a buffer to the encoder port"); + ret = GST_FLOW_ERROR; + } + } + + return ret; +} + +/** + * Create the camera component, set up its ports + * + * @param state Pointer to state control struct + * + * @return MMAL_SUCCESS if all OK, something else otherwise + * + */ +static MMAL_STATUS_T create_camera_component(RASPIVID_STATE *state) +{ + MMAL_COMPONENT_T *camera = NULL; + MMAL_STATUS_T status; + RASPIVID_CONFIG *config = &state->config; + + /* Create the component */ + status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("Failed to create camera component"); + goto error; + } + + MMAL_PARAMETER_INT32_T camera_num = + {{MMAL_PARAMETER_CAMERA_NUM, sizeof(camera_num)}, config->cameraNum}; + + status = mmal_port_parameter_set(camera->control, &camera_num.hdr); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("Could not select camera : error %d", status); + goto error; + } + + if (!camera->output_num) + { + status = MMAL_ENOSYS; + vcos_log_error("Camera doesn't have output ports"); + goto error; + } + + status = mmal_port_parameter_set_uint32(camera->control, MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG, config->sensor_mode); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("Could not set sensor mode : error %d", status); + goto error; + } + + if (config->settings) + { + MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T change_event_request = + {{MMAL_PARAMETER_CHANGE_EVENT_REQUEST, sizeof(MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T)}, + MMAL_PARAMETER_CAMERA_SETTINGS, 1}; + + status = mmal_port_parameter_set(camera->control, &change_event_request.hdr); + if ( status != MMAL_SUCCESS ) + { + vcos_log_error("No camera settings events"); + } + } + + // Enable the camera, and tell it its control callback function + status = mmal_port_enable(camera->control, camera_control_callback); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("Unable to enable control port : error %d", status); + goto error; + } + + state->camera_component = camera; + + return status; + +error: + if (camera) + mmal_component_destroy(camera); + + return status; +} + +MMAL_STATUS_T +raspi_capture_set_format_and_start(RASPIVID_STATE *state) +{ + MMAL_COMPONENT_T *camera = NULL; + MMAL_STATUS_T status; + MMAL_ES_FORMAT_T *format; + MMAL_PORT_T *preview_port = NULL, *video_port = NULL, *still_port = NULL; + RASPIVID_CONFIG *config = &state->config; + + // set up the camera configuration + + MMAL_PARAMETER_CAMERA_CONFIG_T cam_config = + { + { MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) }, + .max_stills_w = config->width, + .max_stills_h = config->height, + .stills_yuv422 = 0, + .one_shot_stills = 0, + .max_preview_video_w = config->width, + .max_preview_video_h = config->height, + .num_preview_video_frames = 3, + .stills_capture_circular_buffer_height = 0, + .fast_preview_resume = 0, + .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RAW_STC + }; + + camera = state->camera_component; + preview_port = camera->output[MMAL_CAMERA_PREVIEW_PORT]; + video_port = camera->output[MMAL_CAMERA_VIDEO_PORT]; + still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT]; + + mmal_port_parameter_set(camera->control, &cam_config.hdr); + + // Now set up the port formats + + // Set the encode format on the Preview port + // HW limitations mean we need the preview to be the same size as the required recorded output + + format = preview_port->format; + + if(config->camera_parameters.shutter_speed > 6000000) + { + MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)}, + { 50, 1000 }, {166, 1000}}; + mmal_port_parameter_set(preview_port, &fps_range.hdr); + } + else if(config->camera_parameters.shutter_speed > 1000000) + { + MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)}, + { 166, 1000 }, {999, 1000}}; + mmal_port_parameter_set(preview_port, &fps_range.hdr); + } + + //enable dynamic framerate if necessary + if (config->camera_parameters.shutter_speed) + { + if (((float)(config->fps_n) / config->fps_d) > 1000000.0 / config->camera_parameters.shutter_speed) + { + config->fps_n = 0; + config->fps_d = 1; + GST_INFO ("Enabling dynamic frame rate to fulfil shutter speed requirement"); + } + } + + format->encoding = MMAL_ENCODING_OPAQUE; + format->encoding_variant = MMAL_ENCODING_I420; + + format->es->video.width = VCOS_ALIGN_UP(config->width, 32); + format->es->video.height = VCOS_ALIGN_UP(config->height, 16); + format->es->video.crop.x = 0; + format->es->video.crop.y = 0; + format->es->video.crop.width = config->width; + format->es->video.crop.height = config->height; + format->es->video.frame_rate.num = config->fps_n; + format->es->video.frame_rate.den = config->fps_d; + + status = mmal_port_format_commit(preview_port); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("camera viewfinder format couldn't be set"); + goto error; + } + + // Set the encode format on the video port + format = video_port->format; + + if(config->camera_parameters.shutter_speed > 6000000) + { + MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)}, + { 50, 1000 }, {166, 1000}}; + mmal_port_parameter_set(video_port, &fps_range.hdr); + } + else if(config->camera_parameters.shutter_speed > 1000000) + { + MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)}, + { 167, 1000 }, {999, 1000}}; + mmal_port_parameter_set(video_port, &fps_range.hdr); + } + + /* If encoding, set opaque tunneling format */ + if (state->encoder_component) { + format->encoding = MMAL_ENCODING_OPAQUE; + format->encoding_variant = MMAL_ENCODING_I420; + } + else { + format->encoding = config->encoding; + format->encoding_variant = config->encoding; + } + + format->es->video.width = VCOS_ALIGN_UP(config->width, 32); + format->es->video.height = VCOS_ALIGN_UP(config->height, 16); + format->es->video.crop.x = 0; + format->es->video.crop.y = 0; + format->es->video.crop.width = config->width; + format->es->video.crop.height = config->height; + format->es->video.frame_rate.num = config->fps_n; + format->es->video.frame_rate.den = config->fps_d; + + status = mmal_port_format_commit(video_port); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("camera video format couldn't be set"); + goto error; + } + + // Ensure there are enough buffers to avoid dropping frames + if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM) + video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM; + + + // Set the encode format on the still port + + format = still_port->format; + + format->encoding = MMAL_ENCODING_OPAQUE; + format->encoding_variant = MMAL_ENCODING_I420; + + format->es->video.width = VCOS_ALIGN_UP(config->width, 32); + format->es->video.height = VCOS_ALIGN_UP(config->height, 16); + format->es->video.crop.x = 0; + format->es->video.crop.y = 0; + format->es->video.crop.width = config->width; + format->es->video.crop.height = config->height; + format->es->video.frame_rate.num = 0; + format->es->video.frame_rate.den = 1; + + status = mmal_port_format_commit(still_port); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("camera still format couldn't be set"); + goto error; + } + + /* Ensure there are enough buffers to avoid dropping frames */ + if (still_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM) + still_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM; + + /* Enable component */ + status = mmal_component_enable(camera); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("camera component couldn't be enabled"); + goto error; + } + + raspicamcontrol_set_all_parameters(camera, &config->camera_parameters); + + update_annotation_data(state); + + if (config->verbose) + fprintf(stderr, "Camera component done\n"); + + return status; + +error: + if (camera) + mmal_component_disable(camera); + + return status; +} + +/** + * Destroy the camera component + * + * @param state Pointer to state control struct + * + */ +static void destroy_camera_component(RASPIVID_STATE *state) +{ + if (state->camera_component) + { + mmal_component_destroy(state->camera_component); + state->camera_component = NULL; + } +} + +gboolean raspi_capture_request_i_frame(RASPIVID_STATE *state) +{ + MMAL_PORT_T *encoder_output = NULL; + MMAL_STATUS_T status; + MMAL_PARAMETER_BOOLEAN_T param = {{ MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME, sizeof(param)}, 1}; + + if (state->encoder_component) + return TRUE; + + encoder_output = state->encoder_component->output[0]; + status = mmal_port_parameter_set(encoder_output, ¶m.hdr); + if (status != MMAL_SUCCESS) + { + vcos_log_error("Unable to request I-frame"); + return FALSE; + } + return TRUE; +} + +/** + * Create the encoder component, set up its ports + * + * @param state Pointer to state control struct + * + * @return MMAL_SUCCESS if all OK, something else otherwise + * + */ +static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state) +{ + MMAL_COMPONENT_T *encoder = 0; + MMAL_PORT_T *encoder_input = NULL, *encoder_output = NULL; + MMAL_STATUS_T status; + RASPIVID_CONFIG *config = &state->config; + + gboolean encoded_format = + (config->encoding == MMAL_ENCODING_H264 || + config->encoding == MMAL_ENCODING_MJPEG || + config->encoding == MMAL_ENCODING_JPEG); + + if (!encoded_format) + return MMAL_SUCCESS; + + if (config->encoding == MMAL_ENCODING_JPEG) + status = mmal_component_create(MMAL_COMPONENT_DEFAULT_IMAGE_ENCODER, &encoder); + else + status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_ENCODER, &encoder); + + if (status != MMAL_SUCCESS) { + vcos_log_error("Unable to create video encoder component"); + goto error; + } + + if (!encoder->input_num || !encoder->output_num) + { + status = MMAL_ENOSYS; + vcos_log_error("Video encoder doesn't have input/output ports"); + goto error; + } + + encoder_input = encoder->input[0]; + encoder_output = encoder->output[0]; + + // We want same format on input and output + mmal_format_copy(encoder_output->format, encoder_input->format); + + // Configure desired encoding + encoder_output->format->encoding = config->encoding; + + encoder_output->format->bitrate = config->bitrate; + + if (config->encoding == MMAL_ENCODING_H264) + encoder_output->buffer_size = encoder_output->buffer_size_recommended; + else + encoder_output->buffer_size = 256<<10; + + if (encoder_output->buffer_size < encoder_output->buffer_size_min) + encoder_output->buffer_size = encoder_output->buffer_size_min; + + encoder_output->buffer_num = encoder_output->buffer_num_recommended; + + if (encoder_output->buffer_num < encoder_output->buffer_num_min) + encoder_output->buffer_num = encoder_output->buffer_num_min; + + GST_DEBUG ("encoder wants %d buffers of size %u", + (guint)encoder_output->buffer_num, (guint)encoder_output->buffer_size); + + // We need to set the frame rate on output to 0, to ensure it gets + // updated correctly from the input framerate when port connected + encoder_output->format->es->video.frame_rate.num = 0; + encoder_output->format->es->video.frame_rate.den = 1; + + // Commit the port changes to the output port + status = mmal_port_format_commit(encoder_output); + if (status != MMAL_SUCCESS) { + vcos_log_error("Unable to set format on video encoder output port"); + goto error; + } + + // Set the rate control parameter + if (0) + { + MMAL_PARAMETER_VIDEO_RATECONTROL_T param = {{ MMAL_PARAMETER_RATECONTROL, sizeof(param)}, MMAL_VIDEO_RATECONTROL_DEFAULT}; + status = mmal_port_parameter_set(encoder_output, ¶m.hdr); + if (status != MMAL_SUCCESS) + { + vcos_log_error("Unable to set ratecontrol"); + goto error; + } + + } + + if (config->encoding == MMAL_ENCODING_H264 && config->intraperiod != -1) + { + MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_INTRAPERIOD, sizeof(param)}, config->intraperiod}; + status = mmal_port_parameter_set(encoder_output, ¶m.hdr); + if (status != MMAL_SUCCESS) + { + vcos_log_error("Unable to set intraperiod"); + goto error; + } + } + + if (config->encoding == MMAL_ENCODING_H264 && config->quantisationParameter) + { + MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT, sizeof(param)}, config->quantisationParameter}; + status = mmal_port_parameter_set(encoder_output, ¶m.hdr); + if (status != MMAL_SUCCESS) + { + vcos_log_error("Unable to set initial QP"); + goto error; + } + + MMAL_PARAMETER_UINT32_T param2 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT, sizeof(param)}, config->quantisationParameter}; + status = mmal_port_parameter_set(encoder_output, ¶m2.hdr); + if (status != MMAL_SUCCESS) + { + vcos_log_error("Unable to set min QP"); + goto error; + } + + MMAL_PARAMETER_UINT32_T param3 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT, sizeof(param)}, config->quantisationParameter}; + status = mmal_port_parameter_set(encoder_output, ¶m3.hdr); + if (status != MMAL_SUCCESS) + { + vcos_log_error("Unable to set max QP"); + goto error; + } + } + + if (config->encoding == MMAL_ENCODING_H264) + { + MMAL_PARAMETER_VIDEO_PROFILE_T param; + param.hdr.id = MMAL_PARAMETER_PROFILE; + param.hdr.size = sizeof(param); + + param.profile[0].profile = config->profile; + param.profile[0].level = MMAL_VIDEO_LEVEL_H264_4; // This is the only value supported + + status = mmal_port_parameter_set(encoder_output, ¶m.hdr); + if (status != MMAL_SUCCESS) + { + vcos_log_error("Unable to set H264 profile"); + goto error; + } + } + + if (config->encoding != MMAL_ENCODING_JPEG) + { + if (mmal_port_parameter_set_boolean(encoder_input, MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT, config->immutableInput) != MMAL_SUCCESS) + { + vcos_log_error("Unable to set immutable input flag"); + // Continue rather than abort.. + } + + //set INLINE HEADER flag to generate SPS and PPS for every IDR if requested + if (mmal_port_parameter_set_boolean(encoder_output, MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER, config->bInlineHeaders) != MMAL_SUCCESS) + { + vcos_log_error("failed to set INLINE HEADER FLAG parameters"); + // Continue rather than abort.. + } + } + + if (config->encoding == MMAL_ENCODING_H264) + { + //set INLINE VECTORS flag to request motion vector estimates + if (mmal_port_parameter_set_boolean(encoder_output, MMAL_PARAMETER_VIDEO_ENCODE_INLINE_VECTORS, config->inlineMotionVectors) != MMAL_SUCCESS) + { + vcos_log_error("failed to set INLINE VECTORS parameters"); + // Continue rather than abort.. + } + + // Adaptive intra refresh settings + if (config->intra_refresh_type != -1) + { + MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T param; + + /* Need to memset, apparently mmal_port_parameter_get() + * doesn't retrieve all parameters, causing random failures + * when we set it + */ + memset (¶m, 0, sizeof (MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T)); + + param.hdr.id = MMAL_PARAMETER_VIDEO_INTRA_REFRESH; + param.hdr.size = sizeof(param); + + // Get first so we don't overwrite anything unexpectedly + status = mmal_port_parameter_get(encoder_output, ¶m.hdr); + + param.refresh_mode = config->intra_refresh_type; + + //if (state->intra_refresh_type == MMAL_VIDEO_INTRA_REFRESH_CYCLIC_MROWS) + // param.cir_mbs = 10; + + status = mmal_port_parameter_set(encoder_output, ¶m.hdr); + if (status != MMAL_SUCCESS) + { + vcos_log_error("Unable to set H264 intra-refresh values"); + goto error; + } + } + } + + if (config->encoding == MMAL_ENCODING_JPEG) + { + status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_JPEG_Q_FACTOR, config->jpegQuality); + if (status != MMAL_SUCCESS) { + vcos_log_error("Unable to set JPEG quality"); + // Continue after warning + } + +#ifdef MMAL_PARAMETER_JPEG_RESTART_INTERVAL + status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_JPEG_RESTART_INTERVAL, config->jpegRestartInterval); + if (status != MMAL_SUCCESS) { + vcos_log_error("Unable to set JPEG restart interval"); + // Continue after warning + } +#endif + } + + // Enable component + status = mmal_component_enable(encoder); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("Unable to enable video encoder component"); + goto error; + } + + state->encoder_component = encoder; + + if (config->verbose) + fprintf(stderr, "Encoder component done\n"); + + return status; + + error: + if (encoder) + mmal_component_destroy(encoder); + + state->encoder_component = NULL; + + return status; +} + +/** + * Destroy the encoder component + * + * @param state Pointer to state control struct + * + */ +static void destroy_encoder_component(RASPIVID_STATE *state) +{ + /* Empty the buffer header q */ + if (state->encoded_buffer_q) { + while (mmal_queue_length(state->encoded_buffer_q)) { + MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state->encoded_buffer_q); + mmal_buffer_header_release(buffer); + } + } + + // Get rid of any port buffers first + if (state->encoder_pool) + { + mmal_port_pool_destroy(state->encoder_output_port, state->encoder_pool); + state->encoder_pool = NULL; + } + + if (state->encoder_component) { + + mmal_component_destroy(state->encoder_component); + state->encoder_component = NULL; + } +} + +/** + * Connect two specific ports together + * + * @param output_port Pointer the output port + * @param input_port Pointer the input port + * @param Pointer to a mmal connection pointer, reassigned if function successful + * @return Returns a MMAL_STATUS_T giving result of operation + * + */ +static MMAL_STATUS_T connect_ports(MMAL_PORT_T *output_port, MMAL_PORT_T *input_port, MMAL_CONNECTION_T **connection) +{ + MMAL_STATUS_T status; + + status = mmal_connection_create(connection, output_port, input_port, MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT); + + if (status == MMAL_SUCCESS) + { + status = mmal_connection_enable(*connection); + if (status != MMAL_SUCCESS) + mmal_connection_destroy(*connection); + } + + return status; +} + +/** + * Checks if specified port is valid and enabled, then disables it + * + * @param port Pointer the port + * + */ +static void check_disable_port(MMAL_PORT_T *port) +{ + if (port && port->is_enabled) + mmal_port_disable(port); +} + +void raspicapture_init(void) +{ + bcm_host_init(); + + // Register our application with the logging system + vcos_log_register("RaspiVid", VCOS_LOG_CATEGORY); +} + +RASPIVID_STATE * +raspi_capture_setup(RASPIVID_CONFIG *config) +{ + // Our main data storage vessel.. + RASPIVID_STATE *state; + + MMAL_STATUS_T status = MMAL_SUCCESS; + + /* Default everything to zero */ + state = calloc(1, sizeof(RASPIVID_STATE)); + + /* Apply passed in config */ + state->config = *config; + + /* Initialize timestamping */ + state->base_time = state->last_second = -1; + + /* So far, all we can do is create the camera component. Actual + * config and connection of encoders etc happens in _start() + */ + // OK, we have a nice set of parameters. Now set up our components + // We have three components. Camera, Preview and encoder. + + if ((status = create_camera_component(state)) != MMAL_SUCCESS) + { + vcos_log_error("%s: Failed to create camera component", __func__); + return NULL; + } + + if ((status = raspipreview_create(&state->preview_state, &config->preview_parameters)) != MMAL_SUCCESS) + { + vcos_log_error("%s: Failed to create preview component", __func__); + destroy_camera_component(state); + return NULL; + } + + state->encoded_buffer_q = mmal_queue_create(); + + return state; +} + +gboolean +raspi_capture_start(RASPIVID_STATE *state) +{ + MMAL_STATUS_T status = MMAL_SUCCESS; + RASPIVID_CONFIG *config = &state->config; + + MMAL_PORT_T *camera_preview_port = NULL; + MMAL_PORT_T *preview_input_port = NULL; + MMAL_PORT_T *encoder_input_port = NULL; + + MMAL_POOL_T *pool; + + if ((status = create_encoder_component(state)) != MMAL_SUCCESS) { + vcos_log_error("%s: Failed to create encode component", __func__); + return FALSE; + } + + if (config->verbose) + { + dump_state(state); + } + + state->camera_video_port = state->camera_component->output[MMAL_CAMERA_VIDEO_PORT]; + state->camera_still_port = state->camera_component->output[MMAL_CAMERA_CAPTURE_PORT]; + camera_preview_port = state->camera_component->output[MMAL_CAMERA_PREVIEW_PORT]; + preview_input_port = state->preview_state.preview_component->input[0]; + + if (state->encoder_component) { + encoder_input_port = state->encoder_component->input[0]; + state->encoder_output_port = state->encoder_component->output[0]; + } else { + state->encoder_output_port = state->camera_video_port; + } + + if ((status = raspi_capture_set_format_and_start(state)) != MMAL_SUCCESS) { + return FALSE; + } + + GST_DEBUG ("Creating pool of %d buffers of size %d", + state->encoder_output_port->buffer_num, state->encoder_output_port->buffer_size); + /* Create pool of buffer headers for the output port to consume */ + pool = mmal_port_pool_create(state->encoder_output_port, + state->encoder_output_port->buffer_num, state->encoder_output_port->buffer_size); + if (!pool) + { + vcos_log_error("Failed to create buffer header pool for encoder output port %s", + state->encoder_output_port->name); + return FALSE; + } + state->encoder_pool = pool; + + if (state->config.verbose) + fprintf(stderr, "Starting component connection stage\n"); + + if (config->preview_parameters.wantPreview ) + { + if (config->verbose) + { + fprintf(stderr, "Connecting camera preview port to preview input port\n"); + fprintf(stderr, "Starting video preview\n"); + } + + // Connect camera to preview + status = connect_ports(camera_preview_port, preview_input_port, &state->preview_connection); + if (status != MMAL_SUCCESS) + { + vcos_log_error("%s: Failed to connect camera to preview", __func__); + return FALSE; + } + } + + if (state->encoder_component) { + if (config->verbose) + fprintf(stderr, "Connecting camera video port to encoder input port\n"); + + // Now connect the camera to the encoder + status = connect_ports(state->camera_video_port, encoder_input_port, &state->encoder_connection); + if (status != MMAL_SUCCESS) + { + if (config->preview_parameters.wantPreview ) + mmal_connection_destroy(state->preview_connection); + vcos_log_error("%s: Failed to connect camera video port to encoder input", __func__); + return FALSE; + } + } + + // Set up our userdata - this is passed though to the callback where we need the information. + state->callback_data.state = state; + state->callback_data.abort = 0; + + state->encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&state->callback_data; + + if (config->verbose) + fprintf(stderr, "Enabling encoder output port\n"); + + // Enable the encoder output port and tell it its callback function + status = mmal_port_enable(state->encoder_output_port, encoder_buffer_callback); + if (status != MMAL_SUCCESS) + { + vcos_log_error("Failed to setup encoder output"); + goto error; + } + + if (config->demoMode) + { + // Run for the user specific time.. + int num_iterations = config->timeout / config->demoInterval; + int i; + + if (config->verbose) + fprintf(stderr, "Running in demo mode\n"); + + for (i=0;config->timeout == 0 || icamera_component); + vcos_sleep(state->config.demoInterval); + } + } + + if (config->verbose) + fprintf(stderr, "Starting video capture\n"); + + if (mmal_port_parameter_set_boolean(state->camera_video_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS) + { + goto error; + } + + // Send all the buffers to the encoder output port + { + int num = mmal_queue_length(state->encoder_pool->queue); + int q; + for (q=0;qencoder_pool->queue); + + if (!buffer) + vcos_log_error("Unable to get a required buffer %d from pool queue", q); + + if (mmal_port_send_buffer(state->encoder_output_port, buffer)!= MMAL_SUCCESS) + vcos_log_error("Unable to send a buffer to encoder output port (%d)", q); + + } + } + + // Now wait until we need to stop. Whilst waiting we do need to check to see if we have aborted (for example + // out of storage space) + // Going to check every ABORT_INTERVAL milliseconds + +#if 0 + for (wait = 0; config->timeout == 0 || wait < config->timeout; wait+= ABORT_INTERVAL) + { + vcos_sleep(ABORT_INTERVAL); + if (state->callback_data.abort) + break; + } + + if (config->verbose) + fprintf(stderr, "Finished capture\n"); +#endif + + return (status == MMAL_SUCCESS); + +error: + raspi_capture_stop(state); + + if (status != MMAL_SUCCESS) { + mmal_status_to_int(status); + raspicamcontrol_check_configuration(128); + } + + return FALSE; +} + +void +raspi_capture_stop(RASPIVID_STATE *state) +{ + RASPIVID_CONFIG *config = &state->config; + + if (config->verbose) + fprintf(stderr, "Closing down\n"); + + if (config->preview_parameters.wantPreview ) + mmal_connection_destroy(state->preview_connection); + + // Disable all our ports that are not handled by connections + check_disable_port(state->camera_still_port); + check_disable_port(state->encoder_output_port); + + if (state->encoder_component) { + mmal_connection_destroy(state->encoder_connection); + mmal_component_disable(state->encoder_component); + destroy_encoder_component(state); + } +} + +void +raspi_capture_free(RASPIVID_STATE *state) +{ + RASPIVID_CONFIG *config = &state->config; + + // Can now close our file. Note disabling ports may flush buffers which causes + // problems if we have already closed the file! + if (state->output_file && state->output_file != stdout) + fclose(state->output_file); + + /* Disable components */ + if (state->encoder_component) + mmal_component_disable(state->encoder_component); + + if (state->preview_state.preview_component) + mmal_component_disable(state->preview_state.preview_component); + + if (state->camera_component) + mmal_component_disable(state->camera_component); + + destroy_encoder_component(state); + raspipreview_destroy(&state->preview_state); + destroy_camera_component(state); + + if (state->encoded_buffer_q) { + mmal_queue_destroy(state->encoded_buffer_q); + state->encoded_buffer_q = NULL; + } + + if (config->verbose) + fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n"); + + free(state); +} + +void +raspi_capture_update_config (RASPIVID_STATE *state, RASPIVID_CONFIG *config, gboolean dynamic) +{ + MMAL_STATUS_T status; + RASPICAM_CAMERA_PARAMETERS *params = &config->camera_parameters; + MMAL_COMPONENT_T *camera = state->camera_component; + + /* Store the new config */ + state->config = *config; + if (!dynamic) + return; + + if (state->encoder_component && config->change_flags & PROP_CHANGE_ENCODING) { + /* BITRATE or QUANT or KEY Interval, intra refresh */ + MMAL_COMPONENT_T *encoder = state->encoder_component; + MMAL_PORT_T *encoder_output = encoder->output[0]; + + status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_VIDEO_BIT_RATE, config->bitrate); + if (status != MMAL_SUCCESS) + vcos_log_warn("Unable to change bitrate dynamically"); + + { + MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_INTRAPERIOD, sizeof(param)}, config->intraperiod}; + status = mmal_port_parameter_set(encoder_output, ¶m.hdr); + if (status != MMAL_SUCCESS) + vcos_log_warn("Unable to change intraperiod dynamically"); + } + +#if 0 /* not dynamically change-able */ + { + MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT, sizeof(param)}, config->quantisationParameter}; + status = mmal_port_parameter_set(encoder_output, ¶m.hdr); + if (status != MMAL_SUCCESS) + vcos_log_warn("Unable to change Initial Quantisation Parameter dynamically"); + + MMAL_PARAMETER_UINT32_T param2 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT, sizeof(param)}, config->quantisationParameter}; + status = mmal_port_parameter_set(encoder_output, ¶m2.hdr); + if (status != MMAL_SUCCESS) + vcos_log_warn("Unable to change Minimum Quantisation Parameter dynamically"); + + MMAL_PARAMETER_UINT32_T param3 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT, sizeof(param)}, config->quantisationParameter}; + status = mmal_port_parameter_set(encoder_output, ¶m3.hdr); + if (status != MMAL_SUCCESS) + vcos_log_warn("Unable to change Maximum Quantisation Parameter dynamically"); + } + + { + // Adaptive intra refresh settings + MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T param; + param.hdr.id = MMAL_PARAMETER_VIDEO_INTRA_REFRESH; + param.hdr.size = sizeof(param); + + // Get first so we don't overwrite anything unexpectedly + status = mmal_port_parameter_get(encoder_output, ¶m.hdr); + if (state != MMAL_SUCCESS) { + /* Need to memset, apparently mmal_port_parameter_get() + * doesn't retrieve all parameters, causing random failures + * when we set it. On older firmware the get fails. + */ + memset (¶m, 0, sizeof (MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T)); + } + param.refresh_mode = config->intra_refresh_type; + + status = mmal_port_parameter_set(encoder_output, ¶m.hdr); + if (status != MMAL_SUCCESS) + vcos_log_warn("Unable to set H264 intra-refresh values dynamically"); + } +#endif + } + if (config->change_flags & PROP_CHANGE_PREVIEW) { + /* Preview settings or fullscreen */ + status = raspipreview_update_config (&state->preview_state, + &config->preview_parameters); + if (status != MMAL_SUCCESS) + vcos_log_warn("Unable to change preview config dynamically"); + } + if (config->change_flags & PROP_CHANGE_COLOURBALANCE) { + raspicamcontrol_set_saturation(camera, params->saturation); + raspicamcontrol_set_sharpness(camera, params->sharpness); + raspicamcontrol_set_contrast(camera, params->contrast); + raspicamcontrol_set_brightness(camera, params->brightness); + } + if (config->change_flags & PROP_CHANGE_SENSOR_SETTINGS) { + /* ISO, EXPOSURE, SHUTTER, DRC, Sensor Mode */ + raspicamcontrol_set_ISO(camera, params->ISO); + raspicamcontrol_set_exposure_compensation(camera, params->exposureCompensation); + raspicamcontrol_set_exposure_mode(camera, params->exposureMode); + raspicamcontrol_set_metering_mode(camera, params->exposureMeterMode); + raspicamcontrol_set_shutter_speed(camera, params->shutter_speed); + raspicamcontrol_set_DRC(camera, params->drc_level); + + /* Can we change sensor mode on the fly? Disable if not */ + status = mmal_port_parameter_set_uint32(camera->control, + MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG, config->sensor_mode); + if (status != MMAL_SUCCESS) + vcos_log_warn("Unable to change sensor mode dynamically"); + } + if (config->change_flags & PROP_CHANGE_VIDEO_STABILISATION) { + raspicamcontrol_set_video_stabilisation(camera, params->videoStabilisation); + } + if (config->change_flags & PROP_CHANGE_AWB) { + raspicamcontrol_set_awb_mode(camera, params->awbMode); + raspicamcontrol_set_awb_gains(camera, params->awb_gains_r, params->awb_gains_b); + } + if (config->change_flags & PROP_CHANGE_IMAGE_COLOUR_EFFECT) { + raspicamcontrol_set_imageFX(camera, params->imageEffect); + raspicamcontrol_set_colourFX(camera, ¶ms->colourEffects); + } + if (config->change_flags & PROP_CHANGE_ORIENTATION) { + raspicamcontrol_set_rotation(camera, params->rotation); + raspicamcontrol_set_flips(camera, params->hflip, params->vflip); + } + if (config->change_flags & PROP_CHANGE_ROI) { + raspicamcontrol_set_ROI(camera, params->roi); + } + if (config->change_flags & PROP_CHANGE_ANNOTATION) + update_annotation_data(state); +} +/* *INDENT-ON* */ diff --git a/sys/rpicamsrc/RaspiCapture.h b/sys/rpicamsrc/RaspiCapture.h new file mode 100644 index 0000000000..20e052cd3e --- /dev/null +++ b/sys/rpicamsrc/RaspiCapture.h @@ -0,0 +1,144 @@ +/* + * GStreamer + * Copyright (C) 2013-2015 Jan Schmidt + * + * 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 __RASPICAPTURE_H__ +#define __RASPICAPTURE_H__ + +#include +#include + +#include "interface/mmal/mmal_common.h" +#include "interface/mmal/mmal_types.h" +#include "interface/mmal/mmal_parameters_camera.h" +#include "interface/mmal/mmal_component.h" +#include "RaspiCamControl.h" +#include "RaspiPreview.h" + +#define RPICAMSRC_MAX_FPS 1000 + +GST_DEBUG_CATEGORY_EXTERN (gst_rpi_cam_src_debug); +#define GST_CAT_DEFAULT gst_rpi_cam_src_debug + +#undef fprintf +#define fprintf(f,...) GST_LOG(__VA_ARGS__) +#undef vcos_log_error +#define vcos_log_error GST_ERROR +#undef vcos_log_warn +#define vcos_log_warn GST_WARNING + +#define GST_FLOW_ERROR_TIMEOUT GST_FLOW_CUSTOM_ERROR +#define GST_FLOW_KEEP_ACCUMULATING GST_FLOW_CUSTOM_SUCCESS + +G_BEGIN_DECLS + +typedef enum +{ + PROP_CHANGE_ENCODING = (1 << 0), /* BITRATE or QUANT or KEY Interval, intra refresh */ + PROP_CHANGE_PREVIEW = (1 << 1), /* Preview opacity or fullscreen */ + PROP_CHANGE_COLOURBALANCE = (1 << 2), + PROP_CHANGE_SENSOR_SETTINGS = (1 << 3), /* ISO, EXPOSURE, SHUTTER, DRC, Sensor Mode */ + PROP_CHANGE_VIDEO_STABILISATION = (1 << 4), + PROP_CHANGE_AWB = (1 << 5), + PROP_CHANGE_IMAGE_COLOUR_EFFECT = (1 << 6), + PROP_CHANGE_ORIENTATION = (1 << 7), + PROP_CHANGE_ROI = (1 << 8), + PROP_CHANGE_ANNOTATION = (1 << 9) +} RpiPropChangeFlags; + +/** Structure containing all state information for the current run + */ +typedef struct +{ + RpiPropChangeFlags change_flags; + + int verbose; /// !0 if want detailed run information + + int timeout; /// Time taken before frame is grabbed and app then shuts down. Units are milliseconds + int width; /// Requested width of image + int height; /// requested height of image + int bitrate; /// Requested bitrate + int fps_n; /// Requested frame rate (fps) numerator + int fps_d; /// Requested frame rate (fps) denominator + int intraperiod; /// Intra-refresh period (key frame rate) + int quantisationParameter; /// Quantisation parameter - quality. Set bitrate 0 and set this for variable bitrate + int bInlineHeaders; /// Insert inline headers to stream (SPS, PPS) + int demoMode; /// Run app in demo mode + int demoInterval; /// Interval between camera settings changes + int immutableInput; /// Flag to specify whether encoder works in place or creates a new buffer. Result is preview can display either + /// the camera output or the encoder output (with compression artifacts) + int profile; /// H264 profile to use for encoding + RASPIPREVIEW_PARAMETERS preview_parameters; /// Preview setup parameters + RASPICAM_CAMERA_PARAMETERS camera_parameters; /// Camera setup parameters + + int inlineMotionVectors; /// Encoder outputs inline Motion Vectors + + int cameraNum; /// Camera number + int settings; /// Request settings from the camera + int sensor_mode; /// Sensor mode. 0=auto. Check docs/forum for modes selected by other values. + int intra_refresh_type; /// What intra refresh type to use. -1 to not set. + + MMAL_FOURCC_T encoding; // Which encoding to use + + int jpegQuality; + int jpegRestartInterval; + + int useSTC; +} RASPIVID_CONFIG; + +typedef struct RASPIVID_STATE_T RASPIVID_STATE; + +void raspicapture_init(void); +void raspicapture_default_config(RASPIVID_CONFIG *config); +RASPIVID_STATE *raspi_capture_setup(RASPIVID_CONFIG *config); +gboolean raspi_capture_start(RASPIVID_STATE *state); +void raspi_capture_update_config (RASPIVID_STATE *state, + RASPIVID_CONFIG *config, gboolean dynamic); +GstFlowReturn raspi_capture_fill_buffer(RASPIVID_STATE *state, GstBuffer **buf, + GstClock *clock, GstClockTime base_time); +void raspi_capture_stop(RASPIVID_STATE *state); +void raspi_capture_free(RASPIVID_STATE *state); +gboolean raspi_capture_request_i_frame(RASPIVID_STATE *state); + +G_END_DECLS + +#endif diff --git a/sys/rpicamsrc/RaspiPreview.c b/sys/rpicamsrc/RaspiPreview.c new file mode 100644 index 0000000000..5db9f1ac31 --- /dev/null +++ b/sys/rpicamsrc/RaspiPreview.c @@ -0,0 +1,309 @@ +/* *INDENT-OFF* */ +/* + * Copyright (c) 2013-2015 Jan Schmidt +Portions: +Copyright (c) 2013, Broadcom Europe Ltd +Copyright (c) 2013, James Hughes +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include + +#include "interface/vcos/vcos.h" + +#include "interface/mmal/mmal.h" +#include "interface/mmal/mmal_logging.h" +#include "interface/mmal/mmal_buffer.h" +#include "interface/mmal/util/mmal_util.h" +#include "interface/mmal/util/mmal_util_params.h" +#include "interface/mmal/util/mmal_default_components.h" +#include "interface/mmal/util/mmal_connection.h" + +#include "RaspiPreview.h" +#include "RaspiCapture.h" + +#if 0 +#define CommandPreview 1 +#define CommandFullScreen 2 +#define CommandOpacity 3 +#define CommandDisablePreview 4 + +static COMMAND_LIST cmdline_commands[] = +{ + { CommandPreview, "-preview", "p", "Preview window settings <'x,y,w,h'>", 1 }, + { CommandFullScreen, "-fullscreen", "f", "Fullscreen preview mode", 0 }, + { CommandOpacity, "-opacity", "op", "Preview window opacity (0-255)", 1}, + { CommandDisablePreview,"-nopreview", "n", "Do not display a preview window", 0}, +}; + +static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]); +#endif + +/** + * Create the preview component, set up its ports + * + * @param state Pointer to state control struct + * + * @return MMAL_SUCCESS if all OK, something else otherwise + * + */ +MMAL_STATUS_T raspipreview_create(RASPIPREVIEW_STATE *state, + RASPIPREVIEW_PARAMETERS *config) +{ + MMAL_COMPONENT_T *preview = 0; + MMAL_STATUS_T status; + + state->havePreview = config->wantPreview; + + if (!config->wantPreview) + { + // No preview required, so create a null sink component to take its place + status = mmal_component_create("vc.null_sink", &preview); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("Unable to create null sink component"); + goto error; + } + + state->preview_component = preview; + } + else + { + status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, + &preview); + if (status != MMAL_SUCCESS) + { + vcos_log_error("Unable to create preview component"); + goto error; + } + + if (!preview->input_num) + { + status = MMAL_ENOSYS; + vcos_log_error("No input ports found on component"); + goto error; + } + + state->preview_component = preview; + + raspipreview_update_config (state, config); + if (status != MMAL_SUCCESS && status != MMAL_ENOSYS) + { + vcos_log_error("unable to set preview port parameters (%u)", status); + goto error; + } + } + + /* Enable component */ + status = mmal_component_enable(preview); + if (status != MMAL_SUCCESS) + { + vcos_log_error("Unable to enable preview/null sink component (%u)", status); + goto error; + } + + return status; + +error: + if (preview) { + mmal_component_destroy(preview); + state->preview_component = NULL; + } + + return status; +} + +MMAL_STATUS_T +raspipreview_update_config (RASPIPREVIEW_STATE *state, + RASPIPREVIEW_PARAMETERS *config) +{ + MMAL_COMPONENT_T *preview = state->preview_component; + MMAL_PORT_T *preview_port = NULL; + MMAL_DISPLAYREGION_T param; + MMAL_STATUS_T status; + + /* Can't update props on the null preview component */ + if (state->havePreview == 0) + return MMAL_SUCCESS; + + preview_port = preview->input[0]; + + param.hdr.id = MMAL_PARAMETER_DISPLAYREGION; + param.hdr.size = sizeof(MMAL_DISPLAYREGION_T); + + param.set = MMAL_DISPLAY_SET_LAYER; + param.layer = PREVIEW_LAYER; + + param.set |= MMAL_DISPLAY_SET_ALPHA; + param.alpha = config->opacity; + + if (config->wantFullScreenPreview) + { + param.set |= MMAL_DISPLAY_SET_FULLSCREEN; + param.fullscreen = 1; + } + else + { + param.set |= (MMAL_DISPLAY_SET_DEST_RECT | MMAL_DISPLAY_SET_FULLSCREEN); + param.fullscreen = 0; + param.dest_rect = config->previewWindow; + } + + status = mmal_port_parameter_set(preview_port, ¶m.hdr); + if (status == MMAL_ENOSYS) + status = MMAL_SUCCESS; + + return status; +} + +/** + * Destroy the preview component + * + * @param state Pointer to state control struct + * + */ +void raspipreview_destroy(RASPIPREVIEW_STATE *state) +{ + if (state->preview_component) + { + mmal_component_destroy(state->preview_component); + state->preview_component = NULL; + } +} + +/** + * Assign set of default parameters to the passed in parameter block + * + * @param state Pointer to parameter block + * + */ +void raspipreview_set_defaults(RASPIPREVIEW_PARAMETERS *config) +{ + config->wantPreview = 1; + config->wantFullScreenPreview = 1; + config->opacity = 255; + config->previewWindow.x = 0; + config->previewWindow.y = 0; + config->previewWindow.width = 1024; + config->previewWindow.height = 768; +} + +/** + * Dump parameters as human readable to stdout + * + * @param state Pointer to parameter block + * + */ +void raspipreview_dump_parameters(RASPIPREVIEW_PARAMETERS *config) +{ + fprintf(stderr, "Preview %s, Full screen %s\n", config->wantPreview ? "Yes" : "No", + config->wantFullScreenPreview ? "Yes" : "No"); + + fprintf(stderr, "Preview window %d,%d,%d,%d\nOpacity %d\n", config->previewWindow.x, + config->previewWindow.y, config->previewWindow.width, + config->previewWindow.height, config->opacity); +}; + +#if 0 +/** + * Parse a possible command pair - command and parameter + * @param arg1 Command + * @param arg2 Parameter (could be NULL) + * @return How many parameters were used, 0,1,2 + */ +int raspipreview_parse_cmdline(RASPIPREVIEW_PARAMETERS *params, const char *arg1, const char *arg2) +{ + int command_id, used = 0, num_parameters; + + if (!arg1) + return 0; + + command_id = raspicli_get_command_id(cmdline_commands, cmdline_commands_size, arg1, &num_parameters); + + // If invalid command, or we are missing a parameter, drop out + if (command_id==-1 || (command_id != -1 && num_parameters > 0 && arg2 == NULL)) + return 0; + + switch (command_id) + { + case CommandPreview: // Preview window + { + int tmp; + + params->wantPreview = 1; + + tmp = sscanf(arg2, "%d,%d,%d,%d", + ¶ms->previewWindow.x, ¶ms->previewWindow.y, + ¶ms->previewWindow.width, ¶ms->previewWindow.height); + + // Failed to get any window parameters, so revert to full screen + if (tmp == 0) + params->wantFullScreenPreview = 1; + else + params->wantFullScreenPreview = 0; + + used = 2; + + break; + } + + case CommandFullScreen: // Want full screen preview mode (overrides display rect) + params->wantPreview = 1; + params->wantFullScreenPreview = 1; + + used = 1; + break; + + case CommandOpacity: // Define preview window opacity + if (sscanf(arg2, "%u", ¶ms->opacity) != 1) + params->opacity = 255; + else + used = 2; + break; + + case CommandDisablePreview: // Turn off preview output + params->wantPreview = 0; + used = 1; + break; + } + + return used; +} + +/** + * Display help for command line options + */ +void raspipreview_display_help() +{ + fprintf(stderr, "\nPreview parameter commands\n\n"); + raspicli_display_help(cmdline_commands, cmdline_commands_size); +} +#endif +/* *INDENT-ON* */ diff --git a/sys/rpicamsrc/RaspiPreview.h b/sys/rpicamsrc/RaspiPreview.h new file mode 100644 index 0000000000..f5e14daf4e --- /dev/null +++ b/sys/rpicamsrc/RaspiPreview.h @@ -0,0 +1,75 @@ +/* +Copyright (c) 2013, Broadcom Europe Ltd +Copyright (c) 2013, James Hughes +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef RASPIPREVIEW_H_ +#define RASPIPREVIEW_H_ + +/// Layer that preview window should be displayed on +#define PREVIEW_LAYER 2 + +// Frames rates of 0 implies variable, but denominator needs to be 1 to prevent div by 0 +#define PREVIEW_FRAME_RATE_NUM 0 +#define PREVIEW_FRAME_RATE_DEN 1 + +#define FULL_RES_PREVIEW_FRAME_RATE_NUM 0 +#define FULL_RES_PREVIEW_FRAME_RATE_DEN 1 + +#define FULL_FOV_PREVIEW_16x9_X 1280 +#define FULL_FOV_PREVIEW_16x9_Y 720 + +#define FULL_FOV_PREVIEW_4x3_X 1296 +#define FULL_FOV_PREVIEW_4x3_Y 972 + +#define FULL_FOV_PREVIEW_FRAME_RATE_NUM 0 +#define FULL_FOV_PREVIEW_FRAME_RATE_DEN 1 + +typedef struct +{ + MMAL_COMPONENT_T *preview_component; /// Pointer to the created preview display component + int havePreview; /// component is preview, else null sink +} RASPIPREVIEW_STATE; + +typedef struct +{ + int wantPreview; /// Display a preview + int wantFullScreenPreview; /// 0 is use previewRect, non-zero to use full screen + int opacity; /// Opacity of window - 0 = transparent, 255 = opaque + MMAL_RECT_T previewWindow; /// Destination rectangle for the preview window. +} RASPIPREVIEW_PARAMETERS; + +MMAL_STATUS_T raspipreview_create(RASPIPREVIEW_STATE *state, + RASPIPREVIEW_PARAMETERS *config); +void raspipreview_destroy(RASPIPREVIEW_STATE *state); +void raspipreview_set_defaults(RASPIPREVIEW_PARAMETERS *config); +void raspipreview_dump_parameters(RASPIPREVIEW_PARAMETERS *config); +int raspipreview_parse_cmdline(RASPIPREVIEW_PARAMETERS *config, const char *arg1, const char *arg2); +void raspipreview_display_help(); +MMAL_STATUS_T raspipreview_update_config (RASPIPREVIEW_STATE *state, + RASPIPREVIEW_PARAMETERS *config); + +#endif /* RASPIPREVIEW_H_ */ diff --git a/sys/rpicamsrc/RaspiStill.c b/sys/rpicamsrc/RaspiStill.c new file mode 100644 index 0000000000..dc7474a11b --- /dev/null +++ b/sys/rpicamsrc/RaspiStill.c @@ -0,0 +1,1517 @@ +/* *INDENT-OFF* */ +/* + * Copyright (c) 2013 Jan Schmidt +Portions: +Copyright (c) 2013, Broadcom Europe Ltd +Copyright (c) 2013, James Hughes +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * \file RaspiStill.c + * Command line program to capture a still frame and encode it to file. + * Also optionally display a preview/viewfinder of current camera input. + * + * \date 31 Jan 2013 + * \Author: James Hughes + * + * Description + * + * 3 components are created; camera, preview and JPG encoder. + * Camera component has three ports, preview, video and stills. + * This program connects preview and stills to the preview and jpg + * encoder. Using mmal we don't need to worry about buffers between these + * components, but we do need to handle buffers from the encoder, which + * are simply written straight to the file in the requisite buffer callback. + * + * We use the RaspiCamControl code to handle the specific camera settings. + */ + +// We use some GNU extensions (asprintf, basename) +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include + +#define VERSION_STRING "v1.3.2" + +#include "bcm_host.h" +#include "interface/vcos/vcos.h" + +#include "interface/mmal/mmal.h" +#include "interface/mmal/mmal_logging.h" +#include "interface/mmal/mmal_buffer.h" +#include "interface/mmal/util/mmal_util.h" +#include "interface/mmal/util/mmal_util_params.h" +#include "interface/mmal/util/mmal_default_components.h" +#include "interface/mmal/util/mmal_connection.h" + + +#include "RaspiCamControl.h" +#include "RaspiPreview.h" +#include "RaspiCLI.h" + +#include + +/// Camera number to use - we only have one camera, indexed from 0. +#define CAMERA_NUMBER 0 + +// Standard port setting for the camera component +#define MMAL_CAMERA_PREVIEW_PORT 0 +#define MMAL_CAMERA_VIDEO_PORT 1 +#define MMAL_CAMERA_CAPTURE_PORT 2 + + +// Stills format information +#define STILLS_FRAME_RATE_NUM 15 +#define STILLS_FRAME_RATE_DEN 1 + +/// Video render needs at least 2 buffers. +#define VIDEO_OUTPUT_BUFFERS_NUM 3 + +#define MAX_USER_EXIF_TAGS 32 +#define MAX_EXIF_PAYLOAD_LENGTH 128 + +int mmal_status_to_int(MMAL_STATUS_T status); + +/** Structure containing all state information for the current run + */ +typedef struct +{ + int timeout; /// Time taken before frame is grabbed and app then shuts down. Units are milliseconds + int width; /// Requested width of image + int height; /// requested height of image + int quality; /// JPEG quality setting (1-100) + int wantRAW; /// Flag for whether the JPEG metadata also contains the RAW bayer image + char *filename; /// filename of output file + char *linkname; /// filename of output file + MMAL_PARAM_THUMBNAIL_CONFIG_T thumbnailConfig; + int verbose; /// !0 if want detailed run information + int demoMode; /// Run app in demo mode + int demoInterval; /// Interval between camera settings changes + MMAL_FOURCC_T encoding; /// Encoding to use for the output file. + const char *exifTags[MAX_USER_EXIF_TAGS]; /// Array of pointers to tags supplied from the command line + int numExifTags; /// Number of supplied tags + int timelapse; /// Delay between each picture in timelapse mode. If 0, disable timelapse + int fullResPreview; /// If set, the camera preview port runs at capture resolution. Reduces fps. + + RASPIPREVIEW_PARAMETERS preview_parameters; /// Preview setup parameters + RASPICAM_CAMERA_PARAMETERS camera_parameters; /// Camera setup parameters + + MMAL_COMPONENT_T *camera_component; /// Pointer to the camera component + MMAL_COMPONENT_T *encoder_component; /// Pointer to the encoder component + MMAL_COMPONENT_T *null_sink_component; /// Pointer to the null sink component + MMAL_CONNECTION_T *preview_connection; /// Pointer to the connection from camera to preview + MMAL_CONNECTION_T *encoder_connection; /// Pointer to the connection from camera to encoder + + MMAL_POOL_T *encoder_pool; /// Pointer to the pool of buffers used by encoder output port + +} RASPISTILL_STATE; + +/** Struct used to pass information in encoder port userdata to callback + */ +typedef struct +{ + FILE *file_handle; /// File handle to write buffer data to. + VCOS_SEMAPHORE_T complete_semaphore; /// semaphore which is posted when we reach end of frame (indicates end of capture or fault) + RASPISTILL_STATE *pstate; /// pointer to our state in case required in callback +} PORT_USERDATA; + +static void display_valid_parameters(char *app_name); +static void store_exif_tag(RASPISTILL_STATE *state, const char *exif_tag); + +/// Comamnd ID's and Structure defining our command line options +#define CommandHelp 0 +#define CommandWidth 1 +#define CommandHeight 2 +#define CommandQuality 3 +#define CommandRaw 4 +#define CommandOutput 5 +#define CommandVerbose 6 +#define CommandTimeout 7 +#define CommandThumbnail 8 +#define CommandDemoMode 9 +#define CommandEncoding 10 +#define CommandExifTag 11 +#define CommandTimelapse 12 +#define CommandFullResPreview 13 +#define CommandLink 14 + +static COMMAND_LIST cmdline_commands[] = +{ + { CommandHelp, "-help", "?", "This help information", 0 }, + { CommandWidth, "-width", "w", "Set image width ", 1 }, + { CommandHeight, "-height", "h", "Set image height ", 1 }, + { CommandQuality, "-quality", "q", "Set jpeg quality <0 to 100>", 1 }, + { CommandRaw, "-raw", "r", "Add raw bayer data to jpeg metadata", 0 }, + { CommandOutput, "-output", "o", "Output filename (to write to stdout, use '-o -'). If not specified, no file is saved", 1 }, + { CommandLink, "-latest", "l", "Link latest complete image to filename ", 1}, + { CommandVerbose, "-verbose", "v", "Output verbose information during run", 0 }, + { CommandTimeout, "-timeout", "t", "Time (in ms) before takes picture and shuts down (if not specified, set to 5s)", 1 }, + { CommandThumbnail,"-thumb", "th", "Set thumbnail parameters (x:y:quality)", 1}, + { CommandDemoMode,"-demo", "d", "Run a demo mode (cycle through range of camera options, no capture)", 0}, + { CommandEncoding,"-encoding", "e", "Encoding to use for output file (jpg, bmp, gif, png)", 1}, + { CommandExifTag, "-exif", "x", "EXIF tag to apply to captures (format as 'key=value')", 1}, + { CommandTimelapse,"-timelapse", "tl", "Timelapse mode. Takes a picture every ms", 1}, + { CommandFullResPreview,"-fullpreview", "fp", "Run the preview using the still capture resolution (may reduce preview fps)", 0}, +}; + +static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]); + +static struct +{ + char *format; + MMAL_FOURCC_T encoding; +} encoding_xref[] = +{ + {"jpg", MMAL_ENCODING_JPEG}, + {"bmp", MMAL_ENCODING_BMP}, + {"gif", MMAL_ENCODING_GIF}, + {"png", MMAL_ENCODING_PNG} +}; + +static int encoding_xref_size = sizeof(encoding_xref) / sizeof(encoding_xref[0]); + + +/** + * Assign a default set of parameters to the state passed in + * + * @param state Pointer to state structure to assign defaults to + */ +static void default_status(RASPISTILL_STATE *state) +{ + if (!state) + { + vcos_assert(0); + return; + } + + state->timeout = 5000; // 5s delay before take image + state->width = 2592; + state->height = 1944; + state->quality = 85; + state->wantRAW = 0; + state->filename = NULL; + state->linkname = NULL; + state->verbose = 0; + state->thumbnailConfig.enable = 1; + state->thumbnailConfig.width = 64; + state->thumbnailConfig.height = 48; + state->thumbnailConfig.quality = 35; + state->demoMode = 0; + state->demoInterval = 250; // ms + state->camera_component = NULL; + state->encoder_component = NULL; + state->preview_connection = NULL; + state->encoder_connection = NULL; + state->encoder_pool = NULL; + state->encoding = MMAL_ENCODING_JPEG; + state->numExifTags = 0; + state->timelapse = 0; + state->fullResPreview = 0; + + // Setup preview window defaults + raspipreview_set_defaults(&state->preview_parameters); + + // Set up the camera_parameters to default + raspicamcontrol_set_defaults(&state->camera_parameters); +} + +/** + * Dump image state parameters to stderr. Used for debugging + * + * @param state Pointer to state structure to assign defaults to + */ +static void dump_status(RASPISTILL_STATE *state) +{ + int i; + + if (!state) + { + vcos_assert(0); + return; + } + + fprintf(stderr, "Width %d, Height %d, quality %d, filename %s\n", state->width, + state->height, state->quality, state->filename); + fprintf(stderr, "Time delay %d, Raw %s\n", state->timeout, + state->wantRAW ? "yes" : "no"); + fprintf(stderr, "Thumbnail enabled %s, width %d, height %d, quality %d\n", + state->thumbnailConfig.enable ? "Yes":"No", state->thumbnailConfig.width, + state->thumbnailConfig.height, state->thumbnailConfig.quality); + fprintf(stderr, "Link to latest frame enabled "); + if (state->linkname) + { + fprintf(stderr, " yes, -> %s\n", state->linkname); + } + else + { + fprintf(stderr, " no\n"); + } + fprintf(stderr, "Full resolution preview %s\n\n", state->fullResPreview ? "Yes": "No"); + + if (state->numExifTags) + { + fprintf(stderr, "User supplied EXIF tags :\n"); + + for (i=0;inumExifTags;i++) + { + fprintf(stderr, "%s", state->exifTags[i]); + if (i != state->numExifTags-1) + fprintf(stderr, ","); + } + fprintf(stderr, "\n\n"); + } + + raspipreview_dump_parameters(&state->preview_parameters); + //raspicamcontrol_dump_parameters(&state->camera_parameters); +} + +/** + * Parse the incoming command line and put resulting parameters in to the state + * + * @param argc Number of arguments in command line + * @param argv Array of pointers to strings from command line + * @param state Pointer to state structure to assign any discovered parameters to + * @return non-0 if failed for some reason, 0 otherwise + */ +static int parse_cmdline(int argc, const char **argv, RASPISTILL_STATE *state) +{ + // Parse the command line arguments. + // We are looking for -- or - + + int valid = 1; + int i; + + for (i = 1; i < argc && valid; i++) + { + int command_id, num_parameters; + + if (!argv[i]) + continue; + + if (argv[i][0] != '-') + { + valid = 0; + continue; + } + + // Assume parameter is valid until proven otherwise + valid = 1; + + command_id = raspicli_get_command_id(cmdline_commands, cmdline_commands_size, &argv[i][1], &num_parameters); + + // If we found a command but are missing a parameter, continue (and we will drop out of the loop) + if (command_id != -1 && num_parameters > 0 && (i + 1 >= argc) ) + continue; + + // We are now dealing with a command line option + switch (command_id) + { + case CommandHelp: + display_valid_parameters(basename(argv[0])); + // exit straight away if help requested + return -1; + + case CommandWidth: // Width > 0 + if (sscanf(argv[i + 1], "%u", &state->width) != 1) + valid = 0; + else + i++; + break; + + case CommandHeight: // Height > 0 + if (sscanf(argv[i + 1], "%u", &state->height) != 1) + valid = 0; + else + i++; + break; + + case CommandQuality: // Quality = 1-100 + if (sscanf(argv[i + 1], "%u", &state->quality) == 1) + { + if (state->quality > 100) + { + fprintf(stderr, "Setting max quality = 100\n"); + state->quality = 100; + } + i++; + } + else + valid = 0; + + break; + + case CommandRaw: // Add raw bayer data in metadata + state->wantRAW = 1; + break; + + case CommandOutput: // output filename + { + int len = strlen(argv[i + 1]); + if (len) + { + state->filename = malloc(len + 10); // leave enough space for any timelapse generated changes to filename + vcos_assert(state->filename); + if (state->filename) + strncpy(state->filename, argv[i + 1], len); + i++; + } + else + valid = 0; + break; + } + + case CommandLink : + { + int len = strlen(argv[i+1]); + if (len) + { + state->linkname = malloc(len + 10); + vcos_assert(state->linkname); + if (state->linkname) + strncpy(state->linkname, argv[i + 1], len); + i++; + } + else + valid = 0; + break; + + } + case CommandVerbose: // display lots of data during run + state->verbose = 1; + break; + + case CommandTimeout: // Time to run viewfinder for before taking picture, in seconds + { + if (sscanf(argv[i + 1], "%u", &state->timeout) == 1) + { + // TODO : What limits do we need for timeout? + i++; + } + else + valid = 0; + break; + } + case CommandThumbnail : // thumbnail parameters - needs string "x:y:quality" + sscanf(argv[i + 1], "%d:%d:%d", &state->thumbnailConfig.width,&state->thumbnailConfig.height, + &state->thumbnailConfig.quality); + i++; + break; + + case CommandDemoMode: // Run in demo mode - no capture + { + // Demo mode might have a timing parameter + // so check if a) we have another parameter, b) its not the start of the next option + if (i + 1 < argc && argv[i+1][0] != '-') + { + if (sscanf(argv[i + 1], "%u", &state->demoInterval) == 1) + { + // TODO : What limits do we need for timeout? + state->demoMode = 1; + i++; + } + else + valid = 0; + } + else + { + state->demoMode = 1; + } + + break; + } + + case CommandEncoding : + { + int len = strlen(argv[i + 1]); + valid = 0; + + if (len) + { + int j; + for (j=0;jencoding = encoding_xref[j].encoding; + valid = 1; + i++; + break; + } + } + } + break; + } + + case CommandExifTag: + store_exif_tag(state, argv[i+1]); + i++; + break; + + case CommandTimelapse: + if (sscanf(argv[i + 1], "%u", &state->timelapse) != 1) + valid = 0; + else + i++; + break; + + case CommandFullResPreview: + state->fullResPreview = 1; + break; + + default: + { + // Try parsing for any image specific parameters + // result indicates how many parameters were used up, 0,1,2 + // but we adjust by -1 as we have used one already + const char *second_arg = (i + 1 < argc) ? argv[i + 1] : NULL; + int parms_used = raspicamcontrol_parse_cmdline(&state->camera_parameters, &argv[i][1], second_arg); + + // Still unused, try preview options + if (!parms_used) + parms_used = raspipreview_parse_cmdline(&state->preview_parameters, &argv[i][1], second_arg); + + // If no parms were used, this must be a bad parameters + if (!parms_used) + valid = 0; + else + i += parms_used - 1; + + break; + } + } + } + + if (!valid) + { + fprintf(stderr, "Invalid command line option (%s)\n", argv[i]); + return 1; + } + + return 0; +} + +/** + * Display usage information for the application to stdout + * + * @param app_name String to display as the application name + */ +static void display_valid_parameters(char *app_name) +{ + fprintf(stderr, "Runs camera for specific time, and take JPG capture at end if requested\n\n"); + fprintf(stderr, "usage: %s [options]\n\n", app_name); + + fprintf(stderr, "Image parameter commands\n\n"); + + raspicli_display_help(cmdline_commands, cmdline_commands_size); + + // Help for preview options + raspipreview_display_help(); + + // Now display any help information from the camcontrol code + raspicamcontrol_display_help(); + + fprintf(stderr, "\n"); + + return; +} + +/** + * buffer header callback function for camera control + * + * No actions taken in current version + * + * @param port Pointer to port from which callback originated + * @param buffer mmal buffer header pointer + */ +static void camera_control_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) +{ + if (buffer->cmd == MMAL_EVENT_PARAMETER_CHANGED) + { + } + else + { + vcos_log_error("Received unexpected camera control callback event, 0x%08x", buffer->cmd); + } + + mmal_buffer_header_release(buffer); +} + +/** + * buffer header callback function for encoder + * + * Callback will dump buffer data to the specific file + * + * @param port Pointer to port from which callback originated + * @param buffer mmal buffer header pointer + */ +static void encoder_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) +{ + int complete = 0; + + // We pass our file handle and other stuff in via the userdata field. + + PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata; + + if (pData) + { + int bytes_written = buffer->length; + + if (buffer->length && pData->file_handle) + { + mmal_buffer_header_mem_lock(buffer); + + bytes_written = fwrite(buffer->data, 1, buffer->length, pData->file_handle); + + mmal_buffer_header_mem_unlock(buffer); + } + + // We need to check we wrote what we wanted - it's possible we have run out of storage. + if (bytes_written != buffer->length) + { + vcos_log_error("Unable to write buffer to file - aborting"); + complete = 1; + } + + // Now flag if we have completed + if (buffer->flags & (MMAL_BUFFER_HEADER_FLAG_FRAME_END | MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED)) + complete = 1; + } + else + { + vcos_log_error("Received a encoder buffer callback with no state"); + } + + // release buffer back to the pool + mmal_buffer_header_release(buffer); + + // and send one back to the port (if still open) + if (port->is_enabled) + { + MMAL_STATUS_T status = MMAL_SUCCESS; + MMAL_BUFFER_HEADER_T *new_buffer; + + new_buffer = mmal_queue_get(pData->pstate->encoder_pool->queue); + + if (new_buffer) + { + status = mmal_port_send_buffer(port, new_buffer); + } + if (!new_buffer || status != MMAL_SUCCESS) + vcos_log_error("Unable to return a buffer to the encoder port"); + } + + if (complete) + vcos_semaphore_post(&(pData->complete_semaphore)); + +} + + +/** + * Create the camera component, set up its ports + * + * @param state Pointer to state control struct. camera_component member set to the created camera_component if successfull. + * + * @return MMAL_SUCCESS if all OK, something else otherwise + * + */ +static MMAL_STATUS_T create_camera_component(RASPISTILL_STATE *state) +{ + MMAL_COMPONENT_T *camera = 0; + MMAL_ES_FORMAT_T *format; + MMAL_PORT_T *preview_port = NULL, *video_port = NULL, *still_port = NULL; + MMAL_STATUS_T status; + + /* Create the component */ + status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("Failed to create camera component"); + goto error; + } + + if (!camera->output_num) + { + status = MMAL_ENOSYS; + vcos_log_error("Camera doesn't have output ports"); + goto error; + } + + preview_port = camera->output[MMAL_CAMERA_PREVIEW_PORT]; + video_port = camera->output[MMAL_CAMERA_VIDEO_PORT]; + still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT]; + + // Enable the camera, and tell it its control callback function + status = mmal_port_enable(camera->control, camera_control_callback); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("Unable to enable control port : error %d", status); + goto error; + } + + // set up the camera configuration + { + MMAL_PARAMETER_CAMERA_CONFIG_T cam_config = + { + { MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) }, + .max_stills_w = state->width, + .max_stills_h = state->height, + .stills_yuv422 = 0, + .one_shot_stills = 1, + .max_preview_video_w = state->preview_parameters.previewWindow.width, + .max_preview_video_h = state->preview_parameters.previewWindow.height, + .num_preview_video_frames = 3, + .stills_capture_circular_buffer_height = 0, + .fast_preview_resume = 0, + .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RESET_STC + }; + + if (state->fullResPreview) + { + cam_config.max_preview_video_w = state->width; + cam_config.max_preview_video_h = state->height; + } + + mmal_port_parameter_set(camera->control, &cam_config.hdr); + } + + raspicamcontrol_set_all_parameters(camera, &state->camera_parameters); + + // Now set up the port formats + + format = preview_port->format; + + format->encoding = MMAL_ENCODING_OPAQUE; + format->encoding_variant = MMAL_ENCODING_I420; + + if (state->fullResPreview) + { + // In this mode we are forcing the preview to be generated from the full capture resolution. + // This runs at a max of 15fps with the OV5647 sensor. + format->es->video.width = state->width; + format->es->video.height = state->height; + format->es->video.crop.x = 0; + format->es->video.crop.y = 0; + format->es->video.crop.width = state->width; + format->es->video.crop.height = state->height; + format->es->video.frame_rate.num = FULL_RES_PREVIEW_FRAME_RATE_NUM; + format->es->video.frame_rate.den = FULL_RES_PREVIEW_FRAME_RATE_DEN; + } + else + { + // use our normal preview mode - probably 1080p30 + format->es->video.width = state->preview_parameters.previewWindow.width; + format->es->video.height = state->preview_parameters.previewWindow.height; + format->es->video.crop.x = 0; + format->es->video.crop.y = 0; + format->es->video.crop.width = state->preview_parameters.previewWindow.width; + format->es->video.crop.height = state->preview_parameters.previewWindow.height; + format->es->video.frame_rate.num = PREVIEW_FRAME_RATE_NUM; + format->es->video.frame_rate.den = PREVIEW_FRAME_RATE_DEN; + } + + status = mmal_port_format_commit(preview_port); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("camera viewfinder format couldn't be set"); + goto error; + } + + // Set the same format on the video port (which we dont use here) + mmal_format_full_copy(video_port->format, format); + status = mmal_port_format_commit(video_port); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("camera video format couldn't be set"); + goto error; + } + + // Ensure there are enough buffers to avoid dropping frames + if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM) + video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM; + + format = still_port->format; + + // Set our stills format on the stills (for encoder) port + format->encoding = MMAL_ENCODING_OPAQUE; + format->es->video.width = state->width; + format->es->video.height = state->height; + format->es->video.crop.x = 0; + format->es->video.crop.y = 0; + format->es->video.crop.width = state->width; + format->es->video.crop.height = state->height; + format->es->video.frame_rate.num = STILLS_FRAME_RATE_NUM; + format->es->video.frame_rate.den = STILLS_FRAME_RATE_DEN; + + + status = mmal_port_format_commit(still_port); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("camera still format couldn't be set"); + goto error; + } + + /* Ensure there are enough buffers to avoid dropping frames */ + if (still_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM) + still_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM; + + /* Enable component */ + status = mmal_component_enable(camera); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("camera component couldn't be enabled"); + goto error; + } + + state->camera_component = camera; + + if (state->verbose) + fprintf(stderr, "Camera component done\n"); + + return status; + +error: + + if (camera) + mmal_component_destroy(camera); + + return status; +} + +/** + * Destroy the camera component + * + * @param state Pointer to state control struct + * + */ +static void destroy_camera_component(RASPISTILL_STATE *state) +{ + if (state->camera_component) + { + mmal_component_destroy(state->camera_component); + state->camera_component = NULL; + } +} + + + +/** + * Create the encoder component, set up its ports + * + * @param state Pointer to state control struct. encoder_component member set to the created camera_component if successfull. + * + * @return a MMAL_STATUS, MMAL_SUCCESS if all OK, something else otherwise + */ +static MMAL_STATUS_T create_encoder_component(RASPISTILL_STATE *state) +{ + MMAL_COMPONENT_T *encoder = 0; + MMAL_PORT_T *encoder_input = NULL, *encoder_output = NULL; + MMAL_STATUS_T status; + MMAL_POOL_T *pool; + + status = mmal_component_create(MMAL_COMPONENT_DEFAULT_IMAGE_ENCODER, &encoder); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("Unable to create JPEG encoder component"); + goto error; + } + + if (!encoder->input_num || !encoder->output_num) + { + status = MMAL_ENOSYS; + vcos_log_error("JPEG encoder doesn't have input/output ports"); + goto error; + } + + encoder_input = encoder->input[0]; + encoder_output = encoder->output[0]; + + // We want same format on input and output + mmal_format_copy(encoder_output->format, encoder_input->format); + + // Specify out output format + encoder_output->format->encoding = state->encoding; + + encoder_output->buffer_size = encoder_output->buffer_size_recommended; + + if (encoder_output->buffer_size < encoder_output->buffer_size_min) + encoder_output->buffer_size = encoder_output->buffer_size_min; + + encoder_output->buffer_num = encoder_output->buffer_num_recommended; + + if (encoder_output->buffer_num < encoder_output->buffer_num_min) + encoder_output->buffer_num = encoder_output->buffer_num_min; + + // Commit the port changes to the output port + status = mmal_port_format_commit(encoder_output); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("Unable to set format on video encoder output port"); + goto error; + } + + // Set the JPEG quality level + status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_JPEG_Q_FACTOR, state->quality); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("Unable to set JPEG quality"); + goto error; + } + + // Set up any required thumbnail + { + MMAL_PARAMETER_THUMBNAIL_CONFIG_T param_thumb = {{MMAL_PARAMETER_THUMBNAIL_CONFIGURATION, sizeof(MMAL_PARAMETER_THUMBNAIL_CONFIG_T)}, 0, 0, 0, 0}; + + if ( state->thumbnailConfig.width > 0 && state->thumbnailConfig.height > 0 ) + { + // Have a valid thumbnail defined + param_thumb.enable = 1; + param_thumb.width = state->thumbnailConfig.width; + param_thumb.height = state->thumbnailConfig.height; + param_thumb.quality = state->thumbnailConfig.quality; + } + status = mmal_port_parameter_set(encoder->control, ¶m_thumb.hdr); + } + + // Enable component + status = mmal_component_enable(encoder); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("Unable to enable video encoder component"); + goto error; + } + + /* Create pool of buffer headers for the output port to consume */ + pool = mmal_port_pool_create(encoder_output, encoder_output->buffer_num, encoder_output->buffer_size); + + if (!pool) + { + vcos_log_error("Failed to create buffer header pool for encoder output port %s", encoder_output->name); + } + + state->encoder_pool = pool; + state->encoder_component = encoder; + + if (state->verbose) + fprintf(stderr, "Encoder component done\n"); + + return status; + + error: + + if (encoder) + mmal_component_destroy(encoder); + + return status; +} + +/** + * Destroy the encoder component + * + * @param state Pointer to state control struct + * + */ +static void destroy_encoder_component(RASPISTILL_STATE *state) +{ + // Get rid of any port buffers first + if (state->encoder_pool) + { + mmal_port_pool_destroy(state->encoder_component->output[0], state->encoder_pool); + } + + if (state->encoder_component) + { + mmal_component_destroy(state->encoder_component); + state->encoder_component = NULL; + } +} + + +/** + * Add an exif tag to the capture + * + * @param state Pointer to state control struct + * @param exif_tag String containing a "key=value" pair. + * @return Returns a MMAL_STATUS_T giving result of operation + */ +static MMAL_STATUS_T add_exif_tag(RASPISTILL_STATE *state, const char *exif_tag) +{ + MMAL_STATUS_T status; + MMAL_PARAMETER_EXIF_T *exif_param = (MMAL_PARAMETER_EXIF_T*)calloc(sizeof(MMAL_PARAMETER_EXIF_T) + MAX_EXIF_PAYLOAD_LENGTH, 1); + + vcos_assert(state); + vcos_assert(state->encoder_component); + + // Check to see if the tag is present or is indeed a key=value pair. + if (!exif_tag || strchr(exif_tag, '=') == NULL || strlen(exif_tag) > MAX_EXIF_PAYLOAD_LENGTH-1) + return MMAL_EINVAL; + + exif_param->hdr.id = MMAL_PARAMETER_EXIF; + + strncpy((char*)exif_param->data, exif_tag, MAX_EXIF_PAYLOAD_LENGTH-1); + + exif_param->hdr.size = sizeof(MMAL_PARAMETER_EXIF_T) + strlen((char*)exif_param->data); + + status = mmal_port_parameter_set(state->encoder_component->output[0], &exif_param->hdr); + + free(exif_param); + + return status; +} + +/** + * Add a basic set of EXIF tags to the capture + * Make, Time etc + * + * @param state Pointer to state control struct + * + */ +static void add_exif_tags(RASPISTILL_STATE *state) +{ + time_t rawtime; + struct tm *timeinfo; + char time_buf[32]; + char exif_buf[128]; + int i; + + add_exif_tag(state, "IFD0.Model=RP_OV5647"); + add_exif_tag(state, "IFD0.Make=RaspberryPi"); + + time(&rawtime); + timeinfo = localtime(&rawtime); + + snprintf(time_buf, sizeof(time_buf), + "%04d:%02d:%02d %02d:%02d:%02d", + timeinfo->tm_year+1900, + timeinfo->tm_mon+1, + timeinfo->tm_mday, + timeinfo->tm_hour, + timeinfo->tm_min, + timeinfo->tm_sec); + + snprintf(exif_buf, sizeof(exif_buf), "EXIF.DateTimeDigitized=%s", time_buf); + add_exif_tag(state, exif_buf); + + snprintf(exif_buf, sizeof(exif_buf), "EXIF.DateTimeOriginal=%s", time_buf); + add_exif_tag(state, exif_buf); + + snprintf(exif_buf, sizeof(exif_buf), "IFD0.DateTime=%s", time_buf); + add_exif_tag(state, exif_buf); + + // Now send any user supplied tags + + for (i=0;inumExifTags && i < MAX_USER_EXIF_TAGS;i++) + { + if (state->exifTags[i]) + { + add_exif_tag(state, state->exifTags[i]); + } + } +} + +/** + * Stores an EXIF tag in the state, incrementing various pointers as necessary. + * Any tags stored in this way will be added to the image file when add_exif_tags + * is called + * + * Will not store if run out of storage space + * + * @param state Pointer to state control struct + * @param exif_tag EXIF tag string + * + */ +static void store_exif_tag(RASPISTILL_STATE *state, const char *exif_tag) +{ + if (state->numExifTags < MAX_USER_EXIF_TAGS) + { + state->exifTags[state->numExifTags] = exif_tag; + state->numExifTags++; + } +} + +/** + * Connect two specific ports together + * + * @param output_port Pointer the output port + * @param input_port Pointer the input port + * @param Pointer to a mmal connection pointer, reassigned if function successful + * @return Returns a MMAL_STATUS_T giving result of operation + * + */ +static MMAL_STATUS_T connect_ports(MMAL_PORT_T *output_port, MMAL_PORT_T *input_port, MMAL_CONNECTION_T **connection) +{ + MMAL_STATUS_T status; + + status = mmal_connection_create(connection, output_port, input_port, MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT); + + if (status == MMAL_SUCCESS) + { + status = mmal_connection_enable(*connection); + if (status != MMAL_SUCCESS) + mmal_connection_destroy(*connection); + } + + return status; +} + + +/** + * Allocates and generates a filename based on the + * user-supplied pattern and the frame number. + * On successful return, finalName and tempName point to malloc()ed strings + * which must be freed externally. (On failure, returns nulls that + * don't need free()ing.) + * + * @param finalName pointer receives an + * @param pattern sprintf pattern with %d to be replaced by frame + * @param frame for timelapse, the frame number + * @return Returns a MMAL_STATUS_T giving result of operation +*/ + +MMAL_STATUS_T create_filenames(char** finalName, char** tempName, char * pattern, int frame) +{ + *finalName = NULL; + *tempName = NULL; + if (0 > asprintf(finalName, pattern, frame) || + 0 > asprintf(tempName, "%s~", *finalName)) + { + if (*finalName != NULL) + { + free(*finalName); + } + return MMAL_ENOMEM; // It may be some other error, but it is not worth getting it right + } + return MMAL_SUCCESS; +} + +/** + * Checks if specified port is valid and enabled, then disables it + * + * @param port Pointer the port + * + */ +static void check_disable_port(MMAL_PORT_T *port) +{ + if (port && port->is_enabled) + mmal_port_disable(port); +} + +/** + * Handler for sigint signals + * + * @param signal_number ID of incoming signal. + * + */ +static void signal_handler(int signal_number) +{ + // Going to abort on all signals + vcos_log_error("Aborting program\n"); + + // Need to close any open stuff... + + exit(130); +} + +/** + * main + */ +int main(int argc, const char **argv) +{ + // Our main data storage vessel.. + RASPISTILL_STATE state; + int exit_code = EX_OK; + + MMAL_STATUS_T status = MMAL_SUCCESS; + MMAL_PORT_T *camera_preview_port = NULL; + MMAL_PORT_T *camera_video_port = NULL; + MMAL_PORT_T *camera_still_port = NULL; + MMAL_PORT_T *preview_input_port = NULL; + MMAL_PORT_T *encoder_input_port = NULL; + MMAL_PORT_T *encoder_output_port = NULL; + + bcm_host_init(); + + // Register our application with the logging system + vcos_log_register("RaspiStill", VCOS_LOG_CATEGORY); + + signal(SIGINT, signal_handler); + + default_status(&state); + + // Do we have any parameters + if (argc == 1) + { + fprintf(stderr, "\%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING); + + display_valid_parameters(basename(argv[0])); + exit(EX_USAGE); + } + + // Parse the command line and put options in to our status structure + if (parse_cmdline(argc, argv, &state)) + { + exit(EX_USAGE); + } + + if (state.verbose) + { + fprintf(stderr, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING); + + dump_status(&state); + } + + // OK, we have a nice set of parameters. Now set up our components + // We have three components. Camera, Preview and encoder. + // Camera and encoder are different in stills/video, but preview + // is the same so handed off to a separate module + + if ((status = create_camera_component(&state)) != MMAL_SUCCESS) + { + vcos_log_error("%s: Failed to create camera component", __func__); + exit_code = EX_SOFTWARE; + } + else if ((status = raspipreview_create(&state.preview_parameters)) != MMAL_SUCCESS) + { + vcos_log_error("%s: Failed to create preview component", __func__); + destroy_camera_component(&state); + exit_code = EX_SOFTWARE; + } + else if ((status = create_encoder_component(&state)) != MMAL_SUCCESS) + { + vcos_log_error("%s: Failed to create encode component", __func__); + raspipreview_destroy(&state.preview_parameters); + destroy_camera_component(&state); + exit_code = EX_SOFTWARE; + } + else + { + PORT_USERDATA callback_data; + + if (state.verbose) + fprintf(stderr, "Starting component connection stage\n"); + + camera_preview_port = state.camera_component->output[MMAL_CAMERA_PREVIEW_PORT]; + camera_video_port = state.camera_component->output[MMAL_CAMERA_VIDEO_PORT]; + camera_still_port = state.camera_component->output[MMAL_CAMERA_CAPTURE_PORT]; + encoder_input_port = state.encoder_component->input[0]; + encoder_output_port = state.encoder_component->output[0]; + + // Note we are lucky that the preview and null sink components use the same input port + // so we can simple do this without conditionals + preview_input_port = state.preview_parameters.preview_component->input[0]; + + // Connect camera to preview (which might be a null_sink if no preview required) + status = connect_ports(camera_preview_port, preview_input_port, &state.preview_connection); + + if (status == MMAL_SUCCESS) + { + VCOS_STATUS_T vcos_status; + + if (state.verbose) + fprintf(stderr, "Connecting camera stills port to encoder input port\n"); + + // Now connect the camera to the encoder + status = connect_ports(camera_still_port, encoder_input_port, &state.encoder_connection); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("%s: Failed to connect camera video port to encoder input", __func__); + goto error; + } + + // Set up our userdata - this is passed though to the callback where we need the information. + // Null until we open our filename + callback_data.file_handle = NULL; + callback_data.pstate = &state; + vcos_status = vcos_semaphore_create(&callback_data.complete_semaphore, "RaspiStill-sem", 0); + + vcos_assert(vcos_status == VCOS_SUCCESS); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("Failed to setup encoder output"); + goto error; + } + + if (state.demoMode) + { + // Run for the user specific time.. + int num_iterations = state.timeout / state.demoInterval; + int i; + for (i=0;iuserdata = (struct MMAL_PORT_USERDATA_T *)&callback_data; + + if (state.verbose) + fprintf(stderr, "Enabling encoder output port\n"); + + // Enable the encoder output port and tell it its callback function + status = mmal_port_enable(encoder_output_port, encoder_buffer_callback); + + // Send all the buffers to the encoder output port + num = mmal_queue_length(state.encoder_pool->queue); + + for (q=0;qqueue); + + if (!buffer) + vcos_log_error("Unable to get a required buffer %d from pool queue", q); + + if (mmal_port_send_buffer(encoder_output_port, buffer)!= MMAL_SUCCESS) + vcos_log_error("Unable to send a buffer to encoder output port (%d)", q); + } + + if (state.verbose) + fprintf(stderr, "Starting capture %d\n", frame); + + if (mmal_port_parameter_set_boolean(camera_still_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS) + { + vcos_log_error("%s: Failed to start capture", __func__); + } + else + { + // Wait for capture to complete + // For some reason using vcos_semaphore_wait_timeout sometimes returns immediately with bad parameter error + // even though it appears to be all correct, so reverting to untimed one until figure out why its erratic + vcos_semaphore_wait(&callback_data.complete_semaphore); + if (state.verbose) + fprintf(stderr, "Finished capture %d\n", frame); + } + + // Ensure we don't die if get callback with no open file + callback_data.file_handle = NULL; + + if (output_file != stdout) + { + fclose(output_file); + vcos_assert(use_filename != NULL && final_filename != NULL); + if (0 != rename(use_filename, final_filename)) + { + vcos_log_error("Could not rename temp file to: %s; %s", + final_filename,strerror(errno)); + } + if (state.linkname) + { + char *use_link; + char *final_link; + status = create_filenames(&final_link, &use_link, state.linkname, frame); + + // Create hard link if possible, symlink otherwise + if (status != MMAL_SUCCESS + || (0 != link(final_filename, use_link) + && 0 != symlink(final_filename, use_link)) + || 0 != rename(use_link, final_link)) + { + vcos_log_error("Could not link as filename: %s; %s", + state.linkname,strerror(errno)); + } + if (use_link) free(use_link); + if (final_link) free(final_link); + } + } + // Disable encoder output port + status = mmal_port_disable(encoder_output_port); + } + + if (use_filename) + { + free(use_filename); + use_filename = NULL; + } + if (final_filename) + { + free(final_filename); + final_filename = NULL; + } + } // end for (frame) + + vcos_semaphore_delete(&callback_data.complete_semaphore); + } + } + else + { + mmal_status_to_int(status); + vcos_log_error("%s: Failed to connect camera to preview", __func__); + } + +error: + + mmal_status_to_int(status); + + if (state.verbose) + fprintf(stderr, "Closing down\n"); + + // Disable all our ports that are not handled by connections + check_disable_port(camera_video_port); + check_disable_port(encoder_output_port); + + mmal_connection_destroy(state.preview_connection); + + mmal_connection_destroy(state.encoder_connection); + + /* Disable components */ + if (state.encoder_component) + mmal_component_disable(state.encoder_component); + + if (state.preview_parameters.preview_component) + mmal_component_disable(state.preview_parameters.preview_component); + + if (state.camera_component) + mmal_component_disable(state.camera_component); + + destroy_encoder_component(&state); + raspipreview_destroy(&state.preview_parameters); + destroy_camera_component(&state); + + if (state.verbose) + fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n"); + } + + if (status != MMAL_SUCCESS) + raspicamcontrol_check_configuration(128); + + return exit_code; +} +/* *INDENT-ON* */ diff --git a/sys/rpicamsrc/RaspiStillYUV.c b/sys/rpicamsrc/RaspiStillYUV.c new file mode 100644 index 0000000000..7b49aeb8f9 --- /dev/null +++ b/sys/rpicamsrc/RaspiStillYUV.c @@ -0,0 +1,958 @@ +/* *INDENT-OFF* */ +/* + * Copyright (c) 2013 Jan Schmidt +Portions: +Copyright (c) 2013, Broadcom Europe Ltd +Copyright (c) 2013, James Hughes +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + * \file RaspiStillYUV.c + * Command line program to capture a still frame and dump uncompressed it to file. + * Also optionally display a preview/viewfinder of current camera input. + * + * \date 4th March 2013 + * \Author: James Hughes + * + * Description + * + * 2 components are created; camera and preview. + * Camera component has three ports, preview, video and stills. + * Preview is connected using standard mmal connections, the stills output + * is written straight to the file in YUV 420 format via the requisite buffer + * callback. video port is not used + * + * We use the RaspiCamControl code to handle the specific camera settings. + * We use the RaspiPreview code to handle the generic preview + */ + +// We use some GNU extensions (basename) +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#define VERSION_STRING "v1.3.2" + +#include "bcm_host.h" +#include "interface/vcos/vcos.h" + +#include "interface/mmal/mmal.h" +#include "interface/mmal/mmal_logging.h" +#include "interface/mmal/mmal_buffer.h" +#include "interface/mmal/util/mmal_util.h" +#include "interface/mmal/util/mmal_util_params.h" +#include "interface/mmal/util/mmal_default_components.h" +#include "interface/mmal/util/mmal_connection.h" + + +#include "RaspiCamControl.h" +#include "RaspiPreview.h" +#include "RaspiCLI.h" + +#include + +/// Camera number to use - we only have one camera, indexed from 0. +#define CAMERA_NUMBER 0 + +// Standard port setting for the camera component +#define MMAL_CAMERA_PREVIEW_PORT 0 +#define MMAL_CAMERA_VIDEO_PORT 1 +#define MMAL_CAMERA_CAPTURE_PORT 2 + + +// Stills format information +#define STILLS_FRAME_RATE_NUM 3 +#define STILLS_FRAME_RATE_DEN 1 + +/// Video render needs at least 2 buffers. +#define VIDEO_OUTPUT_BUFFERS_NUM 3 + +int mmal_status_to_int(MMAL_STATUS_T status); + +/** Structure containing all state information for the current run + */ +typedef struct +{ + int timeout; /// Time taken before frame is grabbed and app then shuts down. Units are milliseconds + int width; /// Requested width of image + int height; /// requested height of image + char *filename; /// filename of output file + int verbose; /// !0 if want detailed run information + int timelapse; /// Delay between each picture in timelapse mode. If 0, disable timelapse + int useRGB; /// Output RGB data rather than YUV + + RASPIPREVIEW_PARAMETERS preview_parameters; /// Preview setup parameters + RASPICAM_CAMERA_PARAMETERS camera_parameters; /// Camera setup parameters + + MMAL_COMPONENT_T *camera_component; /// Pointer to the camera component + MMAL_COMPONENT_T *null_sink_component; /// Pointer to the camera component + MMAL_CONNECTION_T *preview_connection; /// Pointer to the connection from camera to preview + MMAL_POOL_T *camera_pool; /// Pointer to the pool of buffers used by camera stills port +} RASPISTILLYUV_STATE; + + +/** Struct used to pass information in camera still port userdata to callback + */ +typedef struct +{ + FILE *file_handle; /// File handle to write buffer data to. + VCOS_SEMAPHORE_T complete_semaphore; /// semaphore which is posted when we reach end of frame (indicates end of capture or fault) + RASPISTILLYUV_STATE *pstate; /// pointer to our state in case required in callback +} PORT_USERDATA; + +static void display_valid_parameters(char *app_name); + +/// Comamnd ID's and Structure defining our command line options +#define CommandHelp 0 +#define CommandWidth 1 +#define CommandHeight 2 +#define CommandOutput 3 +#define CommandVerbose 4 +#define CommandTimeout 5 +#define CommandTimelapse 6 +#define CommandUseRGB 7 + +static COMMAND_LIST cmdline_commands[] = +{ + { CommandHelp, "-help", "?", "This help information", 0 }, + { CommandWidth, "-width", "w", "Set image width ", 1 }, + { CommandHeight, "-height", "h", "Set image height ", 1 }, + { CommandOutput, "-output", "o", "Output filename . If not specifed, no image is saved", 1 }, + { CommandVerbose, "-verbose", "v", "Output verbose information during run", 0 }, + { CommandTimeout, "-timeout", "t", "Time (in ms) before takes picture and shuts down. If not specified set to 5s", 1 }, + { CommandTimelapse,"-timelapse", "tl", "Timelapse mode. Takes a picture every ms", 1}, + { CommandUseRGB, "-rgb", "rgb","Save as RGB data rather than YUV", 0}, +}; + +static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]); + +/** + * Assign a default set of parameters to the state passed in + * + * @param state Pointer to state structure to assign defaults to + */ +static void default_status(RASPISTILLYUV_STATE *state) +{ + if (!state) + { + vcos_assert(0); + return; + } + + // Default everything to zero + memset(state, 0, sizeof(RASPISTILLYUV_STATE)); + + // Now set anything non-zero + state->timeout = 5000; // 5s delay before take image + state->width = 2592; + state->height = 1944; + state->timelapse = 0; + + // Setup preview window defaults + raspipreview_set_defaults(&state->preview_parameters); + + // Set up the camera_parameters to default + raspicamcontrol_set_defaults(&state->camera_parameters); +} + +/** + * Dump image state parameters to stderr. Used for debugging + * + * @param state Pointer to state structure to assign defaults to + */ +static void dump_status(RASPISTILLYUV_STATE *state) +{ + if (!state) + { + vcos_assert(0); + return; + } + + fprintf(stderr, "Width %d, Height %d, filename %s\n", state->width, state->height, state->filename); + fprintf(stderr, "Time delay %d, Timelapse %d\n", state->timeout, state->timelapse); + + raspipreview_dump_parameters(&state->preview_parameters); + raspicamcontrol_dump_parameters(&state->camera_parameters); +} + +/** + * Parse the incoming command line and put resulting parameters in to the state + * + * @param argc Number of arguments in command line + * @param argv Array of pointers to strings from command line + * @param state Pointer to state structure to assign any discovered parameters to + * @return non-0 if failed for some reason, 0 otherwise + */ +static int parse_cmdline(int argc, const char **argv, RASPISTILLYUV_STATE *state) +{ + // Parse the command line arguments. + // We are looking for -- or - + + int valid = 1; // set 0 if we have a bad parameter + int i; + + for (i = 1; i < argc && valid; i++) + { + int command_id, num_parameters; + + if (!argv[i]) + continue; + + if (argv[i][0] != '-') + { + valid = 0; + continue; + } + + // Assume parameter is valid until proven otherwise + valid = 1; + + command_id = raspicli_get_command_id(cmdline_commands, cmdline_commands_size, &argv[i][1], &num_parameters); + + // If we found a command but are missing a parameter, continue (and we will drop out of the loop) + if (command_id != -1 && num_parameters > 0 && (i + 1 >= argc) ) + continue; + + // We are now dealing with a command line option + switch (command_id) + { + case CommandHelp: + display_valid_parameters(basename(argv[0])); + return -1; + + case CommandWidth: // Width > 0 + if (sscanf(argv[i + 1], "%u", &state->width) != 1) + valid = 0; + else + i++; + break; + + case CommandHeight: // Height > 0 + if (sscanf(argv[i + 1], "%u", &state->height) != 1) + valid = 0; + else + i++; + break; + + case CommandOutput: // output filename + { + int len = strlen(argv[i + 1]); + if (len) + { + state->filename = malloc(len + 1); + vcos_assert(state->filename); + if (state->filename) + strncpy(state->filename, argv[i + 1], len); + i++; + } + else + valid = 0; + break; + } + + case CommandVerbose: // display lots of data during run + state->verbose = 1; + break; + + case CommandTimeout: // Time to run viewfinder for before taking picture, in seconds + { + if (sscanf(argv[i + 1], "%u", &state->timeout) == 1) + { + // TODO : What limits do we need for timeout? + i++; + } + else + valid = 0; + break; + } + + case CommandTimelapse: + if (sscanf(argv[i + 1], "%u", &state->timelapse) != 1) + valid = 0; + else + i++; + break; + + case CommandUseRGB: // display lots of data during run + state->useRGB = 1; + break; + + default: + { + // Try parsing for any image specific parameters + // result indicates how many parameters were used up, 0,1,2 + // but we adjust by -1 as we have used one already + const char *second_arg = (i + 1 < argc) ? argv[i + 1] : NULL; + + int parms_used = (raspicamcontrol_parse_cmdline(&state->camera_parameters, &argv[i][1], second_arg)); + + // Still unused, try preview options + if (!parms_used) + parms_used = raspipreview_parse_cmdline(&state->preview_parameters, &argv[i][1], second_arg); + + + // If no parms were used, this must be a bad parameters + if (!parms_used) + valid = 0; + else + i += parms_used - 1; + + break; + } + } + } + + if (!valid) + { + fprintf(stderr, "Invalid command line option (%s)\n", argv[i]); + return 1; + } + + return 0; +} + +/** + * Display usage information for the application to stdout + * + * @param app_name String to display as the application name + * + */ +static void display_valid_parameters(char *app_name) +{ + fprintf(stderr, "Runs camera for specific time, and take uncompressed YUV capture at end if requested\n\n"); + fprintf(stderr, "usage: %s [options]\n\n", app_name); + + fprintf(stderr, "Image parameter commands\n\n"); + + raspicli_display_help(cmdline_commands, cmdline_commands_size); + + // Help for preview options + raspipreview_display_help(); + + // Now display any help information from the camcontrol code + raspicamcontrol_display_help(); + + fprintf(stderr, "\n"); + + return; +} + +/** + * buffer header callback function for camera control + * + * @param port Pointer to port from which callback originated + * @param buffer mmal buffer header pointer + */ +static void camera_control_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) +{ + fprintf(stderr, "Camera control callback cmd=0x%08x", buffer->cmd); + + if (buffer->cmd == MMAL_EVENT_PARAMETER_CHANGED) + { + } + else + { + vcos_log_error("Received unexpected camera control callback event, 0x%08x", buffer->cmd); + } + + mmal_buffer_header_release(buffer); +} + +/** + * buffer header callback function for camera output port + * + * Callback will dump buffer data to the specific file + * + * @param port Pointer to port from which callback originated + * @param buffer mmal buffer header pointer + */ +static void camera_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) +{ + int complete = 0; + // We pass our file handle and other stuff in via the userdata field. + + + PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata; + + if (pData) + { + int bytes_written = buffer->length; + + if (buffer->length) + { + mmal_buffer_header_mem_lock(buffer); + + bytes_written = fwrite(buffer->data, 1, buffer->length, pData->file_handle); + + mmal_buffer_header_mem_unlock(buffer); + } + + // We need to check we wrote what we wanted - it's possible we have run out of storage. + if (bytes_written != buffer->length) + { + vcos_log_error("Unable to write buffer to file - aborting"); + complete = 1; + } + + // Check end of frame or error + if (buffer->flags & (MMAL_BUFFER_HEADER_FLAG_FRAME_END | MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED)) + complete = 1; + } + else + { + vcos_log_error("Received a camera still buffer callback with no state"); + } + + // release buffer back to the pool + mmal_buffer_header_release(buffer); + + // and send one back to the port (if still open) + if (port->is_enabled) + { + MMAL_STATUS_T status; + MMAL_BUFFER_HEADER_T *new_buffer = mmal_queue_get(pData->pstate->camera_pool->queue); + + // and back to the port from there. + if (new_buffer) + { + status = mmal_port_send_buffer(port, new_buffer); + } + + if (!new_buffer || status != MMAL_SUCCESS) + vcos_log_error("Unable to return the buffer to the camera still port"); + } + + if (complete) + { + vcos_semaphore_post(&(pData->complete_semaphore)); + } +} + + +/** + * Create the camera component, set up its ports + * + * @param state Pointer to state control struct + * + * @return 0 if failed, pointer to component if successful + * + */ +static MMAL_STATUS_T create_camera_component(RASPISTILLYUV_STATE *state) +{ + MMAL_COMPONENT_T *camera = 0; + MMAL_ES_FORMAT_T *format; + MMAL_PORT_T *preview_port = NULL, *video_port = NULL, *still_port = NULL; + MMAL_STATUS_T status; + MMAL_POOL_T *pool; + + /* Create the component */ + status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("Failed to create camera component"); + goto error; + } + + if (!camera->output_num) + { + vcos_log_error("Camera doesn't have output ports"); + goto error; + } + + preview_port = camera->output[MMAL_CAMERA_PREVIEW_PORT]; + video_port = camera->output[MMAL_CAMERA_VIDEO_PORT]; + still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT]; + + // Enable the camera, and tell it its control callback function + status = mmal_port_enable(camera->control, camera_control_callback); + + if (status) + { + vcos_log_error("Unable to enable control port : error %d", status); + goto error; + } + + // set up the camera configuration + { + MMAL_PARAMETER_CAMERA_CONFIG_T cam_config = + { + { MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) }, + .max_stills_w = state->width, + .max_stills_h = state->height, + .stills_yuv422 = 0, + .one_shot_stills = 1, + .max_preview_video_w = state->preview_parameters.previewWindow.width, + .max_preview_video_h = state->preview_parameters.previewWindow.height, + .num_preview_video_frames = 3, + .stills_capture_circular_buffer_height = 0, + .fast_preview_resume = 0, + .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RESET_STC + }; + mmal_port_parameter_set(camera->control, &cam_config.hdr); + } + + raspicamcontrol_set_all_parameters(camera, &state->camera_parameters); + + // Now set up the port formats + + format = preview_port->format; + + format->encoding = MMAL_ENCODING_OPAQUE; + format->encoding_variant = MMAL_ENCODING_I420; + + format->es->video.width = state->preview_parameters.previewWindow.width; + format->es->video.height = state->preview_parameters.previewWindow.height; + format->es->video.crop.x = 0; + format->es->video.crop.y = 0; + format->es->video.crop.width = state->preview_parameters.previewWindow.width; + format->es->video.crop.height = state->preview_parameters.previewWindow.height; + format->es->video.frame_rate.num = PREVIEW_FRAME_RATE_NUM; + format->es->video.frame_rate.den = PREVIEW_FRAME_RATE_DEN; + + status = mmal_port_format_commit(preview_port); + + if (status) + { + vcos_log_error("camera viewfinder format couldn't be set"); + goto error; + } + + // Set the same format on the video port (which we dont use here) + mmal_format_full_copy(video_port->format, format); + status = mmal_port_format_commit(video_port); + + if (status) + { + vcos_log_error("camera video format couldn't be set"); + goto error; + } + + // Ensure there are enough buffers to avoid dropping frames + if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM) + video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM; + + format = still_port->format; + + // Set our stills format on the stills port + if (state->useRGB) + { + format->encoding = MMAL_ENCODING_BGR24; + format->encoding_variant = MMAL_ENCODING_BGR24; + } + else + { + format->encoding = MMAL_ENCODING_I420; + format->encoding_variant = MMAL_ENCODING_I420; + } + format->es->video.width = state->width; + format->es->video.height = state->height; + format->es->video.crop.x = 0; + format->es->video.crop.y = 0; + format->es->video.crop.width = state->width; + format->es->video.crop.height = state->height; + format->es->video.frame_rate.num = STILLS_FRAME_RATE_NUM; + format->es->video.frame_rate.den = STILLS_FRAME_RATE_DEN; + + if (still_port->buffer_size < still_port->buffer_size_min) + still_port->buffer_size = still_port->buffer_size_min; + + still_port->buffer_num = still_port->buffer_num_recommended; + + status = mmal_port_format_commit(still_port); + + if (status) + { + vcos_log_error("camera still format couldn't be set"); + goto error; + } + + /* Enable component */ + status = mmal_component_enable(camera); + + if (status) + { + vcos_log_error("camera component couldn't be enabled"); + goto error; + } + + /* Create pool of buffer headers for the output port to consume */ + pool = mmal_port_pool_create(still_port, still_port->buffer_num, still_port->buffer_size); + + if (!pool) + { + vcos_log_error("Failed to create buffer header pool for camera still port %s", still_port->name); + } + + state->camera_pool = pool; + state->camera_component = camera; + + if (state->verbose) + fprintf(stderr, "Camera component done\n"); + + return status; + +error: + + if (camera) + mmal_component_destroy(camera); + + return status; +} + +/** + * Destroy the camera component + * + * @param state Pointer to state control struct + * + */ +static void destroy_camera_component(RASPISTILLYUV_STATE *state) +{ + if (state->camera_component) + { + mmal_component_destroy(state->camera_component); + state->camera_component = NULL; + } +} + +/** + * Connect two specific ports together + * + * @param output_port Pointer the output port + * @param input_port Pointer the input port + * @param Pointer to a mmal connection pointer, reassigned if function successful + * @return Returns a MMAL_STATUS_T giving result of operation + * + */ +static MMAL_STATUS_T connect_ports(MMAL_PORT_T *output_port, MMAL_PORT_T *input_port, MMAL_CONNECTION_T **connection) +{ + MMAL_STATUS_T status; + + status = mmal_connection_create(connection, output_port, input_port, MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT); + + if (status == MMAL_SUCCESS) + { + status = mmal_connection_enable(*connection); + if (status != MMAL_SUCCESS) + mmal_connection_destroy(*connection); + } + + return status; +} + +/** + * Checks if specified port is valid and enabled, then disables it + * + * @param port Pointer the port + * + */ +static void check_disable_port(MMAL_PORT_T *port) +{ + if (port && port->is_enabled) + mmal_port_disable(port); +} + +/** + * Handler for sigint signals + * + * @param signal_number ID of incoming signal. + * + */ +static void signal_handler(int signal_number) +{ + // Going to abort on all signals + vcos_log_error("Aborting program\n"); + + // Need to close any open stuff... + + exit(255); +} + +/** + * main + */ +int main(int argc, const char **argv) +{ + // Our main data storage vessel.. + RASPISTILLYUV_STATE state; + int exit_code = EX_OK; + + MMAL_STATUS_T status = MMAL_SUCCESS; + MMAL_PORT_T *camera_preview_port = NULL; + MMAL_PORT_T *camera_video_port = NULL; + MMAL_PORT_T *camera_still_port = NULL; + MMAL_PORT_T *preview_input_port = NULL; + FILE *output_file = NULL; + + bcm_host_init(); + + // Register our application with the logging system + vcos_log_register("RaspiStill", VCOS_LOG_CATEGORY); + + signal(SIGINT, signal_handler); + + // Do we have any parameters + if (argc == 1) + { + fprintf(stderr, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING); + + display_valid_parameters(basename(argv[0])); + exit(EX_USAGE); + } + + default_status(&state); + + // Parse the command line and put options in to our status structure + if (parse_cmdline(argc, argv, &state)) + { + status = -1; + exit(EX_USAGE); + } + + if (state.verbose) + { + fprintf(stderr, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING); + dump_status(&state); + } + + // OK, we have a nice set of parameters. Now set up our components + // We have two components. Camera and Preview + // Camera is different in stills/video, but preview + // is the same so handed off to a separate module + + if ((status = create_camera_component(&state)) != MMAL_SUCCESS) + { + vcos_log_error("%s: Failed to create camera component", __func__); + exit_code = EX_SOFTWARE; + } + else if ((status = raspipreview_create(&state.preview_parameters)) != MMAL_SUCCESS) + { + vcos_log_error("%s: Failed to create preview component", __func__); + destroy_camera_component(&state); + exit_code = EX_SOFTWARE; + } + else + { + PORT_USERDATA callback_data; + + if (state.verbose) + fprintf(stderr, "Starting component connection stage\n"); + + camera_preview_port = state.camera_component->output[MMAL_CAMERA_PREVIEW_PORT]; + camera_video_port = state.camera_component->output[MMAL_CAMERA_VIDEO_PORT]; + camera_still_port = state.camera_component->output[MMAL_CAMERA_CAPTURE_PORT]; + + // Note we are lucky that the preview and null sink components use the same input port + // so we can simple do this without conditionals + preview_input_port = state.preview_parameters.preview_component->input[0]; + + // Connect camera to preview (which might be a null_sink if no preview required) + status = connect_ports(camera_preview_port, preview_input_port, &state.preview_connection); + + if (status == MMAL_SUCCESS) + { + VCOS_STATUS_T vcos_status; + + if (state.filename) + { + if (state.verbose) + fprintf(stderr, "Opening output file %s\n", state.filename); + + output_file = fopen(state.filename, "wb"); + if (!output_file) + { + // Notify user, carry on but discarding output buffers + vcos_log_error("%s: Error opening output file: %s\nNo output file will be generated\n", __func__, state.filename); + } + } + + // Set up our userdata - this is passed though to the callback where we need the information. + callback_data.file_handle = output_file; + callback_data.pstate = &state; + + vcos_status = vcos_semaphore_create(&callback_data.complete_semaphore, "RaspiStill-sem", 0); + vcos_assert(vcos_status == VCOS_SUCCESS); + + camera_still_port->userdata = (struct MMAL_PORT_USERDATA_T *)&callback_data; + + if (state.verbose) + fprintf(stderr, "Enabling camera still output port\n"); + + // Enable the camera still output port and tell it its callback function + status = mmal_port_enable(camera_still_port, camera_buffer_callback); + + if (status != MMAL_SUCCESS) + { + vcos_log_error("Failed to setup camera output"); + goto error; + } + + if (state.verbose) + fprintf(stderr, "Starting video preview\n"); + + int num_iterations = state.timelapse ? state.timeout / state.timelapse : 1; + int frame; + FILE *output_file = NULL; + + for (frame = 1;frame<=num_iterations; frame++) + { + if (state.timelapse) + vcos_sleep(state.timelapse); + else + vcos_sleep(state.timeout); + + // Open the file + if (state.filename) + { + if (state.filename[0] == '-') + { + output_file = stdout; + + // Ensure we don't upset the output stream with diagnostics/info + state.verbose = 0; + } + else + { + char *use_filename = state.filename; + + if (state.timelapse) + asprintf(&use_filename, state.filename, frame); + + if (state.verbose) + fprintf(stderr, "Opening output file %s\n", use_filename); + + output_file = fopen(use_filename, "wb"); + + if (!output_file) + { + // Notify user, carry on but discarding encoded output buffers + vcos_log_error("%s: Error opening output file: %s\nNo output file will be generated\n", __func__, use_filename); + } + + // asprintf used in timelapse mode allocates its own memory which we need to free + if (state.timelapse) + free(use_filename); + } + + callback_data.file_handle = output_file; + } + + // And only do the capture if we have specified a filename and its opened OK + if (output_file) + { + // Send all the buffers to the camera output port + { + int num = mmal_queue_length(state.camera_pool->queue); + int q; + + for (q=0;qqueue); + + if (!buffer) + vcos_log_error("Unable to get a required buffer %d from pool queue", q); + + if (mmal_port_send_buffer(camera_still_port, buffer)!= MMAL_SUCCESS) + vcos_log_error("Unable to send a buffer to camera output port (%d)", q); + } + } + + if (state.verbose) + fprintf(stderr, "Starting capture %d\n", frame); + + // Fire the capture + if (mmal_port_parameter_set_boolean(camera_still_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS) + { + vcos_log_error("%s: Failed to start capture", __func__); + } + else + { + // Wait for capture to complete + // For some reason using vcos_semaphore_wait_timeout sometimes returns immediately with bad parameter error + // even though it appears to be all correct, so reverting to untimed one until figure out why its erratic + vcos_semaphore_wait(&callback_data.complete_semaphore); + + if (state.verbose) + fprintf(stderr, "Finished capture %d\n", frame); + } + + // Ensure we don't die if get callback with no open file + callback_data.file_handle = NULL; + + if (output_file != stdout) + fclose(output_file); + } + } + vcos_semaphore_delete(&callback_data.complete_semaphore); + } + else + { + mmal_status_to_int(status); + vcos_log_error("%s: Failed to connect camera to preview", __func__); + } + +error: + + mmal_status_to_int(status); + + if (state.verbose) + fprintf(stderr, "Closing down\n"); + + if (output_file) + fclose(output_file); + + // Disable all our ports that are not handled by connections + check_disable_port(camera_video_port); + + mmal_connection_destroy(state.preview_connection); + + /* Disable components */ + if (state.preview_parameters.preview_component) + mmal_component_disable(state.preview_parameters.preview_component); + + if (state.camera_component) + mmal_component_disable(state.camera_component); + + raspipreview_destroy(&state.preview_parameters); + destroy_camera_component(&state); + + if (state.verbose) + fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n"); + } + + if (status != MMAL_SUCCESS) + raspicamcontrol_check_configuration(128); + + return exit_code; +} + + + +/* *INDENT-ON* */ diff --git a/sys/rpicamsrc/gstrpicam_types.h b/sys/rpicamsrc/gstrpicam_types.h new file mode 100644 index 0000000000..5baa491e7e --- /dev/null +++ b/sys/rpicamsrc/gstrpicam_types.h @@ -0,0 +1,101 @@ +#include "interface/mmal/util/mmal_util_params.h" +#include "interface/mmal/mmal_parameters_camera.h" +#include "RaspiCamControl.h" + +typedef enum { + GST_RPI_CAM_SRC_EXPOSURE_MODE_OFF = MMAL_PARAM_EXPOSUREMODE_OFF, + GST_RPI_CAM_SRC_EXPOSURE_MODE_AUTO = MMAL_PARAM_EXPOSUREMODE_AUTO, + GST_RPI_CAM_SRC_EXPOSURE_MODE_NIGHT = MMAL_PARAM_EXPOSUREMODE_NIGHT, + GST_RPI_CAM_SRC_EXPOSURE_MODE_NIGHTPREVIEW = MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW, + GST_RPI_CAM_SRC_EXPOSURE_MODE_BACKLIGHT = MMAL_PARAM_EXPOSUREMODE_BACKLIGHT, + GST_RPI_CAM_SRC_EXPOSURE_MODE_SPOTLIGHT = MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT, + GST_RPI_CAM_SRC_EXPOSURE_MODE_SPORTS = MMAL_PARAM_EXPOSUREMODE_SPORTS, + GST_RPI_CAM_SRC_EXPOSURE_MODE_SNOW = MMAL_PARAM_EXPOSUREMODE_SNOW, + GST_RPI_CAM_SRC_EXPOSURE_MODE_BEACH = MMAL_PARAM_EXPOSUREMODE_BEACH, + GST_RPI_CAM_SRC_EXPOSURE_MODE_VERYLONG = MMAL_PARAM_EXPOSUREMODE_VERYLONG, + GST_RPI_CAM_SRC_EXPOSURE_MODE_FIXEDFPS = MMAL_PARAM_EXPOSUREMODE_FIXEDFPS, + GST_RPI_CAM_SRC_EXPOSURE_MODE_ANTISHAKE = MMAL_PARAM_EXPOSUREMODE_ANTISHAKE, + GST_RPI_CAM_SRC_EXPOSURE_MODE_FIREWORKS = MMAL_PARAM_EXPOSUREMODE_FIREWORKS +} GstRpiCamSrcExposureMode; + +typedef enum { + GST_RPI_CAM_SRC_EXPOSURE_METERING_MODE_AVERAGE = MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE, + GST_RPI_CAM_SRC_EXPOSURE_METERING_MODE_SPOT = MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT, + GST_RPI_CAM_SRC_EXPOSURE_METERING_MODE_BACKLIST = MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT, + GST_RPI_CAM_SRC_EXPOSURE_METERING_MODE_MATRIX = MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX +} GstRpiCamSrcExposureMeteringMode; + +typedef enum { + GST_RPI_CAM_SRC_AWB_MODE_OFF = MMAL_PARAM_AWBMODE_OFF, + GST_RPI_CAM_SRC_AWB_MODE_AUTO = MMAL_PARAM_AWBMODE_AUTO, + GST_RPI_CAM_SRC_AWB_MODE_SUNLIGHT = MMAL_PARAM_AWBMODE_SUNLIGHT, + GST_RPI_CAM_SRC_AWB_MODE_CLOUDY = MMAL_PARAM_AWBMODE_CLOUDY, + GST_RPI_CAM_SRC_AWB_MODE_SHADE = MMAL_PARAM_AWBMODE_SHADE, + GST_RPI_CAM_SRC_AWB_MODE_TUNGSTEN = MMAL_PARAM_AWBMODE_TUNGSTEN, + GST_RPI_CAM_SRC_AWB_MODE_FLUORESCENT = MMAL_PARAM_AWBMODE_FLUORESCENT, + GST_RPI_CAM_SRC_AWB_MODE_INCANDESCENT = MMAL_PARAM_AWBMODE_INCANDESCENT, + GST_RPI_CAM_SRC_AWB_MODE_FLASH = MMAL_PARAM_AWBMODE_FLASH, + GST_RPI_CAM_SRC_AWB_MODE_HORIZON = MMAL_PARAM_AWBMODE_HORIZON +} GstRpiCamSrcAWBMode; + +typedef enum { + GST_RPI_CAM_SRC_IMAGEFX_NONE = MMAL_PARAM_IMAGEFX_NONE, + GST_RPI_CAM_SRC_IMAGEFX_NEGATIVE = MMAL_PARAM_IMAGEFX_NEGATIVE, + GST_RPI_CAM_SRC_IMAGEFX_SOLARIZE = MMAL_PARAM_IMAGEFX_SOLARIZE, + GST_RPI_CAM_SRC_IMAGEFX_POSTERIZE = MMAL_PARAM_IMAGEFX_POSTERIZE, + GST_RPI_CAM_SRC_IMAGEFX_WHITEBOARD = MMAL_PARAM_IMAGEFX_WHITEBOARD, + GST_RPI_CAM_SRC_IMAGEFX_BLACKBOARD = MMAL_PARAM_IMAGEFX_BLACKBOARD, + GST_RPI_CAM_SRC_IMAGEFX_SKETCH = MMAL_PARAM_IMAGEFX_SKETCH, + GST_RPI_CAM_SRC_IMAGEFX_DENOISE = MMAL_PARAM_IMAGEFX_DENOISE, + GST_RPI_CAM_SRC_IMAGEFX_EMBOSS = MMAL_PARAM_IMAGEFX_EMBOSS, + GST_RPI_CAM_SRC_IMAGEFX_OILPAINT = MMAL_PARAM_IMAGEFX_OILPAINT, + GST_RPI_CAM_SRC_IMAGEFX_HATCH = MMAL_PARAM_IMAGEFX_HATCH, + GST_RPI_CAM_SRC_IMAGEFX_GPEN = MMAL_PARAM_IMAGEFX_GPEN, + GST_RPI_CAM_SRC_IMAGEFX_PASTEL = MMAL_PARAM_IMAGEFX_PASTEL, + GST_RPI_CAM_SRC_IMAGEFX_WATERCOLOUR = MMAL_PARAM_IMAGEFX_WATERCOLOUR, + GST_RPI_CAM_SRC_IMAGEFX_FILM = MMAL_PARAM_IMAGEFX_FILM, + GST_RPI_CAM_SRC_IMAGEFX_BLUR = MMAL_PARAM_IMAGEFX_BLUR, + GST_RPI_CAM_SRC_IMAGEFX_SATURATION = MMAL_PARAM_IMAGEFX_SATURATION, + GST_RPI_CAM_SRC_IMAGEFX_COLOURSWAP = MMAL_PARAM_IMAGEFX_COLOURSWAP, + GST_RPI_CAM_SRC_IMAGEFX_WASHEDOUT = MMAL_PARAM_IMAGEFX_WASHEDOUT, + GST_RPI_CAM_SRC_IMAGEFX_POSTERISE = MMAL_PARAM_IMAGEFX_POSTERISE, + GST_RPI_CAM_SRC_IMAGEFX_COLOURPOINT = MMAL_PARAM_IMAGEFX_COLOURPOINT, + GST_RPI_CAM_SRC_IMAGEFX_COLOURBALANCE = MMAL_PARAM_IMAGEFX_COLOURBALANCE, + GST_RPI_CAM_SRC_IMAGEFX_CARTOON = MMAL_PARAM_IMAGEFX_CARTOON +} GstRpiCamSrcImageEffect; + +typedef enum { + GST_RPI_CAM_SRC_FLICKERAVOID_OFF = MMAL_PARAM_FLICKERAVOID_OFF, + GST_RPI_CAM_SRC_FLICKERAVOID_AUTO = MMAL_PARAM_FLICKERAVOID_AUTO, + GST_RPI_CAM_SRC_FLICKERAVOID_50HZ = MMAL_PARAM_FLICKERAVOID_50HZ, + GST_RPI_CAM_SRC_FLICKERAVOID_60HZ = MMAL_PARAM_FLICKERAVOID_60HZ +} GstRpiCamSrcFlickerAvoidance; + +typedef enum { + GST_RPI_CAM_SRC_DRC_LEVEL_OFF = MMAL_PARAMETER_DRC_STRENGTH_OFF, + GST_RPI_CAM_SRC_DRC_LEVEL_LOW = MMAL_PARAMETER_DRC_STRENGTH_LOW, + GST_RPI_CAM_SRC_DRC_LEVEL_MEDIUM = MMAL_PARAMETER_DRC_STRENGTH_MEDIUM, + GST_RPI_CAM_SRC_DRC_LEVEL_HIGH = MMAL_PARAMETER_DRC_STRENGTH_HIGH +} GstRpiCamSrcDRCLevel; + +typedef enum /*< flags >*/ { + GST_RPI_CAM_SRC_ANNOTATION_MODE_CUSTOM_TEXT = ANNOTATE_USER_TEXT, + GST_RPI_CAM_SRC_ANNOTATION_MODE_TEXT = ANNOTATE_APP_TEXT, + GST_RPI_CAM_SRC_ANNOTATION_MODE_DATE = ANNOTATE_DATE_TEXT, + GST_RPI_CAM_SRC_ANNOTATION_MODE_TIME = ANNOTATE_TIME_TEXT, + GST_RPI_CAM_SRC_ANNOTATION_MODE_SHUTTER_SETTINGS = ANNOTATE_SHUTTER_SETTINGS, + GST_RPI_CAM_SRC_ANNOTATION_MODE_CAF_SETTINGS = ANNOTATE_CAF_SETTINGS, + GST_RPI_CAM_SRC_ANNOTATION_MODE_GAIN_SETTINGS = ANNOTATE_GAIN_SETTINGS, + GST_RPI_CAM_SRC_ANNOTATION_MODE_LENS_SETTINGS = ANNOTATE_LENS_SETTINGS, + GST_RPI_CAM_SRC_ANNOTATION_MODE_MOTION_SETTINGS = ANNOTATE_MOTION_SETTINGS, + GST_RPI_CAM_SRC_ANNOTATION_MODE_FRAME_NUMBER = ANNOTATE_FRAME_NUMBER, + GST_RPI_CAM_SRC_ANNOTATION_MODE_BLACK_BACKGROUND = ANNOTATE_BLACK_BACKGROUND +} GstRpiCamSrcAnnotationMode; + +typedef enum { + GST_RPI_CAM_SRC_INTRA_REFRESH_TYPE_NONE = -1, + GST_RPI_CAM_SRC_INTRA_REFRESH_TYPE_CYCLIC = MMAL_VIDEO_INTRA_REFRESH_CYCLIC, + GST_RPI_CAM_SRC_INTRA_REFRESH_TYPE_ADAPTIVE = MMAL_VIDEO_INTRA_REFRESH_ADAPTIVE, + GST_RPI_CAM_SRC_INTRA_REFRESH_TYPE_BOTH = MMAL_VIDEO_INTRA_REFRESH_BOTH, + GST_RPI_CAM_SRC_INTRA_REFRESH_TYPE_CYCLIC_ROWS = MMAL_VIDEO_INTRA_REFRESH_CYCLIC_MROWS +} GstRpiCamSrcIntraRefreshType; diff --git a/sys/rpicamsrc/gstrpicamsrc.c b/sys/rpicamsrc/gstrpicamsrc.c new file mode 100644 index 0000000000..f719acb4ce --- /dev/null +++ b/sys/rpicamsrc/gstrpicamsrc.c @@ -0,0 +1,1551 @@ +/* + * GStreamer + * Copyright (C) 2013-2015 Jan Schmidt + * + * 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-rpicamsrc + * @title: rpicamsrc + * @short_description: Raspberry Pi Camera Source + * + * Source element for capturing video from the Raspberry Pi camera module. + * + * This element works the same way that the `raspivid` command-line utility + * does and has a similar feature set. + * + * The element can output video in form of raw video frames or encoded as + * (M)JPEG or H.264 video. You can use the element properties to fine-tune + * the capture, image processing and encoding parameters. + * + * ## Example pipelines + * |[ + * gst-launch-1.0 -v rpicamsrc preview=true ! fakesink + * ]| + * should show a preview window on the screen. + * + * |[ + * gst-launch-1.0 -e rpicamsrc bitrate=1000000 ! h264parse ! matroskamux ! filesink location=test.mkv + * ]| + * should produce a file called test.mkv containing an H.264 video stream. We + * pass -e to gst-launch-1.0 so that the pipeline is finalised properly when + * interrupted with Control-C. This makes sure the Matroska file headers are + * updated when streaming ends. + * + * |[ + * gst-launch-1.0 -e rpicamsrc bitrate=5000000 num-buffers=500 keyframe-interval=30 ! h264parse ! splitmuxsink location=video%02d.mov max-size-time=10000000000 max-size-bytes=1000000 + * ]| + * Records a video stream captured from the Raspberry Pi camera module and + * muxes it into ISO mp4 files, splitting as needed to limit size/duration to + * 10 seconds and 1MB maximum size. + * + * gst-launch-1.0 -e rpicamsrc ! image/jpeg,framerate=1/1 ! multifilesink location=image-%05d.jpg + * ]| + * Captures a stream of JPEG images from the Raspberry Pi camera module at + * a rate of 1 frame per second and writes each frame into a new file in the + * current directory, starting with image-00000.jpg, then image-00001.jpg etc. + * + * Since: 1.18 + */ + +#ifdef HAVE_CONFIG_H +# include +#endif +#include + +#include "gstrpicamsrc.h" +#include "gstrpicam_types.h" +#include "gstrpicam-enum-types.h" +#include "gstrpicamsrcdeviceprovider.h" +#include "RaspiCapture.h" + +#include "bcm_host.h" +#include "interface/vcos/vcos.h" + +#include "interface/mmal/mmal.h" +#include "interface/mmal/mmal_logging.h" +#include "interface/mmal/mmal_buffer.h" +#include "interface/mmal/util/mmal_util.h" +#include "interface/mmal/util/mmal_util_params.h" +#include "interface/mmal/util/mmal_default_components.h" +#include "interface/mmal/util/mmal_connection.h" + +GST_DEBUG_CATEGORY (gst_rpi_cam_src_debug); + +/* comment out to use JPEG codec instead of MJPEG */ +// #define USE_JPEG_CODEC + +/* Filter signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_CAMERA_NUMBER, + PROP_BITRATE, + PROP_KEYFRAME_INTERVAL, + PROP_PREVIEW, + PROP_PREVIEW_ENCODED, + PROP_PREVIEW_OPACITY, + PROP_PREVIEW_X, + PROP_PREVIEW_Y, + PROP_PREVIEW_W, + PROP_PREVIEW_H, + PROP_FULLSCREEN, + PROP_SHARPNESS, + PROP_CONTRAST, + PROP_BRIGHTNESS, + PROP_SATURATION, + PROP_ISO, + PROP_VIDEO_STABILISATION, + PROP_EXPOSURE_COMPENSATION, + PROP_EXPOSURE_MODE, + PROP_EXPOSURE_METERING_MODE, + PROP_AWB_MODE, + PROP_AWB_GAIN_RED, + PROP_AWB_GAIN_BLUE, + PROP_IMAGE_EFFECT, + PROP_IMAGE_EFFECT_PARAMS, + PROP_COLOUR_EFFECTS, + PROP_ROTATION, + PROP_HFLIP, + PROP_VFLIP, + PROP_ROI_X, + PROP_ROI_Y, + PROP_ROI_W, + PROP_ROI_H, + PROP_QUANTISATION_PARAMETER, + PROP_INLINE_HEADERS, + PROP_SHUTTER_SPEED, + PROP_SENSOR_MODE, + PROP_DRC, + PROP_ANNOTATION_MODE, + PROP_ANNOTATION_TEXT, + PROP_ANNOTATION_TEXT_SIZE, + PROP_ANNOTATION_TEXT_COLOUR, + PROP_ANNOTATION_TEXT_BG_COLOUR, + PROP_INTRA_REFRESH_TYPE, + PROP_VIDEO_DIRECTION, + PROP_JPEG_QUALITY, + PROP_USE_STC +}; + +#define CAMERA_DEFAULT 0 + +#define BITRATE_DEFAULT 17000000 /* 17Mbit/s default for 1080p */ +#define BITRATE_HIGHEST 25000000 + +#define QUANTISATION_DEFAULT 0 + +#define SHARPNESS_DEFAULT 0 +#define CONTRAST_DEFAULT 0 +#define BRIGHTNESS_DEFAULT 50 +#define SATURATION_DEFAULT 0 +#define ISO_DEFAULT 0 +#define VIDEO_STABILISATION_DEFAULT FALSE +#define EXPOSURE_COMPENSATION_DEFAULT 0 +#define KEYFRAME_INTERVAL_DEFAULT -1 + +#define EXPOSURE_MODE_DEFAULT GST_RPI_CAM_SRC_EXPOSURE_MODE_AUTO +#define EXPOSURE_METERING_MODE_DEFAULT GST_RPI_CAM_SRC_EXPOSURE_METERING_MODE_AVERAGE + +#define DEFAULT_JPEG_QUALITY 50 + +/* + params->exposureMode = MMAL_PARAM_EXPOSUREMODE_AUTO; + params->exposureMeterMode = MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE; + params->awbMode = MMAL_PARAM_AWBMODE_AUTO; + params->imageEffect = MMAL_PARAM_IMAGEFX_NONE; + params->colourEffects.enable = 0; + params->colourEffects.u = 128; + params->colourEffects.v = 128; + params->rotation = 0; + params->hflip = params->vflip = 0; + params->roi.x = params->roi.y = 0.0; + params->roi.w = params->roi.h = 1.0; +*/ + +#define JPEG_CAPS \ + "image/jpeg," \ + "width = " GST_VIDEO_SIZE_RANGE "," \ + "height = " GST_VIDEO_SIZE_RANGE "," \ + "framerate = " GST_VIDEO_FPS_RANGE +#define H264_CAPS \ + "video/x-h264, " \ + "width = " GST_VIDEO_SIZE_RANGE ", " \ + "height = " GST_VIDEO_SIZE_RANGE ", " \ + "framerate = " GST_VIDEO_FPS_RANGE ", " \ + "stream-format = (string) byte-stream, " \ + "alignment = (string) nal, " \ + "profile = (string) { constrained-baseline, baseline, main, high }" +#define RAW_CAPS \ + GST_VIDEO_CAPS_MAKE ("{ I420, RGB, BGR, RGBA }") /* FIXME: Map more raw formats */ + +static GstStaticPadTemplate video_src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (H264_CAPS "; " JPEG_CAPS "; " RAW_CAPS) + ); + + +static void gst_rpi_cam_src_finalize (GObject * object); + +static void gst_rpi_cam_src_colorbalance_init (GstColorBalanceInterface * + iface); +static void gst_rpi_cam_src_orientation_init (GstVideoOrientationInterface * + iface); +static void gst_rpi_cam_src_direction_init (GstVideoDirectionInterface * iface); + +static void gst_rpi_cam_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_rpi_cam_src_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static gboolean gst_rpi_cam_src_start (GstBaseSrc * parent); +static gboolean gst_rpi_cam_src_stop (GstBaseSrc * parent); +static gboolean gst_rpi_cam_src_decide_allocation (GstBaseSrc * src, + GstQuery * query); +static GstFlowReturn gst_rpi_cam_src_create (GstPushSrc * parent, + GstBuffer ** buf); +static GstCaps *gst_rpi_cam_src_get_caps (GstBaseSrc * src, GstCaps * filter); +static gboolean gst_rpi_cam_src_set_caps (GstBaseSrc * src, GstCaps * caps); +static GstCaps *gst_rpi_cam_src_fixate (GstBaseSrc * basesrc, GstCaps * caps); +static gboolean gst_rpi_cam_src_event (GstBaseSrc * src, GstEvent * event); +static gboolean gst_rpi_cam_src_send_event (GstElement * element, + GstEvent * event); + +#define gst_rpi_cam_src_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstRpiCamSrc, gst_rpi_cam_src, + GST_TYPE_PUSH_SRC, + G_IMPLEMENT_INTERFACE (GST_TYPE_COLOR_BALANCE, + gst_rpi_cam_src_colorbalance_init); + G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_DIRECTION, + gst_rpi_cam_src_direction_init); + G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_ORIENTATION, + gst_rpi_cam_src_orientation_init)); + +#define C_ENUM(v) ((gint) v) + +#define GST_RPI_CAM_SRC_TYPE_SENSOR_MODE gst_rpi_cam_src_sensor_mode_get_type() +static GType gst_rpi_cam_src_sensor_mode_get_type (void); + +static GType +gst_rpi_cam_src_sensor_mode_get_type (void) +{ + static const GEnumValue values[] = { + {C_ENUM (GST_RPI_CAM_SRC_SENSOR_MODE_AUTOMATIC), "Automatic", "automatic"}, + {C_ENUM (GST_RPI_CAM_SRC_SENSOR_MODE_1920x1080), "1920x1080 16:9 1-30fps", + "1920x1080"}, + {C_ENUM (GST_RPI_CAM_SRC_SENSOR_MODE_2592x1944_FAST), + "2592x1944 4:3 1-15fps / 3240x2464 15fps w/ v.2 board", + "2592x1944-fast"}, + {C_ENUM (GST_RPI_CAM_SRC_SENSOR_MODE_2592x1944_SLOW), + "2592x1944 4:3 0.1666-1fps / 3240x2464 15fps w/ v.2 board", + "2592x1944-slow"}, + {C_ENUM (GST_RPI_CAM_SRC_SENSOR_MODE_1296x972), "1296x972 4:3 1-42fps", + "1296x972"}, + {C_ENUM (GST_RPI_CAM_SRC_SENSOR_MODE_1296x730), "1296x730 16:9 1-49fps", + "1296x730"}, + {C_ENUM (GST_RPI_CAM_SRC_SENSOR_MODE_640x480_SLOW), + "640x480 4:3 42.1-60fps", "640x480-slow"}, + {C_ENUM (GST_RPI_CAM_SRC_SENSOR_MODE_640x480_FAST), + "640x480 4:3 60.1-90fps", "640x480-fast"}, + {0, NULL, NULL} + }; + static GType id = 0; + if (g_once_init_enter ((gsize *) & id)) { + GType _id; + _id = g_enum_register_static ("GstRpiCamSrcSensorMode", values); + g_once_init_leave ((gsize *) & id, _id); + } + + return id; +} + + +static void +gst_rpi_cam_src_class_init (GstRpiCamSrcClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSrcClass *basesrc_class; + GstPushSrcClass *pushsrc_class; + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + basesrc_class = (GstBaseSrcClass *) klass; + pushsrc_class = (GstPushSrcClass *) klass; + + gobject_class->finalize = gst_rpi_cam_src_finalize; + gobject_class->set_property = gst_rpi_cam_src_set_property; + gobject_class->get_property = gst_rpi_cam_src_get_property; + g_object_class_install_property (gobject_class, PROP_CAMERA_NUMBER, + g_param_spec_int ("camera-number", "Camera Number", + "Which camera to use on a multi-camera system - 0 or 1", 0, + 1, CAMERA_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_BITRATE, + g_param_spec_int ("bitrate", "Bitrate", + "Bitrate for encoding. 0 for VBR using quantisation-parameter", 0, + BITRATE_HIGHEST, BITRATE_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +#ifdef USE_JPEG_CODEC + g_object_class_install_property (gobject_class, PROP_JPEG_QUALITY, + g_param_spec_int ("jpeg-quality", "JPEG Quality", + "Quality setting for JPEG encode", 1, 100, DEFAULT_JPEG_QUALITY, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +#endif + g_object_class_install_property (gobject_class, PROP_KEYFRAME_INTERVAL, + g_param_spec_int ("keyframe-interval", "Keyframe Interface", + "Interval (in frames) between I frames. -1 = automatic, 0 = single-keyframe", + -1, G_MAXINT, KEYFRAME_INTERVAL_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_PREVIEW, + g_param_spec_boolean ("preview", "Preview Window", + "Display preview window overlay", TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_FULLSCREEN, + g_param_spec_boolean ("fullscreen", "Fullscreen Preview", + "Display preview window full screen", TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_PREVIEW_ENCODED, + g_param_spec_boolean ("preview-encoded", "Preview Encoded", + "Display encoder output in the preview", TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PREVIEW_OPACITY, + g_param_spec_int ("preview-opacity", "Preview Opacity", + "Opacity to use for the preview window", 0, 255, 255, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PREVIEW_X, + g_param_spec_int ("preview-x", "Preview window X position", + "Start X coordinate of the preview window (in pixels)", 0, 2048, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PREVIEW_Y, + g_param_spec_int ("preview-y", "Preview window Y position", + "Start Y coordinate of the preview window (in pixels)", 0, 2048, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PREVIEW_W, + g_param_spec_int ("preview-w", "Preview window width", + "Width of the preview window (in pixels)", 0, 2048, 1024, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PREVIEW_H, + g_param_spec_int ("preview-h", "Preview window height", + "Height of the preview window (in pixels)", 0, 2048, 768, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SHARPNESS, + g_param_spec_int ("sharpness", "Sharpness", "Image capture sharpness", + -100, 100, SHARPNESS_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_CONTRAST, + g_param_spec_int ("contrast", "Contrast", "Image capture contrast", -100, + 100, CONTRAST_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_BRIGHTNESS, + g_param_spec_int ("brightness", "Brightness", "Image capture brightness", + 0, 100, BRIGHTNESS_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_SATURATION, + g_param_spec_int ("saturation", "Saturation", "Image capture saturation", + -100, 100, SATURATION_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_ISO, + g_param_spec_int ("iso", "ISO", "ISO value to use (0 = Auto)", 0, 3200, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_VIDEO_STABILISATION, + g_param_spec_boolean ("video-stabilisation", "Video Stabilisation", + "Enable or disable video stabilisation", FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_EXPOSURE_COMPENSATION, + g_param_spec_int ("exposure-compensation", "EV compensation", + "Exposure Value compensation", -10, 10, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_EXPOSURE_MODE, + g_param_spec_enum ("exposure-mode", "Exposure Mode", + "Camera exposure mode to use", + GST_RPI_CAM_SRC_TYPE_EXPOSURE_MODE, EXPOSURE_MODE_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_EXPOSURE_METERING_MODE, + g_param_spec_enum ("metering-mode", "Exposure Metering Mode", + "Camera exposure metering mode to use", + GST_RPI_CAM_SRC_TYPE_EXPOSURE_METERING_MODE, + EXPOSURE_METERING_MODE_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_DRC, + g_param_spec_enum ("drc", "DRC level", "Dynamic Range Control level", + GST_RPI_CAM_SRC_TYPE_DRC_LEVEL, GST_RPI_CAM_SRC_DRC_LEVEL_OFF, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_AWB_MODE, + g_param_spec_enum ("awb-mode", "Automatic White Balance Mode", + "White Balance mode", GST_RPI_CAM_SRC_TYPE_AWB_MODE, + GST_RPI_CAM_SRC_AWB_MODE_AUTO, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_AWB_GAIN_RED, + g_param_spec_float ("awb-gain-red", "AWB Red Gain", + "Manual AWB Gain for red channel when awb-mode=off", 0, 8.0, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_AWB_GAIN_BLUE, + g_param_spec_float ("awb-gain-blue", "AWB Blue Gain", + "Manual AWB Gain for blue channel when awb-mode=off", 0, 8.0, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_IMAGE_EFFECT, + g_param_spec_enum ("image-effect", "Image effect", + "Visual FX to apply to the image", + GST_RPI_CAM_SRC_TYPE_IMAGE_EFFECT, + GST_RPI_CAM_SRC_IMAGEFX_NONE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +#if 0 + PROP_IMAGE_EFFECT_PARAMS, PROP_COLOUR_EFFECTS, +#endif + g_object_class_install_property (gobject_class, PROP_ROTATION, + g_param_spec_int ("rotation", "Rotation", + "Rotate captured image (0, 90, 180, 270 degrees)", 0, 270, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_HFLIP, + g_param_spec_boolean ("hflip", "Horizontal Flip", + "Flip capture horizontally", FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_VFLIP, + g_param_spec_boolean ("vflip", "Vertical Flip", + "Flip capture vertically", FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_ROI_X, + g_param_spec_float ("roi-x", "ROI X", + "Normalised region-of-interest X coord", 0, 1.0, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_ROI_Y, + g_param_spec_float ("roi-y", "ROI Y", + "Normalised region-of-interest Y coord", 0, 1.0, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_ROI_W, + g_param_spec_float ("roi-w", "ROI W", + "Normalised region-of-interest W coord", 0, 1.0, 1.0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_ROI_H, + g_param_spec_float ("roi-h", "ROI H", + "Normalised region-of-interest H coord", 0, 1.0, 1.0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, + PROP_QUANTISATION_PARAMETER, + g_param_spec_int ("quantisation-parameter", + "Quantisation Parameter", + "Set a Quantisation Parameter approx 10-40 with bitrate=0 for VBR encoding. 0 = off", + 0, G_MAXINT, QUANTISATION_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_INLINE_HEADERS, + g_param_spec_boolean ("inline-headers", "Inline Headers", + "Set to TRUE to insert SPS/PPS before each IDR packet", FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_SHUTTER_SPEED, + g_param_spec_int ("shutter-speed", "Shutter Speed", + "Set a fixed shutter speed, in microseconds. (0 = Auto)", 0, + 6000000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_SENSOR_MODE, + g_param_spec_enum ("sensor-mode", "Camera Sensor Mode", + "Manually set the camera sensor mode", + gst_rpi_cam_src_sensor_mode_get_type (), + GST_RPI_CAM_SRC_SENSOR_MODE_AUTOMATIC, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_ANNOTATION_MODE, + g_param_spec_flags ("annotation-mode", "Annotation Mode", + "Flags to control annotation of the output video", + GST_RPI_CAM_SRC_TYPE_ANNOTATION_MODE, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_ANNOTATION_TEXT, + g_param_spec_string ("annotation-text", "Annotation Text", + "Text string to annotate onto video when annotation-mode flags include 'custom-text'", + NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_INTRA_REFRESH_TYPE, + g_param_spec_enum ("intra-refresh-type", "Intra Refresh Type", + "Type of Intra Refresh to use, -1 to disable intra refresh", + GST_RPI_CAM_SRC_TYPE_INTRA_REFRESH_TYPE, + GST_RPI_CAM_SRC_INTRA_REFRESH_TYPE_NONE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_ANNOTATION_TEXT_SIZE, + g_param_spec_int ("annotation-text-size", "Annotation text size", + "Set the size of annotation text (in pixels) (0 = Auto)", 0, + G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_ANNOTATION_TEXT_COLOUR, + g_param_spec_int ("annotation-text-colour", + "Annotation text colour (VUY)", + "Set the annotation text colour, as the integer corresponding to a VUY value eg 0x8080FF = 8421631, -1 for default", + -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, + PROP_ANNOTATION_TEXT_BG_COLOUR, + g_param_spec_int ("annotation-text-bg-colour", + "Annotation text background colour (VUY)", + "Set the annotation text background colour, as the integer corresponding to a VUY value eg 0x8080FF = 8421631, -1 for default", + -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_override_property (gobject_class, PROP_VIDEO_DIRECTION, + "video-direction"); + g_object_class_install_property (gobject_class, PROP_USE_STC, + g_param_spec_boolean ("use-stc", "Use System Time Clock", + "Use the camera STC for timestamping buffers", TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gst_element_class_set_static_metadata (gstelement_class, + "Raspberry Pi Camera Source", "Source/Video", + "Raspberry Pi camera module source", "Jan Schmidt "); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&video_src_template)); + basesrc_class->start = GST_DEBUG_FUNCPTR (gst_rpi_cam_src_start); + basesrc_class->stop = GST_DEBUG_FUNCPTR (gst_rpi_cam_src_stop); + basesrc_class->decide_allocation = + GST_DEBUG_FUNCPTR (gst_rpi_cam_src_decide_allocation); + basesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_rpi_cam_src_get_caps); + basesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_rpi_cam_src_set_caps); + basesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_rpi_cam_src_fixate); + basesrc_class->event = GST_DEBUG_FUNCPTR (gst_rpi_cam_src_event); + gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_rpi_cam_src_send_event); + pushsrc_class->create = GST_DEBUG_FUNCPTR (gst_rpi_cam_src_create); + raspicapture_init (); + + gst_type_mark_as_plugin_api (GST_RPI_CAM_SRC_TYPE_SENSOR_MODE, 0); + gst_type_mark_as_plugin_api (GST_RPI_CAM_SRC_TYPE_EXPOSURE_MODE, 0); + gst_type_mark_as_plugin_api (GST_RPI_CAM_SRC_TYPE_EXPOSURE_METERING_MODE, 0); + gst_type_mark_as_plugin_api (GST_RPI_CAM_SRC_TYPE_AWB_MODE, 0); + gst_type_mark_as_plugin_api (GST_RPI_CAM_SRC_TYPE_IMAGE_EFFECT, 0); + gst_type_mark_as_plugin_api (GST_RPI_CAM_SRC_TYPE_FLICKER_AVOIDANCE, 0); + gst_type_mark_as_plugin_api (GST_RPI_CAM_SRC_TYPE_DRC_LEVEL, 0); + gst_type_mark_as_plugin_api (GST_RPI_CAM_SRC_TYPE_ANNOTATION_MODE, 0); + gst_type_mark_as_plugin_api (GST_RPI_CAM_SRC_TYPE_INTRA_REFRESH_TYPE, 0); +} + +static void +gst_rpi_cam_src_init (GstRpiCamSrc * src) +{ + GstColorBalanceChannel *channel; + + gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME); + gst_base_src_set_live (GST_BASE_SRC (src), TRUE); + raspicapture_default_config (&src->capture_config); + src->capture_config.intraperiod = KEYFRAME_INTERVAL_DEFAULT; + src->capture_config.verbose = 1; + src->capture_config.useSTC = TRUE; + + g_mutex_init (&src->config_lock); + + /* basesrc will generate timestamps if use-stc = false */ + gst_base_src_set_do_timestamp (GST_BASE_SRC (src), TRUE); + + /* Generate the channels list */ + channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL); + channel->label = g_strdup ("CONTRAST"); + channel->min_value = -100; + channel->max_value = 100; + src->channels = g_list_append (src->channels, channel); + + channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL); + channel->label = g_strdup ("BRIGHTNESS"); + channel->min_value = 0; + channel->max_value = 100; + src->channels = g_list_append (src->channels, channel); + + channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL); + channel->label = g_strdup ("SATURATION"); + channel->min_value = -100; + channel->max_value = 100; + src->channels = g_list_append (src->channels, channel); +} + +static void +gst_rpi_cam_src_finalize (GObject * object) +{ + GstRpiCamSrc *src = GST_RPICAMSRC (object); + GList *channels = NULL; + g_mutex_clear (&src->config_lock); + + channels = src->channels; + while (channels) { + GstColorBalanceChannel *channel = channels->data; + + g_object_unref (channel); + channels->data = NULL; + channels = g_list_next (channels); + } + + if (src->channels) + g_list_free (src->channels); + + G_OBJECT_CLASS (gst_rpi_cam_src_parent_class)->finalize (object); +} + +static const GList * +gst_rpi_cam_src_colorbalance_list_channels (GstColorBalance * balance) +{ + GstRpiCamSrc *src = GST_RPICAMSRC (balance); + + g_return_val_if_fail (src != NULL, NULL); + g_return_val_if_fail (GST_IS_RPICAMSRC (src), NULL); + + return src->channels; +} + +static void +gst_rpi_cam_src_colorbalance_set_value (GstColorBalance * balance, + GstColorBalanceChannel * channel, gint value) +{ + GstRpiCamSrc *src = GST_RPICAMSRC (balance); + gboolean changed = FALSE; + + g_return_if_fail (src != NULL); + g_return_if_fail (GST_IS_RPICAMSRC (src)); + g_return_if_fail (channel->label != NULL); + + g_mutex_lock (&src->config_lock); + if (!g_ascii_strcasecmp (channel->label, "SATURATION")) { + changed = value != src->capture_config.camera_parameters.saturation; + src->capture_config.camera_parameters.saturation = value; + } else if (!g_ascii_strcasecmp (channel->label, "BRIGHTNESS")) { + changed = value != src->capture_config.camera_parameters.brightness; + src->capture_config.camera_parameters.brightness = value; + } else if (!g_ascii_strcasecmp (channel->label, "CONTRAST")) { + changed = value != src->capture_config.camera_parameters.contrast; + src->capture_config.camera_parameters.contrast = value; + } + + if (changed) + src->capture_config.change_flags |= PROP_CHANGE_COLOURBALANCE; + + g_mutex_unlock (&src->config_lock); + + if (changed) { + gst_color_balance_value_changed (balance, channel, + gst_color_balance_get_value (balance, channel)); + } +} + +static gint +gst_rpi_cam_src_colorbalance_get_value (GstColorBalance * balance, + GstColorBalanceChannel * channel) +{ + GstRpiCamSrc *src = GST_RPICAMSRC (balance); + gint value = 0; + + g_return_val_if_fail (src != NULL, 0); + g_return_val_if_fail (GST_IS_RPICAMSRC (src), 0); + g_return_val_if_fail (channel->label != NULL, 0); + + g_mutex_lock (&src->config_lock); + + if (!g_ascii_strcasecmp (channel->label, "SATURATION")) { + value = src->capture_config.camera_parameters.saturation; + } else if (!g_ascii_strcasecmp (channel->label, "BRIGHTNESS")) { + value = src->capture_config.camera_parameters.brightness; + } else if (!g_ascii_strcasecmp (channel->label, "CONTRAST")) { + value = src->capture_config.camera_parameters.contrast; + } + + g_mutex_unlock (&src->config_lock); + + return value; +} + +static GstColorBalanceType +gst_rpi_cam_src_colorbalance_get_balance_type (GstColorBalance * balance) +{ + return GST_COLOR_BALANCE_HARDWARE; +} + +static void +gst_rpi_cam_src_reset_custom_orientation (GstRpiCamSrc * src) +{ + src->orientation = GST_VIDEO_ORIENTATION_CUSTOM; +} + +static void +gst_rpi_cam_src_set_orientation (GstRpiCamSrc * src, + GstVideoOrientationMethod orientation) +{ + switch (orientation) { + case GST_VIDEO_ORIENTATION_IDENTITY: + src->capture_config.camera_parameters.rotation = 0; + src->capture_config.camera_parameters.hflip = FALSE; + src->capture_config.camera_parameters.vflip = FALSE; + GST_DEBUG_OBJECT (src, "set orientation identity"); + break; + case GST_VIDEO_ORIENTATION_90R: + src->capture_config.camera_parameters.rotation = 90; + src->capture_config.camera_parameters.hflip = FALSE; + src->capture_config.camera_parameters.vflip = FALSE; + GST_DEBUG_OBJECT (src, "set orientation 90R"); + break; + case GST_VIDEO_ORIENTATION_180: + src->capture_config.camera_parameters.rotation = 180; + src->capture_config.camera_parameters.hflip = FALSE; + src->capture_config.camera_parameters.vflip = FALSE; + GST_DEBUG_OBJECT (src, "set orientation 180"); + break; + case GST_VIDEO_ORIENTATION_90L: + src->capture_config.camera_parameters.rotation = 270; + src->capture_config.camera_parameters.hflip = FALSE; + src->capture_config.camera_parameters.vflip = FALSE; + GST_DEBUG_OBJECT (src, "set orientation 90L"); + break; + case GST_VIDEO_ORIENTATION_HORIZ: + src->capture_config.camera_parameters.rotation = 0; + src->capture_config.camera_parameters.hflip = TRUE; + src->capture_config.camera_parameters.vflip = FALSE; + GST_DEBUG_OBJECT (src, "set orientation hflip"); + break; + case GST_VIDEO_ORIENTATION_VERT: + src->capture_config.camera_parameters.rotation = 0; + src->capture_config.camera_parameters.hflip = FALSE; + src->capture_config.camera_parameters.vflip = TRUE; + GST_DEBUG_OBJECT (src, "set orientation vflip"); + break; + case GST_VIDEO_ORIENTATION_UL_LR: + src->capture_config.camera_parameters.rotation = 90; + src->capture_config.camera_parameters.hflip = FALSE; + src->capture_config.camera_parameters.vflip = TRUE; + GST_DEBUG_OBJECT (src, "set orientation trans"); + break; + case GST_VIDEO_ORIENTATION_UR_LL: + src->capture_config.camera_parameters.rotation = 270; + src->capture_config.camera_parameters.hflip = FALSE; + src->capture_config.camera_parameters.vflip = TRUE; + GST_DEBUG_OBJECT (src, "set orientation trans"); + break; + case GST_VIDEO_ORIENTATION_CUSTOM: + break; + default: + GST_WARNING_OBJECT (src, "unsupported orientation %d", orientation); + break; + } + src->orientation = + orientation >= GST_VIDEO_ORIENTATION_IDENTITY && + orientation <= GST_VIDEO_ORIENTATION_CUSTOM ? + orientation : GST_VIDEO_ORIENTATION_CUSTOM; + src->capture_config.change_flags |= PROP_CHANGE_ORIENTATION; +} + +static void +gst_rpi_cam_src_direction_init (GstVideoDirectionInterface * iface) +{ + /* We implement the video-direction property */ +} + +static void +gst_rpi_cam_src_colorbalance_init (GstColorBalanceInterface * iface) +{ + iface->list_channels = gst_rpi_cam_src_colorbalance_list_channels; + iface->set_value = gst_rpi_cam_src_colorbalance_set_value; + iface->get_value = gst_rpi_cam_src_colorbalance_get_value; + iface->get_balance_type = gst_rpi_cam_src_colorbalance_get_balance_type; +} + +static gboolean +gst_rpi_cam_src_orientation_get_hflip (GstVideoOrientation * orientation, + gboolean * flip) +{ + GstRpiCamSrc *src = GST_RPICAMSRC (orientation); + + g_return_val_if_fail (src != NULL, FALSE); + g_return_val_if_fail (GST_IS_RPICAMSRC (src), FALSE); + + g_mutex_lock (&src->config_lock); + *flip = src->capture_config.camera_parameters.hflip; + g_mutex_unlock (&src->config_lock); + + return TRUE; +} + +static gboolean +gst_rpi_cam_src_orientation_get_vflip (GstVideoOrientation * orientation, + gboolean * flip) +{ + GstRpiCamSrc *src = GST_RPICAMSRC (orientation); + + g_return_val_if_fail (src != NULL, FALSE); + g_return_val_if_fail (GST_IS_RPICAMSRC (src), FALSE); + + g_mutex_lock (&src->config_lock); + *flip = src->capture_config.camera_parameters.vflip; + g_mutex_unlock (&src->config_lock); + + return TRUE; +} + +static gboolean +gst_rpi_cam_src_orientation_set_hflip (GstVideoOrientation * orientation, + gboolean flip) +{ + GstRpiCamSrc *src = GST_RPICAMSRC (orientation); + + g_return_val_if_fail (src != NULL, FALSE); + g_return_val_if_fail (GST_IS_RPICAMSRC (src), FALSE); + + g_mutex_lock (&src->config_lock); + gst_rpi_cam_src_reset_custom_orientation (src); + src->capture_config.camera_parameters.hflip = flip; + src->capture_config.change_flags |= PROP_CHANGE_ORIENTATION; + g_mutex_unlock (&src->config_lock); + + return TRUE; +} + +static gboolean +gst_rpi_cam_src_orientation_set_vflip (GstVideoOrientation * orientation, + gboolean flip) +{ + GstRpiCamSrc *src = GST_RPICAMSRC (orientation); + + g_return_val_if_fail (src != NULL, FALSE); + g_return_val_if_fail (GST_IS_RPICAMSRC (src), FALSE); + + g_mutex_lock (&src->config_lock); + gst_rpi_cam_src_reset_custom_orientation (src); + src->capture_config.camera_parameters.vflip = flip; + src->capture_config.change_flags |= PROP_CHANGE_ORIENTATION; + g_mutex_unlock (&src->config_lock); + + return TRUE; +} + +static void +gst_rpi_cam_src_orientation_init (GstVideoOrientationInterface * iface) +{ + iface->get_hflip = gst_rpi_cam_src_orientation_get_hflip; + iface->set_hflip = gst_rpi_cam_src_orientation_set_hflip; + iface->get_vflip = gst_rpi_cam_src_orientation_get_vflip; + iface->set_vflip = gst_rpi_cam_src_orientation_set_vflip; + + /* TODO: hcenter / vcenter support */ +} + +static void +gst_rpi_cam_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstRpiCamSrc *src = GST_RPICAMSRC (object); + + g_mutex_lock (&src->config_lock); + + switch (prop_id) { + case PROP_CAMERA_NUMBER: + src->capture_config.cameraNum = g_value_get_int (value); + break; + case PROP_BITRATE: + src->capture_config.bitrate = g_value_get_int (value); + src->capture_config.change_flags |= PROP_CHANGE_ENCODING; + break; + case PROP_JPEG_QUALITY: + src->capture_config.jpegQuality = g_value_get_int (value); + src->capture_config.change_flags |= PROP_CHANGE_ENCODING; + break; + case PROP_KEYFRAME_INTERVAL: + src->capture_config.intraperiod = g_value_get_int (value); + src->capture_config.change_flags |= PROP_CHANGE_ENCODING; + break; + case PROP_PREVIEW: + src->capture_config.preview_parameters.wantPreview = + g_value_get_boolean (value); + src->capture_config.change_flags |= PROP_CHANGE_PREVIEW; + break; + case PROP_PREVIEW_ENCODED: + src->capture_config.immutableInput = g_value_get_boolean (value); + src->capture_config.change_flags |= PROP_CHANGE_PREVIEW; + break; + case PROP_FULLSCREEN: + src->capture_config.preview_parameters.wantFullScreenPreview = + g_value_get_boolean (value); + src->capture_config.change_flags |= PROP_CHANGE_PREVIEW; + break; + case PROP_PREVIEW_OPACITY: + src->capture_config.preview_parameters.opacity = g_value_get_int (value); + src->capture_config.change_flags |= PROP_CHANGE_PREVIEW; + break; + case PROP_PREVIEW_X: + src->capture_config.preview_parameters.previewWindow.x = + g_value_get_int (value); + src->capture_config.change_flags |= PROP_CHANGE_PREVIEW; + break; + case PROP_PREVIEW_Y: + src->capture_config.preview_parameters.previewWindow.y = + g_value_get_int (value); + src->capture_config.change_flags |= PROP_CHANGE_PREVIEW; + break; + case PROP_PREVIEW_W: + src->capture_config.preview_parameters.previewWindow.width = + g_value_get_int (value); + src->capture_config.change_flags |= PROP_CHANGE_PREVIEW; + break; + case PROP_PREVIEW_H: + src->capture_config.preview_parameters.previewWindow.height = + g_value_get_int (value); + src->capture_config.change_flags |= PROP_CHANGE_PREVIEW; + break; + case PROP_SHARPNESS: + src->capture_config.camera_parameters.sharpness = g_value_get_int (value); + src->capture_config.change_flags |= PROP_CHANGE_COLOURBALANCE; + break; + case PROP_CONTRAST: + src->capture_config.camera_parameters.contrast = g_value_get_int (value); + src->capture_config.change_flags |= PROP_CHANGE_COLOURBALANCE; + break; + case PROP_BRIGHTNESS: + src->capture_config.camera_parameters.brightness = + g_value_get_int (value); + src->capture_config.change_flags |= PROP_CHANGE_COLOURBALANCE; + break; + case PROP_SATURATION: + src->capture_config.camera_parameters.saturation = + g_value_get_int (value); + src->capture_config.change_flags |= PROP_CHANGE_COLOURBALANCE; + break; + case PROP_ISO: + src->capture_config.camera_parameters.ISO = g_value_get_int (value); + src->capture_config.change_flags |= PROP_CHANGE_SENSOR_SETTINGS; + break; + case PROP_VIDEO_STABILISATION: + src->capture_config.camera_parameters.videoStabilisation = + g_value_get_boolean (value); + src->capture_config.change_flags |= PROP_CHANGE_VIDEO_STABILISATION; + break; + case PROP_EXPOSURE_COMPENSATION: + src->capture_config.camera_parameters.exposureCompensation = + g_value_get_int (value); + src->capture_config.change_flags |= PROP_CHANGE_SENSOR_SETTINGS; + break; + case PROP_EXPOSURE_MODE: + src->capture_config.camera_parameters.exposureMode = + g_value_get_enum (value); + src->capture_config.change_flags |= PROP_CHANGE_SENSOR_SETTINGS; + break; + case PROP_EXPOSURE_METERING_MODE: + src->capture_config.camera_parameters.exposureMeterMode = + g_value_get_enum (value); + src->capture_config.change_flags |= PROP_CHANGE_SENSOR_SETTINGS; + break; + case PROP_ROTATION: + gst_rpi_cam_src_reset_custom_orientation (src); + src->capture_config.camera_parameters.rotation = g_value_get_int (value); + break; + case PROP_AWB_MODE: + src->capture_config.camera_parameters.awbMode = g_value_get_enum (value); + src->capture_config.change_flags |= PROP_CHANGE_AWB; + break; + case PROP_AWB_GAIN_RED: + src->capture_config.camera_parameters.awb_gains_r = + g_value_get_float (value); + src->capture_config.change_flags |= PROP_CHANGE_AWB; + break; + case PROP_AWB_GAIN_BLUE: + src->capture_config.camera_parameters.awb_gains_b = + g_value_get_float (value); + src->capture_config.change_flags |= PROP_CHANGE_AWB; + break; + case PROP_IMAGE_EFFECT: + src->capture_config.camera_parameters.imageEffect = + g_value_get_enum (value); + src->capture_config.change_flags |= PROP_CHANGE_IMAGE_COLOUR_EFFECT; + break; + case PROP_HFLIP: + gst_rpi_cam_src_reset_custom_orientation (src); + src->capture_config.camera_parameters.hflip = g_value_get_boolean (value); + src->capture_config.change_flags |= PROP_CHANGE_ORIENTATION; + break; + case PROP_VFLIP: + gst_rpi_cam_src_reset_custom_orientation (src); + src->capture_config.camera_parameters.vflip = g_value_get_boolean (value); + src->capture_config.change_flags |= PROP_CHANGE_ORIENTATION; + break; + case PROP_ROI_X: + src->capture_config.camera_parameters.roi.x = g_value_get_float (value); + src->capture_config.change_flags |= PROP_CHANGE_ROI; + break; + case PROP_ROI_Y: + src->capture_config.camera_parameters.roi.y = g_value_get_float (value); + src->capture_config.change_flags |= PROP_CHANGE_ROI; + break; + case PROP_ROI_W: + src->capture_config.camera_parameters.roi.w = g_value_get_float (value); + src->capture_config.change_flags |= PROP_CHANGE_ROI; + break; + case PROP_ROI_H: + src->capture_config.camera_parameters.roi.h = g_value_get_float (value); + src->capture_config.change_flags |= PROP_CHANGE_ROI; + break; + case PROP_QUANTISATION_PARAMETER: + src->capture_config.quantisationParameter = g_value_get_int (value); + src->capture_config.change_flags |= PROP_CHANGE_ENCODING; + break; + case PROP_INLINE_HEADERS: + src->capture_config.bInlineHeaders = g_value_get_boolean (value); + break; + case PROP_SHUTTER_SPEED: + src->capture_config.camera_parameters.shutter_speed = + g_value_get_int (value); + src->capture_config.change_flags |= PROP_CHANGE_SENSOR_SETTINGS; + break; + case PROP_DRC: + src->capture_config.camera_parameters.drc_level = + g_value_get_enum (value); + src->capture_config.change_flags |= PROP_CHANGE_SENSOR_SETTINGS; + break; + case PROP_SENSOR_MODE: + src->capture_config.sensor_mode = g_value_get_enum (value); + src->capture_config.change_flags |= PROP_CHANGE_SENSOR_SETTINGS; + break; + case PROP_ANNOTATION_MODE: + src->capture_config.camera_parameters.enable_annotate = + g_value_get_flags (value); + src->capture_config.change_flags |= PROP_CHANGE_ANNOTATION; + break; + case PROP_ANNOTATION_TEXT: + strncpy (src->capture_config.camera_parameters.annotate_string, + g_value_get_string (value), MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V2); + src->capture_config. + camera_parameters.annotate_string[MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V2 + - 1] = '\0'; + src->capture_config.change_flags |= PROP_CHANGE_ANNOTATION; + break; + case PROP_ANNOTATION_TEXT_SIZE: + src->capture_config.camera_parameters.annotate_text_size = + g_value_get_int (value); + src->capture_config.change_flags |= PROP_CHANGE_ANNOTATION; + break; + case PROP_ANNOTATION_TEXT_COLOUR: + src->capture_config.camera_parameters.annotate_text_colour = + g_value_get_int (value); + src->capture_config.change_flags |= PROP_CHANGE_ANNOTATION; + break; + case PROP_ANNOTATION_TEXT_BG_COLOUR: + src->capture_config.camera_parameters.annotate_bg_colour = + g_value_get_int (value); + src->capture_config.change_flags |= PROP_CHANGE_ANNOTATION; + break; + case PROP_INTRA_REFRESH_TYPE: + src->capture_config.intra_refresh_type = g_value_get_enum (value); + src->capture_config.change_flags |= PROP_CHANGE_ENCODING; + break; + case PROP_VIDEO_DIRECTION: + gst_rpi_cam_src_set_orientation (src, g_value_get_enum (value)); + break; + case PROP_USE_STC: + src->capture_config.useSTC = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + + g_mutex_unlock (&src->config_lock); +} + +static void +gst_rpi_cam_src_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstRpiCamSrc *src = GST_RPICAMSRC (object); + + g_mutex_lock (&src->config_lock); + switch (prop_id) { + case PROP_CAMERA_NUMBER: + g_value_set_int (value, src->capture_config.cameraNum); + break; + case PROP_BITRATE: + g_value_set_int (value, src->capture_config.bitrate); + break; + case PROP_JPEG_QUALITY: + g_value_set_int (value, src->capture_config.jpegQuality); + break; + case PROP_KEYFRAME_INTERVAL: + g_value_set_int (value, src->capture_config.intraperiod); + break; + case PROP_PREVIEW: + g_value_set_boolean (value, + src->capture_config.preview_parameters.wantPreview); + break; + case PROP_PREVIEW_ENCODED: + g_value_set_boolean (value, src->capture_config.immutableInput); + break; + case PROP_FULLSCREEN: + g_value_set_boolean (value, + src->capture_config.preview_parameters.wantFullScreenPreview); + break; + case PROP_PREVIEW_OPACITY: + g_value_set_int (value, src->capture_config.preview_parameters.opacity); + break; + case PROP_PREVIEW_X: + g_value_set_int (value, + src->capture_config.preview_parameters.previewWindow.x); + break; + case PROP_PREVIEW_Y: + g_value_set_int (value, + src->capture_config.preview_parameters.previewWindow.y); + break; + case PROP_PREVIEW_W: + g_value_set_int (value, + src->capture_config.preview_parameters.previewWindow.width); + break; + case PROP_PREVIEW_H: + g_value_set_int (value, + src->capture_config.preview_parameters.previewWindow.height); + break; + case PROP_SHARPNESS: + g_value_set_int (value, src->capture_config.camera_parameters.sharpness); + break; + case PROP_CONTRAST: + g_value_set_int (value, src->capture_config.camera_parameters.contrast); + break; + case PROP_BRIGHTNESS: + g_value_set_int (value, src->capture_config.camera_parameters.brightness); + break; + case PROP_SATURATION: + g_value_set_int (value, src->capture_config.camera_parameters.saturation); + break; + case PROP_ISO: + g_value_set_int (value, src->capture_config.camera_parameters.ISO); + break; + case PROP_VIDEO_STABILISATION: + g_value_set_boolean (value, + src->capture_config.camera_parameters.videoStabilisation != 0); + break; + case PROP_EXPOSURE_COMPENSATION: + g_value_set_int (value, + src->capture_config.camera_parameters.exposureCompensation); + break; + case PROP_EXPOSURE_MODE: + g_value_set_enum (value, + src->capture_config.camera_parameters.exposureMode); + break; + case PROP_EXPOSURE_METERING_MODE: + g_value_set_enum (value, + src->capture_config.camera_parameters.exposureMeterMode); + break; + case PROP_ROTATION: + g_value_set_int (value, src->capture_config.camera_parameters.rotation); + break; + case PROP_AWB_MODE: + g_value_set_enum (value, src->capture_config.camera_parameters.awbMode); + break; + case PROP_AWB_GAIN_RED: + g_value_set_float (value, + src->capture_config.camera_parameters.awb_gains_r); + break; + case PROP_AWB_GAIN_BLUE: + g_value_set_float (value, + src->capture_config.camera_parameters.awb_gains_b); + break; + case PROP_IMAGE_EFFECT: + g_value_set_enum (value, + src->capture_config.camera_parameters.imageEffect); + break; + case PROP_HFLIP: + g_value_set_boolean (value, + src->capture_config.camera_parameters.hflip != 0); + break; + case PROP_VFLIP: + g_value_set_boolean (value, + src->capture_config.camera_parameters.vflip != 0); + break; + case PROP_ROI_X: + g_value_set_float (value, src->capture_config.camera_parameters.roi.x); + break; + case PROP_ROI_Y: + g_value_set_float (value, src->capture_config.camera_parameters.roi.y); + break; + case PROP_ROI_W: + g_value_set_float (value, src->capture_config.camera_parameters.roi.w); + break; + case PROP_ROI_H: + g_value_set_float (value, src->capture_config.camera_parameters.roi.h); + break; + case PROP_QUANTISATION_PARAMETER: + g_value_set_int (value, src->capture_config.quantisationParameter); + break; + case PROP_INLINE_HEADERS: + g_value_set_boolean (value, src->capture_config.bInlineHeaders); + break; + case PROP_SHUTTER_SPEED: + g_value_set_int (value, + src->capture_config.camera_parameters.shutter_speed); + break; + case PROP_DRC: + g_value_set_enum (value, src->capture_config.camera_parameters.drc_level); + break; + case PROP_SENSOR_MODE: + g_value_set_enum (value, src->capture_config.sensor_mode); + break; + case PROP_ANNOTATION_MODE: + g_value_set_flags (value, + src->capture_config.camera_parameters.enable_annotate); + break; + case PROP_ANNOTATION_TEXT: + g_value_set_string (value, + src->capture_config.camera_parameters.annotate_string); + break; + case PROP_ANNOTATION_TEXT_SIZE: + g_value_set_int (value, + src->capture_config.camera_parameters.annotate_text_size); + break; + case PROP_ANNOTATION_TEXT_COLOUR: + g_value_set_int (value, + src->capture_config.camera_parameters.annotate_text_colour); + break; + case PROP_ANNOTATION_TEXT_BG_COLOUR: + g_value_set_int (value, + src->capture_config.camera_parameters.annotate_bg_colour); + break; + case PROP_INTRA_REFRESH_TYPE: + g_value_set_enum (value, src->capture_config.intra_refresh_type); + break; + case PROP_VIDEO_DIRECTION: + g_value_set_enum (value, src->orientation); + break; + case PROP_USE_STC: + g_value_set_boolean (value, src->capture_config.useSTC); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + g_mutex_unlock (&src->config_lock); +} + +static gboolean +gst_rpi_cam_src_start (GstBaseSrc * parent) +{ + GstRpiCamSrc *src = GST_RPICAMSRC (parent); + GST_LOG_OBJECT (src, "In src_start()"); + /* Ensure basesrc timestamping is off is use-stc is on */ + if (src->capture_config.useSTC) + gst_base_src_set_do_timestamp (GST_BASE_SRC (src), FALSE); + g_mutex_lock (&src->config_lock); + src->capture_state = raspi_capture_setup (&src->capture_config); + /* Clear all capture flags */ + src->capture_config.change_flags = 0; + g_mutex_unlock (&src->config_lock); + if (src->capture_state == NULL) + return FALSE; + return TRUE; +} + +static gboolean +gst_rpi_cam_src_stop (GstBaseSrc * parent) +{ + GstRpiCamSrc *src = GST_RPICAMSRC (parent); + if (src->started) + raspi_capture_stop (src->capture_state); + raspi_capture_free (src->capture_state); + src->capture_state = NULL; + return TRUE; +} + +static gboolean +gst_rpi_cam_src_send_event (GstElement * parent, GstEvent * event) +{ + GstRpiCamSrc *src = GST_RPICAMSRC (parent); + gboolean ret; + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CUSTOM_DOWNSTREAM: + case GST_EVENT_CUSTOM_UPSTREAM: + if (gst_video_event_is_force_key_unit (event)) { + if (src->started) { + ret = raspi_capture_request_i_frame (src->capture_state); + } else { + ret = FALSE; + } + gst_event_unref (event); + } else { + ret = GST_ELEMENT_CLASS (parent_class)->send_event (parent, event); + } + break; + default: + ret = GST_ELEMENT_CLASS (parent_class)->send_event (parent, event); + break; + } + return ret; +} + +static gboolean +gst_rpi_cam_src_event (GstBaseSrc * parent, GstEvent * event) +{ + GstRpiCamSrc *src = GST_RPICAMSRC (parent); + gboolean ret; + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CUSTOM_DOWNSTREAM: + case GST_EVENT_CUSTOM_UPSTREAM: + if (gst_video_event_is_force_key_unit (event)) { + if (src->started) { + ret = raspi_capture_request_i_frame (src->capture_state); + } else { + ret = FALSE; + } + } else { + ret = GST_BASE_SRC_CLASS (parent_class)->event (parent, event); + } + break; + default: + ret = GST_BASE_SRC_CLASS (parent_class)->event (parent, event); + break; + } + return ret; +} + +static GstCaps * +gst_rpi_cam_src_get_caps (GstBaseSrc * bsrc, GstCaps * filter) +{ + GstRpiCamSrc *src = GST_RPICAMSRC (bsrc); + GstCaps *caps; + gint i; + + caps = gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (bsrc)); + if (src->capture_state == NULL) + goto done; + /* FIXME: Retrieve limiting parameters from the camera module, max width/height fps-range */ + caps = gst_caps_make_writable (caps); + for (i = 0; i < gst_caps_get_size (caps); i++) { + GstStructure *s = gst_caps_get_structure (caps, i); + if (gst_structure_has_name (s, "video/x-h264")) { + gst_caps_set_simple (caps, "width", GST_TYPE_INT_RANGE, 1, 1920, "height", + GST_TYPE_INT_RANGE, 1, 1080, "framerate", GST_TYPE_FRACTION_RANGE, 0, + 1, RPICAMSRC_MAX_FPS, 1, NULL); + } else { + gst_caps_set_simple (caps, "width", GST_TYPE_INT_RANGE, 1, 3240, "height", + GST_TYPE_INT_RANGE, 1, 2464, "framerate", GST_TYPE_FRACTION_RANGE, 0, + 1, RPICAMSRC_MAX_FPS, 1, NULL); + } + } +done: + GST_DEBUG_OBJECT (src, "get_caps returning %" GST_PTR_FORMAT, caps); + return caps; +} + +static gboolean +gst_rpi_cam_src_set_caps (GstBaseSrc * bsrc, GstCaps * caps) +{ + GstRpiCamSrc *src = GST_RPICAMSRC (bsrc); + GstVideoInfo info; + GstStructure *structure; + const gchar *profile_str = NULL; + + GST_DEBUG_OBJECT (src, "In set_caps %" GST_PTR_FORMAT, caps); + if (!gst_video_info_from_caps (&info, caps)) + return FALSE; + + structure = gst_caps_get_structure (caps, 0); + if (gst_structure_has_name (structure, "video/x-h264")) { + src->capture_config.encoding = MMAL_ENCODING_H264; + profile_str = gst_structure_get_string (structure, "profile"); + if (profile_str) { + if (g_str_equal (profile_str, "baseline")) + src->capture_config.profile = MMAL_VIDEO_PROFILE_H264_BASELINE; + else if (g_str_equal (profile_str, "constrained-baseline")) + src->capture_config.profile = + MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE; + else if (g_str_equal (profile_str, "main")) + src->capture_config.profile = MMAL_VIDEO_PROFILE_H264_MAIN; + else if (g_str_equal (profile_str, "high")) + src->capture_config.profile = MMAL_VIDEO_PROFILE_H264_HIGH; + else + g_warning ("Unknown profile string in rpicamsrc caps: %s", profile_str); + } + } else if (gst_structure_has_name (structure, "image/jpeg")) { +#ifdef USE_JPEG_CODEC + src->capture_config.encoding = MMAL_ENCODING_JPEG; +#else + src->capture_config.encoding = MMAL_ENCODING_MJPEG; +#endif + } else { + /* Raw caps */ + switch (GST_VIDEO_INFO_FORMAT (&info)) { + case GST_VIDEO_FORMAT_I420: + src->capture_config.encoding = MMAL_ENCODING_I420; + break; + case GST_VIDEO_FORMAT_RGB: + src->capture_config.encoding = MMAL_ENCODING_RGB24; + break; + case GST_VIDEO_FORMAT_BGR: + src->capture_config.encoding = MMAL_ENCODING_BGR24; + break; + case GST_VIDEO_FORMAT_RGBA: + src->capture_config.encoding = MMAL_ENCODING_RGBA; + break; + default: + return FALSE; + } + } + + src->capture_config.width = info.width; + src->capture_config.height = info.height; + src->capture_config.fps_n = info.fps_n; + src->capture_config.fps_d = info.fps_d; + + if (info.fps_n != 0 && info.fps_d != 0) + src->duration = gst_util_uint64_scale_int (GST_SECOND, info.fps_d, + info.fps_n); + else + src->duration = GST_CLOCK_TIME_NONE; + + return TRUE; +} + +static gboolean +gst_rpi_cam_src_decide_allocation (GstBaseSrc * bsrc, GstQuery * query) +{ + GST_LOG_OBJECT (bsrc, "In decide_allocation"); + return GST_BASE_SRC_CLASS (parent_class)->decide_allocation (bsrc, query); +} + +static GstCaps * +gst_rpi_cam_src_fixate (GstBaseSrc * basesrc, GstCaps * caps) +{ + GstStructure *structure; + gint i; + GST_DEBUG_OBJECT (basesrc, "fixating caps %" GST_PTR_FORMAT, caps); + caps = gst_caps_make_writable (caps); + for (i = 0; i < gst_caps_get_size (caps); ++i) { + structure = gst_caps_get_structure (caps, i); + /* Fixate to 1920x1080 resolution if possible */ + gst_structure_fixate_field_nearest_int (structure, "width", 1920); + gst_structure_fixate_field_nearest_int (structure, "height", 1080); + gst_structure_fixate_field_nearest_fraction (structure, "framerate", 30, 1); + gst_structure_fixate_field (structure, "format"); + } + + GST_DEBUG_OBJECT (basesrc, "fixated caps %" GST_PTR_FORMAT, caps); + caps = GST_BASE_SRC_CLASS (parent_class)->fixate (basesrc, caps); + return caps; +} + +static GstFlowReturn +gst_rpi_cam_src_create (GstPushSrc * parent, GstBuffer ** buf) +{ + GstRpiCamSrc *src = GST_RPICAMSRC (parent); + GstFlowReturn ret; + GstClock *clock = NULL; + GstClockTime base_time; + + if (!src->started) { + g_mutex_lock (&src->config_lock); + raspi_capture_update_config (src->capture_state, &src->capture_config, + FALSE); + src->capture_config.change_flags = 0; + g_mutex_unlock (&src->config_lock); + + if (!raspi_capture_start (src->capture_state)) + return GST_FLOW_ERROR; + src->started = TRUE; + } + + GST_OBJECT_LOCK (src); + if ((clock = GST_ELEMENT_CLOCK (src)) != NULL) + gst_object_ref (clock); + base_time = GST_ELEMENT_CAST (src)->base_time; + GST_OBJECT_UNLOCK (src); + + g_mutex_lock (&src->config_lock); + if (src->capture_config.change_flags) { + raspi_capture_update_config (src->capture_state, &src->capture_config, + TRUE); + src->capture_config.change_flags = 0; + } + g_mutex_unlock (&src->config_lock); + + *buf = NULL; + + do { + GstBuffer *cbuf = NULL; + + /* FIXME: Use custom allocator */ + ret = + raspi_capture_fill_buffer (src->capture_state, &cbuf, clock, base_time); + + if (cbuf != NULL) { + GST_LOG_OBJECT (src, "Made buffer of size %" G_GSIZE_FORMAT, + gst_buffer_get_size (cbuf)); + + if (*buf == NULL) { + /* Only set the duration when we have a PTS update from the rpi encoder. + * not every buffer is a frame */ + if (GST_BUFFER_PTS_IS_VALID (cbuf)) + GST_BUFFER_DURATION (cbuf) = src->duration; + + *buf = cbuf; + } else { + *buf = gst_buffer_append (*buf, cbuf); + } + cbuf = NULL; + } + } while (ret == GST_FLOW_KEEP_ACCUMULATING); + + if (ret == GST_FLOW_ERROR_TIMEOUT) { + GST_ELEMENT_ERROR (src, STREAM, FAILED, + ("Camera capture timed out."), + ("Waiting for a buffer from the camera took too long.")); + ret = GST_FLOW_ERROR; + } + + if (ret != GST_FLOW_OK) + gst_clear_buffer (buf); + + if (clock) + gst_object_unref (clock); + return ret; +} + +/** + * plugin-rpicamsrc: + * + * Since: 1.18 + */ +static gboolean +plugin_init (GstPlugin * plugin) +{ + gboolean ret; + + GST_DEBUG_CATEGORY_INIT (gst_rpi_cam_src_debug, "rpicamsrc", + 0, "rpicamsrc debug"); + + ret = gst_element_register (plugin, "rpicamsrc", GST_RANK_NONE, + GST_TYPE_RPICAMSRC); + + ret &= gst_device_provider_register (plugin, "rpicamsrcdeviceprovider", + GST_RANK_PRIMARY, GST_TYPE_RPICAMSRC_DEVICE_PROVIDER); + + return ret; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + rpicamsrc, + "Raspberry Pi Camera Source", + plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/sys/rpicamsrc/gstrpicamsrc.h b/sys/rpicamsrc/gstrpicamsrc.h new file mode 100644 index 0000000000..dea4cc44c7 --- /dev/null +++ b/sys/rpicamsrc/gstrpicamsrc.h @@ -0,0 +1,107 @@ +/* + * GStreamer + * Copyright (C) 2013 Jan Schmidt + * + * 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_RPICAMSRC_H__ +#define __GST_RPICAMSRC_H__ + +#include +#include +#include /* only used for GST_PLUGINS_BASE_VERSION_* */ +#include "RaspiCapture.h" + +G_BEGIN_DECLS + +#define GST_TYPE_RPICAMSRC (gst_rpi_cam_src_get_type()) +#define GST_RPICAMSRC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RPICAMSRC,GstRpiCamSrc)) +#define GST_RPICAMSRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RPICAMSRC,GstRpiCamSrcClass)) +#define GST_IS_RPICAMSRC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RPICAMSRC)) +#define GST_IS_RPICAMSRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RPICAMSRC)) + +typedef struct _GstRpiCamSrc GstRpiCamSrc; +typedef struct _GstRpiCamSrcClass GstRpiCamSrcClass; + +struct _GstRpiCamSrc +{ + GstPushSrc parent; + + GstPad *video_srcpad; + + RASPIVID_CONFIG capture_config; + RASPIVID_STATE *capture_state; + gboolean started; + + GMutex config_lock; + + /* channels for interface */ + GList *channels; + + GstVideoOrientationMethod orientation; + + GstClockTime duration; +}; + +struct _GstRpiCamSrcClass +{ + GstPushSrcClass parent_class; +}; + +GType gst_rpi_cam_src_get_type (void); + +typedef enum { + GST_RPI_CAM_SRC_SENSOR_MODE_AUTOMATIC = 0, + GST_RPI_CAM_SRC_SENSOR_MODE_1920x1080 = 1, + GST_RPI_CAM_SRC_SENSOR_MODE_2592x1944_FAST = 2, + GST_RPI_CAM_SRC_SENSOR_MODE_2592x1944_SLOW = 3, + GST_RPI_CAM_SRC_SENSOR_MODE_1296x972 = 4, + GST_RPI_CAM_SRC_SENSOR_MODE_1296x730 = 5, + GST_RPI_CAM_SRC_SENSOR_MODE_640x480_SLOW = 6, + GST_RPI_CAM_SRC_SENSOR_MODE_640x480_FAST = 7 +} GstRpiCamSrcSensorMode; + +G_END_DECLS + +#endif /* __GST_RPICAMSRC_H__ */ diff --git a/sys/rpicamsrc/gstrpicamsrcdeviceprovider.c b/sys/rpicamsrc/gstrpicamsrcdeviceprovider.c new file mode 100644 index 0000000000..0a5b82ca88 --- /dev/null +++ b/sys/rpicamsrc/gstrpicamsrcdeviceprovider.c @@ -0,0 +1,154 @@ +/* GStreamer Raspberry Pi Camera Source Device Provider + * Copyright (C) 2014 Tim-Philipp Müller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should 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 "gstrpicamsrcdeviceprovider.h" + +#include + +#include "RaspiCapture.h" + +#include + +static GstRpiCamSrcDevice *gst_rpi_cam_src_device_new (void); + +G_DEFINE_TYPE (GstRpiCamSrcDeviceProvider, gst_rpi_cam_src_device_provider, + GST_TYPE_DEVICE_PROVIDER); + + +static GList *gst_rpi_cam_src_device_provider_probe (GstDeviceProvider * + provider); + +static void +gst_rpi_cam_src_device_provider_class_init (GstRpiCamSrcDeviceProviderClass * + klass) +{ + GstDeviceProviderClass *dprovider_class = GST_DEVICE_PROVIDER_CLASS (klass); + + dprovider_class->probe = gst_rpi_cam_src_device_provider_probe; + + gst_device_provider_class_set_static_metadata (dprovider_class, + "Raspberry Pi Camera Source Device Provider", "Source/Video", + "Lists Raspberry Pi camera devices", + "Tim-Philipp Müller "); +} + +static void +gst_rpi_cam_src_device_provider_init (GstRpiCamSrcDeviceProvider * provider) +{ + raspicapture_init (); +} + +static GList * +gst_rpi_cam_src_device_provider_probe (GstDeviceProvider * provider) +{ + GstRpiCamSrcDevice *device; + int supported = 0, detected = 0; + + raspicamcontrol_get_camera (&supported, &detected); + + if (!detected) { + GST_INFO ("No Raspberry Pi camera module detected."); + return NULL; + } else if (!supported) { + GST_WARNING + ("Raspberry Pi camera module not supported, make sure to enable it."); + return NULL; + } + + GST_INFO ("Raspberry Pi camera module detected and supported."); + + device = gst_rpi_cam_src_device_new (); + + return g_list_append (NULL, device); +} + +G_DEFINE_TYPE (GstRpiCamSrcDevice, gst_rpi_cam_src_device, GST_TYPE_DEVICE); + +static GstElement *gst_rpi_cam_src_device_create_element (GstDevice * device, + const gchar * name); + +static void +gst_rpi_cam_src_device_class_init (GstRpiCamSrcDeviceClass * klass) +{ + GstDeviceClass *device_class = GST_DEVICE_CLASS (klass); + + device_class->create_element = gst_rpi_cam_src_device_create_element; +} + +static void +gst_rpi_cam_src_device_init (GstRpiCamSrcDevice * device) +{ + /* nothing to do here */ +} + +static GstElement * +gst_rpi_cam_src_device_create_element (GstDevice * device, const gchar * name) +{ + return gst_element_factory_make ("rpicamsrc", name); +} + +static GstRpiCamSrcDevice * +gst_rpi_cam_src_device_new (void) +{ + GstRpiCamSrcDevice *device; + GValue profiles = G_VALUE_INIT; + GValue val = G_VALUE_INIT; + GstStructure *s, *jpeg_s; + GstCaps *caps; + + /* FIXME: retrieve limits from the camera module, max width/height/fps etc. */ + s = gst_structure_new ("video/x-h264", + "width", GST_TYPE_INT_RANGE, 1, 1920, + "height", GST_TYPE_INT_RANGE, 1, 1080, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, RPICAMSRC_MAX_FPS, 1, + "stream-format", G_TYPE_STRING, "byte-stream", + "alignment", G_TYPE_STRING, "au", NULL); + + g_value_init (&profiles, GST_TYPE_LIST); + g_value_init (&val, G_TYPE_STRING); + g_value_set_static_string (&val, "high"); + gst_value_list_append_value (&profiles, &val); + g_value_set_static_string (&val, "main"); + gst_value_list_append_value (&profiles, &val); + g_value_set_static_string (&val, "constrained-baseline"); + gst_value_list_append_value (&profiles, &val); + g_value_set_static_string (&val, "baseline"); + gst_value_list_append_and_take_value (&profiles, &val); + gst_structure_take_value (s, "profiles", &profiles); + + jpeg_s = gst_structure_new ("image/jpeg", + "width", GST_TYPE_INT_RANGE, 1, 1920, + "height", GST_TYPE_INT_RANGE, 1, 1080, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, RPICAMSRC_MAX_FPS, 1, + "parsed", G_TYPE_BOOLEAN, "true", NULL); + + caps = gst_caps_new_full (s, jpeg_s, NULL); + + device = g_object_new (GST_TYPE_RPICAMSRC_DEVICE, + "display-name", _("Raspberry Pi Camera Module"), + "device-class", "Video/Source", "caps", caps, NULL); + + gst_caps_unref (caps); + + return device; +} diff --git a/sys/rpicamsrc/gstrpicamsrcdeviceprovider.h b/sys/rpicamsrc/gstrpicamsrcdeviceprovider.h new file mode 100644 index 0000000000..d4ed19cea0 --- /dev/null +++ b/sys/rpicamsrc/gstrpicamsrcdeviceprovider.h @@ -0,0 +1,75 @@ +/* GStreamer Raspberry Pi Camera Source Device Provider + * Copyright (C) 2014 Tim-Philipp Müller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should 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_RPICAMSRC_DEVICE_PROVIDER_H__ +#define __GST_RPICAMSRC_DEVICE_PROVIDER_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +G_BEGIN_DECLS + +typedef struct _GstRpiCamSrcDeviceProvider GstRpiCamSrcDeviceProvider; +typedef struct _GstRpiCamSrcDeviceProviderClass GstRpiCamSrcDeviceProviderClass; + +#define GST_TYPE_RPICAMSRC_DEVICE_PROVIDER (gst_rpi_cam_src_device_provider_get_type()) +#define GST_IS_RPICAMSRC_DEVICE_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RPICAMSRC_DEVICE_PROVIDER)) +#define GST_IS_RPICAMSRC_DEVICE_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RPICAMSRC_DEVICE_PROVIDER)) +#define GST_RPICAMSRC_DEVICE_PROVIDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RPICAMSRC_DEVICE_PROVIDER, GstRpiCamSrcDeviceProviderClass)) +#define GST_RPICAMSRC_DEVICE_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RPICAMSRC_DEVICE_PROVIDER, GstRpiCamSrcDeviceProvider)) +#define GST_RPICAMSRC_DEVICE_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEVICE_PROVIDER, GstRpiCamSrcDeviceProviderClass)) +#define GST_RPICAMSRC_DEVICE_PROVIDER_CAST(obj) ((GstRpiCamSrcDeviceProvider *)(obj)) + +struct _GstRpiCamSrcDeviceProvider { + GstDeviceProvider parent; +}; + +struct _GstRpiCamSrcDeviceProviderClass { + GstDeviceProviderClass parent_class; +}; + +GType gst_rpi_cam_src_device_provider_get_type (void); + +typedef struct _GstRpiCamSrcDevice GstRpiCamSrcDevice; +typedef struct _GstRpiCamSrcDeviceClass GstRpiCamSrcDeviceClass; + +#define GST_TYPE_RPICAMSRC_DEVICE (gst_rpi_cam_src_device_get_type()) +#define GST_IS_RPICAMSRC_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RPICAMSRC_DEVICE)) +#define GST_IS_RPICAMSRC_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RPICAMSRC_DEVICE)) +#define GST_RPICAMSRC_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RPICAMSRC_DEVICE, GstRpiCamSrcDeviceClass)) +#define GST_RPICAMSRC_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RPICAMSRC_DEVICE, GstRpiCamSrcDevice)) +#define GST_RPICAMSRC_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEVICE, GstRpiCamSrcDeviceClass)) +#define GST_RPICAMSRC_DEVICE_CAST(obj) ((GstRpiCamSrcDevice *)(obj)) + +struct _GstRpiCamSrcDevice { + GstDevice parent; +}; + +struct _GstRpiCamSrcDeviceClass { + GstDeviceClass parent_class; +}; + +GType gst_rpi_cam_src_device_get_type (void); + +G_END_DECLS + +#endif /* __GST_RPICAMSRC_DEVICE_PROVIDER_H__ */ diff --git a/sys/rpicamsrc/meson.build b/sys/rpicamsrc/meson.build new file mode 100644 index 0000000000..ef324ec48b --- /dev/null +++ b/sys/rpicamsrc/meson.build @@ -0,0 +1,86 @@ +rpicamsrc_sources = [ + 'gstrpicamsrc.c', + 'gstrpicamsrcdeviceprovider.c', + 'RaspiCapture.c', + 'RaspiCamControl.c', + 'RaspiPreview.c', + 'RaspiCLI.c', +] + +if host_system != 'linux' or (host_cpu != 'arm' and host_cpu != 'aarch64') + assert(not get_option('rpicamsrc').enabled(), 'rpicamsrc was enabled by options but will not be built') + subdir_done() +endif + +if get_option('rpicamsrc').disabled() + subdir_done() +endif + +rpi_inc_path = get_option('rpi-header-dir') +rpi_lib_path = get_option('rpi-lib-dir') + +rpi_inc_args = [ + '-I' + rpi_inc_path, + '-I' + join_paths(rpi_inc_path, 'interface', 'vcos', 'pthreads'), + '-I' + join_paths(rpi_inc_path, 'interface', 'vmcs_host', 'linux'), +] + +if not cc.has_header('bcm_host.h', args: rpi_inc_args) + if get_option('rpicamsrc').enabled() + error('Could not find bcm_host.h. Please pass the location of this header via -Drpi-header-dir=/path') + else + subdir_done() + endif +endif + +thread_dep = dependency('threads') +rt_dep = cxx.find_library('rt', required : false) + +mmal_deps = [thread_dep, rt_dep] +foreach rpi_lib : ['mmal_core', 'mmal_util', 'mmal_vc_client', 'vcos', 'vchostif', 'vchiq_arm', 'bcm_host'] + l = cc.find_library(rpi_lib, dirs: rpi_lib_path, required: false) + if not l.found() + if get_option('rpicamsrc').enabled() + error(''' + Could not find lib@0@ in standard library paths and @1@. + Please pass the location of these libs via -Dwith-rpi-lib-dir=/path. + '''.format(rpi_lib, rpi_lib_path)) + else + subdir_done() + endif + endif + mmal_deps += [l] +endforeach + +rpi_warn_flags = cc.get_supported_arguments([ + # vcos/mmal headers + '-Wno-redundant-decls', + # RaspiCapture.c + RaspiCamControl.c + '-Wno-discarded-qualifiers', + '-Wno-declaration-after-statement', + '-Wno-missing-prototypes', + '-Wno-missing-declarations', + '-Wno-stringop-truncation', +]) + +rpi_link_flags = cc.get_supported_link_arguments(['-Wl,--no-as-needed']) + +gnome = import('gnome') + +enums = gnome.mkenums_simple('gstrpicam-enum-types', + sources: 'gstrpicam_types.h', + identifier_prefix: 'GstRpiCamSrc', + symbol_prefix: 'gst_rpi_cam_src') + +gstrpicamsrc = library('gstrpicamsrc', + rpicamsrc_sources, enums, + c_args: [gst_plugins_good_args, rpi_inc_args, rpi_warn_flags], + link_args: rpi_link_flags, + include_directories: [configinc, libsinc], + dependencies: [gst_dep, gstbase_dep, gstvideo_dep] + mmal_deps, + override_options: ['b_asneeded=false'], + install_dir: plugins_install_dir, + install: true) + +pkgconfig.generate(gstrpicamsrc, install_dir: plugins_pkgconfig_install_dir) +plugins += [gstrpicamsrc] diff --git a/sys/v4l2/ext/types-compat.h b/sys/v4l2/ext/types-compat.h index ea21c9513f..f8d0dc2017 100644 --- a/sys/v4l2/ext/types-compat.h +++ b/sys/v4l2/ext/types-compat.h @@ -24,6 +24,8 @@ #ifndef __TYPES_COMPAT_H__ #define __TYPES_COMPAT_H__ +#define __user + #ifdef __linux__ #include #include diff --git a/sys/v4l2/ext/v4l2-common.h b/sys/v4l2/ext/v4l2-common.h index a2494047a7..08fd92f503 100644 --- a/sys/v4l2/ext/v4l2-common.h +++ b/sys/v4l2/ext/v4l2-common.h @@ -92,6 +92,7 @@ struct v4l2_edid { __u8 *edid; }; +#ifndef __KERNEL__ /* Backward compatibility target definitions --- to be removed. */ #define V4L2_SEL_TGT_CROP_ACTIVE V4L2_SEL_TGT_CROP #define V4L2_SEL_TGT_COMPOSE_ACTIVE V4L2_SEL_TGT_COMPOSE @@ -104,5 +105,6 @@ struct v4l2_edid { #define V4L2_SUBDEV_SEL_FLAG_SIZE_GE V4L2_SEL_FLAG_GE #define V4L2_SUBDEV_SEL_FLAG_SIZE_LE V4L2_SEL_FLAG_LE #define V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG V4L2_SEL_FLAG_KEEP_CONFIG +#endif #endif /* __V4L2_COMMON__ */ diff --git a/sys/v4l2/ext/v4l2-controls.h b/sys/v4l2/ext/v4l2-controls.h index 365182cae7..1464a34246 100644 --- a/sys/v4l2/ext/v4l2-controls.h +++ b/sys/v4l2/ext/v4l2-controls.h @@ -192,6 +192,12 @@ enum v4l2_colorfx { * We reserve 16 controls for this driver. */ #define V4L2_CID_USER_IMX_BASE (V4L2_CID_USER_BASE + 0x10b0) +/* + * The base for the atmel isc driver controls. + * We reserve 32 controls for this driver. + */ +#define V4L2_CID_USER_ATMEL_ISC_BASE (V4L2_CID_USER_BASE + 0x10c0) + /* MPEG-class control IDs */ /* The MPEG controls are applicable to all codec controls * and the 'MPEG' part of the define is historical */ @@ -394,9 +400,11 @@ enum v4l2_mpeg_video_multi_slice_mode { V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE = 0, V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB = 1, V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES = 2, +#ifndef __KERNEL__ /* Kept for backwards compatibility reasons. Stupid typo... */ V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB = 1, V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES = 2, +#endif }; #define V4L2_CID_MPEG_VIDEO_VBV_SIZE (V4L2_CID_MPEG_BASE+222) #define V4L2_CID_MPEG_VIDEO_DEC_PTS (V4L2_CID_MPEG_BASE+223) @@ -465,6 +473,10 @@ enum v4l2_mpeg_video_h264_level { V4L2_MPEG_VIDEO_H264_LEVEL_4_2 = 13, V4L2_MPEG_VIDEO_H264_LEVEL_5_0 = 14, V4L2_MPEG_VIDEO_H264_LEVEL_5_1 = 15, + V4L2_MPEG_VIDEO_H264_LEVEL_5_2 = 16, + V4L2_MPEG_VIDEO_H264_LEVEL_6_0 = 17, + V4L2_MPEG_VIDEO_H264_LEVEL_6_1 = 18, + V4L2_MPEG_VIDEO_H264_LEVEL_6_2 = 19, }; #define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA (V4L2_CID_MPEG_BASE+360) #define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA (V4L2_CID_MPEG_BASE+361) @@ -493,6 +505,7 @@ enum v4l2_mpeg_video_h264_profile { V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA = 14, V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH = 15, V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH = 16, + V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH = 17, }; #define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT (V4L2_CID_MPEG_BASE+364) #define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH (V4L2_CID_MPEG_BASE+365) @@ -910,6 +923,13 @@ enum v4l2_auto_focus_range { #define V4L2_CID_PAN_SPEED (V4L2_CID_CAMERA_CLASS_BASE+32) #define V4L2_CID_TILT_SPEED (V4L2_CID_CAMERA_CLASS_BASE+33) +#define V4L2_CID_CAMERA_ORIENTATION (V4L2_CID_CAMERA_CLASS_BASE+34) +#define V4L2_CAMERA_ORIENTATION_FRONT 0 +#define V4L2_CAMERA_ORIENTATION_BACK 1 +#define V4L2_CAMERA_ORIENTATION_EXTERNAL 2 + +#define V4L2_CID_CAMERA_SENSOR_ROTATION (V4L2_CID_CAMERA_CLASS_BASE+35) + /* FM Modulator class control IDs */ #define V4L2_CID_FM_TX_CLASS_BASE (V4L2_CTRL_CLASS_FM_TX | 0x900) @@ -1032,6 +1052,7 @@ enum v4l2_jpeg_chroma_subsampling { #define V4L2_CID_TEST_PATTERN_GREENR (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 5) #define V4L2_CID_TEST_PATTERN_BLUE (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 6) #define V4L2_CID_TEST_PATTERN_GREENB (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 7) +#define V4L2_CID_UNIT_CELL_SIZE (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 8) /* Image processing controls */ diff --git a/sys/v4l2/ext/videodev2.h b/sys/v4l2/ext/videodev2.h index f5c18a0606..8c356b3b0f 100644 --- a/sys/v4l2/ext/videodev2.h +++ b/sys/v4l2/ext/videodev2.h @@ -54,11 +54,13 @@ * Hans Verkuil * et al. */ -#ifndef __LINUX_VIDEODEV2_H -#define __LINUX_VIDEODEV2_H +#ifndef _UAPI__LINUX_VIDEODEV2_H +#define _UAPI__LINUX_VIDEODEV2_H +#ifndef __KERNEL__ #include #include +#endif #include "ext/types-compat.h" #include "ext/v4l2-common.h" @@ -169,6 +171,8 @@ enum v4l2_buf_type { || (type) == V4L2_BUF_TYPE_SDR_OUTPUT \ || (type) == V4L2_BUF_TYPE_META_OUTPUT) +#define V4L2_TYPE_IS_CAPTURE(type) (!V4L2_TYPE_IS_OUTPUT(type)) + enum v4l2_tuner_type { V4L2_TUNER_RADIO = 1, V4L2_TUNER_ANALOG_TV = 2, @@ -187,6 +191,8 @@ enum v4l2_memory { V4L2_MEMORY_DMABUF = 4, }; +#define V4L2_FLAG_MEMORY_NON_CONSISTENT (1 << 0) + /* see also http://vektor.theorem.ca/graphics/ycbcr/ */ enum v4l2_colorspace { /* @@ -324,12 +330,14 @@ enum v4l2_ycbcr_encoding { /* Rec. 709/EN 61966-2-4 Extended Gamut -- HDTV */ V4L2_YCBCR_ENC_XV709 = 4, +#ifndef __KERNEL__ /* * sYCC (Y'CbCr encoding of sRGB), identical to ENC_601. It was added * originally due to a misunderstanding of the sYCC standard. It should * not be used, instead use V4L2_YCBCR_ENC_601. */ V4L2_YCBCR_ENC_SYCC = 5, +#endif /* BT.2020 Non-constant Luminance Y'CbCr */ V4L2_YCBCR_ENC_BT2020 = 6, @@ -393,8 +401,10 @@ enum v4l2_quantization { * WARNING: Please don't use these deprecated defines in your code, as * there is a chance we have to remove them in the future. */ +#ifndef __KERNEL__ #define V4L2_COLORSPACE_ADOBERGB V4L2_COLORSPACE_OPRGB #define V4L2_XFER_FUNC_ADOBERGB V4L2_XFER_FUNC_OPRGB +#endif enum v4l2_priority { V4L2_PRIORITY_UNSET = 0, /* not initialized */ @@ -416,6 +426,11 @@ struct v4l2_fract { __u32 denominator; }; +struct v4l2_area { + __u32 width; + __u32 height; +}; + /** * struct v4l2_capability - Describes V4L2 device caps returned by VIDIOC_QUERYCAP * @@ -476,6 +491,8 @@ struct v4l2_capability { #define V4L2_CAP_TOUCH 0x10000000 /* Is a touch device */ +#define V4L2_CAP_IO_MC 0x20000000 /* Is input/output controlled by the media controller */ + #define V4L2_CAP_DEVICE_CAPS 0x80000000 /* sets device capabilities field */ /* @@ -554,6 +571,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_Y6 v4l2_fourcc('Y', '0', '6', ' ') /* 6 Greyscale */ #define V4L2_PIX_FMT_Y10 v4l2_fourcc('Y', '1', '0', ' ') /* 10 Greyscale */ #define V4L2_PIX_FMT_Y12 v4l2_fourcc('Y', '1', '2', ' ') /* 12 Greyscale */ +#define V4L2_PIX_FMT_Y14 v4l2_fourcc('Y', '1', '4', ' ') /* 14 Greyscale */ #define V4L2_PIX_FMT_Y16 v4l2_fourcc('Y', '1', '6', ' ') /* 16 Greyscale */ #define V4L2_PIX_FMT_Y16_BE v4l2_fourcc_be('Y', '1', '6', ' ') /* 16 Greyscale BE */ @@ -651,6 +669,10 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_SGBRG12P v4l2_fourcc('p', 'G', 'C', 'C') #define V4L2_PIX_FMT_SGRBG12P v4l2_fourcc('p', 'g', 'C', 'C') #define V4L2_PIX_FMT_SRGGB12P v4l2_fourcc('p', 'R', 'C', 'C') +#define V4L2_PIX_FMT_SBGGR14 v4l2_fourcc('B', 'G', '1', '4') /* 14 BGBG.. GRGR.. */ +#define V4L2_PIX_FMT_SGBRG14 v4l2_fourcc('G', 'B', '1', '4') /* 14 GBGB.. RGRG.. */ +#define V4L2_PIX_FMT_SGRBG14 v4l2_fourcc('G', 'R', '1', '4') /* 14 GRGR.. BGBG.. */ +#define V4L2_PIX_FMT_SRGGB14 v4l2_fourcc('R', 'G', '1', '4') /* 14 RGRG.. GBGB.. */ /* 14bit raw bayer packed, 7 bytes for every 4 pixels */ #define V4L2_PIX_FMT_SBGGR14P v4l2_fourcc('p', 'B', 'E', 'E') #define V4L2_PIX_FMT_SGBRG14P v4l2_fourcc('p', 'G', 'E', 'E') @@ -749,6 +771,7 @@ struct v4l2_pix_format { #define V4L2_META_FMT_VSP1_HGT v4l2_fourcc('V', 'S', 'P', 'T') /* R-Car VSP1 2-D Histogram */ #define V4L2_META_FMT_UVC v4l2_fourcc('U', 'V', 'C', 'H') /* UVC Payload Header metadata */ #define V4L2_META_FMT_D4XX v4l2_fourcc('D', '4', 'X', 'X') /* D4XX Payload Header metadata */ +#define V4L2_META_FMT_VIVID v4l2_fourcc('V', 'I', 'V', 'D') /* Vivid Metadata */ /* priv field value to indicates that subsequent fields are valid. */ #define V4L2_PIX_FMT_PRIV_MAGIC 0xfeedcafe @@ -765,13 +788,15 @@ struct v4l2_fmtdesc { __u32 flags; __u8 description[32]; /* Description string */ __u32 pixelformat; /* Format fourcc */ - __u32 reserved[4]; + __u32 mbus_code; /* Media bus code */ + __u32 reserved[3]; }; #define V4L2_FMT_FLAG_COMPRESSED 0x0001 #define V4L2_FMT_FLAG_EMULATED 0x0002 #define V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM 0x0004 #define V4L2_FMT_FLAG_DYN_RESOLUTION 0x0008 +#define V4L2_FMT_FLAG_ENC_CAP_FRAME_INTERVAL 0x0010 /* Frame Size and frame rate enumeration */ /* @@ -900,20 +925,44 @@ struct v4l2_jpegcompression { /* * M E M O R Y - M A P P I N G B U F F E R S */ + +#ifdef __KERNEL__ +/* + * This corresponds to the user space version of timeval + * for 64-bit time_t. sparc64 is different from everyone + * else, using the microseconds in the wrong half of the + * second 64-bit word. + */ +struct __kernel_v4l2_timeval { + long long tv_sec; +#if defined(__sparc__) && defined(__arch64__) + int tv_usec; + int __pad; +#else + long long tv_usec; +#endif +}; +#endif + struct v4l2_requestbuffers { __u32 count; __u32 type; /* enum v4l2_buf_type */ __u32 memory; /* enum v4l2_memory */ __u32 capabilities; - __u32 reserved[1]; + union { + __u32 flags; + __u32 reserved[1]; + }; }; /* capabilities for struct v4l2_requestbuffers and v4l2_create_buffers */ -#define V4L2_BUF_CAP_SUPPORTS_MMAP (1 << 0) -#define V4L2_BUF_CAP_SUPPORTS_USERPTR (1 << 1) -#define V4L2_BUF_CAP_SUPPORTS_DMABUF (1 << 2) -#define V4L2_BUF_CAP_SUPPORTS_REQUESTS (1 << 3) -#define V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS (1 << 4) +#define V4L2_BUF_CAP_SUPPORTS_MMAP (1 << 0) +#define V4L2_BUF_CAP_SUPPORTS_USERPTR (1 << 1) +#define V4L2_BUF_CAP_SUPPORTS_DMABUF (1 << 2) +#define V4L2_BUF_CAP_SUPPORTS_REQUESTS (1 << 3) +#define V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS (1 << 4) +#define V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF (1 << 5) +#define V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS (1 << 6) /** * struct v4l2_plane - plane info for multi-planar buffers @@ -984,7 +1033,11 @@ struct v4l2_buffer { __u32 bytesused; __u32 flags; __u32 field; +#ifdef __KERNEL__ + struct __kernel_v4l2_timeval timestamp; +#else struct timeval timestamp; +#endif struct v4l2_timecode timecode; __u32 sequence; @@ -1004,6 +1057,7 @@ struct v4l2_buffer { }; }; +#ifndef __KERNEL__ /** * v4l2_timeval_to_ns - Convert timeval to nanoseconds * @ts: pointer to the timeval variable to be converted @@ -1011,10 +1065,11 @@ struct v4l2_buffer { * Returns the scalar nanosecond representation of the timeval * parameter. */ -static __inline__ __u64 v4l2_timeval_to_ns(const struct timeval *tv) +static inline __u64 v4l2_timeval_to_ns(const struct timeval *tv) { return (__u64)tv->tv_sec * 1000000000ULL + tv->tv_usec * 1000; } +#endif /* Flags for 'flags' field */ /* Buffer is mapped (flag) */ @@ -1035,6 +1090,8 @@ static __inline__ __u64 v4l2_timeval_to_ns(const struct timeval *tv) #define V4L2_BUF_FLAG_IN_REQUEST 0x00000080 /* timecode field is valid */ #define V4L2_BUF_FLAG_TIMECODE 0x00000100 +/* Don't return the capture buffer until OUTPUT timestamp changes */ +#define V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF 0x00000200 /* Buffer is prepared for queuing */ #define V4L2_BUF_FLAG_PREPARED 0x00000400 /* Cache handling flags */ @@ -1121,16 +1178,16 @@ struct v4l2_framebuffer { struct v4l2_clip { struct v4l2_rect c; - struct v4l2_clip *next; + struct v4l2_clip __user *next; }; struct v4l2_window { struct v4l2_rect w; __u32 field; /* enum v4l2_field */ __u32 chromakey; - struct v4l2_clip *clips; + struct v4l2_clip __user *clips; __u32 clipcount; - void *bitmap; + void __user *bitmap; __u8 global_alpha; }; @@ -1202,6 +1259,10 @@ struct v4l2_selection { typedef __u64 v4l2_std_id; +/* + * Attention: Keep the V4L2_STD_* bit definitions in sync with + * include/dt-bindings/display/sdtv-standards.h SDTV_STD_* bit definitions. + */ /* one bit for each */ #define V4L2_STD_PAL_B ((v4l2_std_id)0x00000001) #define V4L2_STD_PAL_B1 ((v4l2_std_id)0x00000002) @@ -1665,17 +1726,20 @@ struct v4l2_ext_control { union { __s32 value; __s64 value64; - char *string; - __u8 *p_u8; - __u16 *p_u16; - __u32 *p_u32; - void *ptr; + char __user *string; + __u8 __user *p_u8; + __u16 __user *p_u16; + __u32 __user *p_u32; + struct v4l2_area __user *p_area; + void __user *ptr; }; } __attribute__ ((packed)); struct v4l2_ext_controls { union { +#ifndef __KERNEL__ __u32 ctrl_class; +#endif __u32 which; }; __u32 count; @@ -1686,7 +1750,9 @@ struct v4l2_ext_controls { }; #define V4L2_CTRL_ID_MASK (0x0fffffff) +#ifndef __KERNEL__ #define V4L2_CTRL_ID2CLASS(id) ((id) & 0x0fff0000UL) +#endif #define V4L2_CTRL_ID2WHICH(id) ((id) & 0x0fff0000UL) #define V4L2_CTRL_DRIVER_PRIV(id) (((id) & 0xffff) >= 0x1000) #define V4L2_CTRL_MAX_DIMS (4) @@ -1710,6 +1776,7 @@ enum v4l2_ctrl_type { V4L2_CTRL_TYPE_U8 = 0x0100, V4L2_CTRL_TYPE_U16 = 0x0101, V4L2_CTRL_TYPE_U32 = 0x0102, + V4L2_CTRL_TYPE_AREA = 0x0106, }; /* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */ @@ -1965,6 +2032,7 @@ struct v4l2_encoder_cmd { #define V4L2_DEC_CMD_STOP (1) #define V4L2_DEC_CMD_PAUSE (2) #define V4L2_DEC_CMD_RESUME (3) +#define V4L2_DEC_CMD_FLUSH (4) /* Flags for V4L2_DEC_CMD_START */ #define V4L2_DEC_CMD_START_MUTE_AUDIO (1 << 0) @@ -2317,7 +2385,11 @@ struct v4l2_event { } u; __u32 pending; __u32 sequence; +#ifdef __KERNEL__ + struct __kernel_timespec timestamp; +#else struct timespec timestamp; +#endif __u32 id; __u32 reserved[8]; }; @@ -2384,6 +2456,9 @@ struct v4l2_dbg_chip_info { * @memory: enum v4l2_memory; buffer memory type * @format: frame format, for which buffers are requested * @capabilities: capabilities of this buffer type. + * @flags: additional buffer management attributes (ignored unless the + * queue has V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS capability + * and configured for MMAP streaming I/O). * @reserved: future extensions */ struct v4l2_create_buffers { @@ -2392,7 +2467,8 @@ struct v4l2_create_buffers { __u32 memory; struct v4l2_format format; __u32 capabilities; - __u32 reserved[7]; + __u32 flags; + __u32 reserved[6]; }; /* @@ -2500,4 +2576,4 @@ struct v4l2_create_buffers { #define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */ -#endif /* __LINUX_VIDEODEV2_H */ +#endif /* _UAPI__LINUX_VIDEODEV2_H */ diff --git a/sys/v4l2/gstv4l2allocator.c b/sys/v4l2/gstv4l2allocator.c index 5d95e55296..e82a8532d6 100644 --- a/sys/v4l2/gstv4l2allocator.c +++ b/sys/v4l2/gstv4l2allocator.c @@ -812,6 +812,9 @@ gst_v4l2_allocator_orphan (GstV4l2Allocator * allocator) GST_OBJECT_FLAG_SET (allocator, GST_V4L2_ALLOCATOR_FLAG_ORPHANED); + if (!g_atomic_int_get (&allocator->active)) + return TRUE; + if (obj->ioctl (obj->video_fd, VIDIOC_REQBUFS, &breq) < 0) { GST_ERROR_OBJECT (allocator, "error orphaning buffers buffers: %s", g_strerror (errno)); @@ -1363,7 +1366,7 @@ gst_v4l2_allocator_dqbuf (GstV4l2Allocator * allocator, offset = group->planes[i].data_offset; - if (group->planes[i].bytesused > group->planes[i].data_offset) { + if (group->planes[i].bytesused >= group->planes[i].data_offset) { size = group->planes[i].bytesused - group->planes[i].data_offset; } else { GST_WARNING_OBJECT (allocator, "V4L2 provided buffer has bytesused %" diff --git a/sys/v4l2/gstv4l2bufferpool.c b/sys/v4l2/gstv4l2bufferpool.c index 861885b79a..0830b6cf4d 100644 --- a/sys/v4l2/gstv4l2bufferpool.c +++ b/sys/v4l2/gstv4l2bufferpool.c @@ -463,11 +463,15 @@ gst_v4l2_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buffer, } /* add metadata to raw video buffers */ - if (pool->add_videometa) - gst_buffer_add_video_meta_full (newbuf, GST_VIDEO_FRAME_FLAG_NONE, + if (pool->add_videometa) { + GstVideoMeta *videometa = + gst_buffer_add_video_meta_full (newbuf, GST_VIDEO_FRAME_FLAG_NONE, GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_N_PLANES (info), info->offset, info->stride); + if (videometa) + gst_video_meta_set_alignment (videometa, obj->align); + } *buffer = newbuf; @@ -551,9 +555,9 @@ gst_v4l2_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config) | GST_V4L2_ALLOCATOR_FLAG_DMABUF_CREATE_BUFS); } - if (min_buffers < GST_V4L2_MIN_BUFFERS) { + if (min_buffers < GST_V4L2_MIN_BUFFERS (obj)) { updated = TRUE; - min_buffers = GST_V4L2_MIN_BUFFERS; + min_buffers = GST_V4L2_MIN_BUFFERS (obj); GST_INFO_OBJECT (pool, "increasing minimum buffers to %u", min_buffers); } @@ -650,13 +654,18 @@ gst_v4l2_buffer_pool_streamon (GstV4l2BufferPool * pool) case GST_V4L2_IO_DMABUF: case GST_V4L2_IO_DMABUF_IMPORT: if (!V4L2_TYPE_IS_OUTPUT (pool->obj->type)) { - guint i; + guint num_queued; + guint i, n = 0; + + num_queued = g_atomic_int_get (&pool->num_queued); + if (num_queued < pool->num_allocated) + n = pool->num_allocated - num_queued; /* For captures, we need to enqueue buffers before we start streaming, * so the driver don't underflow immediately. As we have put then back * into the base class queue, resurrect them, then releasing will queue * them back. */ - for (i = 0; i < pool->num_allocated; i++) + for (i = 0; i < n; i++) gst_v4l2_buffer_pool_resurrect_buffer (pool); } @@ -766,7 +775,7 @@ gst_v4l2_buffer_pool_start (GstBufferPool * bpool) &max_buffers)) goto wrong_config; - min_latency = MAX (GST_V4L2_MIN_BUFFERS, obj->min_buffers); + min_latency = MAX (GST_V4L2_MIN_BUFFERS (obj), obj->min_buffers); switch (obj->mode) { case GST_V4L2_IO_RW: @@ -795,7 +804,7 @@ gst_v4l2_buffer_pool_start (GstBufferPool * bpool) V4L2_MEMORY_MMAP); pool->num_allocated = count; - if (count < GST_V4L2_MIN_BUFFERS) { + if (count < GST_V4L2_MIN_BUFFERS (obj)) { min_buffers = count; goto no_buffers; } @@ -825,6 +834,7 @@ gst_v4l2_buffer_pool_start (GstBufferPool * bpool) count = gst_v4l2_allocator_start (pool->vallocator, min_buffers, V4L2_MEMORY_USERPTR); + pool->num_allocated = count; /* There is no rational to not get what we asked */ if (count < min_buffers) { @@ -845,6 +855,7 @@ gst_v4l2_buffer_pool_start (GstBufferPool * bpool) count = gst_v4l2_allocator_start (pool->vallocator, min_buffers, V4L2_MEMORY_DMABUF); + pool->num_allocated = count; /* There is no rational to not get what we asked */ if (count < min_buffers) { @@ -886,7 +897,7 @@ gst_v4l2_buffer_pool_start (GstBufferPool * bpool) goto start_failed; if (!V4L2_TYPE_IS_OUTPUT (obj->type)) { - if (g_atomic_int_get (&pool->num_queued) < min_buffers) + if (g_atomic_int_get (&pool->num_queued) < pool->num_allocated) goto queue_failed; pool->group_released_handler = @@ -908,7 +919,7 @@ gst_v4l2_buffer_pool_start (GstBufferPool * bpool) { GST_ERROR_OBJECT (pool, "we received %d buffer from device '%s', we want at least %d", - min_buffers, obj->videodev, GST_V4L2_MIN_BUFFERS); + min_buffers, obj->videodev, GST_V4L2_MIN_BUFFERS (obj)); gst_structure_free (config); return FALSE; } @@ -957,9 +968,6 @@ gst_v4l2_buffer_pool_stop (GstBufferPool * bpool) GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool); gboolean ret; - if (pool->orphaned) - return gst_v4l2_buffer_pool_vallocator_stop (pool); - GST_DEBUG_OBJECT (pool, "stopping pool"); if (pool->group_released_handler > 0) { @@ -974,7 +982,8 @@ gst_v4l2_buffer_pool_stop (GstBufferPool * bpool) pool->other_pool = NULL; } - gst_v4l2_buffer_pool_streamoff (pool); + if (!pool->orphaned) + gst_v4l2_buffer_pool_streamoff (pool); ret = GST_BUFFER_POOL_CLASS (parent_class)->stop (bpool); @@ -990,6 +999,8 @@ gst_v4l2_buffer_pool_orphan (GstBufferPool ** bpool) GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (*bpool); gboolean ret; + g_return_val_if_fail (pool->orphaned == FALSE, FALSE); + if (!GST_V4L2_ALLOCATOR_CAN_ORPHAN_BUFS (pool->vallocator)) return FALSE; @@ -997,25 +1008,24 @@ gst_v4l2_buffer_pool_orphan (GstBufferPool ** bpool) return FALSE; GST_DEBUG_OBJECT (pool, "orphaning pool"); - gst_buffer_pool_set_active (*bpool, FALSE); - /* - * If the buffer pool has outstanding buffers, it will not be stopped - * by the base class when set inactive. Stop it manually and mark it - * as orphaned - */ - ret = gst_v4l2_buffer_pool_stop (*bpool); - if (!ret) - ret = gst_v4l2_allocator_orphan (pool->vallocator); - if (!ret) - goto orphan_failed; + /* We lock to prevent racing with a return buffer in QBuf, and has a + * workaround of not being able to use the pool hidden activation lock. */ + GST_OBJECT_LOCK (pool); - pool->orphaned = TRUE; - gst_object_unref (*bpool); - *bpool = NULL; + gst_v4l2_buffer_pool_streamoff (pool); + ret = gst_v4l2_allocator_orphan (pool->vallocator); + if (ret) + pool->orphaned = TRUE; + + GST_OBJECT_UNLOCK (pool); + + if (ret) { + gst_object_unref (*bpool); + *bpool = NULL; + } -orphan_failed: return ret; } @@ -1033,7 +1043,7 @@ gst_v4l2_buffer_pool_flush_start (GstBufferPool * bpool) g_cond_broadcast (&pool->empty_cond); GST_OBJECT_UNLOCK (pool); - if (pool->other_pool) + if (pool->other_pool && gst_buffer_pool_is_active (pool->other_pool)) gst_buffer_pool_set_flushing (pool->other_pool, TRUE); } @@ -1044,7 +1054,7 @@ gst_v4l2_buffer_pool_flush_stop (GstBufferPool * bpool) GST_DEBUG_OBJECT (pool, "stop flushing"); - if (pool->other_pool) + if (pool->other_pool && gst_buffer_pool_is_active (pool->other_pool)) gst_buffer_pool_set_flushing (pool->other_pool, FALSE); gst_poll_set_flushing (pool->poll, FALSE); @@ -1149,22 +1159,12 @@ gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstBuffer * buf, if (V4L2_TYPE_IS_OUTPUT (obj->type)) { enum v4l2_field field; - /* Except when field is set to alternate, buffer field is the same as - * the one defined in format */ + /* Buffer field is the same as the one defined in format */ if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) field = obj->format.fmt.pix_mp.field; else field = obj->format.fmt.pix.field; - /* NB: At this moment, we can't have alternate mode because it not handled - * yet */ - if (field == V4L2_FIELD_ALTERNATE) { - if (GST_BUFFER_FLAG_IS_SET (buf, GST_VIDEO_FRAME_FLAG_TFF)) - field = V4L2_FIELD_TOP; - else - field = V4L2_FIELD_BOTTOM; - } - group->buffer.field = field; } @@ -1174,6 +1174,13 @@ gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstBuffer * buf, } GST_OBJECT_LOCK (pool); + + /* If the pool was orphaned, don't try to queue any returned buffers. + * This is done with the objet lock in order to synchronize with + * orphaning. */ + if (pool->orphaned) + goto was_orphaned; + g_atomic_int_inc (&pool->num_queued); pool->buffers[index] = buf; @@ -1191,6 +1198,13 @@ gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstBuffer * buf, GST_ERROR_OBJECT (pool, "the buffer %i was already queued", index); return GST_FLOW_ERROR; } +was_orphaned: + { + GST_DEBUG_OBJECT (pool, "pool was orphaned, not queuing back buffer."); + GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_TAG_MEMORY); + GST_OBJECT_UNLOCK (pool); + return GST_FLOW_FLUSHING; + } queue_failed: { GST_ERROR_OBJECT (pool, "could not queue a buffer %i", index); @@ -1303,6 +1317,14 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer, GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED); GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_FLAG_TFF); break; + case V4L2_FIELD_TOP: + GST_BUFFER_FLAG_SET (outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED); + GST_BUFFER_FLAG_SET (outbuf, GST_VIDEO_BUFFER_FLAG_TOP_FIELD); + break; + case V4L2_FIELD_BOTTOM: + GST_BUFFER_FLAG_SET (outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED); + GST_BUFFER_FLAG_SET (outbuf, GST_VIDEO_BUFFER_FLAG_BOTTOM_FIELD); + break; case V4L2_FIELD_INTERLACED_TB: GST_BUFFER_FLAG_SET (outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED); GST_BUFFER_FLAG_SET (outbuf, GST_VIDEO_BUFFER_FLAG_TFF); @@ -1463,14 +1485,6 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer) GST_DEBUG_OBJECT (pool, "release buffer %p", buffer); - /* If the buffer's pool has been orphaned, dispose of it so that - * the pool resources can be freed */ - if (pool->orphaned) { - GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY); - pclass->release_buffer (bpool, buffer); - return; - } - switch (obj->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: @@ -1669,8 +1683,9 @@ gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps) /* setting a significant unique name */ parent_name = gst_object_get_name (GST_OBJECT (obj->element)); - name = g_strconcat (parent_name, ":", "pool:", - V4L2_TYPE_IS_OUTPUT (obj->type) ? "sink" : "src", NULL); + name = g_strdup_printf ("%s:pool%u:%s", + parent_name, obj->pool_seq++, + V4L2_TYPE_IS_OUTPUT (obj->type) ? "sink" : "src"); g_free (parent_name); pool = (GstV4l2BufferPool *) g_object_new (GST_TYPE_V4L2_BUFFER_POOL, diff --git a/sys/v4l2/gstv4l2codec.c b/sys/v4l2/gstv4l2codec.c index 7ebc65026b..11223438d8 100644 --- a/sys/v4l2/gstv4l2codec.c +++ b/sys/v4l2/gstv4l2codec.c @@ -34,20 +34,19 @@ #include -static GValue * -probe_controls (gint video_fd, guint32 cid, - const gchar * (transform_control) (gint)) +gboolean +gst_v4l2_codec_probe_profiles (const GstV4l2Codec * codec, gint video_fd, + GValue * profiles) { - GValue *controls = NULL; struct v4l2_queryctrl query_ctrl; + gboolean ret = FALSE; memset (&query_ctrl, 0, sizeof (query_ctrl)); - query_ctrl.id = cid; + query_ctrl.id = codec->profile_cid; if (ioctl (video_fd, VIDIOC_QUERYCTRL, &query_ctrl) == 0) { - if (query_ctrl.flags & V4L2_CTRL_FLAG_DISABLED) { - return NULL; - } + if (query_ctrl.flags & V4L2_CTRL_FLAG_DISABLED) + return FALSE; if (query_ctrl.type == V4L2_CTRL_TYPE_MENU) { struct v4l2_querymenu query_menu; @@ -55,48 +54,43 @@ probe_controls (gint video_fd, guint32 cid, memset (&query_menu, 0, sizeof (query_menu)); query_menu.id = query_ctrl.id; - controls = g_new0 (GValue, 1); - g_value_init (controls, GST_TYPE_LIST); + g_value_init (profiles, GST_TYPE_LIST); for (query_menu.index = query_ctrl.minimum; query_menu.index <= query_ctrl.maximum; query_menu.index++) { if (ioctl (video_fd, VIDIOC_QUERYMENU, &query_menu) >= 0) { GValue value = G_VALUE_INIT; g_value_init (&value, G_TYPE_STRING); - g_value_set_string (&value, transform_control (query_menu.index)); - gst_value_list_append_and_take_value (controls, &value); + g_value_set_string (&value, + codec->profile_to_string (query_menu.index)); + gst_value_list_append_and_take_value (profiles, &value); + ret = TRUE; } } - if (gst_value_list_get_size (controls) == 0) { - g_value_unset (controls); - controls = NULL; + + if (gst_value_list_get_size (profiles) == 0) { + g_value_unset (profiles); + ret = FALSE; } } } - return controls; -} - -GValue * -gst_v4l2_codec_probe_profiles (const GstV4l2Codec * codec, gint video_fd) -{ - return probe_controls (video_fd, codec->profile_cid, - codec->profile_to_string); + return ret; } -GValue * -gst_v4l2_codec_probe_levels (const GstV4l2Codec * codec, gint video_fd) +gboolean +gst_v4l2_codec_probe_levels (const GstV4l2Codec * codec, gint video_fd, + GValue * levels) { - GValue *controls = NULL; struct v4l2_queryctrl query_ctrl; + gboolean ret = FALSE; memset (&query_ctrl, 0, sizeof (query_ctrl)); query_ctrl.id = codec->level_cid; if (ioctl (video_fd, VIDIOC_QUERYCTRL, &query_ctrl) == 0) { - if (query_ctrl.flags & V4L2_CTRL_FLAG_DISABLED) { - return NULL; - } + if (query_ctrl.flags & V4L2_CTRL_FLAG_DISABLED) + return FALSE; if (query_ctrl.type == V4L2_CTRL_TYPE_MENU) { struct v4l2_querymenu query_menu; @@ -108,8 +102,7 @@ gst_v4l2_codec_probe_levels (const GstV4l2Codec * codec, gint video_fd) if (ioctl (video_fd, VIDIOC_QUERYMENU, &query_menu) >= 0) { gint32 i; - controls = g_new0 (GValue, 1); - g_value_init (controls, GST_TYPE_LIST); + g_value_init (levels, GST_TYPE_LIST); /* Assume that all levels below the highest one reported by the driver are supported. */ for (i = query_ctrl.minimum; i <= query_ctrl.maximum; i++) { @@ -117,11 +110,17 @@ gst_v4l2_codec_probe_levels (const GstV4l2Codec * codec, gint video_fd) g_value_init (&value, G_TYPE_STRING); g_value_set_string (&value, codec->level_to_string (i)); - gst_value_list_append_and_take_value (controls, &value); + gst_value_list_append_and_take_value (levels, &value); + ret = TRUE; + } + + if (gst_value_list_get_size (levels) == 0) { + g_value_unset (levels); + ret = FALSE; } } } } - return controls; + return ret; } diff --git a/sys/v4l2/gstv4l2codec.h b/sys/v4l2/gstv4l2codec.h index 47161dc9ca..23b85a2c64 100644 --- a/sys/v4l2/gstv4l2codec.h +++ b/sys/v4l2/gstv4l2codec.h @@ -40,8 +40,10 @@ struct _GstV4l2Codec { }; -GValue * gst_v4l2_codec_probe_profiles(const GstV4l2Codec * codec, gint video_fd); -GValue * gst_v4l2_codec_probe_levels(const GstV4l2Codec * codec, gint video_fd); +gboolean gst_v4l2_codec_probe_profiles(const GstV4l2Codec * codec, gint video_fd, + GValue * value); +gboolean gst_v4l2_codec_probe_levels(const GstV4l2Codec * codec, gint video_fd, + GValue * value); G_END_DECLS diff --git a/sys/v4l2/gstv4l2deviceprovider.c b/sys/v4l2/gstv4l2deviceprovider.c index 8f6e9ea8ba..83efe0a8de 100644 --- a/sys/v4l2/gstv4l2deviceprovider.c +++ b/sys/v4l2/gstv4l2deviceprovider.c @@ -116,7 +116,7 @@ gst_v4l2_device_provider_probe_device (GstV4l2DeviceProvider * provider, v4l2obj = gst_v4l2_object_new (NULL, GST_OBJECT (provider), V4L2_BUF_TYPE_VIDEO_CAPTURE, device_path, NULL, NULL, NULL); - if (!gst_v4l2_open (v4l2obj)) + if (!gst_v4l2_open (v4l2obj, NULL)) goto destroy; gst_structure_set (props, "device.api", G_TYPE_STRING, "v4l2", NULL); diff --git a/sys/v4l2/gstv4l2h264codec.c b/sys/v4l2/gstv4l2h264codec.c index 26a80ecd13..2ba16f5030 100644 --- a/sys/v4l2/gstv4l2h264codec.c +++ b/sys/v4l2/gstv4l2h264codec.c @@ -68,6 +68,8 @@ v4l2_profile_from_string (const gchar * profile) v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH; } else if (g_str_equal (profile, "multiview-high")) { v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH; + } else if (g_str_equal (profile, "constrained-high")) { + v4l2_profile = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH; } else { GST_WARNING ("Unsupported profile string '%s'", profile); } @@ -113,6 +115,8 @@ v4l2_profile_to_string (gint v4l2_profile) return "stereo-high"; case V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH: return "multiview-high"; + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH: + return "constrained-high"; default: GST_WARNING ("Unsupported V4L2 profile %i", v4l2_profile); break; @@ -158,6 +162,14 @@ v4l2_level_from_string (const gchar * level) v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_5_0; else if (g_str_equal (level, "5.1")) v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_5_1; + else if (g_str_equal (level, "5.2")) + v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_5_2; + else if (g_str_equal (level, "6")) + v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_6_0; + else if (g_str_equal (level, "6.1")) + v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_6_1; + else if (g_str_equal (level, "6.2")) + v4l2_level = V4L2_MPEG_VIDEO_H264_LEVEL_6_2; else GST_WARNING ("Unsupported level '%s'", level); @@ -200,6 +212,14 @@ v4l2_level_to_string (gint v4l2_level) return "5"; case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: return "5.1"; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_2: + return "5.2"; + case V4L2_MPEG_VIDEO_H264_LEVEL_6_0: + return "6"; + case V4L2_MPEG_VIDEO_H264_LEVEL_6_1: + return "6.1"; + case V4L2_MPEG_VIDEO_H264_LEVEL_6_2: + return "6.2"; default: GST_WARNING ("Unsupported V4L2 level %i", v4l2_level); break; diff --git a/sys/v4l2/gstv4l2h265codec.c b/sys/v4l2/gstv4l2h265codec.c index 7186da8cdd..df7c2a7b6b 100644 --- a/sys/v4l2/gstv4l2h265codec.c +++ b/sys/v4l2/gstv4l2h265codec.c @@ -37,9 +37,9 @@ v4l2_profile_from_string (const gchar * profile) if (g_str_equal (profile, "main")) { v4l2_profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN; - } else if (g_str_equal (profile, "mainstillpicture")) { + } else if (g_str_equal (profile, "main-still-picture")) { v4l2_profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE; - } else if (g_str_equal (profile, "main10")) { + } else if (g_str_equal (profile, "main-10")) { v4l2_profile = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10; } else { GST_WARNING ("Unsupported profile string '%s'", profile); @@ -55,9 +55,9 @@ v4l2_profile_to_string (gint v4l2_profile) case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN: return "main"; case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE: - return "mainstillpicture"; + return "main-still-picture"; case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10: - return "main10"; + return "main-10"; default: GST_WARNING ("Unsupported V4L2 profile %i", v4l2_profile); break; diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c index f348c38a81..cf32bd6bfc 100644 --- a/sys/v4l2/gstv4l2object.c +++ b/sys/v4l2/gstv4l2object.c @@ -425,6 +425,9 @@ gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class, "When enabled, the pixel aspect ratio will be enforced", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_type_mark_as_plugin_api (GST_TYPE_V4L2_DEVICE_FLAGS, 0); + gst_type_mark_as_plugin_api (GST_TYPE_V4L2_TV_NORM, 0); + gst_type_mark_as_plugin_api (GST_TYPE_V4L2_IO_MODE, 0); } void @@ -551,7 +554,7 @@ gst_v4l2_object_destroy (GstV4l2Object * v4l2object) g_return_if_fail (v4l2object != NULL); g_free (v4l2object->videodev); - + g_free (v4l2object->par); g_free (v4l2object->channel); if (v4l2object->formats) { @@ -893,9 +896,9 @@ gst_v4l2_set_defaults (GstV4l2Object * v4l2object) } gboolean -gst_v4l2_object_open (GstV4l2Object * v4l2object) +gst_v4l2_object_open (GstV4l2Object * v4l2object, GstV4l2Error * error) { - if (gst_v4l2_open (v4l2object)) + if (gst_v4l2_open (v4l2object, error)) gst_v4l2_set_defaults (v4l2object); else return FALSE; @@ -1326,7 +1329,7 @@ gst_v4l2_object_v4l2fourcc_to_video_format (guint32 fourcc) format = GST_VIDEO_FORMAT_ABGR; break; case V4L2_PIX_FMT_RGBA32: - format = GST_VIDEO_FORMAT_RGB; + format = GST_VIDEO_FORMAT_RGBA; break; case V4L2_PIX_FMT_ARGB32: format = GST_VIDEO_FORMAT_ARGB; @@ -1617,15 +1620,35 @@ gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc) return template; } +/* Add an 'alternate' variant of the caps with the feature */ +static void +add_alternate_variant (GstV4l2Object * v4l2object, GstCaps * caps, + GstStructure * structure) +{ + GstStructure *alt_s; + + if (v4l2object && v4l2object->never_interlaced) + return; + + if (!gst_structure_has_name (structure, "video/x-raw")) + return; + + alt_s = gst_structure_copy (structure); + gst_structure_set (alt_s, "interlace-mode", G_TYPE_STRING, "alternate", NULL); + + gst_caps_append_structure_full (caps, alt_s, + gst_caps_features_new (GST_CAPS_FEATURE_FORMAT_INTERLACED, NULL)); +} static GstCaps * gst_v4l2_object_get_caps_helper (GstV4L2FormatFlags flags) { GstStructure *structure; - GstCaps *caps; + GstCaps *caps, *caps_interlaced; guint i; caps = gst_caps_new_empty (); + caps_interlaced = gst_caps_new_empty (); for (i = 0; i < GST_V4L2_FORMAT_COUNT; i++) { if ((gst_v4l2_formats[i].flags & flags) == 0) @@ -1658,12 +1681,19 @@ gst_v4l2_object_get_caps_helper (GstV4L2FormatFlags flags) gst_caps_append_structure (caps, structure); - if (alt_s) + if (alt_s) { gst_caps_append_structure (caps, alt_s); + add_alternate_variant (NULL, caps_interlaced, alt_s); + } + + add_alternate_variant (NULL, caps_interlaced, structure); } } - return gst_caps_simplify (caps); + caps = gst_caps_simplify (caps); + caps_interlaced = gst_caps_simplify (caps_interlaced); + + return gst_caps_merge (caps, caps_interlaced); } GstCaps * @@ -1827,6 +1857,10 @@ gst_v4l2_object_get_caps_info (GstV4l2Object * v4l2object, GstCaps * caps, case GST_VIDEO_FORMAT_GRAY16_BE: fourcc = V4L2_PIX_FMT_Y16_BE; break; + case GST_VIDEO_FORMAT_BGR15: + fourcc = V4L2_PIX_FMT_RGB555X; + fourcc_nc = V4L2_PIX_FMT_XRGB555X; + break; default: break; } @@ -1971,7 +2005,7 @@ gst_v4l2_object_get_interlace_mode (enum v4l2_field field, case V4L2_FIELD_ANY: GST_ERROR ("Driver bug detected - check driver with v4l2-compliance from http://git.linuxtv.org/v4l-utils.git\n"); - /* fallthrough */ + return FALSE; case V4L2_FIELD_NONE: *interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE; return TRUE; @@ -1980,6 +2014,9 @@ gst_v4l2_object_get_interlace_mode (enum v4l2_field field, case V4L2_FIELD_INTERLACED_BT: *interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED; return TRUE; + case V4L2_FIELD_ALTERNATE: + *interlace_mode = GST_VIDEO_INTERLACE_MODE_ALTERNATE; + return TRUE; default: GST_ERROR ("Unknown enum v4l2_field %d", field); return FALSE; @@ -1987,8 +2024,8 @@ gst_v4l2_object_get_interlace_mode (enum v4l2_field field, } static gboolean -gst_v4l2_object_get_colorspace (struct v4l2_format *fmt, - GstVideoColorimetry * cinfo) +gst_v4l2_object_get_colorspace (GstV4l2Object * v4l2object, + struct v4l2_format *fmt, GstVideoColorimetry * cinfo) { gboolean is_rgb = gst_v4l2_object_v4l2fourcc_is_rgb (fmt->fmt.pix.pixelformat); @@ -2015,7 +2052,7 @@ gst_v4l2_object_get_colorspace (struct v4l2_format *fmt, case V4L2_COLORSPACE_SMPTE170M: cinfo->range = GST_VIDEO_COLOR_RANGE_16_235; cinfo->matrix = GST_VIDEO_COLOR_MATRIX_BT601; - cinfo->transfer = GST_VIDEO_TRANSFER_BT709; + cinfo->transfer = GST_VIDEO_TRANSFER_BT601; cinfo->primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE170M; break; case V4L2_COLORSPACE_REC709: @@ -2144,8 +2181,13 @@ gst_v4l2_object_get_colorspace (struct v4l2_format *fmt, case V4L2_XFER_FUNC_709: if (colorspace == V4L2_COLORSPACE_BT2020 && fmt->fmt.pix.height >= 2160) cinfo->transfer = GST_VIDEO_TRANSFER_BT2020_12; + else if (colorspace == V4L2_COLORSPACE_SMPTE170M) + cinfo->transfer = GST_VIDEO_TRANSFER_BT601; else cinfo->transfer = GST_VIDEO_TRANSFER_BT709; + + if (v4l2object->transfer) + cinfo->transfer = v4l2object->transfer; break; case V4L2_XFER_FUNC_SRGB: cinfo->transfer = GST_VIDEO_TRANSFER_SRGB; @@ -2159,6 +2201,9 @@ gst_v4l2_object_get_colorspace (struct v4l2_format *fmt, case V4L2_XFER_FUNC_NONE: cinfo->transfer = GST_VIDEO_TRANSFER_GAMMA10; break; + case V4L2_XFER_FUNC_SMPTE2084: + cinfo->transfer = GST_VIDEO_TRANSFER_SMPTE2084; + break; case V4L2_XFER_FUNC_DEFAULT: /* nothing, just use defaults for colorspace */ break; @@ -2210,7 +2255,9 @@ gst_v4l2_object_add_interlace_mode (GstV4l2Object * v4l2object, { struct v4l2_format fmt; GValue interlace_formats = { 0, }; - enum v4l2_field formats[] = { V4L2_FIELD_NONE, V4L2_FIELD_INTERLACED }; + enum v4l2_field formats[] = { V4L2_FIELD_NONE, + V4L2_FIELD_INTERLACED, V4L2_FIELD_ALTERNATE + }; gsize i; GstVideoInterlaceMode interlace_mode, prev = -1; @@ -2224,7 +2271,7 @@ gst_v4l2_object_add_interlace_mode (GstV4l2Object * v4l2object, g_value_init (&interlace_formats, GST_TYPE_LIST); - /* Try twice - once for NONE, once for INTERLACED. */ + /* Try thrice - once for NONE, once for INTERLACED and once for ALTERNATE. */ for (i = 0; i < G_N_ELEMENTS (formats); i++) { memset (&fmt, 0, sizeof (fmt)); fmt.type = v4l2object->type; @@ -2233,8 +2280,19 @@ gst_v4l2_object_add_interlace_mode (GstV4l2Object * v4l2object, fmt.fmt.pix.pixelformat = pixelformat; fmt.fmt.pix.field = formats[i]; - if (gst_v4l2_object_try_fmt (v4l2object, &fmt) == 0 && - gst_v4l2_object_get_interlace_mode (fmt.fmt.pix.field, &interlace_mode) + if (fmt.fmt.pix.field == V4L2_FIELD_ALTERNATE) + fmt.fmt.pix.height /= 2; + + /* if skip_try_fmt_probes is set it's up to the caller to filter out the + * formats from the formats requested by peer. + * For this negotiation to work with 'alternate' we need the caps to contain + * the feature so we have an intersection with downstream caps. + */ + if (!v4l2object->skip_try_fmt_probes + && gst_v4l2_object_try_fmt (v4l2object, &fmt) != 0) + continue; + + if (gst_v4l2_object_get_interlace_mode (fmt.fmt.pix.field, &interlace_mode) && prev != interlace_mode) { GValue interlace_enum = { 0, }; const gchar *mode_string; @@ -2306,7 +2364,7 @@ gst_v4l2_object_add_colorspace (GstV4l2Object * v4l2object, GstStructure * s, /* step 1: get device default colorspace and insert it first as * it should be the preferred one */ if (gst_v4l2_object_try_fmt (v4l2object, &fmt) == 0) { - if (gst_v4l2_object_get_colorspace (&fmt, &cinfo)) + if (gst_v4l2_object_get_colorspace (v4l2object, &fmt, &cinfo)) gst_v4l2_object_fill_colorimetry_list (&list, &cinfo); } @@ -2334,7 +2392,7 @@ gst_v4l2_object_add_colorspace (GstV4l2Object * v4l2object, GstStructure * s, colorspace = fmt.fmt.pix.colorspace; if (colorspace == req_cspace) { - if (gst_v4l2_object_get_colorspace (&fmt, &cinfo)) + if (gst_v4l2_object_get_colorspace (v4l2object, &fmt, &cinfo)) gst_v4l2_object_fill_colorimetry_list (&list, &cinfo); } } @@ -2570,6 +2628,54 @@ sort_by_frame_size (GstStructure * s1, GstStructure * s2) return ((w2 * h2) - (w1 * h1)); } +static void +check_alternate_and_append_struct (GstCaps * caps, GstStructure * s) +{ + const GValue *mode; + + mode = gst_structure_get_value (s, "interlace-mode"); + if (!mode) + goto done; + + if (G_VALUE_HOLDS_STRING (mode)) { + /* Add the INTERLACED feature if the mode is alternate */ + if (!g_strcmp0 (gst_structure_get_string (s, "interlace-mode"), + "alternate")) { + GstCapsFeatures *feat; + + feat = gst_caps_features_new (GST_CAPS_FEATURE_FORMAT_INTERLACED, NULL); + gst_caps_set_features (caps, gst_caps_get_size (caps) - 1, feat); + } + } else if (GST_VALUE_HOLDS_LIST (mode)) { + /* If the mode is a list containing alternate, remove it from the list and add a + * variant with interlace-mode=alternate and the INTERLACED feature. */ + GValue alter = G_VALUE_INIT; + GValue inter = G_VALUE_INIT; + + g_value_init (&alter, G_TYPE_STRING); + g_value_set_string (&alter, "alternate"); + + /* Cannot use gst_value_can_intersect() as it requires args to have the + * same type. */ + if (gst_value_intersect (&inter, mode, &alter)) { + GValue minus_alter = G_VALUE_INIT; + GstStructure *copy; + + gst_value_subtract (&minus_alter, mode, &alter); + gst_structure_take_value (s, "interlace-mode", &minus_alter); + + copy = gst_structure_copy (s); + gst_structure_take_value (copy, "interlace-mode", &inter); + gst_caps_append_structure_full (caps, copy, + gst_caps_features_new (GST_CAPS_FEATURE_FORMAT_INTERLACED, NULL)); + } + g_value_unset (&alter); + } + +done: + gst_caps_append_structure (caps, s); +} + static void gst_v4l2_object_update_and_append (GstV4l2Object * v4l2object, guint32 format, GstCaps * caps, GstStructure * s) @@ -2608,10 +2714,11 @@ gst_v4l2_object_update_and_append (GstV4l2Object * v4l2object, } } - gst_caps_append_structure (caps, s); + check_alternate_and_append_struct (caps, s); - if (alt_s) - gst_caps_append_structure (caps, alt_s); + if (alt_s) { + check_alternate_and_append_struct (caps, alt_s); + } } static GstCaps * @@ -2846,10 +2953,11 @@ gst_v4l2_object_probe_caps_for_format (GstV4l2Object * v4l2object, gst_v4l2_object_add_aspect_ratio (v4l2object, tmp); + /* We could consider setting interlace mode from min and max. */ + gst_v4l2_object_add_interlace_mode (v4l2object, tmp, max_w, max_h, + pixelformat); + if (!v4l2object->skip_try_fmt_probes) { - /* We could consider setting interlace mode from min and max. */ - gst_v4l2_object_add_interlace_mode (v4l2object, tmp, max_w, max_h, - pixelformat); /* We could consider to check colorspace for min too, in case it depends on * the size. But in this case, min and max could not be enough */ gst_v4l2_object_add_colorspace (v4l2object, tmp, max_w, max_h, @@ -3054,7 +3162,9 @@ gst_v4l2_object_extrapolate_info (GstV4l2Object * v4l2object, g_return_if_fail (v4l2object->n_v4l2_planes == 1); - padded_height = info->height + align->padding_top + align->padding_bottom; + padded_height = + GST_VIDEO_INFO_FIELD_HEIGHT (info) + align->padding_top + + align->padding_bottom; for (i = 0; i < finfo->n_planes; i++) { estride = gst_v4l2_object_extrapolate_stride (finfo, i, stride); @@ -3130,7 +3240,8 @@ gst_v4l2_object_save_format (GstV4l2Object * v4l2object, padded_height = GST_ROUND_UP_N (padded_height, tile_height); } - align->padding_bottom = padded_height - info->height - align->padding_top; + align->padding_bottom = + padded_height - GST_VIDEO_INFO_FIELD_HEIGHT (info) - align->padding_top; /* setup the strides and offset */ if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type)) { @@ -3213,6 +3324,9 @@ gst_v4l2_object_save_format (GstV4l2Object * v4l2object, if (info->fps_n > 0 && info->fps_d > 0) { v4l2object->duration = gst_util_uint64_scale_int (GST_SECOND, info->fps_d, info->fps_n); + if (GST_VIDEO_INFO_INTERLACE_MODE (info) == + GST_VIDEO_INTERLACE_MODE_ALTERNATE) + v4l2object->duration /= 2; } else { v4l2object->duration = GST_CLOCK_TIME_NONE; } @@ -3242,11 +3356,32 @@ gst_v4l2_object_extrapolate_stride (const GstVideoFormatInfo * finfo, return estride; } +static enum v4l2_field +get_v4l2_field_for_info (GstVideoInfo * info) +{ + if (!GST_VIDEO_INFO_IS_INTERLACED (info)) + return V4L2_FIELD_NONE; + + if (GST_VIDEO_INFO_INTERLACE_MODE (info) == + GST_VIDEO_INTERLACE_MODE_ALTERNATE) + return V4L2_FIELD_ALTERNATE; + + switch (GST_VIDEO_INFO_FIELD_ORDER (info)) { + case GST_VIDEO_FIELD_ORDER_TOP_FIELD_FIRST: + return V4L2_FIELD_INTERLACED_TB; + case GST_VIDEO_FIELD_ORDER_BOTTOM_FIELD_FIRST: + return V4L2_FIELD_INTERLACED_BT; + case GST_VIDEO_FIELD_ORDER_UNKNOWN: + default: + return V4L2_FIELD_INTERLACED; + } +} + static gboolean gst_v4l2_video_colorimetry_matches (const GstVideoColorimetry * cinfo, - const gchar * color) + GstCaps * caps) { - GstVideoColorimetry ci; + GstVideoInfo info; static const GstVideoColorimetry ci_likely_jpeg = { GST_VIDEO_COLOR_RANGE_0_255, GST_VIDEO_COLOR_MATRIX_BT601, GST_VIDEO_TRANSFER_UNKNOWN, GST_VIDEO_COLOR_PRIMARIES_UNKNOWN @@ -3256,20 +3391,59 @@ gst_v4l2_video_colorimetry_matches (const GstVideoColorimetry * cinfo, GST_VIDEO_TRANSFER_SRGB, GST_VIDEO_COLOR_PRIMARIES_BT709 }; - if (!gst_video_colorimetry_from_string (&ci, color)) + if (!gst_video_info_from_caps (&info, caps)) return FALSE; - if (gst_video_colorimetry_is_equal (&ci, cinfo)) + /* if colorimetry in caps is unknown, use the default one */ + if (info.colorimetry.primaries == GST_VIDEO_COLOR_PRIMARIES_UNKNOWN) + info.colorimetry.primaries = cinfo->primaries; + if (info.colorimetry.range == GST_VIDEO_COLOR_RANGE_UNKNOWN) + info.colorimetry.range = cinfo->range; + if (info.colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_UNKNOWN) + info.colorimetry.matrix = cinfo->matrix; + if (info.colorimetry.transfer == GST_VIDEO_TRANSFER_UNKNOWN) + info.colorimetry.transfer = cinfo->transfer; + + if (gst_video_colorimetry_is_equal (&info.colorimetry, cinfo)) return TRUE; /* Allow 1:4:0:0 (produced by jpegdec) if the device expects 1:4:7:1 */ - if (gst_video_colorimetry_is_equal (&ci, &ci_likely_jpeg) + if (gst_video_colorimetry_is_equal (&info.colorimetry, &ci_likely_jpeg) && gst_video_colorimetry_is_equal (cinfo, &ci_jpeg)) return TRUE; return FALSE; } +static const gchar * +field_to_str (enum v4l2_field f) +{ + switch (f) { + case V4L2_FIELD_ANY: + return "any"; + case V4L2_FIELD_NONE: + return "none"; + case V4L2_FIELD_TOP: + return "top"; + case V4L2_FIELD_BOTTOM: + return "bottom"; + case V4L2_FIELD_INTERLACED: + return "interlaced"; + case V4L2_FIELD_SEQ_TB: + return "seq-tb"; + case V4L2_FIELD_SEQ_BT: + return "seq-bt"; + case V4L2_FIELD_ALTERNATE: + return "alternate"; + case V4L2_FIELD_INTERLACED_TB: + return "interlaced-tb"; + case V4L2_FIELD_INTERLACED_BT: + return "interlaced-bt"; + } + + return "unknown"; +} + static gboolean gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, gboolean try_only, GstV4l2Error * error) @@ -3291,6 +3465,7 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, enum v4l2_ycbcr_encoding matrix = 0; enum v4l2_xfer_func transfer = 0; GstStructure *s; + gboolean disable_interlacing = FALSE; gboolean disable_colorimetry = FALSE; g_return_val_if_fail (!v4l2object->skip_try_fmt_probes || @@ -3304,13 +3479,14 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, gst_video_info_init (&info); gst_video_alignment_reset (&align); + v4l2object->transfer = GST_VIDEO_TRANSFER_UNKNOWN; if (!gst_v4l2_object_get_caps_info (v4l2object, caps, &fmtdesc, &info)) goto invalid_caps; pixelformat = fmtdesc->pixelformat; width = GST_VIDEO_INFO_WIDTH (&info); - height = GST_VIDEO_INFO_HEIGHT (&info); + height = GST_VIDEO_INFO_FIELD_HEIGHT (&info); fps_n = GST_VIDEO_INFO_FPS_N (&info); fps_d = GST_VIDEO_INFO_FPS_D (&info); @@ -3320,16 +3496,11 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, if (!n_v4l_planes || !v4l2object->prefered_non_contiguous) n_v4l_planes = 1; - if (GST_VIDEO_INFO_IS_INTERLACED (&info)) { - GST_DEBUG_OBJECT (v4l2object->dbg_obj, "interlaced video"); - /* ideally we would differentiate between types of interlaced video - * but there is not sufficient information in the caps.. - */ - field = V4L2_FIELD_INTERLACED; - } else { - GST_DEBUG_OBJECT (v4l2object->dbg_obj, "progressive video"); - field = V4L2_FIELD_NONE; - } + field = get_v4l2_field_for_info (&info); + if (field != V4L2_FIELD_NONE) + GST_DEBUG_OBJECT (v4l2object->element, "interlaced video"); + else + GST_DEBUG_OBJECT (v4l2object->element, "progressive video"); /* We first pick the main colorspace from the primaries */ switch (info.colorimetry.primaries) { @@ -3422,8 +3593,14 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, case GST_VIDEO_TRANSFER_GAMMA10: transfer = V4L2_XFER_FUNC_NONE; break; + case GST_VIDEO_TRANSFER_SMPTE2084: + transfer = V4L2_XFER_FUNC_SMPTE2084; + break; + case GST_VIDEO_TRANSFER_BT601: case GST_VIDEO_TRANSFER_BT2020_12: + case GST_VIDEO_TRANSFER_BT2020_10: case GST_VIDEO_TRANSFER_BT709: + v4l2object->transfer = info.colorimetry.transfer; transfer = V4L2_XFER_FUNC_709; break; case GST_VIDEO_TRANSFER_SMPTE240M: @@ -3458,7 +3635,7 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, transfer = V4L2_XFER_FUNC_SRGB; } else { /* SD streams likely use SMPTE170M and HD streams REC709 */ - if (width <= 720 && height <= 576) + if (width <= 720 && GST_VIDEO_INFO_HEIGHT (&info) <= 576) colorspace = V4L2_COLORSPACE_SMPTE170M; else colorspace = V4L2_COLORSPACE_REC709; @@ -3573,11 +3750,11 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, } GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Got format of %dx%d, format " - "%" GST_FOURCC_FORMAT ", nb planes %d, colorspace %d:%d:%d:%d", + "%" GST_FOURCC_FORMAT ", nb planes %d, colorspace %d:%d:%d:%d field: %s", format.fmt.pix.width, format.fmt.pix_mp.height, GST_FOURCC_ARGS (format.fmt.pix.pixelformat), is_mplane ? format.fmt.pix_mp.num_planes : 1, - colorspace, range, matrix, transfer); + colorspace, range, matrix, transfer, field_to_str (format.fmt.pix.field)); #ifndef GST_DISABLE_GST_DEBUG if (is_mplane) { @@ -3616,18 +3793,23 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, /* used to check colorimetry and interlace mode fields presence */ s = gst_caps_get_structure (caps, 0); - if (!gst_v4l2_object_get_interlace_mode (format.fmt.pix.field, - &info.interlace_mode)) - goto invalid_field; - if (gst_structure_has_field (s, "interlace-mode")) { - if (format.fmt.pix.field != field) - goto invalid_field; + if (gst_v4l2_object_get_interlace_mode (format.fmt.pix.field, + &info.interlace_mode)) { + if (gst_structure_has_field (s, "interlace-mode")) { + if (format.fmt.pix.field != field) + goto invalid_field; + } + } else { + /* The driver (or libv4l2) is miss-behaving, just ignore interlace-mode from + * the TRY_FMT */ + disable_interlacing = TRUE; + if (gst_structure_has_field (s, "interlace-mode")) + gst_structure_remove_field (s, "interlace-mode"); } - if (gst_v4l2_object_get_colorspace (&format, &info.colorimetry)) { + if (gst_v4l2_object_get_colorspace (v4l2object, &format, &info.colorimetry)) { if (gst_structure_has_field (s, "colorimetry")) { - if (!gst_v4l2_video_colorimetry_matches (&info.colorimetry, - gst_structure_get_string (s, "colorimetry"))) + if (!gst_v4l2_video_colorimetry_matches (&info.colorimetry, caps)) goto invalid_colorimetry; } } else { @@ -3639,17 +3821,17 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, } /* In case we have skipped the try_fmt probes, we'll need to set the - * colorimetry and interlace-mode back into the caps. */ + * interlace-mode and colorimetry back into the caps. */ if (v4l2object->skip_try_fmt_probes) { + if (!disable_interlacing && !gst_structure_has_field (s, "interlace-mode")) { + gst_structure_set (s, "interlace-mode", G_TYPE_STRING, + gst_video_interlace_mode_to_string (info.interlace_mode), NULL); + } if (!disable_colorimetry && !gst_structure_has_field (s, "colorimetry")) { gchar *str = gst_video_colorimetry_to_string (&info.colorimetry); gst_structure_set (s, "colorimetry", G_TYPE_STRING, str, NULL); g_free (str); } - - if (!gst_structure_has_field (s, "interlace-mode")) - gst_structure_set (s, "interlace-mode", G_TYPE_STRING, - gst_video_interlace_mode_to_string (info.interlace_mode), NULL); } if (try_only) /* good enough for trying only */ @@ -3784,6 +3966,9 @@ gst_v4l2_object_set_format_full (GstV4l2Object * v4l2object, GstCaps * caps, { GST_DEBUG_OBJECT (v4l2object->dbg_obj, "can't parse caps %" GST_PTR_FORMAT, caps); + + GST_V4L2_ERROR (error, RESOURCE, SETTINGS, + (_("Invalid caps")), ("Can't parse caps %" GST_PTR_FORMAT, caps)); return FALSE; } try_fmt_failed: @@ -3950,6 +4135,7 @@ gst_v4l2_object_acquire_format (GstV4l2Object * v4l2object, GstVideoInfo * info) GstVideoFormat format; guint width, height; GstVideoAlignment align; + GstVideoInterlaceMode interlace_mode; gst_video_info_init (info); gst_video_alignment_reset (&align); @@ -3999,23 +4185,27 @@ gst_v4l2_object_acquire_format (GstV4l2Object * v4l2object, GstVideoInfo * info) height = r->height; } - gst_video_info_set_format (info, format, width, height); - switch (fmt.fmt.pix.field) { case V4L2_FIELD_ANY: case V4L2_FIELD_NONE: - info->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE; + interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE; break; case V4L2_FIELD_INTERLACED: case V4L2_FIELD_INTERLACED_TB: case V4L2_FIELD_INTERLACED_BT: - info->interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED; + interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED; + break; + case V4L2_FIELD_ALTERNATE: + interlace_mode = GST_VIDEO_INTERLACE_MODE_ALTERNATE; break; default: goto unsupported_field; } - gst_v4l2_object_get_colorspace (&fmt, &info->colorimetry); + gst_video_info_set_interlaced_format (info, format, interlace_mode, width, + height); + + gst_v4l2_object_get_colorspace (v4l2object, &fmt, &info->colorimetry); gst_v4l2_object_save_format (v4l2object, fmtdesc, &fmt, info, &align); @@ -4066,7 +4256,7 @@ gst_v4l2_object_set_crop (GstV4l2Object * obj) sel.r.left = obj->align.padding_left; sel.r.top = obj->align.padding_top; sel.r.width = obj->info.width; - sel.r.height = obj->info.height; + sel.r.height = GST_VIDEO_INFO_FIELD_HEIGHT (&obj->info); crop.type = obj->type; crop.c = sel.r; @@ -4283,9 +4473,14 @@ gst_v4l2_object_probe_caps (GstV4l2Object * v4l2object, GstCaps * filter) tmp = gst_v4l2_object_probe_caps_for_format (v4l2object, format->pixelformat, template); - if (tmp) + if (tmp) { gst_caps_append (ret, tmp); + /* Add a variant of the caps with the Interlaced feature so we can negotiate it if needed */ + add_alternate_variant (v4l2object, ret, gst_caps_get_structure (ret, + gst_caps_get_size (ret) - 1)); + } + gst_structure_free (template); } @@ -4360,6 +4555,18 @@ gst_v4l2_object_match_buffer_layout (GstV4l2Object * obj, guint n_planes, offset[p], obj->info.offset[p], p); need_fmt_update = TRUE; } + + if (padded_height) { + guint fmt_height; + + if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) + fmt_height = obj->format.fmt.pix_mp.height; + else + fmt_height = obj->format.fmt.pix.height; + + if (padded_height > fmt_height) + need_fmt_update = TRUE; + } } if (need_fmt_update) { @@ -4372,7 +4579,7 @@ gst_v4l2_object_match_buffer_layout (GstV4l2Object * obj, guint n_planes, GST_DEBUG_OBJECT (obj->dbg_obj, "Padded height %u", padded_height); obj->align.padding_bottom = - padded_height - GST_VIDEO_INFO_HEIGHT (&obj->info); + padded_height - GST_VIDEO_INFO_FIELD_HEIGHT (&obj->info); } else { GST_WARNING_OBJECT (obj->dbg_obj, "Failed to compute padded height; keep the default one"); @@ -4691,12 +4898,12 @@ gst_v4l2_object_decide_allocation (GstV4l2Object * obj, GstQuery * query) /* In this case we'll have to configure two buffer pool. For our buffer * pool, we'll need what the driver one, and one more, so we can dequeu */ own_min = obj->min_buffers + 1; - own_min = MAX (own_min, GST_V4L2_MIN_BUFFERS); + own_min = MAX (own_min, GST_V4L2_MIN_BUFFERS (obj)); /* for the downstream pool, we keep what downstream wants, though ensure * at least a minimum if downstream didn't suggest anything (we are * expecting the base class to create a default one for the context) */ - min = MAX (min, GST_V4L2_MIN_BUFFERS); + min = MAX (min, GST_V4L2_MIN_BUFFERS (obj)); /* To import we need the other pool to hold at least own_min */ if (obj->pool == pool) @@ -4834,7 +5041,7 @@ gst_v4l2_object_propose_allocation (GstV4l2Object * obj, GstQuery * query) /* Set defaults allocation parameters */ size = obj->info.size; - min = GST_V4L2_MIN_BUFFERS; + min = GST_V4L2_MIN_BUFFERS (obj); max = VIDEO_MAX_FRAME; gst_query_parse_allocation (query, &caps, &need_pool); @@ -4872,7 +5079,7 @@ gst_v4l2_object_propose_allocation (GstV4l2Object * obj, GstQuery * query) } gst_v4l2_get_driver_min_buffers (obj); - min = MAX (obj->min_buffers, GST_V4L2_MIN_BUFFERS); + min = MAX (obj->min_buffers, GST_V4L2_MIN_BUFFERS (obj)); gst_query_add_allocation_pool (query, pool, size, min, max); diff --git a/sys/v4l2/gstv4l2object.h b/sys/v4l2/gstv4l2object.h index eaaff58923..1731dc3245 100644 --- a/sys/v4l2/gstv4l2object.h +++ b/sys/v4l2/gstv4l2object.h @@ -42,8 +42,12 @@ typedef struct _GstV4l2ObjectClassHelper GstV4l2ObjectClassHelper; #include -/* size of v4l2 buffer pool in streaming case */ -#define GST_V4L2_MIN_BUFFERS 2 +/* size of v4l2 buffer pool in streaming case, obj->info needs to be valid */ +#define GST_V4L2_MIN_BUFFERS(obj) \ + ((GST_VIDEO_INFO_INTERLACE_MODE (&obj->info) == \ + GST_VIDEO_INTERLACE_MODE_ALTERNATE) ? \ + /* 2x buffers needed with each field in its own buffer */ \ + 4 : 2) /* max frame width/height */ #define GST_V4L2_MAX_SIZE (1<<15) /* 2^15 == 32768 */ @@ -139,6 +143,7 @@ struct _GstV4l2Object { struct v4l2_format format; GstVideoInfo info; GstVideoAlignment align; + GstVideoTransferFunction transfer; /* Features */ gboolean need_video_meta; @@ -168,6 +173,8 @@ struct _GstV4l2Object { /* optional pool */ GstBufferPool *pool; + /* the sequence of pool to identify (for debugging) */ + guint pool_seq; /* the video device's capabilities */ struct v4l2_capability vcap; @@ -268,7 +275,7 @@ gboolean gst_v4l2_object_get_property_helper (GstV4l2Object *v4l2objec guint prop_id, GValue * value, GParamSpec * pspec); /* open/close */ -gboolean gst_v4l2_object_open (GstV4l2Object * v4l2object); +gboolean gst_v4l2_object_open (GstV4l2Object * v4l2object, GstV4l2Error * error); gboolean gst_v4l2_object_open_shared (GstV4l2Object * v4l2object, GstV4l2Object * other); gboolean gst_v4l2_object_close (GstV4l2Object * v4l2object); @@ -311,7 +318,7 @@ GstStructure * gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc); /* TODO Move to proper namespace */ /* open/close the device */ -gboolean gst_v4l2_open (GstV4l2Object * v4l2object); +gboolean gst_v4l2_open (GstV4l2Object * v4l2object, GstV4l2Error * error); gboolean gst_v4l2_dup (GstV4l2Object * v4l2object, GstV4l2Object * other); gboolean gst_v4l2_close (GstV4l2Object * v4l2object); @@ -331,6 +338,7 @@ gboolean gst_v4l2_signal_strength (GstV4l2Object * v4l2object, gint tunernum /* attribute control */ gboolean gst_v4l2_get_attribute (GstV4l2Object * v4l2object, int attribute, int * value); gboolean gst_v4l2_set_attribute (GstV4l2Object * v4l2object, int attribute, const int value); +gboolean gst_v4l2_set_string_attribute (GstV4l2Object * v4l2object, int attribute_num, const char *value); gboolean gst_v4l2_set_controls (GstV4l2Object * v4l2object, GstStructure * controls); G_END_DECLS diff --git a/sys/v4l2/gstv4l2radio.c b/sys/v4l2/gstv4l2radio.c index 5a18e5aa24..ab7c76d2f5 100644 --- a/sys/v4l2/gstv4l2radio.c +++ b/sys/v4l2/gstv4l2radio.c @@ -350,12 +350,12 @@ gst_v4l2radio_finalize (GstV4l2Radio * radio) } static gboolean -gst_v4l2radio_open (GstV4l2Radio * radio) +gst_v4l2radio_open (GstV4l2Radio * radio, GstV4l2Error * error) { GstV4l2Object *v4l2object; v4l2object = radio->v4l2object; - if (gst_v4l2_open (v4l2object)) + if (gst_v4l2_open (v4l2object, error)) return gst_v4l2radio_fill_channel_list (radio); else return FALSE; @@ -406,9 +406,9 @@ gst_v4l2radio_set_defaults (GstV4l2Radio * radio) } static gboolean -gst_v4l2radio_start (GstV4l2Radio * radio) +gst_v4l2radio_start (GstV4l2Radio * radio, GstV4l2Error * error) { - if (!gst_v4l2radio_open (radio)) + if (!gst_v4l2radio_open (radio, error)) return FALSE; gst_v4l2radio_set_defaults (radio); @@ -429,13 +429,14 @@ static GstStateChangeReturn gst_v4l2radio_change_state (GstElement * element, GstStateChange transition) { GstV4l2Radio *radio; + GstV4l2Error error = GST_V4L2_ERROR_INIT; GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; radio = GST_V4L2RADIO (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: /*start radio */ - if (!gst_v4l2radio_start (radio)) + if (!gst_v4l2radio_start (radio, &error)) ret = GST_STATE_CHANGE_FAILURE; break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: @@ -457,6 +458,7 @@ gst_v4l2radio_change_state (GstElement * element, GstStateChange transition) break; } + gst_v4l2_error (radio, &error); return ret; } diff --git a/sys/v4l2/gstv4l2sink.c b/sys/v4l2/gstv4l2sink.c index 162835eac7..a971ef4915 100644 --- a/sys/v4l2/gstv4l2sink.c +++ b/sys/v4l2/gstv4l2sink.c @@ -437,6 +437,7 @@ gst_v4l2sink_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GstV4l2Sink *v4l2sink = GST_V4L2SINK (element); + GstV4l2Error error = GST_V4L2_ERROR_INIT; GST_DEBUG_OBJECT (v4l2sink, "%d -> %d", GST_STATE_TRANSITION_CURRENT (transition), @@ -445,8 +446,10 @@ gst_v4l2sink_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: /* open the device */ - if (!gst_v4l2_object_open (v4l2sink->v4l2object)) + if (!gst_v4l2_object_open (v4l2sink->v4l2object, &error)) { + gst_v4l2_error (v4l2sink, &error); return GST_STATE_CHANGE_FAILURE; + } break; default: break; diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c index fd35a5272b..a518aca845 100644 --- a/sys/v4l2/gstv4l2src.c +++ b/sys/v4l2/gstv4l2src.c @@ -696,8 +696,11 @@ gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query) goto done; } - /* min latency is the time to capture one frame */ + /* min latency is the time to capture one frame/field */ min_latency = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n); + if (GST_VIDEO_INFO_INTERLACE_MODE (&obj->info) == + GST_VIDEO_INTERLACE_MODE_ALTERNATE) + min_latency /= 2; /* max latency is total duration of the frame buffer */ if (obj->pool != NULL) @@ -739,6 +742,7 @@ gst_v4l2src_start (GstBaseSrc * src) GstV4l2Src *v4l2src = GST_V4L2SRC (src); v4l2src->offset = 0; + v4l2src->next_offset_same = FALSE; v4l2src->renegotiation_adjust = 0; /* activate settings for first frame */ @@ -790,12 +794,15 @@ gst_v4l2src_change_state (GstElement * element, GstStateChange transition) GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GstV4l2Src *v4l2src = GST_V4L2SRC (element); GstV4l2Object *obj = v4l2src->v4l2object; + GstV4l2Error error = GST_V4L2_ERROR_INIT; switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: /* open the device */ - if (!gst_v4l2_object_open (obj)) + if (!gst_v4l2_object_open (obj, &error)) { + gst_v4l2_error (v4l2src, &error); return GST_STATE_CHANGE_FAILURE; + } break; default: break; @@ -828,6 +835,7 @@ gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf) GstClockTime abs_time, base_time, timestamp, duration; GstClockTime delay; GstMessage *qos_msg; + gboolean half_frame; do { ret = GST_BASE_SRC_CLASS (parent_class)->alloc (GST_BASE_SRC (src), 0, @@ -920,7 +928,7 @@ gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf) " delay %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp), GST_TIME_ARGS (gstnow), GST_TIME_ARGS (delay)); } else { - /* we assume 1 frame latency otherwise */ + /* we assume 1 frame/field latency otherwise */ if (GST_CLOCK_TIME_IS_VALID (duration)) delay = duration; else @@ -953,15 +961,33 @@ gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf) } gst_object_sync_values (GST_OBJECT (src), v4l2src->ctrl_time); - GST_INFO_OBJECT (src, "sync to %" GST_TIME_FORMAT " out ts %" GST_TIME_FORMAT, + GST_LOG_OBJECT (src, "sync to %" GST_TIME_FORMAT " out ts %" GST_TIME_FORMAT, GST_TIME_ARGS (v4l2src->ctrl_time), GST_TIME_ARGS (timestamp)); + if (v4l2src->next_offset_same && + GST_BUFFER_OFFSET_IS_VALID (*buf) && + GST_BUFFER_OFFSET (*buf) != v4l2src->offset) { + /* Probably had a lost field then, best to forget about last field. */ + GST_WARNING_OBJECT (v4l2src, + "lost field detected - ts: %" GST_TIME_FORMAT, + GST_TIME_ARGS (timestamp)); + v4l2src->next_offset_same = FALSE; + } + + half_frame = (GST_BUFFER_FLAG_IS_SET (*buf, GST_VIDEO_BUFFER_FLAG_ONEFIELD)); + if (half_frame) + v4l2src->next_offset_same = !v4l2src->next_offset_same; + /* use generated offset values only if there are not already valid ones * set by the v4l2 device */ if (!GST_BUFFER_OFFSET_IS_VALID (*buf) - || !GST_BUFFER_OFFSET_END_IS_VALID (*buf)) { - GST_BUFFER_OFFSET (*buf) = v4l2src->offset++; - GST_BUFFER_OFFSET_END (*buf) = v4l2src->offset; + || !GST_BUFFER_OFFSET_END_IS_VALID (*buf) + || GST_BUFFER_OFFSET (*buf) <= + (v4l2src->offset - v4l2src->renegotiation_adjust)) { + GST_BUFFER_OFFSET (*buf) = v4l2src->offset; + GST_BUFFER_OFFSET_END (*buf) = v4l2src->offset + 1; + if (!half_frame || !v4l2src->next_offset_same) + v4l2src->offset++; } else { /* adjust raw v4l2 device sequence, will restart at null in case of renegotiation * (streamoff/streamon) */ @@ -969,6 +995,7 @@ gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf) GST_BUFFER_OFFSET_END (*buf) += v4l2src->renegotiation_adjust; /* check for frame loss with given (from v4l2 device) buffer offset */ if ((v4l2src->offset != 0) + && (!half_frame || v4l2src->next_offset_same) && (GST_BUFFER_OFFSET (*buf) != (v4l2src->offset + 1))) { guint64 lost_frame_count = GST_BUFFER_OFFSET (*buf) - v4l2src->offset - 1; GST_WARNING_OBJECT (v4l2src, diff --git a/sys/v4l2/gstv4l2src.h b/sys/v4l2/gstv4l2src.h index cb7f75158f..232916d2a5 100644 --- a/sys/v4l2/gstv4l2src.h +++ b/sys/v4l2/gstv4l2src.h @@ -56,6 +56,7 @@ struct _GstV4l2Src GstV4l2Object * v4l2object; guint64 offset; + gboolean next_offset_same; /* offset adjust after renegotiation */ guint64 renegotiation_adjust; diff --git a/sys/v4l2/gstv4l2transform.c b/sys/v4l2/gstv4l2transform.c index d2a2cf3133..cc5564d446 100644 --- a/sys/v4l2/gstv4l2transform.c +++ b/sys/v4l2/gstv4l2transform.c @@ -115,9 +115,11 @@ gst_v4l2_transform_get_property (GObject * object, static gboolean gst_v4l2_transform_open (GstV4l2Transform * self) { + GstV4l2Error error = GST_V4L2_ERROR_INIT; + GST_DEBUG_OBJECT (self, "Opening"); - if (!gst_v4l2_object_open (self->v4l2output)) + if (!gst_v4l2_object_open (self->v4l2output, &error)) goto failure; if (!gst_v4l2_object_open_shared (self->v4l2capture, self->v4l2output)) @@ -160,6 +162,8 @@ gst_v4l2_transform_open (GstV4l2Transform * self) gst_caps_replace (&self->probed_srccaps, NULL); gst_caps_replace (&self->probed_sinkcaps, NULL); + gst_v4l2_error (self, &error); + return FALSE; } @@ -893,7 +897,8 @@ gst_v4l2_transform_prepare_output_buffer (GstBaseTransform * trans, /* Ensure input internal pool is active */ if (!gst_buffer_pool_is_active (pool)) { GstStructure *config = gst_buffer_pool_get_config (pool); - gint min = MAX (GST_V4L2_MIN_BUFFERS, self->v4l2output->min_buffers); + gint min = MAX (GST_V4L2_MIN_BUFFERS (self->v4l2output), + self->v4l2output->min_buffers); if (self->v4l2output->mode == GST_V4L2_IO_USERPTR || self->v4l2output->mode == GST_V4L2_IO_DMABUF_IMPORT) { diff --git a/sys/v4l2/gstv4l2videodec.c b/sys/v4l2/gstv4l2videodec.c index 39b4fd19a8..2eb07571e8 100644 --- a/sys/v4l2/gstv4l2videodec.c +++ b/sys/v4l2/gstv4l2videodec.c @@ -119,11 +119,12 @@ static gboolean gst_v4l2_video_dec_open (GstVideoDecoder * decoder) { GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder); + GstV4l2Error error = GST_V4L2_ERROR_INIT; GstCaps *codec_caps; GST_DEBUG_OBJECT (self, "Opening"); - if (!gst_v4l2_object_open (self->v4l2output)) + if (!gst_v4l2_object_open (self->v4l2output, &error)) goto failure; if (!gst_v4l2_object_open_shared (self->v4l2capture, self->v4l2output)) @@ -155,6 +156,8 @@ gst_v4l2_video_dec_open (GstVideoDecoder * decoder) gst_caps_replace (&self->probed_srccaps, NULL); gst_caps_replace (&self->probed_sinkcaps, NULL); + gst_v4l2_error (self, &error); + return FALSE; } @@ -220,6 +223,34 @@ gst_v4l2_video_dec_stop (GstVideoDecoder * decoder) return TRUE; } +static gboolean +compatible_caps (GstV4l2VideoDec * self, GstCaps * new_caps) +{ + GstCaps *current_caps, *caps1, *caps2; + GstStructure *s; + gboolean ret; + + current_caps = gst_v4l2_object_get_current_caps (self->v4l2output); + if (!current_caps) + return FALSE; + + caps1 = gst_caps_copy (current_caps); + s = gst_caps_get_structure (caps1, 0); + gst_structure_remove_field (s, "framerate"); + + caps2 = gst_caps_copy (new_caps); + s = gst_caps_get_structure (caps2, 0); + gst_structure_remove_field (s, "framerate"); + + ret = gst_caps_is_equal (caps1, caps2); + + gst_caps_unref (caps1); + gst_caps_unref (caps2); + gst_caps_unref (current_caps); + + return ret; +} + static gboolean gst_v4l2_video_dec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state) @@ -231,7 +262,7 @@ gst_v4l2_video_dec_set_format (GstVideoDecoder * decoder, GST_DEBUG_OBJECT (self, "Setting format: %" GST_PTR_FORMAT, state->caps); if (self->input_state) { - if (gst_v4l2_object_caps_equal (self->v4l2output, state->caps)) { + if (compatible_caps (self, state->caps)) { GST_DEBUG_OBJECT (self, "Compatible caps"); goto done; } @@ -621,8 +652,12 @@ gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder, /* Ensure input internal pool is active */ if (!gst_buffer_pool_is_active (pool)) { GstStructure *config = gst_buffer_pool_get_config (pool); + guint min = MAX (self->v4l2output->min_buffers, + GST_V4L2_MIN_BUFFERS (self->v4l2output)); + guint max = VIDEO_MAX_FRAME; + gst_buffer_pool_config_set_params (config, self->input_state->caps, - self->v4l2output->info.size, 2, 2); + self->v4l2output->info.size, min, max); /* There is no reason to refuse this config */ if (!gst_buffer_pool_set_config (pool, config)) @@ -647,6 +682,10 @@ gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder, if (!gst_v4l2_object_acquire_format (self->v4l2capture, &info)) goto not_negotiated; + /* gst_v4l2_object_acquire_format() does not set fps, copy from sink */ + info.fps_n = self->v4l2output->info.fps_n; + info.fps_d = self->v4l2output->info.fps_d; + /* Create caps from the acquired format, remove the format field */ acquired_caps = gst_video_info_to_caps (&info); GST_DEBUG_OBJECT (self, "Acquired caps: %" GST_PTR_FORMAT, acquired_caps); @@ -1046,7 +1085,7 @@ gst_v4l2_video_dec_subclass_init (gpointer g_class, gpointer data) gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, cdata->src_caps)); - gst_element_class_set_static_metadata (element_class, cdata->longname, + gst_element_class_set_metadata (element_class, cdata->longname, "Codec/Decoder/Video/Hardware", cdata->description, "Nicolas Dufresne "); @@ -1175,17 +1214,18 @@ gst_v4l2_video_dec_register (GstPlugin * plugin, const gchar * basename, continue; } - if (cdata->codec != NULL) { - GValue *value = gst_v4l2_codec_probe_levels (cdata->codec, video_fd); - if (value != NULL) { - gst_caps_set_value (cdata->sink_caps, "level", value); - g_value_unset (value); + if (cdata->codec != NULL && cdata->codec != gst_v4l2_vp8_get_codec () + && cdata->codec != gst_v4l2_vp9_get_codec ()) { + GValue value = G_VALUE_INIT; + + if (gst_v4l2_codec_probe_levels (cdata->codec, video_fd, &value)) { + gst_caps_set_value (cdata->sink_caps, "level", &value); + g_value_unset (&value); } - value = gst_v4l2_codec_probe_profiles (cdata->codec, video_fd); - if (value != NULL) { - gst_caps_set_value (cdata->sink_caps, "profile", value); - g_value_unset (value); + if (gst_v4l2_codec_probe_profiles (cdata->codec, video_fd, &value)) { + gst_caps_set_value (cdata->sink_caps, "profile", &value); + g_value_unset (&value); } } diff --git a/sys/v4l2/gstv4l2videoenc.c b/sys/v4l2/gstv4l2videoenc.c index 36e1515adc..d43f649d65 100644 --- a/sys/v4l2/gstv4l2videoenc.c +++ b/sys/v4l2/gstv4l2videoenc.c @@ -110,11 +110,12 @@ static gboolean gst_v4l2_video_enc_open (GstVideoEncoder * encoder) { GstV4l2VideoEnc *self = GST_V4L2_VIDEO_ENC (encoder); + GstV4l2Error error = GST_V4L2_ERROR_INIT; GstCaps *codec_caps; GST_DEBUG_OBJECT (self, "Opening"); - if (!gst_v4l2_object_open (self->v4l2output)) + if (!gst_v4l2_object_open (self->v4l2output, &error)) goto failure; if (!gst_v4l2_object_open_shared (self->v4l2capture, self->v4l2output)) @@ -159,6 +160,8 @@ gst_v4l2_video_enc_open (GstVideoEncoder * encoder) gst_caps_replace (&self->probed_srccaps, NULL); gst_caps_replace (&self->probed_sinkcaps, NULL); + gst_v4l2_error (self, &error); + return FALSE; } @@ -530,6 +533,9 @@ gst_v4l2_video_enc_negotiate (GstVideoEncoder * encoder) if (self->input_state) return TRUE; + if (!codec) + goto done; + allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder)); if (allowed_caps) { @@ -545,6 +551,9 @@ gst_v4l2_video_enc_negotiate (GstVideoEncoder * encoder) if (gst_caps_foreach (allowed_caps, negotiate_profile_and_level, &ctx)) { goto no_profile_level; } + + gst_caps_unref (allowed_caps); + allowed_caps = NULL; } if (codec->profile_cid && !ctx.profile) { @@ -581,6 +590,7 @@ gst_v4l2_video_enc_negotiate (GstVideoEncoder * encoder) if (codec->level_cid) gst_structure_set (s, "level", G_TYPE_STRING, ctx.level, NULL); +done: if (!GST_VIDEO_ENCODER_CLASS (parent_class)->negotiate (encoder)) return FALSE; @@ -728,10 +738,13 @@ gst_v4l2_video_enc_handle_frame (GstVideoEncoder * encoder, if (task_state == GST_TASK_STOPPED || task_state == GST_TASK_PAUSED) { GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2output->pool); - /* It possible that the processing thread stopped due to an error */ + /* It is possible that the processing thread stopped due to an error or + * when the last buffer has been met during the draining process. */ if (self->output_flow != GST_FLOW_OK && - self->output_flow != GST_FLOW_FLUSHING) { - GST_DEBUG_OBJECT (self, "Processing loop stopped with error, leaving"); + self->output_flow != GST_FLOW_FLUSHING && + self->output_flow != GST_V4L2_FLOW_LAST_BUFFER) { + GST_DEBUG_OBJECT (self, "Processing loop stopped with error: %s, leaving", + gst_flow_get_name (self->output_flow)); ret = self->output_flow; goto drop; } @@ -739,7 +752,8 @@ gst_v4l2_video_enc_handle_frame (GstVideoEncoder * encoder, /* Ensure input internal pool is active */ if (!gst_buffer_pool_is_active (pool)) { GstStructure *config = gst_buffer_pool_get_config (pool); - guint min = MAX (self->v4l2output->min_buffers, GST_V4L2_MIN_BUFFERS); + guint min = MAX (self->v4l2output->min_buffers, + GST_V4L2_MIN_BUFFERS (self->v4l2output)); gst_buffer_pool_config_set_params (config, self->input_state->caps, self->v4l2output->info.size, min, min); @@ -1173,23 +1187,22 @@ gst_v4l2_video_enc_register (GstPlugin * plugin, GType type, GType subtype; gchar *type_name; GstV4l2VideoEncCData *cdata; + GValue value = G_VALUE_INIT; + + filtered_caps = gst_caps_intersect (src_caps, codec_caps); if (codec != NULL && video_fd != -1) { - GValue *value = gst_v4l2_codec_probe_levels (codec, video_fd); - if (value != NULL) { - gst_caps_set_value (src_caps, "level", value); - g_value_unset (value); + if (gst_v4l2_codec_probe_levels (codec, video_fd, &value)) { + gst_caps_set_value (filtered_caps, "level", &value); + g_value_unset (&value); } - value = gst_v4l2_codec_probe_profiles (codec, video_fd); - if (value != NULL) { - gst_caps_set_value (src_caps, "profile", value); - g_value_unset (value); + if (gst_v4l2_codec_probe_profiles (codec, video_fd, &value)) { + gst_caps_set_value (filtered_caps, "profile", &value); + g_value_unset (&value); } } - filtered_caps = gst_caps_intersect (src_caps, codec_caps); - cdata = g_new0 (GstV4l2VideoEncCData, 1); cdata->device = g_strdup (device_path); cdata->sink_caps = gst_caps_ref (sink_caps); diff --git a/sys/v4l2/tuner.c b/sys/v4l2/tuner.c index 37655eaef2..b4c68d7d67 100644 --- a/sys/v4l2/tuner.c +++ b/sys/v4l2/tuner.c @@ -128,8 +128,6 @@ gst_tuner_default_init (GstTunerInterface * iface) * @signal: The new signal strength (an integer) * * Reports that the signal strength has changed. - * - * See Also: gst_tuner_signal_strength() */ gst_tuner_signals[SIGNAL_CHANGED] = g_signal_new ("signal-changed", @@ -137,6 +135,10 @@ gst_tuner_default_init (GstTunerInterface * iface) G_STRUCT_OFFSET (GstTunerInterface, signal_changed), NULL, NULL, NULL, G_TYPE_NONE, 2, GST_TYPE_TUNER_CHANNEL, G_TYPE_INT); + gst_type_mark_as_plugin_api (GST_TYPE_TUNER, 0); + gst_type_mark_as_plugin_api (GST_TYPE_TUNER_CHANNEL, 0); + gst_type_mark_as_plugin_api (GST_TYPE_TUNER_NORM, 0); + initialized = TRUE; } diff --git a/sys/v4l2/tunerchannel.c b/sys/v4l2/tunerchannel.c index 25fa33a551..bdeeec263e 100644 --- a/sys/v4l2/tunerchannel.c +++ b/sys/v4l2/tunerchannel.c @@ -77,8 +77,6 @@ gst_tuner_channel_class_init (GstTunerChannelClass * klass) * @signal: The new signal strength (an integer) * * Reports that the signal strength has changed. - * - * See Also: gst_tuner_signal_strength() */ signals[SIGNAL_SIGNAL_CHANGED] = g_signal_new ("signal-changed", G_TYPE_FROM_CLASS (klass), diff --git a/sys/v4l2/v4l2_calls.c b/sys/v4l2/v4l2_calls.c index 53e2e7d1d3..fdd1ea15ef 100644 --- a/sys/v4l2/v4l2_calls.c +++ b/sys/v4l2/v4l2_calls.c @@ -330,7 +330,8 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object) case V4L2_CTRL_TYPE_MENU: case V4L2_CTRL_TYPE_INTEGER_MENU: case V4L2_CTRL_TYPE_BITMASK: - case V4L2_CTRL_TYPE_BUTTON:{ + case V4L2_CTRL_TYPE_BUTTON: + case V4L2_CTRL_TYPE_STRING:{ control.name[31] = '\0'; gst_v4l2_normalise_control_name ((gchar *) control.name); g_datalist_id_set_data (&v4l2object->controls, @@ -515,7 +516,7 @@ gst_v4l2_adjust_buf_type (GstV4l2Object * v4l2object) * return value: TRUE on success, FALSE on error ******************************************************/ gboolean -gst_v4l2_open (GstV4l2Object * v4l2object) +gst_v4l2_open (GstV4l2Object * v4l2object, GstV4l2Error * error) { struct stat st; int libv4l2_fd = -1; @@ -604,46 +605,43 @@ gst_v4l2_open (GstV4l2Object * v4l2object) /* ERRORS */ stat_failed: { - GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND, + GST_V4L2_ERROR (error, RESOURCE, NOT_FOUND, (_("Cannot identify device '%s'."), v4l2object->videodev), GST_ERROR_SYSTEM); goto error; } no_device: { - GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND, + GST_V4L2_ERROR (error, RESOURCE, NOT_FOUND, (_("This isn't a device '%s'."), v4l2object->videodev), GST_ERROR_SYSTEM); goto error; } not_open: { - GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ_WRITE, + GST_V4L2_ERROR (error, RESOURCE, OPEN_READ_WRITE, (_("Could not open device '%s' for reading and writing."), v4l2object->videodev), GST_ERROR_SYSTEM); goto error; } not_capture: { - GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND, - (_("Device '%s' is not a capture device."), - v4l2object->videodev), + GST_V4L2_ERROR (error, RESOURCE, NOT_FOUND, + (_("Device '%s' is not a capture device."), v4l2object->videodev), ("Capabilities: 0x%x", v4l2object->device_caps)); goto error; } not_output: { - GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND, - (_("Device '%s' is not a output device."), - v4l2object->videodev), + GST_V4L2_ERROR (error, RESOURCE, NOT_FOUND, + (_("Device '%s' is not a output device."), v4l2object->videodev), ("Capabilities: 0x%x", v4l2object->device_caps)); goto error; } not_m2m: { - GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND, - (_("Device '%s' is not a M2M device."), - v4l2object->videodev), + GST_V4L2_ERROR (error, RESOURCE, NOT_FOUND, + (_("Device '%s' is not a M2M device."), v4l2object->videodev), ("Capabilities: 0x%x", v4l2object->device_caps)); goto error; } @@ -970,6 +968,67 @@ gst_v4l2_set_attribute (GstV4l2Object * v4l2object, } } +/****************************************************** + * gst_v4l2_set_string_attribute(): + * try to set the string value of one specific attribute + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2_set_string_attribute (GstV4l2Object * v4l2object, + int attribute_num, const char *value) +{ + struct v4l2_ext_controls ctrls = { {0}, 1 }; + struct v4l2_ext_control ctrl; + struct v4l2_queryctrl control = { 0, }; + + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + control.id = attribute_num; + if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_QUERYCTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2object, + "Failed to find control %d on device '%s'.", + attribute_num, v4l2object->videodev); + return TRUE; + } + + if (control.type != V4L2_CTRL_TYPE_STRING) { + GST_WARNING_OBJECT (v4l2object, + "control %d is not string type on device '%s'.", + attribute_num, v4l2object->videodev); + return TRUE; + } + + ctrl.id = attribute_num; + ctrl.size = strlen (value) + 1; + ctrl.string = g_malloc (ctrl.size); + strcpy (ctrl.string, value); + + ctrls.which = V4L2_CTRL_ID2WHICH (attribute_num); + ctrls.count = 1; + ctrls.controls = &ctrl; + + GST_DEBUG_OBJECT (v4l2object->dbg_obj, "setting value of attribute %d to %s", + attribute_num, value); + + if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_EXT_CTRLS, &ctrls) < 0) + goto ctrl_failed; + + g_free (ctrl.string); + + return TRUE; + + /* ERRORS */ +ctrl_failed: + { + GST_WARNING_OBJECT (v4l2object, + _("Failed to set value %s for control %d on device '%s'."), + value, attribute_num, v4l2object->videodev); + g_free (ctrl.string); + return FALSE; + } +} + static gboolean set_control (GQuark field_id, const GValue * value, gpointer user_data) { @@ -1002,13 +1061,18 @@ set_control (GQuark field_id, const GValue * value, gpointer user_data) g_quark_to_string (field_id)); return TRUE; } - if (!G_VALUE_HOLDS (value, G_TYPE_INT)) { + if (G_VALUE_HOLDS (value, G_TYPE_INT)) { + gst_v4l2_set_attribute (v4l2object, GPOINTER_TO_INT (d), + g_value_get_int (value)); + } else if (G_VALUE_HOLDS (value, G_TYPE_STRING)) { + gst_v4l2_set_string_attribute (v4l2object, GPOINTER_TO_INT (d), + g_value_get_string (value)); + } else { GST_WARNING_OBJECT (v4l2object, - "'int' value expected for control '%s'.", g_quark_to_string (field_id)); + "no compatible value expected for control '%s'.", + g_quark_to_string (field_id)); return TRUE; } - gst_v4l2_set_attribute (v4l2object, GPOINTER_TO_INT (d), - g_value_get_int (value)); return TRUE; } diff --git a/sys/ximage/ximageutil.c b/sys/ximage/ximageutil.c index 57c9392c79..018b605156 100644 --- a/sys/ximage/ximageutil.c +++ b/sys/ximage/ximageutil.c @@ -26,7 +26,7 @@ GType gst_meta_ximage_api_get_type (void) { - static volatile GType type; + static GType type; static const gchar *tags[] = { "memory", NULL }; if (g_once_init_enter (&type)) { diff --git a/tests/check/elements/flvmux.c b/tests/check/elements/flvmux.c index 7b0d1827f1..c397513f81 100644 --- a/tests/check/elements/flvmux.c +++ b/tests/check/elements/flvmux.c @@ -935,23 +935,22 @@ GST_END_TEST; typedef struct { guint media_type; - gint ts; /* timestamp in ms */ - gint rt; /* running_time in ms */ + guint64 ts; /* timestamp in ms */ } InputData; GST_START_TEST (test_incrementing_timestamps) { GstPad *audio_sink, *video_sink, *audio_src, *video_src; GstHarness *h, *audio, *video, *audio_q, *video_q; - GstTestClock *tclock; guint i; + GstEvent *event; guint32 prev_pts; InputData input[] = { - {AUDIO, 155, 175}, - {VIDEO, 156, 191}, - {VIDEO, 190, 191}, - {AUDIO, 176, 195}, - {AUDIO, 197, 215}, + {AUDIO, 155}, + {VIDEO, 156}, + {VIDEO, 190}, + {AUDIO, 176}, + {AUDIO, 197}, }; /* setup flvmuxer with queues in front */ @@ -981,26 +980,27 @@ GST_START_TEST (test_incrementing_timestamps) "video/x-h264, stream-format=(string)avc, alignment=(string)au, " "codec_data=(buffer)0142c00dffe1000d6742c00d95a0507c807844235001000468ce3c80"); - tclock = gst_harness_get_testclock (h); - for (i = 0; i < G_N_ELEMENTS (input); i++) { InputData *d = &input[i]; GstBuffer *buf = gst_buffer_new (); - GstClockTime now = d->rt * GST_MSECOND; - GstClockID pending, res; GST_BUFFER_DTS (buf) = GST_BUFFER_PTS (buf) = d->ts * GST_MSECOND; - gst_test_clock_set_time (tclock, now); if (d->media_type == AUDIO) gst_harness_push (audio_q, buf); else gst_harness_push (video_q, buf); + } + + gst_harness_push_event (audio_q, gst_event_new_eos ()); + gst_harness_push_event (video_q, gst_event_new_eos ()); - gst_test_clock_wait_for_next_pending_id (tclock, &pending); - res = gst_test_clock_process_next_clock_id (tclock); - gst_clock_id_unref (pending); - gst_clock_id_unref (res); + while ((event = gst_harness_pull_event (h)) != NULL) { + GstEventType event_type = GST_EVENT_TYPE (event); + gst_event_unref (event); + + if (event_type == GST_EVENT_EOS) + break; } /* pull the flv metadata */ @@ -1014,6 +1014,9 @@ GST_START_TEST (test_incrementing_timestamps) GstBuffer *buf = gst_harness_pull (h); GstMapInfo map; guint32 pts; + + fail_unless (buf != NULL); + gst_buffer_map (buf, &map, GST_MAP_READ); pts = GST_READ_UINT24_BE (map.data + 4); GST_DEBUG ("media=%u, pts = %u\n", map.data[0], pts); @@ -1024,7 +1027,113 @@ GST_START_TEST (test_incrementing_timestamps) } /* teardown */ - gst_object_unref (tclock); + gst_harness_teardown (h); + gst_harness_teardown (audio); + gst_harness_teardown (video); + gst_harness_teardown (audio_q); + gst_harness_teardown (video_q); +} + +GST_END_TEST; + +GST_START_TEST (test_rollover_timestamps) +{ + GstPad *audio_sink, *video_sink, *audio_src, *video_src; + GstHarness *h, *audio, *video, *audio_q, *video_q; + GstEvent *event; + guint i; + guint64 rollover_pts = (guint64) G_MAXUINT32 + 100; + InputData input[] = { + {AUDIO, 0} + , + {VIDEO, 0} + , + {VIDEO, (guint64) G_MAXUINT32 - 100} + , + {AUDIO, (guint64) G_MAXUINT32 - 95} + , + {AUDIO, rollover_pts} + , + }; + + /* setup flvmuxer with queues in front */ + h = gst_harness_new_with_padnames ("flvmux", NULL, "src"); + audio = gst_harness_new_with_element (h->element, "audio", NULL); + video = gst_harness_new_with_element (h->element, "video", NULL); + audio_q = gst_harness_new ("queue"); + video_q = gst_harness_new ("queue"); + audio_sink = GST_PAD_PEER (audio->srcpad); + video_sink = GST_PAD_PEER (video->srcpad); + audio_src = GST_PAD_PEER (audio_q->sinkpad); + video_src = GST_PAD_PEER (video_q->sinkpad); + gst_pad_unlink (audio->srcpad, audio_sink); + gst_pad_unlink (video->srcpad, video_sink); + gst_pad_unlink (audio_src, audio_q->sinkpad); + gst_pad_unlink (video_src, video_q->sinkpad); + gst_pad_link (audio_src, audio_sink); + gst_pad_link (video_src, video_sink); + g_object_set (h->element, "streamable", TRUE, NULL); + + gst_harness_set_src_caps_str (audio_q, + "audio/mpeg, mpegversion=(int)4, " + "rate=(int)44100, channels=(int)1, " + "stream-format=(string)raw, codec_data=(buffer)1208"); + + gst_harness_set_src_caps_str (video_q, + "video/x-h264, stream-format=(string)avc, alignment=(string)au, " + "codec_data=(buffer)0142c00dffe1000d6742c00d95a0507c807844235001000468ce3c80"); + + for (i = 0; i < G_N_ELEMENTS (input); i++) { + InputData *d = &input[i]; + GstBuffer *buf = gst_buffer_new (); + + GST_BUFFER_DTS (buf) = GST_BUFFER_PTS (buf) = d->ts * GST_MSECOND; + GST_DEBUG ("Push media=%u, pts=%" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT + ")", d->media_type, d->ts, GST_TIME_ARGS (GST_BUFFER_PTS (buf))); + + if (d->media_type == AUDIO) + gst_harness_push (audio_q, buf); + else + gst_harness_push (video_q, buf); + + } + gst_harness_push_event (audio_q, gst_event_new_eos ()); + gst_harness_push_event (video_q, gst_event_new_eos ()); + + while ((event = gst_harness_pull_event (h)) != NULL) { + GstEventType event_type = GST_EVENT_TYPE (event); + gst_event_unref (event); + + if (event_type == GST_EVENT_EOS) + break; + } + + /* pull the flv metadata */ + gst_buffer_unref (gst_harness_pull (h)); + gst_buffer_unref (gst_harness_pull (h)); + gst_buffer_unref (gst_harness_pull (h)); + gst_buffer_unref (gst_harness_pull (h)); + + /* verify rollover pts in the flvheader is handled */ + for (i = 0; i < G_N_ELEMENTS (input); i++) { + GstBuffer *buf = gst_harness_pull (h); + GstMapInfo map; + guint32 pts, pts_ext; + + fail_unless (buf != NULL); + + gst_buffer_map (buf, &map, GST_MAP_READ); + pts = GST_READ_UINT24_BE (map.data + 4); + pts_ext = GST_READ_UINT8 (map.data + 7); + pts |= pts_ext << 24; + GST_DEBUG ("media=%u, pts=%u (%" GST_TIME_FORMAT ")", + map.data[0], pts, GST_TIME_ARGS (pts * GST_MSECOND)); + fail_unless (pts == (guint32) input[i].ts); + gst_buffer_unmap (buf, &map); + gst_buffer_unref (buf); + } + + /* teardown */ gst_harness_teardown (h); gst_harness_teardown (audio); gst_harness_teardown (video); @@ -1059,6 +1168,7 @@ flvmux_suite (void) tcase_add_test (tc_chain, test_audio_caps_change_streamable_single); tcase_add_test (tc_chain, test_video_caps_change_streamable_single); tcase_add_test (tc_chain, test_incrementing_timestamps); + tcase_add_test (tc_chain, test_rollover_timestamps); return s; } diff --git a/tests/check/elements/imagefreeze.c b/tests/check/elements/imagefreeze.c index 7a30d06067..ea33d56711 100644 --- a/tests/check/elements/imagefreeze.c +++ b/tests/check/elements/imagefreeze.c @@ -1,5 +1,6 @@ /* GStreamer * Copyright (C) 2010 Sebastian Dröge + * Copyright (C) 2020 Sebastian Dröge * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -20,6 +21,7 @@ #include #include +#include #include static gboolean @@ -648,6 +650,63 @@ GST_START_TEST (test_imagefreeze_eos) GST_END_TEST; +GST_START_TEST (test_imagefreeze_25_1_live) +{ + GstBuffer *buffer; + GstHarness *h = gst_harness_new_parse ("imagefreeze is-live=true"); + guint i; + + gst_harness_use_testclock (h); + gst_harness_play (h); + + gst_harness_set_src_caps_str (h, + "video/x-raw, format=xRGB, width=640, height=480, framerate=0/1"); + gst_harness_set_sink_caps_str (h, + "video/x-raw, format=xRGB, width=640, height=480, framerate=25/1"); + + /* Fill the buffer */ + buffer = gst_buffer_new (); + fail_unless_equals_int (gst_harness_push (h, buffer), GST_FLOW_EOS); + fail_unless (gst_harness_push_event (h, gst_event_new_eos ())); + + /* Check if we can get 10 buffers under normal circumstances out */ + for (i = 0; i < 10; i++) { + fail_unless (gst_harness_crank_single_clock_wait (h)); + buffer = gst_harness_pull (h); + fail_unless (buffer != NULL); + fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), i * 40 * GST_MSECOND); + gst_buffer_unref (buffer); + } + + /* Skip ahead, now the next buffer would be too late so imagefreeze should + * skip ahead too and continue from there */ + fail_unless (gst_harness_wait_for_clock_id_waits (h, 1, 5)); + gst_harness_set_time (h, 1 * GST_SECOND); + + /* FIXME: Consume one more buffer that went through because of a testclock + * bug. See https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/581 + */ + fail_unless (gst_harness_crank_single_clock_wait (h)); + buffer = gst_harness_pull (h); + fail_unless (buffer != NULL); + fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), i * 40 * GST_MSECOND); + gst_buffer_unref (buffer); + + /* Check if we can get 10 more buffers after the 1s gap */ + for (i = 0; i < 10; i++) { + fail_unless (gst_harness_crank_single_clock_wait (h)); + buffer = gst_harness_pull (h); + fail_unless (buffer != NULL); + fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), + GST_SECOND + i * 40 * GST_MSECOND); + gst_buffer_unref (buffer); + } + + gst_harness_teardown (h); +} + +GST_END_TEST; + static Suite * imagefreeze_suite (void) { @@ -667,6 +726,8 @@ imagefreeze_suite (void) tcase_add_test (tc_chain, test_imagefreeze_num_buffers); tcase_add_test (tc_chain, test_imagefreeze_eos); + tcase_add_test (tc_chain, test_imagefreeze_25_1_live); + return s; } diff --git a/tests/check/elements/qtdemux.c b/tests/check/elements/qtdemux.c index 44aa9b45c0..5271c65762 100644 --- a/tests/check/elements/qtdemux.c +++ b/tests/check/elements/qtdemux.c @@ -22,6 +22,7 @@ #include "qtdemux.h" #include +#include typedef struct { @@ -72,6 +73,106 @@ qtdemux_pad_added_cb (GstElement * element, GstPad * pad, CommonTestData * data) (GstPadProbeCallback) qtdemux_probe, data, NULL); } +GST_START_TEST (test_qtdemux_fuzzed0) +{ + GstHarness *h; + GstBuffer *buf; + guchar *fuzzed_qtdemux; + gsize fuzzed_qtdemux_len; + + /* The goal of this test is to check that qtdemux can properly handle + * a stream that does not contain any stsd entries, by correctly identifying + * the case and erroring out appropriately. + */ + + h = gst_harness_new_parse ("qtdemux"); + gst_harness_set_src_caps_str (h, "video/quicktime"); + + fuzzed_qtdemux = + g_base64_decode + ("AAAAIGZ0eXBtcDQyAAAAAG1wNDJtcDQxaXNvbWlzbzIAAAAIZnJlZQAAAMltZGF0AAAADGdCwAyV" + "oQkgHhEI1AAAAARozjyAAAAAIWW4AA5///wRRQAfHAxwABAJkxWTk6xWuuuupaupa6668AAAABJB" + "4CBX8Zd3d3d3d3d3eJ7E8ZAAAABWQeBAO/wpFAYoDFAYoDFAYkeKAzx4+gAA+kcPHBQGePPHF6jj" + "HP0Qdj/og7H/SHY/6jsf9R2P+o7H/Udj/qOx/1HY/6jsf9R2P+o7H/Udj/qOx/1HY/AAAAAGQeBg" + "O8IwAAAABkHggDvCMAAAA1dtb292AAAAbG12aGQAAAAA1lbpxdZW6cYAAAfQAAAH0AABAAABAAAA" + "AAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAACAAACpnRyYWsAAABcdGtoZAAAAAfWVunF1lbpxgAAAAEAAAAAAAAH0AAA" + "AAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAQAAAAEA" + "AAAAACRlZHRzAAAAHGVsc3QAAIAAAAAAAQAAB9AAAAAAAAEAAAAAAeFtZGlhAAAAIG1kaGQAAAAA" + "1lbpxdZW6cYAAAH0AAAB9FXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZUAAAAAAAAAAAAAAAFZpZGVv" + "SGFuZGxlcgAAAAGMbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAA" + "AAABAAAADHVybCAAAAABAAABTHN0YmwAAADAc3RzZAAAAAAAAAAAAAAAsGF2YzEAAAAAAAAAAQAA" + "AAAAAAAZAAAAAAAAAAAAQABAAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAY//8AAAAjYXZjQwFCwAz/4QAMZ0LADJWhCSAeEQjUAQAEaM48gAAAABRidHJ0AAAA" + "AAAAAAAAAAYIAAAAE2NvbHJuY2x4AAYAAQAGAAAAABBwYXNwAAAAAQAAAAEAAAAYc3R0cwAAAAAA" + "AAABAAAABQAAAAAAAAAUc3RzcwAAAAAAAAABAAAAAQAAABxzdHNjAAAAAAAAAAEAAAABAAAABQAA" + "AAEAAAAoc3RzegAAAAAAAAAAAAAAAQAAAAAAAAAWAAAAWgAAAAoAAAAKAAAAFHN0Y28AAAAAAAAA" + "AQAAADAAAAA9dWR0YQAAADVtZXRhAAAAAAAAACFoZGxyAAAAAG1obJJtZGlyAAAAAAAAAAAAAAAA" + "AAAAAAhpbHN0AAAAPXVkdGEAAAA1bWV0YQAAAAAAAAAhaGRscgAAAABtaGxybWRpcgAAAAAAAAAA" + "AAAAAAAAAAAIaWxzdA==", &fuzzed_qtdemux_len); + + buf = gst_buffer_new_and_alloc (fuzzed_qtdemux_len); + gst_buffer_fill (buf, 0, fuzzed_qtdemux, fuzzed_qtdemux_len); + fail_unless_equals_int (gst_harness_push (h, buf), GST_FLOW_OK); + + fail_unless (gst_harness_buffers_received (h) == 0); + + g_free (fuzzed_qtdemux); + gst_harness_teardown (h); +} + +GST_END_TEST; + +GST_START_TEST (test_qtdemux_fuzzed1) +{ + GstHarness *h; + GstBuffer *buf; + guchar *fuzzed_qtdemux; + gsize fuzzed_qtdemux_len; + + /* The goal of this test is to check that qtdemux can properly handle + * a stream that claims it contains more stsd entries than it can possibly have, + * by correctly identifying the case and erroring out appropriately. + */ + + h = gst_harness_new_parse ("qtdemux"); + gst_harness_set_src_caps_str (h, "video/quicktime"); + + fuzzed_qtdemux = + g_base64_decode + ("AAAAIGZ0eXBtcDQyAAAAAG1wNDJtcDQxaXNvbWlzbzIAAAAIZnJlZQAAAMltZGF0AAAADGdCwAyV" + "oQkgHhEI1AAAAARozjyAAAAAIWW4BA5///wRRQAfHAxwABAJkxWTk6xWuuuupaupa6668AAAABJB" + "4CBX8Zd3d3d3d3d3eJ7E8ZAAAABWQeBAO+opFAYoDFAYoDFAYkeKAzx4oDFAYkcPHBQGePPHF6jj" + "HP0Qdj/og7H/SHY/6jsf9R2P+o7H/Udj/qOx/1HY/6jsf9R2P+o7H/Udj/qOx/1HY/AAAAAGQeBg" + "O8IwAAAABkHggDvCMAAAA1dtb292AAAAbG12aGQAAAAA1lbpxdZW6cYAAAfQAAAH0AABAAABAAAA" + "AAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAACAAACpnRyYWsAAABcdGtoZAAAAAfWVunF1lbpxgAAAAEAAAAAAAAH0AAA" + "AAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAQAAAAEA" + "AAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAB9AAAAAAAAEAAAAAAeFtZGlhAAAAIG1kaGQAAAAA" + "1lbpxdZW6cYAAAH0AAAB9FXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVv" + "SGFuZGxlcgAAAAGMbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAA" + "AAABAAAADHVybCAAAAABAAABTHN0YmwAAADAc3RzZAAAAADv/wABAAAAsGF2YzEAAAAAAAAAAQAA" + "AAAAAAAAAAAAAAAAAAAAQABAAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAY//8AAAAjYXZjQwFCwAz/4QAMZ0LADJWhCSAeEQjUAQAEaM48gAAAABRidHJ0AAAA" + "AAAAAAAAAAYIAAAAE2NvbHJuY2x4AAYAAQAGAAAAABBwYXNwAAAAAQAAAAEAAAAYc3R0cwAAAAAA" + "AAABAAAABQAAAGQAAAAUc3RzcwAAAAAAAAABAAAAAQAAABxzdHNjAAAAAAAAAAEAAAABAAAABQAA" + "AAEAAAAoc3RzegAAAAAAAAAAAAAABQAAAD0AAAAWAAAAWgAAAAoAAAAKAAAAFHN0Y28AAAAAAAAA" + "AQAAADAAAAA9dWR0YQAAADVtZXRhAAAAAAAAACFoZGxyAAAAAG1obHJtZGlyAAAAAAAAAAAAAAAA" + "AAAAAAhpbHN0AAAAPXVkdGEAAAA1bWV0YQAAAAAAAAAhaGRscgAAAABtaGxybWRpcgAAAAAAAAAA" + "AAAAAAAAAAAIaWxzdA==", &fuzzed_qtdemux_len); + + buf = gst_buffer_new_and_alloc (fuzzed_qtdemux_len); + gst_buffer_fill (buf, 0, fuzzed_qtdemux, fuzzed_qtdemux_len); + fail_unless_equals_int (gst_harness_push (h, buf), GST_FLOW_OK); + + fail_unless (gst_harness_buffers_received (h) == 0); + + g_free (fuzzed_qtdemux); + gst_harness_teardown (h); +} + +GST_END_TEST; + GST_START_TEST (test_qtdemux_input_gap) { GstElement *qtdemux; @@ -639,6 +740,152 @@ GST_START_TEST (test_qtdemux_stream_change) GST_END_TEST; +static void +qtdemux_pad_added_cb_check_name (GstElement * element, GstPad * pad, + gchar * data) +{ + gchar *pad_name = gst_pad_get_name (pad); + + GST_DEBUG_OBJECT (pad, "New pad added"); + fail_unless (!g_strcmp0 (pad_name, data)); + g_free (pad_name); +} + +GST_START_TEST (test_qtdemux_pad_names) +{ + GstElement *qtdemux_v; + GstElement *qtdemux_a; + GstPad *sinkpad; + gchar *expected_video_pad_name; + gchar *expected_audio_pad_name; + GstBuffer *inbuf; + GstSegment segment; + GstEvent *event; + GstCaps *caps; + GstCaps *mediacaps; + + /* The goal of this test is to check that qtdemux can create proper + * pad names with encrypted stream caps in mss mode. + * + * Input Caps: + * - media-caps with cenc + * + * Expected behaviour + * - Demux exposes src pad with names in accordance to their media types + */ + expected_video_pad_name = g_strdup ("video_0"); + qtdemux_v = gst_element_factory_make ("qtdemux", NULL); + gst_element_set_state (qtdemux_v, GST_STATE_PLAYING); + sinkpad = gst_element_get_static_pad (qtdemux_v, "sink"); + + /* We'll want to know when the source pad is added */ + g_signal_connect (qtdemux_v, "pad-added", (GCallback) + qtdemux_pad_added_cb_check_name, expected_video_pad_name); + + /* Send the initial STREAM_START and segment (TIME) event */ + event = gst_event_new_stream_start ("TEST"); + GST_DEBUG ("Pushing stream-start event"); + fail_unless (gst_pad_send_event (sinkpad, event) == TRUE); + + /* Send CAPS event* */ + mediacaps = gst_caps_new_simple ("application/x-cenc", + "stream-format", G_TYPE_STRING, "avc", + "format", G_TYPE_STRING, "H264", + "width", G_TYPE_INT, 512, + "height", G_TYPE_INT, 288, + "original-media-type", G_TYPE_STRING, "video/x-h264", + "protection-system", G_TYPE_STRING, + "9a04f079-9840-4286-ab92-e65be0885f95", NULL); + caps = + gst_caps_new_simple ("video/quicktime", "variant", G_TYPE_STRING, + "mss-fragmented", "timesacle", G_TYPE_UINT64, 10000000, "media-caps", + GST_TYPE_CAPS, mediacaps, NULL); + + /* Send segment event* */ + event = gst_event_new_caps (caps); + GST_DEBUG ("Pushing caps event"); + fail_unless (gst_pad_send_event (sinkpad, event) == TRUE); + gst_caps_unref (mediacaps); + gst_caps_unref (caps); + + gst_segment_init (&segment, GST_FORMAT_TIME); + event = gst_event_new_segment (&segment); + GST_DEBUG ("Pushing segment event"); + fail_unless (gst_pad_send_event (sinkpad, event) == TRUE); + + /* Send the first fragment */ + /* NOTE: mss streams don't have moov */ + inbuf = gst_buffer_new_and_alloc (seg_1_moof_size); + gst_buffer_fill (inbuf, 0, seg_1_m4f, seg_1_moof_size); + GST_BUFFER_PTS (inbuf) = 0; + GST_BUFFER_OFFSET (inbuf) = 0; + GST_BUFFER_FLAG_SET (inbuf, GST_BUFFER_FLAG_DISCONT); + GST_DEBUG ("Pushing video fragment"); + fail_unless (gst_pad_chain (sinkpad, inbuf) == GST_FLOW_OK); + + gst_object_unref (sinkpad); + gst_element_set_state (qtdemux_v, GST_STATE_NULL); + gst_object_unref (qtdemux_v); + g_free (expected_video_pad_name); + + /* Repeat test for audio media type */ + expected_audio_pad_name = g_strdup ("audio_0"); + qtdemux_a = gst_element_factory_make ("qtdemux", NULL); + gst_element_set_state (qtdemux_a, GST_STATE_PLAYING); + sinkpad = gst_element_get_static_pad (qtdemux_a, "sink"); + + /* We'll want to know when the source pad is added */ + g_signal_connect (qtdemux_a, "pad-added", (GCallback) + qtdemux_pad_added_cb_check_name, expected_audio_pad_name); + + /* Send the initial STREAM_START and segment (TIME) event */ + event = gst_event_new_stream_start ("TEST"); + GST_DEBUG ("Pushing stream-start event"); + fail_unless (gst_pad_send_event (sinkpad, event) == TRUE); + + /* Send CAPS event* */ + mediacaps = gst_caps_new_simple ("application/x-cenc", + "mpegversion", G_TYPE_INT, 4, + "channels", G_TYPE_INT, 2, + "rate", G_TYPE_INT, 48000, + "original-media-type", G_TYPE_STRING, "audio/mpeg", + "protection-system", G_TYPE_STRING, + "9a04f079-9840-4286-ab92-e65be0885f95", NULL); + caps = + gst_caps_new_simple ("video/quicktime", "variant", G_TYPE_STRING, + "mss-fragmented", "timesacle", G_TYPE_UINT64, 10000000, "media-caps", + GST_TYPE_CAPS, mediacaps, NULL); + + /* Send segment event* */ + event = gst_event_new_caps (caps); + GST_DEBUG ("Pushing caps event"); + fail_unless (gst_pad_send_event (sinkpad, event) == TRUE); + gst_caps_unref (mediacaps); + gst_caps_unref (caps); + + gst_segment_init (&segment, GST_FORMAT_TIME); + event = gst_event_new_segment (&segment); + GST_DEBUG ("Pushing segment event"); + fail_unless (gst_pad_send_event (sinkpad, event) == TRUE); + + /* Send the first fragment */ + /* NOTE: mss streams don't have moov */ + inbuf = gst_buffer_new_and_alloc (seg_1_moof_size); + gst_buffer_fill (inbuf, 0, seg_1_m4f, seg_1_moof_size); + GST_BUFFER_PTS (inbuf) = 0; + GST_BUFFER_OFFSET (inbuf) = 0; + GST_BUFFER_FLAG_SET (inbuf, GST_BUFFER_FLAG_DISCONT); + GST_DEBUG ("Pushing audio fragment"); + fail_unless (gst_pad_chain (sinkpad, inbuf) == GST_FLOW_OK); + + gst_object_unref (sinkpad); + gst_element_set_state (qtdemux_a, GST_STATE_NULL); + gst_object_unref (qtdemux_a); + g_free (expected_audio_pad_name); +} + +GST_END_TEST; + static Suite * qtdemux_suite (void) { @@ -646,9 +893,12 @@ qtdemux_suite (void) TCase *tc_chain = tcase_create ("general"); suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_qtdemux_fuzzed0); + tcase_add_test (tc_chain, test_qtdemux_fuzzed1); tcase_add_test (tc_chain, test_qtdemux_input_gap); tcase_add_test (tc_chain, test_qtdemux_duplicated_moov); tcase_add_test (tc_chain, test_qtdemux_stream_change); + tcase_add_test (tc_chain, test_qtdemux_pad_names); return s; } diff --git a/tests/check/elements/rtp-payloading.c b/tests/check/elements/rtp-payloading.c index 8f99c7bb7b..c7f497763d 100644 --- a/tests/check/elements/rtp-payloading.c +++ b/tests/check/elements/rtp-payloading.c @@ -180,8 +180,12 @@ rtp_pipeline_create (const guint8 * frame_data, int frame_data_size, p->pipeline = gst_pipeline_new (pipeline_name); g_free (pipeline_name); p->appsrc = gst_element_factory_make ("appsrc", NULL); - p->rtppay = gst_element_factory_make (pay, NULL); - p->rtpdepay = gst_element_factory_make (depay, NULL); + p->rtppay = + gst_parse_bin_from_description_full (pay, TRUE, NULL, + GST_PARSE_FLAG_NO_SINGLE_ELEMENT_BINS, NULL); + p->rtpdepay = + gst_parse_bin_from_description_full (depay, TRUE, NULL, + GST_PARSE_FLAG_NO_SINGLE_ELEMENT_BINS, NULL); p->fakesink = gst_element_factory_make ("fakesink", NULL); /* One or more elements are not created successfully or failed to create p? */ @@ -867,7 +871,7 @@ GST_START_TEST (rtp_h264_list_lt_mtu) rtp_pipeline_test (rtp_h264_list_lt_mtu_frame_data, rtp_h264_list_lt_mtu_frame_data_size, rtp_h264_list_lt_mtu_frame_count, "video/x-h264,stream-format=(string)byte-stream,alignment=(string)nal", - "rtph264pay", "rtph264depay", + "rtph264pay aggregate-mode=zero-latency", "rtph264depay", rtp_h264_list_lt_mtu_bytes_sent, rtp_h264_list_lt_mtu_mtu_size, TRUE); } @@ -893,7 +897,7 @@ GST_START_TEST (rtp_h264_list_lt_mtu_avc) rtp_h264_list_lt_mtu_frame_data_size, rtp_h264_list_lt_mtu_frame_count, "video/x-h264,stream-format=(string)avc,alignment=(string)au," "codec_data=(buffer)01640014ffe1001867640014acd94141fb0110000003001773594000f142996001000568ebecb22c", - "rtph264pay", "rtph264depay", + "rtph264pay aggregate-mode=zero-latency", "rtph264depay", rtp_h264_list_lt_mtu_bytes_sent_avc, rtp_h264_list_lt_mtu_mtu_size, TRUE); } @@ -1045,8 +1049,9 @@ GST_START_TEST (rtp_h265_list_lt_mtu_hvc1) "01840010c01ffff01c000000300800000030000030099ac0900a10001003042010101c00" "0000300800000030000030099a00a080f1fe36bbb5377725d602dc040404100000300010" "00003000a0800a2000100074401c172b02240", - "rtph265pay", "rtph265depay", rtp_h265_list_lt_mtu_bytes_sent_hvc1, - rtp_h265_list_lt_mtu_mtu_size, TRUE); + "rtph265pay aggregate-mode=zero-latency", "rtph265depay", + rtp_h265_list_lt_mtu_bytes_sent_hvc1, rtp_h265_list_lt_mtu_mtu_size, + TRUE); } GST_END_TEST; @@ -1295,6 +1300,56 @@ GST_START_TEST (rtp_vorbis) } GST_END_TEST; + +/* videotestsrc pattern=red ! video/x-raw,width=160,height=120 ! vp8enc */ +#define VP8_CAPS "video/x-vp8, profile=(string)0, " \ + "streamheader=(buffer)4f5650383001010000a000780000010000010000001e00000001, " \ + "width=(int)160, height=(int)120, framerate=(fraction)30/1" + +static const guint8 rtp_vp8_frame_data[] = { + 0x30, 0x07, 0x00, 0x9d, 0x01, 0x2a, 0xa0, 0x00, + 0x78, 0x00, 0x00, 0x47, 0x08, 0x85, 0x85, 0x88, + 0x85, 0x84, 0x88, 0x02, 0x02, 0x02, 0x75, 0xaa, + 0x03, 0xf8, 0x03, 0xfa, 0x02, 0x06, 0xc3, 0xef, + 0x05, 0x10, 0x9c, 0x52, 0xd2, 0xa1, 0x38, 0xa5, + 0xa5, 0x42, 0x71, 0x4b, 0x4a, 0x84, 0xe2, 0x96, + 0x95, 0x09, 0xc5, 0x2d, 0x2a, 0x13, 0x8a, 0x5a, + 0x54, 0x27, 0x14, 0xb4, 0xa8, 0x4e, 0x29, 0x69, + 0x50, 0x9b, 0x00, 0xfe, 0xfd, 0x6e, 0xf3, 0xff, + 0xe3, 0x99, 0x37, 0x30, 0xc4, 0xff, 0x8e, 0x6d, + 0xff, 0xf1, 0x61, 0x3c, 0x0e, 0x28, 0xc8, 0xff, + 0xf1, 0x51, 0x00 +}; + +GST_START_TEST (rtp_vp8) +{ + rtp_pipeline_test (rtp_vp8_frame_data, sizeof (rtp_vp8_frame_data), 1, + VP8_CAPS, "rtpvp8pay", "rtpvp8depay", 0, 0, FALSE); +} + +GST_END_TEST; + +/* videotestsrc pattern=red ! video/x-raw,width=160,height=120 ! vp9enc */ +#define VP9_CAPS "video/x-vp9, profile=(string)0, " \ + "width=(int)160, height=(int)120, framerate=(fraction)30/1" + +static const guint8 rtp_vp9_frame_data[] = { + 0x82, 0x49, 0x83, 0x42, 0x00, 0x09, 0xf0, 0x07, + 0x76, 0x00, 0x38, 0x24, 0x1c, 0x18, 0x42, 0x00, + 0x00, 0x30, 0x60, 0x00, 0x00, 0x67, 0x3f, 0xff, + 0xfe, 0x69, 0x95, 0xff, 0xff, 0xff, 0xfe, 0x99, + 0x6b, 0xff, 0xff, 0xff, 0xff, 0x62, 0x98, 0x1d, + 0x45, 0x4c, 0x90, 0xc4, 0x70 +}; + +GST_START_TEST (rtp_vp9) +{ + rtp_pipeline_test (rtp_vp9_frame_data, sizeof (rtp_vp9_frame_data), 1, + VP9_CAPS, "rtpvp9pay", "rtpvp9depay", 0, 0, FALSE); +} + +GST_END_TEST; + static const guint8 rtp_jpeg_frame_data[] = { /* SOF */ 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00, 0x08, 0x00, 0x08, 0x03, 0x00, 0x21, 0x08, 0x01, 0x11, 0x08, 0x02, 0x11, 0x08, @@ -1663,6 +1718,8 @@ rtp_payloading_suite (void) tcase_add_test (tc_chain, rtp_mp4g); tcase_add_test (tc_chain, rtp_theora); tcase_add_test (tc_chain, rtp_vorbis); + tcase_add_test (tc_chain, rtp_vp8); + tcase_add_test (tc_chain, rtp_vp9); tcase_add_test (tc_chain, rtp_jpeg); tcase_add_test (tc_chain, rtp_jpeg_width_greater_than_2040); tcase_add_test (tc_chain, rtp_jpeg_height_greater_than_2040); diff --git a/tests/check/elements/rtpbin.c b/tests/check/elements/rtpbin.c index 2a9266241c..f3686a6c53 100644 --- a/tests/check/elements/rtpbin.c +++ b/tests/check/elements/rtpbin.c @@ -939,7 +939,9 @@ _pad_added (G_GNUC_UNUSED GstElement * rtpbin, GstPad * pad, GstHarness * h) GST_START_TEST (test_quick_shutdown) { - for (guint r = 0; r < 1000; r++) { + guint r; + + for (r = 0; r < 1000; r++) { guint i; GstHarness *h = gst_harness_new_with_padnames ("rtpbin", "recv_rtp_sink_0", NULL); diff --git a/tests/check/elements/rtpfunnel.c b/tests/check/elements/rtpfunnel.c index 5c690e2df8..5224dce8d6 100644 --- a/tests/check/elements/rtpfunnel.c +++ b/tests/check/elements/rtpfunnel.c @@ -22,6 +22,7 @@ */ #include #include +#include GST_START_TEST (rtpfunnel_ssrc_demuxing) { @@ -81,7 +82,8 @@ GST_START_TEST (rtpfunnel_ssrc_demuxing) gst_harness_teardown (h1); } -GST_END_TEST +GST_END_TEST; + GST_START_TEST (rtpfunnel_ssrc_downstream_not_leaking_through) { GstHarness *h = gst_harness_new_with_padnames ("rtpfunnel", @@ -100,7 +102,8 @@ GST_START_TEST (rtpfunnel_ssrc_downstream_not_leaking_through) gst_harness_teardown (h); } -GST_END_TEST +GST_END_TEST; + GST_START_TEST (rtpfunnel_common_ts_offset) { GstHarness *h = gst_harness_new_with_padnames ("rtpfunnel", @@ -122,7 +125,8 @@ GST_START_TEST (rtpfunnel_common_ts_offset) gst_harness_teardown (h); } -GST_END_TEST +GST_END_TEST; + GST_START_TEST (rtpfunnel_stress) { GstHarness *h = gst_harness_new_with_padnames ("rtpfunnel", @@ -173,6 +177,226 @@ GST_START_TEST (rtpfunnel_stress) GST_END_TEST; +#define TWCC_EXTMAP_STR "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01" + +GST_START_TEST (rtpfunnel_twcc_caps) +{ + GstHarness *h, *h0, *h1; + GstCaps *caps, *expected_caps; + + h = gst_harness_new_with_padnames ("rtpfunnel", NULL, "src"); + + /* request a sinkpad, set caps with twcc extmap */ + h0 = gst_harness_new_with_element (h->element, "sink_0", NULL); + gst_harness_set_src_caps_str (h0, "application/x-rtp, " + "ssrc=(uint)123, extmap-5=" TWCC_EXTMAP_STR ""); + + /* request a second sinkpad, and verify the extmap is + present in the caps when doing a caps-query downstream */ + h1 = gst_harness_new_with_element (h->element, "sink_1", NULL); + caps = gst_pad_query_caps (GST_PAD_PEER (h1->srcpad), NULL); + expected_caps = gst_caps_from_string ("application/x-rtp, " + "extmap-5=" TWCC_EXTMAP_STR ""); + fail_unless (gst_caps_is_equal (expected_caps, caps)); + gst_caps_unref (caps); + gst_caps_unref (expected_caps); + + /* now try and set a different extmap (4) on the other sinkpad, + and verify this does not work */ + gst_harness_set_src_caps_str (h1, "application/x-rtp, " + "ssrc=(uint)456, extmap-4=" TWCC_EXTMAP_STR ""); + caps = gst_pad_get_current_caps (GST_PAD_PEER (h1->srcpad)); + fail_unless (caps == NULL); + + /* ...but setting the right extmap (5) will work just fine */ + expected_caps = gst_caps_from_string ("application/x-rtp, " + "ssrc=(uint)456, extmap-5=" TWCC_EXTMAP_STR ""); + gst_harness_set_src_caps (h1, gst_caps_ref (expected_caps)); + caps = gst_pad_get_current_caps (GST_PAD_PEER (h1->srcpad)); + fail_unless (gst_caps_is_equal (expected_caps, caps)); + gst_caps_unref (caps); + gst_caps_unref (expected_caps); + + gst_harness_teardown (h); + gst_harness_teardown (h0); + gst_harness_teardown (h1); +} + +GST_END_TEST; + +static GstBuffer * +generate_test_buffer (guint seqnum, guint ssrc, guint8 twcc_ext_id) +{ + GstBuffer *buf; + GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; + + buf = gst_rtp_buffer_new_allocate (0, 0, 0); + GST_BUFFER_PTS (buf) = seqnum * 20 * GST_MSECOND; + GST_BUFFER_DTS (buf) = GST_BUFFER_PTS (buf); + + gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp); + gst_rtp_buffer_set_payload_type (&rtp, 100); + gst_rtp_buffer_set_seq (&rtp, seqnum); + gst_rtp_buffer_set_timestamp (&rtp, seqnum * 160); + gst_rtp_buffer_set_ssrc (&rtp, ssrc); + + if (twcc_ext_id > 0) { + guint16 data; + GST_WRITE_UINT16_BE (&data, seqnum); + gst_rtp_buffer_add_extension_onebyte_header (&rtp, twcc_ext_id, + &data, sizeof (guint16)); + } + + gst_rtp_buffer_unmap (&rtp); + + return buf; +} + +static gint32 +get_twcc_seqnum (GstBuffer * buf, guint8 ext_id) +{ + GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; + gint32 val = -1; + gpointer data; + + gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp); + if (gst_rtp_buffer_get_extension_onebyte_header (&rtp, ext_id, + 0, &data, NULL)) { + val = GST_READ_UINT16_BE (data); + } + gst_rtp_buffer_unmap (&rtp); + + return val; +} + +static guint32 +get_ssrc (GstBuffer * buf) +{ + guint32 ssrc; + GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; + gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp); + ssrc = gst_rtp_buffer_get_ssrc (&rtp); + gst_rtp_buffer_unmap (&rtp); + return ssrc; +} + +GST_START_TEST (rtpfunnel_twcc_passthrough) +{ + GstHarness *h, *h0; + GstBuffer *buf; + guint16 offset = 65530; + guint packets = 40; + guint i; + + h = gst_harness_new_with_padnames ("rtpfunnel", NULL, "src"); + h0 = gst_harness_new_with_element (h->element, "sink_0", NULL); + gst_harness_set_src_caps_str (h0, "application/x-rtp, " + "ssrc=(uint)123, extmap-5=" TWCC_EXTMAP_STR ""); + + /* push some packets with twcc seqnum */ + for (i = 0; i < packets; i++) { + guint16 seqnum = i + offset; + fail_unless_equals_int (GST_FLOW_OK, + gst_harness_push (h0, generate_test_buffer (seqnum, 123, 5))); + } + + /* and verify the seqnums stays unchanged through the funnel */ + for (i = 0; i < packets; i++) { + guint16 seqnum = i + offset; + buf = gst_harness_pull (h); + fail_unless_equals_int (seqnum, get_twcc_seqnum (buf, 5)); + gst_buffer_unref (buf); + } + + gst_harness_teardown (h); + gst_harness_teardown (h0); +} + +GST_END_TEST; + +GST_START_TEST (rtpfunnel_twcc_mux) +{ + GstHarness *h, *h0, *h1; + GstBuffer *buf; + + h = gst_harness_new_with_padnames ("rtpfunnel", NULL, "src"); + h0 = gst_harness_new_with_element (h->element, "sink_0", NULL); + h1 = gst_harness_new_with_element (h->element, "sink_1", NULL); + gst_harness_set_src_caps_str (h0, "application/x-rtp, " + "ssrc=(uint)123, extmap-5=" TWCC_EXTMAP_STR ""); + gst_harness_set_src_caps_str (h1, "application/x-rtp, " + "ssrc=(uint)456, extmap-5=" TWCC_EXTMAP_STR ""); + + /* push buffers on both pads with different twcc-seqnums on them (500 and 60000) */ + fail_unless_equals_int (GST_FLOW_OK, + gst_harness_push (h0, generate_test_buffer (500, 123, 5))); + fail_unless_equals_int (GST_FLOW_OK, + gst_harness_push (h1, generate_test_buffer (60000, 321, 5))); + + /* verify they are muxed continuously (0 -> 1) */ + buf = gst_harness_pull (h); + fail_unless_equals_int (123, get_ssrc (buf)); + fail_unless_equals_int (0, get_twcc_seqnum (buf, 5)); + gst_buffer_unref (buf); + + buf = gst_harness_pull (h); + fail_unless_equals_int (321, get_ssrc (buf)); + fail_unless_equals_int (1, get_twcc_seqnum (buf, 5)); + gst_buffer_unref (buf); + + gst_harness_teardown (h); + gst_harness_teardown (h0); + gst_harness_teardown (h1); +} + +GST_END_TEST; + + +GST_START_TEST (rtpfunnel_twcc_passthrough_then_mux) +{ + GstHarness *h, *h0, *h1; + GstBuffer *buf; + guint offset0 = 500; + guint offset1 = 45678; + guint i; + + h = gst_harness_new_with_padnames ("rtpfunnel", NULL, "src"); + h0 = gst_harness_new_with_element (h->element, "sink_0", NULL); + gst_harness_set_src_caps_str (h0, "application/x-rtp, " + "ssrc=(uint)123, extmap-5=" TWCC_EXTMAP_STR ""); + + /* push one packet with twcc seqnum 100 on pad0 */ + fail_unless_equals_int (GST_FLOW_OK, + gst_harness_push (h0, generate_test_buffer (offset0, 123, 5))); + + /* add pad1 to the funnel, also with twcc */ + h1 = gst_harness_new_with_element (h->element, "sink_1", NULL); + gst_harness_set_src_caps_str (h1, "application/x-rtp, " + "ssrc=(uint)456, extmap-5=" TWCC_EXTMAP_STR ""); + + /* push one buffer on both pads, with pad1 starting at a different + offset */ + fail_unless_equals_int (GST_FLOW_OK, + gst_harness_push (h0, generate_test_buffer (offset0 + 1, 123, 5))); + fail_unless_equals_int (GST_FLOW_OK, + gst_harness_push (h1, generate_test_buffer (offset1, 321, 5))); + + /* and verify the seqnums are continuous for all 3 packets, using + the inital offset from pad0 */ + for (i = 0; i < 3; i++) { + guint16 seqnum = i + offset0; + buf = gst_harness_pull (h); + fail_unless_equals_int (seqnum, get_twcc_seqnum (buf, 5)); + gst_buffer_unref (buf); + } + + gst_harness_teardown (h); + gst_harness_teardown (h0); + gst_harness_teardown (h1); +} + +GST_END_TEST; + static Suite * rtpfunnel_suite (void) { @@ -187,6 +411,11 @@ rtpfunnel_suite (void) tcase_add_test (tc_chain, rtpfunnel_stress); + tcase_add_test (tc_chain, rtpfunnel_twcc_caps); + tcase_add_test (tc_chain, rtpfunnel_twcc_passthrough); + tcase_add_test (tc_chain, rtpfunnel_twcc_mux); + tcase_add_test (tc_chain, rtpfunnel_twcc_passthrough_then_mux); + return s; } diff --git a/tests/check/elements/rtph264.c b/tests/check/elements/rtph264.c index 51bd041807..087a371736 100644 --- a/tests/check/elements/rtph264.c +++ b/tests/check/elements/rtph264.c @@ -199,6 +199,53 @@ c_mem_app_sink_class_init (CMemAppSinkClass * klass) #define RTP_H264_FILE GST_TEST_FILES_PATH G_DIR_SEPARATOR_S "h264.rtp" +static GstBuffer * +create_codec_data (guint8 * sps, gsize sps_size, guint8 * pps, gsize pps_size) +{ + unsigned int offset = 0; + GstBuffer *codec_data_buffer; + GstMemory *mem; + GstMapInfo map_info; + guint8 *codec_data; + + codec_data_buffer = + gst_buffer_new_allocate (NULL, sps_size + pps_size + 11, NULL); + mem = gst_buffer_peek_memory (codec_data_buffer, 0); + gst_memory_map (mem, &map_info, GST_MAP_WRITE); + + codec_data = map_info.data; + + codec_data[offset++] = 0x01; /* Configuration Version */ + codec_data[offset++] = sps[1]; /* AVCProfileIndication */ + codec_data[offset++] = sps[2]; /* profile_compatibility */ + codec_data[offset++] = sps[3]; /* AVCLevelIndication */ + codec_data[offset++] = 0xff; /* lengthSizeMinusOne == 3 -> length == 4 byte */ + + /* SPS */ + codec_data[offset++] = 0xe1; /* numOfSequenceParameterSets | b11100000 -> numSPS == 1 */ + + g_assert (sps_size <= 0xffff); + codec_data[offset++] = (sps_size >> 8) & 0xff; /* numOfSequenceParameterSets high 8bit */ + codec_data[offset++] = sps_size & 0xff; /* numOfSequenceParameterSets low 8bit */ + memcpy (codec_data + offset, sps, sps_size); + offset += sps_size; + + /* PPS */ + codec_data[offset++] = 0x1; /* numOfPictureParameterSets == 1 */ + + g_assert (pps_size <= 0xffff); + codec_data[offset++] = (pps_size >> 8) & 0xff; + codec_data[offset++] = pps_size & 0xff; + memcpy (codec_data + offset, pps, pps_size); + offset += pps_size; + + gst_memory_unmap (mem, &map_info); + + g_assert (offset == gst_buffer_get_size (codec_data_buffer)); + + return codec_data_buffer; +} + GST_START_TEST (test_rtph264depay_with_downstream_allocator) { GstElement *pipeline, *src, *depay, *sink; @@ -298,21 +345,36 @@ GST_END_TEST; static GstBuffer * -wrap_static_buffer_with_pts (guint8 * buf, gsize size, GstClockTime pts) +wrap_static_buffer_with_pts_full (guint8 * buf, gsize size, GstClockTime pts, + gpointer user_data, GDestroyNotify notify) { GstBuffer *buffer; buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, - buf, size, 0, size, NULL, NULL); + buf, size, 0, size, user_data, notify); GST_BUFFER_PTS (buffer) = pts; return buffer; } +static GstBuffer * +wrap_static_buffer_full (guint8 * buf, gsize size, gpointer user_data, + GDestroyNotify notify) +{ + return wrap_static_buffer_with_pts_full (buf, size, GST_CLOCK_TIME_NONE, + user_data, notify); +} + +static GstBuffer * +wrap_static_buffer_with_pts (guint8 * buf, gsize size, GstClockTime pts) +{ + return wrap_static_buffer_with_pts_full (buf, size, pts, NULL, NULL); +} + static GstBuffer * wrap_static_buffer (guint8 * buf, gsize size) { - return wrap_static_buffer_with_pts (buf, size, GST_CLOCK_TIME_NONE); + return wrap_static_buffer_full (buf, size, NULL, NULL); } /* This was generated using pipeline: @@ -408,6 +470,127 @@ GST_START_TEST (test_rtph264depay_marker_to_flag) GST_END_TEST; +/* This was generated using pipeline: + * gst-launch-1.0 videotestsrc num-buffers=1 pattern=green \ + * ! video/x-raw,width=24,height=16 \ + * ! openh264enc ! rtph264pay mtu=32 ! fakesink dump=1 + */ +/* RTP h264_idr FU-A */ +static guint8 rtp_h264_idr_fu_start[] = { + 0x80, 0x60, 0x5f, 0xd2, 0x20, 0x3b, 0x6e, 0xcf, + 0x6c, 0x54, 0x21, 0x8d, 0x7c, 0x85, 0xb8, 0x00, + 0x04, 0x00, 0x00, 0x09, 0xff, 0xff, 0xf8, 0x22, + 0x8a, 0x00, 0x1f, 0x1c, 0x00, 0x04, 0x1c, 0xe3, +}; + +static guint8 rtp_h264_idr_fu_middle[] = { + 0x80, 0x60, 0x5f, 0xd3, 0x20, 0x3b, 0x6e, 0xcf, + 0x6c, 0x54, 0x21, 0x8d, 0x7c, 0x05, 0x80, 0x00, + 0x84, 0xdf, 0xf8, 0x7f, 0xe0, 0x8e, 0x28, 0x00, + 0x08, 0x37, 0xf8, 0x80, 0x00, 0x20, 0x52, 0x00, +}; + +static guint8 rtp_h264_idr_fu_end[] = { + 0x80, 0xe0, 0x5f, 0xd4, 0x20, 0x3b, 0x6e, 0xcf, + 0x6c, 0x54, 0x21, 0x8d, 0x7c, 0x45, 0x02, 0x01, + 0x91, 0x00, 0x00, 0x40, 0xf4, 0x00, 0x04, 0x08, + 0x30, +}; + +GST_START_TEST (test_rtph264depay_fu_a) +{ + GstHarness *h = gst_harness_new ("rtph264depay"); + GstBuffer *buffer; + GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; + GstFlowReturn ret; + + gst_harness_set_caps_str (h, + "application/x-rtp,media=video,clock-rate=90000,encoding-name=H264", + "video/x-h264,alignment=au,stream-format=byte-stream"); + + buffer = + wrap_static_buffer (rtp_h264_idr_fu_start, + sizeof (rtp_h264_idr_fu_start)); + fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp)); + gst_rtp_buffer_unmap (&rtp); + + ret = gst_harness_push (h, buffer); + fail_unless_equals_int (ret, GST_FLOW_OK); + fail_unless_equals_int (gst_harness_buffers_in_queue (h), 0); + + buffer = + wrap_static_buffer (rtp_h264_idr_fu_middle, + sizeof (rtp_h264_idr_fu_middle)); + ret = gst_harness_push (h, buffer); + fail_unless_equals_int (ret, GST_FLOW_OK); + + buffer = + wrap_static_buffer (rtp_h264_idr_fu_end, sizeof (rtp_h264_idr_fu_end)); + ret = gst_harness_push (h, buffer); + fail_unless_equals_int (ret, GST_FLOW_OK); + + fail_unless_equals_int (gst_harness_buffers_in_queue (h), 1); + + buffer = gst_harness_pull (h); + fail_unless (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_MARKER)); + gst_buffer_unref (buffer); + + gst_harness_teardown (h); +} + +GST_END_TEST; + +GST_START_TEST (test_rtph264depay_fu_a_missing_start) +{ + GstHarness *h = gst_harness_new ("rtph264depay"); + GstBuffer *buffer; + GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; + GstFlowReturn ret; + guint16 seq; + + gst_harness_set_caps_str (h, + "application/x-rtp,media=video,clock-rate=90000,encoding-name=H264", + "video/x-h264,alignment=au,stream-format=byte-stream"); + + buffer = + wrap_static_buffer (rtp_h264_idr_fu_start, + sizeof (rtp_h264_idr_fu_start)); + + ret = gst_harness_push (h, buffer); + fail_unless_equals_int (ret, GST_FLOW_OK); + + buffer = + wrap_static_buffer (rtp_h264_idr_fu_middle, + sizeof (rtp_h264_idr_fu_middle)); + ret = gst_harness_push (h, buffer); + fail_unless_equals_int (ret, GST_FLOW_OK); + + buffer = + wrap_static_buffer (rtp_h264_idr_fu_end, sizeof (rtp_h264_idr_fu_end)); + fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp)); + seq = gst_rtp_buffer_get_seq (&rtp); + gst_rtp_buffer_unmap (&rtp); + ret = gst_harness_push (h, buffer); + fail_unless_equals_int (ret, GST_FLOW_OK); + fail_unless_equals_int (gst_harness_buffers_in_queue (h), 1); + + /* A broken sender case seen in the wild where the seqnums are continuous + * but only contain a FU with an end-bit, no start-bit */ + buffer = + wrap_static_buffer (rtp_h264_idr_fu_end, sizeof (rtp_h264_idr_fu_end)); + fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_WRITE, &rtp)); + gst_rtp_buffer_set_seq (&rtp, ++seq); + gst_rtp_buffer_unmap (&rtp); + ret = gst_harness_push (h, buffer); + fail_unless_equals_int (ret, GST_FLOW_OK); + + fail_unless_equals_int (gst_harness_buffers_in_queue (h), 1); + + gst_harness_teardown (h); +} + +GST_END_TEST; + /* As GStreamer does not have STAP-A yet, this was extracted from * issue #557 provided sample */ @@ -527,6 +710,40 @@ static guint8 h264_idr_slice_2[] = { 0xd7, 0x5d, 0x75, 0xd7, 0x5e }; +/* SPS */ +static guint8 h264_sps_avc[] = { + 0x00, 0x00, 0x00, 0x0E, 0x67, 0x42, 0xc0, 0x29, + 0x8c, 0x8d, 0x41, 0x02, 0x24, 0x03, 0xc2, 0x21, + 0x1a, 0x80 +}; + +/* PPS */ +static guint8 h264_pps_avc[] = { + 0x00, 0x00, 0x00, 0x04, 0x68, 0xce, 0x3c, 0x80 +}; + +/* IDR Slice 1 */ +static guint8 h264_idr_slice_1_avc[] = { + 0x00, 0x00, 0x00, 0x30, 0x65, 0xb8, 0x00, 0x04, + 0x00, 0x00, 0x11, 0xff, 0xff, 0xf8, 0x22, 0x8a, + 0x1f, 0x1c, 0x00, 0x04, 0x0a, 0x63, 0x80, 0x00, + 0x81, 0xec, 0x9a, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0xad, 0x57, 0x5d, 0x75, 0xd7, 0x5d, 0x75, + 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, + 0x75, 0xd7, 0x5d, 0x78 +}; + +/* IDR Slice 2 */ +static guint8 h264_idr_slice_2_avc[] = { + 0x00, 0x00, 0x00, 0x31, 0x65, 0x04, 0x2e, 0x00, + 0x01, 0x00, 0x00, 0x04, 0x7f, 0xff, 0xfe, 0x08, + 0xa2, 0x87, 0xc7, 0x00, 0x01, 0x02, 0x98, 0xe0, + 0x00, 0x20, 0x7b, 0x26, 0xa4, 0xe4, 0xe4, 0xe4, + 0xe4, 0xe4, 0xeb, 0x55, 0xd7, 0x5d, 0x75, 0xd7, + 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, + 0xd7, 0x5d, 0x75, 0xd7, 0x5e +}; + /* The RFC makes special use of NAL type 24 to 27, this test makes sure that * such a NAL from the outside gets ignored properly. */ GST_START_TEST (test_rtph264pay_reserved_nals) @@ -579,7 +796,8 @@ GST_END_TEST; GST_START_TEST (test_rtph264pay_two_slices_timestamp) { - GstHarness *h = gst_harness_new_parse ("rtph264pay timestamp-offset=123"); + GstHarness *h = gst_harness_new_parse ("rtph264pay timestamp-offset=123" + " aggregate-mode=zero-latency"); GstFlowReturn ret; GstBuffer *buffer; GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; @@ -640,7 +858,8 @@ GST_END_TEST; GST_START_TEST (test_rtph264pay_marker_for_flag) { - GstHarness *h = gst_harness_new_parse ("rtph264pay timestamp-offset=123"); + GstHarness *h = gst_harness_new_parse ("rtph264pay timestamp-offset=123" + " aggregate-mode=zero-latency"); GstFlowReturn ret; GstBuffer *buffer; GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; @@ -719,7 +938,8 @@ GST_END_TEST; GST_START_TEST (test_rtph264pay_marker_for_fragmented_au) { GstHarness *h = - gst_harness_new_parse ("rtph264pay timestamp-offset=123 mtu=40"); + gst_harness_new_parse ("rtph264pay timestamp-offset=123 mtu=40" + " aggregate-mode=zero-latency"); GstFlowReturn ret; GstBuffer *slice1, *slice2, *buffer; GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; @@ -769,8 +989,7 @@ GST_START_TEST (test_rtph264pay_aggregate_two_slices_per_buffer) gst_harness_set_src_caps_str (h, "video/x-h264,alignment=nal,stream-format=byte-stream"); - /* No aggregation latency mode */ - + /* No aggregation mode */ g_object_set (e, "aggregate-mode", 0, NULL); buffer = wrap_static_buffer_with_pts (h264_idr_slice_1, @@ -883,7 +1102,8 @@ GST_END_TEST; GST_START_TEST (test_rtph264pay_aggregate_with_aud) { - GstHarness *h = gst_harness_new_parse ("rtph264pay timestamp-offset=123"); + GstHarness *h = gst_harness_new_parse ("rtph264pay timestamp-offset=123" + " aggregate-mode=zero-latency"); GstFlowReturn ret; GstBuffer *buffer; GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; @@ -994,7 +1214,8 @@ GST_END_TEST; GST_START_TEST (test_rtph264pay_aggregate_with_discont) { - GstHarness *h = gst_harness_new_parse ("rtph264pay timestamp-offset=123"); + GstHarness *h = gst_harness_new_parse ("rtph264pay timestamp-offset=123" + " aggregate-mode=zero-latency"); GstFlowReturn ret; GstBuffer *buffer; GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; @@ -1052,7 +1273,7 @@ GST_END_TEST; GST_START_TEST (test_rtph264pay_aggregate_until_vcl) { GstHarness *h = gst_harness_new_parse ("rtph264pay timestamp-offset=123" - " name=p"); + " name=p aggregate-mode=zero-latency"); GstFlowReturn ret; GstBuffer *buffer; GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; @@ -1092,6 +1313,146 @@ GST_START_TEST (test_rtph264pay_aggregate_until_vcl) GST_END_TEST; +GST_START_TEST (test_rtph264pay_avc) +{ + GstHarness *h = gst_harness_new_parse ("rtph264pay timestamp-offset=123" + " aggregate-mode=zero-latency"); + GstFlowReturn ret; + GstBuffer *buffer; + GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; + GstCaps *caps; + GstBuffer *codec_data; + + codec_data = create_codec_data (h264_sps_avc, sizeof (h264_sps_avc) - 4, + h264_pps_avc, sizeof (h264_pps_avc) - 4); + caps = gst_caps_from_string ("video/x-h264,alignment=au,stream-format=avc"); + gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data, NULL); + gst_buffer_unref (codec_data); + + GST_DEBUG ("caps are %" GST_PTR_FORMAT, caps); + + gst_harness_set_src_caps (h, caps); + + ret = gst_harness_push (h, wrap_static_buffer (h264_idr_slice_1_avc, + sizeof (h264_idr_slice_1_avc))); + fail_unless_equals_int (ret, GST_FLOW_OK); + + buffer = + wrap_static_buffer (h264_idr_slice_2_avc, sizeof (h264_idr_slice_2_avc)); + GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_MARKER); + ret = gst_harness_push (h, buffer); + fail_unless_equals_int (ret, GST_FLOW_OK); + + fail_unless_equals_int (gst_harness_buffers_in_queue (h), 2); + + buffer = gst_harness_pull (h); + fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp)); + fail_unless (gst_rtp_buffer_get_marker (&rtp)); + gst_rtp_buffer_unmap (&rtp); + gst_buffer_unref (buffer); + + buffer = gst_harness_pull (h); + fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp)); + fail_unless (gst_rtp_buffer_get_marker (&rtp)); + gst_rtp_buffer_unmap (&rtp); + gst_buffer_unref (buffer); + + gst_harness_teardown (h); +} + +GST_END_TEST; + +/* + * +------------------------------------------------+ + * | GstBuffer | + * +------------------------------------------------+ + * | GstMemory 1 | GstMemory 2 | + * +------------------------------------------------+ + * | Slice 1 Part 1 | Slice 1 Part2, Slice 2 | + * +------------------------------------------------+ + * + * "Slice 1 Part 1" is of size @memory1_len + * + */ +static void +test_rtph264pay_avc_two_slices (gsize memory1_len, guint num_slices) +{ + GstHarness *h = gst_harness_new_parse ("rtph264pay timestamp-offset=123" + " aggregate-mode=zero-latency"); + GstFlowReturn ret; + GstBuffer *slice1; + GstBuffer *slice2; + GstBuffer *buffer; + GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; + GstCaps *caps; + GstBuffer *codec_data; + guint8 *rest_of_image; + gsize rest_of_slice_1_size; + gsize rest_of_image_size; + + fail_unless (num_slices <= 2); + + codec_data = create_codec_data (h264_sps_avc, sizeof (h264_sps_avc) - 4, + h264_pps_avc, sizeof (h264_pps_avc) - 4); + caps = gst_caps_from_string ("video/x-h264,alignment=au,stream-format=avc"); + gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data, NULL); + gst_buffer_unref (codec_data); + + GST_DEBUG ("caps are %" GST_PTR_FORMAT, caps); + + gst_harness_set_src_caps (h, caps); + + slice1 = wrap_static_buffer (h264_idr_slice_1_avc, memory1_len); + rest_of_slice_1_size = sizeof (h264_idr_slice_1_avc) - memory1_len; + + if (num_slices == 2) { + rest_of_image_size = rest_of_slice_1_size + sizeof (h264_idr_slice_2_avc); + rest_of_image = g_malloc (rest_of_image_size); + + memcpy (rest_of_image, h264_idr_slice_1_avc + memory1_len, + rest_of_slice_1_size); + memcpy (rest_of_image + rest_of_slice_1_size, h264_idr_slice_2_avc, + sizeof (h264_idr_slice_2_avc)); + + slice2 = + wrap_static_buffer_full (rest_of_image, rest_of_image_size, + rest_of_image, g_free); + buffer = gst_buffer_append (slice1, slice2); + } else + buffer = slice1; + + GST_DEBUG ("number of memories: %d", gst_buffer_n_memory (buffer)); + + ret = gst_harness_push (h, buffer); + fail_unless_equals_int (ret, GST_FLOW_OK); + + fail_unless_equals_int (gst_harness_buffers_in_queue (h), 1); + + buffer = gst_harness_pull (h); + + fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp)); + gst_rtp_buffer_unmap (&rtp); + gst_buffer_unref (buffer); + + gst_harness_teardown (h); +} + +GST_START_TEST (test_rtph264pay_avc_two_slices_per_buffer) +{ + test_rtph264pay_avc_two_slices (1, 2); + test_rtph264pay_avc_two_slices (2, 2); + test_rtph264pay_avc_two_slices (sizeof (h264_idr_slice_1_avc) - 10, 2); +} + +GST_END_TEST; + +GST_START_TEST (test_rtph264pay_avc_incomplete_nal) +{ + test_rtph264pay_avc_two_slices (sizeof (h264_idr_slice_1_avc) - 10, 1); +} + +GST_END_TEST; + static Suite * rtph264_suite (void) { @@ -1104,6 +1465,8 @@ rtph264_suite (void) tcase_add_test (tc_chain, test_rtph264depay_eos); tcase_add_test (tc_chain, test_rtph264depay_marker_to_flag); tcase_add_test (tc_chain, test_rtph264depay_stap_a_marker); + tcase_add_test (tc_chain, test_rtph264depay_fu_a); + tcase_add_test (tc_chain, test_rtph264depay_fu_a_missing_start); tc_chain = tcase_create ("rtph264pay"); suite_add_tcase (s, tc_chain); @@ -1118,6 +1481,10 @@ rtph264_suite (void) tcase_add_test (tc_chain, test_rtph264pay_aggregate_with_discont); tcase_add_test (tc_chain, test_rtph264pay_aggregate_until_vcl); + tcase_add_test (tc_chain, test_rtph264pay_avc); + tcase_add_test (tc_chain, test_rtph264pay_avc_two_slices_per_buffer); + tcase_add_test (tc_chain, test_rtph264pay_avc_incomplete_nal); + return s; } diff --git a/tests/check/elements/rtph265.c b/tests/check/elements/rtph265.c index 2c2ff3c4f1..23818084fd 100644 --- a/tests/check/elements/rtph265.c +++ b/tests/check/elements/rtph265.c @@ -463,7 +463,8 @@ static guint8 h265_idr_slice_2[] = { GST_START_TEST (test_rtph265pay_two_slices_timestamp) { - GstHarness *h = gst_harness_new_parse ("rtph265pay timestamp-offset=123"); + GstHarness *h = gst_harness_new_parse ("rtph265pay timestamp-offset=123" + " aggregate-mode=zero-latency"); GstFlowReturn ret; GstBuffer *buffer; GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; @@ -524,7 +525,8 @@ GST_END_TEST; GST_START_TEST (test_rtph265pay_marker_for_flag) { - GstHarness *h = gst_harness_new_parse ("rtph265pay timestamp-offset=123"); + GstHarness *h = gst_harness_new_parse ("rtph265pay timestamp-offset=123" + " aggregate-mode=zero-latency"); GstFlowReturn ret; GstBuffer *buffer; GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; @@ -602,7 +604,8 @@ GST_END_TEST; GST_START_TEST (test_rtph265pay_marker_for_fragmented_au) { GstHarness *h = - gst_harness_new_parse ("rtph265pay timestamp-offset=123 mtu=40"); + gst_harness_new_parse ("rtph265pay timestamp-offset=123 mtu=40" + " aggregate-mode=zero-latency"); GstFlowReturn ret; GstBuffer *slice1, *slice2, *buffer; GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; @@ -770,7 +773,8 @@ static guint8 h265_aud[] = { GST_START_TEST (test_rtph265pay_aggregate_with_aud) { - GstHarness *h = gst_harness_new_parse ("rtph265pay timestamp-offset=123"); + GstHarness *h = gst_harness_new_parse ("rtph265pay timestamp-offset=123" + " aggregate-mode=zero-latency"); GstFlowReturn ret; GstBuffer *buffer; GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; @@ -877,7 +881,8 @@ GST_END_TEST; GST_START_TEST (test_rtph265pay_aggregate_with_discont) { - GstHarness *h = gst_harness_new_parse ("rtph265pay timestamp-offset=123"); + GstHarness *h = gst_harness_new_parse ("rtph265pay timestamp-offset=123" + " aggregate-mode=zero-latency"); GstFlowReturn ret; GstBuffer *buffer; GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; @@ -939,7 +944,7 @@ static guint8 h265_eos[] = { GST_START_TEST (test_rtph265pay_aggregate_until_vcl) { GstHarness *h = gst_harness_new_parse ("rtph265pay timestamp-offset=123" - " name=p"); + " name=p aggregate-mode=zero-latency"); GstFlowReturn ret; GstBuffer *buffer; GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; @@ -1004,7 +1009,7 @@ GST_END_TEST; GST_START_TEST (test_rtph265pay_aggregate_verify_nalu_hdr) { GstHarness *h = gst_harness_new_parse ("rtph265pay timestamp-offset=123" - " name=p"); + " name=p aggregate-mode=zero-latency"); GstFlowReturn ret; GstBuffer *buffer; GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; diff --git a/tests/check/elements/rtpjitterbuffer.c b/tests/check/elements/rtpjitterbuffer.c index 92d96d149e..99cc57ca0c 100644 --- a/tests/check/elements/rtpjitterbuffer.c +++ b/tests/check/elements/rtpjitterbuffer.c @@ -28,12 +28,8 @@ #include #include #include - #include -#include "gst/rtpmanager/gstrtpjitterbuffer.h" -#include "gst/rtpmanager/rtptimerqueue.h" - /* For ease of programming we use globals to keep refs for our floating * src and sink pads we create; otherwise we always have to do get_pad, * get_peer, and then remove references in every test function */ @@ -532,6 +528,17 @@ push_test_buffer (GstHarness * h, guint seq_num) generate_test_buffer (seq_num))); } +static void +push_test_buffer_now (GstHarness * h, guint seqnum, guint32 rtptime, + gboolean rtx) +{ + GstClockTime now = gst_clock_get_time (GST_ELEMENT_CLOCK (h->element)); + GstBuffer *buf = generate_test_buffer_full (now, seqnum, rtptime); + if (rtx) + GST_BUFFER_FLAG_SET (buf, GST_RTP_BUFFER_FLAG_RETRANSMISSION); + fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, buf)); +} + static gint get_rtp_seq_num (GstBuffer * buf) { @@ -1285,7 +1292,7 @@ GST_START_TEST (test_rtx_expected_next) * that will have a timeout of the expected arrival-time for that seqnum, * and a delay equal to 2*jitter==0 and 0.5*packet_spacing==10ms */ timeout = next_seqnum * TEST_BUF_DURATION; - rtx_delay_ms = 0.5 * TEST_BUF_MS; + rtx_delay_ms = TEST_BUF_MS / 2; /* We crank the clock to time-out the next scheduled timer */ gst_harness_crank_single_clock_wait (h); @@ -1394,8 +1401,8 @@ GST_START_TEST (test_rtx_two_missing) gint latency_ms = 200; guint next_seqnum; GstClockTime last_rtx_request, now; - gint rtx_delay_ms_0 = 0.5 * TEST_BUF_MS; - gint rtx_delay_ms_1 = 1.0 * TEST_BUF_MS; + gint rtx_delay_ms_0 = TEST_BUF_MS / 2; + gint rtx_delay_ms_1 = TEST_BUF_MS; g_object_set (h->element, "do-retransmission", TRUE, NULL); next_seqnum = construct_deterministic_initial_state (h, latency_ms); @@ -1485,7 +1492,7 @@ GST_START_TEST (test_rtx_buffer_arrives_just_in_time) gint next_seqnum; GstBuffer *buffer; GstClockTime now, last_rtx_request; - gint rtx_delay_ms = 0.5 * TEST_BUF_MS; + gint rtx_delay_ms = TEST_BUF_MS / 2; g_object_set (h->element, "do-retransmission", TRUE, "rtx-max-retries", 1, NULL); @@ -1531,7 +1538,7 @@ GST_START_TEST (test_rtx_buffer_arrives_too_late) gint latency_ms = 5 * TEST_BUF_MS; gint next_seqnum; GstClockTime now, last_rtx_request; - gint rtx_delay_ms = 0.5 * TEST_BUF_MS; + gint rtx_delay_ms = TEST_BUF_MS / 2; g_object_set (h->element, "do-retransmission", TRUE, "do-lost", TRUE, "rtx-max-retries", 1, NULL); @@ -1581,7 +1588,7 @@ GST_START_TEST (test_rtx_original_buffer_does_not_update_rtx_stats) gint next_seqnum; GstBuffer *buffer; GstClockTime now, last_rtx_request; - gint rtx_delay_ms = 0.5 * TEST_BUF_MS; + gint rtx_delay_ms = TEST_BUF_MS / 2; g_object_set (h->element, "do-retransmission", TRUE, "rtx-max-retries", 1, NULL); @@ -1659,8 +1666,8 @@ GST_START_TEST (test_rtx_duplicate_packet_updates_rtx_stats) gint latency_ms = 100; gint next_seqnum; GstClockTime now, rtx_request_6, rtx_request_7; - gint rtx_delay_ms_0 = 0.5 * TEST_BUF_MS; - gint rtx_delay_ms_1 = 1.0 * TEST_BUF_MS; + gint rtx_delay_ms_0 = TEST_BUF_MS / 2; + gint rtx_delay_ms_1 = TEST_BUF_MS; gint i; g_object_set (h->element, "do-retransmission", TRUE, NULL); @@ -1764,7 +1771,7 @@ GST_START_TEST (test_rtx_buffer_arrives_after_lost_updates_rtx_stats) gint latency_ms = 100; gint next_seqnum; GstClockTime now, last_rtx_request; - gint rtx_delay_ms = 0.5 * TEST_BUF_MS; + gint rtx_delay_ms = TEST_BUF_MS / 2; g_object_set (h->element, "do-retransmission", TRUE, "do-lost", TRUE, "rtx-max-retries", 1, NULL); @@ -1815,7 +1822,7 @@ GST_START_TEST (test_rtx_rtt_larger_than_retry_timeout) gint latency_ms = 100; gint next_seqnum; gint rtx_retry_timeout_ms = 20; - gint rtx_delay_ms = 0.5 * TEST_BUF_MS; + gint rtx_delay_ms = TEST_BUF_MS / 2; gint rtt = rtx_retry_timeout_ms * GST_MSECOND + 1; GstClockTime now, first_request, second_request; @@ -2056,6 +2063,7 @@ GST_START_TEST (test_rtx_with_backwards_rtptime) * Note: the jitterbuffer no longer update early timers, as a result * we need to advance the clock to the expected point */ + gst_harness_wait_for_clock_id_waits (h, 1, 1); gst_harness_set_time (h, 6 * TEST_BUF_DURATION + 15 * GST_MSECOND); gst_harness_crank_single_clock_wait (h); verify_rtx_event (h, 6, 5 * TEST_BUF_DURATION + 15 * GST_MSECOND, @@ -2076,7 +2084,7 @@ GST_START_TEST (test_rtx_timer_reuse) { GstHarness *h = gst_harness_new ("rtpjitterbuffer"); gint latency_ms = 5 * TEST_BUF_MS; - gint rtx_delay_ms = 0.5 * TEST_BUF_MS; + gint rtx_delay_ms = TEST_BUF_MS / 2; guint next_seqnum; g_object_set (h->element, "do-retransmission", TRUE, @@ -2545,7 +2553,6 @@ GST_START_TEST (test_considered_lost_packet_in_large_gap_arrives) { GstHarness *h = gst_harness_new ("rtpjitterbuffer"); GstTestClock *testclock; - GstClockID id; GstBuffer *buffer; gint jb_latency_ms = 20; const TestLateArrivalInput *test_input = @@ -2570,34 +2577,25 @@ GST_START_TEST (test_considered_lost_packet_in_large_gap_arrives) gst_event_unref (gst_harness_pull_event (h)); /* hop over 3 packets, and push buffer 4 (gap of 3) */ + gst_harness_set_time (h, 4 * TEST_BUF_DURATION); fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, generate_test_buffer_full (4 * TEST_BUF_DURATION, 4 + seq_offset, 4 * TEST_RTP_TS_DURATION))); - /* the jitterbuffer should be waiting for the timeout of a "large gap timer" - * for buffer 1 and 2 */ - gst_test_clock_wait_for_next_pending_id (testclock, &id); - fail_unless_equals_uint64 (1 * TEST_BUF_DURATION + - jb_latency_ms * GST_MSECOND, gst_clock_id_get_time (id)); - gst_clock_id_unref (id); - - /* now buffer 1 sneaks in before the lost event for buffer 1 and 2 is - * processed */ - fail_unless_equals_int (GST_FLOW_OK, - gst_harness_push (h, - generate_test_buffer_full (late_buffer * TEST_BUF_DURATION, - late_buffer + seq_offset, late_buffer * TEST_RTP_TS_DURATION))); - - /* time out for lost packets 1 and 2 (one event, double duration) */ - fail_unless (gst_harness_crank_single_clock_wait (h)); + /* we get a "bundled" lost-event for the 2 packets now already too late */ verify_lost_event (h, 1 + seq_offset, 1 * TEST_BUF_DURATION, 2 * TEST_BUF_DURATION); - /* time out for lost packets 3 */ - fail_unless (gst_harness_crank_single_clock_wait (h)); + /* and another one for buffer 3 */ verify_lost_event (h, 3 + seq_offset, 3 * TEST_BUF_DURATION, 1 * TEST_BUF_DURATION); + /* A late buffer arrives */ + fail_unless_equals_int (GST_FLOW_OK, + gst_harness_push (h, + generate_test_buffer_full (late_buffer * TEST_BUF_DURATION, + late_buffer + seq_offset, late_buffer * TEST_RTP_TS_DURATION))); + /* buffer 4 is pushed as normal */ buffer = gst_harness_pull (h); fail_unless_equals_int ((4 + seq_offset) & 0xffff, get_rtp_seq_num (buffer)); @@ -2765,295 +2763,6 @@ GST_START_TEST (test_dont_drop_packet_based_on_skew) GST_END_TEST; -GST_START_TEST (test_timer_queue_set_timer) -{ - RtpTimerQueue *queue = rtp_timer_queue_new (); - RtpTimer *timer10, *timer0; - - rtp_timer_queue_set_timer (queue, RTP_TIMER_EXPECTED, 10, 0, - 1 * GST_SECOND, 2 * GST_SECOND, 5 * GST_SECOND, 0); - timer10 = rtp_timer_queue_find (queue, 10); - fail_unless (timer10); - fail_unless_equals_int (10, timer10->seqnum); - fail_unless_equals_int (0, timer10->num); - fail_unless_equals_int (RTP_TIMER_EXPECTED, timer10->type); - /* timer10->timeout = timerout + delay */ - fail_unless_equals_uint64 (3 * GST_SECOND, timer10->timeout); - fail_unless_equals_uint64 (5 * GST_SECOND, timer10->duration); - fail_unless_equals_uint64 (1 * GST_SECOND, timer10->rtx_base); - fail_unless_equals_uint64 (2 * GST_SECOND, timer10->rtx_delay); - fail_unless_equals_uint64 (0, timer10->rtx_retry); - fail_unless_equals_uint64 (GST_CLOCK_TIME_NONE, timer10->rtx_last); - fail_unless_equals_int (0, timer10->num_rtx_retry); - fail_unless_equals_int (0, timer10->num_rtx_received); - - rtp_timer_queue_set_timer (queue, RTP_TIMER_LOST, 0, 10, - 0 * GST_SECOND, 2 * GST_SECOND, 0, 0); - timer0 = rtp_timer_queue_find (queue, 0); - fail_unless (timer0); - fail_unless_equals_int (0, timer0->seqnum); - fail_unless_equals_int (10, timer0->num); - fail_unless_equals_int (RTP_TIMER_LOST, timer0->type); - fail_unless_equals_uint64 (2 * GST_SECOND, timer0->timeout); - fail_unless_equals_uint64 (0, timer0->duration); - fail_unless_equals_uint64 (0, timer0->rtx_base); - fail_unless_equals_uint64 (0, timer0->rtx_delay); - fail_unless_equals_uint64 (0, timer0->rtx_retry); - fail_unless_equals_uint64 (GST_CLOCK_TIME_NONE, timer0->rtx_last); - fail_unless_equals_int (0, timer0->num_rtx_retry); - fail_unless_equals_int (0, timer0->num_rtx_received); - - /* also check order while at it */ - fail_unless (timer10->list.next == NULL); - fail_unless (timer10->list.prev == (GList *) timer0); - fail_unless (timer0->list.next == (GList *) timer10); - fail_unless (timer0->list.prev == NULL); - - g_object_unref (queue); -} - -GST_END_TEST; - -GST_START_TEST (test_timer_queue_insert_head) -{ - RtpTimerQueue *queue = rtp_timer_queue_new (); - RtpTimer *timer, *next, *prev; - - rtp_timer_queue_set_deadline (queue, 1, -1, 0); - rtp_timer_queue_set_deadline (queue, 3, -1, 0); - rtp_timer_queue_set_deadline (queue, 2, -1, 0); - rtp_timer_queue_set_deadline (queue, 0, -1, 0); - - timer = rtp_timer_queue_find (queue, 0); - fail_if (timer == NULL); - fail_unless_equals_int (0, timer->seqnum); - next = (RtpTimer *) timer->list.next; - prev = (RtpTimer *) timer->list.prev; - fail_unless (prev == NULL); - fail_if (next == NULL); - fail_unless_equals_int (1, next->seqnum); - - timer = rtp_timer_queue_find (queue, 3); - fail_if (timer == NULL); - fail_unless_equals_int (3, timer->seqnum); - next = (RtpTimer *) timer->list.next; - prev = (RtpTimer *) timer->list.prev; - fail_if (prev == NULL); - fail_unless_equals_int (2, prev->seqnum); - fail_unless (next == NULL); - - timer = rtp_timer_queue_find (queue, 2); - fail_if (timer == NULL); - fail_unless_equals_int (2, timer->seqnum); - next = (RtpTimer *) timer->list.next; - prev = (RtpTimer *) timer->list.prev; - fail_if (prev == NULL); - fail_if (next == NULL); - fail_unless_equals_int (1, prev->seqnum); - fail_unless_equals_int (3, next->seqnum); - - timer = rtp_timer_queue_find (queue, 1); - fail_if (timer == NULL); - fail_unless_equals_int (1, timer->seqnum); - next = (RtpTimer *) timer->list.next; - prev = (RtpTimer *) timer->list.prev; - fail_if (prev == NULL); - fail_if (next == NULL); - fail_unless_equals_int (0, prev->seqnum); - fail_unless_equals_int (2, next->seqnum); - - g_object_unref (queue); -} - -GST_END_TEST; - -GST_START_TEST (test_timer_queue_reschedule) -{ - RtpTimerQueue *queue = rtp_timer_queue_new (); - RtpTimer *timer, *next, *prev; - - rtp_timer_queue_set_deadline (queue, 3, 1 * GST_SECOND, 0); - rtp_timer_queue_set_deadline (queue, 1, 2 * GST_SECOND, 0); - rtp_timer_queue_set_deadline (queue, 2, 3 * GST_SECOND, 0); - rtp_timer_queue_set_deadline (queue, 0, 4 * GST_SECOND, 0); - - timer = rtp_timer_queue_find (queue, 1); - fail_if (timer == NULL); - - /* move to head, making sure seqnum order is respected */ - rtp_timer_queue_set_deadline (queue, 1, 1 * GST_SECOND, 0); - next = (RtpTimer *) timer->list.next; - prev = (RtpTimer *) timer->list.prev; - fail_unless (prev == NULL); - fail_if (next == NULL); - fail_unless_equals_int (3, next->seqnum); - - /* move head back */ - rtp_timer_queue_set_deadline (queue, 1, 2 * GST_SECOND, 0); - next = (RtpTimer *) timer->list.next; - prev = (RtpTimer *) timer->list.prev; - fail_if (prev == NULL); - fail_if (next == NULL); - fail_unless_equals_int (3, prev->seqnum); - fail_unless_equals_int (2, next->seqnum); - - /* move to tail */ - timer = rtp_timer_queue_find (queue, 2); - fail_if (timer == NULL); - rtp_timer_queue_set_deadline (queue, 2, 4 * GST_SECOND, 0); - next = (RtpTimer *) timer->list.next; - prev = (RtpTimer *) timer->list.prev; - fail_if (prev == NULL); - fail_unless (next == NULL); - fail_unless_equals_int (0, prev->seqnum); - - /* move tail back */ - rtp_timer_queue_set_deadline (queue, 2, 3 * GST_SECOND, 0); - next = (RtpTimer *) timer->list.next; - prev = (RtpTimer *) timer->list.prev; - fail_if (prev == NULL); - fail_if (next == NULL); - fail_unless_equals_int (1, prev->seqnum); - fail_unless_equals_int (0, next->seqnum); - - /* not moving toward head */ - rtp_timer_queue_set_deadline (queue, 2, 2 * GST_SECOND, 0); - next = (RtpTimer *) timer->list.next; - prev = (RtpTimer *) timer->list.prev; - fail_if (prev == NULL); - fail_if (next == NULL); - fail_unless_equals_int (1, prev->seqnum); - fail_unless_equals_int (0, next->seqnum); - - /* not moving toward tail */ - rtp_timer_queue_set_deadline (queue, 2, 3 * GST_SECOND, 0); - next = (RtpTimer *) timer->list.next; - prev = (RtpTimer *) timer->list.prev; - fail_if (prev == NULL); - fail_if (next == NULL); - fail_unless_equals_int (1, prev->seqnum); - fail_unless_equals_int (0, next->seqnum); - - /* inner move toward head */ - rtp_timer_queue_set_deadline (queue, 2, GST_SECOND + GST_SECOND / 2, 0); - next = (RtpTimer *) timer->list.next; - prev = (RtpTimer *) timer->list.prev; - fail_if (prev == NULL); - fail_if (next == NULL); - fail_unless_equals_int (3, prev->seqnum); - fail_unless_equals_int (1, next->seqnum); - - /* inner move toward tail */ - rtp_timer_queue_set_deadline (queue, 2, 3 * GST_SECOND, 0); - next = (RtpTimer *) timer->list.next; - prev = (RtpTimer *) timer->list.prev; - fail_if (prev == NULL); - fail_if (next == NULL); - fail_unless_equals_int (1, prev->seqnum); - fail_unless_equals_int (0, next->seqnum); - - g_object_unref (queue); -} - -GST_END_TEST; - -GST_START_TEST (test_timer_queue_pop_until) -{ - RtpTimerQueue *queue = rtp_timer_queue_new (); - RtpTimer *timer; - - rtp_timer_queue_set_deadline (queue, 2, 2 * GST_SECOND, 0); - rtp_timer_queue_set_deadline (queue, 1, 1 * GST_SECOND, 0); - rtp_timer_queue_set_deadline (queue, 0, -1, 0); - - timer = rtp_timer_queue_pop_until (queue, 1 * GST_SECOND); - fail_if (timer == NULL); - fail_unless_equals_int (0, timer->seqnum); - rtp_timer_free (timer); - - timer = rtp_timer_queue_pop_until (queue, 1 * GST_SECOND); - fail_if (timer == NULL); - fail_unless_equals_int (1, timer->seqnum); - rtp_timer_free (timer); - - timer = rtp_timer_queue_pop_until (queue, 1 * GST_SECOND); - fail_unless (timer == NULL); - - g_object_unref (queue); -} - -GST_END_TEST; - -GST_START_TEST (test_timer_queue_update_timer_seqnum) -{ - RtpTimerQueue *queue = rtp_timer_queue_new (); - RtpTimer *timer; - - rtp_timer_queue_set_deadline (queue, 2, 2 * GST_SECOND, 0); - - timer = rtp_timer_queue_find (queue, 2); - fail_if (timer == NULL); - - rtp_timer_queue_update_timer (queue, timer, 3, 3 * GST_SECOND, 0, 0, FALSE); - - timer = rtp_timer_queue_find (queue, 2); - fail_unless (timer == NULL); - timer = rtp_timer_queue_find (queue, 3); - fail_if (timer == NULL); - - fail_unless_equals_int (1, rtp_timer_queue_length (queue)); - - g_object_unref (queue); -} - -GST_END_TEST; - -GST_START_TEST (test_timer_queue_dup_timer) -{ - RtpTimerQueue *queue = rtp_timer_queue_new (); - RtpTimer *timer; - - rtp_timer_queue_set_deadline (queue, 2, 2 * GST_SECOND, 0); - - timer = rtp_timer_queue_find (queue, 2); - fail_if (timer == NULL); - - timer = rtp_timer_dup (timer); - timer->seqnum = 3; - rtp_timer_queue_insert (queue, timer); - - fail_unless_equals_int (2, rtp_timer_queue_length (queue)); - - g_object_unref (queue); -} - -GST_END_TEST; - -GST_START_TEST (test_timer_queue_timer_offset) -{ - RtpTimerQueue *queue = rtp_timer_queue_new (); - RtpTimer *timer; - - rtp_timer_queue_set_timer (queue, RTP_TIMER_EXPECTED, 2, 0, 2 * GST_SECOND, - GST_MSECOND, 0, GST_USECOND); - - timer = rtp_timer_queue_find (queue, 2); - fail_if (timer == NULL); - fail_unless_equals_uint64 (2 * GST_SECOND + GST_MSECOND + GST_USECOND, - timer->timeout); - fail_unless_equals_int64 (GST_USECOND, timer->offset); - - rtp_timer_queue_update_timer (queue, timer, 2, 3 * GST_SECOND, - 2 * GST_MSECOND, 2 * GST_USECOND, FALSE); - fail_unless_equals_uint64 (3 * GST_SECOND + 2 * GST_MSECOND + - 2 * GST_USECOND, timer->timeout); - fail_unless_equals_int64 (2 * GST_USECOND, timer->offset); - - g_object_unref (queue); -} - -GST_END_TEST; - static gboolean check_drop_message (GstMessage * drop_msg, const char *reason_check, guint seqnum_check, guint num_msg) @@ -3064,19 +2773,15 @@ check_drop_message (GstMessage * drop_msg, const char *reason_check, GstClockTime timestamp; guint seqnum; guint num_too_late; - guint num_already_lost; guint num_drop_on_latency; guint num_too_late_check = 0; - guint num_already_lost_check = 0; guint num_drop_on_latency_check = 0; /* Check that fields exist */ fail_unless (gst_structure_get_uint (s, "seqnum", &seqnum)); fail_unless (gst_structure_get_uint64 (s, "timestamp", ×tamp)); fail_unless (gst_structure_get_uint (s, "num-too-late", &num_too_late)); - fail_unless (gst_structure_get_uint (s, "num-already-lost", - &num_already_lost)); fail_unless (gst_structure_get_uint (s, "num-drop-on-latency", &num_drop_on_latency)); fail_unless (reason_str = gst_structure_get_string (s, "reason")); @@ -3084,8 +2789,6 @@ check_drop_message (GstMessage * drop_msg, const char *reason_check, /* Assing what to compare message fields to based on message reason */ if (g_strcmp0 (reason_check, "too-late") == 0) { num_too_late_check += num_msg; - } else if (g_strcmp0 (reason_check, "already-lost") == 0) { - num_already_lost_check += num_msg; } else if (g_strcmp0 (reason_check, "drop-on-latency") == 0) { num_drop_on_latency_check += num_msg; } else { @@ -3096,7 +2799,6 @@ check_drop_message (GstMessage * drop_msg, const char *reason_check, fail_unless (seqnum == seqnum_check); fail_unless (g_strcmp0 (reason_str, reason_check) == 0); fail_unless (num_too_late == num_too_late_check); - fail_unless (num_already_lost == num_already_lost_check); fail_unless (num_drop_on_latency == num_drop_on_latency_check); return TRUE; @@ -3150,71 +2852,6 @@ GST_START_TEST (test_drop_messages_too_late) GST_END_TEST; -GST_START_TEST (test_drop_messages_already_lost) -{ - GstHarness *h = gst_harness_new ("rtpjitterbuffer"); - GstTestClock *testclock; - GstClockID id; - gint latency_ms = 20; - guint seqnum_late; - guint seqnum_final; - GstBus *bus; - GstMessage *drop_msg; - gboolean have_message = FALSE; - - testclock = gst_harness_get_testclock (h); - g_object_set (h->element, "post-drop-messages", TRUE, NULL); - - /* Create a bus to get the drop message on */ - bus = gst_bus_new (); - gst_element_set_bus (h->element, bus); - - /* Get seqnum from initial state */ - seqnum_late = construct_deterministic_initial_state (h, latency_ms); - - /* Hop over 3 buffers and push buffer (gap of 3) */ - seqnum_final = seqnum_late + 4; - fail_unless_equals_int (GST_FLOW_OK, - gst_harness_push (h, - generate_test_buffer_full (seqnum_final * TEST_BUF_DURATION, - seqnum_final, seqnum_final * TEST_RTP_TS_DURATION))); - - /* The jitterbuffer should be waiting for the timeout of a "large gap timer" - * for buffer seqnum_late and seqnum_late+1 */ - gst_test_clock_wait_for_next_pending_id (testclock, &id); - fail_unless_equals_uint64 (seqnum_late * TEST_BUF_DURATION + - latency_ms * GST_MSECOND, gst_clock_id_get_time (id)); - - /* Now seqnum_late sneaks in before the lost event for buffer seqnum_late and seqnum_late+1 is - * processed. It will be dropped due to already having been considered lost */ - fail_unless_equals_int (GST_FLOW_OK, - gst_harness_push (h, - generate_test_buffer_full (seqnum_late * TEST_BUF_DURATION, - seqnum_late, seqnum_late * TEST_RTP_TS_DURATION))); - - /* Pop the resulting drop message and check its correctness */ - while (!have_message && - (drop_msg = gst_bus_pop_filtered (bus, GST_MESSAGE_ELEMENT)) != NULL) { - if (gst_message_has_name (drop_msg, "drop-msg")) { - fail_unless (check_drop_message (drop_msg, "already-lost", seqnum_late, - 1)); - have_message = TRUE; - } - gst_message_unref (drop_msg); - } - fail_unless (have_message); - - /* Cleanup */ - gst_clock_id_unref (id); - gst_element_set_bus (h->element, NULL); - gst_buffer_unref (gst_harness_take_all_data_as_buffer (h)); - gst_object_unref (bus); - gst_object_unref (testclock); - gst_harness_teardown (h); -} - -GST_END_TEST; - GST_START_TEST (test_drop_messages_drop_on_latency) { GstHarness *h = gst_harness_new ("rtpjitterbuffer"); @@ -3340,23 +2977,186 @@ GST_START_TEST (test_drop_messages_interval) GST_END_TEST; +typedef struct +{ + gint seqnum_d; + gint rtptime_d; + gboolean rtx; + gint sleep_us; +} BufferArrayCtx; + +static void +buffer_array_push (GstHarness * h, GArray * array, + guint16 seqnum_base, guint32 rtptime_base) +{ + guint16 seqnum = seqnum_base; + guint32 rtptime = rtptime_base; + guint i; + + for (i = 0; i < array->len; i++) { + BufferArrayCtx *ctx = &g_array_index (array, BufferArrayCtx, i); + seqnum += ctx->seqnum_d; + rtptime += ctx->rtptime_d; + push_test_buffer_now (h, seqnum, rtptime, ctx->rtx); + g_usleep (ctx->sleep_us); + } +} + +static gint +buffer_array_get_max_seqnum_delta (GArray * array) +{ + gint delta = 0; + gint max_delta = 0; + guint i; + + for (i = 0; i < array->len; i++) { + BufferArrayCtx *ctx = &g_array_index (array, BufferArrayCtx, i); + delta += ctx->seqnum_d; + if (delta > max_delta) + max_delta = delta; + } + return max_delta; +} + +static void +buffer_array_append_sequential (GArray * array, guint num_bufs) +{ + guint i; + for (i = 0; i < num_bufs; i++) { + BufferArrayCtx ctx; + ctx.seqnum_d = 1; + ctx.rtptime_d = TEST_RTP_TS_DURATION; /* 20ms for 8KHz */ + ctx.rtx = FALSE; + ctx.sleep_us = G_USEC_PER_SEC / 1000 * 20; /* 20ms */ + g_array_append_val (array, ctx); + } +} + +static void +buffer_array_append_ctx (GArray * array, BufferArrayCtx * bufs, guint num_bufs) +{ + guint i; + for (i = 0; i < num_bufs; i++) { + g_array_append_val (array, bufs[i]); + } +} + +static gboolean +check_for_stall (GstHarness * h, BufferArrayCtx * bufs, guint num_bufs) +{ + guint latency_ms; + guint initial_bufs; + guint16 base_seqnum = 10000; + guint32 base_rtptime = base_seqnum * TEST_RTP_TS_DURATION; + guint16 max_seqnum; + guint in_queue; + GArray *array; + + gst_harness_use_systemclock (h); + gst_harness_set_src_caps (h, generate_caps ()); + + g_object_get (h->element, "latency", &latency_ms, NULL); + initial_bufs = latency_ms / TEST_BUF_MS; + + array = g_array_new (FALSE, FALSE, sizeof (BufferArrayCtx)); + buffer_array_append_sequential (array, initial_bufs); + buffer_array_append_ctx (array, bufs, num_bufs); + max_seqnum = base_seqnum + buffer_array_get_max_seqnum_delta (array); + buffer_array_push (h, array, base_seqnum, base_rtptime); + g_array_set_size (array, 0); + + /* sleep a bit to settle things down, then find out + how many buffers have been pushed out */ + g_usleep (G_USEC_PER_SEC); + in_queue = gst_harness_buffers_in_queue (h); + + /* push another 50 buffers normally */ + buffer_array_append_sequential (array, 50); + base_seqnum = max_seqnum + 1; + base_rtptime = base_seqnum * TEST_RTP_TS_DURATION; + buffer_array_push (h, array, base_seqnum, base_rtptime); + g_array_unref (array); + + /* we expect at least some of those buffers to come through */ + return gst_harness_buffers_in_queue (h) > in_queue; +} + +GST_START_TEST (test_reset_timers_does_not_stall) +{ + GstHarness *h = gst_harness_new ("rtpjitterbuffer"); + BufferArrayCtx bufs[] = { + /* *INDENT-OFF* */ + { 1, 0, FALSE, 0}, + { 2, 0, FALSE, 0}, + { 3, 0, FALSE, 0}, + { 4, 0, FALSE, 0}, + { 5, 0, FALSE, 0}, + { 6, 0, FALSE, 0}, + { 7, 0, FALSE, 0}, + { 8, 0, FALSE, 0}, + { 9, 0, FALSE, 0}, + {10, 0, FALSE, 0}, + /* *INDENT-ON* */ + }; + + g_object_set (h->element, "latency", 100, + "do-retransmission", TRUE, "do-lost", TRUE, NULL); + g_object_set (h->element, "max-dropout-time", 10, NULL); + fail_unless (check_for_stall (h, bufs, G_N_ELEMENTS (bufs))); + gst_harness_teardown (h); +} + +GST_END_TEST; + +GST_START_TEST (test_multiple_lost_do_not_stall) +{ + GstHarness *h = gst_harness_new ("rtpjitterbuffer"); + BufferArrayCtx bufs[] = { + /* *INDENT-OFF* */ + { 39, 4960, FALSE, 58}, + {-28, -5280, FALSE, 1000}, + /* *INDENT-ON* */ + }; + + g_object_set (h->element, "latency", 200, + "do-retransmission", TRUE, "do-lost", TRUE, NULL); + fail_unless (check_for_stall (h, bufs, G_N_ELEMENTS (bufs))); + gst_harness_teardown (h); +} + +GST_END_TEST; + +GST_START_TEST (test_reset_using_rtx_packets_does_not_stall) +{ + GstHarness *h = gst_harness_new ("rtpjitterbuffer"); + BufferArrayCtx bufs[] = { + /* *INDENT-OFF* */ + { 1, 1 * TEST_RTP_TS_DURATION, FALSE, 2000000}, + { 62, 62 * TEST_RTP_TS_DURATION, FALSE, 0}, + { -13, -13 * TEST_RTP_TS_DURATION, TRUE, 10000}, + { 1, 1 * TEST_RTP_TS_DURATION, TRUE, 0}, + { 1, 1 * TEST_RTP_TS_DURATION, TRUE, 0}, + { 1, 1 * TEST_RTP_TS_DURATION, TRUE, 0}, + { 1, 1 * TEST_RTP_TS_DURATION, TRUE, 0}, + { 1, 1 * TEST_RTP_TS_DURATION, TRUE, 0}, + /* *INDENT-ON* */ + }; + + g_object_set (h->element, "latency", 400, + "do-retransmission", TRUE, "do-lost", TRUE, "max-misorder-time", 1, NULL); + fail_unless (check_for_stall (h, bufs, G_N_ELEMENTS (bufs))); + gst_harness_teardown (h); +} + +GST_END_TEST; + static Suite * rtpjitterbuffer_suite (void) { Suite *s = suite_create ("rtpjitterbuffer"); TCase *tc_chain = tcase_create ("general"); - gst_element_register (NULL, "rtpjitterbuffer", GST_RANK_NONE, - GST_TYPE_RTP_JITTER_BUFFER); - suite_add_tcase (s, tc_chain); - tcase_add_test (tc_chain, test_timer_queue_set_timer); - tcase_add_test (tc_chain, test_timer_queue_insert_head); - tcase_add_test (tc_chain, test_timer_queue_reschedule); - tcase_add_test (tc_chain, test_timer_queue_pop_until); - tcase_add_test (tc_chain, test_timer_queue_update_timer_seqnum); - tcase_add_test (tc_chain, test_timer_queue_dup_timer); - tcase_add_test (tc_chain, test_timer_queue_timer_offset); tcase_add_test (tc_chain, test_push_forward_seq); tcase_add_test (tc_chain, test_push_backward_seq); @@ -3414,10 +3214,14 @@ rtpjitterbuffer_suite (void) tcase_add_test (tc_chain, test_performance); tcase_add_test (tc_chain, test_drop_messages_too_late); - tcase_add_test (tc_chain, test_drop_messages_already_lost); tcase_add_test (tc_chain, test_drop_messages_drop_on_latency); tcase_add_test (tc_chain, test_drop_messages_interval); + tcase_add_test (tc_chain, test_reset_timers_does_not_stall); + tcase_add_test (tc_chain, test_multiple_lost_do_not_stall); + tcase_add_test (tc_chain, test_reset_using_rtx_packets_does_not_stall); + + return s; } diff --git a/tests/check/elements/rtpjpeg.c b/tests/check/elements/rtpjpeg.c new file mode 100644 index 0000000000..a12f7ab1c9 --- /dev/null +++ b/tests/check/elements/rtpjpeg.c @@ -0,0 +1,353 @@ +/* GStreamer RTP jpeg unit test + * + * Copyright (C) 2020 Kristofer Bjorkstrom + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include + + +/* one complete blank jpeg 1x1 */ +static const guint8 rtp_jpeg_frame_data[] = + { /* SOI */ 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, + 0x00, 0x01, 0x01, 0x01, 0x00, 0x60, + 0x00, 0x60, 0x00, 0x00, /* DQT */ 0xff, 0xdb, 0x00, 0x43, 0x00, 0x08, 0x06, + 0x06, 0x07, 0x06, 0x05, 0x08, + 0x07, 0x07, 0x07, 0x09, 0x09, 0x08, 0x0a, 0x0c, 0x14, 0x0d, 0x0c, 0x0b, 0x0b, + 0x0c, 0x19, 0x12, + 0x13, 0x0f, 0x14, 0x1d, 0x1a, 0x1f, 0x1e, 0x1d, 0x1a, 0x1c, 0x1c, 0x20, 0x24, + 0x2e, 0x27, 0x20, + 0x22, 0x2c, 0x23, 0x1c, 0x1c, 0x28, 0x37, 0x29, 0x2c, 0x30, 0x31, 0x34, 0x34, + 0x34, 0x1f, 0x27, + 0x39, 0x3d, 0x38, 0x32, 0x3c, 0x2e, 0x33, 0x34, 0x32, 0xff, 0xdb, 0x00, 0x43, + 0x01, 0x09, 0x09, + 0x09, 0x0c, 0x0b, 0x0c, 0x18, 0x0d, 0x0d, 0x18, 0x32, 0x21, 0x1c, 0x21, 0x32, + 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, /* SOF */ 0xff, 0xc0, + 0x00, 0x11, 0x08, 0x00, 0x01, 0x00, 0x01, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, + 0x01, 0x03, 0x11, + 0x01, 0xff, 0xc4, 0x00, 0x1f, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0xff, 0xc4, 0x00, 0xb5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, + 0x04, 0x03, 0x05, + 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, + 0x05, 0x12, 0x21, + 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, + 0xa1, 0x08, 0x23, + 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, + 0x0a, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, + 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, + 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, + 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, + 0xd3, 0xd4, 0xd5, + 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, + 0xe9, 0xea, 0xf1, + 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xc4, 0x00, 0x1f, + 0x01, 0x00, 0x03, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0xff, 0xc4, 0x00, + 0xb5, 0x11, 0x00, + 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, + 0x02, 0x77, 0x00, + 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, + 0x61, 0x71, 0x13, + 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, + 0x52, 0xf0, 0x15, + 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, + 0x1a, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, + 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, + 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, + 0x86, 0x87, 0x88, + 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, + 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, + 0xc2, 0xc3, 0xc4, + 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, + 0xd9, 0xda, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, + 0xf7, 0xf8, 0xf9, + 0xfa, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, + 0x3f, 0x00, 0xf7, + 0xfa, 0x28, 0xa2, 0x80, 0x3f, 0xff, 0xd9 +}; + +/* first slice of one complete blank jpeg 1x1 */ +static const guint8 rtp_jpeg_frame_data_s1[] = { +/* SOI */ 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x60, + 0x00, 0x60, 0x00 +}; + +/* second slice of one complete blank jpeg 1x1 */ +static const guint8 rtp_jpeg_frame_data_s2[] = { + 0x00, /* DQT */ 0xff, 0xdb, 0x00, 0x43, 0x00, 0x08, 0x06, 0x06, 0x07, 0x06, + 0x05, 0x08, + 0x07, 0x07, 0x07, 0x09, 0x09, 0x08, 0x0a, 0x0c, 0x14, 0x0d, 0x0c, 0x0b, 0x0b, + 0x0c, 0x19, 0x12, + 0x13, 0x0f, 0x14, 0x1d, 0x1a, 0x1f, 0x1e, 0x1d, 0x1a, 0x1c, 0x1c, 0x20, 0x24, + 0x2e, 0x27, 0x20, + 0x22, 0x2c, 0x23, 0x1c, 0x1c, 0x28, 0x37, 0x29, 0x2c, 0x30, 0x31, 0x34, 0x34, + 0x34, 0x1f, 0x27, + 0x39, 0x3d, 0x38, 0x32, 0x3c, 0x2e, 0x33, 0x34, 0x32, 0xff, 0xdb, 0x00, 0x43, + 0x01, 0x09, 0x09, + 0x09, 0x0c, 0x0b, 0x0c, 0x18, 0x0d, 0x0d, 0x18, 0x32, 0x21, 0x1c, 0x21, 0x32, + 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32 +}; + +/* third slice of one complete blank jpeg 1x1 */ +static const guint8 rtp_jpeg_frame_data_s3[] = { + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, /* SOF */ 0xff, 0xc0, + 0x00, 0x11, 0x08, 0x00, 0x01, 0x00, 0x01, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, + 0x01, 0x03, 0x11, + 0x01, 0xff, 0xc4, 0x00, 0x1f, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, + 0x0a, 0x0b +}; + +/* fourth slice of one complete blank jpeg 1x1 */ +static const guint8 rtp_jpeg_frame_data_s4[] = { + 0xff, 0xc4, 0x00, 0xb5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, + 0x05, + 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, + 0x05, 0x12, 0x21, + 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, + 0xa1, 0x08, 0x23, + 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, + 0x0a, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, + 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, + 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, + 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, + 0xd3, 0xd4, 0xd5, + 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, + 0xe9, 0xea, 0xf1, + 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff +}; + +/* fifth and last slice of one complete blank jpeg 1x1 */ +static const guint8 rtp_jpeg_frame_data_s5[] = { + 0xc4, 0x00, 0x1f, 0x01, 0x00, 0x03, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0xff, 0xc4, 0x00, + 0xb5, 0x11, 0x00, + 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, + 0x02, 0x77, 0x00, + 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, + 0x61, 0x71, 0x13, + 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, + 0x52, 0xf0, 0x15, + 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, + 0x1a, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, + 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, + 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, + 0x86, 0x87, 0x88, + 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, + 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, + 0xc2, 0xc3, 0xc4, + 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, + 0xd9, 0xda, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, + 0xf7, 0xf8, 0xf9, + 0xfa, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, + 0x3f, 0x00, 0xf7, + 0xfa, 0x28, 0xa2, 0x80, 0x3f, 0xff, 0xd9 +}; + + +/* + * rfc2435 3.1. JPEG header + * + * Each packet contains a special JPEG header which immediately follows + * the RTP header. The first 8 bytes of this header, called the "main + * JPEG header", are as follows: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type-specific | Fragment Offset | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Q | Width | Height | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ + +GST_START_TEST (test_rtpjpegpay_1_slice) +{ + GstFlowReturn ret; + GstBuffer *buffer; + GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; + GstCaps *caps = gst_caps_from_string ("video/x-jpeg,height=1,width=1"); + gchar *s = g_strdup_printf ("rtpjpegpay"); + GstHarness *h = gst_harness_new_parse (s); + guint8 *payload; + + gst_harness_set_src_caps (h, caps); + g_free (s); + + buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, + (guint8 *) rtp_jpeg_frame_data, sizeof (rtp_jpeg_frame_data), 0, + sizeof (rtp_jpeg_frame_data), NULL, NULL); + + ret = gst_harness_push (h, buffer); + fail_unless_equals_int (ret, GST_FLOW_OK); + + fail_unless_equals_int (gst_harness_buffers_in_queue (h), 1); + + buffer = gst_harness_pull (h); + fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp)); + fail_unless (payload = gst_rtp_buffer_get_payload (&rtp)); + + /* verify JPEG header */ + fail_unless (GST_READ_UINT24_BE (&payload[1]) == 0); /* offset */ + fail_unless (payload[4] == 1); /* type */ + fail_unless (payload[6] == 1); /* Width */ + fail_unless (payload[7] == 1); /* Height */ + + fail_unless (gst_rtp_buffer_get_marker (&rtp)); + gst_rtp_buffer_unmap (&rtp); + gst_buffer_unref (buffer); + + gst_harness_teardown (h); +} + +GST_END_TEST; + +GST_START_TEST (test_rtpjpegpay_5_slices) +{ + GstFlowReturn ret; + GstBuffer *buffer; + GstBuffer *buffer_s1; + GstBuffer *buffer_s2; + GstBuffer *buffer_s3; + GstBuffer *buffer_s4; + GstBuffer *buffer_s5; + GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; + GstCaps *caps = gst_caps_from_string ("video/x-jpeg,height=1,width=1"); + gchar *s = g_strdup_printf ("rtpjpegpay"); + GstHarness *h = gst_harness_new_parse (s); + guint8 *payload; + + gst_harness_set_src_caps (h, caps); + g_free (s); + + buffer_s1 = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, + (guint8 *) rtp_jpeg_frame_data_s1, sizeof (rtp_jpeg_frame_data_s1), 0, + sizeof (rtp_jpeg_frame_data_s1), NULL, NULL); + buffer_s2 = + gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, + (guint8 *) rtp_jpeg_frame_data_s2, sizeof (rtp_jpeg_frame_data_s2), 0, + sizeof (rtp_jpeg_frame_data_s2), NULL, NULL); + buffer_s3 = + gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, + (guint8 *) rtp_jpeg_frame_data_s3, sizeof (rtp_jpeg_frame_data_s3), 0, + sizeof (rtp_jpeg_frame_data_s3), NULL, NULL); + buffer_s4 = + gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, + (guint8 *) rtp_jpeg_frame_data_s4, sizeof (rtp_jpeg_frame_data_s4), 0, + sizeof (rtp_jpeg_frame_data_s4), NULL, NULL); + buffer_s5 = + gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, + (guint8 *) rtp_jpeg_frame_data_s5, sizeof (rtp_jpeg_frame_data_s5), 0, + sizeof (rtp_jpeg_frame_data_s5), NULL, NULL); + + + buffer = gst_buffer_append (buffer_s1, buffer_s2); + buffer = gst_buffer_append (buffer, buffer_s3); + buffer = gst_buffer_append (buffer, buffer_s4); + buffer = gst_buffer_append (buffer, buffer_s5); + + ret = gst_harness_push (h, buffer); + fail_unless_equals_int (ret, GST_FLOW_OK); + + fail_unless_equals_int (gst_harness_buffers_in_queue (h), 1); + + buffer = gst_harness_pull (h); + fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp)); + fail_unless (payload = gst_rtp_buffer_get_payload (&rtp)); + + /* verify JPEG header */ + fail_unless (GST_READ_UINT24_BE (&payload[1]) == 0); /* offset */ + fail_unless (payload[4] == 1); /* type */ + fail_unless (payload[6] == 1); /* Width */ + fail_unless (payload[7] == 1); /* Height */ + + fail_unless (gst_rtp_buffer_get_marker (&rtp)); + gst_rtp_buffer_unmap (&rtp); + gst_buffer_unref (buffer); + + gst_harness_teardown (h); +} + +GST_END_TEST; + + +static Suite * +rtpjpeg_suite (void) +{ + Suite *s = suite_create ("rtpjpeg"); + TCase *tc_chain; + + tc_chain = tcase_create ("rtpjpegpay_memory_slices"); + suite_add_tcase (s, tc_chain); + + tcase_add_test (tc_chain, test_rtpjpegpay_1_slice); + tcase_add_test (tc_chain, test_rtpjpegpay_5_slices); + + return s; +} + +GST_CHECK_MAIN (rtpjpeg); diff --git a/tests/check/elements/rtpopus.c b/tests/check/elements/rtpopus.c new file mode 100644 index 0000000000..35a9af86cc --- /dev/null +++ b/tests/check/elements/rtpopus.c @@ -0,0 +1,92 @@ +/* GStreamer + * + * Copyright (C) 2020 Pexip AS + * @author Havard Graff + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include +#include +#include + +#define buffer_from_array(a) gst_buffer_new_wrapped (g_memdup (a, G_N_ELEMENTS (a)), G_N_ELEMENTS (a)); + +static guint8 opus_data[] = { + 0xf8, 0xb5, 0x0e, 0x7d, 0x91, 0xcc, 0x05, 0x82, + 0x75, 0x72, 0x48, 0xbd, 0xd3, 0x22, 0x24, 0x2e, + 0x59, 0x63, 0xf8, 0xff, 0x5d, 0x59, 0x27, 0xd8, + 0xad, 0x4b, 0xe8, 0xd7, 0xfa, 0x99, 0xaa, 0x46, + 0xb4, 0xf6, 0x29, 0x16, 0x21, 0x86, 0x2a, 0xb5, + 0x83, 0x7d, 0x3a, 0xce, 0xb3, 0xee, 0x37, 0x3b, + 0xf7, 0xb5, 0x03, 0xe7, 0x13, 0x3b, 0xf6, 0x90, + 0x06, 0xea, 0x79, 0xbe, 0x89, 0xc3, 0x2b, 0x1f, + 0x7f, 0x88, 0x5e, 0xe0, 0xe1, 0x88, 0x59, 0x47, + 0x11, 0x10, 0x94, 0xab, 0x5d, 0xa6, 0x3f, 0x5d, + 0xa7, 0xd7, 0x0e, 0x7d, 0x07, 0x85, 0x0d, 0x2f, + 0x7b, 0x3f, 0xf7, 0xc1, 0x8c, 0xb2, 0xda, 0xac, + 0x79, 0x15, 0xda, 0xc7, 0xd2, 0x6e, 0xcc, 0x88, + 0x61, 0x29, 0xcd, 0x78, 0xf4, 0x6d, 0x1b, 0xa6, + 0xe6, 0xd1, 0x7c, 0x76, 0xc2, 0x86, 0x78, 0x3c, + 0xc2, 0x2e, 0x26, 0xd4, 0xdf, 0x7f, 0x3b, 0x98, + 0x7a, 0x7c, 0xbe, 0x1a, 0x17, 0xd2, 0x2d, 0xa5, + 0x90, 0x2a, 0x1b, 0x0b, 0x43, 0x65, 0x63, 0x37, + 0xe5, 0x0d, 0x5c, 0x9c, 0x6c, 0x38, 0xef, 0x2a, + 0xe8, 0x49, 0x47, 0x05, 0x6d, 0x83, 0xcf, 0x6d, +}; + +GST_START_TEST (test_pay_to_depay) +{ + GstHarness *h = gst_harness_new_parse ("rtpopuspay ! rtpopusdepay"); + GstBuffer *buf = buffer_from_array (opus_data); + gst_harness_set_src_caps_str (h, "audio/x-opus,channel-mapping-family=0"); + fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, buf)); + gst_buffer_unref (gst_harness_pull (h)); + + gst_harness_teardown (h); +} + +GST_END_TEST +GST_START_TEST (test_depay_to_pay) +{ + GstHarness *h = gst_harness_new_parse ("rtpopusdepay ! rtpopuspay"); + guint8 opus_rtp_buf[] = { + 0x80, 0x60, 0x54, 0xfd, 0x3b, 0x5a, 0x93, 0xf9, 0x1c, 0x33, 0x2b, 0xbb, + }; + GstBuffer *buf = buffer_from_array (opus_rtp_buf); + gst_harness_set_src_caps_str (h, + "application/x-rtp,encoding-name=OPUS,media=audio,clock-rate=48000,payload=96"); + fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, buf)); + gst_buffer_unref (gst_harness_pull (h)); + + gst_harness_teardown (h); +} + +GST_END_TEST; + +static Suite * +rtpopus_suite (void) +{ + Suite *s = suite_create ("rtpopus"); + TCase *tc_chain; + + suite_add_tcase (s, (tc_chain = tcase_create ("rtpopus"))); + tcase_add_test (tc_chain, test_pay_to_depay); + tcase_add_test (tc_chain, test_depay_to_pay); + + return s; +} + +GST_CHECK_MAIN (rtpopus); diff --git a/tests/check/elements/rtpptdemux.c b/tests/check/elements/rtpptdemux.c new file mode 100644 index 0000000000..b181baa751 --- /dev/null +++ b/tests/check/elements/rtpptdemux.c @@ -0,0 +1,147 @@ +/* GStreamer + * + * unit test for rtpptdemux element + * + * Copyright 2017 Pexip + * @author: Mikhail Fludkov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +static void +new_payload_type (G_GNUC_UNUSED GstElement * element, G_GNUC_UNUSED guint pt, + GstPad * pad, GstHarness ** h) +{ + gst_harness_add_element_src_pad (*h, pad); +} + +static void +test_rtpptdemux_srccaps_from_sinkcaps_base (const gchar * srccaps, + const gchar * sinkcaps) +{ + GstCaps *caps; + gchar *caps_str; + GstHarness *h = gst_harness_new_with_padnames ("rtpptdemux", "sink", NULL); + + gst_harness_set_src_caps_str (h, srccaps); + g_signal_connect (h->element, + "new-payload-type", (GCallback) new_payload_type, &h); + gst_harness_play (h); + + gst_buffer_unref (gst_harness_push_and_pull (h, + gst_rtp_buffer_new_allocate (0, 0, 0))); + + caps = gst_pad_get_current_caps (h->sinkpad); + caps_str = gst_caps_to_string (caps); + fail_unless_equals_string (caps_str, sinkcaps); + + g_free (caps_str); + gst_caps_unref (caps); + gst_harness_teardown (h); +} + +GST_START_TEST (test_rtpptdemux_srccaps_from_sinkcaps) +{ + test_rtpptdemux_srccaps_from_sinkcaps_base + ("application/x-rtp, ssrc=(uint)1111", + "application/x-rtp, ssrc=(uint)1111, payload=(int)0"); +} + +GST_END_TEST; + +GST_START_TEST (test_rtpptdemux_srccaps_from_sinkcaps_nossrc) +{ + test_rtpptdemux_srccaps_from_sinkcaps_base ("application/x-rtp", + "application/x-rtp, payload=(int)0"); +} + +GST_END_TEST; + +static GstCaps * +request_pt_map (G_GNUC_UNUSED GstElement * demux, + G_GNUC_UNUSED guint pt, const gchar * caps) +{ + return gst_caps_from_string (caps); +} + +static void +test_rtpptdemux_srccaps_from_signal_base (const gchar * srccaps, + const gchar * sigcaps, const gchar * sinkcaps) +{ + GstCaps *caps; + gchar *caps_str; + GstHarness *h = gst_harness_new_with_padnames ("rtpptdemux", "sink", NULL); + + gst_harness_set_src_caps_str (h, srccaps); + g_signal_connect (h->element, + "new-payload-type", (GCallback) new_payload_type, &h); + g_signal_connect (h->element, + "request-pt-map", (GCallback) request_pt_map, (gpointer) sigcaps); + gst_harness_play (h); + + gst_buffer_unref (gst_harness_push_and_pull (h, + gst_rtp_buffer_new_allocate (0, 0, 0))); + + caps = gst_pad_get_current_caps (h->sinkpad); + caps_str = gst_caps_to_string (caps); + fail_unless_equals_string (caps_str, sinkcaps); + + g_free (caps_str); + gst_caps_unref (caps); + gst_harness_teardown (h); +} + +GST_START_TEST (test_rtpptdemux_srccaps_from_signal) +{ + test_rtpptdemux_srccaps_from_signal_base + ("application/x-rtp, ssrc=(uint)1111", + "application/x-rtp, encoding-name=(string)H264, media=(string)video, clock-rate=(int)90000", + "application/x-rtp, encoding-name=(string)H264, media=(string)video, clock-rate=(int)90000, payload=(int)0, ssrc=(uint)1111"); +} + +GST_END_TEST; + +GST_START_TEST (test_rtpptdemux_srccaps_from_signal_nossrc) +{ + test_rtpptdemux_srccaps_from_signal_base ("application/x-rtp", + "application/x-rtp, encoding-name=(string)H264, media=(string)video, clock-rate=(int)90000", + "application/x-rtp, encoding-name=(string)H264, media=(string)video, clock-rate=(int)90000, payload=(int)0"); +} + +GST_END_TEST; + +static Suite * +rtpptdemux_suite (void) +{ + Suite *s = suite_create ("rtpptdemux"); + TCase *tc_chain; + + tc_chain = tcase_create ("general"); + tcase_add_test (tc_chain, test_rtpptdemux_srccaps_from_sinkcaps); + tcase_add_test (tc_chain, test_rtpptdemux_srccaps_from_sinkcaps_nossrc); + tcase_add_test (tc_chain, test_rtpptdemux_srccaps_from_signal); + tcase_add_test (tc_chain, test_rtpptdemux_srccaps_from_signal_nossrc); + suite_add_tcase (s, tc_chain); + + return s; +} + +GST_CHECK_MAIN (rtpptdemux) diff --git a/tests/check/elements/rtpsession.c b/tests/check/elements/rtpsession.c index 6c6828ba61..5c3c48c81b 100644 --- a/tests/check/elements/rtpsession.c +++ b/tests/check/elements/rtpsession.c @@ -37,9 +37,13 @@ #define TEST_BUF_SSRC 0x01BADBAD #define TEST_BUF_MS 20 #define TEST_BUF_DURATION (TEST_BUF_MS * GST_MSECOND) -#define TEST_BUF_SIZE (64000 * TEST_BUF_MS / 1000) +#define TEST_BUF_BPS 512000 +#define TEST_BUF_SIZE (TEST_BUF_BPS * TEST_BUF_MS / (1000 * 8)) #define TEST_RTP_TS_DURATION (TEST_BUF_CLOCK_RATE * TEST_BUF_MS / 1000) +#define TEST_TWCC_EXT_ID 5 +#define TWCC_EXTMAP_STR "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01" + static GstCaps * generate_caps (void) { @@ -49,8 +53,9 @@ generate_caps (void) } static GstBuffer * -generate_test_buffer_full (GstClockTime dts, - guint seq_num, guint32 rtp_ts, guint ssrc) +generate_test_buffer_full (GstClockTime ts, + guint seqnum, guint32 rtp_ts, guint ssrc, + gboolean marker_bit, guint8 twcc_ext_id, guint16 twcc_seqnum) { GstBuffer *buf; guint8 *payload; @@ -58,30 +63,57 @@ generate_test_buffer_full (GstClockTime dts, GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; buf = gst_rtp_buffer_new_allocate (TEST_BUF_SIZE, 0, 0); - GST_BUFFER_DTS (buf) = dts; + GST_BUFFER_PTS (buf) = ts; + GST_BUFFER_DTS (buf) = ts; gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp); gst_rtp_buffer_set_payload_type (&rtp, TEST_BUF_PT); - gst_rtp_buffer_set_seq (&rtp, seq_num); + gst_rtp_buffer_set_seq (&rtp, seqnum); gst_rtp_buffer_set_timestamp (&rtp, rtp_ts); gst_rtp_buffer_set_ssrc (&rtp, ssrc); + gst_rtp_buffer_set_marker (&rtp, marker_bit); payload = gst_rtp_buffer_get_payload (&rtp); for (i = 0; i < TEST_BUF_SIZE; i++) payload[i] = 0xff; + if (twcc_ext_id > 0) { + guint8 twcc_seqnum_be[2]; + GST_WRITE_UINT16_BE (twcc_seqnum_be, twcc_seqnum); + gst_rtp_buffer_add_extension_onebyte_header (&rtp, twcc_ext_id, + twcc_seqnum_be, sizeof (twcc_seqnum_be)); + } + gst_rtp_buffer_unmap (&rtp); return buf; } static GstBuffer * -generate_test_buffer (guint seq_num, guint ssrc) +generate_test_buffer (guint seqnum, guint ssrc) +{ + return generate_test_buffer_full (seqnum * TEST_BUF_DURATION, + seqnum, seqnum * TEST_RTP_TS_DURATION, ssrc, FALSE, 0, 0); +} + +static GstBuffer * +generate_twcc_recv_buffer (guint seqnum, + GstClockTime arrival_time, gboolean marker_bit) { - return generate_test_buffer_full (seq_num * TEST_BUF_DURATION, - seq_num, seq_num * TEST_RTP_TS_DURATION, ssrc); + return generate_test_buffer_full (arrival_time, seqnum, + seqnum * TEST_RTP_TS_DURATION, TEST_BUF_SSRC, marker_bit, + TEST_TWCC_EXT_ID, seqnum); } +static GstBuffer * +generate_twcc_send_buffer (guint seqnum, gboolean marker_bit) +{ + return generate_test_buffer_full (seqnum * TEST_BUF_DURATION, + seqnum, seqnum * TEST_RTP_TS_DURATION, TEST_BUF_SSRC, marker_bit, + TEST_TWCC_EXT_ID, seqnum); +} + + typedef struct { GstHarness *send_rtp_h; @@ -94,6 +126,8 @@ typedef struct GstCaps *caps; gboolean running; + GMutex lock; + GstStructure *last_twcc_stats; } SessionHarness; static GstCaps * @@ -103,11 +137,38 @@ _pt_map_requested (GstElement * element, guint pt, gpointer data) return gst_caps_copy (h->caps); } +static void +_notify_twcc_stats (GParamSpec * spec G_GNUC_UNUSED, + GObject * object G_GNUC_UNUSED, gpointer data) +{ + SessionHarness *h = data; + GstStructure *stats; + g_object_get (h->session, "twcc-stats", &stats, NULL); + + g_mutex_lock (&h->lock); + if (h->last_twcc_stats) + gst_structure_free (h->last_twcc_stats); + h->last_twcc_stats = stats; + g_mutex_unlock (&h->lock); +} + +static GstStructure * +session_harness_get_last_twcc_stats (SessionHarness * h) +{ + GstStructure *ret = NULL; + g_mutex_lock (&h->lock); + if (h->last_twcc_stats) + ret = gst_structure_copy (h->last_twcc_stats); + g_mutex_unlock (&h->lock); + return ret; +} + static SessionHarness * session_harness_new (void) { SessionHarness *h = g_new0 (SessionHarness, 1); h->caps = generate_caps (); + g_mutex_init (&h->lock); h->testclock = GST_TEST_CLOCK_CAST (gst_test_clock_new ()); gst_system_clock_set_default (GST_CLOCK_CAST (h->testclock)); @@ -130,6 +191,9 @@ session_harness_new (void) g_signal_connect (h->session, "request-pt-map", (GCallback) _pt_map_requested, h); + g_signal_connect (h->session, "notify::twcc-stats", + (GCallback) _notify_twcc_stats, h); + g_object_get (h->session, "internal-session", &h->internal_session, NULL); return h; @@ -147,6 +211,11 @@ session_harness_free (SessionHarness * h) gst_harness_teardown (h->recv_rtp_h); gst_harness_teardown (h->send_rtp_h); + g_mutex_clear (&h->lock); + + if (h->last_twcc_stats) + gst_structure_free (h->last_twcc_stats); + g_object_unref (h->internal_session); gst_object_unref (h->session); g_free (h); @@ -158,6 +227,12 @@ session_harness_send_rtp (SessionHarness * h, GstBuffer * buf) return gst_harness_push (h->send_rtp_h, buf); } +static GstBuffer * +session_harness_pull_send_rtp (SessionHarness * h) +{ + return gst_harness_pull (h->send_rtp_h); +} + static GstFlowReturn session_harness_recv_rtp (SessionHarness * h, GstBuffer * buf) { @@ -254,6 +329,29 @@ session_harness_rtp_retransmission_request (SessionHarness * h, gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, s)); } +static void +_add_twcc_field_to_caps (GstCaps * caps, guint8 ext_id) +{ + gchar *name = g_strdup_printf ("extmap-%u", ext_id); + gst_caps_set_simple (caps, name, G_TYPE_STRING, TWCC_EXTMAP_STR, NULL); + g_free (name); +} + +static void +session_harness_set_twcc_recv_ext_id (SessionHarness * h, guint8 ext_id) +{ + _add_twcc_field_to_caps (h->caps, ext_id); + g_signal_emit_by_name (h->session, "clear-pt-map"); +} + +static void +session_harness_set_twcc_send_ext_id (SessionHarness * h, guint8 ext_id) +{ + GstCaps *caps = gst_caps_copy (h->caps); + _add_twcc_field_to_caps (caps, ext_id); + gst_harness_set_src_caps (h->send_rtp_h, caps); +} + GST_START_TEST (test_multiple_ssrc_rr) { SessionHarness *h = session_harness_new (); @@ -329,6 +427,10 @@ GST_START_TEST (test_multiple_senders_roundrobin_rbs) g_object_set (h->internal_session, "internal-ssrc", 0xDEADBEEF, NULL); + /* this is a hack to prevent the sources from timing out when cranking and + hence messing with RTCP-generation, making the test fail 1/1000 times */ + g_object_set (h->session, "rtcp-min-interval", 20 * GST_SECOND, NULL); + for (i = 0; i < 2; i++) { /* cycles between RR reports */ for (j = 0; j < 5; j++) { /* packets per ssrc */ gint seq = (i * 5) + j; @@ -535,6 +637,10 @@ GST_START_TEST (test_internal_sources_timeout) g_object_get (h->internal_session, "internal-ssrc", &internal_ssrc, NULL); fail_unless_equals_int (0xDEADBEEF, internal_ssrc); + /* this is a hack to prevent the sources from timing out when cranking and + hence messing with RTCP-generation, making the test fail 1/100 times */ + g_object_set (h->session, "rtcp-min-interval", 20 * GST_SECOND, NULL); + for (i = 1; i < 4; i++) { buf = generate_test_buffer (i, 0xBEEFDEAD); res = session_harness_recv_rtp (h, buf); @@ -2382,6 +2488,1151 @@ GST_START_TEST (test_clear_pt_map_stress) GST_END_TEST; +static GstBuffer * +generate_stepped_ts_buffer (guint i, gboolean stepped) +{ + GstBuffer *buf; + guint ts = (TEST_BUF_CLOCK_RATE * i) / 1000; + + if (stepped) { + const int TEST_BUF_CLOCK_STEP = TEST_BUF_CLOCK_RATE / 30; + + ts /= TEST_BUF_CLOCK_STEP; + ts *= TEST_BUF_CLOCK_STEP; + } + GST_LOG ("ts: %" GST_TIME_FORMAT " rtp: %u (%" GST_TIME_FORMAT "), seq: %u\n", + GST_TIME_ARGS (i * GST_MSECOND), ts, + GST_TIME_ARGS (gst_util_uint64_scale_int (GST_SECOND, ts, + TEST_BUF_CLOCK_RATE)), i); + + buf = generate_test_buffer_full (i * GST_MSECOND, i, ts, 0xAAAA, FALSE, 0, 0); + return buf; +} + +static void +test_packet_rate_impl (gboolean stepped) +{ + SessionHarness *h = session_harness_new (); + GstBuffer *buf; + guint i; + const int PROBATION_CNT = 5; + GstStructure *stats; + GObject *source; + guint pktrate; + + /* First do probation */ + for (i = 0; i < PROBATION_CNT; i++) { + buf = generate_stepped_ts_buffer (i, stepped); + fail_unless_equals_int (session_harness_recv_rtp (h, buf), GST_FLOW_OK); + } + for (i = 0; i < PROBATION_CNT; i++) { + buf = gst_harness_pull (h->recv_rtp_h); + fail_unless (buf); + gst_buffer_unref (buf); + } + + /* Now run the real test */ + for (i = PROBATION_CNT; i < 10000; i++) { + buf = generate_stepped_ts_buffer (i, stepped); + fail_unless_equals_int (session_harness_recv_rtp (h, buf), GST_FLOW_OK); + + buf = gst_harness_pull (h->recv_rtp_h); + fail_unless (buf); + gst_buffer_unref (buf); + } + + g_signal_emit_by_name (h->internal_session, "get-source-by-ssrc", 0xAAAA, + &source); + + g_object_get (source, "stats", &stats, NULL); + + fail_unless (gst_structure_get_uint (stats, "recv-packet-rate", &pktrate)); + fail_unless (pktrate > 900 && pktrate < 1100); /* Allow 10% of error */ + + gst_structure_free (stats); + g_object_unref (source); + + session_harness_free (h); +} + +GST_START_TEST (test_packet_rate) +{ + test_packet_rate_impl (FALSE); +} + +GST_END_TEST; + +GST_START_TEST (test_stepped_packet_rate) +{ + test_packet_rate_impl (TRUE); +} + +GST_END_TEST; + + +/********************* TWCC-tests *********************/ + +static GstRTCPFBType +_gst_buffer_get_rtcp_fbtype (GstBuffer * buf) +{ + GstRTCPFBType ret = GST_RTCP_FB_TYPE_INVALID; + GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT; + GstRTCPPacket packet; + + if (!gst_rtcp_buffer_validate_reduced (buf)) + return ret; + + if (!gst_rtcp_buffer_map (buf, GST_MAP_READ, &rtcp)) + return ret; + + if (!gst_rtcp_buffer_get_first_packet (&rtcp, &packet)) + goto done; + + if (GST_RTCP_TYPE_RTPFB != gst_rtcp_packet_get_type (&packet)) + goto done; + + ret = gst_rtcp_packet_fb_get_type (&packet); + +done: + gst_rtcp_buffer_unmap (&rtcp); + return ret; +} + +static GstBuffer * +session_harness_pull_twcc_rtcp (SessionHarness * h) +{ + GstBuffer *ret = NULL; + + while (ret == NULL) { + GstBuffer *buf = session_harness_pull_rtcp (h); + if (GST_RTCP_RTPFB_TYPE_TWCC == _gst_buffer_get_rtcp_fbtype (buf)) { + ret = buf; + } else { + gst_buffer_unref (buf); + } + } + return ret; +} + +typedef struct +{ + guint16 base_seqnum; + guint16 num_packets; + GstClockTime base_time; + GstClockTime duration; +} TWCCTestData; + +static TWCCTestData twcc_header_and_run_lenght_test_data[] = { + {0, 10, 0, 33 * GST_MSECOND}, + {65530, 12, 37 * 64 * GST_MSECOND, 10 * GST_MSECOND}, /* seqnum wrap */ + {99, 200, 1024 * 64 * GST_MSECOND, 10 * GST_MSECOND}, /* many packets */ + {20000, 23, 0, 250 * GST_USECOND}, /* minimal duration */ + {56000, 15, 1000 * 64 * GST_MSECOND, 10 * GST_MSECOND}, /* timestamp offset */ +}; + +GST_START_TEST (test_twcc_header_and_run_length) +{ + SessionHarness *h = session_harness_new (); + gint i; + GstFlowReturn res; + GstBuffer *buf; + GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT; + GstRTCPPacket packet; + guint8 *fci_data; + guint16 run_length; + + TWCCTestData *td = &twcc_header_and_run_lenght_test_data[__i__]; + + /* enable twcc */ + session_harness_set_twcc_recv_ext_id (h, TEST_TWCC_EXT_ID); + + /* receive some buffers */ + for (i = 0; i < td->num_packets; i++) { + gboolean last_packet = i == (td->num_packets - 1); + + buf = generate_twcc_recv_buffer (i + td->base_seqnum, + td->base_time + i * td->duration, last_packet); + res = session_harness_recv_rtp (h, buf); + fail_unless_equals_int (GST_FLOW_OK, res); + } + + session_harness_produce_rtcp (h, 1); + buf = session_harness_pull_twcc_rtcp (h); + fail_unless (buf); + + gst_rtcp_buffer_map (buf, GST_MAP_READ, &rtcp); + fail_unless (gst_rtcp_buffer_get_first_packet (&rtcp, &packet)); + + fci_data = gst_rtcp_packet_fb_get_fci (&packet); + + /* base seqnum */ + fail_unless_equals_int (td->base_seqnum, GST_READ_UINT16_BE (&fci_data[0])); + + /* packet count */ + fail_unless_equals_int (td->num_packets, GST_READ_UINT16_BE (&fci_data[2])); + + /* reference time (in 64ms units) */ + fail_unless_equals_int (td->base_time, + GST_READ_UINT24_BE (&fci_data[4]) * 64 * GST_MSECOND); + + /* feedback packet number */ + fail_unless_equals_int (0, fci_data[7]); + + /* run-length coding */ + fail_unless_equals_int (0, fci_data[8] & 0x80); + + /* status: small-delta */ + fail_unless_equals_int (0x20, fci_data[8] & 0x60); + + /* packets in run_length */ + run_length = *((guint16 *) & fci_data[8]); + run_length = run_length & ~0xE0; /* mask out the 3 last bits */ + fail_unless_equals_int (td->num_packets, GST_READ_UINT16_BE (&run_length)); + + /* first recv-delta always 0 */ + fail_unless_equals_int (0, fci_data[10]); + + /* following recv-delta equal to duration (in 250us units) */ + fail_unless_equals_clocktime (td->duration, fci_data[11] * 250 * GST_USECOND); + + gst_rtcp_buffer_unmap (&rtcp); + gst_buffer_unref (buf); + + session_harness_free (h); +} + +GST_END_TEST; + +typedef struct +{ + guint16 seqnum; + GstClockTime timestamp; + gboolean marker; +} TWCCPacket; + +#define twcc_push_packets(h, packets) \ +G_STMT_START { \ + guint i; \ + session_harness_set_twcc_recv_ext_id ((h), TEST_TWCC_EXT_ID); \ + for (i = 0; i < G_N_ELEMENTS ((packets)); i++) { \ + TWCCPacket *twcc_pkt = &(packets)[i]; \ + fail_unless_equals_int (GST_FLOW_OK, \ + session_harness_recv_rtp ((h), \ + generate_twcc_recv_buffer (twcc_pkt->seqnum, \ + twcc_pkt->timestamp, twcc_pkt->marker))); \ + } \ +} G_STMT_END + +#define twcc_verify_fci(buf, exp_fci) \ +G_STMT_START { \ + GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT; \ + GstRTCPPacket packet; \ + guint8 *fci_data; \ + guint16 fci_length; \ + fail_unless (gst_rtcp_buffer_validate_reduced (buf)); \ + gst_rtcp_buffer_map (buf, GST_MAP_READ, &rtcp); \ + fail_unless (gst_rtcp_buffer_get_first_packet (&rtcp, &packet)); \ + fail_unless_equals_int (GST_RTCP_TYPE_RTPFB, \ + gst_rtcp_packet_get_type (&packet)); \ + fail_unless_equals_int (GST_RTCP_RTPFB_TYPE_TWCC, \ + gst_rtcp_packet_fb_get_type (&packet)); \ + fci_data = gst_rtcp_packet_fb_get_fci (&packet); \ + fci_length = gst_rtcp_packet_fb_get_fci_length (&packet) * sizeof (guint32); \ + fail_unless_equals_int (fci_length, sizeof (exp_fci)); \ + fail_unless_equals_int (0, memcmp (fci_data, (exp_fci), fci_length)); \ + gst_rtcp_buffer_unmap (&rtcp); \ +} G_STMT_END + +#define twcc_verify_packets_to_fci(h, packets, exp_fci) \ +G_STMT_START { \ + GstBuffer *buf; \ + twcc_push_packets (h, packets); \ + session_harness_produce_rtcp ((h), 1); \ + buf = session_harness_pull_twcc_rtcp ((h)); \ + twcc_verify_fci (buf, exp_fci); \ + gst_buffer_unref (buf); \ +} G_STMT_END + +#define twcc_verify_packets_to_event(packets, event) \ +G_STMT_START { \ + guint i; \ + guint j = 0; \ + GValueArray *packets_array = g_value_get_boxed ( \ + gst_structure_get_value (gst_event_get_structure ((event)), "packets")); \ + for (i = 0; i < packets_array->n_values; i++) { \ + TWCCPacket *twcc_pkt; \ + GstClockTime ts; \ + guint seqnum; \ + gboolean lost; \ + const GstStructure *pkt_s = \ + gst_value_get_structure (g_value_array_get_nth (packets_array, i)); \ + fail_unless (gst_structure_get_boolean (pkt_s, "lost", &lost)); \ + if (lost) \ + continue; \ + fail_unless (gst_structure_get_clock_time (pkt_s, "remote-ts", &ts)); \ + fail_unless (gst_structure_get_uint (pkt_s, "seqnum", &seqnum)); \ + twcc_pkt = &(packets)[j++]; \ + fail_unless_equals_int (twcc_pkt->seqnum, seqnum); \ + fail_unless_equals_clocktime (twcc_pkt->timestamp, ts); \ + } \ + gst_event_unref (event); \ +} G_STMT_END + +#define twcc_verify_packets_to_packets(send_h, recv_h, packets) \ +G_STMT_START { \ + guint i; \ + GstEvent *event; \ + twcc_push_packets ((recv_h), packets); \ + session_harness_produce_rtcp ((recv_h), 1); \ + session_harness_recv_rtcp ((send_h), \ + session_harness_pull_twcc_rtcp ((recv_h))); \ + for (i = 0; i < 2; i++) \ + gst_event_unref (gst_harness_pull_upstream_event ((send_h)->send_rtp_h)); \ + event = gst_harness_pull_upstream_event ((send_h)->send_rtp_h); \ + twcc_verify_packets_to_event (packets, event); \ +} G_STMT_END + +GST_START_TEST (test_twcc_1_bit_status_vector) +{ + SessionHarness *h0 = session_harness_new (); + SessionHarness *h1 = session_harness_new (); + + TWCCPacket packets[] = { + {10, 0 * GST_MSECOND, FALSE}, + {12, 12 * GST_MSECOND, FALSE}, + {14, 14 * GST_MSECOND, FALSE}, + {15, 15 * GST_MSECOND, FALSE}, + {17, 17 * GST_MSECOND, FALSE}, + {20, 20 * GST_MSECOND, FALSE}, + {21, 21 * GST_MSECOND, FALSE}, + {23, 23 * GST_MSECOND, TRUE}, + }; + + guint8 exp_fci[] = { + 0x00, 0x0a, /* base sequence number: 10 */ + 0x00, 0x0e, /* packet status count: 14 */ + 0x00, 0x00, 0x00, /* reference time: 0 */ + 0x00, /* feedback packet count: 0 */ + 0xab, 0x4d, /* packet chunk: 1 0 1 0 1 0 1 1 | 0 1 0 0 1 1 0 1 */ + 0x00, /* recv delta: +0:00:00.000000000 */ + 0x30, /* recv delta: +0:00:00.012000000 */ + 0x08, /* recv delta: +0:00:00.002000000 */ + 0x04, /* recv delta: +0:00:00.001000000 */ + 0x08, /* recv delta: +0:00:00.002000000 */ + 0x0c, /* recv delta: +0:00:00.003000000 */ + 0x04, /* recv delta: +0:00:00.001000000 */ + 0x08, /* recv delta: +0:00:00.002000000 */ + 0x00, 0x00, /* padding */ + }; + + /* check we get the expected fci */ + twcc_verify_packets_to_fci (h0, packets, exp_fci); + + /* and check we can parse this back to the original packets */ + twcc_verify_packets_to_packets (h1, h1, packets); + + session_harness_free (h0); + session_harness_free (h1); +} + +GST_END_TEST; + +GST_START_TEST (test_twcc_2_bit_status_vector) +{ + SessionHarness *h0 = session_harness_new (); + SessionHarness *h1 = session_harness_new (); + + TWCCPacket packets[] = { + {5, 5 * 64 * GST_MSECOND, FALSE}, + {7, 7 * 64 * GST_MSECOND, FALSE}, + {8, 8 * 64 * GST_MSECOND, FALSE}, + {11, 12 * 64 * GST_MSECOND, TRUE}, + }; + + guint8 exp_fci[] = { + 0x00, 0x05, /* base sequence number: 5 */ + 0x00, 0x07, /* packet status count: 7 */ + 0x00, 0x00, 0x05, /* reference time: 5 */ + 0x00, /* feedback packet count: 0 */ + 0xd2, 0x82, /* packet chunk: 1 1 0 1 0 0 1 0 | 1 0 0 0 0 0 1 0 */ + /* normal, missing, large, large, missing, missing, large */ + 0x00, /* recv delta: +0:00:00.000000000 */ + 0x02, 0x00, /* recv delta: +0:00:00.128000000 */ + 0x01, 0x00, /* recv delta: +0:00:00.064000000 */ + 0x04, 0x00, /* recv delta: +0:00:00.256000000 */ + 0x00, 0x00, 0x00, /* padding */ + }; + + twcc_verify_packets_to_fci (h0, packets, exp_fci); + + twcc_verify_packets_to_packets (h1, h1, packets); + + session_harness_free (h0); + session_harness_free (h1); +} + +GST_END_TEST; + +GST_START_TEST (test_twcc_various_gaps) +{ + SessionHarness *h = session_harness_new (); + guint16 seq = 1 + __i__; + + TWCCPacket packets[] = { + {0, 0 * 250 * GST_USECOND, FALSE}, + {seq, seq * 250 * GST_USECOND, TRUE}, + }; + + twcc_verify_packets_to_packets (h, h, packets); + + session_harness_free (h); +} + +GST_END_TEST; + +GST_START_TEST (test_twcc_negative_delta) +{ + SessionHarness *h0 = session_harness_new (); + SessionHarness *h1 = session_harness_new (); + + TWCCPacket packets[] = { + {0, 0 * 250 * GST_USECOND, FALSE}, + {1, 2 * 250 * GST_USECOND, FALSE}, + {2, 1 * 250 * GST_USECOND, FALSE}, + {3, 3 * 250 * GST_USECOND, TRUE}, + }; + + guint8 exp_fci[] = { + 0x00, 0x00, /* base sequence number: 0 */ + 0x00, 0x04, /* packet status count: 4 */ + 0x00, 0x00, 0x00, /* reference time: 0 */ + 0x00, /* feedback packet count: 0 */ + 0xd6, 0x40, /* packet chunk: 1 1 0 1 0 1 1 0 | 0 1 0 0 0 0 0 0 */ + 0x00, /* recv delta: +0:00:00.000000000 */ + 0x02, /* recv delta: +0:00:00.000500000 */ + 0xff, 0xff, /* recv delta: -0:00:00.000250000 */ + 0x02, /* recv delta: +0:00:00.000500000 */ + 0x00, /* padding */ + }; + + twcc_verify_packets_to_fci (h0, packets, exp_fci); + + twcc_verify_packets_to_packets (h1, h1, packets); + + session_harness_free (h0); + session_harness_free (h1); +} + +GST_END_TEST; + +GST_START_TEST (test_twcc_seqnum_wrap) +{ + SessionHarness *h0 = session_harness_new (); + SessionHarness *h1 = session_harness_new (); + + TWCCPacket packets[] = { + {65534, 0 * 250 * GST_USECOND, FALSE}, + {65535, 1 * 250 * GST_USECOND, FALSE}, + {0, 2 * 250 * GST_USECOND, FALSE}, + {1, 3 * 250 * GST_USECOND, TRUE}, + }; + + guint8 exp_fci[] = { + 0xff, 0xfe, /* base sequence number: 65534 */ + 0x00, 0x04, /* packet status count: 4 */ + 0x00, 0x00, 0x00, /* reference time: 0 */ + 0x00, /* feedback packet count: 0 */ + 0x20, 0x04, /* packet chunk: 0 0 1 0 0 0 0 0 | 0 0 0 0 0 1 0 0 */ + 0x00, /* recv delta: +0:00:00.000000000 */ + 0x01, /* recv delta: +0:00:00.000250000 */ + 0x01, /* recv delta: +0:00:00.000250000 */ + 0x01, /* recv delta: +0:00:00.000250000 */ + 0x00, 0x00, /* padding */ + }; + + twcc_verify_packets_to_fci (h0, packets, exp_fci); + + twcc_verify_packets_to_packets (h1, h1, packets); + + session_harness_free (h0); + session_harness_free (h1); +} + +GST_END_TEST; + + +GST_START_TEST (test_twcc_double_packets) +{ + SessionHarness *h = session_harness_new (); + + TWCCPacket packets0[] = { + {11, 11 * GST_MSECOND, FALSE}, + {12, 12 * GST_MSECOND, TRUE}, + }; + + TWCCPacket packets1[] = { + {13, 13 * GST_MSECOND, FALSE}, + {14, 14 * GST_MSECOND, FALSE}, + {15, 15 * GST_MSECOND, TRUE}, + }; + + guint8 exp_fci0[] = { + 0x00, 0x0b, /* base sequence number: 11 */ + 0x00, 0x02, /* packet status count: 14 */ + 0x00, 0x00, 0x00, /* reference time: 0 */ + 0x00, /* feedback packet count: 0 */ + 0x20, 0x02, /* packet chunk: 0 0 1 0 0 0 0 0 | 0 0 0 0 0 0 1 0 */ + 0x2c, 0x04, /* recv deltas */ + }; + + guint8 exp_fci1[] = { + 0x00, 0x0d, /* base sequence number: 13 */ + 0x00, 0x03, /* packet status count: 3 */ + 0x00, 0x00, 0x00, /* reference time: 0 */ + 0x01, /* feedback packet count: 1 */ + 0x20, 0x03, /* packet chunk: 0 0 1 0 0 0 0 0 | 0 0 0 0 0 0 1 1 */ + 0x34, 0x04, 0x04, /* recv deltas */ + 0x00, 0x00, 0x00, /* padding */ + }; + + twcc_verify_packets_to_fci (h, packets0, exp_fci0); + twcc_verify_packets_to_fci (h, packets1, exp_fci1); + + session_harness_free (h); +} + +GST_END_TEST; + +GST_START_TEST (test_twcc_huge_seqnum_gap) +{ + SessionHarness *h = session_harness_new (); + GstBuffer *buf; + + TWCCPacket packets[] = { + {9, 4 * 32 * GST_MSECOND, FALSE}, + {10, 5 * 32 * GST_MSECOND, FALSE}, + {30011, 6 * 32 * GST_MSECOND, FALSE}, + {30012, 7 * 32 * GST_MSECOND, FALSE}, + {30013, 8 * 32 * GST_MSECOND, TRUE}, + }; + + guint8 exp_fci0[] = { + 0x00, 0x09, /* base sequence number: 9 */ + 0x00, 0x02, /* packet status count: 2 */ + 0x00, 0x00, 0x02, /* reference time: 2 * 64ms */ + 0x00, /* feedback packet count: 0 */ + /* packet chunks: */ + 0x20, 0x02, /* 0 0 1 0 0 0 0 0 | 0 0 0 0 0 0 1 0 */ + 0x00, 0x80, /* recv deltas, +0, +32ms */ + }; + + guint8 exp_fci1[] = { + 0x75, 0x3b, /* base sequence number: 300011 */ + 0x00, 0x03, /* packet status count: 3 */ + 0x00, 0x00, 0x03, /* reference time: 3 * 64ms */ + 0x01, /* feedback packet count: 1 */ + /* packet chunks: */ + 0x20, 0x03, /* 0 0 1 0 0 0 0 0 | 0 0 0 0 0 0 1 1 */ + 0x00, 0x80, 0x80, /* recv deltas, +4, +32ms, +32ms */ + 0x00, 0x00, 0x00, /* padding */ + }; + + /* The sequence-number does a huge leap. Instead of encoding this as + a massive run-lenght sequence, like so */ +#if 0 + guint8 exp_fci[] = { + 0x00, 0x09, /* base sequence number: 9 */ + 0x75, 0x35, /* packet status count: 30005 */ + 0x00, 0x00, 0x02, /* reference time: 2 */ + 0x00, /* feedback packet count: 0 */ + /* packet chunks: */ + 0xb0, 0x00, /* 1 bit 2 there, 12 lost: 1 0 1 1 0 0 0 0 | 0 0 0 0 0 0 0 0 */ + 0x1f, 0xff, /* run-length: 8191 lost: 0 0 0 1 1 1 1 1 | 1 1 1 1 1 1 1 1 */ + 0x1f, 0xff, /* run-length: 8191 lost: 0 0 0 1 1 1 1 1 | 1 1 1 1 1 1 1 1 */ + 0x1f, 0xff, /* run-length: 8191 lost: 0 0 0 1 1 1 1 1 | 1 1 1 1 1 1 1 1 */ + 0x15, 0x27, /* run-length: 5415 lost: 0 0 0 1 0 1 0 1 | 0 0 1 0 0 1 1 1 */ + /* 12 + 8191 + 8191 + 8191 + 5415 = 30000 lost packets */ + 0xb8, 0x00, /* 1 bit 3 there : 1 0 1 1 1 0 0 0 | 0 0 0 0 0 0 0 0 */ + + 0x00, 0x80, 0x80, 0x80, 0x80, /* recv deltas */ + 0x00, 0x00, 0x00, /* padding */ + }; +#endif + + /* ...just send two feedback-packets, with + the second one starting from the new sequence-number. */ + twcc_push_packets (h, packets); + + session_harness_produce_rtcp (h, 1); + + buf = session_harness_pull_twcc_rtcp (h); + twcc_verify_fci (buf, exp_fci0); + gst_buffer_unref (buf); + + buf = session_harness_pull_twcc_rtcp (h); + twcc_verify_fci (buf, exp_fci1); + gst_buffer_unref (buf); + + session_harness_free (h); +} + +GST_END_TEST; + +GST_START_TEST (test_twcc_duplicate_seqnums) +{ + SessionHarness *h = session_harness_new (); + GstBuffer *buf; + + /* A duplicate seqnum can be interpreted as a gap of 65536 packets. + Whatever the cause might be, we will follow the behavior of reordered + packets, and drop it */ + TWCCPacket packets[] = { + {1, 4 * 32 * GST_MSECOND, FALSE}, + {2, 5 * 32 * GST_MSECOND, FALSE}, + {2, 6 * 32 * GST_MSECOND, FALSE}, + {3, 7 * 32 * GST_MSECOND, TRUE}, + }; + + guint8 exp_fci0[] = { + 0x00, 0x01, /* base sequence number: 1 */ + 0x00, 0x02, /* packet status count: 2 */ + 0x00, 0x00, 0x02, /* reference time: 2 * 64ms */ + 0x00, /* feedback packet count: 0 */ + /* packet chunks: */ + 0x20, 0x02, /* 0 0 1 0 0 0 0 0 | 0 0 0 0 0 0 1 0 */ + 0x00, 0x80, /* recv deltas: +0, +32ms */ + }; + + guint8 exp_fci1[] = { + 0x00, 0x03, /* base sequence number: 3 */ + 0x00, 0x01, /* packet status count: 1 */ + 0x00, 0x00, 0x03, /* reference time: 3 * 64ms */ + 0x01, /* feedback packet count: 1 */ + /* packet chunks: */ + 0x20, 0x01, /* 0 0 1 0 0 0 0 0 | 0 0 0 0 0 0 0 1 */ + 0x80, /* recv deltas: +32ms */ + 0x00, /* padding */ + }; + + twcc_push_packets (h, packets); + + session_harness_produce_rtcp (h, 1); + + buf = session_harness_pull_twcc_rtcp (h); + twcc_verify_fci (buf, exp_fci0); + gst_buffer_unref (buf); + + buf = session_harness_pull_twcc_rtcp (h); + twcc_verify_fci (buf, exp_fci1); + gst_buffer_unref (buf); + + session_harness_free (h); +} + +GST_END_TEST; + +GST_START_TEST (test_twcc_multiple_markers) +{ + SessionHarness *h = session_harness_new (); + GstBuffer *buf; + + /* for this test, notice how the first recv-delta should relate back to + the reference-time, which is 0 in this case. The packets are incrementing + in timestamps equal to the smallest unit for TWCC (250 microseconds) */ + TWCCPacket packets[] = { + {1, 1 * 250 * GST_USECOND, FALSE}, + {2, 2 * 250 * GST_USECOND, FALSE}, + {3, 3 * 250 * GST_USECOND, TRUE}, + {4, 4 * 250 * GST_USECOND, FALSE}, + {5, 5 * 250 * GST_USECOND, TRUE}, + {6, 6 * 250 * GST_USECOND, FALSE}, + {7, 7 * 250 * GST_USECOND, FALSE}, + {8, 8 * 250 * GST_USECOND, FALSE}, + {9, 9 * 250 * GST_USECOND, TRUE}, + }; + + guint8 exp_fci0[] = { + 0x00, 0x01, /* base sequence number: 1 */ + 0x00, 0x03, /* packet status count: 3 */ + 0x00, 0x00, 0x00, /* reference time: 0 */ + 0x00, /* feedback packet count: 0 */ + /* packet chunks: */ + 0x20, 0x03, /* 0 0 1 0 0 0 0 0 | 0 0 0 0 0 0 1 1 */ + 0x01, 0x01, 0x01, /* recv deltas, +1, +1, +1 */ + 0x00, 0x00, 0x00, /* padding */ + }; + + guint8 exp_fci1[] = { + 0x00, 0x04, /* base sequence number: 4 */ + 0x00, 0x02, /* packet status count: 2 */ + 0x00, 0x00, 0x00, /* reference time: 0 */ + 0x01, /* feedback packet count: 1 */ + /* packet chunks: */ + 0x20, 0x02, /* 0 0 1 0 0 0 0 0 | 0 0 0 0 0 0 1 0 */ + 0x04, 0x01, /* recv deltas, +4, +1, +1 */ + }; + + guint8 exp_fci2[] = { + 0x00, 0x06, /* base sequence number: 6 */ + 0x00, 0x04, /* packet status count: 4 */ + 0x00, 0x00, 0x00, /* reference time: 0 */ + 0x02, /* feedback packet count: 2 */ + /* packet chunks: */ + 0x20, 0x04, /* 0 0 1 0 0 0 0 0 | 0 0 0 0 0 1 0 0 */ + 0x06, 0x01, 0x01, 0x01, /* recv deltas, +6, +1, +1, +1 */ + 0x00, 0x00, + }; + + twcc_push_packets (h, packets); + + /* we should get 1 SR/RR, and then 3x TWCC packets */ + session_harness_produce_rtcp (h, 1); + + buf = session_harness_pull_twcc_rtcp (h); + twcc_verify_fci (buf, exp_fci0); + gst_buffer_unref (buf); + + buf = session_harness_pull_twcc_rtcp (h); + twcc_verify_fci (buf, exp_fci1); + gst_buffer_unref (buf); + + buf = session_harness_pull_twcc_rtcp (h); + twcc_verify_fci (buf, exp_fci2); + gst_buffer_unref (buf); + + session_harness_free (h); +} + +GST_END_TEST; + +GST_START_TEST (test_twcc_no_marker_and_gaps) +{ + SessionHarness *h = session_harness_new (); + guint i; + + g_object_set (h->internal_session, "probation", 1, NULL); + + /* Push packets with gaps and no marker bit. This should not prevent + the feedback packets from being sent at all. */ + for (i = 0; i < 80; i += 10) { + TWCCPacket packets[] = { {i, i * 250 * GST_USECOND, FALSE} + }; + twcc_push_packets (h, packets); + } + + /* verify we did receive some feedback for these packets */ + session_harness_produce_rtcp (h, 1); + for (i = 0; i < 2; i++) { + gst_buffer_unref (session_harness_pull_twcc_rtcp (h)); + } + + session_harness_free (h); +} + +GST_END_TEST; + +static GstBuffer * +generate_twcc_feedback_rtcp (guint8 * fci_data, guint16 fci_length) +{ + GstRTCPPacket packet; + GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT; + GstBuffer *buffer = gst_rtcp_buffer_new (1000); + guint8 *fci; + + fail_unless (gst_rtcp_buffer_map (buffer, GST_MAP_READWRITE, &rtcp)); + fail_unless (gst_rtcp_buffer_add_packet (&rtcp, GST_RTCP_TYPE_RTPFB, + &packet)); + gst_rtcp_packet_fb_set_type (&packet, GST_RTCP_RTPFB_TYPE_TWCC); + gst_rtcp_packet_fb_set_fci_length (&packet, fci_length); + fci = gst_rtcp_packet_fb_get_fci (&packet); + memcpy (fci, fci_data, fci_length); + gst_rtcp_packet_fb_set_sender_ssrc (&packet, TEST_BUF_SSRC); + gst_rtcp_packet_fb_set_media_ssrc (&packet, 0); + gst_rtcp_buffer_unmap (&rtcp); + + return buffer; +} + +GST_START_TEST (test_twcc_bad_rtcp) +{ + SessionHarness *h = session_harness_new (); + guint i; + GstBuffer *buf; + GstEvent *event; + GValueArray *packets_array; + + guint8 fci[] = { + 0xff, 0xff, /* base sequence number: max */ + 0xff, 0xff, /* packet status count: max */ + 0xff, 0xff, 0xff, /* reference time: max */ + 0xff, /* feedback packet count: max */ + 0x3f, 0xff, /* packet chunk: run-length, max */ + 0x00, /* only 1 recv-delta */ + }; + + buf = generate_twcc_feedback_rtcp (fci, sizeof (fci)); + session_harness_recv_rtcp (h, buf); + + /* two reconfigure events */ + for (i = 0; i < 2; i++) + gst_event_unref (gst_harness_pull_upstream_event (h->send_rtp_h)); + + event = gst_harness_pull_upstream_event (h->send_rtp_h); + packets_array = + g_value_get_boxed (gst_structure_get_value (gst_event_get_structure + (event), "packets")); + + /* this ends up with 0 packets, due to completely invalid data */ + fail_unless_equals_int (packets_array->n_values, 0); + + gst_event_unref (event); + session_harness_free (h); +} + +GST_END_TEST; + +GST_START_TEST (test_twcc_delta_ts_rounding) +{ + SessionHarness *h = session_harness_new (); + guint i, j = 0; + GstEvent *event; + GstBuffer *buf; + GValueArray *packets_array; + + TWCCPacket packets[] = { + {2002, 9 * GST_SECOND + 366458177, FALSE} + , + {2003, 9 * GST_SECOND + 366497068, FALSE} + , + {2017, 9 * GST_SECOND + 366929482, FALSE} + , + {2019, 9 * GST_SECOND + 391595309, FALSE} + , + {2020, 9 * GST_SECOND + 426883507, FALSE} + , + {2025, 9 * GST_SECOND + 427021638, TRUE} + , + }; + + TWCCPacket exp_packets[] = { + {2002, 9 * GST_SECOND + 366250000, FALSE} + , + {2003, 9 * GST_SECOND + 366250000, FALSE} + , + {2017, 9 * GST_SECOND + 366750000, FALSE} + , + {2019, 9 * GST_SECOND + 391500000, FALSE} + , + {2020, 9 * GST_SECOND + 426750000, FALSE} + , + {2025, 9 * GST_SECOND + 427000000, TRUE} + , + }; + + guint8 exp_fci[] = { + 0x07, 0xd2, /* base sequence number: 2002 */ + 0x00, 0x18, /* packet status count: 24 */ + 0x00, 0x00, 0x92, /* reference time: 0:00:09.344000000 */ + 0x00, /* feedback packet count: 0 */ + 0xb0, 0x00, /* packet chunk: 1 0 1 1 0 0 0 0 | 0 0 0 0 0 0 0 0 */ + 0x96, 0x10, /* packet chunk: 1 0 0 1 0 1 1 0 | 0 0 0 1 0 0 0 0 */ + 0x59, /* recv delta: 0:00:00.022250000 abs: 0:00:09.366250000 */ + 0x00, /* recv delta: 0:00:00.000000000 abs: 0:00:09.366250000 */ + 0x02, /* recv delta: 0:00:00.000500000 abs: 0:00:09.366750000 */ + 0x63, /* recv delta: 0:00:00.024750000 abs: 0:00:09.391500000 */ + 0x8d, /* recv delta: 0:00:00.035250000 abs: 0:00:09.426750000 */ + 0x01, /* recv delta: 0:00:00.000250000 abs: 0:00:09.427000000 */ + 0x00, 0x00, /* padding */ + }; + + twcc_push_packets (h, packets); + session_harness_produce_rtcp (h, 1); + buf = session_harness_pull_twcc_rtcp (h); + twcc_verify_fci (buf, exp_fci); + + session_harness_recv_rtcp (h, buf); + for (i = 0; i < 2; i++) + gst_event_unref (gst_harness_pull_upstream_event (h->send_rtp_h)); + event = gst_harness_pull_upstream_event (h->send_rtp_h); + + packets_array = + g_value_get_boxed (gst_structure_get_value (gst_event_get_structure + (event), "packets")); + for (i = 0; i < packets_array->n_values; i++) { + TWCCPacket *twcc_pkt; + const GstStructure *pkt_s = + gst_value_get_structure (g_value_array_get_nth (packets_array, i)); + GstClockTime ts; + guint seqnum; + gboolean lost; + fail_unless (gst_structure_get_boolean (pkt_s, "lost", &lost)); + if (lost) + continue; + twcc_pkt = &exp_packets[j++]; + + fail_unless (gst_structure_get_clock_time (pkt_s, "remote-ts", &ts)); + fail_unless (gst_structure_get_uint (pkt_s, "seqnum", &seqnum)); + + fail_unless_equals_int (twcc_pkt->seqnum, seqnum); + fail_unless_equals_clocktime (twcc_pkt->timestamp, ts); + } + + gst_event_unref (event); + session_harness_free (h); +} + +GST_END_TEST; + +GST_START_TEST (test_twcc_double_gap) +{ + SessionHarness *h0 = session_harness_new (); + SessionHarness *h1 = session_harness_new (); + + TWCCPacket packets[] = { + {1202, 5 * GST_SECOND + 717000000, FALSE} + , + {1215, 5 * GST_SECOND + 760250000, FALSE} + , + {1221, 5 * GST_SECOND + 775500000, TRUE} + , + }; + + guint8 exp_fci[] = { + 0x04, 0xb2, /* base sequence number: 1202 */ + 0x00, 0x14, /* packet status count: 20 */ + 0x00, 0x00, 0x59, /* reference time: 0:00:05.696000000 */ + 0x00, /* feedback packet count: 0 */ + 0xa0, 0x01, /* packet chunk: 1 0 1 0 0 0 0 0 | 0 0 0 0 0 0 0 1 */ + 0x81, 0x00, /* packet chunk: 1 0 0 0 0 0 0 1 | 0 0 0 0 0 0 0 0 */ + 0x54, /* recv delta: +0:00:00.021000000 */ + 0xad, /* recv delta: +0:00:00.043250000 */ + 0x3d, /* recv delta: +0:00:00.015250000 */ + 0x00, /* padding */ + }; + + twcc_verify_packets_to_fci (h0, packets, exp_fci); + + twcc_verify_packets_to_packets (h1, h1, packets); + + session_harness_free (h0); + session_harness_free (h1); +} + +GST_END_TEST; + +GST_START_TEST (test_twcc_recv_packets_reordered) +{ + SessionHarness *h = session_harness_new (); + GstBuffer *buf; + + /* a reordered seqence, with marker-bits for #3 and #4 */ + TWCCPacket packets[] = { + {1, 1 * 250 * GST_USECOND, FALSE} + , + {3, 2 * 250 * GST_USECOND, TRUE} + , + {2, 3 * 250 * GST_USECOND, FALSE} + , + {4, 4 * 250 * GST_USECOND, TRUE} + , + }; + + /* first we expect #2 to be reported lost */ + guint8 exp_fci0[] = { + 0x00, 0x01, /* base sequence number: 1 */ + 0x00, 0x03, /* packet status count: 3 */ + 0x00, 0x00, 0x00, /* reference time: 0 */ + 0x00, /* feedback packet count: 0 */ + /* packet chunks: */ + 0xa8, 0x00, /* 1 0 1 0 1 0 0 0 | 0 0 0 0 0 0 0 0 */ + 0x01, 0x01, /* recv deltas, +1, +1 */ + }; + + /* and then when 2 actually arrives, it is already reported lost, + so we will not re-report it, but drop it */ + guint8 exp_fci1[] = { + 0x00, 0x04, /* base sequence number: 4 */ + 0x00, 0x01, /* packet status count: 1 */ + 0x00, 0x00, 0x00, /* reference time: 0 */ + 0x01, /* feedback packet count: 1 */ + /* packet chunks: */ + 0x20, 0x01, /* 0 0 1 0 0 0 0 0 | 0 0 0 0 0 0 0 1 */ + 0x04, /* recv deltas, +4 */ + 0x00, /* padding */ + }; + + twcc_push_packets (h, packets); + + session_harness_produce_rtcp (h, 1); + + buf = session_harness_pull_twcc_rtcp (h); + twcc_verify_fci (buf, exp_fci0); + gst_buffer_unref (buf); + + buf = session_harness_pull_twcc_rtcp (h); + twcc_verify_fci (buf, exp_fci1); + gst_buffer_unref (buf); + + session_harness_free (h); +} + +GST_END_TEST; + +GST_START_TEST (test_twcc_recv_rtcp_reordered) +{ + SessionHarness *send_h = session_harness_new (); + SessionHarness *recv_h = session_harness_new (); + GstBuffer *buf[4]; + GstEvent *event; + guint i; + + /* three frames, two packets each */ + TWCCPacket packets[] = { + {1, 1 * GST_SECOND, FALSE} + , + {2, 2 * GST_SECOND, TRUE} + , + {3, 3 * GST_SECOND, FALSE} + , + {4, 4 * GST_SECOND, TRUE} + , + {5, 5 * GST_SECOND, FALSE} + , + {6, 6 * GST_SECOND, TRUE} + , + {7, 7 * GST_SECOND, FALSE} + , + {8, 8 * GST_SECOND, TRUE} + , + }; + +/* + TWCCPacket expected_packets0[] = { + {1, 1 * 250 * GST_USECOND, FALSE}, + {2, 2 * 250 * GST_USECOND, TRUE}, + }; +*/ + twcc_push_packets (recv_h, packets); + + session_harness_produce_rtcp (recv_h, 1); + + buf[0] = session_harness_pull_twcc_rtcp (recv_h); + buf[1] = session_harness_pull_twcc_rtcp (recv_h); + buf[2] = session_harness_pull_twcc_rtcp (recv_h); + buf[3] = session_harness_pull_twcc_rtcp (recv_h); + + /* reorder the twcc-feedback */ + session_harness_recv_rtcp (send_h, buf[0]); + session_harness_recv_rtcp (send_h, buf[2]); + session_harness_recv_rtcp (send_h, buf[1]); + session_harness_recv_rtcp (send_h, buf[3]); + + for (i = 0; i < 2; i++) + gst_event_unref (gst_harness_pull_upstream_event (send_h->send_rtp_h)); + + event = gst_harness_pull_upstream_event (send_h->send_rtp_h); + twcc_verify_packets_to_event (&packets[0 * 2], event); + + event = gst_harness_pull_upstream_event (send_h->send_rtp_h); + twcc_verify_packets_to_event (&packets[2 * 2], event); + + event = gst_harness_pull_upstream_event (send_h->send_rtp_h); + twcc_verify_packets_to_event (&packets[1 * 2], event); + + event = gst_harness_pull_upstream_event (send_h->send_rtp_h); + twcc_verify_packets_to_event (&packets[3 * 2], event); + + session_harness_free (send_h); + session_harness_free (recv_h); +} + +GST_END_TEST; + +GST_START_TEST (test_twcc_no_exthdr_in_buffer) +{ + SessionHarness *h = session_harness_new (); + + session_harness_set_twcc_recv_ext_id (h, TEST_TWCC_EXT_ID); + + fail_unless_equals_int (GST_FLOW_OK, + session_harness_recv_rtp (h, generate_test_buffer (0, 1234))); + session_harness_free (h); +} + +GST_END_TEST; + + +GST_START_TEST (test_twcc_send_and_recv) +{ + SessionHarness *h_send = session_harness_new (); + SessionHarness *h_recv = session_harness_new (); + guint frame; + const guint num_frames = 2; + const guint num_slices = 15; + + /* enable twcc */ + session_harness_set_twcc_recv_ext_id (h_recv, TEST_TWCC_EXT_ID); + session_harness_set_twcc_send_ext_id (h_send, TEST_TWCC_EXT_ID); + + for (frame = 0; frame < num_frames; frame++) { + GstBuffer *buf; + guint slice; + + for (slice = 0; slice < num_slices; slice++) { + GstFlowReturn res; + guint seq = frame * num_slices + slice; + + /* from payloder to rtpbin */ + buf = generate_twcc_send_buffer (seq, slice == num_slices - 1); + res = session_harness_send_rtp (h_send, buf); + fail_unless_equals_int (GST_FLOW_OK, res); + + /* get the buffer ready for the network */ + buf = session_harness_pull_send_rtp (h_send); + + /* buffer arrives at the receiver */ + res = session_harness_recv_rtp (h_recv, buf); + fail_unless_equals_int (GST_FLOW_OK, res); + } + + /* receiver sends a TWCC packet to the sender */ + session_harness_produce_rtcp (h_recv, 1); + buf = session_harness_pull_twcc_rtcp (h_recv); + /* sender receives the TWCC packet */ + session_harness_recv_rtcp (h_send, buf); + + if (frame > 0) { + GstStructure *twcc_stats; + guint bitrate_sent; + guint bitrate_recv; + guint packets_sent; + guint packets_recv; + gdouble packet_loss_pct; + GstClockTimeDiff avg_delta_of_delta; + twcc_stats = session_harness_get_last_twcc_stats (h_send); + fail_unless (gst_structure_get (twcc_stats, + "bitrate-sent", G_TYPE_UINT, &bitrate_sent, + "bitrate-recv", G_TYPE_UINT, &bitrate_recv, + "packets-sent", G_TYPE_UINT, &packets_sent, + "packets-recv", G_TYPE_UINT, &packets_recv, + "packet-loss-pct", G_TYPE_DOUBLE, &packet_loss_pct, + "avg-delta-of-delta", G_TYPE_INT64, &avg_delta_of_delta, NULL)); + fail_unless_equals_int (TEST_BUF_BPS, bitrate_sent); + fail_unless_equals_int (TEST_BUF_BPS, bitrate_recv); + fail_unless_equals_int (num_slices, packets_sent); + fail_unless_equals_int (num_slices, packets_recv); + fail_unless_equals_float (0.0f, packet_loss_pct); + fail_unless_equals_int64 (0, avg_delta_of_delta); + gst_structure_free (twcc_stats); + } + } + + session_harness_free (h_send); + session_harness_free (h_recv); +} + +GST_END_TEST; + static Suite * rtpsession_suite (void) { @@ -2419,6 +3670,29 @@ rtpsession_suite (void) tcase_add_test (tc_chain, test_disable_probation); tcase_add_test (tc_chain, test_request_late_nack); tcase_add_test (tc_chain, test_clear_pt_map_stress); + tcase_add_test (tc_chain, test_packet_rate); + tcase_add_test (tc_chain, test_stepped_packet_rate); + + /* twcc */ + tcase_add_loop_test (tc_chain, test_twcc_header_and_run_length, + 0, G_N_ELEMENTS (twcc_header_and_run_lenght_test_data)); + tcase_add_test (tc_chain, test_twcc_1_bit_status_vector); + tcase_add_test (tc_chain, test_twcc_2_bit_status_vector); + tcase_add_loop_test (tc_chain, test_twcc_various_gaps, 0, 50); + tcase_add_test (tc_chain, test_twcc_negative_delta); + tcase_add_test (tc_chain, test_twcc_seqnum_wrap); + tcase_add_test (tc_chain, test_twcc_huge_seqnum_gap); + tcase_add_test (tc_chain, test_twcc_double_packets); + tcase_add_test (tc_chain, test_twcc_duplicate_seqnums); + tcase_add_test (tc_chain, test_twcc_multiple_markers); + tcase_add_test (tc_chain, test_twcc_no_marker_and_gaps); + tcase_add_test (tc_chain, test_twcc_bad_rtcp); + tcase_add_test (tc_chain, test_twcc_delta_ts_rounding); + tcase_add_test (tc_chain, test_twcc_double_gap); + tcase_add_test (tc_chain, test_twcc_recv_packets_reordered); + tcase_add_test (tc_chain, test_twcc_recv_rtcp_reordered); + tcase_add_test (tc_chain, test_twcc_no_exthdr_in_buffer); + tcase_add_test (tc_chain, test_twcc_send_and_recv); return s; } diff --git a/tests/check/elements/rtpssrcdemux.c b/tests/check/elements/rtpssrcdemux.c index 179d68e4fb..691fa41405 100644 --- a/tests/check/elements/rtpssrcdemux.c +++ b/tests/check/elements/rtpssrcdemux.c @@ -2,6 +2,8 @@ * * Copyright (C) 2018 Collabora Ltd. * Author: Nicolas Dufresne + * Copyright (C) 2019 Pexip + * Author: Havard Graff * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -102,7 +104,7 @@ rtpssrcdemux_pad_added (G_GNUC_UNUSED GstElement * demux, GstPad * src_pad, GST_START_TEST (test_event_forwarding) { - TestContext ctx = { NULL, }; + TestContext ctx = { NULL, NULL, NULL, NULL }; GstHarness *h; GstEvent *event; GstCaps *caps; @@ -182,8 +184,8 @@ typedef struct } LockTestContext; static void -new_ssrc_pad_cb (GstElement * element, guint ssrc, GstPad * pad, - LockTestContext * ctx) +new_ssrc_pad_cb (G_GNUC_UNUSED GstElement * element, G_GNUC_UNUSED guint ssrc, + G_GNUC_UNUSED GstPad * pad, LockTestContext * ctx) { g_message ("Signalling ready"); g_atomic_int_set (&ctx->ready, 1); @@ -207,9 +209,10 @@ push_buffer_func (gpointer user_data) GST_START_TEST (test_oob_event_locking) { GstHarness *h = gst_harness_new_with_padnames ("rtpssrcdemux", "sink", NULL); - LockTestContext ctx = { FALSE, }; + LockTestContext ctx; GThread *thread; + memset (&ctx, 0, sizeof (LockTestContext)); g_mutex_init (&ctx.mutex); g_cond_init (&ctx.cond); @@ -240,6 +243,120 @@ GST_START_TEST (test_oob_event_locking) GST_END_TEST; + +static void +new_ssrc_pad_found (GstElement * element, G_GNUC_UNUSED guint ssrc, + GstPad * pad, GSList ** src_h) +{ + GstHarness *h = gst_harness_new_with_element (element, NULL, NULL); + gst_harness_add_element_src_pad (h, pad); + *src_h = g_slist_prepend (*src_h, h); +} + +GST_START_TEST (test_rtpssrcdemux_max_streams) +{ + GstHarness *h = gst_harness_new_with_padnames ("rtpssrcdemux", "sink", NULL); + GSList *src_h = NULL; + gint i; + + g_object_set (h->element, "max-streams", 64, NULL); + gst_harness_set_src_caps_str (h, "application/x-rtp"); + g_signal_connect (h->element, + "new-ssrc-pad", (GCallback) new_ssrc_pad_found, &src_h); + gst_harness_play (h); + + for (i = 0; i < 128; ++i) { + fail_unless_equals_int (GST_FLOW_OK, + gst_harness_push (h, create_buffer (0, i))); + } + + fail_unless_equals_int (g_slist_length (src_h), 64); + g_slist_free_full (src_h, (GDestroyNotify) gst_harness_teardown); + gst_harness_teardown (h); +} + +GST_END_TEST; + +static void +new_rtcp_ssrc_pad_found (GstElement * element, G_GNUC_UNUSED guint ssrc, + G_GNUC_UNUSED GstPad * rtp_pad, GSList ** src_h) +{ + GstHarness *h; + gchar *name; + + name = g_strdup_printf ("rtcp_src_%u", ssrc); + h = gst_harness_new_with_element (element, NULL, name); + g_free (name); + *src_h = g_slist_prepend (*src_h, h); +} + +GST_START_TEST (test_rtpssrcdemux_rtcp_app) +{ + GstHarness *h = + gst_harness_new_with_padnames ("rtpssrcdemux", "rtcp_sink", NULL); + GSList *src_h = NULL; + guint8 rtcp_app_pkt[] = { 0x81, 0xcc, 0x00, 0x05, 0x00, 0x00, 0x5d, 0xaf, + 0x20, 0x20, 0x20, 0x20, 0x21, 0x02, 0x00, 0x0a, + 0x00, 0x00, 0x5d, 0xaf, 0x00, 0x00, 0x16, 0x03 + }; + + gst_harness_set_src_caps_str (h, "application/x-rtcp"); + g_signal_connect (h->element, + "new-ssrc-pad", (GCallback) new_rtcp_ssrc_pad_found, &src_h); + gst_harness_play (h); + + fail_unless_equals_int (GST_FLOW_OK, + gst_harness_push (h, gst_buffer_new_wrapped_full (0, rtcp_app_pkt, + sizeof rtcp_app_pkt, 0, sizeof rtcp_app_pkt, NULL, NULL))); + + fail_unless_equals_int (g_slist_length (src_h), 1); + g_slist_free_full (src_h, (GDestroyNotify) gst_harness_teardown); + gst_harness_teardown (h); +} + +GST_END_TEST; + +GST_START_TEST (test_rtpssrcdemux_invalid_rtp) +{ + GstHarness *h = gst_harness_new_with_padnames ("rtpssrcdemux", "sink", NULL); + guint8 bad_pkt[] = { + 0x01, 0x02, 0x03 + }; + + gst_harness_set_src_caps_str (h, "application/x-rtp"); + gst_harness_play (h); + + fail_unless_equals_int (GST_FLOW_OK, + gst_harness_push (h, gst_buffer_new_wrapped_full (0, bad_pkt, + sizeof bad_pkt, 0, sizeof bad_pkt, NULL, NULL))); + + gst_harness_teardown (h); +} + +GST_END_TEST; + +GST_START_TEST (test_rtpssrcdemux_invalid_rtcp) +{ + GstHarness *h = + gst_harness_new_with_padnames ("rtpssrcdemux", "rtcp_sink", NULL); + guint8 bad_pkt[] = { + 0x01, 0x02, 0x03 + }; + + gst_harness_set_src_caps_str (h, "application/x-rtcp"); + gst_harness_play (h); + + fail_unless_equals_int (GST_FLOW_OK, + gst_harness_push (h, gst_buffer_new_wrapped_full (0, bad_pkt, + sizeof bad_pkt, 0, sizeof bad_pkt, NULL, NULL))); + + gst_harness_teardown (h); +} + +GST_END_TEST; + + + static Suite * rtpssrcdemux_suite (void) { @@ -249,6 +366,10 @@ rtpssrcdemux_suite (void) suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_event_forwarding); tcase_add_test (tc_chain, test_oob_event_locking); + tcase_add_test (tc_chain, test_rtpssrcdemux_max_streams); + tcase_add_test (tc_chain, test_rtpssrcdemux_rtcp_app); + tcase_add_test (tc_chain, test_rtpssrcdemux_invalid_rtp); + tcase_add_test (tc_chain, test_rtpssrcdemux_invalid_rtcp); return s; } diff --git a/tests/check/elements/rtptimerqueue.c b/tests/check/elements/rtptimerqueue.c new file mode 100644 index 0000000000..a39da7f91f --- /dev/null +++ b/tests/check/elements/rtptimerqueue.c @@ -0,0 +1,330 @@ +/* GStreamer + * + * Copyright (C) 2019 Net Insight AB + * Author: Nicolas Dufresne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include "gst/rtpmanager/rtptimerqueue.h" + +GST_START_TEST (test_timer_queue_set_timer) +{ + RtpTimerQueue *queue = rtp_timer_queue_new (); + RtpTimer *timer10, *timer0; + + rtp_timer_queue_set_timer (queue, RTP_TIMER_EXPECTED, 10, + 1 * GST_SECOND, 2 * GST_SECOND, 5 * GST_SECOND, 0); + timer10 = rtp_timer_queue_find (queue, 10); + fail_unless (timer10); + fail_unless_equals_int (10, timer10->seqnum); + fail_unless_equals_int (RTP_TIMER_EXPECTED, timer10->type); + /* timer10->timeout = timerout + delay */ + fail_unless_equals_uint64 (3 * GST_SECOND, timer10->timeout); + fail_unless_equals_uint64 (5 * GST_SECOND, timer10->duration); + fail_unless_equals_uint64 (1 * GST_SECOND, timer10->rtx_base); + fail_unless_equals_uint64 (2 * GST_SECOND, timer10->rtx_delay); + fail_unless_equals_uint64 (0, timer10->rtx_retry); + fail_unless_equals_uint64 (GST_CLOCK_TIME_NONE, timer10->rtx_last); + fail_unless_equals_int (0, timer10->num_rtx_retry); + fail_unless_equals_int (0, timer10->num_rtx_received); + + rtp_timer_queue_set_timer (queue, RTP_TIMER_LOST, 0, + 0 * GST_SECOND, 2 * GST_SECOND, 0, 0); + timer0 = rtp_timer_queue_find (queue, 0); + fail_unless (timer0); + fail_unless_equals_int (0, timer0->seqnum); + fail_unless_equals_int (RTP_TIMER_LOST, timer0->type); + fail_unless_equals_uint64 (2 * GST_SECOND, timer0->timeout); + fail_unless_equals_uint64 (0, timer0->duration); + fail_unless_equals_uint64 (0, timer0->rtx_base); + fail_unless_equals_uint64 (0, timer0->rtx_delay); + fail_unless_equals_uint64 (0, timer0->rtx_retry); + fail_unless_equals_uint64 (GST_CLOCK_TIME_NONE, timer0->rtx_last); + fail_unless_equals_int (0, timer0->num_rtx_retry); + fail_unless_equals_int (0, timer0->num_rtx_received); + + /* also check order while at it */ + fail_unless (timer10->list.next == NULL); + fail_unless (timer10->list.prev == (GList *) timer0); + fail_unless (timer0->list.next == (GList *) timer10); + fail_unless (timer0->list.prev == NULL); + + g_object_unref (queue); +} + +GST_END_TEST; + +GST_START_TEST (test_timer_queue_insert_head) +{ + RtpTimerQueue *queue = rtp_timer_queue_new (); + RtpTimer *timer, *next, *prev; + + rtp_timer_queue_set_deadline (queue, 1, -1, 0); + rtp_timer_queue_set_deadline (queue, 3, -1, 0); + rtp_timer_queue_set_deadline (queue, 2, -1, 0); + rtp_timer_queue_set_deadline (queue, 0, -1, 0); + + timer = rtp_timer_queue_find (queue, 0); + fail_if (timer == NULL); + fail_unless_equals_int (0, timer->seqnum); + next = (RtpTimer *) timer->list.next; + prev = (RtpTimer *) timer->list.prev; + fail_unless (prev == NULL); + fail_if (next == NULL); + fail_unless_equals_int (1, next->seqnum); + + timer = rtp_timer_queue_find (queue, 3); + fail_if (timer == NULL); + fail_unless_equals_int (3, timer->seqnum); + next = (RtpTimer *) timer->list.next; + prev = (RtpTimer *) timer->list.prev; + fail_if (prev == NULL); + fail_unless_equals_int (2, prev->seqnum); + fail_unless (next == NULL); + + timer = rtp_timer_queue_find (queue, 2); + fail_if (timer == NULL); + fail_unless_equals_int (2, timer->seqnum); + next = (RtpTimer *) timer->list.next; + prev = (RtpTimer *) timer->list.prev; + fail_if (prev == NULL); + fail_if (next == NULL); + fail_unless_equals_int (1, prev->seqnum); + fail_unless_equals_int (3, next->seqnum); + + timer = rtp_timer_queue_find (queue, 1); + fail_if (timer == NULL); + fail_unless_equals_int (1, timer->seqnum); + next = (RtpTimer *) timer->list.next; + prev = (RtpTimer *) timer->list.prev; + fail_if (prev == NULL); + fail_if (next == NULL); + fail_unless_equals_int (0, prev->seqnum); + fail_unless_equals_int (2, next->seqnum); + + g_object_unref (queue); +} + +GST_END_TEST; + +GST_START_TEST (test_timer_queue_reschedule) +{ + RtpTimerQueue *queue = rtp_timer_queue_new (); + RtpTimer *timer, *next, *prev; + + rtp_timer_queue_set_deadline (queue, 3, 1 * GST_SECOND, 0); + rtp_timer_queue_set_deadline (queue, 1, 2 * GST_SECOND, 0); + rtp_timer_queue_set_deadline (queue, 2, 3 * GST_SECOND, 0); + rtp_timer_queue_set_deadline (queue, 0, 4 * GST_SECOND, 0); + + timer = rtp_timer_queue_find (queue, 1); + fail_if (timer == NULL); + + /* move to head, making sure seqnum order is respected */ + rtp_timer_queue_set_deadline (queue, 1, 1 * GST_SECOND, 0); + next = (RtpTimer *) timer->list.next; + prev = (RtpTimer *) timer->list.prev; + fail_unless (prev == NULL); + fail_if (next == NULL); + fail_unless_equals_int (3, next->seqnum); + + /* move head back */ + rtp_timer_queue_set_deadline (queue, 1, 2 * GST_SECOND, 0); + next = (RtpTimer *) timer->list.next; + prev = (RtpTimer *) timer->list.prev; + fail_if (prev == NULL); + fail_if (next == NULL); + fail_unless_equals_int (3, prev->seqnum); + fail_unless_equals_int (2, next->seqnum); + + /* move to tail */ + timer = rtp_timer_queue_find (queue, 2); + fail_if (timer == NULL); + rtp_timer_queue_set_deadline (queue, 2, 4 * GST_SECOND, 0); + next = (RtpTimer *) timer->list.next; + prev = (RtpTimer *) timer->list.prev; + fail_if (prev == NULL); + fail_unless (next == NULL); + fail_unless_equals_int (0, prev->seqnum); + + /* move tail back */ + rtp_timer_queue_set_deadline (queue, 2, 3 * GST_SECOND, 0); + next = (RtpTimer *) timer->list.next; + prev = (RtpTimer *) timer->list.prev; + fail_if (prev == NULL); + fail_if (next == NULL); + fail_unless_equals_int (1, prev->seqnum); + fail_unless_equals_int (0, next->seqnum); + + /* not moving toward head */ + rtp_timer_queue_set_deadline (queue, 2, 2 * GST_SECOND, 0); + next = (RtpTimer *) timer->list.next; + prev = (RtpTimer *) timer->list.prev; + fail_if (prev == NULL); + fail_if (next == NULL); + fail_unless_equals_int (1, prev->seqnum); + fail_unless_equals_int (0, next->seqnum); + + /* not moving toward tail */ + rtp_timer_queue_set_deadline (queue, 2, 3 * GST_SECOND, 0); + next = (RtpTimer *) timer->list.next; + prev = (RtpTimer *) timer->list.prev; + fail_if (prev == NULL); + fail_if (next == NULL); + fail_unless_equals_int (1, prev->seqnum); + fail_unless_equals_int (0, next->seqnum); + + /* inner move toward head */ + rtp_timer_queue_set_deadline (queue, 2, GST_SECOND + GST_SECOND / 2, 0); + next = (RtpTimer *) timer->list.next; + prev = (RtpTimer *) timer->list.prev; + fail_if (prev == NULL); + fail_if (next == NULL); + fail_unless_equals_int (3, prev->seqnum); + fail_unless_equals_int (1, next->seqnum); + + /* inner move toward tail */ + rtp_timer_queue_set_deadline (queue, 2, 3 * GST_SECOND, 0); + next = (RtpTimer *) timer->list.next; + prev = (RtpTimer *) timer->list.prev; + fail_if (prev == NULL); + fail_if (next == NULL); + fail_unless_equals_int (1, prev->seqnum); + fail_unless_equals_int (0, next->seqnum); + + g_object_unref (queue); +} + +GST_END_TEST; + +GST_START_TEST (test_timer_queue_pop_until) +{ + RtpTimerQueue *queue = rtp_timer_queue_new (); + RtpTimer *timer; + + rtp_timer_queue_set_deadline (queue, 2, 2 * GST_SECOND, 0); + rtp_timer_queue_set_deadline (queue, 1, 1 * GST_SECOND, 0); + rtp_timer_queue_set_deadline (queue, 0, -1, 0); + + timer = rtp_timer_queue_pop_until (queue, 1 * GST_SECOND); + fail_if (timer == NULL); + fail_unless_equals_int (0, timer->seqnum); + rtp_timer_free (timer); + + timer = rtp_timer_queue_pop_until (queue, 1 * GST_SECOND); + fail_if (timer == NULL); + fail_unless_equals_int (1, timer->seqnum); + rtp_timer_free (timer); + + timer = rtp_timer_queue_pop_until (queue, 1 * GST_SECOND); + fail_unless (timer == NULL); + + g_object_unref (queue); +} + +GST_END_TEST; + +GST_START_TEST (test_timer_queue_update_timer_seqnum) +{ + RtpTimerQueue *queue = rtp_timer_queue_new (); + RtpTimer *timer; + + rtp_timer_queue_set_deadline (queue, 2, 2 * GST_SECOND, 0); + + timer = rtp_timer_queue_find (queue, 2); + fail_if (timer == NULL); + + rtp_timer_queue_update_timer (queue, timer, 3, 3 * GST_SECOND, 0, 0, FALSE); + + timer = rtp_timer_queue_find (queue, 2); + fail_unless (timer == NULL); + timer = rtp_timer_queue_find (queue, 3); + fail_if (timer == NULL); + + fail_unless_equals_int (1, rtp_timer_queue_length (queue)); + + g_object_unref (queue); +} + +GST_END_TEST; + +GST_START_TEST (test_timer_queue_dup_timer) +{ + RtpTimerQueue *queue = rtp_timer_queue_new (); + RtpTimer *timer; + + rtp_timer_queue_set_deadline (queue, 2, 2 * GST_SECOND, 0); + + timer = rtp_timer_queue_find (queue, 2); + fail_if (timer == NULL); + + timer = rtp_timer_dup (timer); + timer->seqnum = 3; + rtp_timer_queue_insert (queue, timer); + + fail_unless_equals_int (2, rtp_timer_queue_length (queue)); + + g_object_unref (queue); +} + +GST_END_TEST; + +GST_START_TEST (test_timer_queue_timer_offset) +{ + RtpTimerQueue *queue = rtp_timer_queue_new (); + RtpTimer *timer; + + rtp_timer_queue_set_timer (queue, RTP_TIMER_EXPECTED, 2, 2 * GST_SECOND, + GST_MSECOND, 0, GST_USECOND); + + timer = rtp_timer_queue_find (queue, 2); + fail_if (timer == NULL); + fail_unless_equals_uint64 (2 * GST_SECOND + GST_MSECOND + GST_USECOND, + timer->timeout); + fail_unless_equals_int64 (GST_USECOND, timer->offset); + + rtp_timer_queue_update_timer (queue, timer, 2, 3 * GST_SECOND, + 2 * GST_MSECOND, 2 * GST_USECOND, FALSE); + fail_unless_equals_uint64 (3 * GST_SECOND + 2 * GST_MSECOND + + 2 * GST_USECOND, timer->timeout); + fail_unless_equals_int64 (2 * GST_USECOND, timer->offset); + + g_object_unref (queue); +} + +GST_END_TEST; + +static Suite * +rtptimerqueue_suite (void) +{ + Suite *s = suite_create ("rtptimerqueue"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_timer_queue_set_timer); + tcase_add_test (tc_chain, test_timer_queue_insert_head); + tcase_add_test (tc_chain, test_timer_queue_reschedule); + tcase_add_test (tc_chain, test_timer_queue_pop_until); + tcase_add_test (tc_chain, test_timer_queue_update_timer_seqnum); + tcase_add_test (tc_chain, test_timer_queue_dup_timer); + tcase_add_test (tc_chain, test_timer_queue_timer_offset); + + return s; +} + +GST_CHECK_MAIN (rtptimerqueue); diff --git a/tests/check/elements/splitmuxsink.c b/tests/check/elements/splitmuxsink.c new file mode 100644 index 0000000000..2ff892a736 --- /dev/null +++ b/tests/check/elements/splitmuxsink.c @@ -0,0 +1,851 @@ +/* GStreamer unit test for splitmuxsink elements + * + * Copyright (C) 2007 David A. Schleef + * Copyright (C) 2015 Jan Schmidt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include +#include +#include +#include + +gchar *tmpdir = NULL; +GstClockTime first_ts; +GstClockTime last_ts; +gdouble current_rate; + +static void +tempdir_setup (void) +{ + const gchar *systmp = g_get_tmp_dir (); + tmpdir = g_build_filename (systmp, "splitmux-test-XXXXXX", NULL); + /* Rewrites tmpdir template input: */ + tmpdir = g_mkdtemp (tmpdir); +} + +static void +tempdir_cleanup (void) +{ + GDir *d; + const gchar *f; + + fail_if (tmpdir == NULL); + + d = g_dir_open (tmpdir, 0, NULL); + fail_if (d == NULL); + + while ((f = g_dir_read_name (d)) != NULL) { + gchar *fname = g_build_filename (tmpdir, f, NULL); + fail_if (g_remove (fname) != 0, "Failed to remove tmp file %s", fname); + g_free (fname); + } + g_dir_close (d); + + fail_if (g_remove (tmpdir) != 0, "Failed to delete tmpdir %s", tmpdir); + + g_free (tmpdir); + tmpdir = NULL; +} + +static guint +count_files (const gchar * target) +{ + GDir *d; + const gchar *f; + guint ret = 0; + + d = g_dir_open (target, 0, NULL); + fail_if (d == NULL); + + while ((f = g_dir_read_name (d)) != NULL) + ret++; + g_dir_close (d); + + return ret; +} + +static void +dump_error (GstMessage * msg) +{ + GError *err = NULL; + gchar *dbg_info; + + fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR); + + gst_message_parse_error (msg, &err, &dbg_info); + + g_printerr ("ERROR from element %s: %s\n", + GST_OBJECT_NAME (msg->src), err->message); + g_printerr ("Debugging info: %s\n", (dbg_info) ? dbg_info : "none"); + g_error_free (err); + g_free (dbg_info); +} + +static GstMessage * +run_pipeline (GstElement * pipeline) +{ + GstBus *bus = gst_element_get_bus (GST_ELEMENT (pipeline)); + GstMessage *msg; + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + msg = gst_bus_poll (bus, GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1); + gst_element_set_state (pipeline, GST_STATE_NULL); + + gst_object_unref (bus); + + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) + dump_error (msg); + + return msg; +} + +static void +seek_pipeline (GstElement * pipeline, gdouble rate, GstClockTime start, + GstClockTime end) +{ + /* Pause the pipeline, seek to the desired range / rate, wait for PAUSED again, then + * clear the tracking vars for start_ts / end_ts */ + gst_element_set_state (pipeline, GST_STATE_PAUSED); + gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE); + + /* specific end time not implemented: */ + fail_unless (end == GST_CLOCK_TIME_NONE); + + gst_element_seek (pipeline, rate, GST_FORMAT_TIME, + GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, start, + GST_SEEK_TYPE_END, 0); + + /* Wait for the pipeline to preroll again */ + gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE); + + GST_LOG ("Seeked pipeline. Rate %f time range %" GST_TIME_FORMAT " to %" + GST_TIME_FORMAT, rate, GST_TIME_ARGS (start), GST_TIME_ARGS (end)); + + /* Clear tracking variables now that the seek is complete */ + first_ts = last_ts = GST_CLOCK_TIME_NONE; + current_rate = rate; +}; + +static GstFlowReturn +receive_sample (GstAppSink * appsink, gpointer user_data) +{ + GstSample *sample; + GstSegment *seg; + GstBuffer *buf; + GstClockTime start; + GstClockTime end; + + g_signal_emit_by_name (appsink, "pull-sample", &sample); + fail_unless (sample != NULL); + + seg = gst_sample_get_segment (sample); + fail_unless (seg != NULL); + + buf = gst_sample_get_buffer (sample); + fail_unless (buf != NULL); + + GST_LOG ("Got buffer %" GST_PTR_FORMAT, buf); + + start = GST_BUFFER_PTS (buf); + end = start; + + if (GST_CLOCK_TIME_IS_VALID (start)) + start = gst_segment_to_stream_time (seg, GST_FORMAT_TIME, start); + + if (GST_CLOCK_TIME_IS_VALID (end)) { + if (GST_BUFFER_DURATION_IS_VALID (buf)) + end += GST_BUFFER_DURATION (buf); + + end = gst_segment_to_stream_time (seg, GST_FORMAT_TIME, end); + } + + GST_DEBUG ("Got buffer stream time %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT, + GST_TIME_ARGS (start), GST_TIME_ARGS (end)); + + /* Check time is moving in the right direction */ + if (current_rate > 0) { + if (GST_CLOCK_TIME_IS_VALID (first_ts)) + fail_unless (start >= first_ts, + "Timestamps went backward during forward play, %" GST_TIME_FORMAT + " < %" GST_TIME_FORMAT, GST_TIME_ARGS (start), + GST_TIME_ARGS (first_ts)); + if (GST_CLOCK_TIME_IS_VALID (last_ts)) + fail_unless (end >= last_ts, + "Timestamps went backward during forward play, %" GST_TIME_FORMAT + " < %" GST_TIME_FORMAT, GST_TIME_ARGS (end), GST_TIME_ARGS (last_ts)); + } else { + fail_unless (start <= first_ts, + "Timestamps went forward during reverse play, %" GST_TIME_FORMAT " > %" + GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (first_ts)); + fail_unless (end <= last_ts, + "Timestamps went forward during reverse play, %" GST_TIME_FORMAT " > %" + GST_TIME_FORMAT, GST_TIME_ARGS (end), GST_TIME_ARGS (last_ts)); + } + + /* update the range of timestamps we've encountered */ + if (!GST_CLOCK_TIME_IS_VALID (first_ts) || start < first_ts) + first_ts = start; + if (!GST_CLOCK_TIME_IS_VALID (last_ts) || end > last_ts) + last_ts = end; + + gst_sample_unref (sample); + + if (user_data) { + guint *num_frame = (guint *) user_data; + + *num_frame = *num_frame + 1; + } + + return GST_FLOW_OK; +} + +static void +test_playback (const gchar * in_pattern, GstClockTime exp_first_time, + GstClockTime exp_last_time, gboolean test_reverse) +{ + GstMessage *msg; + GstElement *pipeline; + GstElement *appsink; + GstElement *fakesink2; + GstAppSinkCallbacks callbacks = { NULL }; + gchar *uri; + + GST_DEBUG ("Playing back files matching %s", in_pattern); + + pipeline = gst_element_factory_make ("playbin", NULL); + fail_if (pipeline == NULL); + + appsink = gst_element_factory_make ("appsink", NULL); + fail_if (appsink == NULL); + g_object_set (G_OBJECT (appsink), "sync", FALSE, NULL); + + g_object_set (G_OBJECT (pipeline), "video-sink", appsink, NULL); + fakesink2 = gst_element_factory_make ("fakesink", NULL); + fail_if (fakesink2 == NULL); + g_object_set (G_OBJECT (pipeline), "audio-sink", fakesink2, NULL); + + uri = g_strdup_printf ("splitmux://%s", in_pattern); + + g_object_set (G_OBJECT (pipeline), "uri", uri, NULL); + g_free (uri); + + callbacks.new_sample = receive_sample; + gst_app_sink_set_callbacks (GST_APP_SINK (appsink), &callbacks, NULL, NULL); + + /* test forwards */ + seek_pipeline (pipeline, 1.0, 0, -1); + fail_unless (first_ts == GST_CLOCK_TIME_NONE); + msg = run_pipeline (pipeline); + fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS); + gst_message_unref (msg); + + /* Check we saw the entire range of values */ + fail_unless (first_ts == exp_first_time, + "Expected start of playback range %" GST_TIME_FORMAT ", got %" + GST_TIME_FORMAT, GST_TIME_ARGS (exp_first_time), + GST_TIME_ARGS (first_ts)); + fail_unless (last_ts == exp_last_time, + "Expected end of playback range %" GST_TIME_FORMAT ", got %" + GST_TIME_FORMAT, GST_TIME_ARGS (exp_last_time), GST_TIME_ARGS (last_ts)); + + if (test_reverse) { + /* Test backwards */ + seek_pipeline (pipeline, -1.0, 0, -1); + msg = run_pipeline (pipeline); + fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS); + gst_message_unref (msg); + /* Check we saw the entire range of values */ + fail_unless (first_ts == exp_first_time, + "Expected start of playback range %" GST_TIME_FORMAT + ", got %" GST_TIME_FORMAT, GST_TIME_ARGS (exp_first_time), + GST_TIME_ARGS (first_ts)); + fail_unless (last_ts == exp_last_time, + "Expected end of playback range %" GST_TIME_FORMAT + ", got %" GST_TIME_FORMAT, GST_TIME_ARGS (exp_last_time), + GST_TIME_ARGS (last_ts)); + } + + gst_object_unref (pipeline); +} + +struct splitmux_location_state +{ + GstElement *splitmuxsink; + gboolean got_format_location; + gboolean fragment_opened; + gchar *current_location; +}; + +static gchar * +check_format_location (GstElement * object, + guint fragment_id, GstSample * first_sample, + struct splitmux_location_state *location_state) +{ + GstBuffer *buf = gst_sample_get_buffer (first_sample); + + /* Must have a buffer */ + fail_if (buf == NULL); + GST_LOG ("New file - first buffer %" GST_TIME_FORMAT, + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); + + if (location_state) { + fail_unless (location_state->got_format_location == FALSE, + "Got format-location signal twice without an intervening splitmuxsink-fragment-closed"); + location_state->got_format_location = TRUE; + } + + return NULL; +} + +static GstBusSyncReply +bus_sync_handler (GstBus * bus, GstMessage * message, + struct splitmux_location_state *location_state) +{ + switch (message->type) { + case GST_MESSAGE_ELEMENT: + { + const GstStructure *s = gst_message_get_structure (message); + if (message->src == GST_OBJECT_CAST (location_state->splitmuxsink)) { + if (gst_structure_has_name (s, "splitmuxsink-fragment-opened")) { + const gchar *location = gst_structure_get_string (s, "location"); + fail_unless (location != NULL); + fail_unless (location_state->got_format_location == TRUE, + "Failed to get format-location before fragment start"); + fail_unless (location_state->fragment_opened == FALSE); + location_state->fragment_opened = TRUE; + + /* The location must be different to last time */ + fail_unless (location_state->current_location == NULL + || !g_str_equal (location_state->current_location, location)); + g_free (location_state->current_location); + location_state->current_location = g_strdup (location); + + } else if (gst_structure_has_name (s, "splitmuxsink-fragment-closed")) { + fail_unless (location_state->got_format_location == TRUE); + fail_unless (location_state->fragment_opened == TRUE); + location_state->got_format_location = FALSE; /* We need another format-location before the next open */ + location_state->fragment_opened = FALSE; + } + } + break; + } + default: + break; + } + + return GST_BUS_PASS; +} + +GST_START_TEST (test_splitmuxsink) +{ + GstMessage *msg; + GstElement *pipeline; + GstElement *sink; + GstPad *splitmux_sink_pad; + GstPad *enc_src_pad; + gchar *dest_pattern; + guint count; + gchar *in_pattern; + struct splitmux_location_state location_state = { NULL, FALSE, FALSE, NULL }; + GstBus *bus; + + /* This pipeline has a small time cutoff - it should start a new file + * every GOP, ie 1 second */ + pipeline = + gst_parse_launch + ("videotestsrc num-buffers=15 ! video/x-raw,width=80,height=64,framerate=5/1 ! videoconvert !" + " queue ! theoraenc keyframe-force=5 ! splitmuxsink name=splitsink " + " max-size-time=1000000 max-size-bytes=1000000 muxer=oggmux", NULL); + fail_if (pipeline == NULL); + location_state.splitmuxsink = sink = + gst_bin_get_by_name (GST_BIN (pipeline), "splitsink"); + fail_if (sink == NULL); + g_signal_connect (sink, "format-location-full", + (GCallback) check_format_location, &location_state); + + dest_pattern = g_build_filename (tmpdir, "out%05d.ogg", NULL); + g_object_set (G_OBJECT (sink), "location", dest_pattern, NULL); + g_free (dest_pattern); + g_object_unref (sink); + + bus = gst_element_get_bus (pipeline); + gst_bus_set_sync_handler (bus, (GstBusSyncHandler) bus_sync_handler, + &location_state, NULL); + gst_object_unref (bus); + + msg = run_pipeline (pipeline); + + /* Clean up the location state */ + g_free (location_state.current_location); + + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) + dump_error (msg); + fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS); + gst_message_unref (msg); + + /* unlink manually and release request pad to ensure that we *can* do that + * - https://bugzilla.gnome.org/show_bug.cgi?id=753622 */ + sink = gst_bin_get_by_name (GST_BIN (pipeline), "splitsink"); + fail_if (sink == NULL); + splitmux_sink_pad = gst_element_get_static_pad (sink, "video"); + fail_if (splitmux_sink_pad == NULL); + enc_src_pad = gst_pad_get_peer (splitmux_sink_pad); + fail_if (enc_src_pad == NULL); + fail_unless (gst_pad_unlink (enc_src_pad, splitmux_sink_pad)); + gst_object_unref (enc_src_pad); + gst_element_release_request_pad (sink, splitmux_sink_pad); + gst_object_unref (splitmux_sink_pad); + /* at this point the pad must be released - try to find it again to verify */ + splitmux_sink_pad = gst_element_get_static_pad (sink, "video"); + fail_if (splitmux_sink_pad != NULL); + g_object_unref (sink); + + gst_object_unref (pipeline); + + count = count_files (tmpdir); + fail_unless (count == 3, "Expected 3 output files, got %d", count); + + in_pattern = g_build_filename (tmpdir, "out*.ogg", NULL); + test_playback (in_pattern, 0, 3 * GST_SECOND, TRUE); + g_free (in_pattern); +} + +GST_END_TEST; + +GST_START_TEST (test_splitmuxsink_multivid) +{ + GstMessage *msg; + GstElement *pipeline; + GstElement *sink; + gchar *dest_pattern; + guint count; + gchar *in_pattern; + + /* This pipeline should start a new file every GOP, ie 1 second, + * driven by the primary video stream and with 2 auxiliary video streams */ + pipeline = + gst_parse_launch + ("splitmuxsink name=splitsink " + " max-size-time=1000000 max-size-bytes=1000000 muxer=qtmux " + "videotestsrc num-buffers=15 ! video/x-raw,width=80,height=64,framerate=5/1 ! videoconvert !" + " queue ! vp8enc keyframe-max-dist=5 ! splitsink.video " + "videotestsrc num-buffers=15 pattern=snow ! video/x-raw,width=80,height=64,framerate=5/1 ! videoconvert !" + " queue ! vp8enc keyframe-max-dist=6 ! splitsink.video_aux_0 " + "videotestsrc num-buffers=15 pattern=ball ! video/x-raw,width=80,height=64,framerate=5/1 ! videoconvert !" + " queue ! vp8enc keyframe-max-dist=8 ! splitsink.video_aux_1 ", NULL); + fail_if (pipeline == NULL); + sink = gst_bin_get_by_name (GST_BIN (pipeline), "splitsink"); + fail_if (sink == NULL); + g_signal_connect (sink, "format-location-full", + (GCallback) check_format_location, NULL); + dest_pattern = g_build_filename (tmpdir, "out%05d.m4v", NULL); + g_object_set (G_OBJECT (sink), "location", dest_pattern, NULL); + g_free (dest_pattern); + g_object_unref (sink); + + msg = run_pipeline (pipeline); + + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) + dump_error (msg); + fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS); + gst_message_unref (msg); + + gst_object_unref (pipeline); + + count = count_files (tmpdir); + fail_unless (count == 3, "Expected 3 output files, got %d", count); + + in_pattern = g_build_filename (tmpdir, "out*.m4v", NULL); + /* FIXME: Reverse playback works poorly with multiple video streams + * in qtdemux (at least, maybe other demuxers) at the time this was + * written, and causes test failures like buffers being output + * multiple times by qtdemux as it loops through GOPs. Disable that + * for now */ + test_playback (in_pattern, 0, 3 * GST_SECOND, FALSE); + g_free (in_pattern); +} + +GST_END_TEST; + +GST_START_TEST (test_splitmuxsink_async) +{ + GstMessage *msg; + GstElement *pipeline; + GstElement *sink; + GstPad *splitmux_sink_pad; + GstPad *enc_src_pad; + gchar *dest_pattern; + guint count; + gchar *in_pattern; + + pipeline = + gst_parse_launch + ("videotestsrc num-buffers=15 ! video/x-raw,width=80,height=64,framerate=5/1 ! videoconvert !" + " queue ! theoraenc keyframe-force=5 ! splitmuxsink name=splitsink " + " max-size-time=1000000000 async-finalize=true " + " muxer-factory=matroskamux audiotestsrc num-buffers=15 samplesperbuffer=9600 ! " + " audio/x-raw,rate=48000 ! splitsink.audio_%u", NULL); + fail_if (pipeline == NULL); + sink = gst_bin_get_by_name (GST_BIN (pipeline), "splitsink"); + fail_if (sink == NULL); + g_signal_connect (sink, "format-location-full", + (GCallback) check_format_location, NULL); + dest_pattern = g_build_filename (tmpdir, "matroska%05d.mkv", NULL); + g_object_set (G_OBJECT (sink), "location", dest_pattern, NULL); + g_free (dest_pattern); + g_object_unref (sink); + + msg = run_pipeline (pipeline); + + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) + dump_error (msg); + fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS); + gst_message_unref (msg); + + /* unlink manually and release request pad to ensure that we *can* do that + * - https://bugzilla.gnome.org/show_bug.cgi?id=753622 */ + sink = gst_bin_get_by_name (GST_BIN (pipeline), "splitsink"); + fail_if (sink == NULL); + splitmux_sink_pad = gst_element_get_static_pad (sink, "video"); + fail_if (splitmux_sink_pad == NULL); + enc_src_pad = gst_pad_get_peer (splitmux_sink_pad); + fail_if (enc_src_pad == NULL); + fail_unless (gst_pad_unlink (enc_src_pad, splitmux_sink_pad)); + gst_object_unref (enc_src_pad); + gst_element_release_request_pad (sink, splitmux_sink_pad); + gst_object_unref (splitmux_sink_pad); + /* at this point the pad must be released - try to find it again to verify */ + splitmux_sink_pad = gst_element_get_static_pad (sink, "video"); + fail_if (splitmux_sink_pad != NULL); + g_object_unref (sink); + + gst_object_unref (pipeline); + + count = count_files (tmpdir); + fail_unless (count == 3, "Expected 3 output files, got %d", count); + + in_pattern = g_build_filename (tmpdir, "matroska*.mkv", NULL); + test_playback (in_pattern, 0, 3 * GST_SECOND, TRUE); + g_free (in_pattern); +} + +GST_END_TEST; + +/* For verifying bug https://bugzilla.gnome.org/show_bug.cgi?id=762893 */ +GST_START_TEST (test_splitmuxsink_reuse_simple) +{ + GstElement *sink; + GstPad *pad; + + sink = gst_element_factory_make ("splitmuxsink", NULL); + pad = gst_element_get_request_pad (sink, "video"); + fail_unless (pad != NULL); + g_object_set (sink, "location", "/dev/null", NULL); + + fail_unless (gst_element_set_state (sink, + GST_STATE_PLAYING) == GST_STATE_CHANGE_ASYNC); + fail_unless (gst_element_set_state (sink, + GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS); + fail_unless (gst_element_set_state (sink, + GST_STATE_PLAYING) == GST_STATE_CHANGE_ASYNC); + fail_unless (gst_element_set_state (sink, + GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS); + + gst_element_release_request_pad (sink, pad); + gst_object_unref (pad); + gst_object_unref (sink); +} + +GST_END_TEST; + +GST_START_TEST (test_splitmuxsink_muxer_pad_map) +{ + GstElement *sink, *muxer; + GstPad *muxpad; + GstPad *pad1 = NULL, *pad2 = NULL; + GstStructure *pad_map; + + pad_map = gst_structure_new ("x-pad-map", + "video", G_TYPE_STRING, "video_100", + "audio_0", G_TYPE_STRING, "audio_101", NULL); + + muxer = gst_element_factory_make ("qtmux", NULL); + fail_if (muxer == NULL); + sink = gst_element_factory_make ("splitmuxsink", NULL); + fail_if (sink == NULL); + + g_object_set (sink, "muxer", muxer, "muxer-pad-map", pad_map, NULL); + gst_structure_free (pad_map); + + pad1 = gst_element_get_request_pad (sink, "video"); + fail_unless (g_str_equal ("video", GST_PAD_NAME (pad1))); + muxpad = gst_element_get_static_pad (muxer, "video_100"); + fail_unless (muxpad != NULL); + gst_object_unref (muxpad); + + pad2 = gst_element_get_request_pad (sink, "audio_0"); + fail_unless (g_str_equal ("audio_0", GST_PAD_NAME (pad2))); + muxpad = gst_element_get_static_pad (muxer, "audio_101"); + fail_unless (muxpad != NULL); + gst_object_unref (muxpad); + + g_object_set (sink, "location", "/dev/null", NULL); + + fail_unless (gst_element_set_state (sink, + GST_STATE_PLAYING) == GST_STATE_CHANGE_ASYNC); + fail_unless (gst_element_set_state (sink, + GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS); + + gst_element_release_request_pad (sink, pad1); + gst_object_unref (pad1); + gst_element_release_request_pad (sink, pad2); + gst_object_unref (pad2); + gst_object_unref (sink); +} + +GST_END_TEST; + +static GstPadProbeReturn +count_upstrea_fku (GstPad * pad, GstPadProbeInfo * info, + guint * upstream_fku_count) +{ + GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CUSTOM_UPSTREAM: + if (gst_video_event_is_force_key_unit (event)) + *upstream_fku_count += 1; + break; + default: + break; + } + + return GST_PAD_PROBE_OK; +} + +static void +splitmuxsink_split_by_keyframe (gboolean send_keyframe_request, + guint max_size_time_sec, guint encoder_key_interval_sec) +{ + GstMessage *msg; + GstElement *pipeline; + GstElement *sink; + GstElement *enc; + GstPad *srcpad; + gchar *pipeline_str; + gchar *dest_pattern; + guint count; + guint expected_count; + gchar *in_pattern; + guint upstream_fku_count = 0; + guint expected_fku_count; + + pipeline_str = g_strdup_printf ("splitmuxsink name=splitsink " + "max-size-time=%" G_GUINT64_FORMAT + " send-keyframe-requests=%s muxer=qtmux " + "videotestsrc num-buffers=30 ! video/x-raw,width=80,height=64,framerate=5/1 " + "! videoconvert ! queue ! vp8enc name=enc keyframe-max-dist=%d ! splitsink.video ", + max_size_time_sec * GST_SECOND, send_keyframe_request ? "true" : "false", + encoder_key_interval_sec * 5); + + pipeline = gst_parse_launch (pipeline_str, NULL); + g_free (pipeline_str); + + fail_if (pipeline == NULL); + sink = gst_bin_get_by_name (GST_BIN (pipeline), "splitsink"); + fail_if (sink == NULL); + g_signal_connect (sink, "format-location-full", + (GCallback) check_format_location, NULL); + dest_pattern = g_build_filename (tmpdir, "out%05d.m4v", NULL); + g_object_set (G_OBJECT (sink), "location", dest_pattern, NULL); + g_free (dest_pattern); + g_object_unref (sink); + + enc = gst_bin_get_by_name (GST_BIN (pipeline), "enc"); + fail_if (enc == NULL); + srcpad = gst_element_get_static_pad (enc, "src"); + fail_if (srcpad == NULL); + + gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, + (GstPadProbeCallback) count_upstrea_fku, &upstream_fku_count, NULL); + gst_object_unref (srcpad); + gst_object_unref (enc); + + msg = run_pipeline (pipeline); + + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) + dump_error (msg); + fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS); + gst_message_unref (msg); + + gst_object_unref (pipeline); + + count = count_files (tmpdir); + expected_count = 6 / max_size_time_sec; + fail_unless (count == expected_count, + "Expected %d output files, got %d", expected_count, count); + + if (!send_keyframe_request) { + expected_fku_count = 0; + } else { + expected_fku_count = count; + } + + GST_INFO ("Upstream force keyunit event count %d", upstream_fku_count); + + fail_unless (upstream_fku_count == expected_fku_count, + "Expected upstream force keyunit event count %d, got %d", + expected_fku_count, upstream_fku_count); + + in_pattern = g_build_filename (tmpdir, "out*.m4v", NULL); + /* FIXME: Reverse playback works poorly with multiple video streams + * in qtdemux (at least, maybe other demuxers) at the time this was + * written, and causes test failures like buffers being output + * multiple times by qtdemux as it loops through GOPs. Disable that + * for now */ + test_playback (in_pattern, 0, 6 * GST_SECOND, FALSE); + g_free (in_pattern); +} + +GST_START_TEST (test_splitmuxsink_without_keyframe_request) +{ + /* This encoding option is intended to produce keyframe per 1 seconds + * but splitmuxsink will split file per 2 second without keyframe request */ + splitmuxsink_split_by_keyframe (FALSE, 2, 1); +} + +GST_END_TEST; + +GST_START_TEST (test_splitmuxsink_keyframe_request) +{ + /* This encoding option is intended to produce keyframe per 2 seconds + * and splitmuxsink will request keyframe per 2 seconds as well. + * This should produce 2 seconds long files */ + splitmuxsink_split_by_keyframe (TRUE, 2, 2); +} + +GST_END_TEST; + +GST_START_TEST (test_splitmuxsink_keyframe_request_more) +{ + /* This encoding option is intended to produce keyframe per 2 seconds + * but splitmuxsink will request keyframe per 1 second. This should produce + * 1 second long files */ + splitmuxsink_split_by_keyframe (TRUE, 1, 2); +} + +GST_END_TEST; + +GST_START_TEST (test_splitmuxsink_keyframe_request_less) +{ + /* This encoding option is intended to produce keyframe per 1 second + * but splitmuxsink will request keyframe per 2 seconds. This should produce + * 2 seconds long files */ + splitmuxsink_split_by_keyframe (TRUE, 2, 1); +} + +GST_END_TEST; + +static Suite * +splitmuxsink_suite (void) +{ + Suite *s = suite_create ("splitmuxsink"); + TCase *tc_chain = tcase_create ("general"); + TCase *tc_chain_basic = tcase_create ("basic"); + TCase *tc_chain_complex = tcase_create ("complex"); + TCase *tc_chain_mp4_jpeg = tcase_create ("caps_change"); + TCase *tc_chain_keyframe_request = tcase_create ("keyframe_request"); + gboolean have_theora, have_ogg, have_vorbis, have_matroska, have_qtmux, + have_jpeg, have_vp8; + + /* we assume that if encoder/muxer are there, decoder/demuxer will be a well */ + have_theora = gst_registry_check_feature_version (gst_registry_get (), + "theoraenc", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0); + have_ogg = gst_registry_check_feature_version (gst_registry_get (), + "oggmux", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0); + have_vorbis = gst_registry_check_feature_version (gst_registry_get (), + "vorbisenc", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0); + have_matroska = gst_registry_check_feature_version (gst_registry_get (), + "matroskamux", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0); + have_qtmux = gst_registry_check_feature_version (gst_registry_get (), + "qtmux", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0); + have_jpeg = gst_registry_check_feature_version (gst_registry_get (), + "jpegenc", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0); + have_vp8 = gst_registry_check_feature_version (gst_registry_get (), + "vp8enc", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0); + + suite_add_tcase (s, tc_chain); + suite_add_tcase (s, tc_chain_basic); + suite_add_tcase (s, tc_chain_complex); + suite_add_tcase (s, tc_chain_mp4_jpeg); + suite_add_tcase (s, tc_chain_keyframe_request); + + tcase_add_test (tc_chain_basic, test_splitmuxsink_reuse_simple); + + if (have_theora && have_ogg) { + tcase_add_checked_fixture (tc_chain, tempdir_setup, tempdir_cleanup); + + tcase_add_test (tc_chain, test_splitmuxsink); + + if (have_matroska && have_vorbis) { + tcase_add_checked_fixture (tc_chain_complex, tempdir_setup, + tempdir_cleanup); + + tcase_add_test (tc_chain, test_splitmuxsink_async); + } else { + GST_INFO ("Skipping tests, missing plugins: matroska and/or vorbis"); + } + } else { + GST_INFO ("Skipping tests, missing plugins: theora and/or ogg"); + } + + + if (have_qtmux && have_jpeg) { + tcase_add_checked_fixture (tc_chain_mp4_jpeg, tempdir_setup, + tempdir_cleanup); + tcase_add_test (tc_chain_mp4_jpeg, test_splitmuxsink_muxer_pad_map); + } else { + GST_INFO ("Skipping tests, missing plugins: jpegenc or mp4mux"); + } + + if (have_qtmux && have_vp8) { + tcase_add_checked_fixture (tc_chain_keyframe_request, tempdir_setup, + tempdir_cleanup); + tcase_add_test (tc_chain_keyframe_request, test_splitmuxsink_multivid); + tcase_add_test (tc_chain_keyframe_request, + test_splitmuxsink_without_keyframe_request); + tcase_add_test (tc_chain_keyframe_request, + test_splitmuxsink_keyframe_request); + tcase_add_test (tc_chain_keyframe_request, + test_splitmuxsink_keyframe_request_more); + tcase_add_test (tc_chain_keyframe_request, + test_splitmuxsink_keyframe_request_less); + } else { + GST_INFO ("Skipping tests, missing plugins: vp8enc or mp4mux"); + } + + return s; +} + +GST_CHECK_MAIN (splitmuxsink); diff --git a/tests/check/elements/splitmuxsinktimecode.c b/tests/check/elements/splitmuxsinktimecode.c new file mode 100644 index 0000000000..882b48520d --- /dev/null +++ b/tests/check/elements/splitmuxsinktimecode.c @@ -0,0 +1,838 @@ +/* GStreamer unit test for splitmuxsink elements + * + * Copyright (C) 2007 David A. Schleef + * Copyright (C) 2015 Jan Schmidt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_VALGRIND +# include +#else +#define RUNNING_ON_VALGRIND FALSE +#endif + +#include + +#include +#include +#include +#include + +gchar *tmpdir = NULL; +GstClockTime first_ts; +GstClockTime last_ts; +gdouble current_rate; + +static void +tempdir_setup (void) +{ + const gchar *systmp = g_get_tmp_dir (); + tmpdir = g_build_filename (systmp, "splitmux-timecode-test-XXXXXX", NULL); + /* Rewrites tmpdir template input: */ + tmpdir = g_mkdtemp (tmpdir); +} + +static void +tempdir_cleanup (void) +{ + GDir *d; + const gchar *f; + + fail_if (tmpdir == NULL); + + d = g_dir_open (tmpdir, 0, NULL); + fail_if (d == NULL); + + while ((f = g_dir_read_name (d)) != NULL) { + gchar *fname = g_build_filename (tmpdir, f, NULL); + fail_if (g_remove (fname) != 0, "Failed to remove tmp file %s", fname); + g_free (fname); + } + g_dir_close (d); + + fail_if (g_remove (tmpdir) != 0, "Failed to delete tmpdir %s", tmpdir); + + g_free (tmpdir); + tmpdir = NULL; +} + +static guint +count_files (const gchar * target) +{ + GDir *d; + const gchar *f; + guint ret = 0; + + d = g_dir_open (target, 0, NULL); + fail_if (d == NULL); + + while ((f = g_dir_read_name (d)) != NULL) + ret++; + g_dir_close (d); + + return ret; +} + +static void +dump_error (GstMessage * msg) +{ + GError *err = NULL; + gchar *dbg_info; + + fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR); + + gst_message_parse_error (msg, &err, &dbg_info); + + g_printerr ("ERROR from element %s: %s\n", + GST_OBJECT_NAME (msg->src), err->message); + g_printerr ("Debugging info: %s\n", (dbg_info) ? dbg_info : "none"); + g_error_free (err); + g_free (dbg_info); +} + +static GstMessage * +run_pipeline (GstElement * pipeline) +{ + GstBus *bus = gst_element_get_bus (GST_ELEMENT (pipeline)); + GstMessage *msg; + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + msg = gst_bus_poll (bus, GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1); + gst_element_set_state (pipeline, GST_STATE_NULL); + + gst_object_unref (bus); + + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) + dump_error (msg); + + return msg; +} + +static void +seek_pipeline (GstElement * pipeline, gdouble rate, GstClockTime start, + GstClockTime end) +{ + /* Pause the pipeline, seek to the desired range / rate, wait for PAUSED again, then + * clear the tracking vars for start_ts / end_ts */ + gst_element_set_state (pipeline, GST_STATE_PAUSED); + gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE); + + /* specific end time not implemented: */ + fail_unless (end == GST_CLOCK_TIME_NONE); + + gst_element_seek (pipeline, rate, GST_FORMAT_TIME, + GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, start, + GST_SEEK_TYPE_END, 0); + + /* Wait for the pipeline to preroll again */ + gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE); + + GST_LOG ("Seeked pipeline. Rate %f time range %" GST_TIME_FORMAT " to %" + GST_TIME_FORMAT, rate, GST_TIME_ARGS (start), GST_TIME_ARGS (end)); + + /* Clear tracking variables now that the seek is complete */ + first_ts = last_ts = GST_CLOCK_TIME_NONE; + current_rate = rate; +}; + +static GstFlowReturn +receive_sample (GstAppSink * appsink, gpointer user_data) +{ + GstSample *sample; + GstSegment *seg; + GstBuffer *buf; + GstClockTime start; + GstClockTime end; + + g_signal_emit_by_name (appsink, "pull-sample", &sample); + fail_unless (sample != NULL); + + seg = gst_sample_get_segment (sample); + fail_unless (seg != NULL); + + buf = gst_sample_get_buffer (sample); + fail_unless (buf != NULL); + + GST_LOG ("Got buffer %" GST_PTR_FORMAT, buf); + + start = GST_BUFFER_PTS (buf); + end = start; + + if (GST_CLOCK_TIME_IS_VALID (start)) + start = gst_segment_to_stream_time (seg, GST_FORMAT_TIME, start); + + if (GST_CLOCK_TIME_IS_VALID (end)) { + if (GST_BUFFER_DURATION_IS_VALID (buf)) + end += GST_BUFFER_DURATION (buf); + + end = gst_segment_to_stream_time (seg, GST_FORMAT_TIME, end); + } + + GST_DEBUG ("Got buffer stream time %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT, + GST_TIME_ARGS (start), GST_TIME_ARGS (end)); + + /* Check time is moving in the right direction */ + if (current_rate > 0) { + if (GST_CLOCK_TIME_IS_VALID (first_ts)) + fail_unless (start >= first_ts, + "Timestamps went backward during forward play, %" GST_TIME_FORMAT + " < %" GST_TIME_FORMAT, GST_TIME_ARGS (start), + GST_TIME_ARGS (first_ts)); + if (GST_CLOCK_TIME_IS_VALID (last_ts)) + fail_unless (end >= last_ts, + "Timestamps went backward during forward play, %" GST_TIME_FORMAT + " < %" GST_TIME_FORMAT, GST_TIME_ARGS (end), GST_TIME_ARGS (last_ts)); + } else { + fail_unless (start <= first_ts, + "Timestamps went forward during reverse play, %" GST_TIME_FORMAT " > %" + GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (first_ts)); + fail_unless (end <= last_ts, + "Timestamps went forward during reverse play, %" GST_TIME_FORMAT " > %" + GST_TIME_FORMAT, GST_TIME_ARGS (end), GST_TIME_ARGS (last_ts)); + } + + /* update the range of timestamps we've encountered */ + if (!GST_CLOCK_TIME_IS_VALID (first_ts) || start < first_ts) + first_ts = start; + if (!GST_CLOCK_TIME_IS_VALID (last_ts) || end > last_ts) + last_ts = end; + + gst_sample_unref (sample); + + if (user_data) { + guint *num_frame = (guint *) user_data; + + *num_frame = *num_frame + 1; + } + + return GST_FLOW_OK; +} + +static void +test_playback (const gchar * in_pattern, GstClockTime exp_first_time, + GstClockTime exp_last_time, gboolean test_reverse) +{ + GstMessage *msg; + GstElement *pipeline; + GstElement *appsink; + GstElement *fakesink2; + GstAppSinkCallbacks callbacks = { NULL }; + gchar *uri; + + GST_DEBUG ("Playing back files matching %s", in_pattern); + + pipeline = gst_element_factory_make ("playbin", NULL); + fail_if (pipeline == NULL); + + appsink = gst_element_factory_make ("appsink", NULL); + fail_if (appsink == NULL); + g_object_set (G_OBJECT (appsink), "sync", FALSE, NULL); + + g_object_set (G_OBJECT (pipeline), "video-sink", appsink, NULL); + fakesink2 = gst_element_factory_make ("fakesink", NULL); + fail_if (fakesink2 == NULL); + g_object_set (G_OBJECT (pipeline), "audio-sink", fakesink2, NULL); + + uri = g_strdup_printf ("splitmux://%s", in_pattern); + + g_object_set (G_OBJECT (pipeline), "uri", uri, NULL); + g_free (uri); + + callbacks.new_sample = receive_sample; + gst_app_sink_set_callbacks (GST_APP_SINK (appsink), &callbacks, NULL, NULL); + + /* test forwards */ + seek_pipeline (pipeline, 1.0, 0, -1); + fail_unless (first_ts == GST_CLOCK_TIME_NONE); + msg = run_pipeline (pipeline); + fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS); + gst_message_unref (msg); + + /* Check we saw the entire range of values */ + fail_unless (first_ts == exp_first_time, + "Expected start of playback range %" GST_TIME_FORMAT ", got %" + GST_TIME_FORMAT, GST_TIME_ARGS (exp_first_time), + GST_TIME_ARGS (first_ts)); + fail_unless (last_ts == exp_last_time, + "Expected end of playback range %" GST_TIME_FORMAT ", got %" + GST_TIME_FORMAT, GST_TIME_ARGS (exp_last_time), GST_TIME_ARGS (last_ts)); + + if (test_reverse) { + /* Test backwards */ + seek_pipeline (pipeline, -1.0, 0, -1); + msg = run_pipeline (pipeline); + fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS); + gst_message_unref (msg); + /* Check we saw the entire range of values */ + fail_unless (first_ts == exp_first_time, + "Expected start of playback range %" GST_TIME_FORMAT + ", got %" GST_TIME_FORMAT, GST_TIME_ARGS (exp_first_time), + GST_TIME_ARGS (first_ts)); + fail_unless (last_ts == exp_last_time, + "Expected end of playback range %" GST_TIME_FORMAT + ", got %" GST_TIME_FORMAT, GST_TIME_ARGS (exp_last_time), + GST_TIME_ARGS (last_ts)); + } + + gst_object_unref (pipeline); +} + +static gchar * +check_format_location (GstElement * object, + guint fragment_id, GstSample * first_sample) +{ + GstBuffer *buf = gst_sample_get_buffer (first_sample); + + /* Must have a buffer */ + fail_if (buf == NULL); + GST_LOG ("New file - first buffer %" GST_TIME_FORMAT, + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); + + return NULL; +} + +static GstPadProbeReturn +count_upstrea_fku (GstPad * pad, GstPadProbeInfo * info, + guint * upstream_fku_count) +{ + GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CUSTOM_UPSTREAM: + if (gst_video_event_is_force_key_unit (event)) + *upstream_fku_count += 1; + break; + default: + break; + } + + return GST_PAD_PROBE_OK; +} + +static void +splitmuxsink_split_by_keyframe_timecode (gboolean send_keyframe_request, + const gchar * maxsize_timecode_string, guint maxsize_timecode_in_sec, + guint encoder_key_interval_sec) +{ + GstMessage *msg; + GstElement *pipeline; + GstElement *sink; + GstElement *enc; + GstPad *srcpad; + gchar *pipeline_str; + gchar *dest_pattern; + guint count; + guint expected_count; + gchar *in_pattern; + guint upstream_fku_count = 0; + guint expected_fku_count; + + pipeline_str = g_strdup_printf ("splitmuxsink name=splitsink " + "max-size-timecode=%s" + " send-keyframe-requests=%s muxer=qtmux " + "videotestsrc num-buffers=30 ! video/x-raw,width=80,height=64,framerate=5/1 " + "! videoconvert ! timecodestamper ! queue ! vp8enc name=enc keyframe-max-dist=%d ! splitsink.video ", + maxsize_timecode_string, send_keyframe_request ? "true" : "false", + encoder_key_interval_sec ? encoder_key_interval_sec * 5 : 1); + + pipeline = gst_parse_launch (pipeline_str, NULL); + g_free (pipeline_str); + + fail_if (pipeline == NULL); + sink = gst_bin_get_by_name (GST_BIN (pipeline), "splitsink"); + fail_if (sink == NULL); + g_signal_connect (sink, "format-location-full", + (GCallback) check_format_location, NULL); + dest_pattern = g_build_filename (tmpdir, "out%05d.m4v", NULL); + g_object_set (G_OBJECT (sink), "location", dest_pattern, NULL); + g_free (dest_pattern); + g_object_unref (sink); + + enc = gst_bin_get_by_name (GST_BIN (pipeline), "enc"); + fail_if (enc == NULL); + srcpad = gst_element_get_static_pad (enc, "src"); + fail_if (srcpad == NULL); + + gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, + (GstPadProbeCallback) count_upstrea_fku, &upstream_fku_count, NULL); + gst_object_unref (srcpad); + gst_object_unref (enc); + + msg = run_pipeline (pipeline); + + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) + dump_error (msg); + fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS); + gst_message_unref (msg); + + gst_object_unref (pipeline); + + count = count_files (tmpdir); + expected_count = (6 / maxsize_timecode_in_sec) + + (6 % maxsize_timecode_in_sec ? 1 : 0); + fail_unless (count == expected_count, + "Expected %d output files, got %d", expected_count, count); + + if (!send_keyframe_request) { + expected_fku_count = 0; + } else { + expected_fku_count = count; + } + + GST_INFO ("Upstream force keyunit event count %d", upstream_fku_count); + + fail_unless (upstream_fku_count == expected_fku_count, + "Expected upstream force keyunit event count %d, got %d", + expected_fku_count, upstream_fku_count); + + in_pattern = g_build_filename (tmpdir, "out*.m4v", NULL); + /* FIXME: Reverse playback works poorly with multiple video streams + * in qtdemux (at least, maybe other demuxers) at the time this was + * written, and causes test failures like buffers being output + * multiple times by qtdemux as it loops through GOPs. Disable that + * for now */ + test_playback (in_pattern, 0, 6 * GST_SECOND, FALSE); + g_free (in_pattern); +} + +GST_START_TEST (test_splitmuxsink_without_keyframe_request_timecode) +{ + /* This encoding option is intended to produce keyframe per 1 second + * but splitmuxsink will split file per 2 second without keyframe request */ + splitmuxsink_split_by_keyframe_timecode (FALSE, "00:00:02:00", 2, 1); +} + +GST_END_TEST; + +GST_START_TEST (test_splitmuxsink_keyframe_request_timecode) +{ + /* This encoding option is intended to produce keyframe per 1 second + * but splitmuxsink will request keyframe per 2 seconds. This should produce + * 2 seconds long files */ + splitmuxsink_split_by_keyframe_timecode (TRUE, "00:00:02:00", 2, 1); +} + +GST_END_TEST; + +GST_START_TEST + (test_splitmuxsink_keyframe_request_timecode_trailing_small_segment) { + /* This encoding option is intended to produce keyframe per 1 second + * but splitmuxsink will request keyframe per 4 seconds. This should produce + * 4 seconds long files */ + splitmuxsink_split_by_keyframe_timecode (TRUE, "00:00:04:00", 4, 1); +} + +GST_END_TEST; + +GST_START_TEST (test_splitmuxsink_keyframe_request_timecode_all_intra) +{ + /* This encoding option is intended to produce keyframe for every frame. + * This should produce 1 second long files */ + splitmuxsink_split_by_keyframe_timecode (TRUE, "00:00:01:00", 1, 0); +} + +GST_END_TEST; + +static void +count_frames (const gchar * file_name, guint expected_count) +{ + GstMessage *msg; + GstElement *pipeline; + GstElement *appsink; + GstElement *fakesink2; + GstAppSinkCallbacks callbacks = { NULL }; + gchar *uri; + guint frame_count = 0; + + GST_DEBUG ("Playing back files matching %s", file_name); + + pipeline = gst_element_factory_make ("playbin", NULL); + fail_if (pipeline == NULL); + + appsink = gst_element_factory_make ("appsink", NULL); + fail_if (appsink == NULL); + g_object_set (G_OBJECT (appsink), "sync", FALSE, NULL); + + g_object_set (G_OBJECT (pipeline), "video-sink", appsink, NULL); + fakesink2 = gst_element_factory_make ("fakesink", NULL); + fail_if (fakesink2 == NULL); + g_object_set (G_OBJECT (pipeline), "audio-sink", fakesink2, NULL); + + uri = g_strdup_printf ("file://%s", file_name); + + g_object_set (G_OBJECT (pipeline), "uri", uri, NULL); + g_free (uri); + + callbacks.new_sample = receive_sample; + gst_app_sink_set_callbacks (GST_APP_SINK (appsink), + &callbacks, &frame_count, NULL); + + seek_pipeline (pipeline, 1.0, 0, -1); + fail_unless (first_ts == GST_CLOCK_TIME_NONE); + msg = run_pipeline (pipeline); + fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS); + gst_message_unref (msg); + + fail_unless (frame_count == expected_count, + "Frame count %u is not equal to expected %u frame count %u", + expected_count, frame_count); + + gst_object_unref (pipeline); +} + +typedef struct +{ + const gchar *max_timecode; + guint num_frame[3]; + const gchar *fragment_name[3]; + GstClockTime expected_fku_time[3]; + guint upstream_fku_count; +} TimeCodeTestData; + +static GstPadProbeReturn +count_upstrea_fku_with_data (GstPad * pad, GstPadProbeInfo * info, + TimeCodeTestData * data) +{ + GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CUSTOM_UPSTREAM: + if (gst_video_event_is_force_key_unit (event)) { + GstClockTime running_time; + GstClockTime expected; + + expected = data->expected_fku_time[data->upstream_fku_count]; + + gst_video_event_parse_upstream_force_key_unit (event, + &running_time, NULL, NULL); + + GST_INFO ("expected fku time %" GST_TIME_FORMAT + ", got %" GST_TIME_FORMAT, GST_TIME_ARGS (expected), + GST_TIME_ARGS (running_time)); + + /* splitmuxsink will request keyframe with slightly earlier timestamp */ + fail_unless (expected <= running_time + 5 * GST_USECOND); + fail_unless (expected >= running_time); + + data->upstream_fku_count++; + } + break; + default: + break; + } + + return GST_PAD_PROBE_OK; +} + +static void +splitmuxsink_split_by_keyframe_timecode_framerate_29_97 (gboolean equal_dur, + gboolean all_keyframe) +{ + GstMessage *msg; + GstElement *pipeline; + GstElement *sink; + GstElement *enc; + GstPad *srcpad; + gchar *pipeline_str; + gchar *dest_pattern; + guint count; + guint expected_fku_count; + TimeCodeTestData data; + gint i; + + if (equal_dur) { + data.max_timecode = "00:01:00;02"; + data.num_frame[0] = data.num_frame[1] = 1800; + data.expected_fku_time[0] = + gst_util_uint64_scale (1800 * GST_SECOND, 1001, 30000); + data.expected_fku_time[1] = + gst_util_uint64_scale (2 * 1800 * GST_SECOND, 1001, 30000); + data.expected_fku_time[2] = + gst_util_uint64_scale (3 * 1800 * GST_SECOND, 1001, 30000); + } else { + data.max_timecode = "00:01:00;00"; + data.num_frame[0] = 1800; + data.num_frame[1] = 1798; + data.expected_fku_time[0] = + gst_util_uint64_scale (1800 * GST_SECOND, 1001, 30000); + data.expected_fku_time[1] = + gst_util_uint64_scale ((1800 + 1798) * GST_SECOND, 1001, 30000); + data.expected_fku_time[2] = + gst_util_uint64_scale ((1800 + 2 * 1798) * GST_SECOND, 1001, 30000); + } + data.num_frame[2] = 5000 - (data.num_frame[0] + data.num_frame[1]); + + data.fragment_name[0] = "out0.m4v"; + data.fragment_name[1] = "out1.m4v"; + data.fragment_name[2] = "out2.m4v"; + data.upstream_fku_count = 0; + + pipeline_str = g_strdup_printf ("splitmuxsink name=splitsink " + "max-size-timecode=%s " + "send-keyframe-requests=%s muxer=qtmux " + "videotestsrc num-buffers=5000 ! " + "video/x-raw,width=80,height=64,framerate=30000/1001 " + "! videoconvert ! timecodestamper drop-frame=true ! queue ! " + "vp8enc name=enc keyframe-max-dist=%d ! splitsink.video ", + data.max_timecode, all_keyframe ? "false" : "true", + all_keyframe ? 1 : 5000); + + pipeline = gst_parse_launch (pipeline_str, NULL); + g_free (pipeline_str); + + fail_if (pipeline == NULL); + sink = gst_bin_get_by_name (GST_BIN (pipeline), "splitsink"); + fail_if (sink == NULL); + g_signal_connect (sink, "format-location-full", + (GCallback) check_format_location, NULL); + dest_pattern = g_build_filename (tmpdir, "out%d.m4v", NULL); + g_object_set (G_OBJECT (sink), "location", dest_pattern, NULL); + g_free (dest_pattern); + g_object_unref (sink); + + enc = gst_bin_get_by_name (GST_BIN (pipeline), "enc"); + fail_if (enc == NULL); + srcpad = gst_element_get_static_pad (enc, "src"); + fail_if (srcpad == NULL); + + gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, + (GstPadProbeCallback) count_upstrea_fku_with_data, &data, NULL); + gst_object_unref (srcpad); + gst_object_unref (enc); + + msg = run_pipeline (pipeline); + + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) + dump_error (msg); + fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS); + gst_message_unref (msg); + + gst_object_unref (pipeline); + + count = count_files (tmpdir); + fail_unless (count == 3, "Expected 3 output files, got %d", count); + + if (all_keyframe) { + expected_fku_count = 0; + } else { + expected_fku_count = count; + } + + GST_INFO ("Upstream force keyunit event count %d", data.upstream_fku_count); + + fail_unless (data.upstream_fku_count == expected_fku_count, + "Expected upstream force keyunit event count %d, got %d", + expected_fku_count, data.upstream_fku_count); + + for (i = 0; i < 3; i++) { + gchar *file_name = g_build_filename (tmpdir, data.fragment_name[i], NULL); + count_frames (file_name, data.num_frame[i]); + g_free (file_name); + } +} + +GST_START_TEST (test_splitmuxsink_timecode_framerate_29_97_equal_duration) +{ + splitmuxsink_split_by_keyframe_timecode_framerate_29_97 (TRUE, FALSE); +} + +GST_END_TEST; + +GST_START_TEST + (test_splitmuxsink_timecode_framerate_29_97_equal_duration_all_intra) { + splitmuxsink_split_by_keyframe_timecode_framerate_29_97 (TRUE, TRUE); +} + +GST_END_TEST; + +GST_START_TEST (test_splitmuxsink_timecode_framerate_29_97_not_equal_duration) +{ + splitmuxsink_split_by_keyframe_timecode_framerate_29_97 (TRUE, FALSE); +} + +GST_END_TEST; + +GST_START_TEST + (test_splitmuxsink_timecode_framerate_29_97_not_equal_duration_all_intra) { + splitmuxsink_split_by_keyframe_timecode_framerate_29_97 (TRUE, TRUE); +} + +GST_END_TEST; + +static void +splitmuxsink_timecode_framerate_25 (gboolean all_keyframe) +{ + GstMessage *msg; + GstElement *pipeline; + GstElement *sink; + GstElement *enc; + GstPad *srcpad; + gchar *pipeline_str; + gchar *dest_pattern; + guint count; + guint expected_fku_count; + TimeCodeTestData data; + gint i; + guint num_total_frames = 4000; + + data.max_timecode = "00:01:00;00"; + data.num_frame[0] = 1500; + data.num_frame[1] = 1500; + data.num_frame[2] = + num_total_frames - (data.num_frame[0] + data.num_frame[1]); + /* in case of framerate 25/1 with maxsize timecode "00:01:00;00", + * all fragments will have equal size */ + data.expected_fku_time[0] = GST_SECOND * 60; + data.expected_fku_time[1] = GST_SECOND * 120; + data.expected_fku_time[2] = GST_SECOND * 180; + + data.fragment_name[0] = "out0.m4v"; + data.fragment_name[1] = "out1.m4v"; + data.fragment_name[2] = "out2.m4v"; + data.upstream_fku_count = 0; + + pipeline_str = g_strdup_printf ("splitmuxsink name=splitsink " + "max-size-timecode=%s " + "send-keyframe-requests=%s muxer=qtmux " + "videotestsrc num-buffers=%d ! " + "video/x-raw,width=80,height=64,framerate=25/1 " + "! videoconvert ! timecodestamper drop-frame=true ! queue ! " + "vp8enc name=enc keyframe-max-dist=%d ! splitsink.video ", + data.max_timecode, all_keyframe ? "false" : "true", num_total_frames, + all_keyframe ? 1 : num_total_frames); + + pipeline = gst_parse_launch (pipeline_str, NULL); + g_free (pipeline_str); + + fail_if (pipeline == NULL); + sink = gst_bin_get_by_name (GST_BIN (pipeline), "splitsink"); + fail_if (sink == NULL); + g_signal_connect (sink, "format-location-full", + (GCallback) check_format_location, NULL); + dest_pattern = g_build_filename (tmpdir, "out%d.m4v", NULL); + g_object_set (G_OBJECT (sink), "location", dest_pattern, NULL); + g_free (dest_pattern); + g_object_unref (sink); + + enc = gst_bin_get_by_name (GST_BIN (pipeline), "enc"); + fail_if (enc == NULL); + srcpad = gst_element_get_static_pad (enc, "src"); + fail_if (srcpad == NULL); + + gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, + (GstPadProbeCallback) count_upstrea_fku_with_data, &data, NULL); + gst_object_unref (srcpad); + gst_object_unref (enc); + + msg = run_pipeline (pipeline); + + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) + dump_error (msg); + fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS); + gst_message_unref (msg); + + gst_object_unref (pipeline); + + count = count_files (tmpdir); + fail_unless (count == 3, "Expected 3 output files, got %d", count); + + if (all_keyframe) { + expected_fku_count = 0; + } else { + expected_fku_count = count; + } + + GST_INFO ("Upstream force keyunit event count %d", data.upstream_fku_count); + + fail_unless (data.upstream_fku_count == expected_fku_count, + "Expected upstream force keyunit event count %d, got %d", + expected_fku_count, data.upstream_fku_count); + + for (i = 0; i < 3; i++) { + gchar *file_name = g_build_filename (tmpdir, data.fragment_name[i], NULL); + count_frames (file_name, data.num_frame[i]); + g_free (file_name); + } +} + +GST_START_TEST (test_splitmuxsink_timecode_framerate_25) +{ + splitmuxsink_timecode_framerate_25 (TRUE); +} + +GST_END_TEST; + +GST_START_TEST (test_splitmuxsink_timecode_framerate_25_all_intra) +{ + splitmuxsink_timecode_framerate_25 (FALSE); +} + +GST_END_TEST; + +static Suite * +splitmuxsinktimecode_suite (void) +{ + Suite *s = suite_create ("splitmuxsink-timecode"); + TCase *tc_chain = tcase_create ("general"); + gboolean have_qtmux, have_vp8, have_timecodestamper; + + /* we assume that if encoder/muxer are there, decoder/demuxer will be a well */ + have_qtmux = gst_registry_check_feature_version (gst_registry_get (), + "qtmux", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0); + have_vp8 = gst_registry_check_feature_version (gst_registry_get (), + "vp8enc", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0); + have_timecodestamper = + gst_registry_check_feature_version (gst_registry_get (), + "timecodestamper", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0); + + suite_add_tcase (s, tc_chain); + + if (have_qtmux && have_vp8 && have_timecodestamper) { + tcase_add_checked_fixture (tc_chain, tempdir_setup, tempdir_cleanup); + tcase_add_test (tc_chain, + test_splitmuxsink_without_keyframe_request_timecode); + tcase_add_test (tc_chain, test_splitmuxsink_keyframe_request_timecode); + tcase_add_test (tc_chain, + test_splitmuxsink_keyframe_request_timecode_trailing_small_segment); + tcase_add_test (tc_chain, + test_splitmuxsink_keyframe_request_timecode_all_intra); + if (!(RUNNING_ON_VALGRIND)) { + tcase_add_test (tc_chain, + test_splitmuxsink_timecode_framerate_29_97_equal_duration); + tcase_add_test (tc_chain, + test_splitmuxsink_timecode_framerate_29_97_equal_duration_all_intra); + tcase_add_test (tc_chain, + test_splitmuxsink_timecode_framerate_29_97_not_equal_duration); + tcase_add_test (tc_chain, + test_splitmuxsink_timecode_framerate_29_97_not_equal_duration_all_intra); + tcase_add_test (tc_chain, test_splitmuxsink_timecode_framerate_25); + tcase_add_test (tc_chain, + test_splitmuxsink_timecode_framerate_25_all_intra); + } + } else { + GST_INFO + ("Skipping tests, missing plugins: vp8enc, mp4mux, or timecodestamper"); + } + + return s; +} + +GST_CHECK_MAIN (splitmuxsinktimecode); diff --git a/tests/check/elements/splitmux.c b/tests/check/elements/splitmuxsrc.c similarity index 66% rename from tests/check/elements/splitmux.c rename to tests/check/elements/splitmuxsrc.c index 2919d4d7e5..13e9b0f2bb 100644 --- a/tests/check/elements/splitmux.c +++ b/tests/check/elements/splitmuxsrc.c @@ -1,4 +1,4 @@ -/* GStreamer unit test for splitmuxsrc/sink elements +/* GStreamer unit test for splitmuxsrc elements * * Copyright (C) 2007 David A. Schleef * Copyright (C) 2015 Jan Schmidt @@ -27,6 +27,7 @@ #include #include +#include #include gchar *tmpdir = NULL; @@ -146,17 +147,40 @@ seek_pipeline (GstElement * pipeline, gdouble rate, GstClockTime start, current_rate = rate; }; -static void -receive_handoff (GstElement * object G_GNUC_UNUSED, GstBuffer * buf, - GstPad * arg1 G_GNUC_UNUSED, gpointer user_data G_GNUC_UNUSED) +static GstFlowReturn +receive_sample (GstAppSink * appsink, gpointer user_data G_GNUC_UNUSED) { - GstClockTime start = GST_BUFFER_TIMESTAMP (buf); - GstClockTime end = start; + GstSample *sample; + GstSegment *seg; + GstBuffer *buf; + GstClockTime start; + GstClockTime end; + + g_signal_emit_by_name (appsink, "pull-sample", &sample); + fail_unless (sample != NULL); + + seg = gst_sample_get_segment (sample); + fail_unless (seg != NULL); - if (GST_BUFFER_DURATION_IS_VALID (buf)) - end += GST_BUFFER_DURATION (buf); + buf = gst_sample_get_buffer (sample); + fail_unless (buf != NULL); - GST_LOG ("Got buffer %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT, + GST_LOG ("Got buffer %" GST_PTR_FORMAT, buf); + + start = GST_BUFFER_PTS (buf); + end = start; + + if (GST_CLOCK_TIME_IS_VALID (start)) + start = gst_segment_to_stream_time (seg, GST_FORMAT_TIME, start); + + if (GST_CLOCK_TIME_IS_VALID (end)) { + if (GST_BUFFER_DURATION_IS_VALID (buf)) + end += GST_BUFFER_DURATION (buf); + + end = gst_segment_to_stream_time (seg, GST_FORMAT_TIME, end); + } + + GST_DEBUG ("Got buffer stream time %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end)); /* Check time is moving in the right direction */ @@ -184,6 +208,10 @@ receive_handoff (GstElement * object G_GNUC_UNUSED, GstBuffer * buf, first_ts = start; if (!GST_CLOCK_TIME_IS_VALID (last_ts) || end > last_ts) last_ts = end; + + gst_sample_unref (sample); + + return GST_FLOW_OK; } static void @@ -192,16 +220,21 @@ test_playback (const gchar * in_pattern, GstClockTime exp_first_time, { GstMessage *msg; GstElement *pipeline; - GstElement *fakesink; + GstElement *appsink; GstElement *fakesink2; + GstAppSinkCallbacks callbacks = { NULL }; gchar *uri; + GST_DEBUG ("Playing back files matching %s", in_pattern); + pipeline = gst_element_factory_make ("playbin", NULL); fail_if (pipeline == NULL); - fakesink = gst_element_factory_make ("fakesink", NULL); - fail_if (fakesink == NULL); - g_object_set (G_OBJECT (pipeline), "video-sink", fakesink, NULL); + appsink = gst_element_factory_make ("appsink", NULL); + fail_if (appsink == NULL); + g_object_set (G_OBJECT (appsink), "sync", FALSE, NULL); + + g_object_set (G_OBJECT (pipeline), "video-sink", appsink, NULL); fakesink2 = gst_element_factory_make ("fakesink", NULL); fail_if (fakesink2 == NULL); g_object_set (G_OBJECT (pipeline), "audio-sink", fakesink2, NULL); @@ -211,8 +244,8 @@ test_playback (const gchar * in_pattern, GstClockTime exp_first_time, g_object_set (G_OBJECT (pipeline), "uri", uri, NULL); g_free (uri); - g_signal_connect (fakesink, "handoff", (GCallback) receive_handoff, NULL); - g_object_set (G_OBJECT (fakesink), "signal-handoffs", TRUE, NULL); + callbacks.new_sample = receive_sample; + gst_app_sink_set_callbacks (GST_APP_SINK (appsink), &callbacks, NULL, NULL); /* test forwards */ seek_pipeline (pipeline, 1.0, 0, -1); @@ -223,11 +256,12 @@ test_playback (const gchar * in_pattern, GstClockTime exp_first_time, /* Check we saw the entire range of values */ fail_unless (first_ts == exp_first_time, - "Expected start of playback range 0, got %" GST_TIME_FORMAT, + "Expected start of playback range %" GST_TIME_FORMAT ", got %" + GST_TIME_FORMAT, GST_TIME_ARGS (exp_first_time), GST_TIME_ARGS (first_ts)); fail_unless (last_ts == exp_last_time, - "Expected end of playback range 3s, got %" GST_TIME_FORMAT, - GST_TIME_ARGS (last_ts)); + "Expected end of playback range %" GST_TIME_FORMAT ", got %" + GST_TIME_FORMAT, GST_TIME_ARGS (exp_last_time), GST_TIME_ARGS (last_ts)); if (test_reverse) { /* Test backwards */ @@ -311,189 +345,6 @@ check_format_location (GstElement * object, return NULL; } -GST_START_TEST (test_splitmuxsink) -{ - GstMessage *msg; - GstElement *pipeline; - GstElement *sink; - GstPad *splitmux_sink_pad; - GstPad *enc_src_pad; - gchar *dest_pattern; - guint count; - gchar *in_pattern; - - /* This pipeline has a small time cutoff - it should start a new file - * every GOP, ie 1 second */ - pipeline = - gst_parse_launch - ("videotestsrc num-buffers=15 ! video/x-raw,width=80,height=64,framerate=5/1 ! videoconvert !" - " queue ! theoraenc keyframe-force=5 ! splitmuxsink name=splitsink " - " max-size-time=1000000 max-size-bytes=1000000 muxer=oggmux", NULL); - fail_if (pipeline == NULL); - sink = gst_bin_get_by_name (GST_BIN (pipeline), "splitsink"); - fail_if (sink == NULL); - g_signal_connect (sink, "format-location-full", - (GCallback) check_format_location, NULL); - dest_pattern = g_build_filename (tmpdir, "out%05d.ogg", NULL); - g_object_set (G_OBJECT (sink), "location", dest_pattern, NULL); - g_free (dest_pattern); - g_object_unref (sink); - - msg = run_pipeline (pipeline); - - if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) - dump_error (msg); - fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS); - gst_message_unref (msg); - - /* unlink manually and release request pad to ensure that we *can* do that - * - https://bugzilla.gnome.org/show_bug.cgi?id=753622 */ - sink = gst_bin_get_by_name (GST_BIN (pipeline), "splitsink"); - fail_if (sink == NULL); - splitmux_sink_pad = gst_element_get_static_pad (sink, "video"); - fail_if (splitmux_sink_pad == NULL); - enc_src_pad = gst_pad_get_peer (splitmux_sink_pad); - fail_if (enc_src_pad == NULL); - fail_unless (gst_pad_unlink (enc_src_pad, splitmux_sink_pad)); - gst_object_unref (enc_src_pad); - gst_element_release_request_pad (sink, splitmux_sink_pad); - gst_object_unref (splitmux_sink_pad); - /* at this point the pad must be released - try to find it again to verify */ - splitmux_sink_pad = gst_element_get_static_pad (sink, "video"); - fail_if (splitmux_sink_pad != NULL); - g_object_unref (sink); - - gst_object_unref (pipeline); - - count = count_files (tmpdir); - fail_unless (count == 3, "Expected 3 output files, got %d", count); - - in_pattern = g_build_filename (tmpdir, "out*.ogg", NULL); - test_playback (in_pattern, 0, 3 * GST_SECOND, TRUE); - g_free (in_pattern); -} - -GST_END_TEST; - -GST_START_TEST (test_splitmuxsink_multivid) -{ - GstMessage *msg; - GstElement *pipeline; - GstElement *sink; - gchar *dest_pattern; - guint count; - gchar *in_pattern; - - /* This pipeline should start a new file every GOP, ie 1 second, - * driven by the primary video stream and with 2 auxiliary video streams */ - pipeline = - gst_parse_launch - ("splitmuxsink name=splitsink " - " max-size-time=1000000 max-size-bytes=1000000 muxer=qtmux " - "videotestsrc num-buffers=15 ! video/x-raw,width=80,height=64,framerate=5/1 ! videoconvert !" - " queue ! vp8enc keyframe-max-dist=5 ! splitsink.video " - "videotestsrc num-buffers=15 pattern=snow ! video/x-raw,width=80,height=64,framerate=5/1 ! videoconvert !" - " queue ! vp8enc keyframe-max-dist=6 ! splitsink.video_aux_0 " - "videotestsrc num-buffers=15 pattern=ball ! video/x-raw,width=80,height=64,framerate=5/1 ! videoconvert !" - " queue ! vp8enc keyframe-max-dist=8 ! splitsink.video_aux_1 ", NULL); - fail_if (pipeline == NULL); - sink = gst_bin_get_by_name (GST_BIN (pipeline), "splitsink"); - fail_if (sink == NULL); - g_signal_connect (sink, "format-location-full", - (GCallback) check_format_location, NULL); - dest_pattern = g_build_filename (tmpdir, "out%05d.m4v", NULL); - g_object_set (G_OBJECT (sink), "location", dest_pattern, NULL); - g_free (dest_pattern); - g_object_unref (sink); - - msg = run_pipeline (pipeline); - - if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) - dump_error (msg); - fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS); - gst_message_unref (msg); - - gst_object_unref (pipeline); - - count = count_files (tmpdir); - fail_unless (count == 3, "Expected 3 output files, got %d", count); - - in_pattern = g_build_filename (tmpdir, "out*.m4v", NULL); - /* FIXME: Reverse playback works poorly with multiple video streams - * in qtdemux (at least, maybe other demuxers) at the time this was - * written, and causes test failures like buffers being output - * multiple times by qtdemux as it loops through GOPs. Disable that - * for now */ - test_playback (in_pattern, 0, 3 * GST_SECOND, FALSE); - g_free (in_pattern); -} - -GST_END_TEST; - -GST_START_TEST (test_splitmuxsink_async) -{ - GstMessage *msg; - GstElement *pipeline; - GstElement *sink; - GstPad *splitmux_sink_pad; - GstPad *enc_src_pad; - gchar *dest_pattern; - guint count; - gchar *in_pattern; - - pipeline = - gst_parse_launch - ("videotestsrc num-buffers=15 ! video/x-raw,width=80,height=64,framerate=5/1 ! videoconvert !" - " queue ! theoraenc keyframe-force=5 ! splitmuxsink name=splitsink " - " max-size-time=1000000000 async-finalize=true " - " muxer-factory=matroskamux audiotestsrc num-buffers=15 samplesperbuffer=9600 ! " - " audio/x-raw,rate=48000 ! splitsink.audio_%u", NULL); - fail_if (pipeline == NULL); - sink = gst_bin_get_by_name (GST_BIN (pipeline), "splitsink"); - fail_if (sink == NULL); - g_signal_connect (sink, "format-location-full", - (GCallback) check_format_location, NULL); - dest_pattern = g_build_filename (tmpdir, "matroska%05d.mkv", NULL); - g_object_set (G_OBJECT (sink), "location", dest_pattern, NULL); - g_free (dest_pattern); - g_object_unref (sink); - - msg = run_pipeline (pipeline); - - if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) - dump_error (msg); - fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS); - gst_message_unref (msg); - - /* unlink manually and release request pad to ensure that we *can* do that - * - https://bugzilla.gnome.org/show_bug.cgi?id=753622 */ - sink = gst_bin_get_by_name (GST_BIN (pipeline), "splitsink"); - fail_if (sink == NULL); - splitmux_sink_pad = gst_element_get_static_pad (sink, "video"); - fail_if (splitmux_sink_pad == NULL); - enc_src_pad = gst_pad_get_peer (splitmux_sink_pad); - fail_if (enc_src_pad == NULL); - fail_unless (gst_pad_unlink (enc_src_pad, splitmux_sink_pad)); - gst_object_unref (enc_src_pad); - gst_element_release_request_pad (sink, splitmux_sink_pad); - gst_object_unref (splitmux_sink_pad); - /* at this point the pad must be released - try to find it again to verify */ - splitmux_sink_pad = gst_element_get_static_pad (sink, "video"); - fail_if (splitmux_sink_pad != NULL); - g_object_unref (sink); - - gst_object_unref (pipeline); - - count = count_files (tmpdir); - fail_unless (count == 3, "Expected 3 output files, got %d", count); - - in_pattern = g_build_filename (tmpdir, "matroska*.mkv", NULL); - test_playback (in_pattern, 0, 3 * GST_SECOND, TRUE); - g_free (in_pattern); -} - -GST_END_TEST; - static GstPadProbeReturn intercept_stream_start (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) @@ -784,9 +635,9 @@ GST_START_TEST (test_splitmuxsrc_robust_mux) gchar *dest_pattern; gchar *in_pattern; - /* This test creates a new file only by changing the caps, which - * qtmux will reject (for now - if qtmux starts supporting caps - * changes, this test will break and need fixing/disabling */ + /* This test checks that splitmuxsink can support the + * qtmux robust muxing mode, and switch to a new fragment if the + * file index is about to overflow */ pipeline = gst_parse_launch ("videotestsrc num-buffers=10 !" @@ -823,91 +674,15 @@ GST_START_TEST (test_splitmuxsrc_robust_mux) GST_END_TEST; -/* For verifying bug https://bugzilla.gnome.org/show_bug.cgi?id=762893 */ -GST_START_TEST (test_splitmuxsink_reuse_simple) -{ - GstElement *sink; - GstPad *pad; - - sink = gst_element_factory_make ("splitmuxsink", NULL); - pad = gst_element_get_request_pad (sink, "video"); - fail_unless (pad != NULL); - g_object_set (sink, "location", "/dev/null", NULL); - - fail_unless (gst_element_set_state (sink, - GST_STATE_PLAYING) == GST_STATE_CHANGE_ASYNC); - fail_unless (gst_element_set_state (sink, - GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS); - fail_unless (gst_element_set_state (sink, - GST_STATE_PLAYING) == GST_STATE_CHANGE_ASYNC); - fail_unless (gst_element_set_state (sink, - GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS); - - gst_element_release_request_pad (sink, pad); - gst_object_unref (pad); - gst_object_unref (sink); -} - -GST_END_TEST; - -GST_START_TEST (test_splitmuxsink_muxer_pad_map) -{ - GstElement *sink, *muxer; - GstPad *muxpad; - GstPad *pad1 = NULL, *pad2 = NULL; - GstStructure *pad_map; - - pad_map = gst_structure_new ("x-pad-map", - "video", G_TYPE_STRING, "video_100", - "audio_0", G_TYPE_STRING, "audio_101", NULL); - - muxer = gst_element_factory_make ("qtmux", NULL); - fail_if (muxer == NULL); - sink = gst_element_factory_make ("splitmuxsink", NULL); - fail_if (sink == NULL); - - g_object_set (sink, "muxer", muxer, "muxer-pad-map", pad_map, NULL); - gst_structure_free (pad_map); - - pad1 = gst_element_get_request_pad (sink, "video"); - fail_unless (g_str_equal ("video", GST_PAD_NAME (pad1))); - muxpad = gst_element_get_static_pad (muxer, "video_100"); - fail_unless (muxpad != NULL); - gst_object_unref (muxpad); - - pad2 = gst_element_get_request_pad (sink, "audio_0"); - fail_unless (g_str_equal ("audio_0", GST_PAD_NAME (pad2))); - muxpad = gst_element_get_static_pad (muxer, "audio_101"); - fail_unless (muxpad != NULL); - gst_object_unref (muxpad); - - g_object_set (sink, "location", "/dev/null", NULL); - - fail_unless (gst_element_set_state (sink, - GST_STATE_PLAYING) == GST_STATE_CHANGE_ASYNC); - fail_unless (gst_element_set_state (sink, - GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS); - - gst_element_release_request_pad (sink, pad1); - gst_object_unref (pad1); - gst_element_release_request_pad (sink, pad2); - gst_object_unref (pad2); - gst_object_unref (sink); -} - -GST_END_TEST; - - static Suite * -splitmux_suite (void) +splitmuxsrc_suite (void) { - Suite *s = suite_create ("splitmux"); + Suite *s = suite_create ("splitmuxsrc"); TCase *tc_chain = tcase_create ("general"); - TCase *tc_chain_basic = tcase_create ("basic"); TCase *tc_chain_complex = tcase_create ("complex"); TCase *tc_chain_mp4_jpeg = tcase_create ("caps_change"); gboolean have_theora, have_ogg, have_vorbis, have_matroska, have_qtmux, - have_jpeg, have_vp8; + have_jpeg; /* we assume that if encoder/muxer are there, decoder/demuxer will be a well */ have_theora = gst_registry_check_feature_version (gst_registry_get (), @@ -922,29 +697,22 @@ splitmux_suite (void) "qtmux", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0); have_jpeg = gst_registry_check_feature_version (gst_registry_get (), "jpegenc", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0); - have_vp8 = gst_registry_check_feature_version (gst_registry_get (), - "vp8enc", GST_VERSION_MAJOR, GST_VERSION_MINOR, 0); suite_add_tcase (s, tc_chain); - suite_add_tcase (s, tc_chain_basic); suite_add_tcase (s, tc_chain_complex); suite_add_tcase (s, tc_chain_mp4_jpeg); - tcase_add_test (tc_chain_basic, test_splitmuxsink_reuse_simple); - if (have_theora && have_ogg) { tcase_add_checked_fixture (tc_chain, tempdir_setup, tempdir_cleanup); tcase_add_test (tc_chain, test_splitmuxsrc); tcase_add_test (tc_chain, test_splitmuxsrc_format_location); - tcase_add_test (tc_chain, test_splitmuxsink); if (have_matroska && have_vorbis) { tcase_add_checked_fixture (tc_chain_complex, tempdir_setup, tempdir_cleanup); tcase_add_test (tc_chain_complex, test_splitmuxsrc_sparse_streams); - tcase_add_test (tc_chain, test_splitmuxsink_async); } else { GST_INFO ("Skipping tests, missing plugins: matroska and/or vorbis"); } @@ -958,17 +726,11 @@ splitmux_suite (void) tempdir_cleanup); tcase_add_test (tc_chain_mp4_jpeg, test_splitmuxsrc_caps_change); tcase_add_test (tc_chain_mp4_jpeg, test_splitmuxsrc_robust_mux); - tcase_add_test (tc_chain_mp4_jpeg, test_splitmuxsink_muxer_pad_map); } else { GST_INFO ("Skipping tests, missing plugins: jpegenc or mp4mux"); } - if (have_qtmux && have_vp8) { - tcase_add_test (tc_chain, test_splitmuxsink_multivid); - } else { - GST_INFO ("Skipping tests, missing plugins: vp8enc or mp4mux"); - } return s; } -GST_CHECK_MAIN (splitmux); +GST_CHECK_MAIN (splitmuxsrc); diff --git a/tests/check/elements/videoflip.c b/tests/check/elements/videoflip.c new file mode 100644 index 0000000000..2a9f8cba6a --- /dev/null +++ b/tests/check/elements/videoflip.c @@ -0,0 +1,286 @@ +/* GStreamer + * + * unit test for videofilter elements + * + * Copyright (C) <2006> Mark Nauwelaerts + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include +#include + +static GstBuffer * +create_test_video_buffer_rgba8 (GstVideoInfo * info) +{ + guint8 *data; + guint i = 0, j, k; + gsize stride = GST_VIDEO_INFO_PLANE_STRIDE (info, i); + + data = g_malloc0 (info->size); + + for (j = 0; j < GST_VIDEO_INFO_COMP_HEIGHT (info, i); j++) { + for (k = 0; k < GST_VIDEO_INFO_COMP_WIDTH (info, i); k++) { + data[(j * stride + 4 * k) + 0] = j % 255; + data[(j * stride + 4 * k) + 1] = k % 255; + data[(j * stride + 4 * k) + 2] = (j + k) % 255; + data[(j * stride + 4 * k) + 3] = 255; + } + } + + return gst_buffer_new_wrapped (data, info->size); +} + +GST_START_TEST (test_passthrough) +{ + GstHarness *flip = gst_harness_new ("videoflip"); + GstVideoInfo in_info, out_info; + GstCaps *in_caps, *out_caps; + GstEvent *e; + GstBuffer *buf; + + gst_video_info_set_format (&in_info, GST_VIDEO_FORMAT_RGBA, 4, 9); + in_caps = gst_video_info_to_caps (&in_info); + + gst_harness_set_src_caps (flip, in_caps); + + e = gst_harness_pull_event (flip); + fail_unless_equals_int (GST_EVENT_TYPE (e), GST_EVENT_STREAM_START); + gst_event_unref (e); + e = gst_harness_pull_event (flip); + fail_unless_equals_int (GST_EVENT_TYPE (e), GST_EVENT_CAPS); + gst_event_parse_caps (e, &out_caps); + fail_unless (gst_video_info_from_caps (&out_info, out_caps)); + fail_unless_equals_int (GST_VIDEO_INFO_WIDTH (&in_info), + GST_VIDEO_INFO_WIDTH (&out_info)); + fail_unless_equals_int (GST_VIDEO_INFO_HEIGHT (&in_info), + GST_VIDEO_INFO_HEIGHT (&out_info)); + gst_event_unref (e); + + e = gst_harness_pull_event (flip); + fail_unless_equals_int (GST_EVENT_TYPE (e), GST_EVENT_SEGMENT); + gst_event_unref (e); + + buf = create_test_video_buffer_rgba8 (&in_info); + buf = gst_harness_push_and_pull (flip, buf); + fail_unless (buf != NULL); + gst_buffer_unref (buf); + + gst_harness_teardown (flip); +} + +GST_END_TEST; + +GST_START_TEST (test_change_method) +{ + GstHarness *flip = gst_harness_new ("videoflip"); + GstVideoInfo in_info, out_info; + GstCaps *in_caps, *out_caps; + GstEvent *e; + GstBuffer *buf; + + gst_video_info_set_format (&in_info, GST_VIDEO_FORMAT_RGBA, 4, 9); + in_caps = gst_video_info_to_caps (&in_info); + + gst_harness_set_src_caps (flip, in_caps); + + e = gst_harness_pull_event (flip); + fail_unless_equals_int (GST_EVENT_TYPE (e), GST_EVENT_STREAM_START); + gst_event_unref (e); + e = gst_harness_pull_event (flip); + fail_unless_equals_int (GST_EVENT_TYPE (e), GST_EVENT_CAPS); + gst_event_parse_caps (e, &out_caps); + fail_unless (gst_video_info_from_caps (&out_info, out_caps)); + fail_unless_equals_int (GST_VIDEO_INFO_WIDTH (&in_info), + GST_VIDEO_INFO_WIDTH (&out_info)); + fail_unless_equals_int (GST_VIDEO_INFO_HEIGHT (&in_info), + GST_VIDEO_INFO_HEIGHT (&out_info)); + gst_event_unref (e); + + e = gst_harness_pull_event (flip); + fail_unless_equals_int (GST_EVENT_TYPE (e), GST_EVENT_SEGMENT); + gst_event_unref (e); + + buf = create_test_video_buffer_rgba8 (&in_info); + buf = gst_harness_push_and_pull (flip, buf); + fail_unless (buf != NULL); + gst_buffer_unref (buf); + + g_object_set (flip->element, "video-direction", 1 /* 90r */ , NULL); + + buf = create_test_video_buffer_rgba8 (&in_info); + fail_unless_equals_int (gst_harness_push (flip, buf), GST_FLOW_OK); + e = gst_harness_pull_event (flip); + fail_unless_equals_int (GST_EVENT_TYPE (e), GST_EVENT_CAPS); + gst_event_parse_caps (e, &out_caps); + fail_unless (gst_video_info_from_caps (&out_info, out_caps)); + fail_unless_equals_int (GST_VIDEO_INFO_WIDTH (&in_info), + GST_VIDEO_INFO_HEIGHT (&out_info)); + fail_unless_equals_int (GST_VIDEO_INFO_HEIGHT (&in_info), + GST_VIDEO_INFO_WIDTH (&out_info)); + gst_event_unref (e); + buf = gst_harness_pull (flip); + fail_unless (buf != NULL); + gst_buffer_unref (buf); + + gst_harness_teardown (flip); +} + +GST_END_TEST; + +GST_START_TEST (test_change_method_twice_same_caps_different_method) +{ + GstHarness *flip = gst_harness_new ("videoflip"); + GstVideoInfo in_info, out_info; + GstCaps *in_caps, *out_caps; + GstEvent *e; + GstBuffer *input, *output, *buf; + GstMapInfo in_map_info, out_map_info; + + gst_video_info_set_format (&in_info, GST_VIDEO_FORMAT_RGBA, 4, 9); + in_caps = gst_video_info_to_caps (&in_info); + + gst_harness_set_src_caps (flip, in_caps); + + e = gst_harness_pull_event (flip); + fail_unless_equals_int (GST_EVENT_TYPE (e), GST_EVENT_STREAM_START); + gst_event_unref (e); + e = gst_harness_pull_event (flip); + fail_unless_equals_int (GST_EVENT_TYPE (e), GST_EVENT_CAPS); + gst_event_parse_caps (e, &out_caps); + fail_unless (gst_video_info_from_caps (&out_info, out_caps)); + fail_unless_equals_int (GST_VIDEO_INFO_WIDTH (&in_info), + GST_VIDEO_INFO_WIDTH (&out_info)); + fail_unless_equals_int (GST_VIDEO_INFO_HEIGHT (&in_info), + GST_VIDEO_INFO_HEIGHT (&out_info)); + gst_event_unref (e); + + e = gst_harness_pull_event (flip); + fail_unless_equals_int (GST_EVENT_TYPE (e), GST_EVENT_SEGMENT); + gst_event_unref (e); + + buf = create_test_video_buffer_rgba8 (&in_info); + buf = gst_harness_push_and_pull (flip, buf); + fail_unless (buf != NULL); + gst_buffer_unref (buf); + + g_object_set (flip->element, "video-direction", 1 /* 90r */ , NULL); + g_object_set (flip->element, "video-direction", 2 /* 180 */ , NULL); + + input = create_test_video_buffer_rgba8 (&in_info); + fail_unless_equals_int (gst_harness_push (flip, gst_buffer_ref (input)), + GST_FLOW_OK); + /* caps will not change and basetransform won't send updated ones so we + * can't check for them */ + output = gst_harness_pull (flip); + fail_unless (output != NULL); + + fail_unless (gst_buffer_map (input, &in_map_info, GST_MAP_READ)); + fail_unless (gst_buffer_map (output, &out_map_info, GST_MAP_READ)); + + { + gsize top_right = (GST_VIDEO_INFO_WIDTH (&in_info) - 1) * 4; + gsize bottom_left = + (GST_VIDEO_INFO_HEIGHT (&out_info) - + 1) * GST_VIDEO_INFO_PLANE_STRIDE (&out_info, 0); + + fail_unless_equals_int (in_map_info.data[top_right + 0], + out_map_info.data[bottom_left + 0]); + fail_unless_equals_int (in_map_info.data[top_right + 1], + out_map_info.data[bottom_left + 1]); + fail_unless_equals_int (in_map_info.data[top_right + 2], + out_map_info.data[bottom_left + 2]); + fail_unless_equals_int (in_map_info.data[top_right + 3], + out_map_info.data[bottom_left + 3]); + } + + gst_buffer_unmap (input, &in_map_info); + gst_buffer_unmap (output, &out_map_info); + + gst_buffer_unref (input); + gst_buffer_unref (output); + + gst_harness_teardown (flip); +} + +GST_END_TEST; +GST_START_TEST (test_stress_change_method) +{ + GstHarness *flip = gst_harness_new ("videoflip"); + GParamSpec *pspec = + g_object_class_find_property (G_OBJECT_GET_CLASS (flip->element), + "video-direction"); + GstHarnessThread *thread_identity, *thread_90r; + GValue direction_identity = G_VALUE_INIT, direction_90r = G_VALUE_INIT; + GstVideoInfo in_info; + guint i = 0; +#define N_PUSHES 1000 + + gst_video_info_set_format (&in_info, GST_VIDEO_FORMAT_RGBA, 4, 9); + gst_harness_set_src_caps (flip, gst_video_info_to_caps (&in_info)); + + g_value_init (&direction_identity, pspec->value_type); + g_value_init (&direction_90r, pspec->value_type); + + fail_unless (gst_value_deserialize (&direction_identity, "identity")); + fail_unless (gst_value_deserialize (&direction_90r, "90r")); + + thread_identity = + gst_harness_stress_property_start_full (flip, "video-direction", + &direction_identity, 210); + thread_90r = + gst_harness_stress_property_start_full (flip, "video-direction", + &direction_90r, 160); + + while (i++ < N_PUSHES) { + GstBuffer *buf = create_test_video_buffer_rgba8 (&in_info); + buf = gst_harness_push_and_pull (flip, buf); + fail_unless (buf != NULL); + gst_buffer_unref (buf); + g_usleep (100); + } + + gst_harness_stress_thread_stop (thread_identity); + gst_harness_stress_thread_stop (thread_90r); + + g_value_unset (&direction_identity); + g_value_unset (&direction_90r); + + gst_harness_teardown (flip); +} + +GST_END_TEST; + +static Suite * +videoflip_suite (void) +{ + Suite *s = suite_create ("videoflip"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_passthrough); + tcase_add_test (tc_chain, test_change_method); + tcase_add_test (tc_chain, + test_change_method_twice_same_caps_different_method); + tcase_add_test (tc_chain, test_stress_change_method); + + return s; +} + +GST_CHECK_MAIN (videoflip); diff --git a/tests/check/elements/vp8dec.c b/tests/check/elements/vp8dec.c index 0ebd70ac29..4ff92c7c1f 100644 --- a/tests/check/elements/vp8dec.c +++ b/tests/check/elements/vp8dec.c @@ -19,6 +19,8 @@ */ #include +#include +#include static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, @@ -248,6 +250,38 @@ GST_START_TEST (test_decode_caps_change) GST_END_TEST; +GST_START_TEST (test_decode_invalid_resolution) +{ + GstHarness *h; + + guint8 invalid_width[] = { + 0x50, 0x48, 0x00, 0x9d, 0x01, 0x2a, 0x00, 0x00, 0x11, 0x44, 0x39, 0x63, + }; + guint8 invalid_height[] = { + 0x50, 0x48, 0x00, 0x9d, 0x01, 0x2a, 0x11, 0x44, 0x00, 0x00, 0x39, 0x63, + }; + + h = gst_harness_new_parse ("vp8dec"); + gst_harness_set_src_caps_str (h, "video/x-vp8"); + + fail_unless_equals_int (GST_FLOW_OK, + gst_harness_push (h, + gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, invalid_width, + sizeof (invalid_width), 0, sizeof (invalid_width), NULL, NULL))); + fail_unless (gst_harness_try_pull (h) == NULL); + + fail_unless_equals_int (GST_FLOW_OK, + gst_harness_push (h, + gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, invalid_height, + sizeof (invalid_height), 0, sizeof (invalid_height), NULL, + NULL))); + fail_unless (gst_harness_try_pull (h) == NULL); + + gst_harness_teardown (h); +} + +GST_END_TEST; + static Suite * vp8dec_suite (void) @@ -259,6 +293,7 @@ vp8dec_suite (void) tcase_add_test (tc_chain, test_decode_simple); tcase_add_test (tc_chain, test_decode_caps_change); + tcase_add_test (tc_chain, test_decode_invalid_resolution); return s; } diff --git a/tests/check/elements/vp8enc.c b/tests/check/elements/vp8enc.c index 86b1d929d1..e9d8c071f7 100644 --- a/tests/check/elements/vp8enc.c +++ b/tests/check/elements/vp8enc.c @@ -17,8 +17,9 @@ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ - +#include #include +#include static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, @@ -90,6 +91,7 @@ cleanup_vp8enc (GstElement * vp8enc) gst_check_teardown_element (vp8enc); } + GST_START_TEST (test_encode_simple) { GstElement *vp8enc; @@ -152,6 +154,106 @@ GST_START_TEST (test_encode_simple) GST_END_TEST; +#define gst_caps_new_i420(w, h) gst_caps_new_i420_full (w, h, 30, 1, 1, 1) +static GstCaps * +gst_caps_new_i420_full (gint width, gint height, gint fps_n, gint fps_d, + gint par_n, gint par_d) +{ + GstVideoInfo info; + gst_video_info_init (&info); + gst_video_info_set_format (&info, GST_VIDEO_FORMAT_I420, width, height); + GST_VIDEO_INFO_FPS_N (&info) = fps_n; + GST_VIDEO_INFO_FPS_D (&info) = fps_d; + GST_VIDEO_INFO_PAR_N (&info) = par_n; + GST_VIDEO_INFO_PAR_D (&info) = par_d; + return gst_video_info_to_caps (&info); +} + +static GstBuffer * +gst_harness_create_video_buffer_from_info (GstHarness * h, gint value, + GstVideoInfo * info, GstClockTime timestamp, GstClockTime duration) +{ + GstBuffer *buf; + gsize size; + + size = GST_VIDEO_INFO_SIZE (info); + + buf = gst_harness_create_buffer (h, size); + gst_buffer_memset (buf, 0, value, size); + g_assert (buf != NULL); + + gst_buffer_add_video_meta_full (buf, + GST_VIDEO_FRAME_FLAG_NONE, + GST_VIDEO_INFO_FORMAT (info), + GST_VIDEO_INFO_WIDTH (info), + GST_VIDEO_INFO_HEIGHT (info), + GST_VIDEO_INFO_N_PLANES (info), info->offset, info->stride); + + GST_BUFFER_PTS (buf) = timestamp; + GST_BUFFER_DURATION (buf) = duration; + + return buf; +} + +static GstBuffer * +gst_harness_create_video_buffer_full (GstHarness * h, gint value, + guint width, guint height, GstClockTime timestamp, GstClockTime duration) +{ + GstVideoInfo info; + + gst_video_info_init (&info); + gst_video_info_set_format (&info, GST_VIDEO_FORMAT_I420, width, height); + + return gst_harness_create_video_buffer_from_info (h, value, &info, + timestamp, duration); +} + +GST_START_TEST (test_encode_simple_when_bitrate_set_to_zero) +{ + GstHarness *h = gst_harness_new_parse ("vp8enc target-bitrate=0"); + GstBuffer *buf; + + gst_harness_set_src_caps (h, gst_caps_new_i420 (320, 240)); + + buf = gst_harness_create_video_buffer_full (h, 0x42, + 320, 240, 0, gst_util_uint64_scale (GST_SECOND, 1, 30)); + gst_harness_push (h, buf); + gst_buffer_unref (gst_harness_pull (h)); + gst_harness_teardown (h); +} + +GST_END_TEST; + +GST_START_TEST (test_autobitrate_changes_with_caps) +{ + gint bitrate = 0; + GstHarness *h = gst_harness_new ("vp8enc"); + gst_harness_set_src_caps (h, gst_caps_new_i420_full (1280, 720, 30, 1, 1, 1)); + + /* Default settings for 720p @ 30fps ~1.2Mbps */ + g_object_get (h->element, "target-bitrate", &bitrate, NULL); + fail_unless_equals_int (bitrate, 1199000); + + /* Change bits-per-pixel 0.036 to give us ~1Mbps */ + g_object_set (h->element, "bits-per-pixel", 0.037, NULL); + g_object_get (h->element, "target-bitrate", &bitrate, NULL); + fail_unless_equals_int (bitrate, 1022000); + + /* Halving the framerate should halve the auto bitrate */ + gst_harness_set_src_caps (h, gst_caps_new_i420_full (1280, 720, 15, 1, 1, 1)); + g_object_get (h->element, "target-bitrate", &bitrate, NULL); + fail_unless_equals_int (bitrate, 511000); + + /* Halving the resolution should quarter the auto bitrate */ + gst_harness_set_src_caps (h, gst_caps_new_i420_full (640, 360, 15, 1, 1, 1)); + g_object_get (h->element, "target-bitrate", &bitrate, NULL); + fail_unless_equals_int (bitrate, 127000); + + gst_harness_teardown (h); +} + +GST_END_TEST; + static Suite * vp8enc_suite (void) { @@ -161,6 +263,8 @@ vp8enc_suite (void) suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_encode_simple); + tcase_add_test (tc_chain, test_encode_simple_when_bitrate_set_to_zero); + tcase_add_test (tc_chain, test_autobitrate_changes_with_caps); return s; } diff --git a/tests/check/elements/vp9enc.c b/tests/check/elements/vp9enc.c index f7be0e0fbe..de9eabb625 100644 --- a/tests/check/elements/vp9enc.c +++ b/tests/check/elements/vp9enc.c @@ -21,6 +21,21 @@ #include #include +#define gst_caps_new_i420(w, h) gst_caps_new_i420_full (w, h, 30, 1, 1, 1) +static GstCaps * +gst_caps_new_i420_full (gint width, gint height, gint fps_n, gint fps_d, + gint par_n, gint par_d) +{ + GstVideoInfo info; + gst_video_info_init (&info); + gst_video_info_set_format (&info, GST_VIDEO_FORMAT_I420, width, height); + GST_VIDEO_INFO_FPS_N (&info) = fps_n; + GST_VIDEO_INFO_FPS_D (&info) = fps_d; + GST_VIDEO_INFO_PAR_N (&info) = par_n; + GST_VIDEO_INFO_PAR_D (&info) = par_d; + return gst_video_info_to_caps (&info); +} + GST_START_TEST (test_encode_lag_in_frames) { GstHarness *h = gst_harness_new_parse ("vp9enc lag-in-frames=5 cpu-used=8 " @@ -28,7 +43,7 @@ GST_START_TEST (test_encode_lag_in_frames) gint i; gst_harness_add_src_parse (h, "videotestsrc is-live=true pattern=black ! " - "capsfilter caps=\"video/x-raw,width=320,height=240,framerate=25/1\"", + "capsfilter caps=\"video/x-raw,format=I420,width=320,height=240,framerate=25/1\"", TRUE); /* Push 20 buffers into the encoder */ @@ -62,6 +77,36 @@ GST_START_TEST (test_encode_lag_in_frames) GST_END_TEST; +GST_START_TEST (test_autobitrate_changes_with_caps) +{ + gint bitrate = 0; + GstHarness *h = gst_harness_new ("vp9enc"); + gst_harness_set_src_caps (h, gst_caps_new_i420_full (1280, 720, 30, 1, 1, 1)); + + /* Default settings for 720p @ 30fps ~0.8Mbps */ + g_object_get (h->element, "target-bitrate", &bitrate, NULL); + fail_unless_equals_int (bitrate, 799000); + + /* Change bits-per-pixel 0.036 to give us ~1Mbps */ + g_object_set (h->element, "bits-per-pixel", 0.037, NULL); + g_object_get (h->element, "target-bitrate", &bitrate, NULL); + fail_unless_equals_int (bitrate, 1022000); + + /* Halving the framerate should halve the auto bitrate */ + gst_harness_set_src_caps (h, gst_caps_new_i420_full (1280, 720, 15, 1, 1, 1)); + g_object_get (h->element, "target-bitrate", &bitrate, NULL); + fail_unless_equals_int (bitrate, 511000); + + /* Halving the resolution should quarter the auto bitrate */ + gst_harness_set_src_caps (h, gst_caps_new_i420_full (640, 360, 15, 1, 1, 1)); + g_object_get (h->element, "target-bitrate", &bitrate, NULL); + fail_unless_equals_int (bitrate, 127000); + + gst_harness_teardown (h); +} + +GST_END_TEST; + static Suite * vp9enc_suite (void) { @@ -71,6 +116,7 @@ vp9enc_suite (void) suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_encode_lag_in_frames); + tcase_add_test (tc_chain, test_autobitrate_changes_with_caps); return s; } diff --git a/tests/check/meson.build b/tests/check/meson.build index 78cf84dc87..91efc62d3e 100644 --- a/tests/check/meson.build +++ b/tests/check/meson.build @@ -53,7 +53,9 @@ good_tests = [ [ 'elements/matroskamux', false, [gstriff_dep] ], [ 'elements/matroskaparse', false, [gstriff_dep] ], [ 'elements/multifile' ], - [ 'elements/splitmux', ], + [ 'elements/splitmuxsink', ], + [ 'elements/splitmuxsinktimecode', ], + [ 'elements/splitmuxsrc', ], [ 'elements/qtmux', false, [gstriff_dep, zlib_dep] ], [ 'elements/qtdemux', false, [gstriff_dep, zlib_dep] ], [ 'elements/rganalysis' ], @@ -63,17 +65,20 @@ good_tests = [ [ 'elements/rtph263' ], [ 'elements/rtph264' ], [ 'elements/rtph265' ], + [ 'elements/rtpopus' ], [ 'elements/rtpvp9' ], [ 'elements/rtpbin' ], [ 'elements/rtpbin_buffer_list' ], [ 'elements/rtpcollision' ], [ 'elements/rtpfunnel' ], - [ 'elements/rtpjitterbuffer', false, [gstrtp_dep], - ['../../gst/rtpmanager/gstrtpjitterbuffer.c', - '../../gst/rtpmanager/rtpjitterbuffer.c', - '../../gst/rtpmanager/rtpstats.c', - '../../gst/rtpmanager/rtptimerqueue.c']], + [ 'elements/rtpjitterbuffer' ], + [ 'elements/rtpjpeg' ], + + [ 'elements/rtptimerqueue', false, [gstrtp_dep], + ['../../gst/rtpmanager/rtptimerqueue.c']], + [ 'elements/rtpmux' ], + [ 'elements/rtpptdemux' ], [ 'elements/rtprtx' ], [ 'elements/rtpsession' ], [ 'elements/rtpstorage', false, [], ['../../gst/rtp/gstrtpstorage.c', @@ -90,6 +95,7 @@ good_tests = [ [ 'elements/videobox' ], [ 'elements/videocrop' ], [ 'elements/videofilter' ], + [ 'elements/videoflip' ], [ 'elements/videomixer' ], [ 'elements/aspectratiocrop' ], [ 'pipelines/wavenc' ], @@ -146,10 +152,14 @@ test_defines = [ pluginsdirs = [] if gst_dep.type_name() == 'pkgconfig' - pbase = dependency('gstreamer-plugins-base-' + api_version, required : false) + pbase = dependency('gstreamer-plugins-base-' + api_version, required: true) pluginsdirs = [gst_dep.get_pkgconfig_variable('pluginsdir'), pbase.get_pkgconfig_variable('pluginsdir')] + gst_plugin_scanner_dir = gst_dep.get_pkgconfig_variable('pluginscannerdir') +else + gst_plugin_scanner_dir = subproject('gstreamer').get_variable('gst_scanner_dir') endif +gst_plugin_scanner_path = join_paths(gst_plugin_scanner_dir, 'gst-plugin-scanner') # fake device drivers: we could run hardware element tests against dummy drivers # v4l2: vivo (part of normal kernel) @@ -186,11 +196,12 @@ foreach t : good_tests env.set('GST_STATE_IGNORE_ELEMENTS', state_ignore_elements) env.set('CK_DEFAULT_TIMEOUT', '20') env.set('GST_PLUGIN_LOADING_WHITELIST', 'gstreamer', 'gst-plugins-base', - 'gst-plugins-good@' + meson.build_root()) + 'timecode', 'gst-plugins-good@' + meson.build_root()) env.set('GST_PLUGIN_PATH_1_0', [meson.build_root()] + pluginsdirs) env.set('GSETTINGS_BACKEND', 'memory') env.set('GST_REGISTRY', join_paths(meson.current_build_dir(), '@0@.registry'.format(test_name))) + env.set('GST_PLUGIN_SCANNER_1_0', gst_plugin_scanner_path) exe = executable(test_name, fname, extra_sources, include_directories : [configinc, libsinc], c_args : ['-DHAVE_CONFIG_H=1' ] + test_defines, diff --git a/tests/examples/gtk/meson.build b/tests/examples/gtk/meson.build index 36953dc56b..76e9f4f8ea 100644 --- a/tests/examples/gtk/meson.build +++ b/tests/examples/gtk/meson.build @@ -4,7 +4,7 @@ executable('gtksink', 'gtksink.c', include_directories: [configinc], install: false) -if build_gstgl +if have_gstgl executable('gtkglsink', 'gtkglsink.c', dependencies: [gst_dep, gstgl_dep, gtk_dep, x11_dep], c_args: gst_plugins_good_args, @@ -12,7 +12,7 @@ if build_gstgl install: false) executable('glliveshader', 'glliveshader.c', - dependencies: [gst_dep, gstgl_dep, gtk_dep, x11_dep], + dependencies: [gst_dep, gstgl_dep, gstglproto_dep, gtk_dep, x11_dep], c_args: gst_plugins_good_args, include_directories: [configinc], install: false) diff --git a/tests/examples/meson.build b/tests/examples/meson.build index eec85b4ab4..d5fa1279fd 100644 --- a/tests/examples/meson.build +++ b/tests/examples/meson.build @@ -2,6 +2,11 @@ subdir('audiofx') subdir('cairo') subdir('level') subdir('qt') + +if is_variable('gstrpicamsrc') + subdir('rpicamsrc') +endif + subdir('rtp') subdir('rtsp') subdir('shapewipe') diff --git a/tests/examples/qt/meson.build b/tests/examples/qt/meson.build index 3fa08cfa2c..ede4b5a444 100644 --- a/tests/examples/qt/meson.build +++ b/tests/examples/qt/meson.build @@ -1,2 +1,20 @@ +if qt5_option.disabled() + subdir_done() +endif + +# We already did all the checks when building the qt plugin +if not qt5qml_dep.found() + subdir_done() +endif + +qt5qml_example_deps = dependency('qt5', modules : ['Core', 'Gui', 'Widgets', 'Qml', 'Quick'], + required: get_option('examples')) + +if not qt5qml_example_deps.found() + subdir_done() +endif + +subdir('qmloverlay') subdir('qmlsink') +subdir('qmlsink-dynamically-added') subdir('qmlsrc') diff --git a/tests/examples/qt/qmloverlay/main.cpp b/tests/examples/qt/qmloverlay/main.cpp new file mode 100644 index 0000000000..dbe3629398 --- /dev/null +++ b/tests/examples/qt/qmloverlay/main.cpp @@ -0,0 +1,125 @@ +#include +#include +#include +#include +#include +#include +#include + +class SetPlaying : public QRunnable +{ +public: + SetPlaying(GstElement *); + ~SetPlaying(); + + void run (); + +private: + GstElement * pipeline_; +}; + +SetPlaying::SetPlaying (GstElement * pipeline) +{ + this->pipeline_ = pipeline ? static_cast (gst_object_ref (pipeline)) : NULL; +} + +SetPlaying::~SetPlaying () +{ + if (this->pipeline_) + gst_object_unref (this->pipeline_); +} + +void +SetPlaying::run () +{ + if (this->pipeline_) + gst_element_set_state (this->pipeline_, GST_STATE_PLAYING); +} + +static void +on_overlay_scene_initialized (GstElement * overlay, gpointer unused) +{ + QQuickItem *rootObject; + GST_INFO ("scene initialized"); + g_object_get (overlay, "root-item", &rootObject, NULL); + QQuickItem *videoItem = rootObject->findChild ("inputVideoItem"); + g_object_set (overlay, "widget", videoItem, NULL); +} + +int main(int argc, char *argv[]) +{ + int ret; + + gst_init (&argc, &argv); + + { + QGuiApplication app(argc, argv); + + GstElement *pipeline = gst_pipeline_new (NULL); + GstElement *src = gst_element_factory_make ("videotestsrc", NULL); + GstElement *glupload = gst_element_factory_make ("glupload", NULL); + /* the plugin must be loaded before loading the qml file to register the + * GstGLVideoItem qml item */ + GstElement *overlay = gst_element_factory_make ("qmlgloverlay", NULL); + GstElement *overlay2 = gst_element_factory_make ("qmlgloverlay", NULL); + GstElement *sink = gst_element_factory_make ("qmlglsink", NULL); + + g_assert (src && glupload && overlay && sink); + + gst_bin_add_many (GST_BIN (pipeline), src, glupload, overlay, overlay2, sink, NULL); + gst_element_link_many (src, glupload, overlay, overlay2, sink, NULL); + + /* load qmlglsink output */ + QQmlApplicationEngine engine; + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + + QQuickItem *videoItem; + QQuickWindow *rootObject; + + /* find and set the videoItem on the sink */ + rootObject = static_cast (engine.rootObjects().first()); + videoItem = rootObject->findChild ("videoItem"); + g_assert (videoItem); + g_object_set(sink, "widget", videoItem, NULL); + + QDirIterator it(":", QDirIterator::Subdirectories); + while (it.hasNext()) { + qDebug() << it.next(); + } + + QFile f(":/overlay.qml"); + if(!f.open(QIODevice::ReadOnly)) { + qWarning() << "error: " << f.errorString(); + return 1; + } + QByteArray overlay_scene = f.readAll(); + qDebug() << overlay_scene; + + QFile f2(":/overlay2.qml"); + if(!f2.open(QIODevice::ReadOnly)) { + qWarning() << "error: " << f2.errorString(); + return 1; + } + QByteArray overlay_scene2 = f2.readAll(); + qDebug() << overlay_scene2; + + /* load qmlgloverlay contents */ + g_signal_connect (overlay, "qml-scene-initialized", G_CALLBACK (on_overlay_scene_initialized), NULL); + g_object_set (overlay, "qml-scene", overlay_scene.data(), NULL); + + g_signal_connect (overlay2, "qml-scene-initialized", G_CALLBACK (on_overlay_scene_initialized), NULL); + g_object_set (overlay2, "qml-scene", overlay_scene2.data(), NULL); + + rootObject->scheduleRenderJob (new SetPlaying (pipeline), + QQuickWindow::BeforeSynchronizingStage); + + ret = app.exec(); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); + } + + gst_deinit (); + + return ret; +} diff --git a/tests/examples/qt/qmloverlay/main.qml b/tests/examples/qt/qmloverlay/main.qml new file mode 100644 index 0000000000..0113a1b14b --- /dev/null +++ b/tests/examples/qt/qmloverlay/main.qml @@ -0,0 +1,39 @@ +import QtQuick 2.4 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.3 +import QtQuick.Dialogs 1.2 +import QtQuick.Window 2.1 + +import org.freedesktop.gstreamer.GLVideoItem 1.0 + +ApplicationWindow { + id: window + visible: true + width: 640 + height: 480 + x: 30 + y: 30 + color: "black" + + Item { + anchors.fill: parent + + GstGLVideoItem { + id: video + objectName: "videoItem" + anchors.centerIn: parent + width: parent.width + height: parent.height + } + + Text { + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + text: "qmlglsink text" + font.pointSize: 20 + color: "yellow" + style: Text.Outline + styleColor: "blue" + } + } +} diff --git a/tests/examples/qt/qmloverlay/meson.build b/tests/examples/qt/qmloverlay/meson.build new file mode 100644 index 0000000000..b1912463fb --- /dev/null +++ b/tests/examples/qt/qmloverlay/meson.build @@ -0,0 +1,11 @@ +sources = [ + 'main.cpp', +] + +qt_preprocessed = qt5_mod.preprocess(qresources : 'qmloverlay.qrc') +executable('qmlgloverlay', sources, qt_preprocessed, + dependencies : [gst_dep, qt5qml_example_deps], + override_options : ['cpp_std=c++11'], + c_args : gst_plugins_good_args, + include_directories : [configinc], + install: false) diff --git a/tests/examples/qt/qmloverlay/overlay.qml b/tests/examples/qt/qmloverlay/overlay.qml new file mode 100644 index 0000000000..81faeb573c --- /dev/null +++ b/tests/examples/qt/qmloverlay/overlay.qml @@ -0,0 +1,57 @@ +import QtQuick 2.4 + +import org.freedesktop.gstreamer.GLVideoItem 1.0 + +Item { + /* render upside down for GStreamer */ + transform: Scale { origin.x : 0; origin.y : height / 2.; yScale : -1 } + + GstGLVideoItem { + id: video + objectName: "inputVideoItem" + anchors.centerIn: parent + width: parent.width + height: parent.height + } + + Text { + id: rotatingText + anchors.centerIn: parent + text: "Qt Quick\nrendered to\na texture" + font.pointSize: 20 + color: "black" + style: Text.Outline + styleColor: "white" + + RotationAnimator { + target: rotatingText; + from: 0; + to: 360; + duration: 5000 + running: true + loops: Animation.Infinite + } + } + + Text { + property int elapsedTime: 0 + + id: time + anchors.top: rotatingText.bottom + anchors.horizontalCenter: rotatingText.horizontalCenter + font.pointSize: 12 + style: Text.Outline + styleColor: "black" + color: "white" + + Timer { + interval: 1000 + running: true + repeat: true + onTriggered: { + parent.elapsedTime += interval / 1000 + parent.text = "overlay: " + parent.elapsedTime.toString() + " seconds" + } + } + } +} diff --git a/tests/examples/qt/qmloverlay/overlay2.qml b/tests/examples/qt/qmloverlay/overlay2.qml new file mode 100644 index 0000000000..fbe832a392 --- /dev/null +++ b/tests/examples/qt/qmloverlay/overlay2.qml @@ -0,0 +1,57 @@ +import QtQuick 2.4 + +import org.freedesktop.gstreamer.GLVideoItem 1.0 + +Item { + /* render upside down for GStreamer */ + transform: Scale { origin.x : 0; origin.y : height / 2.; yScale : -1 } + + GstGLVideoItem { + id: video + objectName: "inputVideoItem" + anchors.centerIn: parent + width: parent.width + height: parent.height + } + + Text { + id: rotatingText + anchors.centerIn: parent + text: "Qt Quick\nrendered to\na texture" + font.pointSize: 20 + color: "black" + style: Text.Outline + styleColor: "white" + + RotationAnimator { + target: rotatingText; + from: 0; + to: 360; + duration: 10000 + running: true + loops: Animation.Infinite + } + } + + Text { + property int elapsedTime: 0 + + id: time + anchors.bottom: rotatingText.top + anchors.horizontalCenter: rotatingText.horizontalCenter + font.pointSize: 12 + style: Text.Outline + styleColor: "red" + color: "black" + + Timer { + interval: 1000 + running: true + repeat: true + onTriggered: { + parent.elapsedTime += interval / 1000 + parent.text = "overlay: " + parent.elapsedTime.toString() + " seconds" + } + } + } +} diff --git a/tests/examples/qt/qmloverlay/qmloverlay.qrc b/tests/examples/qt/qmloverlay/qmloverlay.qrc new file mode 100644 index 0000000000..42fb250d63 --- /dev/null +++ b/tests/examples/qt/qmloverlay/qmloverlay.qrc @@ -0,0 +1,7 @@ + + + main.qml + overlay.qml + overlay2.qml + + diff --git a/tests/examples/qt/qmlsink-dynamically-added/.gitignore b/tests/examples/qt/qmlsink-dynamically-added/.gitignore new file mode 100644 index 0000000000..9bbbbc922f --- /dev/null +++ b/tests/examples/qt/qmlsink-dynamically-added/.gitignore @@ -0,0 +1,4 @@ +deployment.pri +play +qrc_qmlsink.cpp +*.o diff --git a/tests/examples/qt/qmlsink-dynamically-added/main.cpp b/tests/examples/qt/qmlsink-dynamically-added/main.cpp new file mode 100644 index 0000000000..dede86dc64 --- /dev/null +++ b/tests/examples/qt/qmlsink-dynamically-added/main.cpp @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +static GstBusSyncReply +on_sync_bus_message (GstBus * bus, GstMessage * msg, gpointer data) +{ + GstElement *pipeline = (GstElement *) data; + + switch (GST_MESSAGE_TYPE (msg)) { + case GST_MESSAGE_HAVE_CONTEXT: { + GstContext *context; + + gst_message_parse_have_context (msg, &context); + + /* if you need specific behviour or a context from a specific element, + * you need to be selective about which context's you set on the + * pipeline */ + if (gst_context_has_context_type (context, GST_GL_DISPLAY_CONTEXT_TYPE)) { + gst_println ("got have-context %p", context); + gst_element_set_context (pipeline, context); + } + + if (context) + gst_context_unref (context); + gst_message_unref (msg); + return GST_BUS_DROP; + } + default: + break; + } + + return GST_BUS_PASS; +} + +static void +connect_tee (GstElement * tee, GstElement * queue) +{ + gst_println ("attaching tee/queue %p %p", tee, queue); + gst_element_link (tee, queue); +} + +static void +connect_qmlglsink (GstElement * pipeline, GstElement * tee, QQuickWindow * rootObject) +{ + GstElement *queue = gst_element_factory_make ("queue", NULL); + GstElement *qmlglsink = gst_element_factory_make ("qmlglsink", NULL); + QQuickItem *videoItem; + + gst_println ("attaching qmlglsink %s at %p", GST_OBJECT_NAME (qmlglsink), qmlglsink); + + gst_bin_add (GST_BIN (pipeline), queue); + gst_bin_add (GST_BIN (pipeline), qmlglsink); + gst_element_link (queue, qmlglsink); + gst_element_set_state (queue, GST_STATE_PLAYING); + + videoItem = rootObject->findChild ("videoItem"); + g_assert (videoItem); + g_object_set (qmlglsink, "widget", videoItem, NULL); + + gst_element_set_state (qmlglsink, GST_STATE_PAUSED); + connect_tee (tee, queue); + gst_element_set_state (qmlglsink, GST_STATE_PLAYING); +} + +int main(int argc, char *argv[]) +{ + int ret; + + gst_init (&argc, &argv); + + { + QGuiApplication app(argc, argv); + + /* test a whole bunch of elements respect the change in display + * and therefore OpenGL context */ + GstElement *pipeline = gst_parse_launch ("gltestsrc ! " + "capsfilter caps=video/x-raw(ANY),framerate=10/1 ! glupload ! " + "glcolorconvert ! glalpha noise-level=16 method=green angle=40 ! " + "glcolorbalance hue=0.25 ! gltransformation rotation-x=30 ! " + "glvideomixerelement ! glviewconvert output-mode-override=side-by-side ! " + "glstereosplit name=s " + "glstereomix name=m ! tee name=t ! queue ! fakesink sync=true " + "s.left ! queue ! m.sink_0 " + "s.right ! queue ! m.sink_1", NULL); + GstBus *bus = gst_element_get_bus (pipeline); + gst_bus_set_sync_handler (bus, on_sync_bus_message, pipeline, NULL); + gst_object_unref (bus); + /* the plugin must be loaded before loading the qml file to register the + * GstGLVideoItem qml item */ + GstElement *sink = gst_element_factory_make ("qmlglsink", NULL); + + g_assert (pipeline && sink); + gst_object_unref (sink); + + QQuickWindow *rootObject; + + /* The Qml scene starts out with the widget not connected to any qmlglsink + * element */ + QQmlApplicationEngine engine; + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + + /* find and set the videoItem on the sink */ + rootObject = static_cast (engine.rootObjects().first()); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + + GstElement *t = gst_bin_get_by_name (GST_BIN (pipeline), "t"); + gst_object_unref (t); /* ref held by pipeline */ + /* add the qmlglsink element */ + QTimer::singleShot(5000, [pipeline, t, rootObject]() { connect_qmlglsink (pipeline, t, rootObject); } ); + + ret = app.exec(); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); + } + + gst_deinit (); + + return ret; +} diff --git a/tests/examples/qt/qmlsink-dynamically-added/main.qml b/tests/examples/qt/qmlsink-dynamically-added/main.qml new file mode 100644 index 0000000000..ffd3cd1650 --- /dev/null +++ b/tests/examples/qt/qmlsink-dynamically-added/main.qml @@ -0,0 +1,60 @@ +import QtQuick 2.4 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.3 +import QtQuick.Dialogs 1.2 +import QtQuick.Window 2.1 + +import org.freedesktop.gstreamer.GLVideoItem 1.0 + +ApplicationWindow { + id: window + visible: true + width: 640 + height: 480 + x: 30 + y: 30 + color: "black" + + Item { + anchors.fill: parent + + GstGLVideoItem { + id: video + objectName: "videoItem" + anchors.centerIn: parent + width: parent.width + height: parent.height + } + + Rectangle { + color: Qt.rgba(1, 1, 1, 0.7) + border.width: 1 + border.color: "white" + anchors.bottom: video.bottom + anchors.bottomMargin: 15 + anchors.horizontalCenter: parent.horizontalCenter + width : parent.width - 30 + height: parent.height - 30 + radius: 8 + + MouseArea { + id: mousearea + anchors.fill: parent + hoverEnabled: true + onEntered: { + parent.opacity = 1.0 + hidetimer.start() + } + } + + Timer { + id: hidetimer + interval: 5000 + onTriggered: { + parent.opacity = 0.0 + stop() + } + } + } + } +} diff --git a/tests/examples/qt/qmlsink-dynamically-added/meson.build b/tests/examples/qt/qmlsink-dynamically-added/meson.build new file mode 100644 index 0000000000..783011aa07 --- /dev/null +++ b/tests/examples/qt/qmlsink-dynamically-added/meson.build @@ -0,0 +1,11 @@ +sources = [ + 'main.cpp', +] + +qt_preprocessed = qt5_mod.preprocess(qresources : 'qmlsink-dyn-added.qrc') +executable('qmlsink-dynamically-added', sources, qt_preprocessed, + dependencies : [gst_dep, gstgl_dep, qt5qml_example_deps], + override_options : ['cpp_std=c++11'], + c_args : gst_plugins_good_args, + include_directories : [configinc], + install: false) diff --git a/tests/examples/qt/qmlsink-dynamically-added/play.pro b/tests/examples/qt/qmlsink-dynamically-added/play.pro new file mode 100644 index 0000000000..2e8192f5d2 --- /dev/null +++ b/tests/examples/qt/qmlsink-dynamically-added/play.pro @@ -0,0 +1,20 @@ +TEMPLATE = app + +QT += qml quick widgets + +QT_CONFIG -= no-pkg-config +CONFIG += link_pkgconfig debug +PKGCONFIG = \ + gstreamer-1.0 \ + gstreamer-video-1.0 + +DEFINES += GST_USE_UNSTABLE_API + +INCLUDEPATH += ../lib + +SOURCES += main.cpp + +RESOURCES += qmlsink-dyn-added.qrc + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = diff --git a/tests/examples/qt/qmlsink-dynamically-added/qmlsink-dyn-added.qrc b/tests/examples/qt/qmlsink-dynamically-added/qmlsink-dyn-added.qrc new file mode 100644 index 0000000000..5f6483ac33 --- /dev/null +++ b/tests/examples/qt/qmlsink-dynamically-added/qmlsink-dyn-added.qrc @@ -0,0 +1,5 @@ + + + main.qml + + diff --git a/tests/examples/qt/qmlsink/meson.build b/tests/examples/qt/qmlsink/meson.build index 2f444372d3..5e2d1c93b9 100644 --- a/tests/examples/qt/qmlsink/meson.build +++ b/tests/examples/qt/qmlsink/meson.build @@ -2,19 +2,10 @@ sources = [ 'main.cpp', ] -if have_cxx and build_gstgl and gstgl_dep.found() - qt5_mod = import('qt5') - qt5qml_deps = dependency('qt5', modules : ['Core', 'Gui', 'Widgets', 'Qml', 'Quick'], - required: get_option('examples')) - - # FIXME Add a way to get that information out of the qt5 module - moc = find_program('moc-qt5', 'moc', required : get_option('examples')) - if qt5qml_deps.found() and moc.found() - qt_preprocessed = qt5_mod.preprocess(qresources : 'qmlsink.qrc') - executable('qmlsink', sources, qt_preprocessed, - dependencies : [gst_dep, qt5qml_deps], - c_args : gst_plugins_good_args, - include_directories : [configinc], - install: false) - endif -endif +qt_preprocessed = qt5_mod.preprocess(qresources : 'qmlsink.qrc') +executable('qmlsink', sources, qt_preprocessed, + dependencies : [gst_dep, qt5qml_example_deps], + override_options : ['cpp_std=c++11'], + c_args : gst_plugins_good_args, + include_directories : [configinc], + install: false) diff --git a/tests/examples/qt/qmlsrc/meson.build b/tests/examples/qt/qmlsrc/meson.build index 122e4a6176..c7f3add642 100644 --- a/tests/examples/qt/qmlsrc/meson.build +++ b/tests/examples/qt/qmlsrc/meson.build @@ -2,18 +2,10 @@ sources = [ 'main.cpp', ] -if have_cxx and build_gstgl and gstgl_dep.found() - qt5_mod = import('qt5') - qt5qml_deps = dependency('qt5', modules : ['Core', 'Gui', 'Widgets', 'Qml', 'Quick'], - required: get_option('examples')) - # FIXME Add a way to get that information out of the qt5 module - moc = find_program('moc-qt5', 'moc', required : get_option('examples')) - if qt5qml_deps.found() and moc.found() - qt_preprocessed = qt5_mod.preprocess(qresources : 'qmlsrc.qrc') - executable('qmlsrc', sources, qt_preprocessed, - dependencies : [gst_dep, qt5qml_deps], - c_args : gst_plugins_good_args, - include_directories : [configinc], - install: false) - endif -endif +qt_preprocessed = qt5_mod.preprocess(qresources : 'qmlsrc.qrc') +executable('qmlsrc', sources, qt_preprocessed, + dependencies : [gst_dep, qt5qml_example_deps], + override_options : ['cpp_std=c++11'], + c_args : gst_plugins_good_args, + include_directories : [configinc], + install: false) diff --git a/tests/examples/rpicamsrc/dynamicprops.py b/tests/examples/rpicamsrc/dynamicprops.py new file mode 100755 index 0000000000..6c1816fbe2 --- /dev/null +++ b/tests/examples/rpicamsrc/dynamicprops.py @@ -0,0 +1,68 @@ +#!/usr/bin/python3 + +import sys +import gi +gi.require_version('Gst', '1.0') +from gi.repository import GObject, Gst + +def bus_call(bus, msg, *args): + # print("BUSCALL", msg, msg.type, *args) + if msg.type == Gst.MessageType.EOS: + print("End-of-stream") + loop.quit() + return + elif msg.type == Gst.MessageType.ERROR: + print("GST ERROR", msg.parse_error()) + loop.quit() + return + return True + +saturation = -100 +def set_saturation(pipeline): + global saturation + if saturation <= 100: + print("Setting saturation to {0}".format(saturation)) + videosrc.set_property("saturation", saturation) + videosrc.set_property("annotation-text", "Saturation %d" % (saturation)) + else: + pipeline.send_event (Gst.Event.new_eos()) + return False + saturation += 10 + return True + + +if __name__ == "__main__": + GObject.threads_init() + # initialization + loop = GObject.MainLoop() + Gst.init(None) + + pipeline = Gst.parse_launch ("rpicamsrc name=src ! video/x-h264,width=320,height=240 ! h264parse ! mp4mux ! filesink name=s") + if pipeline == None: + print ("Failed to create pipeline") + sys.exit(0) + + # watch for messages on the pipeline's bus (note that this will only + # work like this when a GLib main loop is running) + bus = pipeline.get_bus() + bus.add_watch(0, bus_call, loop) + + videosrc = pipeline.get_by_name ("src") + videosrc.set_property("saturation", saturation) + videosrc.set_property("annotation-mode", 1) + + sink = pipeline.get_by_name ("s") + sink.set_property ("location", "test.mp4") + + # this will call set_saturation every 1s + GObject.timeout_add(1000, set_saturation, pipeline) + + # run + pipeline.set_state(Gst.State.PLAYING) + try: + loop.run() + except Exception as e: + print(e) + # cleanup + pipeline.set_state(Gst.State.NULL) + diff --git a/tests/examples/rpicamsrc/meson.build b/tests/examples/rpicamsrc/meson.build new file mode 100644 index 0000000000..87aa482805 --- /dev/null +++ b/tests/examples/rpicamsrc/meson.build @@ -0,0 +1,11 @@ +executable('rpicamsrc-test-color-balance', 'test_color_balance.c', + dependencies: [gstvideo_dep, gst_dep], + c_args: gst_plugins_good_args, + include_directories : [configinc], + install: false) + +executable('rpicamsrc-test-orientation', 'test_orientation.c', + dependencies: [gstvideo_dep, gst_dep], + c_args: gst_plugins_good_args, + include_directories: [configinc], + install: false) diff --git a/tests/examples/rpicamsrc/test_color_balance.c b/tests/examples/rpicamsrc/test_color_balance.c new file mode 100644 index 0000000000..a67b726b9f --- /dev/null +++ b/tests/examples/rpicamsrc/test_color_balance.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2015, Igalia S.L + * Author: Philippe Normand + * Licence: LGPL. (See COPYING.LGPL) + */ + +#include +#include +#include + +#define CONTROL_SATURATION 1 +#define CONTROL_BRIGHTNESS 1 +#define CONTROL_CONTRAST 1 + +#define PIPELINE "rpicamsrc name=src preview=0 fullscreen=0 ! h264parse ! omxh264dec ! glimagesink sync=0" + +#define declare_value(name, value) \ + static gint current_##name = value; \ + static gboolean incrementing_##name = TRUE; + +#if CONTROL_SATURATION +declare_value (SATURATION, 50); +#endif +#if CONTROL_BRIGHTNESS +declare_value (BRIGHTNESS, 50); +#endif +#if CONTROL_CONTRAST +declare_value (CONTRAST, 0); +#endif + +#define update(name, channel, current_value) \ + if (!g_strcmp0(channel->label, #name)) { \ + if (current_value >= channel->max_value) \ + incrementing_##name = FALSE; \ + else if (current_value <= channel->min_value) \ + incrementing_##name = TRUE; \ + current_##name += incrementing_##name ? 10 : -10; \ + g_print("new " #name ": %d\n", current_##name); \ + return current_##name; \ + } + +static gint +compute_value (GstColorBalanceChannel * channel, gint current_value) +{ +#if CONTROL_SATURATION + update (SATURATION, channel, current_value); +#endif +#if CONTROL_BRIGHTNESS + update (BRIGHTNESS, channel, current_value); +#endif +#if CONTROL_CONTRAST + update (CONTRAST, channel, current_value); +#endif + return current_value; +} + +static gboolean +process (gpointer data) +{ + GstColorBalance *balance = (GstColorBalance *) data; + const GList *controls; + GstColorBalanceChannel *channel; + const GList *item; + gint index, new_value, current_value; + + controls = gst_color_balance_list_channels (balance); + + if (controls == NULL) { + g_printerr ("There is no list of colorbalance controls\n"); + return G_SOURCE_REMOVE; + } + + for (item = controls, index = 0; item != NULL; item = item->next, ++index) { + channel = item->data; + current_value = gst_color_balance_get_value (balance, channel); + new_value = compute_value (channel, current_value); + gst_color_balance_set_value (balance, channel, new_value); + } + + return G_SOURCE_CONTINUE; +} + +int +main (int argc, char **argv) +{ + GMainLoop *loop; + GstElement *pipeline; + GError *error = NULL; + GstElement *src; + GstColorBalance *balance; + + gst_init (&argc, &argv); + loop = g_main_loop_new (NULL, FALSE); + + pipeline = gst_parse_launch (PIPELINE, &error); + if (error != NULL) { + g_printerr ("Error parsing '%s': %s", PIPELINE, error->message); + g_error_free (error); + return -1; + } + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + src = gst_bin_get_by_name (GST_BIN (pipeline), "src"); + if (!src) { + g_printerr ("Source element not found\n"); + return -2; + } + + balance = GST_COLOR_BALANCE (src); + g_timeout_add_seconds (1, process, balance); + g_main_loop_run (loop); + + gst_object_unref (src); + gst_element_set_state (pipeline, GST_STATE_NULL); + return 0; +} diff --git a/tests/examples/rpicamsrc/test_orientation.c b/tests/examples/rpicamsrc/test_orientation.c new file mode 100644 index 0000000000..729597ea50 --- /dev/null +++ b/tests/examples/rpicamsrc/test_orientation.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2015, Igalia S.L + * Author: Philippe Normand + * Licence: LGPL. (See COPYING.LGPL) + */ + +#include +#include +#include + +#define PIPELINE "rpicamsrc name=src preview=0 fullscreen=0 ! h264parse ! omxh264dec ! glimagesink sync=0" + +static void +configure_orientation (GstVideoOrientation * orientation) +{ + gboolean flip; + + if (gst_video_orientation_get_hflip (orientation, &flip)) { + g_print ("current hflip: %s\n", flip ? "enabled" : "disabled"); + + if (g_getenv ("HFLIP")) + gst_video_orientation_set_hflip (orientation, TRUE); + + gst_video_orientation_get_hflip (orientation, &flip); + g_print ("new hflip: %s\n", flip ? "enabled" : "disabled"); + } + + if (gst_video_orientation_get_vflip (orientation, &flip)) { + g_print ("current vflip: %s\n", flip ? "enabled" : "disabled"); + + if (g_getenv ("VFLIP")) + gst_video_orientation_set_vflip (orientation, TRUE); + + gst_video_orientation_get_vflip (orientation, &flip); + g_print ("new vflip: %s\n", flip ? "enabled" : "disabled"); + } +} + +int +main (int argc, char **argv) +{ + GMainLoop *loop; + GstElement *pipeline; + GError *error = NULL; + GstElement *src; + GstVideoOrientation *orientation; + + gst_init (&argc, &argv); + loop = g_main_loop_new (NULL, FALSE); + + pipeline = gst_parse_launch (PIPELINE, &error); + if (error != NULL) { + g_printerr ("Error parsing '%s': %s", PIPELINE, error->message); + g_error_free (error); + return -1; + } + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + src = gst_bin_get_by_name (GST_BIN (pipeline), "src"); + if (!src) { + g_printerr ("Source element not found\n"); + return -2; + } + + orientation = GST_VIDEO_ORIENTATION (src); + configure_orientation (orientation); + g_main_loop_run (loop); + + gst_object_unref (src); + gst_element_set_state (pipeline, GST_STATE_NULL); + return 0; +} diff --git a/tests/examples/rpicamsrc/webrtc-unidirectional-h264.c b/tests/examples/rpicamsrc/webrtc-unidirectional-h264.c new file mode 100644 index 0000000000..6944ece079 --- /dev/null +++ b/tests/examples/rpicamsrc/webrtc-unidirectional-h264.c @@ -0,0 +1,585 @@ +#include +#include +#include +#include +#include + +#define GST_USE_UNSTABLE_API +#include + +#include +#include +#include + + + +#define RTP_PAYLOAD_TYPE "96" +#define SOUP_HTTP_PORT 57778 +#define STUN_SERVER "stun.l.google.com:19302" + + + +typedef struct _ReceiverEntry ReceiverEntry; + +ReceiverEntry *create_receiver_entry (SoupWebsocketConnection * connection); +void destroy_receiver_entry (gpointer receiver_entry_ptr); + +GstPadProbeReturn payloader_caps_event_probe_cb (GstPad * pad, + GstPadProbeInfo * info, gpointer user_data); + +void on_offer_created_cb (GstPromise * promise, gpointer user_data); +void on_negotiation_needed_cb (GstElement * webrtcbin, gpointer user_data); +void on_ice_candidate_cb (GstElement * webrtcbin, guint mline_index, + gchar * candidate, gpointer user_data); + +void soup_websocket_message_cb (SoupWebsocketConnection * connection, + SoupWebsocketDataType data_type, GBytes * message, gpointer user_data); +void soup_websocket_closed_cb (SoupWebsocketConnection * connection, + gpointer user_data); + +void soup_http_handler (SoupServer * soup_server, SoupMessage * message, + const char *path, GHashTable * query, SoupClientContext * client_context, + gpointer user_data); +void soup_websocket_handler (G_GNUC_UNUSED SoupServer * server, + SoupWebsocketConnection * connection, const char *path, + SoupClientContext * client_context, gpointer user_data); + +static gchar *get_string_from_json_object (JsonObject * object); + +gboolean exit_sighandler (gpointer user_data); + + + + +struct _ReceiverEntry +{ + SoupWebsocketConnection *connection; + + GstElement *pipeline; + GstElement *webrtcbin; +}; + + + +const gchar *html_source = " \n \ + \n \ + \n \ + \n \ + \n \ + \n \ + \n \ + \n \ +
\n \ + \n \ +
\n \ + \n \ + \n \ +"; + + + + +ReceiverEntry * +create_receiver_entry (SoupWebsocketConnection * connection) +{ + GError *error; + ReceiverEntry *receiver_entry; + + receiver_entry = g_slice_alloc0 (sizeof (ReceiverEntry)); + receiver_entry->connection = connection; + + g_object_ref (G_OBJECT (connection)); + + g_signal_connect (G_OBJECT (connection), "message", + G_CALLBACK (soup_websocket_message_cb), (gpointer) receiver_entry); + + error = NULL; + receiver_entry->pipeline = + gst_parse_launch ("webrtcbin name=webrtcbin stun-server=stun://" + STUN_SERVER " " + "rpicamsrc bitrate=600000 annotation-mode=12 preview=false ! video/x-h264,profile=constrained-baseline,width=640,height=360,level=3.0 ! queue max-size-time=100000000 ! h264parse ! " + "rtph264pay config-interval=-1 name=payloader ! " + "application/x-rtp,media=video,encoding-name=H264,payload=" + RTP_PAYLOAD_TYPE " ! webrtcbin. ", &error); + if (error != NULL) { + g_error ("Could not create WebRTC pipeline: %s\n", error->message); + g_error_free (error); + goto cleanup; + } + + receiver_entry->webrtcbin = + gst_bin_get_by_name (GST_BIN (receiver_entry->pipeline), "webrtcbin"); + g_assert (receiver_entry->webrtcbin != NULL); + + g_signal_connect (receiver_entry->webrtcbin, "on-negotiation-needed", + G_CALLBACK (on_negotiation_needed_cb), (gpointer) receiver_entry); + + g_signal_connect (receiver_entry->webrtcbin, "on-ice-candidate", + G_CALLBACK (on_ice_candidate_cb), (gpointer) receiver_entry); + + gst_element_set_state (receiver_entry->pipeline, GST_STATE_PLAYING); + + return receiver_entry; + +cleanup: + destroy_receiver_entry ((gpointer) receiver_entry); + return NULL; +} + +void +destroy_receiver_entry (gpointer receiver_entry_ptr) +{ + ReceiverEntry *receiver_entry = (ReceiverEntry *) receiver_entry_ptr; + + g_assert (receiver_entry != NULL); + + if (receiver_entry->pipeline != NULL) { + gst_element_set_state (GST_ELEMENT (receiver_entry->pipeline), + GST_STATE_NULL); + + gst_object_unref (GST_OBJECT (receiver_entry->webrtcbin)); + gst_object_unref (GST_OBJECT (receiver_entry->pipeline)); + } + + if (receiver_entry->connection != NULL) + g_object_unref (G_OBJECT (receiver_entry->connection)); + + g_slice_free1 (sizeof (ReceiverEntry), receiver_entry); +} + + +void +on_offer_created_cb (GstPromise * promise, gpointer user_data) +{ + gchar *sdp_string; + gchar *json_string; + JsonObject *sdp_json; + JsonObject *sdp_data_json; + GstStructure const *reply; + GstPromise *local_desc_promise; + GstWebRTCSessionDescription *offer = NULL; + ReceiverEntry *receiver_entry = (ReceiverEntry *) user_data; + + reply = gst_promise_get_reply (promise); + gst_structure_get (reply, "offer", GST_TYPE_WEBRTC_SESSION_DESCRIPTION, + &offer, NULL); + gst_promise_unref (promise); + + local_desc_promise = gst_promise_new (); + g_signal_emit_by_name (receiver_entry->webrtcbin, "set-local-description", + offer, local_desc_promise); + gst_promise_interrupt (local_desc_promise); + gst_promise_unref (local_desc_promise); + + sdp_string = gst_sdp_message_as_text (offer->sdp); + g_print ("Negotiation offer created:\n%s\n", sdp_string); + + sdp_json = json_object_new (); + json_object_set_string_member (sdp_json, "type", "sdp"); + + sdp_data_json = json_object_new (); + json_object_set_string_member (sdp_data_json, "type", "offer"); + json_object_set_string_member (sdp_data_json, "sdp", sdp_string); + json_object_set_object_member (sdp_json, "data", sdp_data_json); + + json_string = get_string_from_json_object (sdp_json); + json_object_unref (sdp_json); + + soup_websocket_connection_send_text (receiver_entry->connection, json_string); + g_free (json_string); + + gst_webrtc_session_description_free (offer); +} + + +void +on_negotiation_needed_cb (GstElement * webrtcbin, gpointer user_data) +{ + GstPromise *promise; + ReceiverEntry *receiver_entry = (ReceiverEntry *) user_data; + + g_print ("Creating negotiation offer\n"); + + promise = gst_promise_new_with_change_func (on_offer_created_cb, + (gpointer) receiver_entry, NULL); + g_signal_emit_by_name (G_OBJECT (webrtcbin), "create-offer", NULL, promise); +} + + +void +on_ice_candidate_cb (G_GNUC_UNUSED GstElement * webrtcbin, guint mline_index, + gchar * candidate, gpointer user_data) +{ + JsonObject *ice_json; + JsonObject *ice_data_json; + gchar *json_string; + ReceiverEntry *receiver_entry = (ReceiverEntry *) user_data; + + ice_json = json_object_new (); + json_object_set_string_member (ice_json, "type", "ice"); + + ice_data_json = json_object_new (); + json_object_set_int_member (ice_data_json, "sdpMLineIndex", mline_index); + json_object_set_string_member (ice_data_json, "candidate", candidate); + json_object_set_object_member (ice_json, "data", ice_data_json); + + json_string = get_string_from_json_object (ice_json); + json_object_unref (ice_json); + + soup_websocket_connection_send_text (receiver_entry->connection, json_string); + g_free (json_string); +} + + +void +soup_websocket_message_cb (G_GNUC_UNUSED SoupWebsocketConnection * connection, + SoupWebsocketDataType data_type, GBytes * message, gpointer user_data) +{ + gsize size; + gchar *data; + gchar *data_string; + const gchar *type_string; + JsonNode *root_json; + JsonObject *root_json_object; + JsonObject *data_json_object; + JsonParser *json_parser = NULL; + ReceiverEntry *receiver_entry = (ReceiverEntry *) user_data; + + switch (data_type) { + case SOUP_WEBSOCKET_DATA_BINARY: + g_error ("Received unknown binary message, ignoring\n"); + g_bytes_unref (message); + return; + + case SOUP_WEBSOCKET_DATA_TEXT: + data = g_bytes_unref_to_data (message, &size); + /* Convert to NULL-terminated string */ + data_string = g_strndup (data, size); + g_free (data); + break; + + default: + g_assert_not_reached (); + } + + json_parser = json_parser_new (); + if (!json_parser_load_from_data (json_parser, data_string, -1, NULL)) + goto unknown_message; + + root_json = json_parser_get_root (json_parser); + if (!JSON_NODE_HOLDS_OBJECT (root_json)) + goto unknown_message; + + root_json_object = json_node_get_object (root_json); + + if (!json_object_has_member (root_json_object, "type")) { + g_error ("Received message without type field\n"); + goto cleanup; + } + type_string = json_object_get_string_member (root_json_object, "type"); + + if (!json_object_has_member (root_json_object, "data")) { + g_error ("Received message without data field\n"); + goto cleanup; + } + data_json_object = json_object_get_object_member (root_json_object, "data"); + + if (g_strcmp0 (type_string, "sdp") == 0) { + const gchar *sdp_type_string; + const gchar *sdp_string; + GstPromise *promise; + GstSDPMessage *sdp; + GstWebRTCSessionDescription *answer; + int ret; + + if (!json_object_has_member (data_json_object, "type")) { + g_error ("Received SDP message without type field\n"); + goto cleanup; + } + sdp_type_string = json_object_get_string_member (data_json_object, "type"); + + if (g_strcmp0 (sdp_type_string, "answer") != 0) { + g_error ("Expected SDP message type \"answer\", got \"%s\"\n", + sdp_type_string); + goto cleanup; + } + + if (!json_object_has_member (data_json_object, "sdp")) { + g_error ("Received SDP message without SDP string\n"); + goto cleanup; + } + sdp_string = json_object_get_string_member (data_json_object, "sdp"); + + g_print ("Received SDP:\n%s\n", sdp_string); + + ret = gst_sdp_message_new (&sdp); + g_assert_cmphex (ret, ==, GST_SDP_OK); + + ret = + gst_sdp_message_parse_buffer ((guint8 *) sdp_string, + strlen (sdp_string), sdp); + if (ret != GST_SDP_OK) { + g_error ("Could not parse SDP string\n"); + goto cleanup; + } + + answer = gst_webrtc_session_description_new (GST_WEBRTC_SDP_TYPE_ANSWER, + sdp); + g_assert_nonnull (answer); + + promise = gst_promise_new (); + g_signal_emit_by_name (receiver_entry->webrtcbin, "set-remote-description", + answer, promise); + gst_promise_interrupt (promise); + gst_promise_unref (promise); + } else if (g_strcmp0 (type_string, "ice") == 0) { + guint mline_index; + const gchar *candidate_string; + + if (!json_object_has_member (data_json_object, "sdpMLineIndex")) { + g_error ("Received ICE message without mline index\n"); + goto cleanup; + } + mline_index = + json_object_get_int_member (data_json_object, "sdpMLineIndex"); + + if (!json_object_has_member (data_json_object, "candidate")) { + g_error ("Received ICE message without ICE candidate string\n"); + goto cleanup; + } + candidate_string = json_object_get_string_member (data_json_object, + "candidate"); + + g_print ("Received ICE candidate with mline index %u; candidate: %s\n", + mline_index, candidate_string); + + g_signal_emit_by_name (receiver_entry->webrtcbin, "add-ice-candidate", + mline_index, candidate_string); + } else + goto unknown_message; + +cleanup: + if (json_parser != NULL) + g_object_unref (G_OBJECT (json_parser)); + g_free (data_string); + return; + +unknown_message: + g_error ("Unknown message \"%s\", ignoring", data_string); + goto cleanup; +} + + +void +soup_websocket_closed_cb (SoupWebsocketConnection * connection, + gpointer user_data) +{ + GHashTable *receiver_entry_table = (GHashTable *) user_data; + g_hash_table_remove (receiver_entry_table, connection); + g_print ("Closed websocket connection %p\n", (gpointer) connection); +} + + +void +soup_http_handler (G_GNUC_UNUSED SoupServer * soup_server, + SoupMessage * message, const char *path, G_GNUC_UNUSED GHashTable * query, + G_GNUC_UNUSED SoupClientContext * client_context, + G_GNUC_UNUSED gpointer user_data) +{ + SoupBuffer *soup_buffer; + + if ((g_strcmp0 (path, "/") != 0) && (g_strcmp0 (path, "/index.html") != 0)) { + soup_message_set_status (message, SOUP_STATUS_NOT_FOUND); + return; + } + + soup_buffer = + soup_buffer_new (SOUP_MEMORY_STATIC, html_source, strlen (html_source)); + + soup_message_headers_set_content_type (message->response_headers, "text/html", + NULL); + soup_message_body_append_buffer (message->response_body, soup_buffer); + soup_buffer_free (soup_buffer); + + soup_message_set_status (message, SOUP_STATUS_OK); +} + + +void +soup_websocket_handler (G_GNUC_UNUSED SoupServer * server, + SoupWebsocketConnection * connection, G_GNUC_UNUSED const char *path, + G_GNUC_UNUSED SoupClientContext * client_context, gpointer user_data) +{ + ReceiverEntry *receiver_entry; + GHashTable *receiver_entry_table = (GHashTable *) user_data; + + g_print ("Processing new websocket connection %p", (gpointer) connection); + + g_signal_connect (G_OBJECT (connection), "closed", + G_CALLBACK (soup_websocket_closed_cb), (gpointer) receiver_entry_table); + + receiver_entry = create_receiver_entry (connection); + g_hash_table_replace (receiver_entry_table, connection, receiver_entry); +} + + +static gchar * +get_string_from_json_object (JsonObject * object) +{ + JsonNode *root; + JsonGenerator *generator; + gchar *text; + + /* Make it the root node */ + root = json_node_init_object (json_node_alloc (), object); + generator = json_generator_new (); + json_generator_set_root (generator, root); + text = json_generator_to_data (generator, NULL); + + /* Release everything */ + g_object_unref (generator); + json_node_free (root); + return text; +} + + +gboolean +exit_sighandler (gpointer user_data) +{ + g_print ("Caught signal, stopping mainloop\n"); + GMainLoop *mainloop = (GMainLoop *) user_data; + g_main_loop_quit (mainloop); + return TRUE; +} + + +int +main (int argc, char *argv[]) +{ + GMainLoop *mainloop; + SoupServer *soup_server; + GHashTable *receiver_entry_table; + + setlocale (LC_ALL, ""); + gst_init (&argc, &argv); + + receiver_entry_table = + g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, + destroy_receiver_entry); + + mainloop = g_main_loop_new (NULL, FALSE); + g_assert (mainloop != NULL); + + g_unix_signal_add (SIGINT, exit_sighandler, mainloop); + g_unix_signal_add (SIGTERM, exit_sighandler, mainloop); + + soup_server = + soup_server_new (SOUP_SERVER_SERVER_HEADER, "webrtc-soup-server", NULL); + soup_server_add_handler (soup_server, "/", soup_http_handler, NULL, NULL); + soup_server_add_websocket_handler (soup_server, "/ws", NULL, NULL, + soup_websocket_handler, (gpointer) receiver_entry_table, NULL); + soup_server_listen_all (soup_server, SOUP_HTTP_PORT, + (SoupServerListenOptions) 0, NULL); + + g_print ("WebRTC page link: http://127.0.0.1:%d/\n", (gint) SOUP_HTTP_PORT); + + g_main_loop_run (mainloop); + + g_object_unref (G_OBJECT (soup_server)); + g_hash_table_destroy (receiver_entry_table); + g_main_loop_unref (mainloop); + + gst_deinit (); + + return 0; +}