glenn-jocher
commited on
Commit
•
683cefe
1
Parent(s):
f340235
YouTube stream ending fix (#3277)
Browse files* YouTube stream ending fix
Properly terminates YouTube streams on video end. Should resolve issues #2769 and #3220.
* Update datasets.py
- utils/datasets.py +15 -16
utils/datasets.py
CHANGED
@@ -270,7 +270,7 @@ class LoadStreams: # multiple IP or RTSP cameras
|
|
270 |
sources = [sources]
|
271 |
|
272 |
n = len(sources)
|
273 |
-
self.imgs = [None] * n
|
274 |
self.sources = [clean_str(x) for x in sources] # clean source names for later
|
275 |
for i, s in enumerate(sources): # index, source
|
276 |
# Start thread to read frames from video stream
|
@@ -284,13 +284,13 @@ class LoadStreams: # multiple IP or RTSP cameras
|
|
284 |
assert cap.isOpened(), f'Failed to open {s}'
|
285 |
w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
286 |
h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
287 |
-
self.fps = (cap.get(cv2.CAP_PROP_FPS) % 100) or 30.0 # assume 30 FPS if cap gets 0 FPS
|
288 |
-
self.frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
289 |
|
290 |
_, self.imgs[i] = cap.read() # guarantee first frame
|
291 |
-
|
292 |
-
print(f" success ({
|
293 |
-
|
294 |
print('') # newline
|
295 |
|
296 |
# check for common shapes
|
@@ -299,18 +299,17 @@ class LoadStreams: # multiple IP or RTSP cameras
|
|
299 |
if not self.rect:
|
300 |
print('WARNING: Different stream shapes detected. For optimal performance supply similarly-shaped streams.')
|
301 |
|
302 |
-
def update(self,
|
303 |
-
# Read
|
304 |
-
n = 0
|
305 |
-
while cap.isOpened():
|
306 |
n += 1
|
307 |
# _, self.imgs[index] = cap.read()
|
308 |
cap.grab()
|
309 |
-
if n
|
310 |
success, im = cap.retrieve()
|
311 |
-
self.imgs[
|
312 |
-
|
313 |
-
time.sleep(1 / self.fps) # wait time
|
314 |
|
315 |
def __iter__(self):
|
316 |
self.count = -1
|
@@ -318,12 +317,12 @@ class LoadStreams: # multiple IP or RTSP cameras
|
|
318 |
|
319 |
def __next__(self):
|
320 |
self.count += 1
|
321 |
-
|
322 |
-
if cv2.waitKey(1) == ord('q'): # q to quit
|
323 |
cv2.destroyAllWindows()
|
324 |
raise StopIteration
|
325 |
|
326 |
# Letterbox
|
|
|
327 |
img = [letterbox(x, self.img_size, auto=self.rect, stride=self.stride)[0] for x in img0]
|
328 |
|
329 |
# Stack
|
|
|
270 |
sources = [sources]
|
271 |
|
272 |
n = len(sources)
|
273 |
+
self.imgs, self.fps, self.frames, self.threads = [None] * n, [0] * n, [0] * n, [None] * n
|
274 |
self.sources = [clean_str(x) for x in sources] # clean source names for later
|
275 |
for i, s in enumerate(sources): # index, source
|
276 |
# Start thread to read frames from video stream
|
|
|
284 |
assert cap.isOpened(), f'Failed to open {s}'
|
285 |
w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
286 |
h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
287 |
+
self.fps[i] = (cap.get(cv2.CAP_PROP_FPS) % 100) or 30.0 # assume 30 FPS if cap gets 0 FPS
|
288 |
+
self.frames[i] = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) or float('inf') # assume infinite stream if 0 len
|
289 |
|
290 |
_, self.imgs[i] = cap.read() # guarantee first frame
|
291 |
+
self.threads[i] = Thread(target=self.update, args=([i, cap]), daemon=True)
|
292 |
+
print(f" success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)")
|
293 |
+
self.threads[i].start()
|
294 |
print('') # newline
|
295 |
|
296 |
# check for common shapes
|
|
|
299 |
if not self.rect:
|
300 |
print('WARNING: Different stream shapes detected. For optimal performance supply similarly-shaped streams.')
|
301 |
|
302 |
+
def update(self, i, cap):
|
303 |
+
# Read stream `i` frames in daemon thread
|
304 |
+
n, f = 0, self.frames[i]
|
305 |
+
while cap.isOpened() and n < f:
|
306 |
n += 1
|
307 |
# _, self.imgs[index] = cap.read()
|
308 |
cap.grab()
|
309 |
+
if n % 4: # read every 4th frame
|
310 |
success, im = cap.retrieve()
|
311 |
+
self.imgs[i] = im if success else self.imgs[i] * 0
|
312 |
+
time.sleep(1 / self.fps[i]) # wait time
|
|
|
313 |
|
314 |
def __iter__(self):
|
315 |
self.count = -1
|
|
|
317 |
|
318 |
def __next__(self):
|
319 |
self.count += 1
|
320 |
+
if not all(x.is_alive() for x in self.threads) or cv2.waitKey(1) == ord('q'): # q to quit
|
|
|
321 |
cv2.destroyAllWindows()
|
322 |
raise StopIteration
|
323 |
|
324 |
# Letterbox
|
325 |
+
img0 = self.imgs.copy()
|
326 |
img = [letterbox(x, self.img_size, auto=self.rect, stride=self.stride)[0] for x in img0]
|
327 |
|
328 |
# Stack
|