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