Webcam->Programm[C]->Ausgabe fehlerhaft



  • Hi,
    Ich wollte mal wieder ein kleines Projekt in Angriff nehmen und zwar die Ansteuerung meiner Webcam mit C. Das Problem ist, dass das ganze unter Ubuntu 8.04 (kernel < 2.6.27) funktionierte, aber seit Ubuntu 8.10, also Kernel 2.6.27, funktioniert es eben nicht mehr. "Funktioniert nicht mehr" heißt, dass das Bild, welches ich erhalte im oberen Teil der reinste Pixelbrei und unten einfach nur schwarz ist. Ich denke, dass das Bild entweder falsch eingelesen wird (weshalb?) oder es etwas mit der Farbtiefe zu tun hat. Die Farbtiefe ist standardmäßig auf 8Bit(/Pixel) eingestellt, was doch 1Byte/Pixel entspricht -> "fwrite( ..., 1, ..., ...);", oder?

    Ausgabe: http://img1.bildupload.com/d2530dadc4bf68d4fbec8e2f1baf0417.jpg

    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>
    #include <linux/videodev.h>
    
    #define GES_LAENGE (352*288)
    
    unsigned char bild[GES_LAENGE];
    
    int main()
    {
        int fd;
        long laenge;
        struct video_window video_win;
        FILE *bilddatei;
    
        if((fd = open("/dev/video0", O_RDONLY)) == -1)
        {
            return 1;
        }
        if( ioctl( fd, VIDIOCGWIN, &video_win) == -1)
        {
            return 1;
        }
        laenge = video_win.width * video_win.height;
        if( laenge > GES_LAENGE)
        {
            return 1;
        }
        if( read( fd, bild, laenge) == -1)
        {
            return 1;
        }
        if((bilddatei = fopen( "bild.ppm", "w+b")) == NULL)
        {
            return 1;
        }
        close(fd);
        fprintf( bilddatei, "P6\n%d %d\n255\n",video_win.width, video_win.height);
        fwrite( bild, 1, video_win.width*video_win.height,bilddatei);
        return 0;
    }
    

    Anzumerken bleibt noch, dass meine Webcam mit anderen Programmen unter Linux( z.B. Cheese) funktioniert.

    Bin für jede Hilfe dankbar!!!

    mfg
    asotbb

    edit by nman: BBCode-Tags aktiviert.



  • Viellicht kommt das Video nicht unkomprimiert, sondern als JPEG-Frame gepackt? (MJPEG lässt grüßen). Dann musst du vorher das Pixel/Bild-Format umstellen..



  • Hi,
    Danke für den Hinweis, so etwas habe ich mir auch schon gedacht, aber leider ist das, zumindest bei meiner Webcam, nicht möglich.

    ...
    struct video_picture video_pict; 
    ...
    ioctl( fd, VIDIOCGPICT, &video_pict);/*Eigenschaften lesen*/
    video_pict.palette = VIDEO_PALETTE_...;/*neue Eigenschaft festlegen*/
    ioctl( fd, VIDIOCSPICT, &video_pict);/*neue Eigenschaften setzen*/
    ...
    

    Mit folgendem Code lässt sich die Palette leider nicht ändern.
    Selbiges gilt mit entsprechendem Code für die Bildtiefe (video_pict.depth).

    Komischerweise ist der Wert von video_pict.palette 0, allerdings sollte der Wert zwischen 1 und 16 liegen, da den VIDEO_PALETTE_...-Flags in "videodev.h" Werte zwischen 1 und 16 zugeordnet wurden.

    Sofern das Umstellen des Pixel/Bild-Formats die einzige Lösung ist, würde ich gerne wissen, ob es sich noch anders umstellen lässt, oder ich das Bild nachträglich umwandeln kann?

    mfg
    asotbb

    edit: Code-Tags…



  • Hi,
    Okay, jetzt habe ich es hinbekommen! Falls es jemanden interessiert:
    Alle open, ioctl, read und close im ersten Code durch v4l1_open, v4l1_ioctl, ... ersetzen.
    So weit so gut. Allerdings brauche ich dann noch folgenden Aufruf: v4l1_ioctl(fd, VIDIOCGPICT, &video_pict); (vor dem Aufruf der read-Funktion). Allerdings will mir nicht einläuchten weshalb, da bei dem Aufruf mit VIDIOCGPICT nur gelesen wird und im Prinzip nichts gemacht wird. Oder irre ich mich?

    mfg
    asotbb



  • Hi,
    ich möchte auch unter Linux meine Webcam auslesen und bin auf diesen Thread gestoßen. Jedoch bekomme ich es noch nicht hin die Webcam auszulesen.

    Mit diesem Code (leicht modifiziert von hier aus dem Thread) erhalte ich folgende Fehlermeldung:

    libv4l2: error converting / decoding frame data: v4l-convert: error destination buffer too small
    
    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>
    #include <libv4l1.h>
    #include <libv4l2.h>
    #include <linux/videodev.h>
    
    #define GES_LAENGE (640*480)
    
    unsigned char  bild[GES_LAENGE];
    
    int main()
    {
            int fd;
            long laenge;
            struct video_window video_win;
            struct video_picture video_pict;
            FILE *bilddatei;
    
            if((fd = v4l1_open("/dev/video0", O_RDONLY)) == -1)
            {
                    printf("Fehler beim Oeffnen von /dev/video0\r\n");
                    return 1;
            }
            if( v4l1_ioctl( fd, VIDIOCGWIN, &video_win) == -1)
            {
                    printf("Fehler beim setzen der Einstellungen\r\n");
                    return 1;
            }
            laenge = video_win.width * video_win.height;
            if( laenge > GES_LAENGE)
            {
                    printf("Bild ist groesser als angegeben\r\n");
                    return 1;
            }
            printf("Länge: %d", laenge);
    
            v4l1_ioctl(fd, VIDIOCGPICT, &video_pict);
    
            if( v4l1_read( fd, bild, laenge) == -1)
            {
                    printf("Auslesen der Kamera nicht möglch\r\n");
                    return 1;
            }
            if((bilddatei = fopen( "bild.ppm", "w+b")) == NULL)
            {
                    printf("Konnte die datei zum schreiben nicht öffnen\r\n");
                    return 1;
            }
            v4l1_close(fd);
            fprintf( bilddatei, "P6\n%d %d\n255\n",video_win.width,
    video_win.height);
            fwrite( bild, 1, video_win.width*video_win.height,bilddatei);
            fclose(bilddatei);
            return 0;
    }
    

    Wenn ich diese Zeile

    v4l1_ioctl(fd, VIDIOCGPICT, &video_pict);
    

    auskommentiere, erhalte ich wie asotbb auch, ein Bild mit Pixelmatsch im oberen Bereich und der rest ist schwarz.

    Kompillieren tue ich mit

    gcc capture.c -o capture -lv4l1 -lv4l2
    

    Wo liegt der Fehler und wo kann ich eine Beschreibung zu der V4L Api finden?



  • Hi,
    Ja, irgendwann hatte sich da mal etwas geändert, was zu dem Fehler geführt hat.
    Ist zwar schon eine Weile her, dass ich mich damit beschäftigt habe, aber wenigstens kann ich mit Quellcode aufwarten, auch wenn ich keine Erklärung mehr dazu bieten kann. (Wenn ich mich recht entsinne, musstest du dir die Eigenschaften deiner Webcam besorgen und sie der Webcam bekannt machen, also an die Webcam zurückschreiben. Irgendwie so war das.)

    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>
    #include <libv4l1.h>
    #include <libv4l2.h>
    #include <linux/videodev.h>
    
    int init_webcam( int *fd, struct video_window *web_win, long *length);
    int take_picture( int fd, int width, int height, unsigned char image[][height][3]);
    int picture_to_file( int width, int height, unsigned char image[][height][3]);
    
    int main()
    {
    	struct video_window web_win;
    	int fd;
    	long length;
    	int i;
    
        if( !init_webcam( &fd, &web_win, &length))
            return 1;
    
    	unsigned char image[web_win.width][web_win.height][3];
    
    	for( i = 0; i < 5; i++)/*take some pictures because the first ones are not useable*/
    	{
    		if( !take_picture( fd, web_win.width, web_win.height, image))
    		{
    			v4l1_close( fd);
    			return 1;
    		}			
    		if( !picture_to_file( web_win.width, web_win.height, image))
    		{
    			v4l1_close( fd);
    			return 1;
    		}
    	}
    	v4l1_close( fd);
    	return 0;
    }
    
    int init_webcam( int *fd, struct video_window *web_win, long *length)
    {
        struct video_capability web_cap;
        struct video_picture web_pict;
    
        if((*fd = v4l1_open("/dev/video0", O_RDONLY)) == -1)/*Open webcam device*/
        {
    		printf( "Unable to open webcam devide\n");
            return 0;
        }
    
        if( v4l1_ioctl( *fd, VIDIOCGPICT, &web_pict) == -1)/*This function call isn't necessary but otherwise you won't get a proper picture*/
        {
    		printf( "Unable to get picture information\n");
            return 0;
        }
        if( ioctl( *fd, VIDIOCGCAP, &web_cap) == -1)/*Get video capabilities*/
        {
    		printf( "Unable to get capabilities\n");
            return 0;
        }
    
        if( v4l1_ioctl( *fd, VIDIOCGWIN, web_win) == -1)/*Get video information*/
        {
    		printf( "Unable to get video information\n");
            return 0;
        }
        web_win->width = web_cap.maxwidth;/*Try to write max solution*/
        web_win->height = web_cap.maxheight;
        if( v4l1_ioctl( *fd, VIDIOCSWIN, web_win) == -1)/*Write new(?!) video information*/
        {
    		printf( "Unable to write video information\n");
            return -1;
        }
        if( v4l1_ioctl( *fd, VIDIOCGWIN, web_win) == -1)/*Read new(?!) video information*/
        {
    		printf( "Unable to get video information\n");
            return 0;
        }
        *length = web_win->width * web_win->height * (web_pict.depth/8);
    
        return 1;
    }
    
    int take_picture( int fd, int width, int height, unsigned char image[][height][3])
    {
        int i, x, y;
        unsigned char picture[width*height*3];
    
        if( v4l1_read(fd, picture, width*height*3) == -1)
        {
            printf( "Error while reading webcam\n");
            return 0;
        }
    	/*1d array to 3d array*/
        for( i = 0, x = 0, y = 0; i < (width*height*3); i+=3, x++)
        {
            if( x == width)
            {
                y++;
                x=0;
            }
            /*bgr to rgb is done here, too*/
    		/*it's possible that you don't need a conversion from brg to rgb*/
            image[x][y][0] = picture[i+2];
            image[x][y][1] = picture[i+1];
            image[x][y][2] = picture[i];
        }
    
        return 1;
    }
    
    int picture_to_file( int width, int height, unsigned char image[][height][3])
    {
    	FILE *imagefile;
    	unsigned char picture[width*height*3];
    	int x, y;
    	int i;
    
    	/*3d array to 1d*/
    	for( i = 0, x = 0, y = 0; i < (width*height*3); i+=3, x++)
        {
            if( x == width)
            {
                y++;
                x=0;
            }
             picture[i] 	= image[x][y][0];
             picture[i+1] 	= image[x][y][1];
             picture[i+2]	= image[x][y][2];
        }
    
    	if((imagefile = fopen( "bild.ppm", "w+b")) == NULL)
    	{
    		    printf("Couldn't open file for writing\n");
    		    return 0;
    	}
    	fprintf( imagefile, "P6\n%d %d\n255\n",width, height);
    	fwrite(picture, 3, width*height, imagefile);
    	fclose(imagefile);
    	return 1;
    }
    

    Wo liegt der Fehler und wo kann ich eine Beschreibung zu der V4L Api finden?

    Naja die Beschreibung der Api findest du hier:
    http://www.linuxtv.org/downloads/video4linux/API/
    (Wahlweise für V4L1 oder V4L2)

    Ich fand die jedoch nicht so berauschend, vor allem die Beispiele waren glaub ich ziemlich happig. Kannst ja mal schauen, ob du daraus schlau wirst.
    Außerdem gibt es ja jede Menge "Webcamprogramme" unter Linux von denen man sich den Quellcode ansehen und inspirieren lassen kann. (Alle oder zumindest die meisten nutzen V4L*)

    Sofern du das Programm noch ausbaust und mit einer zu niedrigen Framerate zu kämpfen hast, solltest du mit dem Prgramm "v4l2ucp", welches unter http://v4l2ucp.sourceforge.net/ zu bekommen ist, "Auto Gain" ausschalten und "exposure" auf ein Minimum reduzieren (updaten danach nicht vergessen), bevor du dein Programm aufrufst. Oder natürlich du machst das dann direkt im Programm.

    mfg
    asotbb



  • Hat das einen besonderen Grund, warum du BBCode in deinen Beiträgen deaktiviert hast? (Das sind die, die dafür sorgen, dass [cpp] etc. auch funktioniert und der Beitrag lesbarer wird)

    (Wenn nicht, dann einfach editieren und unter Optionen das häckchen bei dem Punkt weg machen)



  • Bitte aktivier in Deinem Profil die BBCode-Tags wieder, das ist sonst alles unheimlich mühsam zu lesen. Danke.



  • Hallo,

    auch ich bin auf diesen Thread aufmerksam geworden, konnte aber bislang mit keinem der hier gezeigten Code-Schnipsel etwas erreichen - von dem erwähnten "Pixelmatsch" einmal abgesehen.

    Mir kommt eine Frage, deren Antwort ich hier zu finden hoffe. Da eine bestimmte Information bislang nicht erwähnt wurde, spielt sie entweder keine Rolle oder wird implizit vorausgesetzt: Genügt es, dass die Kamera am PC angeschlossen ist, oder muss auch ein passender Treiber vorhanden sein? Im Handbuch zur Kamera steht verwirrenderweise: "Schnittstelle: Treiberlose USB-2.0-UVC-Technologie" jedoch funktioniert keine der installierten Softwares, z.B. Skype, Ekiga, Cheese, ...
    Eingebunden ist sie als /dev/video1 (zusätzlich gibts noch - vermutlich für das eingebaute Mikrofon - /dev/audio1 und /dev/mixer1).

    `lsusb` zeigt nur: Bus 001 Device 003: ID 18ec:3288

    Muss ich nun erstmal einen passenden Treiber finden? Oder zeigt der Pixelmatsch und die Tatsache, dass das Gerät als /dev/video1 eingebunden ist, dass die Kamera ansprechbar ist und lediglich die hier im Thread gezeigten Code-Schnipsel (noch) nicht korrekt funktionieren?

    Gruß,
    gelignite

    Nachtrag: `cat /dev/video1` liefert seltsamerweise: "cat: /dev/video1: No such device"


Anmelden zum Antworten