Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion.

Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules.

 

Go Back   Doom9's Forum > Capturing and Editing Video > Avisynth Usage

Reply
 
Thread Tools Search this Thread Display Modes
Old 29th May 2008, 12:52   #1  |  Link
tacman1123
Registered User
 
Join Date: Jun 2007
Location: Washington, DC
Posts: 130
Cue Points / Frames

Is there a way to add a Cue Point to an Avisynth output? Basically I'm thinking of something like

Code:
a1=AviSource()
a2=AviSource().AddCue('Starting a2')
a1+a2
And that a cue file would be creating that fired at event when a2 started.

Alternatively, I could create my own, if I had a way to tell what frame I was on when a2 started, but that doesn't seem possible with the Avisynth scripting language (I'm thinking of an event that would be fired upon rendering, that's much more OOP-like). The end result could even just be a file with two columns, FrameNumber and event string (or timecode and event string).

I don't think this is possible, but I'm continually amazed at what Avisynth can do, so I figured I'd ask.

Thx,

Tac
tacman1123 is offline   Reply With Quote
Old 29th May 2008, 14:48   #2  |  Link
gzarkadas
Registered User
 
gzarkadas's Avatar
 
Join Date: Sep 2005
Location: 100011110010001000001 10000011111111000001
Posts: 221
Maybe this will do the job (beware, I havent' actually tested it ):
Code:
cue_text = "Starting a2"
a1=AviSource()
a2=AviSource()
a2 = ScriptClip(a2, """
    return current_frame > 0 \
        ? last \
        : last.WriteFile("cue_file.txt", "cue_text", flush=true)
    """)
a1+a2
__________________
AVSLib, a free extension library for Avisynth. Current version: 1.1.0 (beta), 14/05/2007.
[ Home page | Download page ]
gzarkadas is offline   Reply With Quote
Old 29th May 2008, 18:23   #3  |  Link
tacman1123
Registered User
 
Join Date: Jun 2007
Location: Washington, DC
Posts: 130
Thanks! I had just found the Runtime Environment, but wasn't quite sure how to use to to achieve the cue points.

Can this be written as a function, e.g.

Code:
a2.add_cue("a2")

function add_cue(clip c, string cue_text) {
    ScriptClip(c, """
    return current_frame > 0 \
        ? last \
        : last.WriteFile("cue_file.txt", cue_text, flush=true)
    """)
}
Or would c.current_frame be better?

Hmm, may need some more time to think about this one, there's some interesting possibilities here. Thanks for getting me started.

Tac
tacman1123 is offline   Reply With Quote
Old 29th May 2008, 19:46   #4  |  Link
gzarkadas
Registered User
 
gzarkadas's Avatar
 
Join Date: Sep 2005
Location: 100011110010001000001 10000011111111000001
Posts: 221
Quote:
Originally Posted by tacman1123 View Post
...Can this be written as a function, e.g....
The problem is that cue_text must be a variable in script scope, not a function argument. In addition, if you observe carefully my example, you'll see that I have enclosed cue_text in quotes at the WriteFile call; you must pass the name of the variable in WriteFile, not the content of the variable.

Thus your example must be written and be used as follows:
Code:
function add_cue(clip c, string script_var_name) {
    ScriptClip(c, """
    return current_frame > 0 \
        ? last \
        : last.WriteFile("cue_file.txt", script_var_name, flush=true)
    """)
}

cue2 = "a2"
cue3 = "a3"
cue4 = "a4"

a1 = AviSource()
a2 = AviSource().add_cue("cue2")
a3 = AviSource().add_cue("cue3")
a4 = AviSource().add_cue("cue4")

a1 + a2 + a3 + a4
Tip: If you want to append all strings in the file instead of re-writing its contents at each call, use this version of add_cue:
Code:
function add_cue(clip c, string script_var_name, bool "clear") {
    keep = Default(clear, true)
    ScriptClip(c, """
    return current_frame > 0 \
        ? last \
        : last.WriteFile("cue_file.txt", script_var_name, append=keep, flush=true)
    """)
}
Now you only have to supply a true value for clear when you want to erase cue_file.txt before writing; else you don;t have to supply it at all.
__________________
AVSLib, a free extension library for Avisynth. Current version: 1.1.0 (beta), 14/05/2007.
[ Home page | Download page ]
gzarkadas is offline   Reply With Quote
Old 29th May 2008, 20:47   #5  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,430
Since WriteFile already operates within the runtime environment, and has a convenient conditional variant, I think you can do away with ScriptClip and just write
Code:
function add_cue(clip c, string filename, string script_var_name, bool "keep") {
    keep = Default(keep, true)
    WriteFileIf(c, filename, "current_frame==0", script_var_name, append=keep, flush=true)
}
(I've also made the filename into a parameter)
Gavino is offline   Reply With Quote
Old 29th May 2008, 22:47   #6  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,430
A further refinement - I think tac wanted the overall frame number to appear in the cue file too.

That's a bit trickier because the only place that info is known is at the end of the filter chain and we want it to be available to add_cue. However, the magic of AviSynth's run-time features comes to the rescue again. Extend add_cue to be:
Code:
function add_cue(clip c, string filename, string script_var_name, bool "keep") {
  keep = Default(keep, true)
  WriteFileIf(c, filename, "current_frame==0", "cueFrame", script_var_name, append=keep, flush=true)
}
and add the following line to the end of your script:
Code:
FrameEvaluate("cueFrame=current_frame")
and there you are. Example use:
Code:
file="cue.txt" # might need to be full path name?
text=": starting a2"
a1=BlankClip(100).Subtitle("A1")
a2=BlankClip(100).Subtitle("A2").add_cue(file, "text")
a1+a2
FrameEvaluate("cueFrame=current_frame")
should produce "100: starting a2" in the output file when the script is rendered.

For those new to this runtime stuff, it's important to realise that the variable cueFrame is not just set once at the end (where it would be equivalent to Framecount()), but is continuously updated for each frame of the complete video. Thus the relevant value is available to WriteFileIf (inside add_cue), to be written when the appropriate condition is triggered, (ie when rendering the first frame of the clip to which add_cue is applied).

Last edited by Gavino; 30th May 2008 at 13:57. Reason: Added explanation
Gavino is offline   Reply With Quote
Old 31st May 2008, 12:52   #7  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,430
To follow up my own post yet again (sorry), this version removes the nuisance that the cue text had to be passed indirectly as the name of a variable, as decribed by gzarkadas in post #4.
Code:
function add_cue(clip c, string filename, string cue, bool "keep") {
  keep = Default(keep, true)
  cue = chr(34)+cue+chr(34)
  WriteFileIf(c, filename, "current_frame==0", "cueFrame", cue, append=keep, flush=true)
}
So you can now pass the text directly as a literal, eg add_cue(..., " starting a2"). Of course you can still pass a variable if you want (but in the normal way, without having to enclose the name in quotes).
Gavino is offline   Reply With Quote
Old 31st May 2008, 17:03   #8  |  Link
mikeytown2
Resize Abuser
 
mikeytown2's Avatar
 
Join Date: Apr 2005
Location: Seattle, WA
Posts: 623
I opened up notepad and typed in ALT-034. nice its a ". would tripple quotes """ work instead of char(34)?
mikeytown2 is offline   Reply With Quote
Old 31st May 2008, 19:39   #9  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,430
Quote:
Originally Posted by mikeytown2 View Post
would tripple quotes """ work instead of char(34)?
If you're asking could the line
Code:
  cue = chr(34)+cue+chr(34)
be replaced by
Code:
  cue = """cue"""
then the answer is no - triple quotes would just be as wrong as single quotes here - the quotes need to become part of the string's value, rather than simply delimiting it.

However, you've made me realise that it would be safer as
Code:
  cue = chr(34)+chr(34)+chr(34)+cue+chr(34)+chr(34)+chr(34) # triple-quote the string
which would allow the original cue string (passed in as the parameter) to contain internal quotes.
Gavino is offline   Reply With Quote
Old 7th July 2008, 19:30   #10  |  Link
tacman1123
Registered User
 
Join Date: Jun 2007
Location: Washington, DC
Posts: 130
I'm now trying to do the reverse of what I was going to do with this thread. Basically I'm implementing a closed caption system, and was planning to use ConditionalReader to do so, but it appears that the only types for ConditionalReader are book, int and float. I'm surprised, I would have thought strings would be easy to implement, e.g.

file.txt
Code:
Type string
Default "" (or just nothing)

R 10 180  First Caption 
R 185 250  Second Caption
Then simply

Code:
ScriptClip("subtitle(myvar)")
ConditionalReader("file.txt", "myvar", false)
Suggestions on how to proceed?

Thx,

Tac
tacman1123 is offline   Reply With Quote
Old 7th July 2008, 20:10   #11  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,430
Quote:
Originally Posted by tacman1123 View Post
the only types for ConditionalReader are bool, int and float. I'm surprised, I would have thought strings would be easy to implement
I too was surprised to discover this recently. However, it's a bit more difficult for strings because the filter doesn't know in advance how much memory to allocate. You would also have issues like whether you allow multi-line strings.

Having said that, it certainly wouldn't be beyond the wit of man...

Last edited by Gavino; 7th July 2008 at 20:17.
Gavino is offline   Reply With Quote
Old 8th July 2008, 00:01   #12  |  Link
gzarkadas
Registered User
 
gzarkadas's Avatar
 
Join Date: Sep 2005
Location: 100011110010001000001 10000011111111000001
Posts: 221
Quote:
Originally Posted by tacman1123 View Post
I'm now trying to do the reverse of what I was going to do with this thread. Basically I'm implementing a closed caption system, and was planning to use ConditionalReader to do so, but it appears that the only types for ConditionalReader are book, int and float. I'm surprised, I would have thought strings would be easy to implement, e.g.

file.txt
Code:
Type string
Default "" (or just nothing)

R 10 180  First Caption 
R 185 250  Second Caption
Then simply

Code:
ScriptClip("subtitle(myvar)")
ConditionalReader("file.txt", "myvar", false)
Suggestions on how to proceed?

Thx,

Tac
Didn't have time to test, but the following should work:

1. Put all your captions in a multiline string starting with an empty line (that is hit <Enter> after the opening three doublequotes):
Code:
global captions = """
First Caption 
Second Caption
...
N-th Caption
"""
2. Create a ConditionalReader file of type int and instead of the captions put the indexes to the zero-based array that your multiline string of captions forms (see below):
Code:
Type int
Default 0

R 10  180  1
R 185 250  2
3. Treat the multiline string as an AVSLib array with delimiter CRLF. Then at each frame get the caption that corresponds to the specified array index:
Code:
LoadLibrary("avslib")
...
#assumes global captions is set by the code-snippet above
...
dummy = ArraySetDelimiter(CRLF)
ScriptClip("subtitle(captions.ArrayGet(myvar))")
ConditionalReader("file.txt", "myvar", false)
__________________
AVSLib, a free extension library for Avisynth. Current version: 1.1.0 (beta), 14/05/2007.
[ Home page | Download page ]
gzarkadas is offline   Reply With Quote
Old 8th July 2008, 00:54   #13  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,430
Nice solution, gzarkadas.

Is there a possible overhead in adding empty subtitles? If so, it might be faster to use
Code:
...
ScriptClip("myvar > 0 ? subtitle(captions.ArrayGet(myvar)) : last")
...
Gavino is offline   Reply With Quote
Old 8th July 2008, 07:49   #14  |  Link
gzarkadas
Registered User
 
gzarkadas's Avatar
 
Join Date: Sep 2005
Location: 100011110010001000001 10000011111111000001
Posts: 221
Quote:
Originally Posted by Gavino View Post
Nice solution, gzarkadas.

Is there a possible overhead in adding empty subtitles? If so, it might be faster to use
Code:
...
ScriptClip("myvar > 0 ? subtitle(captions.ArrayGet(myvar)) : last")
...
I doubt it would make a significant difference; thus IMO it is better to keep the code "cleaner" .
__________________
AVSLib, a free extension library for Avisynth. Current version: 1.1.0 (beta), 14/05/2007.
[ Home page | Download page ]
gzarkadas is offline   Reply With Quote
Old 8th July 2008, 10:41   #15  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,430
Quote:
Originally Posted by gzarkadas View Post
I doubt it would make a significant difference; thus IMO it is better to keep the code "cleaner" .
I too prefer cleaner code over unnecessary optimisation, but I have a feeling that Subtitle has a significant startup cost that would be incurred on every frame, even those where nothing is being written.

Of course, the real test is for tacman1123 to try it out and if it's fast enough for him, then fine.
And if he wants most frames to end up with captions, my 'optimisation' won't help anyway.
Gavino is offline   Reply With Quote
Old 20th November 2008, 18:41   #16  |  Link
tacman1123
Registered User
 
Join Date: Jun 2007
Location: Washington, DC
Posts: 130
@gzarkadas: What's the limit on ArrayCreate()? Even using the \ at the end of a line, I run into a problem with a 107 element array (strings total about 2000 characters).

Also, I'm getting the error that ArraySetDelimiter isn't found, is that a different version? I'm using the latest, 1-1-0 beta.

Thanks, this method appears to be working for me, using a global captions=ArrayCreate("one", "two", etc.)

This fails:

Code:
LoadLibrary("avslib", CONFIG_AVSLIB_FULL)

global captions=ArrayCreate("Scn 1 (0-19)", \
"Scn 2 (20-29)", \
"Scn 3 (30-31)", \
"Scn 4 (32-51)", \
"Scn 5 (52-54)", \
"Scn 6 (55-55)", \
"Scn 7 (56-56)", \
"Scn 8 (57-76)", \
"Scn 9 (77-99)", \
"Scn 10 (100-100)", \
"Scn 11 (101-101)", \
"Scn 12 (102-103)", \
"Scn 13 (104-109)", \
"Scn 14 (110-110)", \
"Scn 15 (111-111)", \
"Scn 16 (112-113)", \
"Scn 17 (114-114)", \
"Scn 18 (115-115)", \
"Scn 19 (116-123)", \
"Scn 20 (124-146)", \
"Scn 21 (147-176)", \
"Scn 22 (177-202)", \
"Scn 23 (203-204)", \
"Scn 24 (205-206)", \
"Scn 25 (207-208)", \
"Scn 26 (209-210)", \
"Scn 27 (211-212)", \
"Scn 28 (213-214)", \
"Scn 29 (215-216)", \
"Scn 30 (217-218)", \
"Scn 31 (219-220)", \
"Scn 32 (221-222)", \
"Scn 33 (223-224)", \
"Scn 34 (225-226)", \
"Scn 35 (227-228)", \
"Scn 36 (229-230)", \
"Scn 37 (231-231)", \
"Scn 38 (232-232)", \
"Scn 39 (233-243)", \
"Scn 40 (244-245)", \
"Scn 41 (246-246)", \
"Scn 42 (247-247)", \
"Scn 43 (248-253)", \
"Scn 44 (254-259)", \
"Scn 45 (260-273)", \
"Scn 46 (274-294)", \
"Scn 47 (295-295)", \
"Scn 48 (296-296)", \
"Scn 49 (297-298)", \
"Scn 50 (299-299)", \
"Scn 51 (300-300)", \
"Scn 52 (301-301)", \
"Scn 53 (302-303)", \
"Scn 54 (304-304)", \
"Scn 55 (305-305)", \
"Scn 56 (306-306)", \
"Scn 57 (307-307)", \
"Scn 58 (308-338)", \
"Scn 59 (339-341)", \
"Scn 60 (342-343)", \
"Scn 61 (344-344)", \
"Scn 62 (345-345)", \
"Scn 63 (346-346)", \
"Scn 64 (347-348)", \
"Scn 65 (349-349)", \
"Scn 66 (350-350)", \
"Scn 67 (351-351)", \
"Scn 68 (352-352)", \
"Scn 69 (353-353)", \
"Scn 70 (354-355)", \
"Scn 71 (356-356)", \
"Scn 72 (357-357)", \
"Scn 73 (358-358)", \
"Scn 74 (359-362)", \
"Scn 75 (363-364)", \
"Scn 76 (365-366)", \
"Scn 77 (367-367)", \
"Scn 78 (368-368)", \
"Scn 79 (369-371)", \
"Scn 80 (372-372)", \
"Scn 81 (373-373)", \
"Scn 82 (374-374)", \
"Scn 83 (375-375)", \
"Scn 84 (376-376)", \
"Scn 85 (377-379)", \
"Scn 86 (380-380)", \
"Scn 87 (381-381)", \
"Scn 88 (382-383)", \
"Scn 89 (384-384)", \
"Scn 90 (385-386)", \
"Scn 91 (387-390)", \
"Scn 92 (391-391)", \
"Scn 93 (392-393)", \
"Scn 94 (394-394)", \
"Scn 95 (395-395)", \
"Scn 96 (396-397)", \
"Scn 97 (398-398)", \
"Scn 98 (399-399)", \
"Scn 99 (400-400)", \
"Scn 100 (401-401)", \
"Scn 101 (402-413)", \
"Scn 102 (414-429)", \
"Scn 103 (430-433)", \
"Scn 104 (434-500)", \
"Scn 105 (501-509)", \
"Scn 106 (510-576)", \
"Scn 107 (577-6095)")

# return a valid video clip
colorbars.KillAudio()

Last edited by tacman1123; 22nd November 2008 at 00:05. Reason: added code to script
tacman1123 is offline   Reply With Quote
Old 20th November 2008, 19:24   #17  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,430
Quote:
Originally Posted by tacman1123 View Post
Even using the \ at the end of a line, I run into a problem with a 107 element array (strings total about 2000 characters).
Does it work if you enter the captions as a single multi-line string, as gzarkadas originally suggested in post #12?
Code:
global captions = """
First Caption 
Second Caption
...
N-th Caption
"""
Gavino is offline   Reply With Quote
Old 20th November 2008, 19:37   #18  |  Link
tacman1123
Registered User
 
Join Date: Jun 2007
Location: Washington, DC
Posts: 130
No, although since I'm having a problem with the SetDelimiter call, I'm using ArrayCreate, e.g. ArrayCreate("one", "two" ...), but it fails as well. I thought at first it might be a line limit length in avisynth scripts, but couldn't find any documentation about that. Figured it'd be best to go with the \ format, since I could post it here without horizontal scrolling.
tacman1123 is offline   Reply With Quote
Old 20th November 2008, 19:42   #19  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,430
OK, I understand.

What exactly is the failure you are seeing? Do you get any useful error message?
Gavino is offline   Reply With Quote
Old 22nd November 2008, 00:04   #20  |  Link
tacman1123
Registered User
 
Join Date: Jun 2007
Location: Washington, DC
Posts: 130
The error is "Invalid Arguments to Function ArrayCreate()" I imagine there is some limit, and I've exceeded it, but perhaps I can figure out how to merge an array and add them in chunks. I've modified the script above to show the error if you run it, to see it work without the error simply remove a bunch of the middle elements.

A more significant issue is that
Code:
a=a.ScriptClip("subtitle(captions.ArrayGet(myvar))")
a.ConditionalReader(root + video_code + "_range.txt", "myvar", false)
starts out fine, but as the video plays it gets slower and slower. Even using something like avs2avi I can see the processed frames per second go down and the estimated time left go up. I don't have the same problem when I put in something like, like myvar or current_frame. Do excessive calls to Captions.ArrayGet() not release memory? Or...? Since it's called every frame, it's obviously being called a lot, but it seems fine the first hundred frames or so, then begins to slow down.

I had an idea about skipping the array and assigning each string a variable, but I can't figure out how to dynamically create a variable made up of a prefix and a number. That is, what I want to do is make scriptclip calls to subtitle(caption1), subtitle(caption2), etc. I can create caption1="one", etc., but am not sure how to get from myvar to "caption" + myvar, and have that new variable be evaluated. I think that's what I want to do.

Tac
tacman1123 is offline   Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 13:14.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2023, vBulletin Solutions Inc.