Пример #1
0
    def __init__(self, fdesc, primer, debug=False, dark=False):
        InterchangeObject.__init__(self, fdesc, debug)
        self.primer = primer
        self.dark = dark
        self.data = OrderedDict()
        self.set_type = 'DataSet'
        self.element_mapping = {}

        if self.key.encode('hex_codec') not in MXFDataSet.dataset_names.keys():
            #print "MXFDataSet is dark", self.key.encode('hex_codec')
            self.dark = True
            self.set_type = 'Dark' + self.set_type
        else:
            self.set_type = MXFDataSet.dataset_names[self.key.encode(
                'hex_codec')]

        if not self.dark:
            if not self.key.encode('hex_codec').startswith('060e2b34'):
                raise S377MException('Not a SMPTE administrated label')

            if self.key[4] != '\x02':
                raise S377MException('Not an MXF Set/Pack')

            if self.key[5] != '\x53':
                raise S377MException(
                    'Non-Local set syntax not supported yet (0x%x)' %
                    ord(self.key[5]))
Пример #2
0
    def __init__(self, fdesc, debug=False):
        InterchangeObject.__init__(self, fdesc, debug)
        self.data = OrderedDict()

        if not re.search('060e2b34020501010d01020101(0[2-4])(0[0-4])00',
                         self.key.encode('hex_codec')):
            raise S377MException('Not a valid Partition Pack key: %s' %
                                 self.key.encode('hex_codec'))
Пример #3
0
    def __init__(self, fdesc, rp210=None, debug=False):
        InterchangeObject.__init__(self, fdesc, debug)
        self.data = OrderedDict()

        if rp210:
            self.rp210 = rp210
        else:
            self.rp210 = Singleton(RP210)

        if self.key and not re.search('060e2b34020501..0d01020101050100',
                                      self.key.encode('hex_codec')):
            raise S377MException('Not a valid Primer Pack key: %s' %
                                 self.key.encode('hex_codec'))
Пример #4
0
    def __init__(self, fdesc, rp210=None, debug=False):
        InterchangeObject.__init__(self, fdesc, debug)
        self.data = OrderedDict()

        if rp210:
            self.rp210 = rp210
        else:
            self.rp210 = Singleton(RP210)

        if self.key and not re.search('060e2b34020501..0d01020101050100', self.key.encode('hex_codec')):
            raise S377MException('Not a valid Primer Pack key: %s' % self.key.encode('hex_codec'))
Пример #5
0
    def __init__(self, fdesc, primer, debug=False, dark=False):
        InterchangeObject.__init__(self, fdesc, debug)
        self.primer = primer
        self.dark = dark
        self.data = OrderedDict()
        self.set_type = 'DataSet'
        self.element_mapping = {}

        if self.key.encode('hex_codec') not in MXFDataSet.dataset_names.keys():
            #print "MXFDataSet is dark", self.key.encode('hex_codec')
            self.dark = True
            self.set_type = 'Dark' + self.set_type
        else:
            self.set_type = MXFDataSet.dataset_names[self.key.encode('hex_codec')]

        if not self.dark:
            if not self.key.encode('hex_codec').startswith('060e2b34'):
                raise S377MException('Not a SMPTE administrated label')

            if self.key[4] != '\x02':
                raise S377MException('Not an MXF Set/Pack')

            if self.key[5] != '\x53':
                raise S377MException('Non-Local set syntax not supported yet (0x%x)' % ord(self.key[5]))
Пример #6
0
    def __init__(self, fdesc, debug=False):
        InterchangeObject.__init__(self, fdesc, debug)
        self.data = OrderedDict()

        if not re.search('060e2b34020501010d01020101(0[2-4])(0[0-4])00', self.key.encode('hex_codec')):
            raise S377MException('Not a valid Partition Pack key: %s' % self.key.encode('hex_codec'))
Пример #7
0
class MXFPartition(InterchangeObject):
    """ MXF Partition Pack parser. """

    _compound = [
        ('major_version',       'UInt16', 2),
        ('minor_version',       'UInt16', 2),
        ('kag_size',            'UInt32', 4),
        ('this_partition',      'UInt64', 8),
        ('previous_partition',  'UInt64', 8),
        ('footer_partition',    'UInt64', 8),
        ('header_byte_count',   'UInt64', 8),
        ('index_byte_cout',     'UInt64', 8),
        ('index_sid',           'UInt32', 4),
        ('body_offset',         'UInt64', 8),
        ('body_sid',            'UInt32', 4),
        ('operational_pattern', 'Universal Label', 16),
        #('essence_containers',  'Batch of Universal Labels', 8 + 16n),
    ]

    def __init__(self, fdesc, debug=False):
        InterchangeObject.__init__(self, fdesc, debug)
        self.data = OrderedDict()

        if not re.search('060e2b34020501010d01020101(0[2-4])(0[0-4])00', self.key.encode('hex_codec')):
            raise S377MException('Not a valid Partition Pack key: %s' % self.key.encode('hex_codec'))

    def __str__(self):
        return '<MXF%(type)sPartition pos=%(pos)s %(openness)s and %(completeness)s>' % {
            'pos': self.pos,
            'type': {'\x02': 'Header', '\x03': 'Body', '\x04': 'Footer'}[self.key[13]],
            'openness': ord(self.key[14]) & 0xfe and 'Closed' or 'Open',
            'completeness': ord(self.key[14]) & 0xfd and 'Complete' or 'Incomplete',
        }

    def __smtpe_377m_check(self):
        """ Check conformance to SMTPE 377M 2004. """

        if self.data['major_version'] != 1:
            raise S377MException('Invalid Major version for Partition Pack')
        if self.data['minor_version'] not in (2, 3):
            raise S377MException('Invalid Minor version for Partition Pack')

        # Header Partition Pack checks
        if self.key[13] == '\x02':
            if self.data['this_partition'] != 0:
                raise S377MException('Invalid value for ThisPartition in Header Partition Pack')
            if self.data['previous_partition'] != 0:
                raise S377MException('Invalid value for PreviousPartition in Header Partition Pack')
        # partition_info['operational_pattern'][13] -> 10h –7Fh specialized pattern

        # Footer Patition Pack checks
        if self.key[13] == '\x04':
            if not ord(self.key[14]) & 0xfe:
                raise S377MException('Open Footer Partition is not allowed')

        if len(self.data['essence_containers']) == 0 and self.data['body_sid'] != 0:
            raise S377MException('Invalid value for BodySID in Partition Pack')

    def read(self):
        idx = 0
        data = self.fdesc.read(self.length)

        # Read Partition Pack items
        for pp_item, pp_type, pp_size in self._compound:
            conv = select_converter(pp_type)
            self.data[pp_item] = conv(data[idx:idx+pp_size], pp_type).read()
            idx += pp_size

        # Read essence containers list, if any
        self.data['essence_containers'] = Array(data[idx:], 'Batch of Universal Labels').read()

        self.__smtpe_377m_check()

        if self.debug:
            print "%d essences in partition:" % len(self.data['essence_containers'])

        return

    def write(self):
        ret = ""
        for pp_item, pp_type, _ in self._compound:
            conv = select_converter(pp_type)
            ret += conv(self.data[pp_item], pp_type).write()

        ret += Array(self.data['essence_containers'], 'Batch of Universal Labels').write()

        self.pos = self.fdesc.tell()
        self.length = len(ret)
        self.fdesc.write(self.key + self.ber_encode_length(self.length, bytes_num=8).decode('hex_codec') + ret)
        return

    def human_readable(self):
        for key, item in self.data.items():
            if key == 'essence_containers':
                for i, essence in enumerate(item):
                    print "Essence %d: " % i, essence.encode('hex_codec')
            elif key == 'operational_pattern':
                print "%s: %s" % (key, item.encode('hex_codec'))
            else:
                print "%s: %s" % (key, item)
        return
Пример #8
0
class MXFDataSet(InterchangeObject):
    """ MXF parsing class specialized for loading Sets and Packs. """

    dataset_names = {
         # SMPTE 377M: Strutural Metadata Sets
         '060e2b34025301010d01010101010900': 'Filler',
         '060e2b34025301010d01010101010f00': 'Sequence',

         '060e2b34025301010d01010101011100': 'SourceClip',
         '060e2b34025301010d01010101011400': 'TimecodeComponent',

         '060e2b34025301010d01010101012300': 'EssenceContainerData',
         '060e2b34025301010d01010101012800': 'CDCIEssenceDescriptor',

         '060e2b34025301010d01010101011800': 'ContentStorage',

         '060e2b34025301010d01010101012e00': 'EssenceDescription',
         '060e2b34025301010d01010101013000': 'Identification',

         '060e2b34025301010d01010101013600': 'MaterialPackage',
         '060e2b34025301010d01010101013700': 'SourcePackage',

         '060e2b34025301010d01010101013b00': 'TimelineTrack',
         '060e2b34025301010d01010101013f00': 'TaggedValue', # Avid Dark 2

         '060e2b34025301010d01010101014200': 'GenericSoundEssenceDescriptor',
         '060e2b34025301010d01010101014400': 'MultipleDescriptor',
         '060e2b34025301010d01010101014700': 'AES3PCMDescriptor',
         '060e2b34025301010d01010101014800': 'WaveAudioDescriptor',

         '060e2b34025301010d01010101015100': 'MPEG2VideoDescriptor',
    }

    def __init__(self, fdesc, primer, debug=False, dark=False):
        InterchangeObject.__init__(self, fdesc, debug)
        self.primer = primer
        self.dark = dark
        self.data = OrderedDict()
        self.set_type = 'DataSet'
        self.element_mapping = {}

        if self.key.encode('hex_codec') not in MXFDataSet.dataset_names.keys():
            #print "MXFDataSet is dark", self.key.encode('hex_codec')
            self.dark = True
            self.set_type = 'Dark' + self.set_type
        else:
            self.set_type = MXFDataSet.dataset_names[self.key.encode('hex_codec')]

        if not self.dark:
            if not self.key.encode('hex_codec').startswith('060e2b34'):
                raise S377MException('Not a SMPTE administrated label')

            if self.key[4] != '\x02':
                raise S377MException('Not an MXF Set/Pack')

            if self.key[5] != '\x53':
                raise S377MException('Non-Local set syntax not supported yet (0x%x)' % ord(self.key[5]))

    def __str__(self):
        ret = ['<MXF' + self.set_type]
        ret += ['pos=%d' % self.pos]
        ret += ['size=%d' % self.length]
        ret += ['InstanceUID=%s' % self.data['\x3c\x0a']]
        if self.debug:
            ret += ['tags=%d:\n' % len(self.data) \
                + '\n'.join(["%s: %s" % (
                    i.encode('hex_codec'), j
                ) for i, j in self.data.items()])]
        return ' '.join(ret) + '>'

    def get_element(self, element_name):
        return self.data.get(self.element_mapping.get(element_name, None), None)

    def set_element(self, element_name, value):
        self.data[self.element_mapping[element_name]] = value

    def rm_element(self, element_name):
        if self.element_mapping.get(element_name, None):
            del self.data[self.element_mapping[element_name]]
            del self.element_mapping[element_name]
            return True

        return False

    def get_strong_references(self):
        ref_list = []
        for _, j in self.data.items():
            if isinstance(j, Reference) and j.subtype == 'StrongReference':
                ref_list.append(j.read())
            elif isinstance(j, Array) and j.subtype == 'StrongReference':
                [ref_list.append(k) for k in j.read()]

        return ref_list

    def read(self):
        """ Generic read method for sets and packs. """

        idx = 0
        data = self.fdesc.read(self.length)

        # Get all items
        offset = idx
        while offset < idx + self.length:
            set_size = Integer(data[offset+2:offset+4], 'UInt16').read()
            localtag = data[offset:offset+2]
            localdata = data[offset+4:offset+set_size+4]
            offset += set_size + 4

            element_name, cvalue = self.primer.decode_from_local_tag(localtag, localdata)
            self.element_mapping.update({element_name: localtag})
            self.data.update({localtag: cvalue})

        return

    def write(self):

        ret = []
        for tag, value in self.data.items():
            # Not all values are decoded
            if isinstance(value, basestring):
                localtag = tag
                cvalue = value.decode('hex_codec')
            else:
                localtag, conv = self.primer.encode_from_local_tag(tag, value.read())
                cvalue = conv.write()
            ret.append(localtag + self.ber_encode_length(len(cvalue), bytes_num=2, prefix=False).decode('hex_codec') + cvalue)

        ret = ''.join(ret)
        self.pos = self.fdesc.tell()
        self.length = len(ret)
        self.fdesc.write(self.key + self.ber_encode_length(self.length, bytes_num=8).decode('hex_codec') + ret)
        return

    def human_readable(self, klv_hash=None, indent=None):

        if not indent:
            indent = 0

        print "%s%s" % (4 * indent * ' ', self)

        for i, j in self.data.items():

            element_name = self.primer.get_mapping(i)[1][1]
            if len(element_name) == 0:
                element_name = self.primer.get_mapping(i)[1][2]


            if element_name == 'guid':
                continue

            elif isinstance(j, Reference):
                if j.subtype in ('AUID', 'PackageID', 'Universal Label'):
                    print "%s%s: %s" % (4 * indent * ' ' + '  ', element_name, j)
                elif klv_hash and j.read() not in klv_hash:
                    print "%s%s: broken reference, %s %s" % (4 * indent * ' ' + '  ', element_name, j, j.subtype)
                elif klv_hash and not klv_hash[j.read()]['used']:

                    print "%s%s: New reference" % (4 * indent * ' ' + '  ', element_name)
                    klv_hash[j.read()]['used'] = True
                    klv_hash[j.read()]['klv'].human_readable(klv_hash, indent+1)
                else:
                    print "%s%s: <-> %s" % (4 * indent * ' ' + '  ', element_name, j)

            elif isinstance(j, Array):
                if j.subconv is Reference:
                    print "%s%s: Array (%d items)" % (4 * indent * ' ' + '  ', element_name, len(j.read()))
                    #print "%s" % (4 * indent * ' ' + '  '), [_.encode('hex_codec') for _ in j.read()]
                    for x, k in enumerate(j.read()):
                        if j.subtype in ('AUID', 'Universal Labels'):
                            print "%sitem %d: %s" % (4 * indent * ' ' + '  ', x, Reference(k))
                        elif klv_hash and k not in klv_hash:
                            print "%sitem %d: broken reference, %s" % (4 * indent * ' ' + '  ', x, Reference(k))
                        elif klv_hash and not klv_hash[k]['used']:
                            klv_hash[k]['used'] = True
                            klv_hash[k]['klv'].human_readable(klv_hash, indent+1)
                        else:
                            print "%sitem %d: <-> %s" % (4 * indent * ' ' + '  ', x, Reference(k))
                else:
                    for k in j.read():
                        print "%s%s: %s" % (4 * indent * ' ' + '  ', element_name, k)
            else:
                try:
                    print "%s%s: %s %s" % (4 * indent * ' ' + '  ', element_name, j, type(j))
                except RP210TypesException, error:
                    print error

        print ""
        if klv_hash:
            return klv_hash
        return
Пример #9
0
class MXFPrimer(InterchangeObject):
    """ MXF Primer Pack parser. """

    def __init__(self, fdesc, rp210=None, debug=False):
        InterchangeObject.__init__(self, fdesc, debug)
        self.data = OrderedDict()

        if rp210:
            self.rp210 = rp210
        else:
            self.rp210 = Singleton(RP210)

        if self.key and not re.search('060e2b34020501..0d01020101050100', self.key.encode('hex_codec')):
            raise S377MException('Not a valid Primer Pack key: %s' % self.key.encode('hex_codec'))

    def __str__(self):
        ret = ['<MXFPrimer']
        ret += ['pos=%d' % self.pos]
        ret += ['size=%d' % self.length]
        ret += ['localtags=%d' % len(self.data)]
        if self.debug:
            ret += ['\n']
            for i, j in self.data.items():
                ret += ['%s: %s\n' % (i.encode('hex_codec'), j.encode('hex_codec'))]
        return ' '.join(ret) + '>'

    @staticmethod
    def customize(primer, spec, mappings=None):
        """ Modifies a primer to abide @spec rules with optional @mappings.

        @spec: instance of a sjmxf.rp210 like object
        @mappings: a dictionary that is passed to inject method

        @returns: custimized Primer object.
        """

        import copy
        aprim = copy.copy(primer)

        if mappings:
            spec.inject(mappings)

        aprim.data = {}
        aprim.data.update(primer.data)
        aprim.rp210 = spec

        if mappings:
            aprim.inject(mappings.keys())

        return aprim

    def inject(self, mappings):
        """ Insert new mappings in Primer.

        Allows insertion of new local tag to format UL mappings with their
        RP210 basic type.
        """

        for item in mappings:
            self.data[item.decode('hex_codec')] = item.rjust(32, '0').decode('hex_codec')
        return

    def read(self):

        data = self.fdesc.read(self.length)

        lt_list_size = Integer(data[0:4], 'UInt32').read()
        lt_item_size = Integer(data[4:8], 'UInt32').read()

        idx = 8
        while lt_list_size > len(self.data):
            self.data[data[idx:idx+2]] = Reference(data[idx+2:idx+lt_item_size], 'Universal Label').read()
            idx += lt_item_size

        if self.debug:
            print "%d local tag mappings in Primer Pack" % len(self.data)

        return

    def write(self):

        ret = ""
        for tag, ful in self.data.items():
            ret += tag + Reference(ful, 'Universal Label').write()

        lt_list_size = Integer(len(self.data), 'UInt32').write()
        lt_item_size = Integer(len(ret) / len(self.data), 'UInt32').write()
        ret = lt_list_size + lt_item_size + ret

        self.pos = self.fdesc.tell()
        self.length = len(ret)
        self.fdesc.write(self.key + self.ber_encode_length(self.length, bytes_num=8).decode('hex_codec') + ret)
        return

    def decode_from_local_tag(self, tag, value):
        """ Decode data according to local tag mapping to format Universal Labels. """

        etag = tag.encode('hex_codec')
        evalue = value.encode('hex_codec')

        if tag not in self.data.keys():
            print "Error: Local key '%s' not found in primer" % etag
            return etag, evalue

        #if not self.data[tag].startswith('060e2b34'.decode('hex_codec')):
        #    return "Error: '%s' does not map to a SMPTE format UL '%s'" % (etag, self.data[tag].encode('hex_codec'))

        key = "unkown_data_format"
        # SMTPE RP 210 conversion
        try:
            key = self.rp210.get_triplet_from_format_ul(self.data[tag])[1]
            return key, self.rp210.convert(self.data[tag], value)
        except RP210Exception, error:
            print error
            return key, evalue
Пример #10
0
class MXFPartition(InterchangeObject):
    """ MXF Partition Pack parser. """

    _compound = [
        ('major_version', 'UInt16', 2),
        ('minor_version', 'UInt16', 2),
        ('kag_size', 'UInt32', 4),
        ('this_partition', 'UInt64', 8),
        ('previous_partition', 'UInt64', 8),
        ('footer_partition', 'UInt64', 8),
        ('header_byte_count', 'UInt64', 8),
        ('index_byte_cout', 'UInt64', 8),
        ('index_sid', 'UInt32', 4),
        ('body_offset', 'UInt64', 8),
        ('body_sid', 'UInt32', 4),
        ('operational_pattern', 'Universal Label', 16),
        #('essence_containers',  'Batch of Universal Labels', 8 + 16n),
    ]

    def __init__(self, fdesc, debug=False):
        InterchangeObject.__init__(self, fdesc, debug)
        self.data = OrderedDict()

        if not re.search('060e2b34020501010d01020101(0[2-4])(0[0-4])00',
                         self.key.encode('hex_codec')):
            raise S377MException('Not a valid Partition Pack key: %s' %
                                 self.key.encode('hex_codec'))

    def __str__(self):
        return '<MXF%(type)sPartition pos=%(pos)s %(openness)s and %(completeness)s>' % {
            'pos':
            self.pos,
            'type': {
                '\x02': 'Header',
                '\x03': 'Body',
                '\x04': 'Footer'
            }[self.key[13]],
            'openness':
            ord(self.key[14]) & 0xfe and 'Closed' or 'Open',
            'completeness':
            ord(self.key[14]) & 0xfd and 'Complete' or 'Incomplete',
        }

    def __smtpe_377m_check(self):
        """ Check conformance to SMTPE 377M 2004. """

        if self.data['major_version'] != 1:
            raise S377MException('Invalid Major version for Partition Pack')
        if self.data['minor_version'] not in (2, 3):
            raise S377MException('Invalid Minor version for Partition Pack')

        # Header Partition Pack checks
        if self.key[13] == '\x02':
            if self.data['this_partition'] != 0:
                raise S377MException(
                    'Invalid value for ThisPartition in Header Partition Pack')
            if self.data['previous_partition'] != 0:
                raise S377MException(
                    'Invalid value for PreviousPartition in Header Partition Pack'
                )
        # partition_info['operational_pattern'][13] -> 10h –7Fh specialized pattern

        # Footer Patition Pack checks
        if self.key[13] == '\x04':
            if not ord(self.key[14]) & 0xfe:
                raise S377MException('Open Footer Partition is not allowed')

        if len(self.data['essence_containers']
               ) == 0 and self.data['body_sid'] != 0:
            raise S377MException('Invalid value for BodySID in Partition Pack')

    def read(self):
        idx = 0
        data = self.fdesc.read(self.length)

        # Read Partition Pack items
        for pp_item, pp_type, pp_size in self._compound:
            conv = select_converter(pp_type)
            self.data[pp_item] = conv(data[idx:idx + pp_size], pp_type).read()
            idx += pp_size

        # Read essence containers list, if any
        self.data['essence_containers'] = Array(
            data[idx:], 'Batch of Universal Labels').read()

        self.__smtpe_377m_check()

        if self.debug:
            print "%d essences in partition:" % len(
                self.data['essence_containers'])

        return

    def write(self):
        ret = ""
        for pp_item, pp_type, _ in self._compound:
            conv = select_converter(pp_type)
            ret += conv(self.data[pp_item], pp_type).write()

        ret += Array(self.data['essence_containers'],
                     'Batch of Universal Labels').write()

        self.pos = self.fdesc.tell()
        self.length = len(ret)
        self.fdesc.write(self.key + self.ber_encode_length(
            self.length, bytes_num=8).decode('hex_codec') + ret)
        return

    def human_readable(self):
        for key, item in self.data.items():
            if key == 'essence_containers':
                for i, essence in enumerate(item):
                    print "Essence %d: " % i, essence.encode('hex_codec')
            elif key == 'operational_pattern':
                print "%s: %s" % (key, item.encode('hex_codec'))
            else:
                print "%s: %s" % (key, item)
        return
Пример #11
0
class MXFDataSet(InterchangeObject):
    """ MXF parsing class specialized for loading Sets and Packs. """

    dataset_names = {
        # SMPTE 377M: Strutural Metadata Sets
        '060e2b34025301010d01010101010900': 'Filler',
        '060e2b34025301010d01010101010f00': 'Sequence',
        '060e2b34025301010d01010101011100': 'SourceClip',
        '060e2b34025301010d01010101011400': 'TimecodeComponent',
        '060e2b34025301010d01010101012300': 'EssenceContainerData',
        '060e2b34025301010d01010101012800': 'CDCIEssenceDescriptor',
        '060e2b34025301010d01010101011800': 'ContentStorage',
        '060e2b34025301010d01010101012e00': 'EssenceDescription',
        '060e2b34025301010d01010101013000': 'Identification',
        '060e2b34025301010d01010101013600': 'MaterialPackage',
        '060e2b34025301010d01010101013700': 'SourcePackage',
        '060e2b34025301010d01010101013b00': 'TimelineTrack',
        '060e2b34025301010d01010101013f00': 'TaggedValue',  # Avid Dark 2
        '060e2b34025301010d01010101014200': 'GenericSoundEssenceDescriptor',
        '060e2b34025301010d01010101014400': 'MultipleDescriptor',
        '060e2b34025301010d01010101014700': 'AES3PCMDescriptor',
        '060e2b34025301010d01010101014800': 'WaveAudioDescriptor',
        '060e2b34025301010d01010101015100': 'MPEG2VideoDescriptor',
    }

    def __init__(self, fdesc, primer, debug=False, dark=False):
        InterchangeObject.__init__(self, fdesc, debug)
        self.primer = primer
        self.dark = dark
        self.data = OrderedDict()
        self.set_type = 'DataSet'
        self.element_mapping = {}

        if self.key.encode('hex_codec') not in MXFDataSet.dataset_names.keys():
            #print "MXFDataSet is dark", self.key.encode('hex_codec')
            self.dark = True
            self.set_type = 'Dark' + self.set_type
        else:
            self.set_type = MXFDataSet.dataset_names[self.key.encode(
                'hex_codec')]

        if not self.dark:
            if not self.key.encode('hex_codec').startswith('060e2b34'):
                raise S377MException('Not a SMPTE administrated label')

            if self.key[4] != '\x02':
                raise S377MException('Not an MXF Set/Pack')

            if self.key[5] != '\x53':
                raise S377MException(
                    'Non-Local set syntax not supported yet (0x%x)' %
                    ord(self.key[5]))

    def __str__(self):
        ret = ['<MXF' + self.set_type]
        ret += ['pos=%d' % self.pos]
        ret += ['size=%d' % self.length]
        ret += ['InstanceUID=%s' % self.data['\x3c\x0a']]
        if self.debug:
            ret += ['tags=%d:\n' % len(self.data) \
                + '\n'.join(["%s: %s" % (
                    i.encode('hex_codec'), j
                ) for i, j in self.data.items()])]
        return ' '.join(ret) + '>'

    def get_element(self, element_name):
        return self.data.get(self.element_mapping.get(element_name, None),
                             None)

    def set_element(self, element_name, value):
        self.data[self.element_mapping[element_name]] = value

    def rm_element(self, element_name):
        if self.element_mapping.get(element_name, None):
            del self.data[self.element_mapping[element_name]]
            del self.element_mapping[element_name]
            return True

        return False

    def get_strong_references(self):
        ref_list = []
        for _, j in self.data.items():
            if isinstance(j, Reference) and j.subtype == 'StrongReference':
                ref_list.append(j.read())
            elif isinstance(j, Array) and j.subtype == 'StrongReference':
                [ref_list.append(k) for k in j.read()]

        return ref_list

    def read(self):
        """ Generic read method for sets and packs. """

        idx = 0
        data = self.fdesc.read(self.length)

        # Get all items
        offset = idx
        while offset < idx + self.length:
            set_size = Integer(data[offset + 2:offset + 4], 'UInt16').read()
            localtag = data[offset:offset + 2]
            localdata = data[offset + 4:offset + set_size + 4]
            offset += set_size + 4

            element_name, cvalue = self.primer.decode_from_local_tag(
                localtag, localdata)
            self.element_mapping.update({element_name: localtag})
            self.data.update({localtag: cvalue})

        return

    def write(self):

        ret = []
        for tag, value in self.data.items():
            # Not all values are decoded
            if isinstance(value, basestring):
                localtag = tag
                cvalue = value.decode('hex_codec')
            else:
                localtag, conv = self.primer.encode_from_local_tag(
                    tag, value.read())
                cvalue = conv.write()
            ret.append(localtag + self.ber_encode_length(
                len(cvalue), bytes_num=2, prefix=False).decode('hex_codec') +
                       cvalue)

        ret = ''.join(ret)
        self.pos = self.fdesc.tell()
        self.length = len(ret)
        self.fdesc.write(self.key + self.ber_encode_length(
            self.length, bytes_num=8).decode('hex_codec') + ret)
        return

    def human_readable(self, klv_hash=None, indent=None):

        if not indent:
            indent = 0

        print "%s%s" % (4 * indent * ' ', self)

        for i, j in self.data.items():

            element_name = self.primer.get_mapping(i)[1][1]
            if len(element_name) == 0:
                element_name = self.primer.get_mapping(i)[1][2]

            if element_name == 'guid':
                continue

            elif isinstance(j, Reference):
                if j.subtype in ('AUID', 'PackageID', 'Universal Label'):
                    print "%s%s: %s" % (4 * indent * ' ' + '  ', element_name,
                                        j)
                elif klv_hash and j.read() not in klv_hash:
                    print "%s%s: broken reference, %s %s" % (
                        4 * indent * ' ' + '  ', element_name, j, j.subtype)
                elif klv_hash and not klv_hash[j.read()]['used']:

                    print "%s%s: New reference" % (4 * indent * ' ' + '  ',
                                                   element_name)
                    klv_hash[j.read()]['used'] = True
                    klv_hash[j.read()]['klv'].human_readable(
                        klv_hash, indent + 1)
                else:
                    print "%s%s: <-> %s" % (4 * indent * ' ' + '  ',
                                            element_name, j)

            elif isinstance(j, Array):
                if j.subconv is Reference:
                    print "%s%s: Array (%d items)" % (
                        4 * indent * ' ' + '  ', element_name, len(j.read()))
                    #print "%s" % (4 * indent * ' ' + '  '), [_.encode('hex_codec') for _ in j.read()]
                    for x, k in enumerate(j.read()):
                        if j.subtype in ('AUID', 'Universal Labels'):
                            print "%sitem %d: %s" % (4 * indent * ' ' + '  ',
                                                     x, Reference(k))
                        elif klv_hash and k not in klv_hash:
                            print "%sitem %d: broken reference, %s" % (
                                4 * indent * ' ' + '  ', x, Reference(k))
                        elif klv_hash and not klv_hash[k]['used']:
                            klv_hash[k]['used'] = True
                            klv_hash[k]['klv'].human_readable(
                                klv_hash, indent + 1)
                        else:
                            print "%sitem %d: <-> %s" % (4 * indent * ' ' +
                                                         '  ', x, Reference(k))
                else:
                    for k in j.read():
                        print "%s%s: %s" % (4 * indent * ' ' + '  ',
                                            element_name, k)
            else:
                try:
                    print "%s%s: %s %s" % (4 * indent * ' ' + '  ',
                                           element_name, j, type(j))
                except RP210TypesException, error:
                    print error

        print ""
        if klv_hash:
            return klv_hash
        return
Пример #12
0
class MXFPrimer(InterchangeObject):
    """ MXF Primer Pack parser. """
    def __init__(self, fdesc, rp210=None, debug=False):
        InterchangeObject.__init__(self, fdesc, debug)
        self.data = OrderedDict()

        if rp210:
            self.rp210 = rp210
        else:
            self.rp210 = Singleton(RP210)

        if self.key and not re.search('060e2b34020501..0d01020101050100',
                                      self.key.encode('hex_codec')):
            raise S377MException('Not a valid Primer Pack key: %s' %
                                 self.key.encode('hex_codec'))

    def __str__(self):
        ret = ['<MXFPrimer']
        ret += ['pos=%d' % self.pos]
        ret += ['size=%d' % self.length]
        ret += ['localtags=%d' % len(self.data)]
        if self.debug:
            ret += ['\n']
            for i, j in self.data.items():
                ret += [
                    '%s: %s\n' % (i.encode('hex_codec'), j.encode('hex_codec'))
                ]
        return ' '.join(ret) + '>'

    @staticmethod
    def customize(primer, spec, mappings=None):
        """ Modifies a primer to abide @spec rules with optional @mappings.

        @spec: instance of a sjmxf.rp210 like object
        @mappings: a dictionary that is passed to inject method

        @returns: custimized Primer object.
        """

        import copy
        aprim = copy.copy(primer)

        if mappings:
            spec.inject(mappings)

        aprim.data = {}
        aprim.data.update(primer.data)
        aprim.rp210 = spec

        if mappings:
            aprim.inject(mappings.keys())

        return aprim

    def inject(self, mappings):
        """ Insert new mappings in Primer.

        Allows insertion of new local tag to format UL mappings with their
        RP210 basic type.
        """

        for item in mappings:
            self.data[item.decode('hex_codec')] = item.rjust(
                32, '0').decode('hex_codec')
        return

    def read(self):

        data = self.fdesc.read(self.length)

        lt_list_size = Integer(data[0:4], 'UInt32').read()
        lt_item_size = Integer(data[4:8], 'UInt32').read()

        idx = 8
        while lt_list_size > len(self.data):
            self.data[data[idx:idx + 2]] = Reference(
                data[idx + 2:idx + lt_item_size], 'Universal Label').read()
            idx += lt_item_size

        if self.debug:
            print "%d local tag mappings in Primer Pack" % len(self.data)

        return

    def write(self):

        ret = ""
        for tag, ful in self.data.items():
            ret += tag + Reference(ful, 'Universal Label').write()

        lt_list_size = Integer(len(self.data), 'UInt32').write()
        lt_item_size = Integer(len(ret) / len(self.data), 'UInt32').write()
        ret = lt_list_size + lt_item_size + ret

        self.pos = self.fdesc.tell()
        self.length = len(ret)
        self.fdesc.write(self.key + self.ber_encode_length(
            self.length, bytes_num=8).decode('hex_codec') + ret)
        return

    def decode_from_local_tag(self, tag, value):
        """ Decode data according to local tag mapping to format Universal Labels. """

        etag = tag.encode('hex_codec')
        evalue = value.encode('hex_codec')

        if tag not in self.data.keys():
            print "Error: Local key '%s' not found in primer" % etag
            return etag, evalue

        #if not self.data[tag].startswith('060e2b34'.decode('hex_codec')):
        #    return "Error: '%s' does not map to a SMPTE format UL '%s'" % (etag, self.data[tag].encode('hex_codec'))

        key = "unkown_data_format"
        # SMTPE RP 210 conversion
        try:
            key = self.rp210.get_triplet_from_format_ul(self.data[tag])[1]
            return key, self.rp210.convert(self.data[tag], value)
        except RP210Exception, error:
            print error
            return key, evalue