Текущий архив: 2006.07.16;
Скачать: CL | DM;
ВнизРазделение аудио потоков в AVI Найти похожие ветки
← →
Noby (2006-01-30 14:07) [0]Подскажите, пожалуйста. Каким образом можно в своей программе не используя компонентов разделить аудио потоки в avi файлах и воспроизводить только тот, который нужен?
Нужен код. Заранее спасибо!
← →
NailMan © (2006-01-30 16:41) [1]Уточни исходные данные.
1. Воспроизводишь чем? DirectShow?
2. Как я понял у видео несколько дорожек. Тебе надо воспроизводить одну из них вместе с видео? или только аудио?
---
P.L.U.R. and WBR, NailMan aka 2:5020/3337.13
← →
Noby (2006-01-30 16:58) [2]1. Да через DirectShow.
2. И Видео и аудои
← →
NailMan © (2006-01-30 21:11) [3]Ну тады все просто:
Procedure TVideoEngine.SetMultipleVolume(vLevel:integer);
var
pEnum : IEnumFilters;
pFilter :IBaseFilter;
cFetched : dword;
CL:TGUID;
i:integer;
BA : IBasicAudio;
z : integer;
begin
i:=0;
repeat
// Get filter enumerator
dsGraphBuilder.EnumFilters(pEnum);
while pEnum.Next(1, pFilter, @cFetched) = S_OK do
begin
pFilter.GetClassID(CL);
if IsEqualGUID(CL,CLSID_DSoundRender) then
begin
If i<>CurrentPlayedAUDS then
z:=AUDSVolume[i]
else
z:=vLevel;
pFilter.QueryInterface(IID_IBasicAudio,BA);
BA.put_Volume(VolumeTable[z]);
AUDSVolume[i]:=z;
BA:=nil;
inc(i);
end;
pFilter:=nil;
end;
pFilter:=nil;
pEnum:=nil;
until dword(i)=avi.audstreams;
end;
В данном случае здесь несколько расширенная функция установки громкости звуковых дорожек.
vLevel - уровень матер-дорожки(которая выбрана пользователем, ее номер CurrentPlayedAUDS).
AUDSVolume - это массив уровней громкости(0..16) всех дорожек в файле.
VolumeTable - массив-константа в которой хранятся реальные значения уровней громкости которые принимает DShow. Содержимое константы:VolumeTable : Array[0..16] of Integer = (-10000,-9000,-7500,-6500,-5500,-4500,-4000,-3000,-2000,-1000,-750,-500,-250,-125,-100,-50,0);
расширение функционала тут как раз в исаользовании таблицы(массива) уровней для других дорожек. Типа чтобы можно было помимо самой громкой мастер-дорожки играть тихо(как пользователь выставил) другие. Если остальные надо заглушить, то нужно вместоIf i<>CurrentPlayedAUDS then
z:=AUDSVolume[i]
else
z:=vLevel;
сделатьIf i<>CurrentPlayedAUDS then
z:=-10000
else
z:=vLevel;
Ну и соотвественно лишнее поудалять из тела процедуры.
---
P.L.U.R. and WBR, NailMan aka 2:5020/3337.13
← →
Noby (2006-01-31 14:13) [4]Только, я вот одного не понял что вот это такое
dword(i)=avi.audstreams;
? с чем его есть то...
← →
NailMan © (2006-01-31 15:29) [5]Ну подчистить надо обязательною писалась процедура очень давно и частично не мной.
собсно, зачем добавил проверку на количество аудиорендереров не помню, был какой-то закидон, вот и добавил. Выброси если без этого работает.
---
P.L.U.R. and WBR, NailMan aka 2:5020/3337.13
← →
Noby (2006-01-31 16:01) [6]псиб:), а возможно ли определинть сколько аудио дорожек в файле? Предположим что пользователь не знает о том сколько там дорожек.
← →
Дима (2006-01-31 22:26) [7]я попробовал и у меня при смене воспроизводится отдельно только второе аудио а при переключении на первое воспроизводятся оба… что мне делать с этим как от этого избавиться?
С уважением Дима.
← →
NailMan © (2006-01-31 23:10) [8]Noby
можно узнать несколькими способами.
Самый простой(имея файлик типа DirectX9_c.chm из SDK где описаны структуры AVI-RIFF) - это распотрошить заголовок AVI-RIFF. там все структурированно описано что за потоки, каких форматов, кодеки(номера в случае аудио, чтобы узнать название надо энумератором по реесту поковырять, если надо могу дать процедурку ;-) ) и пр.
В заголовке еще много всякой полезной инфы выудить можно, включая все кодеки всех потоков, длительности, частоты дискретизации, etc...
В общем случае на основе вышеприведенной процедуры делается следующая функция:Function TVideoEngine.GetAudioTracks:Integer;
var
pEnum : IEnumFilters;
pFilter :IBaseFilter;
cFetched : dword;
CL:TGUID;
begin
result:=0;
// Get filter enumerator
dsGraphBuilder.EnumFilters(pEnum);
while pEnum.Next(1, pFilter, @cFetched) = S_OK do
begin
pFilter.GetClassID(CL);
if IsEqualGUID(CL,CLSID_DSoundRender) then inc(Result);
pFilter:=nil;
end;
pFilter:=nil;
pEnum:=nil;
end;
Другими словами сколько аудиорендереров в графе, стока и дорожек ;-)
---
P.L.U.R. and WBR, NailMan aka 2:5020/3337.13
← →
NailMan © (2006-01-31 23:14) [9]Вот так попробуй:
Procedure TVideoEngine.SetMultipleVolume(TrackID:integer;vLevel:integer);
var
pEnum : IEnumFilters;
pFilter :IBaseFilter;
cFetched : dword;
CL:TGUID;
BA : IBasicAudio;
z : integer;
begin
repeat
// Get filter enumerator
dsGraphBuilder.EnumFilters(pEnum);
while pEnum.Next(1, pFilter, @cFetched) = S_OK do
begin
pFilter.GetClassID(CL);
if IsEqualGUID(CL,CLSID_DSoundRender) then
begin
If i<>TrackID then
z:=-10000 else z:=vLevel;
pFilter.QueryInterface(IID_IBasicAudio,BA);
BA.put_Volume(VolumeTable[z]);
BA:=nil;
end;
pFilter:=nil;
end;
pFilter:=nil;
pEnum:=nil;
end;
значение массива VolumeTable тоже что и было.
Указываешь номер дороги и громкость, остальные глушатся в ноль. Алгоритм тут жесткий, что не наше, то глушим.
---
P.L.U.R. and WBR, NailMan aka 2:5020/3337.13
← →
Noby (2006-02-03 02:22) [10]Дима
У меня та же проблема была… у меня нормально работает так: SetMultipleVolume(-1, 0). Глушатся только те что не должны работать, а воспроизведение сразу двух дорожек при этом не прослушивается :).
-1 это номер дорожки, а 0 глушим не нужное.
← →
Noby (2006-02-03 02:27) [11]NailMan
Спасибо за инфу очень полезная для меня и нужная.
Есть еще один вопросик относительно звука… можно ли вывести выбранный звук в буфер и в последствии сохранить его отдельно от видео в любой выбранный пользователем формат?
Хотелось бы конечно выудить все инфу из файла но наверное мне не дано это сделать :( поскольку толком в сети я не смог талькового найти ничего
← →
NailMan © (2006-02-03 11:22) [12]Noby
> Есть еще один вопросик относительно звука… можно ли вывести
> выбранный звук в буфер и в последствии сохранить его отдельно
> от видео в любой выбранный пользователем формат?
Можно выдрать фреймы аудиодорог и собрать их в любой файл или по крайней мере в Wav, но для этого придется по любому растормошить заголовок AVI-RIFF, таблицу индексов в конце файла и потом по таблице разобрать всю секцию данных выдергивая фреймы. Тут нужно знать формат и структуру WAV(это вобщем-то тот же AVI-RIFF только упрощенный).
Чтобы конвертить в другие форматы(в т.ч. и сжатие), можно сделать свой граф на основе исходного, повыкидывать оттуда все ненужное и внедрить на место аудиорендерера кодек сжатия и вобщем-то неизвестный фильтр записи файла на диск или фильтр-заглушку с которой можно получить зажатый фрейм аудио и потом его записывать в нужный формат(*.mp3 например).
Вобщем в этом деле много сложностей. самое простое это просто вырезать дородку по фреймам и в wav слить, как я предложил в первом варианте. Так делает VirtualDub например.
---
P.L.U.R. and WBR, NailMan aka 2:5020/3337.13
← →
Noby (2006-02-04 05:22) [13]Не думал что это такая трудоемкая работа :( Скинь плыз AVI-RIFF, попробую что сделать.
Спасибо и на этом
← →
NailMan © (2006-02-04 13:28) [14]Функция потрошения загововков AVI-RIFF(только модификаций AVI). Собрана с учетом нескольких модификаций структур заголовка, которые пользуют разные программы создания видео.
На выходе выходит заполненная структура, которая и используется далее для удобного выуживания нужной информации о файле.
В теле часто встречается ненужная строчкаmove(PD^,FCC,4);
- это для того чтобы контролировать процесс навигации по секциям во время отладки парсинга нового вида заголовка(с какой-то левой неизвестной секцией). В целом прибить их можно или закоментить.
type
FCC_Type = array[0..3] of char;
Const
FCC_RIFF : FCC_Type = "RIFF";
FCC_hdrl : FCC_Type = "hdrl";
FCC_AVI : FCC_Type = "AVI ";
FCC_avih : FCC_Type = "avih";
FCC_strl : FCC_Type = "strl";
FCC_strh : FCC_Type = "strh";
FCC_strf : FCC_Type = "strf";
FCC_strd : FCC_Type = "strd";
FCC_strn : FCC_Type = "strn";
FCC_MOVI : FCC_Type = "movi";
FCC_LIST : FCC_Type = "LIST";
FCC_JUNK : FCC_Type = "JUNK";
FCC_indx : FCC_Type = "indx";
FCC_vids : FCC_Type = "vids";
FCC_MPEG : FCC_Type = chr($0)+ chr($0) + chr($01)+ chr($BA);
TYPE
TFOURCC = array[0..3] of char;
TVidsFormat = record
BMfmt : TBITMAPINFOHEADER;
DVFmt : TDVINFO;
end;
TVideoStream = record
st : TAVIStreamHeader;
FMT : TVidsFormat;
end;
TAudioStream = record
st : TAVIStreamHeader;
WAVFmt : TWaveFormatEx;
end;
TAviInfo = record
AVIHeader : TAVIMainHeader;
audstreams : DWORD;
vids : TvideoStream;
auds : Array[0..4] of TAudioStream;
CRC : Int64;
end;
Function ReadAVIHeader(Const FName:String;Var Avi:TAviInfo):Cardinal;
var f:Integer;
p,PD:pointer;
NulDD,i,leng:Cardinal;
audstreams:dword;
FCC,FCC2 : Array[0..3] of char;
MH : ^TAVIMainHeader;
SH : ^TAVIStreamHeader;
VFH : ^TVidsFormat;
WVH : ^TWaveFormatEx;
begin
Result:=1; //По умолчанию - AVIVideo
Zeromemory(@AVi,sizeof(TAviInfo));
if FileAutoDetection then avi.CRC:=getfilecrc(fname);
F:=Fileopen(fname,fmopenread or fmsharedenynone);
fileread(f,fcc,4); //RIFF
fileread(f,nuldd,4);
fileread(f,fcc2,4); //AVI_
if (fcc=fcc_riff) and (fcc2<>FCC_AVI) then
begin
result:=0;
Fileclose(F);
exit;
end;
if (fcc<>fcc_riff) then
begin
If FCC=FCC_mpeg then result:=2
else
result:=0;
Fileclose(F);
exit;
end;
Fileread(f,fcc,4); //LIST
fileread(f,nuldd,4);
getmem(p,nuldd+1024);
fileread(f,p^,nuldd);
fileclose(f);
PD:=P; //stay on "hdrl"
inc(DWORD(PD),4); //stay on "avih"
MH:=PD;
AVi.AVIHeader.dwMicroSecPerFrame:=MH^.dwMicroSecPerFrame;
avi.AVIHeader.dwMaxBytesPerSec:=mh^.dwMaxBytesPerSec;
avi.AVIHeader.dwFlags:=mh^.dwFlags;
avi.AVIHeader.dwTotalFrames:=mh^.dwTotalFrames;
avi.AVIHeader.dwStreams:=mh^.dwStreams;
inc(DWORD(PD),sizeof(TAVIMainHeader)); //Stay on LIST
audstreams:=0;
move(PD^,FCC,4);
For i:=0 to avi.AVIHeader.dwStreams-1 do
Begin
inc(DWORD(PD),4); //stay on "strl" length
move(PD^,FCC,4);
inc(DWORD(PD),4); //Stay on "strl"
move(PD^,FCC,4);
inc(DWORD(PD),4); //stay on "strh"
move(PD^,FCC,4);
SH:=PD;
if SH^.fccType=ConvertFCCToDWORD(FCC_vids) then
begin
avi.vids.st:=sh^;
inc(DWORD(PD),sh^.cb+8); //stay on "strf"
move(PD^,FCC,4);
inc(DWORD(PD),4); //stay on length "strf"
move(PD^,leng,4);
inc(DWORD(PD),4); //stay on "strf" data
VFH:=PD;
avi.vids.FMT.BMfmt:=VFH^.BMfmt;
if leng>56 then
avi.vids.FMT.DVFmt:=VFH^.DVFmt;
inc(DWORD(PD),leng);//stay on LIST
move(PD^,FCC,4);
end;
if SH^.fccType=ConvertFCCToDWORD("auds") then begin
avi.auds[audstreams].st:=SH^;
inc(DWORD(PD),sh^.cb+8); //stay on "strf"
move(PD^,FCC,4);
inc(DWORD(PD),4); //stay on length "strf"
move(PD^,leng,4);
inc(DWORD(PD),4); //stay on "strf" data
WVH:=PD;
avi.auds[audstreams].WAVFmt:=WVH^;
inc(DWORD(PD),leng);
inc(audstreams);
end;
Move(PD^,FCC,4);//Stay on JUNK or "strn"
If (FCC=FCC_JUNK) or (FCC=FCC_strn) or (FCC=FCC_strd) or (FCC=FCC_indx) then
begin
inc(DWORD(PD),4);
move(PD^,nuldd,4);
If nuldd mod 2<>0 then inc(nuldd);
inc(DWORD(PD),4+NULDD);
move(PD^,FCC,4);
end;
End;
avi.audstreams:=audstreams;
freemem(p);
end;
---
P.L.U.R. and WBR, NailMan aka 2:5020/3337.13
← →
Noby (2006-02-06 01:28) [15]Огромное человеческое тебе СПАСИБО!!! выручил очень сильно:-)... буду пробовать
Страницы: 1 вся ветка
Текущий архив: 2006.07.16;
Скачать: CL | DM;
Память: 0.52 MB
Время: 0.008 c