From b94f865831ef3cd870be71a9d8482ac8e2d4e82e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Tronel?= Date: Sun, 24 Dec 2023 16:52:40 +0100 Subject: [PATCH] We handle the case where subtitles track are eventually empty after processing. --- removeads.py | 111 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 77 insertions(+), 34 deletions(-) diff --git a/removeads.py b/removeads.py index 251683b..b152b9a 100755 --- a/removeads.py +++ b/removeads.py @@ -190,7 +190,7 @@ def doOCR(vobsubocr, idxs, duration, temporaries, dumpMemFD=False): if status != 0: logger.error('OCR failed with status code: %d' % status) - + if dumpMemFD: try: dumpSrt = open(srtname,'w') @@ -208,7 +208,9 @@ def doOCR(vobsubocr, idxs, duration, temporaries, dumpMemFD=False): temporaries.append(dumpSrt) - res.append((srtfd, lang)) + srtLength = fstat(srtfd).st_size + if srtLength > 0: + res.append((srtfd, lang)) return res @@ -599,6 +601,25 @@ def getStreams(ffprobe, inputFile): 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): logger = logging.getLogger(__name__) @@ -726,14 +747,23 @@ def ffmpegConvert(ffmpeg, ffprobe, inputFile, inputFormat, outputFile, outputFor logger = logging.getLogger(__name__) width, height = getVideoDimensions(ffprobe, inputFile) + subtitles = withSubtitles(ffprobe, inputFile) infd = inputFile.fileno() outfd = outputFile.fileno() set_inheritable(infd, 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', - '-f', outputFormat, '/proc/self/fd/%d' % outfd], stdout=PIPE, close_fds=False) as ffmpeg: + + params = [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'] + 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') for line in pb: if line.startswith('out_time='): @@ -1276,11 +1306,11 @@ def remuxSRTSubtitles(mkvmerge, inputFile, outputFileName, subtitles): status = mkvmerge.wait() if status == 1: - logger.warning('Extraction returns warning') + logger.warning('Remux subtitles returns warning') for w in warnings: logger.warning(w) elif status == 2: - logger.error('Extraction returns errors') + logger.error('Remux subtitles returns errors') def main(): @@ -1460,9 +1490,14 @@ def main(): if nbHeadFrames > args.threshold: # 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) - # 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) + # If we are not at an exact boundary: + if head != None: + # 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 try: @@ -1477,9 +1512,13 @@ def main(): if nbTailFrames > args.threshold: # 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) - # Change private codec data of the new file so that it is the same as the one of the original movie - changeCodecPrivateData(paths['mkvinfo'], tail, codecData) - subparts.append(tail) + if tail != None: + # Change private codec data of the new file so that it is the same as the one of the original movie + changeCodecPrivateData(paths['mkvinfo'], tail, codecData) + subparts.append(tail) + else: + # Nothing to do. + pass if not args.fusion: logger.info('Merging: %s' % subparts) @@ -1505,6 +1544,7 @@ def main(): copyfile('part-1.mkv', finalCutName) else: logger.info("Nothing else to do.") + copyfile(mkvfilename, finalCutName) try: finalCut = open(finalCutName, mode='r') @@ -1540,29 +1580,32 @@ def main(): else: logger.error("Dropping subtitle: %s because it is missing language indication") - logger.debug(sts) - listOfSubtitles = extractSRT(paths['mkvextract'], finalCutName, sts, supportedLangs) - logger.info(listOfSubtitles) - for idxName, subName, _, _ in listOfSubtitles: - try: - idx = open(idxName,'r') - except IOError: - logger.error("Impossible to open %s." % idxName) - exit(-1) - try: - sub = open(subName,'r') - except IOError: - logger.error("Impossible to open %s." % subName) - exit(-1) - - temporaries.append(idx) - temporaries.append(sub) + logger.info(sts) + if len(sts) > 0: + listOfSubtitles = extractSRT(paths['mkvextract'], finalCutName, sts, supportedLangs) + logger.info(listOfSubtitles) + for idxName, subName, _, _ in listOfSubtitles: + try: + idx = open(idxName,'r') + except IOError: + logger.error("Impossible to open %s." % idxName) + exit(-1) + try: + sub = open(subName,'r') + except IOError: + logger.error("Impossible to open %s." % subName) + exit(-1) + + temporaries.append(idx) + temporaries.append(sub) - ocr = doOCR(paths['vobsubocr'], listOfSubtitles, duration, temporaries, args.dump) - logger.info(ocr) + ocr = doOCR(paths['vobsubocr'], listOfSubtitles, duration, temporaries, args.dump) + logger.info(ocr) - # Remux SRT subtitles - remuxSRTSubtitles(paths['mkvmerge'], finalCut, args.outputFile, ocr) + # Remux SRT subtitles + remuxSRTSubtitles(paths['mkvmerge'], finalCut, args.outputFile, ocr) + else: + copyfile(finalCutName, args.outputFile) else: move(finalCutName, args.outputFile)