diff --git a/removeads.py b/removeads.py index a79a010..9865bb8 100755 --- a/removeads.py +++ b/removeads.py @@ -104,22 +104,61 @@ def getNearestIFrame(inputFile, timestamp, before=True, delta=timedelta(seconds= for frame in iframes: if before and timedelta(seconds=float(frame['pts_time'])) <= timestamp: found = True - res = frame + iframe = frame if not before and timedelta(seconds=float(frame['pts_time'])) >= timestamp: found = True - res = frame + iframe = frame break if found: logger.debug("Found: %s" % res) + + its = timedelta(seconds=float(iframe['pts_time'])) + nbFrames = 0 + for frame in frames: + ts = timedelta(seconds=float(frame['pts_time'])) + if before: + if its <= ts and ts <= timestamp: + nbFrames = nbFrames+1 + else: + if timestamp <= ts and ts <= its: + nbFrames = nbFrames+1 else: logger.error("Impossible to find I-frame around: %s" % timestamp) - return(res) + + return(nbFrames-1, iframe) else: logger.error('Impossible to retrieve video frames inside file around [%s,%s]' % (tbegin, tend)) return None - + +def extractMKVPart(inputFile, outputFile, begin, end): + inputFile.seek(0,0) + outputFile.seek(0,0) + infd = inputFile.fileno() + outfd = outputFile.fileno() + set_inheritable(infd, True) + set_inheritable(outfd, True) + with Popen(['mkvmerge', '-o', '/proc/self/fd/%d' % outfd, '--split', 'parts:%s-%s' % (begin, end), '/proc/self/fd/%d' % infd], stdout=PIPE, close_fds=False) as mkvmerge: + for line in TextIOWrapper(mkvmerge.stdout, encoding="utf-8"): + print(line, end='') + +def extractPictures(inputFile, begin, nbFrames, prefix, width=640, height=480): + inputFile.seek(0,0) + infd = inputFile.fileno() + set_inheritable(infd, True) + with Popen(['ffmpeg', '-loglevel', 'quiet', '-ss', '%s'%begin, '-i', '/proc/self/fd/%d' % infd, '-s', '%dx%d'%(width, height), '-vframes', '%d'%nbFrames, '-c:v', 'ppm', '-f', 'image2', '%s-%%03d.ppm' % prefix], stdout=PIPE, close_fds=False) as ffmpeg: + for line in TextIOWrapper(ffmpeg.stdout, encoding="utf-8"): + print(line, end='') + +def extractSound(inputFile, begin, outputFile, channel=0, nbPackets=10, sampleRate=48000, nbChannels=2): + inputFile.seek(0,0) + infd = inputFile.fileno() + set_inheritable(infd, True) + with Popen(['ffmpeg', '-loglevel', 'quiet', '-ss', '%s'%begin, '-i', '/proc/self/fd/%d' % infd, '-frames:a:%d' % channel, '%d' % nbPackets, + '-c:a', 'pcm_s32le', '-sample_rate', '%d' % 48000, '-channels', '%d' % 2, '-f', 's32le', '%s.pcm' % outputFile], stdout=PIPE, close_fds=False) as ffmpeg: + for line in TextIOWrapper(ffmpeg.stdout, encoding="utf-8"): + print(line, end='') def parseTimeInterval(interval): logger = logging.getLogger(__name__) @@ -287,6 +326,8 @@ def main(): for stream in streams: if stream['codec_type'] == 'video' and stream['disposition']['default'] == 1: mainVideo = stream + width = stream['width'] + height = stream['height'] if mainVideo == None: logger.error('Impossible to find main video stream.') @@ -305,17 +346,50 @@ def main(): if postFrame == None: exit(-1) + nbPreFrame, preIFrame = preFrame + nbPostFrame, postIFrame = postFrame - print(preFrame) - print(postFrame) + print("Found pre I-frame and %d frames between: %s" % (nbPreFrame, preIFrame)) + print("Found I-frame and %d frames between: %s" % (nbPostFrame, postIFrame)) - if timedelta(seconds=float(preFrame['pts_time'])) == ts1: + preIFrameTS = timedelta(seconds=float(preIFrame['pts_time'])) + postIFrameTS = timedelta(seconds=float(postIFrame['pts_time'])) + + if ts1 < preIFrameTS: + for stream in streams: + if stream['codec_type'] == 'video': + extractPictures(inputFile=mkv, begin=ts1, nbFrames=nbPreFrame, prefix="pre-part-%d" % partnum, width=width, height=height) + elif stream['codec_type'] == 'audio': + print("Extracting audio stream: %s" % stream) + sampleRate = stream['sample_rate'] + nbChannel = stream['channels'] + extractSound(inputFile=mkv, begin=ts1, nbPackets=nbPreFrame, outputFile="pre-part-%d" % partnum, sampleRate=sampleRate, nbChannels=nbChannels) + else: + pass + else: + # Nothing to do + pass + + if postIFrameTS < ts2: + for stream in streams: + if stream['codec_type'] == 'video': + extractPictures(inputFile=mkv, begin=postIFrameTS, nbFrames=nbPostFrame, prefix="post-part-%d" % partnum, width=width, height=height) + elif stream['codec_type'] == 'audio': + print("Extracting audio stream: %s" % stream) + sampleRate = stream['sample_rate'] + nbChannel = stream['channels'] + # TODO: how many packets should be dumped ... + # TODO: take into account multiple sound tracks ... + extractSound(inputFile=mkv, begin=postIFrameTS, nbPackets=nbPostFrame, outputFile="post-part-%d" % partnum, sampleRate=sampleRate, nbChannels=nbChannels) + else: + pass + else: # Nothing to do ! pass - if timedelta(seconds=float(postFrame['pts_time'])) == ts2: - # Nothing to do ! - pass + # Creating MKV file that corresponds to current part between I-frames + with open('part-%d.mkv' % partnum, 'w') as partmkv: + extractMKVPart(inputFile=mkv, outputFile=partmkv, begin=preIFrameTS, end=postIFrameTS) # Trouver l'estampille de la trame 'I' la plus proche (mais postérieure) au début de la portion. # Trouver l'estampille de la trame 'I' la plus proche (mais antérieure) à la fin de la portion.