Line data Source code
1 : /*
2 : * If not stated otherwise in this file or this component's LICENSE file the
3 : * following copyright and licenses apply:
4 : *
5 : * Copyright 2024 Sky UK
6 : *
7 : * Licensed under the Apache License, Version 2.0 (the "License");
8 : * you may not use this file except in compliance with the License.
9 : * You may obtain a copy of the License at
10 : *
11 : * http://www.apache.org/licenses/LICENSE-2.0
12 : *
13 : * Unless required by applicable law or agreed to in writing, software
14 : * distributed under the License is distributed on an "AS IS" BASIS,
15 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : * See the License for the specific language governing permissions and
17 : * limitations under the License.
18 : */
19 :
20 : #include "CapsBuilder.h"
21 : #include "GstMimeMapping.h"
22 : #include "RialtoServerLogging.h"
23 : #include "TypeConverters.h"
24 :
25 : namespace firebolt::rialto::server
26 : {
27 20 : MediaSourceCapsBuilder::MediaSourceCapsBuilder(const std::shared_ptr<firebolt::rialto::wrappers::IGstWrapper> &gstWrapper,
28 : const std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapper> &glibWrapper,
29 20 : const firebolt::rialto::IMediaPipeline::MediaSourceAV &source)
30 20 : : m_gstWrapper(gstWrapper), m_glibWrapper(glibWrapper), m_attachedSource(source)
31 : {
32 : }
33 19 : GstCaps *MediaSourceCapsBuilder::buildCaps()
34 : {
35 19 : return buildCommonCaps();
36 : }
37 :
38 19 : GstCaps *MediaSourceCapsBuilder::buildCommonCaps()
39 : {
40 19 : GstCaps *caps = firebolt::rialto::server::createSimpleCapsFromMimeType(m_gstWrapper, m_attachedSource);
41 :
42 19 : addAlignmentToCaps(caps);
43 19 : addCodecDataToCaps(caps);
44 19 : addStreamFormatToCaps(caps);
45 :
46 19 : return caps;
47 : }
48 :
49 19 : void MediaSourceCapsBuilder::addAlignmentToCaps(GstCaps *caps) const
50 : {
51 : static const std::unordered_map<firebolt::rialto::SegmentAlignment, std::string> aligmentMap =
52 23 : {{firebolt::rialto::SegmentAlignment::AU, "au"}, {firebolt::rialto::SegmentAlignment::NAL, "nal"}};
53 :
54 19 : auto aligmentMapIt = aligmentMap.find(m_attachedSource.getSegmentAlignment());
55 19 : if (aligmentMapIt != aligmentMap.end())
56 : {
57 7 : m_gstWrapper->gstCapsSetSimple(caps, "alignment", G_TYPE_STRING, aligmentMapIt->second.c_str(), nullptr);
58 : }
59 20 : }
60 :
61 19 : void MediaSourceCapsBuilder::addCodecDataToCaps(GstCaps *caps) const
62 : {
63 19 : const std::shared_ptr<CodecData> &kCodecData = m_attachedSource.getCodecData();
64 19 : if (kCodecData && CodecDataType::BUFFER == kCodecData->type)
65 : {
66 6 : gpointer memory = m_glibWrapper->gMemdup(kCodecData->data.data(), kCodecData->data.size());
67 6 : GstBuffer *buf = m_gstWrapper->gstBufferNewWrapped(memory, kCodecData->data.size());
68 6 : m_gstWrapper->gstCapsSetSimple(caps, "codec_data", GST_TYPE_BUFFER, buf, nullptr);
69 6 : m_gstWrapper->gstBufferUnref(buf);
70 : }
71 13 : else if (kCodecData && CodecDataType::STRING == kCodecData->type)
72 : {
73 2 : std::string codecDataStr{kCodecData->data.begin(), kCodecData->data.end()};
74 1 : m_gstWrapper->gstCapsSetSimple(caps, "codec_data", G_TYPE_STRING, codecDataStr.c_str(), nullptr);
75 : }
76 19 : }
77 :
78 19 : void MediaSourceCapsBuilder::addStreamFormatToCaps(GstCaps *caps) const
79 : {
80 : static const std::unordered_map<firebolt::rialto::StreamFormat, std::string> formatMap =
81 0 : {{firebolt::rialto::StreamFormat::RAW, "raw"},
82 0 : {firebolt::rialto::StreamFormat::AVC, "avc"},
83 0 : {firebolt::rialto::StreamFormat::BYTE_STREAM, "byte-stream"},
84 0 : {firebolt::rialto::StreamFormat::HVC1, "hvc1"},
85 26 : {firebolt::rialto::StreamFormat::HEV1, "hev1"}};
86 :
87 19 : auto formatMapIt = formatMap.find(m_attachedSource.getStreamFormat());
88 19 : if (formatMapIt != formatMap.end())
89 : {
90 7 : m_gstWrapper->gstCapsSetSimple(caps, "stream-format", G_TYPE_STRING, formatMapIt->second.c_str(), nullptr);
91 : }
92 20 : }
93 :
94 13 : MediaSourceAudioCapsBuilder::MediaSourceAudioCapsBuilder(
95 : const std::shared_ptr<firebolt::rialto::wrappers::IGstWrapper> &gstWrapper,
96 : const std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapper> &glibWrapper,
97 13 : const IMediaPipeline::MediaSourceAudio &source)
98 13 : : MediaSourceCapsBuilder(gstWrapper, glibWrapper, source), m_attachedAudioSource(source)
99 : {
100 : }
101 :
102 13 : GstCaps *MediaSourceAudioCapsBuilder::buildCaps()
103 : {
104 13 : std::string mimeType = m_attachedSource.getMimeType();
105 13 : if (mimeType == "audio/x-opus")
106 : {
107 1 : return createOpusCaps();
108 : }
109 :
110 12 : GstCaps *caps = MediaSourceCapsBuilder::buildCaps();
111 12 : if (mimeType == "audio/mp4" || mimeType == "audio/aac")
112 : {
113 5 : addMpegVersion4ToCaps(caps);
114 : }
115 7 : else if (mimeType == "audio/mp3")
116 : {
117 1 : addMp3Caps(caps);
118 : }
119 6 : else if (mimeType == "audio/b-wav" || mimeType == "audio/x-raw")
120 : {
121 3 : addRawAudioData(caps);
122 : }
123 3 : else if (mimeType == "audio/x-flac")
124 : {
125 1 : addFlacSpecificData(caps);
126 : }
127 12 : addSampleRateAndChannelsToCaps(caps);
128 :
129 12 : return caps;
130 13 : }
131 :
132 1 : GstCaps *MediaSourceAudioCapsBuilder::createOpusCaps()
133 : {
134 1 : GstCaps *caps = getAudioSpecificConfiguration();
135 1 : if (!caps)
136 : {
137 0 : caps = m_gstWrapper->gstCapsNewSimple("audio/x-opus", "channel-mapping-family", G_TYPE_INT, 0, nullptr);
138 0 : addSampleRateAndChannelsToCaps(caps);
139 : }
140 :
141 1 : return caps;
142 : }
143 :
144 1 : GstCaps *MediaSourceAudioCapsBuilder::getAudioSpecificConfiguration() const
145 : {
146 1 : GstCaps *caps = nullptr;
147 1 : firebolt::rialto::AudioConfig audioConfig = m_attachedAudioSource.getAudioConfig();
148 1 : if (audioConfig.codecSpecificConfig.size())
149 : {
150 1 : gsize codec_priv_size = audioConfig.codecSpecificConfig.size();
151 1 : gconstpointer codec_priv = audioConfig.codecSpecificConfig.data();
152 :
153 1 : caps = m_gstWrapper->gstCodecUtilsOpusCreateCapsFromHeader(codec_priv, codec_priv_size);
154 1 : if (!caps)
155 : {
156 0 : RIALTO_SERVER_LOG_ERROR("Failed to parse opus header");
157 : }
158 : }
159 :
160 1 : return caps;
161 : }
162 :
163 12 : void MediaSourceAudioCapsBuilder::addSampleRateAndChannelsToCaps(GstCaps *caps) const
164 : {
165 12 : firebolt::rialto::AudioConfig audioConfig = m_attachedAudioSource.getAudioConfig();
166 :
167 12 : if (audioConfig.numberOfChannels != firebolt::rialto::kInvalidAudioChannels)
168 4 : m_gstWrapper->gstCapsSetSimple(caps, "channels", G_TYPE_INT, audioConfig.numberOfChannels, nullptr);
169 :
170 12 : if (audioConfig.sampleRate != firebolt::rialto::kInvalidAudioSampleRate)
171 4 : m_gstWrapper->gstCapsSetSimple(caps, "rate", G_TYPE_INT, audioConfig.sampleRate, nullptr);
172 12 : }
173 :
174 5 : void MediaSourceAudioCapsBuilder::addMpegVersion4ToCaps(GstCaps *caps) const
175 : {
176 5 : m_gstWrapper->gstCapsSetSimple(caps, "mpegversion", G_TYPE_INT, 4, nullptr);
177 : }
178 :
179 1 : void MediaSourceAudioCapsBuilder::addMp3Caps(GstCaps *caps) const
180 : {
181 1 : m_gstWrapper->gstCapsSetSimple(caps, "mpegversion", G_TYPE_INT, 1, nullptr);
182 1 : m_gstWrapper->gstCapsSetSimple(caps, "layer", G_TYPE_INT, 3, nullptr);
183 : }
184 :
185 3 : void MediaSourceAudioCapsBuilder::addRawAudioData(GstCaps *caps) const
186 : {
187 3 : firebolt::rialto::AudioConfig audioConfig = m_attachedAudioSource.getAudioConfig();
188 3 : if (audioConfig.format.has_value())
189 2 : m_gstWrapper->gstCapsSetSimple(caps, "format", G_TYPE_STRING, common::convertFormat(audioConfig.format.value()),
190 : nullptr);
191 3 : if (audioConfig.layout.has_value())
192 2 : m_gstWrapper->gstCapsSetSimple(caps, "layout", G_TYPE_STRING, common::convertLayout(audioConfig.layout.value()),
193 : nullptr);
194 3 : if (audioConfig.channelMask.has_value())
195 2 : m_gstWrapper->gstCapsSetSimple(caps, "channel-mask", GST_TYPE_BITMASK, audioConfig.channelMask.value(), nullptr);
196 3 : }
197 :
198 1 : void MediaSourceAudioCapsBuilder::addFlacSpecificData(GstCaps *caps) const
199 : {
200 1 : firebolt::rialto::AudioConfig audioConfig = m_attachedAudioSource.getAudioConfig();
201 1 : if (audioConfig.streamHeader.size())
202 : {
203 1 : GValue streamHeaderArray = G_VALUE_INIT;
204 1 : m_glibWrapper->gValueInit(&streamHeaderArray, GST_TYPE_ARRAY);
205 2 : for (const auto &header : audioConfig.streamHeader)
206 : {
207 1 : gpointer memory = m_glibWrapper->gMemdup(header.data(), header.size());
208 1 : GstBuffer *buf = m_gstWrapper->gstBufferNewWrapped(memory, header.size());
209 1 : GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_HEADER);
210 :
211 1 : GValue value = G_VALUE_INIT;
212 1 : m_glibWrapper->gValueInit(&value, GST_TYPE_BUFFER);
213 1 : m_gstWrapper->gstValueSetBuffer(&value, buf);
214 1 : m_gstWrapper->gstValueArrayAppendValue(&streamHeaderArray, &value);
215 :
216 1 : m_glibWrapper->gValueUnset(&value);
217 1 : m_gstWrapper->gstBufferUnref(buf);
218 : }
219 1 : m_gstWrapper->gstStructureSetValue(m_gstWrapper->gstCapsGetStructure(caps, 0), "streamheader",
220 : &streamHeaderArray);
221 1 : m_glibWrapper->gValueUnset(&streamHeaderArray);
222 : }
223 1 : if (audioConfig.framed.has_value())
224 : {
225 1 : m_gstWrapper->gstCapsSetSimple(caps, "framed", G_TYPE_BOOLEAN, audioConfig.framed.value(), nullptr);
226 : }
227 : }
228 :
229 7 : MediaSourceVideoCapsBuilder::MediaSourceVideoCapsBuilder(
230 : const std::shared_ptr<firebolt::rialto::wrappers::IGstWrapper> &gstWrapper,
231 : const std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapper> &glibWrapper,
232 7 : const IMediaPipeline::MediaSourceVideo &source)
233 7 : : MediaSourceCapsBuilder(gstWrapper, glibWrapper, source), m_attachedVideoSource(source)
234 : {
235 : }
236 :
237 7 : GstCaps *MediaSourceVideoCapsBuilder::buildCaps()
238 : {
239 7 : GstCaps *caps = MediaSourceCapsBuilder::buildCaps();
240 7 : if (m_attachedVideoSource.getWidth() != firebolt::rialto::kUndefinedSize)
241 6 : m_gstWrapper->gstCapsSetSimple(caps, "width", G_TYPE_INT, m_attachedVideoSource.getWidth(), nullptr);
242 7 : if (m_attachedVideoSource.getHeight() != firebolt::rialto::kUndefinedSize)
243 6 : m_gstWrapper->gstCapsSetSimple(caps, "height", G_TYPE_INT, m_attachedVideoSource.getHeight(), nullptr);
244 :
245 7 : return caps;
246 : }
247 :
248 1 : MediaSourceVideoDolbyVisionCapsBuilder::MediaSourceVideoDolbyVisionCapsBuilder(
249 : const std::shared_ptr<firebolt::rialto::wrappers::IGstWrapper> &gstWrapper,
250 : const std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapper> &glibWrapper,
251 1 : const IMediaPipeline::MediaSourceVideoDolbyVision &source)
252 1 : : MediaSourceVideoCapsBuilder(gstWrapper, glibWrapper, source), m_attachedDolbySource(source)
253 : {
254 : }
255 :
256 1 : GstCaps *MediaSourceVideoDolbyVisionCapsBuilder::buildCaps()
257 : {
258 1 : GstCaps *caps = MediaSourceVideoCapsBuilder::buildCaps();
259 1 : m_gstWrapper->gstCapsSetSimple(caps, "dovi-stream", G_TYPE_BOOLEAN, true, nullptr);
260 1 : m_gstWrapper->gstCapsSetSimple(caps, "dv_profile", G_TYPE_UINT, m_attachedDolbySource.getDolbyVisionProfile(),
261 : nullptr);
262 1 : return caps;
263 : }
264 : } // namespace firebolt::rialto::server
|