fragmentcollector_mpd.cpp
/**
 * @brief Process content protection of adaptation
 *
 * @param[in] adaptationSet Adaptation set object
 * @param[in] mediaType     Type of track
 */
@brief Process content protection of adaptation
@param[in] adaptationSet Adaptation set object
@param[in] mediaType     Type of track
@brief Process content protection of adaptation @param [ in ] adaptationSet Adaptation set object @param [ in ] mediaType Type of track
void PrivateStreamAbstractionMPD::ProcessContentProtection(IAdaptationSet * adaptationSet,MediaType mediaType)
{
	const vector<IDescriptor*> contentProt = adaptationSet->GetContentProtection();
	unsigned char* data   = NULL;
	unsigned char* wvData = NULL;
	unsigned char* prData = NULL;
	size_t dataLength     = 0;
	size_t wvDataLength   = 0;
	size_t prDataLength   = 0;
	bool isWidevine       = false;
	unsigned char* contentMetadata = NULL;
	AAMPLOG_TRACE("[HHH]contentProt.size=%d\n", contentProt.size());
	for (unsigned iContentProt = 0; iContentProt < contentProt.size(); iContentProt++)
	{
		if (contentProt.at(iContentProt)->GetSchemeIdUri().find(COMCAST_DRM_INFO_ID) != string::npos)
		{
			logprintf("[HHH]Comcast DRM Agnostic CENC system ID found!\n");
			const vector<INode*> node = contentProt.at(iContentProt)->GetAdditionalSubNodes();
			string psshData = node.at(0)->GetText();
			data = base64_Decode(psshData.c_str(), &dataLength);
			if(gpGlobalConfig->logging.trace)
			{
				logprintf("content metadata from manifest; length %d\n", dataLength);
				for (int j = 0; j < dataLength; j++)
				{
					logprintf("0x%02x ", data[j]);
					if ((j+1)%8==0) logprintf("\n");
				}
				logprintf("\n");
			}
			if(dataLength != 0)
			{
				int contentMetadataLen = 0;
				contentMetadata = _extractWVContentMetadataFromPssh((const char*)data, dataLength, &contentMetadataLen);
				if(gpGlobalConfig->logging.trace)
				{
					logprintf("content metadata from PSSH; length %d\n", contentMetadataLen);
					for (int j = 0; j < contentMetadataLen; j++)
					{
						logprintf("0x%02x ", contentMetadata[j]);
						if ((j+1)%8==0) logprintf("\n");
					}
					logprintf("\n");
				}
			}
			if(data) free(data);
			continue;
		}
		if (contentProt.at(iContentProt)->GetSchemeIdUri().find(WIDEVINE_SYSTEM_ID) != string::npos)
		{
			logprintf("[HHH]Widevine system ID found!\n");
			const vector<INode*> node = contentProt.at(iContentProt)->GetAdditionalSubNodes();
			string psshData = node.at(0)->GetText();
			wvData = base64_Decode(psshData.c_str(), &wvDataLength);
			mContext->hasDrm = true;
			if(gpGlobalConfig->logging.trace)
			{
				logprintf("init data from manifest; length %d\n", wvDataLength);
				for (int j = 0; j < wvDataLength; j++)
				{
					logprintf("%c", wvData[j]);
				}
				logprintf("\n");
			}
			continue;
		}
		if (contentProt.at(iContentProt)->GetSchemeIdUri().find(PLAYREADY_SYSTEM_ID) != string::npos)
		{
			logprintf("[HHH]Playready system ID found!\n");
			const vector<INode*> node = contentProt.at(iContentProt)->GetAdditionalSubNodes();
			string psshData = node.at(0)->GetText();
			prData = base64_Decode(psshData.c_str(), &prDataLength);
			mContext->hasDrm = true;
			if(gpGlobalConfig->logging.trace)
			{
				logprintf("init data from manifest; length %d\n", prDataLength);
				for (int j = 0; j < prDataLength; j++)
				{
					logprintf("%c", prData[j]);
				}
				logprintf("\n");
			}
			continue;
		}
	}
	if(wvData != NULL && wvDataLength > 0 && ((DRMSystems)gpGlobalConfig->preferredDrm == eDRM_WideVine || prData == NULL))
	{
		isWidevine = true;
		data = wvData;
		dataLength = wvDataLength;
		if(prData){
			free(prData);
		}
	}else if(prData != NULL && prDataLength > 0)
	{
		isWidevine = false;
		data = prData;
		dataLength = prDataLength;
		if(wvData){
			free(wvData);
		}
	}
	if(dataLength != 0)
	{
		int keyIdLen = 0;
		unsigned char* keyId = NULL;
		aamp->licenceFromManifest = true;
		keyId = _extractKeyIdFromPssh((const char*)data, dataLength, &keyIdLen, isWidevine);
		if (!(keyIdLen == lastProcessedKeyIdLen && 0 == memcmp(lastProcessedKeyId, keyId, keyIdLen)))
		{
			struct DrmSessionParams* sessionParams = (struct DrmSessionParams*)malloc(sizeof(struct DrmSessionParams));
			sessionParams->initData = data;
			sessionParams->initDataLen = dataLength;
			sessionParams->stream_type = mediaType;
			sessionParams->aamp = aamp;
			sessionParams->isWidevine = isWidevine;
			sessionParams->contentMetadata = contentMetadata;
			if(drmSessionThreadStarted) 
			{
				void *value_ptr = NULL;
				int rc = pthread_join(createDRMSessionThreadID, &value_ptr);
				if (rc != 0)
				{
					logprintf("pthread_join returned %d for createDRMSession Thread\n", rc);
				}
				drmSessionThreadStarted = false;
			}
			if(0 == pthread_create(&createDRMSessionThreadID,NULL,CreateDRMSession,sessionParams))
			{
				drmSessionThreadStarted = true;
				if(lastProcessedKeyId)
				{
					free(lastProcessedKeyId);
				}
				lastProcessedKeyId =  keyId;
				lastProcessedKeyIdLen = keyIdLen;
				aamp->setCurrentDrm(isWidevine?eDRM_WideVine:eDRM_PlayReady);
			}
			else
			{
				logprintf("%s %d pthread_create failed for CreateDRMSession : error code %d, %s", __FUNCTION__, __LINE__, errno, strerror(errno));
			}
		}
		else
		{
			if(keyId)
			{
				free(keyId);
			}
			free(data);
		}
	}
}
void PrivateStreamAbstractionMPD :: ProcessContentProtection ( IAdaptationSet * adaptationSet , MediaType mediaType ) { const vector < IDescriptor * > contentProt = adaptationSet -> GetContentProtection ( ) ; unsigned char * data = NULL ; unsigned char * wvData = NULL ; unsigned char * prData = NULL ; size_t dataLength = 0 ; size_t wvDataLength = 0 ; size_t prDataLength = 0 ; bool isWidevine = false ; unsigned char * contentMetadata = NULL ; AAMPLOG_TRACE ( " \n " , contentProt . size ( ) ) ; for ( unsigned iContentProt = 0 ; iContentProt < contentProt . size ( ) ; iContentProt ++ ) { if ( contentProt . at ( iContentProt ) -> GetSchemeIdUri ( ) . find ( COMCAST_DRM_INFO_ID ) != string :: npos ) { logprintf ( " \n " ) ; const vector < INode * > node = contentProt . at ( iContentProt ) -> GetAdditionalSubNodes ( ) ; string psshData = node . at ( 0 ) -> GetText ( ) ; data = base64_Decode ( psshData . c_str ( ) , & dataLength ) ; if ( gpGlobalConfig -> logging . trace ) { logprintf ( " \n " , dataLength ) ; for ( int j = 0 ; j < dataLength ; j ++ ) { logprintf ( " " , data [ j ] ) ; if ( ( j + 1 ) % 8 == 0 ) logprintf ( " \n " ) ; } logprintf ( " \n " ) ; } if ( dataLength != 0 ) { int contentMetadataLen = 0 ; contentMetadata = _extractWVContentMetadataFromPssh ( ( const char * ) data , dataLength , & contentMetadataLen ) ; if ( gpGlobalConfig -> logging . trace ) { logprintf ( " \n " , contentMetadataLen ) ; for ( int j = 0 ; j < contentMetadataLen ; j ++ ) { logprintf ( " " , contentMetadata [ j ] ) ; if ( ( j + 1 ) % 8 == 0 ) logprintf ( " \n " ) ; } logprintf ( " \n " ) ; } } if ( data ) free ( data ) ; continue ; } if ( contentProt . at ( iContentProt ) -> GetSchemeIdUri ( ) . find ( WIDEVINE_SYSTEM_ID ) != string :: npos ) { logprintf ( " \n " ) ; const vector < INode * > node = contentProt . at ( iContentProt ) -> GetAdditionalSubNodes ( ) ; string psshData = node . at ( 0 ) -> GetText ( ) ; wvData = base64_Decode ( psshData . c_str ( ) , & wvDataLength ) ; mContext -> hasDrm = true ; if ( gpGlobalConfig -> logging . trace ) { logprintf ( " \n " , wvDataLength ) ; for ( int j = 0 ; j < wvDataLength ; j ++ ) { logprintf ( " " , wvData [ j ] ) ; } logprintf ( " \n " ) ; } continue ; } if ( contentProt . at ( iContentProt ) -> GetSchemeIdUri ( ) . find ( PLAYREADY_SYSTEM_ID ) != string :: npos ) { logprintf ( " \n " ) ; const vector < INode * > node = contentProt . at ( iContentProt ) -> GetAdditionalSubNodes ( ) ; string psshData = node . at ( 0 ) -> GetText ( ) ; prData = base64_Decode ( psshData . c_str ( ) , & prDataLength ) ; mContext -> hasDrm = true ; if ( gpGlobalConfig -> logging . trace ) { logprintf ( " \n " , prDataLength ) ; for ( int j = 0 ; j < prDataLength ; j ++ ) { logprintf ( " " , prData [ j ] ) ; } logprintf ( " \n " ) ; } continue ; } } if ( wvData != NULL && wvDataLength > 0 && ( ( DRMSystems ) gpGlobalConfig -> preferredDrm == eDRM_WideVine || prData == NULL ) ) { isWidevine = true ; data = wvData ; dataLength = wvDataLength ; if ( prData ) { free ( prData ) ; } } else if ( prData != NULL && prDataLength > 0 ) { isWidevine = false ; data = prData ; dataLength = prDataLength ; if ( wvData ) { free ( wvData ) ; } } if ( dataLength != 0 ) { int keyIdLen = 0 ; unsigned char * keyId = NULL ; aamp -> licenceFromManifest = true ; keyId = _extractKeyIdFromPssh ( ( const char * ) data , dataLength , & keyIdLen , isWidevine ) ; if ( ! ( keyIdLen == lastProcessedKeyIdLen && 0 == memcmp ( lastProcessedKeyId , keyId , keyIdLen ) ) ) { struct DrmSessionParams * sessionParams = ( struct DrmSessionParams * ) malloc ( sizeof ( struct DrmSessionParams ) ) ; sessionParams -> initData = data ; sessionParams -> initDataLen = dataLength ; sessionParams -> stream_type = mediaType ; sessionParams -> aamp = aamp ; sessionParams -> isWidevine = isWidevine ; sessionParams -> contentMetadata = contentMetadata ; if ( drmSessionThreadStarted ) { void * value_ptr = NULL ; int rc = pthread_join ( createDRMSessionThreadID , & value_ptr ) ; if ( rc != 0 ) { logprintf ( " \n " , rc ) ; } drmSessionThreadStarted = false ; } if ( 0 == pthread_create ( & createDRMSessionThreadID , NULL , CreateDRMSession , sessionParams ) ) { drmSessionThreadStarted = true ; if ( lastProcessedKeyId ) { free ( lastProcessedKeyId ) ; } lastProcessedKeyId = keyId ; lastProcessedKeyIdLen = keyIdLen ; aamp -> setCurrentDrm ( isWidevine ? eDRM_WideVine : eDRM_PlayReady ) ; } else { logprintf ( " " , __FUNCTION__ , __LINE__ , errno , strerror ( errno ) ) ; } } else { if ( keyId ) { free ( keyId ) ; } free ( data ) ; } } }
@brief Process content protection of adaptation
 @param[in] adaptationSet Adaptation set object
 @param[in] mediaType     Type of track
@brief Process content protection of adaptation @param [ in ] adaptationSet Adaptation set object @param [ in ] mediaType Type of track
// Choose widevine if both widevine and playready contentprotectiondata sections are presenet. // TODO: We need to add more flexible selection logic here (using aamp.cfg etc) //In the case of license rotation /*
			* Memory allocated for data via base64_Decode() and memory for sessionParams
			* is released in CreateDRMSession.
			* Memory for keyId allocated in _extractDataFromPssh() is released
			* a. In the else block of this 'if', if it's previously processed keyID
			* b. Assigned to lastProcessedKeyId which is released before new keyID is assigned
			*     or in the distructor of PrivateStreamAbstractionMPD
			*/