From 477291b969f75a7081fc741eddacd5481bcbd607 Mon Sep 17 00:00:00 2001 From: twall Date: Mon, 13 Jan 2014 11:06:56 +0100 Subject: [PATCH] added starttime option for ffmpeg decoders, fixed ffmpeg ogg encoding, stepping stone for #390 and #275 --- audiotranscode/__init__.py | 24 +++++++++++++--------- cherrymusicserver/httphandler.py | 5 ++++- cherrymusicserver/test/test_httphandler.py | 2 +- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/audiotranscode/__init__.py b/audiotranscode/__init__.py index d5c0ee20..0b214a6d 100644 --- a/audiotranscode/__init__.py +++ b/audiotranscode/__init__.py @@ -36,7 +36,7 @@ def __init__(self,filetype,command): def encode(self, decoder_process, bitrate): cmd = self.command[:] if 'BITRATE' in cmd: - cmd[cmd.index('BITRATE')] = str(bitrate) + cmd[cmd.index('BITRATE')] = '%dk' % bitrate return subprocess.Popen(cmd, stdin=decoder_process.stdout, stdout=subprocess.PIPE, @@ -52,10 +52,13 @@ def __init__(self,filetype,command): self.mimetype = MimeTypes[filetype] self.command = command - def decode(self, filepath): + def decode(self, filepath, starttime=0): cmd = self.command[:] if 'INPUT' in cmd: cmd[cmd.index('INPUT')] = filepath + if 'STARTTIME' in cmd: + hours, minutes, seconds = starttime//3600, starttime//60%60, starttime%60 + cmd[cmd.index('STARTTIME')] = '%d:%d:%d' % (hours, minutes, seconds) return subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=Transcoder.devnull @@ -88,7 +91,7 @@ class AudioTranscode: Encoders = [ #encoders take input from stdin and write output to stout Encoder('ogg', ['oggenc', '-b','BITRATE','-']), - #Encoder('ogg', ['ffmpeg', '-i', '-', '-f', 'ogg', '-acodec', 'vorbis', '-']), #doesn't work yet + Encoder('ogg', ['ffmpeg', '-i', '-', '-f', 'ogg', '-acodec', 'libvorbis', '-ab', 'BITRATE', '-']), Encoder('mp3', ['lame','-b','BITRATE','-','-']), Encoder('mp3', ['ffmpeg', '-i', '-', '-f', 'mp3', '-acodec', 'libmp3lame', '-ab', 'BITRATE', '-']), Encoder('aac', ['faac','-b','BITRATE','-P','-X','-o','-','-']), @@ -100,10 +103,10 @@ class AudioTranscode: Decoders = [ #filepath must be appendable! Decoder('mp3' , ['mpg123', '-w', '-', 'INPUT']), - Decoder('mp3' , ['ffmpeg', '-i', 'INPUT', '-f', 'wav', '-acodec', 'pcm_s16le', '-']), - Decoder('wma' , ['ffmpeg', '-i', 'INPUT', '-f', 'wav', '-acodec', 'pcm_s16le', '-']), + Decoder('mp3' , ['ffmpeg', '-ss', 'STARTTIME', '-i', 'INPUT', '-f', 'wav', '-acodec', 'pcm_s16le', '-']), + Decoder('wma' , ['ffmpeg', '-ss', 'STARTTIME', '-i', 'INPUT', '-f', 'wav', '-acodec', 'pcm_s16le', '-']), Decoder('ogg' , ['oggdec', '-Q','-b', '16', '-o', '-', 'INPUT']), - Decoder('ogg' , ['ffmpeg', '-i', 'INPUT', '-f', 'wav', '-acodec', 'pcm_s16le', '-']), + Decoder('ogg' , ['ffmpeg', '-ss', 'STARTTIME', '-i', 'INPUT', '-f', 'wav', '-acodec', 'pcm_s16le', '-']), Decoder('flac' , ['flac', '-F','-d', '-c', 'INPUT']), Decoder('aac' , ['faad', '-w', 'INPUT']), Decoder('m4a' , ['faad', '-w', 'INPUT']), @@ -126,7 +129,7 @@ def _filetype(self, filepath): if '.' in filepath: return filepath.lower()[filepath.rindex('.')+1:] - def _decode(self, filepath, decoder=None): + def _decode(self, filepath, decoder=None, starttime=0): if not os.path.exists(filepath): filepath = os.path.abspath(filepath) raise DecodeError('File not Found! Cannot decode "file" %s'%filepath) @@ -140,7 +143,7 @@ def _decode(self, filepath, decoder=None): break if self.debug: print(decoder) - return decoder.decode(filepath) + return decoder.decode(filepath, starttime=starttime) def _encode(self, audio_format, decoder_process, bitrate=None,encoder=None): if not audio_format in self.availableEncoderFormats(): @@ -166,11 +169,12 @@ def transcode(self, in_file, out_file, bitrate=None): fh.write(data) fh.close() - def transcodeStream(self, filepath, newformat,bitrate=None,encoder=None,decoder=None): + def transcodeStream(self, filepath, newformat, bitrate=None, + encoder=None, decoder=None, starttime=0): decoder_process = None encoder_process = None try: - decoder_process = self._decode(filepath, decoder) + decoder_process = self._decode(filepath, decoder, starttime=starttime) encoder_process = self._encode(newformat, decoder_process,bitrate=bitrate,encoder=encoder) while encoder_process.poll() == None: data = encoder_process.stdout.read(AudioTranscode.READ_BUFFER) diff --git a/cherrymusicserver/httphandler.py b/cherrymusicserver/httphandler.py index d56cacb3..736e1f52 100644 --- a/cherrymusicserver/httphandler.py +++ b/cherrymusicserver/httphandler.py @@ -251,11 +251,14 @@ def trans(self, newformat, *path, **params): path = codecs.decode(codecs.encode(path, 'latin1'), 'utf-8') fullpath = os.path.join(cherry.config['media.basedir'], path) + starttime = int(params.pop('starttime', 0)) + transcoder = audiotranscode.AudioTranscode() mimetype = transcoder.mimeType(newformat) cherrypy.response.headers["Content-Type"] = mimetype try: - return transcoder.transcodeStream(fullpath, newformat, bitrate=bitrate) + return transcoder.transcodeStream(fullpath, newformat, + bitrate=bitrate, starttime=starttime) except audiotranscode.TranscodeError as e: raise cherrypy.HTTPError(404, e.value) trans.exposed = True diff --git a/cherrymusicserver/test/test_httphandler.py b/cherrymusicserver/test/test_httphandler.py index 4f5f9052..b96b893d 100644 --- a/cherrymusicserver/test/test_httphandler.py +++ b/cherrymusicserver/test/test_httphandler.py @@ -313,7 +313,7 @@ def test_trans(self): httphandler.HTTPHandler(config).trans('newformat', 'path', bitrate=111) - transcoder.transcodeStream.assert_called_with(expectPath, 'newformat', bitrate=111) + transcoder.transcodeStream.assert_called_with(expectPath, 'newformat', bitrate=111, starttime=0) if __name__ == "__main__":