La présente leçon
est la suite immédiate de la leçon
5. Nous pousuivons
le projet commencé, lequel comportait
des fonctions de prévisualisation, et
nous y rajoutons maintenant de quoi enregistrer
le fichier capturé sur disque.On suppose pour
cela
qu'une caméra numérique au format
DV est branchée
sur une carte firewire et allumée en
mode VCR ou Camera, et qu'on sait construire le
graphe de prévisualiation comme vu à
la leçon5..
1. Enregistrer le flux vidéo
Nous partirons de
la situation où une prévisualisation
avec son a été choisie. Je vous
rappelle qu'alors nous avons construit le graphe
suivant:
On y observe
une broche de la catégorie Capture
sur le Smart Tee. C'est celle-ci que
nous allons exploiter avec un renderstream
pour enregistrer le flux souhaité. Pour
rester simple,
nous allons d'abord l'enregistrer en DV de type I, ce
qui est aussi plus économique en ressources
machines. Si votre configuration est assez
puissante, vous pourrez plus loin voir comment construire un
graphe qui enregistre le résultat en
un fichier DV de type II . Si vous avez compris
la leçon 4, cela
devrait être faisable pour vous sans attendre
que je vous donne la solution.
La fonction que
nous créons pour cela est la suivante:
function
TCaptureModule.buildDV1graph (vw:IBaseFilter;fichier:widestring):Boolean;
{La
fonction prend un paramètre qui est de
nouveau le filtre de prévisualisation,
comme vu dans la leçon
5, puis
le nom du fichier à enregistrer, avec
son chemin. L'appel de la fonction se fait donc
selon l'exemple suivant:
if
capturemodule1.buildcapturegraph(videowindow1
as IbaseFilter,'f:\capture\trucmuche.avi') then begin...}
{Les
variables avimux et writersink
sont des pointeurs sur des interfaces qui seront
fournies par
certaines fonctions de l'interface ICaptureGraphBuilder2.}
{On
commence par appeler la fonction de preview
vue à la leçon
5. Si
elle ne marche pas on quitte la fonction}
hr:=cg.SetOutputFileName(MEDIASUBTYPE_Avi,pwidechar(fichier),
{La
fonction SetOutputFileName de l'interface
ICaptureGraphBuilder2 permet de fixer
le nom du fichier de sortie. Nous lui donnons
donc le widestring reçu en paramètre.
Elle fournit un
IBaseFilter avimux qu'il faut
garder pour l'utiliser plus loin dans renderstream. Voyez
dans msdn la référence
de setoutputfilename.}
if
hr<>S_Ok then exit;
hr:=cg.RenderStream(@PIN_CATEGORY_CAPTURE,@MEDIATYPE_Interleaved,
CaptureFiltre as IBaseFilter,nil,avimux);
{On
appelle donc renderstream en demandant
une broche de type Capture, et donnant
un
flux qui entrelace
video et audio. On demande de construire le graphe en partant de la source CaptureFiltre,
pour arriver au filtre avimux qui génère
l'écriture sur disque (ce dernier continuera ensuite
par
le writersink créé par setoutputfilename
pour déterminer le nom du
fichier, mais il est inutile de le repréciser
dans renderstream, car la connexion existe
déjà grâce à setoutputfilename}
except
end;
finally
end;
end;
Le résultat
de cette fonction , quand elle est appelée
avec succès par exemple pour enregistrer
la capture dans un fichier trucmuche.avi donne
le graphe suivant:
On voit que le
renderstream a trouvé la bonne broche
de la catégorie Capture sur le
filtre Smart Tee en partant
du filtre CaptureFiltre, et qu'il a ajouté
deux filtres: Mux qui est en fait le
filtre Avi Mux, qui encapsule le flux
DV audio+vidéo unique dans le format
avi, et le writersink qui a pris ici
le nom de "trucmuche.avi" et
qui enregistre ce fichier sur le disque.
2. Impossible de faire un graphe
de capture "économique"
Je rappelle que
jusqu'ici
nous avons utilisé la fonction preview
de la leçon5. Celle-ci
avait été construite sur la broche
DV A/V Out pour bénéficier
de l'audio. Tout cela nous donne un graphe où
il y a pas mal de travail pour le processeur
et la mémoire vive. Si votre configuration
n'est pas assez puissante, cela risque de "ramer"
un peu.
On pourrait se
demander si on peut faire un graphe de capture
en partant du graphe de prévisualisation
"économique" que nous avons
construit à la leçon
5. Il n'en est rien
pour une raison très spécifique: le driver
msdv qui construit la source de capture,
ici notre CaptureFiltre, ne sait pas
rendre des flux sur ses deux broches de sortie
à la fois. Il faut donc choisir entre
la broche video DV Vid Out qui a servi
pour le graphe de capture économique
sans le son, et la broche DV A/V Out
qui contient audio et vidéo. Pour vous
en convaincre, reportez-vous à la référence
du driver Microsoft msdv.
Par conséquent, si on veut enregistrer
le son, ce qui me paraît presque toujours
le cas, il faut brancher les flux de preview
et de capture sur la seconde broche, et utiliser
un smart tee. Tout au plus peut-on économiser
la branche de rendu de l'audio pendant la préview
si on veut économiser les ressources
machines, et le cas échéant éviter
du larsen. (Mais on peut aussi mettre le volume
du graphe à 0 pour cela).
3. Trouver un filtre dans un
graphe
Nous avons vu
à la leçon5 comment trouver un
filtre DV Splitter, dans un graphe, lorsque nous
avons voulu chercher sa broche audio pour la
rendre. Lorsqu'on travaille avec renderstream
qui introduit des filtres dans un graphe, sans
qu'on les ait créé directement
en leur donnant un nom, il est souvent utile
de chercher ainsi un filtre particulier dans
un graphe. Faisons-en une fonction qui pourra
être réutilisée:
function
TCaptureModule.trouverFiltre(nom:string;var
bf:IBaseFilter):Boolean;
{Attention
au var devant bf qui est indispensable
pour qu'au retour bf pointe bien sur une interface
IbaseFilter, malgré notre fl.free}
var
fl:TFilterList;
i:integer;
4. Enregistrer en DV de type
II
Je vous avais
suggéré plus haut de construire
vous-même un graphe de capture en DV de
type II. Pour les paresseux, ou ceux qui ont
encore des difficultés, je donne la fonction
correspondante ici, car il me paraît plus
pratique et plus naturel de capturer en type
II. Je ne sais d'ailleurs pas quels sont les esprits tordus
qui ont inventé la capture en un seul
flux mêlant audio et vidéo, et
qui sont responsables de beaucoup d'ennuis que
rencontrent les vidéastes. Voir mon freeware
DVdate pour pouvoir jongler
entre les type I et II, ou encore la leçon
4 qui vous permettait de construire votre propre
convertisseur.
Le principe est
d'insérer un filtre nommé DVSplitter (autre
que celui inséré automatiquement
dans la partie preview) et de relier
ses deux broches de sortie à celles d'un
filtre avi muxer. Ajoutez donc un filtre
DV Splitter sur le capturemodule. La fonction
est alors la suivante:
function
TCaptureModule.buildDV2graph(vw:IBaseFilter;fichier:widestring):Boolean;
{La
fonction prend les mêmes paramètres
que buildDV1graph.}
var
avimux,smarttee:IBaseFilter;
writersink:IFileSinkFilter;
hr:HResult;
begin
try
try
{Utile
pour que notre filtre ne soit pas accaparé
par renderstream dans la partie preview}
if
not buildpreviewgraph(vw) then exit;
capturegraph.stop;
cg:=CaptureGraph
as ICaptureGraphBuilder2;
hr:=cg.SetOutputFileName(MEDIASUBTYPE_Avi,
pwidechar(fichier), avimux,writersink);
if
hr<>S_Ok then exit;
if
not trouverFiltre('Smart Tee',smarttee)
then exit;
DVSplitter.filtergraph:=capturegraph;
hr:=cg.RenderStream(nil,nil,smarttee
,DVSplitter as IbaseFilter,avimux);
if
failed(hr) then exit;
hr:=cg.renderstream(nil,@MEDIATYPE_Audio,DVSplitter,nil,avimux);
if
failed(hr) then exit;
result:=true;
except
end;//try
except
finally
end;//try
finally
end;
Si
vous regardez le graphe de capture résultant
dans graphedit, vous obtenez ceci:
5. Conclusion
Au terme de cette
leçon, vous avez appris à construire
des graphes de capture, en utilisant les puissantes
fonctions de l'interface ICaptureGraphBuilder2.
D'une part renderstream qui vous était
déjà familière pour relier
deux filtres, et qui sait ajouter lui-même
les filtres nécessaires
(toujours l'intelligence de directshow) et vous
pouvez même préciser la nature
des broches à relier. D'autre part setoutputfilename
qui construit aisément toute la partie
d'écriture d'un fichier avi sur le disque.
Nous avons construit aussi une fonction "maison"
pour retrouver un filtre dans le graphe lorsqu'on
connaît seulement son nom. Enfin, vous
avez commencé à examiner de plus
près la source de capture DV, et entreaperçu
quelques unes de ses particularités comme
l'impossibilité de rendre les deux broches
à la fois. Il y a évidemment beaucoup
plus à découvrir sur le format
dv dans directshow en parcourant les références
dans msdn
Pour mettre en
oeuvre ces fonctions dans une application delphi,
il vous reste à construire une interface
avec l'utilisateur. Comme d'habitude je vous
livre en téléchargement une petite
démo rudimentaire que vous pourrez améliorer.
Pour vous donner une idée de ce qu'on
peut faire, regardez mon freeware CaptureFlux.
Ici
on peut élécharger le code source de cette
leçon (dans une version delphi 7).
Leçon
5
Leçon 7
retour
vers le haut de la page
|