diff -r 000000000000 -r fd39db613f8b src/pyams_media/converter.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_media/converter.py Wed Sep 02 15:31:55 2015 +0200 @@ -0,0 +1,189 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library +import mimetypes + +from io import StringIO +from tempfile import NamedTemporaryFile + +# import interfaces +from pyams_media.interfaces import IMediaVideoConverter, IMediaAudioConverter, IMediaConversionUtility, IMediaConverter + +# import packages +from pyams_media.ffdocument import FFDocument +from pyams_utils.list import unique +from pyams_utils.registry import utility_config, get_utilities_for, query_utility +from zope.interface import implementer +from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm, getVocabularyRegistry + +from pyams_media import _ + + +class BaseMediaConverter(object): + """Base media converter""" + + format = None + require_temp_file = False + + def require_input_file(self, media): + """Check if a physical file is required to handle conversion""" + return media.content_type == b'video/quicktime' + + def convert(self, media): + """Convert media""" + if self.require_input_file(media): + input = NamedTemporaryFile(prefix='input_', suffix=mimetypes.guess_extension(media.contentType)) + if isinstance(media, str): + input.write(media) + else: + input.write(media.data) + input.file.flush() + document = FFDocument(input.name) + else: + if isinstance(media, str): + media = StringIO(media) + document = FFDocument(media) + self.add_filters(document) + for loop in self.get_conversion_loop(document): + if self.require_temp_file: + output = NamedTemporaryFile(prefix='media_', suffix='.%s' % self.format) + document.get_output(self.format, target=output.name) + output.file.seek(0) + yield loop, output.file.read() + else: + yield loop, document.get_output(self.format) + + def add_filters(self, document): + pass + + def get_conversion_loop(self, document): + yield None + + +# +# Audio converters +# + +@implementer(IMediaAudioConverter) +class BaseAudioConverter(BaseMediaConverter): + """Base media converter""" + + +@utility_config(name='audio/wav', provides=IMediaConverter) +class WavAudioConverter(BaseAudioConverter): + """Default WAV media converter""" + + label = _("WAV audio converter") + format = 'wav' + + +@utility_config(name='audio/mpeg', provides=IMediaConverter) +class Mp3AudioConverter(BaseAudioConverter): + """Default MP3 media converter""" + + label = _("MP3 audio converter") + format = 'mp3' + + +@utility_config(name='audio/ogg', provides=IMediaConverter) +class OggAudioConverter(BaseAudioConverter): + """Default OGG audio converter""" + + label = _("OGG audio converter") + format = 'ogg' + + +class AudioConvertersVocabulary(SimpleVocabulary): + """Audio converters vocabulary""" + + def __init__(self, context=None): + terms = [SimpleTerm(name, title=util.label) + for name, util in unique(get_utilities_for(IMediaConverter)) + if IMediaAudioConverter.providedBy(util)] + super(AudioConvertersVocabulary, self).__init__(terms) + +getVocabularyRegistry().register('PyAMS media audio converters', AudioConvertersVocabulary) + + +# +# Video converters +# + +@implementer(IMediaVideoConverter) +class BaseVideoConverter(BaseMediaConverter): + """Base video converter""" + + def add_filters(self, document): + utility = query_utility(IMediaConversionUtility) + if utility is not None: + if utility.video_audio_sampling: + document.audiosampling(utility.video_audio_sampling) + if utility.video_audio_bitrate: + document.bitrate(utility.video_audio_bitrate) + if utility.video_quantisation: + document.quantizerscale(utility.video_quantisation) + + def get_conversion_loop(self, document): + utility = query_utility(IMediaConversionUtility) + if utility is not None: + for size in utility.video_frame_size or (): + document.size(size) + yield size + + +@utility_config(name='video/x-flv', provides=IMediaConverter) +class FlvVideoConverter(BaseVideoConverter): + """Default FLV media converter""" + + label = _("FLV (Flash Video) video converter") + format = 'flv' + + +@utility_config(name='video/mp4', provides=IMediaConverter) +class Mp4VideoConverter(BaseVideoConverter): + """Default MP4 media converter""" + + label = _("MP4 (HTML5) video converter") + format = 'mp4' + require_temp_file = True + + +@utility_config(name='video/ogg', provides=IMediaConverter) +class OggVideoConverter(BaseVideoConverter): + """OGG media converter""" + + label = _("OGG video converter") + format = 'ogg' + + +@utility_config(name='video/webm', provides=IMediaConverter) +class WebmVideoConverter(BaseVideoConverter): + """WebM Media converter""" + + label = _("WebM video converter") + format = 'webm' + + +class VideoConvertersVocabulary(SimpleVocabulary): + """Video converters vocabulary""" + + def __init__(self, context=None): + terms = [SimpleTerm(name, title=util.label) + for name, util in unique(get_utilities_for(IMediaConverter)) + if IMediaVideoConverter.providedBy(util)] + super(VideoConvertersVocabulary, self).__init__(terms) + +getVocabularyRegistry().register('PyAMS media video converters', VideoConvertersVocabulary)