Однажды мне понадобилось решить простенькую (как мне тогда казалось) задачу – в 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. 5 (более позднее расширение MPEG-2) 01 — зарезервировано 10 — MPEG Версии 2 (ISO/IEC 13818-3) 11 — MPEG Версии 1 (ISO/IEC 11172-3) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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. 5 L1 — Layer I L2 — Layer II L3 — Layer III «свободный» означает свободный формат. Свободный битрейт должен быть постоянным (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. 17 Выразительность здесь используется, чтобы сообщить декодеру, что файл должен быть переделан обратно, то есть, декодер должен провести обработку амплитудно-частотного соотношения в звуке после схемы шумоподавления, подобной 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)