Add functions related to ffmpeg, ppm files and timestamps to dedicated modules.
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Copyright (C) 2026 Frédéric Tronel
|
||||
|
||||
|
||||
import logging
|
||||
import re
|
||||
from math import ceil, log
|
||||
from os import write
|
||||
from typing import IO
|
||||
from io import BytesIO
|
||||
|
||||
|
||||
from typeguard import typechecked
|
||||
|
||||
@typechecked
|
||||
def dump_ppm(pictures: bytes, prefix: str, temporaries: list[IO[bytes]]) -> None:
|
||||
"""
|
||||
Dump PPM pictures from a bytes buffer to files.
|
||||
|
||||
This function takes a bytes buffer containing PPM pictures, a prefix for the output file names,
|
||||
and a list of temporary files.
|
||||
It extracts each PPM picture from the buffer, checks its validity, and writes it to a file.
|
||||
The output files are named according to the prefix and a zero-padded three-digit number.
|
||||
|
||||
Args:
|
||||
pictures (bytes): The bytes buffer containing the PPM pictures.
|
||||
prefix (str): The prefix for the output file names.
|
||||
temporaries (list[IO[bytes]]): A list of temporary files that will be used to store
|
||||
the output files.
|
||||
|
||||
Returns:
|
||||
None
|
||||
|
||||
Raises:
|
||||
None, but logs errors if:
|
||||
- the PPM picture is not valid (e.g. wrong magic number, dimensions, or color encoding)
|
||||
- an I/O error occurs while creating or writing to an output file
|
||||
"""
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# "P6\nWIDTH HEIGHT\n255\n"
|
||||
pos = 0
|
||||
picture = 0
|
||||
|
||||
logger.debug('Dumping %d pictures: %s', len(pictures),prefix)
|
||||
|
||||
while pos<len(pictures):
|
||||
filename = f'{prefix}-{picture:03d}.ppm'
|
||||
header = BytesIO(pictures[pos:])
|
||||
magic = header.readline().decode('utf8')
|
||||
dimensions = header.readline().decode('utf8')
|
||||
max_value = int(header.readline().decode('utf8'))
|
||||
if magic == 'P6\n':
|
||||
pattern = re.compile('^(?P<width>[0-9]+) (?P<height>[0-9]+)\n$')
|
||||
m = pattern.match(dimensions)
|
||||
if m is not None:
|
||||
width = int(m['width'])
|
||||
height = int(m['height'])
|
||||
else:
|
||||
logger.error('Impossible to parse dimensions of picture')
|
||||
return
|
||||
else:
|
||||
logger.error('Not a PPM picture')
|
||||
return
|
||||
|
||||
if max_value != 255:
|
||||
logger.error('Not a valid PPM picture. Color are not encoded on byte. Max value: %d',
|
||||
max_value)
|
||||
|
||||
header_len=2+1+ceil(log(width, 10))+1+ceil(log(height, 10))+1+3+1
|
||||
try:
|
||||
with open(filename, 'wb') as out:
|
||||
temporaries.append(out)
|
||||
outfd = out.fileno()
|
||||
length=header_len+3*width*height
|
||||
nb_bytes = 0
|
||||
while nb_bytes < length:
|
||||
nb_bytes+=write(outfd, pictures[pos+nb_bytes:pos+length])
|
||||
pos+=length
|
||||
picture+=1
|
||||
except OSError:
|
||||
logger.error('Impossible to create file: %s', filename)
|
||||
Reference in New Issue
Block a user