Toon posts:

[Linux] Video4Linux I of II

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik ben bezig om een capture applicatie te bouwen in kylix die plaatjes maakt van een ccd camera en die vervolgens opslaat.

Nu werk ik momenteel met kernel 2.4.18 en dus Video4Linux I.

Ik ben zover dat ik informatie kan opvragen en kan instellen (bijv contrast).

Alleen het uitlezen van het plaatje in het geheugen lukt nog niet.

Maar is het zinvoller om over te stappen op Video4Linux II en zo ja waarom?

Is het daar misschien makkelijker mee?

En moet ik dan heel de kernel opnieuw gaan maken?

Verwijderd

Images capturen in video4linux2 is net zo moeilijk als in video4linux1, het is alleen uitgebreider, d.w.z., je kan meerdere types devices aanspreken en hebt ruimere keuze in properties die je kan instellen en type image wat je kan opvragen. Video4linux2 is niet makkelijker, hooguit handzamer. Afhangende van de capturekaart die je gebruikt kan het gebruik van een nieuwere driver (bv. BTTV-0.9.x i.p.v. BTTV-0.7.x) handig zijn (evt. i.c.m. video4linux2), omdat je dan via read() images kan capturen in plaats van via mmap() en queue/sync cycles, en dat vinden mensen vaak wat makkelijker. Dit hangt echter af van de kaart/driver, sommige drivers supporten dit niet, omdat je dan userspace "paged" (i.e. niet fysiek contiguous) memory (mogelijk zelfs swap, dus moet je eerst unswappable maken in VM) gebruikt voor DMA, wat niet alle kaarten supporten - in-kernel memcpy() van interne buffer naar read() buffer is evil, dus geen read().

Laat je code eens zien? Dan zien we ook wel wat er fout mee is.

Verwijderd

Topicstarter
De code die ik tot nu toe heb en waarmee ik dus wel gegevens kan opvragen en instellen maar geen plaatje van kan krijgen:

Kylix code (code = pascal gaf het niet goed weer)
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
unit V4L;

interface

uses
  SysUtils, Types, Classes, Variants, QTypes, Libc, KernelIoctl;

const
  VIDEO_VC_TUNER = 1;
  VIDEO_VC_AUDIO = 2;
  VIDEO_TYPE_TV = 1;
  VIDEO_TYPE_CAMERA = 2;

  VIDEO_MODE_PAL   = 0;
  VIDEO_MODE_NTSC  = 1;
  VIDEO_MODE_SECAM = 2;
  VIDEO_MODE_AUTO  = 3;

  VIDEO_WINDOW_INTERLACE  = 1;
  VIDEO_WINDOW_CHROMAKEY  = 16; // Overlay by chromakey
  VIDEO_CLIP_BITMAP       = -1;
  // bitmap is 1024x625, a '1' bit represents a clipped pixel
  VIDEO_CLIPMAP_SIZE      = (128 * 625);

  VIDEO_PALETTE_GREY      = 1;   // Linear greyscale
  VIDEO_PALETTE_HI240     = 2;   // High 240 cube (BT848)
  VIDEO_PALETTE_RGB565    = 3;   // 565 16 bit RGB
  VIDEO_PALETTE_RGB24     = 4;   // 24bit RGB
  VIDEO_PALETTE_RGB32     = 5;   // 32bit RGB
  VIDEO_PALETTE_RGB555    = 6;   // 555 15bit RGB
  VIDEO_PALETTE_YUV422    = 7;   // YUV422 capture
  VIDEO_PALETTE_YUYV      = 8;   //
  VIDEO_PALETTE_UYVY      = 9;   // The great thing about standards is ...
  VIDEO_PALETTE_YUV420    = 10;  //
  VIDEO_PALETTE_YUV411    = 11;  // YUV411 capture
  VIDEO_PALETTE_RAW       = 12;  // RAW capture (BT848)
  VIDEO_PALETTE_YUV422P   = 13;  // YUV 4:2:2 Planar
  VIDEO_PALETTE_YUV411P   = 14;  // YUV 4:1:1 Planar
  VIDEO_PALETTE_YUV420P   = 15;  // YUV 4:2:0 Planar
  VIDEO_PALETTE_YUV410P   = 16;  // YUV 4:1:0 Planar
  VIDEO_PALETTE_PLANAR    = 13;  // start of planar entries
  VIDEO_PALETTE_COMPONENT = 7;   // start of component entries

type
  PVideo_Capability = ^TVideo_Capability;
  TVideo_Capability = packed record
    Name: array[0..31] of char;
    VideoType: Cardinal;
    Channels: Cardinal;  // Num channels
    Audios: Cardinal;    // Num audio devices
    MaxWidth: Cardinal;  // Supported width
    MaxHeight: Cardinal; // And height
    MinWidth: Cardinal;  // Supported width
    MinHeight: Cardinal; // And height
  end;

  PVideo_Channel = ^TVideo_Channel;
  TVideo_Channel = packed record
    Channel: Cardinal;
    Name: array [0..31] of char;
    Tuners: Cardinal;
    Flags: DWORD;
    ChannelType: WORD;
    Norm: WORD;
  end;

  PVideo_Picture = ^TVideo_Picture;
  TVideo_Picture = packed record
    Brightness: WORD;
    Hue: WORD;
    Colour: WORD;
    Contrast: WORD;
    Whiteness: WORD;   // Black and white only
    Depth: WORD;       // capture depth
    Palette: WORD;     // Palette in use
  end;

  PVideo_Buf = ^TVideo_Buf;
  TVideo_Buf = packed record
    Base: Pointer;
    Height: Cardinal;
    Width: Cardinal;
    Depth: Cardinal;
    BytesPerLine: Cardinal;
  end;

  PVideo_MMap = ^TVideo_MMap;
  TVideo_MMap = packed record
    Frame: Cardinal;  // Frame (0 - n) for double buffer
    Height: Cardinal;
    Width: Cardinal;
    Format: Cardinal; // should be VIDEO_PALETTE_*
  end;

  PVideo_Window = ^TVideo_Window;
  TVideo_Window = packed record
    X: DWORD;            // Position of window
    Y: DWORD;            // Position of window
    Width: DWORD;        // Its size
    Height: DWORD;       // Its size
    Chromakey: DWORD;
    Flags: DWORD;
    Clips: Pointer;      // Set only
    ClipCount: CARDINAL;
  end;


implementation

end.


Test code:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
var fd: integer;
    VIDIOCGCAP, VIDIOCGCHAN, VIDIOCSCHAN: Cardinal;
    VIDIOCGWIN, VIDIOCSWIN: Cardinal;
    VIDIOCGPICT, VIDIOCSPICT: Cardinal;
    VIDIOCCAPTURE, VIDIOCGMBUF: Cardinal;
    VIDIOCMCAPTURE, VIDIOCSYNC: Cardinal;
    VIDIOCGFBUF, VIDIOCSFBUF: Cardinal;
    Video_Channel: PVideo_Channel;
    Video_Capability: PVideo_Capability;
    Video_Window: PVideo_Window;
    Video_Picture: PVideo_Picture;
    Video_Buf: PVideo_Buf;
    Video_MMap: PVideo_MMap;
    map: Pointer;
    X, Y, i: Integer;
    Bitmap: TBitmap;
    R, G, B: Byte;
begin
  VIDIOCGCAP     := __IOR(Ord('v'), 1, SizeOf(TVideo_Capability)); // Get capabilities
  VIDIOCGCHAN    := __IOWR(Ord('v'), 2, SizeOf(TVideo_Channel));   // Get channel info (sources)
  VIDIOCSCHAN    := __IOW(Ord('v'), 3, SizeOf(TVideo_channel));    // Set channel
  VIDIOCGPICT    := __IOR(Ord('v'), 6, SizeOf(TVideo_Picture));    // Get picture properties
  VIDIOCSPICT    := __IOW(Ord('v'), 7, SizeOf(TVideo_picture));    // Set picture properties
  VIDIOCCAPTURE  := __IOW(Ord('v'), 8, SizeOf(Integer));           // Start, end capture */
  VIDIOCGWIN     := __IOR(Ord('v'), 9, SizeOf(TVideo_Window));      // Get the video overlay window
  VIDIOCSWIN     := __IOW(Ord('v'), 10, SizeOf(TVideo_Window));     // Set the video overlay window - passes clip list for hardware smarts
  VIDIOCGFBUF    := __IOR(Ord('v'), 11, SizeOf(TVideo_Buf));       // Get frame buffer
  VIDIOCSFBUF    := __IOW(Ord('v'), 12, SizeOf(TVideo_Buf));       // Set frame buffer - root only
  VIDIOCSYNC     := __IOW(Ord('v'), 18, SizeOf(Integer));        // Sync with mmap grabbing
  VIDIOCMCAPTURE := __IOW(Ord('v'), 19, SizeOf(TVideo_MMap));        // Grab frames
  VIDIOCGMBUF    := __IOR(Ord('v'), 20, SizeOf(TVideo_Buf));      // Memory map buffer info



  // Open the video capture card
  fd := open('/dev/video0', O_RDONLY);


  Video_Capability := AllocMem(SizeOf(Video_Capability^));
  try
    ioctl(fd, VIDIOCGCAP, Video_Capability);
    edt_VideoCapabilityNaam.Text := Video_Capability^.Name;
    edt_VideoCapabilityVideoType.Text := IntToStr(Video_Capability^.VideoType);
    edt_CapChannels.Text := IntToStr(Video_Capability^.Channels);
    edt_CapAudios.Text := IntToStr(Video_Capability^.Audios);
    edt_CapMaxWidth.Text := IntToStr(Video_Capability^.MaxWidth);
    edt_CapMaxHeight.Text := IntToStr(Video_Capability^.MaxHeight);
    edt_CapMinWidth.Text := IntToStr(Video_Capability^.MinWidth);
    edt_CapMinHeight.Text := IntToStr(Video_Capability^.MinHeight);
  finally
    FreeMem(Video_Capability);
  end;



  Video_Channel := AllocMem(SizeOf(Video_Channel^));
  try
    ioctl(fd, VIDIOCGCHAN, Video_Channel);
    edt_VideoChannel.Text := IntToStr(Video_Channel^.Channel);
    edt_VideoNaam.Text := Video_Channel^.Name;
    edt_VideoTuners.Text := IntToStr(Video_Channel^.Tuners);
    edt_VideoFlags.Text := IntToStr(Video_Channel^.Flags);
    edt_VideoChannelType.Text := IntToStr(Video_Channel^.ChannelType);
    edt_VideoNorm.Text := IntToStr(Video_Channel^.Norm);


    Video_Channel^.Channel := 1;
    // The next line sets no tuners and no audio for the channel
    Video_Channel^.flags := 0;
    Video_Channel^.Name := 'Composite1';

    // The next line sets input type to be of type camera
    Video_Channel^.ChannelType := VIDEO_TYPE_CAMERA;

    // NTSC is an American standard.  Some European countries use PAL
    Video_Channel^.Norm := VIDEO_MODE_PAL;

    // Set the new settings
    ioctl(fd, VIDIOCSCHAN, Video_Channel);


    edt_VideoChannel.Text := IntToStr(Video_Channel^.Channel);
    edt_VideoNaam.Text := Video_Channel^.Name;
    edt_VideoTuners.Text := IntToStr(Video_Channel^.Tuners);
    edt_VideoFlags.Text := IntToStr(Video_Channel^.Flags);
    edt_VideoChannelType.Text := IntToStr(Video_Channel^.ChannelType);
    edt_VideoNorm.Text := IntToStr(Video_Channel^.Norm);
  finally
    FreeMem(Video_Channel);
  end;


  // Set the properties of the image window where the image
  // will be captured.
  Video_Window := AllocMem(SizeOf(Video_Window^));
  try
    ioctl(fd, VIDIOCGWIN, Video_Window);
    Video_Window^.X := 0;
    Video_Window^.Y := 0;
    Video_Window^.Chromakey := 0; // not used
    Video_Window^.Width := 640;
    Video_Window^.Height := 480;
    Video_Window^.Flags := 0; // not used
    Video_Window^.Clips := nil;
    ioctl(fd, VIDIOCSWIN, Video_Window^);
  finally
    FreeMem(Video_Window);
  end;


  // Set the properties of the image to be captured
  Video_Picture := AllocMem(SizeOf(Video_Picture^));
  try
    ioctl(fd, VIDIOCGPICT, Video_Picture);
    Video_Picture^.Depth := 24;  // use 24 for color or 8 for b&w */
    Video_Picture^.Palette := VIDEO_PALETTE_RGB24;
    Video_Picture^.Brightness := 24000; //32767;
    Video_Picture^.Hue := 24000; //32767;
    Video_Picture^.Colour := 24000; //32767;
    Video_Picture^.Contrast := 24000; //32767;
    Video_Picture^.Whiteness := 24000; //32767;
    ioctl(fd, VIDIOCSPICT, Video_Picture^);
  finally
    FreeMem(Video_Picture);
  end;

  // Determine size of card memory to map to user space
  Video_Buf := AllocMem(SizeOf(Video_Buf^));
  ioctl(fd, VIDIOCGMBUF, Video_Buf);
  // For simple image grabbing, do not consider the frames and
  // offsets field of m_buf

  // Map video capture card memory to user space memory
  map := mmap(nil, SizeOf(Video_Buf^), PROT_READ, MAP_SHARED, fd, 0);
  { PROT_READ specifies that the memory mapped will only be read from.
    MAP_SHARED specifies that a change to the video memory will change
    the user space memory
    A good description of mmap() is available at
    http://www.opengroup.org/onlinepubs/7908799/xsh/mmap.html
  }


  // Set the capture parameters for the mapped area
  Video_MMap := AllocMem(SizeOf(Video_MMap^));
  Video_MMap.Frame := 0;
  Video_MMap.Width := 640;
  Video_MMap.Height := 480;
  Video_MMap.Format := VIDEO_PALETTE_RGB24;

  // Capture a frame from the camera
  ioctl(fd, VIDIOCMCAPTURE, Video_MMap);

  // Wait for end of frame
  ioctl(fd, VIDIOCSYNC, Video_MMap);


  Bitmap := TBitmap.Create;
  try
    Bitmap.Width := 640;
    Bitmap.Height := 480;

    i := Integer(map);
    for y := 0 to 479 do
    begin
      for x := 0 to 639 do
      begin
        R := Byte(Ptr(i + 2)^);
        G := Byte(Ptr(i + 1)^);
        B := Byte(Ptr(i)^);
        //Memo1.Lines.Text := Memo1.Lines.Text + 'R=' + IntToStr(R) + ' ';
        //Memo1.Lines.Text := Memo1.Lines.Text + 'G=' + IntToStr(G) + ' ';
        //Memo1.Lines.Text := Memo1.Lines.Text + 'B=' + IntToStr(B) + ' ';

        Bitmap.Canvas.Pixels[X, Y] := TColor((B * 65536) + (G * 256) + R);

        i := i + 3;
      end;
    end;

    Image1.Canvas.Draw(0, 0, Bitmap);
  finally
    Bitmap.Free;
  end;

  FreeMem(Video_Buf);
  FreeMem(Video_MMap);

end;

Verwijderd

Verwijderd schreef op 28 February 2003 @ 15:20:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  // Determine size of card memory to map to user space
  Video_Buf := AllocMem(SizeOf(Video_Buf^));
  ioctl(fd, VIDIOCGMBUF, Video_Buf);
  // For simple image grabbing, do not consider the frames and
  // offsets field of m_buf

  // Map video capture card memory to user space memory
  map := mmap(nil, SizeOf(Video_Buf^), PROT_READ, MAP_SHARED, fd, 0);
  { PROT_READ specifies that the memory mapped will only be read from.
    MAP_SHARED specifies that a change to the video memory will change
    the user space memory
    A good description of mmap() is available at
    http://www.opengroup.org/onlinepubs/7908799/xsh/mmap.html
  }
Tweede argument in mmap() moet de size zijn, dus Video_Buf.size. Nu is je buffer ongeveer 20 byte groot oid.

Je checkt niet overal return values, heb ik het idee, dan zag je dit zelf ook wel in de return values. ;).

Verwijderd

Topicstarter
Verwijderd schreef op 28 February 2003 @ 17:09:Tweede argument in mmap() moet de size zijn, dus video_Buf.size. Nu is je buffer ongeveer 20 byte groot oid.
Wat is die size dan? Video_Buf heeft geen property size.

Verwijderd

code:
1
2
3
4
5
6
struct video_mbuf
{
        int     size;           /* Total memory to map */
        int     frames;         /* Frames */
        int     offsets[VIDEO_MAX_FRAME];
};


[edit]

Ik zie zojuist dat je Video_Buf gebruikt - is dat wel video_mbuf (argument van VIDIOCGMBUF)? Nogmaals, check de return values van je ioctl()s, dan zie je dit soort dingen veel eerder.

[ Voor 35% gewijzigd door Verwijderd op 28-02-2003 19:25 ]


Verwijderd

Topicstarter
Inderdaad waarschijnlijk een domme fout van mij. Ik heb de verkeerde structure/record gebruikt denk ik.

Maar ik ga dit maandag proberen op mijn werk.

Alvast bedankt en ik laat het maandag weten of het gelukt is.

Verwijderd

Topicstarter
Beelzebubu bedankt.

Ik heb inmiddels een plaatje op mijn formulier.

Er zijn nog wel een aantal dingen die gedaan moeten worden, maar dat komt nog wel goed.
Pagina: 1