Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
208 views

FFMS Frame Python Script

This document contains code to take screenshots from a video file at specified frame numbers using Vapoursynth and Pillow. The screenshots are saved with an on-screen display (OSD) showing frame number, picture type, and additional optional text. Vapoursynth is used to load and process the video, Pillow is used to draw the OSD and save images. The code takes command line arguments for the video file, frame numbers, and additional text.

Uploaded by

Kashish Patel
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
208 views

FFMS Frame Python Script

This document contains code to take screenshots from a video file at specified frame numbers using Vapoursynth and Pillow. The screenshots are saved with an on-screen display (OSD) showing frame number, picture type, and additional optional text. Vapoursynth is used to load and process the video, Pillow is used to draw the OSD and save images. The code takes command line arguments for the video file, frame numbers, and additional text.

Uploaded by

Kashish Patel
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 2

import import import import

argparse ctypes io os

import vapoursynth as vs from PIL import Image, ImageFont, ImageDraw, ImageColor # Configuration # Full path to the ffms2 library PATH_TO_FFMS2_DLL = r'C:\ffms2-2.19\x64\ffms2.dll' # Below affects the OSD TEXT_COLOR = ImageColor.getrgb('yellow') FONT_SIZE = 18 OSD = '''Frame Number: {0} of {1} Picture Type: {2}'''

def main(source, frames=[], additional_text=[]): """Take some screenshots using vapoursynth Arguments: frames -- list of frame numbers additional_text -- self explanatory """ core = vs.get_core() core.std.LoadPlugin(path=PATH_TO_FFMS2_DLL) if not os.path.exists(source + '.ffindex'): print('Indexing {0}'.format(os.path.realpath(source))) print('This may take some time.') clip = core.ffms2.Source(source=source) # REQUIRES LIBASS # would be a good alternative to using PIL to draw text # clip = core.assvapour.Subtitle(clip, 'ASSVAPOUR') clip = core.resize.Spline(clip=clip, format=vs.RGB24) print(clip) for frame_num in frames: if frame_num >= clip.num_frames: print('ERROR:', frame_num, 'is out of bounds. Skipping.\n') continue frame = clip.get_frame(frame_num) print('Processing frame', frame_num) R = frame.get_read_ptr(0) G = frame.get_read_ptr(1) B = frame.get_read_ptr(2) r_data = ctypes.string_at(R.value, frame.width*frame.height) g_data = ctypes.string_at(G.value, frame.width*frame.height) b_data = ctypes.string_at(B.value, frame.width*frame.height) # TODO: Make this suck less data = bytearray(frame.width * frame.height * 3) for i in range(frame.width * frame.height): data[i*3] = r_data[i] data[i*3+1] = g_data[i] data[i*3+2] = b_data[i]

data = io.BytesIO(data) data = data.getvalue() image = Image.frombytes('RGB', (frame.width, frame.height), data) font = ImageFont.truetype('verdana.ttf', FONT_SIZE) draw = ImageDraw.Draw(image) x_offset = 8 draw_text(draw, x_offset, 0, OSD.format(frame_num, clip.num_frames, frame.props._PictType.decode()), font, TEXT_COLOR, 'black') for line, text in enumerate(additional_text): draw_text(draw, x_offset, FONT_SIZE + FONT_SIZE*line + 3*line, text, font, TEXT_COLOR, 'black') output = os.path.basename(source) output = os.path.splitext(output)[0] + '-{0}'.format(frame_num) + '.png' image.save(output) def draw_text(draw, x, y, text, font, fill, border): # thin border draw.text((x-1, y), text, border, font) draw.text((x+1, y), text, border, font) draw.text((x, y-1), text, border, font) draw.text((x, y+1), text, border, font) # thicker border draw.text((x-1, y-1), text, border, font) draw.text((x+1, y-1), text, border, font) draw.text((x-1, y+1), text, border, font) draw.text((x+1, y+1), text, border, font) # inner text draw.text((x,y), text, fill, font) if __name__ == '__main__': DESCRIPTION = """Take screenshots using vapoursynth""" parser = argparse.ArgumentParser(description=DESCRIPTION) parser.add_argument('-i', '--input', dest='input', required=True, help='video file from which to take screenshots') parser.add_argument('-f', '--frames', dest='frames', required=True, default='', help='comma separated list of frame numbers') parser.add_argument('--text', dest='text', required=False, default="", help='Additional text to be written after the OSD, separate lines with \\n') args = parser.parse_args() source frames frames text = = args.input = args.frames.split(',') = [ int(frame) for frame in frames ] args.text.split('\\n')

main(source, frames, text)

You might also like