Blog. Just Blog

Парсинг метаданных файлов MPEG-4 на Ассемблере

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Парсинг метаданных файлов MPEG-4 на Ассемблере
Парсинг метаданных файлов MPEG-4 на Ассемблере

Формат MPEG-4 появился еще в 1998 году и включает в себя группу стандартов сжатия цифрового аудио и видео. Это могут быть аудиофайлы M4A и ALAC, видеоролики MP4 и M4V, видео с YouTube M4S, рингтоны для гейфонов M4R, защищенные аудиозаписи iTunes M4P, аудиокниги M4B и, возможно, другие. За счет контейнерной структуры этот формат позволяет хранить внутри файлов не только аудио- и видео-потоки, но и шрифты, 3D-объекты, субтитры, статичные изображения и т.п. Сегодня разберем, как можно извлечь из этих файлов метаданные.

Как я уже упомянул, файл в формате MPEG-4 является набором контейнеров, каждый из которых также является контейнером для других контейнеров, и так далее. Теоретически, вложенность может быть неограниченной. Короче, классический пакет с пакетами. Формат контейнера очень простой. Первые 8 байт - заголовок контейнера. Это DWORD с длиной контейнера, включая содержимое и заголовок, и 4 байта названия контейнера. После этого следует содержимое контейнера.

Для проверки соответствия формата файла надо проверить заголовок самого первого контейнера, его название должно быть строкой "ftyp". Метаданные находятся в контейнере с наименованием "moov".
  1.         ; Открыть медиафайл
  2.         invoke  CreateFile,sample,GENERIC_READ,FILE_SHARE_READ,\
  3.                 0,OPEN_EXISTING,0,0
  4.         mov     [desc],eax
  5.  
  6.         ; Прочитать заголовок первого контейнера
  7.         invoke  _lread,[desc],buff,8
  8.         ; Проверить формат файла на соответствие MPEG-4
  9.         cmp     dword [buff+4],'ftyp'
  10.         jne     loc_close
  11.  
  12.         invoke  _llseek,[desc],0,FILE_BEGIN
  13. loc_read:
  14.         ; Прочитать заголовок контейнера
  15.         invoke  _lread,[desc],buff,8
  16.         ; Контейнер на найден
  17.         cmp     eax,-1
  18.         je      loc_close
  19.  
  20.         mov     ebx,dword[buff]
  21.         bswap   ebx
  22.         sub     ebx,8
  23.  
  24.         cmp     dword [buff+4],'moov'
  25.         je      @f
  26.  
  27.         ; Перейти к следующему контейнеру
  28.         invoke  _llseek,[desc],ebx,FILE_CURRENT
  29.         cmp     eax,-1
  30.         ; Контейнер на найден
  31.         je      loc_close
  32.         jmp     loc_read
  33. @@:
  34.         ; Выделить память под метаданные
  35.         mov     [dMem],ebx
  36.         invoke  GlobalAlloc,GMEM_ZEROINIT,[dMem]
  37.         mov     [hMem],eax
  38.         invoke  GlobalLock,[hMem]
  39.         mov     [pMem],eax
  40.  
  41.         ; Прочитать метаданные
  42.         invoke  _lread,[desc],[pMem],[dMem]
После загрузки контейнера в память, надо последовательно найти внутри него контейнер с именем "udta", внутри него контейнер с именем "meta", а уже внутри него контейнер с названием "ilst". Код будет похожим.
  1.         mov     esi,[pMem]
  2. loc_tag_udta:
  3.         lodsd
  4.         bswap   eax
  5.         mov     ecx,eax
  6.         lodsd
  7.         cmp     eax,'udta'
  8.         je      @f
  9.         ; Проверить выход за границу контейнера
  10.         mov     edx,esi
  11.         add     edx,ecx
  12.         sub     edx,[pMem]
  13.         cmp     edx,[dMem]
  14.         jae     loc_free
  15.  
  16.         add     esi,ecx
  17.         sub     esi,8
  18.  
  19.         jmp     loc_tag_udta
  20. @@:
  21.  
  22. loc_tag_meta:
  23.         lodsd
  24.         bswap   eax
  25.         mov     ecx,eax
  26.         lodsd
  27.         cmp     eax,'meta'
  28.         je      @f
  29.         ; Проверить выход за границу контейнера
  30.         mov     edx,esi
  31.         add     edx,ecx
  32.         sub     edx,[pMem]
  33.         cmp     edx,[dMem]
  34.         jae     loc_free
  35.  
  36.         add     esi,ecx
  37.         sub     esi,8
  38.  
  39.         jmp     loc_tag_meta
  40. @@:
  41.         ; Пропустить 4 байта
  42.         lodsd
  43.  
  44. loc_tag_ilst:
  45.         lodsd
  46.         bswap   eax
  47.         mov     ecx,eax
  48.         lodsd
  49.         cmp     eax,'ilst'
  50.         je      @f
  51.         ; Проверить выход за границу контейнера
  52.         mov     edx,esi
  53.         add     edx,ecx
  54.         sub     edx,[pMem]
  55.         cmp     edx,[dMem]
  56.         jae     loc_free
  57.  
  58.         add     esi,ecx
  59.         sub     esi,8
  60.  
  61.         jmp     loc_tag_ilst
  62. @@:
Метаданные в контейнере записаны в фиде пары контейнеров, имя первого определяет название метаданных, а следующий за ним контейнер с именем "data" содержит непосредственно значение этого метатега. Вот таким образом извлекается, к примеру, имя исполнителя, название композиции и альбом.
  1. loc_tag_scan:
  2.         lodsd
  3.         bswap   eax
  4.         mov     ecx,eax
  5.         lodsd
  6.         mov     ebx,title
  7.         cmp     eax, 0x6D616EA9 ; 'nam'
  8.         je      loc_get_tag
  9.  
  10.         mov     ebx,artist
  11.         cmp     eax, 0x545241A9 ; 'ART'
  12.         je      loc_get_tag
  13.  
  14.         mov     ebx,album
  15.         cmp     eax, 0x626c61A9 ; 'alb'
  16.         je      loc_get_tag
  17.  
  18.         jmp     @f
  19.  
  20. loc_get_tag:
  21.         lodsd
  22.         bswap   eax
  23.         mov     ecx,eax
  24.         lodsd
  25.         cmp     eax,'data'
  26.         jne     @f
  27.  
  28.         sub     ecx,16
  29.         push    ecx
  30.  
  31.         lodsd
  32.         lodsd
  33.         ; UTF-8 -> юникод
  34.         invoke  MultiByteToWideChar,CP_UTF8,0,esi,ecx,0,0
  35.         invoke  MultiByteToWideChar,CP_UTF8,0,esi,-1,ebx,eax
  36.         pop     ecx
  37.         add     esi,ecx
  38.  
  39.         ; Проверить выход за границу контейнера
  40.         mov     edx,esi
  41.         add     edx,ecx
  42.         sub     edx,[pMem]
  43.         cmp     edx,[dMem]
  44.         jae     loc_done
  45.  
  46.         jmp     loc_tag_scan
  47. @@:
  48.         ; Проверить выход за границу контейнера
  49.         mov     edx,esi
  50.         add     edx,ecx
  51.         sub     edx,[pMem]
  52.         cmp     edx,[dMem]
  53.         jae     loc_done
  54.  
  55.         ; Следующий тег в контейнере
  56.         add     esi,ecx
  57.         sub     esi,8
  58.  
  59.         jmp     loc_tag_scan
  60. @@:
В приложении пример программы с исходным текстом, которая парсит и выводит метаданные из файла в формате MPEG-4.

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

MPEG4.Metadata.Demo.zip (617,243 bytes)


Поделиться ссылкой ВКонтакте
Просмотров: 238 | Комментариев: 0

Комментарии

Отзывы посетителей сайта о статье
Комментариeв нет

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.07 сек. / MySQL: 2 (0.0034 сек.) / Память: 4.5 Mb
Наверх