LCOV - code coverage report
Current view: top level - media/server/gstplayer/source - GstDecryptor.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 48.6 % 138 67
Test Date: 2025-02-18 13:13:53 Functions: 57.1 % 14 8

            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
        

Generated by: LCOV version 2.0-1