YOLOv8 Video Stream Inference: Real-Time Detection Guide

YOLOv8 video stream inference allows an Ultralytics YOLO model to detect objects continuously across frames from videos, webcams, IP cameras, RTSP feeds, and other supported streaming sources. Instead of loading an entire video result set into memory, the Python API can use stream=True to return a generator that yields one Results object at a time, which is especially useful for long videos and live feeds.

YOLOv8 can also combine video detection with object tracking so that objects receive persistent IDs across consecutive frames. This makes stream inference useful for surveillance, traffic analytics, people counting, industrial monitoring, sports analysis, and other applications where detections must be processed continuously.

The actual frame rate is hardware-dependent. Model size, image resolution, GPU capability, video decoding speed, number of streams, tracking configuration, and post-processing all influence whether a specific setup can operate at the desired real-time speed.

Table of Contents

Introduction to YOLOv8 Video Stream Inference

Image inference analyzes a fixed image and returns detections once. Video stream inference repeats this process continuously as frames arrive from a video or camera.

A simplified pipeline looks like:

Video / Camera Stream
        ↓
Read Frame
        ↓
Preprocess Frame
        ↓
YOLOv8 Inference
        ↓
Bounding Boxes
Classes
Confidence Scores
        ↓
Display / Save / Analyze
        ↓
Next Frame

Ultralytics Predict mode supports images, videos, and streams through the same general prediction interface. Streaming mode is particularly important for long or continuous sources because it avoids collecting every prediction result in one large Python list.

For live systems, video inference usually has two separate performance requirements: throughput and latency. High throughput means processing many frames per second, while low latency means producing each frame’s result quickly after the frame arrives. A configuration optimized for maximum throughput is not always the configuration with the lowest live-stream delay.

What Is Video Stream Inference in YOLOv8?

Video stream inference is the process of applying a trained YOLOv8 model continuously to sequential frames.

A video can be understood as:

Frame 1
Frame 2
Frame 3
Frame 4
...

YOLOv8 analyzes these frames and creates a separate prediction result for each one.

Without tracking, detections from different frames are independent. YOLO may detect a person in every frame, but ordinary prediction mode does not inherently mean that person has the same identity across frames.

Tracking adds that temporal association.

Video Inference vs Image Inference

Image inference processes a single visual input:

Image
 ↓
YOLOv8
 ↓
Predictions

Video inference repeats the process:

Frame 1 → YOLOv8 → Predictions
Frame 2 → YOLOv8 → Predictions
Frame 3 → YOLOv8 → Predictions

The model architecture does not need to be retrained merely because the input is a video. A normal YOLOv8 detection checkpoint such as:

yolov8n.pt

can process both images and video frames.

The main differences are how the source is loaded, how results are returned, how memory is managed, and whether tracking or persistent frame-level logic is required.

How YOLOv8 Processes Video Frames

The prediction pipeline reads frames from the source and prepares them for model inference.

A simplified sequence is:

Read Frame
   ↓
Resize / Letterbox
   ↓
Convert to Tensor
   ↓
Model Forward Pass
   ↓
Confidence Filtering
   ↓
NMS
   ↓
Results Object

This happens repeatedly until the source ends or the live connection is stopped.

Ultralytics also has dedicated stream-loading infrastructure. Its current LoadStreams implementation supports RTSP, RTMP, HTTP, and TCP streams and is designed to handle multiple video streams simultaneously.

Supported Video Stream Sources

Ultralytics Predict mode accepts several types of video-oriented inputs. These can range from a local MP4 file to a webcam index or remote network stream.

The exact availability of a remote source also depends on the underlying video backend and whether your system can decode the stream format.

Local Video Files

A local video file is one of the easiest sources to process.

Python:

from ultralytics import YOLO

model = YOLO("yolov8n.pt")

results = model.predict(
    source="video.mp4",
    stream=True
)

for result in results:
    print(result.boxes)

CLI:

yolo detect predict model=yolov8n.pt source=video.mp4

A local file is useful for testing because network instability is removed from the pipeline.

Common video formats depend on the installed decoding backend, codecs, and platform.

Webcam Input

A webcam can normally be referenced using its device index.

Python:

from ultralytics import YOLO

model = YOLO("yolov8n.pt")

results = model.predict(
    source=0,
    stream=True
)

for result in results:
    print(result.boxes)

Here:

source=0

usually refers to the first available camera.

If multiple cameras are attached, another device may use:

source=1

or a different index.

Ultralytics Predict mode supports webcam-style input sources as part of its streaming inference workflow.

RTSP and IP Camera Streams

RTSP is commonly used by IP cameras and surveillance systems.

A basic Python example is:

from ultralytics import YOLO

model = YOLO("yolov8n.pt")

results = model.predict(
    source="rtsp://user:password@camera-address/stream",
    stream=True
)

for result in results:
    print(result.boxes)

Current Ultralytics stream-loading code explicitly supports RTSP streams in addition to RTMP, HTTP, and TCP sources.

An RTSP URL may contain:

protocol
username
password
camera IP or hostname
port
stream path

The exact format is determined by the camera manufacturer.

Online Video Streams

Network streams can also be supplied when the source is supported by the loader and video backend.

Ultralytics’ stream loader currently supports protocols including:

RTSP
RTMP
HTTP
TCP

for stream-oriented video loading.

For example:

results = model.predict(
    source="http://server/video-stream",
    stream=True
)

Whether a particular webpage or online video URL works directly depends on whether it resolves to a supported media stream rather than simply being a normal webpage.

How to Run YOLOv8 Video Stream Inference

YOLOv8 video stream inference can be launched through either Python or the CLI.

Python is usually preferred when predictions need to trigger custom logic, while CLI is useful for quick visual testing or saved output.

Stream Inference Using the Python API

A basic memory-efficient example is:

from ultralytics import YOLO

model = YOLO("yolov8n.pt")

results = model.predict(
    source="video.mp4",
    stream=True
)

for result in results:
    print(result.boxes)

Ultralytics documents that stream=True returns a generator of Results objects instead of storing all results in a list.

You can also add common inference settings:

results = model.predict(
    source="video.mp4",
    stream=True,
    conf=0.25,
    iou=0.7,
    imgsz=640,
    device=0
)

Stream Inference Using the YOLO CLI

A video file:

yolo detect predict model=yolov8n.pt source=video.mp4

A webcam:

yolo detect predict model=yolov8n.pt source=0

A compatible RTSP feed can be passed through source:

yolo detect predict model=yolov8n.pt source="rtsp://camera-stream"

Ultralytics CLI supports running prediction without requiring custom Python code.

Additional settings can be supplied using the Ultralytics name=value syntax:

yolo detect predict \
model=yolov8n.pt \
source=video.mp4 \
conf=0.25 \
iou=0.7 \
imgsz=640 \
device=0

Process Frames in Real Time

Using stream=True, each result can be processed as soon as the generator yields it.

Example:

from ultralytics import YOLO

model = YOLO("yolov8n.pt")

for result in model.predict(source=0, stream=True):
    if result.boxes is None:
        continue

    for box in result.boxes:
        cls_id = int(box.cls[0])
        conf = float(box.conf[0])

        print(
            "Class:",
            cls_id,
            "Confidence:",
            conf
        )

You can insert application-specific logic inside the loop:

detect person
→ trigger counter

detect vehicle
→ record event

detect defect
→ send alert

This is one of the main advantages of Python-based stream inference.

Understanding YOLOv8 Stream Results

Every yielded prediction is represented by an Ultralytics Results object.

Depending on the task, a result may contain:

boxes
masks
keypoints
probs
obb

For normal YOLOv8 object detection, result.boxes contains the most important detection information.

Bounding Boxes and Class Labels

Example:

for result in model.predict(
    source="video.mp4",
    stream=True
):
    boxes = result.boxes

    if boxes is not None:
        print(boxes.xyxy)
        print(boxes.cls)

xyxy represents:

x1
y1
x2
y2

for each box.

Class IDs are available through:

result.boxes.cls

and class-name mappings can be accessed through the result’s names mapping.

Confidence Scores

Detection confidence values are available with:

result.boxes.conf

Example:

for box in result.boxes:
    confidence = float(box.conf[0])
    class_id = int(box.cls[0])

    print(class_id, confidence)

A confidence threshold can be configured before results are returned:

results = model.predict(
    source=0,
    stream=True,
    conf=0.40
)

Higher thresholds generally reduce weak detections but can also remove valid low-confidence objects.

Frame-by-Frame Prediction Output

Each iteration corresponds to a processed input item or frame result.

Conceptually:

Frame 1
→ Results 1

Frame 2
→ Results 2

Frame 3
→ Results 3

This allows the program to maintain its own counters, logging, state, visualization, or alert systems.

For example:

frame_number = 0

for result in model.predict(
    source="video.mp4",
    stream=True
):
    frame_number += 1

    count = 0 if result.boxes is None else len(result.boxes)

    print(
        "Frame:",
        frame_number,
        "Detections:",
        count
    )

Using Stream Mode in YOLOv8

The stream option controls how prediction results are returned, not whether the source itself must be a network stream.

This distinction is important.

You can use:

stream=True

with:

local video
webcam
RTSP feed
large input source

because the purpose is memory-efficient result generation.

How stream=True Works

Default prediction behavior:

results = model.predict("video.mp4")

returns a list containing the completed prediction results.

With:

results = model.predict(
    "video.mp4",
    stream=True
)

the API returns a generator.

Ultralytics explicitly documents:

stream=False
→ list of Results

stream=True
→ generator of Results

and recommends generator-based processing for long videos and live streams.

Memory Benefits of Stream Processing

Consider a video with:

100,000 frames

Storing every result may consume substantial memory.

Without streaming:

Result 1
Result 2
Result 3
...
Result 100000
↓
kept in result collection

Streaming instead works conceptually as:

Read frame
↓
Predict
↓
Use result
↓
Release unnecessary data
↓
Next frame

This keeps memory usage much more predictable.

Ultralytics specifically describes streaming mode as memory efficient because results are yielded one at a time.

Iterating Through Prediction Results

A standard pattern is:

results = model.predict(
    source="video.mp4",
    stream=True
)

for result in results:
    print(result.boxes)

You can add processing:

for result in results:

    if result.boxes is None:
        continue

    for box in result.boxes:
        coordinates = box.xyxy[0]
        confidence = box.conf[0]
        class_id = box.cls[0]

        print(
            coordinates,
            confidence,
            class_id
        )

This approach is usually preferable to storing every result when processing long-running camera systems.

Improving YOLOv8 Video Inference Speed

Video inference speed depends on the complete pipeline, not only the neural network.

Potential bottlenecks include:

video decoding
CPU preprocessing
GPU inference
NMS
tracking
drawing
video encoding
network delay

If the application runs at low FPS, identify the slowest stage before changing the model.

Reduce Input Resolution

Reducing imgsz decreases the number of pixels processed by the model.

For example:

results = model.predict(
    source=0,
    stream=True,
    imgsz=640
)

may be considerably lighter than:

results = model.predict(
    source=0,
    stream=True,
    imgsz=1280
)

because the larger input requires substantially more computation.

However, smaller input dimensions can reduce performance for:

tiny objects
distant people
small vehicles
fine defects

so resolution should be benchmarked against detection quality.

Use GPU Acceleration

Select a CUDA GPU:

results = model.predict(
    source="video.mp4",
    stream=True,
    device=0
)

CLI:

yolo detect predict \
model=yolov8n.pt \
source=video.mp4 \
device=0

GPU inference can provide much higher throughput than CPU inference on compatible hardware, especially for larger models and resolutions.

Remember that video decoding may still occur on the CPU depending on the pipeline.

Use Half-Precision Inference

On compatible GPUs, FP16 can be tested with:

results = model.predict(
    source="video.mp4",
    stream=True,
    device=0,
    half=True
)

Half precision can reduce memory use and may improve throughput on hardware with efficient FP16 support.

The actual gain should be benchmarked because it varies by GPU and backend.

Choose a Smaller YOLOv8 Model

YOLOv8 detection models include:

yolov8n
yolov8s
yolov8m
yolov8l
yolov8x

For high-FPS applications:

model = YOLO("yolov8n.pt")

may be more suitable than:

model = YOLO("yolov8x.pt")

because Nano requires much less computation.

The tradeoff is that smaller models generally have lower capacity, so detection quality should be evaluated before deployment.

YOLOv8 Inference on Live Camera Streams

Live cameras add problems that do not exist with prerecorded videos.

A local file can usually be read as fast as the hardware allows. A live camera produces frames according to its own frame rate, network conditions, encoder settings, and connection quality.

For IP cameras, network latency and stream buffering can become as important as model inference speed.

Connect to a Webcam

Basic webcam prediction:

from ultralytics import YOLO

model = YOLO("yolov8n.pt")

results = model.predict(
    source=0,
    stream=True
)

for result in results:
    print(result.boxes)

For faster inference:

results = model.predict(
    source=0,
    stream=True,
    imgsz=640,
    device=0,
    half=True
)

The actual FPS depends on webcam frame rate, model speed, hardware, and drawing/output work.

Use RTSP Camera URLs

Example:

from ultralytics import YOLO

model = YOLO("yolov8n.pt")

rtsp_url = "rtsp://user:password@camera/stream"

for result in model.predict(
    source=rtsp_url,
    stream=True
):
    print(result.boxes)

Ultralytics’ stream loader currently supports RTSP alongside RTMP, HTTP, and TCP streams.

Do not hard-code camera passwords into public repositories. Production systems should load credentials from a secure configuration mechanism.

Handle Unstable or Dropped Frames

Live streams can fail because of:

network packet loss
camera restart
Wi-Fi instability
RTSP timeout
decoder failure
CPU overload
slow model inference

Ultralytics’ stream loader contains logic for asynchronous stream loading, but application-level reconnection handling may still be necessary for production systems.

A robust deployment should consider:

connection timeout
retry logic
logging
camera health checks
buffer management

If the detector processes frames more slowly than they arrive, latency can build up unless the pipeline is designed to discard or skip outdated frames.

Video Stream Inference with Object Tracking

Prediction detects objects independently in each frame.

Tracking attempts to associate detections across frames and assign persistent IDs.

Ultralytics Track mode provides this functionality and currently supports multiple trackers.

Track Objects Across Frames

Python:

from ultralytics import YOLO

model = YOLO("yolov8n.pt")

results = model.track(
    source="video.mp4",
    stream=True,
    persist=True
)

for result in results:
    print(result.boxes)

Tracking extends standard detections with temporal identity information. Ultralytics describes tracking results as normal detection outputs with the added value of object IDs.

Maintain Unique Object IDs

When IDs are available:

for result in results:

    if (
        result.boxes is not None
        and result.boxes.id is not None
    ):
        track_ids = (
            result.boxes.id
            .int()
            .cpu()
            .tolist()
        )

        print(track_ids)

Example:

Frame 1:
Person ID 3

Frame 2:
Person ID 3

Frame 3:
Person ID 3

The goal is to maintain the same identity as the object moves through consecutive frames, though no tracker can guarantee perfect identity consistency in all conditions.

Use BoT-SORT or ByteTrack

Current Ultralytics tracking supports BoT-SORT and ByteTrack, in addition to newer tracker options available in recent versions. BoT-SORT remains a documented default tracker configuration.

BoT-SORT:

results = model.track(
    source="video.mp4",
    tracker="botsort.yaml",
    stream=True
)

ByteTrack:

results = model.track(
    source="video.mp4",
    tracker="bytetrack.yaml",
    stream=True
)

CLI examples:

yolo track \
model=yolov8n.pt \
source=video.mp4 \
tracker=botsort.yaml

and:

yolo track \
model=yolov8n.pt \
source=video.mp4 \
tracker=bytetrack.yaml

Recent Ultralytics releases also document OC-SORT, Deep OC-SORT, FastTracker, and TrackTrack, so available tracking choices can depend on the installed package version.

Saving YOLOv8 Video Stream Results

Stream results can be saved as annotated media, labels, or custom frame-level data.

The best approach depends on whether you need human-readable output, machine-readable detections, or both.

Save Annotated Video Output

Python:

model.predict(
    source="video.mp4",
    save=True
)

CLI:

yolo detect predict \
model=best.pt \
source=video.mp4 \
save=True

The predictor can write processed results to the run output directory. Ultralytics’ predictor includes result-writing functionality for image and video prediction outputs.

For continuous production systems, monitor disk usage because recorded streams can become very large.

Save Detection Labels

You can request text output:

model.predict(
    source="video.mp4",
    save_txt=True
)

Confidence can also be included where appropriate:

model.predict(
    source="video.mp4",
    save_txt=True,
    save_conf=True
)

Ultralytics’ result-writing format supports detection entries containing class and normalized box coordinates, with optional confidence and tracking IDs depending on the result.

Export Frame-Level Results

For complete control, extract predictions programmatically.

Example:

import json
from ultralytics import YOLO

model = YOLO("best.pt")

frame_results = []

for frame_index, result in enumerate(
    model.predict(
        source="video.mp4",
        stream=True
    )
):
    detections = []

    if result.boxes is not None:
        for box in result.boxes:
            detections.append({
                "class_id": int(box.cls[0]),
                "confidence": float(box.conf[0]),
                "xyxy": box.xyxy[0].tolist(),
            })

    frame_results.append({
        "frame": frame_index,
        "detections": detections,
    })

with open("results.json", "w") as f:
    json.dump(frame_results, f)

For extremely long streams, writing each result incrementally is more memory efficient than building one enormous list.

Common YOLOv8 Video Stream Inference Problems

Video systems can fail even when image prediction works correctly because a stream adds decoding, timing, networking, and memory-management requirements.

Troubleshooting should therefore inspect the full pipeline rather than only the YOLO model.

Low FPS and Slow Processing

Possible causes include:

large YOLOv8 model
high imgsz
CPU inference
slow decoding
tracking overhead
drawing every frame
video encoding
disk writes

Test progressively:

YOLOv8x → YOLOv8m → YOLOv8s → YOLOv8n

and:

imgsz=1280
↓
imgsz=960
↓
imgsz=640

while monitoring validation accuracy.

Do not reduce model size or resolution blindly if the system must detect small or difficult objects.

High GPU Memory Usage

Reduce:

imgsz
model size
number of simultaneous streams
batch size where applicable

and test:

half=True

on compatible hardware.

Segmentation and pose models can also use more output memory than simple detection because additional masks or keypoints must be stored.

Stream Connection Errors

If an RTSP stream fails, confirm that it works outside YOLO first.

Check:

camera IP
port
username
password
stream path
network accessibility
codec support

Ultralytics supports common network stream protocols, but it cannot process a stream that the underlying system cannot access or decode.

Delayed or Dropped Frames

If inference is slower than incoming video:

camera = 30 FPS
detector = 10 FPS

the application cannot fully analyze every frame at the original rate without accumulating delay or changing how frames are handled.

Possible solutions include:

use smaller model
reduce imgsz
use GPU
use FP16
skip frames
lower camera FPS
reduce number of streams
avoid expensive drawing/output

For live monitoring, processing the newest available frame can sometimes be more valuable than guaranteeing that every old frame is processed.

FAQs About YOLOv8 Video Stream Inference

How do I run YOLOv8 on a video stream?

Using Python:

from ultralytics import YOLO

model = YOLO("yolov8n.pt")

for result in model.predict(
    source="video.mp4",
    stream=True
):
    print(result.boxes)

Ultralytics documents stream=True as the memory-efficient approach for yielding video or stream prediction results one at a time.

Can YOLOv8 process webcam video in real time?

Yes, webcam input can be used as a prediction source.

Example:

model.predict(
    source=0,
    stream=True
)

Whether the application actually reaches the camera’s real-time frame rate depends on the YOLOv8 model, GPU or CPU, input resolution, camera frame rate, and additional processing.

Can YOLOv8 use RTSP camera streams?

Yes.

Current Ultralytics stream-loading functionality explicitly supports RTSP streams.

Example:

model.predict(
    source="rtsp://camera-stream",
    stream=True
)

What does stream=True mean in YOLOv8?

stream=True changes the prediction output into a generator.

Instead of:

all results
→ returned together as a list

it behaves as:

result 1
→ yield

result 2
→ yield

result 3
→ yield

Ultralytics recommends this for long videos and live streams because it reduces result-storage memory requirements.

How can I increase YOLOv8 video inference FPS?

Common approaches include:

use a faster GPU
reduce imgsz
use YOLOv8n or YOLOv8s
enable FP16 on compatible hardware
reduce output drawing
reduce video encoding overhead
skip unnecessary frames

Always compare the speed improvement against detection quality.

For small or distant targets, aggressively reducing image resolution can increase FPS while significantly reducing recall.

Can YOLOv8 track objects in a live video stream?

Yes.

Use Track mode:

results = model.track(
    source=0,
    stream=True,
    persist=True
)

Ultralytics tracking adds object IDs to detection results and supports trackers including BoT-SORT and ByteTrack.

How do I save YOLOv8 video stream predictions?

For annotated output:

model.predict(
    source="video.mp4",
    save=True
)

For labels:

model.predict(
    source="video.mp4",
    save_txt=True,
    save_conf=True
)

Ultralytics results support text export containing class and box information, with optional confidence and track IDs depending on the prediction type.

Conclusion

YOLOv8 video stream inference allows Ultralytics models to perform continuous object detection on recorded videos, webcams, RTSP cameras, and other supported stream sources.

A basic Python workflow is:

from ultralytics import YOLO

model = YOLO("yolov8n.pt")

results = model.predict(
    source="video.mp4",
    stream=True,
    conf=0.25,
    imgsz=640,
    device=0
)

for result in results:
    print(result.boxes)

The most important setting for memory-efficient video processing is:

stream=True

because current Ultralytics returns a generator that yields Results objects one at a time instead of retaining the entire result collection in memory.

The basic stream pipeline is:

Video / Camera
      ↓
Read Frame
      ↓
YOLOv8 Inference
      ↓
Bounding Boxes
Classes
Confidence
      ↓
Application Logic
      ↓
Next Frame

For IP-camera deployments, current Ultralytics stream loading supports protocols including:

RTSP
RTMP
HTTP
TCP

and can handle multiple video streams.

When object identity matters, use Track mode:

results = model.track(
    source="video.mp4",
    stream=True,
    persist=True,
    tracker="botsort.yaml"
)

Ultralytics tracking adds persistent IDs to detections and supports BoT-SORT, ByteTrack, and additional trackers in recent releases.

A practical optimization workflow is:

Start Video Inference
       ↓
Measure FPS and Latency
       ↓
Check GPU / CPU Usage
       ↓
Reduce imgsz if Appropriate
       ↓
Test Smaller YOLOv8 Model
       ↓
Enable GPU + FP16
       ↓
Reduce Drawing / Saving Overhead
       ↓
Test Live Stream Stability
       ↓
Add Tracking if Required

Real-time performance should always be measured on the actual deployment hardware and camera source. A configuration that performs well on a desktop GPU may behave very differently on a CPU, edge device, or multi-camera server.

For long videos and continuous cameras, stream=True is usually the appropriate Python workflow because it keeps result memory under control while allowing every prediction to be processed immediately as it becomes available.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top