|
| 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-release/cpp-example-collection/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-release/cpp-example-collection/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