Однажды мне понадобилось решить простенькую (как мне тогда казалось) задачу – в PHP-скрипте узнать длительность mp3-файла. Я слышал о ID3 тегах и сразу подумал, что информация о длительности хранится либо в тегах, либо в заголовках mp3-файла. Поверхностные поиски в интернете показали что за пару-тройку минут решить эту задачу не получится. Поскольку от природы я довольно любопытен а время не поджимало — решил не использовать сторонние инструменты а разобраться в одном из самых популярных форматов самостоятельно.
Если Вам интересно, что там внутри – добро пожаловать под кат (трафик).
В данной статье мы не будем подробно останавливаться на извлечении ID3v2 тегов – это можно вынести в отдельную статью, так как там есть различные нюансы. А так же на фрагментах заголовков, которые практически не используются в настоящее время (например, часть Emphasis заголовка mp3-фрейма). Так же мы не рассматриваем структуру самих аудиоданных — тех самых, которые слышим из колонок.
ID3 (от англ. Identify a MP3) — формат метаданных, наиболее часто используемый в звуковых файлах в формате MP3. ID3 подпись содержит данные о названии трека, альбома, имени исполнителя и т. д., которые используются мультимедиапроигрывателями и другими программами, а также аппаратными проигрывателями, для отображения информации о файле и автоматического упорядочивания аудиоколлекции.
Wikipedia
Существует две абсолютно разных версии ID3-данных: ID3v1 и ID3v2.
ID3v1 – имеет фиксированный размер в 128 байт, которые дописываются в конец mp3-файла. Там можно хранить: название трека, исполнитель, альбом, год, комментарий, номер трека (для версии 1.1) и жанр.
Довольно быстро всем стало понятно, что 128 байт – очень уж небольшое место для хранения таких данных. И поэтому, со временем, появилась и успешно используется вторая версия данных – ID3v2.
В отличии от первой версии, теги v2 имеют переменную длину и размещаются в начале файла, что позволяет поддерживать потоковое воспроизведение.
Рассмотрим пример:
В данном случае вместе с заголовком ID3v2 (10 байт) – данные ID3v2 занимают 1024 байта.
После ID3v2-заголовка идут собственно теги. Подробный разбор чтения тегов ID3v2, как сказано выше, я решил не включать в эту статью.
Теперь у нас есть информация о наличии и длине тегов ID3 и мы можем приступать в разбору mp3-фрейма и понять-таки – где же хранится длительность. А заодно понять и всё остальное.
Весь mp3-файл состоит из фреймов, которые можно извлекать только последовательно. Фрейм содержит в себе заголовок и аудио-данные. Поскольку мы не ставим себе целью написать прошивку для магнитофона – нас интересует именно заголовок фрейма.
Размер заголовка – 4 байта.
Описание:
Существует 3 режима сжатия данных:
CBR (constant bitrate) – постоянный битрейт. Не меняется на всем протяжении трека.
VBR (variable bitrate) – переменный битрейт. При этом сжатии битрейт постоянно меняется на протяжении трека.
ABR (average bitrate) – усредненный битрейт. Это понятие используется только при кодировании файла. На «выходе» получается файл с VBR.
Если файл закодирован с постоянным битрейтом – то мы уже можем
получить длительность нашего трека по следующей формуле:
Длительность = Размер аудиоданных / Битрейт (в битах!) * 8
Например, файл имеет размер 350670 байт. Есть ID3v1 теги (128 байт) и ID3v2 теги (1024 байта). Битрейт = 96. Следовательно размер аудиоданных равен 350670 – 128 – 1024 = 349518 байт.
Длительность = 349518 / 96000 * 8 = 29,1265 = 29 секунд
Необходимо пояснить – как определить режим сжатия. Всё просто. Если файл сжат с VBR – то добавляется VBR-заголовок. По его наличию мы и можем понять, что используется переменный битрейт.
Есть два вида заголовков: Xing и VBRI.
Xing размещается со смещением от начала первого mp3-фрейма в позиции, согласно таблице:
Например: у нас ID3v2 тег занимает 1024 байта. Если наш mp3-файл имеет режим канала «Стерео» — то заголовок VBR Xing будет начинаться со смещения 1024 + 32 = 1056 байт.
Заголовок VBRI всегда размещается со смещением +32 байта от начала первого mp3-фрейма.
Первые четыре байта в обоих заголовках содержат маркер ‘Xing’ или ‘Info’ для Xing. И ‘VBRI’ для VBRI.
Эти VBR заголовки имеют переменную длину и содержат различную информацию о кодировании файла. Подробнее о структуре заголовков VBR (и не только) можно почитать, например, тут.
Я же расскажу только о том, что нас интересует в данный момент. А именно – количество фреймов (Number of Frames). Это число длиной 4 байта.
В заголовке Xing оно содержится по смещению +8 байт от начала заголовка. В VBRI +14 байт от начала заголовка.
Используя таблицу Сэмплов на фрейм (Sampler Per Frame) мы можем получить длительность mp3-файла, закодированного с переменным битрейтом.
Длительность = Количество фреймов * Сэмплов на фрейм / Частоту дискретизации
Например: из заголовка VBRI получили количество фреймов 1118, сэмплов на фрейм = 1152. Частота дискретизации = 44100.
Длительность = 1118 * 1152 / 44100 = 29.204 = 29 секунд.
На этом на сегодня всё. Если был кому-то полезен — спасибо.
Для тех, кто захочет немедленно поковырять внутренности mp3 — Тут лежат скрипт на php, которые я писал для себя одновременно с данной статьей и четыре небольших mp3-файла для теста.
id3.org — Читаем о ID3
id3.org — и кое-что о mp3 frame
Довольно подробно о mp3 frame
getID3: Неплохая библиотека для получения информации о mp3. (PHP)
В этой статье приводится спецификация заголовка MP3 формата. Перевод с английского.
Определенного заголовка у файла нет, вместо этого есть заголовок у каждого фрейма. Фрейм — часть аудио данных со своим заголовком. Т.е. в файле фреймов может присутствовать хоть тысяча, хоть миллион и у каждого из них будет свой заголовок. В файлах, закодированных уровнем I/II (MPEG Audio Layer I/II), фреймы абсолютно независимы и могут воспроизводиться отдельно друг от друга. После появления уровня III (MPEG Audio Layer III), фреймы стали зависимыми и теперь, чтобы воспроизвести один фрейм может потребоваться до 9 других фреймов (это произошло из-за использования «резервуара байтов» — некоего буфера).
Размер фрейма 32 бита (4 байта). Первые 12 бит (или первые 11 бит для MPEG 2.5 расширения) заголовка фрейма всегда установлены в 1 и называются «frame sync».
Далее — таблица, соотносящая биты с их значениями.
Длина в битах | Позиция в битах | Описание | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
11 | (31-21) | Frame sync (все биты должны быть равны 1) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2 | (20,19) | Идентификатор версии MPEG Audio
00 — MPEG Версии 2.![]() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2 | (18,17) | Идентификатор уровня 00 — зарезервировано 01 — Layer III 10 — Layer II 11 — Layer I | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 | (16) | 0 — Защита CRC (16 bit CRC follows header) 1 — Нет защиты | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4 | (15-12) | Индекс битрейта
Примечания:
Все значения
V1 — MPEG Версия 1
V2 — MPEG Версия 2 и Версия 2. «свободный» означает свободный формат. Свободный битрейт должен быть постоянным (CBR) и должен быть ниже максимально дозволенного. Со стороны декодера поддержка потока данных со свободным битрейтом не требуется. «неверный» означает, что значение за пределами дозволенного. В MPEG файлах также может быть и переменный битрейт (VBR). В таком случае, каждый фрейм может быть создан с различным битрейтом. Это может быть использовано во всех уровнях. Декодеры Layer III должны поддерживать этот метод. Декодеры Layer I и Layer II могут поддерживать это. Для Layer II могут быть некоторые недозволенные комбинации битрейта и режима. Вот список этих комбинаций:
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2 | (11,10) | Индекс частоты дискретизации
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 | (9) | Бит заполненности
0 — фрейм заполнен
1 — фрейм заполнен с одним лишним слотом Заполненность нужна чтобы точно уложиться во фрейм. Как пример: 128kbps 44.1kHz уровень II использует фреймы в большинстве своем из 418 байтов и некоторые из 417 байтов длиной, чтобы получить точный битрейт 128k. Для уровня I слот 32 бита длиной, для уровня II и уровня III слот длиной в 8 бит. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 | (8) | Персональный бит. Всего лишь для информации. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2 | (7,6) | Каналы
00 — Stereo (стерео)
01 — Joint stereo (совместное стерео)
10 — Dual channel (2 моно канала)
11 — Single channel (моно) Примечание: Dual channel режим является двумя абсолютно независимыми моно каналами. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2 | (5,4) | Расширение режима (Используется только вместе с Joint stereo) Расширение режима используется для соединения информации, которая не используется для стерео эффекта, таким образом уменьшается количество требуемых битов. Эти биты динамически определяются кодером в режиме Joint Stereo, и Joint Stereo может меняться в разных фреймах и даже включаться или выключаться. Полный диапазон частоты звучания в MPEG файле разделена на подмножества. Всего 32 таких подмножества. Для уровня I и II эти два бита определяют подмножества, где применено Intensity stereo. Для уровня III эти два бита определяют, что за тип Joint Stereo используется (Intensity stereo или m/s stereo).
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 | (3) | Авторское право 0 — Не защищено авторскими правами 1 — Защищено авторскими правами | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 | (2) | Оригинал 0 — Копия оригинальной композиции 1 — Оригинальная композиция | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2 | (1,0) | Выразительность
00 — отсутствует
01 — 50/15 ms
10 — зарезервировано
11 — CCIT J.![]() Выразительность здесь используется, чтобы сообщить декодеру, что файл должен быть переделан обратно, то есть, декодер должен провести обработку амплитудно-частотного соотношения в звуке после схемы шумоподавления, подобной Dolby. Это редко используется. |
спросил
Изменено 11 лет, 3 месяца назад
Просмотрено 49 тысяч раз
Я хочу читать файлы MP3 на C++ и предпочитаю писать для этого собственный код. В основном, чтобы узнать, как работает тип файла. Я хочу прочитать все биты шестнадцатеричных данных файла MP3 и воспроизвести их на моих динамиках. 🙂 Я понятия не имею, с чего начать, так как я еще не знаю, как данные на самом деле сохраняются в файле MP3.
Спасибо за помощь
1
Начните с изучения структуры mp3-файла. Затем, если вам все еще интересно, найдите хороший учебник о том, как декодировать аудиоданные в каждом кадре. Это довольно сложно, поэтому вам понадобится немало времени, чтобы сделать это с нуля.
2
Вы можете купить спецификацию для формата MP3 здесь. Это около 160 евро.
Да, и кстати, это не «шестнадцатеричные данные». Если вы все еще находитесь в точке, где вы называете любые данные, не предназначенные для чтения человеком, «шестнадцатеричной» (которая является системой счисления), погружение с головой в двоичный формат данных, который включает сложные алгоритмы декодирования/кодирования, может быть немного слишком много для вас на данный момент.
Как насчет того, чтобы начать с написания проигрывателя, который может воспроизводить файлы . wav? (Заметьте, любой подходящий файл .wav, принимая во внимание формат файла и различные аудиоформаты)
5
Я провел небольшое исследование, может оно вам поможет.
Структура файла
Файл MP3 состоит из нескольких кадров MP3, состоящих из заголовка и блока данных. Эта последовательность кадров называется элементарным потоком. Кадры не являются независимыми элементами («хранилищем байтов») и поэтому не могут быть извлечены на произвольных границах фреймов. Блоки данных MP3 содержат (сжатую) аудиоинформацию с точки зрения частот и амплитуд. На диаграмме показано, что заголовок MP3 состоит из слова синхронизации, которое используется для идентификации начала допустимого кадра. За ним следует бит, указывающий, что это стандарт MPEG, и два бита, указывающие на то, что используется уровень 3; следовательно, MPEG-1 Audio Layer 3 или MP3. После этого значения будут различаться в зависимости от файла MP3. ISO/IEC 11172-3 определяет диапазон значений для каждого раздела заголовка вместе со спецификацией заголовка. Большинство файлов MP3 сегодня содержат метаданные ID3, которые предшествуют кадрам MP3 или следуют за ними; как отмечено на схеме.
Исходный код LAME
LAME — это библиотека MP3, но она также имеет открытый исходный код, что означает, что вы можете загрузить исходный код и изучить его. http://sourceforge.net/projects/lame/files/lame/3.98.4/lame-3.98.4.tar.gz/download Я сам посмотрел на него, и он, кажется, написан на C или C++, так что вам повезло. Если вы изучите исходный код LAME и поймете, как он работает, возможно, вам удастся создать собственную библиотеку MP3. Просто обратите внимание, что LAME — это библиотека не для воспроизведения файлов MP3, а для их кодирования. Но поскольку он создает MP3, а не читает их, я думаю, что структура должна быть немного более ясной, чем с любой другой библиотекой MP3-плеера.
Объяснение формата файла MP3
Это также, кажется, объясняет, как работает MP3 довольно хорошо, но это чистая теория, так что вам понадобится много терпения. http://www.mp3-converter.com/mp3codec/
0
Ну, это было бы жестко 🙂
В любом случае, ваше приложение должно состоять из двух частей — декомпрессионная библиотека/подпрограммы и ваш основной бэкенд , который бы занял некоторый распакованный блок данных и собственно сыграй.
Я бы порекомендовал «Сжатие данных» книгу Дэвида Соломона чтобы понять, как ваш декодер должен делать это на самом деле . Варианты для ваших вторых частей, к сожалению, слишком широки, чтобы охватить их одним предложением.
Вы также можете попробовать исследовать некоторые mp3
декодеры / декодирующие библиотеки с открытым исходным кодом, подобные этой.
1
Если вы настаиваете на том, чтобы сделать это самостоятельно, вам придется начать со спецификации:
http://mpgedit. org/mpgedit/mpeg_format/MP3Format.html
задача, что-то вроде http://sourceforge.net/projects/mpg123net/
Также есть декодер MAD… http://www.underbit.com/products/mad/
Чтобы правильно прочитать mp3 файл есть много математики, и я думаю, что вы действительно не хотите вдаваться в это…
Задавать вопрос
спросил
Изменено 3 года, 1 месяц назад
Просмотрено 26 тысяч раз
Я пишу библиотеку C++ для декодирования и кодирования аудио между различными форматами/кодеками. У меня есть процедура для быстрого определения формата перед загрузкой необходимой библиотеки кодеков.
Для файлов WAV можно просто найти значения ASCII «RIFF» и «WAVE» в начале файла. То же самое относится и к FLAC, мы можем просто прочитать первые 4 байта, которые будут «fLaC».
Но как быстро определить, является ли файл MP3? Я не могу полагаться на расширение файла. Я также не могу попытаться декодировать первый кадр MP3, так как в начале файла могут быть дополнительные данные (например, ID3, обложка и т. д.).
Определить, является ли файл MP3, сложнее, чем найти фиксированный шаблон в файле.
Некоторые концепции
(подробности см. на http://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header)