-
-
Notifications
You must be signed in to change notification settings - Fork 247
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Bug]: Freezes video thread when processing background thread? #393
Comments
@aronchick The issue you're facing is likely due to the fact that the Possible Solution:To address this, you can try the following approach:
|
Thank you very much for the feedback! I've tried to rework it so that it now spins off a thread into a new pool, but it still freezes every time the model runs. Any suggestions?
|
@aronchick These parameters won't work since you're using a custom frame producer. |
Solution for using CPU Extensive code with WebGear API custom source:@aronchick Here's how you do it properly. I used queues and Separate Video Reading and Model Inference as suggested earlier: # import necessary libs
import uvicorn, asyncio, cv2
from vidgear.gears.asyncio import WebGear
from vidgear.gears.asyncio.helper import reducer
import random
import asyncio
import queue
import threading
class AsyncCPUIntensiveTask:
def __init__(self, max_queue_size=100):
self.queue = queue.Queue(maxsize=max_queue_size)
self.threads = []
self.running = False
async def put_data(self, data):
"""
Add data to the queue.
"""
try:
self.queue.put_nowait(data)
except queue.Full:
print("Queue is full. Waiting for space to become available...")
await self.queue.put(data)
def worker(self):
"""
Worker thread to process data from the queue.
"""
while self.running:
try:
data = self.queue.get(block=False)
except queue.Empty:
continue
else:
# Perform CPU-intensive task with data
result = self._process_data(data)
# Do something with the result
print(f"Result: {result}")
self.queue.task_done()
def _process_data(self, data):
"""
Placeholder for CPU-intensive task.
"""
# Put object detection code and use data(list of frames) for processing
# Simulate CPU-intensive task
# !!! warning remove this code !!!
result = sum(i**2 for i in range(1000000))
return result
def start(self, num_threads=4):
"""
Start worker threads.
"""
self.running = True
for _ in range(num_threads):
thread = threading.Thread(target=self.worker)
thread.start()
self.threads.append(thread)
def stop(self):
"""
Stop worker threads.
"""
self.running = False
for thread in self.threads:
thread.join()
self.threads.clear()
# initialize WebGear app without any source
web = WebGear(logging=True)
async def frames_producer():
# settings = get_settings()
# ml_model_config = settings.get("ml_model_config")
# if ml_model_config["source_video_path"] is None:
# print("No video file found - reloading model config")
# settings.load_model_config()
# ml_model_config = settings.get("ml_model_config")
# number_of_seconds_per_clip = ml_model_config["number_of_seconds_per_clip"]
# FPS = settings.get("FPS")
# I gave some dummy values
number_of_seconds_per_clip = 2
FPS = 30.0
# video_file = ml_model_config["source_video_path"]
video_file = "big_buck_bunny_scene.mp4"
stream = cv2.VideoCapture(video_file)
total_frames = int(stream.get(cv2.CAP_PROP_FRAME_COUNT))
frames_in_current_clip = random.randint(0, total_frames)
stream.set(cv2.CAP_PROP_POS_FRAMES, frames_in_current_clip)
frames_in_current_clip = 0
current_clip_frames = []
task = AsyncCPUIntensiveTask()
task.start() # Start worker threads
# while settings.get_continue_stream():
while True:
(grabbed, frame) = stream.read()
frames_in_current_clip += 1
current_clip_frames.append(frame)
if not grabbed or frames_in_current_clip >= number_of_seconds_per_clip * FPS:
# If not grabbed, assume we're at the end, and start over
if not grabbed:
stream.set(cv2.CAP_PROP_POS_FRAMES, 0)
(grabbed, frame) = stream.read()
print("Starting background task to track video.")
print(f"Frames in current clip: {frames_in_current_clip}")
# put frames list for object detection here
await task.put_data(frames_in_current_clip)
frames_in_current_clip = 0
current_clip_frames = []
continue
# # reducer frames size if you want more performance otherwise comment this line
# frame = await reducer(frame, percentage=50) # reduce frame by 50%
# handle JPEG encoding
encodedImage = cv2.imencode(".jpg", frame)[1].tobytes()
# yield frame in byte format
yield (b"--frame\r\nContent-Type:image/jpeg\r\n\r\n" + encodedImage + b"\r\n")
await asyncio.sleep(1.0 / 30.0)
# close stream
stream.release()
# add your custom frame producer to config
web.config["generator"] = frames_producer
# run this app on Uvicorn server at address http://localhost:8000/
uvicorn.run(web(), host="localhost", port=8000)
# close app safely
web.shutdown() |
@aronchick Put your Object detection and tracking code in this function in above code: def _process_data(self, data):
"""
Placeholder for CPU-intensive task.
"""
# Put object detection code and use data(list of frames) for processing
# Simulate CPU-intensive task
# !!! warning remove this code !!!
result = sum(i ** 2 for i in range(1000000))
return result Goodluck with your project. And thanks a million for the donation. 🥇 |
Description
Love your product! I'm trying to do object detection in the video, and when I run the model thread, it freezes the front most video thread.
Do you have any examples of how to do this properly? Here is my frames_producer function:
Issue Checklist
Expected behaviour
The video stream should keep going with no stutter.
Actual behaviour
The video stream stutters even though the high compute item (
run_model
) is done in the background.Steps to reproduce
Just run the above code where run_model is an intensive process.
Terminal log output
No response
Python Code(Optional)
No response
VidGear Version
0.3.2
Python version
3.10.14
OpenCV version
4.9.0
Operating System version
MacOS Sonoma 14.4.1
Any other Relevant Information?
No
The text was updated successfully, but these errors were encountered: