[pssh] Support widevine pssh generation with protection_scheme

- Also import the version of the protobuf bundled in packager first,
  this avoids importing the installed version of the protobuf, which
  may not be compatible with this script.
- Print help if no argument is supplied.

Fixes #162

Change-Id: I1b5e87ba7fb51e81b0d4dd3791aaeb37ee0fd6ce
This commit is contained in:
Kongqun Yang 2016-10-07 18:32:00 -07:00
parent 4f9bbe3769
commit 472fae24f2
2 changed files with 32 additions and 7 deletions

View File

@ -34,4 +34,9 @@ message WidevinePsshData {
// Optional protected context for group content. The grouped_license is a // Optional protected context for group content. The grouped_license is a
// serialized SignedMessage. // serialized SignedMessage.
optional bytes grouped_license = 8; optional bytes grouped_license = 8;
// Protection scheme identifying the encryption algorithm. Represented as one
// of the following 4CC values: 'cenc' (AES-CTR), 'cbc1' (AES-CBC),
// 'cens' (AES-CTR subsample), 'cbcs' (AES-CBC subsample).
optional uint32 protection_scheme = 9;
} }

View File

@ -11,20 +11,21 @@ import argparse
import base64 import base64
import itertools import itertools
import os import os
import struct
import sys import sys
# Append the local protobuf location. Use a path relative to the tools/pssh # Append the local protobuf location. Use a path relative to the tools/pssh
# folder where this file should be found. This allows the file to be executed # folder where this file should be found. This allows the file to be executed
# from any directory. # from any directory.
_pssh_dir = os.path.dirname(os.path.realpath(__file__)) _pssh_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(_pssh_dir, '../../third_party/protobuf/python')) sys.path.insert(0, os.path.join(_pssh_dir, '../../third_party/protobuf/python'))
# Import the widevine protobuf. Use either Release or Debug. # Import the widevine protobuf. Use either Release or Debug.
_proto_path_format = os.path.join( _proto_path_format = os.path.join(
_pssh_dir, '../../../out/%s/pyproto/packager/media/base') _pssh_dir, '../../../out/%s/pyproto/packager/media/base')
if os.path.isdir(_proto_path_format % 'Release'): if os.path.isdir(_proto_path_format % 'Release'):
sys.path.append(_proto_path_format % 'Release') sys.path.insert(0, _proto_path_format % 'Release')
else: else:
sys.path.append(_proto_path_format % 'Debug') sys.path.insert(0, _proto_path_format % 'Debug')
try: try:
import widevine_pssh_data_pb2 # pylint: disable=g-import-not-at-top import widevine_pssh_data_pb2 # pylint: disable=g-import-not-at-top
except ImportError: except ImportError:
@ -157,11 +158,15 @@ def _create_uuid(data):
'-' + ret[20:]) '-' + ret[20:])
def _generate_widevine_data(key_ids, content_id, provider): def _generate_widevine_data(key_ids, content_id, provider, protection_scheme):
"""Generate widevine pssh data."""
wv = widevine_pssh_data_pb2.WidevinePsshData() wv = widevine_pssh_data_pb2.WidevinePsshData()
wv.key_id.extend(key_ids) wv.key_id.extend(key_ids)
wv.provider = provider or '' wv.provider = provider or ''
wv.content_id = content_id wv.content_id = content_id
# 'cenc' is the default, so omitted to save bytes.
if protection_scheme and protection_scheme != 'cenc':
wv.protection_scheme = struct.unpack('>L', protection_scheme)[0]
return wv.SerializeToString() return wv.SerializeToString()
@ -183,6 +188,9 @@ def _parse_widevine_data(data):
ret.append('Policy: ' + wv.policy) ret.append('Policy: ' + wv.policy)
if wv.HasField('crypto_period_index'): if wv.HasField('crypto_period_index'):
ret.append('Crypto Period Index: %d' % wv.crypto_period_index) ret.append('Crypto Period Index: %d' % wv.crypto_period_index)
if wv.HasField('protection_scheme'):
protection_scheme = struct.pack('>L', wv.protection_scheme)
ret.append('Protection Scheme: %s' % protection_scheme)
return ret return ret
@ -292,8 +300,9 @@ it will appear before the generated one.
An alternative to --pssh-data is to generate Widevine PSSH data. This is only An alternative to --pssh-data is to generate Widevine PSSH data. This is only
valid with --widevine-system-id. Passing --content-id will make it generate valid with --widevine-system-id. Passing --content-id will make it generate
Widevine PSSH data instead. You can optionally add --provider. It will Widevine PSSH data instead. You can optionally add --provider and/or
generate a v0 PSSH box for compatibility reasons.""") --protection-scheme. It will generate a v0 PSSH box for compatibility
reasons.""")
formats = parser.add_mutually_exclusive_group() formats = parser.add_mutually_exclusive_group()
formats.add_argument('--base64', formats.add_argument('--base64',
@ -358,6 +367,9 @@ generate a v0 PSSH box for compatibility reasons.""")
extra.add_argument('--provider', extra.add_argument('--provider',
metavar='<string>', metavar='<string>',
help='Sets the provider of the Widevine PSSH data') help='Sets the provider of the Widevine PSSH data')
extra.add_argument('--protection-scheme',
choices=['cenc', 'cbcs', 'cens', 'cbc1'],
help='Set the protection scheme of the Widevine PSSH data')
return parser return parser
@ -366,6 +378,9 @@ def main(all_args):
boxes = [] boxes = []
output_format = None output_format = None
parser = _create_argument_parser() parser = _create_argument_parser()
if not all_args:
parser.print_help()
sys.exit(1)
arg_groups = _split_list_on(all_args, '--') arg_groups = _split_list_on(all_args, '--')
for args in arg_groups: for args in arg_groups:
ns = parser.parse_args(args) ns = parser.parse_args(args)
@ -382,10 +397,15 @@ def main(all_args):
pssh_data = ns.pssh_data pssh_data = ns.pssh_data
if pssh_data and ns.content_id: if pssh_data and ns.content_id:
raise Exception('Cannot specify both --pssh-data and --content-id') raise Exception('Cannot specify both --pssh-data and --content-id')
if ns.protection_scheme:
if ns.system_id != WIDEVINE_SYSTEM_ID:
raise Exception(
'--protection-scheme only valid with Widevine system ID')
if ns.content_id: if ns.content_id:
if ns.system_id != WIDEVINE_SYSTEM_ID: if ns.system_id != WIDEVINE_SYSTEM_ID:
raise Exception('--content-id only valid with Widevine system ID') raise Exception('--content-id only valid with Widevine system ID')
pssh_data = _generate_widevine_data(ns.key_id, ns.content_id, ns.provider) pssh_data = _generate_widevine_data(ns.key_id, ns.content_id, ns.provider,
ns.protection_scheme)
# Ignore if we have no data. # Ignore if we have no data.
if not pssh_data and not ns.key_id and not ns.system_id: if not pssh_data and not ns.key_id and not ns.system_id: