@@ -2,3 +2,174 @@ pub mod traits;
2
2
3
3
pub mod mmap;
4
4
pub mod userptr;
5
+
6
+ use std:: { io, mem, ptr, slice, sync:: Arc } ;
7
+
8
+ use v4l2_sys:: { v4l2_buffer, v4l2_format, v4l2_requestbuffers} ;
9
+
10
+ use crate :: buffer;
11
+ use crate :: device:: Handle ;
12
+ use crate :: memory:: { Memory , Mmap , UserPtr } ;
13
+ use crate :: v4l2;
14
+
15
+ /// Manage mapped buffers
16
+ ///
17
+ /// All buffers are unmapped in the Drop impl.
18
+ /// In case of errors during unmapping, we panic because there is memory corruption going on.
19
+ pub ( crate ) struct Arena < T > {
20
+ handle : Arc < Handle > ,
21
+ pub bufs : Vec < T > ,
22
+ pub buf_mem : Memory ,
23
+ pub buf_type : buffer:: Type ,
24
+ }
25
+
26
+ impl < T > Arena < T > {
27
+ fn request ( & mut self , count : u32 ) -> io:: Result < u32 > {
28
+ // free all buffers by requesting 0
29
+ let mut v4l2_reqbufs = v4l2_requestbuffers {
30
+ count,
31
+ type_ : self . buf_type as u32 ,
32
+ memory : self . buf_mem as u32 ,
33
+ ..unsafe { mem:: zeroed ( ) }
34
+ } ;
35
+ unsafe {
36
+ v4l2:: ioctl (
37
+ self . handle . fd ( ) ,
38
+ v4l2:: vidioc:: VIDIOC_REQBUFS ,
39
+ & mut v4l2_reqbufs as * mut _ as * mut std:: os:: raw:: c_void ,
40
+ ) ?;
41
+ }
42
+
43
+ Ok ( v4l2_reqbufs. count )
44
+ }
45
+ }
46
+
47
+ impl < T > Drop for Arena < T > {
48
+ fn drop ( & mut self ) {
49
+ if self . bufs . is_empty ( ) {
50
+ // nothing to do
51
+ return ;
52
+ }
53
+
54
+ // free all buffers by requesting 0
55
+ if let Err ( e) = self . request ( 0 ) {
56
+ if let Some ( code) = e. raw_os_error ( ) {
57
+ // ENODEV means the file descriptor wrapped in the handle became invalid, most
58
+ // likely because the device was unplugged or the connection (USB, PCI, ..)
59
+ // broke down. Handle this case gracefully by ignoring it.
60
+ if code == 19 {
61
+ /* ignore */
62
+ return ;
63
+ }
64
+ }
65
+
66
+ panic ! ( "{:?}" , e)
67
+ }
68
+ }
69
+ }
70
+
71
+ impl < ' a > Arena < Mmap < ' a > > {
72
+ /// Returns a new buffer manager instance
73
+ ///
74
+ /// You usually do not need to use this directly.
75
+ /// A MappedBufferStream creates its own manager instance by default.
76
+ ///
77
+ /// # Arguments
78
+ ///
79
+ /// * `handle` - Device handle to get its file descriptor
80
+ /// * `buf_type` - Type of the buffers
81
+ pub fn new ( handle : Arc < Handle > , buf_type : buffer:: Type ) -> Self {
82
+ Arena {
83
+ handle,
84
+ bufs : Vec :: new ( ) ,
85
+ buf_mem : Memory :: Mmap ,
86
+ buf_type,
87
+ }
88
+ }
89
+
90
+ pub fn allocate ( & mut self , count : u32 ) -> io:: Result < u32 > {
91
+ let count = self . request ( count) ?;
92
+ for index in 0 ..count {
93
+ let mut v4l2_buf = v4l2_buffer {
94
+ index,
95
+ type_ : self . buf_type as u32 ,
96
+ memory : self . buf_mem as u32 ,
97
+ ..unsafe { mem:: zeroed ( ) }
98
+ } ;
99
+ unsafe {
100
+ v4l2:: ioctl (
101
+ self . handle . fd ( ) ,
102
+ v4l2:: vidioc:: VIDIOC_QUERYBUF ,
103
+ & mut v4l2_buf as * mut _ as * mut std:: os:: raw:: c_void ,
104
+ ) ?;
105
+
106
+ let ptr = v4l2:: mmap (
107
+ ptr:: null_mut ( ) ,
108
+ v4l2_buf. length as usize ,
109
+ libc:: PROT_READ | libc:: PROT_WRITE ,
110
+ libc:: MAP_SHARED ,
111
+ self . handle . fd ( ) ,
112
+ v4l2_buf. m . offset as libc:: off_t ,
113
+ ) ?;
114
+
115
+ let slice =
116
+ slice:: from_raw_parts_mut :: < u8 > ( ptr as * mut u8 , v4l2_buf. length as usize ) ;
117
+ self . bufs . push ( Mmap ( slice) ) ;
118
+ }
119
+ }
120
+
121
+ Ok ( count)
122
+ }
123
+ }
124
+
125
+ impl Arena < UserPtr > {
126
+ /// Returns a new buffer manager instance
127
+ ///
128
+ /// You usually do not need to use this directly.
129
+ /// A MappedBufferStream creates its own manager instance by default.
130
+ ///
131
+ /// # Arguments
132
+ ///
133
+ /// * `handle` - Device handle to get its file descriptor
134
+ /// * `buf_type` - Type of the buffers
135
+ pub fn new ( handle : Arc < Handle > , buf_type : buffer:: Type ) -> Self {
136
+ Arena {
137
+ handle,
138
+ bufs : Vec :: new ( ) ,
139
+ buf_mem : Memory :: UserPtr ,
140
+ buf_type,
141
+ }
142
+ }
143
+
144
+ pub fn allocate ( & mut self , count : u32 ) -> io:: Result < u32 > {
145
+ // we need to get the maximum buffer size from the format first
146
+ let mut v4l2_fmt = v4l2_format {
147
+ type_ : self . buf_type as u32 ,
148
+ ..unsafe { mem:: zeroed ( ) }
149
+ } ;
150
+ unsafe {
151
+ v4l2:: ioctl (
152
+ self . handle . fd ( ) ,
153
+ v4l2:: vidioc:: VIDIOC_G_FMT ,
154
+ & mut v4l2_fmt as * mut _ as * mut std:: os:: raw:: c_void ,
155
+ ) ?;
156
+ }
157
+
158
+ #[ cfg( feature = "v4l-sys" ) ]
159
+ eprintln ! (
160
+ "\n ### WARNING ###\n \
161
+ As of early 2020, libv4l2 still does not support USERPTR buffers!\n \
162
+ You may want to use this crate with the raw v4l2 FFI bindings instead!\n "
163
+ ) ;
164
+
165
+ // allocate the new user buffers
166
+ let count = self . request ( count) ?;
167
+ for _ in 0 ..count {
168
+ let size = unsafe { v4l2_fmt. fmt . pix . sizeimage } ;
169
+ let buf = vec ! [ 0u8 ; size as usize ] ;
170
+ self . bufs . push ( UserPtr ( buf) ) ;
171
+ }
172
+
173
+ Ok ( count)
174
+ }
175
+ }
0 commit comments