Table Of Contents

Source code for kivy.core.video

'''
Video
=====

Core class for reading video files and managing the video
:class:`~kivy.graphics.texture.Texture`.

.. versionchanged:: 3.0.0
    Extended :class:`VideoBase` with:

      - :meth:`VideoBase.generate_thumbnail` classmethod for creating a
        :class:`~kivy.graphics.texture.Texture` from a frame at a
        given timestamp without instantiating / playing the video.
      - :attr:`VideoBase.buffering` observable boolean that is True
        while playback is delayed/stalled while trying to satisfy
        ``state='play'``, and the :attr:`VideoBase.on_buffering`
        event that fires whenever it changes.
      - :attr:`VideoBase.options` provider-specific options dict so apps
        can pass opaque configuration through to the backend
        implementation. Each provider documents the keys it honors.

.. versionchanged:: 1.10.0
    The pyglet, pygst and gi providers have been removed.

.. versionchanged:: 1.8.0
    There are now 2 distinct Gstreamer implementations: one using Gi/Gst
    working for both Python 2+3 with Gstreamer 1.0, and one using PyGST
    working only for Python 2 + Gstreamer 0.10.

.. note::

    Recording is not supported.
'''

__all__ = ('VideoBase', 'Video')

from kivy.clock import Clock
from kivy.core import core_select_lib, get_provider_modules, make_provider_tuple
from kivy.event import EventDispatcher
from kivy.logger import Logger


[docs] class VideoBase(EventDispatcher): '''VideoBase, a class used to implement a video reader. :Parameters: `filename`: str Filename of the video. Can be a file or an URI. `eos`: str, defaults to 'pause' Action to take when EOS is hit. Can be one of 'pause', 'stop' or 'loop'. .. versionchanged:: 1.4.0 added 'pause' `async`: bool, defaults to True Load the video asynchronously (may be not supported by all providers). `autoplay`: bool, defaults to False Auto play the video on init. `options`: dict, defaults to {} Provider-specific options forwarded opaquely to the underlying implementation. The base class consumes the documented kwargs above; any other keys are placed in :attr:`options` for the selected provider to consume. Each provider documents the keys it honors. Keys not recognized by the selected provider are typically logged as a warning and ignored. .. versionadded:: 3.0.0 :Events: `on_eos` Fired when EOS is hit. `on_load` Fired when the video is loaded and the texture is available. `on_frame` Fired when a new frame is written to the texture. `on_buffering` Fired when :attr:`buffering` changes. Strictly a transition event; the boolean is also readable as a property. .. versionadded:: 3.0.0 ''' __slots__ = ('_wantplay', '_buffer', '_filename', '_texture', '_volume', 'eos', '_state', '_async', '_autoplay', '_fps', '_options', '_buffering') __events__ = ('on_eos', 'on_load', 'on_frame', 'on_buffering') def __init__(self, **kwargs): kwargs.setdefault('filename', None) kwargs.setdefault('eos', 'stop') kwargs.setdefault('async', True) kwargs.setdefault('autoplay', False) kwargs.setdefault('fps', 30) kwargs.setdefault('options', {}) super(VideoBase, self).__init__() self._wantplay = False self._buffer = None self._filename = None self._texture = None self._volume = 1. self._state = '' self._buffering = False self._autoplay = kwargs.get('autoplay') self._async = kwargs.get('async') self.eos = kwargs.get('eos') self._fps = kwargs.get('fps') self._options = kwargs['options'] if self.eos == 'pause': Logger.warning("'pause' is deprecated. Use 'stop' instead.") self.eos = 'stop' self.filename = kwargs.get('filename') Clock.schedule_interval(self._update, 1 / self._fps) if self._autoplay: self.play() def __del__(self): self.unload() def on_eos(self): pass def on_load(self): pass def on_frame(self): pass
[docs] def on_buffering(self, value): '''Fired when :attr:`buffering` transitions. `value` is the new buffering state (``True`` or ``False``). .. versionadded:: 3.0.0 ''' pass
def _get_filename(self): return self._filename def _set_filename(self, filename): if filename == self._filename: return self.unload() self._filename = filename if self._filename is None: return self.load() filename = property(lambda self: self._get_filename(), lambda self, x: self._set_filename(x), doc='Get/set the filename/uri of the current video') def _get_position(self): return 0 def _set_position(self, pos): self.seek(pos) position = property(lambda self: self._get_position(), lambda self, x: self._set_position(x), doc='Get/set the position in the video (in seconds)') def _get_volume(self): return self._volume def _set_volume(self, volume): self._volume = volume volume = property(lambda self: self._get_volume(), lambda self, x: self._set_volume(x), doc='Get/set the volume in the video (1.0 = 100%)') def _get_duration(self): return 0 duration = property(lambda self: self._get_duration(), doc='Get the video duration (in seconds)') def _get_texture(self): return self._texture texture = property(lambda self: self._get_texture(), doc='Get the video texture') def _get_state(self): return self._state state = property(lambda self: self._get_state(), doc='Get the video playing status') def _get_options(self): return self._options options = property(lambda self: self._get_options(), doc='Get the provider-specific options dict that was ' 'passed to the provider at construction time. ' 'Read-only at the base class level; providers may ' 'mutate it during their lifetime. ' '\n\n.. versionadded:: 3.0.0') def _get_buffering(self): return self._buffering buffering = property( lambda self: self._get_buffering(), doc='Whether playback is currently delayed/stalled while ' "trying to satisfy ``state='play'``. Always False while " "``state`` is ``'pause'`` or ``'stop'`` (the player is " 'doing what was asked; there is no delay relative to ' "intent). ``True`` covers both the initial pre-playback " 'wait (asset still loading, buffer still filling) and ' 'any mid-stream rebuffer. Providers update this from ' 'their own authoritative signal; providers that cannot ' 'detect stalls leave it ``False``. Apps that want a ' 'loading overlay can use ' "``not video.loaded or video.buffering`` as the gate." '\n\n.. versionadded:: 3.0.0')
[docs] @classmethod def generate_thumbnail(cls, filename, time, size=None): '''Generate a thumbnail :class:`~kivy.graphics.texture.Texture` from the given video file at the given timestamp, without requiring playback. :Parameters: `filename`: str Path or URI to the video. `time`: float Timestamp in seconds at which to grab the thumbnail. `size`: tuple of (int, int), optional Target ``(width, height)``. When ``None`` the source video's native frame size is used. :Returns: A :class:`~kivy.graphics.texture.Texture` containing the decoded frame, or ``None`` if the provider does not support thumbnail generation or could not decode the asset at the requested time. Providers should override this. The default implementation logs an informational message and returns ``None``. .. versionadded:: 3.0.0 ''' Logger.info( 'VideoBase: generate_thumbnail is not supported by ' 'provider {!r}'.format(cls.__name__)) return None
def _do_eos(self, *args): ''' .. versionchanged:: 1.4.0 Now dispatches the `on_eos` event. ''' if self.eos == 'pause': self.pause() elif self.eos == 'stop': self.stop() elif self.eos == 'loop': self.position = 0 self.play() self.dispatch('on_eos') def _update(self, dt): '''Update the video content to texture. ''' pass
[docs] def seek(self, percent, precise=True): '''Move to position as percentage (strictly, a proportion from 0 - 1) of the duration''' pass
[docs] def stop(self): '''Stop the video playing''' self._state = ''
[docs] def pause(self): '''Pause the video .. versionadded:: 1.4.0 ''' self._state = 'paused'
[docs] def play(self): '''Play the video''' self._state = 'playing'
[docs] def load(self): '''Load the video from the current filename''' pass
[docs] def unload(self): '''Unload the actual video''' self._state = '' if self._buffering: self._buffering = False self.dispatch('on_buffering', False)
# Load the appropriate provider # Build platform-specific list from registry all_providers = get_provider_modules('video') video_providers = [] # avfoundation is the default video provider on Darwin (macOS / iOS). # It is compiled only when c_options['use_avfoundation'] is True in # setup.py, so the import naturally fails on non-Darwin platforms and # core_select_lib falls through to a different provider. video_providers.append(make_provider_tuple( 'avfoundation', all_providers, 'VideoAVFoundation' )) try: from kivy.lib.gstplayer import GstPlayer # NOQA video_providers.append(make_provider_tuple( 'gstplayer', all_providers, 'VideoGstplayer' )) except ImportError: pass video_providers.append(make_provider_tuple('ffmpeg', all_providers, 'VideoFFMpeg')) video_providers.append(make_provider_tuple('ffpyplayer', all_providers, 'VideoFFPy')) video_providers.append(make_provider_tuple('null', all_providers, 'VideoNull')) Video: VideoBase = core_select_lib('video', video_providers)