|
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) |