vericudebuget commited on
Commit
3a24bc8
·
verified ·
1 Parent(s): a82ac88

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +97 -101
app.py CHANGED
@@ -1,111 +1,107 @@
1
- import time
2
- import cv2
3
- import numpy as np
4
  import streamlit as st
5
- from streamlit_webrtc import webrtc_streamer, WebRtcMode, VideoTransformerBase
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
- # Set wide layout and page title
8
- st.set_page_config(page_title="Live Stream Broadcast", layout="wide")
 
 
9
 
10
- # -----------------------------------------------------------------------------
11
- # Custom CSS: Hide the timeline parts of the video controls (works in WebKit‑based browsers)
12
- st.markdown(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  """
14
- <style>
15
- video::-webkit-media-controls-timeline {
16
- display: none !important;
17
- }
18
- video::-webkit-media-controls-current-time-display {
19
- display: none !important;
20
- }
21
- video::-webkit-media-controls-time-remaining-display {
22
- display: none !important;
23
- }
24
- </style>
25
- """,
26
- unsafe_allow_html=True,
27
- )
28
- # -----------------------------------------------------------------------------
29
- st.title("Live Streaming Space")
30
 
31
- # -----------------------------------------------------------------------------
32
- # A simple video transformer that “buffers” frames for 3 seconds.
33
- # (In a more complex app you might encode these frames into a video segment file.)
34
- class BufferingTransformer(VideoTransformerBase):
35
- def __init__(self):
36
- self.buffer = [] # List to hold frames
37
- self.buffer_duration = 3.0 # Buffer duration in seconds
38
- self.last_flush_time = time.time()
 
39
 
40
- def transform(self, frame):
41
- # Convert the frame (a VideoFrame object) into a NumPy array (BGR format)
42
- img = frame.to_ndarray(format="bgr24")
43
- self.buffer.append(img)
44
- now = time.time()
45
- if now - self.last_flush_time >= self.buffer_duration:
46
- # Here you could (for example) encode/store the buffered frames.
47
- # For this demo we just clear the buffer every 3 seconds.
48
- self.buffer = []
49
- self.last_flush_time = now
50
- # Return the image unchanged for display
51
- return img
52
 
53
- # -----------------------------------------------------------------------------
54
- # Sidebar: Password input for broadcasting. Only if you enter the correct password
55
- # ("test123") do you get access to the broadcast controls.
56
- password = st.sidebar.text_input("Enter broadcasting password", type="password")
57
- if password == "test123":
58
- st.sidebar.success("Authenticated for broadcasting!")
59
- broadcast_mode = True
60
- else:
61
- broadcast_mode = False
62
 
63
- # -----------------------------------------------------------------------------
64
- if broadcast_mode:
65
- st.sidebar.header("Broadcast Settings")
66
- # (In a real app you might enumerate the actual connected cameras.
67
- # Here we simply provide a dummy list of choices.)
68
- camera_options = ["Camera 0", "Camera 1", "Camera 2"]
69
- camera_choice = st.sidebar.selectbox("Select Camera", camera_options)
70
- camera_index = int(camera_choice.split(" ")[-1])
71
 
72
- st.write("### You are in **BROADCASTING** mode")
73
- st.write("Your live stream is being sent to all viewers.")
 
 
 
 
 
 
 
 
 
 
 
74
 
75
- # Start the WebRTC streamer in SENDONLY mode (broadcasting).
76
- # The same key ("live_stream") is used so that viewers join the same “room.”
77
- webrtc_ctx = webrtc_streamer(
78
- key="live_stream",
79
- mode=WebRtcMode.SENDONLY,
80
- video_device_index=camera_index,
81
- media_stream_constraints={"video": True, "audio": False},
82
- video_transformer_factory=BufferingTransformer,
83
- video_html_attrs={
84
- "controls": True,
85
- "style": {
86
- "width": "100%",
87
- "border": "2px solid #ccc",
88
- "border-radius": "10px",
89
- },
90
- },
91
- rtc_configuration={"iceServers": [{"urls": ["stun:stun.l.google.com:19302"]}]},
92
- )
93
- else:
94
- st.write("### Viewing Broadcast")
95
- st.info("If you have the broadcasting password, enter it in the sidebar to broadcast your own stream.")
96
- # In viewing mode, join the same “room” in RECVONLY mode so you can see the active stream.
97
- webrtc_ctx = webrtc_streamer(
98
- key="live_stream",
99
- mode=WebRtcMode.RECVONLY,
100
- media_stream_constraints={"video": True, "audio": False},
101
- video_transformer_factory=BufferingTransformer,
102
- video_html_attrs={
103
- "controls": True,
104
- "style": {
105
- "width": "100%",
106
- "border": "2px solid #ccc",
107
- "border-radius": "10px",
108
- },
109
- },
110
- rtc_configuration={"iceServers": [{"urls": ["stun:stun.l.google.com:19302"]}]},
111
- )
 
 
 
 
1
  import streamlit as st
2
+ import cv2
3
+ import time
4
+ import threading
5
+ import os
6
+ from streamlit_autorefresh import st_autorefresh
7
+
8
+ # Initialize session state for broadcasting if not already set
9
+ if "broadcasting" not in st.session_state:
10
+ st.session_state.broadcasting = False
11
+ if "broadcaster_thread" not in st.session_state:
12
+ st.session_state.broadcaster_thread = None
13
+
14
+ def broadcast_loop(camera_index):
15
+ """
16
+ Capture 3-second segments from the selected camera and write them to 'latest.mp4'.
17
+ This loop runs in a background thread while st.session_state.broadcasting is True.
18
+ """
19
+ cap = cv2.VideoCapture(int(camera_index))
20
+ if not cap.isOpened():
21
+ st.error("Could not open camera.")
22
+ return
23
 
24
+ # Try to determine FPS; default to 20 if not available.
25
+ fps = cap.get(cv2.CAP_PROP_FPS)
26
+ if fps is None or fps < 1:
27
+ fps = 20
28
 
29
+ width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
30
+ height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
31
+
32
+ while st.session_state.broadcasting:
33
+ # Open a VideoWriter to record a 3-second segment.
34
+ fourcc = cv2.VideoWriter_fourcc(*'mp4v')
35
+ out = cv2.VideoWriter("latest.mp4", fourcc, fps, (width, height))
36
+ segment_start = time.time()
37
+
38
+ while time.time() - segment_start < 3 and st.session_state.broadcasting:
39
+ ret, frame = cap.read()
40
+ if not ret:
41
+ break
42
+ out.write(frame)
43
+ time.sleep(1.0 / fps)
44
+ out.release() # Close the file so that it can be served.
45
+ cap.release()
46
+
47
+ def start_broadcast(password, camera_index):
48
+ """
49
+ Start broadcasting if the correct password is entered.
50
  """
51
+ if password != "test123":
52
+ return "Incorrect password! Broadcast not started."
53
+ if not st.session_state.broadcasting:
54
+ st.session_state.broadcasting = True
55
+ thread = threading.Thread(target=broadcast_loop, args=(camera_index,), daemon=True)
56
+ st.session_state.broadcaster_thread = thread
57
+ thread.start()
58
+ return "Broadcasting started."
59
+ else:
60
+ return "Already broadcasting."
 
 
 
 
 
 
61
 
62
+ def stop_broadcast():
63
+ """
64
+ Stop broadcasting by setting the broadcasting flag to False.
65
+ """
66
+ if st.session_state.broadcasting:
67
+ st.session_state.broadcasting = False
68
+ return "Broadcast stopped."
69
+ else:
70
+ return "Not broadcasting."
71
 
72
+ def get_latest_video_path():
73
+ """
74
+ Return the path to the latest video if it exists.
75
+ """
76
+ return "latest.mp4" if os.path.exists("latest.mp4") else None
 
 
 
 
 
 
 
77
 
78
+ # Set page configuration
79
+ st.set_page_config(page_title="Temporary File‑Based Live Stream", layout="wide")
80
+ st.title("Temporary File‑Based Live Stream with Streamlit")
 
 
 
 
 
 
81
 
82
+ # Create two tabs: one for broadcasting and one for viewing.
83
+ tabs = st.tabs(["Broadcast", "View"])
 
 
 
 
 
 
84
 
85
+ with tabs[0]:
86
+ st.header("Broadcasting Controls")
87
+ password_input = st.text_input("Enter broadcast password:", type="password")
88
+ camera_index_input = st.number_input("Camera Index", min_value=0, value=0, step=1)
89
+ col1, col2 = st.columns(2)
90
+ with col1:
91
+ if st.button("Start Broadcasting"):
92
+ status = start_broadcast(password_input, camera_index_input)
93
+ st.info(status)
94
+ with col2:
95
+ if st.button("Stop Broadcasting"):
96
+ status = stop_broadcast()
97
+ st.info(status)
98
 
99
+ with tabs[1]:
100
+ st.header("Live View")
101
+ video_path = get_latest_video_path()
102
+ if video_path:
103
+ # Automatically refresh the app every 3 seconds to load the latest file.
104
+ st_autorefresh(interval=3000, key="video_autorefresh")
105
+ st.video(video_path)
106
+ else:
107
+ st.write("No broadcast available yet.")