2

我不太确定为什么我的 C 程序会泄漏,它与set_image_scaled()我很确定的功能有关,并且与我调整图像大小有关。基本上,一旦我用 gphoto2 拍照,我将该文件保存为 jpg,然后我在 GTK 中打开该图片并使用 pixbuf 调整它的大小,然后相应地在显示器上设置图像小部件。我怎样才能解决这个问题?我搞不清楚了。已经玩了几个小时了。我在 raspbian 上使用树莓派。模型 3b+。

这是它给我的错误:

(guiphoto:2344): GdkPixbuf-CRITICAL **: 13:57:26.656: gdk_pixbuf_scale_simple: assertion 'GDK_IS_PIXBUF (src)' failed
**
ERROR:guiphoto.c:94:set_image_scaled: assertion failed (err == NULL): Failed to load image “/media/pi/SD CARD/cam-1_1_b_back.jpg”: Insufficient memory to open TIFF file (gdk-pixbuf-error-quark, 1)
Aborted

不断遇到内存泄漏的有问题的代码在 cam_main 函数中,特别是:

if (front == 1)
    set_image_scaled(front_cams[i], buf);
else
    set_image_scaled(back_cams[i], buf);

所以我相信这与这里的代码和我程序顶部的静态变量有关:

void set_image_scaled(GtkWidget* img, const char* path) {
    pixbuf = gdk_pixbuf_new_from_file(path, &err);
    pxbscaled = gdk_pixbuf_scale_simple(pixbuf, 500, 300, GDK_INTERP_BILINEAR);
    gtk_image_set_from_pixbuf(GTK_IMAGE(img), pxbscaled);
    g_assert_no_error(err);
}

这是我的完整代码:

#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdarg.h>
#include <gphoto2/gphoto2-camera.h>
#include <gphoto2/gphoto2-context.h>
#include <wiringPi.h>
#include <gtk/gtk.h>
#include <pthread.h>

//program
static int running = 1;
//libgphoto2
static CameraList* list;
static Camera** cams;
static GPContext* context;
static const char *name, *value;
static int ret, count;
static int pic = 0;
static int front = 1;
//GTK
static GtkWidget *window, *hbox, *hbox2, *vbox, *button1;
static GtkWidget *front_cams[3];
static GtkWidget *back_cams[3];
static GdkPixbuf *pxbscaled;
static GdkPixbuf *pixbuf;
static GError* err = NULL;

static void button_clicked(GtkWidget *widget, gpointer data) {
    gtk_button_set_label(GTK_BUTTON(button1), "click me 2"); //change button text
}

void *main_gtk() {
    //INIT GTK
    gtk_init(NULL, NULL);

    //SETUP WINDOW
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    //button1=gtk_button_new_with_label("Click me");
    //gtk_button_set_label(GTK_BUTTON(button1), "click me 1");
    g_signal_connect(window,"delete-event", G_CALLBACK(gtk_main_quit), NULL);
    //g_signal_connect(button1, "clicked", G_CALLBACK(button_clicked), NULL);

    //SET WINDOW SIZE AND TITLE
    //gtk_widget_set_size_request(window, 600, 400);
    gtk_window_set_title(GTK_WINDOW(window), "CaptureGui");

    //RESIZE IMAGES
    //image
    front_cams[0] = gtk_image_new();
    front_cams[1] = gtk_image_new();
    front_cams[2] = gtk_image_new();
    back_cams[0] = gtk_image_new();
    back_cams[1] = gtk_image_new();
    back_cams[2] = gtk_image_new();

    //g_print("1");

    //set_image_scaled(front_cams[0], "/media/pi/SD CARD/cam-1_1_a_front.jpg");
    //set_image_scaled(front_cams[1], "/media/pi/SD CARD/cam-1_1_a_front.jpg");
    //set_image_scaled(front_cams[2], "/media/pi/SD CARD/cam-1_1_b_back.jpg");

    //PACK
    hbox = gtk_hbox_new(0, 0);
    gtk_box_pack_start(GTK_BOX(hbox), front_cams[0], 0, 0, 0);
    gtk_box_pack_start(GTK_BOX(hbox), front_cams[1], 0, 0, 0);
    gtk_box_pack_start(GTK_BOX(hbox), front_cams[2], 0, 0, 0);
    gtk_box_pack_start(GTK_BOX(hbox), back_cams[0], 0, 0, 0);
    gtk_box_pack_start(GTK_BOX(hbox), back_cams[1], 0, 0, 0);
    gtk_box_pack_start(GTK_BOX(hbox), back_cams[2], 0, 0, 0);
    gtk_container_add(GTK_CONTAINER(window), hbox);

    //ADD ELEMENTS TO GUI
    //gtk_container_add(GTK_CONTAINER(window), image1);
    //gtk_container_add(GTK_CONTAINER(window), image2);
    //image2 = gtk_image_new_from_file("/media/pi/SD CARD/cam-1_0_b_back.jpg");
    //gtk_container_add(GTK_CONTAINER(window), image2);

    //SHOW GUI
    gtk_widget_show_all(window);
    gtk_main();
}

void set_image_scaled(GtkWidget *img, const char *path) {
    pixbuf = gdk_pixbuf_new_from_file(path, &err);
    pxbscaled = gdk_pixbuf_scale_simple(pixbuf, 500, 300, GDK_INTERP_BILINEAR);
    gtk_image_set_from_pixbuf(GTK_IMAGE(img), pxbscaled);
    g_assert_no_error(err);
}

void *cam_main() {
    while (running == 1) {
        if (digitalRead(4) == 0) {
            printf("taking pics of %s item %i\n", (front == 1) ? "front" : "back", pic);
            for (int i = 0; i < count; i++) {
                int fd, retval;
                CameraFile *file;
                CameraFilePath cfPath;
                strcpy(cfPath.folder, "/");
                strcpy(cfPath.name, "foo1.jpg");
                printf("Capturing cam%i...\n", i + 1);
                int res = gp_camera_capture(cams[i], GP_CAPTURE_IMAGE, &cfPath, context);
                //printf(gp_port_result_as_string(res));
                printf("capture result: %i\n", res);
                //Camera won't take pic if busy and will continue to program end
                char buf[256];
                snprintf(buf, sizeof(buf), "/media/pi/SD CARD/cam-%i_%i_%s.jpg", i + 1, pic, (front == 1) ? "a_front" : "b_back"); //a_ to make front come before back otherwise systems will order incorrectly
                fd = open(buf, O_CREAT | O_WRONLY, 0644);
                retval = gp_file_new_from_fd(&file, fd);
                retval = gp_camera_file_get(cams[i], cfPath.folder, cfPath.name, GP_FILE_TYPE_NORMAL, file, context);
                retval = gp_camera_file_delete(cams[i], cfPath.folder, cfPath.name, context);
                gp_file_free(file);

                if (front == 1)
                    set_image_scaled(front_cams[i], buf);
                else
                    set_image_scaled(back_cams[i], buf);
            }
            if (front == 1)
                front = 0;
            else {
                front = 1;
                pic += 1;
            }
            printf("pics taken...\n");
        }
    }
}

int main(int argc, char **argv) {
    //Kill any processes using cams
    system("pkill -f gphoto2");

    //main_gtk();

    //Wiring pi init
    wiringPiSetupGpio();

    //Init
    context = gp_context_new();

    detect_cams();

    pthread_t logic_thread_handle, gui_thread_handle;
    pthread_create(&logic_thread_handle, NULL, cam_main, NULL);
    pthread_create(&gui_thread_handle, NULL, main_gtk, NULL);
    pthread_join(gui_thread_handle, 0);
    pthread_join(logic_thread_handle, 0);

    //Deinit
    for (int i = 0; i < count; i++) {
        gp_camera_exit(cams[i], context);
        gp_camera_free(cams[i]);
    }
    return 0;
}

void detect_cams() {
    //Detecting all cameras and loading them into mem
        //Detecting all cameras
    ret = gp_list_new(&list);
    if (ret < GP_OK) return 1;
    gp_list_reset(list);
    count = gp_camera_autodetect(list, context);
    if (count < 1) {
        printf("No cameras detected.\n");
        return 1;
    }

    //Open all cameras
    printf("Number of cameras: %d\n", count);
    cams = calloc(sizeof (Camera*), count);
    for (int i = 0; i < count; i++) {
        gp_list_get_name(list, i, &name);
        gp_list_get_value(list, i, &value);
        ret = open_cam(&cams[i], name, value, context);
        if (ret < GP_OK)
            fprintf(stderr, "Camera %s on port %s failed to open\n", name, value);
    }
}

int open_cam(Camera ** camera, const char *model, const char *port, GPContext *context) {
    GPPortInfoList      *portinfolist = NULL;
    CameraAbilitiesList *abilities = NULL;
    int     ret, m, p;
    CameraAbilities a;
    GPPortInfo  pi;

    ret = gp_camera_new (camera);
    if (ret < GP_OK) return ret;

    if (!abilities) {
        /* Load all the camera drivers we have... */
        ret = gp_abilities_list_new (&abilities);
        if (ret < GP_OK) return ret;
        ret = gp_abilities_list_load (abilities, context);
        if (ret < GP_OK) return ret;
    }

    /* First lookup the model / driver */
        m = gp_abilities_list_lookup_model (abilities, model);
    if (m < GP_OK) return ret;
        ret = gp_abilities_list_get_abilities (abilities, m, &a);
    if (ret < GP_OK) return ret;
        ret = gp_camera_set_abilities (*camera, a);
    if (ret < GP_OK) return ret;

    if (!portinfolist) {
        /* Load all the port drivers we have... */
        ret = gp_port_info_list_new (&portinfolist);
        if (ret < GP_OK) return ret;
        ret = gp_port_info_list_load (portinfolist);
        if (ret < 0) return ret;
        ret = gp_port_info_list_count (portinfolist);
        if (ret < 0) return ret;
    }

    /* Then associate the camera with the specified port */
    p = gp_port_info_list_lookup_path (portinfolist, port);
    switch (p) {
      case GP_ERROR_UNKNOWN_PORT:
        fprintf(stderr, "The port you specified "
               "('%s') can not be found. Please "
               "specify one of the ports found by "
               "'gphoto2 --list-ports' and make "
               "sure the spelling is correct "
               "(i.e. with prefix 'serial:' or 'usb:').",
               port);
        break;
      default:
        break;
    }
    if (p < GP_OK) return p;

    ret = gp_port_info_list_get_info (portinfolist, p, &pi);
    if (ret < GP_OK) return ret;
    ret = gp_camera_set_port_info (*camera, pi);
    if (ret < GP_OK) return ret;
    return GP_OK;
}
4

1 回答 1

2

可能很多内存被未发布的 GdkPixbufs 占用。

尝试这个:

void set_image_scaled(GtkWidget *img, const char *path) {
    pixbuf = gdk_pixbuf_new_from_file(path, &err);
    g_assert_no_error(err);
    pxbscaled = gdk_pixbuf_scale_simple(pixbuf, 500, 300, GDK_INTERP_BILINEAR);
    gtk_image_set_from_pixbuf(GTK_IMAGE(img), pxbscaled);
    g_object_unref(pixbuf);
    g_object_unref(pxbscaled);
}

引用计数和内存管理

于 2020-03-21T00:50:38.220 回答