H264 concatenation functions are moved to cutting module.

This commit is contained in:
Frédéric Tronel
2026-08-30 17:45:03 +02:00
parent 34d1bc26f3
commit d756fede54
5 changed files with 93 additions and 122 deletions
+66 -2
View File
@@ -4,10 +4,19 @@
import logging
from datetime import timedelta
from os import (
SEEK_SET,
fstat,
lseek,
read,
write,
)
from shutil import copyfile
from typing import IO, Any
from typing import IO, Any, BinaryIO, Sequence, TextIO
import hexdump
from tqdm import tqdm
from typeguard import typechecked
from tscut.exceptions import InvalidMediaError
from tscut.h264.avc import get_avc_config_from_h264
@@ -25,11 +34,66 @@ from tscut.tools.mkvtoolnix import (
remove_video_tracks_from_mkv,
)
from tscut.tools.timeframe import get_ts_frame
from tscut.tscut import concatenate_h264_parts, concatenate_h264_ts_parts
logger = logging.getLogger(__name__)
@typechecked
def concatenate_h264_parts(h264parts: Sequence[BinaryIO], output: BinaryIO) -> None:
logger = logging.getLogger(__name__)
total_length = 0
for h264 in h264parts:
fd = h264.fileno()
total_length += fstat(fd).st_size
logger.info('Total length: %d', total_length)
outfd = output.fileno()
lseek(outfd, 0, SEEK_SET)
pb = tqdm(total=total_length, unit='bytes', desc='Concatenation')
for h264 in h264parts:
fd = h264.fileno()
lseek(fd, 0, SEEK_SET)
while True:
buf = read(fd, 1000000)
if buf is None or len(buf) == 0:
break
pos = 0
while pos < len(buf):
nb_bytes = write(outfd, buf[pos:])
pb.update(nb_bytes)
pos += nb_bytes
def concatenate_h264_ts_parts(h264_ts_parts: Sequence[TextIO], output: TextIO) -> None:
logger = logging.getLogger(__name__)
header = '# timestamp format v2\n'
output.write(header)
last = 0.
first = True
for part in h264_ts_parts:
if first:
offset = last
else:
# TODO: take framerate into account
offset = last + 40
logger.debug('Parsing file: %s. Offset=%d', part, offset)
isheader = part.readline()
if (not isheader) or (isheader != header):
logger.error('Impossible to find a valid header: "%s"', isheader)
exit(-1)
while True:
line = part.readline()
if not line:
break
ts = offset + float(line)
last = max(last,ts)
output.write(f'{ts:f}\n')
if first:
first = False
def cut_recording(media: PreparedMedia, options: ProcessingOptions,
temporaries: list[IO[Any]]) -> CutResult: