Skip to content

Instantly share code, notes, and snippets.

@theSoberSobber
Created October 9, 2025 21:33
Show Gist options
  • Save theSoberSobber/bdb4254c3c89e34537d987510736509b to your computer and use it in GitHub Desktop.
Save theSoberSobber/bdb4254c3c89e34537d987510736509b to your computer and use it in GitHub Desktop.
Stream your local DVR Camera without the broken UIs of your providers.

DVR Camera Streaming Guide

Complete documentation for accessing camera streams from PT-DR1A08G-K1 DVR system.


📋 Table of Contents

  1. System Information
  2. Working Solutions
  3. Python Scripts
  4. Explored but Not Working
  5. Technical Discoveries

System Information

DVR Model: PT-DR1A08G-K1
IP Address: 192.168.1.2
Active Channels: 1, 4, 5, 6, 7, 8 (6 cameras total)
Authentication: HTTP Digest Auth
Username: admin
Password: admin
Timezone: IST (UTC+5:30)
Resolution: 960x1088 (all channels)


Working Solutions

Live Streaming (HTTP Snapshots)

Status:WORKING - Truly live with <1 second latency

Description

HTTP endpoint provides live JPEG snapshots from all cameras. This is the only method for true real-time streaming (<1 second delay).

Endpoint Format

http://192.168.1.2/ISAPI/Streaming/channels/{channelID}/picture

Available Channels

  • Channel 1: http://192.168.1.2/ISAPI/Streaming/channels/101/picture
  • Channel 4: http://192.168.1.2/ISAPI/Streaming/channels/401/picture
  • Channel 5: http://192.168.1.2/ISAPI/Streaming/channels/501/picture
  • Channel 6: http://192.168.1.2/ISAPI/Streaming/channels/601/picture
  • Channel 7: http://192.168.1.2/ISAPI/Streaming/channels/701/picture
  • Channel 8: http://192.168.1.2/ISAPI/Streaming/channels/801/picture

Authentication

HTTP Digest Authentication required:

from requests.auth import HTTPDigestAuth
auth = HTTPDigestAuth('admin', 'admin')

Python Script: snapshot_streamer.py

Usage:

python3 snapshot_streamer.py <camera_number>

Examples:

python3 snapshot_streamer.py 1    # Stream camera 1
python3 snapshot_streamer.py 4    # Stream camera 4
python3 snapshot_streamer.py 5    # Stream camera 5

Features:

  • Live video display in OpenCV window
  • ~5-10 FPS continuous streaming
  • <1 second latency
  • Press 'q' to quit
  • Press 's' to save snapshot
  • Automatically creates output directory for saved frames

Code Example:

import cv2
import requests
from requests.auth import HTTPDigestAuth
import time

url = "http://192.168.1.2/ISAPI/Streaming/channels/101/picture"
auth = HTTPDigestAuth('admin', 'admin')

while True:
    response = requests.get(url, auth=auth)
    if response.status_code == 200:
        # Convert to OpenCV image
        img_array = np.frombuffer(response.content, np.uint8)
        frame = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
        
        cv2.imshow('Live Camera', frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    
    time.sleep(0.1)  # ~10 FPS

cv2.destroyAllWindows()

Performance:

  • Image size: ~200KB JPEG per frame
  • Sustainable FPS: 5-10 FPS
  • Latency: <1 second
  • Network bandwidth: ~1-2 MB/s per camera

Historical Streaming (RTSP)

Status:WORKING - Near-live with ~20-30 minute delay

Description

RTSP endpoint provides video playback from DVR recordings. Due to DVR recording buffer, there is approximately 20-30 minute delay from current time.

Endpoint Format

rtsp://admin:[email protected]/Streaming/tracks/{trackID}/?starttime=YYYYMMDDThhmmssZ&endtime=YYYYMMDDThhmmssZ

Track ID Mapping

  • Camera 1 → Track 101
  • Camera 4 → Track 401
  • Camera 5 → Track 501
  • Camera 6 → Track 601
  • Camera 7 → Track 701
  • Camera 8 → Track 801

Critical: Timezone Handling

⚠️ IMPORTANT: DVR uses LOCAL TIME (IST) in timestamp parameters, NOT UTC!

Despite the 'Z' suffix (which typically indicates UTC), the DVR interprets timestamps as local IST time.

# ✅ CORRECT: Use local IST time
from datetime import datetime, timedelta

ist_now = datetime.now()  # Local IST time
start_time = ist_now - timedelta(minutes=30)
end_time = ist_now + timedelta(hours=1)

# Format as YYYYMMDDThhmmssZ (values are IST, not UTC!)
start_str = start_time.strftime('%Y%m%dT%H%M%SZ')
end_str = end_time.strftime('%Y%m%dT%H%M%SZ')
# ❌ WRONG: Using UTC time will show old recordings
from datetime import datetime
utc_now = datetime.utcnow()  # This will fail!

Python Script: stream_near_live.py

Usage:

python3 stream_near_live.py <camera_number>

Examples:

python3 stream_near_live.py 1    # Stream camera 1 (30 min delay)
python3 stream_near_live.py 4    # Stream camera 4 (30 min delay)
python3 stream_near_live.py 5    # Stream camera 5 (30 min delay)

Features:

  • Video playback in OpenCV window
  • Full FPS (15-30 FPS depending on camera)
  • H.264 video stream
  • ~20-30 minute delay from current time
  • Press 'q' to quit
  • Press 's' to save snapshot
  • Displays frame counter and elapsed time

Code Example:

import cv2
from datetime import datetime, timedelta

# Configuration
HOST = '192.168.1.2'
USERNAME = 'admin'
PASSWORD = 'admin'
TRACK_ID = 101  # Camera 1

# Get IST time and go back 30 minutes
ist_now = datetime.now()
start_time = ist_now - timedelta(minutes=30)
end_time = ist_now + timedelta(hours=1)

# Format timestamps (IST time, not UTC!)
start_str = start_time.strftime('%Y%m%dT%H%M%SZ')
end_str = end_time.strftime('%Y%m%dT%H%M%SZ')

# Build RTSP URL
rtsp_url = f'rtsp://{USERNAME}:{PASSWORD}@{HOST}/Streaming/tracks/{TRACK_ID}/?starttime={start_str}&endtime={end_str}'

# Open stream with OpenCV
cap = cv2.VideoCapture(rtsp_url)

while True:
    ret, frame = cap.read()
    if not ret:
        break
    
    cv2.imshow('Camera', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

Performance:

  • FPS: 15-30 FPS (full video stream)
  • Resolution: 960x1088
  • Codec: H.264
  • Latency: ~20-30 minutes
  • Network bandwidth: ~1-3 MB/s per camera

Additional RTSP Tools

playback_manager.py - Complete playback management:

from playback_manager import DVRPlayback
from datetime import datetime, timedelta

dvr = DVRPlayback('192.168.1.2', 'admin', 'admin')

# Search for recordings
now = datetime.now()
start = now - timedelta(hours=24)
segments = dvr.search_recordings(101, start, now)

# Get recording calendar
calendar = dvr.get_recording_calendar(101, 2025, 10)

# Build RTSP URL
start_time = datetime(2025, 10, 9, 14, 30)
end_time = datetime(2025, 10, 9, 15, 0)
url = dvr.build_rtsp_url(101, start_time, end_time)

extract_rtsp_frames.py - Extract frames from historical recordings:

# Extract 100 frames from a specific time period
python3 extract_rtsp_frames.py

Python Scripts

Summary of Available Scripts

Script Purpose Input Output
snapshot_streamer.py Live HTTP snapshot streaming Camera number Live video window
stream_near_live.py Near-live RTSP streaming Camera number Video window (30 min delay)
playback_manager.py Playback management library Track ID, time range Recording data, RTSP URLs
extract_rtsp_frames.py Extract frames from recordings RTSP URL JPEG frames on disk
live_stream_viewer.py Generic RTSP viewer Camera number Video window

Quick Start Examples

1. Watch Live Camera (truly live, <1s delay):

python3 snapshot_streamer.py 1

2. Watch Near-Live Camera (video stream, 30 min delay):

python3 stream_near_live.py 1

3. Search for Recordings:

from playback_manager import DVRPlayback
from datetime import datetime, timedelta

dvr = DVRPlayback('192.168.1.2', 'admin', 'admin')
now = datetime.now()
yesterday = now - timedelta(days=1)

# Find all recordings from last 24 hours
segments = dvr.search_recordings(101, yesterday, now)
for seg in segments:
    print(f"{seg['start_time']} to {seg['end_time']}")

4. Extract Historical Frames:

import cv2
from datetime import datetime

# Specific time from yesterday
start_str = '20251009T143000Z'  # Oct 9, 2:30 PM IST
end_str = '20251009T150000Z'    # Oct 9, 3:00 PM IST

url = f'rtsp://admin:[email protected]/Streaming/tracks/101/?starttime={start_str}&endtime={end_str}'

cap = cv2.VideoCapture(url)
frame_num = 0

while True:
    ret, frame = cap.read()
    if not ret:
        break
    
    cv2.imwrite(f'frame_{frame_num:04d}.jpg', frame)
    frame_num += 1

cap.release()

Explored but Not Working

❌ HTTP Snapshots with Time Parameter

Attempted:

http://192.168.1.2/ISAPI/Streaming/channels/101/picture?time=20251008T205822Z

Problem:
The DVR ignores the time parameter completely and always returns the current frame, regardless of the timestamp provided.

Testing:

  • Requested frames from Oct 8, 2025 (2 days ago)
  • Response always showed current timestamp in image overlay
  • MD5 hashes confirmed images were different but all current
  • Time parameter has no effect

Conclusion:
HTTP endpoint only supports live snapshots, not historical retrieval.


❌ RTSP Live Stream (No Time Parameters)

Attempted:

rtsp://admin:[email protected]/Streaming/tracks/101/

Problem:
Without time parameters, the DVR defaults to the oldest available recording in storage, not the live feed.

Testing:

  • Opened stream without starttime/endtime parameters
  • Video showed timestamp overlay from December 2024
  • This was the oldest recording still in DVR storage
  • No way to get "live" feed without time parameters

Conclusion:
RTSP endpoint requires time parameters. Without them, it serves oldest recording, not live stream.


❌ RTSP with /Channels/ Format

Attempted:

rtsp://admin:[email protected]:554/Streaming/Channels/101

Problem:
Stream opens but produces corrupted/encrypted H.264 data that cannot be decoded.

Errors Observed:

[h264 @ 0x...] A non-intra slice in an IDR NAL unit.
[h264 @ 0x...] decode_slice_header error
[h264 @ 0x...] no frame!
[h264 @ 0x...] Missing reference picture, default is 0
[h264 @ 0x...] non-existing PPS 2 referenced
[h264 @ 0x...] deblocking_filter_idc 6 out of range

Testing:

  • cv2.VideoCapture() reports stream as "opened"
  • Reports resolution: 960x1088, FPS: 15.0
  • Cannot read any frames successfully
  • Continuous H.264 decoder errors
  • Zero frames extracted

Theory:
This endpoint may be using proprietary encryption or non-standard H.264 implementation. The web UI doesn't use this format either.

Conclusion:
This RTSP format is not usable with standard video players/libraries.


❌ RTSP with UTC Timestamps

Attempted:

from datetime import datetime
utc_now = datetime.utcnow()
start_str = utc_now.strftime('%Y%m%dT%H%M%SZ')

Problem:
DVR interprets timestamps as local time (IST), causing 5.5 hour offset.

Testing:

  • Used UTC timestamps for current time
  • Video showed recordings from 1 month ago (September 2025)
  • Requested yesterday's recordings, got 2-month-old footage (August 2025)
  • Offset matched IST timezone difference (UTC+5:30)

Discovery:
Despite using 'Z' suffix (UTC indicator), DVR expects local IST time values.

Solution:
Use datetime.now() for local IST time, not datetime.utcnow().

Conclusion:
Always use local IST time. UTC causes 5.5 hour timezone mismatch.


⚠️ True Live RTSP Streaming

Status: Not possible due to DVR recording buffer

Problem:
DVR has ~20-30 minute recording buffer before video is available via RTSP.

Testing:

  • Attempted RTSP with current time minus 2 minutes
  • Stream failed to open (recording doesn't exist yet)
  • Tried current time minus 5, 10, 15 minutes - all failed
  • Only works with 20-30 minute delay

Why:
DVR writes recordings to disk with a buffer delay. RTSP can only access finalized recordings, not live buffer.

Workaround:
Use HTTP snapshots for truly live streaming (<1s latency).

Conclusion:
RTSP provides "near-live" at best (~30 min delay). For truly live, use HTTP snapshots.


❌ Alternative RTSP Endpoints

Attempted formats:

  1. rtsp://192.168.1.2/Streaming/tracks/101/ (no params) → Shows Dec 2024
  2. rtsp://192.168.1.2:554/Streaming/tracks/101/ (explicit port) → Same as #1
  3. rtsp://192.168.1.2/Streaming/channels/101/ → Connection refused
  4. rtsp://192.168.1.2:554/Streaming/Channels/101 → Corrupted H.264
  5. rtsp://192.168.1.2/ISAPI/Streaming/channels/101/ → Connection refused

Conclusion:
Only working format is:

rtsp://admin:[email protected]/Streaming/tracks/{trackID}/?starttime=YYYYMMDDThhmmssZ&endtime=YYYYMMDDThhmmssZ

Technical Discoveries

Recording Search API

Endpoint: /ISAPI/ContentMgmt/search

Purpose: Find recording segments within a time range

Request:

<?xml version="1.0" encoding="UTF-8"?>
<CMSearchDescription>
    <searchID>unique-uuid-here</searchID>
    <trackList>
        <trackID>101</trackID>
    </trackList>
    <timeSpanList>
        <timeSpan>
            <startTime>2025-10-09T00:00:00Z</startTime>
            <endTime>2025-10-10T23:59:59Z</endTime>
        </timeSpan>
    </timeSpanList>
    <maxResults>100</maxResults>
    <searchResultPostion>0</searchResultPostion>
    <metadataList>
        <metadataDescriptor>videoloss</metadataDescriptor>
    </metadataList>
</CMSearchDescription>

Response:

<CMSearchResult>
    <matchList>
        <searchMatchItem>
            <trackID>101</trackID>
            <startTime>2025-10-09T08:34:21Z</startTime>
            <endTime>2025-10-09T13:12:29Z</endTime>
            <playbackURI>rtsp://...</playbackURI>
        </searchMatchItem>
    </matchList>
</CMSearchResult>

Recording Calendar API

Endpoint: /ISAPI/ContentMgmt/record/tracks/{trackID}/dailyDistribution

Purpose: Get list of days with recordings for a specific month

Query Params:

  • year=2025
  • month=10

Response:

<trackDailyParam>
    <trackID>101</trackID>
    <year>2025</year>
    <monthIdx>10</monthIdx>
    <dayList>
        <day>1</day>
        <day>2</day>
        <day>8</day>
        <day>9</day>
        <day>10</day>
    </dayList>
</trackDailyParam>

Authentication

Method: HTTP Digest Authentication

Credentials:

  • Username: admin
  • Password: admin

Python:

from requests.auth import HTTPDigestAuth
auth = HTTPDigestAuth('admin', 'admin')

cURL:

curl --digest -u admin:admin "http://192.168.1.2/ISAPI/Streaming/channels/101/picture"

Video Properties

Resolution: 960x1088 (all channels)
Codec: H.264
FPS: Varies by channel (15-30 FPS)
Audio: PCM μ-law (not compatible with MP4 container)

Network Bandwidth

HTTP Snapshots:

  • Per frame: ~200KB JPEG
  • At 10 FPS: ~2 MB/s
  • At 5 FPS: ~1 MB/s

RTSP Streams:

  • H.264 stream: ~1-3 MB/s per camera
  • Varies by motion and complexity

Troubleshooting

Stream Won't Open

Check recording exists:

from playback_manager import DVRPlayback
from datetime import datetime, timedelta

dvr = DVRPlayback('192.168.1.2', 'admin', 'admin')
now = datetime.now()
past = now - timedelta(hours=1)

segments = dvr.search_recordings(101, past, now)
if segments:
    print("✅ Recordings exist")
else:
    print("❌ No recordings in this time range")

Verify timezone (use IST, not UTC):

# ✅ Correct
ist_now = datetime.now()

# ❌ Wrong
utc_now = datetime.utcnow()

Use sufficient delay for RTSP:

# ✅ Works (30 minute delay)
start_time = datetime.now() - timedelta(minutes=30)

# ❌ Might fail (2 minute delay too recent)
start_time = datetime.now() - timedelta(minutes=2)

Poor HTTP Snapshot Performance

Reduce FPS:

time.sleep(0.2)  # 5 FPS instead of 10 FPS

Use smaller window:

cv2.resizeWindow('Camera', 640, 360)  # Smaller display

Check network:

ping 192.168.1.2

RTSP Playback Issues

Check OpenCV FFMPEG support:

import cv2
print(cv2.getBuildInformation())
# Look for: Video I/O: FFMPEG: YES

Verify credentials:

curl --digest -u admin:admin "http://192.168.1.2/ISAPI/System/deviceInfo"

Test connectivity:

ping 192.168.1.2
telnet 192.168.1.2 554

Conclusion

✅ Recommended Solution

For Live Monitoring: Use HTTP snapshots (snapshot_streamer.py)

  • Truly live (<1 second delay)
  • Lightweight (~200KB per frame)
  • Works reliably at 5-10 FPS

For Video Playback: Use RTSP with time parameters (stream_near_live.py)

  • Full video stream (15-30 FPS)
  • ~20-30 minute delay
  • H.264 high quality
  • Good for reviewing recent events

🚫 What Doesn't Work

  • True live RTSP (DVR has 20-30 min recording buffer)
  • HTTP historical snapshots (time parameter ignored)
  • RTSP /Channels/ format (corrupted H.264)
  • RTSP without time parameters (shows oldest recording)

📚 Files Reference

Working Scripts:

  • snapshot_streamer.py - HTTP live streaming
  • stream_near_live.py - RTSP near-live streaming
  • playback_manager.py - Recording management library
  • extract_rtsp_frames.py - Frame extraction

Documentation:

  • WORKING_METHODS_SUMMARY.md - Quick reference guide
  • DVR_STREAMING_GUIDE.md - This comprehensive guide

Document Version: 1.0
Last Updated: October 10, 2025
DVR Model: PT-DR1A08G-K1
Tested Channels: 1, 4, 5, 6, 7, 8
Python Version: 3.x
Dependencies: opencv-python, requests, numpy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment