Skip to content

Commit

Permalink
Initial upload
Browse files Browse the repository at this point in the history
  • Loading branch information
electric-monk authored Dec 31, 2019
1 parent 68d2f23 commit 7b3d329
Show file tree
Hide file tree
Showing 6 changed files with 827 additions and 0 deletions.
64 changes: 64 additions & 0 deletions decoder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@

# "Autobox" dongle driver for HTML 'streaming'
# Created by Colin Munro, December 2019
# See README.md for more information

"""Simple utility code to decode an h264 stream to a series of PNGs."""

import subprocess, threading, os, fcntl

class Decoder:
class _Thread(threading.Thread):
def __init__(self, owner):
super().__init__()
self.owner = owner
self.running = threading.Event()
self.shutdown = False

def run(self):
png_header = bytearray([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])
captured_data = b''
checked = 0
while not self.shutdown:
data = self.owner.child.stdout.read(1024000)
if data is None or not len(data):
self.running.clear()
self.running.wait(timeout=0.1)
continue
captured_data += data
first_header = captured_data.find(png_header)
if first_header == -1:
continue
if first_header != 0:
captured_data = captured_data[first_header:]
while True:
second_header = captured_data.find(png_header, checked)
if second_header == -1:
checked = len(captured_data) - len(png_header)
break
png = captured_data[:second_header]
captured_data = captured_data[second_header:]
checked = len(png_header)
self.owner.on_frame(png)

def __init__(self):
self.child = subprocess.Popen(["ffmpeg", "-threads", "4", "-i", "-", "-vf", "fps=7", "-c:v", "png", "-f", "image2pipe", "-"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, bufsize=1)
fd = self.child.stdout.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
self.thread = self._Thread(self)
self.thread.start()

def stop(self):
self.child.terminate()
self.thread.shutdown = True
self.thread.join()

def send(self, data):
self.child.stdin.write(data)
self.child.stdin.flush()
self.thread.running.set()

def on_frame(self, png):
"""Callback for when a frame is received [called from a worker thread]."""
pass
4 changes: 4 additions & 0 deletions downloadassets.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash
curl "http://121.40.123.198:8080/AutoKit/AutoKit.apk" > AutoKit.apk
unzip AutoKit.apk 'assets/*'

91 changes: 91 additions & 0 deletions link.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@

# "Autobox" dongle driver for HTML 'streaming'
# Created by Colin Munro, December 2019
# See README.md for more information

"""Dongle USB connection code."""

import usb.core
import usb.util
import threading
import protocol

class Connection:
idVendor = 0x1314
idProduct = 0x1520

def __init__(self):
self._device = usb.core.find(idVendor = self.idVendor, idProduct = self.idProduct)
if self._device is None:
raise RuntimeError("Couldn't find USB device")
self._device.reset()
self._device.set_configuration()
self._interface = self._device.get_active_configuration()[(0,0)]
self._ep_in = usb.util.find_descriptor(self._interface, custom_match = lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_IN)
if self._ep_in is None:
raise RuntimeError("Couldn't find input endpoint")
self._ep_in.clear_halt()
self._ep_out = usb.util.find_descriptor(self._interface, custom_match = lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT)
if self._ep_out is None:
raise RuntimeError("Couldn't find output endpoint")
self._ep_out.clear_halt()
self._out_locker = threading.Lock()
self._run = True
self._thread = threading.Thread(target=self._read_thread)
self._thread.start()

def send_message(self, message):
data = message.serialise()
while not self._out_locker.acquire():
pass
try:
self._ep_out.write(data[:message.headersize])
self._ep_out.write(data[message.headersize:])
finally:
self._out_locker.release()

def send_multiple(self, messages):
for x in messages:
self.send_message(x)

def stop(self):
self._run = False
self._thread.join()

def on_message(self, message):
"""Handle message from dongle [called from another thread]"""
pass

def on_error(self, error):
"""Handle exception on dongle read thread [called from another thread]"""
self._run = False

def _read_thread(self):
while self._run:
try:
data = self._ep_in.read(protocol.Message.headersize)
except usb.core.USBError as e:
if e.errno != 110: # Timeout
self.on_error(e)
continue
if len(data) == protocol.Message.headersize:
header = protocol.Message()
header.deserialise(data)
needlen = len(header._data())
if needlen:
try:
msg = header.upgrade(self._ep_in.read(needlen))
except usb.core.USBError as e:
self._threaderror(e)
continue
else:
msg = header
try:
self.on_message(msg)
except Exception as e:
self.on_error(e)
continue
else:
print(f"R> Bad data: {data}")

Error = usb.core.USBError
Loading

0 comments on commit 7b3d329

Please sign in to comment.