problème de capture son avec Directshow sous VC++6

problème de capture son avec Directshow sous VC++6 - C++ - Programmation

Marsh Posté le 06-11-2003 à 15:51:28    

Bonjour.
 
Je cherche à capturer du son en DirectX9 (Visual C++6) et j'utilise un filtergraph de la forme suivante :
 
http://r.lourd.free.fr/divers/graph-forum-developpez.jpg
 
C'est assez simple et mon problème concerne la configuration du Samplegrabber donc voici le détail :
 

Code :
  1. // Configuration du filtre SampleGrabber2
  2.      
  3.    WAVEFORMATEX fluxAudio;
  4.    fluxAudio.wFormatTag = WAVE_FORMAT_PCM;
  5.    fluxAudio.nChannels = 1;
  6.    fluxAudio.nSamplesPerSec = 8000;
  7.    fluxAudio.nAvgBytesPerSec = 16000;
  8.    fluxAudio.nBlockAlign = 2;
  9.    fluxAudio.wBitsPerSample = 16;
  10.    fluxAudio.cbSize = 0;  // apparemment aucun effet
  11.  
  12.    AM_MEDIA_TYPE mt2;
  13.    ZeroMemory(&mt2, sizeof(AM_MEDIA_TYPE));
  14.    mt2.majortype = MEDIATYPE_Audio;
  15.    mt2.subtype = MEDIASUBTYPE_PCM;
  16.    mt2.formattype = FORMAT_WaveFormatEx;
  17.    hr = pGrabber2->SetMediaType(&mt2);
  18.    if (FAILED(hr))
  19.     {
  20.         Msg(TEXT("Impossible de mettre à jour le type de média du sample grabber 2, hr=0x%x\r\n\r\n" )
  21.             TEXT("Le programme va se terminer" ), hr);
  22.         pGrabberF2->Release();
  23.         return hr;
  24.     }


 
J'utilise donc une structure WAVEFORMATEX qui devrait me capturer le son en 8000Hz 16bits mono or le son que j'obtiens (stocké dans un fichier avec le code ci-après) est en 44100Hz 16bits stéréo, et la moitié seulement est capturée :
 

Code :
  1. long cbBufferAudio = 176400;
  2. char *pBufferAudio = new char[cbBufferAudio];
  3. while (!stopenvoi)
  4. {
  5.         // On va chercher dans le buffer de capture la dernière trame son capturée.
  6. pGrabber2->GetCurrentBuffer(&cbBufferAudio,reinterpret_cast<long*>(pBufferAudio));
  7.         // Ecriture d'une trame de son brut capturée pendant 1s dans "son_brut.raw"
  8.    // situé dans le même répertoire que applicap.exe
  9.    FILE *son_brut;
  10.    if ((son_brut=fopen("son_brut.raw","a" ))!=NULL)
  11.    {
  12.       fwrite(pBufferAudio,176400,1,son_brut);
  13.       fclose(son_brut);
  14.    }
  15.    else
  16.    {
  17.       printf("Problem opening the file\n" );
  18.    }
  19. ...


 
Passons sur la gestion gourmande du fichier (que je vais corriger immédiatement !) ; d'après vous d'où pourrait provenir l'erreur ?
 
Merci d'avance car après cette capture il faut que je traite le son pour le diffuser en mu-Law par sockets (d'où le while (!stopenvoi))...


---------------
.: Passions | Galerie | Blog :.
Reply

Marsh Posté le 06-11-2003 à 15:51:28   

Reply

Marsh Posté le 06-11-2003 à 16:32:30    

Je ne crois pas que tu puisse systématiquement imposer ce genre de chose, tout dépends de la source et du splitter derrière ( s'il y a ), car si c'est un fichier avi par example, il a déjà son format et tu ne peux pas le changer à moins de passer par un filtre de transformation si ça existe.
Quel est la source dans ton cas ?

Reply

Marsh Posté le 06-11-2003 à 16:36:28    

flûte, je n'avais pas vu le graph ...
Mais bon, ça ne change rien je pense, si le filtre de capture n'est pas prévu pour fonctionner à 8KHz et en 8 bits, soit il ne fonctionne pas soit il envoie ce qu'il a.
Donc c'est à toi de faire le downSampling ;-)

Reply

Marsh Posté le 06-11-2003 à 16:46:26    

Et comment construis-tu le graph ?
tu laisses faire ou tu connectes à la main ?

Reply

Marsh Posté le 06-11-2003 à 17:22:41    

j'utilise le code suivant (je mets juste les exemples, par tout ce serait trop long). Pour la création des filtres :
 

Code :
  1. // Ajout du filtre capture audio au filtre graphique
  2.     hr = g_pGraph->AddFilter(pAudioSrcFilter, L"Audio Capture" );
  3.     if (FAILED(hr))
  4.     {
  5.         Msg(TEXT("Impossible d'ajouter le filtre source audio au graphique, hr=0x%x\r\n\r\n" )
  6.             TEXT("Le programme va se terminer" ), hr);
  7.         pAudioSrcFilter->Release();
  8.         return hr;
  9.     }


 
Pour la connexion des filtres :
 

Code :
  1. // Connexion du filtre source AUDIO avec le filtre SAMPLE GRABBER 2
  2. IPin* pinOutSource2 = NULL;
  3. hr = g_pCapture->FindPin(pAudioSrcFilter, PINDIR_OUTPUT, NULL, NULL, FALSE, 0, &pinOutSource2);
  4.     if (FAILED(hr))
  5. {
  6.         return hr;
  7. }
  8. hr = ConnectFilters(g_pGraph,pinOutSource2, pGrabberF2);
  9. if  FAILED(hr)
  10. {
  11.  Msg(TEXT( "Echec de la connexion du filtre source audio avec le filtre SAMPLE GRABBER2, " )
  12.   TEXT( "hr=0x%x" ), hr);
  13.  return hr;
  14. }


 
Voilà comment je construit mon filtergraph.


---------------
.: Passions | Galerie | Blog :.
Reply

Marsh Posté le 06-11-2003 à 17:24:23    

L'ennui pour la capture c'est que ça "semble" être du 44100-16-stereo, mais il m'écrit que la moitié dans le buffer...
De plus ça me dérangerait pas du 44100, vu que j'ai l'algo pour le downsampler...


---------------
.: Passions | Galerie | Blog :.
Reply

Marsh Posté le 06-11-2003 à 17:25:48    

En gros ça m'écrit 0.5s de son, puis rien puis 0.5s de son, puis rien... en le lisant à 44100-16-stéréo les durées correspondent bien, mais je perds au final la moitié des infos sonores, et je sais pas pourquoi :??:


---------------
.: Passions | Galerie | Blog :.
Reply

Marsh Posté le 06-11-2003 à 21:32:44    

A mon avis tu devrais laisser faire le graph pour le rendering, mais j'ai encore un peu de mal à me rendre compte ( suis pas non plus un grand spécialiste ... ).
si ça ne te gène pas envois moi le source que je regardes en détail : cricrac@free.fr

Reply

Marsh Posté le 07-11-2003 à 09:58:36    

ok no problemo...


---------------
.: Passions | Galerie | Blog :.
Reply

Marsh Posté le 07-11-2003 à 11:35:50    

J'ai un peu regardé, moi je pense que tu devrais laisser le graph se construire tout seul, pas besoin de se connecter manuellement normalement pour un truc dans ce genre, un renderstream avec la source, le grabber et le renderer doivent suffire, idem pour l'audio, et s'il y a des trucs à rajouter entre comme le SmartTee, le graph doit s'en charger.
PAs sûr que ça résolve ton pb mais bon ...

Reply

Marsh Posté le 07-11-2003 à 11:35:50   

Reply

Marsh Posté le 07-11-2003 à 13:09:31    

ok je vais essayer ça... merci je te tiens au courant.


Message édité par rody83 le 07-11-2003 à 13:47:14

---------------
.: Passions | Galerie | Blog :.
Reply

Marsh Posté le 08-11-2003 à 09:25:05    

J'ai un peu relu les docs DirectShow et, à priori, seule les infos majortype, subtype et formattype sont prises en compte ...
donc ça expliquerai pourquoi ça ne marche pas.
Maintenant je n'ai pas trouvé ce qu'il faudrait faire ;-(
tiens-moi au courant, je vais aussi essayer d'en discuter avec un autre develo moins nul que moi sur le sujet ;-)

Reply

Marsh Posté le 08-11-2003 à 14:58:06    

conseille de tester avec GraphEdit, tu charges juste la source, et clic droit sur la pin de sortie et choisis "render pin", de façon à voir comment le truc va se construire automatiquement et voir là ou on peut sélectionner les paramètres.
D'ailleur c'est quoi la source ? une caméra ? autre ? comment est branché le micro ?


Message édité par cricri_ le 08-11-2003 à 14:59:14
Reply

Marsh Posté le 12-11-2003 à 11:09:29    

J'ai fait plein de tests, et le problème que je rencontre doit venir de la taille du buffer audio : l'ennui, c'est que la taille n'est définie nulle part (comme la vidéo, d'ailleurs, qui marche pourtant nickel)... sinon avec GraphEdit, quand je veux ouvrir mon source (.cpp), il me dit "Could not construct a graph from this file", idem pour le .dsp du projet.
J'ai donc construit le graphe à la main, comme décrit dans le soft et en sortie du SampleGrabber relié à Null Renderer (si tu veux je peux te mailer le graphe complet), il m'indique comme format :
Major Type: Audio
Sub Type: PCMAudio
Format: WaveFormatex: 44.100 KHz 16 bit stereo


---------------
.: Passions | Galerie | Blog :.
Reply

Marsh Posté le 12-11-2003 à 11:14:34    

Concernant le périphérique de capture, c'est soit un micro, soit une webcam mais dans les deux cas il faut bien que je définisse (point à améliorer par la suite) le périphérique de capture par défaut au niveau de Windows ; sinon j'ai le même problème que j'utilise un micro ou une webcam. J'ai calculé la taille d'un buffer de 1s avec ce type de données brut, soit : 44100*16*2/8=176400 octets mais seulement la moitié est remplie de son correct à chaque envoi, l'autre moitié étant "silencieuse" (donnée CD partout).
Je précise aussi que lorsque je joue le fichier que j'écris (.raw) en 44100 16bits stereo la durée correspond à la durée réelle de parole.


Message édité par rody83 le 12-11-2003 à 11:16:38

---------------
.: Passions | Galerie | Blog :.
Reply

Marsh Posté le 12-11-2003 à 12:59:16    

Non, tu ne peux pas ouvrir ton cpp dans graphedit ..
Mais tu peux sélectionner ta source dans les filtres, soit la webcam soit le micro, et la tu peux faire un render Pin.
La taille du buffer audio c'est different, je n'ai pas ton code ici, mais si tu fais :
HRESULT GetCurrentBuffer(
  long *pBufferSize,
  long *pBuffer
);
 
avec la taille initialisé à NULL ça doit te renvoyé la taille par sample.

Reply

Marsh Posté le 12-11-2003 à 15:17:08    

j'ai essayé (c'était dans la doc de directx ça m'avait échappé) et il me renvoie une taille de buffer de 88200 octets, soit la moitié de ce que j'ai calculé... et lorsque j'effectue une capture, j'ai toujours la moitié du buffer qui reste vide, quelle que soit la taille ?!


Message édité par rody83 le 12-11-2003 à 15:17:20

---------------
.: Passions | Galerie | Blog :.
Reply

Marsh Posté le 12-11-2003 à 16:24:26    

Ok, mais qu'est-ce qui te fait dire que tu vas recevoir un sample d'1s. ?
Car en général c'est aussi lié au debit vidéo quand il y en a.

Reply

Marsh Posté le 12-11-2003 à 16:35:49    

justement les paquets vidéo sont envoyés toutes les 1s ; de plus si le buffer que je définis était trop petit, il serait quand même rempli : je n'arrive pas à m'expliquer ce phénomène...


---------------
.: Passions | Galerie | Blog :.
Reply

Marsh Posté le 12-11-2003 à 16:42:04    

Ok, et as-tu essayé de sauver bout à bout ces samples et les rejouer ?
Car j'aurai tendance à penser que tu ne récupère qu'un canal ...
Et pour le graph t'as essayé de ne charger que le filtre source et de faire un render pin ?

Reply

Marsh Posté le 12-11-2003 à 17:08:18    

Justement c'est la méthode que j'emploie pour les samples : à chaque tour d'une boucle je les écris à la suite dans un fichier que je joue par la suite avec CoolEdit (pratique vu qu'il lit les fichiers raw sans en-tête) ; le problème reste donc le même. Concernant la perte d'un canal j'y ai pensé aussi, malheureusement lorsque j'essaie de jouer le fichier en mono, c'est comme si je divisais par deux la fréquence (voix grave et ralentie). En fait le son reste bien synchrone lors de la lecture, mais 1/2s manque à chaque seconde, comme si la webcam s'arrêtait de fonctionner pendant ce temps-là... J'ai vérifié avec d'autres webcams sur d'autres pc ; même problème.
Pour le graphe je peux pas le faire en auto ; en effet je cherche à envoyer des données dans un tableau de char, pour ensuite les transmettre par socket, je dois donc utiliser le filtre SampleGrabber en mode "bufferisé".


---------------
.: Passions | Galerie | Blog :.
Reply

Marsh Posté le 12-11-2003 à 21:19:48    

Bon, j'ai une Webcam qqpart je vais essayer de trouver un peu de temps ce WE ...
 
Concernant le Graph on s'est mal compris, je parle de Graphedit, et juste pour faire des tests et voir comment le graph se construit.
 
Dans le principe tu ouvre Graphedit, tu choisis ton filtre source, donc la Webcam ou autre, et clic droit sur la sortie et fais render pin. Et là tu devrais pouvoir observer comment le truc est construit, et voir peut-être sur quelle partie il faut jouer pour les paramètres.
 
Et normalement il suffit de virer le renderer et de remplacer ça par le grabber et un NULL renderer pour avoir l'équivalent de ce que tu cherches à avoir en programmanation.
 
Perso je fais presque la même chose, je crée 3 filtres, 1 source, le sample grabber, le NULL renderer, je fais "Add Filter" de tous ces trucs, un renderStream de tout ça, idem pour l'audio, et c'est tout ! C'est le GraphBuilder qui s'occupe d'ajouter des trucs qui manquerait comme le splitter dans le cas d'une source audio/video.


Message édité par cricri_ le 12-11-2003 à 21:21:08
Reply

Marsh Posté le 13-11-2003 à 11:16:18    

C'est exactement ce que j'ai fait, mais j'ai toujours le même problème... Par contre j'ai trouvé un exemple intéressant de DirectX : AudioCap. Il ne fait pas la bufferisation, mais il écrit le flux dans un fichier ; je vais voir ce que je peux faire avec ça. En tout cas merci pour ton aide :-) !


---------------
.: Passions | Galerie | Blog :.
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed