Merge pull request #2358 from matham/ffpy-image

Add ffpyplayer provider for image
This commit is contained in:
Akshay Arora 2014-07-26 14:25:18 +05:30
commit 6bcaecdf18
4 changed files with 98 additions and 7 deletions

View File

@ -186,7 +186,7 @@ kivy_options = {
'video': ('gstplayer', 'ffmpeg', 'ffpyplayer', 'gi', 'pygst', 'pyglet',
'null'),
'audio': ('gstplayer', 'pygame', 'gi', 'pygst', 'ffpyplayer', 'sdl'),
'image': ('tex', 'imageio', 'dds', 'gif', 'pil', 'pygame'),
'image': ('tex', 'imageio', 'dds', 'gif', 'pil', 'pygame', 'ffpy'),
'camera': ('opencv', 'gi', 'pygst', 'videocapture', 'avfoundation'),
'spelling': ('enchant', 'osxappkit', ),
'clipboard': ('android', 'pygame', 'dummy'), }

View File

@ -40,13 +40,13 @@ class ImageData(object):
The container will always have at least the mipmap level 0.
'''
__slots__ = ('fmt', 'mipmaps', 'source', 'flip_vertical')
__slots__ = ('fmt', 'mipmaps', 'source', 'flip_vertical', 'source_image')
_supported_fmts = ('rgb', 'rgba', 'bgr', 'bgra', 's3tc_dxt1', 's3tc_dxt3',
's3tc_dxt5', 'pvrtc_rgb2', 'pvrtc_rgb4', 'pvrtc_rgba2',
'pvrtc_rgba4', 'etc1_rgb8')
def __init__(self, width, height, fmt, data, source=None,
flip_vertical=True):
flip_vertical=True, source_image=None):
assert fmt in ImageData._supported_fmts
#: Decoded image format, one of a available texture format
@ -62,10 +62,14 @@ class ImageData(object):
#: Indicate if the texture will need to be vertically flipped
self.flip_vertical = flip_vertical
# the original image, which we might need to save if it is a memoryview
self.source_image = source_image
def release_data(self):
mm = self.mipmaps
for item in mm.values():
item[2] = None
self.source_image = None
@property
def width(self):
@ -445,7 +449,6 @@ class Image(EventDispatcher):
else:
raise Exception('Unable to load image type {0!r}'.format(arg))
def remove_from_cache(self):
'''Remove the Image from cache. This facilitates re-loading of
images from disk in case the image content has changed.
@ -797,6 +800,7 @@ image_libs += [
('tex', 'img_tex'),
('dds', 'img_dds'),
('pygame', 'img_pygame'),
('ffpy', 'img_ffpyplayer'),
('pil', 'img_pil'),
('gif', 'img_gif')]
libs_loaded = core_register_libs('image', image_libs)

View File

@ -0,0 +1,86 @@
'''
FFPyPlayer: FFmpeg based image loader
'''
__all__ = ('ImageLoaderFFPy', )
import ffpyplayer
from ffpyplayer.pic import ImageLoader as ffImageLoader, SWScale
from ffpyplayer.tools import set_log_callback, loglevels, get_log_callback
from kivy.logger import Logger
from kivy.core.image import ImageLoaderBase, ImageData, ImageLoader
Logger.info('ImageLoaderFFPy: Using ffpyplayer {}'.format(ffpyplayer.version))
logger_func = {'quiet': Logger.critical, 'panic': Logger.critical,
'fatal': Logger.critical, 'error': Logger.error,
'warning': Logger.warning, 'info': Logger.info,
'verbose': Logger.debug, 'debug': Logger.debug}
def _log_callback(message, level):
message = message.strip()
if message:
logger_func[level]('ImageLoaderFFPy: {}'.format(message))
if not get_log_callback():
set_log_callback(_log_callback)
class ImageLoaderFFPy(ImageLoaderBase):
'''Image loader based on the ffpyplayer library.
.. versionadded:: 1.8.1
.. note:
This provider may support more formats than what is listed in
:meth:`extensions`.
'''
@staticmethod
def extensions():
'''Return accepted extensions for this loader'''
# See https://www.ffmpeg.org/general.html#Image-Formats
return ('bmp', 'dpx', 'exr', 'gif', 'ico', 'jpeg', 'jpg2000', 'jpg',
'jls', 'pam', 'pbm', 'pcx', 'pgm', 'pgmyuv', 'pic', 'png',
'ppm', 'ptx', 'sgi', 'ras', 'tga', 'tiff', 'webp', 'xbm',
'xface', 'xwd')
def load(self, filename):
try:
loader = ffImageLoader(filename)
except:
Logger.warning('Image: Unable to load image <%s>' % filename)
raise
# update internals
self.filename = filename
images = []
while True:
frame, t = loader.next_frame()
if frame is None:
break
images.append(frame)
if not len(images):
raise Exception('No image found in {}'.format(filename))
w, h = images[0].get_size()
ifmt = images[0].get_pixel_format()
if ifmt != 'rgba' and ifmt != 'rgb24':
fmt = 'rgba'
sws = SWScale(w, h, ifmt, ofmt=fmt)
for i, image in enumerate(images):
images[i] = sws.scale(image)
else:
fmt = ifmt if ifmt == 'rgba' else 'rgb'
return [ImageData(w, h, fmt, img.to_memoryview()[0], source_image=img)
for img in images]
# register
ImageLoader.register(ImageLoaderFFPy)

View File

@ -57,9 +57,10 @@ from kivy.properties import StringProperty, ObjectProperty, ListProperty, \
AliasProperty, BooleanProperty, NumericProperty
from kivy.logger import Logger
# delayed imports
# delayed imports
Loader = None
class Image(Widget):
'''Image class, see module documentation for more information.
'''
@ -322,8 +323,8 @@ class AsyncImage(Image):
if not self.is_uri(source):
source = resource_find(source)
self._coreimage = image = Loader.image(source,
nocache=self.nocache,
mipmap=self.mipmap)
nocache=self.nocache, mipmap=self.mipmap,
anim_delay=self.anim_delay)
image.bind(on_load=self._on_source_load)
image.bind(on_texture=self._on_tex_change)
self.texture = image.texture