1 | from mmpython import mediainfo |
---|
2 | import mmpython |
---|
3 | |
---|
4 | import struct |
---|
5 | |
---|
6 | # http://www.atsc.org/standards/a_52a.pdf |
---|
7 | # fscod: Sample rate code, 2 bits |
---|
8 | # 00 48 |
---|
9 | # 01 44.1 |
---|
10 | # 10 32 |
---|
11 | # 11 reserved |
---|
12 | |
---|
13 | FSCOD = [ 48000, 44100, 32000, 0 ] |
---|
14 | |
---|
15 | # bsmod: Bit stream mode, 3 bits |
---|
16 | # bsmod acmod Type of Service |
---|
17 | # 000 any main audio service: complete main (CM) |
---|
18 | # 001 any main audio service: music and effects (ME) |
---|
19 | # 010 any associated service: visually impaired (VI) |
---|
20 | # 011 any associated service: hearing impaired (HI) |
---|
21 | # 100 any associated service: dialogue (D) |
---|
22 | # 101 any associated service: commentary (C) |
---|
23 | # 110 any associated service: emergency (E) |
---|
24 | # 111 001 associated service: voice over (VO) |
---|
25 | # 111 010 - 111 main audio service: karaoke |
---|
26 | # |
---|
27 | # acmod: Audio coding mode, 3 bits |
---|
28 | # 000 1+1 2 Ch1, Ch2 |
---|
29 | # 001 1/0 1 C |
---|
30 | # 010 2/0 2 L, R |
---|
31 | # 011 3/0 3 L, C, R |
---|
32 | # 100 2/1 3 L, R, S |
---|
33 | # 101 3/1 4 L, C, R, S |
---|
34 | # 110 2/2 4 L, R, SL, SR |
---|
35 | # 111 3/2 5 L, C, R, SL, SR |
---|
36 | |
---|
37 | ACMOD = [ ( '1+1', 2, 'Ch1, Ch2' ), |
---|
38 | ( '1/0', 1, 'C' ), |
---|
39 | ( '2/0', 2, 'L, R' ), |
---|
40 | ( '3/0', 3, 'L, C, R' ), |
---|
41 | ( '2/1', 3, 'L, R, S' ), |
---|
42 | ( '3/1', 4, 'L, C, R, S' ), |
---|
43 | ( '2/2', 4, 'L, R, SL, SR' ), |
---|
44 | ( '3/2', 5, 'L, C, R, SL, SR' ) ] |
---|
45 | |
---|
46 | |
---|
47 | # dsurmod: Dolby surround mode, 2 bits |
---|
48 | # 00 not indicated |
---|
49 | # 01 Not Dolby Surround encoded |
---|
50 | # 10 Dolby Surround encoded |
---|
51 | # 11 reserved |
---|
52 | # |
---|
53 | # lfeon: Low frequency effects channel on, 1 bit |
---|
54 | # This bit has a value of 1 if the lfe (sub woofer) channel is on, and a |
---|
55 | # value of 0 if the lfe channel is off. |
---|
56 | # |
---|
57 | # frmsizcod: |
---|
58 | # byte&0x3e = 0x00 \b, 32 kbit/s |
---|
59 | # byte&0x3e = 0x02 \b, 40 kbit/s |
---|
60 | # byte&0x3e = 0x04 \b, 48 kbit/s |
---|
61 | # byte&0x3e = 0x06 \b, 56 kbit/s |
---|
62 | # byte&0x3e = 0x08 \b, 64 kbit/s |
---|
63 | # byte&0x3e = 0x0a \b, 80 kbit/s |
---|
64 | # byte&0x3e = 0x0c \b, 96 kbit/s |
---|
65 | # byte&0x3e = 0x0e \b, 112 kbit/s |
---|
66 | # byte&0x3e = 0x10 \b, 128 kbit/s |
---|
67 | # byte&0x3e = 0x12 \b, 160 kbit/s |
---|
68 | # byte&0x3e = 0x14 \b, 192 kbit/s |
---|
69 | # byte&0x3e = 0x16 \b, 224 kbit/s |
---|
70 | # byte&0x3e = 0x18 \b, 256 kbit/s |
---|
71 | # byte&0x3e = 0x1a \b, 320 kbit/s |
---|
72 | # byte&0x3e = 0x1c \b, 384 kbit/s |
---|
73 | # byte&0x3e = 0x1e \b, 448 kbit/s |
---|
74 | # byte&0x3e = 0x20 \b, 512 kbit/s |
---|
75 | # byte&0x3e = 0x22 \b, 576 kbit/s |
---|
76 | # byte&0x3e = 0x24 \b, 640 kbit/s |
---|
77 | |
---|
78 | FRMSIZCOD = [ 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, |
---|
79 | 224, 256, 320, 384, 448, 512, 576, 640 ] |
---|
80 | |
---|
81 | class AC3Info(mediainfo.MusicInfo): |
---|
82 | def __init__(self,file): |
---|
83 | mediainfo.MusicInfo.__init__(self) |
---|
84 | if file.name.endswith('.ac3'): |
---|
85 | # when the ending is ac3, force the detection. It may not be necessary |
---|
86 | # the the header is at the beginning but in the first 2000 bytes |
---|
87 | check_length = 1000 |
---|
88 | else: |
---|
89 | check_length = 1 |
---|
90 | for i in range(check_length): |
---|
91 | if file.read(2) == '\x0b\x77': |
---|
92 | break |
---|
93 | else: |
---|
94 | self.valid = False |
---|
95 | return |
---|
96 | |
---|
97 | info = struct.unpack('<HBBBB',file.read(6)) |
---|
98 | self.samplerate = FSCOD[info[1] >> 6] |
---|
99 | self.bitrate = FRMSIZCOD[(info[1] & 0x3F) >> 1] * 1000 |
---|
100 | bsmod = info[2] & 0x7 |
---|
101 | channels = ACMOD[info[3] >> 5] |
---|
102 | acmod = info[3] >> 5 |
---|
103 | self.channels = ACMOD[acmod][1] |
---|
104 | bits = 0 |
---|
105 | if acmod & 0x01 and not acmod == 0x01: |
---|
106 | bits += 2 |
---|
107 | if acmod & 0x04: |
---|
108 | bits += 2 |
---|
109 | if acmod == 0x02: |
---|
110 | bits += 2 |
---|
111 | |
---|
112 | # info is now 5 bits of info[3] and all bits of info[4] ( == 13 bits) |
---|
113 | # 'bits' bits (0-6) bits are information we don't need, after that, |
---|
114 | # the bit we need is lfeon. |
---|
115 | info = (((info[3] & 0x1F) << 8) + info[4]) |
---|
116 | |
---|
117 | # now we create the mask we need (based on 'bits') |
---|
118 | # the bit number 13 - 'bits' is what we want to read |
---|
119 | for i in range(13 - bits - 1): |
---|
120 | info = info >> 1 |
---|
121 | if info & 1: |
---|
122 | # subwover |
---|
123 | self.channels += 1 |
---|
124 | self.valid = True |
---|
125 | self.codec = 'AC3' |
---|
126 | self.mime = 'audio/ac3' |
---|
127 | |
---|
128 | mmpython.registertype( 'audio/ac3', ('ac3',), mediainfo.TYPE_MUSIC, AC3Info ) |
---|