thermalcam_decoder/decode.py

83 lines
2.2 KiB
Python
Raw Normal View History

2023-12-25 23:09:03 +02:00
from os import system
import numpy as np
from tqdm import tqdm
import pandas as pd
import pcapng
2023-12-26 15:34:22 +02:00
from struct import unpack
2023-12-25 23:09:03 +02:00
from PIL import Image
2023-12-26 16:35:32 +02:00
# Read packets from a pcap file
2023-12-25 23:09:03 +02:00
scanner = pcapng.scanner.FileScanner(open('in.pcap', 'rb'))
blocks = list(tqdm(scanner))
2023-12-26 16:35:32 +02:00
# Helper function to safely get an attribute from an object
2023-12-25 23:09:03 +02:00
def tryget(obj, att):
if hasattr(obj, att):
return getattr(obj, att)
return None
2023-12-26 15:34:22 +02:00
2023-12-25 23:09:03 +02:00
2023-12-26 16:35:32 +02:00
# Create a DataFrame with packet lengths
2023-12-25 23:09:03 +02:00
df = pd.DataFrame([{'index': i, 'length': tryget(obj, 'packet_len')} for i, obj in enumerate(blocks)])
2023-12-26 16:35:32 +02:00
# Filter and extract data packets of a specific length
2023-12-25 23:09:03 +02:00
data = [blocks[i] for i in df[df.length == 6972.0].index]
2023-12-26 16:35:32 +02:00
# Remove the UDP header from the packets
2023-12-25 23:09:03 +02:00
raw = [d.packet_data[0x2a:] for d in data]
2023-12-26 16:35:32 +02:00
# Function to parse packet data
2023-12-25 23:09:03 +02:00
def parse(data):
2023-12-26 16:35:32 +02:00
hdr = 4 + 2 * 7 # Header length
# Unpack data into variables
2023-12-25 23:09:03 +02:00
c1, c2, part, a, ffaa, b, c, d = unpack('>Lhhhhhhh', data[:hdr])
ret = locals()
del ret['data']
del ret['hdr']
ret['data'] = data[hdr:]
return ret
2023-12-26 15:34:22 +02:00
2023-12-26 16:35:32 +02:00
# Parse each packet and create a DataFrame
2023-12-25 23:09:03 +02:00
df = pd.DataFrame([parse(d) for d in raw])
df2 = df[[c for c in df.columns if c != 'data']]
2023-12-26 16:35:32 +02:00
# Function to group data into frames
2023-12-25 23:09:03 +02:00
def getframes(df):
frames = []
current = []
for i, row in df.iterrows():
if row.part == 0:
if len(current) > 0:
frames.append(current)
current = []
current.append(row['data'])
if len(current) > 0:
frames.append(current)
return [b''.join(parts) for parts in frames]
2023-12-26 16:35:32 +02:00
# Function to convert binary frame data into images
2023-12-25 23:09:03 +02:00
def image16(frame, width, height, pixelformat='>H'):
2023-12-26 15:34:22 +02:00
return [
Image.fromarray(np.frombuffer(frame, dtype=pixelformat).reshape(width, height)) for frame in frames
if len(frame) == 2 * width * height
2023-12-26 16:35:32 +02:00
]
2023-12-25 23:09:03 +02:00
2023-12-26 16:35:32 +02:00
# Get frames and convert them to images
2023-12-25 23:09:03 +02:00
frames = getframes(df)
images = image16(frames, 384, 288)
2023-12-26 16:35:32 +02:00
# Save each image as a PNG file
2023-12-25 23:09:03 +02:00
for i, img in enumerate(tqdm(images)):
img.save(f'{i:04}.png')
2023-12-26 16:35:32 +02:00
# Produce a video from the saved images
system('ffmpeg -hide_banner -loglevel info -y -f image2 -framerate 25 -i %04d.png -vf "transpose=1" -s 384x288 -vcodec libx264 -pix_fmt yuv420p thermal.mp4')
2023-12-25 23:55:12 +02:00
print('to play: ffplay thermal.mp4')