1package environment
2
3import (
4 "fmt"
5 "os"
6 "strconv"
7 "strings"
8
9 "github.com/bnema/dumber/internal/config"
10 "github.com/bnema/dumber/internal/logging"
11)
12
13// ApplyCodecConfiguration applies codec preferences to environment variables and GStreamer settings
14func ApplyCodecConfiguration(codecPrefs config.CodecConfig) {
15 logging.Info(fmt.Sprintf("[codec] Applying codec preferences: preferred=%s, force_av1=%t, block_vp9=%t",
16 codecPrefs.PreferredCodecs, codecPrefs.ForceAV1, codecPrefs.BlockVP9))
17
18 // Build comprehensive GStreamer plugin rankings
19 var rankSettings []string
20
21 // Get existing GST_PLUGIN_FEATURE_RANK or start fresh
22 existingRank := os.Getenv("GST_PLUGIN_FEATURE_RANK")
23 if existingRank != "" {
24 rankSettings = strings.Split(existingRank, ",")
25 }
26
27 // AV1 decoder promotions (high priority)
28 if codecPrefs.ForceAV1 || strings.Contains(codecPrefs.PreferredCodecs, "av1") {
29 av1Ranks := []string{
30 "vaav1dec:768", // VA-API AV1 decoder (highest priority)
31 "nvav1dec:512", // NVDEC AV1 decoder
32 "av1dec:384", // Software AV1 decoder (fallback)
33 "avdec_av1:256", // libav AV1 decoder
34 }
35 rankSettings = append(rankSettings, av1Ranks...)
36 logging.Info(fmt.Sprintf("[codec] Promoted AV1 decoders for maximum priority"))
37 }
38
39 // H.264 decoder management
40 if strings.Contains(codecPrefs.PreferredCodecs, "h264") {
41 h264Ranks := []string{
42 "vah264dec:512", // VA-API H.264 decoder
43 "nvh264dec:384", // NVDEC H.264 decoder
44 "avdec_h264:256", // Software H.264 decoder
45 }
46 rankSettings = append(rankSettings, h264Ranks...)
47 }
48
49 // VP9 decoder demotion/blocking
50 if codecPrefs.DisableVP9Hardware || codecPrefs.BlockVP9 {
51 vp9Demotions := []string{
52 "vaapivp9dec:0", // Block VA-API VP9
53 "nvvp9dec:0", // Block NVDEC VP9
54 }
55 if codecPrefs.BlockVP9 {
56 vp9Demotions = append(vp9Demotions, "vp9dec:0", "avdec_vp9:0") // Block all VP9
57 } else {
58 // Allow software VP9 with low priority
59 vp9Demotions = append(vp9Demotions, "vp9dec:64", "avdec_vp9:64")
60 }
61 rankSettings = append(rankSettings, vp9Demotions...)
62 logging.Info(fmt.Sprintf("[codec] Demoted/blocked VP9 decoders"))
63 }
64
65 // VP8 decoder blocking
66 if codecPrefs.BlockVP8 {
67 vp8Demotions := []string{
68 "vaapivp8dec:0",
69 "vp8dec:0",
70 "avdec_vp8:0",
71 }
72 rankSettings = append(rankSettings, vp8Demotions...)
73 logging.Info(fmt.Sprintf("[codec] Blocked VP8 decoders"))
74 }
75
76 // Apply the complete ranking system
77 if len(rankSettings) > 0 {
78 finalRank := strings.Join(rankSettings, ",")
79 if err := os.Setenv("GST_PLUGIN_FEATURE_RANK", finalRank); err != nil {
80 logging.Warn(fmt.Sprintf("[codec] Warning: failed to set GST_PLUGIN_FEATURE_RANK: %v", err))
81 } else {
82 logging.Info(fmt.Sprintf("[codec] Set comprehensive GST_PLUGIN_FEATURE_RANK: %s", finalRank))
83 }
84 }
85
86 // Set video buffer sizes if specified
87 if codecPrefs.VideoBufferSizeMB > 0 {
88 bufferSize := strconv.Itoa(codecPrefs.VideoBufferSizeMB * 1024 * 1024)
89
90 if err := os.Setenv("GST_BUFFER_SIZE", bufferSize); err != nil {
91 logging.Warn(fmt.Sprintf("[codec] Warning: failed to set GST_BUFFER_SIZE: %v", err))
92 }
93
94 if err := os.Setenv("GST_QUEUE2_MAX_SIZE_BYTES", bufferSize); err != nil {
95 logging.Warn(fmt.Sprintf("[codec] Warning: failed to set GST_QUEUE2_MAX_SIZE_BYTES: %v", err))
96 }
97
98 logging.Info(fmt.Sprintf("[codec] Set video buffer size to %dMB", codecPrefs.VideoBufferSizeMB))
99 }
100
101 // Set queue buffer time if specified
102 if codecPrefs.QueueBufferTimeSec > 0 {
103 // Convert seconds to nanoseconds for GStreamer
104 bufferTime := strconv.Itoa(codecPrefs.QueueBufferTimeSec * 1000000000)
105
106 if err := os.Setenv("GST_QUEUE2_MAX_SIZE_TIME", bufferTime); err != nil {
107 logging.Warn(fmt.Sprintf("[codec] Warning: failed to set GST_QUEUE2_MAX_SIZE_TIME: %v", err))
108 } else {
109 logging.Info(fmt.Sprintf("[codec] Set queue buffer time to %ds", codecPrefs.QueueBufferTimeSec))
110 }
111 }
112
113 // Set additional codec-specific environment variables
114 if codecPrefs.ForceAV1 {
115 // Enable AV1 hardware decoding if available
116 if err := os.Setenv("GST_AV1_DECODER_ENABLE_HW", "1"); err != nil {
117 logging.Warn(fmt.Sprintf("[codec] Warning: failed to set GST_AV1_DECODER_ENABLE_HW: %v", err))
118 }
119 }
120
121 // Disable video post-processing to avoid VA-API issues
122 if err := os.Setenv("GST_VAAPI_DISABLE_VPP", "1"); err != nil {
123 logging.Warn(fmt.Sprintf("[codec] Warning: failed to set GST_VAAPI_DISABLE_VPP: %v", err))
124 }
125
126 logging.Info(fmt.Sprintf("[codec] Codec configuration applied successfully"))
127}
128
129// BuildBlockedCodecsList converts config codec blocking preferences to a string slice
130func BuildBlockedCodecsList(codecPrefs config.CodecConfig) []string {
131 var blocked []string
132
133 if codecPrefs.BlockVP9 {
134 blocked = append(blocked, "vp9")
135 }
136 if codecPrefs.BlockVP8 {
137 blocked = append(blocked, "vp8")
138 }
139
140 return blocked
141}