Programmatically Changing Refresh Rate on my HDTV

I recently got myself (as a present) a nice new Denon AVR 1910 AV Receiver, which has HDMI video switching. So I duly plugged my HTPC into one of the HDMI inputs and hooked my HDTV up to the HDMI monitor out. All was well, everything worked as it did before. That is after I’d spent a few hours setting the amp up.

Whilst fiddling around with my new toy, I switched the amp to a different HDMI video input and then back to the HTPC input. Whoa, what’s this black border around the whole picture?! I have a Toshiba 42WLT66 which is a 1080i panel, that means it’s got a native resolution of 1920×1080 (albeit only capable of interlaced video). So, I’ve got my PC configured to 1920×1080 @ 25Hz. But when I checked the video settings, it had defaulted back to 30 Hz, hence the black border.

I found that if I switched the amp on first and let it go through the startup routine, then switch the TV on and then the HTPC all was well. Anything other than that order and the HTPC defaulted to 30Hz, which was useless for my purposes. So, I’ve since spent a lot of time researching different ways of fixing the problem on the web. I even installed the latest ATI Catalyst drivers and Catalyst Control Centre, but that just made matter worse. The black border was present on all three refresh rate that my HDTV supports (25, 29 and 30Hz). System Restore came to my rescue.

So, I decided to write a little piece of software to reset the refresh rate. That, when combined with the MyPrograms plugin for MediaPortal, gives me a way of setting the HTPC back to 25Hz refresh rate via my remote control

So, here is how I did it…

Firstly I needed to use a few functions in user32.dll, so I created the following class…

class User32
{
    [DllImport("user32.dll")]
    public static extern int EnumDisplaySettings(string deviceName, int modeNum, ref DEVMODE devMode);

    [DllImport("user32.dll")]
    public static extern int ChangeDisplaySettings(ref DEVMODE devMode, int flags);

    public const int ENUM_CURRENT_SETTINGS = -1;
}

The User32 class needs the DEVMODE struct …

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct DEVMODE
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string dmDeviceName;

    public short dmSpecVersion;
    public short dmDriverVersion;
    public short dmSize;
    public short dmDriverExtra;
    public int dmFields;
    public int dmPositionX;
    public int dmPositionY;
    public int dmDisplayOrientation;
    public int dmDisplayFixedOutput;
    public short dmColor;
    public short dmDuplex;
    public short dmYResolution;
    public short dmTTOption;
    public short dmCollate;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string dmFormName;

    public short dmLogPixels;
    public short dmBitsPerPel;
    public int dmPelsWidth;
    public int dmPelsHeight;
    public int dmDisplayFlags;
    public int dmDisplayFrequency;
    public int dmICMMethod;
    public int dmICMIntent;
    public int dmMediaType;
    public int dmDitherType;
    public int dmReserved1;
    public int dmReserved2;
    public int dmPanningWidth;
    public int dmPanningHeight;

    public static DEVMODE Create()
    {
        DEVMODE dm = new DEVMODE();
        dm.dmDeviceName = new string(new char[32]);
        dm.dmFormName = new string(new char[32]);
        dm.dmSize = (short) Marshal.SizeOf(dm);
        return dm;
    }
}

Since all I wanted to do was to reset the refresh rate, I just created a console application …

static class Program
{
    [STAThread]
    static void Main(string[] args)
    {
        int refreshRate;

        if (args.Length == 0 || !int.TryParse(args[0], out refreshRate))
        {
            refreshRate = 25;
        }

        bool silent = args.Length > 1 && args[1].ToLower() == "silent";

        string deviceName = Screen.PrimaryScreen.DeviceName;
        if (!silent)
        {
            Console.WriteLine("Device Name = " + deviceName);
            Console.WriteLine("Press [Enter] to proceed, or any other key to abort");
        }
        if (silent || Console.ReadKey().Key == ConsoleKey.Enter)
        {
            DEVMODE dm = DEVMODE.Create();
            User32.EnumDisplaySettings(Screen.PrimaryScreen.DeviceName, User32.ENUM_CURRENT_SETTINGS, ref dm);

            if (!silent)
            {
                Console.WriteLine(string.Format("Press [Enter] to set refresh rate to {0}Hz, any other key to abort", refreshRate));
            }

            if (silent || Console.ReadKey().Key == ConsoleKey.Enter)
            {
                dm.dmDisplayFrequency = refreshRate;
                User32.ChangeDisplaySettings(ref dm, 0);
            }
        }
    }
}

The primary screen name is fetched …

string deviceName = Screen.PrimaryScreen.DeviceName;

The User32.EnumDisplaySettings is called in order to fill in the DEVMODE struct, as all I wanted to do was to change the refresh rate …

DEVMODE dm = DEVMODE.Create();
User32.EnumDisplaySettings(Screen.PrimaryScreen.DeviceName, User32.ENUM_CURRENT_SETTINGS, ref dm);

Next, I set the refresh rate to what I want and call User32.ChangeDisplaySettings …

dm.dmDisplayFrequency = refreshRate;
User32.ChangeDisplaySettings(ref dm, 0);

It works a treat in combination with the MyPrograms plugin for MediaPortal, with the command line of “25 silent”.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s