H264 concatenation functions are moved to cutting module.
This commit is contained in:
+66
-2
@@ -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:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user