18 |
18 |
19 from io import StringIO |
19 from io import StringIO |
20 from tempfile import NamedTemporaryFile |
20 from tempfile import NamedTemporaryFile |
21 |
21 |
22 # import interfaces |
22 # import interfaces |
23 from pyams_media.interfaces import IMediaVideoConverter, IMediaAudioConverter, IMediaConversionUtility, IMediaConverter |
23 from pyams_media.interfaces import IMediaVideoConverter, IMediaAudioConverter, IMediaConversionUtility, IMediaConverter, \ |
|
24 VIDEO_FRAME_SIZE |
24 |
25 |
25 # import packages |
26 # import packages |
26 from pyams_media.ffdocument import FFDocument |
27 from pyams_media.ffdocument import FFDocument |
27 from pyams_utils.list import unique |
28 from pyams_utils.list import unique |
28 from pyams_utils.registry import utility_config, get_utilities_for, query_utility |
29 from pyams_utils.registry import utility_config, get_utilities_for, query_utility |
54 document = FFDocument(input.name) |
55 document = FFDocument(input.name) |
55 else: |
56 else: |
56 if isinstance(media, str): |
57 if isinstance(media, str): |
57 media = StringIO(media) |
58 media = StringIO(media) |
58 document = FFDocument(media) |
59 document = FFDocument(media) |
59 self.add_filters(document) |
60 self.add_common_filters(document) |
60 for loop in self.get_conversion_loop(document): |
61 for loop in self.get_conversion_loop(document): |
61 if self.require_temp_file: |
62 if self.require_temp_file: |
62 output = NamedTemporaryFile(prefix='media_', suffix='.%s' % self.format) |
63 output = NamedTemporaryFile(prefix='media_', suffix='.%s' % self.format) |
63 document.get_output(self.format, target=output.name) |
64 document.get_output(self.format, target=output.name) |
64 output.file.seek(0) |
65 output.file.seek(0) |
65 yield loop, output.file.read() |
66 yield loop, output.file.read() |
66 else: |
67 else: |
67 yield loop, document.get_output(self.format) |
68 yield loop, document.get_output(self.format) |
68 |
69 |
|
70 def add_common_filters(self, document): |
|
71 pass |
|
72 |
69 def add_filters(self, document): |
73 def add_filters(self, document): |
70 pass |
74 pass |
71 |
75 |
72 def get_conversion_loop(self, document): |
76 def get_conversion_loop(self, document): |
|
77 self.add_filters(document) |
73 yield None |
78 yield None |
74 |
79 |
75 |
80 |
76 # |
81 # |
77 # Audio converters |
82 # Audio converters |
78 # |
83 # |
79 |
84 |
80 @implementer(IMediaAudioConverter) |
85 @implementer(IMediaAudioConverter) |
81 class BaseAudioConverter(BaseMediaConverter): |
86 class BaseAudioConverter(BaseMediaConverter): |
82 """Base media converter""" |
87 """Base media converter""" |
|
88 |
|
89 def add_common_filters(self, document): |
|
90 super(BaseAudioConverter, self).add_common_filters(document) |
|
91 utility = query_utility(IMediaConversionUtility) |
|
92 if utility is not None: |
|
93 if utility.audio_sampling: |
|
94 document.audiosampling(utility.audio_sampling) |
|
95 if utility.audio_bitrate: |
|
96 document.audiobitrate(utility.audio_bitrate) |
83 |
97 |
84 |
98 |
85 @utility_config(name='audio/wav', provides=IMediaConverter) |
99 @utility_config(name='audio/wav', provides=IMediaConverter) |
86 class WavAudioConverter(BaseAudioConverter): |
100 class WavAudioConverter(BaseAudioConverter): |
87 """Default WAV media converter""" |
101 """Default WAV media converter""" |
137 document.quantizerscale(utility.video_quantisation) |
151 document.quantizerscale(utility.video_quantisation) |
138 |
152 |
139 def get_conversion_loop(self, document): |
153 def get_conversion_loop(self, document): |
140 utility = query_utility(IMediaConversionUtility) |
154 utility = query_utility(IMediaConversionUtility) |
141 if utility is not None: |
155 if utility is not None: |
|
156 # Get video resolution |
|
157 video_info = document.get_stream_info('video') |
|
158 if video_info is not None: |
|
159 frame_width = video_info.get('width') |
|
160 else: |
|
161 frame_width = (0, 0) |
|
162 # Check same resolution conversion |
|
163 if video_info.get('format', {}).get('format_name') != self.format: |
|
164 yield None |
|
165 # Convert to lower resolutions |
|
166 self.add_filters(document) |
142 for size in utility.video_frame_size or (): |
167 for size in utility.video_frame_size or (): |
143 document.size(size) |
168 target_width = VIDEO_FRAME_SIZE.get(size, (0, 0))[0] |
144 yield size |
169 if target_width < frame_width: |
|
170 document.size(size) |
|
171 yield size |
145 |
172 |
146 |
173 |
147 @utility_config(name='video/x-flv', provides=IMediaConverter) |
174 @utility_config(name='video/x-flv', provides=IMediaConverter) |
148 class FlvVideoConverter(BaseVideoConverter): |
175 class FlvVideoConverter(BaseVideoConverter): |
149 """Default FLV media converter""" |
176 """Default FLV media converter""" |
150 |
177 |
151 label = _("FLV (Flash Video) video converter") |
178 label = _("FLV (Flash Video) video converter") |
152 format = 'flv' |
179 format = 'flv' |
153 |
180 |
|
181 def add_common_filters(self, document): |
|
182 super(FlvVideoConverter, self).add_common_filters(document) |
|
183 # Audio sampling is required by FLV converter! |
|
184 utility = query_utility(IMediaConversionUtility) |
|
185 if utility is not None: |
|
186 if utility.video_audio_sampling: |
|
187 document.audiosampling(utility.video_audio_sampling) |
|
188 |
154 |
189 |
155 @utility_config(name='video/mp4', provides=IMediaConverter) |
190 @utility_config(name='video/mp4', provides=IMediaConverter) |
156 class Mp4VideoConverter(BaseVideoConverter): |
191 class Mp4VideoConverter(BaseVideoConverter): |
157 """Default MP4 media converter""" |
192 """Default MP4 media converter""" |
158 |
193 |
159 label = _("MP4 (HTML5) video converter") |
194 label = _("MP4 (HTML5) video converter") |
160 format = 'mp4' |
195 format = 'mp4' |
161 require_temp_file = True |
196 require_temp_file = True |
162 |
197 |
|
198 def add_common_filters(self, document): |
|
199 effects = document.__effects__ |
|
200 effects['filter:v'] = 'setsar=1/1' |
|
201 effects['pix_fmt'] = 'yuv420p' |
|
202 effects['preset:v'] = 'slow' |
|
203 effects['profile:v'] = 'baseline' |
|
204 effects['x264opts'] = 'level=3.0:ref=1' |
|
205 effects['r:v'] = '25/1' |
|
206 effects['movflags'] = '+faststart' |
|
207 |
163 |
208 |
164 @utility_config(name='video/ogg', provides=IMediaConverter) |
209 @utility_config(name='video/ogg', provides=IMediaConverter) |
165 class OggVideoConverter(BaseVideoConverter): |
210 class OggVideoConverter(BaseVideoConverter): |
166 """OGG media converter""" |
211 """OGG media converter""" |
167 |
212 |
173 class WebmVideoConverter(BaseVideoConverter): |
218 class WebmVideoConverter(BaseVideoConverter): |
174 """WebM Media converter""" |
219 """WebM Media converter""" |
175 |
220 |
176 label = _("WebM video converter") |
221 label = _("WebM video converter") |
177 format = 'webm' |
222 format = 'webm' |
|
223 |
|
224 def add_common_filters(self, document): |
|
225 effects = document.__effects__ |
|
226 effects['filter:v'] = 'setsar=1/1' |
|
227 effects['pix_fmt'] = 'yuv420p' |
|
228 effects['r:v'] = '25/1' |
178 |
229 |
179 |
230 |
180 class VideoConvertersVocabulary(SimpleVocabulary): |
231 class VideoConvertersVocabulary(SimpleVocabulary): |
181 """Video converters vocabulary""" |
232 """Video converters vocabulary""" |
182 |
233 |