diff --git a/ChangeLog b/ChangeLog index a24018a5cb..ec9d69718f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +2006-07-13 Aaron Bockover + + * gstreamer-sharp/BindingHelper.cs: Static helper class to assist + in making element bindings (delegate manipulation/invocation) + + * gstreamer-sharp/DynamicSignal.cs: Updated DynamicSignalArgs so they + can more easily be derived + + * gstreamer-sharp/Makefile.am: Updated build + + * sample/HelloWorld.cs: More cleaning + + * sample/Makefile.am: + * sample/TypeFind.cs: Added typefind sample + + * gstreamer-sharp.mdp: Updated MonoDevelop project + + * gstreamer-sharp/plugins-base/DecodeBin.cs: Signal support rewritten + to use BindingHelper/DynamicSignal + + * gstreamer-sharp/plugins-base/TypeFindElement.cs: New typefind + element wrapper using BindingHelper/DynamicSignal + + * gstreamer-sharp/Element.custom: Fixed property getter/setter methods + and added indexer wrapper for property lookup for syntax convenience + 2006-07-12 Aaron Bockover * sample/HelloWorld.cs: Cleaned up, works with new dynamic signal stuff diff --git a/gstreamer-sharp.mdp b/gstreamer-sharp.mdp index 2bc8330949..62e20545f4 100644 --- a/gstreamer-sharp.mdp +++ b/gstreamer-sharp.mdp @@ -42,6 +42,9 @@ + + + \ No newline at end of file diff --git a/gstreamer-sharp/BindingHelper.cs b/gstreamer-sharp/BindingHelper.cs new file mode 100644 index 0000000000..0fc660dfe8 --- /dev/null +++ b/gstreamer-sharp/BindingHelper.cs @@ -0,0 +1,52 @@ +// +// BindingHelper.cs: Utility methods to make creating +// element bindings by hand an easier task +// +// Authors: +// Aaron Bockover (abockover@novell.com) +// +// (C) 2006 Novell, Inc. +// + +using System; +using GLib; + +namespace Gst +{ + public static class BindingHelper + { + public static Delegate AddProxySignalDelegate(Element element, string signal, + GLib.DynamicSignalHandler baseHandler, Delegate existingHandler, Delegate addHandler) + { + if(existingHandler == null) { + element.Connect(signal, baseHandler); + } + + return Delegate.Combine(existingHandler, addHandler); + } + + public static Delegate RemoveProxySignalDelegate(Element element, string signal, + GLib.DynamicSignalHandler baseHandler, Delegate existingHandler, Delegate removeHandler) + { + Delegate temp_delegate = Delegate.Remove(existingHandler, removeHandler); + if(temp_delegate == null) { + element.Disconnect(signal, baseHandler); + } + + return temp_delegate; + } + + public static void InvokeProxySignalDelegate(Delegate raiseDelegate, Type type, + object o, GLib.DynamicSignalArgs args) + { + if(!type.IsSubclassOf(typeof(GLib.DynamicSignalArgs))) { + throw new ArgumentException("Args type must derive DynamicSignalArgs"); + } + + if(raiseDelegate != null) { + raiseDelegate.DynamicInvoke(new object [] { o, + Activator.CreateInstance(type, new object [] { args }) }); + } + } + } +} diff --git a/gstreamer-sharp/DynamicSignal.cs b/gstreamer-sharp/DynamicSignal.cs index 02cf892f64..5a8c7f6a3e 100644 --- a/gstreamer-sharp/DynamicSignal.cs +++ b/gstreamer-sharp/DynamicSignal.cs @@ -19,23 +19,29 @@ namespace GLib { private GLib.Object sender; private object [] args; - - internal DynamicSignalArgs(GLib.Object sender, object [] args) + + public DynamicSignalArgs() { - this.sender = sender; - this.args = args; } + public DynamicSignalArgs(DynamicSignalArgs args) + { + Sender = args.Sender; + Args = args.Args; + } + public object this[int index] { get { return Args[index]; } } public GLib.Object Sender { get { return sender; } + internal set { sender = value; } } public object [] Args { get { return args; } + internal set { args = value; } } } @@ -124,7 +130,10 @@ namespace GLib DynamicSignalHandler handler = (DynamicSignalHandler)((GCHandle)userdata).Target; if(handler != null) { - handler(gobject, new DynamicSignalArgs(gobject, args)); + DynamicSignalArgs dargs = new DynamicSignalArgs(); + dargs.Sender = gobject; + dargs.Args = args; + handler(gobject, dargs); } } diff --git a/gstreamer-sharp/Element.custom b/gstreamer-sharp/Element.custom index add700ce60..a56578ee00 100644 --- a/gstreamer-sharp/Element.custom +++ b/gstreamer-sharp/Element.custom @@ -1,4 +1,9 @@ + public object this[string property] { + get { return GetProperty(property).Val; } + set { SetProperty(property, value); } + } + public new GLib.Value GetProperty(string propertyName) { return base.GetProperty(propertyName); @@ -9,22 +14,29 @@ base.SetProperty(propertyName, value); } - public void SetProperty(string propertyName, string value) + public void SetProperty(string propertyName, object value) { - GLib.Value val = new GLib.Value(value); - base.SetProperty(propertyName, val); + base.SetProperty(propertyName, new GLib.Value(value)); } - public void SetProperty(string propertyName, double value) + public void SetProperty(string propertyName, string value) { - GLib.Value val = new GLib.Value(value); - base.SetProperty(propertyName, val); + base.SetProperty(propertyName, new GLib.Value(value)); + } + + public void SetProperty(string propertyName, int value) + { + base.SetProperty(propertyName, new GLib.Value(value)); + } + + public void SetProperty(string propertyName, double value) + { + base.SetProperty(propertyName, new GLib.Value(value)); } public void SetProperty(string propertyName, bool value) { - GLib.Value val = new GLib.Value(value); - base.SetProperty(propertyName, val); + base.SetProperty(propertyName, new GLib.Value(value)); } [DllImport("gstreamer-0.10.dll")] diff --git a/gstreamer-sharp/Makefile.am b/gstreamer-sharp/Makefile.am index e5e94b4576..e5e8717db0 100644 --- a/gstreamer-sharp/Makefile.am +++ b/gstreamer-sharp/Makefile.am @@ -38,12 +38,14 @@ clean-local: sources = \ DynamicSignal.cs \ + BindingHelper.cs \ Application.cs \ Version.cs \ AssemblyInfo.cs \ CommonTags.cs \ plugins-base/PlayBin.cs \ - plugins-base/DecodeBin.cs + plugins-base/DecodeBin.cs \ + plugins-base/TypeFindElement.cs build_sources = $(addprefix $(srcdir)/, $(sources)) diff --git a/gstreamer-sharp/plugins-base/DecodeBin.cs b/gstreamer-sharp/plugins-base/DecodeBin.cs index f053f47700..7face8d879 100644 --- a/gstreamer-sharp/plugins-base/DecodeBin.cs +++ b/gstreamer-sharp/plugins-base/DecodeBin.cs @@ -8,14 +8,18 @@ // using System; -using System.Runtime.InteropServices; +using Gst; namespace Gst { public delegate void NewDecodedPadHandler(object o, NewDecodedPadArgs args); - public class NewDecodedPadArgs : GLib.SignalArgs + public class NewDecodedPadArgs : GLib.DynamicSignalArgs { + public NewDecodedPadArgs(GLib.DynamicSignalArgs args) : base(args) + { + } + public Gst.Pad Pad { get { return (Gst.Pad)Args[0]; } } @@ -27,84 +31,27 @@ namespace Gst public class DecodeBin : Bin { + private Delegate new_decoded_pad_delegate; + public DecodeBin(IntPtr raw) : base(raw) { - } + } - [GLib.CDeclCallback] - private delegate void NewDecodedPadSignalDelegate(IntPtr arg0, IntPtr arg1, bool arg2, IntPtr gch); - - private static void NewDecodedPadSignalCallback(IntPtr arg0, IntPtr arg1, bool arg2, IntPtr gch) + protected virtual void OnNewDecodedPad(object o, GLib.DynamicSignalArgs args) { - GLib.Signal sig = ((GCHandle)gch).Target as GLib.Signal; - if(sig == null) { - throw new Exception("Unknown signal GC handle received " + gch); - } - - Gst.NewDecodedPadArgs args = new Gst.NewDecodedPadArgs(); - args.Args = new object[2]; - args.Args[0] = GLib.Object.GetObject(arg1) as Gst.Pad; - args.Args[1] = arg2; - - Gst.NewDecodedPadHandler handler = (Gst.NewDecodedPadHandler)sig.Handler; - handler(GLib.Object.GetObject(arg0), args); + BindingHelper.InvokeProxySignalDelegate(new_decoded_pad_delegate, + typeof(NewDecodedPadArgs), o, args); } - - [GLib.CDeclCallback] - private delegate void NewDecodedPadVMDelegate(IntPtr bin, IntPtr pad, bool last); - - private static NewDecodedPadVMDelegate NewDecodedPadVMCallback; - - private static void newdecodedpad_cb(IntPtr bin, IntPtr pad, bool last) - { - DecodeBin bin_managed = GLib.Object.GetObject(bin, false) as DecodeBin; - bin_managed.OnNewDecodedPad(GLib.Object.GetObject(pad) as Gst.Pad, last); - } - - private static void OverrideNewDecodedPad(GLib.GType gtype) - { - if(NewDecodedPadVMCallback == null) { - NewDecodedPadVMCallback = new NewDecodedPadVMDelegate(newdecodedpad_cb); - } - - OverrideVirtualMethod(gtype, "new-decoded-pad", NewDecodedPadVMCallback); - } - - [GLib.DefaultSignalHandler(Type=typeof(Gst.DecodeBin), ConnectionMethod="OverrideNewDecodedPad")] - protected virtual void OnNewDecodedPad(Gst.Pad pad, bool last) - { - GLib.Value ret = GLib.Value.Empty; - GLib.ValueArray inst_and_params = new GLib.ValueArray(3); - GLib.Value [] vals = new GLib.Value[3]; - - vals[0] = new GLib.Value(this); - inst_and_params.Append(vals[0]); - - vals[1] = new GLib.Value(pad); - inst_and_params.Append(vals[1]); - - vals[2] = new GLib.Value(last); - inst_and_params.Append(vals[2]); - - g_signal_chain_from_overridden(inst_and_params.ArrayPtr, ref ret); - - foreach(GLib.Value v in vals) { - v.Dispose(); - } - } - - [GLib.Signal("new-decoded-pad")] - public event Gst.NewDecodedPadHandler NewDecodedPad { + + public event NewDecodedPadHandler NewDecodedPad { add { - GLib.Signal sig = GLib.Signal.Lookup(this, "new-decoded-pad", - new NewDecodedPadSignalDelegate(NewDecodedPadSignalCallback)); - sig.AddDelegate(value); + new_decoded_pad_delegate = BindingHelper.AddProxySignalDelegate(this, + "new-decoded-pad", OnNewDecodedPad, new_decoded_pad_delegate, value); } remove { - GLib.Signal sig = GLib.Signal.Lookup(this, "new-decoded-pad", - new NewDecodedPadSignalDelegate(NewDecodedPadSignalCallback)); - sig.RemoveDelegate(value); + new_decoded_pad_delegate = BindingHelper.RemoveProxySignalDelegate(this, + "new-decoded-pad", OnNewDecodedPad, new_decoded_pad_delegate, value); } } } diff --git a/gstreamer-sharp/plugins-base/TypeFindElement.cs b/gstreamer-sharp/plugins-base/TypeFindElement.cs new file mode 100644 index 0000000000..38b6a6cb11 --- /dev/null +++ b/gstreamer-sharp/plugins-base/TypeFindElement.cs @@ -0,0 +1,103 @@ +// +// TypeFindElement.cs: typefind element binding +// +// Authors: +// Aaron Bockover (abockover@novell.com) +// +// (C) 2006 Novell, Inc. +// + +using System; + +namespace Gst +{ + public delegate void HaveTypeHandler(object o, HaveTypeArgs args); + + public class HaveTypeArgs : GLib.DynamicSignalArgs + { + public HaveTypeArgs(GLib.DynamicSignalArgs args) : base(args) + { + } + + public uint Probability { + get { return (uint)Args[0]; } + } + + public Gst.Caps Caps { + get { return (Gst.Caps)Args[1]; } + } + } + + public class TypeFindElement : Element + { + private Delegate have_type_delegate; + + public TypeFindElement(IntPtr raw) : base(raw) + { + } + + public static TypeFindElement Make(string name) + { + return ElementFactory.Make("typefind", name) as TypeFindElement; + } + + protected virtual void OnHaveType(object o, GLib.DynamicSignalArgs args) + { + BindingHelper.InvokeProxySignalDelegate(have_type_delegate, typeof(HaveTypeArgs), o, args); + } + + public event HaveTypeHandler HaveType { + add { + have_type_delegate = BindingHelper.AddProxySignalDelegate(this, "have-type", + OnHaveType, have_type_delegate, value); + } + + remove { + have_type_delegate = BindingHelper.RemoveProxySignalDelegate(this, "have-type", + OnHaveType, have_type_delegate, value); + } + } + + [GLib.Property("caps")] + public Gst.Caps Caps { + get { + GLib.Value val = GetProperty("caps"); + Gst.Caps caps = (Gst.Caps)val.Val; + val.Dispose(); + return caps; + } + } + + [GLib.Property("minimum")] + public uint Minimum { + get { + GLib.Value val = GetProperty("minimum"); + uint ret = (uint)val.Val; + val.Dispose(); + return ret; + } + + set { + GLib.Value val = new GLib.Value(value); + SetProperty("minimum", val); + val.Dispose(); + } + } + + [GLib.Property("maximum")] + public uint Maximum { + get { + GLib.Value val = GetProperty("maximum"); + uint ret = (uint)val.Val; + val.Dispose(); + return ret; + } + + set { + GLib.Value val = new GLib.Value(value); + SetProperty("maximum", val); + val.Dispose(); + } + } + } +} diff --git a/sample/HelloWorld.cs b/sample/HelloWorld.cs index b452a7c25e..6f17dcbc33 100644 --- a/sample/HelloWorld.cs +++ b/sample/HelloWorld.cs @@ -17,11 +17,8 @@ public class HelloWorld Application.Init(); loop = new MainLoop(); - - if((pipeline = new Pipeline("audio-player")) == null) { - Console.WriteLine("Could not create audio player pipeline"); - } - + pipeline = new Pipeline("audio-player"); + if((source = ElementFactory.Make("filesrc", "file-source")) == null) { Console.WriteLine("Could not create file-source"); } @@ -32,7 +29,7 @@ public class HelloWorld identity = ElementFactory.Make("identity", "identitye"); sink = ElementFactory.Make("alsasink", "alsa-output"); - source.SetProperty("location", args[0]); + source["location"] = args[0]; Bin bin = (Bin) pipeline; bin.Bus.AddWatch(new BusFunc(BusCall)); diff --git a/sample/Makefile.am b/sample/Makefile.am index b54979ef63..ed8cd02eb7 100644 --- a/sample/Makefile.am +++ b/sample/Makefile.am @@ -1,6 +1,8 @@ -TARGETS = playbin-player.exe decodebin-transcoder.exe helloworld.exe +TARGETS = playbin-player.exe decodebin-transcoder.exe helloworld.exe typefind.exe DEBUGS = $(addsuffix .mdb, $(TARGETS)) +all: $(TARGETS) link + assemblies=$(top_builddir)/gstreamer-sharp/gstreamer-sharp.dll references=$(addprefix /r:, $(assemblies)) @@ -14,9 +16,16 @@ decodebin-transcoder.exe: $(srcdir)/DecodeBinTranscoder.cs $(assemblies) helloworld.exe: $(srcdir)/HelloWorld.cs $(assemblies) $(CSC) -out:$@ $(GLIBSHARP_LIBS) $(references) $(srcdir)/HelloWorld.cs +typefind.exe: $(srcdir)/TypeFind.cs $(assemblies) + $(CSC) -out:$@ $(GLIBSHARP_LIBS) $(references) $(srcdir)/TypeFind.cs + +link: + ln -sf $(top_builddir)/gstreamer-sharp/gstreamer-sharp.dll gstreamer-sharp.dll + ln -sf $(top_builddir)/gstreamer-sharp/gstreamer-sharp.dll.config gstreamer-sharp.dll.config + noinst_SCRIPTS = $(TARGETS) -CLEANFILES = $(TARGETS) $(DEBUGS) +CLEANFILES = $(TARGETS) $(DEBUGS) gstreamer-sharp.dll* MAINTAINERCLEANFILES = Makefile.in EXTRA_DIST = \ diff --git a/sample/TypeFind.cs b/sample/TypeFind.cs new file mode 100644 index 0000000000..5eb743aaca --- /dev/null +++ b/sample/TypeFind.cs @@ -0,0 +1,37 @@ +using System; +using Gst; + +public static class GstTypefindTest +{ + private static TypeFindElement typefind; + + public static void Main(string [] args) + { + Application.Init(); + + Pipeline pipeline = new Pipeline("pipeline"); + Element source = ElementFactory.Make("filesrc", "source"); + typefind = TypeFindElement.Make("typefind"); + Element sink = ElementFactory.Make("fakesink", "sink"); + + source.SetProperty("location", args[0]); + + typefind.HaveType += OnHaveType; + + pipeline.AddMany(source, typefind, sink); + source.Link(typefind); + typefind.Link(sink); + + pipeline.SetState(State.Paused); + pipeline.SetState(State.Null); + + pipeline.Dispose(); + } + + private static void OnHaveType(object o, HaveTypeArgs args) + { + args.Caps.Refcount++; + Console.WriteLine("MimeType: {0}, {1}", args.Caps, typefind.Caps); + } +} +