SPEV / media.py
spragian's picture
Release isolated single-pass SPEV decision head
2e0601e verified
Raw History Blame Contribute Delete
2.48 kB
"""Bounded video sampling for SPEV evidence."""
import io
import math
from tempfile import NamedTemporaryFile
import av
from transformers.video_utils import load_video
def decode_video(data, video_processor, *, fps, max_seconds, max_frames, max_bytes):
if len(data) > max_bytes:
raise ValueError("Video exceeds the checkpoint byte limit")
try:
with av.open(io.BytesIO(data)) as container:
if not container.streams.video:
raise ValueError("Video has no visual stream")
stream = container.streams.video[0]
duration = float(stream.duration * stream.time_base) if stream.duration is not None else None
if duration is None and container.duration is not None:
duration = container.duration / av.time_base
if duration is None or not math.isfinite(duration) or not 0 < duration <= max_seconds:
raise ValueError("Video duration is missing or exceeds the checkpoint limit")
frame_rate = float(stream.average_rate) if stream.average_rate is not None else None
if frame_rate is None or not math.isfinite(frame_rate) or frame_rate <= 0:
raise ValueError("Video frame rate is missing or invalid")
frame_count = stream.frames or math.ceil(duration * frame_rate)
if not 0 < frame_count <= max_frames:
raise ValueError("Video frame count is missing or exceeds the checkpoint limit")
except av.FFmpegError as exc:
raise ValueError("Invalid or unsupported video") from exc
def sample_indices(metadata, **kwargs):
metadata.total_num_frames = frame_count
metadata.fps = frame_rate
metadata.duration = frame_count / frame_rate
return video_processor.sample_frames(metadata=metadata, fps=fps)
with NamedTemporaryFile() as source:
source.write(data)
source.flush()
try:
frames, metadata = load_video(source.name, backend="pyav", sample_indices_fn=sample_indices)
except (av.FFmpegError, OSError) as exc:
raise ValueError("Invalid or unsupported video") from exc
if not len(frames) or not metadata.fps or not metadata.total_num_frames:
raise ValueError("Video has no decodable frames")
if metadata.frames_indices is None or len(frames) != len(metadata.frames_indices):
raise ValueError("Video sampled-frame decode is incomplete")
return frames, metadata