Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
MySQL на примерах. Авторы: Кузнецов М.В., Симдянов И.В. C++. Мастер-класс в задачах и примерах. Авторы: Кузнецов М.В., Симдянов И.В. PHP. Практика создания Web-сайтов (второе издание). Авторы: Кузнецов М.В., Симдянов И.В. Социальная инженерия и социальные хакеры. Авторы: Кузнецов М.В., Симдянов И.В. PHP на примерах (2 издание). Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум PHP

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: помогите разпарсить riff wave файл
 
 автор: FoReAcH   (19.12.2007 в 16:58)   письмо автору
 
 

Знающие люди кто с этим работал,помогите разобратся с реализацией чтения инфы о wav файле.Мне нужно извлечь из wav файла данные о частоте дискретизации и битрейте.
Нашол в инете вот такую инфу о wave(riff) файле:
Для примера разберем начало простенького PCM WAVE файла по байтам. Все смещения (слева) и размеры полей (справа в квадратных скобках ) приведены в hex виде.

---------------------- Начало RIFF-чанка
00 'RIFF' [4]
04 DWORD - размер RIFF-чанка [4]
---------------------- Начало WAVE-формы
08 'WAVE' [4]
---------------------- Начало fmt-чанка
0C 'fmt ' [4]
10 DWORD - размер fmt-чанка (10h или 12h) [4]
---------------------- Структура WaveFormat (или WaveFormatEx)
14 WORD wFormatTag = 1 (это же PCM) [2]
16 WORD nChannels = 1 [2]
18 DWORD nSamplesPerSec = 11025 [4]
1C DWORD nAvgBytesPerSec = 11025 [4]
20 WORD nBlockAlign = 1 [2]
22 WORD nBitsPerSample = 8 [2]
24 WORD cbSize (=0 или отсутствует для PCM. [2]
Далее в круглых скобках приведены
смещения для случая без cbSize)
---------------------- Конец fmt-чанка
---------------------- Начало data-чанка
26 (24) 'data' [4]
2A (28) DWORD размер data-чанка [4]
2E (2C) Sample0,Sample1,Sample2,... [???]
---------------------- Конец WAVE-формы
---------------------- Конец RIFF-чанка
Обьясните что это за цифры слева(00,04,08,...0C и.т.д) я смотрел в winhex'е но так ничего и не понял.Подскажите как можно это все в php реализовать.Юзал функцию pack() извлекает только заголовок WAVE.
Юзал вот так: pack("nvc*",0x6461,0x6174),так же и извлекает только название fmt и все.
Если можно приведите простеникий пример на php как это можно реализовать.

   
 
 автор: sim5   (19.12.2007 в 17:02)   письмо автору
 
   для: FoReAcH   (19.12.2007 в 16:58)
 

Я же давал вам ссылку, там практически уже готовое, чуть подправить под РНР, и все описано.

   
 
 автор: FoReAcH   (19.12.2007 в 17:27)   письмо автору
 
   для: sim5   (19.12.2007 в 17:02)
 

Если бы я еще знал си...Вообщем там не совсем полная документация.Я не разобрался :(

   
 
 автор: mihdan   (19.12.2007 в 17:25)   письмо автору
 
   для: FoReAcH   (19.12.2007 в 16:58)
 

>pack("nvc*",0x6461,0x6174)
так это и есть на РНР

http://php.mirror.camelnetwork.com/manual/ru/ref.openal.php

   
 
 автор: FoReAcH   (19.12.2007 в 17:34)   письмо автору
 
   для: mihdan   (19.12.2007 в 17:25)
 

Я знаю что это на php(это я пытался расковырять файл).
Спасибо конечно за мануал,но не могли бы вы привести простенький пример реализации этого на php.

   
 
 автор: mihdan   (19.12.2007 в 17:37)   письмо автору
 
   для: FoReAcH   (19.12.2007 в 17:34)
 

В чем именно трудность? В алгоритме или просто в незнании фунций? Вы сами что-нить пробовали? Если да, то кидайте код - вместе попробуем

   
 
 автор: FoReAcH   (19.12.2007 в 17:43)   письмо автору
 
   для: mihdan   (19.12.2007 в 17:37)
 

Конечно вся сложность в алгоритме,не понимаю как это все в php реализовать.

   
 
 автор: mihdan   (19.12.2007 в 17:53)   письмо автору
 
   для: FoReAcH   (19.12.2007 в 17:43)
 

Смотри, есть сишный алгоритм


#include 
#include 

typedef struct {
    char id_riff[4];
        long len_riff;

    char id_chuck[4];
    char fmt[4];
    long len_chuck;

    int  type;
    int  channels;
    long freq;
    long bytes;
    int  align;
    int  bits;

    char id_data[4];
    long len_data;
} TitleWave;


void    main
    ( int argc, char * argv[] )
{
FILE * f;
TitleWave tw;

if ( argc<2 ) { printf("Укажи имя .wav файла\n"); return ; }
f=fopen(argv[1],"rb");
if ( f==0 ) { printf("Не открыть файл - %s\n",argv[1]); return; }
fread(&tw,sizeof(TitleWave),1,f);
fclose(f);
printf("LEN RIFF\t - %ld\n", tw.len_riff );
if ( strncmp(tw.id_riff,"RIFF",4)!=0 )
    printf("Не совпал идентификатор RIFF\n");
printf("LEN Chuck\t - %ld\n", tw.len_chuck );
if ( strncmp(tw.id_chuck,"WAVE",4)!=0 )
    printf("Не совпал идентификатор CHUCK\n");
if ( strncmp(tw.fmt,"fmt ",4)!=0 )
    printf("Не совпал идентификатор FMT\n");
printf("Type\t\t - %d\n", tw.type );
printf("Channels\t - %d\n", tw.channels );
printf("Sample Per Sec\t - %d\n", tw.freq );
printf("Bytes Per Sec\t - %d\n", tw.bytes );
printf("Bits\t\t - %d\n", tw.bits );
printf("Aligned\t\t - %d\n", tw.align );
printf("LEN Data\t - %ld\n", tw.len_data );
if ( strncmp(tw.id_data,"data",4)!=0 )
    printf("Не совпал идентификатор DATA\n");
}


РНР - написан на Си. Все фунции идентичны! Скажи что тут непонятно, попробую пояснить

   
 
 автор: FoReAcH   (19.12.2007 в 18:10)   письмо автору
 
   для: mihdan   (19.12.2007 в 17:53)
 

tw.len_riff,tw.fmt...-вот это что такое?char id_data[4]; -это массив или что?
И где тут обращение по адресам?

   
 
 автор: sim5   (19.12.2007 в 22:54)   письмо автору
 
   для: FoReAcH   (19.12.2007 в 18:10)
 

Ну зачем вам это - объявление типов и прочее... char id_data[4] - это 4 байта или двойное слово. Вас ведь интересует всего-то некоторые смещения заголовка:

16 WORD nChannels - число каналов (2 байта, смещение в дес. 22), если 2 - стерео.

18 DWORD nSamplesPerSec - т.е. по смещению (24 в десятичном) находится 4 байта которые указывают частоту дескридитации потока, для WAV это всего первых два байта, при этом сперва идет младший байт, а затем старший, например для качества CD 44100 КГц, будет равна 44АС в заголовке, что равно AC44, что равно 44100 в десятичном исчислении.

22 WORD nBitsPerSample - размер выборки (тоже самое, что уровней квантования, смещение 34 дес.), два байта.

Битрейт будет равен nSamplesPerSec * nBitsPerSample * nChannels.

   
 
 автор: Trianon   (20.12.2007 в 00:56)   письмо автору
 
   для: sim5   (19.12.2007 в 22:54)
 

RIFF - тэговый формат. Говорить о каких-то фиксированных смещениях применительно к нему, все равно, что говорить о фиксированных смещениях в файле с объектным кодом... или в HTML-файле.

   
 
 автор: sim5   (20.12.2007 в 09:15)   письмо автору
 
   для: Trianon   (20.12.2007 в 00:56)
 

Trianon, ну а какие проблемы? По смещению 8 находится тип файла, узнаем, что это WAVE [4], далее следует fmt [3], ну а далее согласно описанию заголовка вычислить нужное смещение ведь не трудно? Кстати для WAV от PCM до ADPCM смещиния от указанного не наблюдал.

PS. Зато семплинг задал шик просто - 44100 КГц :))

   
 
 автор: FoReAcH   (20.12.2007 в 14:20)   письмо автору
 
   для: sim5   (20.12.2007 в 09:15)
 

Вот попробовал узнать число каналов,вроде получилось.Скажите правильно или нет я это реализовал.

$file=fopen("test2.wav","r");
fseek($file, 22);
$bindata = fread($file,2);
fclose($file);
$bindata = unpack('Cint/Cint2', $bindata);
echo $bindata[int];

   
 
 автор: sim5   (20.12.2007 в 14:32)   письмо автору
 
   для: FoReAcH   (20.12.2007 в 14:20)
 

echo $bindata['int'];

PS. Кстати, для получения семпла (по семщению 24), нужно брать:

fseek($file, 24); 
$bindata = fread($file,4); 
fclose($file); 
$bindata = unpack('Iint', $bindata); 
echo $bindata['int'];

да вообще-то для всего надо не char указывать в формате, а I - беззнаковый integer (машиннозависимый размер и байтовый порядок)

   
 
 автор: FoReAcH   (20.12.2007 в 15:01)   письмо автору
 
   для: sim5   (20.12.2007 в 14:32)
 

так оно и так работает

   
 
 автор: sim5   (20.12.2007 в 15:02)   письмо автору
 
   для: FoReAcH   (20.12.2007 в 15:01)
 

Без кавычек? У меня РНР5 не позволяет такое.

PS. Просто у вас видимо выключен вывод предупреждений, при включенном вместе с данными, вы получите и, что "так не красиво делать".

PPS. Для dword надо указывать формат L, а для word формат S, а то "апшипся" чуточку. :)

   
 
 автор: FoReAcH   (20.12.2007 в 18:48)   письмо автору
 
   для: sim5   (20.12.2007 в 15:02)
 

Спасибо,все получилось!Подскажите еще как мне продолжительность файла узнать?

   
 
 автор: sim5   (20.12.2007 в 20:12)   письмо автору
 
   для: FoReAcH   (20.12.2007 в 18:48)
 

Получить размер файла по смещению 4 (4 байта):
$size = unpack('Lint', $size);
Получить частоту выдачи байтов по смещению 28 (4 байта):
$samp = unpack('Lint', $samp);
$time = $size/$samp //время звучания в сек.

   
 
 автор: Trianon   (20.12.2007 в 21:44)   письмо автору
 
   для: sim5   (20.12.2007 в 09:15)
 

>далее следует fmt [3]

это может быть совсем не fmt.

Riff состоит из элементов, которые могут являться контейнерами.

Разбирать этот формат следует по отдельным записям переменной длины.

   
 
 автор: sim5   (20.12.2007 в 21:49)   письмо автору
 
   для: Trianon   (20.12.2007 в 21:44)
 

Trianon, только спокойствие. :) Видимо в Питере начался сезон Белых ночей?
Для WAVE это всегда будет fmt, а вот выборок действительно может быть несколько, но у них свой идентификатор data, за ним размер выборки, затем данные.

   
 
 автор: Trianon   (20.12.2007 в 21:55)   письмо автору
 
   для: sim5   (20.12.2007 в 21:49)
 

просто Вы никогда не напарывались на Wave с блоком коммента в начале. :)

Насчет сезона - Вам виднее.

   
 
 автор: sim5   (20.12.2007 в 22:01)   письмо автору
 
   для: Trianon   (20.12.2007 в 21:55)
 

Можете привести пример такого файла? Я просто не разу ни в одном из руководств не читал о комментарии в заголовке. Не разу не приходилось парсить заголовок в РНР, а вот в Delphi да, и слышу такое впервые от вас.

Да мне то откуда знать о такой прелести как "Белые ночи", я могу только мечтать увидеть такое, и когда они наступают... Просто смотрю, Trianon только подключился, а уже такой сердитый, подумал - это влияние этих ночей. :))

   
 
 автор: Trianon   (20.12.2007 в 22:14)   письмо автору
 
   для: sim5   (20.12.2007 в 22:01)
 

Не могу... Давно дело было...

А касательно "сердитый" - поклеп. Сердиться на Вас мне в голову не придет всяко.

   
 
 автор: sim5   (20.12.2007 в 22:20)   письмо автору
 
   для: Trianon   (20.12.2007 в 22:14)
 

Ну хорошо, на Sound Forge сам наготовлю, проверю. Ну даже если и добавляется, то просто есть идентификтор fmt (я думаю, что это сокращение от format), а после него все должно следовать строго заголовку, так что просто нужно будет получить смещение после fmt как базовое, а от него плясать. Кстати оно всегда и узнается, так что вы скорее правы, а я просто не встречал такого.

Ну значит показалось, что сердитый. :)

   
 
 автор: sim5   (21.12.2007 в 08:55)   письмо автору
 
   для: Trianon   (20.12.2007 в 21:55)
 

Trianon: Сделал я комментарий для файла - в WAV он помещается в самый конец файла. Идентификатором начала блока служит LIST, далее копирайт, название, артист... Пробовал добавить к описанию изображение - комментарий в файл не записался в итоге, хотя это может быть связано с тем, что я неподходящий размер файла указал или палитру. Заголовок изменяется (его размер), если WAV формат записать с применением компрессора. В этом случае в заголовке помещается идентификатор fact перед идентификатором data. Смещение идентификатора fmt постоянное - 12.

Foreach: По смещению 4 находится размер файла без заголовка, и при добавлении комментария этот размер изменяется естественно, поэтому, для определения времени звучания он не годится (если только не вычитать из него размер блока комментария и изображения). Следует брать тогда размер блока данных, который помещен сразу после идентификатора data, но если таких блоков несколько, то нужно будет естественно получить сумму размеров этих блоков.
Интересно посмотреть заголовки WAV в HEX-редакторе при применении компрессоров, например, если WAV упакован в mp3, то по смещению 34 нет размера выборки. Если в Проводнике по правому щелчку получить информацию о файле, то в сводке можно узнать тип компрессора, но вот как он записывается в файле не знаю, HEX-редактор таких меток не находит.

Итого: Для исключения "пролетов", нужно поискать более подробную информацию о заголовках.

   
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования