Попал ко мне в руки жёсткий диск от видеорегистратора неизвестной марки с нетривиальной для меня задачей – восстановить видео за определённый период времени.
Выбор программного обеспечения
Сканирование диска программой DVR Examiner (обычно её использовал для подобных целей) показало, что на диске всего 4 видеофрагмента с одной камеры. То есть программа не очень отработала.
Дальше просканировал диск программой myCCTV Recovery – демо версия нашла все камеры и все ролики. Правда восстановить ничего не позволяет, а за однократное использование программа просит 200 Евро. Слишком много вообще-то. Не могу себе позволить. Но я убедился, что видео на диске есть. Будем копать дальше.
Нашёл ещё одну китайскую программу – аналогично myCCTV Recovery, все видео нашла, но восстановить тоже 200 Евро. Активированную не нашёл. Что же дальше.
Ручное восстановление
Посовещавшись со знакомыми экспертами в этой области я решил попробовать выковырять видеопоток вручную.
Снял образ с диска (на всякий случай) и посмотрел начало диска в HEX-редакторе:
Сигнатура ZHILING1.0 – спецификацию не этот формат я не нашёл, но мне подсказали опорные моменты.
Итак, идёт сигнатура вышеупомянутая, затем большая область нулей.
Начиная со смещения 0x0008F60000 пошёл видеопоток.
Формат следующий:
- Начало фрейма: 4 байта (5A 4C 41 56) “ZLAV”;
- Тип фрейма: 2 байта (00 FC);
- Номер канала (камера, нумерация с 0): 2 байта (00 00);
- Номер последовательности: 4 байта (00 00 00 3E);
- Секунды: 4 байта (00 00 06 0F);
- Далее неизвестное поле и данные фрейма в формате h264;
- Окончание фрейма: 4 байта (7A 6C 61 76) “zlav”;
И такая ситуация циклична…
То есть мне по сути надо читать содержимое диска, искать по сигнатуре ZLAV, затем прочитать номер канала – если это нужная камера, то выгрузить фрейм в выходной файл. Далее нужно будет упорядочить по номеру последовательности и сконвертировать в mpeg например бесплатной ffmpeg.exe.
Python-скрипт
import io import os f_input = open(r'1.dd', 'rb') f_input.seek(0, io.SEEK_END) file_size = f_input.tell() print('file size = {}'.format(file_size)) START_OFFSET = 0x0008F60000 CHUNK_SIZE = 1024 * 1024 * 16 frames_count = 0 channels_var = dict() types_var = dict() frame_seq_prev = -1 f_input.seek(START_OFFSET, io.SEEK_SET) data_bytes = bytearray() total_bytes_done = 0 f_output_ch_index = 0 f_output_ch = None while f_input.tell() < file_size: data_bytes.extend(bytearray(f_input.read(CHUNK_SIZE))) frame_channel = -1 for i in range(0, len(data_bytes) - 64): if b'ZLAV' in data_bytes[i:i + 4]: frame_offset = i frame_type = data_bytes[i + 4] frame_channel = data_bytes[i + 6] if frame_channel != 2: continue frame_seq = int.from_bytes(data_bytes[i + 8:i + 12], byteorder='little', signed=False) frame_time_seconds = int.from_bytes(data_bytes[i + 16:i + 20], byteorder='little', signed=False) if b'zlav' in data_bytes[i:i + 4]: frames_count = frames_count + 1 frame_size = int.from_bytes(data_bytes[i + 4:i + 8], byteorder='little', signed=False) if frame_channel == 2: if frame_type == 0xfc or frame_type == 0xfd: if f_output_ch is None: f_output_ch = open('ch{}_{}_{}.h264'.format(frame_channel + 1, frame_time_seconds, f_output_ch_index), 'wb') f_output_ch.write(data_bytes[frame_offset + 8:frame_offset + frame_size - 8]) f_output_ch.flush() if frame_channel not in channels_var.keys(): channels_var[frame_channel] = 0 channels_var[frame_channel] = channels_var[frame_channel] + 1 if frame_seq_prev + 1 != frame_seq: f_output_ch.close() f_output_ch_index = f_output_ch_index + 1 f_output_ch = open('ch{}_{}_{}.h264'.format(frame_channel + 1, frame_time_seconds, f_output_ch_index), 'wb') frame_seq_prev = frame_seq frame_str = '' total_bytes_done = total_bytes_done + 1 data_bytes = data_bytes[-64:] print('chunk done, total bytes = {}'.format(START_OFFSET + total_bytes_done)) print('frames count = {}'.format(frames_count)) print('channels = {}'.format(channels_var)) f_input.close() f_output_ch.close()
На 500 Гб образе скрипт работал примерно неделю. На выходе получил множество .h264 файлов видеопотока.
После чего запустил батник:
FOR %%f IN (*.h264) DO ffmpeg.exe -i %%f -vcodec copy %%f.mpeg
И файлы преобразуются в mpeg. Их уже можно просмотреть в обычном проигрывателе Media Player Classic. Осталось найти нужный фрагмент и при желании склеить отдельные куски.
P.S. Скрипт мне подсказал коллега, который пожелал остаться неизвестным. )
Comments: