src/pyams_media/converter.py
changeset 0 fd39db613f8b
child 5 73e9b218db71
equal deleted inserted replaced
-1:000000000000 0:fd39db613f8b
       
     1 #
       
     2 # Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
       
     3 # All Rights Reserved.
       
     4 #
       
     5 # This software is subject to the provisions of the Zope Public License,
       
     6 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
       
     7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
       
     8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
     9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
       
    10 # FOR A PARTICULAR PURPOSE.
       
    11 #
       
    12 
       
    13 __docformat__ = 'restructuredtext'
       
    14 
       
    15 
       
    16 # import standard library
       
    17 import mimetypes
       
    18 
       
    19 from io import StringIO
       
    20 from tempfile import NamedTemporaryFile
       
    21 
       
    22 # import interfaces
       
    23 from pyams_media.interfaces import IMediaVideoConverter, IMediaAudioConverter, IMediaConversionUtility, IMediaConverter
       
    24 
       
    25 # import packages
       
    26 from pyams_media.ffdocument import FFDocument
       
    27 from pyams_utils.list import unique
       
    28 from pyams_utils.registry import utility_config, get_utilities_for, query_utility
       
    29 from zope.interface import implementer
       
    30 from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm, getVocabularyRegistry
       
    31 
       
    32 from pyams_media import _
       
    33 
       
    34 
       
    35 class BaseMediaConverter(object):
       
    36     """Base media converter"""
       
    37 
       
    38     format = None
       
    39     require_temp_file = False
       
    40 
       
    41     def require_input_file(self, media):
       
    42         """Check if a physical file is required to handle conversion"""
       
    43         return media.content_type == b'video/quicktime'
       
    44 
       
    45     def convert(self, media):
       
    46         """Convert media"""
       
    47         if self.require_input_file(media):
       
    48             input = NamedTemporaryFile(prefix='input_', suffix=mimetypes.guess_extension(media.contentType))
       
    49             if isinstance(media, str):
       
    50                 input.write(media)
       
    51             else:
       
    52                 input.write(media.data)
       
    53             input.file.flush()
       
    54             document = FFDocument(input.name)
       
    55         else:
       
    56             if isinstance(media, str):
       
    57                 media = StringIO(media)
       
    58             document = FFDocument(media)
       
    59         self.add_filters(document)
       
    60         for loop in self.get_conversion_loop(document):
       
    61             if self.require_temp_file:
       
    62                 output = NamedTemporaryFile(prefix='media_', suffix='.%s' % self.format)
       
    63                 document.get_output(self.format, target=output.name)
       
    64                 output.file.seek(0)
       
    65                 yield loop, output.file.read()
       
    66             else:
       
    67                 yield loop, document.get_output(self.format)
       
    68 
       
    69     def add_filters(self, document):
       
    70         pass
       
    71 
       
    72     def get_conversion_loop(self, document):
       
    73         yield None
       
    74 
       
    75 
       
    76 #
       
    77 # Audio converters
       
    78 #
       
    79 
       
    80 @implementer(IMediaAudioConverter)
       
    81 class BaseAudioConverter(BaseMediaConverter):
       
    82     """Base media converter"""
       
    83 
       
    84 
       
    85 @utility_config(name='audio/wav', provides=IMediaConverter)
       
    86 class WavAudioConverter(BaseAudioConverter):
       
    87     """Default WAV media converter"""
       
    88 
       
    89     label = _("WAV audio converter")
       
    90     format = 'wav'
       
    91 
       
    92 
       
    93 @utility_config(name='audio/mpeg', provides=IMediaConverter)
       
    94 class Mp3AudioConverter(BaseAudioConverter):
       
    95     """Default MP3 media converter"""
       
    96 
       
    97     label = _("MP3 audio converter")
       
    98     format = 'mp3'
       
    99 
       
   100 
       
   101 @utility_config(name='audio/ogg', provides=IMediaConverter)
       
   102 class OggAudioConverter(BaseAudioConverter):
       
   103     """Default OGG audio converter"""
       
   104 
       
   105     label = _("OGG audio converter")
       
   106     format = 'ogg'
       
   107 
       
   108 
       
   109 class AudioConvertersVocabulary(SimpleVocabulary):
       
   110     """Audio converters vocabulary"""
       
   111 
       
   112     def __init__(self, context=None):
       
   113         terms = [SimpleTerm(name, title=util.label)
       
   114                  for name, util in unique(get_utilities_for(IMediaConverter))
       
   115                  if IMediaAudioConverter.providedBy(util)]
       
   116         super(AudioConvertersVocabulary, self).__init__(terms)
       
   117 
       
   118 getVocabularyRegistry().register('PyAMS media audio converters', AudioConvertersVocabulary)
       
   119 
       
   120 
       
   121 #
       
   122 # Video converters
       
   123 #
       
   124 
       
   125 @implementer(IMediaVideoConverter)
       
   126 class BaseVideoConverter(BaseMediaConverter):
       
   127     """Base video converter"""
       
   128 
       
   129     def add_filters(self, document):
       
   130         utility = query_utility(IMediaConversionUtility)
       
   131         if utility is not None:
       
   132             if utility.video_audio_sampling:
       
   133                 document.audiosampling(utility.video_audio_sampling)
       
   134             if utility.video_audio_bitrate:
       
   135                 document.bitrate(utility.video_audio_bitrate)
       
   136             if utility.video_quantisation:
       
   137                 document.quantizerscale(utility.video_quantisation)
       
   138 
       
   139     def get_conversion_loop(self, document):
       
   140         utility = query_utility(IMediaConversionUtility)
       
   141         if utility is not None:
       
   142             for size in utility.video_frame_size or ():
       
   143                 document.size(size)
       
   144                 yield size
       
   145 
       
   146 
       
   147 @utility_config(name='video/x-flv', provides=IMediaConverter)
       
   148 class FlvVideoConverter(BaseVideoConverter):
       
   149     """Default FLV media converter"""
       
   150 
       
   151     label = _("FLV (Flash Video) video converter")
       
   152     format = 'flv'
       
   153 
       
   154 
       
   155 @utility_config(name='video/mp4', provides=IMediaConverter)
       
   156 class Mp4VideoConverter(BaseVideoConverter):
       
   157     """Default MP4 media converter"""
       
   158 
       
   159     label = _("MP4 (HTML5) video converter")
       
   160     format = 'mp4'
       
   161     require_temp_file = True
       
   162 
       
   163 
       
   164 @utility_config(name='video/ogg', provides=IMediaConverter)
       
   165 class OggVideoConverter(BaseVideoConverter):
       
   166     """OGG media converter"""
       
   167 
       
   168     label = _("OGG video converter")
       
   169     format = 'ogg'
       
   170 
       
   171 
       
   172 @utility_config(name='video/webm', provides=IMediaConverter)
       
   173 class WebmVideoConverter(BaseVideoConverter):
       
   174     """WebM Media converter"""
       
   175 
       
   176     label = _("WebM video converter")
       
   177     format = 'webm'
       
   178 
       
   179 
       
   180 class VideoConvertersVocabulary(SimpleVocabulary):
       
   181     """Video converters vocabulary"""
       
   182 
       
   183     def __init__(self, context=None):
       
   184         terms = [SimpleTerm(name, title=util.label)
       
   185                  for name, util in unique(get_utilities_for(IMediaConverter))
       
   186                  if IMediaVideoConverter.providedBy(util)]
       
   187         super(VideoConvertersVocabulary, self).__init__(terms)
       
   188 
       
   189 getVocabularyRegistry().register('PyAMS media video converters', VideoConvertersVocabulary)