123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- //nolint:goconst
- package transcoder
- import (
- "fmt"
- "os/exec"
- "strings"
- log "github.com/sirupsen/logrus"
- )
- // Codec represents a supported codec on the system.
- type Codec interface {
- Name() string
- DisplayName() string
- GlobalFlags() string
- PixelFormat() string
- ExtraArguments() string
- ExtraFilters() string
- VariantFlags(v *HLSVariant) string
- GetPresetForLevel(l int) string
- }
- var supportedCodecs = map[string]string{
- (&Libx264Codec{}).Name(): "libx264",
- (&OmxCodec{}).Name(): "omx",
- (&VaapiCodec{}).Name(): "vaapi",
- (&NvencCodec{}).Name(): "NVIDIA nvenc",
- }
- // Libx264Codec represents an instance of the Libx264 Codec.
- type Libx264Codec struct {
- }
- // Name returns the codec name.
- func (c *Libx264Codec) Name() string {
- return "libx264"
- }
- // DisplayName returns the human readable name of the codec.
- func (c *Libx264Codec) DisplayName() string {
- return "x264"
- }
- // GlobalFlags are the global flags used with this codec in the transcoder.
- func (c *Libx264Codec) GlobalFlags() string {
- return ""
- }
- // PixelFormat is the pixel format required for this codec.
- func (c *Libx264Codec) PixelFormat() string {
- return "yuv420p" //nolint:goconst
- }
- // ExtraArguments are the extra arguments used with this codec in the transcoder.
- func (c *Libx264Codec) ExtraArguments() string {
- return strings.Join([]string{
- "-tune", "zerolatency", // Option used for good for fast encoding and low-latency streaming (always includes iframes in each segment)
- }, " ")
- }
- // ExtraFilters are the extra filters required for this codec in the transcoder.
- func (c *Libx264Codec) ExtraFilters() string {
- return ""
- }
- // VariantFlags returns a string representing a single variant processed by this codec.
- func (c *Libx264Codec) VariantFlags(v *HLSVariant) string {
- return strings.Join([]string{
- fmt.Sprintf("-x264-params:v:%d \"scenecut=0:open_gop=0\"", v.index), // How often the encoder checks the bitrate in order to meet average/max values
- fmt.Sprintf("-bufsize:v:%d %dk", v.index, v.getBufferSize()),
- fmt.Sprintf("-profile:v:%d %s", v.index, "high"), // Encoding profile
- }, " ")
- }
- // GetPresetForLevel returns the string preset for this codec given an integer level.
- func (c *Libx264Codec) GetPresetForLevel(l int) string {
- presetMapping := []string{
- "ultrafast",
- "superfast",
- "veryfast",
- "faster",
- "fast",
- }
- if l >= len(presetMapping) {
- return "superfast" //nolint:goconst
- }
- return presetMapping[l]
- }
- // OmxCodec represents an instance of the Omx codec.
- type OmxCodec struct {
- }
- // Name returns the codec name.
- func (c *OmxCodec) Name() string {
- return "h264_omx"
- }
- // DisplayName returns the human readable name of the codec.
- func (c *OmxCodec) DisplayName() string {
- return "OpenMAX (omx)"
- }
- // GlobalFlags are the global flags used with this codec in the transcoder.
- func (c *OmxCodec) GlobalFlags() string {
- return ""
- }
- // PixelFormat is the pixel format required for this codec.
- func (c *OmxCodec) PixelFormat() string {
- return "yuv420p"
- }
- // ExtraArguments are the extra arguments used with this codec in the transcoder.
- func (c *OmxCodec) ExtraArguments() string {
- return strings.Join([]string{
- "-tune", "zerolatency", // Option used for good for fast encoding and low-latency streaming (always includes iframes in each segment)
- }, " ")
- }
- // ExtraFilters are the extra filters required for this codec in the transcoder.
- func (c *OmxCodec) ExtraFilters() string {
- return ""
- }
- // VariantFlags returns a string representing a single variant processed by this codec.
- func (c *OmxCodec) VariantFlags(v *HLSVariant) string {
- return ""
- }
- // GetPresetForLevel returns the string preset for this codec given an integer level.
- func (c *OmxCodec) GetPresetForLevel(l int) string {
- presetMapping := []string{
- "ultrafast",
- "superfast",
- "veryfast",
- "faster",
- "fast",
- }
- if l >= len(presetMapping) {
- return "superfast"
- }
- return presetMapping[l]
- }
- // VaapiCodec represents an instance of the Vaapi codec.
- type VaapiCodec struct {
- }
- // Name returns the codec name.
- func (c *VaapiCodec) Name() string {
- return "h264_vaapi"
- }
- // DisplayName returns the human readable name of the codec.
- func (c *VaapiCodec) DisplayName() string {
- return "VA-API"
- }
- // GlobalFlags are the global flags used with this codec in the transcoder.
- func (c *VaapiCodec) GlobalFlags() string {
- flags := []string{
- "-vaapi_device", "/dev/dri/renderD128",
- }
- return strings.Join(flags, " ")
- }
- // PixelFormat is the pixel format required for this codec.
- func (c *VaapiCodec) PixelFormat() string {
- return "vaapi_vld"
- }
- // ExtraFilters are the extra filters required for this codec in the transcoder.
- func (c *VaapiCodec) ExtraFilters() string {
- return "format=nv12,hwupload"
- }
- // ExtraArguments are the extra arguments used with this codec in the transcoder.
- func (c *VaapiCodec) ExtraArguments() string {
- return ""
- }
- // VariantFlags returns a string representing a single variant processed by this codec.
- func (c *VaapiCodec) VariantFlags(v *HLSVariant) string {
- return ""
- }
- // GetPresetForLevel returns the string preset for this codec given an integer level.
- func (c *VaapiCodec) GetPresetForLevel(l int) string {
- presetMapping := []string{
- "ultrafast",
- "superfast",
- "veryfast",
- "faster",
- "fast",
- }
- if l >= len(presetMapping) {
- return "superfast"
- }
- return presetMapping[l]
- }
- // NvencCodec represents an instance of the Nvenc Codec.
- type NvencCodec struct {
- }
- // Name returns the codec name.
- func (c *NvencCodec) Name() string {
- return "h264_nvenc"
- }
- // DisplayName returns the human readable name of the codec.
- func (c *NvencCodec) DisplayName() string {
- return "nvidia nvenc"
- }
- // GlobalFlags are the global flags used with this codec in the transcoder.
- func (c *NvencCodec) GlobalFlags() string {
- flags := []string{
- "-hwaccel cuda",
- }
- return strings.Join(flags, " ")
- }
- // PixelFormat is the pixel format required for this codec.
- func (c *NvencCodec) PixelFormat() string {
- return "yuv420p"
- }
- // ExtraArguments are the extra arguments used with this codec in the transcoder.
- func (c *NvencCodec) ExtraArguments() string {
- return ""
- }
- // ExtraFilters are the extra filters required for this codec in the transcoder.
- func (c *NvencCodec) ExtraFilters() string {
- return ""
- }
- // VariantFlags returns a string representing a single variant processed by this codec.
- func (c *NvencCodec) VariantFlags(v *HLSVariant) string {
- tuning := "ll" // low latency
- return fmt.Sprintf("-tune:v:%d %s", v.index, tuning)
- }
- // GetPresetForLevel returns the string preset for this codec given an integer level.
- func (c *NvencCodec) GetPresetForLevel(l int) string {
- presetMapping := []string{
- "p1",
- "p2",
- "p3",
- "p4",
- "p5",
- }
- if l >= len(presetMapping) {
- return "p3"
- }
- return presetMapping[l]
- }
- // QuicksyncCodec represents an instance of the Intel Quicksync Codec.
- type QuicksyncCodec struct {
- }
- // Name returns the codec name.
- func (c *QuicksyncCodec) Name() string {
- return "h264_qsv"
- }
- // DisplayName returns the human readable name of the codec.
- func (c *QuicksyncCodec) DisplayName() string {
- return "Intel QuickSync"
- }
- // GlobalFlags are the global flags used with this codec in the transcoder.
- func (c *QuicksyncCodec) GlobalFlags() string {
- return ""
- }
- // PixelFormat is the pixel format required for this codec.
- func (c *QuicksyncCodec) PixelFormat() string {
- return "nv12"
- }
- // ExtraArguments are the extra arguments used with this codec in the transcoder.
- func (c *QuicksyncCodec) ExtraArguments() string {
- return ""
- }
- // ExtraFilters are the extra filters required for this codec in the transcoder.
- func (c *QuicksyncCodec) ExtraFilters() string {
- return ""
- }
- // VariantFlags returns a string representing a single variant processed by this codec.
- func (c *QuicksyncCodec) VariantFlags(v *HLSVariant) string {
- return ""
- }
- // GetPresetForLevel returns the string preset for this codec given an integer level.
- func (c *QuicksyncCodec) GetPresetForLevel(l int) string {
- presetMapping := []string{
- "ultrafast",
- "superfast",
- "veryfast",
- "faster",
- "fast",
- }
- if l >= len(presetMapping) {
- return "superfast"
- }
- return presetMapping[l]
- }
- // Video4Linux represents an instance of the V4L Codec.
- type Video4Linux struct{}
- // Name returns the codec name.
- func (c *Video4Linux) Name() string {
- return "h264_v4l2m2m"
- }
- // DisplayName returns the human readable name of the codec.
- func (c *Video4Linux) DisplayName() string {
- return "Video4Linux"
- }
- // GlobalFlags are the global flags used with this codec in the transcoder.
- func (c *Video4Linux) GlobalFlags() string {
- return ""
- }
- // PixelFormat is the pixel format required for this codec.
- func (c *Video4Linux) PixelFormat() string {
- return "nv21"
- }
- // ExtraArguments are the extra arguments used with this codec in the transcoder.
- func (c *Video4Linux) ExtraArguments() string {
- return ""
- }
- // ExtraFilters are the extra filters required for this codec in the transcoder.
- func (c *Video4Linux) ExtraFilters() string {
- return ""
- }
- // VariantFlags returns a string representing a single variant processed by this codec.
- func (c *Video4Linux) VariantFlags(v *HLSVariant) string {
- return ""
- }
- // GetPresetForLevel returns the string preset for this codec given an integer level.
- func (c *Video4Linux) GetPresetForLevel(l int) string {
- presetMapping := []string{
- "ultrafast",
- "superfast",
- "veryfast",
- "faster",
- "fast",
- }
- if l >= len(presetMapping) {
- return "superfast"
- }
- return presetMapping[l]
- }
- // GetCodecs will return the supported codecs available on the system.
- func GetCodecs(ffmpegPath string) []string {
- codecs := make([]string, 0)
- cmd := exec.Command(ffmpegPath, "-encoders")
- out, err := cmd.CombinedOutput()
- if err != nil {
- log.Errorln(err)
- return codecs
- }
- response := string(out)
- lines := strings.Split(response, "\n")
- for _, line := range lines {
- if strings.Contains(line, "H.264") {
- fields := strings.Fields(line)
- codec := fields[1]
- if _, supported := supportedCodecs[codec]; supported {
- codecs = append(codecs, codec)
- }
- }
- }
- return codecs
- }
- func getCodec(name string) Codec {
- switch name {
- case (&NvencCodec{}).Name():
- return &NvencCodec{}
- case (&VaapiCodec{}).Name():
- return &VaapiCodec{}
- case (&QuicksyncCodec{}).Name():
- return &QuicksyncCodec{}
- case (&OmxCodec{}).Name():
- return &OmxCodec{}
- case (&Video4Linux{}).Name():
- return &Video4Linux{}
- default:
- return &Libx264Codec{}
- }
- }
|