Vala/Clutter texture loading with thread

有些话、适合烂在心里 提交于 2019-12-25 04:15:37

问题


I am trying to load image files in vala/clutter while running a timeout animation, using "image.set_load_async" stops the animation for a while when the file loads are requested. This is the source:

// 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;
}

I have also tried to use "threads" but I get a "Segmentation fault (core dumped)" that I don't know how to debug or fix. This is the example:

// 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;
}

回答1:


The execution "stop" is produced due two reasons:

  • The file load (can be threaded)
  • The image/actor creation (can't be threaded but improved)

I received help from an expert (thanks Victor), the next code improves it with:

  • Threads the file load
  • Scales the image to its final "clutter" size

This is the code:

/**
 * 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 ();
}


来源:https://stackoverflow.com/questions/16919447/vala-clutter-texture-loading-with-thread

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!