RDK SVP Design(Specification)

Created on March 26, 2024


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.

1. Introduction

1.1. Overview

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.

1.2. Purpose of Document

This document defines data types and method interfaces that comprise the RDK SVP architectural design.


2. References


3. Abbreviations and Acronyms

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


4. SVP Decrypt Software Stack

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.

SVPDecryptSoftwareStack


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.

4.1. Gstreamer Decrypter Filter/Application Direct Connect

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.

4.2. WPEFramework

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.

4.3. OCDM MediaSession

 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.


5. Platform Abstractions

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.


6. Support for multiple decode paths

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.


7. GST-SVP-EXT

7.1. Data Structures

7.1.1. Encrypted Data Chunk

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;

};

7.1.2. SVP Meta Data

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;

};

 

7.2. Methods

7.2.1.1. gst_buffer_append_svp_transform

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


7.2.1.2. svp_buffer_to_token

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

7.2.1.3. svp_buffer_from_token

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

7.2.1.4. gst_buffer_append_svp_metadata

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

7.2.1.5. gst_svp_ext_get_context

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

7.2.1.6. gst_svp_ext_context_set_caps

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.


7.2.1.7. gst_svp_ext_free_context

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

7.2.1.8. gst_svp_ext_transform_caps

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

7.2.1.9. gst_svp_ext_transform_from_clear_data

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

7.2.1.10. gst_buffer_svp_segmented_decrypt_size

Yet to be Implemented.

guint32  gst_buffer_svp_segmented_decrypt_size(guint32 nEncryptedDataSize);

Function Parameter

Description

Guint32

Indicate the size of Encrypted data

7.2.1.11. gst_buffer_append_svp_transform_segmented_init

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

7.2.1.12. gst_buffer_append_svp_transform_segmented_process

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

7.2.1.13. gst_buffer_append_svp_transform_segmented_finalize

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

7.2.1.14. svp_token_size

This API returns the size of the svp token created.

guint32  svp_token_size(void);

Function Parameter

Description

void


7.2.1.15. svp_buffer_allocation_token

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

7.2.1.16. svp_buffer_free_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

7.2.1.17. svp_pipeline_buffers_available

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

7.2.1.18. gst_buffer_append_init_metadata

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

7.2.1.19. svp_allocate_secure_buffers

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


7.2.1.20. svp_release_secure_buffers

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 *


 

7.3. Header file

/*
 * 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__

Go To Top