Consistent 24p on OpenPHT

Posted by Thoughts and Ramblings on Wednesday, August 23, 2017

For quite a while, I’ve been having issues with OpenELEC (OE) based devices detecting the 24p frame rate (23.976 frames per second) on my TV. Usually when I play something in 24p and the TV doesn’t switch into this mode, I will reboot the OE player and it would resolve the problem. Then after the TV is turned off and later turned back on, about 1/4 of the time, the problem would resurface. I’ve seen this behavior with both OpenPHT (and it’s predecessor Plex Home Theater) and Plex Media Player. I finally got annoyed enough with the situation that I decided to do something about it.

I read through the code to OpenPHT to see if there is anything that it may be doing wrong. I didn’t spot any issues but it does log enough data that I could piece together the current behavior. My TV has 41 resolution and rate modes detected by my Intel NUC (Haswell). 40 of these modes are natively detected and one was added by myself to support a 50Hz refresh rate at 1080p. I use this last mode for playing British content. Sometimes, OpenPHT would log that it only detected 35 modes and even sometimes that it detected 25. The 35 seemed to correspond to when it read the modes as the TV is being turned off and the 25 if it read the modes after the TV was already off. It fairly regularly read 35 modes when the TV was turned off but occasionally it would read the 25 (race condition). If it read 25, then the 1080p 23.976fps mode was not among them. It did not seem to read these modes during or after the TV was turned on. It reads these modes through a tool called xbmc-randr.

Then I noticed something interesting: If I ran xbmc-randr on the command-line myself while the TV was on and OpenPHT did not previously know about all 41 modes, then OpenPHT would often be notified of changes in the display and would read these modes itself. My suspicion is that by manually running xbmc-randr myself, it prompts the OS to reach the EDI modes, and having detected the changes, informs any consumers wishing to be informed of these changes. OpenPHT is definitely one such consumer. I only needed to account for the cases where it does not do the above actions by restarting the computer. This lead me to a solution:

I looked for a keyboard shortcut that I could repurpose to run a script which will itself call xbmc-randr. Since OpenPHT does have the ability to run arbitrary shell scripts, I configured my /storage/.plexht/userdata/keymaps/keyboard.xml with:

<keymap>
  <global>
    <keyboard>
      <return mod="ctrl,alt">System.Exec("/storage/ensureAllRates.py")</return>
      …
    </keyboard>
  </global>
  …
</keymap>

Then my /storage/ensureAllRates.py file contained:

#!/usr/bin/env python2

import re
import subprocess
import sys
import time

expectedCount = 41

def getRateCount():
  list = subprocess.check_output(["grep", "Output 'HDMI1' has", "/storage/.plexht/temp/plexhometheater.log"], universal_newlines=True).split("\n")
  if len(list) < 2:
    return -1

  line = list[-2]
  match = re.search(".*Output 'HDMI1' has (\\d+) modes", line)
  if not match:
    return -1

  return int(match.group(1))

if getRateCount() == expectedCount:
  sys.exit()

subprocess.check_output(["/usr/lib/plexht/xbmc-xrandr"])
time.sleep(2)
if getRateCount() == expectedCount:
  sys.exit()

subprocess.check_output(["shutdown", "-r", "now"])

(If you are running OpenPHT 1.8, I’ve noticed the path is different. You should adjust accordingly.)

Above I have configured ctrl-alt-return to run my script. When this keypress is sent, OpenPHT dutifully ran the it. Then, if OpenPHT got the full list of modes, everything that was the end of it. If it did not, the system was rebooted. Thus far, this script has always resulted in the 24p output mode being known and used when appropriate.

Lastly, I use a Logitech Harmony Hub for my remote needs. One of the features is it runs a series of scripts to switch to and from a device. I configured the script on switching to my OpenPHT player to send the Fullscreen command. Seeing as how this OpenPHT is always full screen, I figured this command is least likely to do anything already. Turns out, it sends 3 keyboard commands, of which none are bound to any action. The last was ctrl-alt-return which I now bound with my above keyboard override. This completed my setup to have this command run every time without any interaction by myself.