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 18 : MediaSourceCapsBuilder::MediaSourceCapsBuilder(std::shared_ptr<firebolt::rialto::wrappers::IGstWrapper> gstWrapper,
28 : std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapper> glibWrapper,
29 18 : const firebolt::rialto::IMediaPipeline::MediaSourceAV &source)
30 18 : : m_gstWrapper(gstWrapper), m_glibWrapper(glibWrapper), m_attachedSource(source)
31 : {
32 : }
33 17 : GstCaps *MediaSourceCapsBuilder::buildCaps()
34 : {
35 17 : return buildCommonCaps();
36 : }
37 :
38 17 : GstCaps *MediaSourceCapsBuilder::buildCommonCaps()
39 : {
40 17 : GstCaps *caps = firebolt::rialto::server::createSimpleCapsFromMimeType(m_gstWrapper, m_attachedSource);
41 :
42 17 : addAlignmentToCaps(caps);
43 17 : addCodecDataToCaps(caps);
44 17 : addStreamFormatToCaps(caps);
45 :
46 17 : return caps;
47 : }
48 :
49 17 : void MediaSourceCapsBuilder::addAlignmentToCaps(GstCaps *caps) const
50 : {
51 : static const std::unordered_map<firebolt::rialto::SegmentAlignment, std::string> aligmentMap =
52 21 : {{firebolt::rialto::SegmentAlignment::AU, "au"}, {firebolt::rialto::SegmentAlignment::NAL, "nal"}};
53 :
54 17 : auto aligmentMapIt = aligmentMap.find(m_attachedSource.getSegmentAlignment());
55 17 : if (aligmentMapIt != aligmentMap.end())
56 : {
57 7 : m_gstWrapper->gstCapsSetSimple(caps, "alignment", G_TYPE_STRING, aligmentMapIt->second.c_str(), nullptr);
58 : }
59 18 : }
60 :
61 17 : void MediaSourceCapsBuilder::addCodecDataToCaps(GstCaps *caps) const
62 : {
63 17 : const std::shared_ptr<CodecData> &kCodecData = m_attachedSource.getCodecData();
64 17 : 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 11 : 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 17 : }
77 :
78 17 : 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 24 : {firebolt::rialto::StreamFormat::HEV1, "hev1"}};
86 :
87 17 : auto formatMapIt = formatMap.find(m_attachedSource.getStreamFormat());
88 17 : if (formatMapIt != formatMap.end())
89 : {
90 7 : m_gstWrapper->gstCapsSetSimple(caps, "stream-format", G_TYPE_STRING, formatMapIt->second.c_str(), nullptr);
91 : }
92 18 : }
93 :
94 11 : MediaSourceAudioCapsBuilder::MediaSourceAudioCapsBuilder(
95 : std::shared_ptr<firebolt::rialto::wrappers::IGstWrapper> gstWrapper,
96 11 : std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapper> glibWrapper, const IMediaPipeline::MediaSourceAudio &source)
97 11 : : MediaSourceCapsBuilder(gstWrapper, glibWrapper, source), m_attachedAudioSource(source)
98 : {
99 : }
100 :
101 11 : GstCaps *MediaSourceAudioCapsBuilder::buildCaps()
102 : {
103 11 : std::string mimeType = m_attachedSource.getMimeType();
104 11 : if (mimeType == "audio/x-opus")
105 : {
106 1 : return createOpusCaps();
107 : }
108 :
109 10 : GstCaps *caps = MediaSourceCapsBuilder::buildCaps();
110 10 : if (mimeType == "audio/mp4" || mimeType == "audio/aac")
111 : {
112 3 : addMpegVersion4ToCaps(caps);
113 : }
114 7 : else if (mimeType == "audio/mp3")
115 : {
116 1 : addMp3Caps(caps);
117 : }
118 6 : else if (mimeType == "audio/b-wav" || mimeType == "audio/x-raw")
119 : {
120 3 : addRawAudioData(caps);
121 : }
122 3 : else if (mimeType == "audio/x-flac")
123 : {
124 1 : addFlacSpecificData(caps);
125 : }
126 10 : addSampleRateAndChannelsToCaps(caps);
127 :
128 10 : return caps;
129 11 : }
130 :
131 1 : GstCaps *MediaSourceAudioCapsBuilder::createOpusCaps()
132 : {
133 1 : GstCaps *caps = getAudioSpecificConfiguration();
134 1 : if (!caps)
135 : {
136 0 : caps = m_gstWrapper->gstCapsNewSimple("audio/x-opus", "channel-mapping-family", G_TYPE_INT, 0, nullptr);
137 0 : addSampleRateAndChannelsToCaps(caps);
138 : }
139 :
140 1 : return caps;
141 : }
142 :
143 1 : GstCaps *MediaSourceAudioCapsBuilder::getAudioSpecificConfiguration() const
144 : {
145 1 : GstCaps *caps = nullptr;
146 1 : firebolt::rialto::AudioConfig audioConfig = m_attachedAudioSource.getAudioConfig();
147 1 : if (audioConfig.codecSpecificConfig.size())
148 : {
149 1 : gsize codec_priv_size = audioConfig.codecSpecificConfig.size();
150 1 : gconstpointer codec_priv = audioConfig.codecSpecificConfig.data();
151 :
152 1 : caps = m_gstWrapper->gstCodecUtilsOpusCreateCapsFromHeader(codec_priv, codec_priv_size);
153 1 : if (!caps)
154 : {
155 0 : RIALTO_SERVER_LOG_ERROR("Failed to parse opus header");
156 : }
157 : }
158 :
159 1 : return caps;
160 : }
161 :
162 10 : void MediaSourceAudioCapsBuilder::addSampleRateAndChannelsToCaps(GstCaps *caps) const
163 : {
164 10 : firebolt::rialto::AudioConfig audioConfig = m_attachedAudioSource.getAudioConfig();
165 :
166 10 : if (audioConfig.numberOfChannels != firebolt::rialto::kInvalidAudioChannels)
167 4 : m_gstWrapper->gstCapsSetSimple(caps, "channels", G_TYPE_INT, audioConfig.numberOfChannels, nullptr);
168 :
169 10 : if (audioConfig.sampleRate != firebolt::rialto::kInvalidAudioSampleRate)
170 4 : m_gstWrapper->gstCapsSetSimple(caps, "rate", G_TYPE_INT, audioConfig.sampleRate, nullptr);
171 10 : }
172 :
173 3 : void MediaSourceAudioCapsBuilder::addMpegVersion4ToCaps(GstCaps *caps) const
174 : {
175 3 : m_gstWrapper->gstCapsSetSimple(caps, "mpegversion", G_TYPE_INT, 4, nullptr);
176 : }
177 :
178 1 : void MediaSourceAudioCapsBuilder::addMp3Caps(GstCaps *caps) const
179 : {
180 1 : m_gstWrapper->gstCapsSetSimple(caps, "mpegversion", G_TYPE_INT, 1, nullptr);
181 1 : m_gstWrapper->gstCapsSetSimple(caps, "layer", G_TYPE_INT, 3, nullptr);
182 : }
183 :
184 3 : void MediaSourceAudioCapsBuilder::addRawAudioData(GstCaps *caps) const
185 : {
186 3 : firebolt::rialto::AudioConfig audioConfig = m_attachedAudioSource.getAudioConfig();
187 3 : if (audioConfig.format.has_value())
188 2 : m_gstWrapper->gstCapsSetSimple(caps, "format", G_TYPE_STRING, common::convertFormat(audioConfig.format.value()),
189 : nullptr);
190 3 : if (audioConfig.layout.has_value())
191 2 : m_gstWrapper->gstCapsSetSimple(caps, "layout", G_TYPE_STRING, common::convertLayout(audioConfig.layout.value()),
192 : nullptr);
193 3 : if (audioConfig.channelMask.has_value())
194 2 : m_gstWrapper->gstCapsSetSimple(caps, "channel-mask", GST_TYPE_BITMASK, audioConfig.channelMask.value(), nullptr);
195 3 : }
196 :
197 1 : void MediaSourceAudioCapsBuilder::addFlacSpecificData(GstCaps *caps) const
198 : {
199 1 : firebolt::rialto::AudioConfig audioConfig = m_attachedAudioSource.getAudioConfig();
200 1 : if (audioConfig.streamHeader.size())
201 : {
202 1 : GValue streamHeaderArray = G_VALUE_INIT;
203 1 : m_glibWrapper->gValueInit(&streamHeaderArray, GST_TYPE_ARRAY);
204 2 : for (const auto &header : audioConfig.streamHeader)
205 : {
206 1 : gpointer memory = m_glibWrapper->gMemdup(header.data(), header.size());
207 1 : GstBuffer *buf = m_gstWrapper->gstBufferNewWrapped(memory, header.size());
208 1 : GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_HEADER);
209 :
210 1 : GValue value = G_VALUE_INIT;
211 1 : m_glibWrapper->gValueInit(&value, GST_TYPE_BUFFER);
212 1 : m_gstWrapper->gstValueSetBuffer(&value, buf);
213 1 : m_gstWrapper->gstValueArrayAppendValue(&streamHeaderArray, &value);
214 :
215 1 : m_glibWrapper->gValueUnset(&value);
216 1 : m_gstWrapper->gstBufferUnref(buf);
217 : }
218 1 : m_gstWrapper->gstStructureSetValue(m_gstWrapper->gstCapsGetStructure(caps, 0), "streamheader",
219 : &streamHeaderArray);
220 1 : m_glibWrapper->gValueUnset(&streamHeaderArray);
221 : }
222 1 : if (audioConfig.framed.has_value())
223 : {
224 1 : m_gstWrapper->gstCapsSetSimple(caps, "framed", G_TYPE_BOOLEAN, audioConfig.framed.value(), nullptr);
225 : }
226 : }
227 :
228 7 : MediaSourceVideoCapsBuilder::MediaSourceVideoCapsBuilder(
229 : std::shared_ptr<firebolt::rialto::wrappers::IGstWrapper> gstWrapper,
230 7 : std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapper> glibWrapper, const IMediaPipeline::MediaSourceVideo &source)
231 7 : : MediaSourceCapsBuilder(gstWrapper, glibWrapper, source), m_attachedVideoSource(source)
232 : {
233 : }
234 :
235 7 : GstCaps *MediaSourceVideoCapsBuilder::buildCaps()
236 : {
237 7 : GstCaps *caps = MediaSourceCapsBuilder::buildCaps();
238 7 : if (m_attachedVideoSource.getWidth() != firebolt::rialto::kUndefinedSize)
239 6 : m_gstWrapper->gstCapsSetSimple(caps, "width", G_TYPE_INT, m_attachedVideoSource.getWidth(), nullptr);
240 7 : if (m_attachedVideoSource.getHeight() != firebolt::rialto::kUndefinedSize)
241 6 : m_gstWrapper->gstCapsSetSimple(caps, "height", G_TYPE_INT, m_attachedVideoSource.getHeight(), nullptr);
242 :
243 7 : return caps;
244 : }
245 :
246 1 : MediaSourceVideoDolbyVisionCapsBuilder::MediaSourceVideoDolbyVisionCapsBuilder(
247 : std::shared_ptr<firebolt::rialto::wrappers::IGstWrapper> gstWrapper,
248 : std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapper> glibWrapper,
249 1 : const IMediaPipeline::MediaSourceVideoDolbyVision &source)
250 1 : : MediaSourceVideoCapsBuilder(gstWrapper, glibWrapper, source), m_attachedDolbySource(source)
251 : {
252 : }
253 :
254 1 : GstCaps *MediaSourceVideoDolbyVisionCapsBuilder::buildCaps()
255 : {
256 1 : GstCaps *caps = MediaSourceVideoCapsBuilder::buildCaps();
257 1 : m_gstWrapper->gstCapsSetSimple(caps, "dovi-stream", G_TYPE_BOOLEAN, true, nullptr);
258 1 : m_gstWrapper->gstCapsSetSimple(caps, "dv_profile", G_TYPE_UINT, m_attachedDolbySource.getDolbyVisionProfile(),
259 : nullptr);
260 1 : return caps;
261 : }
262 : } // namespace firebolt::rialto::server
|