Advanced Usage#

This guide covers advanced configuration options for the NVIDIA Synthetic Video Detector NIM.

Model Behavior and Classification Threshold#

The Synthetic Video Detector is designed to identify synthetic (AI-generated) videos. The service returns a calibrated synthetic probability and applies no threshold itself; the client applies the decision threshold. The default classification threshold is 0.44 (the balanced configuration). Lower it to 0.26 (the conservative configuration) to catch more synthetic content, at the cost of more false positives on authentic videos.

The following table describes the behavior of the two configurations:

Threshold

Behavior

Recommended Use Case

0.44 (default, balanced)

Balanced: Provides equal weight to correctly identifying both synthetic and authentic content.

General-purpose classification where both false positives and false negatives are minimized.

0.26 (conservative)

Conservative: Prioritizes catching all synthetic content. Might produce more false positives on authentic videos.

High-stakes screening in which missing a synthetic video is unacceptable.

Adjust the threshold according to your use case.

Reference Accuracy#

The following table summarizes detection accuracy for the two V2 configurations, measured on H.264/AVC-encoded videos from an internal evaluation dataset that includes content from COSMOS, Sora, Midjourney, Veo, OmniAvatar, OVI, NVIDIA LipSync, NVIDIA Video Live Portrait, and NVIDIA Speech Live Portrait generators.

Threshold

Synthetic Content Accuracy

Real Content Accuracy

0.44 (default, balanced)

94.3%

87.2%

0.26 (conservative)

96.6%

78.5%

Lowering the threshold from 0.44 to 0.26 raises synthetic content accuracy by 2.3 points but costs 8.7 points of real content accuracy, so roughly one in five authentic videos is flagged as synthetic. Select the conservative configuration only where missing synthetic content is more costly than reviewing false positives.

Note

Reported accuracy metrics are measured on H.264/AVC-encoded videos. Detection performance has not been independently characterized for H.265/HEVC, AV1, VP8, or VP9 and may differ from H.264/AVC performance.

Limited internal testing indicates that the detector continues to identify synthetic videos across these codecs; however, codec changes may increase the false-positive rate for real videos.

These results are based on internal benchmarks and may vary with video quality, compression settings, codec implementation, and the generative model used to create the content.

Service Information in the Response#

Each response stream opens with a one-shot ServiceInfo message on the service_info field of DetectSyntheticVideoResponse, before any detection results. It reports nim_version, model_version, and request_id. Quote request_id when reporting an issue because it locates the request in the server logs.

for response in response_iterator:
    if response.HasField("service_info"):
        print(response.service_info.request_id)
    elif response.HasField("final_result"):
        print(response.final_result.synthetic_probability)

Model Caching#

When the container launches for the first time, it downloads the required models from NGC. To avoid downloading the models on subsequent runs, you can cache them locally by using a cache directory:

# Create the cache directory on the host machine
export LOCAL_NIM_CACHE=~/.cache/nim
mkdir -p "$LOCAL_NIM_CACHE"
chmod 777 $LOCAL_NIM_CACHE

# Run the container with the cache directory mounted
docker run -it --rm --name=synthetic-video-detector-nim \
  --runtime=nvidia \
  --gpus all \
  -e NGC_API_KEY=$NGC_API_KEY \
  -e NIM_HTTP_API_PORT=8000 \
  -p 8000:8000 \
  -p 8001:8001 \
  -v "$LOCAL_NIM_CACHE:/opt/nim/.cache" \
  nvcr.io/nim/nvidia/synthetic-video-detector:latest

The NIM selects a compatible model profile automatically. To pin a specific profile instead, refer to Overriding the Model Profile.

Overriding the Model Profile#

NIM_MODEL_PROFILE is optional. Set it only when you need to pin the NIM to one specific profile instead of the profile it selects automatically. The model manifest holds one profile for each GPU architecture and compute capability (CC), listed in the following table.

GPU Architecture (compute capability)

Model Profile ID

Blackwell (cc 12.0)

ee5a8384534d149862e2b5984897c909d429a45b01d582f69d05e54168d9f927

Blackwell (cc 10.0)

f13812fed9023eccda9061cb60e888252d3126d416be737a39bb05386e82e7fa

Hopper (cc 9.0)

478ef2817ba6d3a7b2badc3da9057fca6c6b40d3220fd30aff97048c24736bbf

Ada (cc 8.9)

38e51aea8d80e70d96889d7d2b495f200b5c0188c5723feda2b9ccdd89d422ba

Ampere (cc 8.6)

afbf0a3a3bc02a3c791c640b62465c4d6c7de78d01de7490afa28d37d1b5d3c5

Ampere (cc 8.0)

db2aa3fb4659ec3cd789f222ab29da7f5885eef2cf637eae11f2f04af602d576

Turing (cc 7.5)

65db16e792ca900c2a5fdd9399a0f13b55eac80bba2069cee2f803265ff79af3

To pin a profile, pass it to the container, for example -e NIM_MODEL_PROFILE=38e51aea8d80e70d96889d7d2b495f200b5c0188c5723feda2b9ccdd89d422ba. Ensure the profile’s GPU architecture is compatible with the target hardware; using an incompatible profile ID causes a deserialization error on inference.

SSL Enablement#

The Synthetic Video Detector NIM supports SSL/TLS to ensure secure communication between clients and the server by encrypting data in transit.

To enable SSL, provide the path to the SSL certificate and key files in the container. The following example shows how to do this:

export NGC_API_KEY=<add-your-api-key>
SSL_CERT=path/to/ssl_key

docker run -it --rm --name=synthetic-video-detector-nim \
  --runtime=nvidia \
  --gpus all \
  --shm-size=16GB \
  -v $SSL_CERT:/opt/nim/crt/:ro \
  -e NGC_API_KEY=$NGC_API_KEY \
  -p 8000:8000 \
  -p 8001:8001 \
  -e NIM_SSL_MODE="mtls" \
  -e NIM_SSL_CA_CERTS_PATH="/opt/nim/crt/ssl_ca.pem" \
  -e NIM_SSL_CERT_PATH="/opt/nim/crt/ssl_cert_server.pem" \
  -e NIM_SSL_KEY_PATH="/opt/nim/crt/ssl_key_server.pem" \
  nvcr.io/nim/nvidia/synthetic-video-detector:latest

NIM_SSL_MODE can be set to mtls, tls, or disabled. If set to mtls, the container uses mutual TLS authentication. If set to tls, the container uses TLS authentication.

Note

Verify the permissions of the SSL certificate and key files on the host machine. The container cannot access the files if they are not readable by the user running the container.

For more information, refer to Environment Variables.

Multi-GPU#

On hosts with more than one visible GPU, NV_AI4M_SVD_PIN_MODEL_TO_SHM_GPU selects how requests are placed across the available devices. The default is true (pinned).

Mode

Value

Behavior

Pinned

true (default)

The NIM creates one model instance per ensemble member per visible GPU and keeps each request’s CUDA shared memory pool and inference on the same device, which avoids inter-GPU memory transfers.

Unpinned

false, 0, no, or off (case-insensitive)

One shared model instance per ensemble member is spanned across all visible GPUs, and Triton’s scheduler places each batch on any of them. Transfers between devices use peer-to-peer memory copy where available. Requires the host to boot with IOMMU passthrough (iommu=pt).

An unset, empty, or unrecognized value keeps the pinned default.

Pinned mode suits most deployments. Because decoding, preprocessing, and inference all stay on one device, there is no cross-device payload traffic, and it is the higher-throughput path on typical PCIe multi-GPU systems.

Unpinned mode lets Triton pick an idle GPU rather than the one that owns the request’s shared memory, which can help when load is uneven across devices. It depends on cross-device shared-memory reads, so it is only safe with IOMMU passthrough. If you request unpinned mode on a host without passthrough, the NIM logs a warning and starts in pinned mode instead of running a configuration that can corrupt data.

At start-up the NIM reports the mode it resolved, so you can confirm which one is active:

GPU affinity: pinned (each request runs on the GPU holding its shared memory)

For the IOMMU passthrough requirement and the steps to enable it in GRUB, refer to PCIe Multi-GPU Systems.

Pre-signed URL Ingest#

By default, a client streams the video to the NIM as gRPC byte chunks. With pre-signed URL ingest, the client instead sends one small request carrying a pre-signed HTTPS URL to the video object; the NIM fetches the object, integrity-checks it, and runs the same detection pipeline. This is useful when the video already lives in object storage (for example, AWS S3) and you prefer to pass a time-limited URL rather than push the bytes through the client. The default host allowlist permits AWS S3 endpoints; add other hostnames with NV_AI4M_PRESIGNED_ALLOWED_HOSTS. For client usage, refer to Pre-signed URL (S3) Ingest.

URL ingest always uses the transactional workflow: the object is downloaded in full before decoding begins. The streaming workflow is never used for URL ingest, regardless of codec or container.

How It Works#

The client sends one DetectSyntheticVideoRequest whose input carries a PresignedUrl message (instead of the usual byte chunks). On receipt, the service runs these stages before any inference happens:

  1. Structural validation (no network): the URL is validated before any connection is made:

    • The scheme must be https (plaintext http is accepted only when explicitly allowed).

    • The URL must not contain embedded credentials or a fragment.

    • The host must be a DNS name; IP literals are rejected.

    • The port must be in the allowlist.

    • The host must match the configured host allowlist.

    • The URL expiry is checked, and when the request declares the S3 provider, the AWS SigV4 query-parameter shape is validated.

  2. SSRF guard: the host is resolved and every resolved address must be a public IP (private, loopback, link-local, reserved, and multicast addresses are refused). The connection is then pinned to a validated IP while still using the original hostname for SNI and TLS certificate verification, which makes the fetch safe against DNS rebinding.

  3. Download: exactly one GET request is issued — redirects disabled, no client-supplied headers forwarded — and the body is streamed into a per-request tmpfs workspace under a size cap and an overall deadline. Optional checksum (MD5, SHA-256, or SHA-512), Content-Length, and Content-Type checks run when the request asks for them. The signed query string is never logged.

  4. Inference: once the object is fully downloaded to local disk, it flows through the transactional inference workflow (the same decode and inference pipeline as the byte-streaming path), and the server streams back the usual responses. The workspace is cleaned up afterward.

Note

The video is downloaded only temporarily for inference. It is held in a per-request workspace (tmpfs) for the duration of the request, removed as soon as inference finishes (or if the request fails or is cancelled), and never stored permanently.

The downloader uses only the Python standard library, so this feature adds no third-party dependency to the container.

Security Measures#

Some protections are always on and not configurable:

  • TLS certificate and hostname verification (SNI against the real host).

  • Connection pinned to a validated IP (prevents DNS rebinding).

  • Redirects are refused.

  • No client-supplied HTTP headers are forwarded.

  • URLs with embedded credentials (user:pass@) or a fragment are rejected.

  • IP-literal hosts are rejected (checks are hostname-based).

  • The signed URL query string is never logged.

The remaining protections are policy knobs you can relax or tighten with the environment variables in the next section (for example, NV_AI4M_PRESIGNED_ALLOW_HTTP, NV_AI4M_PRESIGNED_ALLOWED_HOSTS, NV_AI4M_PRESIGNED_ALLOW_PRIVATE_IPS, and the URL-expiry and size caps).

Note

Checksum verification is request-driven, not an environment variable. In the PresignedUrl message, when verify_checksum is unset or true, the request must include a checksum and the downloaded bytes must match it; when verify_checksum is false, no checksum is expected and one must not be supplied. Supported algorithms are md5, sha256, and sha512.

Pre-signed URL Environment Variables#

The following environment variables tune pre-signed URL ingestion. Pass them with -e NAME=value on the docker run command. Boolean variables accept 1/true/yes/on (case-insensitive) as true.

Variable

Default

Description

NV_AI4M_PRESIGNED_ALLOWED_HOSTS

AWS S3 endpoints (s3.amazonaws.com, s3.*.amazonaws.com, *.s3.amazonaws.com, *.s3.*.amazonaws.com)

Comma-separated allowlist of hostnames. Shell-glob patterns, matched case-insensitively. Set this to add other providers or S3-compatible endpoints.

NV_AI4M_PRESIGNED_ALLOWED_PORTS

443

Comma-separated allowlist of TCP ports. Invalid or out-of-range values are ignored; falls back to 443 if none remain.

NV_AI4M_PRESIGNED_ALLOW_HTTP

false

Allow plaintext http:// URLs. Testing only; leave disabled in production.

NV_AI4M_PRESIGNED_ALLOW_PRIVATE_IPS

false

Allow the host to resolve to a private, loopback, or link-local address (required for a local object store such as MinIO on localhost). Testing only; keep disabled in production.

NV_AI4M_PRESIGNED_MAX_URL_EXPIRY_S

0 (no cap)

Opt-in ceiling on the URL’s total validity window, in seconds. For S3 URLs, the X-Amz-Expires value must not exceed this. 0 disables the cap; already-expired URLs are always rejected regardless.

NV_AI4M_PRESIGNED_MIN_URL_REMAINING_S

0

Reject URLs with fewer than this many seconds of validity remaining at request time. 0 disables the check.

NV_AI4M_PRESIGNED_MAX_FILE_BYTES

2147483648 (2 GiB)

Hard object-size cap. Enforced against a declared or Content-Length size and while streaming the body.

NV_AI4M_PRESIGNED_CONNECT_TIMEOUT_S

10

TCP/TLS connect timeout, in seconds.

NV_AI4M_PRESIGNED_DOWNLOAD_TIMEOUT_S

60

Overall download deadline for the object body, in seconds.

NV_AI4M_PRESIGNED_READ_CHUNK_BYTES

1048576 (1 MiB)

Streaming read chunk size, in bytes.

NV_AI4M_TRANSACTION_WORKDIR

""

Root directory for per-request download workspaces. Empty means the service picks its default upload sink (tmpfs).