# Stream-Based run_detect

**Task**: AZ-173_stream_based_run_detect
**Name**: Replace path-based run_detect with stream-based API in inference.pyx
**Description**: Refactor `run_detect` in `inference.pyx` to accept media bytes/stream instead of a config dict with local file paths. Enable simultaneous disk write and frame-by-frame detection for video.
**Complexity**: 3 points
**Dependencies**: None (core change, other subtasks depend on this)
**Component**: Inference
**Jira**: AZ-173
**Parent**: AZ-172

## Problem

`run_detect` currently takes a `config_dict` containing `paths: list[str]` — local filesystem paths. It iterates over them, guesses media type via `mimetypes.guess_type`, and opens files with `cv2.VideoCapture` or `cv2.imread`. This doesn't work when the caller is on a different device.

## Current State

```python
cpdef run_detect(self, dict config_dict, object annotation_callback, object status_callback=None):
    ai_config = AIRecognitionConfig.from_dict(config_dict)
    for p in ai_config.paths:
        if self.is_video(p): videos.append(p)
        else: images.append(p)
    self._process_images(ai_config, images)    # cv2.imread(path)
    for v in videos:
        self._process_video(ai_config, v)       # cv2.VideoCapture(path)
```

## Target State

Split into two dedicated methods:

- `run_detect_video(self, stream, AIRecognitionConfig ai_config, str media_name, str save_path, ...)` — accepts a video stream/bytes, writes to `save_path` while decoding frames for detection
- `run_detect_image(self, bytes image_bytes, AIRecognitionConfig ai_config, str media_name, ...)` — accepts image bytes, decodes in memory

Remove:
- `is_video(self, str filepath)` method
- `paths` iteration loop in `run_detect`
- Direct `cv2.VideoCapture(local_path)` and `cv2.imread(local_path)` calls

## Video Stream Processing — PyAV (preferred)

Use **PyAV** (`av` package) for byte-stream video decoding. Preferred approach per user decision.

**Why PyAV**: Decode frames directly from bytes/stream via `av.open(io.BytesIO(data))` without intermediate file I/O. Most flexible for streaming, no concurrent file read/write synchronization needed.

**Investigation needed during implementation**:
- Verify PyAV can decode frames from a growing `BytesIO` or chunked stream (not just complete files)
- Check if `av.open()` supports reading from an async generator or pipe for true streaming
- Evaluate whether simultaneous disk write can be done with a `tee`-style approach (write bytes to file while feeding to PyAV)
- Confirm PyAV frame format (RGB/BGR/YUV) compatibility with existing `process_frames` pipeline (expects BGR numpy arrays)
- Check PyAV version compatibility with the project's Python/Cython setup
- Fallback: if PyAV streaming is not viable, use write-then-read with `cv2.VideoCapture` on completed file

## Acceptance Criteria

- [ ] Video can be processed from bytes/stream without a local file path from the caller
- [ ] Video is simultaneously written to disk and processed frame-by-frame
- [ ] Image can be processed from bytes without a local file path
- [ ] `_process_video_batch` and batch processing logic preserved (only input source changes)
- [ ] All existing detection logic (tile splitting, validation, tracking) unaffected

## File Changes

| File | Action | Description |
|------|--------|-------------|
| `src/inference.pyx` | Modified | New stream-based methods, remove path-based `run_detect` |
| `src/main.py` | Modified | Adapt callers to new method signatures |
