Парсинг метаданных файлов TAK на Ассемблере
Парсинг метаданных файлов TAK на Ассемблере
TAK (аббревиатура на немецком, которая расшифровывается как "Tom's lossless Audio Compressor") - это алгоритм сжатия аудиофайлов без потерь. Кодек TAK обеспечивает эффективность сжатия на уровне формата APE, достигая при этом скорости декодирования, как у популярного кодека FLAC. Формат достаточно экзотичный, но при этом его понимают некоторые плееры. Но для меня главное, что формат TAK поддерживает метатеги, которые меня интересуют в плане парсинга.
К сожалению, в настоящее время формат считает проприетарным, при этом ни нормальной документации, ни официального описания структуры файлов я не нашел. Пришлось работать с готовыми файлами, благо там ничего особо сложного нет, хотя и без своих заморочек не обошлось. Но обо всем по порядку.
Файл начинается с 4-байтной сигнатуры "tBaK", за которым следует 35h байт служебных данных, назначение которых мне не удалось идентифицировать. Тут важно, что их размер фиксированный. За ними следует заголовок WAV-файла с метаданными. Очень немного напоминает разобранный ранее формат OptimFROG. А вот проблема заключается в том, что размер этого заголовка достоверно установить не удается, в некоторых файлах определенный DWORD соответствует их размеру, но в других там оказывается вообще неправильное значение. По итогу я решил просто читать достаточное количество байт, в которое поместятся метаданные, а затем его парсить, как и в предыдущем примере. Код получился следующим:
Code (Assembler) : Убрать нумерацию
- ; Прочитать заголовок файла
- invoke _llseek,[desc],0,FILE_BEGIN
- invoke _lread,[desc],buff,39h
- cmp dword[buff],'tBaK'
- jne loc_close_tak
- ; Прочитать данные WAV
- invoke _lread,[desc],buff,BUFF_SIZE
- ; Проверить корректность данных
- mov esi,buff
- lodsd
- cmp eax,'RIFF'
- jne loc_close_tak
- lodsd
- lodsd
- cmp eax,'WAVE'
- jne loc_close_tak
- lodsd
- lodsd
- add esi,eax
- loc_parse_tak:
- ; Название секции
- lodsd
- ; Перевести в нижний регистр
- or eax,20202020h
- cmp eax,'data'
- jne @f
- ; Пропускаем секцию "data", если она есть
- lodsd
- jmp loc_parse_tak
- @@:
- ; Метаданные в секции LIST?
- cmp eax,'list'
- je loc_read_list
- ; Метаданные в секции ID3?
- cmp eax,'id3 '
- je loc_read_id3
- ; Неизвестные данные, останавливаем парсинг
- jmp loc_close_tak
- loc_read_list:
- ; Размер секции
- lodsd
- ; Учесть выравнивание секции
- inc eax
- and eax,0FFFFFFFEh
- mov ebx,eax
- mov [dPos],esi
- lodsd
- ; Перевести в нижний регистр
- or eax,20202020h
- cmp eax,'info'
- jne loc_close_tak
- loc_scan_list_tags:
- ; Все теги обработали?
- mov eax,esi
- sub eax,[dPos]
- cmp eax,ebx
- jae loc_parse_tak
- ; Пропустить финальные нули
- cmp byte[esi],0
- jne @f
- inc esi
- jmp loc_scan_list_tags
- @@:
- ; Наименование тега
- lodsd
- ; Перевести в нижний регистр
- or eax,20202020h
- mov edi,album
- cmp eax,'iprd'
- je @f
- mov edi,artist
- cmp eax,'iart'
- je @f
- mov edi,title
- cmp eax,'inam'
- je @f
- lodsd
- add esi,eax
- jmp loc_scan_list_tags
- @@:
- lodsd
- ; UTF-8 -> юникод
- push eax
- invoke MultiByteToWideChar,CP_UTF8,0,esi,eax,0,0
- invoke MultiByteToWideChar,CP_UTF8,0,esi,-1,edi,eax
- pop eax
- ; Следующий тег
- add esi,eax
- jmp loc_scan_list_tags
- ;----------------------------------------------
- ; Обработка секции ID3
- ;----------------------------------------------
- loc_read_id3:
- ; Размер секции
- lodsd
- ; Учесть выравнивание секции
- inc eax
- and eax,0FFFFFFFEh
- mov ebx,eax
- mov [dPos],esi
- ; ID3v2.3
- cmp dword [esi],0x03334449
- je @f
- ; ID3v2.4
- cmp dword [esi],0x04334449
- je @f
- add esi,ebx
- jmp loc_parse_tak
- @@:
- add esi,10
- loc_scan_id3_tags:
- ; Все теги обработали?
- mov eax,esi
- sub eax,[dPos]
- cmp eax,ebx
- jae loc_parse_tak
- cmp byte[esi],0
- je loc_close_tak
- ; Проверить валидность названия тега
- xor ecx,ecx
- loc_check_id3_wav:
- mov dl,byte[esi+ecx]
- cmp dl,'0'
- jb loc_close_tak
- cmp dl,'9'
- jbe @f
- cmp dl,'A'
- jb loc_close_tak
- cmp dl,'Z'
- ja loc_close_tak
- @@:
- inc ecx
- cmp ecx,4
- jb loc_check_id3_wav
- ; Album
- mov edi,album
- cmp dword [esi],'TALB'
- je @f
- ; Artist
- mov edi,artist
- cmp dword [esi],'TPE1'
- je @f
- ; Title
- mov edi,title
- cmp dword [esi],'TIT2'
- je @f
- ; Пропустить тег
- lodsd
- ; Размер данных
- lodsd
- bswap eax
- add esi,eax
- lodsw
- jmp loc_scan_id3_tags
- @@:
- lodsd
- ; Размер данных
- lodsd
- bswap eax
- mov ecx,eax
- ; Размер без учета байта типа кодировки
- dec ecx
- lodsw
- ; Тип кодировки строки
- lodsb
- or al,al
- jz loc_load_utf8
- loc_load_utf16:
- ; Пропустить BOM
- cmp word[esi],0xFEFF
- jne @f
- lodsw
- dec ecx
- dec ecx
- @@:
- ; Просто скопировать строку UTF-16
- rep movsb
- xor eax,eax
- stosw
- jmp loc_scan_id3_tags
- loc_load_utf8:
- ; UTF-8 -> юникод
- push ecx
- invoke MultiByteToWideChar,CP_UTF8,0,esi,ecx,0,0
- invoke MultiByteToWideChar,CP_UTF8,0,esi,-1,edi,eax
- pop ecx
- ; Следующий тег
- add esi,ecx
- jmp loc_scan_id3_tags
- loc_close_tak:
- invoke CloseHandle,[desc]
- ; title -> название композиции
- ; artist -> исполнитель
- ; album -> альбом
Просмотров: 182 | Комментариев: 2
Метки: Assembler, мультимедиа
Комментарии
Отзывы посетителей сайта о статье
Сергей Озеров
(30.11.2024 в 14:58):
Подскажите пожалуйста, а какая практическая польза от этого ? Кроме интересного исследования.
Добавить комментарий
Заполните форму для добавления комментария
Чтоб в ступе воду не толочь,
Душа обязана трудиться
И день и ночь, и день и ночь!
// Николай Заболоцкий
А если серьезно, то разбор метатегов используются у меня как минимум в двух проектах. Ну а раз все равно сделал парсер, то почему бы не поделиться результатами исследований с людьми? Может быть пригодится кому-нибудь еще.