72 lines
2.3 KiB
Python
72 lines
2.3 KiB
Python
#!/usr/bin/python3.11
|
|
# SPDX-License-Identifier: MPL-2.0
|
|
"""Narrow stdio-to-socket adapter for the Android CameraService broker."""
|
|
import os
|
|
import json
|
|
import socket
|
|
import sys
|
|
|
|
SOCKET = '/work/camera-ipc/camera.sock'
|
|
|
|
def read_exact(stream, size):
|
|
data = bytearray()
|
|
while len(data) < size:
|
|
chunk = stream.recv(size - len(data))
|
|
if not chunk:
|
|
raise EOFError('Camera broker closed the session')
|
|
data.extend(chunk)
|
|
return bytes(data)
|
|
|
|
def forward(sock, target, size):
|
|
header = read_exact(sock, size)
|
|
target.write(header); target.flush()
|
|
return header
|
|
|
|
def packet(sock, output):
|
|
header = read_exact(sock, 4)
|
|
size = int.from_bytes(header, 'little')
|
|
if size > 65536:
|
|
raise ValueError('Camera broker sent an oversized response')
|
|
payload = read_exact(sock, size)
|
|
output.write(header + payload); output.flush()
|
|
return json.loads(payload.decode('utf-8'))
|
|
|
|
def main():
|
|
client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
client.connect(SOCKET)
|
|
output = os.fdopen(os.dup(1), 'wb', buffering=0)
|
|
try:
|
|
client.sendall(b'start\n')
|
|
header = forward(client, output, 4)
|
|
length = int.from_bytes(header, 'little')
|
|
if not 0 < length <= 65536:
|
|
return 2
|
|
forward(client, output, length)
|
|
while True:
|
|
command = sys.stdin.buffer.readline(2049)
|
|
if not command or len(command) > 2048:
|
|
break
|
|
client.sendall(command)
|
|
if command.strip() == b'frame':
|
|
header = forward(client, output, 8)
|
|
length = int.from_bytes(header[4:], 'little')
|
|
if length > 320 * 240 * 3 // 2:
|
|
return 3
|
|
if length:
|
|
forward(client, output, length)
|
|
elif command.strip() == b'stop':
|
|
packet(client, output)
|
|
break
|
|
else:
|
|
response = packet(client, output)
|
|
jpeg = response.get('jpegLength', 0)
|
|
if isinstance(jpeg, int) and 0 < jpeg <= 32 * 1024 * 1024:
|
|
forward(client, output, jpeg)
|
|
except (BrokenPipeError, ConnectionError, EOFError):
|
|
return 0
|
|
finally:
|
|
client.close(); output.close()
|
|
return 0
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|