svt / encore

Transcode media files in an epic manner
European Union Public License 1.2
273 stars 25 forks source link

Does Encore support GPUs? #20

Closed jd7352 closed 10 months ago

jd7352 commented 2 years ago

How can I make Encore benefit from GPU?

zaki699 commented 11 months ago

Hi @jd7352,

You have to compile FFMPEG with CUBA codecs for Nvidia and change the code from encore-common. For example, with CUBA you will no longer used libx265 or libx264 but the proprietary nvidia codecs. Also I'll suggest to use the HW scaler and decoder from Nvidia as well to enjoy all the benefits of the GPU.

jd7352 commented 10 months ago

Hi @jd7352,

You have to compile FFMPEG with CUBA codecs for Nvidia and change the code from encore-common. For example, with CUBA you will no longer used libx265 or libx264 but the proprietary nvidia codecs. Also I'll suggest to use the HW scaler and decoder from Nvidia as well to enjoy all the benefits of the GPU.

This is great. I hope I can see your sharing in the future.

zaki699 commented 10 months ago

Hi @jd7352,

Let me know if you want me to share a code that will allow you to use HW decoding, HW scaling and HW encoding.

I'll suggest you to check this page and see what are the pro and con of using HW decoding. Personally I'll recommend you to use SW decoding if you have a good machine and keep the GPU for the HW scaling and encoding.

To give you some hint about the code :

You have to create a class NVENCEncode under the package se.svt.oss.encore.model.profile in the encore-common module. This class has to use the abstract class X26XEncode.

`// SPDX-FileCopyrightText: 2020 Sveriges Television AB // // SPDX-License-Identifier: EUPL-1.2

package se.svt.oss.encore.model.profile

import com.fasterxml.jackson.annotation.JsonProperty import se.svt.oss.encore.model.input.DEFAULT_VIDEO_LABEL

data class NVENCEncode( override val width: Int?, override val height: Int?, override val twoPass: Boolean, @JsonProperty("params") override val ffmpegParams: LinkedHashMap<String, String> = linkedMapOf(), @JsonProperty("nvidia-params") override val codecParams: LinkedHashMap<String, String> = linkedMapOf(), override val filters: List = emptyList(), override val audioEncode: AudioEncoder? = null, override val audioEncodes: List = emptyList(), override val suffix: String, override val format: String = "mp4", override val inputLabel: String = DEFAULT_VIDEO_LABEL ) : X26XEncode() { override val codecParamName: String get() = "" override val codec: String get() = "h264_nvenc" }`

Register the class to the output produce : se.svt.oss.encore.model.profile.OutputProducer

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonSubTypes( JsonSubTypes.Type(value = AudioEncode::class, name = "AudioEncode"), JsonSubTypes.Type(value = SimpleAudioEncode::class, name = "SimpleAudioEncode"), JsonSubTypes.Type(value = X264Encode::class, name = "X264Encode"), JsonSubTypes.Type(value = X265Encode::class, name = "X265Encode"), JsonSubTypes.Type(value = X265Encode::class, name = "NVENCEncode"), JsonSubTypes.Type(value = GenericVideoEncode::class, name = "VideoEncode"), JsonSubTypes.Type(value = ThumbnailEncode::class, name = "ThumbnailEncode"), JsonSubTypes.Type(value = ThumbnailMapEncode::class, name = "ThumbnailMapEncode") )

Then the commandBuilder class: se.svt.oss.encore.process.CommandBuilder L164 / L175

private fun inputParams(inputs: List<Input>): List<String> { val readDuration = encoreJob.duration?.let { it + (encoreJob.seekTo ?: 0.0) } return listOf( "ffmpeg", "-hide_banner", "-loglevel", "+level", "-hwaccel cuda", "-hwaccel_output_format cuda", "-y" ) + inputs.inputParams(readDuration) }

and for the HW scaling: se.svt.oss.encore.model.profile.VideoEncode L86

Replace: videoFilters.add("scale=$scaleToWidth:$scaleToHeight:force_original_aspect_ratio=decrease:force_divisible_by=2")

with: videoFilters.add("scale_npp=$scaleToWidth:$scaleToHeight")

I did not try the code but it will certainly work well minus a few differences from Nvidia version

Regards,

Zaki