Sunday, April 3, 2011

Weekend Project: Movie Roll

A question entered my mind and didn't go away like silly questions normally do: How difficult would it be to make a movie roll image - you know the ones with snapshots taken from a movie, and nicely stuck together in a single image. Surely this couldn't be difficult to pull off. How about if I have to do it in Windows? Using standard command shell as a glue. And using only general purpose tools, preferably something I already have on my machine, command-line tools, because they are small and usually quite customizable. How long would it take me?

Turns out quite a few hours. But it did it! Using nothing but standard Windows cmd and ffmpeg. Not only that, turns out ffmpeg, even though it wasn't designed for this, is quite capable of doing movie rolls all by itself in a single pass, and all it needs is just a set of few clever instructions.

So I made this little script:

@echo off
rem standard WinXP CMD script with FFMPEG being the only external program required 
rem originally made by Gregor Brecko, apr-2011
rem
setLocal EnableDelayedExpansion

rem USER SETTINGS

set src=%~1
set ffmpeg=W:\Program Files\3GP\ffmpeg.exe
set /a duration=(1*60+10)*60
set /a countX=8
set /a countY=10
set /a thumbWidth=320
set /a thumbHeight=(thumbWidth * 9) / 16
rem set /a thumbHeight=(thumbWidth * 3) / 4
set /a padding=1


if not exist "%src%" (
  echo File not found. Usage: MOVIEROLL1 your-movie-file
  exit /b
)


rem BUILD THUMBNAILS (USING 1-PASS FFMPEG -- fast but with limitations)

rem FFMPEG limitations:
rem   - each option must be less than 1000 characters long
rem     so we temporarily rename the original video to save command-line space
rem   - movie-filter's seek_point doesn't work beyond 1:11:00 mark (2^32 microseconds)
rem   - creating movie-filters is memory intensive; you may make it with 120 or more for
rem     small video frame sizes, and around 80 with 720p ones

for /f "tokens=* delims= " %%f in ("%src%") do (
  cd /d "%%~dpf"
  if errorlevel 1 exit /b
  set ext=a%%~xf
)

set /a interval=duration / (1 + countX * countY)
set /a T=%interval%
set /a forY=padding
for /L %%Y in (1,1,%countY%) do (
  set /a forX=padding
  for /L %%X in (1,1,%countX%) do (   
    rem set vf1=!vf1!movie=%ext%:sp=!T!,scale=%thumbWidth%:-1,setpts=PTS-STARTPTS[%%Xx%%Y];
    set vf1=!vf1!movie=%ext%:sp=!T!,scale=%thumbWidth%:-1[%%Xx%%Y];
    set vf2=!vf2!,[%%Xx%%Y]overlay=!forX!:!forY!
    set /a forX=!forX! + padding + thumbWidth
    set /a T=!T! + interval
  )
  set /a forY=!forY! + padding + thumbHeight
)
set /a forX=forX + padding
set /a forY=forY + padding

rem bail out if we failed already, don't want to do a rename and then fail some more, possibly stuck and unable to rename back
if errorlevel 1 exit /b
echo. >"%src%.ren"
ren "%src%" "%ext%"
if errorlevel 1 exit /b

"%ffmpeg%" -i "%ext%" -vframes 1 -vf "[in]scale=%thumbWidth%:-1,setpts=PTS-STARTPTS[i2];%vf1%color=black:%forX%x%forY%,[i2]overlay=%padding%:%padding%%vf2%" "%src%.jpg"

rem reset errorlevel
cmd /c "exit /b 0"

move "%ext%" "%src%"
if errorlevel 1 exit /b
del "%src%.ren"


And the result? See for yourself:


No comments:

Post a Comment