mirror of
				https://github.com/devine-dl/pywidevine.git
				synced 2025-11-04 03:44:50 +00:00 
			
		
		
		
	PSSH: Implement Widevine to PlayReady conversion
The XML creation is a bit dodgy because I despise XML. If you like lxml, feel free to make a pull request.
This commit is contained in:
		
							parent
							
								
									2648d1c669
								
							
						
					
					
						commit
						c9f55c6e6b
					
				@ -326,6 +326,72 @@ class PSSH:
 | 
				
			|||||||
        self.init_data = cenc_header.SerializeToString()
 | 
					        self.init_data = cenc_header.SerializeToString()
 | 
				
			||||||
        self.system_id = PSSH.SystemId.Widevine
 | 
					        self.system_id = PSSH.SystemId.Widevine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def widevine_to_playready(
 | 
				
			||||||
 | 
					        self,
 | 
				
			||||||
 | 
					        la_url: Optional[str] = None,
 | 
				
			||||||
 | 
					        lui_url: Optional[str] = None,
 | 
				
			||||||
 | 
					        ds_id: Optional[bytes] = None,
 | 
				
			||||||
 | 
					        decryptor_setup: Optional[str] = None,
 | 
				
			||||||
 | 
					        custom_data: Optional[str] = None
 | 
				
			||||||
 | 
					    ) -> None:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Convert Widevine PSSH data to PlayReady v4.3.0.0 PSSH data.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Note that it is impossible to create the CHECKSUM values for AES-CTR Key IDs
 | 
				
			||||||
 | 
					        as you must encrypt the Key ID with the Content Encryption Key using AES-ECB.
 | 
				
			||||||
 | 
					        This may cause software incompatibilities.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Parameters:
 | 
				
			||||||
 | 
					            la_url: Contains the URL for the license acquisition Web service.
 | 
				
			||||||
 | 
					                Only absolute URLs are allowed.
 | 
				
			||||||
 | 
					            lui_url: Contains the URL for the license acquisition Web service.
 | 
				
			||||||
 | 
					                Only absolute URLs are allowed.
 | 
				
			||||||
 | 
					            ds_id: Service ID for the domain service.
 | 
				
			||||||
 | 
					            decryptor_setup: This tag may only contain the value "ONDEMAND". It
 | 
				
			||||||
 | 
					                indicates to an application that it should not expect the full
 | 
				
			||||||
 | 
					                license chain for the content to be available for acquisition, or
 | 
				
			||||||
 | 
					                already present on the client machine, prior to setting up the
 | 
				
			||||||
 | 
					                media graph. If this tag is not set then it indicates that an
 | 
				
			||||||
 | 
					                application can enforce the license to be acquired, or already
 | 
				
			||||||
 | 
					                present on the client machine, prior to setting up the media graph.
 | 
				
			||||||
 | 
					            custom_data: The content author can add custom XML inside this
 | 
				
			||||||
 | 
					                element. Microsoft code does not act on any data contained inside
 | 
				
			||||||
 | 
					                this element. The Syntax of this params XML is not validated.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if self.system_id != PSSH.SystemId.Widevine:
 | 
				
			||||||
 | 
					            raise ValueError(f"This is not a Widevine PSSH, {self.system_id}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        key_ids_xml = ""
 | 
				
			||||||
 | 
					        for key_id in self.key_ids:
 | 
				
			||||||
 | 
					            # Note that it's impossible to create the CHECKSUM value without the Key for the KID
 | 
				
			||||||
 | 
					            key_ids_xml += f"""
 | 
				
			||||||
 | 
					            <KID ALGID="AESCTR" VALUE="{base64.b64encode(key_id.bytes).decode()}"></KID>
 | 
				
			||||||
 | 
					            """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        prr_value = f"""
 | 
				
			||||||
 | 
					        <WRMHEADER xmlns="http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader" version="4.3.0.0">
 | 
				
			||||||
 | 
					            <DATA>
 | 
				
			||||||
 | 
					                <PROTECTINFO>
 | 
				
			||||||
 | 
					                    <KIDS>{key_ids_xml}</KIDS>
 | 
				
			||||||
 | 
					                </PROTECTINFO>
 | 
				
			||||||
 | 
					                {f'<LA_URL>%s</LA_URL>' % la_url if la_url else ''}
 | 
				
			||||||
 | 
					                {f'<LUI_URL>%s</LUI_URL>' % lui_url if lui_url else ''}
 | 
				
			||||||
 | 
					                {f'<DS_ID>%s</DS_ID>' % base64.b64encode(ds_id).decode() if ds_id else ''}
 | 
				
			||||||
 | 
					                {f'<DECRYPTORSETUP>%s</DECRYPTORSETUP>' % decryptor_setup if decryptor_setup else ''}
 | 
				
			||||||
 | 
					                {f'<CUSTOMATTRIBUTES xmlns="">%s</CUSTOMATTRIBUTES>' % custom_data if custom_data else ''}
 | 
				
			||||||
 | 
					            </DATA>
 | 
				
			||||||
 | 
					        </WRMHEADER>
 | 
				
			||||||
 | 
					        """.encode("utf-16-le")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        prr_length = len(prr_value).to_bytes(2, "little")
 | 
				
			||||||
 | 
					        prr_type = (1).to_bytes(2, "little")  # Has PlayReadyHeader
 | 
				
			||||||
 | 
					        pro_record_count = (1).to_bytes(2, "little")
 | 
				
			||||||
 | 
					        pro = pro_record_count + prr_type + prr_length + prr_value
 | 
				
			||||||
 | 
					        pro = (len(pro) + 4).to_bytes(4, "little") + pro
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.init_data = pro
 | 
				
			||||||
 | 
					        self.system_id = PSSH.SystemId.PlayReady
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def set_key_ids(self, key_ids: list[UUID]) -> None:
 | 
					    def set_key_ids(self, key_ids: list[UUID]) -> None:
 | 
				
			||||||
        """Overwrite all Key IDs with the specified Key IDs."""
 | 
					        """Overwrite all Key IDs with the specified Key IDs."""
 | 
				
			||||||
        if self.system_id != PSSH.SystemId.Widevine:
 | 
					        if self.system_id != PSSH.SystemId.Widevine:
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user