Okay, this is for everyone who has had problems viewing videos with Cxbx lately. I don't know how many of you are having problems with Cxbx's video playback lately, but I know I have... for a long time! Ever since I updated my video card drivers for my laptop (I have an NVIDIA GeForce 8400 GS Mobile 128MB) back in August, I noticed that Cxbx's video playback was broken. Even though my GPU supports DirectDraw's hardware accelerated overlay surfaces (or at least it claims to), it still never worked anymore! This was driving me crazy because it meant less screenshots to show you guys (it's great to have proof).
"So, what did you do to fix it?" Well, I made quite a few changes to get this working again (and a few extra changes to get it working right without problems for some games). The first thing I did was force Cxbx to update the overlay surface in software using a YUV -> RGB conversion (which Cxbx already did support). After initializing DirectDraw, Cxbx will check for hardware YUV overlay support. If it is detected, it will use the hardware mode automatically. If not, then it does the conversion in software and writes the pixels to the backbuffer. To disable it, I just commented out this in EmuD3D8.cpp: g_bSupportsYUY2 = true; While the hardware accelerated method was a good idea, it did have a few drawbacks which are just now beginning to surface. To further illustrate, I'll show the pros and cons of each:
1. Hardware YUV
- Automatically updates itself (no need to call D3DDevice::Present)
- Usually too fast! Can cause "robotic" audio
- Can cause crashes (Unreal Championship)
- Can't take screenshots easily
2. Software YUV
- More accurate speed wise (at least for me)
- Can take screenshots with print screen button
- More compatible
- Can be too slow depending on your hardware
- Does not update automatically (requires hack, but easily fixed)
A good idea would be to give the user the option to use hardware or software YUV overlay updates for maximum compatibility to the user's liking.
More on the "hacks" used to get this working properly. This was really easy to do. One thing I noticed was that when trying to play videos with Dead to Rights and PacMan Worlds 2 was that before playing the video, all the parameters would be NULL. So if there's no surface passed in for the first parameter, don't update the overlay or else you'll crash and burn. The second thing is that I noticed that when I disabled the hardware overlay flag, some videos would play and others still wouldn't show up. That's because the Xbox expects each frame to show up without the need to call D3DDevice::Present. So for every time that the overlay surface is updated and Present or Swap is not called, call Present after the overlay update. And as you can see above, the results were great!
One more benefit is that since the fact that most videos play at about 30 FPS, they will generally play at that frame rate, resulting in better sounding audio (still a bit choppy sometimes, but less robotic). So there you have it. I'll see to it that there's an option to use hardware and software overlays at your discretion so you won't go through the same problems I did.