Live TV MPEG2 Direct Stream / Deinterlacing to 60fps

ED: This analysis was somewhat off, but, please see my latest findings here:

Long story short, as of PMS 1.22.2.4276, Plex finally appears to be trying to get MPEG2 Live TV to work. Thanks! But there are some pitfalls right now to the point where it’s not really usable (details in the thread). That said, I have written a wrapper for PMS for Windows that tells the Plex Transcoder to deinterlace at full rather than half-rate, and this actually works well! I’m not sure if I’ll release the code anywhere as it’s kind of janky, but that’s not set in stone/if there’s interest I could. (On other platforms, such a wrapper is much easier to implement.)

My original post follows below.

Original title: Bug: deinterlace live TV to 60fps on Roku, not 30fps (already done for DVR)
Server Version#: 1.21.1.3830
Player Version#: 6.7.4.6764-abf6bf3df-Plex

A while ago I noticed that whenever I try to watch live 1080i content (so mainly stuff I’ve got from live TV), the material is force-deinterlaced before viewing. This would be fine except that whatever deinterlacing setting Plex uses throws out half the frames, thus turning e.g. a 1080i60 feed into 1080p30. While this is passably OK for a lot of 1080i content out there, particularly stuff that’s just been telecined from a progressive source, it makes sports look choppy and terrible–which makes sense, because you’re throwing out half of the temporal resolution…

My ‘solution’ to this was to enable ‘Force’ under Direct Play, thus getting the original 1080i MPEG2 stream untouched. Unfortunately, this absolutely breaks seeking, at least on Rokus.

I have not used ffmpeg to deinterlace but it beggars belief that it forces you to throw out half the frames like this. 1080p60 is not a huge ask performance-wise for today’s modern media players, even ones that aren’t TOTL. Keeping all the frames should not result in a significantly larger file size and nor would it result in a performance hit on the server side, not on modern machines. And even if these are still concerns, you could allow users to enable or disable this under advanced settings.

Please take this under consideration. Otherwise Plex users who want to watch live sports from an interlaced source are left having to sacrifice seeking ability, or else are left having to replace their client devices entirely. It is best practice and should not require much effort given it’s just an encoding parameter.

There is a readily available alternative: if you absolutely insist on deinterlacing to half-temporal rates when transcoding like this, then at minimum can you guys just tweak whatever Direct Stream so that it actually works on Live TV? Because right now the calculus appears to be: Live TV —> force h264, regardless of client support for mpeg2 → force deinterlace to 30, not 60. But for DVR, or anything else, the MPEG2 enabling flag is respected, and the material appears to be remuxed unmolested (listed as ‘copy’). This would not solve problems for people who are bandwidth-limited, since any transcode appears to force a deinterlace that throws out half the frames. At minimum though, it would allow those of us fortunate enough to have it and local wired users to watch MPEG2 interlaced Live TV without compromises. In truth, there’s no reason not to do both: deinterlace without compromise, and respect MPEG2 playback capabilities for Live TV when clients advertise it.

FWIW, I enabled verbose logging, and a request (X-Plex-Client-Profile-Extra) for a recorded TV stream appears to be identical to a request for a Live TV stream in terms of transcode options, so prima-facie this doesn’t appear to be a client-side issue.

Live TV:

Dec 19, 2020 04:37:05.308 [8288] VERBOSE - * X-Plex-Client-Profile-Extra => append-transcode-target-audio-codec(type=videoProfile&context=streaming&protocol=hls&audioCodec=ac3)+add-limitation(scope=videoAudioCodec&scopeName=ac3&type=upperBound&name=audio.channels&value=6&isRequired=false)+append-transcode-target-audio-codec(type=videoProfile&context=streaming&protocol=hls&audioCodec=eac3)+add-limitation(scope=videoAudioCodec&scopeName=eac3&type=upperBound&name=audio.channels&value=8&isRequired=false)+append-transcode-target-codec(type=videoProfile&context=streaming&protocol=hls&videoCodec=mpeg2video)+add-limitation(scope=videoTranscodeTarget&scopeName=hevc&scopeType=videoCodec&context=streaming&protocol=hls&type=match&name=video.colorTrc&list=bt709|bt470m|bt470bg|smpte170m|smpte240m|bt2020-10|bt2020-10&isRequired=false)+append-transcode-target-codec(type=videoProfile&context=streaming&protocol=hls&videoCodec=hevc)+add-limitation(scope=videoCodec&scopeName=hevc&type=upperBound&name=video.bitDepth&value=10&isRequired=false)+add-limitation(scope=videoCodec&scopeName=h264&type=upperBound&name=video.level&value=51)+add-limitation(scope=videoCodec&scopeName=h264&type=upperBound&name=video.refFrames&value=8&replace=true)

DVR:

Dec 19, 2020 04:59:04.200 [3200] VERBOSE - * X-Plex-Client-Profile-Extra => append-transcode-target-audio-codec(type=videoProfile&context=streaming&protocol=hls&audioCodec=ac3)+add-limitation(scope=videoAudioCodec&scopeName=ac3&type=upperBound&name=audio.channels&value=6&isRequired=false)+append-transcode-target-audio-codec(type=videoProfile&context=streaming&protocol=hls&audioCodec=eac3)+add-limitation(scope=videoAudioCodec&scopeName=eac3&type=upperBound&name=audio.channels&value=8&isRequired=false)+append-transcode-target-codec(type=videoProfile&context=streaming&protocol=hls&videoCodec=mpeg2video)+add-limitation(scope=videoTranscodeTarget&scopeName=hevc&scopeType=videoCodec&context=streaming&protocol=hls&type=match&name=video.colorTrc&list=bt709|bt470m|bt470bg|smpte170m|smpte240m|bt2020-10|bt2020-10&isRequired=false)+append-transcode-target-codec(type=videoProfile&context=streaming&protocol=hls&videoCodec=hevc)+add-limitation(scope=videoCodec&scopeName=hevc&type=upperBound&name=video.bitDepth&value=10&isRequired=false)+add-limitation(scope=videoCodec&scopeName=h264&type=upperBound&name=video.level&value=51)+add-limitation(scope=videoCodec&scopeName=h264&type=upperBound&name=video.refFrames&value=8&replace=true)

Would be nice to get an acknowledgment here. If more information is needed, I cantry to provide it. If this is a wontfix, then a rationale would be appreciated (though honestly I can’t imagine what justification could be provided here particularly given that the behavior I am asking for is already the default in contexts other than Live TV).

Roku doesn’t support H.264/AVC level 4.2, which would be necessary for 1080p60.

Roku

Advanced Video Coding - Wikipedia

If the H.264 decoder doesn’t support 1080p60, that might indicate that the “legacy” half of the chipset, including MPEG2, just doesn’t have the bandwidth for it.

I know there were some Roku devices that supported outputting to a 1080i display, but I’m not sure any of them have support for interlaced content.

It’s possible the Roku just never expected to need to deal with it. It started as a “streaming” box, which never would have needed to deal with interlaced content. Curious if anybody knows more.

It wouldn’t work for live viewing, but you could postprocess your DVR content to 1080p60 and re-encode it to H.265/HEVC.

Hi, thanks for your response!

Except the thing is, we know it does have the bandwidth for it, right? As I said earlier, prerecorded content at 1080i60, if Direct Stream and MPEG2 are enabled within the Plex Roku app, is in fact remuxed to HLS without issue:

But for DVR, or anything else, the MPEG2 enabling flag is respected, and the material appears to be remuxed unmolested (listed as ‘copy’).

I also pointed out that even Live TV MPEG2 at 1080i60 works when Direct Play is forced, and the ts stream is just served straight up without being remuxed to HLS–but again, this has the very significant drawback of seeking not working at all:

My ‘solution’ to this was to enable ‘Force’ under Direct Play, thus getting the original 1080i MPEG2 stream untouched. Unfortunately, this absolutely breaks seeking , at least on Rokus.

So with respect to enabling MPEG2, this seems like a transcoding logic bug. Some path is being taken with recorded content that isn’t being taken with live content. They should change this behavior or at very minimum account for it publicly, though I have no idea what possible justification they could have for this. It looks like an oversight rather than an intentional decision.

As for this suggestion–

thanks for your concern and suggestion, but, I have enough WAN bandwidth at both locations where I watch recorded shows such that any postprocessing or reencoding is unnecessary the vast majority of the time.

It looked like you might have had the right idea re the transcoding problem…

…but, the very chart you link to itself allows for both L4.1 and L4.2. Further drilling it down by hardware itself:

Roku

and you quickly find that while legacy models like Roku 2s or 3s are limited to 1080p30, and can only do 60p for 720p content and lower, basically everything newer than that, including my Roku Premiere+ 4620X and Roku Ultra 4640X, do not have any such caveat. It’s plausible that there is some ‘Roku encoding profile’ that Plex came up with years ago, when Roku 2s and 3s proliferated, and was never updated or complicated, I guess. I really hope that isn’t what happened, but if it did, I’d encourage them to revisit.

Beyond this, the Plex Roku app specifically has a ‘Maximum h.264 Level’ setting that allows you to set the maximum H.264 profile anywhere from ‘4.0’ to ‘5.1’, along with an ‘Auto’ setting and Profile 4.1 appearing as ‘(Recommended)’–this even though only legacy Rokus appear to actually be limited to Profile 4.1 per the implications of the chart I just linked to. Anyway, the setting here appears not to affect transcoding targets–I had it set to 5.1 (I do have some content above 4.2) the entire time I’ve experienced this issue. The accompanying description for the setting in the app reads:

Choose the maximum H.264 level to be considered when deciding if the media will Direct Play, Direct Stream, or Transcode.

This seems to imply that this just sets a maximum for native H.264 content. If the encoding profile for an entire class of devices precludes transcoding above 4.1, this does not override. But they should consider allowing it do so or adding another such setting that does, if they don’t revisit and/or update their device encoding profiles entirely.

All that said, even if you were right about H.264 profiles that Rokus support–and this doesn’t seem? to be supported by their own docs–that wouldn’t explain why remuxing/copying 1080i60 MPEG2 content is enabled in literally every case except for Live TV, which is when the lion’s share of people will ever encounter such content to begin with. I really hope they address this at least, though I’d also appreciate some server-side experimental override that enabled full-rate rather than half-rate deinterlacing when transcoding, or maybe a client-side override for maximum H.264 level which accomplishes the same.

Failing that, I’ve been wondering if I could manually implement all of this. There is a thread I found the other day where you and some others appear to do just such a thing for audio:

Feature request: use ffmpeg's `-ac` flag for downmixing

but I don’t really understand how it is intercepting these commands, whether it is feasible for video transcoder settings as well (particularly on a Win7 box), or which settings are causing half-rate deinterlacing (though from your response here, I’d hazard that it’d be the target Level) or precluding a straight remux from being done for Live TV MPEG2.

1 Like

I’m looking at the ffmpeg docs, and apparently it has a few built-in deinterlacing filters to choose from (I am not really familiar with ffmpeg, and mainly use AviSynth and 3rd party filters for it for my own encodes). But it’s not clear to me which of these is used by the Plex Transcoder. (I’m also not sure how to force-call a wrapper script of the type mentioned in that thread).

You’re right and I’m apparently insane.

What has me most concerned - about myself - is that I opened that Roku link to see if it said anything about interlaced specifically, and to confirm the Level officially supported. And although I’ve seen it decode higher Levels, somehow I still read it as 4.1.

And I haven’t even had any eggnog. But I’m going to have some now and question my reading comprehension skills.

I misunderstood what you were saying about the changed behavior in Plex in different scenarios.

I might guess that transcoding is required for Live or in-progress recordings because the file isn’t complete and thus can’t be direct-played or direct-streamed.

Still, it could technically preserve interlacing. My guess is that it doesn’t because the Plex Transcoder wants to produce very compatible output.

I’m annoyed about being a bonehead and am going to noodle about this.

1 Like

Reviewing the request sent by the Roku above, it seems like it is telling it that its max video level is 5.1 already. But I guess, again, that this is simply not taken into account, or that deinterlacing when transcoding is just always done at half-rate regardless of the target level. I don’t actually know that this is true, I need to try other clients.

Which Roku, out of curiosity?

lol it’s cool, i probably could have written it more clearly. And I do appreciate that someone actually chimed in (I made four other threads detailing issues I’m facing and this is the only one anybody has engaged with at all) though I was a bit frustrated

This is interesting but it’s rather strange to me that you can’t just pipe the damn thing? I do have a few straight-up AVC channels, so that could be an easy way to check this.

Yeah, or just full rate rather than half-rate progressive for clients that support it :confused:

Look if someone other than me sticks with this it’s already a partial win. At this point I’m really interested in how use this wrapper to manipulate the encoder/remultiplexer rather than hoping that someone at Plex agrees the behavior should be changed and then changes it :confused:

1 Like

This is the 4640X Ultra. I can try it with the 4620X as well but the hardware is nearly identical.

Well, I just tried playing back Live TV sports (a rerun) using Plex for Windows. Unfortunately after a few minutes it just stopped of its own accord, similar to what is currently happening on Android TV, but that aside, it looked like it was serving 1080p60 given how the scrolling chyrons and sports motion looked like (I’m not sure how to check this literally in that app).
ETA: I am not confident in this assessment at all. I’m not sure where the debug info for this client is.

For what it’s worth, this issue persists. If there is a workaround involving manually setting parameters for the transcoder, the way there is in that audio thread, I’m not sure how to invoke it. I hope someone at Plex takes notice and comments on this at some point. (If there is a place to do formal bug reporting, I don’t know where it is.)

-Upon further testing it appears that half-rate deinterlacing is done blindly, regardless of the client used, as it is the default for the deinterlacer specified (yadif, unless using hardware-assisted decoding). The frame rate is also set manually later on in the command (in this case to 29.969999999999999, which is not really equivalent to 30000/1001 so I’m not sure why they’re doing this). In any case, I now have an idea of how this command could be modified for full-rate transcoding, at least when using the CPU to transcode.
-After an initial open-ended piping/remuxing session is begun, depending upon what decisions Plex makes about client support, a subsequent transcode session is begun a few seconds later (with a separate log).
-The initial pipe/remux session has the flag -noaccurate_seek. I suspect that volts was right about being able to remux a live mpeg2 stream vs a recorded one, though I’m not sure why this is the case.
-The Android client I’m using appears to support the piped/remuxed video, but the seek bar is outright disabled.
-The Roku client used to be able to play these if Direct Play was set to Force, but this is only intermittently respected now, and more often an h264 transcode is forced at half-rate. When “Force” is respected, seeking is highly dubious, sometimes working, sometimes causing the stream to restart from the beginning (which explains why seeking is disabled in Android and why they might not want to respect “Force”).
-The maximum h264 level set in e.g. a Roku or Android client is in fact passed to the transcoder (which is just a specialized build of ffmpeg).

Something appears to have changed with the latest beta, 1.22.2.4276. They’re now remuxing MPEG2 to a format that Rokus can use instead of forcing a transcode or passing along the raw stream. Hurray! Thank you for finally following up on this!

However, there appear to be problems. A specific McDonald’s commercial, on two separate occasions, caused playback to choke and screen to go blank for a bit, before proceeding to play back choppily, with the audio getting progressively more and more out of sync. My guess here based on dealing with this kind of video in the past is that the ac3 stream for the commercial has a different amount of channels from the program itself, and however the remux is being done, the client (Roku) spazzes out on encountering this. The situation is worse with 480i (SD) streams. The picture constantly drops out (and when drop out I mean totally, the TV stops receiving any picture for a second or two before ‘getting sync’ back) and when it comes back, plays back choppily, to the point of being unwatchable. (Turning off MPEG2 in the options avoids this). I find the format of these streams varies–sometimes they are pillarboxed, and sometimes they’re anamorphic (!) but both streams have trouble.

Separately–PMS no longer recognize that clients are, in fact, remote–it now appears to ignore the X-Forwarded-For header and now shows the local IP of my reverse proxy server for any remote client, instead of properly showing the IP address, as in the past.

That said, I have also (finally!) figured out how to modify the commands for the Plex Transcoder so that it deinterlaces at full rather than half-rate, and under Windows to boot. This is done as before–blindly, presuming that the clients can support it. It works so far on Roku, Android, a̶n̶d̶ ̶W̶i̶n̶d̶o̶w̶s̶(Windows client appears to choke on this on the one PC I tried it on). It does not appear to have much of an impact on encoder speed (ED: but perhaps enough that a disclaimer be included). I have not figured out how to get this working with GPU transcoders yet, as I need to read the documentation for Intel (I do not have an NVIDIA GPU in this machine and adding one is a chore) but in principle, if the option exists, then asking for 60fps could be done in the same manner. Note that I have done this NTSC-style framerates, but setting it up for PAL rates should not be difficult in principle.

Few updates–the Windows client appears to choke and stutter on 60fps created like this. Possibly because I’m giving the parameter 60000/1001 for fps instead of a decimal rounded off (59.939999999…), since native 720p60 content does not so choke. Intel QSV does not appear to have an option for deinterlacing to full-rate, and if there’s a way to deinterlace using yadif before handing off to qsv for encoding, I’m not sure how to invoke it: when I try, it crashes. I have not tried with Nvidia yet, either. While yadif is not extremely intensive at full-rate, it is not as free as I thought it was. That said, it should be included as an advanced option, perhaps named ‘high-quality deinterlace’ or something.

Can you share how you modified the commands to the transcoder? I want to deinterlace at full frame rate also!

I’ve found that whatever change was made to make Live TV MPEG2 seekable in Roku, it was either a fluke or it’s since been reverted. Also, having recently acquired an Apple TV, it seems like in that case, MPEG2 is seekable, but the Apple TV video player (the old and the new) deinterlaces at half-rate (incredibly). I’m assuming this is an Apple restriction but regardless, it’s incredibly silly; a single full-rate deinterlace should be child’s play for the A12, particularly since the comparatively underpowered Roku 4630X could do it. It’s a shame this appears to be on nobody’s radar and not prioritized at all.

In essence, what you do is what you think you have to do: write an intermediary program with the same name as the one being called that then modifies the commands it’s given and then calls the actual binary (which you’ve renamed or relocated beforehand). (There’s lots you can do with this; I am using this to crop and resize specific letterboxed SD channels for example.) This is kind of tricky to do in Windows and still have it work with Plex because forking in the same way unices can is not a thing, so any spawned process has a new PID that Plex is unaware of. The way I am doing it is OK but fails sometimes and I need to make revisions. Am not sure if I’ll ever make a public release and suspect the devs here would not appreciate it but similar things already exist (just not specifically for Windows).

and for the uninitiated? :smiley: