]> git.parisson.com Git - timeside.git/commitdiff
Encoder : add Opus encoder
authorThomas Fillon <thomas@parisson.com>
Mon, 3 Mar 2014 10:22:16 +0000 (11:22 +0100)
committerThomas Fillon <thomas@parisson.com>
Mon, 3 Mar 2014 10:22:16 +0000 (11:22 +0100)
tests/test_encoding.py
tests/test_transcoding_streaming.py
timeside/encoder/__init__.py
timeside/encoder/opus.py [new file with mode: 0644]

index 5fe617f7b53a116b3ef8db2db17de14dd2a59053..8df16b652705896077c22bdeef25a354e611df57 100755 (executable)
@@ -88,6 +88,13 @@ class TestEncoding(unittest.TestCase):
                                                  overwrite=self.overwrite,
                                                  video=True)
 
+    def testOpus(self):
+        "Test opus encoding"
+        from timeside.encoder.opus import OpusEncoder
+        self.encoder_function = OpusEncoder
+        self.delta = 0.1
+        self.samplerate = 48000  # 44100 is not supported by opusenc
+
     def tearDown(self):
 
         # Source through ArrayDecoder
index 457f6eb0cf3403eeeee030fe2a57193b65e71460..2ff0f4a3a0614c83bfd063b84653ad5d88572750 100644 (file)
@@ -22,6 +22,7 @@ class TestTranscodingStreaming(unittest.TestCase):
         self.test_duration = True
         self.test_channels = True
         self.filesize_delta = None
+        self.expected_sample_rate = None
 
     def testMp3(self):
         "Test conversion to mp3"
@@ -32,6 +33,11 @@ class TestTranscodingStreaming(unittest.TestCase):
         "Test conversion to ogg"
         self.encoder_function = VorbisEncoder
 
+    def testOpus(self):
+        "Test conversion to opus"
+        self.encoder_function = OpusEncoder
+        self.expected_sample_rate = 48000
+
     def testWebM(self):
         "Test conversion to webm"
         self.encoder_function = WebMEncoder
@@ -75,7 +81,9 @@ class TestTranscodingStreaming(unittest.TestCase):
         else:
             self.assertEqual(2, decoder_encoded.channels())  # voaacenc bug ?
 
-        self.assertEqual(decoder.samplerate(),
+        if not self.expected_sample_rate:
+            self.expected_sample_rate = decoder.samplerate()
+        self.assertEqual(self.expected_sample_rate,
                          decoder_encoded.samplerate())
 
         if self.test_duration:
index 37cd6b6066d9337c2ea3484ad041ddf71ac25017..0d341a2073aa1a1abf4a4a84c1d3f07aad17c11b 100644 (file)
@@ -6,4 +6,5 @@ from mp3 import Mp3Encoder
 from flac import FlacEncoder
 from m4a import AacEncoder
 from webm import WebMEncoder
-from audiosink import AudioSink
\ No newline at end of file
+from audiosink import AudioSink
+from opus import OpusEncoder
\ No newline at end of file
diff --git a/timeside/encoder/opus.py b/timeside/encoder/opus.py
new file mode 100644 (file)
index 0000000..c2e379d
--- /dev/null
@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007-2014 Parisson SARL
+# Copyright (c) 2006-2014 Guillaume Pellerin <pellerin@parisson.com>
+# Copyright (c) 2010-2014 Paul Brossier <piem@piem.org>
+# Copyright (c) 2009-2010 Olivier Guilyardi <olivier@samalyse.com>
+# Copyright (c) 2013-2014 Thomas Fillon <thomas@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>
+#          Thomas Fillon <thomas@parisson.com>
+
+from timeside.core import implements, interfacedoc
+from timeside.encoder.core import GstEncoder
+from timeside.api import IEncoder
+
+
+class OpusEncoder(GstEncoder):
+    """ gstreamer-based mp3 encoder """
+    implements(IEncoder)
+
+    @interfacedoc
+    def setup(self, channels=None, samplerate=None, blocksize=None,
+              totalframes=None):
+        super(OpusEncoder, self).setup(channels, samplerate, blocksize,
+                                       totalframes)
+
+        self.pipe = '''appsrc name=src
+                  ! audioconvert ! audioresample
+                  ! opusenc audio=true
+                  ! oggmux
+                  '''
+
+        if self.filename and self.streaming:
+            self.pipe += ''' ! tee name=t
+            ! queue ! filesink location=%s
+            t. ! queue! appsink name=app sync=False
+            ''' % self.filename
+
+        elif self.filename:
+            self.pipe += '! filesink location=%s async=False sync=False ' % self.filename
+        else:
+            self.pipe += '! queue ! appsink name=app sync=False'
+
+        self.start_pipeline(channels, samplerate)
+
+    @staticmethod
+    @interfacedoc
+    def id():
+        return "gst_opus_enc"
+
+    @staticmethod
+    @interfacedoc
+    def description():
+        return "Opus GStreamer based encoder"
+
+    @staticmethod
+    @interfacedoc
+    def format():
+        return "Opus"
+
+    @staticmethod
+    @interfacedoc
+    def file_extension():
+        return "opus"
+
+    @staticmethod
+    @interfacedoc
+    def mime_type():
+        return "audio/mpeg"
+
+    @interfacedoc
+    def set_metadata(self, metadata):
+        self.metadata = metadata