示例#1
0
    def check_subtitle_cpl_duplicated_uuid(self, playlist, asset, folder):
        """ Issue when using the same UUID for Subtitle XML and MXF.

            This can cause issue on certain hardware, eg. Dolby server using
            a version prior to 2.8.18, see patch notes extract below :
            Fixed an error where the server did not extract SMPTE timedtext
            (as in subtitles/captions) from the MXF file that was incorrectly
            created using the same universally unique identifier (UUID) for
            the MXF file and the main XML inside the MXF files. [DCPLYR-3418]
        """
        st_dict = self.st_util.get_subtitle_xml(asset, folder)
        if not st_dict:
            return

        st_uuid = self.st_util.get_subtitle_uuid(st_dict)
        _, asset = asset

        if self.dcp.schema == 'SMPTE':
            mxf_uuid = asset['Probe'].get('AssetUUID', "")
            if st_uuid == mxf_uuid:
                raise CheckException(
                    "Using the same UUID for Subtitle ID and MXF UUID can "
                    "cause issue on Dolby server prior to 2.8.18 firmware.")
示例#2
0
    def check_cpl_reel_coherence(self, playlist):
        """ CPL reel attributes shall be coherents across all reels. """
        cpl = playlist['Info']['CompositionPlaylist']

        coherence_keys = [
            'EditRate',
            'FrameRate',
            'HighFrameRate',
            'ScreenAspectRatio',
            'Stereoscopic',
            'Resolution',
            'DecompositionLevels',
            'Precincts',
            'ChannelCount',
            'ChannelFormat',
            'ChannelConfiguration',
            'SoundLanguage',
        ]

        for k in coherence_keys:
            if cpl[k] == "Mixed":
                raise CheckException(
                    "{} is not coherent for all reels".format(k))
示例#3
0
    def check_dcnc_field_claim_audio(self, playlist, fields):
        """ Audio format from CPL and ContentTitleText shall match. """
        # NOTE : MXF track count don't seems to be related to the actual
        # number of audio channels (there could be metadata and/or reserved
        # tracks).
        # TODO : SMPTE 428-12 add SoundField UL structure that could be used
        # to have a more meanigful check
        audio_format = fields['AudioType'].get('Channels')
        audio_map = DCP_SETTINGS['sound']['format_channels']
        sounds = list(
            list_cpl_assets(playlist,
                            filters=['Sound'],
                            required_keys=['Probe']))

        if sounds and audio_format:
            _, asset = sounds[0]
            asset_cc = asset['Probe']['ChannelCount']
            cpl_cc = audio_map.get(audio_format)

            if cpl_cc and asset_cc < cpl_cc:
                raise CheckException(
                    "ContentTitle claims {} audio but CPL contains only "
                    " {} channels".format(audio_format, asset_cc))
示例#4
0
    def check_certif_date(self, cert, index):
        """ Certificate date validation.

            Reference :
                SMPTE 430-2-2017 6.2 9
        """
        # 9. Check time validity
        # Note : Date are formatted in ASN.1 Time YYYYMMDDhhmmssZ
        time_format = '%Y%m%d%H%M%SZ'

        if self.context_time == 'NOW':
            validity_time = datetime.now()
        elif self.context_time != '':
            validity_time = datetime.strptime(self.context_time, time_format)

        if self.context_time:
            not_before_str = cert.get_notBefore().decode("utf-8")
            not_before = datetime.strptime(not_before_str, time_format)
            not_after_str = cert.get_notAfter().decode("utf-8")
            not_after = datetime.strptime(not_after_str, '%Y%m%d%H%M%SZ')

            if validity_time < not_before or validity_time > not_after:
                raise CheckException("Certificate is not valid at this time")
示例#5
0
    def check_subtitle_cpl_font_ref(self, playlist, asset, folder):
        """ Subtitle font references check.

            Reference :
                SMPTE ST 428-7-2014 5.11.1
                Interop TI Subtitle Spec 1.1 2.7
        """
        st_dict = self.st_util.get_subtitle_xml(asset, folder)
        if not st_dict:
            return

        if self.dcp.schema == 'SMPTE':
            font_id = self.st_util.get_subtitle_elem(st_dict, 'LoadFont@ID')
            font_ref = keys_by_name_dict(st_dict, 'Font@ID')
        else:
            font_id = self.st_util.get_subtitle_elem(st_dict, 'LoadFont@Id')
            font_ref = keys_by_name_dict(st_dict, 'Font@Id')

        for ref in font_ref:
            if ref != font_id:
                raise CheckException(
                    "Subtitle reference unknown font {} (loaded {})".format(
                        ref, font_id))
示例#6
0
    def metadata_cmp_pair(
        self,
        playlist,
        metadata,
        type_a,
        type_b,
        cmp=operator.eq,
        message=""
    ):
        for reel in playlist['Info']['CompositionPlaylist']['ReelList']:
            metadatas = {
                k: v[metadata] for k, v in six.iteritems(reel['Assets'])
                if v.get(metadata) and k in [type_a, type_b]
            }

            vals = list(metadatas.values())
            if len(vals) == 2 and not cmp(vals[0], vals[1]):
                what = "{} / {} {} mismatch for Reel {}".format(
                        type_a, type_b, metadata, reel['Position'])
                if message:
                    what += ", {}".format(message)

                raise CheckException(what)
示例#7
0
    def check_picture_cpl_encoding(self, playlist, asset):
        """ Picture wavelet transform levels SMPTE compliance. """
        resolutions = self.settings['resolutions']
        levels_map = {
            '2K': self.settings['dwt_levels_2k'],
            '4K': self.settings['dwt_levels_4k'],
        }

        _, asset = asset
        if 'Probe' in asset and self.dcp.schema == 'SMPTE':
            levels = asset['Probe']['DecompositionLevels']
            resolution = asset['Probe']['Resolution']
            resolution_name = ''

            for k, v in six.iteritems(resolutions):
                if resolution in v:
                    resolution_name = k
                    break

            is_dci = resolution_name in levels_map
            if is_dci and levels_map[resolution_name] != levels:
                raise CheckException(
                    "Picture must have {} wavelet transform levels, {}"
                    " found".format(levels_map[resolution_name], levels))
示例#8
0
 def check_assets_cpl_hash(self, playlist, asset):
     """ CPL assets Hash shall be present alongside KeyId (encrypted). """
     if 'KeyId' in asset and 'Hash' not in asset:
         raise CheckException("Encrypted asset must have a Hash element")
示例#9
0
 def check_cpl_referenced_by_pkl(self, playlist):
     """ CPL shall be present in PKL. """
     cpl = playlist['Info']['CompositionPlaylist']
     pkl_id = cpl.get('PKLId')
     if not pkl_id:
         raise CheckException("CPL is not referenced in any PKL")
示例#10
0
 def check_sign_issuer_serial(self, source):
     """ XML signature serial number check. """
     sig = source['Signer']['X509Data']['X509IssuerSerial']
     # Signer Serial number
     if sig['X509SerialNumber'] != self.cert_list[-1].get_serial_number():
         raise CheckException("Invalid Signer Serial Number")
示例#11
0
 def check_certif_version(self, cert, index):
     """ Certificate version check (X509 v3). """
     if cert.get_version() != crypto.x509.Version.v3.value:
         raise CheckException("Invalid certificate version")
示例#12
0
 def check_assets_am_uuid(self, am, asset):
     """ AssetMap UUIDs validation. """
     uuid, _, _ = asset
     if not check_uuid(uuid):
         raise CheckException(
             "Invalid uuid found : {}".format(uuid))
示例#13
0
 def check_assets_pkl_referenced_by_assetamp(self, pkl, asset):
     """ PKL assets shall be present in AssetMap. """
     uuid, _, _ = asset
     # Note : dcp._list_asset is directly extracted from Assetmap
     if uuid not in self.dcp._list_asset.keys():
         raise CheckException("Not present in Assetmap")
示例#14
0
 def check_dcnc_field_claim_standard(self, playlist, fields):
     """ DCP Standard coherence check. """
     standard = fields['Standard'].get('Schema')
     if standard and standard != self.dcp.schema:
         raise CheckException("ContentTitle claims {} but DCP schema is {}".format(
             standard, self.dcp.schema))