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. |
9th November 2010, 18:35 | #1 | Link |
Registered User
Join Date: Dec 2009
Posts: 21
|
Avisynth Script - Personal Subtitles hardcoding...
Hi all,
I wanted to share with you this script I did these days, in order to hardcode subtitles in videos starting from .srt files. I know there are plugins or functions which already do this task (TextSub for example), but I had precise needs and I couldn't use it for my task. So I decied to study bit of Avisynth and something else (like GScript etc)... Here's what it does: it takes video, .srt file, background image for titles and fuse titles on the video. It can handle collisions e vertical alignment in case of single line title (in my case there aren't subtitle with more than two lines). The real deal (I couldn't do with TextSub) was the overlaying the background image only when subtitles are on screen. At the end, something which can look a bit more professional... Now the whole workflow is quite faster than doing all the subs in Premiere pasting from a .doc file. Translating in VisualVobSynch is easier when you get confident with it. This is how the video looks like after hardcoding... Code:
#LOCAL PATHS plugins_dir = "C:\Programmi\AviSynth 2.5\plugins\" video_dir = "C:\Documents and Settings\aelmi\Desktop\105 - CLUB NATION - CHEMICAL - 10-2010 SYNCH.avi" sottopancia_dir = "C:\Documents and Settings\aelmi\Desktop\sottopancia1280.tif" subs_dir = "C:\Documents and Settings\aelmi\Desktop\chemicals.srt" #STUFF NEEDED LoadPlugin(plugins_dir+"GScript.dll") LoadModule("avslib", "base", "constants") LoadModule("avslib", "base", "conversion") LoadPackage("avslib", "array") LoadPackage("avslib", "clip") LoadModule("avslib", "numeric", "rounding") #IMPORT OF VIDEO, SUBS AND BACKGROUND c=DirectShowSource(video_dir, audio=false) fps = c.framerate dar = 16/9 #ASSUME 16:9 sar = c.width/c.height par = dar/sar bg=ImageReader(sottopancia_dir).BicubicResize(c.Width,c.Height) bgALPHA=ImageReader(sottopancia_dir,pixel_type="RGB32").ShowAlpha(pixel_type="RGB32").BicubicResize(c.Width,c.Height) subs = import(subs_dir) offset_iniziale = FindStr(subs,"1") sotto_subs = ArrayCreate(midstr(subs, offset_iniziale)) ArrayDelimiterSet(CRLF+CRLF) #SUB PROPERTIES y_sottopancia = 0 y_sub = 0.825 font_sub = "LT_50543.TTF" size_sub = 0.0642 text_color_sub = $FFFFFF halo_color_sub = $303030 align_sub = 5 lsp_sub = 0.017 font_width_sub = 9 GScript(""" if(sotto_subs.ArrayLen()>0) { start_last_frame = -100 end_last_frame = -100 text_last_frame = "" y_last_sub = y_sub for(i=0, Floor(Log(sotto_subs.ArrayLen())/Log(10)), 1){ startloop = int(Pow(10,i)-1) offset = i if(sotto_subs.ArrayLen()>int(Pow(10,i+1)-3)){ endloop = int(Pow(10,i+1)-2) } else { endloop = sotto_subs.ArrayLen()-1 } for (j = startloop , endloop, 1) { #CALCULATING IN-OUT FRAME OF THE SINGLE SUB single_sub = sotto_subs.ArrayGet(j) start_sub_H = MidStr(single_sub, 4+offset,2) start_sub_M = MidStr(single_sub, 7+offset,2) start_sub_S = MidStr(single_sub, 10+offset,2) start_sub_ms = MidStr(single_sub, 13+offset,3) start_sub_frame = value(start_sub_H)*60*60*fps+value(start_sub_M)*60*fps+value(start_sub_S)*fps+value(start_sub_ms)*fps/1000 end_sub_H = MidStr(single_sub, 21+offset,2) end_sub_M = MidStr(single_sub, 24+offset,2) end_sub_S = MidStr(single_sub, 27+offset,2) end_sub_ms = MidStr(single_sub, 30+offset,3) end_sub_frame = value(end_sub_H)*60*60*fps+value(end_sub_M)*60*fps+value(end_sub_S)*fps+value(end_sub_ms)*fps/1000 single_sub_text = MidStr(single_sub, 35+offset) #HANDLING COLLISIONS if(start_sub_frame<=end_last_frame){ start_sub_frame = start_sub_frame+(start_sub_frame-end_last_frame)+1 } if((int(start_sub_frame)-int(end_last_frame))<10&&start_sub_frame-end_last_frame>1){ for(k=1,int(start_sub_frame-end_last_frame-1), 1){ c_overlaied=c.Trim(int(end_last_frame+k),int(end_last_frame+k)) c_overlaied=Overlay(x=0,y=y_sottopancia,c_overlaied,bg,mask=bgALPHA) c=c.Trim(0,int(end_last_frame+k-1))+c_overlaied+c.Trim(int(end_last_frame+k+1),c.framecount) c=Subtitle(c, text_last_frame, first_frame=int(end_last_frame+k), last_frame=int(end_last_frame+k), y=round(c.Height*y_last_sub+y_sottopancia), font=font_sub, size=round(c.Height*size_sub), text_color=text_color_sub, halo_color=halo_color_sub, align=align_sub, lsp=round(c.Height*lsp_sub), font_width=round(par*font_width_sub)) } } #HANDLING TWO LINES break=Findstr(single_sub_text, CRLF) if(break!=0){ single_sub_text=LeftStr(single_sub_text,break-1)+"\n"+Rightstr(single_sub_text, single_sub_text.StrLen-break-1) } c_overlaied=c.Trim(int(start_sub_frame),int(end_sub_frame)) c_overlaied=Overlay(x=0,y=y_sottopancia,c_overlaied,bg,mask=bgALPHA) c=c.Trim(0,int(start_sub_frame-1))+c_overlaied+c.Trim(int(end_sub_frame+1),c.framecount) #HANDLING VERTICAL ALIGN OF SINGLE LINE SUBS if(break==0){ y_this_sub = y_sub+0.5*size_sub } else{ y_this_sub = y_sub } c=Subtitle(c, single_sub_text, first_frame=int(start_sub_frame), last_frame=int(end_sub_frame), y=round(c.Height*y_this_sub+y_sottopancia), font=font_sub, size=round(c.Height*size_sub), text_color=text_color_sub, halo_color=halo_color_sub, align=align_sub, lsp=round(c.Height*lsp_sub), font_width=round(par*font_width_sub)) start_last_frame = start_sub_frame end_last_frame = end_sub_frame text_last_frame = single_sub_text y_last_sub = y_this_sub } } } """) audio=DirectShowSource(video_dir, video=false) return (AudioDub(c,audio)) Do you have any suggestion? Anyway at the end of the story I have a problem: when VirtualDub encodes the .avs says "out of memory". Do you know why? Where does the code get heavy to run? Cheers! |
9th November 2010, 19:12 | #2 | Link |
Avisynth language lover
Join Date: Dec 2007
Location: Spain
Posts: 3,437
|
Impressive use of GScript - I think that's the most complex example I've seen!
Is memory usage more or less proportional to the number of subtitles used? It looks like you have an instance of Overlay and Subtitle for each title (and in some cases for each frame of the title?), which can mount up. Not sure if it can be avoided though - perhaps if you know the titles will always be only on a small area of the screen, you could build up a smaller overlay clip, using less memory. Also, watch out with this code: Code:
c_overlaied=c.Trim(int(start_sub_frame),int(end_sub_frame)) c_overlaied=Overlay(x=0,y=y_sottopancia,c_overlaied,bg,mask=bgALPHA) c=c.Trim(0,int(start_sub_frame-1))+c_overlaied+c.Trim(int(end_sub_frame+1),c.framecount) |
9th November 2010, 23:05 | #3 | Link |
Registered User
Join Date: Dec 2009
Posts: 21
|
First of all thank you for appreciating that... But YOU did the most impressive job! (without the possibility of cycling and other scripting stuff would lose most of his power).
You're right on each you're consideration! 1)Ok for "framecount-1"... 2)I think I can manage titles starting on 1st or 2nd frame by inserting at the beginning of the FOR CYCLE a check which shifts the start to frame 3. Anyway it's quite unusual for my job... 3)It happens that it calls an instance of Subtitle() and Overlay() on each frame when fixing collisions (or covering too short gap between frame, 10 in that code). When gap is too short the previous is lengthen untill the next starts, in order to avoid the 'blinking effect'... A solution can be - in the collision managing - calculating the gap and overlaying+subtitling for all the gap instead frame by frame.. There could be a for-cycle less! By the way in your opinion... what is the memory usage related to? I mean... let's say I have a two or three nested for-cycles which all of them scroll along the whole clip, does it need to keep the all video (uncompressed) in RAM? The clip which gave me that error message was a 5 minutes DV-AVI interview with and around 50 titles... I can't imagine a 2-hours Full-HD clip... Is there a way to optimize this usage? And last question: is there the equivalent of LIST instead of ARRAY? The real tricky task is parsing a text file... Thank you in advance |
9th November 2010, 23:50 | #4 | Link |
Excessively jovial fellow
Join Date: Jun 2004
Location: rude
Posts: 1,100
|
if the "image" you want to overlay as a background is just a semitransparent rectangle (with or without borders and whatnot) then that is fairly easy to do with textsub (although you'll need to use .ass, not .srt. but it's trival to convert between the two.)
hope this helps |
10th November 2010, 00:36 | #5 | Link | ||
Avisynth language lover
Join Date: Dec 2007
Location: Spain
Posts: 3,437
|
Quote:
So a trick that can be used, if the titles are confined to a specific part of the screen, is to Crop the clip into 5 different parts as follows: Code:
_________________________________________________ | | | | | A | | | |_________________________________________________| | | | | | | | | | B | C | D | | | | | |_______________|_______________|_________________| | | | | | E | | | |_________________________________________________| You can then apply the overlays/titles to the smaller clip C (using less memory, and faster) and put the other parts back at the end using StackVertical(A, StackHorizontal(B, C, D), E). Quote:
|
||
10th November 2010, 10:01 | #6 | Link | |
Registered User
Join Date: Dec 2009
Posts: 21
|
Quote:
.ASS won't be a problem because I use VisualVobSynch and it can export .ass as well. Maybe I'm wrong on that. Or just in case... do you know if I can mix the two ways (ASS+SCRIPTING)? I mean... ASS subtitles use the section EVENTS when each title appear with its begin/end timings... Would be nice doing something like: for each EVENT do an Overlay() functions or something else... and write it inside .ass file. Am I drunk? I will try using Gavino's idea - dividing the frame in portions. It seems it definetly saves memory. Thank you both |
|
10th November 2010, 16:26 | #7 | Link |
͡҉҉ ̵̡̢̛̗̘̙̜̝̞̟̠͇̊̋̌̍̎̏̿̿
Join Date: Feb 2009
Location: No support in PM
Posts: 720
|
There is a simpler way IMHO, using vsfilter:
__________________
dither 1.28.1 for AviSynth | avstp 1.0.4 for AviSynth development | fmtconv r30 for Vapoursynth & Avs+ | trimx264opt segmented encoding Last edited by cretindesalpes; 10th November 2010 at 16:29. |
12th November 2010, 11:45 | #8 | Link | |
Excessively jovial fellow
Join Date: Jun 2004
Location: rude
Posts: 1,100
|
Quote:
There are several scripting environments/frameworks intended for use with ASS; the one I have the most experience with is Aegisub's automation, which uses Lua. It has a lot of helper functions and semiautomatic functionality in place that would make what you want (generate a background box for each subtitle line) a matter of maybe ten minutes of scripting for a decently experienced user. |
|
Tags |
avisynth, gscript, subtitles, vobsub |
Thread Tools | Search this Thread |
Display Modes | |
|
|