mirror of
https://github.com/azaion/detections.git
synced 2026-04-22 09:56:32 +00:00
be4cab4fcb
- Added `/detect/video` endpoint for true streaming video detection, allowing inference to start as upload bytes arrive. - Introduced `run_detect_video_stream` method in the inference module to handle video processing from a file-like object. - Updated media hashing to include a new function for computing hashes directly from files with minimal I/O. - Enhanced documentation to reflect changes in video processing and API behavior. Made-with: Cursor
94 lines
2.8 KiB
Python
94 lines
2.8 KiB
Python
import os
|
|
import tempfile
|
|
import threading
|
|
|
|
|
|
class StreamingBuffer:
|
|
def __init__(self, temp_dir: str | None = None, total_size: int | None = None):
|
|
fd, self.path = tempfile.mkstemp(dir=temp_dir, suffix=".tmp")
|
|
os.close(fd)
|
|
self._writer = open(self.path, "wb")
|
|
self._reader = open(self.path, "rb")
|
|
self._written = 0
|
|
self._total_size = total_size
|
|
self._eof = False
|
|
self._cond = threading.Condition()
|
|
|
|
def append(self, data: bytes) -> None:
|
|
with self._cond:
|
|
self._writer.write(data)
|
|
self._writer.flush()
|
|
self._written += len(data)
|
|
self._cond.notify_all()
|
|
|
|
def close_writer(self) -> None:
|
|
with self._cond:
|
|
self._writer.close()
|
|
self._eof = True
|
|
self._cond.notify_all()
|
|
|
|
def read(self, size: int = -1) -> bytes:
|
|
with self._cond:
|
|
pos = self._reader.tell()
|
|
if size < 0:
|
|
while not self._eof:
|
|
self._cond.wait()
|
|
to_read = self._written - pos
|
|
else:
|
|
while self._written <= pos and not self._eof:
|
|
self._cond.wait()
|
|
available = self._written - pos
|
|
if available <= 0:
|
|
return b""
|
|
to_read = min(size, available)
|
|
return self._reader.read(to_read)
|
|
|
|
def seek(self, offset: int, whence: int = 0) -> int:
|
|
with self._cond:
|
|
if whence == 2:
|
|
if self._total_size is not None:
|
|
target = self._total_size + offset
|
|
self._reader.seek(target, 0)
|
|
return target
|
|
while not self._eof:
|
|
self._cond.wait()
|
|
return self._reader.seek(offset, 2)
|
|
if whence == 1:
|
|
target = self._reader.tell() + offset
|
|
else:
|
|
target = offset
|
|
if target <= self._written:
|
|
return self._reader.seek(offset, whence)
|
|
if self._total_size is not None:
|
|
self._reader.seek(target, 0)
|
|
return target
|
|
while target > self._written and not self._eof:
|
|
self._cond.wait()
|
|
return self._reader.seek(offset, whence)
|
|
|
|
def tell(self) -> int:
|
|
return self._reader.tell()
|
|
|
|
def readable(self) -> bool:
|
|
return True
|
|
|
|
def seekable(self) -> bool:
|
|
return True
|
|
|
|
def writable(self) -> bool:
|
|
return False
|
|
|
|
def close(self) -> None:
|
|
try:
|
|
self._reader.close()
|
|
except Exception:
|
|
pass
|
|
try:
|
|
self._writer.close()
|
|
except Exception:
|
|
pass
|
|
|
|
@property
|
|
def written(self) -> int:
|
|
return self._written
|