from mmpython import mediainfo import mmpython import struct # http://www.atsc.org/standards/a_52a.pdf # fscod: Sample rate code, 2 bits # 00 48 # 01 44.1 # 10 32 # 11 reserved FSCOD = [ 48000, 44100, 32000, 0 ] # bsmod: Bit stream mode, 3 bits # bsmod acmod Type of Service # 000 any main audio service: complete main (CM) # 001 any main audio service: music and effects (ME) # 010 any associated service: visually impaired (VI) # 011 any associated service: hearing impaired (HI) # 100 any associated service: dialogue (D) # 101 any associated service: commentary (C) # 110 any associated service: emergency (E) # 111 001 associated service: voice over (VO) # 111 010 - 111 main audio service: karaoke # # acmod: Audio coding mode, 3 bits # 000 1+1 2 Ch1, Ch2 # 001 1/0 1 C # 010 2/0 2 L, R # 011 3/0 3 L, C, R # 100 2/1 3 L, R, S # 101 3/1 4 L, C, R, S # 110 2/2 4 L, R, SL, SR # 111 3/2 5 L, C, R, SL, SR ACMOD = [ ( '1+1', 2, 'Ch1, Ch2' ), ( '1/0', 1, 'C' ), ( '2/0', 2, 'L, R' ), ( '3/0', 3, 'L, C, R' ), ( '2/1', 3, 'L, R, S' ), ( '3/1', 4, 'L, C, R, S' ), ( '2/2', 4, 'L, R, SL, SR' ), ( '3/2', 5, 'L, C, R, SL, SR' ) ] # dsurmod: Dolby surround mode, 2 bits # 00 not indicated # 01 Not Dolby Surround encoded # 10 Dolby Surround encoded # 11 reserved # # lfeon: Low frequency effects channel on, 1 bit # This bit has a value of 1 if the lfe (sub woofer) channel is on, and a # value of 0 if the lfe channel is off. # # frmsizcod: # byte&0x3e = 0x00 \b, 32 kbit/s # byte&0x3e = 0x02 \b, 40 kbit/s # byte&0x3e = 0x04 \b, 48 kbit/s # byte&0x3e = 0x06 \b, 56 kbit/s # byte&0x3e = 0x08 \b, 64 kbit/s # byte&0x3e = 0x0a \b, 80 kbit/s # byte&0x3e = 0x0c \b, 96 kbit/s # byte&0x3e = 0x0e \b, 112 kbit/s # byte&0x3e = 0x10 \b, 128 kbit/s # byte&0x3e = 0x12 \b, 160 kbit/s # byte&0x3e = 0x14 \b, 192 kbit/s # byte&0x3e = 0x16 \b, 224 kbit/s # byte&0x3e = 0x18 \b, 256 kbit/s # byte&0x3e = 0x1a \b, 320 kbit/s # byte&0x3e = 0x1c \b, 384 kbit/s # byte&0x3e = 0x1e \b, 448 kbit/s # byte&0x3e = 0x20 \b, 512 kbit/s # byte&0x3e = 0x22 \b, 576 kbit/s # byte&0x3e = 0x24 \b, 640 kbit/s FRMSIZCOD = [ 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640 ] class AC3Info(mediainfo.MusicInfo): def __init__(self,file): mediainfo.MusicInfo.__init__(self) if file.name.endswith('.ac3'): # when the ending is ac3, force the detection. It may not be necessary # the the header is at the beginning but in the first 2000 bytes check_length = 1000 else: check_length = 1 for i in range(check_length): if file.read(2) == '\x0b\x77': break else: self.valid = False return info = struct.unpack('> 6] self.bitrate = FRMSIZCOD[(info[1] & 0x3F) >> 1] * 1000 bsmod = info[2] & 0x7 channels = ACMOD[info[3] >> 5] acmod = info[3] >> 5 self.channels = ACMOD[acmod][1] bits = 0 if acmod & 0x01 and not acmod == 0x01: bits += 2 if acmod & 0x04: bits += 2 if acmod == 0x02: bits += 2 # info is now 5 bits of info[3] and all bits of info[4] ( == 13 bits) # 'bits' bits (0-6) bits are information we don't need, after that, # the bit we need is lfeon. info = (((info[3] & 0x1F) << 8) + info[4]) # now we create the mask we need (based on 'bits') # the bit number 13 - 'bits' is what we want to read for i in range(13 - bits - 1): info = info >> 1 if info & 1: # subwover self.channels += 1 self.valid = True self.codec = 'AC3' self.mime = 'audio/ac3' mmpython.registertype( 'audio/ac3', ('ac3',), mediainfo.TYPE_MUSIC, AC3Info )