10 # FOR A PARTICULAR PURPOSE. |
10 # FOR A PARTICULAR PURPOSE. |
11 # |
11 # |
12 |
12 |
13 __docformat__ = 'restructuredtext' |
13 __docformat__ = 'restructuredtext' |
14 |
14 |
15 |
|
16 # import standard library |
|
17 import os.path |
15 import os.path |
18 import subprocess |
16 import subprocess |
19 |
|
20 from tempfile import NamedTemporaryFile |
17 from tempfile import NamedTemporaryFile |
21 |
18 |
22 # import interfaces |
19 import transaction |
23 from pyams_file.interfaces import IVideo, IThumbnails, IThumbnailFile |
20 from pyramid.threadlocal import get_current_registry |
24 from pyams_media.interfaces import IVideoType |
|
25 from pyams_utils.interfaces.tales import ITALESExtension |
|
26 from zope.annotation.interfaces import IAnnotations |
21 from zope.annotation.interfaces import IAnnotations |
|
22 from zope.interface import Interface, alsoProvides |
|
23 from zope.lifecycleevent import ObjectAddedEvent, ObjectCreatedEvent |
|
24 from zope.location import locate |
27 from zope.traversing.interfaces import ITraversable |
25 from zope.traversing.interfaces import ITraversable |
28 |
|
29 # import packages |
|
30 import transaction |
|
31 |
26 |
32 from pyams_file.file import ImageFile, get_magic_content_type |
27 from pyams_file.file import ImageFile, get_magic_content_type |
33 from pyams_file.image import ThumbnailGeometry |
28 from pyams_file.image import ThumbnailGeometry |
|
29 from pyams_file.interfaces import IThumbnailFile, IThumbnails, IVideo |
34 from pyams_media.ffbase import FFmpeg |
30 from pyams_media.ffbase import FFmpeg |
35 from pyams_utils.adapter import adapter_config, ContextAdapter, ContextRequestViewAdapter |
31 from pyams_media.interfaces import IVideoType |
36 from pyramid.threadlocal import get_current_registry |
32 from pyams_utils.adapter import ContextAdapter, ContextRequestViewAdapter, adapter_config |
37 from zope.interface import alsoProvides, Interface |
33 from pyams_utils.interfaces.tales import ITALESExtension |
38 from zope.lifecycleevent import ObjectCreatedEvent, ObjectAddedEvent |
|
39 from zope.location import locate |
|
40 |
34 |
41 |
35 |
42 THUMBNAIL_ANNOTATION_KEY = 'pyams_media.video.thumbnail' |
36 THUMBNAIL_ANNOTATION_KEY = 'pyams_media.video.thumbnail' |
43 THUMBNAIL_SIZE_ANNOTATION_KEY = 'pyams_media.video.thumbnail_size' |
37 THUMBNAIL_SIZE_ANNOTATION_KEY = 'pyams_media.video.thumbnail_size' |
44 |
38 |
108 else: |
102 else: |
109 return None, None |
103 return None, None |
110 |
104 |
111 def get_thumbnail(self, thumbnail_name, format=None, time=5): |
105 def get_thumbnail(self, thumbnail_name, format=None, time=5): |
112 if self.thumbnail is None: |
106 if self.thumbnail is None: |
113 pipe = subprocess.Popen(('avconv', '-i', '-', '-ss', str(time), '-f', 'image2', '-vframes', '1', '-'), |
107 pipe = subprocess.Popen(('avconv', |
114 stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
108 '-i', '-', |
|
109 '-ss', str(time), |
|
110 '-f', 'image2', |
|
111 '-vframes', '1', |
|
112 '-'), |
|
113 stdin=subprocess.PIPE, |
|
114 stdout=subprocess.PIPE, |
|
115 stderr=subprocess.PIPE) |
115 if pipe: |
116 if pipe: |
116 stdout, stderr = pipe.communicate(self.video.data) |
117 stdout, stderr = pipe.communicate(self.video.data) |
117 # Some videos formats can't be converted via pipes |
118 # Some videos formats can't be converted via pipes |
118 # If so, we must provide a temporay file... |
119 # If so, we must provide a temporay file... |
119 if not stdout: |
120 if not stdout: |
120 output = NamedTemporaryFile(prefix='video_', suffix='.thumb') |
121 output = NamedTemporaryFile(prefix='video_', suffix='.thumb') |
121 output.write(self.video.data) |
122 output.write(self.video.data) |
122 output.file.flush() |
123 output.file.flush() |
123 pipe = subprocess.Popen(('avconv', '-i', output.name, '-ss', str(time), '-f', 'image2', |
124 pipe = subprocess.Popen(('avconv', |
124 '-vframes', '1', '-'), |
125 '-i', output.name, |
125 stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
126 '-ss', str(time), |
|
127 '-f', 'image2', |
|
128 '-vframes', '1', |
|
129 '-'), |
|
130 stdin=subprocess.PIPE, |
|
131 stdout=subprocess.PIPE, |
|
132 stderr=subprocess.PIPE) |
126 if pipe: |
133 if pipe: |
127 stdout, stderr = pipe.communicate() |
134 stdout, stderr = pipe.communicate() |
128 # Create final image |
135 # Create final image |
129 registry = get_current_registry() |
136 registry = get_current_registry() |
130 annotations = IAnnotations(self.video) |
137 annotations = IAnnotations(self.video) |
193 @property |
200 @property |
194 def video_type(self): |
201 def video_type(self): |
195 return 'video/flash' |
202 return 'video/flash' |
196 |
203 |
197 |
204 |
198 @adapter_config(name='video_type', context=(Interface, Interface, Interface), provides=ITALESExtension) |
205 def get_video_type(context, registry): |
|
206 """Get video type of given context""" |
|
207 if not IVideo.providedBy(context): |
|
208 return None |
|
209 content_type = context.content_type |
|
210 if isinstance(content_type, bytes): |
|
211 content_type = content_type.decode() |
|
212 adapter = registry.queryAdapter(context, IVideoType, name=content_type) |
|
213 if adapter is None: |
|
214 adapter = registry.queryAdapter(context, IVideoType) |
|
215 if adapter is not None: |
|
216 video_type = adapter.video_type |
|
217 if isinstance(video_type, bytes): |
|
218 video_type = video_type.decode() |
|
219 return video_type |
|
220 |
|
221 |
|
222 @adapter_config(name='video_type', |
|
223 context=(Interface, Interface, Interface), |
|
224 provides=ITALESExtension) |
199 class VideoTypeExtension(ContextRequestViewAdapter): |
225 class VideoTypeExtension(ContextRequestViewAdapter): |
200 """extension:video_type(media) TALES extension""" |
226 """extension:video_type(media) TALES extension""" |
201 |
227 |
202 def render(self, context=None): |
228 def render(self, context=None): |
203 if context is None: |
229 if context is None: |
204 context = self.context |
230 context = self.context |
205 if not IVideo.providedBy(context): |
231 return get_video_type(context, self.request.registry) |
206 return None |
|
207 registry = self.request.registry |
|
208 content_type = context.content_type |
|
209 if isinstance(content_type, bytes): |
|
210 content_type = content_type.decode() |
|
211 adapter = registry.queryAdapter(context, IVideoType, name=content_type) |
|
212 if adapter is None: |
|
213 adapter = registry.queryAdapter(context, IVideoType) |
|
214 if adapter is not None: |
|
215 video_type = adapter.video_type |
|
216 if isinstance(video_type, bytes): |
|
217 video_type = video_type.decode() |
|
218 return video_type |
|