diff --git a/ChangeLog b/ChangeLog index 373d7becc4..5deffdb5ef 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2006-05-21 Aaron Bockover + + * gstreamer-sharp/plugins-base/DecodeBin.cs: Added a quick binding for + decodebin to test new-decoded-pad; probably is only a temporary solution + + * sample/DecodeBinTranscoder.cs: Added a small decodebin sample + + * sample/Makefile.am: Added build rules for decodebin sample + + * gstreamer-sharp.mdp: Updated MonoDevelop project + + * gstreamer-sharp/Makefile.am: Added plugins-base/DecodeBin.cs + 2006-05-20 Aaron Bockover * autogen.sh: Fixed a left over configure.in to configure.ac diff --git a/gstreamer-sharp.mdp b/gstreamer-sharp.mdp index 60421db095..e37560b394 100644 --- a/gstreamer-sharp.mdp +++ b/gstreamer-sharp.mdp @@ -35,6 +35,9 @@ + + + \ No newline at end of file diff --git a/gstreamer-sharp/Makefile.am b/gstreamer-sharp/Makefile.am index 211dc32763..7c5e7f613b 100644 --- a/gstreamer-sharp/Makefile.am +++ b/gstreamer-sharp/Makefile.am @@ -36,12 +36,13 @@ uninstall-local: clean-local: rm -rf generated -sources = \ - Application.cs \ +sources = \ + Application.cs \ Version.cs \ - AssemblyInfo.cs \ - CommonTags.cs \ - plugins-base/PlayBin.cs + AssemblyInfo.cs \ + CommonTags.cs \ + plugins-base/PlayBin.cs \ + plugins-base/DecodeBin.cs build_sources = $(addprefix $(srcdir)/, $(sources)) diff --git a/gstreamer-sharp/plugins-base/DecodeBin.cs b/gstreamer-sharp/plugins-base/DecodeBin.cs new file mode 100644 index 0000000000..f053f47700 --- /dev/null +++ b/gstreamer-sharp/plugins-base/DecodeBin.cs @@ -0,0 +1,111 @@ +// +// DecodeBin.cs: decodebin element binding +// +// Authors: +// Aaron Bockover (abockover@novell.com) +// +// (C) 2006 Novell, Inc. +// + +using System; +using System.Runtime.InteropServices; + +namespace Gst +{ + public delegate void NewDecodedPadHandler(object o, NewDecodedPadArgs args); + + public class NewDecodedPadArgs : GLib.SignalArgs + { + public Gst.Pad Pad { + get { return (Gst.Pad)Args[0]; } + } + + public bool Last { + get { return (bool)Args[1]; } + } + } + + public class DecodeBin : Bin + { + 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) + { + 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); + } + + [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 { + add { + GLib.Signal sig = GLib.Signal.Lookup(this, "new-decoded-pad", + new NewDecodedPadSignalDelegate(NewDecodedPadSignalCallback)); + sig.AddDelegate(value); + } + + remove { + GLib.Signal sig = GLib.Signal.Lookup(this, "new-decoded-pad", + new NewDecodedPadSignalDelegate(NewDecodedPadSignalCallback)); + sig.RemoveDelegate(value); + } + } + } +} diff --git a/sample/DecodeBinTranscoder.cs b/sample/DecodeBinTranscoder.cs new file mode 100644 index 0000000000..4e353f403d --- /dev/null +++ b/sample/DecodeBinTranscoder.cs @@ -0,0 +1,196 @@ +// +// DecodeBinTranscoder.cs: sample transcoder using DecodeBin binding +// +// Authors: +// Aaron Bockover (abockover@novell.com) +// +// (C) 2006 Novell, Inc. +// + +using System; +using Gst; + +public delegate void ErrorHandler(object o, ErrorArgs args); +public delegate void ProgressHandler(object o, ProgressArgs args); + +public class ErrorArgs : EventArgs +{ + public string Error; +} + +public class ProgressArgs : EventArgs +{ + public long Duration; + public long Position; +} + +public class DecodeBinTranscoder : IDisposable +{ + private Pipeline pipeline; + private Element filesrc; + private Element filesink; + private Element audioconvert; + private Element encoder; + private DecodeBin decodebin; + + private uint progress_timeout; + + public event EventHandler Finished; + public event ErrorHandler Error; + public event ProgressHandler Progress; + + public DecodeBinTranscoder() + { + ConstructPipeline(); + } + + public void Transcode(string inputFile, string outputFile) + { + filesrc.SetProperty("location", inputFile); + filesink.SetProperty("location", outputFile); + + pipeline.SetState(State.Playing); + progress_timeout = GLib.Timeout.Add(250, OnProgressTimeout); + } + + public void Dispose() + { + pipeline.Dispose(); + } + + protected virtual void OnFinished() + { + EventHandler handler = Finished; + if(handler != null) { + handler(this, new EventArgs()); + } + } + + protected virtual void OnError(string error) + { + ErrorHandler handler = Error; + if(handler != null) { + ErrorArgs args = new ErrorArgs(); + args.Error = error; + handler(this, args); + } + } + + protected virtual void OnProgress(long position, long duration) + { + ProgressHandler handler = Progress; + if(handler != null) { + ProgressArgs args = new ProgressArgs(); + args.Position = position; + args.Duration = duration; + handler(this, args); + } + } + + private void ConstructPipeline() + { + pipeline = new Pipeline("pipeline"); + + filesrc = ElementFactory.Make("filesrc", "filesrc"); + filesink = ElementFactory.Make("filesink", "filesink"); + audioconvert = ElementFactory.Make("audioconvert", "audioconvert"); + encoder = ElementFactory.Make("wavenc", "wavenc"); + decodebin = ElementFactory.Make("decodebin", "decodebin") as DecodeBin; + decodebin.NewDecodedPad += OnNewDecodedPad; + + pipeline.AddMany(filesrc, decodebin, audioconvert, encoder, filesink); + + filesrc.Link(decodebin); + audioconvert.Link(encoder); + encoder.Link(filesink); + + pipeline.Bus.AddWatch(new BusFunc(OnBusMessage)); + } + + private void OnNewDecodedPad(object o, NewDecodedPadArgs args) + { + Pad sinkpad = audioconvert.GetPad("sink"); + + if(sinkpad.IsLinked) { + return; + } + + Caps caps = args.Pad.Caps; + Structure structure = caps.GetStructure(0); + + if(!structure.Name.StartsWith("audio")) { + return; + } + + args.Pad.Link(sinkpad); + } + + private bool OnBusMessage(Bus bus, Message message) + { + switch(message.Type) { + case MessageType.Error: + string error; + message.ParseError(out error); + GLib.Source.Remove(progress_timeout); + OnError(error); + break; + case MessageType.Eos: + pipeline.SetState(State.Null); + GLib.Source.Remove(progress_timeout); + OnFinished(); + break; + } + + return true; + } + + private bool OnProgressTimeout() + { + long duration, position; + + if(pipeline.QueryDuration(Gst.Format.Time, out duration) && + encoder.QueryPosition(Gst.Format.Time, out position)) { + OnProgress(position, duration); + } + + return true; + } + + private static GLib.MainLoop loop; + + public static void Main(string [] args) + { + if(args.Length < 2) { + Console.WriteLine("Usage: mono decodebin-transcoder.exe "); + return; + } + + Gst.Application.Init(); + loop = new GLib.MainLoop(); + + DecodeBinTranscoder transcoder = new DecodeBinTranscoder(); + + transcoder.Error += delegate(object o, ErrorArgs args) { + Console.WriteLine("Error: {0}", args.Error); + transcoder.Dispose(); + loop.Quit(); + }; + + transcoder.Finished += delegate { + Console.WriteLine("\nFinished"); + transcoder.Dispose(); + loop.Quit(); + }; + + transcoder.Progress += delegate(object o, ProgressArgs args) { + Console.Write("\rEncoding: {0} / {1} ({2:00.00}%) ", + new TimeSpan((args.Position / Clock.GstSecond) * TimeSpan.TicksPerSecond), + new TimeSpan((args.Duration / Clock.GstSecond) * TimeSpan.TicksPerSecond), + ((double)args.Position / (double)args.Duration) * 100.0); + }; + + transcoder.Transcode(args[0], args[1]); + + loop.Run(); + } +} diff --git a/sample/Makefile.am b/sample/Makefile.am index 21a9aa1add..38d06a0ae4 100644 --- a/sample/Makefile.am +++ b/sample/Makefile.am @@ -1,4 +1,4 @@ -TARGETS = playbin-player.exe +TARGETS = playbin-player.exe decodebin-transcoder.exe DEBUGS = $(addsuffix .mdb, $(TARGETS)) assemblies=$(top_builddir)/gstreamer-sharp/gstreamer-sharp.dll @@ -8,10 +8,14 @@ playbin-player.exe: $(srcdir)/PlayBinPlayer.cs $(assemblies) $(CSC) $(GLIBSHARP_LIBS) $(references) $(srcdir)/PlayBinPlayer.cs \ /out:playbin-player.exe +decodebin-transcoder.exe: $(srcdir)/DecodeBinTranscoder.cs $(assemblies) + $(CSC) -out:$@ $(GLIBSHARP_LIBS) $(references) $(srcdir)/DecodeBinTranscoder.cs + noinst_SCRIPTS = $(TARGETS) CLEANFILES = $(TARGETS) $(DEBUGS) MAINTAINERCLEANFILES = Makefile.in -EXTRA_DIST = \ - PlayBinPlayer.cs +EXTRA_DIST = \ + PlayBinPlayer.cs \ + DecodeBinTranscoder.cs