# How to Implement Adaptive Streaming with video-use: A Complete Guide

> Learn to implement adaptive streaming with video-use. Extend the ffmpeg wrapper to generate multi-bitrate HLS or DASH manifests for optimized video delivery.

- Repository: [Browser Use/video-use](https://github.com/browser-use/video-use)
- Tags: how-to-guide
- Published: 2026-07-10

---

**You can implement adaptive streaming in video-use by extending the existing ffmpeg wrapper in [`helpers/render.py`](https://github.com/browser-use/video-use/blob/main/helpers/render.py) to generate multi-bitrate HLS or DASH manifests after the final MP4 render completes.**

The video-use repository processes video edits through an automated pipeline that produces a single finalized MP4 at `edit/final.mp4`. To implement adaptive streaming with video-use, you must generate multiple bitrate renditions and a master playlist that video players can switch between on-the-fly based on network conditions. This guide demonstrates how to extend the existing ffmpeg-based architecture to output HTTP Live Streaming (HLS) or MPEG-DASH assets without modifying the core editing logic.

## Understanding the video-use Rendering Architecture

### Centralized ffmpeg Execution in render.py

All video processing in video-use funnels through [`helpers/render.py`](https://github.com/browser-use/video-use/blob/main/helpers/render.py), where ffmpeg commands are constructed as argument lists and executed via the `run()` function. This centralized approach ensures consistent handling of cuts, color grading, and loudness normalization throughout the pipeline.

The `run()` function accepts a command list and handles execution, making it the ideal extension point for post-render adaptive streaming generation.

### Reusing Color Grading Filters

The repository applies per-clip color grading through [`helpers/grade.py`](https://github.com/browser-use/video-use/blob/main/helpers/grade.py), which utilizes ffmpeg's `signalstats` filter to compute custom filter chains. When implementing adaptive streaming, you can reuse these exact filter strings to ensure each bitrate rendition maintains the same visual grade as the final MP4.

### Temporary File Management

Following the pattern established in [`helpers/timeline_view.py`](https://github.com/browser-use/video-use/blob/main/helpers/timeline_view.py), which uses `tempfile.mkdtemp` for temporary directories, adaptive streaming generation should write to a dedicated temporary folder (e.g., `hls/`) that can be safely removed after upload to your CDN.

## Creating the Adaptive Streaming Helper

### Implementing the make_hls Function

Create a new file at [`helpers/adaptive_stream.py`](https://github.com/browser-use/video-use/blob/main/helpers/adaptive_stream.py) that imports the existing `run()` function and generates HLS assets:

```python

# helpers/adaptive_stream.py

import json, pathlib, subprocess
from .render import run

def make_hls(video_path: pathlib.Path, out_dir: pathlib.Path, resolutions=None):
    """Create HLS adaptive-bitrate assets from *video_path*."""
    if resolutions is None:
        # Default renditions (width, height, bitrate Kbps)

        resolutions = [(1920, 1080, 5000),
                       (1280, 720, 2800),
                       (854, 480, 1400),
                       (640, 360, 800)]

    out_dir.mkdir(parents=True, exist_ok=True)
    variant_playlists = []

    for i, (w, h, br) in enumerate(resolutions):
        variant = out_dir / f"variant{i}.m3u8"
        cmd = [
            "ffmpeg", "-y", "-i", str(video_path),
            "-vf", f"scale=w={w}:h={h}",
            "-c:v", "libx264", "-b:v", f"{br}k",
            "-c:a", "aac", "-b:a", "128k",
            "-hls_time", "6",
            "-hls_playlist_type", "vod",
            "-hls_segment_filename", str(out_dir / f"seg{i}_%03d.ts"),
            str(variant)
        ]
        run(cmd, quiet=True)
        variant_playlists.append((w, h, variant.name))

    # Master playlist

    master = out_dir / "master.m3u8"
    with master.open("w") as fp:
        fp.write("#EXTM3U\n")
        for w, h, v in variant_playlists:
            fp.write(f'#EXT-X-STREAM-INF:BANDWIDTH={int(br*1000)},RESOLUTION={w}x{h}\n{v}\n')
    return master

```

### Handling Multiple Bitrate Renditions

The function generates four standard renditions by default: 1080p at 5000 Kbps, 720p at 2800 Kbps, 480p at 1400 Kbps, and 360p at 800 Kbps. Each rendition uses ffmpeg's `scale` filter to resize the video while maintaining the original aspect ratio, ensuring the adaptive stream covers a full range of device capabilities and network speeds.

### Generating the Master Playlist

After creating individual variant playlists, the helper generates a master playlist (`master.m3u8`) that maps each resolution to its corresponding bandwidth and segment file using the `#EXT-X-STREAM-INF` tag. This manifest enables players to automatically switch between qualities as network conditions change.

## Integrating Adaptive Streaming into the Pipeline

### Hooking into the Render Process

Modify [`helpers/render.py`](https://github.com/browser-use/video-use/blob/main/helpers/render.py) or the top-level script that invokes the render step to call `make_hls` immediately after the final MP4 production:

```python
from .adaptive_stream import make_hls

# after the normal render finishes:

final_mp4 = output_dir / "final.mp4"
hls_dir = output_dir / "hls"
make_hls(final_mp4, hls_dir)
print(f"✅ Adaptive HLS ready at {hls_dir / 'master.m3u8'}")

```

### Serving HLS Assets

The generated `hls/` directory contains the `master.m3u8` manifest and segmented `.ts` files. You can deploy these files to any static web server, CDN, GitHub Pages, or Netlify. Point your video player to `https://your-host/hls/master.m3u8` to enable adaptive playback.

For HTML5 playback in browsers without native HLS support, use hls.js:

```html
<video id="vid" controls></video>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script>
if (Hls.isSupported()) {
  const hls = new Hls();
  hls.loadSource('https://your-host/edit/hls/master.m3u8');
  hls.attachMedia(document.getElementById('vid'));
}
</script>

```

## Implementing DASH as an Alternative

### MPEG-DASH Configuration

For MPEG-DASH compatibility, replace the HLS-specific ffmpeg arguments with `-f dash` and adjust the segment filename pattern. The same helper pattern works; just modify the command to generate a `manifest.mpd` file instead of an m3u8 playlist:

```python
cmd = [
    "ffmpeg", "-y", "-i", str(video_path),
    "-vf", f"scale=w={w}:h={h}",
    "-c:v", "libx264", "-b:v", f"{br}k",
    "-f", "dash",
    "-dash_segment_filename", str(out_dir / f"seg{i}_%03d.m4s"),
    str(out_dir / f"manifest{i}.mpd")
]

```

## Summary

- Extend [`helpers/render.py`](https://github.com/browser-use/video-use/blob/main/helpers/render.py) by creating a new `make_hls` function in [`helpers/adaptive_stream.py`](https://github.com/browser-use/video-use/blob/main/helpers/adaptive_stream.py) that leverages the existing `run()` wrapper
- Generate multiple bitrate renditions (1080p, 720p, 480p, 360p) while preserving color grading consistency from [`helpers/grade.py`](https://github.com/browser-use/video-use/blob/main/helpers/grade.py)
- Create a master playlist that maps bandwidth to resolution for automatic quality switching by video players
- Store temporary HLS files in a dedicated subdirectory following the `tempfile.mkdtemp` pattern used in [`helpers/timeline_view.py`](https://github.com/browser-use/video-use/blob/main/helpers/timeline_view.py)
- Serve the resulting `.m3u8` and `.ts` files via any static web server, CDN, or GitHub Pages

## Frequently Asked Questions

### Can I use the existing color grades with adaptive streaming?

Yes. The [`helpers/grade.py`](https://github.com/browser-use/video-use/blob/main/helpers/grade.py) module generates ffmpeg filter strings that you can apply to each bitrate rendition during the HLS generation process. This ensures visual consistency across all quality levels by utilizing the same `signalstats`-based filter chains used in the main render pipeline.

### Where should I store the generated HLS files?

Store them in a temporary subdirectory (e.g., `hls/` inside the output directory) following the pattern established in [`helpers/timeline_view.py`](https://github.com/browser-use/video-use/blob/main/helpers/timeline_view.py), which uses `tempfile.mkdtemp` for temporary file management. You can safely remove these files after uploading to your CDN or streaming server.

### How do I serve the adaptive streaming content?

Serve the `hls/` folder contents via any static web server, Nginx, GitHub Pages, or Netlify. For HTML5 playback, use hls.js or native HLS support in Safari and mobile devices by pointing the player to `master.m3u8`.

### Does this work with live streaming or only VOD?

The implementation described targets Video on Demand (VOD) using `-hls_playlist_type vod`. For live streaming, you would need to modify the ffmpeg arguments to use `-hls_playlist_type event` or `-hls_playlist_type live` and implement a continuous upload mechanism to your streaming server.