[v4l/v4l2] Arbeitsweise des Buffer Queue



  • Hallo,

    ich habe heute eine Frage zu der v4l/v4l2 Lib. Ich arbeite schon eine Weile mit dieser und ich kann ganz normal Bilder aus einer Webcam auslesen. Eine Sache hat sich mir dabei aber noch nicht so erschlossen. Die Wirkungsweise vom Buffer Queue.

    Also ich kann diesen natürlich verwenden, aber es treten "komische" Phänomene auf.
    Zum 1.) wenn mehrere Webcams angeschlossen sind, können die empfangenen Bilder 1-2 Sekunden nachhängen. Bedeutet ich zeige ein Objekt in die Kamera, dies wird aber erst 1-2 Sekunden später im Bild dargestellt.
    Zum 2.) wenn ich ein Bild aus dem Ringpuffer (Buffer Queue) ziehe scheint dieser immer die gleiche Nummer (Indize) zu haben. z.B. Buffer 0.

    Ok bevor ich gleich noch einiges an Quellcode hier zeige, wollte ich "meinen!" Versuch einer Erklärung kurz darlegen, wie der Buffer Queue funktionieren könnte, damit die beiden oberen Phänomene mit abgedeckt sind.

    Alte Vorstellung zum Buffer Queue (ohne Beachtung der Phänomene):
    Also bisher dachte ich immer der Buffer Queue ist ein Ringpuffer. Heißt ich habe zum Beispiel 5 Buffer mit den Indizes 0 .. 4. Diese werden in einer festen Reihenfolge 0,1,2,3,4,0,1,2,3,4,0, ... je nach fps der Webcam beschrieben. Wenn ich ein Bild abrufe, frage ich zuerst nach dem zuletzt beschriebenen Buffer durch die v4l(2) Lib. Ergebnis ist z.B. Indize 3. Diesen ziehe (dequeue) ich aus dem Ringpuffer heraus, kopiere ihn und stecke (queue) ihn wieder zurück. Somit erhalte ich immer ein aktuelles Bild. Schlussfolgerung ist, ich erhalte immer unterschiedliche Buffer Indizes und ich sehe keine Verzögerung im Bild.

    Dieser Ablauf scheint aber nicht mit den bei mir auftretenden Phänomenen zu passen, deswegen hier ein Ansatz, der passen könnte:
    Nach dem Aufbau des Buffer Queue werden je nach Anzahl z.B. 5 Buffer = 5 Bilder gespeichert. Die v4l(2) Lib macht jetzt nichts weiter, da alle Buffer beschrieben sind. Ich muss nun 1 Buffer herausziehen (dequeue), damit ein neues Bild in den erneut hereingesteckten (queue) Buffer geschrieben werden kann. Wenn ich nun nachfrage, welches der zuletzt beschriebene Buffer ist, erhalte ich immer die selbe Nummer (Indize), da nur noch mit dem zuletzt herausgezogenen Buffer gearbeitet werden kann (wird regelmäßig dequeue und queue). Außerdem wird erst ein neues Bild geschrieben, wenn mit einem Buffer von mir gearbeitet wird. Bedeutet, wenn mein Programm 1-2 Sekunden Arbeitszeit hat, ist das nächste Bild welches ich aus dem Buffer Queue ziehe auch 1-2 Sekunden alt.

    Vieleicht ist hier ja jemand, der mir erklären kann, wie der interne Ablauf des Buffer Queue ist. Wie gesagt, mit dem Ablauf habe ich keine Probleme. Ich kann den Speicher mit mmap erstellen, erstelle den Buffer Queue ohne Fehlermeldungen und auch das dequeue und queue für das kopieren von Speicher funcktioniert.

    Hier aber noch ein wenig Quellecode:
    request buffers

    req.count = V4LCAMERA_BUFFERCOUNT;
        req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        req.memory = V4L2_MEMORY_MMAP;
    
        if (-1 == V4LCAMERA_ioctl(V4LCamera->Handle, VIDIOC_REQBUFS, &req))
        {
            if (EINVAL == errno) 
    		{
    			sprintf(errmsg, "%s does not support memory mapping", V4LCAMERA_Get_DeviceName(V4LCamera));
    			APPLICATION_Set_Error(V4LCamera->Application, V4LCAMERA, errmsg, 184, -10, APPLICATION_ERROR_MESSAGE);
    			V4LCamera->DeviceUseable = 1;
    		}
            else 
            {
            	sprintf(errmsg, "%s VIDIOC_REQBUFS failed", V4LCAMERA_Get_DeviceName(V4LCamera));
    			APPLICATION_Set_Error(V4LCamera->Application, V4LCAMERA, errmsg, 190, -11, APPLICATION_ERROR_MESSAGE);
    			V4LCamera->DeviceUseable = 1;
            }
        }
    

    mmap buffers

    for (i = 0; i < V4LCAMERA_BUFFERCOUNT; ++i)
    	{
            struct v4l2_buffer buf;
    
            CLEAR(buf);
    
            buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            buf.memory      = V4L2_MEMORY_MMAP;
            buf.index       = i;
    
            if (-1 == V4LCAMERA_ioctl(V4LCamera->Handle, VIDIOC_QUERYBUF, &buf))
            {
            	sprintf(errmsg, "%s VIDIOC_QUERYBUF failed", V4LCAMERA_Get_DeviceName(V4LCamera));
    			APPLICATION_Set_Error(V4LCamera->Application, V4LCAMERA, errmsg, 237, -14, APPLICATION_ERROR_MESSAGE);
    			V4LCamera->DeviceUseable = 1;
            } 
    
    		V4LCamera->PictureBuffer[i].s_tLength = buf.length;
            V4LCamera->PictureBuffer[i].pStart = mmap((void*)NULL ,
                          buf.length,
                          PROT_READ,
                          MAP_SHARED,
                          V4LCamera->Handle, buf.m.offset);
    
            if (MAP_FAILED == V4LCamera->PictureBuffer[i].pStart)
            {
            	sprintf(errmsg, "%s mmap failed", V4LCAMERA_Get_DeviceName(V4LCamera));
    			APPLICATION_Set_Error(V4LCamera->Application, V4LCAMERA, errmsg, 243, -15, APPLICATION_ERROR_MESSAGE);
    			V4LCamera->DeviceUseable = 1;
            }
        }
    

    queue buffers

    for (i = 0; i < V4LCAMERA_BUFFERCOUNT; ++i)
    	{
            struct v4l2_buffer buf;
    
            CLEAR(buf);
            buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            buf.memory = V4L2_MEMORY_MMAP;
            buf.index = i;
    
            if (-1 == V4LCAMERA_ioctl(V4LCamera->Handle, VIDIOC_QBUF, &buf))
            {
            	sprintf(errmsg, "%s queue the buffers failed", V4LCAMERA_Get_DeviceName(V4LCamera));
    			APPLICATION_Set_Error(V4LCamera->Application, V4LCAMERA, errmsg, 285, -16, APPLICATION_ERROR_MESSAGE);
    			V4LCamera->DeviceUseable = 1;
            }
        }
    

    Ich hoffe jemand kann mir hier helfen. Wenn nicht werde ich ein Testprogramm schreiben, was aber ein paar Stunden oder vieleicht auch Tage (kann immer nur ein paar Stunden pro Tag hieran arbeiten) dauern wird.

    Vielen Dank

    mirrowwinger


Log in to reply