2008-09-02 11 views
25

Ich lese einige MPEG Transport Stream-Protokoll über UDP und es hat einige funky Bitfields (Länge 13 zum Beispiel). Ich benutze die "struct" -Bibliothek, um das breite Entpacken zu machen, aber gibt es eine einfache Möglichkeit, "die nächsten 13 Bits zu greifen", anstatt die Bit-Manipulation manuell zu optimieren? Ich möchte etwas wie die Art, wie C Bitfelder macht (ohne zu C zurückkehren zu müssen).Was ist der beste Weg, Bit-Feld-Manipulation in Python zu machen?

Vorschläge?

Antwort

25

Das bitstring Modul nur dieses Problem zu lösen ausgelegt ist. Sie können Daten lesen, ändern und konstruieren, indem Sie Bits als Grundbausteine ​​verwenden. Die neuesten Versionen sind für Python 2.6 oder höher (einschließlich Python 3), aber Version 1.0 unterstützt auch Python 2.4 und 2.5.

Ein relevantes Beispiel für Sie könnte dies sein, die aus einem Transportstrom alle Nullpakete abstreift (und möglicherweise verwendet Ihre 13-Bit-Feld?):

from bitstring import Bits, BitStream 

# Opening from a file means that it won't be all read into memory 
s = Bits(filename='test.ts') 
outfile = open('test_nonull.ts', 'wb') 

# Cut the stream into 188 byte packets 
for packet in s.cut(188*8): 
    # Take a 13 bit slice and interpret as an unsigned integer 
    PID = packet[11:24].uint 
    # Write out the packet if the PID doesn't indicate a 'null' packet 
    if PID != 8191: 
     # The 'bytes' property converts back to a string. 
     outfile.write(packet.bytes) 

Hier ist ein weiteres Beispiel einschließlich von Bitströmen Lesen :

# You can create from hex, binary, integers, strings, floats, files... 
# This has a hex code followed by two 12 bit integers 
s = BitStream('0x000001b3, uint:12=352, uint:12=288') 
# Append some other bits 
s += '0b11001, 0xff, int:5=-3' 
# read back as 32 bits of hex, then two 12 bit unsigned integers 
start_code, width, height = s.readlist('hex:32, 2*uint:12') 
# Skip some bits then peek at next bit value 
s.pos += 4 
if s.peek(1): 
    flags = s.read(9) 

können Sie Standard-Slice-Notation schneiden, löschen umzukehren, zu überschreiben, usw. auf Bit-Ebene, und es gibt finden Bit-Ebene, ersetzen, geteilt usw. Funktionen. Verschiedene Endianesses werden ebenfalls unterstützt.

# Replace every '1' bit by 3 bits 
s.replace('0b1', '0b001') 
# Find all occurrences of a bit sequence 
bitposlist = list(s.findall('0b01000')) 
# Reverse bits in place 
s.reverse() 

Die vollständige Dokumentation ist here.

+0

Ich denke, das Paket [11:24] .uint sollte Paket sein [12:24] .uint. Das Feld ist 13 Bit lang, beginnt bei Bit 12 und endet bei Bit 24. –

+0

Das hätte eigentlich ein Kommentar sein sollen und keine Antwort, aber nein, es ist wirklich [11:24]. Indizes sind nullbasiert und schließen den Endindex nicht ein (was in Python und vielen anderen Sprachen standardmäßig verwendet wird). So wäre eine Scheibe nur des ersten Bits [0: 1], während [12:24] eine 12-Bit-Scheibe vom 13. bis einschließlich 24. Bit wäre. Beachten Sie, dass die Länge immer die Differenz zwischen den beiden Indizes ist. –