Compare commits

...

4 Commits

View File

@@ -26,11 +26,15 @@ from shutil import copyfile, which
def checkRequiredTools(): def checkRequiredTools():
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
tools = ['ffmpeg', 'ffprobe', 'mkvmerge'] required = ['ffmpeg', 'ffprobe', 'mkvmerge']
for tool in tools: optional = ['mkvextract', 'vobusbocr']
for tool in required:
if which(tool) == None: if which(tool) == None:
logger.error('Required tool: %s is missing.' % tool) logger.error('Required tool: %s is missing.' % tool)
exit(-1) exit(-1)
for tool in optional:
if which(tool) == None:
logger.info('Optional tool: %s is missing.' % tool)
@unique @unique
@@ -49,6 +53,11 @@ class SupportedFormat(IntEnum):
else: else:
return 'Unsupported format' return 'Unsupported format'
# Extract SPS/PPS
# https://gitlab.com/mbunkus/mkvtoolnix/-/issues/2390
# ffmpeg -i <InputFile (before concatenation)> -c:v copy -an -sn -bsf:v trace_headers -t 0.01 -report -loglevel 0 -f null -
def getFormat(inputFile): def getFormat(inputFile):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -352,10 +361,11 @@ def extractPictures(inputFile, begin, nbFrames, width=640, height=480):
# "P6\nWIDTH HEIGHT\n255\n" # "P6\nWIDTH HEIGHT\n255\n"
headerLen=2+1+ceil(log(width, 10))+1+ceil(log(height, 10))+1+3+1 headerLen=2+1+ceil(log(width, 10))+1+ceil(log(height, 10))+1+3+1
logger.debug('Header length: %d' % headerLen) logger.debug('Header length: %d' % headerLen)
length = (width*height*3+headerLen)*nbFrames imageLength = width*height*3+headerLen
length = imageLength*nbFrames
logger.debug("Estimated length: %d" % length) logger.debug("Estimated length: %d" % length)
pg = trange(length) pg = trange(nbFrames)
images = bytes() images = bytes()
with Popen(['ffmpeg', '-loglevel', 'quiet' ,'-y', '-ss', '%s'%begin, '-i', '/proc/self/fd/%d' % infd, '-s', '%dx%d'%(width, height), '-vframes', '%d'%nbFrames, '-c:v', 'ppm', '-f', 'image2pipe', '/proc/self/fd/%d' % fdw ], stdout=PIPE, close_fds=False) as ffmpeg: with Popen(['ffmpeg', '-loglevel', 'quiet' ,'-y', '-ss', '%s'%begin, '-i', '/proc/self/fd/%d' % infd, '-s', '%dx%d'%(width, height), '-vframes', '%d'%nbFrames, '-c:v', 'ppm', '-f', 'image2pipe', '/proc/self/fd/%d' % fdw ], stdout=PIPE, close_fds=False) as ffmpeg:
while ffmpeg.poll() == None: while ffmpeg.poll() == None:
@@ -363,11 +373,11 @@ def extractPictures(inputFile, begin, nbFrames, width=640, height=480):
# fds, _, _ = select([fdr, ffmpeg.stdout], [], [], .1) # fds, _, _ = select([fdr, ffmpeg.stdout], [], [], .1)
fds, _, _ = select([fdr], [], [], .1) fds, _, _ = select([fdr], [], [], .1)
if fdr in fds: if fdr in fds:
buf = os.read(fdr, 1000000) buf = os.read(fdr, imageLength)
# print("Read %d bytes of image. ffmpeg finished: %s" % (len(buf), ffmpeg.poll())) # print("Read %d bytes of image. ffmpeg finished: %s" % (len(buf), ffmpeg.poll()))
if len(buf) == 0: if len(buf) == 0:
break break
pg.update(len(buf)) pg.update(len(buf)/imageLength)
images=images+buf images=images+buf
if ffmpeg.stdout in fds: if ffmpeg.stdout in fds:
for line in TextIOWrapper(ffmpeg.stdout, encoding="utf-8"): for line in TextIOWrapper(ffmpeg.stdout, encoding="utf-8"):
@@ -379,11 +389,11 @@ def extractPictures(inputFile, begin, nbFrames, width=640, height=480):
while True: while True:
fd, _, _ = select([fdr], [], [], .1) fd, _, _ = select([fdr], [], [], .1)
if fd != []: if fd != []:
buf = os.read(fdr, 1000000) buf = os.read(fdr, imageLength)
# print("Read %d bytes of image" % len(buf)) # print("Read %d bytes of image" % len(buf))
if len(buf) == 0: if len(buf) == 0:
break break
pg.update(len(buf)) pg.update(len(buf)/imageLength)
images=images+buf images=images+buf
else: else:
# Nothing more to read # Nothing more to read
@@ -661,6 +671,28 @@ def mergeMKVs(inputs, outputName):
return out return out
def findSubtitlesTracks(filename):
# ffprobe -loglevel quiet -select_streams s -show_entries stream=index:stream_tags=language -of json corgi.ts
logger = logging.getLogger(__name__)
with Popen(['ffprobe', '-i', filename, '-select_streams', 's', '-show_entries', 'stream=index:stream_tags=language', '-of', 'json'], stdout=PIPE, close_fds=False) as ffprobe:
out, _ = ffprobe.communicate()
out = json.load(BytesIO(out))
if 'streams' in out:
return out['streams']
else:
logger.error('Impossible to retrieve format of file')
pass
def extractSubTitleTrack(inputFileName, index, lang):
# mkvextract video.mkv tracks position:nom [position:nom]
logger = logging.getLogger(__name__)
with Popen(['mkvextract', inputFileName, 'tracks', '%d:%s' % (index,lang)], stdout=PIPE, close_fds=False) as mkvextract:
out, _ = mkvextract.communicate()
for lines in out:
logger.info(out)
def main(): def main():
@@ -673,6 +705,7 @@ def main():
parser.add_argument("-p", "--part", dest='parts', nargs='+', required=False, action='append', metavar="hh:mm:ss[.mmm]-hh:mm:ss[.mmm]", help="Extract this exact part of the original file.") parser.add_argument("-p", "--part", dest='parts', nargs='+', required=False, action='append', metavar="hh:mm:ss[.mmm]-hh:mm:ss[.mmm]", help="Extract this exact part of the original file.")
parser.add_argument("-k", "--keep", action='store_true', help="Do not cleanup temporary files after processing.") parser.add_argument("-k", "--keep", action='store_true', help="Do not cleanup temporary files after processing.")
parser.add_argument("--dump-pictures", action='store_true', dest='dump', help="For debug purpose, dump pictures of headers (and trailers) before (after) each part. They are kept in memory only otherwise.") parser.add_argument("--dump-pictures", action='store_true', dest='dump', help="For debug purpose, dump pictures of headers (and trailers) before (after) each part. They are kept in memory only otherwise.")
parser.add_argument("-s","--srt", action='store_true', dest='srt', help="Dump subtitles ")
args = parser.parse_args() args = parser.parse_args()
logger.debug("Arguments: %s" % args) logger.debug("Arguments: %s" % args)
@@ -857,6 +890,38 @@ def main():
else: else:
logger.info("Nothing else to do.") logger.info("Nothing else to do.")
if args.srt:
logger.info("Find subtitles tracks and language.")
subtitles = findSubtitlesTracks(args.outputFile)
sts = {}
for subtitle in subtitles:
index = subtitle['index']
if 'tags' in subtitle:
if 'language' in subtitle['tags']:
lang = subtitle['tags']['language']
if lang in sts:
sts[lang].append(index)
else:
sts[lang] = [index]
else:
logger.error("Dropping subtitle: %s because it is missing language indication")
else:
logger.error("Dropping subtitle: %s because it is missing language indication")
for lang in sts:
indexes = sts[lang]
if len(indexes) == 0:
# Nothing to do. This should not happen.
continue
if len(indexes) == 1:
index = indexes[0]
filename = 'essai-%s.srt' % lang
elif len(indexes) > 1:
nbsrt = 1
for index in indexes:
filename = 'essai-%s-%d.srt' % (lang, nbsrt)
nbsrt+=1
if not args.keep: if not args.keep:
logger.info("Cleaning temporary files") logger.info("Cleaning temporary files")
for f in temporaries: for f in temporaries: