Jump to content

Recommended Posts

Posted (edited)

Hello forum members,

 

I am using Emby for a few days now, and my not very powerful Atom Windows server can't encode 2 users on-the-fly. For that reason I wanted to

convert my entire video library to h264+aac mp4 files. I couldn't find any program that converts a folder+subfolders automatically, so I made a simple

vbs file that does. So for everyone with the same problem, this is the code:

Option Explicit

Const ForWriting = 2
Dim objFSO, oShell, curFile, curName, curExt, curFol, tempNum, tempFn, param, fullCom, baseFol 
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set oShell = CreateObject ("WScript.Shell")

Recurse objFSO.GetFolder(oShell.CurrentDirectory)

Sub Recurse(objFolder)
    Dim objFile, objSubFolder

    For Each objFile In objFolder.Files
        If ((LCase(objFSO.GetExtensionName(objFile.Name)) = "mkv") OR (LCase(objFSO.GetExtensionName(objFile.Name)) = "mp4") OR (LCase(objFSO.GetExtensionName(objFile.Name)) = "avi") OR (LCase(objFSO.GetExtensionName(objFile.Name)) = "wmv") OR (LCase(objFSO.GetExtensionName(objFile.Name)) = "m4v") OR (LCase(objFSO.GetExtensionName(objFile.Name)) = "m4p") OR (LCase(objFSO.GetExtensionName(objFile.Name)) = "mpg")  OR (LCase(objFSO.GetExtensionName(objFile.Name)) = "mpeg") OR (LCase(objFSO.GetExtensionName(objFile.Name)) = "3gp")) Then
		curFile = objFile.Path
		curName = Replace(objFile.Name,"." & objFSO.GetExtensionName(objFile.Path),"")
		curExt = objFSO.GetExtensionName(objFile.Name)
		curFol = objFolder
		tempFn = "temp_" & curName & "." & curExt
		objFSO.GetFile(curFile).Name = tempFn
		param = "-i """ & curFol & "\" & tempFn & """ -o """ & curFol & "\" & curName & ".mp4"" -f av_mp4 -O -e x264 -E av_aac -X 1280 -Y 720"
		fullCom = """C:\Program Files\HandBrake\HandBrakeCLI.exe """ & param
		oShell.run fullCom, 1, true
		objFSO.DeleteFile(curFol & "\" & tempFn)
        End If
    Next

    For Each objSubFolder In objFolder.SubFolders
        Recurse objSubFolder
    Next
End Sub

A vbs file with this script is in the zip in the attachment.

 

Usage: Place the file in the folder that you want to convert, and dubble click it.

 

It converts mkv, mp4, avi, wmv, m4v, m4p, mpg, mpeg and 3gp files using the handbrake cli, so having that installed is a requirement.

Change 'C:\Program Files\HandBrake\HandBrakeCLI.exe' to the path of the 'HandBrakeCLI.exe' file. Note the space after the file path, this should not be removed!

Note: It also converts mp4 files that are alread in the correct format! The script does not check the file. It is very basic.

 

Another very important note; THIS SCRIPT DELETES THE ORIGINAL FILE.

Place a ' in front of the line 'objFSO.DeleteFile(curFol & "\" & tempFn)' to prevent that from happening. The original file will have its original name with 'temp_' in front of it.

 

Questions are welcome. Feel free to edit the code and post the updated version here. I know the currect code is very basic but it is good enough for me.

 

Hope to help someone with this  :)

 

Edit: The max resolution it converts to is 1280x720 (720p). If the input file has a lower resolution it will keep the same resolution. Aspect ratio will always be the same in the output file.

Encode_sub_dir.zip

Edited by sjigoow
  • Like 2
mastrmind11
Posted

Pretty cool, but the built in Sync feature of the server already does this :)

Posted

That's true, but you need a premium account for that. I want to make sure my NAS works good before putting more money in it.

mastrmind11
Posted

Gotcha.  Nice work anyway.

Posted

How could you make it to add 5.1 sound and 1920x1080  ??

Posted (edited)

Simply changing '720' to '1080', '1280' to '1920' should do the trick for the resolution. HandbrakeCLI however tells me that AAC only goes up to 2.0 audio. To be able to

use 5.1, the used codec should be 'ac3', 'eac3', 'flac16', 'flac24' or 'opus'. To go up to 7.1, you should use one of the last 3 options.

Option Explicit

Const ForWriting = 2
Dim objFSO, oShell, curFile, curName, curExt, curFol, tempNum, tempFn, param, fullCom, baseFol 
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set oShell = CreateObject ("WScript.Shell")

Recurse objFSO.GetFolder(oShell.CurrentDirectory)

Sub Recurse(objFolder)
    Dim objFile, objSubFolder

    For Each objFile In objFolder.Files
        If ((LCase(objFSO.GetExtensionName(objFile.Name)) = "mkv") OR (LCase(objFSO.GetExtensionName(objFile.Name)) = "mp4") OR (LCase(objFSO.GetExtensionName(objFile.Name)) = "avi") OR (LCase(objFSO.GetExtensionName(objFile.Name)) = "wmv") OR (LCase(objFSO.GetExtensionName(objFile.Name)) = "m4v") OR (LCase(objFSO.GetExtensionName(objFile.Name)) = "m4p") OR (LCase(objFSO.GetExtensionName(objFile.Name)) = "mpg")  OR (LCase(objFSO.GetExtensionName(objFile.Name)) = "mpeg") OR (LCase(objFSO.GetExtensionName(objFile.Name)) = "3gp")) Then
curFile = objFile.Path
curName = Replace(objFile.Name,"." & objFSO.GetExtensionName(objFile.Path),"")
curExt = objFSO.GetExtensionName(objFile.Name)
curFol = objFolder
tempFn = "temp_" & curName & "." & curExt
objFSO.GetFile(curFile).Name = tempFn
param = "-i """ & curFol & "\" & tempFn & """ -o """ & curFol & "\" & curName & ".mp4"" -f av_mp4 -O -e x264 -E ac3 -6 5point1 -X 1920 -Y 1080"
fullCom = """C:\Program Files\HandBrake\HandBrakeCLI.exe """ & param
oShell.run fullCom, 1, true
objFSO.DeleteFile(curFol & "\" & tempFn)
        End If
    Next

    For Each objSubFolder In objFolder.SubFolders
        Recurse objSubFolder
    Next
End Sub

objFSO.DeleteFile(WScript.ScriptFullName) 
Few things to note:

1. If your input file has a resolution lower than 1920px x 1080px the resolution of the output file will be the same as the input file.

2. This script was slightly changed. The last line causes the script to delete itself when it's done. I found that to be easier, but you need to make sure always to have a backup.

 

Let's take a look at the line

param = "-i """ & curFol & "\" & tempFn & """ -o """ & curFol & "\" & curName & ".mp4"" -f av_mp4 -O -e x264 -E ac3 -6 5point1 -X 1920 -Y 1080"

This is the line that contains the parameters with which HandbrakeCLI knows what to do. As you can see, it currently encodes video with the 'x264' encoder (-e x264). Change that to (-e x265) to encode with the 'x265' encoder. (hope that answers your question in your pm.) Next we see it encodes audio with the 'ac3' encoder (-E ac3). Note the difference in uppercase/lowercase. Changing that to one of the encoders in the second line of this message changes the audio encoder accordingly ('ac3' should be 'av_aac' for aac). The next part (-6 5point1) tells handbrake that the audio should be encoded to 5.1 chanels. Removing this will keep the original chanels. Aac can't go higher than 2.0! '-X 1920 -Y 1080' speaks for itself.

 

Hope to have helped someone with this. I am certainly not an expert, keep that in mind.

Edited by sjigoow
  • Like 1
Posted

sjigoow, thank you

Posted

Why would you want to use x265 and 5.1 sound btw? The idea behind this script was to convert my library to a format that almost any player can decode, so my server won't have to encode it all on-the-go. 

Posted

I guess i was thinking wrong,[convert my library,(13,000+ videos) automatically].

Posted (edited)

Change 'C:\Program Files\HandBrake\HandBrakeCLI.exe' to the path of the 'HandBrakeCLI.exe' file. Note the space after the file path, this should not be removed!

 

Wouldnt that be the same path ?

Win7 and Win8.1

 

About how many days does the re-encoding take ?

Edited by x88dually
Posted

For anyone unsure about doing this (and you should be careful), create a test folder and copy several files there and use the script. This will help you find out if it works on your system, how long it takes and if you like the results.  ;)

Posted

@@x88dually Depends on where you put the file.

 

Converting a small library (about 5 series and 20 movies) costed me like a week. But that was on my super slow server.

My laptop (3rd gen i5) usually converts @100fps, meaning that it takes about 1/4th the duration of a movie to convert that movie.

 

Encoding simply costs a lot of processing power, and your cpu will be running @100% when you are converting, just keep that in mind.

 

@@Latchmor True. You can also put a ' in front of this line: 

objFSO.DeleteFile(curFol & "\" & tempFn)

This is the line that deletes the original file. Putting a ' in front of it:

'objFSO.DeleteFile(curFol & "\" & tempFn)

keeps the script from deleting it. Your original file will have the text 'temp_' in front of its original file name.

  • Like 1
Posted (edited)

So if handbrake installs to default folder, then i shouldnt have to change the path in your file. ?

Then your file goes into folder i wanna convert, and double click the db file to make it convert all files in that folder ?

So, how do i make the convert media button work within emby ?

Edited by x88dually
Posted

HandbrakeCLI isn't installed with Handbrake, it is a seperate package that you can get from https://handbrake.fr/downloads2.php

Put 'HandbrakeCLI.exe' in 'C:\Program Files\HandBrake\' and you're good to go.

 

I don't know what you mean with 'db file'? It's supposed to be a vbs file.

 

Guess you would need a plugin for that. I'm not an Emby expert though. Keep in mind that this script also converts files that are already in the correct format.

Posted (edited)

Thank You

 

And yes i meant the vbs file.  the db was database file.

 

What bitrate does it reencode at ? or is that taken from original file ? or can it be set ?

Edited by x88dually
Posted

It reencodes at HandbrakeCLI's standard settings. Not sure what bitrate or quality this is, but I tested it once and it is good enough for me. To change it, you can add parameters to set bitrate or set quality.

 

See https://handbrake.fr/docs/en/latest/cli/cli-guide.html for HandbrakeCLI's guide.

Posted (edited)

i dont need anything perfect or blue-ray matching quality. i'm looking for good and up, and to  shrink my library with 265 with good sound, i'm fine with 48 khz an 2 channel stereo (tv shows, more then 1/2 my library).

Movies are a different thing.

 

Thx for the link.

Edited by x88dually
  • 11 months later...
josephdouce
Posted

I modified this to use ffmpeg instead, also would be better to check the codec of the files and only convert non h264 files and just change the container of files that are h264

josephdouce
Posted (edited)

you don't need to transcode if its already h264 with aac or mp3 so I wrote a little powershell script the following flags are available 

 

-list                   lists all non mp4 files 

-transcode       transcode all files to h264 + aac in mp4 container if they are not already

-container        changes container on files that are alreay h264 and aac

 

you can supply the transcode and container flags together, it wont mindlessly transcode files that are already h264 

 param (
    [switch]$list = $false,
    [switch]$container = $false,
    [switch]$transcode = $false
 )

#get all files in the directory recirsivley with included extensions
$file_names = Get-Childitem -File -Include *.mkv, *avi -Recurse

#create a powershell array
$file_info = @()

#iterate over the files and get the audio and video codecs
for ($i=0; $i -lt $file_names.Count; $i++){
    #get the video codec
    $video_codec = C:\tools\ffmpeg-3.4.1\bin\ffprobe.exe -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 $file_names[$i].FullName
    #get the audio codec 
    $audio_codec = C:\tools\ffmpeg-3.4.1\bin\ffprobe.exe -v error -select_streams a:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 $file_names[$i].FullName
    #add the properties to a powershell object 
    $file = New-Object -TypeName PSObject
    $file | Add-Member -Type NoteProperty -Name "Full Name" -Value $file_names[$i].FullName
    $file | Add-Member -Type NoteProperty -Name "Name" -Value $file_names[$i].Basename
    $file | Add-Member -Type NoteProperty -Name "Extension" -Value $file_names[$i].Extension
    $file | Add-Member -Type NoteProperty -Name "Video Codec" -Value $video_codec
    $file | Add-Member -Type NoteProperty -Name "Audio Codec" -Value $audio_codec
    #add each ojject to the array
    $file_info += $file
}

if ($list) {
    Write-Host ($file_info | Format-Table -Property "Name", "Extension", "Video Codec", "Audio Codec" | Out-String)
}
#itterate through the array of files 
foreach ($file in $file_info){
    $video_codec_out = "libx264"
    $audio_codec_out = "aac"
    #copy the video stream if it is already h264
    if ($file."Video Codec" -eq "h264"){
        $video_codec_out = "copy"
    }
    #copy the audio stream if it is already aac or mp3
    if ($file."Audio Codec" -eq "aac" -or $file."Audio Codec" -eq "mp3"){
        $audio_codec_out = "copy"
    }
    #dont transcode only change containers
    if ($container) {
        if (($video_codec_out -eq "copy") -and ($audio_codec_out -eq "copy")) {
            #create temp file name
            $new_file_name = [io.path]::ChangeExtension($file."Full Name", '.mp4')
            $argument_list = " -i """ + $file."Full Name" + """ -c:v " + $video_codec_out + " -c:a " + $audio_codec_out + " """ + $new_file_name + """ -hide_banner"
            #start ffmpeg
            Start-Process -FilePath C:\tools\ffmpeg-3.4.1\bin\ffmpeg.exe $argument_list -Wait -NoNewWindow
            #delete origional
            Remove-Item $file."Full Name"
        }
    }
    if ($transcode) {
        if (($video_codec_out -ne "copy") -or ($audio_codec_out -ne "copy")) {
            #create temp file name
            $new_file_name = [io.path]::ChangeExtension($file."Full Name", '.mp4')
            $argument_list = " -i """ + $file."Full Name" + """ -c:v " + $video_codec_out + " -c:a " + $audio_codec_out + " """ + $new_file_name + """ -hide_banner"
            #start ffmpeg
            Start-Process -FilePath C:\tools\ffmpeg-3.4.1\bin\ffmpeg.exe $argument_list -Wait -NoNewWindow
            #delete origional
            Remove-Item $file."Full Name"
        }
    }
}
Edited by josephdouce
  • 4 months later...
Posted

How would someone use the Sync feature to do this?

I want to decrease the size of my library.

 

I would like to just click a series and decrease the size of those media files. Lets say, convert to x265 with a small size parameter.

I got some tv series with 6GB size for a 1 hour show, its getting rediculous.

 

I dont wont to create multiple files, i just want to re-encode my library to a more efficient codec (x265) and a low size paramter.

 

Any ideas?

 

Thanks

 

Frank

Posted

The next release will have a convert feature to help with this.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...