 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
FR C++ Guest
|
Posted: Fri Jun 16, 2006 5:40 pm Post subject: Problème de design |
|
|
Bonjour à tous,
comme le titre l'indique, j'ai un souci de design de classe.
J'ai créé trois classes qui me permettent d'afficher de la vidéo
grâce à DirectShow.
J'ai une classe DS_InfosVideo, DS_AffichVideo, qui sont assez
explicites, et une dernière classe TVideoAffich qui est la fenêtre
qui affichera la vidéo, et qui a comme membres privés les deux
classes précédentes...
Je peux afficher 3 types de vidéo: les fichiers vidéo, des fichiers
XML pour la prévisualisation de montages vidéo, et de la vidéo en
temps-réel provenant d'une caméra numérique.
J'ai donc utilisé l'idiome du constructeur nommé pour chacune de ces
3 classes, ce qui me permet de charger les bonnes infos.
Par exemple, pour un fichier vidéo:
class TVideoAffich
{
private:
DS_InfosVideo * Infos;
DS_AffichVideo * Affich;
public:
static TVideoAffich * CreateFromFile(const std::string & path)
{
Infos = DS_InfosVideo::CReateFromFile(path);
Affich = DS_AffichVideo::CReateFromFile(path);
}
};
Pour l'instant, je limite le rendu de la vidéo à un renderer que j'ai
choisi.
Ce que j'aimerai faire maintenant, c'est proposer d'autres choix de
renderer.
Mais je ne me vois pas faire des fonctions du genre pour chacune des
classes:
static TVideoAffich * CreateFromFileVMRRenderer(const std::string &
path);
static TVideoAffich * CreateFromFileBasicRenderer(const std::string &
path);
static TVideoAffich * CreateFromSBEVMRRenderer(const std::string &
path);
etc...
Je voyais bien un truc du genre:
template <class Input>
class DS_InfosVideo : public Input
{
public:
DS_InfosVideo(const std::string & path);
};
template <class Input , class Renderer>
class TVideoAffich : public Input, public Renderer
{
private:
DS_InfosVideo<Input> * Infos;
DS_AffichVideo<Input,Renderer> * Affich;
public:
TVideoAffich(const std::string & path);
};
Seulement la classe Input passée à TVideoAffich n'est pas la même
que celle que doit recevoir DS_InfosVideo ni celle de DS_AffichVideo...
Est-ce que c'est possible de poser des conditions à la compilation, de
telle sorte qu'on ait un truc du genre:
pour TVideoAffich
si Input == VideoAffichInputFile
{
DS_InfosVideo<Infos_Input_File> * Infos;
si Renderer == VideoAffichVMRRenderer
DS_AffichVideo<Affich_Input_File,Affich_VMR_Renderer> * Affich;
sinon
DS_AffichVideo<Affich_Input_File,Affich_Basic_Renderer> *
Affich;
}
sinon
{
///
}
Voilà tout :)
Merci d'avance
Mike |
|
| Back to top |
|
 |
Fabien LE LEZ Guest
|
Posted: Fri Jun 16, 2006 6:26 pm Post subject: Re: Problème de design |
|
|
On 16 Jun 2006 05:40:38 -0700,
Problème logiciel ? Ton nom est passé à la trappe :-(
<michael.delva (AT) gmail (DOT) com>:
| Quote: | J'ai créé trois classes qui me permettent d'afficher de la vidéo
grâce à DirectShow.
|
Tel que je comprends le truc, tu as trois types de classe :
- une classe "Source" (dans laquelle on va chercher la vidéo)
- une classe "Destination" (on lui envoie les pixels, et elle s'occupe
de les afficher à l'écran)
- une classe qui chapeaute le tout.
La solution me paraît évidente (mais il est possible que j'aie oublié
un détail) : deux hiérarchies de classes.
class Source
{
public:
virtual Pixels GetPixels() const= 0;
};
class Source_FichierAvi: public Source
{
public:
virtual Pixels GetPixels() const; // implémentation
};
class Destination
{
public:
virtual void EnvoyerPixels (Pixels const&)= 0;
};
class Destination_Renderer1: public Destination
etc.
La classe "Chapeaute" aura alors un membre Source* (pointeur vers un
Source_quelque_chose) et un membre Destination*. |
|
| Back to top |
|
 |
Michael Guest
|
Posted: Fri Jun 16, 2006 8:24 pm Post subject: Re: Problème de design |
|
|
En fait ce n'est pas tout à fait ça...
La classe Infos se charge de récupérer les caractéristiques de la
source (largeur, hauteur, framerate, etc...), avec des fonctions
différentes selon la source.
La classe Affich se charge de connecter une source à une destination,
mais la manière de traiter la source est différente de la classe
Infos.
La classe qui chapeaute le tout se sert de Infos pour la taille de la
fenêtre, et de Affich pour afficher la vidéo sur cette même
fenêtre...
Ce que je veux, c'est pouvoir définir pour la classe qui chapeaute le
tout la manière dont Infos et Affich vont s'occuper de la source et de
l'affichage...
Donc:
VideoAffich<Basic,Fichier> t; entrainerait Infos<Fichier> et
Affich<Basic,Fichier>..
J'ai essayé de m'en sortir avec de la templatisation partielle:
class Infos_InputFile {}
class Affich_InputFile {}
class Affich_AffichVMR {}
class Affich_AffichBasic {}
class TVA_InputFichier {}
class TVA_InputXML {}
class TVA_RenderVMR {}
class TVA_RenderBasic {}
template <class Input , class Renderer>
class TVideoAffich
{
private:
typedef Infos<Input> infos;
typedef Affich<Input,Render> affich;
infos i;
affich a:
public:
TVideoAffich();
void SetPosition(const int position) { // }
};
et en spécialisant pour chacune des solutions possibles
template <>
class TVideoAffich<TVA_InputFile,TVA_RenderBasic>
{
private:
typedef Infos<Infos_InputFile> infos;
typedef Affich<Affich_InputFile,Affich_RenderBasic> affich;
infos i;
affich a:
public:
TVideoAffich();
};
Mais si je fais par exemple:
typedef TVideoAffich<TVA_InputFile,TVA_RenderBasic> toto;
toto t;
t.SetPOsition( ;
ça ne marche pas parce que SetPOsition n'est pas définie pour la
spécialisation utilisée...
Sinon, plutôt que de passer une classe comme paramètre template, je
pensais passer un entier issu d'une énumération, et en fonction de la
valeur de cette enum utiliser derrière les bons template...
du genre:
enum InputType { File , XML , XBE };
enum RendererType { VMR , Basic };
template <InputType input, RendererType render>
class TVideoAffich
{
private:
typedef Infos<input> infos;
typedef Affich<input,render> affich;
infos i;
affich a;
public:
//.....
};
Et pour Infos par exemple:
template<int Input>
class Infos
{
};
Et là je bloque: comment changer le comportement de Infos en fonction
de la valeur de l'énumération, et de préférence à la compilation?
La spécialisation fonctionne comme ça:
template<>
class Infos<0>
{
//File
};
template<>
class Infos<1>
{
//XML
};
Après, peut-être tout simplement que les template ne sont pas la
solution, mais je ne vois pas comment faire dans ce cas...
J''espère avoir été clair  |
|
| Back to top |
|
 |
Sylvain Togni Guest
|
Posted: Fri Jun 16, 2006 8:56 pm Post subject: Re: Problème de design |
|
|
Michael a écrit :
| Quote: | Après, peut-être tout simplement que les template ne sont pas la
solution, mais je ne vois pas comment faire dans ce cas...
|
Il y a deux principaux types de polymorphisme :
- Le polymorphisme statique (templates, surchage, ...).
Le comportement est choisi *pendant la compilation* et
reste donc fixe pendant l'exécution.
- Le polymorphisme dynamique (fonctions virtuelles, ...)
Le comportement est choisi *pendant l'exécution*.
Je n'ai pas tout compris, mais il me semble que c'est plutôt
le second qui répond à tes besoins.
--
Sylvain Togni |
|
| Back to top |
|
 |
Fabien LE LEZ Guest
|
Posted: Fri Jun 16, 2006 9:29 pm Post subject: Re: Problème de design |
|
|
On 16 Jun 2006 08:24:48 -0700, "Michael" <michael.delva (AT) gmail (DOT) com>:
| Quote: | La classe Infos se charge de récupérer les caractéristiques de la
source (largeur, hauteur, framerate, etc...), avec des fonctions
différentes selon la source.
|
Si les fonctions ont des noms différents mais des fonctionnalités
identiques (ou suffisamment proches), il faut créer un adaptateur.
Tu commences par définir une interface pour la classe abstraite
Source :
class Source
{
public:
Taille GetTailleImage() const= 0;
};
Ensuite, tu l'implémentes, en appelant les fonctions qui vont bien.
J'ai pris l'exemple de deux classes, FichierAVI et FichierXML issues
de deux bibliothèques (fictives) différentes, et ayant des façons
différentes de donner la taille de l'image :
class Source_Avi: public Source
{
public:
Taille GetTailleImage() const
{
return Taille (fichier_avi.GetLargeur(),
fichier_avi.GetHauteur());
}
private:
FichierAVI fichier_avi;
};
class Source_XML: public Source
{
public:
Taille GetTailleImage() const
{
Taille reponse;
if (fichier_xml.ObtenirTaille (reponse))
{
return reponse;
}
else
{
throw quelque_chose;
}
}
private:
FichierXML fichier_xml;
}; |
|
| Back to top |
|
 |
Fabien LE LEZ Guest
|
Posted: Fri Jun 16, 2006 9:30 pm Post subject: Re: Problème de design |
|
|
On 16 Jun 2006 08:24:48 -0700, "Michael" <michael.delva (AT) gmail (DOT) com>:
| Quote: | Après, peut-être tout simplement que les template ne sont pas la
solution
|
C'était implicite dans le message auquel tu réponds
(<news:tub59216lj1gtun3b7p5e5221j840jq32h (AT) 4ax (DOT) com>). |
|
| Back to top |
|
 |
Fabien LE LEZ Guest
|
Posted: Fri Jun 16, 2006 9:52 pm Post subject: Re: Problème de design |
|
|
On 16 Jun 2006 08:24:48 -0700, "Michael" <michael.delva (AT) gmail (DOT) com>:
| Quote: | Après, peut-être tout simplement que les template ne sont pas la
solution
|
Les templates peuvent éventuellement remplacer le polymorphisme
d'héritage (même si ça ne me paraît pas conseillé dans cette situation
précise).
Par contre, il me semble que les spécialisations de templates n'ont
rien à faire ici. |
|
| Back to top |
|
 |
Michael Guest
|
Posted: Sat Jun 17, 2006 12:08 am Post subject: Re: Problème de design |
|
|
J'ai bien sûr déjà pensé à l'héritage, mais ça me pose un
problème:
pour le moment j'ai uniquement le paramètre Input qui varie, parce que
j'ai un seul Renderer défini.
Donc j'ai les classes:
class InfosVideo;
class InfosVideo_XML : public : InfosVideo;
class InfosVideo_FileL : public : InfosVideo;
class InfosVideo_SBE : public : InfosVideo;
class AffichVideo;
class AffichVideo_XML : public : AffichVideo;
class AffichVideo_FileL : public : AffichVideo;
class AffichVideo_SBE : public : AffichVideo;
ce qui ne me pose pas vraiment de soucis.
Mais je compte proposer un renderer de plus. Ca ne change rien aux
classes InfosVideo et dérivées, mais du coup ça multiplie le nombre
de classes AffichVideo par 2!
class AffichVideo_XML_VMR : public : AffichVideo;
class AffichVideo_XML_Overlay : public : AffichVideo;
etc...
Et donc si on ajoute encore des options, ça devient vite ingérable...
J'avais donc pensé aux templates pour faire quelque chose comme les
policies.
On a une classe de départ, et on change 2 paramètres template pour
définir de quel type est le fichier d'entrée, et grâce à quel
renderer il va s'afficher.
On passe donc ces deux paramètres à la classe qui englobe InfosVideo
et AffichVideo, qui elle se charge derrière de les instancier avec les
bons paramètres template, propres à chacune. (Le paramètre Input de
AffichVideo n'est pas le même que celui de InfosVideo)...
Il serait possible je pense de faire un truc du genre:
template <class InputTypeInfos , class InputTypeAffich, class
RenderType>
class Global
{
private:
Infos<InputTypeInfos> i;
Affich<InputTypeAffich,RenderType> a;
//...
}
Mais j'aimerai éviter la redondance entre InputTypeInfos et
InputTypeAffich qui indiquent tous les deux qu'il s'agit de le même
entrée...
J'avoue ne pas vraiment voir de solution à base de template, sûrement
parce que je ne maitrise pas encore vraiment.
Mais une solution à base de polymorphisme me semble compliquée
également... |
|
| Back to top |
|
 |
Jean-Marc Bourguet Guest
|
Posted: Sat Jun 17, 2006 1:07 am Post subject: Re: Probleme de design |
|
|
"Michael" <michael.delva (AT) gmail (DOT) com> writes:
| Quote: | Mais une solution à base de polymorphisme me semble compliquée
également...
|
Si je comprends bien ton problème, tu oublies que
l'interface de InfosVideo doit suffire à un descendant de
AffichVideo pour fonctioner. Donc il y a simplement autant
de descendants de AffichVideo qu'il y a de renderer, autant
de descendants de InfosVideo qu'il y a de format de fichier.
A+
--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org |
|
| Back to top |
|
 |
Fabien LE LEZ Guest
|
Posted: Sat Jun 17, 2006 1:14 am Post subject: Re: Problème de design |
|
|
On 16 Jun 2006 12:08:43 -0700, "Michael" <michael.delva (AT) gmail (DOT) com>:
| Quote: | class AffichVideo_XML_VMR : public : AffichVideo;
class AffichVideo_XML_Overlay : public : AffichVideo;
|
Il y a à mon avis une erreur ici : tu as mélangé deux classes dans une
seule.
"XML", c'est la source.
"VMR" ou "Overlay", c'est la destination.
J'ai l'impression que tu as séparé deux éléments de "source" (i.e. la
lecture des pixels proprement dite, et la lecture des caractéristiques
de la vidéo, comme la taille), tout en mélangeant la source et la
destination des pixels dans la même classe.
C'est pour ça que je te conseille d'avoir deux hiérarchies séparées,
une regroupant tout ce qui concerne la source, et l'autre regroupant
tout ce qui concerne la destination.
Ainsi, l'objet "Chapeau" sait qu'il a une source, qui lui donne des
pixels et des renseignements sur ces pixels, et une destination, qui
attend des pixels et quelques autres informations.
À aucun moment, l'objet "Chapeau" ne doit savoir ce que signifie "XML"
ou "Overlay" -- c'est pas son problème.
De plus, comme n'importe quelle source peut être mise en rapport avec
n'importe quelle destination (sans que la destination connaisse les
spécificités de la source), les types (Taille, Pixel, etc.) doivent
être unifiés. Du coup, l'utilisation de templates ne se justifie pas. |
|
| Back to top |
|
 |
Michael Guest
|
Posted: Sat Jun 17, 2006 2:28 am Post subject: Re: Problème de design |
|
|
J'ai du mal m'exprimer alors...
InfosVideo n'est pas une interface qu'on peut assimiler à une
source... Elle utilise des interfaces COM uniquement dédiées à la
récupération des infos d'une source vidéo.
Par contre AffichVideo est composée de deux "sous-objets": une source
(dont les interfaces COM sont différentes selon le type de la source :
XML, Fichier...) et un renderer, qui, peut-importe la source affiche le
rendu de cette source; Ce renderer peut lui aussi être de différents
types (VMR, Overlay, etc...)
Donc j'ai bien de multiples interfaces à gérer : Nbre sources dispos
* Nbre renderer dispos... |
|
| Back to top |
|
 |
Fabien LE LEZ Guest
|
Posted: Sat Jun 17, 2006 2:47 am Post subject: Re: Problème de design |
|
|
On 16 Jun 2006 14:28:17 -0700, "Michael" <michael.delva (AT) gmail (DOT) com>:
| Quote: | Elle utilise des interfaces COM
|
Hors-sujet. C'est un détail d'implémentation, et on parle ici de
design.
| Quote: | InfosVideo n'est pas une interface qu'on peut assimiler à une
source [...] récupération des infos d'une source vidéo.
Par contre AffichVideo est composée de deux "sous-objets": une source
(dont les interfaces COM sont différentes selon le type de la source :
XML, Fichier...) et un renderer, qui, peut-importe la source affiche le
rendu de cette source; Ce renderer peut lui aussi être de différents
types (VMR, Overlay, etc...)
|
Hé bien, tout va bien.
class Source { ... [cf mes autres messages] };
class Destination { ... [idem] };
class AffichVideo
{
Source* la_source;
Destination* la_destination;
};
class Source_XML: public Source
{
...
};
class Destination_Overlay: public Destination
{ ...
};
À aucun moment, AffichVideo ne doit savoir ce que "XML" ou "Overlay"
signifie.
Source et Destination contiennent des fonctions virtuelles pures.
Source_XML et ses potes implémentent ces fonctions, à grands coups de
COM et autres joyeusetés Win32. |
|
| Back to top |
|
 |
Sylvain Guest
|
Posted: Sat Jun 17, 2006 2:54 am Post subject: Re: Problème de design |
|
|
Michael wrote on 16/06/2006 21:08:
| Quote: |
Mais je compte proposer un renderer de plus. Ca ne change rien aux
classes InfosVideo et dérivées, mais du coup ça multiplie le nombre
de classes AffichVideo par 2!
|
qu'est-ce un renderer ici ?
je le comprends comme le machin DirectX (un IGraphBuilder) qui affiche
effectivement le flux construit à partir de la source (un
ISampleGrabber). il est de fait unique (sauf peut être subtilitées
avancées) dans l'architecture DX en tant qu'objet de rendu.
ce qui peut changer est plus facilement les 'filtres' appliquées à la
source; cela peut inclure du mixage, de la décompression hard, de la
conversion (entre standards TV par ex.).
partant, je pense que le lieu des éventuelles adaptations est plus entre
la source et le visualisateur, mais ni l'un, ni l'autre; la gestion des
ces filtres pluggables revient vient à 'chapeau' qui saura mettre bout à
bout des filtres entre ses 2 maillons.
Sylvain. |
|
| Back to top |
|
 |
Michael Guest
|
Posted: Mon Jun 19, 2006 10:21 pm Post subject: Re: Problème de design |
|
|
Bon, suivant vos conseils, j'en suis arrivé à ça:
class AV_Input
{
};
class AV_InputFile : public AV_Input
{
};
class AV_InputXML : public AV_Input
{
};
class AV_Renderer
{
};
class AV_RendererVMR : public AV_Renderer
{
};
class AV_RendererBasic : public AV_Renderer
{
};
class AffichVideo
{
private:
AV_Renderer * Renderer;
AV_Input * Input;
public:
AffichVideo(AV_Renderer * renderer, AV_Input * input)
: Renderer(renderer),Input(input)
{}
};
Ce qui m'oblige à l'utiliser comme ça:
AffichVideo * affich = new AffichVideo(new AV_RendererVMR(),new
AV_InputFile());
affich->toto();
Je suis un peu embêté avec les new...
J'aurais préféré, si c'est possible, utiliser une syntaxe comme celle-ci:
AffichVideo * affich = new AffichVideo(AV_RendererVMR(),AV_InputFile());
Et utiliser des références dans AffichVideo. Mais mes premiers essais ne
sont pas très concluants.
Mais je pense que je suis obligé avec le polymorphisme? |
|
| Back to top |
|
 |
Fabien LE LEZ Guest
|
Posted: Mon Jun 19, 2006 10:45 pm Post subject: Re: Problème de design |
|
|
On 19 Jun 2006 17:21:14 GMT, Michael <michael.at.gmail.dot.com>:
| Quote: | Ce qui m'oblige à l'utiliser comme ça:
AffichVideo * affich = new AffichVideo(new AV_RendererVMR(),new
AV_InputFile());
[...]
Je suis un peu embêté avec les new...
|
Les "new" de "AV_RendererVMR" et "AV_InputFile" font pendant au "new"
de "AffichVideo".
Tu aurais pu écrire :
AV_RendererVMR mon_renderer;
AV_InputFile mon_input;
AffichVideo afficheur (&mon_renderer, &mon_input);
| Quote: | J'aurais préféré, si c'est possible, utiliser une syntaxe comme celle-ci:
AffichVideo * affich = new AffichVideo(AV_RendererVMR(),AV_InputFile());
|
Sauf que l'objet "AV_RendererVMR" est détruit à la fin de la ligne...
| Quote: | Et utiliser des références dans AffichVideo.
|
Ça, tu peux :
class AffichVideo
{
private:
AV_Renderer& renderer;
AV_Input const& input;
public:
AffichVideo(AV_Renderer& renderer_, AV_Input const& input_)
: renderer(renderer_),input(input_)
{}
Mais ça ne change rien au problème de durée de vie.
| Quote: | Mais je pense que je suis obligé avec le polymorphisme?
|
Tu as une alternative :
template <class Input, class Renderer> class AffichVideo
{
private:
Renderer renderer;
Input input;
....
};
Tu passes alors d'un polymorphisme d'héritage à un polymorphisme de
templates.
AMHA, ça ne se justifie pas ici, mais c'est une solution qui existe. |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|