diff --git a/removeads.py b/removeads.py index 79f6a93..3629b80 100755 --- a/removeads.py +++ b/removeads.py @@ -359,7 +359,9 @@ def extractPictures(inputFile, begin, nbFrames, width=640, height=480): 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: while ffmpeg.poll() == None: - fds, _, _ = select([fdr, ffmpeg.stdout], [], [], .1) + # TODO: understand why this line ends up in reading on an already closed file descriptor + # fds, _, _ = select([fdr, ffmpeg.stdout], [], [], .1) + fds, _, _ = select([fdr], [], [], .1) if fdr in fds: buf = os.read(fdr, 1000000) # print("Read %d bytes of image. ffmpeg finished: %s" % (len(buf), ffmpeg.poll())) @@ -415,11 +417,47 @@ def extractSound(inputFile, begin, outputFile, subChannel=0, nbPackets=0, sample if status != 0: logger.error('Sound extraction returns error code: %d' % status) -def dumpPPM(pictures, prefix): - # "P6\nWIDTH HEIGHT\n255\n" - # headerLen=2+1+ceil(log(width, 10))+1+ceil(log(height, 10))+1+3+1 - pass - +def dumpPPM(pictures, prefix, temporaries): + logger = logging.getLogger(__name__) + + # "P6\nWIDTH HEIGHT\n255\n" + pos = 0 + picture = 0 + while pos[0-9]+) (?P[0-9]+)\n$') + m = pattern.match(dimensions) + if m != None: + width = int(m['width']) + height = int(m['height']) + else: + logger.error('Impossible to parse dimensions of picture') + return + else: + logger.error('Not a PPM picture') + return + + headerLen=2+1+ceil(log(width, 10))+1+ceil(log(height, 10))+1+3+1 + try: + out = open(filename, 'w') + outfd = out.fileno() + except IOError: + logger.error('Impossible to create file: %s' % filename) + temporaries.append(out) + + length=headerLen+3*width*height + nbBytes = 0 + while nbBytes < length: + nbBytes+=os.write(outfd, pictures[pos+nbBytes:pos+length]) + pos+=length + picture+=1 + + def extractAllStreams(inputFile, begin, end, streams, filesPrefix, nbFrames, width, height, temporaries, dumpPictures=False): logger = logging.getLogger(__name__) # encoderParams = [ 'ffmpeg', '-y', '-loglevel', 'quiet' ] @@ -460,7 +498,7 @@ def extractAllStreams(inputFile, begin, end, streams, filesPrefix, nbFrames, wid codec = stream['codec_name'] imagesBytes = extractPictures(inputFile=inputFile, begin=begin, nbFrames=nbFrames, width=width, height=height) if dumpPictures: - dumpPPM(imagesBytes, '%s-%d' % (filesPrefix,videoID)) + dumpPPM(imagesBytes, '%s-%d' % (filesPrefix,videoID), temporaries) # imagesBytes contains now a buffer of bytes that represents the pictures that have been dumped by ffmpeg. fdr, fdw = os.pipe() @@ -634,7 +672,7 @@ def main(): parser.add_argument("-o", "--output", dest='outputFile', type=str, required=True, help="Output MKV file to produce.") 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("--dump-pictures", action='store_true', 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.") args = parser.parse_args() logger.debug("Arguments: %s" % args) @@ -782,7 +820,7 @@ def main(): if nbHeadFrames > 0: # We extract all frames between the beginning upto the frame that immediately preceeds the I-frame. - head = extractAllStreams(inputFile=mkv, begin=ts1, end=headIFrameTS, nbFrames=nbHeadFrames-1, filesPrefix='part-%d-head' % (partnum), streams=streams, width=width, height=height, temporaries=temporaries) + head = extractAllStreams(inputFile=mkv, begin=ts1, end=headIFrameTS, nbFrames=nbHeadFrames-1, filesPrefix='part-%d-head' % (partnum), streams=streams, width=width, height=height, temporaries=temporaries, dumpPictures=args.dump) subparts.append(head) # Creating MKV file that corresponds to current part between I-frames @@ -797,7 +835,7 @@ def main(): if nbTailFrames > 0: # We extract all frames between the I-frame (including it) upto the end. - tail = extractAllStreams(inputFile=mkv, begin=tailIFrameTS, end=ts2, nbFrames=nbTailFrames, filesPrefix='part-%d-tail' % (partnum), streams=streams, width=width, height=height, temporaries=temporaries) + tail = extractAllStreams(inputFile=mkv, begin=tailIFrameTS, end=ts2, nbFrames=nbTailFrames, filesPrefix='part-%d-tail' % (partnum), streams=streams, width=width, height=height, temporaries=temporaries, dumpPictures=args.dump) subparts.append(tail) logger.info('Merging: %s' % subparts)