Testys commited on
Commit
e5303f6
Β·
verified Β·
1 Parent(s): 0534bd0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +41 -27
app.py CHANGED
@@ -139,16 +139,14 @@ CHUNK_FRAME_COUNT = int(VIDEO_FPS * CHUNK_SIZE_SECONDS)
139
  TEMP_VIDEO_FILE = "temp_video_chunk.mp4"
140
 
141
  def process_video_chunk(frame, state_dict):
142
- """
143
- Processes a single frame, adds it to a buffer, and encodes a video chunk
144
- when the buffer is full. Now includes detailed timing logs.
145
- """
146
  if frame is None:
147
  return None, "Status: Inactive", None, state_dict
148
 
149
  # Unpack the state
150
  frame_buffer = state_dict['buffer']
151
  start_time = state_dict['start_time']
 
 
152
 
153
  # If the buffer is empty, this is the first frame of a new chunk. Record start time.
154
  if not frame_buffer:
@@ -165,45 +163,52 @@ def process_video_chunk(frame, state_dict):
165
  level = indic.get("drowsiness_level", "Awake")
166
  lighting = indic.get("lighting", "Good")
167
  score = indic.get("details", {}).get("Score", 0.0)
168
- # The status text is updated on every single frame.
169
- status_txt = f"Lighting: {lighting}\nStatus: {level}\nScore: {score:.2f}"
170
-
171
  audio_payload = alert_manager.trigger_alert(level, lighting)
172
  audio_out = gr.Audio(value=audio_payload, autoplay=True) if audio_payload else None
173
 
174
  # --- Video Buffering Logic ---
175
  frame_buffer.append(processed_frame)
176
 
177
- video_out = None # No video output until the chunk is ready
178
  if len(frame_buffer) >= CHUNK_FRAME_COUNT:
179
- # --- NEW: Logging buffer fill time ---
180
  buffer_fill_time = time.perf_counter() - start_time
181
  logging.info(f"BUFFER: Filled {len(frame_buffer)} frames in {buffer_fill_time:.2f} seconds.")
182
-
183
- # --- NEW: Logging encoding time ---
184
- encoding_start_time = time.perf_counter()
185
 
186
- # Encode the buffer to a video file
187
  h, w, _ = frame_buffer[0].shape
188
  fourcc = cv2.VideoWriter_fourcc(*'mp4v')
189
  writer = cv2.VideoWriter(TEMP_VIDEO_FILE, fourcc, VIDEO_FPS, (w, h))
190
  for f in frame_buffer:
191
  writer.write(f)
192
  writer.release()
193
-
194
  encoding_time = time.perf_counter() - encoding_start_time
195
  logging.info(f"ENCODING: Video chunk encoded in {encoding_time:.2f} seconds.")
 
 
 
 
 
 
196
 
197
- video_out = TEMP_VIDEO_FILE # Set the output to the new video file path
198
- frame_buffer = [] # Clear the buffer for the next chunk
199
- start_time = None # Reset start time
 
 
 
 
200
 
201
  # Pack state back up to return
202
- new_state = {'buffer': frame_buffer, 'start_time': start_time}
 
 
 
 
 
203
 
204
- # Note: Status and Audio are returned on every frame for real-time feedback
205
  return video_out, status_txt, audio_out, new_state
206
 
 
207
  # ───────────────────────────── UI Definition
208
  def create_readme_tab():
209
  """Creates the content for the 'About' tab."""
@@ -284,7 +289,7 @@ def create_detection_tab():
284
  )
285
 
286
  def create_video_experiment_tab():
287
- """Creates the content for the Video Chunk experiment tab."""
288
  with gr.Blocks() as video_tab:
289
  gr.Markdown("## πŸ§ͺ Video Output Experiment")
290
  gr.Markdown(f"This feed buffers processed frames and outputs them as **{CHUNK_SIZE_SECONDS}-second video chunks**. Notice the trade-off between smoothness and latency. Alerts remain real-time.")
@@ -292,20 +297,29 @@ def create_video_experiment_tab():
292
  with gr.Column(scale=2):
293
  cam_video = gr.Image(sources=["webcam"], streaming=True, label="Live Camera Feed")
294
  with gr.Column(scale=1):
295
- out_video = gr.Video(label="Processed Video Chunk")
296
- out_text_video = gr.Textbox(label="Live Status", lines=3, interactive=False)
 
 
297
  out_audio_video = gr.Audio(label="Alert", autoplay=True, visible=False)
298
 
299
- # NEW: State is now a dictionary to hold the buffer and start time
300
- frame_buffer_state = gr.State({'buffer': [], 'start_time': None})
 
 
 
 
 
 
301
 
302
  cam_video.stream(
303
  fn=process_video_chunk,
304
- inputs=[cam_video, frame_buffer_state],
305
- outputs=[out_video, out_text_video, out_audio_video, frame_buffer_state]
306
  )
307
  return video_tab
308
-
 
309
  with gr.Blocks(title="πŸš— Drive Paddy – Drowsiness Detection", theme=gr.themes.Soft()) as app:
310
  gr.Markdown("# πŸš— **Drive Paddy**")
311
  with gr.Tabs():
 
139
  TEMP_VIDEO_FILE = "temp_video_chunk.mp4"
140
 
141
  def process_video_chunk(frame, state_dict):
 
 
 
 
142
  if frame is None:
143
  return None, "Status: Inactive", None, state_dict
144
 
145
  # Unpack the state
146
  frame_buffer = state_dict['buffer']
147
  start_time = state_dict['start_time']
148
+ last_buffer_fill_time = state_dict['last_buffer_fill_time']
149
+ last_encoding_time = state_dict['last_encoding_time']
150
 
151
  # If the buffer is empty, this is the first frame of a new chunk. Record start time.
152
  if not frame_buffer:
 
163
  level = indic.get("drowsiness_level", "Awake")
164
  lighting = indic.get("lighting", "Good")
165
  score = indic.get("details", {}).get("Score", 0.0)
 
 
 
166
  audio_payload = alert_manager.trigger_alert(level, lighting)
167
  audio_out = gr.Audio(value=audio_payload, autoplay=True) if audio_payload else None
168
 
169
  # --- Video Buffering Logic ---
170
  frame_buffer.append(processed_frame)
171
 
172
+ video_out = None
173
  if len(frame_buffer) >= CHUNK_FRAME_COUNT:
 
174
  buffer_fill_time = time.perf_counter() - start_time
175
  logging.info(f"BUFFER: Filled {len(frame_buffer)} frames in {buffer_fill_time:.2f} seconds.")
 
 
 
176
 
177
+ encoding_start_time = time.perf_counter()
178
  h, w, _ = frame_buffer[0].shape
179
  fourcc = cv2.VideoWriter_fourcc(*'mp4v')
180
  writer = cv2.VideoWriter(TEMP_VIDEO_FILE, fourcc, VIDEO_FPS, (w, h))
181
  for f in frame_buffer:
182
  writer.write(f)
183
  writer.release()
 
184
  encoding_time = time.perf_counter() - encoding_start_time
185
  logging.info(f"ENCODING: Video chunk encoded in {encoding_time:.2f} seconds.")
186
+
187
+ video_out = TEMP_VIDEO_FILE
188
+ last_buffer_fill_time = buffer_fill_time
189
+ last_encoding_time = encoding_time
190
+ frame_buffer = []
191
+ start_time = None
192
 
193
+ # --- NEW: Update status text to include buffer/encoding times ---
194
+ status_txt = (
195
+ f"Status: {level} (Score: {score:.2f})\n"
196
+ f"Buffer Fill Time: {last_buffer_fill_time:.2f}s\n"
197
+ f"Video Encode Time: {last_encoding_time:.2f}s"
198
+ )
199
+ logging.info(f"Status: {status_txt}")
200
 
201
  # Pack state back up to return
202
+ new_state = {
203
+ 'buffer': frame_buffer,
204
+ 'start_time': start_time,
205
+ 'last_buffer_fill_time': last_buffer_fill_time,
206
+ 'last_encoding_time': last_encoding_time
207
+ }
208
 
 
209
  return video_out, status_txt, audio_out, new_state
210
 
211
+
212
  # ───────────────────────────── UI Definition
213
  def create_readme_tab():
214
  """Creates the content for the 'About' tab."""
 
289
  )
290
 
291
  def create_video_experiment_tab():
292
+ """Creates the content for the Video Chunk experiment tab - UPDATED."""
293
  with gr.Blocks() as video_tab:
294
  gr.Markdown("## πŸ§ͺ Video Output Experiment")
295
  gr.Markdown(f"This feed buffers processed frames and outputs them as **{CHUNK_SIZE_SECONDS}-second video chunks**. Notice the trade-off between smoothness and latency. Alerts remain real-time.")
 
297
  with gr.Column(scale=2):
298
  cam_video = gr.Image(sources=["webcam"], streaming=True, label="Live Camera Feed")
299
  with gr.Column(scale=1):
300
+ # --- NEW: Use the blank video as the initial value ---
301
+ out_video = gr.Video(label="Processed Video Chunk", value=BLANK_VIDEO_FILE)
302
+ # --- NEW: Textbox is now larger to show more info ---
303
+ out_text_video = gr.Textbox(label="Live Status", lines=4, interactive=False)
304
  out_audio_video = gr.Audio(label="Alert", autoplay=True, visible=False)
305
 
306
+ # --- NEW: State is a dictionary to hold the buffer and timing info ---
307
+ initial_state = {
308
+ 'buffer': [],
309
+ 'start_time': None,
310
+ 'last_buffer_fill_time': 0.0,
311
+ 'last_encoding_time': 0.0
312
+ }
313
+ state = gr.State(initial_state)
314
 
315
  cam_video.stream(
316
  fn=process_video_chunk,
317
+ inputs=[cam_video, state],
318
+ outputs=[out_video, out_text_video, out_audio_video, state]
319
  )
320
  return video_tab
321
+
322
+
323
  with gr.Blocks(title="πŸš— Drive Paddy – Drowsiness Detection", theme=gr.themes.Soft()) as app:
324
  gr.Markdown("# πŸš— **Drive Paddy**")
325
  with gr.Tabs():