You are not logged in.

#1 08-05-2013 04:00:32

mermaldad
Nouveau membre
Registered: 08-13-2012
Posts: 7

A little python utility for adjusting slide durations

I just finished working on a slideshow project in which I was synchronizing my chapters to music (i.e. I wanted the chapters to end just as the song was ending).  I needed a way to adjust the duration of many slides to make everything line up, so I wrote a little python script to do it.  I thought I would share the script, in case it is useful for someone else.  The program takes advantage of the fact that ffDiaporama's .ffd files are ASCII .xml files, so they are easy to read and manipulate with a script.  The program is a liitle simple-minded in that it assumes that the sum of the shot durations minus the sum of the transition durations equals the length of the clip, but features like video clips can override the shot duration, so be careful about these.  Also, if you have divided your show into chapters, this script does not adjust the length of the chapters, stored in the .ffd file.  However, I found that ffDiaporama does not seem to rely on these values. 

Of course, it would be nice to put this functionality into ffDiaporama itself (and I wouldn't be completely surprised if someone told me it's already in there, but I couldn't find it).  However, my C++ skills are limited and 24 hours before a project is to be finished is not the time to try to learn how to modify the code.  Enjoy!

#^Still to do:
    # Need to account for overridden durations, video clips, for example
    # Would be nice if this program adjusted the time information for chapters
import re
firstObject = [0,95,180] # Careful! Slide #1 is Object #0 and so forth
lastObject = [94,179,259]
mode = 1 # 0 = Set the duration of each object;
        # 1 = Set the duration of the group;
        # 2 = Scale the duration of each object
duration = ["5:05","4:38","4:14"] # (modes 0,1) in [[h:]m:]s format, examples "2:35:17.212", "2:38", "15.2"
scale = [1.096] # (mode 2 only)
directory = "C:/Users/Owner/Videos/2013/WM2013/Source Files/Workarea"
inputFileName = directory + "/WM2013 Slideshow.ffd" #
outputFileName = directory + "/python output.ffd"

def getSec(s):
    l = s.split(':')
    if len(l) == 3:
        return float(l[0]) * 3600 + float(l[1]) * 60 + float(l[2])
    elif len(l) == 2:
        return float(l[0])*60 + float(l[1])
    elif len(l) == 1:
        return float(l[0])

def addDur(objArray,obj,shot,dur): # Adds a duration to the object array
    # In theory all the shots and objects are in numerical order, but just to
    # be sure...
    shotArray=[0 for i in range(shot)]
    shotArray.append(dur)
    if len(objArray)<=obj:
        objArrayAdd = [[] for i in range(obj - len(objArray))]
        objArrayAdd.append(shotArray)
        objArray = objArray + objArrayAdd
    else:
        if len(objArray[obj])<=shot:
            shotArrayAdd = [0 for i in range(shot - len(objArray[obj]))]
            shotArrayAdd.append(dur)
            objArray[obj] = objArray[obj] + shotArrayAdd
        else:
            objArray[obj][shot] = dur
    return objArray

outputFile = open(outputFileName,"w")

durationAfter = [int(getSec(duration[i])*1000) for i in range(len(duration))] # convert to milliseconds
currentObject = -1
la = len(firstObject)
objects = [[] for i in range(la)]
transitions = [[] for i in range(la)]
durationBefore = []
scale = []
with open(inputFileName) as inputFile:
    for line in inputFile: # First pass, gather durations
        match = re.search('<Object-[0-9]*',line)
        if match:
            currentObject = int(match.group(0)[8:])
        match = re.search('</Object-',line)
        if match:
            currentObject = -1
        for i in range(la):
            match = re.search('<Shot-[0-9]*',line)
            if match and currentObject >= firstObject[i] and currentObject <= lastObject[i]:
                #print match.group(0)
                currentShot = int(match.group(0)[6:])
                dur = int(line[line.find('Duration=')+9:].split('"')[1])
                objects[i] = addDur(objects[i], currentObject, currentShot, dur)
            match = re.search('<Transition',line)
            if match and currentObject >= firstObject[i] and currentObject <= lastObject[i]:
                dur = int(line[line.find('Duration=')+9:].split('"')[1])
                transitions[i].append(dur)
                #print(line)
    for i in range(la):
        durationBefore.append( sum([sum(j) for j in objects[i]]) - sum(transitions[i]))
        if mode==1:
            scale.append( float(durationAfter[i])/float(durationBefore[i]))
            print "Duration Before:",durationBefore[i]
            print "Duration After:",durationAfter[i]
        if mode>0:
            print "Scaling duration of objects ",firstObject[i]," to ",lastObject[i]," by ",scale[i]

with open(inputFileName) as inputFile:
    for line in inputFile: # second pass, apply the scaling factor
        match = re.search('<Object-[0-9]*',line)
        if match:
            currentObject = int(match.group(0)[8:])
        match = re.search('</Object-',line)
        if match:
            currentObject = -1
        for i in range(la):
            match = re.search('<Shot-[0-9]*',line)
            if match and currentObject >= firstObject[i] and currentObject <= lastObject[i]:
                currentShot = int(match.group(0)[6:])
                if mode==0:
                    line = re.sub('Duration="[0-9]*"','Duration="'+str(int(durationAfter[i]))+'"',line)
                else: # modes 1 and 2 both use scale
                    line = re.sub('Duration="[0-9]*"','Duration="'+str(int(objects[i][currentObject][currentShot]*scale[i]))+'"',line)
                #print(line)
        outputFile.write(line)

#inputFile.close() #Not needed, the with structure automatically closes the file (something new I learned today!)
outputFile.close()

Offline

Board footer