Парсинг метаданных OGG-файлов на Ассемблере
Парсинг метаданных OGG-файлов на Ассемблере
OGG - открытый формат кодирования аудио, направленный в первую очередь для хранения высококачественной музыки с высоким битрейтом. Как ни странно, на данный момент не существует официального единого стандарта записи метаданных в контейнер OGG. Так что пришлось совмещать теоретические сведения из имеющейся документации с практическими данными из дикой природы.
Сперва немного теории. OGG-файл состоит из так называемых страниц, каждая из которых состоит из заголовка и данных, в зависимости от типа секции. Для удобства дальнейшей работы я оформил заголовок в виде структуры:
Code (Assembler) : Убрать нумерацию
- struct OGG_PAGE_HEADER
- dMagic dd ? ; Capture pattern 'OggS'
- bVersion db ? ; Version
- bType db ? ; Header type
- qGranule dq ? ; Granule position
- dSerial dd ? ; Bitstream serial number
- dPage dd ? ; Page sequence number
- dCRC dd ? ; Checksum
- bSegments db ? ; Page segments
- ends
При парсинге поочередно читаем из файла заголовки каждой страницы, если поле dPage имеет нужное значение, то определяем размер данных, резервируем под них память и считываем. Иначе просто перемещаем указатель в файле на окончание текущей страницы.
Code (Assembler) : Убрать нумерацию
- invoke CreateFile,sample,GENERIC_READ,FILE_SHARE_READ,\
- 0,OPEN_EXISTING,0,0
- mov [desc],eax
- loc_read:
- ; Прочитать заголовок страницы
- invoke _lread,[desc],buff,sizeof.OGG_PAGE_HEADER
- ; Проверить корректность страницы
- mov esi,buff
- cmp [esi+OGG_PAGE_HEADER.dMagic],'OggS'
- jne loc_close
- ; Количество сегментов в странице
- movzx ebx,[esi+OGG_PAGE_HEADER.bSegments]
- ; Прочитать таблицу размеров сегментов
- invoke _lread,[desc],tTable,ebx
- ; Подсчитать длину всех сегментов
- mov ecx,ebx
- mov esi,tTable
- xor ebx,ebx
- @@:
- lodsb
- movzx eax,al
- add ebx,eax
- loop @b
- ; Метаданные записаны в страницу 1
- mov esi,buff
- cmp [esi+OGG_PAGE_HEADER.dPage],1
- jne loc_skip
- ; Выделить память под метаданные
- invoke GlobalAlloc,GMEM_ZEROINIT,ebx
- mov [hMem],eax
- invoke GlobalLock,[hMem]
- mov [pMem],eax
- ; Прочитать метаданные
- invoke _lread,[desc],[pMem],ebx
- ; Сигнатура блока метаданных
- mov esi,[pMem]
- cmp byte [esi],3
- jne loc_free
- cmp dword [esi+1],'vorb'
- jne loc_free
- cmp word [esi+5],'is'
- jne loc_free
- ; Пропустить сигнатуру
- add esi,7
- ; Длина строки названия кодировщика
- add esi,dword[esi]
- add esi,4
- ; Количество тегов
- mov ebx,dword[esi]
- add esi,4
- ; Метаданных нет
- or ebx,ebx
- jz loc_free
- loc_get_tags:
- push ebx
- ; Размер тега
- mov ecx,dword[esi]
- add esi,4
- ; Первые 4 символа названия тега
- mov eax,[esi]
- ; Перевести в нижний регистр
- or eax,20202020h
- mov ebx,title
- cmp eax,'titl'
- je @f
- mov ebx,artist
- cmp eax,'arti'
- je @f
- mov ebx,album
- cmp eax,'albu'
- je @f
- ; Пропустить тег
- add esi,ecx
- jmp loc_next_tag
- @@:
- ; Найти символ-разделитель
- mov al,'='
- mov edi,esi
- repne scasb
- ; Передвинуть указатель на значение тега
- mov esi,edi
- ; Разделитель не нашелся, битые данные
- or ecx,ecx
- jz loc_next_tag
- ; UTF-8 -> юникод
- push ecx
- invoke MultiByteToWideChar,CP_UTF8,0,edi,ecx,0,0
- invoke MultiByteToWideChar,CP_UTF8,0,edi,-1,ebx,eax
- pop ecx
- ; Перейти к следующему тегу
- add esi,ecx
- loc_next_tag:
- pop ebx
- ; Все теги обработали?
- sub ebx,1
- jnz loc_get_tags
- ...
- ; artist -> наименование исполнителя
- ; album -> название альбома
- ; title -> название трека
- ...
- loc_free:
- ; Освободить память
- invoke GlobalUnlock,[hMem]
- jmp loc_close
- loc_skip:
- ; Перейти к следующей странице
- invoke _llseek,[desc],ebx,FILE_CURRENT
- cmp eax,-1
- je loc_close
- jmp loc_read
- loc_close:
- invoke CloseHandle,[desc]
В приложении пример программы с исходным текстом, которая парсит метаданные из OGG-файла и выводит их.
Просмотров: 659 | Комментариев: 0
Метки: Assembler, мультимедиа
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
Комментариeв нет
Добавить комментарий
Заполните форму для добавления комментария