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('<HBBBB',file.read(6))
        self.samplerate = FSCOD[info[1] >> 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 )
