]> git.parisson.com Git - timeside.git/commitdiff
fix encoding speed and buffer size, enable mp3 and ogg encoder streaming mode, cleanup
authoryomguy <yomguy@parisson.com>
Thu, 3 Mar 2011 17:36:48 +0000 (17:36 +0000)
committeryomguy <yomguy@parisson.com>
Thu, 3 Mar 2011 17:36:48 +0000 (17:36 +0000)
timeside/analyzer/max_level.py
timeside/analyzer/mean_level.py
timeside/decoder/core.py
timeside/encoder/__init__.py
timeside/encoder/mp3.py
timeside/encoder/mp3_stream.py [deleted file]
timeside/encoder/ogg.py
timeside/encoder/ogg_stream.py [deleted file]
timeside/encoder/wav.py
timeside/tests/api/test_mp3.py
timeside/tests/api/test_vorbis.py

index e60a047b513dcb6f530c3389c0126049f17df490..cc1b848c79f976b379c752389b4b0f8b0f505b41 100644 (file)
@@ -50,7 +50,7 @@ class MaxLevel(Processor):
         return "dB"
 
     def process(self, frames, eod=False):
-        max = numpy.round(20*numpy.log(frames.max()), 3)
+        max = numpy.round(20*numpy.log(frames.max()), 2)
         if max > self.value:
             self.value = max
         return frames, eod
index 9d114f01c4d53d2aa9215e0030e335e8dbe84c00..6d47b86af88577b25e43527600be3fda52e3df79 100644 (file)
@@ -52,7 +52,7 @@ class MeanLevel(Processor):
         return "%s %s" % (str(self.value), unit())
 
     def process(self, frames, eod=False):
-        value = numpy.round(20*numpy.log10(numpy.mean(numpy.sqrt(numpy.square(frames)))), 3)
+        value = numpy.round(20*numpy.log10(numpy.mean(numpy.sqrt(numpy.square(frames)))), 2)
         if value > self.value:
             self.value = value
         return frames, eod
index 15255d2804758d885a70df1025ad620752b1e220..b5cb9c937e7ec9bc30fe8cf91f784f7080a1abfd 100644 (file)
@@ -55,16 +55,16 @@ class FileDecoder(Processor):
     def setup(self, channels = None, samplerate = None, nframes = None):
         # the output data format we want
         caps = "audio/x-raw-float, width=32"
-        pipeline = gst.parse_launch('''uridecodebin uri="%s"
+        self.pipeline = gst.parse_launch('''uridecodebin uri="%s"
             ! audioconvert
             ! %s
             ! appsink name=sink sync=False ''' % (self.uri, caps))
         # store a pointer to appsink in our decoder object
-        self.sink = pipeline.get_by_name('sink')
+        self.sink = self.pipeline.get_by_name('sink')
         # adjust length of emitted buffers
         # self.sink.set_property('blocksize', 0x10000)
         # start pipeline
-        pipeline.set_state(gst.STATE_PLAYING)
+        self.pipeline.set_state(gst.STATE_PLAYING)
 
     @interfacedoc
     def channels(self):
@@ -181,7 +181,7 @@ class SubProcessPipe:
         self.buffer_size = 0xFFFF
 
         if not stdin:
-            stdin =  subprocess.PIPE
+            stdin = subprocess.PIPE
 
         self.proc = subprocess.Popen(command.encode('utf-8'),
                     shell = True,
index e53e08800022539258e8ee9bb7eb38fb761aca3c..4698489fd39cacc30e413614d35b57fbf0699a91 100644 (file)
@@ -5,7 +5,5 @@ from ogg import *
 from wav import *
 from mp3 import *
 from m4a import *
-from mp3_stream import *
-from ogg_stream import *
 
 #from timeside.encoder.flac import *
index 9272c1c994a21129eb76e19ec3232b845ebb5937..9bd27f28a63acdf8b6225012d45745727b118f13 100644 (file)
@@ -36,24 +36,43 @@ class Mp3Encoder(Processor):
     """ gstreamer-based mp3 encoder """
     implements(IEncoder)
 
-    def __init__(self, output):
-        self.file = None
+    def __init__(self, output,  streaming=False):
         if isinstance(output, basestring):
             self.filename = output
         else:
-            raise Exception("Streaming not supported")
+            self.filename = None
+        self.streaming = streaming
+        
+        if not self.filename and self.streaming:
+            raise Exception('Must give an output')
 
     @interfacedoc
     def setup(self, channels=None, samplerate=None, nframes=None):
         super(Mp3Encoder, self).setup(channels, samplerate, nframes)
         #TODO: open file for writing
-        # the output data format we want
-        pipeline = gst.parse_launch(''' appsrc name=src
-            ! audioconvert
-            ! lame name=enc vbr=0 bitrate=256 ! id3v2mux
-            ! filesink location=%s ''' % self.filename)
+        # the output data format we want        
+        pipe = ''' appsrc name=src max-bytes=32768 block=true
+                  ! audioconvert 
+                  ! lame name=enc vbr=0 bitrate=256 ! id3v2mux 
+                  '''
+        if self.filename and self.streaming:
+            pipe += '''
+            ! queue2 name=q0 ! tee name=tee
+            tee. ! queue name=q1 ! appsink name=app 
+            tee. ! queue name=q2 ! filesink location=%s
+            ''' % self.filename
+            
+        elif self.filename :
+            pipe += '! filesink location=%s' % self.filename
+        else:
+            pipe += '! appsink name=app'
+            
+        self.pipeline = gst.parse_launch(pipe)
+        # store a pointer to appsrc in our encoder object
+        self.src = self.pipeline.get_by_name('src')
         # store a pointer to appsink in our encoder object
-        self.src = pipeline.get_by_name('src')
+        self.app = self.pipeline.get_by_name('app')
+        
         srccaps = gst.Caps("""audio/x-raw-float,
             endianness=(int)1234,
             channels=(int)%s,
@@ -62,8 +81,7 @@ class Mp3Encoder(Processor):
         self.src.set_property("caps", srccaps)
 
         # start pipeline
-        pipeline.set_state(gst.STATE_PLAYING)
-        self.pipeline = pipeline
+        self.pipeline.set_state(gst.STATE_PLAYING)
 
     @staticmethod
     @interfacedoc
@@ -99,6 +117,8 @@ class Mp3Encoder(Processor):
     def process(self, frames, eod=False):
         buf = self.numpy_array_to_gst_buffer(frames)
         self.src.emit('push-buffer', buf)
+        if self.streaming:
+            frames = self.app.emit('pull-buffer')
         if eod: self.src.emit('end-of-stream')
         return frames, eod
         
diff --git a/timeside/encoder/mp3_stream.py b/timeside/encoder/mp3_stream.py
deleted file mode 100644 (file)
index 8b3de51..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-    # -*- coding: utf-8 -*-
-#
-# Copyright (C) 2007 Parisson SARL
-# Copyright (c) 2006-2007 Guillaume Pellerin <pellerin@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 2 of the License, or
-# (at your option) any later version.
-
-# TimeSide is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-# Authors: Guillaume Pellerin <yomguy@parisson.com>
-#          Paul Brossier <piem@piem.org>
-
-from timeside.core import Processor, implements, interfacedoc
-from timeside.api import IEncoder
-from numpy import array, frombuffer, getbuffer, float32
-
-import pygst
-pygst.require('0.10')
-import gst
-import gobject
-gobject.threads_init()
-
-
-class Mp3EncoderStream(Processor):
-    """ gstreamer-based streaming mp3 encoder with an appsink tee"""
-    implements(IEncoder)
-
-    def __init__(self, output=None):
-        self.filename = output
-        
-    @interfacedoc
-    def setup(self, channels=None, samplerate=None, nframes=None):
-        super(Mp3EncoderStream, self).setup(channels, samplerate, nframes)
-        #TODO: open file for writing
-        # the output data format we want        
-        pipe = '''appsrc name=src ! audioconvert 
-                  ! lame name=enc vbr=0 bitrate=256 ! id3v2mux 
-                  '''
-        if self.filename:
-            pipe += '''
-            ! queue2 name=q0 ! tee name=tee
-            tee. ! queue name=q1 ! appsink name=app
-            tee. ! queue name=q2 ! filesink location=%s
-            ''' % self.filename
-        else:
-            pipe += '! appsink name=app'
-            
-        pipeline = gst.parse_launch(pipe)
-        # store a pointer to appsrc in our encoder object
-        self.src = pipeline.get_by_name('src')
-        # store a pointer to appsink in our encoder object
-        self.app = pipeline.get_by_name('app')
-        
-        srccaps = gst.Caps("""audio/x-raw-float,
-            endianness=(int)1234,
-            channels=(int)%s,
-            width=(int)32,
-            rate=(int)%d""" % (int(channels), int(samplerate)))
-        self.src.set_property("caps", srccaps)
-
-        # start pipeline
-        pipeline.set_state(gst.STATE_PLAYING)
-        self.pipeline = pipeline
-
-    @staticmethod
-    @interfacedoc
-    def id():
-        return "gst_mp3_enc_stream"
-
-    @staticmethod
-    @interfacedoc
-    def description():
-        return "MP3 GStreamer based encoder and streamer"
-
-    @staticmethod
-    @interfacedoc
-    def format():
-        return "MP3"
-
-    @staticmethod
-    @interfacedoc
-    def file_extension():
-        return "mp3"
-
-    @staticmethod
-    @interfacedoc
-    def mime_type():
-        return "audio/mpeg"
-
-    @interfacedoc
-    def set_metadata(self, metadata):
-        #TODO: 
-        pass
-
-    @interfacedoc
-    def process(self, frames, eod=False):
-        buf = self.numpy_array_to_gst_buffer(frames)
-        self.src.emit('push-buffer', buf)
-        appbuffer = self.app.emit('pull-buffer')
-        if eod: self.src.emit('end-of-stream')
-        return appbuffer, eod
-        
-    def numpy_array_to_gst_buffer(self, frames):
-        """ gstreamer buffer to numpy array conversion """
-        buf = gst.Buffer(getbuffer(frames))
-        return buf
index 39de8dd2acccf2e966936c7c4099ee46aac08c37..25d224d330dacc62a81c7b7b615cc371046d1745 100644 (file)
@@ -34,25 +34,44 @@ class VorbisEncoder(Processor):
     """ gstreamer-based vorbis encoder """
     implements(IEncoder)
 
-    def __init__(self, output):
-        self.file = None
+    def __init__(self, output,  streaming=False):
         if isinstance(output, basestring):
             self.filename = output
         else:
-            raise Exception("Streaming not supported")
+            self.filename = None
+        self.streaming = streaming
+        
+        if not self.filename and self.streaming:
+            raise Exception('Must give an output')
 
     @interfacedoc
     def setup(self, channels=None, samplerate=None, nframes=None):
         super(VorbisEncoder, self).setup(channels, samplerate, nframes)
         # TODO open file for writing
-        # the output data format we want
-        pipeline = gst.parse_launch(''' appsrc name=src
-            ! audioconvert
-            ! vorbisenc
-            ! oggmux
-            ! filesink location=%s ''' % self.filename)
+        # the output data format we want        
+        pipe = ''' appsrc name=src max-bytes=32768 block=true
+                  ! audioconvert 
+                  ! vorbisenc
+                  ! oggmux
+                  '''
+        if self.filename and self.streaming:
+            pipe += '''
+            ! queue2 name=q0 ! tee name=tee
+            tee. ! queue name=q1 ! appsink name=app 
+            tee. ! queue name=q2 ! filesink location=%s
+            ''' % self.filename
+            
+        elif self.filename :
+            pipe += '! filesink location=%s' % self.filename
+        else:
+            pipe += '! appsink name=app'
+            
+        self.pipeline = gst.parse_launch(pipe)
+        # store a pointer to appsrc in our encoder object
+        self.src = self.pipeline.get_by_name('src')
         # store a pointer to appsink in our encoder object
-        self.src = pipeline.get_by_name('src')
+        self.app = self.pipeline.get_by_name('app')
+        
         srccaps = gst.Caps("""audio/x-raw-float,
             endianness=(int)1234,
             channels=(int)%s,
@@ -61,8 +80,7 @@ class VorbisEncoder(Processor):
         self.src.set_property("caps", srccaps)
 
         # start pipeline
-        pipeline.set_state(gst.STATE_PLAYING)
-        self.pipeline = pipeline
+        self.pipeline.set_state(gst.STATE_PLAYING)
 
     @staticmethod
     @interfacedoc
@@ -91,21 +109,19 @@ class VorbisEncoder(Processor):
 
     @interfacedoc
     def set_metadata(self, metadata):
-        #TODO
+        #TODO:
         pass
 
     @interfacedoc
     def process(self, frames, eod=False):
         buf = self.numpy_array_to_gst_buffer(frames)
         self.src.emit('push-buffer', buf)
+        if self.streaming:
+            frames = self.app.emit('pull-buffer')
         if eod: self.src.emit('end-of-stream')
         return frames, eod
-        
 
     def numpy_array_to_gst_buffer(self, frames):
         """ gstreamer buffer to numpy array conversion """
         buf = gst.Buffer(getbuffer(frames))
         return buf
-
-
-
diff --git a/timeside/encoder/ogg_stream.py b/timeside/encoder/ogg_stream.py
deleted file mode 100644 (file)
index 7978f46..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2010 Paul Brossier <piem@piem.org>
-# Copyright (c) 2010 Guillaume Pellerin <yomguy@parisson.com>
-
-# This file is part of TimeSide.
-
-# TimeSide is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 2 of the License, or
-# (at your option) any later version.
-
-# TimeSide is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with TimeSide.  If not, see <http://www.gnu.org/licenses/>.
-
-
-from timeside.core import Processor, implements, interfacedoc
-from timeside.api import IEncoder
-from numpy import array, frombuffer, getbuffer, float32
-
-import pygst
-pygst.require('0.10')
-import gst
-import gobject
-gobject.threads_init()
-
-
-class VorbisEncoderStream(Processor):
-    """ gstreamer-based vorbis encoder """
-    implements(IEncoder)
-
-    def __init__(self, output=None):
-        self.filename = output
-        
-    @interfacedoc
-    def setup(self, channels=None, samplerate=None, nframes=None):
-        super(VorbisEncoderStream, self).setup(channels, samplerate, nframes)
-        # TODO open file for writing
-        # the output data format we want
-        pipe = '''appsrc name=src ! audioconvert
-                ! vorbisenc ! oggmux
-                '''
-        if self.filename:
-            pipe += '''
-            ! queue2 name=q0 ! tee name=tee
-            tee. ! queue name=q1 ! appsink name=app
-            tee. ! queue name=q2 ! filesink location=%s
-            ''' % self.filename
-        else:
-            pipe += '! appsink name=app'
-            
-        pipeline = gst.parse_launch(pipe)
-        # store a pointer to appsrc in our encoder object
-        self.src = pipeline.get_by_name('src')
-        # store a pointer to appsink in our encoder object
-        self.app = pipeline.get_by_name('app')
-        
-        srccaps = gst.Caps("""audio/x-raw-float,
-            endianness=(int)1234,
-            channels=(int)%s,
-            width=(int)32,
-            rate=(int)%d""" % (int(channels), int(samplerate)))
-        self.src.set_property("caps", srccaps)
-
-        # start pipeline
-        pipeline.set_state(gst.STATE_PLAYING)
-        self.pipeline = pipeline
-
-    @staticmethod
-    @interfacedoc
-    def id():
-        return "gst_vorbis_enc_stream"
-
-    @staticmethod
-    @interfacedoc
-    def description():
-        return "Vorbis GStreamer based encoder and streamer"
-
-    @staticmethod
-    @interfacedoc
-    def format():
-        return "OGG"
-
-    @staticmethod
-    @interfacedoc
-    def file_extension():
-        return "ogg"
-
-    @staticmethod
-    @interfacedoc
-    def mime_type():
-        return "application/ogg"
-
-    @interfacedoc
-    def set_metadata(self, metadata):
-        #TODO:
-        pass
-
-    @interfacedoc
-    def process(self, frames, eod=False):
-        buf = self.numpy_array_to_gst_buffer(frames)
-        self.src.emit('push-buffer', buf)
-        appbuffer = self.app.emit('pull-buffer')
-        if eod: self.src.emit('end-of-stream')
-        return appbuffer, eod
-
-    def numpy_array_to_gst_buffer(self, frames):
-        """ gstreamer buffer to numpy array conversion """
-        buf = gst.Buffer(getbuffer(frames))
-        return buf
index 234763a409dd46fac49c07c7faa89cb81983009d..b49e5b09eb3e3bc0a7d169f737e486024c76587d 100644 (file)
@@ -47,12 +47,12 @@ class WavEncoder(Processor):
         super(WavEncoder, self).setup(channels, samplerate, nframes)
         # TODO open file for writing
         # the output data format we want
-        pipeline = gst.parse_launch(''' appsrc name=src
+        self.pipeline = gst.parse_launch(''' appsrc name=src
             ! audioconvert
             ! wavenc
             ! filesink location=%s ''' % self.filename)
         # store a pointer to appsink in our encoder object
-        self.src = pipeline.get_by_name('src')
+        self.src = self.pipeline.get_by_name('src')
         srccaps = gst.Caps("""audio/x-raw-float,
             endianness=(int)1234,
             channels=(int)%s,
@@ -61,8 +61,7 @@ class WavEncoder(Processor):
         self.src.set_property("caps", srccaps)
 
         # start pipeline
-        pipeline.set_state(gst.STATE_PLAYING)
-        self.pipeline = pipeline
+        self.pipeline.set_state(gst.STATE_PLAYING)
 
     @staticmethod
     @interfacedoc
index eaf093bd4aa62f3c8e158a8fea539aef0e65b3b2..c3330678b2c5cd08a5dc502fa800f677c498c7ab 100644 (file)
@@ -2,9 +2,10 @@
 
 from timeside.decoder import *
 from timeside.encoder import *
+import os.path
 
-source = "../samples/sweep.wav"
-dest = "../results/sweep_wav.mp3"
+source = os.path.join(os.path.dirname(__file__), "../samples/sweep.wav")
+dest = os.path.join(os.path.dirname(__file__), "../results/sweep_wav.mp3")
 
 decoder  = FileDecoder(source)
 encoder  = Mp3Encoder(dest)
index ba0655a91fed30ab6eb23af8df600e1687c54167..53818cd7ea252af3ede3950debd948cf36d99894 100644 (file)
@@ -2,9 +2,10 @@
 
 from timeside.decoder import *
 from timeside.encoder import *
+import os.path
 
-source = "../samples/sweep.wav"
-dest = "../results/sweep_wav.ogg"
+source = os.path.join(os.path.dirname(__file__), "../samples/sweep.wav")
+dest = os.path.join(os.path.dirname(__file__), "../results/sweep_wav.ogg")
 
 decoder  = FileDecoder(source)
 encoder  = VorbisEncoder(dest)