FpIOCtl kann record nicht schreiben

Antworten
Mathias
Beiträge: 6208
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

FpIOCtl kann record nicht schreiben

Beitrag von Mathias »

Ich bin gerade an einem einfachen Webcam-Versuch dran,
Dafür habe ich eine C-Bibliothek übersetzt und eingebunden, mit dieser funktioniert alles.
Nun wollte ich Befehl für Befehl nach Pascal übernehmen, Dabei musste ich fesstellen, wen ich FpIOCtl() zum auslesen der Parameter und später auch für die Video-Daten verwende, ist alles io. Sobald ich aber FpIOCtl zum schreiben verwende, scheitert es.

Zuerst die zei Code-Schnipsel in C, die eignen sich ideal, da der Set und Get die gleiche struct/record für dir Daten verwenden. Somit scheidet ein Fehler aus, was die Übersetzung der struct zu record betrifft, ansonsten würde mein GetFormat in Pascal nicht funktionieren.

Code: Alles auswählen

// set format
int v4l2_sfmt(int fd, uint32_t pfmt) {
  struct v4l2_format fmt;
  fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  fmt.fmt.pix.pixelformat = pfmt;
  fmt.fmt.pix.height = IMAGE_HEIGHT;
  fmt.fmt.pix.width = IMAGE_WIDTH;
  fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;

  if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) {
    fprintf(stderr, "Unable to set format\n");
    return -1;
  }
  return 0;
}

// get format
int v4l2_gfmt(int fd) {
  struct v4l2_format fmt;
  if (ioctl(fd, VIDIOC_G_FMT, &fmt) == -1) {
    fprintf(stderr, "Unable to get format\n");
    return -1;
  }
  printf("\033[33mpix.pixelformat:\t%c%c%c%c\n\033[0m",
         fmt.fmt.pix.pixelformat & 0xFF, (fmt.fmt.pix.pixelformat >> 8) & 0xFF,
         (fmt.fmt.pix.pixelformat >> 16) & 0xFF,
         (fmt.fmt.pix.pixelformat >> 24) & 0xFF);
  printf("pix.height:\t\t%d\n", fmt.fmt.pix.height);
  printf("pix.width:\t\t%d\n", fmt.fmt.pix.width);
  printf("pix.field:\t\t%d\n", fmt.fmt.pix.field);
  return 0;}
Hier noch meine beiden neuen Pascal-Fuctionen.
Ich habe noch versucht direkt die ioctl() von der clib zu verwenden, aber wie erwartet ohne Erfolg. Lesen geht, Schreiben scheitert.

Code: Alles auswählen

 function ioctl(fd: cint; request: culong): cint; cdecl; varargs; external;  // als Test
 
 function SetFormat(fHandle: cint; pfmt: uint32): cint;
  var
    fmt: Tv4l2_format;
  begin
    WriteLn(SizeOf(fmt));
    WriteLn(SizeOf(fmt.fmt.pix));
    //  FillChar(fmt, SizeOf(fmt), $00);
    //  FillChar(fmt.fmt.pix, SizeOf(fmt.fmt.pix), $00);

    fmt._type := V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.pixelformat := pfmt;
    fmt.fmt.pix.Height := IMAGE_HEIGHT;
    fmt.fmt.pix.Width := IMAGE_WIDTH;
    fmt.fmt.pix.field := V4L2_FIELD_INTERLACED;

    if IOCtl(fHandle, VIDIOC_S_FMT, @fmt) = -1 then begin
      Result := -1;  // Wird nicht ausgelöst, obwohl falsche Daten geschrieben.
      WriteLn('Fehler: SetFormat()');
      Exit;
    end;

    Result := 0;
  end;

  function GetFormat(fHandle: cint): cint;
  var
    fmt: Tv4l2_format;
  begin
    FillChar(fmt, SizeOf(fmt), $00);
    fmt.fmt.pix.Height := 122;
    if IOCtl(fHandle, VIDIOC_G_FMT, @fmt) = -1 then begin
      Result := -1; // Der Fehler kommt hier, wen SetFormat falsch geschrieben hat.
      WriteLn('Fehler: GetFormat()');
      Exit;
    end;
    WriteLn(#27'[33mpix.pixelformatth: ',
      char(fmt.fmt.pix.pixelformat and $FF),
      char(fmt.fmt.pix.pixelformat shr 8 and $FF),
      char(fmt.fmt.pix.pixelformat shr 16 and $FF),
      char(fmt.fmt.pix.pixelformat shr 24 and $FF), #27'[0m');

    WriteLn('pix.width:    ', fmt.fmt.pix.Width);
    WriteLn('pix.height:   ', fmt.fmt.pix.Height);
    WriteLn('pix.field:    ', fmt.fmt.pix.field);

    Result := 0;
  end;
So sieht der Schnipsel im Hauptprogramm aus.
Verwende ich das C-SetFormat, gehen beide GetFormat, und beim Pascal-Setformat, scheitern beide GetFormat.
Was ich noch sagen muss, bei meinem SetFormat wird keine Fehler bei ioctrl ausgespuckt, aber es wird was falsches geschriebn, ansonsten würde ja das GetFormat funktionieren, erst da merke ich, das falsche Daten geschrieben wurden.

Code: Alles auswählen

  
  v4l2_sfmt(video_fildes, V4L2_PIX_FMT_YUYV); // geht
  SetFormat(video_fildes, V4L2_PIX_FMT_YUYV); // geht nicht

  WriteLn(#10#27'[0m--- Pascal ---');
  GetFormat(video_fildes); // geht 
  WriteLn(#10'--- C ---');
  v4l2_gfmt(video_fildes); // geht
Einer eine Idee an was das liegen könnte ?

Das Auslesen später der Daten mit FpIOCtl () geht ohne Probleme.

Code: Alles auswählen

    fpFD_ZERO(fds);
    fpFD_SET(video_fildes, fds);

    fpSelect(video_fildes + 1, @fds, nil, nil, @tv);

    buf._type := V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory := V4L2_MEMORY_MMAP;
    FpIOCtl(video_fildes, VIDIOC_DQBUF, @buf);  
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6216
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: FpIOCtl kann record nicht schreiben

Beitrag von af0815 »

Übrigends, wenn man mit dem Kopf durch die Wand will, geht das ab besten durch die Türe.

Es gibt V4L bereits in Pascal, mit dem man sehr rasch Kameras ansprechen kann. Wenn das schreiben scheitert, dann würde ich es mal mit erhöhten Rechten versuchen. Oft reicht es, wenn man in der richtigen Gruppe ist. Zuerst einmal als root versuchen, wenn das geht, dann schauen ob es nicht eine Gruppe mit Rechten gibt, oder für die App mit setcap die entsprechenden Rechte erweitern.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Mathias
Beiträge: 6208
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: FpIOCtl kann record nicht schreiben

Beitrag von Mathias »

Wenn das schreiben scheitert, dann würde ich es mal mit erhöhten Rechten versuchen. Oft reicht es, wenn man in der richtigen Gruppe ist. Zuerst einmal als root versuchen, wenn das geht, dann schauen ob es nicht eine Gruppe mit Rechten gibt, oder für die App mit setcap die entsprechenden Rechte erweitern.
Ich habe es als Root probiert, aber wie erwartet der gleiche Fehler.
Es hätte mich stark verwundert, da es mit der C-Bibliothek funktioniert.

Kennt jemand ein Beispiel, welches einen record mit fpioctl schreibt. Es muss keinen Zusammenhang mit der Webcam haben. Einfach zum probieren ob es mit fpc geht.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6216
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: FpIOCtl kann record nicht schreiben

Beitrag von af0815 »

Ist da was dabei für dich ? https://github.com/afriess/fpcVideo4L2
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Mathias
Beiträge: 6208
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: FpIOCtl kann record nicht schreiben

Beitrag von Mathias »

Ist da was dabei für dich ? https://github.com/afriess/fpcVideo4L2
Ja teils. ich habe diese Bibliotheken mit meiner kombiniert. Ich hatte meine schön mit Txxx bei den Typen deklariert. DIe andere war ohne das T bei den Typen, Dafür waren dort die wichtigsten #define schon aufgelöst.
Dafür habe ich jetzt folgende Warnung:

Code: Alles auswählen

project1.lpr(76,39) Warning: Range check error while evaluating constants (-1067952623 must be between 0 and 18446744073709551615)
DIe wollte ich beheben bei den Konstanten bei deinem Link, die Warnung war weg, aber dafür ging es nicht mehr.

Die SetFormat und GetFormat konnte ich weglassen, jetzt läuft's. Nur komisch, das die beiden Funktionen in der C-Variante funktionieren, aber in Pascal nicht. Vielleicht hängt dieses Problem mit der Warnung oben zusammen.


Zu ioctl() habe ich noch eine Frage.
In C ist sie folgendermassen deklariert, und zwar mit varargs.

Code: Alles auswählen

extern int ioctl (int __fd, unsigned long int __request, ...) __THROW;  
Bei der Variante von FPC ist dies nicht der Fall.

Code: Alles auswählen

    Function  FpIOCtl      (Handle:cint;Ndx: TIOCtlRequest; Data: Pointer):cint; external name  'FPC_SYSC_IOCTL';
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

sstvmaster
Beiträge: 576
Registriert: Sa 22. Okt 2016, 23:12
OS, Lazarus, FPC: W10, L 2.2.6
CPU-Target: 32+64bit
Wohnort: Dresden

Re: FpIOCtl kann record nicht schreiben

Beitrag von sstvmaster »

Hi Mathias,

hilft dir das eventuell weiter?

https://forum.lazarus.freepascal.org/in ... l#msg96605
LG Maik

Windows 10,
- Lazarus 2.2.6 (stable) + fpc 3.2.2 (stable)
- Lazarus 2.2.7 (fixes) + fpc 3.3.1 (main/trunk)

Mathias
Beiträge: 6208
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: FpIOCtl kann record nicht schreiben

Beitrag von Mathias »

sstvmaster hat geschrieben:
Di 8. Aug 2023, 19:32
Hi Mathias,

hilft dir das eventuell weiter?

https://forum.lazarus.freepascal.org/in ... l#msg96605
Danke, leider nein.
Dort wird ein Integer und kein struct/Record übergeben.

So nebenbei, mit I²C habe ich es schon hingekriegt.

Die SetFormat und GetFormat konnte ich weglassen, jetzt läuft's. Nur komisch, das die beiden Funktionen in der C-Variante funktionieren, aber in Pascal nicht. Vielleicht hängt dieses Problem mit der Warnung oben zusammen.
Da habe ich mich leider getäuscht, als ich in der Zwischenzeit den PC aus hatte, ging es nachher nicht mehr. Anscheinend waren die Parameter in der Kamera gespeichert solange sie unter Strom stand.

Ich vermute, es muss ein Fehler in meinem SetFormat stecken, irgendwas übersehe ich. Aber was ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

_Bernd
Beiträge: 145
Registriert: Di 13. Feb 2007, 11:16

Re: FpIOCtl kann record nicht schreiben

Beitrag von _Bernd »

Hallo,
Mathias hat geschrieben:
Di 8. Aug 2023, 20:03
Ich vermute, es muss ein Fehler in meinem SetFormat stecken, irgendwas übersehe ich. Aber was ?
Ich tippe darauf, dass etwas an dem Record (fmt) nicht passt. Ist der korrekt aufgebaut? Stimmt das Alignment?

Gruß, Bernd.

Mathias
Beiträge: 6208
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: FpIOCtl kann record nicht schreiben

Beitrag von Mathias »

So wie es aussieht, habe ich den Fehler gefunden.
Die Funktion im ursprünglich C-Code scheint fehlerhaft zu sein.
Zufälligerweise, hat es dort funktioniert, weil alte Werte vom SetFormat noch im Stack waren. Vor allem betrifft es fmt.type.
Und dies ging auch nur, weil ich SetFormat und anschliessend gerade GetFormat aufrufte.
Hatte ich fmt.type auf 0 gesetzt, ging es in C auch nicht mehr.

Code: Alles auswählen

  struct v4l2_format fmt;
  fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // neu

  if (ioctl(fd, VIDIOC_G_FMT, &fmt) == -1) {
    fprintf(stderr, "Unable to get format\n");
  }
  printf("\033[33mpix.pixelformat:\t%c%c%c%c\n\033[0m",
         fmt.fmt.pix.pixelformat & 0xFF, (fmt.fmt.pix.pixelformat >> 8) & 0xFF,
         (fmt.fmt.pix.pixelformat >> 16) & 0xFF,
         (fmt.fmt.pix.pixelformat >> 24) & 0xFF);
  printf("pix.width:\t\t%d\n", fmt.fmt.pix.width);
  printf("pix.height:\t\t%d\n", fmt.fmt.pix.height);
  printf("pix.field:\t\t%d\n", fmt.fmt.pix.field);
  printf("pix.sizeimage:\t\t%d\n", fmt.fmt.pix.sizeimage);
  return 0;
}
Pascal-Seitig habe ich es so gelöst und es klappt.

Code: Alles auswählen

function Tv4l2.GetFormat: cint;
var
  fmt: Tv4l2_format;
begin
   fmt._type := V4L2_BUF_TYPE_VIDEO_CAPTURE;

  if FpIOCtl(fHandle, VIDIOC_g_FMT, @fmt) = -1 then begin
    Result := -1;
    WriteLn('Fehler: GetFormat()');
    //    Exit;
  end;
  WriteLn(#27'[33mpix.pixelformatth: ',
    char(fmt.fmt.pix.pixelformat and $FF),
    char(fmt.fmt.pix.pixelformat shr 8 and $FF),
    char(fmt.fmt.pix.pixelformat shr 16 and $FF),
    char(fmt.fmt.pix.pixelformat shr 24 and $FF), #27'[0m');

  WriteLn('pix.width:     ', fmt.fmt.pix.Width);
  WriteLn('pix.height:    ', fmt.fmt.pix.Height);
  WriteLn('pix.field:     ', fmt.fmt.pix.field);
  WriteLn('pix.sizeimage: ', fmt.fmt.pix.sizeimage);

  Result := 0;
end;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten