The following code runs well on python 3.8 on MacOS Big Sur and Windows 10: quits with 'q' and can be re-run many times.
But on Ubuntu 20.04, it does not release webcam resource on 'q' and subsequent runs returns VIDIOC_QBUF: No buffer space available
. The system needs to be hard rebooted to fix this.
If I comment out the line cam_process.terminate()
, then code does not exit on 'q' until CTRL-C
is pressed.
How should I:
- Correct the code with
cam_process.terminate()
to release webcam resource on Ubuntu? - Correct the code to quit properly without
cam_process.terminate()
?
Any technical insights into the why is most appreciated.
Edit: fix f-strings typo errors.
import multiprocessing
import cv2
# Notes:
# 0. Tested on python 3.8 on all platforms.
# 1. Code works fine on MacOS and Windows. Can quit and run many times.
# 2. Code does NOT release webcam on Ubuntu, needs hard reboot!
# Problem caused by line *: cam_process.terminate()
# Subsequent runs gets VIDIOC_QBUF: No buffer space available error
# 3. If comment out line *, then subprocess does not end, needs CTRL-C to break.
def cam_loop(cam_image_queue, msg_queue):
cap = cv2.VideoCapture(0)
while True:
hello, img = cap.read()
cam_image_queue.put(img)
if not msg_queue.empty():
print("got quit msg")
break
print(f"before cap release, isOpened={cap.isOpened()}")
cap.release()
print(f"after cap release, isOpened={cap.isOpened()}")
def main():
cam_image_queue = multiprocessing.Queue()
msg_queue = multiprocessing.Queue()
cam_process = multiprocessing.Process(
target=cam_loop,
args=(cam_image_queue, msg_queue,),
)
print("starting process...")
cam_process.start()
while True:
if cam_image_queue.empty():
continue
img = cam_image_queue.get()
cv2.imshow("from queue", img)
key = cv2.waitKey(1)
if key == ord("q"):
msg_queue.put("quit")
break
print("closing process...")
# using terminate() or close() will hang webcam resource on Ubuntu!
cam_process.terminate() # *
all_done = False
while not all_done:
cam_process.join(1)
if cam_process.exitcode is not None:
all_done = True
else:
print("code=", cam_process.exitcode)
print("after cam_process join")
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
CodePudding user response:
Ok, after working on this for the last 2 hours, I finally got my own answer for 2, to quit properly without cam_process.terminate()
.
The code could not quit properly (hung) because the cam_image_queue
was not empty. It contained the last frame put by the cam_loop
. After I flushed the cam_image_queue
, the program quit gracefully as expected and released the webcam resource properly. It seems Ubuntu is more particular about flushing the queue than MacOS or Windows.
To answer 1: do not call cam_process.terminate()
as it kills the process without releasing resources properly.