Enhancing dvd videos

From Avisynth wiki
Jump to: navigation, search

by axelfoey133(at)hotmail(dot)com

I'm surprised that so many people seem to love Avisynth for its ability to alter video for conversion yet no one I know has ever mentioned using it for playback.

For example, enhancing the appearance of dvd vob files. Why limit the quality of video to a program that concentrates on speed, not quality? running a p4 2.6, I have cpu cycles to burn so I burn them hard.

This guide is for enhancing PAL dvds (I'm an aussie, and pal is better for displaying film anyway (progressive encoding, higher resolution). NTSC would be quite similar, except some dimensions would need to change and you would need to deinterlace.

I use the mpeg2dec3dg vob decoding library and use dvd2avi to make the d2v files, and virtualdub to get some numbers for Avisynth. My script is incredibly complex but I will just use a simple example and put up the bigger version later. I also use acm ac3 decoder and dvd decrypter.

A. Ripping to the hard disk

  • Load dvd decrypter and select the vob to decode in IFO mode.
  • Select the chapters that you want to rip and the data streams. You should only need a single video and audio stream both on direct stream copy.
  • Make sure you select stream information in the tool options. Select all the options for removing protection (css, macrovision, etc).
  • Rip it to your hard disk.

B. Loading the vob video stream

  • Create a .d2v file for your video file with DVD2AVI.
  • Create an .avs script into the same folder as the .d2v.
  • Put this code into the script and replace the x's. See the notes for more information.
Video = MPEG2Source ("xxxxxxxx.d2v")    # Load the video
# Convert video to more compatible format. It's actually faster on my computer anyway
Video = ConvertToYUY2 (Video)
# Start and ending frame numbers if you don't want to watch the entire chapter. 
# use virtualdub to find specific frame numbers           
Video = Trim (Video, xx, xx) 
# Crop the matte bars off the video if your watching anamorphic 2."35:1" films. 
# use virtualdub to find specific offsets
Video = Crop (Video, 0, xxx, 720, xxx) 
Video = LanczosResize (Video, 1024, Video.Height) # Uses the most effective resizer to span the video out.
Video = Sharpen (Video, 0.78) # Helps sharpen smoothness enlarging does. 0.78 = (1.25*(1024/720))-1
Return Video

That does the video stream to the max with quality. Now the audio.

C. The audio

  • Load the vob file into virtualdub. Make sure you have acm ac3 decoder installed to read the audio.
  • Direct stream copy the audio into the same folder as the d2v file.
  • Open the stream information file that dvd decrypter produced and note the delay (in milliseconds).
  • Add this to the script in the the gap.
Audio = WAVSource ("xxxxxxxx.wav")    # Load the audio
# xxx is the delay of audio in seconds (not milliseconds, so divide by 1000)
Audio = DelayAudio (Audio, xxx)
Video = AudioDub (Video, Audio)       # Mix audio and video together.

Voila!

As I said that is a very simple but effective dvd script. Extras that I have included in my ultra-complex script are playing the video at 24 fps (instead of pal's 25), and options to flip the video horizontally, boost levels, change the frame rate, swap the color channels (can look very good at times) and display delta data.

The structure of my code is entirely different to what i presented above. I actually use a single core avs - with several public functions - to do the processing for all vob files, while each video gets its own avs with references and numbers (no processing) to hand to the core to provide outputs.

Sort of like the brain has all the information, but the body does the work, and neither will work without the other. It allows you to make changes to the core code without replacing each individual script. So here is my complete code for those who can understand it.

Note: I use a modified audio track, because it seems my computer doesn't like to slow 48000 Hz audio to 46080 Hz when I slow the video down to 24 fps. So I use virtualdub to resample to 50000 Hz and then Avisynth will slow it back to 48000. So just note, my audio tracks are playing at 50 Khz, not 48.

Import ("C:\Videos\DVD's\DVD AVS's\Core.avs")     # Import the Core code
SetMemoryMax (64)       # Set 64 Mb memory for operation

Folder = "C:\Videos\DVD's\The Matrix Reloaded"    # For SetWorkingFolder later on
VideoName = "Upgrades"  # Video name (The Upgrades Scene)
AudioName = ""          # Alternate audio track if found
AudioDelay = -40        # delay in milliseconds (converted to seconds later)
MusicName = ""          # Optional Music track
MusicDelay = 0          # delay in milliseconds (converted to seconds later)
MusicGain = 0.1         # Music is often louder than dvd audio, so turn the music volume down
TrackMix = 1            # 1=Audio, 2=Music, 3=Audio and music mixed

Start = 758             # Start frame
End = 3157              # End frame
TopBar = 75             # Number of lines in top black matte
BottomBar = 75          # Number of lines in bottom black matte
VideoHeight = 576 - (TopBar + BottomBar)    # Extract Number for Video's height
DisplayMode = "Nil"                         # Default 'null transform' mode

Effects = 0             # Sets the Effects variable to 0
Gamma = 1.4             # Default Gamma for levels boost, but it can change
Speed = 30              # For chipmonk video!

DisplayMode = "Anamorphic"     # Sets up core for anamorphic function
# DisplayMode = "Widescreen"     # Sets up core for widescreen function
# DisplayMode = "Fullscreen"     # Sets up core for fullscreen function
# DisplayMode = "TV"             # Sets up core to simulate TV
# Displaymode = "hq_fullscreen" # Set up core to maximum screen 1024 x 768 (Slow)

# Effects work on an additive process to provide a single number (in this case from 0 to 31)
# The core will reverse this process to discover which effects are wanted

Effects = (DisplayMode == "TV") ? Effects : Effects + 1    # Boost Levels
# Effects = Effects + 2           # Show Delta Data
# Effects = Effects + 4           # Swap Colour Channels
Effects = (DisplayMode == "TV") ? Effects : Effects + 8    # Change Speed
Effects = Effects + 16           # Flip Horizontal

# Since TV mode will use the speed and gamma options, 
# they are discounted when TV mode is being used 

# All necessary data has now been noted
# Now pass it on to the core

LoadVOB (VideoName, AudioName, AudioDelay, MusicName, MusicDelay, \
    MusicGain, TrackMix, Folder)
CreateFilm (Start, End, TopBar, VideoHeight)   # Crop, Trim and slow to 24 fps
(DisplayMode != "tv") \
    ? ApplyEffects (Effects, Speed, Gamma) \
    : Last                # Apply effects before enlarging
# Loads the function that has the same name as DisplayMode.
Eval (DisplayMode + "()")
(DisplayMode == "Anamorphic") \
    ? ApplyEffects (Effects, Speed, Gamma) \
    : Last                # Apply effects after shrinking

That's the reference script's code. Here's the core.

Function LoadVOB (string VideoName, string AudioName, int AudioDelay, \
    string MusicName, int MusicDelay, float MusicGain, int TrackMix, \
    string Folder) {
# Loads the VOB and WAV files and mixes them together
# Output: YV12 Video @ 720 x 576, 25 fps, 50000 Khz 16 bit stereo

    SetWorkingDir (Folder)

    Video = (Exist (VideoName + ".d2v") == True) \
        ? MPEG2Source (VideoName + ".d2v", idct = 5) \
        : Subtitle(BlankClip (Width = 720, Height = 576, fps = 25), \
            "Couldn't find video")
    # Loads video if it exists, or an error message

    Audio1 = (Exist (VideoName + ".wav") == True) \
        ? WAVSource (VideoName + ".wav") \
        : BlankClip (Audio_Rate = 50000, Stereo = True)
    Audio1 = (Exist (AudioName + ".wav") == True) \
        ? WAVSource (AudioName + ".wav") \
        : Audio1
    Audio1 = DelayAudio(Audio1, AudioDelay/1000)
    # Loads alternate audio track over original audio (if alternate 
    # exists), or a blank track if neither is found

    Audio2 = (Exist (MusicName + ".wav") == True) \
        ? WAVSource (MusicName + ".wav") \
        : BlankClip (Audio_Rate = 50000, Stereo = True)
    Audio2 = Amplify (Audio2, MusicGain)
    Audio2 = ResampleAudio (Audio2, 48000)
    Audio2 = AssumeSampleRate(Audio2, 50000)
    Audio2 = DelayAudio(Audio2, MusicDelay/1000)
    # Fiddle with the music track so that it is the same format as the audio and sped up to 25 fps.

    Audio3 = MixAudio (Audio1, Audio2)
    # Create mixed track

    Eval ("Video = AudioDub (Video, Audio" + String (TrackMix) + ")")
    # Use the audio track with the TrackMix number on the end.
    Video = ConvertToYUY2 (Video)
    # Convert the video so it is more compatible when cropping. 
    # and YUY2 is faster than YV12 on my PC for some reason...
    Return Video
}
Function CreateFilm (clip Video, int Start, int End, \
    int TopBar, int VideoHeight) {
# Slows PAL DVD's to 24 fps and 48000 Khz, trims the video, and crops black bars
# Output: YUY2 Video @ 720 x xxx, 24 fps, 48000 Khz 16 bit stereo

    Video = AssumeFPS (Video, 24, True)       # Slow to film rate. Audio slows to 48 Khz
    Video = Trim (Video, Start, End)          # Trim out the parts you don't want
    Video = Crop (Video, 0, TopBar, 720, VideoHeight)    # Crop off the black bars
    Return Video
}
Function Nil (clip Video) {
# Null Transform
# Output: Input
# Does nothing. Used as default if all other DisplayMode functions are not enabled
    Return Video
}
Function Anamorphic (clip Video) {
# Horizontal resize to 1024 pixels
# Output: 1024 x xxx Video

    Video = LancZosResize (Video, 1024, Video.Height)
    Video = Sharpen (Video, 0.78)# Same methods used in my example script.
    Return Video
}
Function Widescreen (clip Video) {
# Resize video to 16:9 Academy Widescreen
# Output: 960 x 540 Video

    NLeft = Round (360 - (0.625 * Video.Height))
    NWidth = Round (720 - (2 * NLeft))
    NHeight = Video.Height
    Video = LancZosResize (Video, 960, 540, NLeft, 0, NWidth, Video.Height)
    Video = Sharpen (Video, Int (1.25 * ((Video.Width / NWidth) - 1)))

# This cuts off some of the sides and enlarges it so that you get 
# a near full screen 16:9 widescreen image
    Return Video
}
Function Fullscreen (clip Video) {
# Resize video to 4:3 Fullscreen
# Output: 768 x 576 Video

    NLeft = Round (360 - (0.46875 * Video.Height))
    NWidth = Round (720 - (2 * NLeft))
    NHeight = Video.Height
    Video = LancZosResize (Video, 768, 576, NLeft, 0, NWidth, Video.Height)
    Video = Sharpen (Video, Int (1.25 * ((Video.Width / NWidth) - 1)))

# This cuts off more of the sides and enlarges it so that you get 
# a near 4:3 fullscreen image
    Return Video
}
Function TV (clip Video) {
# Resize video to SDTV
# Output: 648 x xxx Video

    Video = BilinearResize (Video, 576, Round (45 * Video.Height / 64), \
        72, 0, 576, Video.Height)
    Video = Limiter (Video, 16, 235, 16, 240)
    Video = ApplyEffects (Video, 9, 25, 1.4)

# Reduces the resolution and removes part of the sides to simulate a TV look. 
# also increases the gamma and changes speed to 25 fps.
# When in this mode, it uses ApplyEffects to control speed and gamma 
# (why they are deactivated in the reference script)

    Return Video
} 
Function ApplyEffects (clip Video, int Effects, float Speed, float Gamma) {

    Video = (Effects >= 16) ? FlipHorizontal(Video) : Video
    Effects = (Effects >= 16) ? Effects - 16 : Effects
    Video = (Effects >= 8) ? AssumeFPS (Video, Speed, True) : Video
    Effects = (Effects >= 8) ? Effects - 8 : Effects
    Video = (Effects >= 4) ? SwapUV(Video) : Video
    Effects = (Effects >= 4) ? Effects - 4 : Effects
    Video = (Effects >= 2) ? Subtract (Trim (Video, 1, 0), Video) : Video
    Effects = (Effects >= 2) ? Effects - 2 : Effects
    Video = (Effects >= 1) ? Levels (Video, 0, Gamma, 255, 0, 255) : Video
    Effects = (Effects >= 1) ? Effects - 1 : Effects

# Uses the reverse process to work out what functions to use. 
# speed and gamma options are also brought in.

    Return Video
}
Function HQ_Widescreen (clip Video) {
# Resize video to 16:9 Academy Widescreen
# Output: 1024 x 576 Video

    NLeft = Round (360 - (0.625 * Video.Height))
    NWidth = Round (720 - (2 * NLeft))
    NHeight = Video.Height
    Video = LancZosResize (Video, 1024, 576, NLeft, 0, NWidth, Video.Height)
    Video = Sharpen (Video, Int (1.25 * ((Video.Width / NWidth) - 1)))

# Same as Widescreen except it gives a larger image. my computer can't handle 
# this at runtime, so i only use it to grab high quality frames for backgrounds or the like

    Return Video
}
Function HQ_Fullscreen (clip Video) {
# Resize video to 4:3 Fullscreen
# Output: 1024 x 768 Video

    NLeft = Round (360 - (0.46875 * Video.Height))
    NWidth = Round (720 - (2 * NLeft))
    NHeight = Video.Height
    Video = LancZosResize (Video, 1024, 768, NLeft, 0, NWidth, Video.Height)
    Video = Sharpen (Video, Int (1.25 * ((Video.Width / NWidth) - 1)))

# It gives a larger fullscreen image. my computer can't handle this, 
# so i only use it to grab high quality frames

    Return Video
}

That's it... that's all there is to it.

Personal tools