Парсинг метаданных файлов OptimFROG на Ассемблере
Парсинг метаданных файлов OptimFROG на Ассемблере
OptimFROG - это аудиокодек для сжатия без потерь. Он оптимизирован для достижения максимально высокой степени сжатия и в настоящее время имеет один из лучших показателей по этому параметру. В качестве исходных данных используются WAV или RAW-файлы. При конвертировании в формат OptimFROG они сжимаются по специальному алгоритму, заточенному именно под аудиопотоки.
Файлы OFR представляют собой контейнеры, внутри которых записаны сжатые исходные данные в формате PCM (RAW) или WAV, соответственно, все метаданные извлекаются из них. Но из исходных форматов метаданные поддерживает только формат WAV. К этому мы еще вернемся, пока же начнем с парсинга внутренней структуры файла OptimFROG. Контейнер состоит из блоков, каждый из которых начинается с 4-байтного идентификатора, за которым следует DWORD с размером содержимого блока и за ним уже следуют сами данные. Первый блок всегда имеет идентификатор "OFR_" (последний символ - пробел), за ним блок "HEAD", в котором могут содержаться метаданные. Потом в файле записаны один или несколько блоков с идентификаторами "COMP" и завершается файл блоком "TAIL", в котором также могут содержаться метаданные. Корректность файла проверяется по идентификатору первого блока. Парсинг заключается в проверке наличия метаданных в блоке "HEAD" и/или "TAIL" и их последующим разбором в точности, как это делается с метаданными файлов WAV. Осталось оформить это в виде кода.
Code (Assembler) : Убрать нумерацию
- ; Прочитать заголовок файла
- invoke _llseek,[desc],0,FILE_BEGIN
- invoke _lread,[desc],buff,8
- cmp dword[buff],'OFR '
- jne loc_close_ofr
- invoke _llseek,[desc],dword [buff+4],FILE_CURRENT
- loc_parse_ofr:
- ; Прочитать первые 8 байт блока в контейнере
- invoke _lread,[desc],buff,8
- cmp eax,8
- jb loc_close_ofr
- cmp dword[buff],'HEAD'
- je loc_process_head
- cmp dword[buff],'TAIL'
- je loc_process_tail
- ; Следующий блок
- invoke _llseek,[desc],dword [buff+4],FILE_CURRENT
- jmp loc_parse_ofr
- loc_close_ofr:
- invoke CloseHandle,[desc]
- ; title -> название композиции
- ; artist -> исполнитель
- ; album -> альбом
- ...
- ...
- ...
- ;-----------------------------------------
- ; Разбор блока "HEAD"
- ;-----------------------------------------
- loc_process_head:
- mov eax,dword [buff+4]
- mov [dSize],eax
- ; Прочитать содержимое блока
- invoke GlobalAlloc,GMEM_ZEROINIT,[dSize]
- mov [hMem],eax
- invoke GlobalLock,[hMem]
- mov [pMem],eax
- ; Прочитать содержимое блока
- invoke _lread,[desc],[pMem],[dSize]
- cmp eax,[dSize]
- jb loc_close_head
- ; Проверить корректность данных
- mov esi,[pMem]
- lodsd
- cmp eax,'RIFF'
- jne loc_close_head
- lodsd
- lodsd
- cmp eax,'WAVE'
- jne loc_close_head
- lodsd
- lodsd
- add esi,eax
- mov eax,esi
- sub eax,[pMem]
- cmp eax,[dSize]
- jae loc_close_head
- ; Поискать метаданные
- stdcall parse_block
- loc_close_head:
- ; Освободить память
- invoke GlobalUnlock,[hMem]
- ; Следующий блок
- jmp loc_parse_ofr
- ;-----------------------------------------
- ; Разбор блока "TAIL"
- ;-----------------------------------------
- loc_process_tail:
- mov eax,dword [buff+4]
- mov [dSize],eax
- ; "Хвост" пустой?
- cmp [dSize],0
- je loc_close_ofr
- ; Прочитать содержимое блока
- invoke GlobalAlloc,GMEM_ZEROINIT,[dSize]
- mov [hMem],eax
- invoke GlobalLock,[hMem]
- mov [pMem],eax
- ; Прочитать содержимое блока
- invoke _lread,[desc],[pMem],[dSize]
- cmp eax,[dSize]
- jb loc_close_tail
- mov esi,[pMem]
- stdcall parse_block
- loc_close_tail:
- ; Освободить память
- invoke GlobalUnlock,[hMem]
- jmp loc_close_ofr
- ;-----------------------------------------
- ; Парсинг содержимого блока
- ;-----------------------------------------
- parse_block:
- mov eax,esi
- sub eax,[pMem]
- cmp eax,[dSize]
- jae parse_block_ret
- ; Название секции
- lodsd
- ; Перевести в нижний регистр
- or eax,20202020h
- ; Метаданные в секции LIST?
- cmp eax,'list'
- je loc_read_list
- ; Метаданные в секции ID3?
- cmp eax,'id3 '
- je loc_read_id3
- ; Размер секции
- lodsd
- ; Учесть выравнивание секции
- inc eax
- and eax,0FFFFFFFEh
- add esi,eax
- mov eax,esi
- sub eax,[pMem]
- cmp eax,[dSize]
- jb parse_block
- parse_block_ret:
- retn
- ;----------------------------------------------
- ; Обработка секции LIST
- ;----------------------------------------------
- loc_read_list:
- ; Размер секции
- lodsd
- ; Учесть выравнивание секции
- inc eax
- and eax,0FFFFFFFEh
- mov ebx,eax
- lodsd
- ; Перевести в нижний регистр
- or eax,20202020h
- cmp eax,'info'
- jne parse_block_ret
- loc_scan_list_tags:
- ; Все теги обработали?
- mov eax,esi
- sub eax,[pMem]
- cmp eax,ebx
- jae parse_block_ret
- ; Пропустить финальные нули
- 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 esi,[pMem]
- ; ID3v2.3
- cmp dword [esi],0x03334449
- je @f
- ; ID3v2.4
- cmp dword [esi],0x04334449
- je @f
- add esi,ebx
- jmp parse_block
- @@:
- add esi,10
- loc_scan_id3_tags:
- ; Все теги обработали?
- mov eax,esi
- sub eax,[pMem]
- cmp eax,ebx
- jae parse_block_ret
- cmp byte[esi],0
- je parse_block_ret
- ; Проверить валидность названия тега
- xor ecx,ecx
- loc_check_id3_wav:
- mov dl,byte[esi+ecx]
- cmp dl,'0'
- jb parse_block_ret
- cmp dl,'9'
- jbe @f
- cmp dl,'A'
- jb parse_block_ret
- cmp dl,'Z'
- ja parse_block_ret
- @@:
- 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
В приложении пример программы с исходным текстом, которая парсит и выводит метаданные из файла в формате OptimFROG.
Просмотров: 152 | Комментариев: 0
Метки: Assembler, мультимедиа
Комментарии
Отзывы посетителей сайта о статье
Комментариeв нет
Добавить комментарий
Заполните форму для добавления комментария