| Previous | EuroHacker Magazine, issue #1 | Next |
Written by: guess who?
A while ago I needed to sample a pretty vast file collection, belonging to a dude I know on the Net. The files were large movie files and so I would have to download all of them just to check out if I liked 'em. This annoyed me so I thought about what to do. The idea I came up with was using mplayer to rip stills out of each file, so I could easily check out if it was worth downloading. In hindsight I could have downloaded chunks of each file using HTTP's Range header and then done mplayer -idx on them but I don't know if that would work plus that's an unnecessary waste of bandwidth. This solution only requires me to run the script on the dude's box.
It's worked so far, but it wouldn't surprise me if it craps out. YMMV. Also, this is my first and only Python script at this point, so don't harass me.
#!/usr/bin/python
import os, sys, commands, re, string, glob
def usage():
print 'pr0ngallery - A movie still gallery generator'
print 'Usage: pr0ngallery <files>'
def make_stills(filename, dir, interval, num_stills):
os.chdir(dir)
i=1
while i <= num_stills:
# grab a few frames
# I've found that to avoid black frames, cluttered frames and other crap, generally you need to grab the fourth frame
# -ss seek to second
# -frames number of frames to grab (you need to increment the desired number by one, oddly enough)
# -vo video out
# -ao audio out
# -z png compression level
os.system('mplayer -ss %d -frames 5 -vo png -z 1 -ao null "%s" 2>/dev/null >/dev/null' % (i*interval, filename))
#print "num_stills: %d" % num_stills
print 'Creating still %d for "%s"' % (i, filename)
try:
try:
os.rename('00000004.png', 'still_%06d.png' % i) # may fail, I've found
except OSError:
print 'Error, skipping'
continue
finally:
# delete all the crap
d=glob.glob('*.png')
for curr in d:
if not re.compile('^still.+$').match(curr):
os.unlink(curr)
i+=1
os.chdir('..')
def get_movie_info(filename):
buffer=commands.getoutput('mplayer -vo null -ao null -frames 0 -identify "%s"' % filename)
m=re.compile(r'.*?ID_VIDEO_FORMAT=([^\n]+).*?ID_VIDEO_BITRATE=([^\n]+).*?ID_VIDEO_WIDTH=([^\n]+).*?ID_VIDEO_HEIGHT=([^\n]+).*?ID_VIDEO_FPS=([^\n]+).*?ID_VIDEO_ASPECT=([^\n]+).*?ID_AUDIO_CODEC=([^\n]+).*?ID_AUDIO_FORMAT=([^\n]+).*?ID_AUDIO_BITRATE=([^\n]+).*?ID_AUDIO_RATE=([^\n]+).*?ID_AUDIO_NCH=([^\n]+).*?ID_LENGTH=([^\n]+)', re.S).match(buffer)
if not m:
print 'Unexpected error!'
sys.exit(-1)
t=m.groups()
info={'vformat': t[0], 'vbitrate': int(t[1]), 'vwidth': int(t[2]), 'vheight': int(t[3]), 'vfps': float(t[4]), 'vaspect': float(t[5]), 'acodec': t[6], 'aformat': int(t[7]), 'abitrate': int(t[8]), 'arate': int(t[9]), 'anch': int(t[10]), 'length': int(t[11])}
return info
if __name__ == '__main__':
# TODO: this shouldn't be hardcoded
base_dir='gallery'
if len(sys.argv) < 2:
usage()
sys.exit(-1)
# get curr dir
launch_dir=os.getcwd()
# make the dir where the galleries will be made
# abort if it already exists
if (os.access(base_dir, os.F_OK)):
print '"%s" already exists, aborting' % base_dir
sys.exit(-1)
# make the dir
os.mkdir(base_dir)
# change into it
os.chdir(base_dir)
i=1
# loop thru all the filenames given to us
for filename in sys.argv[1:]:
if not os.path.isabs(filename):
filename='%s/%s' % (launch_dir, filename)
num_stills=200 # TODO: shouldn't be hardcoded
movie_info=get_movie_info(filename)
#print movie_info
if movie_info['length'] == 0:
print 'Zero-length movie, skipping...'
continue
elif movie_info['length'] <= 10:
num_stills=1
# determine number of stills we need
# there should be at least 10 seconds between stills
elif float(movie_info['length'])/float(num_stills) < 10:
num_stills=int(float(movie_info['length'])/10)
interval=int(float(movie_info['length'])/num_stills)
print 'Making %d stills for movie "%s"' % (num_stills, filename)
print 'Using an interval of %d seconds for the stills' % interval
print 'Length of movie: %d seconds' % movie_info['length']
dir="stills_%09d" % i
os.mkdir('%s' % dir)
make_stills(filename, dir, interval, num_stills)
i+=1