【问题标题】:Vala/Clutter texture loading with thread使用线程加载 Vala/Clutter 纹理
【发布时间】:2013-06-04 13:40:19
【问题描述】:

我试图在运行超时动画时在 vala/clutter 中加载图像文件,当请求文件加载时,使用“image.set_load_async”会停止动画一段时间。这是来源:

// valac --thread --pkg clutter-1.0 --pkg=gio-2.0  test_1.vala -o test_1
using Clutter;
class SlideImage : Clutter.Actor {


    protected Texture image = new Texture ();
    public int loaded = 0;
    public SlideImage (string file) {
        try {
            loaded = 1;
            image.set_load_async (true);
            image.load_finished.connect((t, a) => {
                                            loaded = 2;
                                            this.add_actor (image);
                                            });
            image.set_from_file (file);
        } catch (Error e) {
            warning("Error setting SlideImageReflected gradient : %s", e.message);
        }
    }
}
class ClutterSlideShow {
    protected Stage stage;
    protected int width = 800;
    protected int height =700;
    protected string[] file_names = {};
    private int file_pointer = 0;
    private int counter = 0;
    private SlideImage showA = null;
    private SlideImage showB = null;
    private SlideImage showC = null;
    private SlideImage showD = null;
    private SlideImage showE = null;
    public ClutterSlideShow (string folder) {
        try {
            var directory = File.new_for_path (folder);
            var enumerator = directory.enumerate_children (FileAttribute.STANDARD_NAME,0);
            FileInfo file_info;
            while ((file_info = enumerator.next_file ()) != null) {
                file_names += folder+"/"+file_info.get_name ();
            }
        } catch (Error e) {
            stderr.printf ("Error ClutterSlideShow listing files: %s\n", e.message);
        }
        stage = Stage.get_default ();
        stage.hide.connect (Clutter.main_quit);
        stage.color = Color () { red = 0, green = 0, blue = 0, alpha = 255 };;
        stage.set_size (width, height);
        stage.show_all ();
    }
    protected string get_next_file () {
        file_pointer++;
        if (file_pointer > file_names.length) file_pointer = 1;
        return file_names[file_pointer-1];
    }
    public void start () {
        Timeout.add (15, run);
    }
    private bool run () {
        if (showA == null) {
            showA = new SlideImage (get_next_file ());
            showA.set_x (0);
            showA.set_y (0);
        } else if (showA.loaded == 2) {
            stage.add_actor (showA);
            showA.loaded = 3;
        } else if (showA.loaded == 3) {
            showA.set_y (showA.get_y () + 1);
            counter++;
            if (counter==100) {
                showB = new SlideImage (get_next_file ());
                showB.set_x (100);
                showB.set_y (0);
                stage.add_actor (showB);
                showC = new SlideImage (get_next_file ());
                showC.set_x (200);
                showC.set_y (0);
                stage.add_actor (showC);
                showD = new SlideImage (get_next_file ());
                showD.set_x (300);
                showD.set_y (0);
                stage.add_actor (showD);
                showE = new SlideImage (get_next_file ());
                showE.set_x (400);
                showE.set_y (0);
                stage.add_actor (showE);
            }
        }
        return true;
    }
}
int main (string[] args) {
    if (Thread.supported () == false) {
        stderr.printf ("Threads are not supported!\n");
        return -1;
    }
    var result = init (ref args);
    if (result != Clutter.InitError.SUCCESS) {
        stderr.printf("Error: %s\n", result.to_string());
        return 1;
    }
    var slide_show = new ClutterSlideShow ("/usr/share/backgrounds/");
    slide_show.start ();
    Clutter.main ();
    return 0;
}

我也尝试过使用“线程”,但出现“分段错误(核心转储)”,我不知道如何调试或修复。这是一个例子:

// valac --thread --pkg clutter-1.0 --pkg=gio-2.0  test_2.vala -o test_2
using Clutter;
class SlideImage : Clutter.Actor {
    protected Texture image = new Texture ();
    public int loaded = 0;
    public SlideImage (string file) {
        loaded = 1;
        load_image_in_background.begin(file, (obj, res) => {
            try {
                loaded = 2;
                this.add_actor (image);
            } catch (ThreadError e) {
                string msg = e.message;
                stderr.printf(@"Thread error: $msg\n");
            }
        });
    }
    async void load_image_in_background (string file) throws ThreadError {
        SourceFunc callback = load_image_in_background.callback;
        ThreadFunc<void*> run = () => {
            try {
                // Help ! The next line results in "Segmentation fault"
                image.set_from_file (file);
            } catch (Error e) {
                warning("Error setting SlideImage texture : %s", e.message);
            }
            Idle.add((owned) callback);
            return null;
        };
        Thread.create<void*>(run, false);
        yield;
    }
}
class ClutterSlideShow {
    protected Stage stage;
    protected int width = 800;
    protected int height =700;
    protected string[] file_names = {};
    private int file_pointer = 0;
    private int counter = 0;
    private SlideImage showA = null;
    private SlideImage showB = null;
    private SlideImage showC = null;
    private SlideImage showD = null;
    private SlideImage showE = null;
    public ClutterSlideShow (string folder) {
        try {
            var directory = File.new_for_path (folder);
            var enumerator = directory.enumerate_children (FileAttribute.STANDARD_NAME,0);
            FileInfo file_info;
            while ((file_info = enumerator.next_file ()) != null) {
                file_names += folder+"/"+file_info.get_name ();
            }
        } catch (Error e) {
            stderr.printf ("Error ClutterSlideShow listing files: %s\n", e.message);
        }
        stage = Stage.get_default ();
        stage.hide.connect (Clutter.main_quit);
        stage.color = Color () { red = 0, green = 0, blue = 0, alpha = 255 };;
        stage.set_size (width, height);
        stage.show_all ();
    }
    protected string get_next_file () {
        file_pointer++;
        if (file_pointer > file_names.length) file_pointer = 1;
        return file_names[file_pointer-1];
    }
    public void start () {
        Timeout.add (15, run);
    }
    private bool run () {
        if (showA == null) {
            showA = new SlideImage (get_next_file ());
            showA.set_x (0);
            showA.set_y (0);
        } else if (showA.loaded == 2) {
            stage.add_actor (showA);
            showA.loaded = 3;
        } else if (showA.loaded == 3) {
            showA.set_y (showA.get_y () + 1);
            counter++;
            if (counter==100) {
                showB = new SlideImage (get_next_file ());
                showB.set_x (100);
                showB.set_y (0);
                stage.add_actor (showB);
                showC = new SlideImage (get_next_file ());
                showC.set_x (200);
                showC.set_y (0);
                stage.add_actor (showC);
                showD = new SlideImage (get_next_file ());
                showD.set_x (300);
                showD.set_y (0);
                stage.add_actor (showD);
                showE = new SlideImage (get_next_file ());
                showE.set_x (400);
                showE.set_y (0);
                stage.add_actor (showE);
            }
        }
        return true;
    }
}
int main (string[] args) {
    if (Thread.supported () == false) {
        stderr.printf ("Threads are not supported!\n");
        return -1;
    }
    var result = init (ref args);
    if (result != Clutter.InitError.SUCCESS) {
        stderr.printf("Error: %s\n", result.to_string());
        return 1;
    }
    var slide_show = new ClutterSlideShow ("/usr/share/backgrounds/");
    slide_show.start ();
    Clutter.main ();
    return 0;
}

【问题讨论】:

    标签: c++ multithreading vala


    【解决方案1】:

    执行“停止”的产生有两个原因:

    • 文件加载(可以线程化)
    • 图像/演员创建(不能线程化但改进)

    我得到了专家的帮助(感谢 Victor),下一个代码改进了它:

    • 线程文件加载
    • 将图像缩放到最终的“杂乱”大小

    这是代码:

    /**
     * Build with:
     * valac --thread --pkg clutter-1.0 --pkg gio-2.0 --pkg gdk-3.0 --target-glib=2.32 test_2.vala -o test_2
    */
    
    const string SLIDESHOW_PATH = "/usr/share/backgrounds";
    
    public class SlideImage : Clutter.Actor {
        public bool ready { get; private set; default = false; }
    
        private Clutter.Image image;
        private Thread thread;
    
        public SlideImage (File file, int width, int height) {
            load_image_async.begin (file, width, height, (obj, res) => {
                if (image == null)
                    return;
    
                set_size (width, height);
                set_content_scaling_filters (Clutter.ScalingFilter.TRILINEAR,
                                             Clutter.ScalingFilter.LINEAR);
                set_content_gravity (Clutter.ContentGravity.CENTER);
                set_content (image);
    
                ready = true;
            });
        }
    
        private async void load_image_async (File file, int width, int height) {
            var pixbuf = yield load_pixbuf_from_file_async (file);
    
            if (pixbuf != null) {
                image = new Clutter.Image ();
    
                try {
                    float relation_w = pixbuf.get_width () / width;
                    float relation_h = pixbuf.get_height () / height;
                    float offset_x = 0.0f;
                    float offset_y = 0.0f;
                    float scale = 1.0f;
    
                if (relation_w > relation_h) {
                    scale = (float) height / (float) pixbuf.get_height ();
                    if (pixbuf.get_width () > width)
                        offset_x = -((float) ((pixbuf.get_width () * scale) - width)) / 2.0f;
                    } else {
                        scale = (float) width / (float) pixbuf.get_width ();
                        if (pixbuf.get_height () > height)
                            offset_y = -((float) ((pixbuf.get_height () * scale) - height)) / 2.0f;
                    }
    
                    var pixbuf_scaled = new Gdk.Pixbuf (pixbuf.get_colorspace (),
                                                         pixbuf.get_has_alpha (),
                                                         pixbuf.get_bits_per_sample (),
                                                         width,
                                                         height);
                    pixbuf.scale (pixbuf_scaled, 0, 0, width, height, offset_x, offset_y, scale, scale, Gdk.InterpType.BILINEAR); 
                    image.set_data (pixbuf_scaled.get_pixels (),
                                    pixbuf_scaled.get_has_alpha () ? Cogl.PixelFormat.RGBA_8888 : Cogl.PixelFormat.RGB_888,
                                    pixbuf_scaled.get_width (),
                                    pixbuf_scaled.get_height (),
                                    pixbuf_scaled.get_rowstride ());
                } catch (Error err) {
                    warning ("Could not set image from pixbuf: %s", err.message);
                    image = null;
                }
            }
        }
    
        private async Gdk.Pixbuf? load_pixbuf_from_file_async (File file) {
            SourceFunc callback = load_pixbuf_from_file_async.callback;
            Gdk.Pixbuf? pixbuf = null;
    
            ThreadFunc<void*> thread_func = () => {
                try {
                    pixbuf = new Gdk.Pixbuf.from_file (file.get_path ());
                    message ("loaded pixbuf");
                } catch (Error e) {
                    warning ("Error loading pixbuf: %s", e.message);
                }
    
                Idle.add ((owned) callback);
                return null;
            };
    
            thread = new Thread<void*> ("load-pixbuf-in-background", thread_func);
            yield;
    
            return pixbuf;
        }
    }
    
    public class ClutterSlideShow {
        private const int WIDTH = 800;
        private const int HEIGHT = 600;
    
        private int counter = 0;
        private List<File> files;
        private Clutter.Stage stage;
        private SlideImage showA;
        private SlideImage showB;
        private SlideImage showC;
        private SlideImage showD;
        private SlideImage showE;
    
        public ClutterSlideShow (string folder) {
            load_files (File.new_for_path (folder));
            init_stage ();
        }
    
        public void start () {
            Timeout.add (15, run);
        }
    
        protected File? get_next_file () {
            var file = files.nth_data (0);
    
            if (file != null)
                files.remove (file);
    
            return file;
        }
    
        private void load_files (File directory) {
            files = new List<File> ();
    
            try {
                var enumerator = directory.enumerate_children (FileAttribute.STANDARD_NAME,0);
    
                FileInfo file_info;
    
                while ((file_info = enumerator.next_file ()) != null) {
                    var child_file = directory.get_child (file_info.get_name ());
                        files.prepend (child_file);
                }
            } catch (Error e) {
                warning (e.message);
            }    
        }
    
        private void init_stage () {
            stage = new Clutter.Stage ();
            stage.background_color = Clutter.Color () { red = 0, green = 0, blue = 0, alpha = 255 };
            stage.set_size (WIDTH, HEIGHT);
    
            stage.show ();
    
            stage.hide.connect (Clutter.main_quit);
        }
    
        private bool run () {
            if (showA == null) {
                showA = new SlideImage (get_next_file (), 400, 400);
                showA.x = 0;
                showA.y = 0;
            } else if (showA.get_parent () != stage) {
                stage.add_child (showA);
            } else if (showA.ready) {
                showA.set_y (showA.get_y () + 1);
                counter++;
    
                if (counter == 50) {
                showB = new SlideImage (get_next_file (), 400, 400);
                showB.set_x (100);
                showB.set_y (0);
                stage.add_child (showB);
                showC = new SlideImage (get_next_file (), 400, 400);
                showC.set_x (200);
                showC.set_y (0);
                stage.add_child (showC);
                showD = new SlideImage (get_next_file (), 400, 400);
                showD.set_x (300);
                showD.set_y (0);
                stage.add_child (showD);
                showE = new SlideImage (get_next_file (), 400, 400);
                showE.set_x (400);
                showE.set_y (0);
                stage.add_child (showE);
                }
            }
            return true;
        }
    }
    
    void main (string[] args) {
        var result = Clutter.init (ref args);
    
        if (result != Clutter.InitError.SUCCESS)
            error ("Failed to init clutter: %s", result.to_string ());
    
        var slide_show = new ClutterSlideShow (SLIDESHOW_PATH);
    
        slide_show.start ();
        Clutter.main ();
    }
    

    【讨论】:

    • 只是对线程的评论:Glib/GTK+ 很少需要它,并且使用线程通常是难以调试问题的途径...加载图像也不例外,请参阅stackoverflow.com/questions/10831889异步图片加载示例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-13
    • 2015-04-27
    相关资源
    最近更新 更多