initial code commit
This commit is contained in:
commit
e5d1ba5726
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.idea/
|
||||
|
0
py_aax_decode/__init__.py
Normal file
0
py_aax_decode/__init__.py
Normal file
233
py_aax_decode/native.py
Normal file
233
py_aax_decode/native.py
Normal file
@ -0,0 +1,233 @@
|
||||
from enum import Enum
|
||||
import ctypes
|
||||
import wave
|
||||
|
||||
|
||||
class MetaData(Enum):
|
||||
album_artist = 0x40617574
|
||||
publisher = 0x4070726F
|
||||
artist = 0x406E6172
|
||||
title = 0x406C6465 # TIT3
|
||||
copyright = 0x40636F70
|
||||
date = 0x40706461
|
||||
JPEG = 0x40636172
|
||||
audible_id = 0x40706964
|
||||
album = 0x40746974
|
||||
# _unknown1 = 0x40707469
|
||||
# _unknown2 = 0x40736465 #SHORTDESC
|
||||
# _unknown3 = 0x4075616 #STILLNOKLINGON?
|
||||
|
||||
|
||||
def main(in_file, out_file):
|
||||
handle = open_file(dll, in_file)
|
||||
|
||||
a = (dll, handle)
|
||||
channels = get_audio_channel_count(*a)
|
||||
sample_rate = get_sample_rate(*a)
|
||||
seek(*a, 0)
|
||||
authenticate(*a)
|
||||
|
||||
enc_buf = ctypes.create_string_buffer(0x400)
|
||||
dec_buf = ctypes.create_string_buffer(0x400 * 200)
|
||||
|
||||
length = 0
|
||||
with wave.open(out_file, 'wb') as wav:
|
||||
wav.setnchannels(channels)
|
||||
wav.setframerate(sample_rate)
|
||||
|
||||
while True:
|
||||
enc_data, enc_len = get_encoded_audio(*a, enc_buf)
|
||||
|
||||
if enc_len == 0:
|
||||
break
|
||||
|
||||
dec_data, dec_len = decode_pcm_frame(*a, enc_buf, enc_len, dec_buf)
|
||||
length += dec_len
|
||||
|
||||
wav.writeframes(dec_buf)
|
||||
|
||||
close_file(*a)
|
||||
|
||||
|
||||
def open_file(dll, filename):
|
||||
handle = ctypes.pointer(ctypes.c_byte)
|
||||
res = dll.AAXOpenFileWinW(handle, filename)
|
||||
|
||||
if res != 0:
|
||||
raise Exception('AAXOpenFileWinW: {}'.format(res))
|
||||
|
||||
return handle
|
||||
|
||||
|
||||
def close_file(dll, handle):
|
||||
res = dll.AAXCloseFile(handle)
|
||||
|
||||
if res != 0:
|
||||
raise Exception('AAXCloseFile: {}'.format(res))
|
||||
|
||||
|
||||
def get_audio_channel_count(dll, handle):
|
||||
n_channels = ctypes.c_uint()
|
||||
res = dll.AAXGetAudioChannelCount(handle, n_channels)
|
||||
|
||||
if res != 0:
|
||||
raise Exception('AAXGetAudioChannelCount: {}'.format(res))
|
||||
|
||||
return n_channels
|
||||
|
||||
|
||||
def get_sample_rate(dll, handle):
|
||||
sample_rate = ctypes.c_uint()
|
||||
res = dll.AAXGetSampleRate(handle, n_channels)
|
||||
|
||||
if res != 0:
|
||||
raise Exception('AAXGetSampleRate: {}'.format(res))
|
||||
|
||||
return sample_rate
|
||||
|
||||
|
||||
def seek(dll, handle, position=0):
|
||||
res = dll.AAXSeek(handle, position)
|
||||
|
||||
if res != 0:
|
||||
raise Exception('AAXSeek: {}'.format(res))
|
||||
|
||||
|
||||
def authenticate(dll, handle):
|
||||
res = dll.AAXAuthenticateWin(handle)
|
||||
|
||||
if res != 0:
|
||||
raise Exception('AAXAuthenticateWin: {}'.format(res))
|
||||
|
||||
|
||||
def get_encoded_audio(dll, handle, buf=None):
|
||||
if buf is None:
|
||||
buf = ctypes.create_string_buffer(0x400)
|
||||
|
||||
data_len = ctypes.c_uint()
|
||||
res = dll.AAXGetEncodedAudio(handle, buf, len(buf), data_len)
|
||||
|
||||
if res != 0:
|
||||
raise Exception('AAXGetEncodedAudio: {}'.format(res))
|
||||
|
||||
return buf, data_len
|
||||
|
||||
|
||||
def decode_pcm_frame(dll, handle, in_buf, in_len, out_buf=None):
|
||||
if out_buf is None:
|
||||
out_buf = ctypes.create_string_buffer(0x400 * 200)
|
||||
|
||||
data_len = ctypes.c_uint()
|
||||
res = dll.AAXDecodedPCMFrame(handle, in_buf, in_len, out_buf, len(out_buf), data_len)
|
||||
|
||||
if res != 0:
|
||||
raise Exception('AAXDecodedPCMFrame: {}'.format(res))
|
||||
|
||||
return out_buf, data_len
|
||||
|
||||
|
||||
def get_chapter_text(dll, handle, chapter_num, buf=None):
|
||||
if buf is None:
|
||||
buf = ctypes.create_string_buffer(0x400)
|
||||
|
||||
data_len = ctypes.c_uint()
|
||||
res = dll.AAXGetChapterText(handle, chapter_num, buf, len(buf), data_len)
|
||||
|
||||
if res != 0:
|
||||
raise Exception('AAXGetChapterText: {}'.format(res))
|
||||
|
||||
return buf, data_len
|
||||
|
||||
|
||||
def get_metadata(dll, handle, mdn):
|
||||
data_len = ctypes.c_uint()
|
||||
res = dll.AAXGetMetadataInfo(handle, mdn, None, data_len)
|
||||
|
||||
if res != 0:
|
||||
raise Exception('AAXGetMetadataInfo: {}'.format(res))
|
||||
|
||||
buf = ctypes.create_string_buffer(data_len)
|
||||
res = dll.AAXGetMetadata(handle, mdn, buf, data_len)
|
||||
|
||||
if res != 0:
|
||||
raise Exception('AAXGetChapterText: {}'.format(res))
|
||||
|
||||
return buf, data_len
|
||||
|
||||
|
||||
def seek_to_chapter(dll, handle, chapter):
|
||||
res = dll.AAXSeekToChapter(handle, chapter)
|
||||
|
||||
if res != 0:
|
||||
raise Exception('AAXSeekToChapter: {}'.format(res))
|
||||
|
||||
|
||||
def get_chapter_count(dll, handle):
|
||||
n_chapters = ctypes.c_uint()
|
||||
res = dll.AAXGetChapterCount(handle, n_chapters)
|
||||
|
||||
if res != 0:
|
||||
raise Exception('AAXGetChapterCount: {}'.format(res))
|
||||
|
||||
return n_chapters
|
||||
|
||||
|
||||
def get_current_chapter(dll, handle):
|
||||
chapter = ctypes.c_uint()
|
||||
res = dll.AAXGetCurrentChapter(handle, chapter)
|
||||
|
||||
if res != 0:
|
||||
raise Exception('AAXGetCurrentChapter: {}'.format(res))
|
||||
|
||||
return chapter
|
||||
|
||||
|
||||
def get_duration(dll, handle):
|
||||
duration = ctypes.c_uint()
|
||||
res = dll.AAXGetDuration(handle, duration)
|
||||
|
||||
if res != 0:
|
||||
raise Exception('AAXGetDuration: {}'.format(res))
|
||||
|
||||
return duration
|
||||
|
||||
|
||||
def get_playback_position(dll, handle):
|
||||
position = ctypes.c_uint()
|
||||
res = dll.AAXGetPlaybackPosition(handle, position)
|
||||
|
||||
if res != 0:
|
||||
raise Exception('AAXGetPlaybackPosition: {}'.format(res))
|
||||
|
||||
return position
|
||||
|
||||
|
||||
def get_chapter_start_time(dll, handle, chapter):
|
||||
position = ctypes.c_uint()
|
||||
res = dll.AAXGetChapterStartTime(handle, position, chapter)
|
||||
|
||||
if res != 0:
|
||||
raise Exception('AAXGetChapterStartTime: {}'.format(res))
|
||||
|
||||
return position
|
||||
|
||||
|
||||
def get_avg_bitrate(dll, handle):
|
||||
bitrate = ctypes.c_uint()
|
||||
res = dll.AAXGetAvgBitrate(handle, bitrate)
|
||||
|
||||
if res != 0:
|
||||
raise Exception('AAXGetAvgBitrate: {}'.format(res))
|
||||
|
||||
return bitrate
|
||||
|
||||
|
||||
def get_max_bitrate(dll, handle):
|
||||
bitrate = ctypes.c_uint()
|
||||
res = dll.AAXGetMaxBitrate(handle, bitrate)
|
||||
|
||||
if res != 0:
|
||||
raise Exception('AAXGetAvgBitrate: {}'.format(res))
|
||||
|
||||
return bitrate
|
||||
|
Loading…
Reference in New Issue
Block a user