diff --git a/audioread/__init__.py b/audioread/__init__.py index eecce32..325438d 100644 --- a/audioread/__init__.py +++ b/audioread/__init__.py @@ -68,45 +68,45 @@ def _mad_available(): return True -def audio_open(path): +def audio_open(path=None, audio=None): """Open an audio file using a library that is available on this system. """ # Standard-library WAV and AIFF readers. - from . import rawread - try: - return rawread.RawAudioFile(path) - except DecodeError: - pass + #from . import rawread + #try: + # return rawread.RawAudioFile(path) + #except DecodeError: + # pass # Core Audio. - if _ca_available(): - from . import macca - try: - return macca.ExtAudioFile(path) - except DecodeError: - pass + #if _ca_available(): + # from . import macca + # try: + # return macca.ExtAudioFile(path) + # except DecodeError: + # pass # GStreamer. - if _gst_available(): - from . import gstdec - try: - return gstdec.GstAudioFile(path) - except DecodeError: - pass + #if _gst_available(): + # from . import gstdec + # try: + # return gstdec.GstAudioFile(path) + # except DecodeError: + # pass # MAD. - if _mad_available(): - from . import maddec - try: - return maddec.MadAudioFile(path) - except DecodeError: - pass + #if _mad_available(): + # from . import maddec + # try: + # return maddec.MadAudioFile(path) + # except DecodeError: + # pass # FFmpeg. from . import ffdec try: - return ffdec.FFmpegAudioFile(path) + return ffdec.FFmpegAudioFile(path,audio) except DecodeError: pass diff --git a/audioread/__init__.pyc b/audioread/__init__.pyc new file mode 100644 index 0000000..6a007a3 Binary files /dev/null and b/audioread/__init__.pyc differ diff --git a/audioread/ffdec.py b/audioread/ffdec.py index 622f31d..837ef9f 100644 --- a/audioread/ffdec.py +++ b/audioread/ffdec.py @@ -22,6 +22,7 @@ import threading import time import os +from cStringIO import StringIO try: import queue except ImportError: @@ -51,11 +52,13 @@ class NotInstalledError(FFmpegError): class ReadTimeoutError(FFmpegError): """Reading from the ffmpeg command-line tool timed out.""" +class NoInputError(FFmpegError): + """Reading from the ffmpeg command-line tool timed out.""" class QueueReaderThread(threading.Thread): """A thread that consumes data from a filehandle and sends the data over a Queue. - """ + """ def __init__(self, fh, blocksize=1024, discard=False): super(QueueReaderThread, self).__init__() self.fh = fh @@ -67,12 +70,25 @@ def __init__(self, fh, blocksize=1024, discard=False): def run(self): while True: data = self.fh.read(self.blocksize) + #print data if not self.discard: self.queue.put(data) if not data: # Stream closed (EOF). break +class WriterThread(threading.Thread): + """A thread that writes data to a filehandle + """ + def __init__(self, fh, audio=None): + super(WriterThread, self).__init__() + self.fh = fh + self.audio = audio + self.daemon = True + + def run(self): + self.fh.write(self.audio.read()) + self.fh.close() def popen_multiple(commands, command_args, *args, **kwargs): """Like `subprocess.Popen`, but can try multiple commands in case @@ -100,7 +116,10 @@ def popen_multiple(commands, command_args, *args, **kwargs): class FFmpegAudioFile(object): """An audio file decoded by the ffmpeg command-line utility.""" - def __init__(self, filename, block_size=4096): + def __init__(self, filename=None, audio=None, block_size=4096): + self.openFile = True if filename is not None else False + self.readAudio = True if audio is not None else False + # On Windows, we need to disable the subprocess's crash dialog # in case it dies. Passing SEM_NOGPFAULTERRORBOX to SetErrorMode # disables this behavior. @@ -116,16 +135,28 @@ def __init__(self, filename, block_size=4096): ctypes.windll.kernel32.SetErrorMode( previous_error_mode | SEM_NOGPFAULTERRORBOX ) - + try: - self.devnull = open(os.devnull) - self.proc = popen_multiple( - COMMANDS, - ['-i', filename, '-f', 's16le', '-'], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - stdin=self.devnull, - ) + if self.openFile: + self.devnull = open(os.devnull) + self.proc = popen_multiple( + COMMANDS, + ['-i', filename, '-f', 's16le', '-'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=self.devnull, + ) + elif self.readAudio: + self.devnull = open(os.devnull) + self.proc = popen_multiple( + COMMANDS, + ['-i', '-', '-f', 's16le', '-'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + ) + else: + raise NoInputError() except OSError: raise NotInstalledError() @@ -141,11 +172,16 @@ def __init__(self, filename, block_size=4096): finally: windows_error_mode_lock.release() + # Start a thread to write the compressed audio to Popen.stdin + if self.readAudio: + self.stdin_writer = WriterThread(self.proc.stdin,audio) + self.stdin_writer.start() + # Start another thread to consume the standard output of the # process, which contains raw audio data. self.stdout_reader = QueueReaderThread(self.proc.stdout, block_size) self.stdout_reader.start() - + # Read relevant information from stderr. self._get_info() @@ -165,6 +201,7 @@ def read_data(self, timeout=10.0): data = None try: data = self.stdout_reader.queue.get(timeout=timeout) + if data: yield data else: @@ -192,6 +229,7 @@ def _get_info(self): out_parts = [] while True: line = self.proc.stderr.readline() + if not line: # EOF and data not found. raise CommunicationError("stream info not found") diff --git a/audioread/ffdec.pyc b/audioread/ffdec.pyc new file mode 100644 index 0000000..6a002ca Binary files /dev/null and b/audioread/ffdec.pyc differ diff --git a/audioread/gstdec.pyc b/audioread/gstdec.pyc new file mode 100644 index 0000000..535f604 Binary files /dev/null and b/audioread/gstdec.pyc differ diff --git a/audioread/rawread.pyc b/audioread/rawread.pyc new file mode 100644 index 0000000..d81ab23 Binary files /dev/null and b/audioread/rawread.pyc differ diff --git a/decode.py b/decode.py old mode 100644 new mode 100755 index 40d369a..b20c115 --- a/decode.py +++ b/decode.py @@ -1,3 +1,5 @@ +#!/usr/bin/python + # This file is part of audioread. # Copyright 2011, Adrian Sampson. # @@ -28,7 +30,7 @@ def decode(filename): sys.exit(1) try: - with audioread.audio_open(filename) as f: + with audioread.audio_open(audio=open(filename,"r")) as f: print('Input file: %i channels at %i Hz; %.1f seconds.' % (f.channels, f.samplerate, f.duration), file=sys.stderr)