示例#1
0
def save_video_thumbnail(source, output):
    """Saves thumbnail of the given video under the given name"""
    player = MediaPlayer(source, ff_opts={'ss': 1.0})
    frame, val = None, None
    while not frame:
        frame, val = player.get_frame(force_refresh=True)
    player.close_player()
    if val == 'eof':
        return None
    elif frame is None:
        return None
    else:
        img = frame[0]
        pixel_format = img.get_pixel_format()
        img_size = img.get_size()
        thumb_size = 256, int(img_size[1] * 256 / img_size[0])
        codec = 'tiff'
        output_format = get_supported_pixfmts(codec, pixel_format)[0]
        #resize and convert into the best pixel format
        sws = SWScale(img_size[0], img_size[1], pixel_format, thumb_size[0],
                      thumb_size[1], output_format)
        thumbnail = sws.scale(img)
        streams = [{
            'pix_fmt_in': output_format,
            'width_in': thumb_size[0],
            'height_in': thumb_size[1],
            'codec': codec,
            'frame_rate': (30, 1)
        }]
        writer = MediaWriter(output,
                             streams,
                             lib_opts={'compression_algo': 'lzw'})
        writer.write_frame(img=thumbnail, pts=0, stream=0)
        writer.close()
示例#2
0
    def save_image(fname, img, codec='bmp', pix_fmt='', lib_opts={}):
        """Saves the given image to disk in the format requested.

        :param fname: The filename where to save the image.
        :param img: The :class:`ffpyplayer.pic.Image` to save.
        :param codec: The codec to pass to
            :class:`ffpyplayer.writer.MediaWriter` that determines the image
            type. Defaults to 'bmp'.
        :param pix_fmt: The pixel format into which to convert the image before
            saving. If empty, the original pixel format is used. If the
            codec doesn't support the image format, we first convert it to the
            closest supported format.
        :param lib_opts: Any additional `lib_opts` options to pass to
            :class:`ffpyplayer.writer.MediaWriter`.
        :return: The estimated size of the image on disk.
        """
        fmt = img.get_pixel_format()
        w, h = img.get_size()

        if not codec:
            codec = get_format_codec(fname)
            ofmt = get_supported_pixfmts(codec, fmt)[0]
        else:
            ofmt = get_supported_pixfmts(codec, pix_fmt or fmt)[0]
        if ofmt != fmt:
            sws = SWScale(w, h, fmt, ofmt=ofmt)
            img = sws.scale(img)
            fmt = ofmt

        out_opts = {'pix_fmt_in': fmt, 'width_in': w, 'height_in': h,
                    'frame_rate': (30, 1), 'codec': codec}
        writer = MediaWriter(fname, [out_opts], lib_opts=lib_opts)
        size = writer.write_frame(img=img, pts=0, stream=0)
        writer.close()
        return size
示例#3
0
 def get_converted_frame(self):
     if self.first_frame:
         frame = self.first_frame
         self.first_frame = None
     else:
         self.player.set_pause(False)
         frame = None
         while not frame:
             frame, value = self.player.get_frame(force_refresh=False)
             if value == 'eof':
                 return None
         self.player.set_pause(True)
     self.frame_number = self.frame_number + 1
     if self.max_frames:
         if self.frame_number > self.max_frames:
             return None
     frame_image = frame[0]
     frame_size = frame_image.get_size()
     frame_converter = SWScale(frame_size[0],
                               frame_size[1],
                               frame_image.get_pixel_format(),
                               ofmt='rgb24')
     new_frame = frame_converter.scale(frame_image)
     image_data = bytes(new_frame.to_bytearray()[0])
     image = Image.frombuffer(mode='RGB',
                              size=(frame_size[0], frame_size[1]),
                              data=image_data,
                              decoder_name='raw')
     #for some reason, video frames are read upside-down? fix it here...
     image = image.transpose(PIL.Image.FLIP_TOP_BOTTOM)
     if image.mode != 'RGB':
         image = image.convert('RGB')
     image = self.adjust_image(image, preview=False)
     return [image, frame[1]]
    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
        ]
示例#5
0
    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]
示例#6
0
    def process_in_kivy_thread(self, *largs):
        """Processes messages from the client in the kivy thread.
        """
        while self.to_kivy_queue is not None:
            try:
                msg, value = self.to_kivy_queue.get(block=False)

                if msg == 'exception':
                    e, exec_info = value
                    cpl_media.error_callback(e, exc_info=exec_info)
                elif msg == 'exception_exit':
                    e, exec_info = value
                    cpl_media.error_callback(e, exc_info=exec_info)
                    self.stop_all()
                    if self.play_state != 'none':
                        self.complete_stop()
                elif msg == 'started_recording':
                    if self.play_state == 'starting':
                        self.ts_play = self._ivl_start = clock()
                        self._frame_count = 0

                        self.metadata_play_used = VideoMetadata(*value)
                        self.complete_start()
                elif msg == 'stopped_recording':
                    self.stop()
                elif msg == 'stopped_playing':
                    self.complete_stop()
                elif msg == 'image':
                    if self.play_state != 'playing':
                        continue

                    t = clock()
                    if t - self._ivl_start >= 1.:
                        self.real_rate = self._frame_count / (t -
                                                              self._ivl_start)
                        self._frame_count = 0
                        self._ivl_start = t

                    self._frame_count += 1
                    self.frames_played += 1

                    plane_buffers, pix_fmt, size, linesize, metadata = value
                    sws = SWScale(*size, pix_fmt, ofmt=pix_fmt)
                    img = Image(plane_buffers=plane_buffers,
                                pix_fmt=pix_fmt,
                                size=size,
                                linesize=linesize)
                    self.process_frame(sws.scale(img), metadata)
                else:
                    print('Got unknown RemoteVideoPlayer message', msg, value)
            except Empty:
                break
示例#7
0
def test_pic():
    from ffpyplayer.pic import SWScale

    size = w, h = 500, 100
    img = create_image(size)

    assert not img.is_ref()
    assert img.get_size() == (w, h)

    sws = SWScale(w, h, img.get_pixel_format(), ofmt='yuv420p')

    img2 = sws.scale(img)
    assert img2.get_pixel_format() == 'yuv420p'
    planes = img2.to_bytearray()
    assert list(map(len, planes)) == [w * h, w * h / 4, w * h / 4, 0]
示例#8
0
    def test_pic(self):
        from ffpyplayer.pic import Image, SWScale

        size = w, h = 500, 100
        img = self.create_image(size)

        self.assertFalse(img.is_ref())
        self.assertEqual(img.get_size(), (w, h))

        sws = SWScale(w, h, img.get_pixel_format(), ofmt='yuv420p')

        img2 = sws.scale(img)
        self.assertEqual(img2.get_pixel_format(), 'yuv420p')
        planes = img2.to_bytearray()
        self.assertEqual(list(map(len, planes)), [w * h, w * h / 4, w * h / 4, 0])
示例#9
0
    def test_pic(self):
        from ffpyplayer.pic import Image, SWScale

        size = w, h = 500, 100
        img = self.create_image(size)

        self.assertFalse(img.is_ref())
        self.assertEqual(img.get_size(), (w, h))

        sws = SWScale(w, h, img.get_pixel_format(), ofmt='yuv420p')

        img2 = sws.scale(img)
        self.assertEqual(img2.get_pixel_format(), 'yuv420p')
        planes = img2.to_bytearray()
        self.assertEqual(list(map(len, planes)),
                         [w * h, w * h / 4, w * h / 4, 0])
示例#10
0
    def process_in_kivy_thread(self, *largs):
        while self.to_kivy_queue is not None:
            try:
                msg, value = self.to_kivy_queue.get(block=False)

                if msg == 'exception':
                    e, exec_info = value
                    App.get_running_app().handle_exception(
                        e, exc_info=exec_info)
                    self.stop_listener()
                elif msg == 'server_exception':
                    e, exec_info = value
                    App.get_running_app().handle_exception(
                        e, exc_info=exec_info)
                elif msg == 'track_cam_setting':
                    player = knspace.player
                    if player is not None:
                        player.bind_pt_remote_setting(value)
                elif msg == 'get_cam_settings':
                    player = knspace.player
                    if player is not None:
                        self.send_cam_settings('cam_settings', player.get_valid_pt_settings())
                elif msg == 'set_cam_setting':
                    player = knspace.player
                    if player is not None:
                        player.change_pt_setting_opt(*value)
                elif msg == 'reload_cam_setting':
                    player = knspace.player
                    if player is not None:
                        player.reload_pt_setting_opt(value)
                elif msg == 'remote_image':
                    remote_player = App.get_running_app().remote_player
                    plane_buffers, pix_fmt, size, linesize = value
                    sws = SWScale(*size, pix_fmt, ofmt=pix_fmt)
                    img = Image(
                        plane_buffers=plane_buffers, pix_fmt=pix_fmt,
                        size=size, linesize=linesize)
                    remote_player.last_image = sws.scale(img)
                    remote_player.display_trigger()
                else:
                    print('got', msg, value)
            except Empty:
                break
示例#11
0
def play(screen, asciiToNum, videoPath):
    player = MediaPlayer(videoPath)
    screen.nodelay(True)
    while 1:
        frame, val = player.get_frame()

        if val == 'eof':
            break
        elif frame is None:
            time.sleep(0.01)
        else:
            time_bf = time.time()
            c = screen.getch()
            if c == ord('q'):
                break
            img, t = frame
            w, h = img.get_size()
            sws = SWScale(w,
                          h,
                          img.get_pixel_format(),
                          ofmt='yuv420p',
                          ow=w // 8,
                          oh=h // 8)
            img_scaled = sws.scale(img)
            frame_scaled = np.uint8(
                np.array(list(img_scaled.to_bytearray()[0]))).reshape(
                    h // 8, w // 8)
            transformedAscii = transform(frame_scaled, asciiToNum)
            s = arrayToString(transformedAscii)
            time_af = time.time()
            screen.erase()
            screen.addstr(s)
            screen.addstr(str(t))
            screen.refresh()
            time.sleep(0 if 0 > val - (time_af - time_bf) else val -
                       (time_af - time_bf))

    player.close_player()
    def predict_image(self, image):
        fmt = image.get_pixel_format()
        scaler = self.image_scaler

        if fmt != 'gray':
            if scaler is None or fmt != self.last_img_fmt:
                scaler = self.image_scaler = SWScale(*image.get_size(),
                                                     fmt,
                                                     ofmt='gray')
                self.last_img_fmt = fmt
            image = scaler.scale(image)

        buffer = np.frombuffer(image.to_bytearray()[0], dtype=np.uint8)
        w, h = image.get_size()
        buffer = np.reshape(buffer, (h, w))
        #cv2.imshow('Video', buffer)

        buffer = resize(buffer, (100, 200))
        buffer = buffer.flatten()
        buffer = buffer[np.newaxis, :]

        pred = self.clf.predict(buffer)[0]
        return buffer, pred
示例#13
0
文件: __init__.py 项目: cplab/ceed
    def _show_image(config,
                    img,
                    scale=None,
                    translation=None,
                    rotation=None,
                    transform_matrix=None):
        from kivy.graphics.texture import Texture
        from kivy.graphics.fbo import Fbo
        from kivy.graphics import (Mesh, StencilPush, StencilUse, StencilUnUse,
                                   StencilPop, Rectangle, Color)
        from kivy.graphics.context_instructions import (PushMatrix, PopMatrix,
                                                        Rotate, Translate,
                                                        Scale,
                                                        MatrixInstruction,
                                                        BindTexture)
        from kivy.graphics.transformation import Matrix
        img_fmt = img.get_pixel_format()
        img_w, img_h = img.get_size()
        size = config['orig_size']
        pos = config['pos']
        canvas = config['canvas']

        if img_fmt not in ('yuv420p', 'rgba', 'rgb24', 'gray', 'bgr24',
                           'bgra'):
            ofmt = get_best_pix_fmt(
                img_fmt, ('yuv420p', 'rgba', 'rgb24', 'gray', 'bgr24', 'bgra'))
            swscale = SWScale(iw=img_w,
                              ih=img_h,
                              ifmt=img_fmt,
                              ow=0,
                              oh=0,
                              ofmt=ofmt)
            img = swscale.scale(img)
            img_fmt = img.get_pixel_format()

        kivy_ofmt = {
            'yuv420p': 'yuv420p',
            'rgba': 'rgba',
            'rgb24': 'rgb',
            'gray': 'luminance',
            'bgr24': 'bgr',
            'bgra': 'bgra'
        }[img_fmt]

        if kivy_ofmt == 'yuv420p':
            w2 = int(img_w / 2)
            h2 = int(img_h / 2)
            tex_y = Texture.create(size=(img_w, img_h), colorfmt='luminance')
            tex_u = Texture.create(size=(w2, h2), colorfmt='luminance')
            tex_v = Texture.create(size=(w2, h2), colorfmt='luminance')

            with canvas:
                fbo = Fbo(size=(img_w, img_h))
            with fbo:
                BindTexture(texture=tex_u, index=1)
                BindTexture(texture=tex_v, index=2)
                Rectangle(size=fbo.size, texture=tex_y)
            fbo.shader.fs = CeedDataReader._YUV_RGB_FS
            fbo['tex_y'] = 0
            fbo['tex_u'] = 1
            fbo['tex_v'] = 2

            tex = fbo.texture
            dy, du, dv, _ = img.to_memoryview()
            tex_y.blit_buffer(dy, colorfmt='luminance')
            tex_u.blit_buffer(du, colorfmt='luminance')
            tex_v.blit_buffer(dv, colorfmt='luminance')
        else:
            tex = Texture.create(size=(img_w, img_h), colorfmt=kivy_ofmt)
            tex.blit_buffer(img.to_memoryview()[0], colorfmt=kivy_ofmt)
        tex.flip_vertical()

        with canvas:
            StencilPush()
            Rectangle(pos=pos, size=size)
            StencilUse()

            PushMatrix()
            center = pos[0] + size[0] / 2, pos[1] + size[1] / 2
            if rotation:
                Rotate(angle=rotation, axis=(0, 0, 1), origin=center)
            if scale:
                Scale(scale, scale, 1, origin=center)
            if translation:
                Translate(*translation)
            if transform_matrix is not None:
                mat = Matrix()
                mat.set(array=transform_matrix)
                m = MatrixInstruction()
                m.matrix = mat
            Rectangle(size=(img_w, img_h), texture=tex, pos=pos)
            PopMatrix()

            StencilUnUse()
            Rectangle(pos=pos, size=size)
            StencilPop()
示例#14
0
    def update_img(self, img, force=False):
        ''' Updates the screen with a new image.

        :Parameters:

            `img`: :class:`~ffpyplayer.pic.Image` instance
                The image to be displayed.
        '''
        from ffpyplayer.tools import get_best_pix_fmt
        from ffpyplayer.pic import SWScale
        if img is None:
            return

        img_fmt = img.get_pixel_format()
        self.image_size = img_w, img_h = img.get_size()

        update = force
        if self._iw != img_w or self._ih != img_h:
            update = True

        if img_fmt not in ('yuv420p', 'rgba', 'rgb24', 'gray', 'bgr24', 'bgra'):
            swscale = self._swscale
            if img_fmt != self._sw_src_fmt or swscale is None or update:
                ofmt = get_best_pix_fmt(
                    img_fmt, (
                        'yuv420p', 'rgba', 'rgb24', 'gray', 'bgr24', 'bgra'))
                self._swscale = swscale = SWScale(
                    iw=img_w, ih=img_h, ifmt=img_fmt, ow=0, oh=0, ofmt=ofmt)
                self._sw_src_fmt = img_fmt
            img = swscale.scale(img)
            img_fmt = img.get_pixel_format()

        w, h = self.available_size or self.size
        if (not w) or not h:
            self.img = img
            return

        if self._fmt != img_fmt:
            self._fmt = img_fmt
            self._kivy_ofmt = {
                'yuv420p': 'yuv420p', 'rgba': 'rgba', 'rgb24': 'rgb',
                'gray': 'luminance', 'bgr24': 'bgr', 'bgra': 'bgra'}[img_fmt]
            update = True

        if update or w != self._last_w or h != self._last_h or \
                self.rotation != self._last_rotation:
            if self.scale_to_image:
                rotation = self.rotation
                rot = self.rotation * math.pi / 180
                rot_w = abs(img_w * math.cos(rot)) + abs(img_h * math.sin(rot))
                rot_h = abs(img_h * math.cos(rot)) + abs(img_w * math.sin(rot))
                scalew, scaleh = w / rot_w, h / rot_h
                scale = min(min(scalew, scaleh), 1)
                self.transform = Matrix()
                self.rotation = rotation
                self.apply_transform(Matrix().scale(scale, scale, 1),
                                     post_multiply=True)
                self.pos = 0, 0
            self._iw, self._ih = img_w, img_h
            self._last_h = h
            self._last_w = w
            self._last_rotation = self.rotation

        self.img = img
        kivy_ofmt = self._kivy_ofmt

        if update:
            self.canvas.remove_group(str(self) + 'image_display')
            if kivy_ofmt == 'yuv420p':
                w2 = int(img_w / 2)
                h2 = int(img_h / 2)
                self._tex_y = Texture.create(size=(img_w, img_h),
                                             colorfmt='luminance')
                self._tex_u = Texture.create(size=(w2, h2),
                                             colorfmt='luminance')
                self._tex_v = Texture.create(size=(w2, h2),
                                             colorfmt='luminance')
                with self.canvas:
                    self._fbo = fbo = Fbo(size=(img_w, img_h),
                                          group=str(self) + 'image_display')
                with fbo:
                    BindTexture(texture=self._tex_u, index=1)
                    BindTexture(texture=self._tex_v, index=2)
                    Rectangle(size=fbo.size, texture=self._tex_y)
                fbo.shader.fs = BufferImage._YUV_RGB_FS
                fbo['tex_y'] = 0
                fbo['tex_u'] = 1
                fbo['tex_v'] = 2
                tex = self.img_texture = fbo.texture
                fbo.add_reload_observer(self.reload_buffer)
            else:
                tex = self.img_texture = Texture.create(
                    size=(img_w, img_h), colorfmt=kivy_ofmt)
                tex.add_reload_observer(self.reload_buffer)

            tex.flip_vertical()
            if self.flip:
                tex.flip_horizontal()
            self.texture_size = img_w, img_h

        if kivy_ofmt == 'yuv420p':
            dy, du, dv, _ = img.to_memoryview()
            self._tex_y.blit_buffer(dy, colorfmt='luminance')
            self._tex_u.blit_buffer(du, colorfmt='luminance')
            self._tex_v.blit_buffer(dv, colorfmt='luminance')
            self._fbo.ask_update()
            self._fbo.draw()
        else:
            self.img_texture.blit_buffer(img.to_memoryview()[0],
                                         colorfmt=kivy_ofmt)
            self.canvas.ask_update()
示例#15
0
#fmt = 'rgb565le'

buffer_size = 3686400  # get form fb_fix_screeninfo.smem_len
h = buffer_size / line_length
codec = 'png'

file = open(sys.argv[1], "rb")
buf = bytearray(file.read())

img = Image(plane_buffers=[buf], pix_fmt=fmt, size=(w, h))

# make sure the output codec supports the input pixel format type
# otherwise, convert it to the best pixel format
ofmt = get_supported_pixfmts(codec, fmt)[0]
if ofmt != fmt:
    sws = SWScale(w, h, fmt, ofmt=ofmt)
    img = sws.scale(img)
    fmt = ofmt

out_opts = {
    'pix_fmt_in': fmt,
    'width_in': w,
    'height_in': h,
    'frame_rate': (30, 1),
    'codec': codec
}
writer = MediaWriter('output.' + codec, [out_opts])
writer.write_frame(img=img, pts=0, stream=0)
writer.close()

file.close()
示例#16
0
    def reload_edit_image(self):
        """Regenerate the edit preview image."""
        if self.video:
            if not self.player:
                return
            location = self.length * self.position
            frame = self.seek_player(location)
            frame = frame[0]
            frame_size = frame.get_size()
            pixel_format = frame.get_pixel_format()
            frame_converter = SWScale(frame_size[0],
                                      frame_size[1],
                                      pixel_format,
                                      ofmt='rgb24')
            new_frame = frame_converter.scale(frame)
            image_data = bytes(new_frame.to_bytearray()[0])

            original_image = Image.frombuffer(mode='RGB',
                                              size=(frame_size[0],
                                                    frame_size[1]),
                                              data=image_data,
                                              decoder_name='raw')
            #for some reason, video frames are read upside-down? fix it here...
            original_image = original_image.transpose(
                PIL.Image.FLIP_TOP_BOTTOM)
            self.original_width = original_image.size[0]
            self.original_height = original_image.size[1]
            self.original_image = original_image
            image = original_image.copy()

        else:
            original_image = Image.open(self.source)
            try:
                self.exif = original_image.info.get('exif', b'')
            except:
                self.exif = ''
            if self.angle != 0:
                if self.angle == 90:
                    original_image = original_image.transpose(
                        PIL.Image.ROTATE_90)
                if self.angle == 180:
                    original_image = original_image.transpose(
                        PIL.Image.ROTATE_180)
                if self.angle == 270:
                    original_image = original_image.transpose(
                        PIL.Image.ROTATE_270)
            self.original_width = original_image.size[0]
            self.original_height = original_image.size[1]
            image = original_image.copy()
            self.original_image = original_image.copy()
            original_image.close()
        image_width = Window.width * .75
        width = int(image_width)
        height = int(image_width * (image.size[1] / image.size[0]))
        if width < 10:
            width = 10
        if height < 10:
            height = 10
        image = image.resize((width, height))
        if image.mode != 'RGB':
            image = image.convert('RGB')
        self.size_multiple = self.original_width / image.size[0]
        self.edit_image = image
        Clock.schedule_once(
            self.update_histogram
        )  #Need to delay this because kivy will mess up the drawing of it on first load.
#trainer = Trainer(train_path="data/trainer_touch/", test_path="data/tester_touch/")
#trainer.train()
print("loading classifier..")
clf = load('filename.joblib')

print("start video...")
while True:
    frame, val = player.get_frame()
    if val == 'eof':
        break
    elif frame is None:
        time.sleep(0.01)
    else:
        img, t = frame
        fmt = img.get_pixel_format()
        scaler = SWScale(*img.get_size(), fmt, ofmt='gray')
        image = scaler.scale(img)
        #print(val, t, img.get_pixel_format(), img.get_buffer_size())
        buffer = np.frombuffer(image.to_bytearray()[0], dtype=np.uint8)
        w, h = image.get_size()
        buffer = np.reshape(buffer, (h, w))
        #buffer = resize(buffer, (100, 200))
        #bu, pred = trainer.predict_image(img)

        bu = resize(buffer, (100, 200), mode='constant')
        bu = bu.flatten()
        bu = bu[np.newaxis, :]

        pred = clf.predict(bu)[0]

        #pred = 1
示例#18
0
文件: __init__.py 项目: matham/Ceed
    def _show_image(
            config, img, scale=None, translation=None,
            rotation=None, transform_matrix=None):
        from kivy.graphics.texture import Texture
        from kivy.graphics.fbo import Fbo
        from kivy.graphics import (
            Mesh, StencilPush, StencilUse, StencilUnUse, StencilPop, Rectangle,
            Color)
        from kivy.graphics.context_instructions import (
            PushMatrix, PopMatrix, Rotate, Translate, Scale, MatrixInstruction,
            BindTexture)
        from kivy.graphics.transformation import Matrix
        img_fmt = img.get_pixel_format()
        img_w, img_h = img.get_size()
        size = config['orig_size']
        pos = config['pos']
        canvas = config['canvas']

        if img_fmt not in ('yuv420p', 'rgba', 'rgb24', 'gray', 'bgr24', 'bgra'):
            ofmt = get_best_pix_fmt(
                img_fmt, ('yuv420p', 'rgba', 'rgb24', 'gray', 'bgr24', 'bgra'))
            swscale = SWScale(
                iw=img_w, ih=img_h, ifmt=img_fmt, ow=0, oh=0, ofmt=ofmt)
            img = swscale.scale(img)
            img_fmt = img.get_pixel_format()

        kivy_ofmt = {
            'yuv420p': 'yuv420p', 'rgba': 'rgba', 'rgb24': 'rgb',
            'gray': 'luminance', 'bgr24': 'bgr', 'bgra': 'bgra'}[img_fmt]

        if kivy_ofmt == 'yuv420p':
            w2 = int(img_w / 2)
            h2 = int(img_h / 2)
            tex_y = Texture.create(size=(img_w, img_h), colorfmt='luminance')
            tex_u = Texture.create(size=(w2, h2), colorfmt='luminance')
            tex_v = Texture.create(size=(w2, h2), colorfmt='luminance')

            with canvas:
                fbo = Fbo(size=(img_w, img_h))
            with fbo:
                BindTexture(texture=tex_u, index=1)
                BindTexture(texture=tex_v, index=2)
                Rectangle(size=fbo.size, texture=tex_y)
            fbo.shader.fs = CeedDataReader._YUV_RGB_FS
            fbo['tex_y'] = 0
            fbo['tex_u'] = 1
            fbo['tex_v'] = 2

            tex = fbo.texture
            dy, du, dv, _ = img.to_memoryview()
            tex_y.blit_buffer(dy, colorfmt='luminance')
            tex_u.blit_buffer(du, colorfmt='luminance')
            tex_v.blit_buffer(dv, colorfmt='luminance')
        else:
            tex = Texture.create(size=(img_w, img_h), colorfmt=kivy_ofmt)
            tex.blit_buffer(img.to_memoryview()[0], colorfmt=kivy_ofmt)
        tex.flip_vertical()

        with canvas:
            StencilPush()
            Rectangle(pos=pos, size=size)
            StencilUse()

            PushMatrix()
            center = pos[0] + size[0] / 2, pos[1] + size[1] / 2
            if rotation:
                Rotate(angle=rotation, axis=(0, 0, 1), origin=center)
            if scale:
                Scale(scale, scale, 1, origin=center)
            if translation:
                Translate(*translation)
            if transform_matrix is not None:
                mat = Matrix()
                mat.set(array=transform_matrix)
                m = MatrixInstruction()
                m.matrix = mat
            Rectangle(size=(img_w, img_h), texture=tex, pos=pos)
            PopMatrix()

            StencilUnUse()
            Rectangle(pos=pos, size=size)
            StencilPop()