# `Dala.Media.Video`
[🔗](https://github.com/manhvu/dala/blob/main/lib/dala/media/video.ex#L1)

Hardware-accelerated video streaming surface.

Uses VideoToolbox (iOS) / MediaCodec (Android) for zero-copy GPU texture rendering.
Decoded frames become GPU textures directly — no CPU bitmap copy.

Architecture:
    H264/H265 stream → Hardware Decoder → GPU Texture → Renderer

## Example

    # Start a video stream from URL
    {:ok, stream} = Dala.Media.Video.start_stream(socket, "https://example.com/video.mp4")

    # Control playback
    Dala.Media.Video.play(stream)
    Dala.Media.Video.pause(stream)
    Dala.Media.Video.seek(stream, 5000)  # milliseconds

    # Events arrive as handle_info:
    #   {:video, :frame_ready, %{texture_id: id, pts: timestamp}}
    #   {:video, :ended, %{}}
    #   {:video, :error, %{reason: reason}}

# `stream_ref`

```elixir
@type stream_ref() :: pid()
```

# `texture_id`

```elixir
@type texture_id() :: non_neg_integer()
```

# `timestamp_ms`

```elixir
@type timestamp_ms() :: non_neg_integer()
```

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `current_texture`

```elixir
@spec current_texture(stream_ref()) :: texture_id() | nil
```

Get the GPU texture ID for the current frame (for compositing).

# `duration`

```elixir
@spec duration(stream_ref()) :: timestamp_ms() | :unknown
```

Get stream duration in milliseconds.

# `pause`

```elixir
@spec pause(stream_ref()) :: :ok
```

Pause playback (keeps decoder and texture alive).

# `play`

```elixir
@spec play(stream_ref()) :: :ok
```

Resume or start playback.

# `position`

```elixir
@spec position(stream_ref()) :: timestamp_ms()
```

Get current playback position in milliseconds.

# `prepare_stream`

```elixir
@spec prepare_stream(Dala.Socket.t(), String.t(), keyword()) ::
  {:ok, stream_ref()} | {:error, term()}
```

Start decoding a stream but don't render yet (for buffering).

# `seek`

```elixir
@spec seek(stream_ref(), timestamp_ms()) :: :ok
```

Seek to a position in milliseconds.

# `set_loop`

```elixir
@spec set_loop(stream_ref(), boolean()) :: :ok
```

Set whether the stream should loop.

# `set_volume`

```elixir
@spec set_volume(stream_ref(), float()) :: :ok
```

Set volume (0.0 to 1.0).

# `start_camera_stream`

```elixir
@spec start_camera_stream(
  Dala.Socket.t(),
  keyword()
) :: {:ok, stream_ref()} | {:error, term()}
```

Start a stream from a camera feed (uses existing camera preview).

# `start_stream`

```elixir
@spec start_stream(Dala.Socket.t(), String.t(), keyword()) ::
  {:ok, stream_ref()} | {:error, term()}
```

Start a video stream from a URL or local path.

# `state`

```elixir
@spec state(stream_ref()) :: atom()
```

Get current state.

# `stop`

```elixir
@spec stop(stream_ref()) :: :ok
```

Stop playback and release all resources.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
