;+ ; NAME: ; mk_flick ; PURPOSE: ; Make movie from group of image files ; CATEGORY: ; sat/idl/util ; CALLING SEQUENCE: PRO mk_flick, movie, filter, $ delay = delay , $ loop = loop , $ mpeg = mpeg , $ png = png , $ gif = gif , $ first = first , $ last = last , $ fps = fps , $ bits = bits , $ timestamp=timestamp , $ frames = frames , $ cleanup = cleanup , $ silent = silent , $ step = step ; INPUTS: ; movie scalar; type: string ; name of movie file; if no directory is specified the ; movie file is created in the current directory ; filter scalar or array; type: string ; a scalar identifying a group of image files. This ; could be a directory (all files) or a filter containing ; a wild card. An array should be a list of file names. ; OPTIONAL INPUT PARAMETERS: ; first=first scalar; type: integer ; last =last scalar; type: integer ; number of images used to make movies ; use only first or last group of files (after sorting ; file names) to make a movie ; /png makes an mng movie (this is the default) ; /mpeg makes an mpeg movie ; /gif makes an animated gif movie using gifsicle ; step=step scalar; type: integer ; Use only one frame of every 'step' frames ; ; Keywords for mng and gif movies (tested with convert and gifsicle): ; ; delay=delay sets the delay between images in units of 0.01 seconds ; /loop created an animation with an infinite loop ; ; ffmpeg keywords: ; ; fps=fps frames per second ; bits=bits bits per second ; OUTPUTS: ; (creates movie file) ; INCLUDE: @compile_opt.pro ; On error, return to caller ; CALLS: ; InitVar, CheckDir, FindAllSubdirs, IsType ; RESTRICTIONS: ; Runs only on Linux so far. ; PROCEDURE: ; PNG animation (mng movie): ; ; Uses 'convert'. This is part of ImageMagick, and is usually located ; in /usr/X11R6/bin or /usr/bin. It is called with keywords -loop 0 ; (if /loop is set) and -delay (if delay=delay is specified). ; ; GIF animation (gif movie): ; Uses 'gifsicle'. It is called with keywords --loop (if /loop ; is set) and --delay= (if delay=delay is specified). ; ; MPG animation (mpeg movie) ; Uses 'ffmpeg'. It is called with keywords fps and bits (if provided ; as keywords). ; ; The executable is located by spawning a 'which' command, i.e. the ; movie maker program must be in the path. ; MODIFICATION HISTORY: ; APR-2001, Paul Hick (UCSD/CASS) ; SEP-2001, Paul Hick (UCSD/CASS) ; Merged Kevin's mk_mpeg with this procedure. ; MAY-2003, Paul Hick (UCSD/CASS) ; Added PNG animation. This is now the default. ; OCT-2006, John Clover, Paul Hick (UCSD/CASS; pphick@ucsd.edu) ; MPEG support is now done with ffmpeg ;- InitVar, png , /key InitVar, gif , /key InitVar, whirl , /key InitVar, mpeg , /key InitVar, timestamp, /key InitVar, cleanup, /key InitVar, silent , 0 InitVar, step , 1 png = png OR (1-gif AND 1-mpeg) files = filter nfile = n_elements(files) ; A scalar might be a directory. Pick up all files in the directory. IF nfile EQ 1 THEN $ IF CheckDir(files[0],/silent) THEN $ files = file_search(filepath(root=files[0], '*.*'), count=nfile) IF IsType(first, /defined) OR IsType(last, /defined) THEN BEGIN ; A list of all files is needed in case a wildcard is specified ; (if not the wildcard is passed directly to gifsicle). IF nfile EQ 1 THEN files = file_search(files[0], count=nfile) IF nfile GT 0 THEN BEGIN files = files[sort(files)] CASE IsType(last,/defined) OF 0: files = files[0:(first < nfile)-1] 1: files = files[(nfile-last) > 0:nfile-1] ENDCASE nfile = n_elements(files) ENDIF ENDIF ; Check whether individual image files are available to make movie. ; If not then display message and return IF nfile EQ 0 THEN BEGIN message, /info, 'no files to make '+movie RETURN ENDIF ; Pick the movie program. Default is the animated gif program 'gifsicle' CASE 1 OF png : movie_prog = 'convert' gif : movie_prog = 'gifsicle' mpeg : movie_prog = 'ffmpeg' ENDCASE ; First look for a native version of the movie maker program by spawning ; a 'which' command. CASE !version.os_family OF 'unix': BEGIN spawn, 'which '+movie_prog+' 2> /dev/null', movie_maker ; Search for executable movie_maker = movie_maker[0] IF timestamp THEN BEGIN spawn, 'which convert 2> /dev/null', timestamp timestamp = timestamp[0] ENDIF END ELSE : movie_maker = '' ENDCASE ; SolarSoft contains several movie maker programs: whirlgif and mpeg_encode. ; Try to find the executable there. We pick the subdirectory in ; $SSW/packages/binaries/exe containing the string !version.os in its name; ; then search that directory for the executable. ssw = getenv('SSW') ; Check for SolarSoft IF ssw NE '' AND movie_maker EQ '' THEN BEGIN exe = filepath(root=SSW, subdir=['packages','binaries','exe'],'') sub = FindAllSubdirs(exe, count=count) ; Get subdirectories for different OS if count ne 0 then begin i = (where( strpos( strmid(sub, strlen(exe)), !version.os) NE -1, count ))[0] IF count Ne -1 THEN $ ; Subdirectory for !version.os found movie_maker = ( file_search( filepath(root=sub[i], movie_prog) ) )[0] ENDIF ENDIF ; If movie_maker program was not found, return after displaying message IF movie_maker EQ '' THEN BEGIN message, /info, movie_prog+' not found' RETURN ENDIF ; Now make the movie CASE 1 OF gif : BEGIN InitVar, loop, /key real_cmd = movie_maker ; Add keywords ( --loop and --delay=?? ) hide_cmd = hide_env(movie_maker) add_cmd = '' IF IsType(delay, /defined) THEN add_cmd += ' --delay='+strcompress(delay, /rem) IF loop THEN add_cmd += ' --loop' real_cmd += add_cmd hide_cmd += add_cmd IF step EQ 1 THEN BEGIN CASE nfile EQ 1 OF 0: files = strjoin(files, ' ') 1: BEGIN files = files[0] ; Probably contains wildcard nfile = n_elements(file_search(files)) END ENDCASE ENDIF ELSE BEGIN IF nfile EQ 1 THEN files = file_search(files[0],count=nfile) nfile /= step files = files[ step*lindgen(nfile) ] files = strjoin(files, ' ') ENDELSE real_cmd += ' '+files+' > '+movie ; Setup up shell command and spawn it. hide_cmd += ' '+hide_env(files)+' > '+hide_env(movie) END png: BEGIN InitVar, loop, /key real_cmd = movie_maker ; Add keywords ( --loop and --delay=?? ) hide_cmd = hide_env(movie_maker) add_cmd = '' IF IsType(delay, /defined) THEN add_cmd += ' -delay '+strcompress(delay, /rem) IF loop THEN add_cmd += ' -loop 0' real_cmd += add_cmd hide_cmd += add_cmd IF step EQ 1 THEN BEGIN CASE nfile EQ 1 OF 0: files = strjoin(files, ' ') 1: BEGIN files = files[0] ; Probably contains wildcard nfile = n_elements(file_search(files)) END ENDCASE ENDIF ELSE BEGIN IF nfile EQ 1 THEN files = file_search(files[0],count=nfile) nfile /= step files = files[ step*lindgen(nfile) ] files = strjoin(files, ' ') ENDELSE real_cmd += ' '+files+' '+movie ; Setup up shell command and spawn it. hide_cmd += ' '+hide_env(files)+' '+hide_env(movie) END mpeg : BEGIN IF nfile EQ 1 THEN $ ; files[0] probably contains wildcard files = file_search(files[0],count=nfile); Need list of files for convert IF timestamp THEN BEGIN stampinfo = qframestamp(1) IF IsType(stampinfo,/array) THEN BEGIN FOR i=0,nfile-1 DO BEGIN real_cmd = timestamp IF stampinfo[0] THEN real_cmd += " -box '#0009' -font helvetica -fill white -pointsize 12 -gravity "+stampinfo[0]+" -annotate +0+0 "+'"'+frames[i]+'" ' IF stampinfo[1] NE "" AND stampinfo[2] NE "" THEN real_cmd += " -box '#0009' -font helvetica -fill white -pointsize 12 -gravity "+stampinfo[1]+" -annotate +0+0 "+'"'+stampinfo[2]+'" ' real_cmd += files[i]+" "+files[i] spawn, real_cmd ENDFOR ENDIF ENDIF real_cmd = movie_maker hide_cmd = hide_env(movie_maker) add_cmd = '' IF IsType(fps ,/defined) THEN add_cmd += ' -r '+strcompress(string(fps ),/rem) IF IsType(bits,/defined) THEN add_cmd += ' -b '+strcompress(string(bits),/rem) real_cmd += add_cmd hide_cmd += add_cmd SetFileSpec, files file_type = GetFileSpec(part='type') file_type = file_type[uniq(file_type)] IF n_elements(file_type) GT 1 THEN BEGIN message, /info, 'mixed file types, '+strjoin(file_type,',') RETURN ENDIF file_dir = GetFileSpec(part='directory') file_dir = file_dir[uniq(file_dir)] IF n_elements(file_dir) GT 1 THEN BEGIN message, /info, 'more than one directory used, '+strjoin(file_dir,',') RETURN ENDIF file_dir = file_dir[0] IF file_dir EQ '' THEN file_dir = getenv('PWD') maker = GetFileSpec(movie_maker,part='name') tmp_files = filepath(root=file_dir,maker+'_tmp_'+string(indgen(nfile),format='(I5.5)')+file_type) IF silent LE 0 THEN message, /info, 'renaming frames ...' FOR i=0,nfile-1 DO tmp = do_file(/move, files[i], tmp_files[i], /silent) file_template = filepath(root=file_dir,maker+'_tmp_%05d'+file_type) real_cmd += ' -i '+file_template+' -vcodec msmpeg4v2 -y '+movie hide_cmd += ' -i '+hide_env(file_template)+' -vcodec msmpeg4v2 -y '+hide_env(movie) END ENDCASE IF movie_maker NE '' THEN BEGIN IF silent LE 0 THEN print, hide_cmd spawn, real_cmd message, /info, hide_env(movie_maker)+' makes '+hide_env(movie)+' ('+strcompress(nfile,/rem)+' files)' ENDIF CASE 1 OF mpeg: BEGIN IF silent LE 0 THEN message, /info, (['renaming','deleting'])[cleanup]+' frames ...' CASE cleanup OF 0: FOR i=0,nfile-1 DO tmp = do_file(/move, tmp_files[i], files[i], /silent) 1: tmp = do_file(/delete, tmp_files,/silent) ENDCASE END ELSE: IF cleanup THEN tmp = do_file(files, /delete) ENDCASE RETURN & END