Skip to content
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

[Lib+CLI] On Demand Feature + New Class Structure #6

Draft
wants to merge 33 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
9e0bb45
[Lib] Introduce has_demand method
egeakman Feb 11, 2024
4b29152
Merge branch 'main' into on-demand
egeakman Feb 22, 2024
e15e99d
Found the overhead, remove temporary tests
egeakman Feb 22, 2024
28e454c
Add .editorconfig
egeakman Feb 24, 2024
de8b61d
Added a bunch of stuff, gonna need tons of debugging
egeakman Feb 24, 2024
3b1700e
[Lib] The classes look alright
egeakman Feb 25, 2024
49a83fe
[Lib] typing + code quality
egeakman Feb 25, 2024
085117f
[Lib] Update __init__.py
egeakman Feb 25, 2024
5844b63
Update __init__.py
egeakman Feb 25, 2024
7fa3b09
Update requirements-dev.txt
egeakman Feb 25, 2024
b9f9e27
Update StreamBase._check_encoding
egeakman Mar 10, 2024
51a47f8
Seperate files
egeakman Mar 10, 2024
5bba6c3
update
egeakman Mar 10, 2024
c60b7f4
Merge branch 'main' into on-demand
egeakman Apr 2, 2024
568ae1d
Fix #12 and #13
egeakman Apr 3, 2024
1342a95
Clean up a bit
egeakman Apr 5, 2024
1c56c86
#12 and #13 were reintroduced in 1342a95f4beb3d027e0e3ef78e667dc3e634…
egeakman Apr 5, 2024
9428e3d
Merge branch 'main' into on-demand
egeakman Apr 12, 2024
0c2108d
Merge branch 'main' into on-demand
egeakman Apr 17, 2024
cc76948
Merge branch 'main' into on-demand
egeakman May 3, 2024
e57fa88
This fixes #12 but only tried on Windows
egeakman May 3, 2024
2ea77e3
Add performance test results + #13 fix is validated, it works on Linu…
egeakman May 4, 2024
0ada5d0
Update py-spy-results.md
egeakman May 4, 2024
37179de
Update usage-tests.md
egeakman May 4, 2024
a97bdb6
Update py-spy-results.md
egeakman May 4, 2024
d938e4e
Update usage-tests.md
egeakman May 4, 2024
b6d257f
Update tests
egeakman May 5, 2024
38a13fe
Fix #24
egeakman May 5, 2024
2b4e5be
update gitignore
egeakman May 5, 2024
8104740
Merge branch 'main' into on-demand
egeakman May 8, 2024
9d4d5a8
Make CLI use ManagedStream
egeakman May 8, 2024
56b0034
small improvement
egeakman May 8, 2024
4e63aaf
Handle ConnectionError
egeakman May 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
charset = utf-8
indent_size = 4
indent_style = space
insert_final_newline = true
root = true
trim_trailing_whitespace = true
5 changes: 3 additions & 2 deletions mjpeg_streamer/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .mjpeg_streamer import MjpegServer, Stream
from .server import MjpegServer, Server
from .stream import ManagedStream, Stream, StreamBase

__all__ = ["MjpegServer", "Stream"]
__all__ = ["StreamBase", "ManagedStream", "MjpegServer", "Stream", "Server"]
__version__ = "2024.2.8"
75 changes: 24 additions & 51 deletions mjpeg_streamer/cli.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import argparse
import re
import threading
from typing import List, Tuple, Union
import time
from typing import Dict, List, Tuple, Union

import cv2

from mjpeg_streamer import MjpegServer, Stream
from .server import Server
from .stream import ManagedStream


def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser()
parser.add_argument("--host", type=str, default="localhost")
parser.add_argument("--port", type=int, default=8080)
parser.add_argument(
"--prefix", type=str, default="source", help="Name prefix for the streams"
"--prefix", type=str, default="", help="Name prefix for the streams"
)
parser.add_argument(
"--source",
Expand All @@ -34,84 +33,58 @@ def parse_args() -> argparse.Namespace:
)
args: argparse.Namespace = parser.parse_args()
args.prefix = re.sub("[^0-9a-zA-Z]+", "_", args.prefix)
args.source: List[Union[int, str],] = [[0]] if args.source is None else args.source
args.source = [[0]] if args.source is None else args.source
args.source = [item for sublist in args.source for item in sublist]
args.source = list(set(args.source))
return args


def run(
cap: cv2.VideoCapture,
stream: Stream,
stop_event: threading.Event,
show_bandwidth: bool,
) -> None:
while not stop_event.is_set():
ret, frame = cap.read()
if not ret:
stop_event.set()
break
stream.set_frame(frame)
if show_bandwidth:
global bandwidth
bandwidth[stream.name] = stream.get_bandwidth()
cap.release()


def main() -> None:
args = parse_args()
size: Tuple[int, int] = (args.width, args.height)
server = MjpegServer(args.host, args.port)
threads: List[threading.Thread,] = []
stop_events: List[threading.Event,] = []
streams: List[ManagedStream] = []
server = Server(args.host, args.port)

if args.show_bandwidth:
global bandwidth
bandwidth = {} # dict[str, int]
bandwidth: Dict[str, int] = {}

for source in args.source:
source: Union[int, str] = int(source) if str(source).isdigit() else source
cap = cv2.VideoCapture(source)
source_display = (
re.sub("[^0-9a-zA-Z]+", "_", source) if isinstance(source, str) else source
)
stream = Stream(
f"{args.prefix}_{source_display!s}",
stream = ManagedStream(
f"{args.prefix}{'_' if args.prefix else ''}{source_display!s}",
source=source,
size=size,
quality=args.quality,
fps=args.fps,
)
server.add_stream(stream)
stop_event = threading.Event()
stop_events.append(stop_event)
thread = threading.Thread(
target=run, args=(cap, stream, stop_event, args.show_bandwidth)
)
threads.append(thread)
streams.append(stream)

try:
for thread in threads:
thread.start()
for stream in streams:
stream.start()
server.start()
while True:
if args.show_bandwidth:
for stream in streams:
bandwidth[stream.name] = stream.get_bandwidth()
print(
f"{' | '.join([f'{k}: {round(v / 1024, 2)} KB/s' for k, v in bandwidth.items()])}",
end="\r",
)
else:
time.sleep(1) # Keep the main thread alive, but don't consume CPU
except KeyboardInterrupt:
for stop_event in stop_events:
stop_event.set()
server.stop()
for thread in threads:
thread.join()
print("\nExiting...")
except Exception as e:
print(e)
for stop_event in stop_events:
stop_event.set()
print("Error:", e)
finally:
for stream in streams:
stream.stop()
server.stop()
for thread in threads:
thread.join()


if __name__ == "__main__":
Expand Down
164 changes: 0 additions & 164 deletions mjpeg_streamer/mjpeg_streamer.py

This file was deleted.

Loading