We handle the case where subtitles track are eventually empty after processing.

This commit is contained in:
Frédéric Tronel
2023-12-24 16:52:40 +01:00
parent 48cc4f8a27
commit b94f865831

View File

@@ -190,7 +190,7 @@ def doOCR(vobsubocr, idxs, duration, temporaries, dumpMemFD=False):
if status != 0: if status != 0:
logger.error('OCR failed with status code: %d' % status) logger.error('OCR failed with status code: %d' % status)
if dumpMemFD: if dumpMemFD:
try: try:
dumpSrt = open(srtname,'w') dumpSrt = open(srtname,'w')
@@ -208,7 +208,9 @@ def doOCR(vobsubocr, idxs, duration, temporaries, dumpMemFD=False):
temporaries.append(dumpSrt) temporaries.append(dumpSrt)
res.append((srtfd, lang)) srtLength = fstat(srtfd).st_size
if srtLength > 0:
res.append((srtfd, lang))
return res return res
@@ -599,6 +601,25 @@ def getStreams(ffprobe, inputFile):
return None return None
def withSubtitles(ffprobe, inputFile):
logger = logging.getLogger(__name__)
infd = inputFile.fileno()
lseek(infd, 0, SEEK_SET)
set_inheritable(infd, True)
with Popen([ffprobe, '-loglevel', 'quiet', '-show_streams', '-of', 'json', '-i', '/proc/self/fd/%d' % infd], stdout=PIPE, close_fds=False) as ffprobe:
out, _ = ffprobe.communicate()
out = json.load(BytesIO(out))
if 'streams' in out:
streams = out['streams']
for stream in streams:
if 'codec_type' in stream and stream['codec_type'] == 'subtitle':
return True
else:
logger.error('Impossible to retrieve streams inside file')
return False
def parseTimestamp(ts): def parseTimestamp(ts):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -726,14 +747,23 @@ def ffmpegConvert(ffmpeg, ffprobe, inputFile, inputFormat, outputFile, outputFor
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
width, height = getVideoDimensions(ffprobe, inputFile) width, height = getVideoDimensions(ffprobe, inputFile)
subtitles = withSubtitles(ffprobe, inputFile)
infd = inputFile.fileno() infd = inputFile.fileno()
outfd = outputFile.fileno() outfd = outputFile.fileno()
set_inheritable(infd, True) set_inheritable(infd, True)
set_inheritable(outfd, True) set_inheritable(outfd, True)
with Popen([ffmpeg, '-y', '-loglevel', 'quiet', '-progress', '/dev/stdout', '-canvas_size', '%dx%d' % (width, height), '-f', inputFormat, '-i', '/proc/self/fd/%d' % infd,
'-map', '0:v', '-map', '0:a', '-map', '0:s', '-bsf:v', 'h264_mp4toannexb,dump_extra=freq=keyframe', '-vcodec', 'copy', '-acodec', 'copy', '-scodec', 'dvdsub', params = [ffmpeg, '-y', '-loglevel', 'quiet', '-progress', '/dev/stdout', '-canvas_size', '%dx%d' % (width, height), '-f', inputFormat, '-i', '/proc/self/fd/%d' % infd,
'-f', outputFormat, '/proc/self/fd/%d' % outfd], stdout=PIPE, close_fds=False) as ffmpeg: '-map', '0:v', '-map', '0:a']
if subtitles:
params.extend(['-map', '0:s'])
params.extend(['-bsf:v', 'h264_mp4toannexb,dump_extra=freq=keyframe', '-vcodec', 'copy', '-acodec', 'copy'])
if subtitles:
params.extend(['-scodec', 'dvdsub'])
params.extend(['-f', outputFormat, '/proc/self/fd/%d' % outfd])
with Popen(params, stdout=PIPE, close_fds=False) as ffmpeg:
pb = tqdm(TextIOWrapper(ffmpeg.stdout, encoding="utf-8"), total=int(duration/timedelta(seconds=1)), unit='s', desc='Conversion') pb = tqdm(TextIOWrapper(ffmpeg.stdout, encoding="utf-8"), total=int(duration/timedelta(seconds=1)), unit='s', desc='Conversion')
for line in pb: for line in pb:
if line.startswith('out_time='): if line.startswith('out_time='):
@@ -1276,11 +1306,11 @@ def remuxSRTSubtitles(mkvmerge, inputFile, outputFileName, subtitles):
status = mkvmerge.wait() status = mkvmerge.wait()
if status == 1: if status == 1:
logger.warning('Extraction returns warning') logger.warning('Remux subtitles returns warning')
for w in warnings: for w in warnings:
logger.warning(w) logger.warning(w)
elif status == 2: elif status == 2:
logger.error('Extraction returns errors') logger.error('Remux subtitles returns errors')
def main(): def main():
@@ -1460,9 +1490,14 @@ def main():
if nbHeadFrames > args.threshold: if nbHeadFrames > args.threshold:
# We extract all frames between the beginning upto the frame that immediately preceeds the I-frame. # We extract all frames between the beginning upto the frame that immediately preceeds the I-frame.
head = extractAllStreams(ffmpeg=paths['ffmpeg'], ffprobe=paths['ffprobe'], inputFile=mkv, begin=ts1, end=headIFrameTS, nbFrames=nbHeadFrames-1, filesPrefix='part-%d-head' % (partnum), streams=streams, width=width, height=height, temporaries=temporaries, dumpMemFD=args.dump) head = extractAllStreams(ffmpeg=paths['ffmpeg'], ffprobe=paths['ffprobe'], inputFile=mkv, begin=ts1, end=headIFrameTS, nbFrames=nbHeadFrames-1, filesPrefix='part-%d-head' % (partnum), streams=streams, width=width, height=height, temporaries=temporaries, dumpMemFD=args.dump)
# Change private codec data of the new file so that it is the same as the one of the original movie # If we are not at an exact boundary:
changeCodecPrivateData(paths['mkvinfo'], head, codecData) if head != None:
subparts.append(head) # Change private codec data of the new file so that it is the same as the one of the original movie
changeCodecPrivateData(paths['mkvinfo'], head, codecData)
subparts.append(head)
else:
# Nothing to do.
pass
# Creating MKV file that corresponds to current part between I-frames # Creating MKV file that corresponds to current part between I-frames
try: try:
@@ -1477,9 +1512,13 @@ def main():
if nbTailFrames > args.threshold: if nbTailFrames > args.threshold:
# We extract all frames between the I-frame (including it) upto the end. # We extract all frames between the I-frame (including it) upto the end.
tail = extractAllStreams(ffmpeg=paths['ffmpeg'], ffprobe=paths['ffprobe'], inputFile=mkv, begin=tailIFrameTS, end=ts2, nbFrames=nbTailFrames, filesPrefix='part-%d-tail' % (partnum), streams=streams, width=width, height=height, temporaries=temporaries, dumpMemFD=args.dump) tail = extractAllStreams(ffmpeg=paths['ffmpeg'], ffprobe=paths['ffprobe'], inputFile=mkv, begin=tailIFrameTS, end=ts2, nbFrames=nbTailFrames, filesPrefix='part-%d-tail' % (partnum), streams=streams, width=width, height=height, temporaries=temporaries, dumpMemFD=args.dump)
# Change private codec data of the new file so that it is the same as the one of the original movie if tail != None:
changeCodecPrivateData(paths['mkvinfo'], tail, codecData) # Change private codec data of the new file so that it is the same as the one of the original movie
subparts.append(tail) changeCodecPrivateData(paths['mkvinfo'], tail, codecData)
subparts.append(tail)
else:
# Nothing to do.
pass
if not args.fusion: if not args.fusion:
logger.info('Merging: %s' % subparts) logger.info('Merging: %s' % subparts)
@@ -1505,6 +1544,7 @@ def main():
copyfile('part-1.mkv', finalCutName) copyfile('part-1.mkv', finalCutName)
else: else:
logger.info("Nothing else to do.") logger.info("Nothing else to do.")
copyfile(mkvfilename, finalCutName)
try: try:
finalCut = open(finalCutName, mode='r') finalCut = open(finalCutName, mode='r')
@@ -1540,29 +1580,32 @@ def main():
else: else:
logger.error("Dropping subtitle: %s because it is missing language indication") logger.error("Dropping subtitle: %s because it is missing language indication")
logger.debug(sts) logger.info(sts)
listOfSubtitles = extractSRT(paths['mkvextract'], finalCutName, sts, supportedLangs) if len(sts) > 0:
logger.info(listOfSubtitles) listOfSubtitles = extractSRT(paths['mkvextract'], finalCutName, sts, supportedLangs)
for idxName, subName, _, _ in listOfSubtitles: logger.info(listOfSubtitles)
try: for idxName, subName, _, _ in listOfSubtitles:
idx = open(idxName,'r') try:
except IOError: idx = open(idxName,'r')
logger.error("Impossible to open %s." % idxName) except IOError:
exit(-1) logger.error("Impossible to open %s." % idxName)
try: exit(-1)
sub = open(subName,'r') try:
except IOError: sub = open(subName,'r')
logger.error("Impossible to open %s." % subName) except IOError:
exit(-1) logger.error("Impossible to open %s." % subName)
exit(-1)
temporaries.append(idx)
temporaries.append(sub) temporaries.append(idx)
temporaries.append(sub)
ocr = doOCR(paths['vobsubocr'], listOfSubtitles, duration, temporaries, args.dump) ocr = doOCR(paths['vobsubocr'], listOfSubtitles, duration, temporaries, args.dump)
logger.info(ocr) logger.info(ocr)
# Remux SRT subtitles # Remux SRT subtitles
remuxSRTSubtitles(paths['mkvmerge'], finalCut, args.outputFile, ocr) remuxSRTSubtitles(paths['mkvmerge'], finalCut, args.outputFile, ocr)
else:
copyfile(finalCutName, args.outputFile)
else: else:
move(finalCutName, args.outputFile) move(finalCutName, args.outputFile)