简体   繁体   English

如何将Kivy转换为视频文件

[英]How to convert kivy to a video file

I wrote a kivy app to render some animation on linux server. 我编写了一个kivy应用程序来在linux服务器上渲染一些动画。 Is there a good way to convert the animation to a video file directly? 是否有直接将动画转换为视频文件的好方法?

Currently I tried Xvfb + ffmpeg approach. 目前,我尝试了Xvfb + ffmpeg的方法。 However it has some issues I want to avoid such as: 但是,它有一些我要避免的问题,例如:

  • ffmpeg will also record the empty x-windows desktop before the animation start. ffmpeg还将在动画开始之前记录空的x-windows桌面。

You can use kivy.uix.widget.Widget.export_to_png in order to save Widget into a image file after every frame and then build a movie using tools like ffmpeg or cv2 library, but that would slow down the animation since saving data to disk tooks time. 您可以使用kivy.uix.widget.Widget.export_to_png ,以便在每帧后将小部件保存到图像文件中,然后使用ffmpegcv2库之类的工具制作电影,但这会减慢动画的速度,因为将数据保存到磁盘需要时间。 So here's an alternative approach: 因此,这是另一种方法:

from functools import partial

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
from kivy.animation import Animation
from kivy.graphics import Fbo, ClearColor, ClearBuffers, Scale, Translate

Builder.load_string('''
<MyWidget>:
    Button:
        size_hint: 0.4, 0.2
        pos_hint: {'center_x' : 0.5, 'center_y' : 0.5}
        text: 'click me'
        on_press: root.click_me(args[0])
''')

class MyWidget(FloatLayout):
    def click_me(self, button, *args):    
        anim = Animation(
            size_hint = (0.8, 0.4)
        )

        textures = []
        anim.bind(on_complete=partial(self.save_video, textures))
        anim.bind(on_progress=partial(self.save_frame, textures))            

        anim.start(button)   

    # modified https://github.com/kivy/kivy/blob/master/kivy/uix/widget.py#L607
    def save_frame(self, textures, *args):
        if self.parent is not None:
            canvas_parent_index = self.parent.canvas.indexof(self.canvas)
            if canvas_parent_index > -1:
                self.parent.canvas.remove(self.canvas)

        fbo = Fbo(size=self.size, with_stencilbuffer=True)

        with fbo:
            ClearColor(0, 0, 0, 1)
            ClearBuffers()
            Scale(1, -1, 1)
            Translate(-self.x, -self.y - self.height, 0)

        fbo.add(self.canvas)
        fbo.draw()
        textures.append(fbo.texture)  # append to array instead of saving to file
        fbo.remove(self.canvas)

        if self.parent is not None and canvas_parent_index > -1:
            self.parent.canvas.insert(canvas_parent_index, self.canvas)

        return True        

    def save_video(self, textures, *args):
        for i, texture in enumerate(textures):
            texture.save("frame{:03}.png".format(i), flipped=False)       

class MyApp(App):
    def build(self):        
        return MyWidget()

if __name__ == '__main__':
    MyApp().run()

I modified export_to_png method so it doesn't try to save the texture into file but instead it appends it into a list. 我修改了export_to_png方法,因此它不尝试将纹理保存到文件中,而是将其附加到列表中。 Then when animation is over, I save all the data into the separate images. 然后,当动画结束时,我将所有数据保存到单独的图像中。 It'd be good to add some kind of "animation is saving..." modal, since during that time application is less responsive. 最好添加某种“动画正在保存...”模式,因为在此期间应用程序的响应速度较慢。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM