A python .ap and .sc generator for enigma2 recordings
In my quest to make a transcoder for recordings on my enigma2 satellite receiver I've made an .ap and .sc file generator in python. The .ap and .sc files are used for more accurate skipping in the recording when viewing on the receiver. As input and inspiration I used ProcessApSc plugin by Michel Hartman and also the OpenPli source forpvrparse.cpp.
from struct import pack, unpack import io import os.path import sys LEN = 24064 PACKET_SIZE = 188 def WriteBufInternal(f, sc, tm): f.write(pack( '>QQ' , sc, tm)) def FrameGenerator(ts, packetoffset = 0 , maxlen = - 1 ): s = io. open (ts, 'rb' , buffering = LEN ) buf = bytearray(PACKET_SIZE) streamtype = - 1 pid = - 1 while len (s.peek())> = PACKET_SIZE: #Skip if not a whole packet left while ord (s.peek()[ 0 ]) ! = 0x47 : #Sync stream s.read( 1 ) print ( "Skipped 1 byte" ) filepos = s.tell() if maxlen > = 0 and filepos > maxlen: #Limit reading for debugging purposes break if s.readinto(buf) ! = PACKET_SIZE: #If not enough data quit s.close() break if not buf[ 3 ]& 0x10 : #Skip if there is no payload continue pos = buf[ 4 ] + 5 if buf[ 3 ]& 0x20 else 4 #Skip adaption field if pos > PACKET_SIZE: #Skip large adaption field continue tpid = ((buf[ 1 ]& 0x1F ) << 8 ) | buf[ 2 ] #Read current packet pid if ( not (buf[pos] or buf[pos + 1 ] or not buf[pos + 2 ]& 0x01 ) and buf[pos + 3 ]& 0xf0 = = 0xe0 and buf[ 1 ]& 0x040 ): #Find video pid pid = tpid elif pid> = 0 and pid ! = tpid: #Wrong pid continue pts = - 1 if buf[ 1 ]& 0x40 : #Pusi if buf[pos] or buf[pos + 1 ] or not buf[pos + 2 ]& 0x01 : print ( "Broken startcode" ) continue if buf[pos + 7 ]& 0x80 : #PTS present? pts = ((buf[pos + 9 ]& 0xE ) << 29 | (buf[pos + 10 ]& 0xFF ) << 22 | (buf[pos + 11 ]& 0xFE ) << 14 | (buf[pos + 12 ]& 0xFF ) << 7 | (buf[pos + 13 ]& 0xFE ) >> 1 ) pos = buf[pos + 8 ] + 9 while pos < PACKET_SIZE - 4 : if not (buf[pos] or buf[pos + 1 ] or not buf[pos + 2 ]& 0x01 ): sc = buf[pos + 3 ] if streamtype < 0 : #Stream type is unknown if sc in [ 0x00 , 0xb3 , 0xb8 ]: streamtype = 0 print ( "Detected MPEG2 stream type" ) elif sc in [ 0x09 ]: streamtype = 1 print ( "Detected H264 stream type" ) else : pos + = 1 continue if streamtype = = 0 : #MPEG2 if sc in [ 0x00 , 0xb3 , 0xb8 ]: #Picture, sequence, group start code retpos = retpts = retdat = retpos2 = - 1 if sc = = 0xb3 and pts > = 0 : #Sequence header retpos = filepos retpts = pts if pos < PACKET_SIZE - 6 : retdat = sc | buf[pos + 4 ] << 8 | buf[pos + 5 ] << 16 if pts > = 0 : retdat | = (pts << 31 ) | 0x1000000 ; retpos2 = filepos + pos yield (retpts, retpos, retdat, retpos2) elif streamtype = = 1 : if sc = = 0x09 : retpos = retpts = retdat = retpos2 = - 1 retdat = sc | (buf[pos + 4 ] << 8 ) if pts > = 0 : retdat | = (pts << 31 ) | 0x1000000 retpos2 = filepos + pos if (buf[pos + 4 ]& 0x60 ) = = 0 : if pts > = 0 : retpos = filepos retpts = pts yield (retpts, retpos, retdat, retpos2) pos + = 1 def ProcessScAp(ts, maxlen = - 1 ): scf = open (ts + '.sc' , 'wb' ) apf = open (ts + '.ap' , 'wb' ) filesize = os.path.getsize(ts) lastprogress = - 1 for (pts, pos, dat, pos2) in FrameGenerator(ts, maxlen = maxlen): curpos = max (pos, pos2) if curpos > = 0 : progress = curpos * 100 / filesize if progress > lastprogress: print ( "{0}%" . format (progress)) lastprogress = progress if pts > = 0 and pos > = 0 : WriteBufInternal(apf, pos, pts) if dat > = 0 and pos2 > = 0 : WriteBufInternal(scf, pos2, dat) scf.close() apf.close() |
Posting Komentar