def decode(self): """ decode SCTE35 Avail Descriptor """ bitbin = BitBin(self.bites) self.parse_id(bitbin) self.provider_avail_id = bitbin.asint(32)
def __init__(self, mesg): mesg = self.mkbits(mesg) self.bitbin = BitBin(mesg) self.descriptors = [] self.info_section = None self.command = None self.do()
def decode(self): """ decode SCTE35 Time Descriptor """ bitbin = BitBin(self.bites) self.parse_id(bitbin) self.tai_seconds = bitbin.asint(48) self.tai_ns = bitbin.asint(32) self.utc_offset = bitbin.asint(16)
def parse_pusi(self, packetdata): ''' If the pusi data contains these markers, we can pull a PTS value.. ''' if packetdata[2] == 1: if packetdata[3] not in self.NON_PTS_STREAM_IDS: if (packetdata[6] >> 6) == 2: if (packetdata[7] >> 6) == 2: if (packetdata[9] >> 4) == 2: bitbin = BitBin(packetdata[9:]) bitbin.forward(4) self.parse_pts(bitbin)
def parse_tspacket(self, packet): two_bytes, one_byte = unpack('>HB', packet[:3]) # tei = two_bytes >> 15 pusi = two_bytes >> 14 & 0x1 # ts_priority = two_bytes >>13 & 0x1 pid = two_bytes & 0x1fff # scramble = one_byte >>6 afc = (one_byte & 48) >> 4 # count = 0 if afc in [2, 3]: afcl = unpack('>B', packet[4:5])[0] afcl += 12 fu = packet[4:afcl] bitbin = BitBin(fu) adaptation_fields(bitbin) return # No PTS times in pid 101 if pid == 101: return # Here's where you find PTS if pusi: self.parse_pusi(packet[3:19]) # SCTE35_TID (0xfc) is required . if packet[4] != self.SCTE35_TID: return # If the SCTE 35 pid is known, the packet pid must match. if self.PID and (pid != self.PID): return # Only show splice_null commands if self.show_null is True if not self.show_null: if packet[17] == 0: return try: tf = Splice(packet[4:]) except: return print() tf.show() if not self.PID: self.PID = pid return
def decode(self): """ decode is called only by a TimeSignal instance """ bitbin = BitBin(self.bites) start = bitbin.idx self._decode_pts(bitbin) self._set_len(start, bitbin.idx)
def decode(self): """ Decode SCTE35 Audio Descriptor """ bitbin = BitBin(self.bites) self.parse_id(bitbin) self.audio_count = a_c = bitbin.asint(4) bitbin.forward(4) while a_c: a_c -= 1 comp = {} comp["component_tag"] = bitbin.asint(8) comp["ISO_code="] = bitbin.asint(24) comp["bit_stream_mode"] = bitbin.asint(3) comp["num_channels"] = bitbin.asint(4) comp["full_srvc_audio"] = bitbin.asflag(1) self.components.append(comp)
def mk_command(self, payload): cmdbb = BitBin(payload) bit_start = cmdbb.idx self.set_splice_command(cmdbb) bit_end = cmdbb.idx cmdl = self.command.splice_command_length = int((bit_start - bit_end) >> 3) self.info_section.splice_command_length = cmdl return payload[cmdl:]
def _program_association_table(self, pkt): """ parse program association table ( pid 0 ) to program to program table pid mappings. """ sectionlen = (pkt[6] & 15 << 8) | pkt[7] pkt = pkt[13:(sectionlen + 5)] bitbin = BitBin(pkt) slib = sectionlen << 3 slib -= 40 while slib > 32: program_number = bitbin.asint(16) bitbin.forward(3) if program_number == 0: bitbin.forward(13) else: self._pmt_pids.add(bitbin.asint(13)) slib -= 32 bitbin.forward(32)
def parse_private_upid_SBSB(bites, upid_length): bitbin = BitBin(bites) return { "private_cni": hex(bitbin.asint(16)), "private_version": bitbin.asint(8), "private_transmission_id": struct.unpack("<Q", bitbin.asbites(64))[0], "private_product_code": struct.unpack("<Q", bitbin.asbites(64))[0], "private_web_publication_key": bitbin.astext(25 * 8), }
def parse_tspacket(packet, packetnum): three_bytes = BitBin(packet[:3]) tei = three_bytes.asflag(1) pusi = three_bytes.asflag(1) ts_priority = three_bytes.asflag(1) pid = three_bytes.asint(13) if pusi: parse_pes(packet, packetnum)
def decode(self): """ decode SCTE35 Dtmf Descriptor """ bitbin = BitBin(self.bites) self.parse_id(bitbin) self.preroll = bitbin.asint(8) self.dtmf_count = d_c = bitbin.asint(3) bitbin.forward(5) while d_c: d_c -= 1 self.dtmf_chars.append(bitbin.astext(8))
def set_splice_descriptor(self, payload): ''' Splice Descriptors looked up in self.descriptor_map ''' # splice_descriptor_tag 8 uimsbf tag = payload[0] desc_len = payload[1] payload = payload[2:] bitbin = BitBin(payload[:desc_len]) payload = payload[desc_len:] if tag in self.descriptor_map.keys(): sd = self.descriptor_map[tag](bitbin, tag) sd.descriptor_length = desc_len return sd else: return False
def _set_splice_descriptor(self, payload): """ Splice Descriptors looked up in self._descriptor_map """ # splice_descriptor_tag 8 uimsbf tag = payload[0] desc_len = payload[1] payload = payload[2:] bitbin = BitBin(payload[:desc_len]) payload = payload[desc_len:] if tag in self._descriptor_map: spliced = self._descriptor_map[tag](tag) spliced.decode(bitbin) spliced.descriptor_length = desc_len return spliced return False
def decode(self): """ SpliceInsert.decode """ bitbin = BitBin(self.bites) start = bitbin.idx self.splice_event_id = bitbin.asint(32) self.splice_event_cancel_indicator = bitbin.asflag(1) bitbin.forward(7) if not self.splice_event_cancel_indicator: self._decode_flags(bitbin) if self.program_splice_flag: if not self.splice_immediate_flag: self._decode_pts(bitbin) else: self._decode_components(bitbin) if not self.splice_immediate_flag: self._decode_pts(bitbin) if self.duration_flag: self._decode_break(bitbin) self.unique_program_id = bitbin.asint(16) self.avail_num = bitbin.asint(8) self.avail_expected = bitbin.asint(8) self._set_len(start, bitbin.idx)
def decode(self): """ decode a segmentation descriptor """ bitbin = BitBin(self.bites) self.parse_id(bitbin) self.segmentation_event_id = bitbin.ashex(32) # 4 bytes self.segmentation_event_cancel_indicator = bitbin.asflag(1) bitbin.forward(7) # 1 byte if not self.segmentation_event_cancel_indicator: self._decode_flags(bitbin) # 1 byte if not self.program_segmentation_flag: self._decode_components(bitbin) self._decode_segmentation(bitbin)
def _program_map_section(self, pkt): """ parse program maps for streams """ # table_id = pkt[5] sectioninfolen = (pkt[6] & 15 << 8) | pkt[7] slib = sectioninfolen << 3 program_number = (pkt[8] << 8) | pkt[9] # version = pkt[10] >> 1 & 31 # current_next = pkt[10] & 1 if self.the_program and (program_number != self.the_program): return None # section_number = pkt[11] # last_section_number = pkt[12] # pcr_pid = (pkt[13]& 31) << 8 | pkt[14] proginfolen = (pkt[15] & 15 << 8) | pkt[16] pkt = pkt[(17 + proginfolen):(slib + 9)] bitbin = BitBin(pkt) pilib = proginfolen << 3 slib -= 72 slib -= pilib # Skip descriptors self._parse_program_streams(slib, bitbin, program_number)
def parse_pes(packet, packetnum): bb = BitBin(packet[3:]) if bb.asint(24) == 1 and bb.asint(8) not in NON_PTS_STREAM_IDS: PES_packet_length = bb.asint(16) if bb.asint(2) == 2: bb.asint(6) if bb.asint(2) in [2, 3]: bb.asint(14) if bb.asint(4) in [2, 3]: to33 = bb.asint(3) << 30 bb.asflag(1) to30 = bb.asint(15) << 15 bs.asflag(1) to15 = bb.asint(15) d = to33 + to30 + to15 print(f" PTS {d/90000:.6f} on Packet {packetnum}")
def decode(self, bites): bitbin = BitBin(bites) self.table_id = bitbin.ashex(8) if self.table_id != "0xfc": to_stderr("splice info section table id should be 0xfc") self.section_syntax_indicator = bitbin.asflag(1) self.private = bitbin.asflag(1) self.reserved = bitbin.ashex(2) if self.reserved != "0x3": to_stderr("splice info section reserved should be 0x3") self.section_length = bitbin.asint(12) self.protocol_version = bitbin.asint(8) if self.protocol_version != 0: to_stderr("splice info section protocol version should be 0") self.encrypted_packet = bitbin.asflag(1) self.encryption_algorithm = bitbin.asint(6) self.pts_adjustment = bitbin.as90k(33) self.cw_index = bitbin.ashex(8) self.tier = bitbin.ashex(12) self.splice_command_length = bitbin.asint(12) self.splice_command_type = bitbin.asint(8) self.descriptor_loop_length = 0
class Splice: descriptor_map = { 0: Avail_Descriptor, 1: Dtmf_Descriptor, 2: Segmentation_Descriptor, 3: Time_Descriptor, 4: Audio_Descriptor } command_map = { 0: Splice_Null, 4: Splice_Schedule, 5: Splice_Insert, 6: Time_Signal, 7: Bandwidth_Reservation, 255: Private_Command } def __init__(self, mesg): mesg = self.mkbits(mesg) self.bitbin = BitBin(mesg) self.descriptors = [] self.info_section = None self.command = None self.do() def do(self): self.info_section = Splice_Info_Section() self.info_section.decode(self.bitbin) self.set_splice_command() self.descriptorloop() self.info_section.crc = self.bitbin.ashex(32) def descriptorloop(self): self.info_section.descriptor_loop_length = self.bitbin.asint(16) dll = self.info_section.descriptor_loop_length tag_plus_header_size = 2 # 1 byte for descriptor_tag, 1 byte for header? while dll > 0: try: sd = self.set_splice_descriptor() sdl = sd.descriptor_length self.descriptors.append(sd) except: sdl = 0 bit_move = sdl + tag_plus_header_size dll -= bit_move def kvprint(self, obj): print(f'{json.dumps(vars(obj))}') def sectionstart(self, section_name): print(f'{section_name}') def mkbits(self, s): if s[:2].lower() == '0x': s = s[2:] if s[:2].lower() == 'fc': return bytes.fromhex(s) try: return b64decode(s) except: return s def set_splice_command(self): sct = self.info_section.splice_command_type if sct not in self.command_map.keys(): raise ValueError('unknown splice command type') self.command = self.command_map[sct]() self.command.decode(self.bitbin) def set_splice_descriptor(self): # splice_descriptor_tag 8 uimsbf tag = self.bitbin.asint(8) if tag in self.descriptor_map.keys(): return self.descriptor_map[tag](self.bitbin, tag) def show_info_section(self): if self.info_section and self.command: self.sectionstart('Splice Info Section') self.kvprint(self.info_section) else: return False def show_command(self): if self.command: self.sectionstart('Splice Command') self.kvprint(self.command) else: return False def show_descriptors(self): if len(self.descriptors) > 0: for d in self.descriptors: idx = self.descriptors.index(d) self.sectionstart(f'Splice Descriptor {idx}') self.kvprint(d) def show(self): if self.info_section and self.command: self.sectionstart('[SCTE 35 Message]') self.show_info_section() self.show_command() self.show_descriptors() else: return False
def parse_pusi(self, packet): bitbin = BitBin(packet) if bitbin.asint(24) != 1: return if bitbin.asint(8) in self.NON_PTS_STREAM_IDS: return # PES_packet_length = bitbin.forward(16) if bitbin.asint(2) != 2: return bitbin.forward(6) ''' PES_scramble_control = bitbin.asint(2) PES_priority = bitbin.asint(1) data_align_ind = bitbin.asint(1) copyright = bitbin.asint(1) orig_or_copy = bitbin.asint(1) ''' if bitbin.asint(2) != 2: return bitbin.forward(14) if bitbin.asint(4) != 2: return a = bitbin.asint(3) << 30 bitbin.forward(1) b = bitbin.asint(15) << 15 bitbin.forward(1) c = bitbin.asint(15) d = (a + b + c) / 90000.0 fpts = f'PTS \033[92m{d:.3f}\033[0m ' print(f'\r{fpts}', end="\r") return
def decode(self, bites): bitbin = BitBin(bites) self.table_id = bitbin.ashex(8) if self.table_id != '0xfc': raise ValueError('splice_info_section.table_id should be 0xfc') self.section_syntax_indicator = bitbin.asflag(1) self.private = bitbin.asflag(1) self.reserved = bitbin.ashex(2) if self.reserved != '0x3': raise ValueError('splice_info_section.reserved should be 0x3') self.section_length = bitbin.asint(12) self.protocol_version = bitbin.asint(8) if self.protocol_version != 0: raise ValueError( 'splice_info_section.protocol_version should be 0') self.encrypted_packet = bitbin.asflag(1) self.encryption_algorithm = bitbin.asint(6) self.pts_adjustment = bitbin.as90k(33) self.cw_index = bitbin.ashex(8) self.tier = bitbin.ashex(12) self.splice_command_length = bitbin.asint(12) self.splice_command_type = bitbin.asint(8) self.descriptor_loop_length = 0