ezhikstract
CLI tool to extract playable video from EZVIZ and Hikvision SD cards' proprietary round-robin storage format.
It works specifically with security camera or video doorbell SD cards that contain files named hiv<xxxxx>.mp4 and an index00.bin metadata/index file. The tool parses the index file, validates video segments, extracts the raw MPEG-PS / HEVC streams, and remuxes them into standard .mp4 containers, merging segments from the same day into a single daily video file formatted in your local timezone.
No full video re-encoding is performed; video streams (HEVC) are copied directly. Audio streams (AAC / PCM G.711) are transcoded to Opus to ensure broad compatibility with standard media players.
Installation
Ensure you have Python 3.10 or higher installed. You can install the package directly:
pip install ezhikstract
Usage
The CLI provides two primary command groups: list and extract. Both groups support operations on either videos or pictures.
1. The list Command Group
Used to inspect valid records on the SD card without extracting any files. Timestamps are formatted in your system's local timezone.
Videos
Lists all valid active video segments detected on the SD card.
ezhikstract list videos INPUT_DIR
INPUT_DIR(Required): Root directory of the SD card containing theindex00.binfile.
Pictures
Lists all valid picture/thumbnail records detected on the SD card.
ezhikstract list pictures INPUT_DIR
INPUT_DIR(Required): Root directory of the SD card containing theindex00p.binfile.
2. The extract Command Group
Used to retrieve and process records from the SD card.
Videos
Extracts raw video segments from active container files, filters them by timestamp if requested, remuxes/transcodes them into standard .mp4 containers, and merges segments from the same calendar day into a single daily file named after the local start time (DDMMYYYY HHMMSS.mp4).
ezhikstract extract videos INPUT_DIR [OPTIONS]
INPUT_DIR(Required): Root directory of the SD card containing theindex00.binfile.
Options:
-o, --output PATH: The output directory for the daily merged.mp4files. Default is./recordings.--from DATETIME: Start time filter (inclusive) in local time, format:"YYYY-MM-DD HH:MM:SS".--to DATETIME: End time filter (exclusive) in local time, format:"YYYY-MM-DD HH:MM:SS".--replace / --no-replace: Overwrite existing files in the output directory. Default is--replace.
Pictures
Extracts raw snapshot thumbnails from picture container files, filters them by timestamp if requested, and writes them out as standard JPEG (.jpg) files named by local timestamp.
ezhikstract extract pictures INPUT_DIR [OPTIONS]
INPUT_DIR(Required): Root directory of the SD card containing theindex00p.binfile.
Options:
-o, --output PATH: The output directory for the extracted.jpgfiles. Default is./pictures.--from DATETIME: Start time filter (inclusive) in local time, format:"YYYY-MM-DD HH:MM:SS".--to DATETIME: End time filter (exclusive) in local time, format:"YYYY-MM-DD HH:MM:SS".--replace / --no-replace: Overwrite existing files in the output directory. Default is--replace.
How it Works
The SD cards of these cameras use a pre-allocated round-robin storage file format:
index00.bin(and the backup copyindex01.bin) contains pointers, timestamps, offsets, per-file header records, and checksums for the recorded video segments.- The video data is written to pre-allocated
hivxxxxx.mp4files, which are all exactly 268.4 MB (as are the index files). ezhikstractparses the 32-byte per-file header records inindex00.binto filter out inactive / unwritten round-robin container files (segment_count == 65535).- It aligns segment start offsets past proprietary headers to the MPEG-PS / HEVC start codes (
0x000001). - It executes an intelligent 3-tier fallback extraction chain:
- MPEG-PS + AAC/Opus: Decodes MPEG-PS streams with AAC/PCM audio transcoded to Opus.
- MPEG-PS Video-Only: Falls back to video-only (
-an) if audio headers are missing or corrupted. - Raw HEVC Stream: Uses
-f hevcif the segment is a raw Annex-B HEVC stream without container headers.
- Daily segments are grouped by local calendar day and concatenated using FFmpeg concat demuxer (
-map 0:v -map 0:a?) to preserve audio wherever present.
Architecture and Design Decisions
The repository is built around several design choices to maintain clean separation, high performance, and robustness:
1. Stream-Piped Concurrency & Non-Blocking I/O
- Piped I/O: Segments are read in memory chunks and passed to the standard input of
ffmpegsubprocesses usingproc.communicate(input=segment_data, timeout=30)to eliminate OS pipe deadlocks. - Bounded Multithreading: Uses a
ThreadPoolExecutorto process segments in parallel. Concurrency limits are tuned to avoid high disk latency (limited to 4 workers for videos and 8 for pictures).
2. Lossless Remuxing & Transcoding
- Video Quality: Video streams (HEVC) are copied directly (
-c:v copy) using the-tag:v hvc1format to ensure native, lossless rendering on iOS, macOS, and desktop media players. - Audio Compatibility: AAC / PCM G.711 audio tracks are transcoded on the fly to Opus (
-c:a libopus), resolving compatibility issues without modifying the underlying video track. - Concat Demuxer: Uses the FFmpeg concat demuxer (
-f concat -map 0:v -map 0:a?) to combine chronological daily segments into a single file. This is a stream-copy operation, meaning no full video re-encoding is executed.
3. Integrity and Validation
- Active Round-Robin Filtering: Reads the per-file 32-byte header records in
index00.binto ignore unwritten round-robin files (segment_count == 65535), preventing stale clips from past recording cycles from being extracted. - Dummy Timestamp Filtering: Automatically discards zeroed / pre-2020 dummy segment slots (
start_time_raw < 1577836800). - MPEG-PS Validation: Checks the first 2KB of each raw sector boundary for MPEG Program Stream start codes (
0x000001). Any sectors corrupt from sudden power loss or circular buffer overwrites are ignored. - JPEG Verification: Validates the Start of Image (SOI) magic bytes (
0xFF 0xD8 0xFF) for all picture/thumbnail files before parsing. - Local Timezone Support: Converts all timestamps using the system's local timezone (
.astimezone()) so merged daily files correspond 100% to local calendar days.
Storage Format
The security camera SD cards (typically EZVIZ / Hikvision) use a pre-allocated, round-robin storage format. All files (index00.bin, index01.bin, and the video files hivxxxxx.mp4) are pre-allocated to the exact same size of 268.4 MB (281,444,352 bytes). The same pre-allocation strategy applies to the mobile app thumbnails (index00p.bin and hivxxxxx.pic).
Files
index00.bin: The primary index file containing pointers, timestamps, offsets, and checksums for the recorded video segments.index01.bin: A redundant copy ofindex00.binused for backup and reliability.hivxxxxx.mp4: Pre-allocated video containers (numbered fromhiv00000.mp4upwards) containing segment-based raw MPEG-PS streams.index00p.bin: Metadata and index for the pictures/thumbnails used for mobile app push notifications (human/motion detection).hivxxxxx.pic: Pre-allocated picture containers (numbered fromhiv00000.picupwards) containing segment-based raw JPEG images.
Index File Layout (index00.bin / index00p.bin)
An index file consists of:
- A 1280-byte header (
HEADER_BUFFER_LENGTH). - An array of AV-File records (each 32 bytes).
- An array of Segment records (80 bytes for video, 96 bytes for pictures).
1. File Header (1280 Bytes)
The first 1280 bytes of the index file contains general settings, the number of files, and state flags. Both index00.bin and index00p.bin share this exact structure.
| Offset | Size (Bytes) | Field Name | Data Type | Description |
|---|---|---|---|---|
0 |
8 |
modify_counter |
uint64_t (LE) |
Number of times the video segments have been modified. |
8 |
4 |
index_version |
uint32_t (LE) |
Version of the index file (typically 2 or 3). |
12 |
4 |
av_files |
uint32_t (LE) |
Total number of pre-allocated .mp4 or .pic files. |
16 |
4 |
next_file_no |
uint32_t (LE) |
File number (xxxxx) of the next file to be written. |
20 |
4 |
last_file_no |
uint32_t (LE) |
File number of the last recording stored. |
24 |
1176 |
cur_file_info |
bytes |
Info about the current file (includes timestamps, write progress, and padding). |
1200 |
76 |
unknown |
bytes |
Reserved padding. |
1276 |
4 |
checksum |
uint32_t (LE) |
Custom checksum for header validation (not standard CRC32). |
2. AV-File Records Section
Immediately following the header at offset 1280, there is a contiguous array of AV-File records.
- Record Size: 32 bytes (
FILE_RECORD_LENGTH). - Total Records: Equal to
av_filesfrom the header. - Span: Offset
1280to1280 + (av_files * 32). - Note: In
index00p.bin, these blocks are primarily empty placeholder values (0xffff...).
3. Segment Records Section
The segment records list begins directly after the AV-File records section.
Video Segments (index00.bin)
Each segment record is exactly 80 bytes (SEGMENT_RECORD_LENGTH).
For each pre-allocated video file, the index contains space for up to 256 segment entries (MAX_SEGMENTS_PER_SOURCE_FILE).
| Offset | Size (Bytes) | Field Name | Data Type | Description |
|---|---|---|---|---|
0 |
8 |
Unused | bytes |
Contains segmentType, status, reservedA, and resolution. |
8 |
8 |
start_time_raw |
uint64_t (LE) |
Segment start timestamp. Lower 32 bits represent the Unix epoch. |
16 |
8 |
end_time_raw |
uint64_t (LE) |
Segment end timestamp. Lower 32 bits represent the Unix epoch. A value of 0 denotes an empty slot. |
24 |
16 |
Unused | bytes |
Contains keyframe timestamps (firstKeyFrameAbsTime, etc.). |
40 |
4 |
start_offset |
uint32_t (LE) |
Start byte offset of this segment inside its hivxxxxx.mp4 file. |
44 |
4 |
end_offset |
uint32_t (LE) |
End byte offset of this segment inside its hivxxxxx.mp4 file. |
48 |
32 |
Unused | bytes |
Reserved fields and metadata info segments. |
Picture Segments (index00p.bin)
Each segment record is exactly 96 bytes. Unused segment slots are padded with zero bytes (0x0000...).
| Offset | Size (Bytes) | Field Name | Data Type | Description |
|---|---|---|---|---|
0 |
8 |
flags |
bytes |
Type/Status flag for the segment (e.g. 0x0d00010000000000). |
8 |
8 |
start_time_raw |
uint64_t (LE) |
Segment timestamp. Lower 32 bits represent the Unix epoch. |
16 |
8 |
end_time_raw |
uint64_t (LE) |
Segment end timestamp (usually matches start_time_raw for pictures). |
24 |
16 |
Unused | bytes |
Reserved timestamp block. |
40 |
4 |
start_offset |
uint32_t (LE) |
Start byte offset of this segment inside its hivxxxxx.pic file. |
44 |
4 |
end_offset |
uint32_t (LE) |
End byte offset of this segment inside its hivxxxxx.pic file. |
48 |
32 |
info |
bytes |
Contains INFO string and related info offsets. |
80 |
16 |
watermark |
bytes |
ASCII camera ID/Watermark string appended at the end of the segment (e.g., BK1721071). |
Media Container Structures
Video File Structure (hivxxxxx.mp4)
Despite the .mp4 file extension, these files are not standard MP4 containers. Instead, they are pre-allocated byte blocks containing raw MPEG Program Streams (MPEG-PS):
- Streams:
- Video Codec: HEVC (H.265).
- Audio Codec: PCM (G.711 A-law /
pcm_alaw). Note: Original recordings do not use AAC.
- Segment Storage:
- Multiple recordings are written sequentially into these containers, mapped by the offsets defined in the segment tables in
index00.bin.
- Multiple recordings are written sequentially into these containers, mapped by the offsets defined in the segment tables in
- MPEG-PS Validation:
- Valid segments start with the standard MPEG Program Stream Pack Start Code
0x000001BA(with MPEG-2 marker prefix byte0x40at offset 4). - A System Header sequence
0x000001BBis present within the first 2KB of any valid segment. - When a device is abruptly powered down or files are overwritten, segment blocks can become corrupted or partially written, which requires checking these magic bytes to prevent loading corrupt recordings.
- Valid segments start with the standard MPEG Program Stream Pack Start Code
Picture File Structure (hivxxxxx.pic)
These files act identically to the .mp4 files but are used exclusively for storing raw JPEG images (snapshots/thumbnails).
- Format:
- Standard JPEG binary images containing SOI (Start of Image) magic bytes
0xFF 0xD8 0xFF.
- Standard JPEG binary images containing SOI (Start of Image) magic bytes
- Segment Storage:
- Successive snapshots are dumped sequentially into the 256.4 MB block.
- Offsets mapping to exact byte locations in the
.picblock are found withinindex00p.bin.
Metadata
Release files for ezhikstract 1.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ezhikstract-1.0.1.tar.gz | 27.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ezhikstract-1.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 47.9 kB
Release files / ezhikstract-1.0.1.tar.gz
| Download URL | ezhikstract-1.0.1.tar.gz |
|---|---|
| Size | 27.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2603aa4f44d79f41eee2da2fce2f03b19b2b7ebd36f46b9572f3902b904c7f5b
|
|
BLAKE2b-256 checksum How to use checksums |
03d20a492357a3c3191996650b8634b8c891edb5a95d6c01642a753c30691afc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 2, 2026.
Transparency logRelease files / ezhikstract-1.0.1-py3-none-any.whl
| Download URL | ezhikstract-1.0.1-py3-none-any.whl |
|---|---|
| Size | 20.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
55a1dff2cd41a6778a5191c0f0805a423144c606b84d1b933265c2b54ce48200
|
|
BLAKE2b-256 checksum How to use checksums |
bb55e09a58f95aeeff51dfae4c47434104b91e1eac9bf880c176eb74980995ad
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 2, 2026.
Transparency log