Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
AutoIt3 script to seamlessly loop videos using MLT. Just select all the videos you want to loop, it'll take care of the rest. You'll need MLT, which is included with many open-source video editors like Shotcut. So you can install Shotcut and the script will find the .exe file as long as it's in the default location.
#cs ----------------------------------------------------------------------------
AutoIt Version: 3.3.12.0
Author: Kawika (Ugotsta)
Script Function:
Loops files seamlessy using MLT framework
MLT is installed with free software like Shotcut,
installing Shotcut is the easiest way to use it.
#ce ----------------------------------------------------------------------------
#include <FileConstants.au3>
#include <MsgBoxConstants.au3>
#include <File.au3>
#include <Array.au3>
CONST $melt = "C:\Program Files\Shotcut\melt.exe"
CONST $output_folder = "looped"
CONST $transition_length = 3; seconds
; Names of split video parts, in case they need to be renamed.
CONST $p1 = "part1"
CONST $p2 = "part2"
; Set title match mode so any occurrence within title will succeed
AutoItSetOption ( "WinTitleMatchMode", 2)
; Allow user to select videos
$video_formats = "Presets (*.mkv;*.avi;*.mpg;*.mpeg;*.wmv)"
$videos = GetFiles( "Select videos to seamlessly loop.", $video_formats )
$video_path = $videos[0]
; --------------------------------------------------------
; LOOP start - begin looping through selected preset files
For $i = 0 To UBound( $videos ) - 1
; skip 0 index, it's just the path
if $i > 0 Then
LoopIt( $videos[ $i ], $video_path )
EndIf
Next
MsgBox( $MB_SYSTEMMODAL, "", "Operation completed." )
Func LoopIt( $video, $video_path )
Local $drive = "", $dir = "", $filename = "", $ext = ""
Local $path = _PathSplit( $video, $drive, $dir, $filename, $ext)
; create 2 copies ( part1.mkv and part2.mkv )
Local $part1 = $video_path & "\" & $p1 & $ext
Local $part2 = $video_path & "\" & $p2 & $ext
; Just in case files exist, delete them so we can start anew
FileDelete( $part1 )
FileDelete( $part1 )
FileDelete( "melt.xml" )
; Copy video for merge later
FileCopy( $video_path & "\" & $video, $part1 )
FileCopy( $video_path & "\" & $video, $part2 )
; "melt c:\video\video.ext -consumer xml:melt.xml"
$p = $part1 & " -consumer xml:melt.xml"
ShellExecute ( $melt, $p )
Sleep( 2000 )
; Get total frames from melt.xml
Local $total_frames = FindRowInFile( "melt.xml", '<property name="length">' )
$total_frames = GetNumbers( $total_frames, 900 )
; Get frames per second from melt.xml
Local $fps = FindRowInFile( "melt.xml", 'stream.frame_rate">' )
$fps = GetNumbers( $fps, 30 )
Local $half = Round( $total_frames / 2 )
Local $transition = $fps * $transition_length
; Setup output folder
DirCreate ( $video_path & "\" & $output_folder )
; Setup for splice operation
Local $out = ' out=' & $half & ' '
Local $in = ' in=' & $half & ' '
Local $mix = '-mix ' & $transition & ' -mixer luma' & ' -mixer mix:-1'
Local $merge = '"' & $part2 & '"' & $in & '"' & $part1 & '"' & $out & $mix
; "part2.mkv out=$half part1.mkv in=$half -mix $transition -mixer luma"
Local $output_file = $video_path & "\" & $output_folder & "\" & $video
Local $format = ' -consumer avformat:"' & $output_file & '"'
$p = " " & $merge & $format
; MsgBox( $MB_SYSTEMMODAL, "", $melt & $p )
ShellExecute ( $melt, $p )
; Wait for melt to load and complete operation
$title = "melt"
$Win = WinWait( $title, "", 5 )
WinActivate( $title )
Sleep( 1000 )
WinWaitClose( $title, "", 90 )
Sleep( 1000 )
; Cleanup copies and melt.xml
FileDelete( $part1 )
FileDelete( $part2 )
FileDelete( "melt.xml" )
EndFunc
Func GetNumbers( $str, $default )
If $str NOT = "" Then
$values = StringRegExp( $str, '\d+', 3 )
If @error Then
Return $default
Else
; Return first non-zero value in array
For $val In $values
If $val > 0 Then
Return $val
EndIf
Next
EndIf
EndIf
Return $default
EndFunc
Func FindRowInFile( $file, $search )
Local $result = ''
Local $line_content = ''
Local $line_content = ''
Local $f = FileOpen( $file )
If $f = -1 Then
MsgBox( 0, 'ERROR', 'Unable to open file.' )
Exit 1
EndIf
; Search
While 1
$line_content = FileReadLine( $f )
If @error = -1 Then ExitLoop
If StringInStr( $line_content, $search ) Then
FileClose($f)
Return $line_content
ExitLoop
EndIf
WEnd
FileClose($f)
Return $result
EndFunc
Func FindFile( $msg, $wildcard )
; Create a constant variable in Local scope of the message to display in FileOpenDialog.
Local Const $sMessage = $msg
; Display an open dialog to select a file.
Local $sFileOpenDialog = FileOpenDialog($sMessage, @WindowsDir & "\", $wildcard, $FD_FILEMUSTEXIST)
If @error Then
; Display error message.
MsgBox($MB_SYSTEMMODAL, "", "No file was selected.")
FileChangeDir(@ScriptDir)
Else
FileChangeDir(@ScriptDir)
; Replace instances of "|" with @CRLF in the string returned by FileOpenDialog.
$sFileOpenDialog = StringReplace($sFileOpenDialog, "|", @CRLF)
Return $sFileOpenDialog
EndIf
EndFunc
Func GetFiles( $msg, $wildcard )
; Display an open dialog to select a list of file(s).
Local $sFileOpenDialog = FileOpenDialog( $msg, @WindowsDir & "\", $wildcard, $FD_FILEMUSTEXIST + $FD_MULTISELECT )
If @error Then
MsgBox($MB_SYSTEMMODAL, "", "No file(s) were selected.")
FileChangeDir(@ScriptDir)
Else
FileChangeDir(@ScriptDir)
; Split results into array.
Local $fileArray = StringSplit( $sFileOpenDialog, "|", 2 )
; Special handler when user selects just one file.
If UBound( $fileArray ) = 1 Then
Local $drive = "", $dir = "", $filename = "", $ext = ""
Local $path = _PathSplit( $sFileOpenDialog, $drive, $dir, $filename, $ext)
Local $file = $filename & $ext
$fileArray[0] = StringTrimRight( $sFileOpenDialog, StringLen( $file ) + 1 )
_ArrayAdd( $fileArray, $file )
EndIf
Return $fileArray
EndIf
EndFunc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment