Я создаю фрагмент кода для проверки mp3-файлов на моем сервере и получения результата, если некоторые из них имеют ложную синхронизацию или нет. Короче говоря, я загружаю эти файлы в PHP с помощью функции fread () и получаю поток в переменную. После разделения этого потока, чтобы получить отдельные потоки для id3v1 (не обязательно, это не предмет синхронизации), id3v2 (основная проблема) и аудио, я должен реализовать эту схему для потока id3v2.
Согласно официальной документации ID3v2 :
Единственная цель «схемы несинхронизации» - сделать тег ID3v2 как можно более совместимым с существующим программным обеспечением. В «несинхронизированных» тегах нет смысла, если файл должен обрабатываться только новым программным обеспечением. Несинхронизация может выполняться только с файлами MPEG 2 layer I, II и III и MPEG 2.5.
Всякий раз, когда в теге обнаруживается ложная синхронизация, один нулевой байт вставляется после первого байта ложной синхронизации. Формат правильной синхронизации, который должен быть изменен кодерами ID3, выглядит следующим образом:
% 11111111 111xxxxx
И следует заменить на:
% 11111111 00000000 111xxxxx
У этого побочного эффекта есть необходимость изменить все комбинации $ FF 00, чтобы на них не влиял процесс декодирования. Поэтому все комбинации $ FF 00 должны быть заменены комбинацией $ FF 00 00 во время несинхронизации.
Чтобы указать использование несинхронизации, должен быть установлен первый бит в «флагах ID3» (примечание: я нашел этот бит). Этот бит следует устанавливать только в том случае, если тег содержит, теперь исправленную, ложную синхронизацию. Этот бит должен быть очищен только в том случае, если тег не содержит ложных синхронизаций.
Имейте в виду, что, если кодер использует схему сжатия, схема несинхронизации должна применяться после . При декодировании сжатого «несинхронизированного» файла сначала необходимо проанализировать «схему несинхронизации», а затем декомпрессию.
Мои вопросы:
- Как найти и заменить этот битовый шаблон
%11111111 111xxxxx
на %11111111 00000000 111xxxxx
?
- И наоборот, как найти и заменить этот битовый шаблон
%11111111 00000000 111xxxxx
на %11111111 111xxxxx
?
... с использованием preg_replace () .
Код, который я создал до сих пор, прекрасно работает, и у меня есть только одна строка (ну, в точности две).
<?php
// some basic checkings here, such as 'does file exist'
// and 'is it readable'
$f = fopen('test.mp3', 'r');
// ...rest of my code...
$pattern1 = '?????'; // pattern from 1st question
$id3stream = preg_replace($pattern1, 'something1', $id3stream);
// ...extracting frames...
$pattern1 = '?????'; // pattern from 2nd question
$id3stream = preg_replace($pattern2, 'something2', $id3stream);
// ..do more job...
fclose($f);
?>
Как заставить эти две строки с функцией preg_replace () работать?
P.S. Я знаю, как это делать, читая байты за байтами в каком-то цикле, но я уверен, что это возможно с помощью регулярных выражений (кстати, если честно, я впитываю регулярные выражения).
Дайте мне знать, если вам нужно больше деталей.
Еще одна вещь ...
В данный момент я использую этот шаблон
$pattern0 = '/[\x00].*/';
echo preg_replace($pattern0, '', $input_string);
отрезать часть строки, начиная с первого нулевого байта и до конца. Это правильный способ сделать это?
Обновление
( @ mario's answer ).
В первой паре тестов ... этот код вернул правильный результат.
// print original stream
printStreamHex($stream_original, 'ORIGINAL STREAM');
// adding zero pads on unsync scheme
$stream_1 = preg_replace(':([\\xFF])([\\xE0-\\xFF]):', "$1\x00$2", $stream_original);
printStreamHex($stream_1, 'AFTER ADDING ZEROS');
// reversing process
$stream_2 = preg_replace(':([\\xFF])([\\x00])([\\xE0-\\xFF]):', "$1$3", $stream_1);
printStreamHex($stream_2, 'AFTER REMOVING ZEROS');
echo "Status: <b>" . ($stream_original == $stream_2 ? "OK" : "Failed") . "</b>";
Но через несколько минут я обнаружил конкретный случай, когда все выглядит как ожидаемый результат, но в потоке все еще есть пары FFE0 +.
ORIGINAL STREAM
+-----------------------------------------------------------------+
| FF E0 DB 49 53 BE 3B E0 90 40 EA 2B 3A 61 FF FA |
| 84 E0 A9 99 1F 39 B5 E1 54 FF E7 ED B8 B1 3A 36 |
| 88 01 69 CA 7D 47 FA E1 70 7C 85 34 B8 1A FF FF |
| FF F8 21 F9 2F FF F7 17 67 EB 2A EB 6E 41 82 FF |
+-----------------------------------------------------------------+
AFTER ADDING ZEROS
+-----------------------------------------------------------------+
| FF 00 E0 DB 49 53 BE 3B E0 90 40 EA 2B 3A 61 FF |
| 00 FA 84 E0 A9 99 1F 39 B5 E1 54 FF 00 E7 ED B8 |
| B1 3A 36 88 01 69 CA 7D 47 FA E1 70 7C 85 34 B8 |
| 1A FF 00 FF FF 00 F8 21 F9 2F FF 00 F7 17 67 EB |
| 2A EB 6E 41 82 FF |
+-----------------------------------------------------------------+
AFTER REMOVING ZEROS
+-----------------------------------------------------------------+
| FF E0 DB 49 53 BE 3B E0 90 40 EA 2B 3A 61 FF FA |
| 84 E0 A9 99 1F 39 B5 E1 54 FF E7 ED B8 B1 3A 36 |
| 88 01 69 CA 7D 47 FA E1 70 7C 85 34 B8 1A FF FF |
| FF F8 21 F9 2F FF F7 17 67 EB 2A EB 6E 41 82 FF |
+-----------------------------------------------------------------+
Status: OK
Если поток содержит что-то вроде FF FF FF FF
, он будет заменен на FF 00 FF FF 00 FF
, но это должно быть FF 00 FF 00 FF 00 FF
. Эта пара FF FF
снова выполнит ложную синхронизацию mp3, поэтому моя миссия состоит в том, чтобы избегать каждого паттерна FFE0+
перед аудиопотоком (в тэге ID3v2; потому что mp3 начинается с байтовой пары FFE0+
, и это должно быть первым появлением в начале аудио данных). Я понял, что могу циклически повторять те же регулярные выражения, пока не получу поток без байтовой пары FFE0 +. Есть ли решение, которое не требует цикла?
Отличная работа @mario, большое спасибо!