Streaming DVDs to the Xbox 360 using MCE
DVDs and DVD players are everywhere. this works fine if you're a luddite and dont mind shuttling DVDs back and forth using the sneakernet. the problem is DVDs are not supported in the extender model (e.g. Xbox 360s connecting to an MCE server). i.e. all i want to do is set my MCE DVD Changer up on an MCE machine, and then be able to stream that DVD content to any Xbox 360 in the house. this article will detail my attempt to write an app for streaming DVDs from an MCE server to Xbox 360s.
NOTE the result ends up only partially working and is not ready for general use. this project was bogging me down so i'm pushing it out half baked to work on other stuff
2 transcoders with some level of DVD and Xbox 360 support are Transcode360 and WebGuide
1) Transcode 360 came out about a month after the /mceDivX360 article. it used a different programming model and quickly replaced mceDivX360 as the transcoder of choice (exactly what i hoped would happen, because i hate supporting software). now it has been integrated into MyMovies. the recent builds use Mencoder or VLC to perform the actual transcoding. so it works by allowing a user to select a video file or DVD, it gathers some data about the video/DVD, constructs a command line for calling Mencoder/VLC, calls the transcoder to convert the video/DVD into MPEG-2, and then plays that file on the Xbox 360. DVDs are already MPEG-2 (VOBs are a wrapper around MPEG-2 streams), so it doesnt transcode the audio or video streams. instead, it just pulls out the raw streams and puts a new container around them. this ends up being much faster than actual transcoding. so dumping an entire DVD might take 10 to 20 minutes. for CSS encrypted DVDs, Mencoder (i think VLC does too?) uses libdvdcss to strip off the encryption ... this is also really fast. a problem with Transcode 360 is skipping. it starts streaming the video file to the 360 immediately, while its still being transcoded. sometimes as its playing, it will skip forward some # of minutes or to the end of the file and stop playback. my guess is that this is being caused by reading from the file while its being written to. MS gets around this with LiveTV by using a StreamBufferSink. the problem is there doesnt seem to be a way to get the Mencoder output into a StreamBufferSink. but i do really like how efficient this method is, such that a single MCE server could support DVD streaming to multiple 360s.
2) WebGuide started out extending a users MCE guide through a web server so that you could schedule TV recordings while you were away from home. it evolved to allow you to view your content while you are away, and the most recent build has Xbox 360 support. i haven't used WebGuide ... but i took a look at how it streams DVDs. believe it or not, i actually mocked up an app to transcode DVDs using an identical method about 1 week before the first beta was put out. it works by playing the DVD on an MCE stream server, and then transcoding that on the fly to be streamed to the Xbox 360. it does this using DirectShow and the DvdNavigator filter. the DvdNavigator handles reading and playing a DVD, user input from mouse clicks/keyboard/remote control, and events from DVD playback. i like this method in that it doesnt have to worry about CSS at all, because the DVD is actually being played. also, this method allows full menu support. also like how a user can select what chapter they want to play. the part i dont like is its CPU intensive to play and transcode a DVD at the same time, and quality is reduced.
for the app, i wanted to use the parts that i liked from both methods above
for the UI, i chose XBAP, because i wanted to crank this out quick. more interested in getting media to play than making the app look the best. because the point is to get DVD playback to occur ... to watch the DVD, not to watch full fidelity button animations :)
for DVD support, the goal was to support MCE changers, ISO files, and ripped DVD directories (e.g. DVD Library). 1) MCE Changers are easy, because the MCE SDK provides an API. the tricky parts are that you have to poll the DVD changer when populating the list of discs that are loaded. also, you have to lock the DVD changer to keep other apps from interfering, which involves continually pinging its IsLocked property. an unexpected problem is that MediaCenter Extender sessions (MCX#) dont seem to have permission to read the contents of DVD drives. so when the app executes the process to transcode the app, that process will have to run as a user account with increased permissions. because of this, i should have broken out the transcoding part to run as a service ... but i didnt. 2) ISO files are the next step. this involves having the app execute a command line process to an ISO loader like Daemon Tools or Virtual CloneDrive. tried Daemon Tools first, but had an issue with it popping up a window to ask for permission. popping up a window within MediaCenter plugins is bad ... and will either crash or lock your app, or crash the entire MCE shell (its not very robust). Virtual CloneDrive did not open a window, so thats what it works with now. 3) ripped DVD directories didnt require any special work whatsoever, and the MCX# user account could work against it without any additional security privileges.
the pic above shows an MCE changer, 2 rip directories, and a standard DVD drive
if you just read the raw files from a DVD, you'll see .ifo, .bup, and .vob files. .ifo files are metadata for how the content should be played. .bup files are backup of .ifo files, in case you scratch them. .vob files are the actual content. since the Xbox 360 can play MPEG-2 through MCE, if you have a VOB file (without CSS), then it might be able to play that file directly. so the app lets you click on a VOB file to play it without any transcoding or ripping at all, it just calls PlayMedia() on it. if you call PlayMedia() on VOBs with CSS, they might play, but the video will be choppy. and for some VOB files, it will crash the app or MCE ... MCE is way too fragile. related, MCE will sometime crash when its trying to generate thumbnails for video files and it hits a codec it doesnt like. so this app is text based, which also makes it really quick on extenders. also, MCE will not list video files for extensions it does not know (e.g. flv). this app checks for the file extensions that i have DirectShow codecs installed for, and it displays them all. i'll end up using that feature on my MCE machine thats connected directly to a TV, because the app has access to all DirectShow filters on the machine. for extender sessions i should change it to only display files that are extender friendly.
shows the file listing of a VIDEO_TS directory on a DVD. the VOBs show their size in megabytes
the next level of DVD reading involves using the DvdNavigator. this will let you find the DiscId, number of titles/chapters, audio languages, subtitles, etc... DVDs are made up of video streams, audio streams, and subtitles. instead of using the actual DVDs menu, you can generate your own menu to show the available titles, what languages it has dubs for, as well as what languages it has subtitles for. this app shows which titles/chapters are available, and you can specify what audio/subtitle language you want in a config file. i'd like to update it so that audio/subtitle can be chosen using the remote. the part that sucks about DvdNavigator is that it doesnt tell you the playtime of a Title or Chapter until the DVD is actually playing. the same goes for getting angle info. had some code working that would start playing the DVD in the background and then grab the play time for each title and whether it had multiple angles. ended up taking this out because playing the DVD was slow and involved respecting UOPs (User OPerations). example UOPs are having to sit through the FBI warning or trailers for other DVDs. added in logic to wait for the UOPs, but there were some DVDs that it still got stuck on, so i took it out (i'll have to get that working again to support multiple angles). an alternate method to get play times for Titles/Chapters is DVD XML (see DvdXml.com). DvdXml is an XML format which provides metadata about a DVD. it includes such items as name, cover image, title names and duration, actors, genre, description, etc... if you use the DVD Library function in Vista, then it has already used DVD XML to retrieve additional METADATA XML for your ripped titles. so the app uses the DiscId to try and find the associated METADATA XML file on your file system, and then it uses that data to provide more info to the user. if the rip directory doesnt already have a DVD XML file, it will create a basic one and save it to the directory.
for more fun, the ffdshow codec was popping up a dialog here during the construction of the DvdNavigator graph. when developing on the desktop, ffdshow would popup a dialog asking if i wanted to use ffdshow with the app or not. so i just clicked on that dialog and told it not to bug me anymore. but the problem is i couldnt dismiss this dialog in an extender session ... which would crash my app. it ignored my previous setting, because an extender runs as a different user. had to add a bit of code in to set a registry flag to not open the dialog before the DvdNavigator graph is constructed. also, when i started out creating the DvdNavigator, i didnt pass the NOVPE flag to keep it from rendering on a computer screen. without this flag, my app was crashing saying that it was 'Not Responding'. ends up that it was responding, but the real problem was that a window was being created behinds the scene.
mapping cached METADATA info to DVD titles and displaying cover art
now the app can pretty much see all the DVD content, now its time to try and actually play a DVD. so i needed to decide which method to use. started out with the DirectShow DvdNavigator transcode-on-the-fly approach. since i'd already mocked this up, the goal was to try and reduce the CPU usage and increase the quality. the obvious approach here is hardware encoding. got a hold of an AdsTech InstantVideo To-Go, which is a hardware MP4 encoder ... that has DirectShow filters! thought that was going to work beautifully, the problem is that i could not hack its configuration files to support widescreen DVD formats, nor could i figure out how to wire up its DirectShow filter in my own app. the other hope was that i could get access to the MPEG-2 encoder on MCE TV tuners. but that wont work because the MPEG-2 encoders only work with external analog content. it doesnt provide a way for me to pipe content to it over USB, have it hardware encode it, and then pipe the result back over USB. tried to figure out if i could use DirectShow to strip the CSS, and then just pull out the raw streams and put it into an MPEG-2 wrapper. could probably get that to work if there was a DirectShow filter that wrapped libdvdcss? if i could get that to work, then it would also have the added benefit of being able to dump the output into a StreamBufferSink; which might fix the stutter problem Transcode360 has. never written a DirectShow filter before, and because of the MPAA, there is no way a libdvdcss filter would be my first. couldnt think of any other options, so i decided to try the Mencoder route ... which i hadnt ever played with.
to use Mencoder involves building up a set of command line arguments and then running Mencoder in a separate process. so the app starts up a separate thread which creates the Mencoder process and then has child threads for reading StandardOutput and StandardError from that process. it does some minimal processing to determine its progress and fires off events that allows the plugin to display what's happening. NOTE reading Standard Out/Err has to occur on a separate thread, otherwise the plugin will crash with the obligatory 'Not Responding' message. also, to avoid the stutter problem, i decided that the app would not being playback until Mencoder was done executing.
displaying title info and the Mencoder dump in the background. the red Title means it has 8 chapters
started out wading through all its command line options for Mencoder. found the flags to extract the audio and video streams and then rewrap with an MPEG-2 container. initial testing was on a Sealab DVD rip ... and it worked!
"C:\Program Files\mplayer\mencoder.exe" -v -oac copy -of mpeg -mpegopts format=dvd -o "C:\DVD\output.mpg" -ovc copy dvd://7 -dvd-device "G:\...\VIDEO_TS"
but that happiness was short lived, because i tried it on The Punisher next, and the audio was out of sync. looking at the command line dump showed that frames were being skipped, so i added in the -noskip flag ... and that worked.
then i tried Resident Evil ... and Milla was speaking French. so i added in the audio language and subtitle language settings : −alang en -slang en
next up was X-Men 2. that failed after 10 minutes saying "Too many audio packets in the buffer". this seemed to be because the DVD was telecine? tried the following flags to fix that : -ovc lavc -ofps 24000/1001. this did better but it ended up encoding for too long and when it played the scenes were out of order ... although the audio was always in sync.
kept trying other flags such as : -vf pullup,softskip but i haven't worked out how to make it work properly with all DVDs ... which is the goal. anyway, i ran out of time, so this part still needs work.
showing the Mencoder dump and overlaying the # of minutes that have been processed
there is an XML file that is used for configuration, an example is below
this article details some of the different ways i've been playing around with getting DVDs to the Xbox 360. for DVD coverage, its where i wanted to get to : MCE DVD Changer, ISOs, rip directories, loose VOBs. DVD metadata is almost there, but it needs to be reworked to reliably get title/chapter duration and angle info. but it falls apart when using Mencoder to dump the streams to MPEG-2. it might be fixed by simply figuring out the appropriate command line arguments to pass to Mencoder, or by switching to VLC. ultimately, i think that using DvdNavigator to transcode on the fly is the more reliable approach with the added benefit of being able to dump to a StreamBufferSink for simultaneous reading and writing ... but i dont think this approach will really take off until a hardware transcoder can be added to the graph to improve quality and reduce CPU usage.
here is the C# source code
going to set this to the side for a while. might revisit this later if i find a better encoder for stripping the raw streams from a DVD or can get a hardware transcoder to work.
probably a UMPC + MCE app. later