End-to-End Demo Chart#
Overview#
The nvidia-lipsync-h4m-sample Helm chart deploys a complete LipSync demo pipeline on Holoscan for Media. This includes the following components:
Sender pipeline.
LipSync NIM service (
nvidia-lipsync-h4m-service).Receiver pipeline (ST 2110 or NMOS).
SRT output for preview.
This chart provides a ready-to-run setup for evaluating and demonstrating LipSync capabilities within a Holoscan for Media environment.
Installation#
Prerequisites#
Complete all prerequisite steps (Rivermax license, image pull and model pull secrets, GPU node, Multus attachment for SMPTE ST 2110) before running helm install. For details, refer to Getting Started.
If not already done, add the Helm repository and pull the chart:
helm pull nim-repo/nvidia-lipsync-h4m-sample --version 1.0.0
Helm Installation#
The chart includes a default values.yaml and can be deployed from the .tgz with -f. For the sample ST 2110 or NMOS pipelines, copy the YAML from Helm Configuration Parameters into values-st2110.yaml or values-nmos.yaml, adjust fields, and run the matching install command.
Default deployment (NMOS mode, 1080p):
Important
The default values.yaml ships with example values for cluster-specific fields such as node selector (example-gpu-node), image pull secret, network name, and scheduler. You must update these values to match your cluster before deploying. The easiest approach is to use the global overrides so that each value is specified once for all components (sender, receiver, and NIM service). For details, refer to Global Overrides.
With global overrides:
helm upgrade --install lipsync-h4m-sample \
nvidia-lipsync-h4m-sample-1.0.0.tgz \
--set global.nodeSelector.hostname=<gpu-node-name> \
--set global.image.secret=<image-pull-secret> \
--set global.network.name=<multus-net-attach-def> \
--set global.schedulerName=<scheduler-name> \
--set global.service.type=NodePort \
--set nvidia-lipsync-h4m-service.ngcApiKeySecret.name=<model-pull-secret>
Alternatively, set values per component when the sender, receiver, and NIM service run on different nodes or use different pull secrets:
helm upgrade --install lipsync-h4m-sample \
nvidia-lipsync-h4m-sample-1.0.0.tgz \
--set sender.nodeSelector.hostname=<gpu-node-name> \
--set receiver.nodeSelector.hostname=<gpu-node-name> \
--set nvidia-lipsync-h4m-service.nodeSelector.hostname=<gpu-node-name> \
--set sender.image.secret=<image-pull-secret> \
--set receiver.image.secret=<image-pull-secret> \
--set nvidia-lipsync-h4m-service.image.secret=<image-pull-secret> \
--set nvidia-lipsync-h4m-service.ngcApiKeySecret.name=<model-pull-secret>
For all available Helm values, refer to the Configuration Reference.
After installation, check the status of the pods:
kubectl get pods
Example output:
NAME READY STATUS
nvidia-lipsync-nim-nmos-556d95b4f6-4m2cj 1/1 Running
nvidia-lipsync-receiver-nmos-f6ddc9f59-v5w5l 1/1 Running
nvidia-lipsync-sender-nmos-6586c98f9d-vn9tg 1/1 Running
Confirm that the sender, LipSync NIM, and receiver pods all show 1/1 in the READY column before continuing.
Check the pod state:
kubectl get pods -o wide
kubectl describe pod <pod-name>
Look for Pulling image in the events (normal—wait longer) or CrashLoopBackOff / ErrImagePull (actionable: check secrets and node resources).
For NMOS, refer to Chrome Remote Desktop for UI access and setup steps.
For NMOS connection order and NMOS known issues, refer to Limitations and Known Behaviors.
High-Speed Network Configuration#
For ST 2110, confirm the high-speed network attachment name in the cluster, and then set the same network.name on the sender, receiver, and nvidia-lipsync-h4m-service so it matches that attachment (for example, the name from a NetworkAttachmentDefinition or what the platform documents).
Inline overrides (append to helm install):
--set sender.network.name=media-a-tx-net \
--set receiver.network.name=media-a-tx-net \
--set nvidia-lipsync-h4m-service.network.name=media-a-tx-net
Or in values YAML:
sender:
network:
name: "media-a-tx-net"
receiver:
network:
name: "media-a-tx-net"
nvidia-lipsync-h4m-service:
network:
name: "media-a-tx-net"
Replace media-a-tx-net with the attachment name used in the cluster.
Persistent Storage#
To persist model cache and service logs across pod restarts or re-deployments, enable nimModelCache, serverLogs, or both in the values file. Both Persistent Volume Claims (PVCs) are optional and disabled by default.
nimModelCachestores downloaded models locally, preventing re-downloads on subsequent runs.serverLogspersists service logs for debugging and analysis.
nvidia-lipsync-h4m-service:
nimModelCache:
enabled: true
serverLogs:
enabled: true
Sender Sample Media#
Input Media Files#
The sender expects an MPEG Transport Stream (.ts) file containing specific media streams required for lip synchronization.
Stream Composition#
Each input .ts file must contain the following streams:
Video stream: Source video to be processed by the LipSync NIM.
Original audio stream: The original audio associated with the video (used as reference audio).
Translated audio stream: The target audio (such as a different language) to be synchronized with the video.
Codecs#
Video codec: H.264
Audio codec: Opus, 48 kHz, mono (both the original and translated audio streams)
Bundled Sample Files#
The sender container includes sample .ts files:
/workspace/assets/
Pattern |
Resolution |
Frame Rate |
|---|---|---|
|
1080p |
30 |
|
4K |
30000/1001 |
Language Variants#
_de: German_es: Spanish_fr: French
Use the same resolution and frame rate (FPS) for the sender, LipSync NIM service (nvidia-lipsync-h4m-service), and receiver.
Ensure that the resolution and frame rate specified in Helm (sender.video and related settings) match the selected input file.
sender:
video:
inputFile: /workspace/assets/sample1_de.ts
width: 1920
height: 1080
framerateNum: 30
framerateDen: 1
Helm Configuration Parameters#
Copy the appropriate configuration into values-st2110.yaml or values-nmos.yaml, adjust fields for your environment, and pass it to helm upgrade --install with -f.
For a full reference of all Helm keys and pipeline tuning parameters, refer to the Configuration Reference.
ST 2110 (Static Mode) Configuration (values-st2110.yaml)#
sender:
enabled: true
appName: nvidia-lipsync-sender-st2110
scriptName: sender-st2110-2languages
nodeSelector:
hostname: example-gpu-node
network:
name: media-a-tx-net
schedulerName: topo-aware-scheduler
image:
repository: nvcr.io/nim/nvidia/lipsync-h4m-sample-sender
tag: "1.0.0"
secret: ngc-secret-key
# Mount PVC sender-assets (upload .ts via asset-loader)
assetsPVC:
enabled: false
claimName: sender-assets
mountPath: "/mnt/sender-assets"
readOnly: true
video:
width: 1920
height: 1080
framerateNum: 30
framerateDen: 1
# Sample TS files (uncomment one to use):
inputFile: /workspace/assets/sample1_de.ts
# inputFile: /workspace/assets/sample1_es.ts
# inputFile: /workspace/assets/sample1_fr.ts
# inputFile: /workspace/assets/sample2_de.ts
# inputFile: /workspace/assets/sample2_es.ts
# inputFile: /workspace/assets/sample2_fr.ts
# inputFile: /mnt/sender-assets/custom_sample.ts
hostIp: "234.5.8.9"
st2110Ports:
video: 5001
audio1: 6001
audio2: 7001
service:
enabled: true
type: NodePort
port: 9010
nodePort: 32514
receiver:
enabled: true
appName: nvidia-lipsync-receiver-st2110
scriptName: receiver-to-srt-st2110
nodeSelector:
hostname: example-gpu-node
network:
name: media-a-tx-net
schedulerName: topo-aware-scheduler
image:
repository: nvcr.io/nim/nvidia/lipsync-h4m-sample-receiver
tag: "1.0.0"
secret: ngc-secret-key
video:
width: 1920
height: 1080
framerateNum: 30
framerateDen: 1
audioSampleRate: 48000
hostIp: "234.5.8.9"
st2110Port:
video: 5002
audio: 7001
srtPort:
internal: 8999
external: 32511
service:
enabled: true
type: NodePort
port: 9010
nodePort: 32515
nvidia-lipsync-h4m-service:
enabled: true
appName: nvidia-lipsync-nim-st2110
containerSecurityContext:
runAsUser: 1000
runAsGroup: 1000
runAsNonRoot: true
allowPrivilegeEscalation: true
nodeSelector:
hostname: example-gpu-node
network:
name: media-a-tx-net
schedulerName: topo-aware-scheduler
image:
repository: nvcr.io/nim/nvidia/lipsync-h4m-nim
tag: "1.0.0"
secret: ngc-secret-key
ngcApiKeySecret:
name: model-download-api-key
key: NGC_API_KEY
video:
width: 1920
height: 1080
framerateNum: 30
framerateDen: 1
nmos:
enabled: false
hostname: lipsync-nim.local
description: Nvidia LipSync NIM
label: Nvidia-LipSync-NIM
service:
enabled: true
type: NodePort
port: 9010
nodePort: 32513
nim:
enabled: 1
logging:
level: 3
input:
video:
sessionName: video_in
localInterfaceName: net1
hostIp: "234.5.8.9"
hostPort: "5001"
hostNumSubnetBits: 24
audio:
sessionName: audio_in
localInterfaceName: net1
hostIp: "234.5.8.9"
hostPort: "7001"
hostNumSubnetBits: 24
ancillaryData:
enabled: false
sessionName: ancillary_data_in
localInterfaceName: net1
hostIp: "234.5.8.9"
hostPort: "8001"
hostNumSubnetBits: 24
output:
video:
sessionName: video_out
localInterfaceName: net1
hostIp: "234.5.8.9"
hostPort: "5002"
hostNumSubnetBits: 24
boundingBoxEnabled: false
model:
headMovementSpeed: 0
nimModelCache:
enabled: false
size: 10Gi
storageClassName: ""
serverLogs:
enabled: false
size: 5Gi
storageClassName: ""
NMOS Configuration (values-nmos.yaml)#
sender:
enabled: true
appName: nvidia-lipsync-sender-nmos
scriptName: sender-nmos-2languages
nodeSelector:
hostname: example-gpu-node
network:
name: media-a-tx-net
schedulerName: topo-aware-scheduler
image:
repository: nvcr.io/nim/nvidia/lipsync-h4m-sample-sender
tag: "1.0.0"
secret: ngc-secret-key
# Mount PVC sender-assets (upload .ts via asset-loader)
assetsPVC:
enabled: false
claimName: sender-assets
mountPath: "/mnt/sender-assets"
readOnly: true
video:
width: 1920
height: 1080
framerateNum: 30
framerateDen: 1
# Sample TS files (uncomment one to use):
inputFile: /workspace/assets/sample1_de.ts
# inputFile: /workspace/assets/sample1_es.ts
# inputFile: /workspace/assets/sample1_fr.ts
# inputFile: /workspace/assets/sample2_de.ts
# inputFile: /workspace/assets/sample2_es.ts
# inputFile: /workspace/assets/sample2_fr.ts
# inputFile: /mnt/sender-assets/custom_sample.ts
service:
enabled: true
type: NodePort
port: 9010
nodePort: 32514
receiver:
enabled: true
appName: nvidia-lipsync-receiver-nmos
scriptName: receiver-to-srt-nmos
nodeSelector:
hostname: example-gpu-node
network:
name: media-a-tx-net
schedulerName: topo-aware-scheduler
image:
repository: nvcr.io/nim/nvidia/lipsync-h4m-sample-receiver
tag: "1.0.0"
secret: ngc-secret-key
video:
width: 1920
height: 1080
framerateNum: 30
framerateDen: 1
audioSampleRate: 48000
srtPort:
internal: 8999
external: 32512
service:
enabled: true
type: NodePort
port: 9010
nodePort: 32515
nvidia-lipsync-h4m-service:
enabled: true
appName: nvidia-lipsync-nim-nmos
containerSecurityContext:
runAsUser: 1000
runAsGroup: 1000
runAsNonRoot: true
allowPrivilegeEscalation: true
nodeSelector:
hostname: example-gpu-node
network:
name: media-a-tx-net
schedulerName: topo-aware-scheduler
image:
repository: nvcr.io/nim/nvidia/lipsync-h4m-nim
tag: "1.0.0"
secret: ngc-secret-key
ngcApiKeySecret:
name: model-download-api-key
key: NGC_API_KEY
nmos:
enabled: true
hostname: lipsync-nim.local
description: Nvidia LipSync NIM
label: Nvidia-LipSync-NIM
service:
enabled: true
type: NodePort
port: 9010
nodePort: 32513
nim:
enabled: 1
logging:
level: 3
video:
width: 1920
height: 1080
framerateNum: 30
framerateDen: 1
audio:
pcmFormat: S24BE
samplingRate: 48000
numChannels: 1
input:
video:
sessionName: video_in
audio:
sessionName: audio_in
ancillaryData:
enabled: false
sessionName: ancillary_data_in
output:
video:
sessionName: video_out
boundingBoxEnabled: false
model:
headMovementSpeed: 0
nimModelCache:
enabled: false
size: 10Gi
storageClassName: ""
serverLogs:
enabled: false
size: 5Gi
storageClassName: ""
Install#
ST 2110:
helm install lipsync-h4m-sample nvidia-lipsync-h4m-sample-1.0.0.tgz \
-f values-st2110.yaml
NMOS:
helm install lipsync-h4m-sample nvidia-lipsync-h4m-sample-1.0.0.tgz \
-f values-nmos.yaml
Note: Connect the receiver first by establishing sender audio and LipSync NIM output to receiver. After the receiver connection is in place, connect the sender audio and video streams to the LipSync NIM. For more information, refer to Limitations and Known Behaviors.
View Output via SRT#
kubectl get nodes -o wide
Use the internal IP address from the output. With the sample values in this guide, ST 2110 output is on port 32511 and NMOS on 32512—for example, srt://<internal-ip>:32511 or srt://<internal-ip>:32512 in VLC or ffplay.
ffplay "srt://<internal-ip>:32511" # ST 2110
ffplay "srt://<internal-ip>:32512" # NMOS
Disabling Components#
You can disable individual pipeline components during helm install or helm upgrade without removing the release by setting their enabled flag to false.
--set sender.enabled=false
--set receiver.enabled=false
--set nvidia-lipsync-h4m-service.enabled=false
This stops only the selected component; the rest of the pipeline continues to run.
Uninstall#
helm uninstall lipsync-h4m-sample
Note: If
serverLogsornimModelCachewere enabled, their PVCs are retained after uninstall (resource-policy: keep). Delete manually if no longer needed:kubectl delete pvc <appName>-server-logs <appName>-model-cache
Verify and Check Logs#
helm status lipsync-h4m-sample
kubectl get pods -o wide
Replace the deploy names in kubectl logs with sender.appName, receiver.appName, and nvidia-lipsync-h4m-service.appName from the values file. (ST 2110 and NMOS use different names.)
kubectl logs deploy/nvidia-lipsync-sender-nmos
kubectl logs deploy/nvidia-lipsync-nim-nmos
kubectl logs deploy/nvidia-lipsync-receiver-nmos
On Red Hat OpenShift, replace kubectl with oc. For log access, refer to Observability.
End-to-End Setup and Validation#
Create
values-st2110.yamlorvalues-nmos.yamlfrom Starter Configuration Files and run the matching Install command.Confirm all pods show READY 1/1 with
kubectl get pods.Open the SRT preview; refer to View Output via SRT. For VLC steps, NMOS wiring, and screenshots, refer to Verification.
Run
helm uninstall lipsync-h4m-sample.
# Install sample release (NMOS; for ST 2110, use -f values-st2110.yaml)
helm install lipsync-h4m-sample nvidia-lipsync-h4m-sample-1.0.0.tgz -f values-nmos.yaml
# Confirm all pods show READY 1/1
kubectl get pods
# Node IPs (use internal IP address in the SRT URL)
kubectl get nodes -o wide
# Example SRT: srt://<internal-ip>:32512 (NMOS) or srt://<internal-ip>:32511 (ST 2110)
# Remove the Helm release
helm uninstall lipsync-h4m-sample
For troubleshooting, refer to Advanced Usage.