Log in

View Full Version : Can a script save particular frames out to jpg?


mroz
23rd October 2007, 17:15
I've written a short script below to help investigate problems using MVTools with SetMTMode.

It compares two files frame by frame, spitting out some stats to a log file for any frame pairs which don't match:

leaf1="noSetMT"
leaf2="SetMT-t1-b10"
global c1=AVISource("E:\Work\test\hfyu_MVMT-longtest-"+leaf1+".avi")
global c2=AVISource("E:\Work\test\hfyu_MVMT-longtest-"+leaf2+".avi")
global total=0
file="E:\Work\test\compare-"+leaf1+"-"+leaf2+".log"
Subtract(c1,c2)
WriteFileStart(file, """ "vim:tabstop=6"+chr(10) """, """ Time("%#c")+chr(10) """, """ "Frame"+chr(9)+"Total"+chr(9)+"Variation" """, append=true)
#nb compare against 0.0001 instead of 0 to allow for rounding errors - 2 identical files will report a variation of 0.000022
WriteFileIf(file, "variation>0.0001", "current_frame", "chr(9)", "total", "chr(9)", "variation")
WriteFileEnd(file, """ "Test complete."+chr(10) """)
ScriptClip( "global variation = LumaDifference(c1,c2)+ChromaUDifference(c1,c2)+ChromaVDifference(c1,c2)"+chr(13) \
+"global total = total + ((variation>0.0001) ? 1 : 0)"+chr(13) \
+"Subtitle(String(variation))" \
)

I'd also like to get it to save to file (as a jpg or png preferably) the problem frames from the returned clip. Can this be done?

Failing that, is there any application, preferably command line driven, which will take a text file listing frame numbers & spit out a capture for each of the listed frames?

Wilbert
23rd October 2007, 17:39
Sure, use ImageWriter.

foxyshadis
23rd October 2007, 22:53
Just to make it a bit cleaner, you can also have newlines in quotes:

ScriptClip( "global variation = LumaDifference(c1,c2)+ChromaUDifference(c1,c2)+ChromaVDifference(c1,c2)
global total = total + ((variation>0.0001) ? 1 : 0)
Subtitle(String(variation))
")
avsp doesn't like it unless you use triple-quotes, but either is legal.

mroz
24th October 2007, 02:16
@Wilbert: Don't know how I missed it - spent a while looking for an external filter to do the job. Cheers :)

@Foxyshadis: Thanks, I didn't know that. Think I switched to the triple quote version since posting.

I'm trying to speed it up atm & get it to work with MT. I figured I don't need the subtract output for every frame; it's only the log that's important (& maybe grabs of the problem frames). Getting rid of the subtract & subtitling has nearly doubled throughput. SetMTMode(2,0) trebles it further on a quad core, but introduces a few problems.

Here's the current version:
SetMTMode(2,0)
leaf1="noSetMT"
leaf2="SetMT-t1-b10"
global c1=AVISource("E:\Work\test\hfyu_MVMT-longtest-"+leaf1+".avi")
global c2=AVISource("E:\Work\test\hfyu_MVMT-longtest-"+leaf2+".avi")
global total=0
global file="E:\Work\test\compare-"+leaf1+"-"+leaf2+".log"
BlankClip(c1, width=16, height=16) # maybe 15% faster than using c1 as our 'dummy' clip (& 100% faster than using subtract(c1,c2) with variation subtitled)
WriteFileStart(file, """ "vim:tabstop=6"+chr(10) """, """ Time("%#c")+chr(10) """, """ "Frame"+chr(9)+"Total"+chr(9)+"Variation" """, append=true)
WriteFileEnd(file, """ "Test complete."+chr(10) """)
ScriptClip( """
variation = LumaDifference(c1,c2)+ChromaUDifference(c1,c2)+ChromaVDifference(c1,c2)
# nb1 keeping writefile inside here allows us to store variation as local, reducing problems with running in MTMode 2
# nb2 aside: writefile doesn't want to write anything when called inside FrameEvaluate; anyone know why?
# nb3 sometimes the running total is reported incorrectly in MTMode 2 as another thread updates the total before code writes out data to log;
# this isn't terribly important & can be corrected as is implicit in data set
# nb4 compare against 0.0001 instead of 0 to allow for rounding errors - 2 identical files will report a variation of 0.000022
WriteFileIf(file, "variation>0.0001", "current_frame", "chr(9)", "total", "chr(9)", "variation")
global total = total + ((variation>0.0001) ? 1 : 0)
return last
""" )

It's less elegant but six times faster. Here's some example output which demonstrates all the problems:

vim:tabstop=6
Wednesday, October 24, 2007 01:39:43
Frame Total Variation
vim:tabstop=6
Wednesday, October 24, 2007 01:39:43
Frame Total Variation
vim:tabstop=6
Wednesday, October 24, 2007 01:39:43
Frame Total Variation
vim:tabstop=6
Wednesday, October 24, 2007 01:39:43
Frame Total Variation
15858 1 1.816673
15861 3 0.210538
15859 3 3.181405
Test complete.

Test complete.

Test complete.

Test complete.



Problems:

1) Cosmetic but annoying: headers & footers are getting written four times, once for each thread. Any solution/workaround?

2) Results no longer in frame order - I don't really care, but it could be a problem if data used for subsequent processing & order required. Can't be avoided afaics atm when using MT.

3) Running total is sometimes wrong as noted in the comments. Any way around this? I can't see how to track the total without using a global & then multithreading makes it almost inevitable.

mroz
24th October 2007, 03:15
Hm, can mostly work around 3) with:
SetMTMode(2,0)
leaf1="noSetMT"
leaf2="SetMT-t1-b10"
global c1=AVISource("E:\Work\test\hfyu_MVMT-longtest-"+leaf1+".avi")
global c2=AVISource("E:\Work\test\hfyu_MVMT-longtest-"+leaf2+".avi")
global total=0
global file="E:\Work\test\compare-"+leaf1+"-"+leaf2+".log"
BlankClip(c1, width=16, height=16) # maybe 15% faster than using c1 as our 'dummy' clip (& 100% faster than using subtract(c1,c2) with variation subtitled)
WriteFileStart(file, """ "vim:tabstop=6"+chr(10) """, """ Time("%#c")+chr(10) """, """ "Frame"+chr(9)+"Total"+chr(9)+"Variation" """, append=true)
WriteFileEnd(file, """ "Test complete."+chr(10) """)
ScriptClip( """
variation = LumaDifference(c1,c2)+ChromaUDifference(c1,c2)+ChromaVDifference(c1,c2)
# nb1 keeping writefile inside here allows us to store variation as local, reducing problems with running in MTMode 2
# nb2 aside: writefile doesn't want to when called inside FrameEvaluate; anyone know why?
# nb3 sometimes the running total is reported incorrectly in MTMode 2 as another thread updates the total before code writes out data to log;
# this isn't terribly important & can be corrected as is implicit in data set
# nb4 compare against 0.0001 instead of 0 to allow for rounding errors - 2 identical files will report a variation of 0.000022
WriteFileIf(file, "variation>0.0001", "current_frame", "chr(9)", "thistotal", "chr(9)", "variation")
global total = total + ((variation>0.0001) ? 1 : 0)
thistotal = total # massively reduce chance of MTMode 2 screwing up logging of total
return last
""" )

Edit: Although I understand the filter chain is initially built up backwards, I'm puzzled why the above workaround requires the assignment to total to be after WriteFileIf, but is happy for the variation assignment to be before. Are there any detailed docs on how parsing is handled? For instance, are expressions involving globals handled very differently to locals in respect of parse order?

foxyshadis
24th October 2007, 05:08
That's pretty much what a race condition is. You have to use something called an interlocked increment to completely eliminate those, or mutually exclusive code sections (critical sections/mutexes/semaphores), but this situation was never foreseen in avisynth (or by tsp), of course, so it isn't available.

To stop the multiple headers, use
SetMTMode(2)
#Sources....
SetMTMode(5)
#WriteFileStart/End
SetMTMode(2)
#ScriptClip

There might be a way to enforce order, but I'll have to experiment once I get home.

mroz
24th October 2007, 05:29
That's pretty much what a race condition is. You have to use something called an interlocked increment to completely eliminate those, or mutually exclusive code sections (critical sections/mutexes/semaphores), but this situation was never foreseen in avisynth (or by tsp), of course, so it isn't available.

Indeed. In the dim past I used to occasionally code interrupt routines in ARM assembler, which involves such matters.

To stop the multiple headers, use
SetMTMode(2)
#Sources....
SetMTMode(5)
#WriteFileStart/End
SetMTMode(2)
#ScriptClip

Already tried it. I expected it to work. It didn't :/

I forget which modes did what, but some gave me four sets of headers while others gave me two.

There might be a way to enforce order, but I'll have to experiment once I get home.

Thanks. Have fun. I'm going to sleep now, five hours later than I intended :)