Nazo
2[H]4U
- Joined
- Apr 2, 2002
- Messages
- 3,672
Ok, I'm trying to create a somewhat universal script for taking a source video, changing the framerate, and resizing it for a portable player (namely my iAudio U3.) Basically how it works is that it should take the video, convert the framerate (via the switch mode since the framerate decrease is too extreme to just blend -- I wonder if anyone might know if there might be a more optimal value than the zone=80 that the documentation suggests?) then resize the video.
The tricky part here is that I want it to either add borders or crop the video (depending on my personal preference for the particular video) and I really want it to be able to figure it out on its own (otherwise it wouldn't be very universal after all.) To this end, I tried to create one function for each method and determine within each function first the size to resize to (maintaining the original source aspect ratio but fitting the correct target dimension depending on which method is being used) and then the amount to add or subtract to get the correct output.
The problem is, AVISynth seems to be ignoring something and resizing into a square image every time. With the border adding resize (where it resizes to the same width as the target but should resize to a lower height) it resizes to TargetWidth*TargetWidth and with the cropping resize (where it resizes to the same height as the target but should resize to a larger height) it resizes to TargetHeight*TargetHeight. In other words, if I take a 352x240 video (eg the colorbars I'm using for testing atm) with the borders enabled, I should be getting an output of 160x128 with black bars such that the actual video itself is 160x109 within those bars and instead I get an output of 160x160 with no borders. If I use cropping on that same resolution video, I should see video actually being about 188x128 cropped down to 160x128 (eg 14 pixels cut off of the left and the right for a removal of 28 total width) and instead I get a 128x128 video with no cropping.
To determine resize width or height, I first find out the aspect ratio of the source video by dividing width and height (eg 4/3 = 1.3333) and then I multiply that ratio by the target height to get the resize width (eg 1.3333 * 128 = 170.6624) for cropping or divide that ratio from the target width to get the resize height (eg 160 / 1.3333 = 120.0030) for borders. I was hoping to get away without needing rounding, but I think I will have to (it was my hope that it was smart enough to blend and such as needed -- like it can do with the crop function, but I think the resize won't allow that. As it turns out, I'm going to have to figure out how to make sure that the height and width in the resize are always integrally divisible by 2 and then correct the border adding or cropping as needed. I can do this, but right now I'm just too tired to deal with it, and more importantly, I can't get far enough along into the process to need to figure it out just yet since it craps out before it gets to the border or crop functions. Once I figure out those, I'll deal with the headache of the integral divide by 2 resolutions.)
Anyway, if someone can figure out what I am (or AVISynth is) doing wrong, I'd be terribly grateful. Perhaps I'm just getting too tired to see it, but I'd swear that no matter how hard I look, I wrote the actual function correctly (minus the integral divide by 2 resolution problem that I still haven't even run into.) When I try to follow the formula I put in with a calculator, I get the correct results, but it is apparently getting incorrect results. Here's my full code complete with as much white space and commentation as I could manage for hopefully maximum readability:
The tricky part here is that I want it to either add borders or crop the video (depending on my personal preference for the particular video) and I really want it to be able to figure it out on its own (otherwise it wouldn't be very universal after all.) To this end, I tried to create one function for each method and determine within each function first the size to resize to (maintaining the original source aspect ratio but fitting the correct target dimension depending on which method is being used) and then the amount to add or subtract to get the correct output.
The problem is, AVISynth seems to be ignoring something and resizing into a square image every time. With the border adding resize (where it resizes to the same width as the target but should resize to a lower height) it resizes to TargetWidth*TargetWidth and with the cropping resize (where it resizes to the same height as the target but should resize to a larger height) it resizes to TargetHeight*TargetHeight. In other words, if I take a 352x240 video (eg the colorbars I'm using for testing atm) with the borders enabled, I should be getting an output of 160x128 with black bars such that the actual video itself is 160x109 within those bars and instead I get an output of 160x160 with no borders. If I use cropping on that same resolution video, I should see video actually being about 188x128 cropped down to 160x128 (eg 14 pixels cut off of the left and the right for a removal of 28 total width) and instead I get a 128x128 video with no cropping.
To determine resize width or height, I first find out the aspect ratio of the source video by dividing width and height (eg 4/3 = 1.3333) and then I multiply that ratio by the target height to get the resize width (eg 1.3333 * 128 = 170.6624) for cropping or divide that ratio from the target width to get the resize height (eg 160 / 1.3333 = 120.0030) for borders. I was hoping to get away without needing rounding, but I think I will have to (it was my hope that it was smart enough to blend and such as needed -- like it can do with the crop function, but I think the resize won't allow that. As it turns out, I'm going to have to figure out how to make sure that the height and width in the resize are always integrally divisible by 2 and then correct the border adding or cropping as needed. I can do this, but right now I'm just too tired to deal with it, and more importantly, I can't get far enough along into the process to need to figure it out just yet since it craps out before it gets to the border or crop functions. Once I figure out those, I'll deal with the headache of the integral divide by 2 resolutions.)
Anyway, if someone can figure out what I am (or AVISynth is) doing wrong, I'd be terribly grateful. Perhaps I'm just getting too tired to see it, but I'd swear that no matter how hard I look, I wrote the actual function correctly (minus the integral divide by 2 resolution problem that I still haven't even run into.) When I try to follow the formula I put in with a calculator, I get the correct results, but it is apparently getting incorrect results. Here's my full code complete with as much white space and commentation as I could manage for hopefully maximum readability:
Code:
#Set user variable values
useBorders = 1 #Resize and maintain ratio via a crop (0) or border (1)
useBilinear = 1 #Resize using Point filter (0) or Bilinear filter (1)
targetWidth = 160 #Target width
targetHeight = 128 #Target height
targetFPS = 13.000 #Target framerate - Note: Simple @ L3 suggests <= 15 FPS
#End of user variables
#Please modify nothing below this line unless you know what you are doing.
#------------------------------------------------------------------------------
#Start of script
videoIn = ColorBars(352,240) #REMOVE ME LATER!!!
#videoIn = DirectShowSource("%VideoPathFile%") #ADD ME LATER!!!
#YUY2 is required for some filters (like ConvertFPS) so we need to convert if
#the source is not YUY2. The output will be YV12 for MPEG standards, so even
#if the source is RGB or YV12, this is probably a harmless conversion.
videoOut = (IsYUY2(videoIn) == true) ? videoIn : videoIn.ConvertToYUY2
#Convert to the target framerate with switch for the low framerate to output
videoOut = (Framerate(videoOut) == targetFPS) ?
\ videoOut : videoOut.ConvertFPS(targetFPS, zone=80)
#Resize with borders or cropping, depending on useBorders variable
videoOut = (useBorders == 1) ?
\ ResizeBorder(videoOut, targetWidth, targetHeight, useBilinear) :
\ ResizeNoBorder(videoOut, targetWidth, targetHeight, useBilinear)
#MPEG uses YV12. I'm not sure if AVISynth has a better filter, but I suspect
#it would not be worse, so I'll just go ahead and convert to YV12. It probably
#depends on what encoder you will be using. Perhaps AVISynth is better?
videoOut = videoOut.ConvertToYV12
videoOut = (AudioRate(videoOut) == 44100) ? videoOut : videoOut.SSRC(44100)
videoOut = (AudioBits(videoOut) == 16) ? videoOut : videoOut.ConvertAudioTo16Bit
return(videoOut)
#End of script
#------------------------------------------------------------------------------
#Start of functions
#Resize the clip to target adding borders where needed
Function ResizeBorder(videoInput, outWidth, outHeight, useBilinear) {
videoWidth = Width(videoInput)
videoHeight = Height(videoInput)
videoRatio = videoWidth / videoHeight
targetRatio = outWidth / outHeight
#What height do I resize to with the source aspect ratio but target width?
resizeHeight = outWidth / videoRatio
#Find out how much to add on each side
eachSide = (videoRatio == targetRatio) ? 0 : (outHeight - resizeHeight) / 2
videoOutput = (useBilinear == 1) ?
\ videoInput.BilinearResize(outWidth, resizeHeight) :
\ videoInput.PointResize(outWidth, resizeHeight)
videoOutput = videoOutput.AddBorders(0, eachSide, 0, eachSide)
return videoOutput
}
#Resize the clip to target using clipping where needed
Function ResizeNoBorder(videoInput, outWidth, outHeight, useBilinear) {
videoWidth = Width(videoInput)
videoHeight = Height(videoInput)
videoRatio = videoWidth / videoHeight
targetRatio = outWidth / outHeight
#What width do I resize to with the source aspect ratio but target height?
resizeWidth = videoRatio * outHeight
#Find out how much to subtract on each side
eachSide = (videoRatio == targetRatio) ? 0 : (resizeWidth - outWidth) / 2
videoOutput = (useBilinear == 1) ?
\ videoInput.BilinearResize(resizeWidth, outHeight) :
\ videoInput.PointResize(outWidth, resizeHeight)
Crop(videoOutput, eachSide, 0, (eachSide * -1), -0)
return videoOutput
}
#End of functions