How to Convert RTSP to HLS with FFmpeg
This article provides a straightforward guide on using FFmpeg to
convert a remote RTSP (Real-Time Streaming Protocol) feed from an IP
camera into HTTP Live Streaming (HLS) format. By executing a single
FFmpeg command, you can capture the network stream, segment the video,
and generate an .m3u8 playlist along with .ts
media segments suitable for playback in standard web browsers and mobile
devices.
Direct Stream Copy (Recommended)
If your RTSP camera already outputs video in H.264 and audio in AAC, you do not need to re-encode the stream. Using stream copy minimizes CPU usage and introduces minimal latency.
Run the following command in your terminal:
ffmpeg -rtsp_transport tcp -i "rtsp://username:password@camera_ip:554/stream" \
-c:v copy \
-c:a aac \
-f hls \
-hls_time 2 \
-hls_list_size 5 \
-hls_flags delete_segments \
-hls_segment_filename "segment_%03d.ts" \
index.m3u8Parameter Breakdown
-rtsp_transport tcp: Forces TCP instead of UDP to prevent dropped packets, frame smearing, and video corruption over unstable network links.-i "rtsp://...": Specifies the input URL of the remote RTSP camera.-c:v copy: Copies the video stream without re-encoding, preserving quality and keeping CPU load near zero.-c:a aac: Ensures the audio stream is encoded in AAC format, which is the standard requirement for HLS playback.-f hls: Sets the output container format to HLS.-hls_time 2: Sets the target duration for each.tsvideo chunk (in seconds).-hls_list_size 5: Limits the.m3u8playlist to a maximum of 5 recent segments, which is standard for live streaming.-hls_flags delete_segments: Automatically deletes older segment files from the disk when they drop off the playlist to avoid filling storage.-hls_segment_filename "segment_%03d.ts": Defines the naming pattern for generated segment files.index.m3u8: The final manifest file accessed by the video player.
Transcoding the Stream
If your camera outputs an unsupported codec (such as H.265 or MJPEG),
or if the keyframe intervals are too inconsistent for clean
segmentation, transcode the video using the libx264
encoder:
ffmpeg -rtsp_transport tcp -i "rtsp://username:password@camera_ip:554/stream" \
-c:v libx264 \
-preset veryfast \
-tune zerolatency \
-g 60 \
-sc_threshold 0 \
-c:a aac \
-b:a 128k \
-f hls \
-hls_time 2 \
-hls_list_size 5 \
-hls_flags delete_segments \
-hls_segment_filename "segment_%03d.ts" \
index.m3u8Additional Parameters for Transcoding
-c:v libx264: Encodes video to H.264 standard.-preset veryfast: Optimizes encoding speed to prevent the stream from falling behind real time.-tune zerolatency: Reduces buffering and pipeline delay for live streaming.-g 60: Sets the Group of Pictures (GOP) size to 60 frames. For a 30 fps stream, this generates an IDR/keyframe every 2 seconds, aligning perfectly with-hls_time 2.-sc_threshold 0: Disables scene change detection so keyframe intervals remain strictly predictable.
Serving the HLS Output
Once FFmpeg is running, place the output directory inside the root of a web server such as Nginx or Apache. Ensure the server includes proper Cross-Origin Resource Sharing (CORS) headers and MIME types:
.m3u8:application/vnd.apple.mpegurl.ts:video/mp2t- Header:
Access-Control-Allow-Origin: *
The feed can then be loaded in web players such as Video.js or Hls.js
using the URL pointing to index.m3u8.