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