Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Media";
Текущий архив: 2006.07.16;
Скачать: [xml.tar.bz2];

Вниз

Разделение аудио потоков в 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 вся ветка

Форум: "Media";
Текущий архив: 2006.07.16;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.52 MB
Время: 0.016 c
2-1151321009
bulavkin
2006-06-26 15:23
2006.07.16
DelphiX D7 --- Undeclared identifier: TBackgroudSprite


10-1122298976
Max4
2005-07-25 17:42
2006.07.16
Excel


2-1151329549
novill
2006-06-26 17:45
2006.07.16
Текущий каталог для сервиса(службы)?


15-1150154457
Модемщик
2006-06-13 03:20
2006.07.16
Почему модемный доступ настолько дороже выделенки?


2-1151673095
Vitalik__
2006-06-30 17:11
2006.07.16
приложение для интернета





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский