def analyseFromTS(self, filepath, pid): ts = TS() data = ts.extract(pid=pid, infilepath=filepath) print "TS extraction done" self.bits = bitstring.ConstBitStream(hex=data) with open("userdata.bin", "wb") as f: f.write(data) # self.analyse() print self.bits.pos print "nb PES : %s" % len(list(self.bits.findall("0x000001e0"))) print self.bits.pos self.bits.pos = 0 print self.bits.pos print "pictures : %s" % list(self.bits.findall("0x00000100")) print self.bits.pos print "sequence header : %s" % list(self.bits.findall("0x000001b3")) self.parse_sequence_header(list(self.bits.findall("0x000001b3"))) print self.bits.pos print "GOP : %s" % list(self.bits.findall("0x000001b8")) print self.bits.pos print "user data : %s" % list(self.bits.findall("0x000001b2")) print self.bits.pos print "ATSC_user_data : %s" % list(self.bits.findall("0x000001b247413934")) print self.bits.pos print "afd_data : %s" % list(self.bits.findall("0x000001b244544731")) # print 'SEI itu_t_35 : %s' %list(self.bits.findall('0xb50031')) print "SEI ATSC_user_data : %s" % list(self.bits.findall("0xb5003147413934")) for pos in list(self.bits.findall("0xb5003147413934", bytealigned=True)): self.parse_ATSC_user_data(pos + (7 * 8)) print "SEI afd_data : %s" % list(self.bits.findall("0xb5003144544731")) for pos in list(self.bits.findall("0xb5003144544731", bytealigned=True)): self.parse_afd_data(pos + (7 * 8)) print self.bits.find("0x000001b2") # self.getUserData() self.write()
class vbiPES(object): def __init__(self): self.bits=None self.ts=TS() self.line_infos=[] self.pesInfos=[] #list of currentPES dict self.currentPES={} self.pesStat=[] # [ {pts:PTS,data:[(line_idx,data_type),(line_idx,data_type)]}, # {pts:PTS,data:[(line_idx,data_type),(line_idx,data_type)]}, # {pts:PTS,data:[(line_idx,data_type),(line_idx,data_type)]} ] def find_sync(self): return self.bits.find('0x000001bd') def parse_header(self): self.packet_start_code,self.stream_id,self.pes_packet_lentgh = self.bits.readlist('hex:24,hex:8,uint:16') #use le when generating from lib... #print 'packet_start_code 0x%s' %self.packet_start_code #print 'stream_id 0x%s' %self.stream_id #print 'pes_packet_lentgh %s' %self.pes_packet_lentgh #self.pesInfos.append(pesInfos) logging.debug('packet_start_code : 0x%s' %str(self.packet_start_code)) if (self.packet_start_code == '000001') : #000001 if(self.stream_id == 'bd' ): optional_pes_header_part,self.pes_header_data_length=self.bits.readlist('hex:16,uint:8') self.currentPES={} pesInfos={} pesInfos['optional_pes_header_part']=optional_pes_header_part pesInfos['pes_header_data_length']=self.pes_header_data_length #print 'optional_pes_header_part 0x%s' %optional_pes_header_part #print 'pes_header_data_length %s' %self.pes_header_data_length if self.pes_header_data_length>0: if optional_pes_header_part=='8480': # PTS field present if self.pes_header_data_length == 5: pts_field=self.bits.read('hex:40') #5*8 pesInfos['PTS']=pts_field elif self.pes_header_data_length == 36: pts_field=self.bits.read('hex:40') stuffing=self.bits.read('hex:248') pesInfos['PTS']=pts_field else: print 'error : pes_header_data_length %d' %self.pes_header_data_length pesInfos['error']='pes header data' elif optional_pes_header_part == '8401': if self.pes_header_data_length == 36: pesInfos['PTS']=self.bits.read('hex:288') else: print 'error : pes_header_data_length' pesInfos['error']='pes_header_data_length' else: print 'error optional_pes_header_part 0x%s, skipping %s bytes...' %(str(optional_pes_header_part),str(self.pes_header_data_length)) skip=self.pes_header_data_length*8 self.bits.read('hex:%s' %str(skip)) pesInfos['error']='error optional_pes_header_part 0x%s, skipping %s bytes...' %(str(optional_pes_header_part),str(self.pes_header_data_length)) self.currentPES['header']=pesInfos return True else: logging.error('VBI PES header : stream_id=0x%s' %self.stream_id) return False else: logging.error('VBI PES header : packet_start_code=0x%s at bytes %d/%d' %(self.packet_start_code,self.bits.bytepos,(len(self.bits)/8))) return False def parsePayload(self): self.data_identifier=self.bits.read('uint:8') logging.debug('data_identifier %s' %self.data_identifier) if self.data_identifier==16: #while self.parse_teletext_data()==True: # pass self.parse_teletext_data() #return successful or not? else: logging.warning('other data_identifier : %s , skipping bytes...' %str(self.data_identifier)) skip=self.bits.read('hex:%s' %str((self.pes_packet_lentgh-2-self.pes_header_data_length-2)*8)) return self.pes_packet_lentgh-2-self.pes_header_data_length-2 def parse_teletext_data(self): lenght=self.pes_packet_lentgh-2-self.pes_header_data_length-1-1 logging.debug('%s nb bytes to parse' %str(lenght)) self.line_infos=[] while lenght>0: if (self.bits.pos+(3*8)) < len(self.bits): data_unit_id,data_unit_lenght,reserved,field_parity,line = self.bits.readlist('hex:8,uint:8,bin:2,bin:1,uint:5') if data_unit_lenght == 0: print 'Error sync !?? Aborting... lenght=%s data_unit_id=%s' %(lenght,data_unit_id) return False logging.debug('data_unit_id %s ' %data_unit_id) logging.debug('data_unit_lenght %s ' %data_unit_lenght) logging.debug('line %s ' %line) if (self.bits.pos+((data_unit_lenght-1)*8)) < len(self.bits): data=self.bits.read('hex:%s' %str((data_unit_lenght-1)*8)) self.line_infos.append( (data_unit_id,data_unit_lenght,field_parity,line,data) ) lenght-=(data_unit_lenght+2) #self.print_line_infos() #store infos else: return False else: return False self.print_line_infos() return True def print_line_infos(self): logging.debug('### new PES') #add pes packet nb infos=[] self.currentPES['payload']=[] for data_unit_id,data_unit_lenght,field_parity,line,data in self.line_infos: if data_unit_id in data_unit_info.keys(): logging.debug('* found %s on line %s '%(data_unit_info[data_unit_id],line)) line_infos={} line_infos['data_unit_id']=data_unit_id line_infos['data_unit_lenght']=data_unit_lenght #if field_parity == 0 and (data_unit_id=='02' or data_unit_id=='03'): # line+=314 line_infos['line']=line #check fo doublon? line_infos['data']=data infos.append(line_infos) self.currentPES['payload']=infos #payload image number? #print data def fromFile(self,filepath): self.bits=bitstring.ConstBitStream(filename=filepath) #def analysefromES(self,filepath=None): #self.parsePayload() def analyse(self,filepath=None): #fromPES logging.info('PES analyse') if filepath !=None: self.fromFile(filepath) self.find_sync() #while self.bits.pos+48 < len(self.bits) : #6*8+4*8 while self.parse_header() == True: size=self.parsePayload() #better to return info dict self.pesInfos.append(self.currentPES) #print 'resyncing' #self.bits.pos+=8 #print self.bits.pos #print len(self.bits) def analyseFromTS(self,filepath,pid): data = self.ts.extract(pid=pid,infilepath=filepath) logging.info('TS extraction done') self.bits=bitstring.ConstBitStream(hex=data) #with open('vbipes.bin','wb') as f: # f.write(data) self.analyse() self.computeStat() def computeStat(self): pesStat=[] for pes in self.pesInfos: stat={} if 'header' in pes.keys(): if 'PTS' in pes['header'].keys(): stat['pts']=pes['header']['PTS'] else: stat['pts']=None else: stat['pts']=None data=[] if 'payload' in pes.keys(): for line_info in pes['payload']: data.append( (line_info['line'],line_info['data_unit_id']) ) stat['data']=data pesStat.append(stat) self.pesStat=pesStat # Write functions def writeES(self,filepath): logging.warning('ES stream writing not implemented yet...') pass def writePES(self,filepath): self.ts.writePES(filepath) #or write self.bits! def writeReport(self,filepath,mode='md'): logging.info('writeReport (%s): write %s pes infos' %(mode,str(len(self.pesInfos)))) logging.debug('write into %s' %str(os.path.basename(filepath))) if mode == 'md': with open(filepath,'a') as mdfile: pesidx=0 for pes in self.pesInfos: pesidx+=1 mdfile.write('* PES %s infos \n' %str(pesidx)) mdfile.write(' \n') if 'header' in pes.keys(): for key in pes['header'].keys(): mdfile.write(' %s : %s \n'%(key,pes['header'][key])) if 'payload' in pes.keys(): for line_info in pes['payload']: mdfile.write(' found %s on line %s : %s bytes \n'%(data_unit_info[line_info['data_unit_id']],line_info['line'],line_info['data_unit_lenght'])) mdfile.write(' \n') mdfile.close() # Check functions def checkDeltaPTS(self,valueInTick): delta=[] prev_pts=self.pesStat[0]['pts'] result=False status='no PTS found' for pes in self.pesStat[1:]: try: delta.append(long(pes['pts'],base=16)-long(prev_pts,base=16)) except : pass prev_pts=pes['pts'] if len(delta): logging.debug('Delta PTS min : %s' %str(min(delta))) logging.debug('Delta PTS max : %s' %str(max(delta))) if min(delta[1:])==long(valueInTick): result=True status='Min:%s / Max:%s' %( str(min(delta[1:])),str(max(delta[1:])) ) return (result,status) def checkDataUnit(self,value): result=False status='not found' return (result,status) def checkDataLine(self,lineNb,param,value): result=False status='not found' value_list=[] pes_idx=0 for pes in self.pesInfos: pes_idx+=1 if 'payload' in pes.keys(): for line_info in pes['payload']: if line_info['line']==int(lineNb): if int(line_info[param])==int(value): #print 'found param %s:%s' %(param,line_info[param]) value_list.append(True) if len(value_list)>0: result=True status='%d/%d' %(len(value_list),pes_idx) return (result,status) def check(self,action,lineNb=None,param=None,value=None,report=None): #available_action=['line','data_unit','PTS'] if action=='line': msg='line %d check if %s=%s...' %(int(lineNb),str(param),str(value)) res=self.checkDataLine(lineNb,param,value) elif action=='data_unit': msg='check if data_unit=%s...' %(str(value)) res=self.checkDataUnit(value) elif action=='PTS': msg='check if Delta PTS=%s...' %(str(value)) res=self.checkDeltaPTS(value) else: msg='Unknown check expression %s.Skipping.' %action return False logging.info(' %s : %s' %(str(msg),str(res)) ) if report!=None: md=' %s : %s\n' %(str(msg),str(res)) mdfile=open(report,'a') # codecs.open(report,'a','utf8') mdfile.write(md) #mdfile.write(' \n') mdfile.close() return res