diff --git a/.gitignore b/.gitignore index 6566fd0..ba3d198 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ hls -venv/ \ No newline at end of file +venv/ +sockets \ No newline at end of file diff --git a/core/Dockerfile b/core/Dockerfile new file mode 100644 index 0000000..83a7577 --- /dev/null +++ b/core/Dockerfile @@ -0,0 +1,17 @@ +FROM python:3.10 + +# Set working directory +WORKDIR /core + +# Install dependencies +COPY requirements.txt requirements.txt +RUN pip install --no-cache-dir -r requirements.txt + +# Copy application code +COPY . . + +# Expose Flask's port +EXPOSE 5000 + +# Start the Flask app +CMD ["python", "app.py"] diff --git a/database/requirements.txt b/database/requirements.txt new file mode 100644 index 0000000..8ab6294 --- /dev/null +++ b/database/requirements.txt @@ -0,0 +1 @@ +flask \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..de39df5 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,22 @@ +version: '3.9' +services: + nginx: + build: + context: ./nginx + ports: + - "1935:1935" # RTMP + depends_on: + - flask + networks: + - app_network + + flask: + build: + context: ./core + ports: + - "5000:5000" + networks: + - app_network + +networks: + app_network: diff --git a/nginx/Dockerfile b/nginx/Dockerfile new file mode 100644 index 0000000..5e276d2 --- /dev/null +++ b/nginx/Dockerfile @@ -0,0 +1,26 @@ +FROM ubuntu:22.04 + +# Install dependencies +RUN apt-get update && apt-get install -y \ + build-essential \ + libpcre3 libpcre3-dev \ + libssl-dev \ + zlib1g-dev \ + wget git + +# Download and build NGINX with RTMP +RUN wget http://nginx.org/download/nginx-1.25.2.tar.gz && \ + tar -xzvf nginx-1.25.2.tar.gz && \ + git clone https://github.com/arut/nginx-rtmp-module.git && \ + cd nginx-1.25.2 && \ + ./configure --add-module=../nginx-rtmp-module --with-http_ssl_module && \ + make && make install + +# Copy custom NGINX configuration +COPY nginx.conf /etc/nginx/nginx.conf + +# Expose RTMP and HTTP ports +EXPOSE 1935 + +# Start NGINX +CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"] diff --git a/nginx/nginx.conf b/nginx/nginx.conf new file mode 100644 index 0000000..80f8cfd --- /dev/null +++ b/nginx/nginx.conf @@ -0,0 +1,12 @@ +rtmp { + server { + listen 1935; + chunk_size 4096; + + application live { + live on; + record off; + } + } +} + diff --git a/sockets/rtmp_server.py b/sockets/rtmp_server.py deleted file mode 100644 index 487ab2a..0000000 --- a/sockets/rtmp_server.py +++ /dev/null @@ -1,149 +0,0 @@ -import socket, threading, os, time, traceback, struct - -class RTMPClientState: - """Enumeration of RTMP client states.""" - EPOCH = 0 - -class RTMPServer: - def __init__(self, host='192.168.1.15', port=1935): - self.host = host - self.port = port - self.server_socket = None - self.is_running = True - self.clients = [] - - def start(self): - """Starts a basic server to display incoming packets.""" - # Create a TCP socket - self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.server_socket.bind((self.host, self.port)) - self.server_socket.listen(1) - print(f"RTMP Server started on {self.host}:{self.port}. Waiting for connections...") - - while self.is_running: - try: - client_socket, address = self.server_socket.accept() - print(f"Connection accepted from {address}") - client_thread = threading.Thread(target=self.handle_client, args=(client_socket,)) - client_thread.daemon = True - client_thread.start() - except Exception as e: - print(f"Error accepting connection: {e}") - print(traceback.format_exc()) - break - - def handle_client(self, client_socket): - """ - Handle an incoming RTMP client connection. - - :param client_socket: The client socket object. - """ - try: - # Perform RTMP handshake - if not self._attempt_handshake(client_socket): - print("Handshake failed.") - client_socket.close() - return - - print("Handshake successful. Ready to handle RTMP stream.") - except Exception as e: - print(f"Error handling client: {e}") - print(traceback.format_exc()) - finally: - client_socket.close() - - def _attempt_handshake(self, client_socket): - """Performs the RTMP handshake with the client.""" - # Receive C0 and C1 packets and validate - c0 = int.from_bytes(client_socket.recv(1)) - if c0 != 3: - print("Invalid RTMP version.") - return False - - c1 = client_socket.recv(1536) - time_epoch = int.from_bytes(c1[:4]) - zeros = int.from_bytes(c1[4:8]) - random_bytes = c1[8:] - - if zeros != 0: - print("Invalid C1 packet.") - return False - - # Send S0 - s0 = bytes([3]) - client_socket.send(s0) - - # Send S1 - s1 = bytearray(c1) - server_random = os.urandom(1528) - current_timestamp = struct.pack(">I" ,int(time.time())) - s1[:4] = current_timestamp - s1[8:] = server_random - client_socket.send(bytes(s1)) - - # Receive C2 - c2 = client_socket.recv(1536) - if c2[8:] != server_random: - print("Invalid C2 packet.") - return False - - - - - # debug - print(f"Version: {c0}") - print(f"Epoch time: {time_epoch}") - print(f"Zeros: {zeros}") - #print(f"Random bytes: {random_bytes}") - - - def stop(self): - """ - Stop the RTMP server. - """ - self.is_running = False - if self.server_socket: - self.server_socket.close() - print("RTMP Server stopped.") - - -def start_rtmp_server(host='127.0.0.1', port=1935): - """Starts a basic RTMP server to display incoming packets.""" - try: - # Create a TCP socket - server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_socket.bind((host, port)) - server_socket.listen(1) - print(f"RTMP server started on {host}:{port}. Waiting for connections...") - - # Accept a connection - conn, addr = server_socket.accept() - print(f"Connection established with {addr}") - - while True: - # Receive RTMP C0 and C1 packets - data = conn.recv(1) - if not data: - print("Connection closed by client.") - break - - # Display the received RTMP packets - print(f"Version: {int.from_bytes(data)}") - break - - except KeyboardInterrupt: - print("\nServer shutting down.") - except Exception as e: - print(f"Error: {e}") - finally: - server_socket.close() - print("Server socket closed.") - -if __name__ == "__main__": - c = RTMPServer() - try: - c.start() - except KeyboardInterrupt: - print("Shutting down RTMP Server...") - c.stop() - diff --git a/sockets/stream_generator.py b/sockets/stream_generator.py deleted file mode 100644 index 482144f..0000000 --- a/sockets/stream_generator.py +++ /dev/null @@ -1,12 +0,0 @@ -from subprocess import Popen, PIPE - -def generate_stream(STREAM_PATH, STREAM_NAME): - """Function to run FFmpeg to convert the stream and create HLS""" - # FFmpeg command to receive the stream and convert to HLS - command = [ - 'ffmpeg', '-i', 'udp://127.0.0.1:1935/live', '-c:v', 'libx264', '-preset', 'veryfast', - '-c:a', 'aac', '-ar', '44100', '-ac', '2', '-f', 'hls', '-hls_time', '4', '-hls_list_size', '5', - '-hls_segment_filename', f'{STREAM_PATH}/{STREAM_NAME}%03d.ts', f"{STREAM_PATH}/{STREAM_NAME}.m3u8" - ] - - Popen(command, stdout=PIPE, stderr=PIPE) \ No newline at end of file