BuyDRM - Widevine and Playready

Qencode and BuyDRM integration uses KeyOS CPIX API. Detailed CPIX Implementation Guidelines from BuyDRM are located here (requires BuyDRM login).

Currently you should use python2 Qencode SDK to work with BuyDRM. If you need to use BuyDRM with any other Qencode SDK or programming language, please contact Qencode support.

1Prerequisites: obtain BuyDRM x509 End User's certificate

In order to use Qencode with BuyDRM you need to make sure you have BuyDRM x509 End User's certificate. It consists of two files in .pem format:

  • private key (e.g. user_private_key.pem)
  • public key (e.g. user_public_cert.pem)

If you are a BuyDRM client and don't have the certificate yet, please contact BuyDRM support for further instructions.

2Prerequisites: install Qencode SDK for python2

For the most of platforms you can install Qencode SDK for python2 with the following command:

pip install qencode

3Generate signed CPIX request

Specify paths to private and public keys. Make sure you are not exposing your private .pem file to unauthorized access.
# specify path to your BuyDRM certificate files
USER_PVT_KEY_PATH = './keys/user_private_key.pem'
USER_PUB_CERT_PATH = './keys/user_public_cert.pem'

key_ids = [
  { 'kid': str(uuid.uuid4()), 'track_type': 'SD' },
  { 'kid': str(uuid.uuid4()), 'track_type': 'HD' }
]
media_id = 'my first stream'
# this creates signed request to BuyDRM
  cpix_request = create_cpix_user_request(
    key_ids, media_id, USER_PVT_KEY_PATH, USER_PUB_CERT_PATH,
    use_playready=True, use_widevine=True
  )

4Add "buydrm_drm" object to your Qencode API request JSON

"buydrm_drm" object must contain "request" attribute with base64-encoded signed CPIX request.

QUERY = """
{
  "query": {
    "format": [
      {
        "output": "advanced_dash",
        "destination": {
          ...
        },
        "stream": [
          ...
        ],
        "buydrm_drm": {
          "request": "{cpix_request}"
        }
      }
    ],
    "source": "https://nyc3.s3.qencode.com/qencode/bbb_30s.mp4"
  }
}
"""

Prepare query JSON and launch a transcoding job:

client = qencode.client(API_KEY)
task = client.create_task()
query = QUERY.replace('{cpix_request}', base64.b64encode(cpix_request))
task.custom_start(query)

The full example code is available here.

5Testing playback

To configure your player for playback of the content encrypted with BuyDRM you need to provide the following settings:

Here's an example of configuring Qencode Player:

var params = {
    licenseKey: "f223fb50-8d26-6b9e-637c-eb62a5e79edb",
    videoSources: {
        src: "https://yourserver.com/content/playlist.mpd",
        emeHeaders: {
            'customdata': "PEtleU9TQXV0aGVudGljYXRpb25YTUw+CjxEYXRhPgogIDxHZW5lcmF0aW9uVGltZT4yMDIxLTA0LTA0IDA5OjU0OjI1Ljc3MDwvR2VuZXJhdGlvblRpbWU+CiAgPEV4cGlyYXRpb25UaW1lPjIwMjEtMDUtMDQgMDk6NTQ6MjUuNzcwPC9FeHBpcmF0aW9uVGltZT4KICA8VW5pcXVlSWQ+NzQxMjJjNjE3ODk3OTJiZmZjYmVlYmRlYzE0ZTExMzg8L1VuaXF1ZUlkPgogIDxSU0FQdWJLZXlJZD45NjZlMGM4MWRkN2UyZDY4NzFlNmNmNmY2ZmFiZmFhZDwvUlNBUHViS2V5SWQ+CiAgPFdpZGV2aW5lUG9saWN5IGZsX0NhblBsYXk9InRydWUiIGZsX0NhblBlcnNpc3Q9ImZhbHNlIiAvPgogIDxXaWRldmluZUNvbnRlbnRLZXlTcGVjIFRyYWNrVHlwZT0iSEQiPgogICAgPFNlY3VyaXR5TGV2ZWw+MTwvU2VjdXJpdHlMZXZlbD4KICA8L1dpZGV2aW5lQ29udGVudEtleVNwZWM+CiAgPEZhaXJQbGF5UG9saWN5IHBlcnNpc3RlbnQ9ImZhbHNlIiAvPgogIDxMaWNlbnNlIHR5cGU9InNpbXBsZSIgLz4KPC9EYXRhPgo8U2lnbmF0dXJlPmhsQld4aFRJN3NBQkZxOEdZMVM4Nzk4T0ZwenBIS0c0enFIb3NYWUZQYmhoejcyVWFueDFheHJFRU9oREdYTThVYjlmZW1qYjNMckhUU2JqKzRxa0tXWEczR1ZSQ0hVYlJ4SXVlRWdGdXdaQkFSMHY2UnM2R0dvcDdiRXBTSVNIaWQwWXVWajZZa05CV2JVa1FLa25qbnY1VU83Z1JYdEdqSkZvN3pydzNPdFpDd0xabGNwRnRwRytqT0dsV3A1U2tSOTNQZ1oxZFhZaWlSZWNLZVRkZG1DeDBPRlQxZHZFbWlDWXRzWkpCcnpVOFBmYkZ6MXdWR3I2TFlaK1BPRGtEeExRQ1ZVcGJtNXhGVnRBNk5hT0xCYlpITDVXYkN6MHB2N0c5OW1iaEszdkZIQlJDM241L01lYXZKcXB2Q0NXSWY5OWVQVnBMRFU2V2Y3bGJUMHBYQT09PC9TaWduYXR1cmU+CjwvS2V5T1NBdXRoZW50aWNhdGlvblhNTD4=",
        },
        keySystems: {
            'com.widevine.alpha': "https://wv-keyos.licensekeyserver.com/",
        },
    },
}

qPlayer('my_player', params, function() { 
    // optional callback function after player is loaded   
    console.log("Player is loaded");                                    
});