Scott Hanselman

Batch Converting a Directory Tree of Videos Recursively with Handbrake for Streaming to an Xbox360

September 18, 2009 Comment on this post [22] Posted in PowerShell | Tools
Sponsored By

Babies! I've got many many gigs of 640x480 video of the kids and family taken on my Flip Ultra and then HiDef video taken with a Creative Vado HD, my current favorite pocket video camera. There's also a bunch of random videos taken with whatever video-capable digital camera I might have had with me at the moment.

These are fantastic video cameras (especially the Vado) but unfortunately the output they produce aren't easily streamed to any Game Console like a PS3 or Xbox360.

There's a glorious open-source multi-platform video transcoder out there called HandBrake. There's also the more sophisticated Expression Encoder. I usually use these applications (both can be called from the command-line) when I need to encode videos.

I figured I'd just drag the whole folder over and magically these apps would happily encode these hundreds of files and all subdirectories. Both apps are fantastic for doing one file at a time, but when you want to do a thousand, things break down. I googled with Bing for a while then decided that the batch files and MacGyver solutions I was finding were silly. Why not make my own ridiculous solution that at least worked for me?

Even better, why not do it as a one line PowerShell script and see if it's useful to you, Dear Reader? Even better, perhaps you'll re-write it in the comments and one day it won't suck as deeply as it does now.

Regardless, this script is currently, happily chewing away at all my videos and even better, these versions are streamable to my Xbox360 from my Windows Home Server. Woot. The Wife is happy.

Here it is:

gci . *.avi -R | foreach-object { $newfile = $_.Path + $_.DirectoryName + "\" + $_.BaseName + "-convert" + $_.Extension; &"C:\Program Files (x86)\HandBrake\HandBrakeCLI.exe" -i "$_.FullName" -o "$newfile" --preset "Xbox 360" }

Eek! But what price my immortal soul?

You need PowerShell for this, if you don't already have it. If you have Windows 7, it's already installed!

This poorly written script takes every *.avi file in the current (.) folder, and all folders underneath it (-R), and for each of this files, creates a new filename with the word "-convert" inside. It then calls the HandBrake command line (yours may be in "C:\Program Files" so you might need to change that. It uses the Xbox360 preset.

After this runs, you'll end up with a whole pile of foo-convert.avi files that should/will stream from your machine to your Xbox360 if you are using the free Windows Media Sharing Services. You can also change that profile and convert all your phone for your phone, or whatever you like.

Here's a snapshot of a classic baby video shown on the big screen. Don't you want to come over for dinner now? You can watch slideshows of all our still videos and now hours of family movies. Woot! Works For Me.

PowerShell experts? I'm quite rusty, and I was just interested in the "Getterdone" version. How can we make it better? How about making it so it only updates files that haven't already been encoded?

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service
September 18, 2009 12:45
Very nice work Scott - Loving the picture of your kid on the big screen - thinking about doing a similar thing for a slideshow, bookmarked!
September 18, 2009 12:49
This is probably a silly question, but why don't you just use a media sharing app that does on-the-fly transcoding like tversity or ps3 media server (works with 360 as well)?

I think Windows 7 does it too -

(PS: I don't think you mean "Windows Media Streaming Services", which is a enterprise media server thing)

September 18, 2009 15:17
> I googled with Bing

Nearly choked on my sandwich when I read this. Good one!

Handbrake is the bomb, but I hate it when you spend literally 2 or 3 days encoding a hi-def video only to find accidentally messed up a parameter and the resultant video isn't compatible with your media setup (PS3 in my case). Also, the UI is bug-ridden and can cause no end of pain when you think you're encoding with one set of parameters only to find those parameters weren't correctly passed onto the command line.
September 18, 2009 15:55
@Fowl: I recently switched from Twonky to ps3mediaserver and won't be switching back. That said, I'm not at all satisfied with the performance of ps3mediaserver. Browsing my photos is just not an option anymore - it takes FOREVER to bring them up, with my server churning at 100% CPU for extensive periods (java process, if you were wondering). Other than that, it rocks, so I'm hoping the perf issues get ironed out over time.

The reason I still occasionally need to use handbrake (rather than transcoding on the fly) is to reduce file sizes. I just can't justify using upwards of 10GB for a single movie, so I use handbrake to get it down to a much more reasonable size, without too much loss of quality.

I never had any luck with TVersity. Seemed good in theory, but in practice it was way too instable and buggy for me.
September 18, 2009 16:24
You could use dirmon. It will process all the files in a directory running any single or group of commands based on what files exist and/or don't exist next to the files.
September 18, 2009 17:07
can you use a where clause like this to filter the converted ones out or is there a propertie we can check ?

I did think something like this (not tested)

gci . *.avi -R |
where {$_.basename -notmatch 'convert'} |
foreach {
&"C:\Program Files (x86)\HandBrake\HandBrakeCLI.exe" -i $_.FullName -o "$($_.DirectoryName)\($_.BaseName)-convert$($_.Extension)" --preset "Xbox 360"

Greetings MOW
September 18, 2009 19:48
Thanks, Scott! That is something I've been wanting to do for _ages_!
September 18, 2009 20:59
MOW - thank goodness you showed up! You're right, this can only run well ONCE!
September 18, 2009 22:05
Quoting the immortal words of Raymond Chen: response to "How do I write a batch file that..." some people will say, "First, install <perl|bash|monad|...>". This doesn't actually solve the problem; it merely replaces it with a different problem.

In particular, if the solution begins with "First, install..." you've pretty much lost out of the gate. Solving a five-minute problem by taking a half hour to download and install a program is a net loss.

In the spirit of those words, here is a version that will, in theory, run on every version of Windows without requiring PowerShell or any third-party shell:

@for /f "delims=-. tokens=1-3" %%F in ('dir /b /s *.avi') do @if /i not [%%G] == [convert] (
"C:\Program Files (x86)\HandBrake\HandBrakeCLI.exe" -i "%%F.%%G" -o "%%F-convert.%%G" --preset "Xbox 360"

If you were outputting the files to a new directory, you could eliminate the @if condition and use:

@for /r %%F in (*.avi) do @echo "C:\Program Files (x86)\HandBrake\HandBrakeCLI.exe" -i "%%F" -o "C:\OUTPUT%%~pnF-convert%%~xF" --preset "Xbox 360"
September 18, 2009 22:18

Did you see the powershell sample that came with Expression Encoder? It does exactly what you are looking for.
September 18, 2009 22:25
XBMC plays everything out of the box!
September 18, 2009 22:35
Chris, I see only ScriptSamples.ps1 with Expression Encoder?
September 19, 2009 6:33
Rather than a one-liner this would probably be easier to understand as a script:

$handbrake = "C:\Program Files (x86)\HandBrake\HandBrakeCLI.exe"
$files = @(Get-ChildItem . *.avi -Recurse | Where {$_ -notmatch '-convert\.avi$'})
foreach ($file in $files) {
$newFileName = $file.Fullname -replace '\.avi$','-convert.avi'
& $handbrake -i $file.FullName -o $newFileName --preset "Xbox 360"
if ($LastExitCode -ne 0) { Write-Warning "Error converting $($file.FullName)" }

Note: I'm not sure handbrakeCLI returns a non-zero exit code to indicate an error but if it does, you probably want to know about it.
September 19, 2009 14:12
"I googled with Bing..."
Is that even possible? I would assume that one can only 'google' (verb) with google (noun).
I don't know what you would do with bing though. 'I bunged with bing...' or maybe just the more boring 'Searched with bing...'

At the very least, if that's not a grammatical mistake, it must surely be a marketing nightmare.
September 19, 2009 21:10

That is the one, along with the Expression powershell module that is in the same folder you can convert an entire folder of videos to the template of your choice.

Either I suppose it works. I preferred Expression to Handbrake because I thought to output of the expression encoder was better and I had issue with handbrake crashing on my Win7 x64 machine.
September 20, 2009 4:05
Does Handbrake work with Flip Mino HD files?
September 20, 2009 5:00
Good tip but I still hate the fact you have to do any transcoding for playing on the 360, it should be able to play almost anything natively making it a true media hub, I don't want to transcode everytime I want to play something along with that niggling feeling that I am losing quality and wasting time.

As mentioned above, the reason why XBMC is so popular is it can handle almost anything (and from anywhere) if the 360 could sit under my TV and do the same it would be great.
September 22, 2009 10:01
Here's some updated info from the Expression Encoder!

Open *admin* cmd prompt or powershell

cd "C:\Program Files (x86)\Microsoft Expression\Encoder 3\SDK\samples\EncoderPowerShellModule"

close and open a new powershell. To encode a folder full of videos to H.264 for the new Zune HD

Import-Module ExpressionEncoder

gci 'C:\users\Public\Videos\Sample Videos' | Convert-Media -H264ZuneHDAVDockPlayback -Output $home\desktop

More sample scripts listed in here:

C:\Program Files (x86)\Microsoft Expression\Encoder 3\SDK\Doc\Microsoft.Expression.Encoder.chm
September 29, 2009 19:15
here is some code i modified to check and see if the files have been previously encoded:

$handbrake = "C:\Program Files (x86)\HandBrake\HandBrakeCLI.exe"
$files = @(Get-ChildItem . *.avi -Recurse | Where {$_ -notmatch '-convert\.avi$'})
foreach ($file in $files)
$newFileName = $file.Fullname -replace '\.avi$','-convert.avi'
& $handbrake -i $file.FullName -o $newFileName --preset "Xbox 360"
if ($LastExitCode -ne 0)
Write-Warning "Error converting $($file.FullName)"
write-Warning "File $($file.FullName) Previously Converted"

Sorry about the formatting...
September 30, 2009 0:57
Sorry, slight typo above: should be if(![System.IO.File]::Exists($newFileName)...
December 17, 2009 18:18
I've been meaning to ask this question for a few weeks now... I've got a process setup on my home server that runs every 10 minutes looking for new files to encode. Finding none, it exits out. If it finds new files, it converts/encodes and then sends me an email to let me know its done and where to find the new files. Good stuff. However, the one thing I don't account for is if a file is still being copied to the folder when the script runs. This hasn't caused any problems yet, but I'm hoping that with PS there is a better way.

So, finally my question: can PowerShell tell that the file is still being copied to the directory (the file is incomplete), and ignore it?
February 08, 2010 21:15

Thank you for posting scripts in various languages. Scriptability is better compared to manually handling each file, one at a time.

I am currently in need of biterscripting scripts for handling media files. There are some scripts at but noone handle media files.

Can you post some biterscripts when you get a chance ? Will be very useful. Thanks.


Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.