Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for encoding with libx265 and hevc_nvenc #1433

Merged
merged 2 commits into from Aug 19, 2019
Merged

Add support for encoding with libx265 and hevc_nvenc #1433

merged 2 commits into from Aug 19, 2019

Conversation

fhriley
Copy link
Contributor

@fhriley fhriley commented Jun 1, 2019

Changes

This implements encoding support for h265 using libx265 or hevc_nvenc. Note that I did not implement it for other hardware encoders because I don't know enough about them, and I do not have that hardware. Also note that this will require changes in clients to actually request h265.

Issues

Fix #1432.

{"mediacodec", "h264_mediacodec"},
{"vaapi", "h264_vaapi"}
{"qsv", hwEncoder + "_qsv"},
{hwEncoder + "_qsv", hwEncoder + "_qsv"},
Copy link
Member

@EraYaN EraYaN Jun 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are there these _qsv maps doubled? Can we remove those? And that _v4l2m2m one also maps to itself. Should probably be a default value or something.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are there these _qsv maps doubled? Can we remove those?

I'm assuming the original author wanted both those values to map to the correct hw encoder. I think a refactor and using enums would answer/solve these questions (see my response in your other discussion).

And that _v4l2m2m one also maps to itself. Should probably be a default value or something.

I'm not sure I understand as I don't see a problem here. Presumably the mapping to itself is the correct action so that we don't have to do any special casing in the code below that uses the map.

@@ -119,6 +127,11 @@ public string GetVideoEncoder(EncodingJobInfo state, EncodingOptions encodingOpt

if (!string.IsNullOrEmpty(codec))
{
if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase) ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All these strings, h265, hevc, 265 and all the others used through out the code, should probably be enums or something.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely agree. I've never seen so many string comparisons in a chunk of code in my life. I initially went down the road of creating enums, but I quickly realized how much code this was going to touch so I changed my mind. I believe that change should go in its own Issue and PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm gonna give you a little tip... enums are a bad idea... Take it or leave it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate? It seems like codecs for example internally in ffmpeg are already essentially an enumeration, besides they do not change all that often. And for serialization you can specify the string values if you do not want to deal with numbers (codec IDs for example) in your JSON bodies.

@anthonylavado anthonylavado requested a review from a team June 4, 2019 15:46
@DrPandemic
Copy link
Contributor

What would be the easiest way of testing this PR?

@fhriley
Copy link
Contributor Author

fhriley commented Jun 14, 2019

What would be the easiest way of testing this PR?

I tested it by doing the following:

  1. Open the developer tools in Chrome
  2. Play a file on the jellyfin web interface that will require transcoding
  3. Grab the URL of the video stream
  4. Change all the h264 options to h265
  5. Use VLC and "open network" with the above URL.
  6. Verify it plays and also that the media information is hevc
  7. At the same time, use nvidia-smi to verify it is transcoding on the GPU

An example URL that I tested:

https://jellyfin.<redacted>.com/emby/videos/06890f52-7dbe-c2a7-60fe-4dd88a8ab6fa/hls1/main/0.ts?DeviceId=TW96aWxsYS81LjAgKE1hY2ludG9zaDsgSW50ZWwgTWFjIE9TIFggMTBfMTRfNCkgQXBwbGVXZWJLaXQvNTM3LjM2IChLSFRNTCwgbGlrZSBHZWNrbykgQ2hyb21lLzc0LjAuMzcyOS4xMzEgU2FmYXJpLzUzNy4zNnwxNTU4Nzk2Njc1NTg0&MediaSourceId=06890f527dbec2a760fe4dd88a8ab6fa&VideoCodec=h265&AudioCodec=mp3,aac&AudioStreamIndex=1&VideoBitrate=2000000&AudioBitrate=384000&PlaySessionId=dedb51012aa44ef1b1385dbd0bbc48cc&api_key=<redacted>&TranscodingMaxAudioChannels=2&RequireAvc=false&Tag=870288a2ba397d0faa3c305e9a9a7e26&SegmentContainer=ts&MinSegments=2&BreakOnNonKeyFrames=True&h265-profile=main&h265-level=51

This results in the following ffmpeg command:

/usr/local/bin/ffmpeg -c:v hevc_cuvid -resize 720x404 -i file:"/media/movies/Captain Marvel (2019)/Captain Marvel (2019) [Remux-2160p HEVC TrueHD Atmos 7.1 HDR].mkv" -map_metadata -1 -map_chapters -1 -threads 0 -map 0:0 -map 0:1 -map -0:s -codec:v:0 hevc_nvenc -pix_fmt yuv420p -preset default -b:v 2000000 -maxrate 2000000 -bufsize 4000000 -profile:v main -force_key_frames "expr:gte(t,n_forced*3)" -copyts -vsync -1 -codec:a:0 libmp3lame -ac 2 -ab 384000 -f segment -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -segment_time 3 -individual_header_trailer 0 -segment_format mpegts -segment_list_type m3u8 -segment_start_number 0 -segment_list "/cache/transcoding-temp/b304c64eae0b6b9f32cdb0d1b73675f2.m3u8" -y "/cache/transcoding-temp/b304c64eae0b6b9f32cdb0d1b73675f2%d.ts"

Note that to test libx265 you need a fairly powerful CPU and to test hevc_nvenc you need a turing GPU that supports HEVC.

@EraYaN
Copy link
Member

EraYaN commented Jun 19, 2019

NVENC for h265 will work on much older GPUs than a Turing. 10-bit support came with Pascal, but even some Maxwell cards will do 4K, and GM206 even 4:4:4.

Reference Table: https://developer.nvidia.com/nvidia-video-codec-sdk#NVENCFeatures

@fhriley
Copy link
Contributor Author

fhriley commented Jun 19, 2019

NVENC for h265 will work on much older GPUs than a Turing. 10-bit support came with Pascal, but even some Maxwell cards will do 4K, and GM206 even 4:4:4.

Reference Table: https://developer.nvidia.com/nvidia-video-codec-sdk#NVENCFeatures

I was thinking of HEVC with B frame support.

@cvium
Copy link
Member

cvium commented Jul 29, 2019

@fhriley I'm sorry this PR has gotten stale (this is our fault). Can you fix the merge conflicts?

@joshuaboniface
Copy link
Member

@fhriley I'm sorry this PR has gotten stale (this is our fault). Can you fix the merge conflicts?

@fhriley Just a ping on this one, are you able to quickly review and correct that merge conflict?

<<<<<<< h265
        protected virtual bool EnableOutputInSubFolder => false;

        protected readonly CultureInfo UsCulture = new CultureInfo("en-US");

        protected virtual string GetDefaultEncoderPreset()
        {
            return "superfast";
        }
=======
        protected virtual string GetDefaultH264Preset() => "superfast";
>>>>>>> master

The Contributors one should just have your name at the bottom of the existing list since it's been updated since.

@joshuaboniface joshuaboniface added the merge conflict Merge conflicts should be resolved before a merge label Aug 11, 2019
@joshuaboniface joshuaboniface changed the title Fix #1432. Add support for encoding with libx265 and hevc_nvenc. Add support for encoding with libx265 and hevc_nvenc Aug 11, 2019
Copy link
Member

@joshuaboniface joshuaboniface left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me, but review from @jellyfin/backend members would be appreciated.

@joshuaboniface joshuaboniface added Breaks Plugin API and removed merge conflict Merge conflicts should be resolved before a merge labels Aug 19, 2019
@joshuaboniface joshuaboniface merged commit 1bce9a8 into jellyfin:master Aug 19, 2019
@anthonylavado anthonylavado added this to Done in Release 10.4.0 Sep 2, 2019
}

private string GetH264OrH265Encoder(string defaultEncoder, string hwEncoder, EncodingJobInfo state, EncodingOptions encodingOptions)
{
// Only use alternative encoders for video files.
// When using concat with folder rips, if the mfx session fails to initialize, ffmpeg will be stuck retrying and will not exit gracefully
// Since transcoding of folder rips is expiremental anyway, it's not worth adding additional variables such as this.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jellyfin fails to user Hardware accleration when trying to stream a BluRay Folder. THis needs to be fixed here.

@Spamm00r
Copy link

Hi,

thanks for adding hevc support to jellyfin. That is really an helpful feature for me and many others with limited upload speeds.

I can confirm that the method works as described by @fhriley grabbing the URL and using vlc.

Unfortunately there is no setting in Jellyfin to avoid to having to use external programs to make Jellyfin stream in HEVC.

Also trying to change the h264 setting in that url on the fly with an browser addon for example fails in jellyfin with the Error: #2803

In that case the error is probably valid because the browser may not support HEVC decoding.

Please add a solution to tell jellyfin to stream using HEVC. Maybe using an external player like vlc, so that we don't have to use the hack method to force Jellyfin to play HEVC.

Also I might add, that Jellyfin fails to use Hardware acceleration when trying to stream a Bluray FOlder.

Thanks for adding this feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
No open projects
Development

Successfully merging this pull request may close these issues.

Add support for transcoding using libx265 and hevc_nvenc
7 participants