RDK Resources
[*RDK Preferred*]
Code Management Facility
RDK Forums
[RDK Conferences]
RDK Support
Archives
Papers & Presentations Archive
Document Status Codes
Work in Progress (W) | An incomplete document designed to guide discussion and generate feedback that may include several alternative requirements for consideration. |
Draft (D) | A document in specification format considered largely complete, but lacking review. Drafts are susceptible to substantial change during the review process. |
Issued (I) | A stable document that has undergone rigorous review and is suitable for product design and development. It will serve as a basis for testing requirements. |
Secure video path is a means to protect decrypted content from the host processor. This means that the decrypted data is only accessible to the secure process space on the device and any rouge actor that gains access to the device will not be able to extract the content data.
This document defines data types and method interfaces that comprise the RDK SVP architectural design.
This document uses the following abbreviations and acronyms.
Term | Definition |
---|---|
CENC | Common Encryption |
SoC | System-on-Chip |
STB | Set-Top Box |
SVP | Secure Video Path |
TEE | Trusted Execution Environment |
The normal DRM decrypt flow in the RDK is for the player application either directly or through the gstreamer decryptor filter to call the OCDM service to decrypt a blob of data. This data arrives in the form of a GstBuffer object with meta data describing any CENC information about the location of clear and encrypted data chunks.
There are two ways to handle the decryption of data. In-place and handle based decryption. In-place decryption is used for streams whose licenses do not require the highest level of content protection (generally SD and HD streams). Handle based decryption (SVP) is generally used for UHD content
In the in-place decryption use case the OCDM service receives encrypted data from the player app and then calls via RPC the DRM plugin operating in a different process that understands the interface of the DRM library (Playready or Widevine) that it encapsulates. This container manages the DRM session context. The Media Session object which receives the data chunk (generally reassembled into a contiguous block of encrypted data) calls the specific DRM method to decrypt the data.
The DRM decrypts the data chunk and returns the decrypted data in a buffer. This buffer is then returned via the same RPC mechanism to the OCDM service which puts it back into the GstBuffer, replacing the encrypted chunks with the newly decrypted data. The reassembled GstBuffer is then returned to the gstreamer pipeline where it will be processed by the appropriate decoder filter.
In the handle-based (SVP) use case, the DRM module allocates a secure buffer using an RDK SecAPI method to abstract the platform specifics of the allocation. This is then passed into the SecAPI using the SecCipher_ProcessOpaque() method. The decrypted data is returned in another Sec_OpaqueBufferHandle. This handle is then returned via shared memory to the player process space using a platform specific method. Once back in the ocdm adapter layer the platform specific handle for secure memory (the one that the HW decoder needs to access the memory) is extracted and added to the GstBuffer metadata along with the clear/encrypted data locations so that the HW decoder can reassemble the data before processing.
Applications can process encrypted data in the gstreamer pipeline in two ways. First, they can decrypt the data directly and then push the result into the gstreamer pipeline directly via an appsrc filter. Second, they can setup the pipeline to have a decrypt filter. This filter will take the encrypted data and process it so that it can proceed to the media decoder.
In both cases the encrypted data will be passed to the OCDM service via the opencdm_gstreamer_session_decrypt() function.
/** * \brief Performs decryption based on adapter implementation. * * This method accepts encrypted data and will typically decrypt it * out-of-process (for security reasons). The actual data copying is * performed using a memory-mapped file (for performance reasons). If * the DRM system allows access to decrypted data (i.e. decrypting is * not performed in a TEE), the decryption is performed in-place. * \param session \ref OpenCDMSession instance. * \param buffer Gstreamer buffer containing encrypted data and related * meta data. If applicable, decrypted data will be stored here after * this call returns. * \param subSample Gstreamer buffer containing subsamples size which * has been parsed from protection meta data. * \param subSampleCount count of subsamples * \param IV Gstreamer buffer containing initial vector (IV) used * during decryption. * \param keyID Gstreamer buffer containing keyID to use for decryption * \return Zero on success, non-zero on error. */
EXTERNAL OpenCDMError opencdm_gstreamer_session_decrypt(struct OpenCDMSession* session, GstBuffer* buffer, GstBuffer* subSample, const uint32_t subSampleCount, GstBuffer* IV, GstBuffer* keyID, uint32_t initWithLast15=0, uint32_t width=0, uint32_t height=0);
This function runs in the application process space and will process and marshal the data over RPC to the DRM plugin running in the wpeframework process space.
The opencdm_gstreamer_session_decrypt() function will parse the incoming data, merge all the encrypted data into one block and call the DRM plugin decrypt function.
/** * \brief Performs decryption. * * This method accepts encrypted data and will typically decrypt it * out-of-process (for security reasons). The actual data copying is * performed using a memory-mapped file (for performance reasons). If * the DRM system allows access to decrypted data * (i.e. decrypting is not performed in a TEE), the decryption is * performed in-place. * \param session \ref OpenCDMSession instance. * \param encrypted Buffer containing encrypted data. * If applicable, decrypted * data will be stored here after this call returns. * \param encryptedLength Length of encrypted data buffer (in bytes). * \param IV Initial vector (IV) used during decryption. Can be NULL, * in that case and IV of all zeroes is assumed. * \param IVLength Length of IV buffer (in bytes). * \param keyID keyID to use for decryption * \param keyIDLength Length of keyID buffer (in bytes). * \param initWithLast15 Whether decryption context needs to be * initialized with last 15 bytes. * Currently this only applies to PlayReady DRM. * \return Zero on success, non-zero on error. */ EXTERNAL OpenCDMError opencdm_session_decrypt( struct OpenCDMSession* session, uint8_t encrypted[], const uint32_t encryptedLength, const uint8_t* IV, uint16_t IVLength, const uint8_t* keyId, const uint16_t keyIdLength, uint32_t initWithLast15 = 0, uint32_t width = 0, uint32_t height = 0 );
If the DRM plugin decides that the content requires decryption using the SVP pipeline then the function will return ERROR_NONE_SVP, otherwise for in-place decryption it will return ERROR_NONE.
When the SVP data return is signaled then this function will detokenize the data using the gst-svp-ext library function
boolean svp_buffer_from_token(void* svp_token, void** svp_handle);
which will convert the data back into the structure allocated by the DRM to house the SVP decrypted data.
Then the function will call gst_buffer_append_svp_transform() to assemble the GstBuffer in a manner that is appropriate for the platform implementation.
/* * GstBuffer *buffer - gstreamer buffer that svp * meta data will be appended to * svp_meta_data_t *svp_metadata - svp meta data */ gboolean gst_buffer_append_svp_transform(GstBuffer* buffer, GstBuffer* subSampleBuffer, const guint32 subSampleCount, guint32 encryptedData);
This function takes in the GstBuffer to be returned to the gstreamer pipeline, the returned encrypted data, and the meta data about the CENC clear/encrypted data locations and transforms the buffer into something that the platforms HW media decoders can consume. The SoC specific implementation needed to achive this is hidden in the gst-svp-ext library.
This GstBuffer is then returned to the calling application and processed through the gstreamer filters. Any allocated memory pointers contained in the GstBuffer or its metadata will need to be freed by the hardware decoder.
The opencdm_session_decrypt() function will call into the DRM plugin associated with the session variable using the wpeframeworks built in RPC mechanism. This will end up in the MediaSession::decrypt() function
CDMi_RESULT MediaKeySession::Decrypt( const uint8_t *f_pbSessionKey, uint32_t f_cbSessionKey, const uint32_t *f_pdwSubSampleMapping, uint32_t f_cdwSubSampleMapping, const uint8_t *f_pbIV, uint32_t f_cbIV, const uint8_t *payloadData, uint32_t payloadDataSize, uint32_t *f_pcbOpaqueClearContent, uint8_t **f_ppbOpaqueClearContent, const uint8_t keyIdLength, const uint8_t* f_keyId, bool initWithLast15 #ifdef USE_STREAM_RESOLUTION_API ,uint32_t f_dwStreamWidth ,uint32_t f_dwStreamHeight #endif )
The MediaKeySession object will track the license requirements of the DRM via its specific callback mechanisms and decide if this session will require handle-based decryption (SVP) or in-place decryption. If SVP is indicated, then the MediaSession will call the appropriate DRM entry point for handle-based decryption. The decrypted data is returned as a handle to opaque memory that only the secure processor can access.
This handle will need to get tokenized so that it can be transported across process space and returned to the application memory context.
The gst-svp-ext library will provide an abstraction for the tokenization/detokenization routines.
boolean svp_buffer_to_token(void* svp_handle, void** svp_token);
This function will take the handle returned from the DRM library and turn it into a value that can be dereferenced in the application process space.
The function will then return ERROR_NONE_SVP to indicate that the returned data contains a token and not the actual decrypted data.
The way SVP data is generated, tokenized, and consumed will be different for each specific SoC platform. The gst-svp-ext library will abstract the platform dependencies at each step.
There will be a public interface defined by the RDK and each SoC will have its own implementation in separate repositories that perform the necessary functions.
On some platforms the audio decode path can not support the use of SVP data handles. This will be handled by the dictates of the license provided for the content. If the license states that the content requires handle-based decryption then the DRM will decrypt the data in that format. If the license allows in place decryption then the DRM will return the decrypted data to host accessible memory for decoding.
If forcing the DRM to use handle-based decryption (SVP) then an additional flag or configuration parameter will be needed at the MediaKeySession layer.
This structure defines a chunk of data with both encrypted and clear data segments. It is used to describe sections of the CENC data.
Structure Name | Description |
enc_chunk_data_t | typedef struct enc_data_chunk enc_chunk_data_t; struct enc_data_chunk { guint32 clear_data_size; guint32 enc_data_size; }; |
This structure defines the metadata that is appended to the gstreamer buffer. It contains an array of data chunks and the handle to the secure memory that contains the decrypted data.
Structure Name | Description |
svp_meta_data_t | typedef struct svp_meta_data svp_meta_data_t; struct svp_meta_data { guint32 secure_memory_ptr; guint32 num_chunks; enc_chunk_data *info; }; |
This function transforms the GstBuffer returned to gstreamer to a format that the SoC plarform knows how to consume. Any conversion of the data contained in the final buffer returned to gstreamer is performed in this function
gboolean gst_buffer_append_svp_transform(void * pContext, GstBuffer* buffer, GstBuffer* subSampleBuffer, const guint32 subSampleCount, guint8* encryptedData,const guint32 mappedDataSize=0);
Function Parameter | Description |
---|---|
GstBuffer * | Pointer to gstreamer buffer containing the original CENC data chunk |
GstBuffer * | Pointer to gstreamer buffer containing the map of clear and encrypted chunks for the buffer in parameter 1 |
guint32 | The count of the number of clear and encrypted data pairs |
guint32 | Handle to the opaque data containing the decrypted data |
const guint32 |
This function converts the SVP data handle into a token that will allow a different process to regenerate the SVP data handle and use it in that memory space.
boolean svp_buffer_to_token(void* svp_handle, void** svp_token);
Function Parameter | Description |
---|---|
void * | Handle to the SVP data returned from the DRM |
void** | Pointer to the token that can be used to revive the SVP handle in a different process |
This function converts the SVP token back into a handle that can be used in the memory space of the current process.
boolean svp_buffer_from_token(void* svp_token, void** svp_handle);
Function Parameter | Description |
---|---|
void * | Token used to identify the SVP data handle |
void** | Pointer to the SVP data handle |
This function appends the svp_meta_data_t structure to a GstBuffer for later processing by the TEE responsible for video processing. The function returns TRUE on success, FALSE on failure.
gboolean gst_buffer_append_svp_metadata(GstBuffer * buffer, svp_meta_data_t * svp_metadata, const guint32 mappedDataSize=0);
Function Parameter | Description |
---|---|
GstBuffer * | Pointer to gstreamer buffer containing the original CENC data chunk |
svp_meta_data_t * | Pointer to a the svp meta data structure typedef struct svp_meta_data svp_meta_data_t; struct svp_meta_data { guint32 secure_memory_ptr; guint32 num_chunks; enc_chunk_data_t *info; }; |
Const guint32 | A const mappedDataSize and set to zero |
This function creates a new context to perform all further SVP related operation, if a context is not already created.
gboolean gst_svp_ext_get_context(void ** ppContext, context_type type, unsigned int rpcID);
Function Parameter | Description |
---|---|
Void **ppContnext | Pointer to SVP context created by SOC platform |
Context_type | Indicate type of the context going to create. Possible Values: Client Server |
rpcID | Not Using |
This function uses to set the Caps that is part of SVP context with capabilities passed to it.
gboolean gst_svp_ext_context_set_caps(void * pContext, GstCaps *caps)
Function Parameter | Description |
---|---|
Void *pContext | Pointer to SVP context created by SOC platform |
GstCaps * | Describes the media Type and associated properties of the media type. |
This function free the context created.
gboolean gst_svp_ext_free_context(void * pContext)
Function Parameter | Description |
---|---|
Void *pContext | Pointer to SVP context created by SOC platform |
This function decides which memory (SOC specific Implementation) to be used based on the caps string passed to it.
gboolean gst_svp_ext_transform_caps(GstCaps **caps, gboolean bEncrypted);
Function Parameter | Description |
---|---|
GstCaps ** | Describes the media Type and associated properties of the media type. |
Gboolean bEncrypted | Not Using |
This function allocates a secure memory of Gst buffer size and put the newly allocated secure memory into gstBuffer.
gboolean gst_buffer_svp_transform_from_cleardata_impl(void * pContext, GstBuffer* buffer, media_type mediaType)
Function Parameter | Description |
---|---|
void *pContext | Pointer to SVP context created by SOC platform |
GstBuffer* | Pointer to gstreamer buffer containing the original data chunk |
Media_type | Indicate the type of the media. Possible values are. Audio Video |
Yet to be Implemented.
guint32 gst_buffer_svp_segmented_decrypt_size(guint32 nEncryptedDataSize);
Function Parameter | Description |
---|---|
Guint32 | Indicate the size of Encrypted data |
Yet to be Implemented.
gboolean gst_buffer_append_svp_transform_segmented_init(void * pContext, GstBuffer* buffer, GstBuffer* subSampleBuffer, const guint32 subSampleCount);
Function Parameter | Description |
---|---|
Void * pContext | Pointer to SVP context created by SOC platform |
GstBuffer * | Pointer to gstreamer buffer containing the original data chunk |
GstBuffer * | Pointer to gstreamer buffer containing the map of clear and encrypted chunks for the buffer in parameter 1 |
guint32 | The count of the number of clear and encrypted data pairs |
Yet to be Implemented.
gboolean gst_buffer_append_svp_transform_segmented_process(void * pContext, guint8* encryptedData, guint32 encyptedDataLength);
Function Parameter | Description |
---|---|
Void * pContext | Pointer to SVP context created by SOC platform |
Guint8 *encryptedData | Copy the encrypted data converted as the token at the appropriate index of the buffer based on the subsample inform |
guint32 encryptedDataLength | Indicate the length of the encrypted data |
Yet to be Implemented.
gboolean gst_buffer_append_svp_transform_segmented_finalize(void * pContext);
Function Parameter | Description |
---|---|
Void * pContext | Pointer to SVP context created by SOC platform |
This API returns the size of the svp token created.
guint32 svp_token_size(void);
Function Parameter | Description |
---|---|
void |
This API allocates a secure memory. To this memory the DRM decrypt’s opaque data pointer is copied in the form of the svp_token using the svp_buffer_to_token() API
gboolean svp_buffer_alloc_token(void **token);
Function Parameter | Description |
---|---|
Void **token | Allocate the memory of size as returned by svp_token_size_impl() to the token |
This API free up the memory allocated for the token.
gboolean svp_buffer_free_token(void *token);
Function Parameter | Description |
---|---|
Void *token | Token to free up the memory |
This API checks if the secure buffer memory and sec mem handles are available for usage and are within the allowable thresholds.
gboolean svp_pipeline_buffers_available(void * pContext, media_type mediaType);
Function Parameter | Description |
---|---|
Void * | Token to free up the memory |
Media_type | Indicate the type of the media. Possible values are: Audio Video |
Yet to be Implemented
gboolean gst_buffer_append_init_metadata(GstBuffer * buffer);
Function Parameter | Description |
---|---|
GstBuffer * | Pointer to gstreamer buffer containing the original data chunk |
Yet to be Implemented
uint32_t svp_allocate_secure_buffers(void** ppInBuf, void** ppOutBuf, const uint8_t* pInData, const size_t nDataLen);
Function Parameter | Description |
---|---|
void ** | |
Void ** | |
Const uint8_t * | |
Const size_t |
Yet to be Implemented
uint32_t svp_release_secure_buffers(void* pInBuf, void* pOutBuf, uint8_t* pDataOut, size_t nDataOutMax, void* pContext);
Function Parameter | Description |
---|---|
void * | |
void * | |
uint8_t * | |
size_t | |
void * |
/* * If not stated otherwise in this file or this component's LICENSE file the * following copyright and licenses apply: * * Copyright 2020 RDK Management * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __GST_BUFFER_SVP_H__ #define __GST_BUFFER_SVP_H__ #include <stdint.h> #include <stdio.h> #include <string.h> #include <gst/gst.h> #include <gst/base/gstbytereader.h> #include "gst_svp_performance.h" G_BEGIN_DECLS typedef struct enc_data_chunk enc_chunk_data_t; struct enc_data_chunk { guint32 clear_data_size; guint32 enc_data_size; }; typedef struct svp_meta_data { guint32 secure_memory_ptr; guint32 num_chunks; enc_chunk_data_t *info; } svp_meta_data_t; typedef enum context_type_e { Server = 0, Client, InProcess } context_type; typedef enum TokenType_e { InPlace = 0, Handle = 1 } TokenType; typedef enum media_type_e { Unknown = 0, Video, Audio, Data } media_type; /* * GstBuffer *buffer - gstreamer buffer that svp meta data will be appended to * svp_meta_data_t *svp_metadata - svp meta data */ gboolean gst_svp_ext_get_context(void ** ppContext, context_type type, unsigned int rpcID); gboolean gst_svp_ext_context_set_caps(void * pContext, GstCaps *caps); gboolean gst_svp_ext_free_context(void * pContext); gboolean gst_svp_ext_transform_caps(GstCaps **caps, gboolean bEncrypted); gboolean gst_buffer_svp_transform_from_cleardata(void * pContext, GstBuffer* buffer, media_type mediaType); gboolean gst_buffer_append_svp_transform(void * pContext, GstBuffer* buffer, GstBuffer* subSampleBuffer, const guint32 subSampleCount, guint8* encryptedData,const guint32 mappedDataSize=0); guint32 gst_buffer_svp_segmented_decrypt_size(guint32 nEncryptedDataSize); gboolean gst_buffer_append_svp_transform_segmented_init(void * pContext, GstBuffer* buffer, GstBuffer* subSampleBuffer, const guint32 subSampleCount); gboolean gst_buffer_append_svp_transform_segmented_process(void * pContext, guint8* encryptedData, guint32 encyptedDataLength); gboolean gst_buffer_append_svp_transform_segmented_finalize(void * pContext); gboolean gst_buffer_append_svp_metadata(GstBuffer * buffer, svp_meta_data_t * svp_metadata, const guint32 mappedDataSize=0); gboolean svp_buffer_to_token(void * pContext, void* svp_handle, void* svp_token); gboolean svp_buffer_from_token(void * pContext, void* svp_token, void* svp_handle); guint32 svp_token_size(void); gboolean svp_buffer_alloc_token(void **token); gboolean svp_buffer_free_token(void *token); gboolean svp_pipeline_buffers_available(void * pContext, media_type mediaType); gboolean gst_buffer_append_init_metadata(GstBuffer * buffer); uint32_t svp_allocate_secure_buffers(void** ppInBuf, void** ppOutBuf, const uint8_t* pInData, const size_t nDataLen); uint32_t svp_release_secure_buffers(void* pInBuf, void* pOutBuf, uint8_t* pDataOut, size_t nDataOutMax, void* pContext); G_END_DECLS #endif // __GST_BUFFER_SVP_H__