Skip to content

Commit 3911fd8

Browse files
encoded_video_ingest
1 parent 6055c28 commit 3911fd8

7 files changed

Lines changed: 1214 additions & 44 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,4 @@ add_subdirectory(simple_joystick_receiver)
9494
add_subdirectory(ping_pong_ping)
9595
add_subdirectory(ping_pong_pong)
9696
add_subdirectory(user_timestamped_video)
97+
add_subdirectory(encoded-video-ingest)
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Copyright 2026 LiveKit, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
add_executable(EncodedVideoIngestProducer
16+
producer.cpp
17+
)
18+
19+
target_include_directories(EncodedVideoIngestProducer PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
20+
target_link_libraries(EncodedVideoIngestProducer PRIVATE ${LIVEKIT_CORE_TARGET})
21+
22+
if(WIN32)
23+
target_link_libraries(EncodedVideoIngestProducer PRIVATE ws2_32)
24+
endif()
25+
26+
livekit_copy_windows_runtime_dlls(EncodedVideoIngestProducer)
27+
28+
add_executable(EncodedVideoIngestConsumer
29+
consumer.cpp
30+
../simple_room/sdl_video_renderer.cpp
31+
../simple_room/sdl_video_renderer.h
32+
)
33+
34+
target_include_directories(EncodedVideoIngestConsumer PRIVATE
35+
${CMAKE_CURRENT_SOURCE_DIR}
36+
${CMAKE_CURRENT_SOURCE_DIR}/../simple_room
37+
)
38+
target_link_libraries(EncodedVideoIngestConsumer PRIVATE ${LIVEKIT_CORE_TARGET} SDL3::SDL3)
39+
40+
livekit_copy_windows_runtime_dlls(EncodedVideoIngestConsumer)

encoded-video-ingest/README.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# encoded-video-ingest
2+
3+
End-to-end encoded video ingest demo for the LiveKit C++ SDK. GStreamer serves
4+
an encoded bytestream over TCP; the producer reads that stream, splits complete
5+
frames, pushes them into an encoded `VideoSource`, and publishes a normal local
6+
video track. The consumer subscribes to the decoded track and renders it with
7+
SDL.
8+
9+
This example intentionally does not use the removed `EncodedTcpIngest` helper.
10+
TCP reconnect and bytestream framing are application code; the SDK surface is
11+
`VideoSource(width, height, EncodedVideoSourceOptions{codec})` plus
12+
`captureEncodedFrame`.
13+
14+
## Prerequisites
15+
16+
- A LiveKit server, such as `livekit-server --dev`.
17+
- GStreamer 1.22+ with `good`, `bad`, `ugly`, and `libav` plugins.
18+
- Producer and consumer tokens for the same room.
19+
20+
```bash
21+
export LIVEKIT_URL=ws://localhost:7880
22+
export PRODUCER_TOKEN="$(lk token create -r encoded-video-demo -i encoded-sender --join --publish)"
23+
export CONSUMER_TOKEN="$(lk token create -r encoded-video-demo -i encoded-receiver --join --subscribe)"
24+
```
25+
26+
## H.264
27+
28+
Start a camera pipeline that serves AUD-delimited Annex-B H.264 on TCP port
29+
5005:
30+
31+
```bash
32+
gst-launch-1.0 -v \
33+
avfvideosrc device-index=0 ! \
34+
video/x-raw,width=640,height=480,format=NV12,framerate=30/1 ! \
35+
videoconvert ! \
36+
x264enc tune=zerolatency speed-preset=ultrafast bitrate=1000 key-int-max=60 aud=true ! \
37+
h264parse config-interval=1 ! \
38+
video/x-h264,stream-format=byte-stream,alignment=au ! \
39+
tcpserversink host=0.0.0.0 port=5005 sync=false async=false
40+
```
41+
42+
Linux: replace `avfvideosrc device-index=0` with
43+
`v4l2src device=/dev/video0`. Windows: use `mfvideosrc device-index=0`.
44+
45+
Run the producer:
46+
47+
```bash
48+
LIVEKIT_URL=ws://localhost:7880 LIVEKIT_TOKEN="$PRODUCER_TOKEN" \
49+
./build/encoded-video-ingest/EncodedVideoIngestProducer \
50+
--tcp-host 127.0.0.1 --tcp-port 5005 \
51+
--width 640 --height 480 \
52+
--codec h264
53+
```
54+
55+
Run the consumer:
56+
57+
```bash
58+
LIVEKIT_URL=ws://localhost:7880 LIVEKIT_TOKEN="$CONSUMER_TOKEN" \
59+
./build/encoded-video-ingest/EncodedVideoIngestConsumer \
60+
--from encoded-sender \
61+
--track-name encoded-h264
62+
```
63+
64+
## Other Codecs
65+
66+
H.265 uses the same Annex-B framing path:
67+
68+
```bash
69+
gst-launch-1.0 -v \
70+
avfvideosrc device-index=0 ! \
71+
video/x-raw,width=640,height=480,format=NV12,framerate=30/1 ! \
72+
videoconvert ! \
73+
x265enc tune=zerolatency speed-preset=ultrafast bitrate=1000 key-int-max=60 \
74+
option-string="aud=1:repeat-headers=1" ! \
75+
h265parse config-interval=1 ! \
76+
video/x-h265,stream-format=byte-stream,alignment=au ! \
77+
tcpserversink host=0.0.0.0 port=5005 sync=false async=false
78+
```
79+
80+
Pass `--codec h265` and use `--track-name encoded-h265` on the consumer.
81+
82+
VP8 and AV1 use IVF framing:
83+
84+
```bash
85+
gst-launch-1.0 -v \
86+
avfvideosrc device-index=0 ! \
87+
video/x-raw,width=640,height=480,format=NV12,framerate=30/1 ! \
88+
videoconvert ! \
89+
vp8enc deadline=1 target-bitrate=1000000 keyframe-max-dist=60 ! \
90+
ivfmux ! \
91+
tcpserversink host=0.0.0.0 port=5005 sync=false async=false
92+
```
93+
94+
Pass `--codec vp8` and use `--track-name encoded-vp8`. For AV1, replace the
95+
encoder with `av1enc`, `svtav1enc`, or `rav1enc`, pass `--codec av1`, and use
96+
`--track-name encoded-av1`.
97+
98+
VP9 is intentionally omitted from this example because the current passthrough
99+
path does not yet provide the VP9 RTP descriptor plumbing needed for reliable
100+
ingest.

0 commit comments

Comments
 (0)