Last active
December 6, 2017 08:24
-
-
Save knthls/d67f06cbb87f85c4f39ffa2ba2ef66df to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Basic Idea taken from http://stackoverflow.com/a/8111621/6420372 | |
""" | |
import os | |
import socket | |
import subprocess | |
from select import select | |
import time | |
import contextlib | |
import settings | |
try: | |
import winreg | |
except ImportError: | |
import _winreg as winreg | |
def _get_vlc_path(): | |
views = [(winreg.HKEY_CURRENT_USER, 0), | |
(winreg.HKEY_LOCAL_MACHINE, winreg.KEY_WOW64_64KEY), | |
(winreg.HKEY_LOCAL_MACHINE, winreg.KEY_WOW64_32KEY)] | |
subkey = r'Software\VideoLAN\VLC' | |
access = winreg.KEY_QUERY_VALUE | |
for hroot, flag in views: | |
try: | |
with winreg.OpenKey(hroot, subkey, 0, access | flag) as hkey: | |
value, type_id = winreg.QueryValueEx(hkey, None) | |
if type_id == winreg.REG_SZ: | |
return value | |
except WindowsError: | |
pass | |
raise SystemExit("Error: VLC not found.") | |
def send_command(sock, cmd, get_result=False): | |
try: | |
cmd = (cmd + '\n').encode('ascii') | |
except AttributeError: | |
cmd += b'\n' | |
sent = total = sock.send(cmd) | |
while total < len(cmd): | |
sent = sock.send(cmd[total:]) | |
if sent == 0: | |
raise socket.error('Socket connection broken.') | |
total += sent | |
if get_result: | |
return receive_result(sock) | |
def receive_result(sock): | |
data = bytearray() | |
sock.setblocking(0) | |
while select([sock], [], [], 1.0)[0]: | |
chunk = sock.recv(1024) | |
if chunk == b'': | |
raise socket.error('Socket connection broken.') | |
data.extend(chunk) | |
sock.setblocking(1) | |
return data.decode('utf-8') | |
def _outfile(id_): | |
return os.path.join(settings.DATA_DIR, | |
'recording_{}_.mp4'.format(id_)) | |
def _sout_options(id_): | |
""" | |
somehow passing them as single options doesn't work | |
:param id_: | |
:return: | |
""" | |
return "--sout=#transcode{" \ | |
"vcodec=h264,vb=1024,fps=" + \ | |
str(settings.CAM_FRAME_RATE) + ",width=640" \ | |
"}:standard{access=file,mux=ts," \ | |
"dst=" + "\"{}\"".format(_outfile(id_)) + "}" | |
def _stream_options(): | |
return ['--dshow-size={}x{}'.format(*settings.CAM_RES), | |
'--dshow-adev=None', | |
'--dshow-fps={}'.format(settings.CAM_FRAME_RATE), | |
'--dshow-vdev=USB_Camera'] | |
@contextlib.contextmanager | |
def vlc(address, port, id_): | |
rc_host = '{0}:{1}'.format(address, port) | |
vlc = subprocess.Popen([_get_vlc_path(), '-I', 'rc', '--rc-host', rc_host, | |
'--rc-quiet', 'dshow://'] + _stream_options() + | |
[_sout_options(id_),'--qt-start-minimized']) | |
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
try: | |
sock.connect((address, port)) | |
yield sock | |
send_command(sock, 'stop') | |
send_command(sock, 'quit') | |
except socket.error as e: | |
exit("Error: " + e.args[0]) | |
finally: | |
sock.close() | |
# give vlc some time to finish transcoding the stream? | |
time.sleep(5) | |
if vlc.poll() is None: | |
vlc.terminate() | |
if __name__ == '__main__': | |
with vlc('localhost', 12345, 42) as sock: | |
time.sleep(10) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment