problemy z dźwiękiem w strumieniach AV

0

Witam,

mam dwa problemy i proszę o pomoc bardziej doświadczonych.

Problem 1
Tworzę dwa odzielne strumienie/sample, jeden video drugi audio.
Odtwarzam je z prędkością standardową 25 klatek/s.
Obraz jest idealny. Dźwięk jest zakłócany /trzaski, pyknięcia, z tego co sprawdziłem co 1/25 sekundy. Dlaczego? Co robię źle?

Problem 2
Dlaczego to co zrobiłem /dźwięk/ nie działa pod XP. Działa pod 2000 tylko !!!

Poniżej wkleiłem dwie testowe części kodu.

Otwarcie strumieni:

CoCreateinstance(CLSID_AMMULTIMEDIASTREAM,nil,CLSCTX_INPROC_SERVER,IID_IAMMULTIMEDIASTREAM,AMStream);
MultiByteToWideChar(CP_ACP,0,Pchar(Filename),-1,wPath,Sizeof(wPAth) div sizeof(wPath[0]));
AMStream.Initialize(STREAMTYPE_READ,AMMSF_NOGRAPHTHREAD,nil);
AMStream.AddMediaStream(nil,MSPID_PrimaryAudio,0,AStream);
AMStream.AddMediaStream(Form12.DXDraw1.DDraw.IDraw,MSPID_PrimaryVideo,0,Media);
AMStream.OpenFile(wPAth,AMMSF_NOCLOCK);
MMStream := AMStream;

MMstream.GetMediaStream(MSPID_PrimaryAudio,PrimaryAudStream);
PrimaryAudStream.QueryInterface(IID_IAudioMediaStream,AudioStream);

AudioStream.GetFormat(WaveFormat);

CoCreateInstance(CLSID_AMAudioData,nil,CLSCTX_INPROC_SERVER,IID_IAudioData,AudioData);

SizeBuffer := waveformat.nAvgBytesPerSec div 25;

GetMem(Buffer,SizeBuffer);

AudioData.SetBuffer(SizeBuffer,Buffer,0);
AudioData.SetFormat(waveFormat);
AudioStream.CreateSample(AudioData,0,AudioSample);

WaveOutOpen(@hwo,wave_mapper,@waveformat,DWORD(Self.Handle), DWORD(Self),CALLBACK_WINDOW);

for i := 0 to 1 do
begin
with woh[i] do
begin
lpData := Buffer;
dwBufferLength := SizeBuffer;
dwBytesRecorded := 0;
dwUser := 0;
dwFlags := 0;
dwLoops := 0;
lpNext := nil;
reserved := 0;
end;
waveOutPrepareHeader(hwo,@woh[i],SizeOf(woh[i]));
end;

Wywoływany 25 razy na sekundę update audiosampla:

if assigned(AudioSample) then
begin
if AudioSample.Update(0,0,nil,0) <> S_OK then
begin
waveOutReset(hwo);
waveOutUnprepareHeader(hwo,@woh[0],sizeof(woh[0]));
waveOutUnprepareHeader(hwo,@woh[1],sizeof(woh[1]));
waveOutClose(hwo);
end
else
begin
waveOutWrite(hwo, @woh[0], sizeof(woh[0]));
waveOutWrite(hwo, @woh[1], sizeof(woh[1]));
end;
end;
</b>

0

Dźwięk jest zakłócany /trzaski, pyknięcia, z tego co sprawdziłem co 1/25 sekundy. Dlaczego? Co robię źle?

Spróbuj zamiast CALLBACK_WINDOW zrobić inny sposób powiadamiania... Choć to nie musi być przyczyną "pyknięć".

--- edit ---

Nie wiem czy dobrze odczytałem kod (programuje w C/C++), ale zamiast dwóch 40ms bufforów daj np. 20 ;)

0

nic z tego to nie było to - nadal pierdzi.
Co do wielkosci bufora to gdy zwiekszam wartosc bufora na 1 sekunde na przykład to pykanie jest co 1 sekundę. Ale nie urządza mnie to gdyz musze miec dokładnie co 25 czesc sekundy. Tak jak obraz.
Jakieś inne pomysły?

0

nic z tego to nie było to - nadal pierdzi.

No a jaki dałeś callback???

Co do wielkosci bufora to gdy zwiekszam wartosc bufora na 1 sekunde na przykład to pykanie jest co 1 sekundę

Sprawdzałeś dane/sample na począktu/końcu buffor'a??? Może źle go wypełniasz??? Aha ważne jest też to, żebyś przed odpaleniem całości zakolejkował wszystkie buffory audio (prebuffering).

Tu chyba jest coś nie tak:

if assigned(AudioSample) then
          begin
            if AudioSample.Update(0,0,nil,0) <> S_OK then
              begin
                waveOutReset(hwo);
                waveOutUnprepareHeader(hwo,@woh[0],sizeof(woh[0]));
                waveOutUnprepareHeader(hwo,@woh[1],sizeof(woh[1]));
                waveOutClose(hwo);
              end
            else
              begin
                waveOutWrite(hwo, @woh[0], sizeof(woh[0]));
                waveOutWrite(hwo, @woh[1], sizeof(woh[1]));
              end;
          end;    

Zasada jest taka, że jeden buffor "gra", a reszta odegranych jest wypełniana nowymi samplami i kolejkowana.

Ale nie urządza mnie to gdyz musze miec dokładnie co 25 czesc sekundy

No tak tylko pamiętaj, że 2x40ms może nie wystarczyć - taka bezpieczna wielkość to 1 sekunda (10x100ms prebuffered). Nie wiem czym renderujesz obraz ale może lepiej będzie synchronizować go do dźwięku, a nie na odwrót?

0

co do calbacka to dawałem wszystkie po kolei jakie mozna było.
Dzieki za ostatnie uwagi. Pobawie sie intensywnie w najblizszy weekend.
Moze rzeczywiscie sprobuje synchronizowac odwrotnie. Chociaż próbowałem
w ten sposób odgrywac same pliki dzwiekowe /wav, mp3, wma/ bez obrazu,
a efekt był ten sam.

Korzystam z bibliotek DelphiX.

Czy myslisz ze powinienem skorzystac z flag informujacych o odegraniu
wszystkich próbek z bufora i dopiero po uzyskaniu potwierdzenia updatować
sampla? Chyba sa takie z tego co pamietam...

zasada ta co napisałeś jest jak najbardziej słuszna /gdy chce odczytac z czystego pliku audio/, wydaje mi sie ze w tym przypadku gdy wypełniam bufor, a wlasciwie wypełnia sie on automatycznie, poprzez IID_IAudioData sa one zapisywane do jednego bufora. Tzn. dane wszystkich kanałów do jednego bufora. Eksperymentowałem z roznymi ustawieniami, w tym z jednym buforem i efekty były bardzo ciekawe aczkolwiek nie nadajace sie do niczego.
Probowałem odtwarzac tylko wavy tak jak w dostepnym przykladzie tutaj na forum i wtedy było ok. Ale sposób działania jest troche inny.
Wkurza mnie to juz troche ale musze to zrobic...

0

Czy myslisz ze powinienem skorzystac z flag informujacych o odegraniu wszystkich próbek z bufora i dopiero po uzyskaniu potwierdzenia updatować sampla?

To zależy. Jeżeli masz ustawiony jakiś mechanizm powiadamiania np. CALLBACK_WINDOW. to nie musisz sprawdzać flag - driver zwraca adres do odegranego buffora WAVEHDR. Jeżeli nie masz żadnego mechanizmu powiadamiania - CALLBACK_NULL, wtedy musisz sprawdzać flagi poszczególnych bufforów (oddzielny wątek, pętla itd.).

[...] wypełnia sie on automatycznie, poprzez IID_IAudioData sa one zapisywane do jednego bufora

Nie ma to jak DirectX Interfaces Hell [diabel]

Możesz spróbować przed IAudioStreamSample::Update dać IAudioData::SetBuffer ze wskaźnikiem kolejnych WAVEHDR::lpData. Oczywiście każdy WAVEHDR to oddzielny buffor!!! Mniej więcej wyglądałoby to tak:

Buffor I:
IAudioData::SetBuffer
IAudioStreamSample::Update
waveOutWrite
Buffor II:
IAudioData::SetBuffer
IAudioStreamSample::Update
waveOutWrite
...itd.

PS. Oczywiście tu mogę się mylić bo nie korzystałem z tych strumieni - opierałem się tylko na dokumentacji ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1