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 2022 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 "GstDecryptorElementFactory.h"
21 : #include "GstDecryptorPrivate.h"
22 : #include "GstProtectionMetadataHelperFactory.h"
23 : #include "RialtoServerLogging.h"
24 : #include <stdexcept>
25 :
26 : #include <gst/base/gstbasetransform.h>
27 : #include <gst/gst.h>
28 :
29 : G_BEGIN_DECLS
30 :
31 : #define GST_RIALTO_DECRYPTOR_TYPE (gst_rialto_decryptor_get_type())
32 : #define GST_RIALTO_DECRYPTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_RIALTO_DECRYPTOR_TYPE, GstRialtoDecryptor))
33 : #define GST_RIALTO_DECRYPTOR_CLASS(klass) \
34 : (G_TYPE_CHECK_CLASS_CAST((klass), GST_RIALTO_DECRYPTOR_TYPE, GstRialtoDecryptorClass))
35 :
36 : typedef struct _GstRialtoDecryptor GstRialtoDecryptor;
37 : typedef struct _GstRialtoDecryptorClass GstRialtoDecryptorClass;
38 : typedef struct firebolt::rialto::server::GstRialtoDecryptorPrivate GstRialtoDecryptorPrivate;
39 :
40 : GType gst_rialto_decryptor_get_type(void); // NOLINT(build/function_format)
41 :
42 : struct _GstRialtoDecryptor
43 : {
44 : GstBaseTransform parent;
45 : GstRialtoDecryptorPrivate *priv;
46 : };
47 :
48 : struct _GstRialtoDecryptorClass
49 : {
50 : GstBaseTransformClass parentClass;
51 : };
52 :
53 : G_END_DECLS
54 :
55 : static GstStaticPadTemplate sinkTemplate =
56 : GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY);
57 :
58 : static GstStaticPadTemplate srcTemplate =
59 : GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY);
60 :
61 : GST_DEBUG_CATEGORY(gst_rialto_decryptor_debug_category);
62 : #define GST_CAT_DEFAULT gst_rialto_decryptor_debug_category
63 :
64 : #define gst_rialto_decryptor_parent_class parent_class
65 8 : G_DEFINE_TYPE_WITH_PRIVATE(GstRialtoDecryptor, gst_rialto_decryptor, GST_TYPE_BASE_TRANSFORM);
66 :
67 : static void gst_rialto_decryptor_finalize(GObject *); // NOLINT(build/function_format)
68 : static GstCaps *gst_rialto_decryptor_transform_caps(GstBaseTransform *, // NOLINT(build/function_format)
69 : GstPadDirection, GstCaps *, GstCaps *);
70 : static GstFlowReturn gst_rialto_decryptor_transform_ip(GstBaseTransform *base, // NOLINT(build/function_format)
71 : GstBuffer *buffer);
72 :
73 5 : static const char *toString(const firebolt::rialto::CipherMode &cipherMode)
74 : {
75 5 : switch (cipherMode)
76 : {
77 0 : case firebolt::rialto::CipherMode::CBCS:
78 : {
79 0 : return "cbcs";
80 : }
81 5 : case firebolt::rialto::CipherMode::CENC:
82 : {
83 5 : return "cenc";
84 : }
85 0 : case firebolt::rialto::CipherMode::CBC1:
86 : {
87 0 : return "cbc1";
88 : }
89 0 : case firebolt::rialto::CipherMode::CENS:
90 : {
91 0 : return "cens";
92 : }
93 0 : case firebolt::rialto::CipherMode::UNKNOWN:
94 : default:
95 : {
96 0 : return "unknown";
97 : }
98 : }
99 : }
100 :
101 0 : static void gst_rialto_decryptor_class_init(GstRialtoDecryptorClass *klass) // NOLINT(build/function_format)
102 : {
103 0 : GST_DEBUG_CATEGORY_INIT(gst_rialto_decryptor_debug_category, "rialtodecryptor", 0, "Decryptor for Rialto");
104 :
105 0 : GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
106 0 : gobject_class->finalize = GST_DEBUG_FUNCPTR(gst_rialto_decryptor_finalize);
107 :
108 0 : GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
109 0 : gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&sinkTemplate));
110 0 : gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&srcTemplate));
111 0 : gst_element_class_set_static_metadata(element_class, "Rialto Decryptor", GST_ELEMENT_FACTORY_KLASS_DECRYPTOR,
112 : "Decryptor for Rialto.",
113 : "Luke Williamson <luke.williamson@sky.uk>\n"
114 : "Adam Czynszak <adam.czynszak@sky.uk>");
115 :
116 0 : GstBaseTransformClass *base_transform_class = GST_BASE_TRANSFORM_CLASS(klass);
117 0 : base_transform_class->transform_caps = GST_DEBUG_FUNCPTR(gst_rialto_decryptor_transform_caps);
118 0 : base_transform_class->transform_ip = GST_DEBUG_FUNCPTR(gst_rialto_decryptor_transform_ip);
119 0 : base_transform_class->transform_ip_on_passthrough = FALSE;
120 : }
121 :
122 0 : static void gst_rialto_decryptor_init(GstRialtoDecryptor *self) // NOLINT(build/function_format)
123 : {
124 : GstRialtoDecryptorPrivate *priv =
125 0 : reinterpret_cast<GstRialtoDecryptorPrivate *>(gst_rialto_decryptor_get_instance_private(self));
126 0 : GstBaseTransform *base = GST_BASE_TRANSFORM(self);
127 :
128 0 : self->priv = new (priv) GstRialtoDecryptorPrivate(base, firebolt::rialto::wrappers::IGstWrapperFactory::getFactory(),
129 0 : firebolt::rialto::wrappers::IGlibWrapperFactory::getFactory());
130 :
131 0 : gst_base_transform_set_in_place(base, TRUE);
132 0 : gst_base_transform_set_passthrough(base, FALSE);
133 0 : gst_base_transform_set_gap_aware(base, FALSE);
134 : }
135 :
136 0 : static void gst_rialto_decryptor_finalize(GObject *object) // NOLINT(build/function_format)
137 : {
138 0 : GstRialtoDecryptor *self = GST_RIALTO_DECRYPTOR(object);
139 : GstRialtoDecryptorPrivate *priv =
140 0 : reinterpret_cast<GstRialtoDecryptorPrivate *>(gst_rialto_decryptor_get_instance_private(self));
141 :
142 0 : priv->~GstRialtoDecryptorPrivate();
143 :
144 0 : GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object));
145 : }
146 :
147 0 : static GstCaps *gst_rialto_decryptor_transform_caps(GstBaseTransform *base, // NOLINT(build/function_format)
148 : GstPadDirection direction, GstCaps *caps, GstCaps *filter)
149 : {
150 0 : if (direction == GST_PAD_UNKNOWN)
151 0 : return nullptr;
152 :
153 0 : GstRialtoDecryptor *self = GST_RIALTO_DECRYPTOR(base);
154 :
155 0 : GST_DEBUG_OBJECT(self, "Transform in direction: %s, caps %" GST_PTR_FORMAT ", filter %" GST_PTR_FORMAT,
156 : direction == GST_PAD_SINK ? "GST_PAD_SINK" : "GST_PAD_SRC", caps, filter);
157 :
158 0 : return GST_BASE_TRANSFORM_CLASS(parent_class)->transform_caps(base, direction, caps, filter);
159 : }
160 :
161 0 : static GstFlowReturn gst_rialto_decryptor_transform_ip(GstBaseTransform *base, // NOLINT(build/function_format)
162 : GstBuffer *buffer)
163 : {
164 0 : GstRialtoDecryptor *self = GST_RIALTO_DECRYPTOR(base);
165 : GstRialtoDecryptorPrivate *priv =
166 0 : reinterpret_cast<GstRialtoDecryptorPrivate *>(gst_rialto_decryptor_get_instance_private(self));
167 :
168 0 : GST_TRACE_OBJECT(self, "Transform in place buf=(%" GST_PTR_FORMAT ")", buffer);
169 :
170 0 : GstPad *sink_pad = gst_element_get_static_pad(GST_ELEMENT(self), "sink");
171 0 : GstCaps *caps = gst_pad_get_current_caps(sink_pad);
172 :
173 0 : GstFlowReturn result = priv->decrypt(buffer, caps);
174 0 : gst_caps_unref(caps);
175 0 : gst_object_unref(sink_pad);
176 :
177 0 : return result;
178 : }
179 :
180 : namespace firebolt::rialto::server
181 : {
182 3 : std::shared_ptr<IGstDecryptorElementFactory> IGstDecryptorElementFactory::createFactory()
183 : {
184 3 : std::shared_ptr<IGstDecryptorElementFactory> factory;
185 :
186 : try
187 : {
188 3 : factory = std::make_shared<GstDecryptorElementFactory>();
189 : }
190 0 : catch (const std::exception &e)
191 : {
192 0 : RIALTO_SERVER_LOG_ERROR("Failed to create the decryptor element factory, reason: %s", e.what());
193 : }
194 :
195 3 : return factory;
196 : }
197 :
198 0 : GstElement *GstDecryptorElementFactory::createDecryptorElement(
199 : const gchar *name, firebolt::rialto::server::IDecryptionService *decryptionService,
200 : const std::shared_ptr<firebolt::rialto::wrappers::IGstWrapper> &gstWrapper) const
201 : {
202 : // Bypass the glib wrapper here, this is the only place we can create a proper Decryptor element
203 0 : GstRialtoDecryptor *decryptor = GST_RIALTO_DECRYPTOR(g_object_new(GST_RIALTO_DECRYPTOR_TYPE, nullptr));
204 0 : if (name)
205 : {
206 0 : if (!gstWrapper->gstObjectSetName(GST_OBJECT(decryptor), name))
207 : {
208 0 : RIALTO_SERVER_LOG_ERROR("Failed to set the decryptor name to %s", name);
209 0 : g_object_unref(GST_OBJECT(decryptor));
210 0 : return nullptr;
211 : }
212 : }
213 :
214 : GstRialtoDecryptorPrivate *priv =
215 0 : reinterpret_cast<GstRialtoDecryptorPrivate *>(gst_rialto_decryptor_get_instance_private(decryptor));
216 : std::shared_ptr<firebolt::rialto::server::IGstProtectionMetadataHelperFactory> metadataFactory =
217 0 : firebolt::rialto::server::IGstProtectionMetadataHelperFactory::createFactory();
218 0 : if (priv)
219 : {
220 0 : priv->setDecryptionService(decryptionService);
221 0 : priv->setProtectionMetadataWrapper(metadataFactory->createProtectionMetadataWrapper(gstWrapper));
222 0 : return GST_ELEMENT(decryptor);
223 : }
224 : else
225 : {
226 0 : RIALTO_SERVER_LOG_ERROR("Failed to create the decryptor element");
227 0 : g_object_unref(GST_OBJECT(decryptor));
228 0 : return nullptr;
229 : }
230 : }
231 :
232 10 : GstRialtoDecryptorPrivate::GstRialtoDecryptorPrivate(
233 : GstBaseTransform *parentElement,
234 : const std::shared_ptr<firebolt::rialto::wrappers::IGstWrapperFactory> &gstWrapperFactory,
235 10 : const std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapperFactory> &glibWrapperFactory)
236 10 : : m_decryptorElement(parentElement)
237 : {
238 10 : if ((!gstWrapperFactory) || (!(m_gstWrapper = gstWrapperFactory->getGstWrapper())))
239 : {
240 1 : throw std::runtime_error("Cannot create GstWrapper");
241 : }
242 :
243 9 : if ((!glibWrapperFactory) || (!(m_glibWrapper = glibWrapperFactory->getGlibWrapper())))
244 : {
245 1 : throw std::runtime_error("Cannot create GlibWrapper");
246 : }
247 14 : }
248 :
249 7 : GstFlowReturn GstRialtoDecryptorPrivate::decrypt(GstBuffer *buffer, GstCaps *caps)
250 : {
251 7 : GstRialtoDecryptor *self = GST_RIALTO_DECRYPTOR(m_decryptorElement);
252 7 : GstRialtoProtectionData *protectionData = m_metadataWrapper->getProtectionMetadataData(buffer);
253 7 : GstFlowReturn returnStatus = GST_BASE_TRANSFORM_FLOW_DROPPED; // By default drop frame on failure
254 7 : if (!protectionData)
255 : {
256 1 : GST_TRACE_OBJECT(self, "Clear sample");
257 1 : returnStatus = GST_FLOW_OK;
258 : }
259 : else
260 : {
261 6 : if (!m_decryptionService)
262 : {
263 1 : GST_ERROR_OBJECT(self, "No decryption service object");
264 : }
265 : else
266 : {
267 5 : if (protectionData->cipherMode == firebolt::rialto::CipherMode::CBC1 ||
268 5 : protectionData->cipherMode == firebolt::rialto::CipherMode::CENS)
269 : {
270 0 : GST_WARNING_OBJECT(self, "Untested cipher mode '%s'", toString(protectionData->cipherMode));
271 : }
272 :
273 5 : if (protectionData->encryptionPatternSet)
274 : {
275 4 : if (protectionData->cipherMode == firebolt::rialto::CipherMode::CENC ||
276 0 : protectionData->cipherMode == firebolt::rialto::CipherMode::CBC1)
277 : {
278 4 : GST_WARNING_OBJECT(self, "Encryption pattern set for non-pattern cipherMode '%s'",
279 : toString(protectionData->cipherMode));
280 : }
281 : }
282 :
283 5 : if (protectionData->key && m_decryptionService->isNetflixPlayreadyKeySystem(protectionData->keySessionId))
284 : {
285 : GstMapInfo keyMap;
286 2 : if (m_gstWrapper->gstBufferMap(protectionData->key, &keyMap, GST_MAP_READ))
287 : {
288 1 : std::vector<uint8_t> playreadyKey(keyMap.data, keyMap.data + keyMap.size);
289 1 : m_gstWrapper->gstBufferUnmap(protectionData->key, &keyMap);
290 1 : m_decryptionService->selectKeyId(protectionData->keySessionId, playreadyKey);
291 1 : m_gstWrapper->gstBufferUnref(protectionData->key);
292 1 : protectionData->key = m_gstWrapper->gstBufferNew();
293 : }
294 : else
295 : {
296 1 : GST_ERROR_OBJECT(self, "Failed to map playready key id");
297 : }
298 : }
299 :
300 : // Create new GstProtectionMeta decrypt
301 5 : GstStructure *info = createProtectionMetaInfo(protectionData);
302 5 : GstProtectionMeta *meta = m_gstWrapper->gstBufferAddProtectionMeta(buffer, info);
303 5 : if (meta == nullptr)
304 : {
305 0 : GST_ERROR_OBJECT(self, "Failed to add protection meta to the buffer");
306 : }
307 : else
308 : {
309 : firebolt::rialto::MediaKeyErrorStatus status =
310 5 : m_decryptionService->decrypt(protectionData->keySessionId, buffer, caps);
311 5 : if (firebolt::rialto::MediaKeyErrorStatus::OK != status)
312 : {
313 1 : GST_ERROR_OBJECT(self, "Failed decrypt the buffer");
314 : }
315 : else
316 : {
317 4 : GST_TRACE_OBJECT(self, "Decryption successful");
318 4 : returnStatus = GST_FLOW_OK;
319 : }
320 : }
321 : }
322 :
323 6 : m_metadataWrapper->removeProtectionMetadata(buffer);
324 : }
325 :
326 7 : if (GST_BASE_TRANSFORM_FLOW_DROPPED == returnStatus)
327 : {
328 : // Notify dropped frame upstream as a non-fatal message
329 2 : std::string message = "Failed to decrypt buffer, dropping frame and continuing";
330 2 : GError *gError{m_glibWrapper->gErrorNewLiteral(GST_STREAM_ERROR, GST_STREAM_ERROR_DECRYPT, message.c_str())};
331 : gboolean result =
332 4 : m_gstWrapper->gstElementPostMessage(GST_ELEMENT_CAST(self),
333 2 : m_gstWrapper->gstMessageNewWarning(GST_OBJECT_CAST(self), gError,
334 : message.c_str()));
335 2 : if (!result)
336 : {
337 0 : GST_WARNING_OBJECT(self, "Could not post decrypt warning");
338 : }
339 2 : m_glibWrapper->gErrorFree(gError);
340 : }
341 7 : return returnStatus;
342 : }
343 :
344 5 : GstStructure *GstRialtoDecryptorPrivate::createProtectionMetaInfo(GstRialtoProtectionData *protectionData)
345 : {
346 10 : GstStructure *info = m_gstWrapper->gstStructureNew("application/x-cenc", "kid", GST_TYPE_BUFFER,
347 : protectionData->key, "iv", GST_TYPE_BUFFER, protectionData->iv,
348 : "subsample_count", G_TYPE_UINT, protectionData->subsampleCount,
349 : "subsamples", GST_TYPE_BUFFER, protectionData->subsamples,
350 : "encryption_scheme", G_TYPE_UINT, 0, "init_with_last_15",
351 : G_TYPE_UINT, protectionData->initWithLast15, "cipher-mode",
352 5 : G_TYPE_STRING, toString(protectionData->cipherMode), NULL);
353 :
354 5 : if (protectionData->encryptionPatternSet)
355 : {
356 4 : m_gstWrapper->gstStructureSet(info, "crypt_byte_block", G_TYPE_UINT, protectionData->crypt, NULL);
357 4 : m_gstWrapper->gstStructureSet(info, "skip_byte_block", G_TYPE_UINT, protectionData->skip, NULL);
358 : }
359 5 : return info;
360 : }
361 :
362 8 : void GstRialtoDecryptorPrivate::setDecryptionService(IDecryptionService *decryptionService)
363 : {
364 8 : m_decryptionService = decryptionService;
365 : }
366 :
367 7 : void GstRialtoDecryptorPrivate::setProtectionMetadataWrapper(std::unique_ptr<IGstProtectionMetadataHelper> &&metadataWrapper)
368 : {
369 7 : m_metadataWrapper = std::move(metadataWrapper);
370 : }
371 :
372 : }; // namespace firebolt::rialto::server
|