-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
68d2f23
commit 7b3d329
Showing
6 changed files
with
827 additions
and
0 deletions.
There are no files selected for viewing
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
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 |
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
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/*' | ||
|
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
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 |
Oops, something went wrong.