1
"""
2
Contains Media panes including renderers for Audio and Video content.
3
"""
4 6
from __future__ import absolute_import, division, unicode_literals
5

6 6
import os
7

8 6
from base64 import b64encode
9 6
from io import BytesIO
10 6
from six import string_types
11

12 6
import numpy as np
13 6
import param
14

15 6
from ..models import Audio as _BkAudio, Video as _BkVideo
16 6
from ..util import isfile, isurl
17 6
from .base import PaneBase
18

19

20 6
class _MediaBase(PaneBase):
21

22 6
    loop = param.Boolean(default=False, doc="""
23
        Whether the meida should loop""")
24

25 6
    time = param.Number(default=0, doc="""
26
        The current timestamp""")
27

28 6
    throttle = param.Integer(default=250, doc="""
29
        How frequently to sample the current playback time in milliseconds""")
30

31 6
    paused = param.Boolean(default=True, doc="""
32
        Whether the media is currently paused""")
33

34 6
    object = param.String(default='', allow_None=True, doc="""
35
        The media file either local or remote.""")
36

37 6
    volume = param.Number(default=None, bounds=(0, 100), doc="""
38
        The volume of the media player.""")
39

40 6
    _default_mime = None
41

42 6
    _formats = []
43

44 6
    _media_type = None
45

46 6
    _rename = {'name': None, 'sample_rate': None, 'object': 'value'}
47

48 6
    _updates = True
49

50 6
    __abstract = True
51

52 6
    @classmethod
53 1
    def applies(cls, obj):
54 6
        if isinstance(obj, string_types):
55 6
            if isfile(obj) and any(obj.endswith('.'+fmt) for fmt in cls._formats):
56 0
                return True
57 6
            if isurl(obj, cls._formats):
58 0
                return True
59 6
        if hasattr(obj, 'read'):  # Check for file like object
60 0
            return True
61 6
        return False
62

63 6
    def _init_properties(self):
64 6
        return {k: v for k, v in self.param.get_param_values()
65
                if v is not None and k not in ['default_layout']}
66

67 6
    def _get_model(self, doc, root=None, parent=None, comm=None):
68 6
        props = self._process_param_change(self._init_properties())
69 6
        model = self._bokeh_model(**props)
70 6
        if root is None:
71 6
            root = model
72 6
        self._models[root.ref['id']] = (model, parent)
73 6
        self._link_props(model, list(model.properties()), doc, root, comm)
74 6
        return model
75

76 6
    def _from_numpy(self, data):
77 0
        from scipy.io import wavfile
78 0
        buffer = BytesIO()
79 0
        wavfile.write(buffer, self.sample_rate, data)
80 0
        return buffer
81

82 6
    def _process_param_change(self, msg):
83 6
        msg = super(_MediaBase, self)._process_param_change(msg)
84 6
        if 'value' in msg:
85 0
            value = msg['value']
86 0
            if isinstance(value, np.ndarray):
87 0
                fmt = 'wav'
88 0
                buffer = self._from_numpy(value)
89 0
                data = b64encode(buffer.getvalue())
90 0
            elif os.path.isfile(value):
91 0
                fmt = value.split('.')[-1]
92 0
                with open(value, 'rb') as f:
93 0
                    data = f.read()
94 0
                data = b64encode(data)
95 0
            elif value.lower().startswith('http'):
96 0
                return msg
97 0
            elif not value:
98 0
                data, fmt = b'', self._default_mime
99
            else:
100 0
                raise ValueError('Object should be either path to a sound file or numpy array')
101 0
            template = 'data:audio/{mime};base64,{data}'
102 0
            msg['value'] = template.format(data=data.decode('utf-8'),
103
                                           mime=fmt)
104
            
105 6
        return msg
106

107

108 6
class Audio(_MediaBase):
109

110 6
    object = param.ClassSelector(default='', class_=(string_types + (np.ndarray,)),
111
                                 allow_None=True, doc="""
112
        The audio file either local or remote.""")
113

114 6
    sample_rate = param.Integer(default=44100, doc="""
115
        The sample_rate of the audio when given a NumPy array.""")
116

117 6
    _bokeh_model = _BkAudio
118

119 6
    _default_mime = 'wav'
120

121 6
    _formats = ['mp3', 'wav', 'ogg']
122

123 6
    _media_type = 'audio'
124

125 6
    @classmethod
126 1
    def applies(cls, obj):
127 6
        return (super(Audio, cls).applies(obj) or 
128
                (isinstance(obj, np.ndarray) and obj.ndim==1 and obj.dtype in [np.int16, np.uint16]))
129

130

131 6
class Video(_MediaBase):
132

133 6
    _bokeh_model = _BkVideo
134

135 6
    _default_mime = 'mp4'
136

137 6
    _formats = ['mp4', 'webm', 'ogg']
138

139 6
    _media_type = 'video'
140

Read our documentation on viewing source code .

Loading