From 6d14b011c45edc73f2dbed9eda3d5db964cd4fed Mon Sep 17 00:00:00 2001 From: aler9 <46489434+aler9@users.noreply.github.com> Date: Fri, 6 Jan 2023 16:48:35 +0100 Subject: [PATCH] hls muxer: improve generation of H265 codec parameters --- internal/hls/codecparameters.go | 98 ++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 2 deletions(-) diff --git a/internal/hls/codecparameters.go b/internal/hls/codecparameters.go index 4e4053de..cbc26538 100644 --- a/internal/hls/codecparameters.go +++ b/internal/hls/codecparameters.go @@ -2,6 +2,7 @@ package hls import ( "encoding/hex" + "fmt" "strconv" "strings" @@ -9,6 +10,93 @@ import ( "github.com/aler9/gortsplib/v2/pkg/format" ) +func encodeProfileSpace(v uint8) string { + switch v { + case 1: + return "A" + case 2: + return "B" + case 3: + return "C" + } + return "" +} + +func encodeCompatibilityFlag(v [32]bool) string { + var o uint32 + for i, b := range v { + if b { + o |= 1 << i + } + } + return fmt.Sprintf("%x", o) +} + +func encodeGeneralTierFlag(v uint8) string { + if v > 0 { + return "H" + } + return "L" +} + +func encodeGeneralConstraintIndicatorFlags(v *h265.SPS_ProfileTierLevel) string { + var ret []string + + var o1 uint8 + if v.GeneralProgressiveSourceFlag { + o1 |= 1 << 7 + } + if v.GeneralInterlacedSourceFlag { + o1 |= 1 << 6 + } + if v.GeneralNonPackedConstraintFlag { + o1 |= 1 << 5 + } + if v.GeneralFrameOnlyConstraintFlag { + o1 |= 1 << 4 + } + if v.GeneralMax12bitConstraintFlag { + o1 |= 1 << 3 + } + if v.GeneralMax10bitConstraintFlag { + o1 |= 1 << 2 + } + if v.GeneralMax8bitConstraintFlag { + o1 |= 1 << 1 + } + if v.GeneralMax422ChromeConstraintFlag { + o1 |= 1 << 0 + } + + ret = append(ret, fmt.Sprintf("%x", o1)) + + var o2 uint8 + if v.GeneralMax420ChromaConstraintFlag { + o2 |= 1 << 7 + } + if v.GeneralMaxMonochromeConstraintFlag { + o2 |= 1 << 6 + } + if v.GeneralIntraConstraintFlag { + o2 |= 1 << 5 + } + if v.GeneralOnePictureOnlyConstraintFlag { + o2 |= 1 << 4 + } + if v.GeneralLowerBitRateConstraintFlag { + o2 |= 1 << 3 + } + if v.GeneralMax14BitConstraintFlag { + o2 |= 1 << 2 + } + + if o2 != 0 { + ret = append(ret, fmt.Sprintf("%x", o2)) + } + + return strings.Join(ret, ".") +} + func codecParametersGenerate(track format.Format) string { switch ttrack := track.(type) { case *format.H264: @@ -21,8 +109,13 @@ func codecParametersGenerate(track format.Format) string { var sps h265.SPS err := sps.Unmarshal(ttrack.SafeSPS()) if err == nil { - return "hvc1." + strconv.FormatInt(int64(sps.ProfileTierLevel.GeneralProfileIdc), 10) + - ".4.L" + strconv.FormatInt(int64(sps.ProfileTierLevel.GeneralLevelIdc), 10) + ".B0" + return "hvc1." + + encodeProfileSpace(sps.ProfileTierLevel.GeneralProfileSpace) + + strconv.FormatInt(int64(sps.ProfileTierLevel.GeneralProfileIdc), 10) + "." + + encodeCompatibilityFlag(sps.ProfileTierLevel.GeneralProfileCompatibilityFlag) + "." + + encodeGeneralTierFlag(sps.ProfileTierLevel.GeneralTierFlag) + + strconv.FormatInt(int64(sps.ProfileTierLevel.GeneralLevelIdc), 10) + "." + + encodeGeneralConstraintIndicatorFlags(&sps.ProfileTierLevel) } case *format.MPEG4Audio: @@ -40,6 +133,7 @@ func codecParametersAreSupported(codecs string) bool { for _, codec := range strings.Split(codecs, ",") { if !strings.HasPrefix(codec, "avc1.") && !strings.HasPrefix(codec, "hvc1.") && + !strings.HasPrefix(codec, "hev1.") && !strings.HasPrefix(codec, "mp4a.") && codec != "opus" { return false