From b32f1b68543797e00d0c109554c3027d72bdcf0e Mon Sep 17 00:00:00 2001 From: yomguy Date: Fri, 18 Mar 2011 13:03:47 +0000 Subject: [PATCH] try to get encoders working but some are blocking : the output buffer size of the decoder seems too low sometimes (stereo WAV for example but not mono !). DON'T use encoders for now :( --- timeside/decoder/core.py | 3 +- timeside/encoder/flac.py | 2 +- timeside/encoder/mp3.py | 95 ++++++++++++------- timeside/encoder/ogg.py | 2 +- timeside/tests/api/test_lolevel_streaming.py | 16 ++-- .../tests/api/test_lolevel_streaming_bad.py | 42 ++++++++ 6 files changed, 114 insertions(+), 46 deletions(-) create mode 100644 timeside/tests/api/test_lolevel_streaming_bad.py diff --git a/timeside/decoder/core.py b/timeside/decoder/core.py index b5cb9c9..66540b0 100644 --- a/timeside/decoder/core.py +++ b/timeside/decoder/core.py @@ -61,8 +61,9 @@ class FileDecoder(Processor): ! appsink name=sink sync=False ''' % (self.uri, caps)) # store a pointer to appsink in our decoder object self.sink = self.pipeline.get_by_name('sink') + self.sink.set_property('emit-signals', True) # adjust length of emitted buffers - # self.sink.set_property('blocksize', 0x10000) + self.sink.set_property('blocksize', 0x8000) # start pipeline self.pipeline.set_state(gst.STATE_PLAYING) diff --git a/timeside/encoder/flac.py b/timeside/encoder/flac.py index dce1caa..0f177a1 100644 --- a/timeside/encoder/flac.py +++ b/timeside/encoder/flac.py @@ -60,7 +60,7 @@ class FlacEncoder(Processor): elif self.filename : self.pipe += '! filesink location=%s ' % self.filename else: - self.pipe += '! appsink name=sink blocksize=16384 sync=False ' + self.pipe += '! appsink name=sink sync=False ' self.pipeline = gst.parse_launch(self.pipe) # store a pointer to appsrc in our encoder object diff --git a/timeside/encoder/mp3.py b/timeside/encoder/mp3.py index bbe97a6..9191749 100644 --- a/timeside/encoder/mp3.py +++ b/timeside/encoder/mp3.py @@ -31,6 +31,7 @@ import pygst pygst.require('0.10') import gst import gobject +import Queue gobject.threads_init() @@ -48,8 +49,10 @@ class Mp3Encoder(Processor): if not self.filename and not self.streaming: raise Exception('Must give an output') - self.max_bytes = 65536 - self.size_adapter = self.max_bytes + self.eod = False + self.buffer_size = 8192 + self.max_bytes = 4096 + self.adapter_size = self.max_bytes @interfacedoc def setup(self, channels=None, samplerate=None, nframes=None): @@ -57,12 +60,12 @@ class Mp3Encoder(Processor): super(Mp3Encoder, self).setup(channels, samplerate, nframes) #TODO: open file for writing # the output data format we want - self.pipe = '''appsrc name=src max-bytes=%s + self.pipe = '''appsrc name=src ! audioconvert ! lamemp3enc bitrate=256 ! id3v2mux - ''' % self.max_bytes + ''' if self.filename and self.streaming: - self.pipe += ''' ! queue ! tee name=t + self.pipe += ''' ! tee name=t ! queue ! filesink location=%s t. ! queue ! appsink name=app sync=False ''' % self.filename @@ -87,9 +90,16 @@ class Mp3Encoder(Processor): # start pipeline if self.streaming: + self.queue = Queue.Queue(self.buffer_size) self.app.set_property('emit-signals', True) + self.app.connect("new-buffer", self.buffer) + self.pipeline.set_state(gst.STATE_PLAYING) - self.adapter = FixedSizeInputAdapter(self.size_adapter, channels, pad=True) + self.adapter = FixedSizeInputAdapter(self.adapter_size, channels, pad=True) + + def buffer(self, appsink): + data = appsink.props.last_buffer.data + self.queue.put_nowait(data) @staticmethod @interfacedoc @@ -123,22 +133,21 @@ class Mp3Encoder(Processor): @interfacedoc def process(self, frames, eod=False): + self.eod = eod print frames.shape - emit = 0 - for samples, end in self.adapter.process(frames, eod): - print 'push: ', samples.shape - buf = self.numpy_array_to_gst_buffer(samples) - self.src.emit('push-buffer', buf) - if self.streaming: - pull = self.app.emit('pull-buffer') - emit = 1 + + buf = self.numpy_array_to_gst_buffer(frames) + self.src.emit('push-buffer', buf) + +# for samples, end in self.adapter.process(frames, eod): +# print 'push: ', samples.shape +# buf = self.numpy_array_to_gst_buffer(samples) +# self.src.emit('push-buffer', buf) + if self.streaming: - if emit: - return pull, eod - else: - return None, eod - else: - return frames, eod + self.chunk = self.queue.get(self.buffer_size) + + return frames, eod def numpy_array_to_gst_buffer(self, frames): """ gstreamer buffer to numpy array conversion """ @@ -146,8 +155,8 @@ class Mp3Encoder(Processor): return buf -class Mp3EncoderOld: - """Defines methods to encode to MP3""" +class Mp3EncoderSubprocess(object): + """MP3 encoder in a subprocess pipe""" # implements(IEncoder) @@ -172,26 +181,42 @@ class Mp3EncoderOld: 'publisher': 'tc', #comment 'date': 'ty', #year } - + + @interfacedoc + def setup(self, channels=None, samplerate=None, nframes=None): + self.channels = channels + super(Mp3EncoderSubprocess, self).setup(channels, samplerate, nframes) + @staticmethod + @interfacedoc def id(): - return "mp3enc" + return "subprocess_mp3_enc" - def format(self): - return 'MP3' + @staticmethod + @interfacedoc + def description(): + return "MP3 subprocess based encoder" - def file_extension(self): - return 'mp3' + @staticmethod + @interfacedoc + def format(): + return "MP3" - def mime_type(self): - return 'audio/mpeg' + @staticmethod + @interfacedoc + def file_extension(): + return "mp3" - def description(self): - return """ - MPEG-1 Audio Layer 3, more commonly referred to as MP3, is a patented - digital audio encoding format using a form of lossy data compression. - """ + @staticmethod + @interfacedoc + def mime_type(): + return "audio/mpeg" + @interfacedoc + def set_metadata(self, metadata): + #TODO: + pass + def get_file_info(self): try: file_out1, file_out2 = os.popen4('mp3info "'+self.dest+'"') diff --git a/timeside/encoder/ogg.py b/timeside/encoder/ogg.py index 981bbcb..3da76c6 100644 --- a/timeside/encoder/ogg.py +++ b/timeside/encoder/ogg.py @@ -118,7 +118,7 @@ class VorbisEncoder(Processor): self.src.emit('push-buffer', buf) if self.streaming: pull = self.app.emit('pull-buffer') - if eod: self.src.emit('end-of-stream') +# if eod: self.src.emit('end-of-stream') if not self.streaming: return frames, eod else: diff --git a/timeside/tests/api/test_lolevel_streaming.py b/timeside/tests/api/test_lolevel_streaming.py index 8bc444f..1bca250 100644 --- a/timeside/tests/api/test_lolevel_streaming.py +++ b/timeside/tests/api/test_lolevel_streaming.py @@ -11,7 +11,7 @@ if len(sys.argv) > 1: source = sys.argv[1] else: import os.path - source= os.path.join (os.path.dirname(__file__), "../samples/sweep.wav") + source= os.path.join (os.path.dirname(__file__), "../samples/sweep_source.wav") decoder = FileDecoder(source) print "Creating decoder with id=%s for: %s" % (decoder.id(), source) @@ -21,19 +21,19 @@ print 'channels :', channels samplerate = decoder.samplerate() nframes = decoder.nframes() -dest1 = "/tmp/test.mp3" -dest2 = "/tmp/test2.mp3" +dest1 = "/tmp/test_filesink.mp3" +dest2 = "/tmp/test_appsink.mp3" f = open(dest2,'w') streaming=True -encoder = Mp3Encoder(dest1, streaming=streaming) +encoder = Mp3Encoder(dest1, streaming=True) encoder.setup(channels=channels, samplerate=samplerate) while True: - buf, eod = encoder.process(*decoder.process()) - if streaming and buf: - f.write(buf) - if eod : + encoder.process(*decoder.process()) + if streaming: + f.write(encoder.chunk) + if encoder.eod : break f.close() diff --git a/timeside/tests/api/test_lolevel_streaming_bad.py b/timeside/tests/api/test_lolevel_streaming_bad.py new file mode 100644 index 0000000..e414ead --- /dev/null +++ b/timeside/tests/api/test_lolevel_streaming_bad.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- + +from timeside.core import * +from timeside.decoder import * +from timeside.analyzer import * +from timeside.encoder import * +from timeside.api import * + +import sys +if len(sys.argv) > 1: + source = sys.argv[1] +else: + import os.path + source= os.path.join (os.path.dirname(__file__), "../samples/sweep.wav") + +decoder = FileDecoder(source) +print "Creating decoder with id=%s for: %s" % (decoder.id(), source) +decoder.setup() +channels = decoder.channels() +print 'channels :', channels +samplerate = decoder.samplerate() +nframes = decoder.nframes() + +dest1 = "/tmp/test_filesink.mp3" +dest2 = "/tmp/test_appsink.mp3" +f = open(dest2,'w') + +streaming=True +encoder = Mp3Encoder(dest1, streaming=True) +encoder.setup(channels=channels, samplerate=samplerate) + +print encoder.pipe + +while True: + encoder.process(*decoder.process()) + if streaming: + f.write(encoder.chunk) + if encoder.eod : + break + +f.close() +print encoder.pipe -- 2.39.5