How to take a full-resolution JPEG snapshot from a Hi351x IP camera via HTTP

Hi351x-family cameras (Hi3510/Hi3516 and compatible SoCs, hfonvif/1.0 ONVIF stack — the kind that identify as IPCamera and stream via rtsp://<ip>:554/stream_0/stream_1) can serve a full-resolution JPEG still over plain HTTP — without decoding the RTSP stream yourself.

The snapshot URL

snapshot.sh
curl -o snapshot.jpg "http://10.91.1.207/action/cgi_images"

This returns Content-Type: image/jpeg at the camera’s main-stream resolution (e.g. 1920×1080). Verified working on firmware 22.010.30.6_MAIN_V44.

If the endpoint returns a JSON error like {"code":208,...} on other paths, note that the correct path is /action/cgi_images — not /snap.jpg, /webcapture.jpg, or /tmpfs/auto.jpg (those all 404 on this family).

Discovering it via ONVIF (port 8080)

The same URI is what ONVIF GetSnapshotUri advertises. Useful for confirming the endpoint on a different firmware or when the path differs:

onvif_snapshot_uri.sh
# 1) Find the Media service XAddr
curl -s -X POST -H "Content-Type: application/soap+xml" \
  --data '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Body><GetCapabilities xmlns="http://www.onvif.org/ver10/device/wsdl"><Category>Media</Category></GetCapabilities></s:Body></s:Envelope>' \
  http://10.91.1.207:8080/onvif/device_service | grep -o '<tt:XAddr>[^<]*'

# 2) List profiles → take the profile token (e.g. profile0)
curl -s -X POST -H "Content-Type: application/soap+xml" \
  --data '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Body><GetProfiles xmlns="http://www.onvif.org/ver10/media/wsdl"/></s:Body></s:Envelope>' \
  http://10.91.1.207:8080/onvif/Media | grep -o 'token="profile[0-9]*"'

# 3) GetSnapshotUri
curl -s -X POST -H "Content-Type: application/soap+xml" \
  --data '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Body><GetSnapshotUri xmlns="http://www.onvif.org/ver10/media/wsdl"><ProfileToken>profile0</ProfileToken></GetSnapshotUri></s:Body></s:Envelope>' \
  http://10.91.1.207:8080/onvif/Media | grep -o '<tt:Uri>[^<]*'

Expected output:

output.txt
http://10.91.1.207:80/action/cgi_images

Python example

snapshot.py
import urllib.request

def take_snapshot(ip, out_path="snapshot.jpg", timeout=10):
    url = f"http://{ip}/action/cgi_images"
    data = urllib.request.urlopen(url, timeout=timeout).read()
    if not data.startswith(b"\xff\xd8"):
        raise ValueError(f"not a JPEG ({len(data)} bytes)")
    with open(out_path, "wb") as f:
        f.write(data)
    return out_path

take_snapshot("10.91.1.207")

Camera configuration

For configuring the camera’s streams, encoders, resolution, GOP etc., use Hi351x-Camera-CLI — a CLI tool that scans the network for these cameras, dumps their full configuration and applies changes (setVencConf, etc.) across single devices or whole subnets.


Check out similar posts by category: IP-Cameras