Build Local Video Streaming with Spring Boot, FFmpeg, and ZLMediaKit
This tutorial demonstrates building a local video streaming pipeline using Spring Boot to orchestrate FFmpeg for transcoding and ZLMediaKit as the media server, covering Docker deployment, RTMP/HLS configuration, and a web-based FLV player using flv.js.
Environment Preparation
ZLMediaKit Installation and Configuration
Deploy ZLMediaKit via Docker with the following command, exposing ports for RTMP (1935), HTTP API (8099), RTSP (8554), and WebRTC (10000/udp, 8000/udp). Mount a local config.ini for HLS settings.
# Pull image
docker pull zlmediakit/zlmediakit:master
# Start container
docker run -d \
--name zlm-server \
-p 1935:1935 \
-p 8099:80 \
-p 8554:554 \
-p 10000:10000 \
-p 10000:10000/udp \
-p 8000:8000/udp \
-v /docker-volumes/zlmediakit/conf/config.ini:/opt/media/conf/config.ini \
zlmediakit/zlmediakit:masterKey HLS configuration in config.ini:
[hls]
broadcastRecordTs=0
deleteDelaySec=300 # Keep stream 5 minutes
fileBufSize=65536
filePath=./www # Save path
segDur=2 # Segment duration (seconds)
segNum=1000 # Max segments in m3u8
segRetain=9999 # Retain history segments on diskVerify startup with docker logs -f zlm-server.
FFmpeg Installation
Download FFmpeg (e.g., version 7.0.2) from the official site, extract, and add the bin directory to the system PATH environment variable.
Spring Boot Backend Implementation
Dependencies
Add Apache Commons Exec for process management:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-exec</artifactId>
<version>1.3</version>
</dependency>Stream Configuration Class
Map properties under prefix stream:
@Data
@Component
@ConfigurationProperties(prefix = "stream")
public class StreamConfig {
private String zlmHost;
private Integer rtmpPort;
private Integer httpPort;
private String ffmpegPath;
private String videoPath;
}Stream Service Class
Core service managing FFmpeg processes via DefaultExecutor and ExecuteWatchdog. Uses ConcurrentHashMap to track active streams and manual stop flags.
Start Streaming ( startStream )
Validate video file exists.
Build RTMP URL: rtmp://{zlmHost}:{rtmpPort}/live/{streamKey}.
Construct FFmpeg command line: -re — read at native frame rate -i {videoPath} — input file -c:v libx264 — video codec -c:a aac — audio codec -f flv — output format -flvflags no_duration_filesize — FLV flags for streaming
Output to RTMP URL
Configure executor with infinite watchdog, output stream handler, and async ExecuteResultHandler to log completion/failure and clean up maps.
Store executor reference keyed by streamKey.
Stop Streaming ( stopStream )
Retrieve executor by streamKey.
Set manual stop flag.
Destroy process via watchdog.
Remove from maps and log result.
Utility Methods getPlayUrl(streamKey, protocol) — returns HTTP-FLV ( http://{host}:{httpPort}/live/{key}.live.flv) or HLS ( http://{host}:{httpPort}/live/{key}/hls.m3u8) playback URLs. isStreaming(streamKey) — checks if streamKey exists in active map.
Application Configuration (YAML)
stream:
zlm-host: 192.168.159.129
rtmp-port: 1935
http-port: 8099
ffmpeg-path: ffmpeg
video-path: \videos\
spring:
servlet:
multipart:
max-file-size: 1GB
max-request-size: 1GBUsage Instructions
Streaming Workflow
Start ZLMediaKit service.
Upload video file to server.
Call streaming endpoint with video path and stream key.
Spring Boot launches FFmpeg to push RTMP stream to ZLMediaKit.
Playback Workflow
Obtain playback URL (HTTP-FLV or HLS) via getPlayUrl.
Supports live playback and recorded playback (HLS).
Manual FFmpeg Test Command
ffmpeg -re -i "C:\Users\lyk19\Videos\8月9日.mp4" \
-c:v libx264 -preset ultrafast -tune zerolatency \
-c:a aac -ar 44100 -b:a 128k \
-f flv rtmp://192.168.159.129:1935/live/streamFrontend Player (flv.js)
HTML page loads flv.js from CDN, creates a <video> element, and attaches an FLV player instance with configuration:
flvPlayer = flvjs.createPlayer({
type: 'flv',
url: 'http://192.168.159.129:8099/live/stream.live.flv',
isLive: true
}, {
enableWorker: false,
lazyLoad: true,
lazyLoadMaxDuration: 3 * 60,
deferLoadAfterSourceOpen: false,
autoCleanupSourceBuffer: true,
enableStashBuffer: false
});
flvPlayer.attachMediaElement(videoElement);
flvPlayer.load();Event listeners handle errors, loading completion, recovery, and video element events (loadstart, canplay, playing, pause, error). UI controls for play, pause, stop, mute with status updates.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
