Skip to content

Commit 568ae1d

Browse files
committed
Fix #12 and #13
1 parent c60b7f4 commit 568ae1d

File tree

4 files changed

+32
-27
lines changed

4 files changed

+32
-27
lines changed

mjpeg_streamer/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from .server import MjpegServer
1+
from .server import MjpegServer, Server
22
from .stream import CustomStream, ManagedStream, Stream
33

4-
__all__ = ["CustomStream", "ManagedStream", "MjpegServer", "Stream"]
4+
__all__ = ["CustomStream", "ManagedStream", "MjpegServer", "Stream", "Server"]
55
__version__ = "2024.2.8"

mjpeg_streamer/server.py

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from typing import List, Union
44

55
import aiohttp
6-
import netifaces
76
from aiohttp import MultipartWriter, web
87
from aiohttp.web_runner import GracefulExit
98
from multidict import MultiDict
@@ -51,29 +50,20 @@ async def __call__(self, request: web.Request) -> web.StreamResponse:
5150
return response
5251

5352

54-
class MjpegServer:
53+
class Server:
5554
def __init__(
5655
self, host: Union[str, List[str,]] = "localhost", port: int = 8080
5756
) -> None:
58-
if isinstance(host, str) and host != "0.0.0.0":
57+
if isinstance(host, str):
5958
self._host: List[str,] = [
6059
host,
6160
]
6261
elif isinstance(host, list):
6362
if "0.0.0.0" in host:
64-
host.remove("0.0.0.0")
65-
host = host + [
66-
netifaces.ifaddresses(iface)[netifaces.AF_INET][0]["addr"]
67-
for iface in netifaces.interfaces()
68-
if netifaces.AF_INET in netifaces.ifaddresses(iface)
69-
]
63+
host = ["0.0.0.0"]
64+
if "localhost" in host and "127.0.0.1" in host:
65+
host.remove("localhost")
7066
self._host = list(set(host))
71-
else:
72-
self._host = [
73-
netifaces.ifaddresses(iface)[netifaces.AF_INET][0]["addr"]
74-
for iface in netifaces.interfaces()
75-
if netifaces.AF_INET in netifaces.ifaddresses(iface)
76-
]
7767
self._port = port
7868
self._app: web.Application = web.Application()
7969
self._app_is_running: bool = False
@@ -131,3 +121,11 @@ def stop(self) -> None:
131121
print("\nServer stopped\n")
132122
else:
133123
print("\nServer is not running\n")
124+
125+
126+
class MjpegServer(Server):
127+
# Alias for Server, to maintain backwards compatibility
128+
def __init__(
129+
self, host: Union[str, List[str,]] = "localhost", port: int = 8080
130+
) -> None:
131+
super().__init__(host, port)

mjpeg_streamer/stream.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,6 @@ def __init__(
2727
self._deque_background_task: Optional[asyncio.Task] = None
2828
self._active_viewers: Set[str,] = set()
2929

30-
async def _add_viewer(self, viewer_token: Optional[str] = None) -> str:
31-
viewer_token = viewer_token or str(uuid.uuid4())
32-
self._active_viewers.add(viewer_token)
33-
return viewer_token
34-
35-
async def _remove_viewer(self, viewer_token: str) -> None:
36-
self._active_viewers.discard(viewer_token)
37-
3830
async def __clear_deque(self) -> None:
3931
while True:
4032
await asyncio.sleep(1 / self.fps)
@@ -44,6 +36,14 @@ async def __clear_deque(self) -> None:
4436
):
4537
self._frame_buffer.clear()
4638

39+
async def _add_viewer(self, viewer_token: Optional[str] = None) -> str:
40+
viewer_token = viewer_token or str(uuid.uuid4())
41+
self._active_viewers.add(viewer_token)
42+
return viewer_token
43+
44+
async def _remove_viewer(self, viewer_token: str) -> None:
45+
self._active_viewers.discard(viewer_token)
46+
4747
async def _ensure_background_tasks(self) -> None:
4848
if self._deque_background_task is None or self._deque_background_task.done():
4949
self._deque_background_task = asyncio.create_task(self.__clear_deque())
@@ -85,7 +85,8 @@ def set_fps(self, fps: int) -> None:
8585
async def _get_frame(self) -> np.ndarray:
8686
# A little hacky, if you have a better way, please let me know
8787
await self._ensure_background_tasks()
88-
# Checking here to avoid continous polling
88+
# Checking the encoding here instead of set_frame
89+
# to avoid continous polling
8990
if self._check_encoding(self._frame) != "jpeg":
9091
raise ValueError(
9192
"Input is not an encoded JPEG frame. Use OpenCV's imencode method to encode the frame to JPEG."
@@ -113,6 +114,7 @@ def __init__(
113114
) -> None:
114115
self.size = size
115116
self.quality = max(1, min(quality, 100))
117+
self._last_processed_frame: np.ndarray = np.zeros((320, 240, 1), dtype=np.uint8)
116118
super().__init__(name, fps)
117119

118120
async def __process_current_frame(self) -> np.ndarray:
@@ -131,9 +133,12 @@ async def __process_current_frame(self) -> np.ndarray:
131133
)
132134
self._frame_buffer.append(len(frame.tobytes()))
133135
self._bandwidth_last_modified_time = time.time()
136+
self._last_processed_frame = frame
134137
return frame
135138

136139
async def _get_frame(self) -> np.ndarray:
140+
if time.time() - self._bandwidth_last_modified_time <= 1 / self.fps:
141+
return self._last_processed_frame
137142
await self._ensure_background_tasks()
138143
async with self._lock:
139144
return await self.__process_current_frame()
@@ -242,12 +247,15 @@ async def __process_current_frame(self) -> np.ndarray:
242247
raise ValueError("Error encoding frame")
243248
self._frame_buffer.append(len(frame.tobytes()))
244249
self._bandwidth_last_modified_time = time.time()
250+
self._last_processed_frame = frame
245251
return frame
246252

247253
async def _get_frame(self) -> np.ndarray:
248254
if not self._is_running:
249255
print("Stream is not running, please call the start method first.")
250256
return self._frame
257+
if time.time() - self._bandwidth_last_modified_time <= 1 / self.fps:
258+
return self._last_processed_frame
251259
await self._ensure_background_tasks()
252260
async with self._lock:
253261
return await self.__process_current_frame()

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ dependencies = [
5454
'aiohttp==3.8.6; python_version >= "3.6" and python_version <= "3.7"',
5555
'aiohttp==3.9.1; python_version == "3.8"',
5656
'aiohttp; python_version >= "3.9"',
57-
"netifaces",
5857
'numpy==1.19.5; python_version == "3.6"',
5958
'numpy==1.21.6; python_version == "3.7"',
6059
'numpy==1.24.4; python_version == "3.8"',

0 commit comments

Comments
 (0)