vlc/python | branch: master | Saveliy Yusufov <[email protected]> | Fri Feb 28 12:18:25 2020 -0500| [b45d75bc51d7615c0faf173d900d16bc149a01b5] | committer: Saveliy Yusufov
Fixes a bug in the client/server implementation The recv() system call returns any data that is available, up to the requested amount, rather than waiting for receipt of the full amount of data requested. The previous implementation attempted to split messages into sections using a ',', but this is a poor implementation due to the assumptions that were made about receipt of data. The fix adds two methods to the Client class, namely recv_all() and recv_msg(). We use a struct in order to send the length of the data as a message header (in network byte order). That struct is unpacked on the client's end. recv_msg() first recvs and unpacks the 4 byte msg header that tells us how many bytes we are supposed to recv. Finally, recv_msg() calls recv_all() with that number of bytes and keeps recving until the buffer is filled with `size` number of bytes. The data_receiver() method was simplified by calling recv_mesg() and then decoding, parsing, and queueing the messages. The diagram in the README was rereated to paint a clearer picture of the architecture. Added the GPL3 header to the pyqt5 example. > http://git.videolan.org/gitweb.cgi/vlc/python.git/?a=commit;h=b45d75bc51d7615c0faf173d900d16bc149a01b5 --- examples/pyqt5vlc.py | 18 +++++++++++++++ examples/video_sync/README.md | 4 ++-- examples/video_sync/figure.png | Bin 118904 -> 28647 bytes examples/video_sync/network.py | 49 ++++++++++++++++++++++++++++++----------- 4 files changed, 56 insertions(+), 15 deletions(-) diff --git a/examples/pyqt5vlc.py b/examples/pyqt5vlc.py index abf0cf2..cb3d294 100644 --- a/examples/pyqt5vlc.py +++ b/examples/pyqt5vlc.py @@ -1,3 +1,21 @@ +# +# PyQt5 example for VLC Python bindings +# Copyright (C) 2009-2010 the VideoLAN team +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. +# """ A simple example for VLC python bindings using PyQt5. diff --git a/examples/video_sync/README.md b/examples/video_sync/README.md index c3792d8..120b658 100644 --- a/examples/video_sync/README.md +++ b/examples/video_sync/README.md @@ -1,6 +1,6 @@ ## Video Synchronization with python-vlc -<img src="figure.png" width="500" align="right"> +<img src="figure.png" width="600" align="center"> Each video player is launched as a separate process. `main.py` is the entry point into the program. It creates the "main" video player with all of its respective controls. The main video player is started alongside a multithreaded server that "broadcasts" signals (e.g. play, pause, stop, and etc.) and the current time of the video player, to all client/slave videos. Specifically, this is accomplished by putting the current time or the signal of the main video player into a `queue` (FIFO). The multithreaded server gets the value from the queue and sends the value to each connected client. @@ -8,4 +8,4 @@ In a somewhat similar fashion, each "slave" video player is launched as a separa In order to facilitate interprocess communication, UNIX domain sockets are used to send and receive data. For the time being, Windows users have to use TCP/IP sockets. -Note: for the sake of clarity, the figure on the right only shows the case of 3 client/slave videos. +Note: for the sake of clarity, the figure only shows the case of 3 client/slave videos. diff --git a/examples/video_sync/figure.png b/examples/video_sync/figure.png index f0feb1d..63268cb 100644 Binary files a/examples/video_sync/figure.png and b/examples/video_sync/figure.png differ diff --git a/examples/video_sync/network.py b/examples/video_sync/network.py index d657764..9835cf7 100644 --- a/examples/video_sync/network.py +++ b/examples/video_sync/network.py @@ -27,8 +27,9 @@ Date: 25 January 2019 import os import platform import socket -import threading import sys +import struct +import threading import logging from concurrent import futures @@ -104,11 +105,13 @@ class Server: def data_sender(self): while True: - data = "{},".format(self.data_queue.get()) + data = self.data_queue.get() + data = str(data).encode() + msg = struct.pack(">I", len(data)) + data with futures.ThreadPoolExecutor(max_workers=5) as ex: for client in self.clients: - ex.submit(self.sendall, client, data.encode()) + ex.submit(self.sendall, client, msg) def sendall(self, client, data): """Wraps socket module's `sendall` function""" @@ -153,22 +156,42 @@ class Client: thread.daemon = True thread.start() + def recv_all(self, size): + """Helper function to recv `size` number of bytes, or return False""" + data = bytearray() + + while (len(data) < size): + packet = self.sock.recv(size - len(data)) + if not packet: + return False + + data.extend(packet) + + return data + + def recv_msg(self): + """Receive the message size, n, and receive n bytes into a buffer""" + raw_msg_size = self.recv_all(4) + if not raw_msg_size: + return False + + msg_size = struct.unpack(">I", raw_msg_size)[0] + return self.recv_all(msg_size) + def data_receiver(self): """Handles receiving, parsing, and queueing data""" logger.info("New data receiver thread started.") try: while True: - data = self.sock.recv(4096) - if data: - data = data.decode() - - for char in data.split(','): - if char: - if char == 'd': - self.data_queue.queue.clear() - else: - self.data_queue.put(char) + raw_data = self.recv_msg() + if raw_data: + data = raw_data.decode() + if 'd' in set(data): + self.data_queue.queue.clear() + continue + else: + self.data_queue.put(data) except: logger.exception("Closing socket: %s", self.sock) self.sock.close() _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
