Created
November 6, 2025 10:15
-
-
Save jannejava/d0af62aaa07cbec41e2bdb5d8c87cb69 to your computer and use it in GitHub Desktop.
Convert H264 to SER
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| """Convert video to SER format for Planet Stacker X""" | |
| import struct | |
| import subprocess | |
| import sys | |
| from datetime import datetime | |
| def create_ser_file(input_file, output_file): | |
| """ | |
| Create a proper SER file with correct headers. | |
| SER format specification: http://www.grischa-hahn.homepage.t-online.de/astro/ser/ | |
| """ | |
| # Get video info using ffprobe | |
| cmd = [ | |
| 'ffprobe', '-v', 'error', | |
| '-select_streams', 'v:0', | |
| '-count_frames', | |
| '-show_entries', 'stream=width,height,nb_read_frames,r_frame_rate', | |
| '-of', 'default=noprint_wrappers=1', | |
| input_file | |
| ] | |
| result = subprocess.run(cmd, capture_output=True, text=True) | |
| lines = result.stdout.strip().split('\n') | |
| width = height = frames = 0 | |
| for line in lines: | |
| if line.startswith('width='): | |
| width = int(line.split('=')[1]) | |
| elif line.startswith('height='): | |
| height = int(line.split('=')[1]) | |
| elif line.startswith('nb_read_frames='): | |
| frames = int(line.split('=')[1]) | |
| if not all([width, height, frames]): | |
| print(f"Error: Could not get video info. w={width}, h={height}, frames={frames}") | |
| return False | |
| print(f"Video info: {width}x{height}, {frames} frames") | |
| # SER Header structure | |
| file_id = b'LUCAM-RECORDER' # 14 bytes | |
| lu_id = 0 # 4 bytes (LuID) | |
| color_id = 0 # 4 bytes (0 = MONO, 8 = BAYER_RGGB, etc.) | |
| little_endian = 0 # 4 bytes (0 = big-endian, 1 = little-endian) | |
| image_width = width # 4 bytes | |
| image_height = height # 4 bytes | |
| pixel_depth = 8 # 4 bytes (bits per pixel, 8 or 16) | |
| frame_count = frames # 4 bytes | |
| observer = b''.ljust(40, b'\x00') # 40 bytes | |
| instrument = b''.ljust(40, b'\x00') # 40 bytes | |
| telescope = b''.ljust(40, b'\x00') # 40 bytes | |
| date_time = 0 # 8 bytes (UTC time) | |
| date_time_utc = 0 # 8 bytes | |
| # Write SER header | |
| with open(output_file, 'wb') as f: | |
| f.write(file_id) | |
| f.write(struct.pack('<I', lu_id)) | |
| f.write(struct.pack('<I', color_id)) | |
| f.write(struct.pack('<I', little_endian)) | |
| f.write(struct.pack('<I', image_width)) | |
| f.write(struct.pack('<I', image_height)) | |
| f.write(struct.pack('<I', pixel_depth)) | |
| f.write(struct.pack('<I', frame_count)) | |
| f.write(observer) | |
| f.write(instrument) | |
| f.write(telescope) | |
| f.write(struct.pack('<Q', date_time)) | |
| f.write(struct.pack('<Q', date_time_utc)) | |
| print(f"SER header written (178 bytes)") | |
| # Extract frames using ffmpeg and append to SER file | |
| print("Extracting frames as raw grayscale data...") | |
| cmd = [ | |
| 'ffmpeg', '-i', input_file, | |
| '-f', 'rawvideo', | |
| '-pix_fmt', 'gray', | |
| '-' | |
| ] | |
| process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
| with open(output_file, 'ab') as f: | |
| while True: | |
| chunk = process.stdout.read(1024 * 1024) # Read 1MB at a time | |
| if not chunk: | |
| break | |
| f.write(chunk) | |
| process.wait() | |
| if process.returncode == 0: | |
| print(f"✓ SER file created successfully: {output_file}") | |
| return True | |
| else: | |
| print(f"Error during conversion") | |
| print(process.stderr.read().decode()) | |
| return False | |
| if __name__ == '__main__': | |
| input_file = 'input.mp4' | |
| output_file = 'output.ser' | |
| if len(sys.argv) > 1: | |
| input_file = sys.argv[1] | |
| if len(sys.argv) > 2: | |
| output_file = sys.argv[2] | |
| print(f"Converting {input_file} to SER format...") | |
| create_ser_file(input_file, output_file) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment