[banshee] gst#: Add initial Transcoder feature
- From: Bertrand Lorentz <blorentz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [banshee] gst#: Add initial Transcoder feature
- Date: Thu, 18 Aug 2011 19:49:26 +0000 (UTC)
commit 4a64ae6513a873df7023b038215e01d0bfb120f3
Author: Olivier Dufour <olivier duff gmail com>
Date: Thu May 26 22:29:43 2011 +0200
gst#: Add initial Transcoder feature
Signed-off-by: Bertrand Lorentz <bertrand lorentz gmail com>
.../Banshee.GStreamerSharp.csproj | 1 +
.../Banshee.GStreamerSharp/Transcoder.cs | 314 ++++++++++++++++++++
src/Backends/Banshee.GStreamerSharp/Makefile.am | 3 +-
3 files changed, 317 insertions(+), 1 deletions(-)
---
diff --git a/src/Backends/Banshee.GStreamerSharp/Banshee.GStreamerSharp.csproj b/src/Backends/Banshee.GStreamerSharp/Banshee.GStreamerSharp.csproj
index dc063bc..5eb1f97 100644
--- a/src/Backends/Banshee.GStreamerSharp/Banshee.GStreamerSharp.csproj
+++ b/src/Backends/Banshee.GStreamerSharp/Banshee.GStreamerSharp.csproj
@@ -74,6 +74,7 @@
<Compile Include="Banshee.GStreamerSharp\BpmDetector.cs" />
<Compile Include="Banshee.GStreamerSharp\CddaManager.cs" />
<Compile Include="Banshee.GStreamerSharp\AudioCdRipper.cs" />
+ <Compile Include="Banshee.GStreamerSharp\Transcoder.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
diff --git a/src/Backends/Banshee.GStreamerSharp/Banshee.GStreamerSharp/Transcoder.cs b/src/Backends/Banshee.GStreamerSharp/Banshee.GStreamerSharp/Transcoder.cs
new file mode 100644
index 0000000..5ad02eb
--- /dev/null
+++ b/src/Backends/Banshee.GStreamerSharp/Banshee.GStreamerSharp/Transcoder.cs
@@ -0,0 +1,314 @@
+//
+// Transcoder.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+// Olivier Dufour <olivier duff gmail com>
+//
+// Copyright (C) 2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Runtime.InteropServices;
+using Mono.Unix;
+
+using Hyena;
+using Banshee.Base;
+using Banshee.Collection;
+using Banshee.ServiceStack;
+using Banshee.MediaEngine;
+using Banshee.MediaProfiles;
+using Banshee.Configuration.Schema;
+
+using Gst;
+
+namespace Banshee.GStreamerSharp
+{
+ public class Transcoder : ITranscoder
+ {
+ private class AudioSinkBin : Bin
+ {
+ public AudioSinkBin (IntPtr o) : base (o)
+ {}
+
+ public AudioSinkBin (string elementName, string encoder_pipeline, string output_uri) : base (elementName)
+ {
+ Element encoder_elem = null;
+ Element sink_elem;
+ Element conv_elem;
+ Element resample_elem;
+ Pad encoder_pad;
+
+ sink_elem = ElementFactory.MakeFromUri (URIType.Sink, output_uri, "sink");
+ if (sink_elem == null) {
+ throw new Exception (Catalog.GetString ("Could not create sink element"));
+ }
+
+ conv_elem = ElementFactory.Make ("audioconvert", "audioconvert");
+ if (conv_elem == null) {
+ throw new Exception (Catalog.GetString ("Could not create 'audioconvert' plugin"));
+ }
+
+ resample_elem = ElementFactory.Make ("audioresample", "audioresample");
+ if (resample_elem == null) {
+ throw new Exception (Catalog.GetString ("Could not create 'audioresample' plugin"));
+ }
+
+ try {
+ encoder_elem = Parse.BinFromDescription (encoder_pipeline, true);
+ } catch (Exception e) {
+ string err = Catalog.GetString ("Could not create encoding pipeline : {0}");
+ throw new Exception (String.Format (err, e.Message));
+ }
+
+ encoder_pad = conv_elem.GetStaticPad ("sink");
+ if (encoder_pad == null) {
+ throw new Exception (Catalog.GetString ("Could not get sink pad from encoder"));
+ }
+
+ Add (conv_elem, resample_elem, encoder_elem, sink_elem);
+ Element.Link (conv_elem, resample_elem, encoder_elem, sink_elem);
+
+ AddPad (new GhostPad ("sink", encoder_pad));
+ }
+ }
+
+ public event TranscoderProgressHandler Progress;
+ public event TranscoderTrackFinishedHandler TrackFinished;
+ public event TranscoderErrorHandler Error;
+
+ private TrackInfo current_track;
+ private string error_message;
+ private SafeUri output_uri;
+
+ bool is_transcoding;
+ Gst.Pipeline pipeline;
+ AudioSinkBin sink_bin;
+ System.Timers.Timer timer;
+
+ public Transcoder ()
+ {
+ timer = new System.Timers.Timer ();
+ timer.Interval = 200;
+ timer.AutoReset = true;
+ timer.Elapsed += OnTick;
+ }
+
+ void OnTick (object o, System.Timers.ElapsedEventArgs args)
+ {
+ Format format = Format.Time;
+ long position, duration;
+
+ if (!pipeline.QueryDuration (ref format, out duration) ||
+ !sink_bin.QueryPosition (ref format, out position)) {
+ return;
+ }
+
+ RaiseProgress (current_track, (double)position / (double)duration);
+ }
+
+ public void Finish ()
+ {
+ timer.Stop ();
+
+ if(pipeline != null) {
+ pipeline.SetState (State.Null);
+ pipeline = null;
+ }
+
+ if(output_uri != null) {
+ output_uri = null;
+ }
+ }
+
+ public void Cancel ()
+ {
+ timer.Stop ();
+ is_transcoding = false;
+
+ if(pipeline != null) {
+ pipeline.SetState (State.Null);
+ pipeline = null;
+ }
+
+ output_uri = null;
+ }
+
+ public void TranscodeTrack (TrackInfo track, SafeUri outputUri, ProfileConfiguration config)
+ {
+ if(IsTranscoding) {
+ throw new ApplicationException("Transcoder is busy");
+ }
+
+ Log.DebugFormat ("Transcoding {0} to {1}", track.Uri, outputUri);
+ output_uri = outputUri;
+
+ error_message = null;
+
+ current_track = track;
+ Transcode (config.Profile.Pipeline.GetProcessById("gstreamer"));
+
+ }
+
+ private bool ConstructPipeline (string encoder_pipeline)
+ {
+ Element source_elem;
+ Element decoder_elem;
+
+ pipeline = new Gst.Pipeline ("pipeline");
+
+ source_elem = ElementFactory.MakeFromUri (URIType.Src, current_track.Uri.AbsoluteUri, "source");
+ if (source_elem == null) {
+ RaiseError (current_track, Catalog.GetString ("Could not create source element"));
+ return false;
+ }
+
+ decoder_elem = ElementFactory.Make ("decodebin2", "decodebin2");
+ if (decoder_elem == null) {
+ RaiseError (current_track, Catalog.GetString ("Could not create 'decodebin2' plugin"));
+ return false;
+ }
+
+ try {
+ sink_bin = new AudioSinkBin ("sinkbin", encoder_pipeline, output_uri.AbsoluteUri);
+ } catch (Exception e) {
+ RaiseError (current_track, e.Message);
+ }
+
+ if (sink_bin == null) {
+ RaiseError (current_track, Catalog.GetString ("Could not create 'sinkbin' plugin"));
+ return false;
+ }
+
+ pipeline.Add (source_elem, decoder_elem, sink_bin);
+
+ source_elem.Link (decoder_elem);
+
+ decoder_elem.PadAdded += OnPadAdded;
+
+ pipeline.Bus.AddWatch (OnBusMessage);
+
+ return true;
+ }
+
+ private void OnPadAdded (object sender, PadAddedArgs args)
+ {
+ Caps caps;
+ Structure str;
+ Pad audiopad;
+
+ audiopad = sink_bin.GetStaticPad ("sink");
+
+ if (audiopad.IsLinked) {
+ return;
+ }
+
+ caps = args.Pad.Caps;
+ str = caps [0];
+
+ if(!str.Name.Contains ("audio")) {
+ return;
+ }
+
+ args.Pad.Link (audiopad);
+ }
+
+ private bool OnBusMessage (Bus bus, Message msg)
+ {
+ switch (msg.Type) {
+ case MessageType.Eos:
+ pipeline.SetState (State.Null);
+ pipeline = null;
+ is_transcoding = false;
+ timer.Stop ();
+ RaiseTrackFinished (current_track, output_uri);
+ break;
+
+ case MessageType.Error:
+ Enum error_type;
+ string err_msg, debug;
+ is_transcoding = false;
+ timer.Stop ();
+ msg.ParseError (out error_type, out err_msg, out debug);
+ RaiseError (current_track, String.Format ("{0} : {1}", err_msg, debug));
+ timer.Stop ();
+ break;
+
+ default:
+ break;
+ }
+
+ return true;
+ }
+
+ private void Transcode (string encoder_pipeline)
+ {
+ if (IsTranscoding) {
+ return;
+ }
+ if(!ConstructPipeline (encoder_pipeline)) {
+ RaiseError (current_track, Catalog.GetString ("Could not construct pipeline"));
+ return;
+ }
+
+ is_transcoding = true;
+ pipeline.SetState (State.Playing);
+ timer.Start ();
+ }
+
+ protected virtual void RaiseProgress (TrackInfo track, double fraction)
+ {
+ TranscoderProgressHandler handler = Progress;
+ if (handler != null) {
+ handler (this, new TranscoderProgressArgs (track, fraction, track.Duration));
+ }
+ }
+
+ protected virtual void RaiseTrackFinished (TrackInfo track, SafeUri outputUri)
+ {
+ TranscoderTrackFinishedHandler handler = TrackFinished;
+ if (handler != null) {
+ handler (this, new TranscoderTrackFinishedArgs (track, outputUri));
+ }
+ }
+
+ protected virtual void RaiseError (TrackInfo track, string message)
+ {
+ try {
+ Banshee.IO.File.Delete (output_uri);
+ } catch {}
+
+ TranscoderErrorHandler handler = Error;
+ if (handler != null) {
+ handler (this, new TranscoderErrorArgs (track, message));
+ }
+ }
+
+ public bool IsTranscoding {
+ get { return is_transcoding; }
+ }
+
+ public string ErrorMessage {
+ get { return error_message; }
+ }
+ }
+}
diff --git a/src/Backends/Banshee.GStreamerSharp/Makefile.am b/src/Backends/Banshee.GStreamerSharp/Makefile.am
index 9405300..9c25355 100644
--- a/src/Backends/Banshee.GStreamerSharp/Makefile.am
+++ b/src/Backends/Banshee.GStreamerSharp/Makefile.am
@@ -7,7 +7,8 @@ SOURCES = \
Banshee.GStreamerSharp/AudioCdRipper.cs \
Banshee.GStreamerSharp/BpmDetector.cs \
Banshee.GStreamerSharp/CddaManager.cs \
- Banshee.GStreamerSharp/PlayerEngine.cs
+ Banshee.GStreamerSharp/PlayerEngine.cs \
+ Banshee.GStreamerSharp/Transcoder.cs
RESOURCES = Banshee.GStreamerSharp.addin.xml
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]