mirror of
https://github.com/azaion/detections.git
synced 2026-04-22 14:56:31 +00:00
[AZ-178] Implement streaming video detection endpoint
- 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
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
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
|
||||
Reference in New Issue
Block a user