@@ -174,10 +174,30 @@ def _stop(self):
174174 fcntl .ioctl (self .vd , VIDIOC_REQBUFS , reqbufs )
175175 self .vd .close ()
176176
177+ def _check_for_picture (self , buf ):
178+ """Check whether the encoded buffer actually contains a picture."""
179+ # At low bitrates, we can get a buffer with an SPS and a PPS but no picture.
180+ # We must avoid writing these to the output. However, an SPS and PPS together
181+ # can't be very large, so assume anything larger than this must be OK:
182+ if len (buf ) > 64 :
183+ return True
184+
185+ # Search the start codes to see if there's a picture here. Start codes are
186+ # always the four bytes 0 0 0 1, and the low nibble of the subsequent byte tells
187+ # us what's we've got.
188+ start_code = b'\x00 \x00 \x00 \x01 ' # H.264 start code sequence
189+ picture_codes = {5 , 1 } # IDR and non-IDR pictures
190+ pos = 0
191+ while (pos := buf .find (start_code , pos )) != - 1 :
192+ pos += 4
193+ if pos < len (buf ) and buf [pos ] & 15 in picture_codes :
194+ return True
195+ return False
196+
177197 def thread_poll (self , buf_available ):
178198 """Outputs encoded frames"""
179199 pollit = select .poll ()
180- pollit .register (self .vd , select .POLLIN )
200+ pollit .register (self .vd , select .POLLIN | select . POLLOUT )
181201
182202 while self ._running or self .buf_frame .qsize () > 0 :
183203 events = pollit .poll (400 )
@@ -194,8 +214,11 @@ def thread_poll(self, buf_available):
194214 queue_item .release ()
195215 break
196216
197- for _ , event in events :
198- if event & select .POLLIN :
217+ for fd_event , event in events :
218+ if fd_event != self .vd .fileno ():
219+ continue
220+
221+ if event & select .POLLOUT :
199222 buf = v4l2_buffer ()
200223 planes = v4l2_plane * VIDEO_MAX_PLANES
201224 planes = planes ()
@@ -208,11 +231,17 @@ def thread_poll(self, buf_available):
208231 if ret == 0 :
209232 buf_available .put (buf .index )
210233
234+ # Release frame from camera
235+ queue_item = self .buf_frame .get ()
236+ queue_item .release ()
237+
238+ if event & select .POLLIN :
211239 buf = v4l2_buffer ()
212240 buf .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
213241 buf .memory = V4L2_MEMORY_MMAP
214242 buf .length = 1
215- ctypes .memset (planes , 0 , ctypes .sizeof (v4l2_plane ) * VIDEO_MAX_PLANES )
243+ planes = v4l2_plane * VIDEO_MAX_PLANES
244+ planes = planes ()
216245 buf .m .planes = planes
217246 ret = fcntl .ioctl (self .vd , VIDIOC_DQBUF , buf )
218247 keyframe = (buf .flags & V4L2_BUF_FLAG_KEYFRAME ) != 0
@@ -224,7 +253,8 @@ def thread_poll(self, buf_available):
224253 # Write output to file
225254 b = self .bufs [buf .index ][0 ].read (buf .m .planes [0 ].bytesused )
226255 self .bufs [buf .index ][0 ].seek (0 )
227- self .outputframe (b , keyframe , (buf .timestamp .secs * 1000000 ) + buf .timestamp .usecs )
256+ if self ._check_for_picture (b ):
257+ self .outputframe (b , keyframe , (buf .timestamp .secs * 1000000 ) + buf .timestamp .usecs )
228258
229259 # Requeue encoded buffer
230260 buf = v4l2_buffer ()
@@ -239,10 +269,6 @@ def thread_poll(self, buf_available):
239269 buf .m .planes [0 ].length = buflen
240270 ret = fcntl .ioctl (self .vd , VIDIOC_QBUF , buf )
241271
242- # Release frame from camera
243- queue_item = self .buf_frame .get ()
244- queue_item .release ()
245-
246272 def _encode (self , stream , request ):
247273 """Encodes a frame
248274
0 commit comments