xref: /aosp_15_r20/external/webrtc/modules/desktop_capture/linux/wayland/screencast_stream_utils.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright 2022 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "modules/desktop_capture/linux/wayland/screencast_stream_utils.h"
12 
13 #include <libdrm/drm_fourcc.h>
14 #include <pipewire/pipewire.h>
15 #include <spa/param/video/format-utils.h>
16 
17 #include <string>
18 
19 #include "rtc_base/string_to_number.h"
20 
21 #if !PW_CHECK_VERSION(0, 3, 29)
22 #define SPA_POD_PROP_FLAG_MANDATORY (1u << 3)
23 #endif
24 #if !PW_CHECK_VERSION(0, 3, 33)
25 #define SPA_POD_PROP_FLAG_DONT_FIXATE (1u << 4)
26 #endif
27 
28 namespace webrtc {
29 
Parse(const absl::string_view & version)30 PipeWireVersion PipeWireVersion::Parse(const absl::string_view& version) {
31   std::vector<absl::string_view> parsed_version = rtc::split(version, '.');
32 
33   if (parsed_version.size() != 3) {
34     return {};
35   }
36 
37   absl::optional<int> major = rtc::StringToNumber<int>(parsed_version.at(0));
38   absl::optional<int> minor = rtc::StringToNumber<int>(parsed_version.at(1));
39   absl::optional<int> micro = rtc::StringToNumber<int>(parsed_version.at(2));
40 
41   // Return invalid version if we failed to parse it
42   if (!major || !minor || !micro) {
43     return {};
44   }
45 
46   return {major.value(), minor.value(), micro.value()};
47 }
48 
operator >=(const PipeWireVersion & other)49 bool PipeWireVersion::operator>=(const PipeWireVersion& other) {
50   if (!major && !minor && !micro) {
51     return false;
52   }
53 
54   return std::tie(major, minor, micro) >=
55          std::tie(other.major, other.minor, other.micro);
56 }
57 
operator <=(const PipeWireVersion & other)58 bool PipeWireVersion::operator<=(const PipeWireVersion& other) {
59   if (!major && !minor && !micro) {
60     return false;
61   }
62 
63   return std::tie(major, minor, micro) <=
64          std::tie(other.major, other.minor, other.micro);
65 }
66 
BuildFormat(spa_pod_builder * builder,uint32_t format,const std::vector<uint64_t> & modifiers,const struct spa_rectangle * resolution)67 spa_pod* BuildFormat(spa_pod_builder* builder,
68                      uint32_t format,
69                      const std::vector<uint64_t>& modifiers,
70                      const struct spa_rectangle* resolution) {
71   spa_pod_frame frames[2];
72   spa_rectangle pw_min_screen_bounds = spa_rectangle{1, 1};
73   spa_rectangle pw_max_screen_bounds = spa_rectangle{UINT32_MAX, UINT32_MAX};
74 
75   spa_pod_builder_push_object(builder, &frames[0], SPA_TYPE_OBJECT_Format,
76                               SPA_PARAM_EnumFormat);
77   spa_pod_builder_add(builder, SPA_FORMAT_mediaType,
78                       SPA_POD_Id(SPA_MEDIA_TYPE_video), 0);
79   spa_pod_builder_add(builder, SPA_FORMAT_mediaSubtype,
80                       SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), 0);
81   spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_format, SPA_POD_Id(format), 0);
82 
83   if (modifiers.size()) {
84     if (modifiers.size() == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) {
85       spa_pod_builder_prop(builder, SPA_FORMAT_VIDEO_modifier,
86                            SPA_POD_PROP_FLAG_MANDATORY);
87       spa_pod_builder_long(builder, modifiers[0]);
88     } else {
89       spa_pod_builder_prop(
90           builder, SPA_FORMAT_VIDEO_modifier,
91           SPA_POD_PROP_FLAG_MANDATORY | SPA_POD_PROP_FLAG_DONT_FIXATE);
92       spa_pod_builder_push_choice(builder, &frames[1], SPA_CHOICE_Enum, 0);
93 
94       // modifiers from the array
95       bool first = true;
96       for (int64_t val : modifiers) {
97         spa_pod_builder_long(builder, val);
98         // Add the first modifier twice as the very first value is the default
99         // option
100         if (first) {
101           spa_pod_builder_long(builder, val);
102           first = false;
103         }
104       }
105       spa_pod_builder_pop(builder, &frames[1]);
106     }
107   }
108 
109   if (resolution) {
110     spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_size,
111                         SPA_POD_Rectangle(resolution), 0);
112   } else {
113     spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_size,
114                         SPA_POD_CHOICE_RANGE_Rectangle(&pw_min_screen_bounds,
115                                                        &pw_min_screen_bounds,
116                                                        &pw_max_screen_bounds),
117                         0);
118   }
119 
120   return static_cast<spa_pod*>(spa_pod_builder_pop(builder, &frames[0]));
121 }
122 
123 }  // namespace webrtc
124