From: yomguy Date: Wed, 9 Feb 2011 12:27:56 +0000 (+0000) Subject: make mp3_stream file writing conditional to the output arg, cleanup X-Git-Tag: 0.3.2~79 X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=2f110775ada5dad3872e3c2b415d54ae61965c22;p=timeside.git make mp3_stream file writing conditional to the output arg, cleanup --- diff --git a/timeside/analyzer/__init__.py b/timeside/analyzer/__init__.py index 19db5e3..1cc1d5c 100644 --- a/timeside/analyzer/__init__.py +++ b/timeside/analyzer/__init__.py @@ -1,4 +1,4 @@ - # -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- from core import * diff --git a/timeside/encoder/__init__.py b/timeside/encoder/__init__.py index 1332cec..28d1c4d 100644 --- a/timeside/encoder/__init__.py +++ b/timeside/encoder/__init__.py @@ -4,5 +4,7 @@ from core import * from ogg import * from wav import * from mp3 import * +from mp3_stream import * from m4a import * + #from timeside.encoder.flac import * diff --git a/timeside/encoder/mp3.py b/timeside/encoder/mp3.py index 1625161..9272c1c 100644 --- a/timeside/encoder/mp3.py +++ b/timeside/encoder/mp3.py @@ -29,7 +29,7 @@ import pygst pygst.require('0.10') import gst import gobject -gobject.threads_init () +gobject.threads_init() class Mp3Encoder(Processor): @@ -101,7 +101,7 @@ class Mp3Encoder(Processor): self.src.emit('push-buffer', buf) 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)) diff --git a/timeside/encoder/mp3_stream.py b/timeside/encoder/mp3_stream.py new file mode 100644 index 0000000..e343520 --- /dev/null +++ b/timeside/encoder/mp3_stream.py @@ -0,0 +1,120 @@ + # -*- coding: utf-8 -*- +# +# Copyright (C) 2007 Parisson SARL +# Copyright (c) 2006-2007 Guillaume Pellerin + +# 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 . + +# Authors: Guillaume Pellerin +# Paul Brossier + +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.file = 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 + diff --git a/timeside/encoder/ogg.py b/timeside/encoder/ogg.py index c7ad5e3..39de8dd 100644 --- a/timeside/encoder/ogg.py +++ b/timeside/encoder/ogg.py @@ -27,7 +27,7 @@ import pygst pygst.require('0.10') import gst import gobject -gobject.threads_init () +gobject.threads_init() class VorbisEncoder(Processor): @@ -100,6 +100,7 @@ class VorbisEncoder(Processor): self.src.emit('push-buffer', buf) 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 """ diff --git a/timeside/encoder/wav.py b/timeside/encoder/wav.py index 026d6b9..234763a 100644 --- a/timeside/encoder/wav.py +++ b/timeside/encoder/wav.py @@ -28,7 +28,7 @@ import pygst pygst.require('0.10') import gst import gobject -gobject.threads_init () +gobject.threads_init() class WavEncoder(Processor): diff --git a/timeside/grapher/core.py b/timeside/grapher/core.py index 0f94be9..e79ecb7 100644 --- a/timeside/grapher/core.py +++ b/timeside/grapher/core.py @@ -255,10 +255,7 @@ class WaveformImage(object): self.image.save(filename) def release(self): - self.pixel = 0 - self.image = 0 - self.draw = 0 - self.spectrum = 0 + pass class WaveformImageJoyContour(WaveformImage): @@ -370,6 +367,8 @@ class WaveformImageJoyContour(WaveformImage): #self.image = self.image.transpose(Image.FLIP_TOP_BOTTOM) self.image.save(filename) + def release(self): + pass class WaveformImageSimple(object): """ Builds a PIL image representing a waveform of the audio stream. @@ -467,11 +466,7 @@ class WaveformImageSimple(object): self.image.save(filename) def release(self): - self.pixels_adapter.process = 0 - self.pixel = 0 - self.image = 0 - self.draw = 0 - self.spectrum = 0 + pass class SpectrogramImage(object): """ Builds a PIL image representing a spectrogram of the audio stream (level vs. frequency vs. time). @@ -547,7 +542,9 @@ class SpectrogramImage(object): self.image.putdata(self.pixels) self.image.transpose(Image.ROTATE_90).save(filename) - + def release(self): + pass + class Noise(object): """A class that mimics audiolab.sndfile but generates noise instead of reading a wave file. Additionally it can be told to have a "broken" header and thus crashing diff --git a/timeside/grapher/spectrogram.py b/timeside/grapher/spectrogram.py index 5d53331..0d98a0d 100644 --- a/timeside/grapher/spectrogram.py +++ b/timeside/grapher/spectrogram.py @@ -55,8 +55,6 @@ class Spectrogram(Processor): @interfacedoc def setup(self, channels=None, samplerate=None, nframes=None): super(Spectrogram, self).setup(channels, samplerate, nframes) - if self.graph: - self.graph = None self.graph = SpectrogramImage(self.width, self.height, self.nframes(), self.samplerate(), self.FFT_SIZE, bg_color=self.bg_color, color_scheme=self.color_scheme) diff --git a/timeside/grapher/waveform.py b/timeside/grapher/waveform.py index 486802f..3077d09 100644 --- a/timeside/grapher/waveform.py +++ b/timeside/grapher/waveform.py @@ -55,8 +55,6 @@ class Waveform(Processor): @interfacedoc def setup(self, channels=None, samplerate=None, nframes=None): super(Waveform, self).setup(channels, samplerate, nframes) - if self.graph: - self.graph = None self.graph = WaveformImage(self.width, self.height, self.nframes(), self.samplerate(), self.FFT_SIZE, bg_color=self.bg_color, color_scheme=self.color_scheme) @@ -70,3 +68,4 @@ class Waveform(Processor): if output: self.graph.save(output) return self.graph.image + diff --git a/timeside/grapher/waveform_awdio.py b/timeside/grapher/waveform_awdio.py index 5f2746b..49c848f 100644 --- a/timeside/grapher/waveform_awdio.py +++ b/timeside/grapher/waveform_awdio.py @@ -61,12 +61,10 @@ class WaveformAwdio(Processor): def process(self, frames, eod=False): self.graph.process(frames, eod) return frames, eod -# -# def release(self): -# self.graph.release() @interfacedoc def render(self, output): if output: self.graph.save(output) -# return self.graph.image + return self.graph.image + diff --git a/timeside/grapher/waveform_joydiv.py b/timeside/grapher/waveform_joydiv.py index 83b2535..526541c 100644 --- a/timeside/grapher/waveform_joydiv.py +++ b/timeside/grapher/waveform_joydiv.py @@ -57,8 +57,8 @@ class WaveformJoyDiv(Processor): @interfacedoc def setup(self, channels=None, samplerate=None, nframes=None): super(WaveformJoyDiv, self).setup(channels, samplerate, nframes) - if self.graph: - self.graph = None +# if self.graph: +# self.graph = None self.graph = WaveformImageJoyContour(self.width, self.height, self.nframes(), self.samplerate(), self.FFT_SIZE, bg_color=self.bg_color, color_scheme=self.color_scheme, ndiv=self.ndiv, symetry=self.symetry) @@ -72,3 +72,6 @@ class WaveformJoyDiv(Processor): if output: self.graph.save(output) return self.graph.image + + def release(self): + self.graph.release()