Skip to content

Releases: masa-iwm/GstSharp.Net

v1.28.10

Choose a tag to compare

@github-actions github-actions released this 12 Sep 14:33

The release where the containers the gir hides finally cross the boundary. A
GBytes is an argument and a return like any other, a GHashTable of strings
arrives as a dictionary, a GSList return is read the way a GList already
was, a counted array the caller supplies is filled in place, and the borrowed constant
structure a C lookup hands back is copied out rather than refused. Around them a
fraction becomes a value type the property system knows, the child properties of
a timeline element can be listed and overridden, an RTSP message yields the
credentials it was challenged with, an ICE agent the candidates it gathered, and
a bus the descriptor a foreign event loop can wait on. Net, forty-three fewer
symbols sit under the catch-all skip reason. Three
things changed behaviour, and each of them is one line below. All eighteen
packages ship as one version, 1.28.10, generated from the GStreamer 1.28.6
.gir files, 50 commits after 1.28.9.

Added

  • A block of bytes across the boundary. Gst.Buffer.NewWrappedBytes(Gst.GLib.Bytes)
    wraps the block zero-copy as read-only memory, and an empty block gives a
    buffer with no memory in it.
  • The adapter copy that answers a block. Gst.Base.Adapter.Copy(nuint offset, nuint size)
    answers a Gst.GLib.Bytes; a size of zero is an empty block, and an offset
    past Available throws even then.
  • The RTP payload and header extension as blocks. Gst.Rtp.RTPBuffer.GetPayload()
    and GetExtensionData(out ushort bits) answer the payload and the header
    extension as blocks, and the static
    GetExtensionOnebyteHeaderFromBytes(Gst.GLib.Bytes, ushort, byte, uint, out byte[]?)
    reads the nth one-byte header extension of a given id back out of one.
  • A MIKEY message from and to a block. Gst.Sdp.MIKEYMessage.NewFromBytes(Gst.GLib.Bytes, Gst.Sdp.MIKEYDecryptInfo?)
    answers null for a malformed message, and ToBytes(Gst.Sdp.MIKEYEncryptInfo?)
    serialises one back out.
  • A fraction the property system knows. Gst.Fraction is a readonly record
    struct whose ToString is N/D, with GetFraction() on
    Gst.GObject.Value, ValueView and ValueRef, SetFraction(Gst.Fraction)
    on Value and ValueRef, and
    Gst.GObject.Object.SetProperty(string, object) and GetProperty<Gst.Fraction>
    widened to carry it — writing a denominator of zero, or either term as
    int.MinValue, is an ArgumentOutOfRangeException, and GStreamer reduces and
    sign-normalises what it stores.
  • The first fraction-typed property. Gst.Audio.AudioAggregator.OutputBufferDurationFraction
    is emitted through those accessors.
  • The child properties of a timeline element. GES.TimelineElement.ListChildrenProperties()
    answers an owned Gst.GObject.ParamSpec[] in the name order GES sorts, and the
    caller disposes each element.
  • Three child-property slots to override. GES.TimelineElement.OnListChildrenProperties,
    OnLookupChild(string, out Gst.GObject.Object?, out Gst.GObject.ParamSpec?) and
    OnSetChildProperty(Gst.GObject.Object, Gst.GObject.ParamSpec, Gst.GObject.ValueView)
    with their chain-ups; a ParamSpec returned or passed on is consumed, a
    borrowed one is call-scoped, and a true answer requires both outputs.
  • The query and fragment of a URI as tables. Gst.Uri.GetQueryTable() and
    GetMediaFragmentTable() answer a Dictionary<string, string?>? snapshot —
    a null value is a key with no =, "" is key=, no query or fragment is
    null and a bare ? or # is empty — and Gst.Uri.SetQueryTable(IReadOnlyDictionary<string, string?>?)
    copies one in, or clears the query when given null.
  • Every control binding of a track element. GES.TrackElement.GetAllControlBindings()
    answers a Dictionary<string, Gst.ControlBinding> snapshot keyed by the name
    passed to SetControlSource, whose values are interned and need no dispose.
  • The debug categories the library registered. Gst.Global.DebugGetAllCategories()
    answers an IReadOnlyList<Gst.DebugCategory> snapshot of borrowed categories
    that live until gst_deinit.
  • A format list that carries its own end. Gst.Global.FormatsContains(ReadOnlySpan<Gst.Format>, Gst.Format)
    searches one without the caller writing the terminator loop.
  • A control source sampled a run at a time. Gst.ControlBinding.GetGValueArray(ClockTime timestamp, ClockTime interval, Span<Value> values)
    and Gst.Object.GetGValueArray(string propertyName, ClockTime, ClockTime, Span<Value>)
    fill empty slots the caller supplies; what lands in them is the control
    source's business.
  • A MIKEY timestamp whose length its kind decides. Gst.Sdp.MIKEYPayload.TSet(MIKEYTSType, ReadOnlySpan<byte>)
    and Gst.Sdp.MIKEYMessage.AddT(MIKEYTSType, ReadOnlySpan<byte>) take exactly
    the 8, 8 or 4 bytes the type calls for.
  • One VBI line at a time. Gst.Video.VideoVBIEncoder.WriteLine(Span<byte>)
    and Gst.Video.VideoVBIParser.AddLine(ReadOnlySpan<byte>) want one line of
    the stride the format and the pixel width of New fix, which the wrapper now
    remembers.
  • A channel order a ring buffer will accept. Gst.Audio.AudioRingBuffer.SetChannelPositions(ReadOnlySpan<Gst.Audio.AudioChannelPosition>)
    checks the acquired state and the channel count, and may be called from inside
    OnPrepare.
  • Both blocks of a DSD conversion measured. Gst.Audio.AudioGlobal.DsdConvert(...)
    validates the extent, the overlap and the whole-frame rule of the input and
    output blocks before the call.
  • The credentials a message was challenged with. Gst.Rtsp.RTSPMessage.ParseAuthCredentials(RTSPHeaderField)
    answers an RTSPAuthCredential[] of the Basic and Digest credentials of a
    WWW-Authenticate, Proxy-Authenticate or Authorization header, copied so
    they outlive the message, and an absent header is an empty array.
  • The parameters of one credential. Gst.Rtsp.RTSPAuthCredential.GetParams()
    answers a fresh RTSPAuthParam[] on each call, which the caller disposes.
  • The ICE candidates an agent gathered. Gst.WebRTC.WebRTCICE.GetLocalCandidates(WebRTCICEStream)
    and GetRemoteCandidates(WebRTCICEStream) answer a WebRTCICECandidateStats[]
    snapshot whose elements belong to the caller.
  • The transports a session media keeps a slot for. Gst.RtspServer.RTSPSessionMedia.GetTransports()
    answers an RTSPStreamTransport?[] indexed by stream index, with null where
    no SETUP has happened yet.
  • Six borrowed constant structures copied out. Gst.FormatExtensions.GetDetails(Gst.Format),
    Gst.Rtp.RTPPayloadInfo.ForName(string media, string encodingName) and
    ForPt(byte), Gst.Sdp.MIKEYMessage.GetCsSrtp(uint) and
    Gst.Sdp.MIKEYPayload.SpGetParam(uint) answer a nullable copy of the static
    row the C points at, null for a value the library does not know, while
    Gst.Video.VideoColorPrimariesExtensions.GetInfo(VideoColorPrimaries) is
    non-nullable behind a guard; Gst.Sdp.MIKEYPayloadSPParam.Val reads the
    counted block that record's C field points at.
  • A property-notify message built without losing the value.
    Gst.Message.NewPropertyNotify(Gst.Object src, string propertyName, in Gst.GObject.Value? value)
    hands the C a g_value_copy duplicate, so the caller's Value stays alive and
    stays the caller's to dispose and an object value keeps a reference of the
    message's own; null is a notification without a value and an empty Value is
    an ArgumentException.
  • A poll descriptor and the wait over it. Gst.GLib.PollFD (Fd, Events,
    Revents), Gst.GLib.IOCondition and the static
    Gst.GLib.PollFD.Poll(Span<PollFD>, int timeoutMs) project GPollFD and
    g_poll with the descriptor width the platform decides — a HANDLE on 64-bit
    Windows, a file descriptor elsewhere, checked by the ABI probe against the
    running library; an empty set is an ArgumentException, Windows waits on
    handles, answers Revents = Events and stops at 64, and a Unix wait broken by
    a signal resumes with the remaining timeout. Gst.PollFD is GstPollFD and
    Gst.GLib.PollFD is GPollFD, so code that opens both namespaces qualifies
    the two, as it already does for Gst.DateTime.
  • The descriptor a bus signals through. Gst.Bus.GetPollfd() gives a foreign
    event loop the descriptor that reports a pending message; the descriptor
    belongs to the bus and must not be read, written or closed, and a bus built
    without asynchronous delivery throws InvalidOperationException.
  • The read half of a poll set. Gst.Poll.GetReadGpollfd() supplies the out
    direction the gir omits; Gst.Poll itself is still not constructible from
    managed code.
  • A variant handle and the discoverer round trip. Gst.GLib.Variant
    (Handle, TypeString, ToBytes(), FromBytes(string, Gst.GLib.Bytes),
    Dispose) sinks the floating GVariant the C returns and refuses an
    indefinite type string, and Gst.Pbutils.DiscovererInfo.ToVariant(DiscovererSerializeFlags)
    / static FromVariant(Gst.GLib.Variant) carry a discoverer result through
    bytes — ToVariant refuses a result that is neither Ok nor
    MissingPlugins or has no stream tree, FromVariant refuses anything that is
    not a "v", both of them ahead of a NULL dereference in the C.

Behavioural

  • Gst.Sdp.MIKEYMessage.NewFromData(ReadOnlySpan<byte>, Gst.Sdp.MIKEYDecryptInfo? info) takes a nullable info and is callable for the first time: the argument used to be non-nullable and every call threw ArgumentNullException before reaching the C, and an empty span is still a GLib critical and an InvalidOperationException.
  • Every generated method, extension and subclass chain-up now places its GC.KeepAlive barriers at the end of the body rather than before the output conversions, closing a latent window in which a wrapper could be finalized while a borrowed output array, string or list was still being read; no signature and no observable behaviour changed.
  • `G...
Read more

v1.28.9

Choose a tag to compare

@github-actions github-actions released this 07 Sep 02:18

Another gap-closing release. An appsink can be consumed as one queue of samples
and events rather than two, four mini objects the gir hides behind static
inline functions can be copied, a bus can be built without the asynchronous
half it may not need, the quark keyed data native code hangs off a mini object
can be read and stolen, and the RTSP surface gains header serialisation and the
TLS authentication mode of its authenticator. Some of what moved in the counts
is a correction rather than new surface: a hand written record no longer files
its members under the catch-all reason. Nothing that shipped changed behaviour.
All eighteen packages ship as one version, 1.28.9, generated from the GStreamer
1.28.6 .gir files, 16 commits after 1.28.8.

Added

  • One pull loop for samples and events. Gst.App.AppSink.PullObject() and
    TryPullObject(Gst.ClockTime) answer a Gst.MiniObject?, which is a
    Gst.Sample for a buffer or a buffer list and a Gst.Event for every
    serialized event but the end of the stream — stream-start, caps, segment,
    tag, gap and a serialized custom event among them — so the caller matches on
    the type it is handed. The queue read is the one PullSample and
    TryPullSample read, and those two discard every event they are given, so a
    consumer picks one of the two families and stays with it. The end of the
    stream is never queued: a null answer always comes with IsEos() true, and
    for the timed overload a null with IsEos() false is the timeout and nothing
    else. The caller owns what it is handed and disposes it. The generator refuses
    both on their shape — the return is a GstMiniObject* whose concrete type is
    decided at run time — so the two members read the GType out of the first
    word of the object and let the type registry build the wrapper.
  • The copy of an event, a sample, a buffer list and a query.
    Gst.Event.Copy(), Gst.Sample.Copy(), Gst.BufferList.Copy() and
    Gst.Query.Copy(). All four are static inline functions in the C headers and
    the gir marks each introspectable="0", so no overlay can bring them back;
    the library exports the four by name as well, but the one import of the
    gst_mini_object_copy they all forward to serves every type, since the copy
    carries the type of the original, and that call is why each of them answers a
    nullable value — the C answers NULL for a type that installed no copy
    function, which none of these four is. What a copy carries is what the C
    copies: an event and a query take a copy of their structure, a sample
    references the buffer, the caps and the buffer list of the original and
    copies its segment and info structure, and a buffer list references its
    buffers rather than copying them — CopyDeep is the other half of that one.
    Each copy holds the only reference to itself and is therefore writable where
    the original usually is not.
  • A bus without asynchronous delivery. Gst.Bus.New(bool enableAsync).
    enable-async is construct only and write only, so the only moment it can be
    given a value is while the bus is being built, which is what this overload
    does; New() is the same call with the property left at its default, true.
    A bus built with false runs its synchronous handler and emits
    sync-message, and then drops the message instead of queueing it, which is
    the point of the option: an element that needs only its own synchronous
    handler pays for no delivery machinery. Such a bus is for a synchronous
    handler and the non-blocking pops, and for nothing else — the watches install
    a source that never delivers, Poll sees nothing, and TimedPop and
    TimedPopFiltered answer null with a GLib critical for every timeout but
    zero — and the binding can guard none of it, because a write-only property
    cannot be read back. The remarks say so member by member.
  • The quark keyed data of a mini object.
    Gst.MiniObject.GetQData(Gst.GLib.Quark) and StealQData(Gst.GLib.Quark)
    answer an nint, where nint.Zero means nothing is stored and is an ordinary
    answer rather than a failure. What GetQData reads stays owned by the mini
    object, together with the destroy notification that will release it; what
    StealQData takes off the object belongs to the caller, and dropping it is a
    leak, since nothing will run that notification any more. Gst.GLib.Quark.Zero
    names no string and is refused with an ArgumentException, which keeps the
    programming error the C answers with a critical apart from the empty entry.
  • Two RTSP additions. Gst.Rtsp.RTSPMessage.AppendHeaders(StringBuilder)
    answers an RTSPResult and appends every header of the message as
    Name: value followed by CRLF, in the order the message holds them, leaving
    what is already in the builder alone; the blank line that separates the
    headers from the body is deliberately not written, so the call composes with
    the request line before it. The C takes a GString, which has no place in a
    managed signature, and the member owns that buffer for the length of the call.
    Gst.RtspServer.RTSPAuth.GetTlsAuthenticationMode() and
    SetTlsAuthenticationMode(Gst.Gio.TlsAuthenticationMode) are generated now
    that the planner's runtime-enumeration map names
    Gst.Gio.TlsAuthenticationMode, a hand-written mirror of
    GTlsAuthenticationMode in the runtime beside TlsCertificateFlags and
    SocketFamily, whose None, Requested and Required are the same numbers
    on every platform. Anything but None makes the server emit
    accept-certificate, which then has to be handled.

Samples

  • samples/CustomMeta is new: an API type registered with no tags, an
    implementation over an unmanaged payload through the Meta.Register<T> of
    1.28.8, one item attached to every frame pushed into an appsrc and read
    back off the frames a videoconvert allocated on the other side;
    samples/RtspServer gains --mount <path> and --disable-rtcp, the last two
    options of test-launch.c it was missing; samples/GstPlay gains
    --playlist <file>, --wait-on-eos and --flags <spec>, and its header
    comment says why --gapless and --instant-uri stay out;
    samples/tutorials/README.md now lists every basic and playback tutorial
    that is not ported and why. CI gains a CustomMeta step on each of its three
    sample-running legs, and the GstPlay step of all three runs the new flags
    and playlist path.
  • docs/samples.md is a new page of the documentation site: the sixteen
    samples grouped by theme, the binding APIs each one exercises and what it
    deliberately leaves out, with the README table as the short index into it.

Tooling

  • The skip ledger stops mixing a decision with a shape. A member of a
    hand-written record used to be filed under the catch-all
    UnsupportedSignature unless an overlay named it; it is now filed under
    whatever the rules actually say about the symbol — NotIntrospectable, an
    overlay skip, and so on — and only a member the rules would have let through
    falls back to the catch-all, because it is generatable and still absent.
    ShadowedBy and MovedTo are the two answers that must not be passed on,
    since both claim the symbol is emitted under another declaration and of a
    hand-written record nothing is emitted at all. Beside it,
    gst_param_spec_fraction and gst_param_spec_array are filed as hand bound
    rather than as an unsupported signature, and the overlay comment that
    explained the skip is corrected: the gir does declare the fields and the two
    functions, and generating the records unskipped would answer a public class
    with no public member in it.
  • CI gates NativeAOT on the macOS leg as well, publishing and running
    samples/AotSmoke for osx-arm64, so all three RIDs the binding claims are
    covered.

Compatibility

This release is additive: every entry above is new surface, and nothing that
shipped changed behaviour, which is what the 1.28.x promise allows. The
binding is generated from the GStreamer 1.28.6 .gir files and the run-time
floor is still GStreamer 1.24 — neither moved.

The census counts moved for two reasons this time. Where new surface says they
should: GstApp counts no unsupported signature rather than 2 and 7 hand-bound
symbols rather than 5, the two appsink pulls; GstRtsp counts 12 unsupported
signatures rather than 13 and 3 hand-bound symbols rather than 2,
gst_rtsp_message_append_headers; GstRtspServer counts 14 unsupported
signatures rather than 16 and 384 emitted methods rather than 382, the two TLS
authentication mode accessors; and in Gst, Gst.Bus:enable-async,
gst_mini_object_copy and the two qdata calls leave UnsupportedSignature
while the four copy functions leave NotIntrospectable, all eight for the
hand-bound ledger. Where the ledger was simply wrong: gst_param_spec_fraction
and gst_param_spec_array were hand bound all along and are filed as such now,
and gst_mini_object_init, _steal, _weak_ref and _weak_unref move from
the catch-all UnsupportedSignature to NotIntrospectable, the reason that
really keeps them out. Net, in girs/skip-report.md, Gst counts 43
unsupported signatures rather than 53 and its HandBound section grows from 52
entries to 62, while its 112 symbols under NotIntrospectable are 112 before
and after: the four mini object internals arrived exactly as the four copy
functions left.

PackageValidationBaselineVersion in src/Directory.Build.props is 1.28.8, and
all eighteen packages are packed against it.

Changes

  • Gate NativeAOT on the macOS leg
  • Add a samples page to the documentation site
  • List the tutorials that are not ported yet
  • Port the playlist, wait-on-eos and flags options to the play sample
  • Add mount and rtcp options to the RTSP server sample
  • Add a custom meta sample
  • Correct the remarks of the pulled object and copy members
  • Copy an event, sample, buffer list or query through the mini object
  • P...
Read more

v1.28.8

Choose a tag to compare

@github-actions github-actions released this 06 Sep 08:21

A gap-closing release. Managed code can author a buffer metadata implementation
of its own now, two attach functions the gir could not describe are bound by
hand, the frame and state fields a subclass writes in C have take-and-replace
setters, the GES asynchronous requests accept a GCancellable the caller
already holds and can run on the application's own GLib main context, and four
GES signals whose shapes the generator used to refuse are emitted. Nothing that
shipped changed behaviour. All eighteen packages ship as one version, 1.28.8,
generated from the GStreamer 1.28.6 .gir files, 33 commits after 1.28.7.

Added

  • A metadata implementation written in C#. Gst.Meta.Register<T>(api, impl, …)
    registers an implementation whose item is the GstMeta header followed by one
    unmanaged T, with optional init, free, transform, serialize, deserialize and
    clear delegates — Gst.MetaInitFunction, MetaFreeFunction,
    MetaTransformFunction, MetaSerializeFunction, MetaDeserializeFunction and
    MetaClearFunction, mirroring the C callbacks including the serialisation,
    deserialisation and clear ones that arrived in 1.24. The payload of such an
    item is reached as a ref T through the item's Payload<T>(), and
    Gst.ByteArrayInterface.AppendData(ReadOnlySpan<byte>) is the sink a
    serialize delegate writes through. A registration lives for the rest of the
    process, and the delegates are rooted for that long. docs/ownership.md
    gains an "Authoring a metadata implementation" section.
  • Two attach functions that were not introspectable.
    Gst.Audio.AudioGlobal.BufferAddAudioDownmixMeta takes the downmix matrix as
    one row-major ReadOnlySpan<float> and builds the row table the C function
    wants; a shared buffer throws InvalidOperationException.
    Gst.Video.VideoGlobal.BufferAddVideoGLTextureUploadMeta attaches a managed
    upload function, the new Gst.Video.VideoGLTextureUpload delegate, which stays
    reachable for as long as any buffer carries the item — every copy takes a
    handle of its own to the same delegate; the upload is invoked through
    VideoGLTextureUploadMeta.Upload(ReadOnlySpan<uint>), and a shared buffer
    answers null the way BufferAddVideoMeta does.
  • Take-and-replace setters for the fields a subclass owns.
    Gst.Base.BaseParseFrame.SetBuffer(Buffer?),
    Gst.Video.VideoCodecFrame.SetInputBuffer(Buffer?) and SetOutputBuffer(Buffer?),
    Gst.Video.VideoCodecState.SetCaps(Caps?) and SetAllocationCaps(Caps?) — the
    same shape as the shipped BaseParseFrame.SetOutBuffer: the wrapper's reference
    is taken over, the replaced value is released, and null clears the field.
  • A GCancellable the caller already holds. GES.Asset.RequestAsync and
    GES.UriClipAsset.NewAsync gained overloads taking a Gst.Gio.Cancellable.
    The binding borrows it — it never cancels, resets or disposes it — and a
    cancelled result surfaces as a canceled Task carrying no token.
  • GstSharp.GioAsyncContext. A static MainContext?, null by default. An
    application that runs its own GLib main loop can host the binding's
    asynchronous Gio operations on that context instead of on the binding's
    background thread: the application iterates the context, the value is read once
    when an operation starts, and the binding pushes the context thread-default
    around the native _async call so the callback lands on it. docs/gio-async.md
    describes it.
  • Four GES signals. GES.Layer.ActiveChanged (Active, and Tracks as a
    GES.Track[] snapshot), GES.Timeline.GroupRemoved (Group, and Children as
    a GES.Container[] snapshot), GES.Timeline.SelectTracksForObject — whose
    handler answers GES.Track[]?, where null and an empty array both mean the
    element joins no track, and connecting a handler replaces the timeline's default
    track selection — and the notify-meta signal of GESMetaContainer, connected
    through GES.MetaContainerExtensions.AddNotifyMetaHandler and
    RemoveNotifyMetaHandler on GES.IMetaContainer, whose arguments carry Key,
    HasValue and Value, a ValueView lent for the emission only; reading it once
    the emission has ended throws InvalidOperationException. The generator rules
    behind them are narrow — a GPtrArray of GObject-class elements, and a const
    GValue argument on a signal — and docs/ownership.md states the ownership of
    the lent value and of the answered array.

Samples

  • samples/GstPlay gained gst-play-1.0's --shuffle option and its d key,
    which flips the playback direction. Trick modes stay out because GstPlay
    offers no seek-flag API; the header comment says so.
  • samples/GesLaunch ports the last four ges-launch-1.0 branches:
    --container-profile, which re-parents the encoding profile under a bare muxer
    profile; --profile-from <clip name>, which rebuilds every track from the named
    URI clip's discoverer streams; the profile pick --smart-rendering makes when
    no --format is given, taken from the URI-clip assets and faithfully the
    least common qualifying one, because the C tool sorts its candidates
    ascending; and --embed-nesteds, which embeds nested .xges
    projects into the saved project. The sample prints which path chose the encoding
    profile and how many nested projects were embedded, and four Linux-only CI steps
    exercise them.

Tooling

  • The generator no longer counts what it refuses to ship: a slot rejected by
    GEN0040 (a return type collision) or GEN0047 (a borrowed return with no
    documented owner) is left out of the census as well as out of the file. The
    generator also takes --report-dir, which defaults to the --gir-dir
    directory; a run that writes its sources elsewhere passes it as well, so that
    the committed girs/skip-report.md is left alone.

Compatibility

This release is additive: every entry above is new surface, and nothing that
shipped changed behaviour, which is what the 1.28.x promise allows. The
binding is generated from the GStreamer 1.28.6 .gir files and the run-time
floor is still GStreamer 1.24 — neither moved. The census counts did move,
and only where the new surface says they should: the four GES signals leave
UnsupportedSignature and are counted as emitted, so GES counts 39 signals
rather than 35 and 8 unsupported signatures rather than 12; and six symbols move
into the hand-bound ledger from the reasons that used to keep them out — the
three registration entry points behind Gst.Meta.Register<T>, the
gst_buffer_iterate_meta_filtered that Gst.Buffer.IterateMeta already
implemented in managed code, and the two attach functions above.

PackageValidationBaselineVersion in src/Directory.Build.props is 1.28.7, and
GstSharp.Net.RtspServer no longer opts out of the gate: with the package now
published, all eighteen are packed against a baseline on nuget.org rather than
seventeen of them.

Source note. A literal default in the cancellation position of
GES.Asset.RequestAsync or GES.UriClipAsset.NewAsync is now ambiguous
(CS0121) between CancellationToken and Gst.Gio.Cancellable. Omit the
argument, or write default(CancellationToken).

Changes

  • Gate the smart rendering step on the profile pick alone
  • Gate the nested project embedding on the Linux leg
  • Give the rebuilt tracks back to the timeline that owns them
  • Gate the three new profile paths of GesLaunch on Linux
  • Embed the nested timelines into the saved project
  • Pick the smart rendering profile out of the clips of the timeline
  • Build the tracks and the profile from a named clip
  • Re-parent the encoding profile into --container-profile
  • State the ownership of the ungroup call the test makes
  • Say what the pointer array rules and the ungroup call really do
  • Cover the four GES container and value signals against the library
  • Show a signal handler the GValue an emission lends it
  • Let a signal handler answer with a GPtrArray of objects
  • Read a GPtrArray signal argument out into an array of wrappers
  • Port shuffle and the direction key to the GstPlay sample
  • Take the reference on a borrowed GCancellable where it is released
  • Let an application host the Gio async operations on its own loop
  • Let a caller bring the GCancellable an async request watches
  • Let subclasses write the frame and state fields they own
  • Take back only the entry the refused registration filed
  • Close the two windows a metadata registration leaves open
  • Say what each refusal of a metadata registration means
  • File the metadata authorship entry points under HandBound
  • Let managed code author a fixed-layout metadata implementation
  • Say which half of the upload pair leaks and which double-frees
  • Say what the copy of a texture upload item takes with it
  • Attach a managed OpenGL texture upload to a buffer
  • Attach a downmix matrix to a buffer from managed code
  • Name the report-dir test and the CONTRIBUTING sentence for what they check
  • Let a run say where the skip report belongs
  • Leave a refused slot out of the count as well as the file
  • Validate the RTSP server package against its published surface
  • Move the version and the validation baseline to 1.28.7

Full Changelog: v1.28.7...v1.28.8

v1.28.7

Choose a tag to compare

@github-actions github-actions released this 05 Sep 22:27

The subclassing release: a GStreamer element written in C# is a first-class element now. Twenty eight classes are subclassable — Gst.Element and Gst.Bin, Gst.Pad, the GstBase sources, sinks, transforms, parsers and aggregators, the GstAudio and GstVideo decoders, encoders, filters and sinks, and seven GES timeline classes — with thirty class struct mirrors and 242 vfunc slots, every mirror probed against the running library. The surface is generated, not hand written, which is what made it possible to go from the six hand-bound bases of the previous release to twenty eight in one cycle. An instance the library creates reaches managed code as its managed type, so ElementFactory.Make of a registered type, a pad built from a template and a pad an aggregator requests all dispatch their vfuncs; a managed type installs GObject properties, defines signals and implements GstURIHandler; and a lent GstSegment, GstVideoInfo or GstVideoCodecFrame is wrapped without a copy and invalidated when the call returns. Beside it, an eighteenth package ships for the first time — GstSharp.Net.RtspServer, libgstrtspserver-1.0 — and the introspection half of GObject arrives: the GParamSpec subclasses with their ranges and defaults, the enumeration, flags and interface tables of a GType, and Object.As<T>(). Three samples are new, RtspServer, GesCustomSource and GesLaunch, the last a port of ges-launch-1.0; samples/GstInspect prints every section the real gst-inspect-1.0 prints and CI diffs the two; and benches/ holds a BenchmarkDotNet harness for the dispatch, property and mapping paths. All eighteen packages ship as one version, 1.28.7, generated from the GStreamer 1.28 girs, 249 commits after 1.28.6.

Highlights

  • Managed subclasses, generated. Every subclassable class gets its subclassing surface emitted by the generator rather than written by hand. Nineteen of them are the core and base-library classes — Gst.Element, Gst.Bin, GstBase BaseSrc, PushSrc, BaseSink, BaseTransform, Aggregator and BaseParse, GstAudio AudioBaseSink, AudioBaseSrc, AudioSink, AudioSrc, AudioFilter, AudioDecoder and AudioEncoder, GstVideo VideoSink, VideoFilter, VideoDecoder and VideoEncoder. Each class struct is mirrored, and every mirror's layout is checked against the running library by the integration tests, so a slot patched at the wrong offset fails a test run rather than a pipeline. More than twenty gir annotation corrections were needed to make the slots come out right. A lent boxed record — a GstSegment, an AudioInfo or VideoInfo, a BaseParseFrame, a VideoCodecFrame or VideoCodecState — is wrapped around the address the caller owns instead of copied, and detached when the call returns, which is also what binds six slots the first wave had to skip (BaseSrc::do_seek and ::prepare_seek_segment, BaseTransform::filter_meta, AudioFilter::setup, VideoFilter and VideoSink::set_info); VideoCodecFrame.Copy() and VideoCodecState.Copy() are there for a handler that needs one past the call. AudioDecoder.OnPrePush(ref Buffer?) and its encoder sibling take the inout parameter whose ownership transfers in both directions. handle_frame is required at DefineSubclass time for the parser and the four codec classes, the way a pad template is.
  • Native-initiated construction. IManagedSubclass<TSelf>.CreateWrapper and a generic DefineSubclass<TSelf> overload let an instance GStreamer creates arrive as its managed type with its vfuncs dispatched: an element made through ElementFactory.Make, a pad built from a PadTemplate.NewWithGtype template, a pad an aggregator requests. SubclassType.NewInstance(IReadOnlyDictionary<string, object?>) passes construct-only properties, which is what a GstPad needs for its direction. Gst.Pad and GstBase.AggregatorPad are subclassable in their own right — OnLinked, OnUnlinked, OnFlush, OnSkipBuffer — and Aggregator.OnCreateNewPad is bound. A type defined with the non-generic DefineSubclass keeps the ancestor-wrapper behaviour it had. docs/subclassing.md §5.4 states the fabrication rules: never sink, one winner per handle, and a CreateWrapper that runs on a streaming thread and must do nothing but forward its arguments.
  • Properties, signals and GstURIHandler. ObjectClassConfig.InstallProperty with OnSetProperty and OnGetProperty installs a GObject property on a managed type, Object.Notify(ParamSpec) emits its notification, and Object.SetPropertyOverride/GetPropertyOverride reach a property a base class owns. AddSignal defines a signal with a class handler and an accumulator, SignalAccumulator.TrueHandled or FirstWins. A DefineSubclass<TSelf>(…, SubclassOptions, …) overload on every subclassable class adds interfaces, GstURIHandler first, through URIHandlerImplementation.For<TSelf>(). CONSTRUCT and CONSTRUCT_ONLY are refused by design: GObject dispatches the write to the class that owns the property while the instance is still being built, before the wrapper that would serve it exists. Twenty ParamSpecX.New factories cover the GObject kinds, plus ParamSpecFraction and ParamSpecArray, and five more ParamSpec classes are bound — boxed, object, pointer, param and variant.
  • GES subclassing. GES.TimelineElement, TrackElement, Source, VideoSource, AudioSource, Clip and SourceClip join the subclassable set, with OnCreateSource, OnCreateTrackElement, OnSetParent and the timeline-element setters; class struct mirrors lay out <union> members for it, and Asset.Extract<T>() is hand bound, because that is the child contract a managed OnCreateTrackElement has to satisfy. A create_source or create_element override that answers null or throws gets an identity element substituted and the failure reported: GES 1.28.6 would otherwise free the track element's nleobject while it is still referenced.
  • GstSharp.Net.RtspServer — GstRtspServer. The eighteenth package binds libgstrtspserver-1.0: 18 classes and 41 signals, including the 21 request signals of RTSPClient and the eight socket members of RTSPStream. RTSPMountPoints.AddFactory is hand written so the factory wrapper and its handlers stay alive as long as the mount point holds them, and RTSPServer.Detach is hand written too. samples/RtspServer is a port of the upstream test-launch.c. docs/ownership.md gains an "RTSP server" section with the lock, thread and shutdown rules. Skipped on purpose: the set_send_func pair, which asserts on every reachable path, and RTSPThreadPool.GetThread and RTSPThread.New, which leak a thread without a stop.
  • GParamSpec and GType introspection, and Object.As<T>(). The ParamSpec subclasses are bound — ParamSpecInt through ParamSpecGType in Gst.GObject, plus Gst.ParamSpecFraction and ParamSpecArray — with Minimum, Maximum, Default, Epsilon, Values and IsAType, and ParamSpec itself gains Nick, Blurb, OwnerType, NativeType, DefaultValue as a borrowed ValueView, RedirectTarget and FromNative. GType.GetEnumValues, GetFlagsValues, GetInterfaces and IsInterface read the tables a GType carries, SignalQuery.List(GType) lists its signals, Gst.Object.Flags and IsFlagSet read the object's own flags, and Object.As<T>() casts to an interface through a generated adapter — the module that declares the interface has to be initialised first. ModuleInterfaceEntry and a three-argument NativeModule carry that registration.
  • Runtime additions. Gst.GObject.Object.ListProperties(GType) lists the properties of a class without an instance, which is what gst-inspect-1.0 prints as "Pad Properties". Discoverer.TryDiscoverUri(uri, out GException? error) hands back the DiscovererInfo together with the error, so a missing-plugin result keeps its installer details; DiscoverUri still throws. Gst.GLib.UserDirectories.CacheDir reads g_get_user_cache_dir.
  • Pad functions. A pad's chain, chain-list, get-range, event, event-full, query, iterate-internal-links, link, unlink, activate and activate-mode functions can be set from C# — Pad.SetChainFunction through SetActivateModeFunction, keyed by the pad instance, with null unsetting — and CollectPads.SetBufferFunction and SetClipFunction beside them.
  • Samples and tools. samples/GstInspect is a full port: properties with their ranges and their enumeration and flags tables, element flags, clocking, implemented interfaces, URI protocols, pads with their Type: and pad-property blocks, signals and action signals, children, presets and typefind extensions. CI diffs the page against the real gst-inspect-1.0 on every leg whose tool is new enough. samples/GesLaunch ports ges-launch-1.0 — the ges: timeline grammar, project load and save, rendering, preview sinks, track options, --list-transitions and the interactive keyboard — and shows the one thing the C tool hides inside its GMainLoop: GESProject::loaded is always deferred to the default GMainContext, so a loop-less application pumps Gst.GLib.MainContext.Default.Iteration(false) on the extracting thread until Loaded or ErrorLoading. samples/GesCustomSource is a managed GES source end to end. samples/GstDiscoverer prints installer details, strips arrays of buffers out of its caps and answers --print-cache-dir; samples/GstTranscode runs on the Linux CI leg. Every sample and the integration tests build with the analyzers applied, so a sample that uses the binding the way a rule forbids fails the build.
  • benches/GstSharp.Benchmarks. A BenchmarkDotNet harness for the four paths that carry the cost — trampoline dispatch against a native identity, property get and set with their boxing, Buffer.Map as a span against a copy, and interned wrapper lookup. Every CI job builds it and none of them runs it. The numbers in `benches/README...
Read more

v1.28.6

Choose a tag to compare

@github-actions github-actions released this 03 Sep 09:05

The RTP release: a seventeenth package ships for the first time — GstSharp.Net.Rtp, the RTP and RTCP buffer helpers of gst-plugins-base — and the planner stops handing a number to a C function that dereferences a pointer. A gir parameter or return whose type is a plain scalar and whose C type carries a star was projected by value: an address truncated to the scalar's width coming out, and the value itself where an address was meant going in. That shape is refused now, on a member, on a callback argument and on a signal argument alike, and the two published members that projected it are hand written with signatures that do what the C does. The other half of the same reading — the direction an overlay corrects, taken after the correction — is what lets an out parameter reach a pointer to a scalar and to an enumeration, and that is what unlocks the eighteen RTCP extended report readers of the new module. Beside the new package, the fifteen field accessors the last release parked are decided, and a video time code hands out the configuration it embeds. All seventeen packages ship as one version, 1.28.6, generated from the GStreamer 1.28 girs. The callable ledger goes from 861 entries to 910: forty-seven are the new module's own section, and the remaining two are the members that moved into hand-written code and stay listed as skipped. The field ledger falls from 163 entries to 147, and the section of the fields another member already answers grows from 14 to 18.

Highlights

  • GstSharp.Net.Rtp — GstRtp. The RTP and RTCP buffer helpers of gst-plugins-base, the payloader and depayloader base classes and the header extension API, which is what drives the payloader and depayloader elements the RTP plugins ship and the header extensions built into the library. Authoring a payloader of your own means subclassing GstRTPBasePayload, which the binding does not ship: the module binds the classes as they are used from the outside, not as they are derived from. The gir needs eleven corrections to come out right — the RTCP map, first-packet and add-packet structures are outputs, three returns answer NULL on ordinary input, the digit-led payload name becomes RTPPayload.Fs1016, and gst_rtp_buffer_map and gst_rtcp_buffer_map become MapBuffer while gst_rtcp_packet_get_type becomes GetPacketType, because the names they derive are taken by a field and by object.GetType, and the eighteen extended report readers whose out parameters are typed as bare scalars are skipped until the planner can redirect one — which is the correction the next bullet lifts. Eight members are bound by hand: the FCI and APP data spans, the four byte APP name, the source meta whose SSRC pointer the generator would have passed by value, and the two NTP setters of a later bullet.
  • The RTP mapped structures are not scopes. RTPBuffer and RTCPBuffer are the plain structures the C API declares, and the binding hands them out as they are: declare one as a local, map it once with MapBuffer, unmap it exactly once, and never copy it, store it in a field or capture it in a lambda — the internal ensure_buffers of gstrtpbuffer.c unmaps and remaps through the very structure it is handed, so a call made on a copy unmaps a second time. The Gst.Buffer wrapper the mapping came from has to stay reachable until after the unmap, because the library stores the raw pointer and takes no reference of it; reachability ends at the last use and not at the end of a variable's scope, so a buffer obtained inline as the argument of MapBuffer is finalizable the moment that call returns. An RTCPPacket borrows the address of the RTCPBuffer it was taken from and is usable only while that variable lives. A header accessor called on an RTPBuffer that was never mapped crashes the process — the C side dereferences rtp->data[0] without a guard — while the RTCP half is guarded throughout. docs/ownership.md states all of it under "RTP mapped structures".
  • The RTCP XR report block readers — 18 members, RTCPPacket.XrGetDlrrBlock through XrGetVoipSignalMetrics, with 51 out parameters between them. The gir types every one of those parameters as a bare scalar with the star in the c:type alone and no direction, so a direction: out correction could not reach them: the out and ref arm of the override stopped at a plain structure and at a GValue. It reaches a blittable scalar and a boolean whose C type is a pointer now — the out projection of a guint32 or a gboolean is a local of exactly the width the C declaration names, and its address is what the callee was handed all along — and, separately, an enumeration and a bitfield of the same shape, which is what RTCPPacket.SdesGetEntry and SdesCopyEntry needed for the GstRTCPSDESType * they write through (gstrtcpbuffer.c:1539-1540). The star of the c:type is the evidence that the C side writes through the parameter, so a scalar whose c:type carries none keeps the value projection it had.
  • GstRtp.Initialize(). The new module gets the public entry class every other binding assembly already has, so an application names it beside GstApp.Initialize() rather than relying on the first RTPBuffer mapping to bring the library up.
  • The NTP header extension setters take a Span<byte>. The gir spells the data of gst_rtp_hdrext_set_ntp_56 and _64 as a bare gpointer with no array element, while the matching getters carry an array length, so the generated setters handed the block out as a raw nint beside a size the caller had to keep honest. Both are hand written over Span<byte> instead, and the seven or eight byte length the extension needs is checked before the call, so a short span answers false and leaves the block untouched rather than reaching the critical the C logs. A sweep of every gir finds this shape nowhere else in GStreamer.
  • samples/RtpPacketDump — the RTP module end to end. An audiotestsrc runs through rtpL16pay into an appsink; every packet is read through a mapped RTPBuffer — sequence number, timestamp, SSRC, payload type, marker and payload length — and then a compound RTCP packet of a sender report and an SDES item is built through RTCPBuffer and RTCPPacket, unmapped, mapped again and walked back. Each mapping is released in a finally, so a console write that throws cannot leave one alive into the disposal of its buffer. It is headless, and the three CI legs with a native installation run it.
  • Field accessors the previous release held back — 15 members. Eight are pointers whose consumer contract the C sources do state, so the borrowed read is safe where the C makes it: Buffer.Pool, AudioRingBufferSpec.GetCaps(), BaseParseFrame.GetBuffer() and .GetOutBuffer(), VideoCodecFrame.GetInputBuffer() and .GetOutputBuffer(), VideoCodecState.GetCaps() and .GetAllocationCaps(). Three are embedded records the wave that landed that rule left behind: AudioRingBufferSpec.GetInfo(), CollectData.GetSegment() and VideoTimeCodeMeta.GetTc(). Two are metadata infos whose derived name is taken by a static member that shipped, so the overlays name them after the type they hand out instead: AudioMeta.GetAudioInfo() and ProtectionMeta.GetStructure(). And two are pointers to a plain structure, a shape with no wrapper to project — the address is the library's own storage and a NULL pointer is the structure saying it carries none — so they are copied out as nullable values: VideoCodecState.ContentLightLevel and .MasteringDisplayInfo. Two more fields left the ledger for the section another member answers, CollectData.buffer through CollectPads.Peek and AudioBuffer.info through the hand-written mapping scope, and nine stay unbound for reasons the entries now state one by one rather than for one reason that held for none of them. The window a read of one of these has to happen in is a place as much as a time, so docs/ownership.md says which call, which thread and which lock each of them names, and five integration tests read each accessor where the C contract puts the read.
  • VideoTimeCode reads the configuration it embeds. GstVideoTimeCode carries its GstVideoTimeCodeConfig by value and the configuration wrapper has no public producer, so the frame rate, the flags and the daily jam of a time code were unreachable from C#. FpsN, FpsD and Flags are copies read through the handle of the time code; GetLatestDailyJam() comes back owning a reference of its own, which is why it is a method the caller disposes — the instant stays valid after the time code is gone — and why null says the time code carries none.
  • A field newer than the support floor carries no accessor. The support floor is GStreamer 1.24, and a structure a 1.24 library allocates is not long enough to hold a field that arrived later; there is nothing for a field access to fail on, so no accessor is emitted at all and the ledger line says which version put the field there. The rule covers fixed size inline storage as well now, which used to be answered by a branch that ran ahead of the check. No shipped accessor changes: no fixed size field of any gir is newer than the floor, which the generator verify run confirms.
  • Ledger and diagnostics. A direction, or any other non-nullable override, written on a callback or signal parameter key used to be consumed silently before it could take effect; it is reported as GEN0017 now, and the committed overlays produce none. The entry classes no longer let the claim that the registry sweep covers an application which never names them stand on its own: the sweep reaches assemblies rather than wrappers, and a wrapper built before an assembly is loaded keeps the type it was given. And the remarks of the obsolete override say which member an entry must not name, because a generated property delegates to its accessors, so an entry keyed on one of those turns the property body into a call to an o...
Read more

v1.28.5

Choose a tag to compare

@github-actions github-actions released this 02 Sep 11:41

The record field release: a sixteenth package ships for the first time — GstSharp.Net.Play, the high level playback API of gst-plugins-bad — and wave E turns the fields of a record into API. A string field, a field that points at something the bindings wrap, a record another record embeds by value and the members of the reserved ABI union at the end of a released structure all reach the surface as get-only accessors, so a hundred-odd values that carried API in C and nothing in C# can be read. All sixteen packages ship as one version, 1.28.5, generated from the GStreamer 1.28 girs. The field ledger falls from 267 entries to 163, with fourteen more moved to a section of the fields another member already answers; the callable ledger goes from 817 to 861, and the whole increase of forty-four is the new module's own section.

Highlights

  • GstSharp.Net.Play — GstPlay. A URI, the play controls around it, its media information and its message bus. Upstream marks the library API unstable (docs/libs/play/index.md in the GStreamer monorepo). The 1.24 floor carries only the index-based track selection API, which the generator marks [Obsolete] because upstream deprecated it in 1.26 in favour of the track-id calls. Play.Start() is gst_play_play, renamed because Play.Play is not a legal C# member name and playback could not be started at all without it.
  • What the Play module hand writes. The entry points the planner refuses, or that the C source shows to be unsafe as generated, are written by hand with the same signatures: Play(IPlayVideoRenderer?) mints the extra reference gst_play_new consumes, so the renderer stays usable; Play.SetConfig frees the copy the C function leaks whenever the play is not stopped; PlayMessageExtensions.ParseError / ParseWarning take a GError ** beside a GstStructure **, a shape the planner does not bind, and ParseErrorMissingPlugin / ParseWarningMissingPlugin check the message kind first, where the imported pair reads an uninitialised one for a foreign message; PlaySignalAdapter.New / NewWithMainContext / NewSyncEmit keep the play alive, because the C adapter stores it without referencing it, and PlaySignalAdapter.GetPlay answers ObjectDisposedException afterwards; Play.GetVisualizations() walks the NULL-terminated array and frees it once; and the two PlayVideoOverlayVideoRenderer constructors route a null sink to the constructor that does not touch the video-sink property. Play.Dispose sets the API bus flushing, which breaks the reference cycle the C documentation describes — dispose every PlaySignalAdapter of a play before the play itself.
  • samples/GstPlay — the gst-play-1.0 user experience on the Play object: a playlist, the keyboard controls with the volume and rate pairs moved apart, --volume, --audiosink / --videosink written onto the pipeline GetPipeline answers, --visualization beside --list-visualizations, and a media info summary, all driven by a timed pop of the API bus rather than by a main loop or a signal adapter. Headless is the default: nothing reads the keyboard without --interactive, and --duration bounds the run, which is what lets CI gate it.
  • String fields of a record — 61 get-only properties. A const gchar* field is copied out of the structure on every read, because the storage belongs to the C structure and may be freed or replaced with it. No gir spells nullable on a field, so an accessor is string? unless the overlays correct it against the C. The session description strings and most of the RTSP and WebRTC ones stay nullable; the nineteen the overlays correct are PluginDesc.Name, .Description, .License, .Origin, .Package, .Source and .Version, RTSPUrl.Abspath and .Host, RTSPAuthParam.Name and .Value, StaticPadTemplate.NameTemplate, AudioFormatInfo.Name and .Description, VideoFormatInfo.Name and .Description, FormatDefinition.Nick and .Description, and WebRTCICECandidateStats.Proto.
  • Handle fields of a record — 20 accessors. A field that points at something the bindings wrap is projected through the very expression a transfer-none return of the same type gets, so a field and a getter of it never hand out two different things. The flavour of the wrapper decides the form: a GObject is interned and an opaque wrapper owns nothing, so both are properties — Memory.Allocator, CollectData.Collect and .Pad — while a mini object is referenced and a boxed value copied, so both are read through a Get method the caller disposes: Memory.GetParent(), MapInfo.GetMemory(), VideoMeta.GetBuffer(), VideoCodecState.GetCodecData(), VideoMetaTransform.GetInInfo() / .GetOutInfo() and the same pair on VideoMetaTransformMatrix, WebRTCICECandidatePair.GetLocal() / .GetRemote(), WebRTCICECandidate.GetStats() and the rest. A pointer to a pointer is refused the way the planner refuses an argument of that shape, and a pointer the library replaces or clears while a consumer holds the structure is held back, because the reference the projection takes would be taken after the read.
  • Embedded records — 8 accessors for a record another record holds by value: the four port ranges of a transport, RTSPTransport.Interleaved, .Port, .ClientPort and .ServerPort; VideoInfo.Colorimetry; VideoMeta.Alignment; and the embedded video infos VideoCodecState.GetInfo() and VideoInfoDmaDrm.GetVinfo() answer. A plain structure is copied out by the assignment and read as a property; a boxed value is wrapped from the address the field sits at through the transfer-none projection, which copies it, so the caller disposes what a read produced and the member is a Get method. An embedded record whose wrapper is a bare pointer holder is refused: it would borrow what the declaring record owns and dangle with it.
  • The reserved ABI union is laid out. GStreamer grows a released structure by spending the pointers it reserved at its end, declaring the padding array and the new fields as the two members of a union. The mirrors stopped in front of every union, so six records ended as a prefix shorter than the C structure and three more that embed one of them by value were not laid out at all. That shape is now recognised and laid out as the pointers it reserves, and the accessor is named from the member alone: VideoInfo.MultiviewMode, .MultiviewFlags and .FieldOrder, AudioRingBufferSpec.DsdFormat, CollectData.Dts, WebRTCICECandidateStats.RelatedPort and .TcpType, VideoInfoDmaDrm.DrmFourcc and .DrmModifier, and VideoFrame.Flags and .Id. PadProbeInfo, AudioRingBufferSpec, CollectData, VideoCodecFrame, VideoInfo, WebRTCICECandidateStats, VideoFrame, VideoInfoDmaDrm and VideoCodecState all reach the size of the C structure; only RTSPMessage is a prefix mirror now. The ABI probes are the gate, extended and added against the 1.28.5 headers.
  • AudioClippingMeta.Format is a Gst.Format. An enumeration another generated module declares is one an accessor can hand out after all: the mirror keeps the underlying integer, because a mirror is interop storage and the integer is what crosses, and the accessor casts it — the same thing every signature naming a type of another module already relies on.
  • Ledger and diagnostics. A record field is not a callable and has no c:identifier, so the overlays gain a vocabulary of their own: fieldSkips, keyed by the c:type of the record and the gir name of the field, states either the generated member that answers the same value or that a hand-written one does — exactly one of the two — and moves the field into a new ## Fields exposed elsewhere section; fieldAnnotations carries the nullable: false and accessor: false corrections, every entry citing the C file and line the claim rests on. A stale or self-contradictory entry is reported as GEN0025 and GEN0026, and both codes join GEN0020, GEN0023 and GEN0024 among the five the committed overlays are held to producing none of. The field ledger stops filing eleven fields under Other and names the cause instead — HandWritten, NoLayout, CrossNamespaceEnum — and reports a laid-out union member by member rather than as one line.
  • Documentation and coverage. docs/ownership.md states the three contracts of a field accessor — a string copied on read, a wrapper projected the way a transfer-none return of the same type is, and an embedded record copied out whole — and says when a read has to happen for a structure the library only fills for the length of one call. samples/PlaybinPlayer was the one sample no job ran and now runs headless on the three legs that have a native installation, beside the gst-play port.

Behavioural notes

One shipped member is marked obsolete; nothing else that shipped changed. IRTSPExtension.GetTransports(RTSPLowerTrans, string) gains [Obsolete] in favour of the new RTSPResult GetTransports(this IRTSPExtension ext, RTSPLowerTrans protocols, out string? transport) extension method, which is what the C function actually does (it writes the transport string back through a gchar **). It reads the string the extension wrote, frees it, and answers null when no extension named a transport, which is also what an extension that does not implement the call leaves behind. The old member's signature and behaviour are unchanged. No other member of the fifteen packages of 1.28.4 changes its signature or its behaviour in this release. Everything else above is new surface.

How that is checked. The two generator changes that refuse a pointer-to-handle-pointer parameter — in a call, and in a callback or signal — leave the generated tree and the skip report byte-identical: no shipped gir has an introspectable instance of the first shape, and every instance of the second was already refused ahead of it. Adding the Play module changes no other module's generated output, an...

Read more

v1.28.4

Choose a tag to compare

@github-actions github-actions released this 31 Aug 07:05

The module release: three new packages ship for the first time — GstSharp.Net.Tag, GstSharp.Net.Allocators and GstSharp.Net.Transcoder — which takes the set to fifteen, and the API reference is published as a site. Beside them, wave D closes more families of the skip ledger (the mutators that consume their instance, the GValue a callback is handed, the fixed-size fields of a record, the GParamSpec callables) and the G4 batch fixes the callback-state leaks the clock and custom-meta entry points were hiding. The ledger goes from 848 entries to 817 even with the entries the new modules bring, and a new ## Fields section counts the 267 record fields no accessor reaches yet.

Highlights

  • GstSharp.Net.Tag — the GstTag library. The whole gir: the two abstract element bases that tag demuxers and muxers derive from, the XMP writer interface, and the forty functions that turn an ID3v1 record, a Vorbis comment, an XMP packet or an EXIF IFD into a tag list and back. Five returns the gir does not mark nullable are corrected against the C, because NULL is an ordinary answer there and not an error.
  • GstSharp.Net.Allocators — the fd, dmabuf, shm and DRM dumb allocators. The module registers its five allocator classes; the 1.28-only udmabuf type is left out of the registry on older installations, and the two DRM dumb returns that are NULL on every build without libdrm carry a nullable annotation overlay.
  • GstSharp.Net.Transcoder — GstTranscoder. Transcoder.Run is a one-shot per instance and has to be called from a thread that has no thread-default main context — that is, one that uses the global default: build a new Transcoder for every job, and do not mix Run and RunAsync on one instance. RunAsync reports its two synchronous failures — no encoding profile, and a state change the pipeline refused — on the calling thread before it returns, and every other message arrives on the internal worker thread of the transcoder; the recommended route is RunAsync together with a poll of GetMessageBus, which is what samples/GstTranscode does. TranscoderMessageExtensions.ParseError / ParseWarning are hand written so that a message without issue details answers null, where the imported pair aborts the process.
  • API reference site — the API reference extracted from the XML documentation of the packable projects, together with the guides under docs/, is published with DocFX at https://masa-iwm.github.io/GstSharp.Net/, deployed from main.
  • Mutators that consume their instance — the twenty-one callables whose instance is transfer-full are bound. A _make_writable adopts in place and returns the wrapper it was called on, so caps.MakeWritable() reads as the C idiom it stands for; everything else mints the reference the call takes over and answers a second wrapper, leaving the receiver untouched.
  • GValue arguments of a callback — a const GValue* argument arrives as Gst.GObject.ValueView and a writable one as Gst.GObject.ValueRef, both ref structs over storage somebody else owns. That unlocks the three structure walks, their _id_str twins and the two iterator walks.
  • Fixed-size record fields — 18 get-only properties over GstVideo, GstAudio and GstSdp, the plane stride and offset arrays of VideoInfo and the per-component tables of VideoFormatInfo among them, with hand-written Format and FormatInfo on VideoInfo and AudioInfo beside them. The skip report gains a ## Fields section that counts the 267 public fields no accessor answers yet.
  • GParamSpec callables — a parameter specification reaches a generated signature in both directions, which unlocks eight callables: gst_child_proxy_lookup, gst_object_default_deep_notify, gst_value_deserialize_with_pspec and the five child-property members of GESTimelineElement.
  • Element factories that carry their propertiesElementFactory.MakeWithProperties and .CreateWithProperties ask the class of the loaded factory what type each named value has to hold, write a construct-only property rather than refusing it, and answer an ArgumentException for an unknown or unwritable name instead of the console message GLib prints.
  • GLib.DateSystem.DateOnly — a GDate has no identity and no state a caller could observe, so it is converted at the boundary instead of wrapped, at the six date callables of Gst and the GES meta container.
  • Ledger and diagnostics — sixty-nine C symbols the bindings cover from src/*/Custom and from the runtime are declared hand-bound, so the remaining sections of the skip report measure the gap that is real; a stale overlay entry is now reported (GEN0020 / GEN0023 / GEN0024) and the committed overlays are held to producing none; generate deletes a committed generated file the run no longer emits and verify reports it as a difference; and the class remarks now describe every callback scope the planner binds.
  • Community and coverage — the Contributor Covenant 2.1, a new docs/platform-notes.md for what is a property of a platform rather than of the binding, and new integration tests and samples: BasicTutorial07 and BasicTutorial09, samples/AppSrcPush, the base-utils feature surface, the audio format / meta / converter / volume surfaces, and the VideoCodecFrame user-data contract.

Behavioural fixes

Gst.Clock.IdWaitAsync — callback state leak, and a double free on a refused wait. gst_clock_id_wait_async writes the callback, its state and the destroy notification onto the entry immediately before it dispatches to the clock, so the three exits in front of that assignment never see the notification and the generated member leaked the GCHandle on every one of them. The entry point is now hand written with the same signature and documentation: it releases the state on GST_CLOCK_BADTIME, on GST_CLOCK_UNSUPPORTED and on a GST_CLOCK_ERROR with no clock alone, and leaves it with the entry for the refusals the clock itself answers — GST_CLOCK_UNSCHEDULED for an entry that was unscheduled beforehand, and GST_CLOCK_ERROR when the clock could not start its waiting thread — which the earlier code freed a second time, hitting an unrelated live handle. The reference taken on the clock of the entry across the call is held as a bare handle rather than through a wrapper, because wrappers are interned and disposing one disposed the clock of the caller.

Gst.Meta.RegisterCustom — transform state leak on a refused registration. gst_meta_register_custom only writes the transform function, its state and the destroy notification onto the implementation block once that block exists; both failures before it — an API type that could not be registered, which is what a name that is already taken produces, and a block that could not be allocated — answer NULL. The generated member allocated the GCHandle of the transform first and reported the NULL as an InvalidOperationException, so the throw leaked it. The entry point is now hand written with the same signature and releases the state before it raises. gst_meta_register_custom_simple is a different entry point and stays generated.

Callback state is allocated after every guard and prologue. A member whose only materializing argument was a callback took the GCHandle of the callback before the guard of a later parameter and before the UTF-8 copy of a later string, so either of those throwing stranded the handle, the delegate and everything the closure captured for the life of the process. The allocation is now the last statement before the call.

WebRTCDataChannel.OnMessageData — documentation correction. The remarks named a streaming thread of the pipeline; the handler in fact runs on the main context of the thread webrtcbin starts for the connection. Doc-only.

Behavioural notes

Two hardenings that only change what happens on input C would have mishandled:

  • Buffer.MakeWritable(), Caps.MakeWritable() and every generated *.MakeWritable() now throw an InvalidOperationException when the writable copy could not be made. The C function consumed the reference all the same, so the wrapper is left disposed and the failure is raised, instead of silently handing back an already-consumed wrapper.
  • Value.SetBoxed(Boxed?) and Value.SetMiniObject(MiniObject?) now check that the value holds a boxed type at all and that the GType of the content is that type or derives from it, and throw an InvalidOperationException otherwise — on an uninitialized value, a value of another family, or a content of another type. GLib copies the content with the copy function of the type the value holds, so a wrapper of another type was silently handed to the wrong copy function and left a corrupt value behind; the raw SetBoxed(nint) overload has no type to check and is unchanged. This mirrors the check ValueRef has performed since it shipped.

No signature changed for either.

Changes

  • Check the content type at the two wrapper setters of Value
  • Say which context the discoverer takes and that its signal is bound
  • Cover the base utils features and port the tee, discoverer and appsrc samples
  • Convert GLib.Date to System.DateOnly at the six date callables
  • Count the three new modules across the docs, workflows and tests
  • Bind the Gst.Transcoder module, its sample and the API bus parses
  • Bind the GstTag library as the GstSharp.Net.Tag module
  • Bind the fd, dmabuf, shm and DRM dumb allocators of GstAllocators
  • Publish the API reference and guides with DocFX on GitHub Pages
  • Bind the element factories that take their properties with them
  • Bind the callables that take or hand out a GParamSpec
  • Pin the VideoCodecFrame user data contract through theoradec
  • Cover the audio format, meta, converter and volume surfaces with integration tests
  • Ledger on-message-data as hand bound and correct the thread its remarks name
  • Replace the gir returns text of adopt in place membe...
Read more

v1.28.3

Choose a tag to compare

@github-actions github-actions released this 23 Aug 03:04

The generator capability release: fourteen planner and emitter extensions turn the largest remaining gaps of the skip ledger into generated members. Every existing API keeps compiling, enforced by package validation against the 1.28.2 baseline; the ledger shrinks from 1,335 entries to 848.

Highlights

  • Consuming in-parameters are generated — callables whose callee takes ownership (AppSrc.PushBuffer-style) are emitted with the same mint-and-dispose contract the hand-written members established; the wrapper stays valid after the call.
  • GValue everywhere — callables that take or return a Value, the ValueArray entry points, and the fundamental value-container functions (ValueArray / ValueList / ValueUniqueList) are bound, so caps fields that hold lists can be read and written.
  • Properties without a C accessor — 191 GObject properties that only existed as pspecs are now typed C# properties.
  • Caller-allocates out parameters, value-struct methods and record fields — the (out caller-allocates) shape, the methods declared on plain value structs, and accessors on boxed and opaque records (Meta records included) are generated, with the layouts pinned by ABI probes.
  • Strings and arrays — NULL-terminated string arrays, the array annotations the girs leave short, and GLib.DateTime with the transfer-full signal returns.
  • Callbacks — asynchronous callbacks with a destroy notify, honouring the nullable annotation on callback parameters.
  • Lists and errorsGList / GSList input parameters, and the GError signals and callables projected onto GException.
  • Buffer meta — the meta attachment cluster is hand-bound (Buffer.AddMeta / ForeachMeta and friends).
  • Zero-copy wrappersBuffer.NewWrappedFull and Memory.NewWrapped hand a managed buffer to GStreamer without a copy and release it through the notify.

Behavioural fixes (release-note callouts per the compatibility promise)

Gst.Base.CollectPads.SetFunction / SetCompareFunction / SetEventFunction / SetFlushFunction / SetQueryFunction — use-after-free fix. The gir declares these callbacks as call-scoped; the C library stores them and invokes them from the streaming thread. The shipped members freed the managed trampoline when the setter returned, so the next buffer dereferenced a dead delegate. The binding now keeps the callback state alive for the life of the process, because the library offers no destroy notification to release it: one handle is leaked per call, so install each function once, at construction — replacing it does not release the previous state.

Gst.Meta.ApiTypeAggregateParams — signature and behaviour fix. The overload that shipped in 1.28.2 never worked: the C function takes a GstStructure**, the gir declares a GstStructure*, and every call overwrote the GType header of the structure the caller handed in and leaked the copy the aggregator had just made. The result now comes back through an out parameter: bool ApiTypeAggregateParams(GType api, out Structure? aggregatedParams, Structure? params0, Structure? params1). The shipped overload is kept as an [Obsolete] member that throws NotSupportedException and will be removed in 1.30 — it is kept because an out parameter is passed by reference, so a consumer compiled against 1.28.2 would otherwise get a MissingMethodException and one recompiling would get CS1620. Package validation does not see that break: it compares member signatures without the ref kind, so the 1.28.x source and binary promise is what keeps the bridge alive, not the gate. Do not delete it on the strength of a green gate.

Gst.Video.VideoGlobal.BufferAddVideoMeta and BufferAddVideoMetaFull now return VideoMeta?. Both C functions answer NULL for a format/width/height combination gst_video_info_set_format rejects, and on a buffer that is not writable — the gir marks neither return nullable, so the generated members turned a legitimate caller condition into an InvalidOperationException whose message named the wrong cause. They now answer null. Code that dereferenced the result unconditionally will see a nullable-reference warning; that warning is the bug it was hiding.

Behavioural notes

Three hardenings that only change what happens on input C would have mishandled:

  • Hidden array lengths narrower than int (byte / ushort, the nine MIKEY members) now throw ArgumentException for a span too long to describe instead of silently wrapping the count.
  • Value.CopyFrom with a non-NULL source whose type is 0 now leaves the target empty instead of forwarding to g_value_copy and its g_critical.
  • Value.SetObject keeps the wrapper it was given alive for as long as the value holds it.

No signature changed for any of these. Members bound for the first time in this release (AudioGlobal.BufferGetAudioDownmixMetaForChannels among them) chose their nullable shape at first binding and affect no existing caller.

Changes

  • Bind the GError signals and callables onto GException
  • Bind the GList and GSList input parameters
  • Hand-bind the buffer meta attachment cluster and fix the aggregate-params corruption
  • Honour the nullable annotation on callback parameters
  • Bind the asynchronous callbacks and keep the CollectPads functions alive
  • Complete the array annotations the girs leave short
  • Bind the NULL-terminated string arrays
  • Branch the null select-element-track answer on the 1.28 discard gate
  • Bind GLib.DateTime and the transfer-full GObject signal returns
  • Plan a discarded gboolean return as a void callee
  • Bind the methods declared on plain value structs
  • Bind the caller-allocates out parameters
  • Bind field accessors on boxed and opaque records
  • Bind the fundamental value container functions
  • Add a shared GStreamer 1.28 availability probe for tests
  • Bind properties that have no C accessor
  • Bind the GValueArray entry points
  • Bind callables that take or return a GValue
  • Say what AudioBuffer actually ships
  • Bind in-parameters whose callee takes ownership
  • Order generated prologues as guards, then handle reads, then allocations
  • Say what the SDK floor actually decides
  • Say 1.28.2 in the pin table too
  • Accept any .NET 10 SDK
  • Guard the 1.28.2 surface too
  • Say 1.28.2 when nobody passes a version
  • Drop csproj files from the NuGet cache key

Full Changelog: v1.28.2...v1.28.3

v1.28.2

Choose a tag to compare

@github-actions github-actions released this 18 Aug 13:30

Additive quick wins on the 1.28.1 surface: every existing API keeps compiling, enforced by package validation against the 1.28.1 baseline.

Highlights

  • playbin3 track switchingEvent.NewSelectStreams / ParseSelectStreams.
  • TagList write pathAddValue plus typed writers (AddString, AddUint, ...); a recording can finally carry a title.
  • Properties by name in one lineSetProperty(string, object?), GetProperty<T>(string) and FindProperty(string) for the elements no .gir file describes (x264enc, the d3d11 family, webrtcbin).
  • Segment fields — rate, start, stop, position and the rest are readable and writable, with the layout pinned by ABI probes.
  • Five consuming calls hand-boundEvent.NewCustom, Message.NewCustom, Query.NewCustom, Promise.Reply, EncodingContainerProfile.AddProfile.
  • Controller module complete — LFO and trigger control sources, ARGB and proxy bindings, still zero InternalsVisibleTo.
  • TypeFind.TryPeek — a registered typefinder can read the stream it identifies.
  • Gst.Global.MacosMain / MacosMainSimple — really bound, [SupportedOSPlatform("macos")].

Behavioral fixes (release-note callouts per the compatibility promise)

Two by-name property members no longer fail silently. In C, g_object_get_property / g_object_set_property answer misuse with a console warning and no effect; these now throw instead:

  • Object.GetProperty(string) throws ArgumentException for a property that cannot be read (previously: an unfilled Value).
  • Object.SetProperty(string, in Value) throws ArgumentException for an unknown name, an unwritable or construct-only property, an empty value, or a value type GObject cannot transform (previously: a silent no-op). Every conversion GObject performs — an int into a gdouble property, for example — still goes through unchanged.

No signature changed; code that used these members correctly is unaffected.

Changes

  • Guard the value-taking property writer too
  • Let a property be asked about before it is touched
  • Keep the segment tests on the 1.24 floor
  • Tell the twelve packages apart on nuget.org
  • Bind the gst_macos_main family for real
  • Bind the rest of libgstcontroller
  • Make a property one line in either direction
  • Expose the fields of a segment
  • Give stream selection its write side
  • Hand-bind the five hottest consuming calls
  • Give the tag list a write path
  • Let typefinders read the stream they identify
  • Say 1.28.1 when nobody passes a version
  • Hold every push to the 1.28.1 surface

Full Changelog: v1.28.1...v1.28.2

v1.28.1

Choose a tag to compare

@github-actions github-actions released this 18 Aug 07:42

This release is the new compatibility baseline, and the last breaking one. 1.28.1 is the one-time shape fix taken in the first week of the series, while nothing yet depended on the surface: the buffer metas, StaticCaps/StaticPadTemplate, VideoResampler and their kin moved from value snapshots to the pointer-backed wrappers their C contracts require; the members that discarded or overran what the native call wrote — two of them corrupting the caller's stack, one freeing the ring buffer's own memory — were repaired; the digit-led enum members got names that say what they mean; and the byte/bit cursors were declared out of scope in favor of Span<byte> and BinaryPrimitives. From here on, within 1.28.x the public surface only grows — the promise in the README's "Status and versioning" counts from this release. 1.28.0 and its previews are unlisted accordingly.

Changes

  • Hold the Roslyn floor by hand
  • build: Bump Microsoft.CodeAnalysis.CSharp.Analyzer.Testing from 1.1.2 to 1.1.4 (#2)
  • build: Bump Microsoft.NET.Test.Sdk from 17.14.1 to 18.9.0 (#3)
  • build: Bump xunit.runner.visualstudio from 3.1.5 to 4.0.0 (#4)
  • Stop freeing the ring buffer's own memory
  • Ride the fixes that break nothing
  • Count the promise from 1.28.1
  • Keep the natural field names free for typed accessors
  • Hand back what the callee wrote
  • Reach the static caps cache instead of copying it
  • Address the buffer metas through the buffer that owns them
  • Name the enum members the underscore was hiding
  • Declare the byte and bit cursors out of scope
  • Run the NativeAOT gate on linux-x64 as well
  • Give the WebRTC tests a leg that runs them
  • List the commits in the release notes
  • Pin the actions to commit shas and let dependabot move them
  • Add issue forms, a PR template and a security policy
  • Explain what to do when the census fails
  • Stop claiming gst_macos_main is bound

Full Changelog: v1.28.0...v1.28.1