src/pyams_media/video.py
changeset 131 41ec6731bf1b
parent 95 b379aa42a359
equal deleted inserted replaced
130:0ec5e1dc039c 131:41ec6731bf1b
    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