From pouchintv-dev at baysse.fr Fri Jul 3 00:33:00 2009 From: pouchintv-dev at baysse.fr (=?iso-8859-1?q?Liste_utilis=E9e_par_les_d=E9veloppeurs?=) Date: Thu, 02 Jul 2009 22:33:00 -0000 Subject: [Pouchintv-dev] [PouchinTVMod] gingko | r193 - trunk Message-ID: <20090702223243.842565F1D6@mail.baysse.fr> Author: gingko Date: 2009-07-03 00:32:42 +0200 (ven 03 jui 2009) New Revision: 193 Modified: trunk/capture.cpp trunk/capture.h trunk/channels.cpp trunk/channels.h trunk/grabber.cpp trunk/grabber.h trunk/graph.h trunk/ini.cpp trunk/ini.h trunk/main.cpp trunk/main.h trunk/record.cpp trunk/record.h trunk/recprog.cpp trunk/res.rc trunk/resource.h trunk/settings.cpp Log: Anticipation temporisée au changement de chaîne et de zoom. Davantage de choix pour la molette de la souris. main.cpp, main.h, channels.cpp, channels.h : * Implémentation d'une anticipation temporisée sur la sélection de chaînes au clavier ainsi qu'avec la molette de la souris : ces commandes n'ont maintenant plus pour effet immédiat que de faire défiler les noms des chaînes à l'affichage. Le changement effectif a lieu seulement après que l'utilisateur se fixe sur une chaîne sans changement pendant deux secondes (réduit à 500 mS si ni l'OSD, ni la barre d'état ne sont disponibles). * Implémentation d'une anticipation similaire (mais avec un délai plus court : 500 mS) pour les commandes de zoom. ini.h, ini.cpp, settings.cpp, main.cpp, res.rc, resource.h : * Ajout d'une sélection possible pour la molette de la souris, qui consiste à ne faire défiler que les chaînes de multiplex (à l'image de ce qui existait déjà si un enregistrement est en cours) * Ajout d'une option pour inverser le sens des commandes données par cette molette. * Ajout de commandes de menu virtuel (car pas de menu réel correspondant) pour ce défilement de chaînes du multiplex. En particulier, cela permet de définir des raccourcis clavier correspondants. capture.h, capture.cpp, main.cpp, record.h, record.cpp, recprog.cpp : * Changement de nom de plusieurs variables dont le nom était basé sur "grab" (pour "grabber"), alors que ce terme devrait se limiter au filtre qui permet de récupérer les échantillons à enregistrer. Les nouveaux noms sont donc maintenant basés sur la notion de "descripteur d'enregistrement" ou de "capture", selon le cas. En particulier, toutes les variables qui sont en fait des index de descripteur d'enregistrement sont renommées de "grab" (le plus souvent) en "ixRecDescr". record.h, record.cpp : * Factorisation supplémentaire pour les fonctions qui démarrent les enregistrements. graph.h, grabber.h, grabber.cpp : * Changements mineurs ou de commentaires Modifié: trunk/capture.cpp =================================================================== --- trunk/capture.cpp 2009-06-28 00:28:13 UTC (rev 192) +++ trunk/capture.cpp 2009-07-02 22:32:42 UTC (rev 193) @@ -163,7 +163,7 @@ PS_chunk::PS_chunk(const PS_hdr_wd & hdr, PS_buffer & cBuff) : src_hdr(hdr), - cGrabber(*cBuff.pcGrab), + cGrabber(*cBuff.pCapt), ixBuf(0), p_curPES(NULL) { @@ -363,7 +363,7 @@ // ************************************************************ PS_buffer::PS_buffer(UINT16 used_pid, UINT8 maxChnk IF_CONSOLE_CB(LPCSTR nom_dbg)) : - pcGrab(NULL), + pCapt(NULL), IF_CONSOLE_CA(nom_debug(nom_dbg)) pid(used_pid), valid(false), @@ -396,7 +396,7 @@ } if (new_PES_starts_here) { - if (pcGrab->capt_state >= cs_stopping) { + if (pCapt->capt_state >= cs_stopping) { flush(); valid = false; } else @@ -410,7 +410,7 @@ return; // on l'ignore, et le test de continuité sera faux au prochain passage. // Paquet valide et "Payload" présent - pcGrab->byte_count += ptr_size; + pCapt->byte_count += ptr_size; put_data(uw_th.p_payload, ptr_size, new_PES_starts_here); } @@ -434,7 +434,7 @@ start = false; } - pcGrab->byte_count += added_bytes; + pCapt->byte_count += added_bytes; } CCapture_PS::CCapture_PS(HANDLE hFil, UINT16 video, UINT16 audio) : @@ -452,8 +452,8 @@ video_build(video, 128 IF_CONSOLE_CB("la vidéo")), audio_build(audio, 32 IF_CONSOLE_CB("le son")) { - video_build.pcGrab = this; - audio_build.pcGrab = this; + video_build.pCapt = this; + audio_build.pCapt = this; if (fichier_valide()) { capt_state = cs_started; } else Modifié: trunk/capture.h =================================================================== --- trunk/capture.h 2009-06-28 00:28:13 UTC (rev 192) +++ trunk/capture.h 2009-07-02 22:32:42 UTC (rev 193) @@ -76,7 +76,7 @@ friend class CCapture_PS; friend class PS_chunk; - CCapture_PS * pcGrab; + CCapture_PS * pCapt; IF_CONSOLE(LPCSTR nom_debug;) UINT16 pid; bool valid; Modifié: trunk/channels.cpp =================================================================== --- trunk/channels.cpp 2009-06-28 00:28:13 UTC (rev 192) +++ trunk/channels.cpp 2009-07-02 22:32:42 UTC (rev 193) @@ -37,10 +37,13 @@ /// Tableau des chaînes Chaines Canaux; -int ixChaineCourante = -1; //!< Index de la chaîne couramment utilisée -int ixSonCourant = 0; //!< Index de la piste sonore couramment utilisée -bool suspendu = true; //!< \p true si vidéo et audio suspendus (à l'initialisation, - //!< ou si minimisé + \p suspend_minimized) +int ixChaineCourante = -1; //!< Index de la chaîne couramment utilisée +int ixChaineAvance = -1; /*!< Index de la chaîne pendant les transitions de zapping + (normalement identique à \p ixChaineCourante, sauf entre la + sélection d'une chaîne et l'application de cette sélection) */ +int ixSonCourant = 0; //!< Index de la piste sonore couramment utilisée +bool suspendu = true; //!< \p true si vidéo et audio suspendus (à l'initialisation, + //!< ou si minimisé + \p suspend_minimized) // Taille des images des chaînes (largeur et longueur) #define TAILLE_IMAGE_CHAINE 16 @@ -683,6 +686,7 @@ change_frequence(nouveau_canal.khz); ixChaineCourante = ixChaine_ok(ixChaine) ? ixChaine : -1; + ixChaineAvance = ixChaineCourante; // Ne reconnecter l'interface que si elle l'était avant : if (!sauve_suspend) Modifié: trunk/channels.h =================================================================== --- trunk/channels.h 2009-06-28 00:28:13 UTC (rev 192) +++ trunk/channels.h 2009-07-02 22:32:42 UTC (rev 193) @@ -271,6 +271,10 @@ extern Chaines Canaux; extern int ixChaineCourante; //!< Index de la chaîne couramment utilisée +extern int ixChaineAvance; /*!< Index de la chaîne pendant les transitions de zapping + (normalement identique à \p ixChaineCourante, sauf entre la + sélection d'une chaîne et l'application de cette sélection) */ + extern int ixSonCourant; //!< Index de la piste sonore couramment utilisée extern bool suspendu; //!< \p true si vidéo et audio suspendus (à l'initialisation, //!< ou si minimisé + \p suspend_minimized) Modifié: trunk/grabber.cpp =================================================================== --- trunk/grabber.cpp 2009-06-28 00:28:13 UTC (rev 192) +++ trunk/grabber.cpp 2009-07-02 22:32:42 UTC (rev 193) @@ -64,7 +64,7 @@ * param[in] nSize Taille de l'échantillon * param[in] pPtr Pointeur sur les données de l'échantillon **/ -void CSampleGrabber::traite_sample(UINT32 nSize, const BYTE * pPtr) +void CSampleGrabber::traite_sample(size_t nSize, const BYTE * pPtr) { UINT32 i = 0; Modifié: trunk/grabber.h =================================================================== --- trunk/grabber.h 2009-06-28 00:28:13 UTC (rev 192) +++ trunk/grabber.h 2009-07-02 22:32:42 UTC (rev 193) @@ -83,7 +83,7 @@ * param[in] nSize Taille de l'échantillon * param[in] pPtr Pointeur sur les données de l'échantillon **/ - void traite_sample(UINT32 nSize, const BYTE * pPtr); + void traite_sample(size_t nSize, const BYTE * pPtr); /** * Traitement d'un paquet TS reçu du tuner (issu du découpage de l'échantillon, et même Modifié: trunk/graph.h =================================================================== --- trunk/graph.h 2009-06-28 00:28:13 UTC (rev 192) +++ trunk/graph.h 2009-07-02 22:32:42 UTC (rev 193) @@ -50,8 +50,8 @@ * quand elle l'est, puisqu'elle induit la possibilité que soient utilisés des * codecs qui n'ont pas été choisis en cas d'échec de ceux qui l'ont été. **/ -#define AUTO_RENDER 0 //!< Recherche automatique de filtres appropriés en - //!< cas d'échec de l'insertion du filtre initialement prévu +#define AUTO_RENDER 0 /*!< \brief Recherche automatique de filtres appropriés en + cas d'échec de l'insertion du filtre initialement prévu */ /** @} */ Modifié: trunk/ini.cpp =================================================================== --- trunk/ini.cpp 2009-06-28 00:28:13 UTC (rev 192) +++ trunk/ini.cpp 2009-07-02 22:32:42 UTC (rev 193) @@ -59,6 +59,8 @@ // Changement de chaînes {IDM_CHAN_AUG, TEXT("Chaîne suivante"), TEXT("Chaîne suiv"), {false, false, false, VK_DOWN}}, {IDM_CHAN_DIM, TEXT("Chaîne précédente"), TEXT("Chaîne préc"), {false, false, false, VK_UP}}, + {IDM_CHAN_AUG_MPX, TEXT("Chaîne suivante du multiplex"), TEXT("Chaîne suiv"), {true, false, false, VK_DOWN}}, + {IDM_CHAN_DIM_MPX, TEXT("Chaîne précédente du multiplex"), TEXT("Chaîne préc"), {true, false, false, VK_UP}}, {IDM_CHAN_TUNE, TEXT("Forcer une resyntonisation"), TEXT("Chaîne Resyntoniser"),{false, true, false, TEXT('F')}}, // EPG {IDM_EPG, TEXT("Guide des programmes"), TEXT("EPG Guide progs"), {false, false, false, TEXT('G')}}, @@ -171,6 +173,7 @@ bool use_multimedia = true; MouseWheelUsage role_molette = mwu_Channels; +bool inversion_molette = false; TCHAR motif_noms_enreg[MAX_PATH]; //!< Motifs pour les noms des enregistrements @@ -277,6 +280,7 @@ static TCHAR ini_volume[] = TEXT("Volume"); static TCHAR ini_use_multimedia[] = TEXT("Gérer les commandes multimédia"); static TCHAR ini_role_molette[] = TEXT("Molette de la souris"); +static TCHAR ini_inversion_molette[] = TEXT("Inversion du sens de la molette"); static TCHAR ini_motif_noms_enreg[] = TEXT("Nom du fichier d'enregistrement"); static TCHAR ini_position_fenetre[] = TEXT("Position fenêtre"); static TCHAR ini_use_vmr_deinterlace[] = TEXT("Utilise le désentrelacement du VMR"); @@ -444,14 +448,14 @@ * Tableau associatif décrivant les différents rôles possibles de la molette de la souris **/ AssocElement aMWheelTable[] = -{ // PanModes +{ // MouseWheelUsage {TEXT("Aucun"), (DWORD)mwu_None}, {TEXT("Chaînes"), (DWORD)mwu_Channels}, + {TEXT("Chaînes multiplex"), (DWORD)mwu_Channels_MX}, {TEXT("Volume"), (DWORD)mwu_Volume}, {TEXT("Zoom"), (DWORD)mvu_Zoom}, {NULL, 0} // -> terminateur }; - // ==================================================================================== // Raccourcis (clavier) // ==================================================================================== @@ -2047,6 +2051,7 @@ cConfig.save_int(ini_volume, volumeCourant); cConfig.save_bool(ini_use_multimedia, use_multimedia); cConfig.save_assoc(ini_role_molette, aMWheelTable, role_molette); + cConfig.save_bool(ini_inversion_molette, inversion_molette); if (epg_typerecvideo!=meth_multiplex) // On ne sauve pas le mode "enregistrement du multiplex" cConfig.save_assoc(ini_epg_typerecvideo, aEpgRecVideo, epg_typerecvideo); @@ -2395,6 +2400,7 @@ volumeCourant = cConfig.load_int(ini_volume, 100); use_multimedia = cConfig.load_bool(ini_use_multimedia, true); role_molette = (MouseWheelUsage)cConfig.load_assoc(ini_role_molette, aMWheelTable, mwu_Channels); + inversion_molette = cConfig.load_bool(ini_inversion_molette); epg_typerecvideo = (MethodeEnregistrement)cConfig.load_assoc(ini_epg_typerecvideo, aEpgRecVideo, meth_TS); epg_typerecaudio = (AudioMode)cConfig.load_assoc(ini_epg_typerecaudio, aEpgRecAudio, audio_1); Modifié: trunk/ini.h =================================================================== --- trunk/ini.h 2009-06-28 00:28:13 UTC (rev 192) +++ trunk/ini.h 2009-07-02 22:32:42 UTC (rev 193) @@ -128,6 +128,7 @@ enum MouseWheelUsage { mwu_None, //!< Aucun effet mwu_Channels, //!< Changer de chaîne + mwu_Channels_MX, //!< Changer de chaîne (même multiplex) mwu_Volume, //!< Régler le volume mvu_Zoom //!< Régler le zoom }; @@ -192,6 +193,7 @@ extern bool use_multimedia; //!< Utiliser les commandes multimédia extern MouseWheelUsage role_molette; //!< Rôle de la molette de la souris +extern bool inversion_molette; //!< Inversion du sens de la molette de la souris /** * Motif pour le nom des fichiers pour les enregistrements
Modifié: trunk/main.cpp
===================================================================
--- trunk/main.cpp 2009-06-28 00:28:13 UTC (rev 192)
+++ trunk/main.cpp 2009-07-02 22:32:42 UTC (rev 193)
@@ -91,6 +91,20 @@
/// Délai de persistance du curseur (pointeur souris) en mode plein écran :
#define DUREE_CURSEUR 3000 // Valeur en millisecondes
+/// Temps avant qu'une suite de numéros se traduise par un changement de chaîne
+#define DUREE_SAISIE 1000
+
+/// Temps avant qu'un zapping par rotation (clavier ou molette de la souris) se
+/// traduise par un changement de chaîne
+#define DUREE_ZAPPING 2000
+
+/// Temps avant qu'un zapping par rotation (clavier ou molette de la souris) se
+/// traduise par un changement de chaîne, si pas d'OSD ni de barre d'état
+#define DUREE_ZAPPING_NOAFF 500
+
+/// Temps avant application d'un changement de zoom
+#define DUREE_ZOOM 500
+
/// Délai d'attente avant affichage des informations OSD de la chaîne, une fois qu'on
/// a changé de chaîne
#define DUREE_SHOW_PROGRAMME 2500
@@ -364,9 +378,9 @@
return -1;
}
-static void formate_menu_chaine_nom(int ixGrabber, LPCTSTR prefixe, LPTSTR pstr, size_t bufSize)
+static void formate_menu_chaine_nom(int ixRecDescr, LPCTSTR prefixe, LPTSTR pstr, size_t bufSize)
{
- LPCSTR nom = enregistrements_actuels[ixGrabber].channelName();
+ LPCSTR nom = enregistrements_actuels[ixRecDescr].channelName();
if (*nom=='*')
_stprintf_s(pstr, bufSize, TEXT("%s du multiplex"), prefixe);
@@ -377,16 +391,16 @@
static void update_menu_recording(HMENU hMenu)
{
HMENU hRecMenu = GetSubMenu(hMenu, MENU_CAPTURES_POSITION);
- int ixGrabber = enregistrements_actuels.getGrabberChaine(ixChaineCourante);
- bool curChannelRecording = ixGrabber != -1;
- bool freeGrabberAvailable = enregistrements_actuels.getFreeGrabber() != -1;
- bool isMpeg2 = ixChaine_ok(ixChaineCourante) && Canaux[ixChaineCourante].video_type==vst_MPEG2;
- bool active;
+ int ixRecDescr = enregistrements_actuels.getRecordingDescr(ixChaineCourante);
+ bool curChannelRecording = ixRecDescr != -1;
+ bool bFreeRecAvailable = enregistrements_actuels.getFreeDescriptor() != -1;
+ bool isMpeg2 = ixChaine_ok(ixChaineCourante) && Canaux[ixChaineCourante].video_type==vst_MPEG2;
+ bool active;
// Items d'enregistrement de la chaîne courante : ces items sont actifs
// si la chaîne courante n'est pas déjà en cours d'enregistrement, et si
// le nombre maximal de chaînes enregistrées n'est pas atteint.
- active = freeGrabberAvailable && !curChannelRecording;
+ active = bFreeRecAvailable && !curChannelRecording;
set_menu_enable_state(hRecMenu, IDM_RECORD_CHANNEL_PS, active && isMpeg2);
set_menu_enable_state(hRecMenu, IDM_RECORD_CHANNEL_TS, active);
@@ -403,7 +417,7 @@
"Enregistrer le &multiplex");
}
set_menu_enable_state(hRecMenu, IDM_RECORD_STREAM,
- freeGrabberAvailable && enregistrements_actuels.getGrabberChaine(STREAM_PSEUDO_INDEX)==-1);
+ bFreeRecAvailable && enregistrements_actuels.getRecordingDescr(STREAM_PSEUDO_INDEX)==-1);
} else
DeleteMenu(hRecMenu, IDM_RECORD_STREAM, MF_BYCOMMAND);
@@ -424,7 +438,7 @@
if (enreg.recording()) {
active = true; // Au moins en enregistrement en cours
// Ce poste correspond à une chaîne en cours d'enregistrement.
- if (i==ixGrabber)
+ if (i==ixRecDescr)
continue; // ... mais il s'agit de la chaîne courante
// Enregistrement sur une autre chaîne que la chaîne en cours :
@@ -921,24 +935,17 @@
}
}
-static void update_status_bar()
+/// Copie les informations d'une chaîne dans la barre d'état, si elle existe
+static void set_chaine_status(const Chaine & canal)
{
- if (!ixChaine_ok(ixChaineCourante))
- return;
-
- const Chaine & canal_courant = Canaux[ixChaineCourante];
-
- if (use_osd)
- RedrawWindow(hMainWnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE);
-
if (hMainStatus != NULL) {
TCHAR str[40];
- strcpy_T(str, canal_courant.nom);
+ strcpy_T(str, canal.nom);
SendMessage(hMainStatus, SB_SETTEXT, 0, (LPARAM)str);
- for (int nEmis=0; nEmis<_countof(canal_courant.emis); nEmis++) {
- const Emission & emis = canal_courant.emis[nEmis];
+ for (int nEmis=0; nEmis<_countof(canal.emis); nEmis++) {
+ const Emission & emis = canal.emis[nEmis];
str[0] = 0;
if (emis.isOk())
@@ -946,11 +953,26 @@
SendMessage(hMainStatus, SB_SETTEXT, nEmis*2+1, (LPARAM)str);
SendMessage(hMainStatus, SB_SETTEXT, nEmis*2+2, (LPARAM)(emis.getName()));
}
+ }
+}
- if (!use_osd) {
- _stprintf_s(str, TEXT("%s %i"), muted ? TEXT("Sourdine") : TEXT("Volume"), volumeCourant);
- SendMessage(hMainStatus, SB_SETTEXT, 5, (LPARAM)str);
- }
+static void update_status_bar()
+{
+ if (!ixChaine_ok(ixChaineCourante))
+ return;
+
+ if (use_osd)
+ RedrawWindow(hMainWnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE);
+
+ const Chaine & canal_courant = Canaux[ixChaineCourante];
+
+ set_chaine_status(canal_courant);
+
+ if (hMainStatus != NULL && !use_osd) {
+ TCHAR str[16];
+
+ _stprintf_s(str, TEXT("%s %i"), muted ? TEXT("Sourdine") : TEXT("Volume"), volumeCourant);
+ SendMessage(hMainStatus, SB_SETTEXT, 5, (LPARAM)str);
}
#ifdef USE_LOGITECH_LCD
@@ -1231,7 +1253,7 @@
numeroChaineSaisi = (numeroChaineSaisi * 10 + (WORD)nb) % 1000;
// (modulo 1000 au cas où il y aurait trop de chiffres)
- SetTimer(hMainWnd, TIMER_NUMBER, 1000, NULL);
+ SetTimer(hMainWnd, TIMER_NUMBER, DUREE_SAISIE, NULL);
if (pOSD)
pOSD->DisplayChannelNumber(numeroChaineSaisi);
@@ -1389,9 +1411,9 @@
change_etat_curseur(nouveau_curseur);
}
-static void mute()
+void SetMute(bool bMute)
{
- muted = !muted;
+ muted = bMute;
#ifdef USE_LOGITECH_LCD
lcd.Mute(muted);
#endif // #ifdef USE_LOGITECH_LCD
@@ -1418,27 +1440,43 @@
pOSD->DisplayVolume(volumeCourant);
}
-static void chaine_avance(int pas) // pas = 1 ou -1
+/**
+ * Changement de chaîne par rotation
+ * \param[in] pas Sens de la progression
+ * \param[in] bInMultiplex Si \p true, on reste dans le même multiplex
+ **/
+static void chaine_avance(int pas, bool bInMultiplex=false) // pas = 1 ou -1
{
- if (ixChaine_ok(ixChaineCourante)) {
+ if (ixChaine_ok(ixChaineAvance)) {
int nbChaines = (int)Canaux.size();
- bool enregistre = enregistrements_actuels.recording()!=0;
- INT32 freq_courante = Canaux[ixChaineCourante].khz;
+ INT32 freq_courante = Canaux[ixChaineAvance].khz;
- for (int i = ixChaineCourante ;; ) {
- i = (i+nbChaines+pas)%nbChaines;
- if (i==ixChaineCourante)
- break;
+ // Si enregistrement en cours, on reste dans le même multiplex
+ if (enregistrements_actuels.recording()!=0)
+ bInMultiplex = true;
- const Chaine & canal = Canaux[i];
+ for (int ixTmp=ixChaineAvance;;) {
+ ixChaineAvance = (ixChaineAvance+nbChaines+pas)%nbChaines;
+ if (ixTmp==ixChaineAvance)
+ break; // Protection contre boucle infinie
+ const Chaine & canal = Canaux[ixChaineAvance];
+
if (canal.etat != ec_preferee)
continue; // On ne retient que les chaînes "préférées"
- if (enregistre && canal.khz != freq_courante) {
+ if (bInMultiplex && canal.khz != freq_courante) {
// Si enregistrement, la chaîne doit avoir la même fréquence
continue;
}
- zappe_index(i);
+
+ numeroChaineSaisi = canal.nNumeroChaine;
+
+ SetTimer(hMainWnd, TIMER_NUMBER,
+ pOSD || hMainStatus ? DUREE_ZAPPING : DUREE_ZAPPING_NOAFF, NULL);
+
+ if (pOSD)
+ pOSD->DisplayChannelInfo(canal);
+ set_chaine_status(canal);
break;
}
}
@@ -1456,6 +1494,10 @@
if (!ixChaine_ok(ixChaine))
return;
+ // ... et ne pas être identique à la chaîne courante :
+ if (ixChaine==ixChaineCourante)
+ return;
+
// Si enregistrement en cours, ne changer de chaîne que si on ne change pas de multiplex :
if (enregistrements_actuels.recording()!=0 && Canaux[ixChaine].khz != Canaux[ixChaineCourante].khz)
return;
@@ -1463,6 +1505,26 @@
zappe_index(ixChaine);
}
+static void change_zoom(bool bInc)
+{
+ #define ZOOM_STEP 2
+
+ if (bInc) {
+ zoom_ratio += (ZOOM_STEP - (zoom_ratio % ZOOM_STEP));
+
+ if (zoom_ratio > 200)
+ zoom_ratio = 200;
+ } else {
+ zoom_ratio -= (ZOOM_STEP + (zoom_ratio % ZOOM_STEP));
+ if (zoom_ratio <= 0)
+ zoom_ratio = 1;
+ }
+ update_menus(hMainWnd, 1, update_aspect_menus);
+ if (pOSD)
+ pOSD->DisplayZoom(zoom_ratio);
+ SetTimer(hMainWnd, TIMER_ZOOM, DUREE_ZOOM, NULL);
+}
+
/**
* Déplace la fenêtre de PTVM (si celle-ci n'est pas en plein écran) quand on maintient enfoncé le bouton de la souris
*
@@ -1574,7 +1636,7 @@
static void do_command(WORD wID, LPARAM lParam)
{
- int grab;
+ int ixRecDescr;
switch (wID) {
case IDM_QUIT:
@@ -1659,23 +1721,11 @@
break;
case IDM_ZOOM:
- zoom_ratio++;
- if (zoom_ratio > 200)
- zoom_ratio = 200;
- update_menus(hMainWnd, 1, update_aspect_menus);
- update_coords();
- if (pOSD)
- pOSD->DisplayZoom(zoom_ratio);
+ change_zoom(true);
break;
case IDM_DEZOOM:
- zoom_ratio--;
- if (zoom_ratio <= 0)
- zoom_ratio = 1;
- update_menus(hMainWnd, 1, update_aspect_menus);
- update_coords();
- if (pOSD)
- pOSD->DisplayZoom(zoom_ratio);
+ change_zoom(false);
break;
case IDM_DEFAULT_ZOOM:
@@ -1713,7 +1763,7 @@
case IDM_RECORD_CHANNEL_TS:
// On regarde si la chaîne n'est pas déjà en cours d'enregistrement
- if (enregistrements_actuels.getGrabberChaine(ixChaineCourante) != -1)
+ if (enregistrements_actuels.getRecordingDescr(ixChaineCourante) != -1)
// Chaîne déjà en cours d'enregistrement
break;
if (enregistrements_actuels.start_record_ts(ixChaineCourante)>=0)
@@ -1722,7 +1772,7 @@
case IDM_RECORD_CHANNEL_PS:
// On regarde si la chaîne n'est pas déjà en cours d'enregistrement
- if (enregistrements_actuels.getGrabberChaine(ixChaineCourante) != -1)
+ if (enregistrements_actuels.getRecordingDescr(ixChaineCourante) != -1)
// Chaîne déjà en cours d'enregistrement
break;
if (enregistrements_actuels.start_record_ps(ixChaineCourante, ixSonCourant)>=0)
@@ -1735,9 +1785,9 @@
break;
case IDM_STOP_RECORD:
- grab = enregistrements_actuels.getGrabberChaine(ixChaineCourante);
- if (grab>=0) {
- enregistrements_actuels[grab].stop(epr_interrompu);
+ ixRecDescr = enregistrements_actuels.getRecordingDescr(ixChaineCourante);
+ if (ixRecDescr>=0) {
+ enregistrements_actuels[ixRecDescr].stop(epr_interrompu);
update_record_menus(hMainWnd);
}
break;
@@ -1765,7 +1815,7 @@
break; }
case IDM_MUTE:
- mute();
+ SetMute(!muted);
if (!use_osd)
update_status_bar();
break;
@@ -1860,14 +1910,22 @@
chaine_avance(-1);
break;
- case IDM_UPDATE:
- do_web_update(hMainWnd);
+ case IDM_CHAN_DIM_MPX:
+ chaine_avance(-1, true);
break;
case IDM_CHAN_AUG:
chaine_avance(1);
break;
+ case IDM_CHAN_AUG_MPX:
+ chaine_avance(1, true);
+ break;
+
+ case IDM_UPDATE:
+ do_web_update(hMainWnd);
+ break;
+
#ifdef _DEBUG
case IDM_GRAPH_STATE:
display_graph_state();
@@ -1941,6 +1999,11 @@
chaine_saisie();
break;
+ case TIMER_ZOOM:
+ KillTimer(hMainWnd, TIMER_ZOOM);
+ update_coords();
+ break;
+
case TIMER_BORDER:
// Gestion du timer qui permet, lors d'un clic sur l'écran, de distinguer entre le passage en plein
// écran et l'activation / désactivation des bordures de fenêtre.
@@ -2196,20 +2259,32 @@
case WM_MOUSEWHEEL: {
short zDelta = GET_WHEEL_DELTA_WPARAM(wParam);
WORD wID = 0;
+ bool bIncr = false;
- if (zDelta >= WHEEL_DELTA) {
+ if (zDelta >= WHEEL_DELTA)
+ bIncr = true;
+ else if (zDelta > -WHEEL_DELTA)
+ break;
+
+ if (inversion_molette)
+ bIncr = ! bIncr;
+
+ if (bIncr) {
switch (role_molette) {
- case mwu_Channels: wID = IDM_CHAN_DIM; break;
- case mwu_Volume: wID = IDM_VOL_AUG; break;
- case mvu_Zoom: wID = IDM_ZOOM;
+ case mwu_Channels: wID = IDM_CHAN_AUG; break;
+ case mwu_Channels_MX: wID = IDM_CHAN_AUG_MPX; break;
+ case mwu_Volume: wID = IDM_VOL_AUG; break;
+ case mvu_Zoom: wID = IDM_ZOOM;
}
- } else if (zDelta <= -WHEEL_DELTA) {
+ } else {
switch (role_molette) {
- case mwu_Channels: wID = IDM_CHAN_AUG; break;
- case mwu_Volume: wID = IDM_VOL_DIM; break;
- case mvu_Zoom: wID = IDM_DEZOOM;
+ case mwu_Channels: wID = IDM_CHAN_DIM; break;
+ case mwu_Channels_MX: wID = IDM_CHAN_DIM_MPX; break;
+ case mwu_Volume: wID = IDM_VOL_DIM; break;
+ case mvu_Zoom: wID = IDM_DEZOOM;
}
}
+
if (wID)
PostMessage(hWnd, WM_COMMAND, wID, 0);
break; }
Modifié: trunk/main.h
===================================================================
--- trunk/main.h 2009-06-28 00:28:13 UTC (rev 192)
+++ trunk/main.h 2009-07-02 22:32:42 UTC (rev 193)
@@ -67,6 +67,7 @@
#define TIMER_CHAN_LVDRAG 133 //!< Cadencement du scrolling de la réorganisation des chaînes
#define TIMER_NOTIFY_UPDATE 134 //!< Auto-mise à jour du tooltip de l'icône de notification et du message MSN
#define TIMER_ZAPPING2 135 //!< Comme #TIMER_ZAPPING, mais 2ème essai
+#define TIMER_ZOOM 136 //!< Temps avant application d'un changement de zoom
/** @} */ // fin de TIMER_codes
Modifié: trunk/record.cpp
===================================================================
--- trunk/record.cpp 2009-06-28 00:28:13 UTC (rev 192)
+++ trunk/record.cpp 2009-07-02 22:32:42 UTC (rev 193)
@@ -35,37 +35,44 @@
#include "capture.h"
/**
- * Table des enregistrements d'émissions en cours de traitement
- * (parfois dénommés "grabbers" en raison de l'usage d'un filtre
- * "Sample grabber" pour chacun de ces enregistrements)
+ * Table des descripteurs d'enregistrements en cours de traitement
**/
Enregistrements enregistrements_actuels;
/**
* Démarrage d'un enregistrement.
- * \param[in] pGrabberCB Pointeur sur un objet dérivé de \p ISampleGrabberCB, implémentant les
- * méthode "callback" nécessaires à la récupération des échantillons
- * à enregistrer
+ * \param[in] pCapt Pointeur sur un objet dérivé de \p CCapture, implémentant les
+ * méthode de traitement des échantillons à enregistrer
* \param[in] ixChaine Index (dans la table #Canaux) de la chaîne à enregistrer, ou bien
* \p STREAM_PSEUDO_INDEX pour spécifier tout le multiplex
* \param[in] pProg Pointeur facultatif sur la programmation horaire ayant servi à démarrer
* l'enregistrement : s'il n'est pas \p NULL, des paramètres additionnels
* y sont récupérés
+ * \return \p true si succès, \p false si échec
**/
-void Enregistrement::start(ISampleGrabberCB * pGrabberCB, int ixChaine, Programme * pProg)
+bool Enregistrement::start(CCapture * pCapt, int ixChaine, Programme * pProg)
{
UINT32 cleCh = indexToCle(ixChaine);
stop(epr_interrompu); // précaution
- if (pSample && pGrabberCB && cleCh!=0) {
- if (pProg) {
- memcpy(this, pProg, sizeof(RecordInfo));
- pProg->etat = epr_encours;
- programmation_modifiee = true;
+ if (pSample && cleCh!=0) {
+ CSampleGrabber * pGrabberCB = new CSampleGrabber(pCapt);
+
+ if (pGrabberCB) {
+ if (pProg) {
+ memcpy(this, pProg, sizeof(RecordInfo));
+ pProg->etat = epr_encours;
+ programmation_modifiee = true;
+ }
+ pSample->SetCallback(pGrabberCB, 0);
+ cleChaine = cleCh;
+ return true;
}
- pSample->SetCallback(pGrabberCB, 0);
- cleChaine = cleCh;
}
+
+ // Si on arrive ici, c'est que la requête a échoué
+ delete pCapt; // Déstruction de l'objet de capture que l'on ne peut pas utiliser
+ return false;
}
/**
@@ -125,8 +132,8 @@
programmation_modifiee = true;
}
}
-
- pSample->SetCallback(NULL, 0);
+ pSample->SetCallback(NULL, 0); // Ceci appelle indirectement "CSampleGrabber::Release()",
+ // CSampleGrabber::StopThread() ainsi que "delete pCapture;"
}
nom[0] = 0;
@@ -222,13 +229,13 @@
/**
* Rechercher si une chaîne est en cours d'enregistrement,
- * et si oui, obtenir l'index des informations concernant cet enregistrement.
+ * et si oui, obtenir l'index du descripteur de cet enregistrement.
* \param[in] ixChaine Index (dans la table #Canaux) de la chaîne concernée, ou bien
* \p STREAM_PSEUDO_INDEX pour spécifier tout le multiplex courant
- * \retval Index de l'enregistrement ("grabber") dans la table des enregistrements en cours
+ * \retval Index du descripteur dans la table des descripteurs d'enregistrements en cours
* \retval -1 si la chaîne n'est pas en cours d'enregistrement.
**/
-int Enregistrements::getGrabberChaine(int ixChaine)
+int Enregistrements::getRecordingDescr(int ixChaine)
{
UINT32 cleChaine = indexToCle(ixChaine);
@@ -242,11 +249,11 @@
}
/**
- * Chercher un index d'enregistrement libre ("grabber")
- * \retval Index de l'enregistrement dans la table des enregistrements en cours
- * \retval -1 si tous les index possibles sont utilisés.
+ * Chercher un descripteur d'enregistrement libre
+ * \retval Index du descripteur dans la table des descripteurs d'enregistrements en cours
+ * \retval -1 si tous les descripteurs possibles sont utilisés.
**/
-int Enregistrements::getFreeGrabber()
+int Enregistrements::getFreeDescriptor()
{
for (int nInx=0; nInx < count(); nInx++) {
if (!cRecord[nInx].recording())
@@ -313,7 +320,7 @@
* \param[in] pProg Pointeur facultatif sur la programmation horaire ayant servi à démarrer
* l'enregistrement : s'il n'est pas \p NULL, des paramètres additionnels
* y sont récupérés
- * \retval Index de l'enregistrement ("grabber") dans la table des enregistrements en cours
+ * \retval Index du descripteur dans la table des descripteurs d'enregistrements en cours
* \retval -1 si aucun enregistrement n'a pu démarrer.
**/
int Enregistrements::start_record_ts(int ixChaine, Programme * pProg)
@@ -321,31 +328,30 @@
if (!ixChaine_ok(ixChaine))
return -1;
- int grab = getFreeGrabber();
- if (grab>=0) {
- const Chaine & canal = Canaux[ixChaine];
- NomFichierAvecDate nom_fichier(video_dir, getProgName(pProg), canal.nom, TEXT("ts"));
- UINT16 video = canal.video_pid ;
- CSampleGrabber * pGrabberCB = NULL;
- HANDLE hFile = nom_fichier.Create();
+ int ixRecDescr = getFreeDescriptor();
- if (hFile != INVALID_HANDLE_VALUE) {
- pGrabberCB =
- new CSampleGrabber(
- new CCapture_TS(hFile,
- canal.pmt_pid, video, canal.sons, canal.autr));
+ if (ixRecDescr < 0)
+ return -1;
- if (pGrabberCB!=NULL) {
- myprintf(TEXT("Enregistre TS, video=%i, pmt=%i\n"), video, canal.pmt_pid);
- cRecord[grab].start(pGrabberCB, ixChaine, pProg);
- }
- } else
- myprintf(TEXT("Erreur création '%s' code %u\n"), nom_fichier.nom, GetLastError());
+ const Chaine & canal = Canaux[ixChaine];
+ NomFichierAvecDate nom_fichier(video_dir, getProgName(pProg), canal.nom, TEXT("ts"));
+ UINT16 video = canal.video_pid ;
+ HANDLE hFile = nom_fichier.Create();
- if (pGrabberCB==NULL)
- return -1;
+ if (hFile == INVALID_HANDLE_VALUE) {
+ myprintf(TEXT("Erreur création '%s' code %u\n"), nom_fichier.nom, GetLastError());
+ return -1;
}
- return grab;
+
+ CCapture_TS * pCapture = new CCapture_TS(hFile, canal.pmt_pid,
+ video, canal.sons, canal.autr);
+
+ if (pCapture==NULL)
+ return -1;
+
+ myprintf(TEXT("Enregistre TS, video=%i, pmt=%i\n"), video, canal.pmt_pid);
+ cRecord[ixRecDescr].start(pCapture, ixChaine, pProg);
+ return ixRecDescr;
}
/**
@@ -356,7 +362,7 @@
* \param[in] pProg Pointeur facultatif sur la programmation horaire ayant servi à démarrer
* l'enregistrement : s'il n'est pas \p NULL, des paramètres additionnels
* y sont récupérés
- * \retval Index de l'enregistrement ("grabber") dans la table des enregistrements
+ * \retval Index du descripteur dans la table des descripteurs d'enregistrements en cours
* \retval -1 si aucun enregistrement n'a pu démarrer.
**/
int Enregistrements::start_record_ps(int ixChaine, int ixSon, Programme * pProg)
@@ -364,35 +370,34 @@
if (!ixChaine_ok(ixChaine))
return -1;
- int grab = getFreeGrabber();
- if (grab>=0) {
- const Chaine & canal = Canaux[ixChaine];
+ int ixRecDescr = getFreeDescriptor();
- if (canal.video_type!=vst_MPEG2) // PS en MPEG2 seulement pour le moment
- return 0;
+ if (ixRecDescr < 0)
+ return -1;
- NomFichierAvecDate nom_fichier(video_dir, getProgName(pProg), canal.nom, TEXT("mpg"));
- UINT16 video_pid = canal.video_pid;
- UINT16 audio_pid = canal.sons.tbl[ixSon].pid;
- CSampleGrabber * pGrabberCB = NULL;
- HANDLE hFile = nom_fichier.Create();
+ const Chaine & canal = Canaux[ixChaine];
- if (hFile != INVALID_HANDLE_VALUE) {
- pGrabberCB =
- new CSampleGrabber(
- new CCapture_PS(hFile, video_pid, audio_pid));
+ if (canal.video_type!=vst_MPEG2) // PS en MPEG2 seulement pour le moment
+ return -1;
- if (pGrabberCB!=NULL) {
- myprintf(TEXT("Enregistre PS, video=%i, audio=%i\n"), video_pid, audio_pid);
- cRecord[grab].start(pGrabberCB, ixChaine, pProg);
- }
- } else
- myprintf(TEXT("Erreur création '%s' code %u\n"), nom_fichier.nom, GetLastError());
+ NomFichierAvecDate nom_fichier(video_dir, getProgName(pProg), canal.nom, TEXT("mpg"));
+ UINT16 video_pid = canal.video_pid;
+ UINT16 audio_pid = canal.sons.tbl[ixSon].pid;
+ HANDLE hFile = nom_fichier.Create();
- if (pGrabberCB==NULL)
- return -1;
+ if (hFile == INVALID_HANDLE_VALUE) {
+ myprintf(TEXT("Erreur création '%s' code %u\n"), nom_fichier.nom, GetLastError());
+ return -1;
}
- return grab;
+
+ CCapture_PS * pCapture = new CCapture_PS(hFile, video_pid, audio_pid);
+
+ if (pCapture==NULL)
+ return -1;
+
+ myprintf(TEXT("Enregistre PS, video=%i, audio=%i\n"), video_pid, audio_pid);
+ cRecord[ixRecDescr].start(pCapture, ixChaine, pProg);
+ return ixRecDescr;
}
/**
@@ -400,31 +405,30 @@
* \param[in] pProg Pointeur facultatif sur la programmation horaire ayant servi à démarrer
* l'enregistrement : s'il n'est pas \p NULL, des paramètres additionnels
* y sont récupérés
- * \retval Index de l'enregistrement ("grabber") dans la table des enregistrements en cours
+ * \retval Index du descripteur dans la table des descripteurs d'enregistrements en cours
* \retval -1 si aucun enregistrement n'a pu démarrer.
**/
int Enregistrements::start_record_stream(Programme * pProg)
{
- int grab = getFreeGrabber();
- if (grab>=0) {
- NomFichierAvecDate nom_fichier(video_dir, getProgName(pProg), "Transport Stream", TEXT("ts"));
- CSampleGrabber * pGrabberCB = NULL;
- HANDLE hFile = nom_fichier.Create();
+ int ixRecDescr = getFreeDescriptor();
- if (hFile != INVALID_HANDLE_VALUE) {
- pGrabberCB =
- new CSampleGrabber(
- new CCapture_Stream(hFile));
+ if (ixRecDescr < 0)
+ return -1;
- if (pGrabberCB!=NULL) {
- myprintf(TEXT("Enregistre multiplex\n"));
- cRecord[grab].start(pGrabberCB, STREAM_PSEUDO_INDEX, pProg);
- }
- } else
- myprintf(TEXT("Erreur création '%s' code %u\n"), nom_fichier.nom, GetLastError());
+ NomFichierAvecDate nom_fichier(video_dir, getProgName(pProg), "Transport Stream", TEXT("ts"));
+ HANDLE hFile = nom_fichier.Create();
- if (pGrabberCB==NULL)
- return -1;
+ if (hFile == INVALID_HANDLE_VALUE) {
+ myprintf(TEXT("Erreur création '%s' code %u\n"), nom_fichier.nom, GetLastError());
+ return -1;
}
- return grab;
+
+ CCapture_Stream * pCapture = new CCapture_Stream(hFile);
+
+ if (pCapture==NULL)
+ return -1;
+
+ myprintf(TEXT("Enregistre multiplex\n"));
+ cRecord[ixRecDescr].start(pCapture, STREAM_PSEUDO_INDEX, pProg);
+ return ixRecDescr;
}
Modifié: trunk/record.h
===================================================================
--- trunk/record.h 2009-06-28 00:28:13 UTC (rev 192)
+++ trunk/record.h 2009-07-02 22:32:42 UTC (rev 193)
@@ -29,6 +29,7 @@
#pragma once
#include "recprog.h"
+#include "capture.h"
/**
* Durée maximale qui sépare deux appels au timer de début d'enregistrement.
@@ -61,16 +62,16 @@
/**
* Démarrage d'un enregistrement.
- * \param[in] pGrabberCB Pointeur sur un objet dérivé de \p ISampleGrabberCB, implémentant les
- * méthode "callback" nécessaires à la récupération des échantillons
- * à enregistrer
+ * \param[in] pCapt Pointeur sur un objet dérivé de \p CCapture, implémentant les
+ * méthode de traitement des échantillons à enregistrer
* \param[in] ixChaine Index (dans la table #Canaux) de la chaîne à enregistrer, ou bien
* \p STREAM_PSEUDO_INDEX pour spécifier tout le multiplex
* \param[in] pProg Pointeur facultatif sur la programmation horaire ayant servi à démarrer
* l'enregistrement : s'il n'est pas \p NULL, des paramètres additionnels
* y sont récupérés
+ * \return \p true si succès, \p false si échec
**/
- void start(ISampleGrabberCB * pGrabberCB, int ixChaine, Programme * pProg);
+ bool start(CCapture * pCapt, int ixChaine, Programme * pProg);
/**
* Prise en compte d'une programmation affectant une chaîne déjà en cours d'enregistrement.
@@ -154,20 +155,20 @@
/**
* Rechercher si une chaîne est en cours d'enregistrement,
- * et si oui, obtenir l'index des informations concernant cet enregistrement.
+ * et si oui, obtenir l'index du descripteur de cet enregistrement.
* \param[in] ixChaine Index (dans la table #Canaux) de la chaîne concernée, ou bien
* \p STREAM_PSEUDO_INDEX pour spécifier tout le multiplex courant
- * \retval Index de l'enregistrement ("grabber") dans la table #enregistrements_actuels
+ * \retval Index du descripteur dans la table des descripteurs d'enregistrements en cours
* \retval -1 si la chaîne n'est pas en cours d'enregistrement.
**/
- int getGrabberChaine(int ixChaine);
+ int getRecordingDescr(int ixChaine);
/**
- * Chercher un index d'enregistrement libre ("grabber")
- * \retval Index de l'enregistrement dans la table #enregistrements_actuels
- * \retval -1 si tous les index possibles sont utilisés.
+ * Chercher un descripteur d'enregistrement libre
+ * \retval Index du descripteur dans la table des descripteurs d'enregistrements en cours
+ * \retval -1 si tous les descripteurs possibles sont utilisés.
**/
- int getFreeGrabber();
+ int getFreeDescriptor();
/**
* Trouver l'index d'un enregistrement effectif et actif sur la base de son nom.
@@ -195,7 +196,7 @@
* \param[in] pProg Pointeur facultatif sur la programmation horaire ayant servi à démarrer
* l'enregistrement : s'il n'est pas \p NULL, des paramètres additionnels
* y sont récupérés
- * \retval Index de l'enregistrement ("grabber") dans la table des enregistrements en cours
+ * \retval Index du descripteur dans la table des descripteurs d'enregistrements en cours
* \retval -1 si aucun enregistrement n'a pu démarrer.
* \todo Retirer la restriction sur la syntonisation, et ajouter le paramètre \p ixSon
* pour choisir de n'enregistrer qu'une seule piste audio, si ce paramètre n'est pas -1.
@@ -210,7 +211,7 @@
* \param[in] pProg Pointeur facultatif sur la programmation horaire ayant servi à démarrer
* l'enregistrement : s'il n'est pas \p NULL, des paramètres additionnels
* y sont récupérés
- * \retval Index de l'enregistrement ("grabber") dans la table des enregistrements en cours
+ * \retval Index du descripteur dans la table des descripteurs d'enregistrements en cours
* \retval -1 si aucun enregistrement n'a pu démarrer.
* \todo Retirer la restriction sur la syntonisation, et faire en sorte que toutes
* les pistes son soient enregistrées si \p ixSon = -1
@@ -222,7 +223,7 @@
* \param[in] pProg Pointeur facultatif sur la programmation horaire ayant servi à démarrer
* l'enregistrement : s'il n'est pas \p NULL, des paramètres additionnels
* y sont récupérés
- * \retval Index de l'enregistrement ("grabber") dans la table des enregistrements en cours
+ * \retval Index du descripteur dans la table des descripteurs d'enregistrements en cours
* \retval -1 si aucun enregistrement n'a pu démarrer.
* \todo Ajouter un paramètre (par ex. \p ixChaine) pour que soit préalablement syntonisé
* le multiplex correspondant à la chaîne désignée.
Modifié: trunk/recprog.cpp
===================================================================
--- trunk/recprog.cpp 2009-06-28 00:28:13 UTC (rev 192)
+++ trunk/recprog.cpp 2009-07-02 22:32:42 UTC (rev 193)
@@ -1397,7 +1397,7 @@
HWND hDlg;
HWND hEnrCombo;
HWND hTimeCtl;
- int grab; // index de l'enregistrement en cours
+ int ixRecDescr; // index du descripteur d'enregistrement
int comboSel; // item couramment sélectionné dans la combo box
Enregistrement * penreg; // pointeur enregistrement à modifier
SYSTEMTIME refTime; // Contenu du contrôle de temps, soit en tant qu'heure de fin,
@@ -1409,7 +1409,7 @@
DlgEditState dlgEditState; // niveau de modifications effectuées
void remplitCombo();
- void load(bool initActive); // charger les données de l'enregistrement N° 'grab'
+ void load(bool initActive); // charger les données de l'enregistrement N° 'ixRecDescr'
void setCtlTime(); // Transférer le temps de référence dans le contrôle, selon le mode courant
bool needTimer() const {return delayActive && dispEndTime != useEndTime;}
void toEndTime(void); // convertir en mode "heure de fin"
@@ -1439,14 +1439,14 @@
strcpy_T(buf, nom);
res = (int)SendMessage(hEnrCombo, CB_ADDSTRING, 0, LPARAM(buf));
SendMessage(hEnrCombo, CB_SETITEMDATA, res, i);
- if (i==grab)
+ if (i==ixRecDescr)
sel = res;
}
comboSel = (int)SendMessage(hEnrCombo, CB_SETCURSEL, sel, 0);
}
-// Chargement des données de l'enregistrement 'grab'.
+// Chargement des données de l'enregistrement 'ixRecDescr'.
// Si 'initActive' = true, le dialogue sera préparé pour activation si aucune
// temporisation n'existait auparavant pour cet enregistrement
// (afin d'éviter à l'utilisateur d'avoir à cliquer sur la case d'activation
@@ -1454,9 +1454,9 @@
// ce changement.
void DelayEditData::load(bool initActive)
{
- if (grab<0)
- grab = 0;
- penreg = &enregistrements_actuels[grab];
+ if (ixRecDescr<0)
+ ixRecDescr = 0;
+ penreg = &enregistrements_actuels[ixRecDescr];
CheckDlgButton(hDlg, IDC_DELAY_BY_REMTIME, BST_CHECKED);
dispEndTime = false;
@@ -1600,7 +1600,7 @@
edat.hDlg = hDlg;
edat.hEnrCombo = GetDlgItem(hDlg, IDC_RECORD);
edat.hTimeCtl = GetDlgItem(hDlg, IDC_DELAYED_STOP);
- edat.grab = enregistrements_actuels.getGrabberChaine(ixChaineCourante);
+ edat.ixRecDescr = enregistrements_actuels.getRecordingDescr(ixChaineCourante);
edat.load(false /*true*/);
edat.remplitCombo(); // Chargement du combo des enregistrements
@@ -1641,7 +1641,7 @@
}
}
edat.comboSel = newSel;
- edat.grab = (int)SendMessage(edat.hEnrCombo, CB_GETITEMDATA, WPARAM(newSel), 0);
+ edat.ixRecDescr = (int)SendMessage(edat.hEnrCombo, CB_GETITEMDATA, WPARAM(newSel), 0);
edat.load(false /*true*/);
}
return TRUE; }
@@ -1834,24 +1834,24 @@
rebranche(false);
// Voir si la chaîne choisie n'est pas déjà en cours d'enregistrement :
- int grab = enregistrements_actuels.getGrabberChaine(ixChaine);
+ int ixRecDescr = enregistrements_actuels.getRecordingDescr(ixChaine);
- if (grab < 0) {
+ if (ixRecDescr < 0) {
// Si elle ne l'est pas, on démarre l'enregistrement :
int ixSon = selection_son(canal.sons, prog.audio); // utilisé seulement en PS pour le moment
switch(prog.methode) {
case meth_TS:
- grab = enregistrements_actuels.start_record_ts(ixChaine, &prog);
+ ixRecDescr = enregistrements_actuels.start_record_ts(ixChaine, &prog);
break;
case meth_PS:
- grab = enregistrements_actuels.start_record_ps(ixChaine, ixSon, &prog);
+ ixRecDescr = enregistrements_actuels.start_record_ps(ixChaine, ixSon, &prog);
break;
case meth_multiplex:
- grab = enregistrements_actuels.start_record_stream(&prog);
+ ixRecDescr = enregistrements_actuels.start_record_stream(&prog);
}
- if (grab < 0) {
+ if (ixRecDescr < 0) {
// L'enregistrement n'a pas pu démarrer
prog.etat = epr_erreur;
programmation_modifiee = true;
@@ -1859,7 +1859,7 @@
} else
// Programmation sur une chaîne déjà en cours d'enregistrement :
- enregistrements_actuels[grab].modify_prog(&prog);
+ enregistrements_actuels[ixRecDescr].modify_prog(&prog);
changement = true;
}
Modifié: trunk/res.rc
===================================================================
--- trunk/res.rc 2009-06-28 00:28:13 UTC (rev 192)
+++ trunk/res.rc 2009-07-02 22:32:42 UTC (rev 193)
@@ -420,13 +420,14 @@
CAPTION "Raccourcis"
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
- CONTROL "",IDC_SHORTCUT,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,276,162
- PUSHBUTTON "Par défaut…",IDC_SHORTCUT_REINIT,7,173,62,18
- LTEXT "Double clic pour modifier le raccourci. Clic droit pour avoir plus d'options.",IDC_STATIC,73,171,210,16
+ CONTROL "",IDC_SHORTCUT,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,276,152
+ PUSHBUTTON "Par défaut…",IDC_SHORTCUT_REINIT,7,164,62,18
+ LTEXT "Double clic pour modifier le raccourci. Clic droit pour avoir plus d'options.",IDC_STATIC,73,162,210,16
CONTROL "Prise en charge des commandes multimédia",IDC_USE_MULTIMEDIA,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,197,160,10
- LTEXT "Rôle de la molette de la souris :",IDC_STATIC,179,183,104,8
- COMBOBOX IDC_WHEEL_USAGE,179,194,104,54,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_GROUP | WS_TABSTOP,7,187,119,16
+ LTEXT "Rôle de la molette de la souris :",IDC_STATIC,146,172,137,8
+ COMBOBOX IDC_WHEEL_USAGE,146,183,137,54,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Défilement de la molette inversé",IDC_WHEEL_INVERT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,146,197,137,10
END
IDD_UPDATE DIALOGEX 0, 0, 251, 155
Modifié: trunk/resource.h
===================================================================
--- trunk/resource.h 2009-06-28 00:28:13 UTC (rev 192)
+++ trunk/resource.h 2009-07-02 22:32:42 UTC (rev 193)
@@ -118,13 +118,13 @@
#define IDC_AFTER_RECORD 1113
#define IDC_AFTER_NOTE 1114
#define IDC_DELAY_LABEL 1115
-#define IDC_SHORTCUT 1116
-#define IDC_SHORTCUT_REINIT 1117
-#define IDC_USE_MULTIMEDIA 1118
-#define IDC_WHEEL_USAGE 1119
-#define IDC_UPDATE_PROGRESS 1120
-#define IDC_UPDATE_CHECK 1121
-#define IDC_UPDATE_LIST 1122
+
+#define IDC_SHORTCUT 1120
+#define IDC_SHORTCUT_REINIT 1121
+#define IDC_USE_MULTIMEDIA 1122
+#define IDC_WHEEL_USAGE 1125
+#define IDC_WHEEL_INVERT 1126
+
#define IDC_SCAN_CHANLIST 1128
#define IDC_SCAN_LOOP 1129
#define IDC_AUTONUM_UNDEF 1130
@@ -156,6 +156,10 @@
#define IDC_POUCHINTVMOD_LOL_URL 1154
#define IDC_AUTHORS 1155
+#define IDC_UPDATE_PROGRESS 1160
+#define IDC_UPDATE_CHECK 1161
+#define IDC_UPDATE_LIST 1162
+
#define MY_TRAY_ICON_ID 20001
#define IDM_CHAINES_BASE 39000 // Offset de base pour changement chaîne
@@ -204,18 +208,20 @@
#define IDM_VOL_AUG 40050
#define IDM_VOL_DIM 40051
-#define IDM_ZOOM 40053
-#define IDM_DEZOOM 40054
-#define IDM_DEFAULT_ZOOM 40055
-#define IDM_ALLWDT 40056
-#define IDM_ALLHGT 40057
-#define IDM_CHAN_AUG 40058
-#define IDM_CHAN_DIM 40059
-#define IDM_PISTES 40060
-#define IDM_CHAINES 40061
-#define IDM_SHORT_DEFAUT 40062
-#define IDM_SHORT_EFFACER 40063
-#define IDM_CHAN_TUNE 40064
+#define IDM_ZOOM 40052
+#define IDM_DEZOOM 40053
+#define IDM_DEFAULT_ZOOM 40054
+#define IDM_ALLWDT 40055
+#define IDM_ALLHGT 40056
+#define IDM_CHAN_AUG 40057
+#define IDM_CHAN_DIM 40058
+#define IDM_CHAN_AUG_MPX 40059
+#define IDM_CHAN_DIM_MPX 40060
+#define IDM_PISTES 40061
+#define IDM_CHAINES 40062
+#define IDM_SHORT_DEFAUT 40063
+#define IDM_SHORT_EFFACER 40064
+#define IDM_CHAN_TUNE 40065
#define IDM_ETIRER 40066
#define IDM_UPDATE 40067
#define IDM_SHOW_PROGRAMME 40068
@@ -236,7 +242,7 @@
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 137
#define _APS_NEXT_COMMAND_VALUE 40079
-#define _APS_NEXT_CONTROL_VALUE 1156
+#define _APS_NEXT_CONTROL_VALUE 1163
#define _APS_NEXT_SYMED_VALUE 121
#endif
#endif
Modifié: trunk/settings.cpp
===================================================================
--- trunk/settings.cpp 2009-06-28 00:28:13 UTC (rev 192)
+++ trunk/settings.cpp 2009-07-02 22:32:42 UTC (rev 193)
@@ -2509,12 +2509,18 @@
**/
void SetMWheelUsage(HWND hDlg, MouseWheelUsage eMWheel)
{
+ static LPCTSTR apszWheelUsage[] = {
+ TEXT("Aucun"),
+ TEXT("Changer de chaîne"),
+ TEXT("Changer de chaîne dans multiplex"),
+ TEXT("Régler le volume"),
+ TEXT("Ajuster le zoom")
+ };
+
HWND hCtl = GetDlgItem(hDlg, IDC_WHEEL_USAGE);
- SendMessage(hCtl, CB_ADDSTRING, 0, (LPARAM)TEXT("Aucun"));
- SendMessage(hCtl, CB_ADDSTRING, 0, (LPARAM)TEXT("Changer de chaîne"));
- SendMessage(hCtl, CB_ADDSTRING, 0, (LPARAM)TEXT("Régler le volume"));
- SendMessage(hCtl, CB_ADDSTRING, 0, (LPARAM)TEXT("Ajuster le zoom"));
+ for (int nInx=0; nInx < _countof(apszWheelUsage); ++nInx)
+ SendMessage(hCtl, CB_ADDSTRING, 0, (LPARAM)apszWheelUsage[nInx]);
SendMessage(hCtl, CB_SETCURSEL, eMWheel, 0);
}
@@ -2599,6 +2605,7 @@
ListView_AjouteColonnes(hList, t_cols);
remplit_liste_shorcut(hList, dx, dy);
SetMWheelUsage(hDlg, role_molette);
+ set_check(hDlg, IDC_WHEEL_INVERT, inversion_molette);
set_check(hDlg, IDC_USE_MULTIMEDIA, use_multimedia);
return TRUE;
@@ -2677,6 +2684,7 @@
remplit_liste_shorcut(hList, dx, dy);
// ... (passage à travers)
case _cmd_(IDC_WHEEL_USAGE, CBN_SELCHANGE) :
+ case _cmd_(IDC_WHEEL_INVERT, BN_CLICKED) :
case _cmd_(IDC_USE_MULTIMEDIA, BN_CLICKED) :
// Indique une modification
PropSheet_Changed(GetParent(hDlg), hDlg);
@@ -2695,6 +2703,7 @@
update_shortcuts_menus();
use_multimedia = get_check(hDlg, IDC_USE_MULTIMEDIA);
role_molette = (MouseWheelUsage)SendDlgItemMessage(hDlg, IDC_WHEEL_USAGE, CB_GETCURSEL, 0, 0);
+ inversion_molette = get_check(hDlg, IDC_WHEEL_INVERT);
return psn_result(hDlg, PSNRET_NOERROR);
case PSN_KILLACTIVE:{ // Validation des changements
From pouchintv-dev at baysse.fr Fri Jul 3 12:53:27 2009
From: pouchintv-dev at baysse.fr (=?iso-8859-1?q?Liste_utilis=E9e_par_les_d=E9veloppeurs?=)
Date: Fri, 03 Jul 2009 10:53:27 -0000
Subject: [Pouchintv-dev] [PouchinTVMod] gingko | r194 - trunk
Message-ID: <20090703105312.207926EE99@mail.baysse.fr>
Author: gingko
Date: 2009-07-03 12:53:11 +0200 (ven 03 jui 2009)
New Revision: 194
Added:
trunk/memfifo.cpp
trunk/memfifo.h
Modified:
trunk/Pouchin TV_2005.vcproj
trunk/Pouchin TV_2008.vcproj
trunk/base.h
trunk/capture.cpp
trunk/grabber.cpp
trunk/grabber.h
trunk/graph.cpp
trunk/graph.h
trunk/record.cpp
trunk/record.h
Log:
Réduction à un seul du nombre de filtres "Grabber" pour les enregistrements, et
utilisation d'un "thread" pour réaliser ceux-ci.
Quatre enregistrements simultanés possibles.
grabber.h, grabber.cpp, graph.h, graph.cpp, memfifo.h, memfifo.cpp, record.h,
record.cpp, base.h, capture.cpp, Pouchin TV_2005.vcproj, Pouchin TV_2008.vcproj,
enfin bref, tous les fichiers modifiés ou ajoutés, quoi :
* Utilisation d'un seul filtre "Grabber" pour effectuer les enregistrements
au lieu de trois auparavant.
* On profite de cet allègement de ressources pour permettre quatre enregistrements
simultanés au lieu de trois auparavant.
* Utilisation d'un "thread" dédié pour les effectuer les enregistrements : au lieu
d'écrire directement dans les fichiers, le "Grabber" copie tous les échantillons
reçus (tout le multiplex) dans une pile FIFO allouée en mémoire, et un "thread"
distinct se charge de les récupérer, de les traiter et de les répartir dans les
différents enregistrements en cours.
Cette stratégie (que j'ai reprise de VLC 1.0 rc4) améliore considérablement la
résistance aux "ruptures" de flux lorsqu'on enregistre et que d'autres accès disque
ont lieu concurremment du fait d'autres applications.
* Deux fichiers ajoutés pour gérer la pile FIFO : memfifo.h et memfifo.cpp
Noter que deux macros "USE_SINGLE_GRABBER" et "USE_THREAD_IN_GRABBER" (définies dans
"graph.h"), qui seront supprimées dans quelques versions, permettent d'activer ou de
désactiver sélectivement ces deux nouvelles fonctionnalités, permettant ainsi aux
personnes qui peuvent compiler de comparer les fonctionnements avec et sans ces ajouts.
Modifié: trunk/Pouchin TV_2005.vcproj
===================================================================
--- trunk/Pouchin TV_2005.vcproj 2009-07-02 22:32:42 UTC (rev 193)
+++ trunk/Pouchin TV_2005.vcproj 2009-07-03 10:53:11 UTC (rev 194)
@@ -160,7 +160,7 @@
OutputFile="$(OutDir)\PouchinTVMod_debug_x64.exe"
LinkIncremental="2"
AdditionalLibraryDirectories="BaseClasses\$(ConfigurationName)_$(PlatformName)"
- IgnoreDefaultLibraryNames="MSVCRTD.lib"
+ IgnoreDefaultLibraryNames="msvcrtd.lib"
GenerateDebugInformation="true"
SubSystem="2"
TargetMachine="17"
@@ -812,6 +812,10 @@
>
+
+
@@ -930,6 +934,10 @@
>
+
+
Modifié: trunk/Pouchin TV_2008.vcproj
===================================================================
--- trunk/Pouchin TV_2008.vcproj 2009-07-02 22:32:42 UTC (rev 193)
+++ trunk/Pouchin TV_2008.vcproj 2009-07-03 10:53:11 UTC (rev 194)
@@ -805,6 +805,10 @@
>
+
+
@@ -923,6 +927,10 @@
>
+
+
Modifié: trunk/base.h
===================================================================
--- trunk/base.h 2009-07-02 22:32:42 UTC (rev 193)
+++ trunk/base.h 2009-07-03 10:53:11 UTC (rev 194)
@@ -151,9 +151,6 @@
/// Nombre max de chaînes
#define NB_MAX_CHAINES 500
-/// Nombre max d'enregistrements simultanés sur un même multiplex
-#define NB_MAX_ENREG 3
-
///////////////////////////////////////////////////////////////////
//
// Fin des variables pouvant être modifiées pour la compilation
Modifié: trunk/capture.cpp
===================================================================
--- trunk/capture.cpp 2009-07-02 22:32:42 UTC (rev 193)
+++ trunk/capture.cpp 2009-07-03 10:53:11 UTC (rev 194)
@@ -35,6 +35,7 @@
CCapture::CCapture(HANDLE hFil) :
hFile(hFil)
{
+ myprintf(TEXT("## Construction CCapture, début d'enregistrement (0x%08x)\n"), hFile);
}
//UINT64 CCapture::pos_fichier(void)
@@ -64,7 +65,7 @@
CCapture::~CCapture()
{
- myprintf(TEXT("Grabber détruit\n"));
+ myprintf(TEXT("## Destruction CCapture, fin d'enregistrement (0x%08x)\n"), hFile);
CloseHandle(hFile);
}
Modifié: trunk/grabber.cpp
===================================================================
--- trunk/grabber.cpp 2009-07-02 22:32:42 UTC (rev 193)
+++ trunk/grabber.cpp 2009-07-03 10:53:11 UTC (rev 194)
@@ -29,19 +29,40 @@
#include "base.h"
#include "grabber.h"
+#include "record.h"
+#if USE_THREAD_IN_GRABBER
+ #include "memfifo.h"
+#endif
+
/// Constructeur de base
+#if USE_SINGLE_GRABBER
+CSampleGrabber::CSampleGrabber() :
+#else
CSampleGrabber::CSampleGrabber(CCapture * pCapt) :
+#endif
CUnknown(TEXT("Sample grabber"), NULL),
+#if USE_SINGLE_GRABBER
+ hMutex(CreateMutex(NULL, FALSE, NULL)),
+#else
pCapture(pCapt),
+#endif
+#if USE_THREAD_IN_GRABBER
+ hThread(NULL),
+#endif
taille_paquet_buf(0)
{
+#if USE_SINGLE_GRABBER
+ myprintf(TEXT("## Construction CSampleGrabber\n"));
+#else
+ myprintf(TEXT("## Construction CSampleGrabber, pCapture=0x%08x\n"), pCapture);
+#endif
}
STDMETHODIMP CSampleGrabber::SampleCB(double SampleTime, IMediaSample *pSample) // virtual
{
- long l = pSample->GetActualDataLength();
+ long l = pSample->GetActualDataLength();
// (note : pSample->IsDiscontinuity ne semble pas donner d'informations significatives sur les
// tuners testés, mais qui sait d'autres tuners donneront peut-être des résultats meilleurs)
@@ -52,9 +73,13 @@
if (l>0) {
BYTE * p;
- pSample->GetPointer(&p);
+ pSample->GetPointer(&p);
+#if USE_THREAD_IN_GRABBER
+ cMemFifo.Put(l, p);
+#else
traite_sample(l, p);
+#endif
}
return S_OK;
}
@@ -113,15 +138,112 @@
**/
void CSampleGrabber::traite_paquet(const TS_packet & p) // virtual
{
+#if USE_SINGLE_GRABBER
+ if (Lock()) {
+ for (int nInx=0; nInx < enregistrements_actuels.count(); ++nInx) {
+ Enregistrement & sRec = enregistrements_actuels[nInx];
+
+ if (sRec.pCapture)
+ sRec.pCapture->traite_paquet(p);
+ }
+ Unlock();
+ }
+#else // USE_SINGLE_GRABBER
if (pCapture)
pCapture->traite_paquet(p);
+#endif // USE_SINGLE_GRABBER
}
+#if USE_SINGLE_GRABBER
+/// Verrouillage de l'accès aux descripteurs d'enregistrements pendant l'accès ou la modification
+/// à ceux-ci.
+bool CSampleGrabber::Lock()
+{
+ return WaitForSingleObject(hMutex, 1000L)==WAIT_OBJECT_0;
+}
+
+/// Libération de l'accès aux descripteurs d'enregistrements
+void CSampleGrabber::Unlock()
+{
+ ReleaseMutex(hMutex);
+}
+#endif // USE_SINGLE_GRABBER
+
+#if USE_THREAD_IN_GRABBER
+
+DWORD CSampleGrabber::GrabThread()
+{
+ myprintf(TEXT("## Entrée dans CSampleGrabber::GrabThread\n"));
+
+ const CMemFifoBlock * pBlock;
+
+ while ((pBlock = cMemFifo.WaitGet())!=NULL) {
+ const BYTE * pPtr = pBlock->ptr();
+ size_t nSize = pBlock->size();
+
+ if (nSize)
+ traite_sample(nSize, pPtr);
+
+ delete pBlock;
+ if (nSize==0)
+ break;
+ }
+
+ myprintf(TEXT("## Sortie de CSampleGrabber::GrabThread\n"));
+ return 0;
+}
+
+DWORD WINAPI CSampleGrabber::GrabThreadProc(LPVOID lpParameter)
+{
+ CSampleGrabber * pGrabberCB = reinterpret_cast(lpParameter);
+
+ return pGrabberCB->GrabThread();
+}
+
+/// Démarrage du "thread" de capture
+bool CSampleGrabber::StartThread()
+{
+ if (hThread==NULL)
+ hThread = CreateThread(0, 0, GrabThreadProc, this, 0, 0);
+ return hThread != NULL;
+}
+
+/// Arrêt du "thread" de capture
+bool CSampleGrabber::StopThread()
+{
+ if (hThread) {
+ // Envoyer un échantillon vide pour terminer le "Thread"
+ cMemFifo.Put(NULL, 0);
+
+ // Attendre une seconde
+ if (WaitForSingleObject(hThread, 1000)!=WAIT_OBJECT_0) {
+ myprintf(TEXT("Le thread du grabber ne s'est pas terminé correctement\n"));
+ return false;
+ }
+ hThread = NULL;
+ }
+ cMemFifo.Free(); // Libération des échantillons mémoire résiduels
+ return true;
+}
+
+#endif // USE_THREAD_IN_GRABBER
+
/// Destructeur général
CSampleGrabber::~CSampleGrabber()
{
+#if USE_THREAD_IN_GRABBER
+ StopThread(); // S'assurer de l'arrêt du "thread"
+#endif // USE_THREAD_IN_GRABBER
+
+#if USE_SINGLE_GRABBER
+ myprintf(TEXT("## Destruction CSampleGrabber\n"));
+ CloseHandle(hMutex);
+ hMutex = NULL;
+#else
+ myprintf(TEXT("## Destruction CSampleGrabber, pCapture=0x%08x\n"), pCapture);
if (pCapture) {
delete pCapture;
pCapture = NULL;
}
+#endif
}
Modifié: trunk/grabber.h
===================================================================
--- trunk/grabber.h 2009-07-02 22:32:42 UTC (rev 193)
+++ trunk/grabber.h 2009-07-03 10:53:11 UTC (rev 194)
@@ -29,10 +29,16 @@
#pragma once
#include "capture.h"
+#include "graph.h" // pour USE_SINGLE_GRABBER & USE_THREAD_IN_GRABBER
+#if USE_THREAD_IN_GRABBER
+ #include "memfifo.h"
+#endif
+
/// Classe implémentant les méthodes "callback" à associer à un "Sample grabber"
class CSampleGrabber : public CUnknown, public ISampleGrabberCB // The Filter Interface
{
+public:
//
// --- Implémentation des méthodes abstraites de l'interface ISampleGrabberCB --
//
@@ -73,11 +79,36 @@
// --- Données et méthodes propres à l'application ---
//
- CCapture * pCapture; //!< Pointeur sur la classe de traitement des paquets TS capturés
+#if USE_SINGLE_GRABBER
+ HANDLE hMutex; //!< Mutex protégeant les débuts et fins d'enregistrements
+#else
+ CCapture * pCapture; //!< Pointeur sur la classe de traitement des paquets TS capturés
+#endif
+#if USE_THREAD_IN_GRABBER
+ HANDLE hThread;
+#endif
- BYTE taille_paquet_buf; //!< Longueur du paquet partiel mémorisé
- TS_packet paquet_buf; //!< Tampon de mémorisation de paquet partiel
+ BYTE taille_paquet_buf; //!< Longueur du paquet partiel mémorisé
+ TS_packet paquet_buf; //!< Tampon de mémorisation de paquet partiel
+#if USE_THREAD_IN_GRABBER
+
+ CMemFifo cMemFifo; //!< Buffer "First In First Out" de mémorisation des échantillons reçus
+
+ /// Fonction d'exécution principale statique du 'thread'.
+ static DWORD WINAPI
+ GrabThreadProc(LPVOID lpParameter);
+
+ /// Fonction d'exécution principale effective du 'thread'.
+ DWORD GrabThread();
+
+ /// Démarrage du "thread" de capture
+ bool StartThread();
+
+ /// Arrêt du "thread" de capture
+ bool StopThread();
+#endif // USE_THREAD_IN_GRABBER
+
/**
* Traitement d'un échantillon reçu du tuner
* param[in] nSize Taille de l'échantillon
@@ -91,10 +122,23 @@
*
* param[in] p Référence sur le paquet reçu (qui a une longueur fixe)
**/
- void traite_paquet(const TS_packet & p);
+ void traite_paquet(const TS_packet & p);
public:
+#if USE_SINGLE_GRABBER
+ /// Constructeur de base
+ CSampleGrabber();
+
+ /// Verrouillage de l'accès aux descripteurs d'enregistrements pendant l'accès ou la modification
+ /// à ceux-ci.
+ bool Lock();
+
+ /// Libération de l'accès aux descripteurs d'enregistrements
+ void Unlock();
+#else
+ /// Constructeur de base
CSampleGrabber(CCapture * pCapt);
+#endif
/// Destructeur général
virtual ~CSampleGrabber();
Modifié: trunk/graph.cpp
===================================================================
--- trunk/graph.cpp 2009-07-02 22:32:42 UTC (rev 193)
+++ trunk/graph.cpp 2009-07-03 10:53:11 UTC (rev 194)
@@ -42,6 +42,10 @@
#include
+#if USE_SINGLE_GRABBER
+ #include "grabber.h"
+#endif
+
// ====================================================================================
// Variables globales
// ====================================================================================
@@ -75,6 +79,11 @@
CComPtr pNetworkTuner;
CComPtr pReceiverComponent;
+#if USE_SINGLE_GRABBER
+CComPtr pGrabberCB;
+CComPtr pGrabber;
+#endif
+
CComPtr pBDAControl;
CComPtr pBDAFreq;
@@ -208,6 +217,10 @@
pDSound.Release();
pDSoundAc3.Release();
+#if USE_SINGLE_GRABBER
+ pGrabberCB.Release();
+ pGrabber.Release();
+#endif
pNetworkTuner.Release();
pReceiverComponent.Release();
@@ -217,9 +230,11 @@
pBDAControl.Release();
// Libère les interfaces d'enregistrements
- for (int i=0; i filtrePrec;
+
+ hr = create_and_add_filter(CLSID_SampleGrabber, TEXT("Grabber"), filtrePrec);
+ if (FAILED(hr))
+ return hr;
+
+ hr = connect_filters(pAvantDemux, filtrePrec);
+ if (FAILED(hr))
+ return erreur(
+ TEXT("Le grabber n'a pas pu être connecté à la carte TNT, ")
+ TEXT("veuillez effacer \"%s%s\" et redémarrer"), hr, prefix_conf, config_file);
+
+ hr = filtrePrec.QueryInterface(&pGrabber);
+ if (FAILED(hr))
+ return erreur(TEXT("L'interface du grabber n'a pas été trouvée"), hr);
+
+ pGrabberCB = new CSampleGrabber();
+ if (pGrabberCB==NULL)
+ return erreur(TEXT("L'interface de callback du grabber n'a pas pu être créée"), E_FAIL);
+
+#else
CComPtr filtrePrec = pAvantDemux;
for (int i=0; i < enregistrements_actuels.count(); i++) {
@@ -1281,7 +1318,9 @@
enregistrements_actuels[i].query(pGrabber);
filtrePrec = pGrabber;
}
+#endif
+
// connect 4
hr = create_and_add_filter(CLSID_MPEG2Demultiplexer, TEXT("MPEG2 Demultiplexer"), pDemux);
Modifié: trunk/graph.h
===================================================================
--- trunk/graph.h 2009-07-02 22:32:42 UTC (rev 193)
+++ trunk/graph.h 2009-07-03 10:53:11 UTC (rev 194)
@@ -43,6 +43,12 @@
* @{ */
#define USE_AUTO_RETUNE 1 //!< Resyntonisation automatique
+
+#define USE_SINGLE_GRABBER 1 //!< Tests réduction à un seul filtre pour enregistrer
+#define USE_THREAD_IN_GRABBER 1 /*!< \brief Le "grabber" délègue l'enregistrement à un "thread" distinct
+ \note Utiliser de préférence avec \p USE_SINGLE_GRABBER, car
+ sinon on va créer trois threads ! */
+
#define USE_PMTFILTER 1 //!< Activation/désactivation filtre PMT
/**
* Macro facilitant les essais de désactivation d'une fonctionnalité relativement
@@ -112,6 +118,11 @@
extern CComPtr pNetworkTuner;
extern CComPtr pReceiverComponent;
+#if USE_SINGLE_GRABBER
+extern CComPtr pGrabberCB;
+extern CComPtr pGrabber;
+#endif
+
extern CComPtr pBDAControl;
extern CComPtr pBDAFreq;
Ajouté: trunk/memfifo.cpp
===================================================================
--- trunk/memfifo.cpp (rev 0)
+++ trunk/memfifo.cpp 2009-07-03 10:53:11 UTC (rev 194)
@@ -0,0 +1,122 @@
+/*
+ * memfifo.cpp
+ * Copyright (C) 2009 gingko - http://gingko.homeip.net/
+ *
+ * This file is part of Pouchin TV Mod, a free DVB-T viewer.
+ * See http://pouchintv.baysse.fr/ for updates.
+ *
+ * Pouchin TV Mod is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Pouchin TV Mod is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *
+ * Most files of this project have been changed from the Pouchin TV
+ * project (Copyright (C) 2006 Pouchin ),
+ * to use with a modified version of this software.
+ * See http://pouchinteve.free.fr/ for the original project.
+ */
+
+#include "memfifo.h"
+
+/// Constructeur
+CMemFifoBlock::CMemFifoBlock(size_t nSize, const BYTE * pPtr) :
+ pNext(NULL),
+ nDataSize(nSize)
+{
+ if (nSize) {
+ if (pPtr)
+ CopyMemory(this+1, pPtr, nSize);
+ else
+ ZeroMemory(this+1, nSize);
+ }
+}
+
+/**
+ * Ajout d'un échantillon en fin de pile FiFo
+ * \param[in] nSize Taille de l'échantillon
+ * \param[in] pPtr Pointeur sur les données de l'échantillon
+ **/
+void CMemFifo::Put(size_t nSize, const BYTE * pPtr)
+{
+ CMemFifoBlock * pNewBlock = CMemFifoBlock::new_block(nSize, pPtr);
+
+ EnterCriticalSection(&sCritSec);
+
+ if (pFirst == NULL)
+ pFirst = pNewBlock;
+ if (pLast)
+ pLast->pNext = pNewBlock;
+ pLast = pNewBlock;
+
+ LeaveCriticalSection(&sCritSec);
+ SetEvent(hEvent);
+}
+
+/**
+ * Extraire un échantillon de la pile FiFo.
+ * Retourne NULL si aucun échantillon n'est disponible.
+ * \note L'échantillon retourné DOIT être détruit par \p delete (sans [])
+ * après usage.
+ **/
+const CMemFifoBlock * CMemFifo::Get()
+{
+ EnterCriticalSection(&sCritSec);
+
+ CMemFifoBlock * pRetBlock = pFirst;
+
+ if (pFirst)
+ pFirst = pFirst->pNext;
+ if (pFirst==NULL)
+ pLast = NULL;
+ LeaveCriticalSection(&sCritSec);
+
+ return pRetBlock;
+}
+
+/**
+ * Extraire un échantillon de la pile FiFo.
+ * Si aucun échantillon n'est disponible, reste en attente jusqu'à ce qu'un
+ * échantillon soit ajouté (par un autre thread).
+ * Retourne NULL si en cas d'erreur.
+ * \note L'échantillon retourné DOIT être détruit par \p delete (sans [])
+ * après usage.
+ **/
+const CMemFifoBlock * CMemFifo::WaitGet()
+{
+ while (pFirst==NULL) {
+ if (WaitForSingleObject(hEvent, INFINITE)!=WAIT_OBJECT_0)
+ return NULL;
+ }
+
+ return Get();
+}
+
+/// Destruction de tous les blocs alloués
+void CMemFifo::Free()
+{
+ const CMemFifoBlock * pRetBlock;
+
+ while ((pRetBlock = Get())!=NULL)
+ delete pRetBlock;
+}
+
+CMemFifo::~CMemFifo()
+{
+ // Détruire tous les blocs alloués :
+ const CMemFifoBlock * pRetBlock;
+
+ while ((pRetBlock = Get())!=NULL)
+ delete pRetBlock;
+
+ DeleteCriticalSection(&sCritSec);
+}
Ajouté: trunk/memfifo.h
===================================================================
--- trunk/memfifo.h (rev 0)
+++ trunk/memfifo.h 2009-07-03 10:53:11 UTC (rev 194)
@@ -0,0 +1,144 @@
+/*
+ * memfifo.h
+ * Copyright (C) 2009 gingko - http://gingko.homeip.net/
+ *
+ * This file is part of Pouchin TV Mod, a free DVB-T viewer.
+ * See http://pouchintv.baysse.fr/ for updates.
+ *
+ * Pouchin TV Mod is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Pouchin TV Mod is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *
+ * Most files of this project have been changed from the Pouchin TV
+ * project (Copyright (C) 2006 Pouchin ),
+ * to use with a modified version of this software.
+ * See http://pouchinteve.free.fr/ for the original project.
+ */
+
+#pragma once
+
+#include
+
+/**
+ * Classe d'allocation d'un échantillon en mémoire.
+ * Afin de limiter le nombre de requêtes d'allocation mémoire, les données
+ * stockées sont situées dans l'espace mémoire se trouvant immédiatement après
+ * les données membres de la classe. Pour cette raison, les instances de cette
+ * classe ne doivent être créés qu'à l'aide de la fonction membre statique
+ * \p new_block.
+ **/
+class CMemFifoBlock
+{
+ friend class CMemFifo;
+
+ CMemFifoBlock * pNext;
+ size_t nDataSize;
+
+ /**
+ * Opérateur \p new surchargé, utilisant la syntaxe "placement new".
+ * \param[in] nSize Taille de la structure (implicite au langage C++)
+ * \param[in] nExtraSize Taille ajoutée après la structure.
+ **/
+ void * operator new(size_t nSize, size_t nExtraSize) {
+ return new BYTE[nSize + nExtraSize]; }
+public:
+ /// Constructeur
+ CMemFifoBlock(size_t nSize, const BYTE * pPtr=NULL);
+
+ /// Opérateur \p delete surchargé, devant être utilisé pour détruire
+ /// les échantillons après usage.
+ void operator delete (void * pPtr) {
+ delete [] reinterpret_cast(pPtr); }
+ /// Opérateur \p delete surchargé n°2 (version probablement jamais utilisée,
+ /// mais requise par le langage).
+ void operator delete (void * pPtr, size_t) {
+ delete [] reinterpret_cast(pPtr); }
+
+ /** Allocation d'un bloc pour un échantillon
+ * \param[in] nSize Taille de l'échantillon (devient \p nExtraSize
+ * pour l'opérateur \p new surchargé)
+ * \param[in] pPtr Pointeur sur les données de l'échantillon, à copier
+ * dans l'espace alloué. Si NULL, l'espace alloué est
+ * initialisé avec des zéros.
+ * \return Pointeur sur l'object alloué (structure + données)
+ **/
+ static CMemFifoBlock *
+ new_block(size_t nSize, const BYTE * pPtr=NULL) {
+ return new (nSize) CMemFifoBlock(nSize, pPtr);}
+
+ /// Obtenir la taille des données (seules)
+ size_t size() const {
+ return nDataSize;}
+ /// Obtenir un pointeur sur les données (\p const)
+ const BYTE * ptr() const {
+ return reinterpret_cast(this+1); }
+ /// Obtenir un pointeur sur les données
+ BYTE * ptr() {
+ return reinterpret_cast(this+1); }
+};
+
+/// Classe de gestion d'une pile "FiFo" destinée aux échantillons reçus du tuner.
+/// Le chargement et le déchargement de la pile doivent normalement se faire dans
+/// des "threads" différents.
+class CMemFifo
+{
+ CMemFifoBlock * pFirst; //!< Pointeur sur le premier échantillon
+ CMemFifoBlock * pLast; //!< Pointeur sur le dernier échantillon
+ HANDLE hEvent; //!< Handle d'objet "Event" pour signaler au thread de
+ //!< traitement que des données ont été ajoutées
+ CRITICAL_SECTION sCritSec; //!< Objet "critical section" pour protéger les ajouts
+ //!< et les extractions
+public:
+ /// Constructeur
+ CMemFifo() :
+ pFirst(NULL),
+ pLast(NULL),
+ hEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
+ {
+ InitializeCriticalSection(&sCritSec);
+ }
+
+ /**
+ * Ajout d'un échantillon en fin de pile FiFo
+ * \param[in] nSize Taille de l'échantillon
+ * \param[in] pPtr Pointeur sur les données de l'échantillon
+ **/
+ void Put(size_t nSize, const BYTE * pPtr);
+
+ /**
+ * Extraire un échantillon de la pile FiFo.
+ * Retourne NULL si aucun échantillon n'est disponible.
+ * \note L'échantillon retourné DOIT être détruit par \p delete (sans [])
+ * après usage.
+ **/
+ const CMemFifoBlock * Get();
+
+ /**
+ * Extraire un échantillon de la pile FiFo.
+ * Si aucun échantillon n'est disponible, reste en attente jusqu'à ce qu'un
+ * échantillon soit ajouté (par un autre thread).
+ * Retourne NULL si en cas d'erreur.
+ * \note L'échantillon retourné DOIT être détruit par \p delete (sans [])
+ * après usage.
+ **/
+ const CMemFifoBlock * WaitGet();
+
+ /// Destruction de tous les blocs alloués
+ void Free();
+
+ /// Destructeur
+ ~CMemFifo();
+};
+
+
Modifié: trunk/record.cpp
===================================================================
--- trunk/record.cpp 2009-07-02 22:32:42 UTC (rev 193)
+++ trunk/record.cpp 2009-07-03 10:53:11 UTC (rev 194)
@@ -55,6 +55,37 @@
UINT32 cleCh = indexToCle(ixChaine);
stop(epr_interrompu); // précaution
+#if USE_SINGLE_GRABBER // USE_SINGLE_GRABBER
+ if (pGrabber && cleCh!=0 && pGrabberCB) {
+ if (pProg) {
+ memcpy(this, pProg, sizeof(RecordInfo));
+ pProg->etat = epr_encours;
+ programmation_modifiee = true;
+ }
+
+ CSampleGrabber & cSg = dynamic_cast(*pGrabberCB);
+
+ if (cSg.Lock()) { // On a l'accès au mutex
+ // Nombre d'enregistrement avant le démarrage de celui-ci :
+ int nPrevRecCount = enregistrements_actuels.count_recording();
+
+ if (pCapture)
+ delete pCapture; // Au cas où il y en aurait déjà un (ne devrait pas arriver)
+ pCapture = pCapt;
+ cSg.Unlock();
+ cleChaine = cleCh;
+
+ // S'il n'y avait aucun enregitrement en cours auparavant, on démarre le "callback" maintenant :
+ if (nPrevRecCount==0) {
+ pGrabber->SetCallback(pGrabberCB, 0);
+ #if USE_THREAD_IN_GRABBER
+ cSg.StartThread(); // Démarrage du "thread"
+ #endif
+ }
+ return true;
+ }
+ }
+#else // USE_SINGLE_GRABBER
if (pSample && cleCh!=0) {
CSampleGrabber * pGrabberCB = new CSampleGrabber(pCapt);
@@ -65,11 +96,15 @@
programmation_modifiee = true;
}
pSample->SetCallback(pGrabberCB, 0);
+ #if USE_THREAD_IN_GRABBER
+ pGrabberCB->StartThread();
+ #endif
cleChaine = cleCh;
return true;
}
}
+#endif // USE_SINGLE_GRABBER
// Si on arrive ici, c'est que la requête a échoué
delete pCapt; // Déstruction de l'objet de capture que l'on ne peut pas utiliser
return false;
@@ -123,6 +158,41 @@
if (recording()) {
after = apres;
+#if USE_SINGLE_GRABBER
+ if (cleChaine!=0) {
+ if (raison!=epr_null) {
+ int ixProg = trouve_prog_par_nom(nom);
+
+ if (ixProg>=0) {
+ Programmes[ixProg].etat = raison;
+ programmation_modifiee = true;
+ }
+ }
+ if (pCapture && pGrabberCB) {
+ CSampleGrabber & cSg = dynamic_cast(*pGrabberCB);
+
+ if (cSg.Lock()) {
+ CCapture * pCapt = pCapture;
+
+ pCapture = NULL;
+ delete pCapt;
+ cSg.Unlock();
+ cleChaine = 0; // Nécessaire pour le comptage
+
+ // Nombre d'enregistrement qui restent en cours :
+ int nPrevRecCount = enregistrements_actuels.count_recording();
+
+ // S'il n'y a plus aucun enregistrement en cours, on arrête le "callback" maintenant :
+ if (nPrevRecCount==0) {
+ pGrabber->SetCallback(NULL, 0);
+ #if USE_THREAD_IN_GRABBER
+ cSg.StopThread();
+ #endif
+ }
+ }
+ }
+ }
+#else // USE_SINGLE_GRABBER
if (pSample && cleChaine!=0) {
if (raison!=epr_null) {
int ixProg = trouve_prog_par_nom(nom);
@@ -135,14 +205,16 @@
pSample->SetCallback(NULL, 0); // Ceci appelle indirectement "CSampleGrabber::Release()",
// CSampleGrabber::StopThread() ainsi que "delete pCapture;"
}
-
+#endif // USE_SINGLE_GRABBER
nom[0] = 0;
- cleChaine = 0;
+ cleChaine = 0; // Parfois redondant, mais tant pis
apres = apr_null;
}
return after;
}
+#if USE_SINGLE_GRABBER == 0
+
void Enregistrement::query(CComPtr & pGrabber)
{
if (!pSample) {
@@ -156,6 +228,8 @@
pSample.Release();
}
+#endif // #if USE_SINGLE_GRABBER == 0
+
/**
* Obtenir le nom de la chaîne enregistrée (retourne un "*" s'il s'agit du multiplex entier) :
* \retval Pointeur sur le nom de la chaîne
Modifié: trunk/record.h
===================================================================
--- trunk/record.h 2009-07-02 22:32:42 UTC (rev 193)
+++ trunk/record.h 2009-07-03 10:53:11 UTC (rev 194)
@@ -29,8 +29,17 @@
#pragma once
#include "recprog.h"
+#include "graph.h"
#include "capture.h"
+#if USE_SINGLE_GRABBER
+/// Nombre max d'enregistrements simultanés sur un même multiplex
+#define NB_MAX_ENREG 4
+#else
+/// Nombre max d'enregistrements simultanés sur un même multiplex
+#define NB_MAX_ENREG 3
+#endif
+
/**
* Durée maximale qui sépare deux appels au timer de début d'enregistrement.
* Si le temps avant l'enregistrement suivant est plus long que ce délai,
@@ -47,10 +56,18 @@
/// Description d'un enregistrement (capture) de chaîne qui est en cours de traitement
class Enregistrement : public RecordInfo {
public:
+#if USE_SINGLE_GRABBER
+ CCapture * pCapture;
+#else
CComPtr pSample;
+#endif
/// Constructeur
- Enregistrement() {}
+ Enregistrement()
+#if USE_SINGLE_GRABBER
+ : pCapture(NULL)
+#endif
+ {}
/// Déterminer si cet enregistrement de chaîne est couramment actif
bool recording() const {
@@ -89,11 +106,13 @@
**/
bool modify_prog(Programme * pProg);
+#if USE_SINGLE_GRABBER == 0
/// Obtenir l'interface du "Sample grabber"
void query(CComPtr & pGrabber);
/// Libérer l'interface du "Sample grabber"
void release();
+#endif
/**
* Calcul du temps restant avant la fin de l'enregistrement.
From pouchintv-dev at baysse.fr Thu Jul 9 18:19:35 2009
From: pouchintv-dev at baysse.fr (=?iso-8859-1?q?Liste_utilis=E9e_par_les_d=E9veloppeurs?=)
Date: Thu, 09 Jul 2009 16:19:35 -0000
Subject: [Pouchintv-dev] [PouchinTVMod] gingko | r195 - trunk
Message-ID: <20090709161922.F01096EFE6@mail.baysse.fr>
Author: gingko
Date: 2009-07-09 18:19:22 +0200 (jeu 09 jui 2009)
New Revision: 195
Added:
trunk/changelog.html
trunk/style.css
Modified:
trunk/Pouchin TV_2005.vcproj
trunk/Pouchin TV_2008.vcproj
trunk/Programme_Install.nsi
trunk/channels.cpp
trunk/channels.h
trunk/console.cpp
trunk/console.h
trunk/ini.cpp
trunk/ini.h
trunk/main.cpp
trunk/record.cpp
trunk/rendering.cpp
trunk/rendering.h
trunk/res.rc
trunk/resource.h
trunk/settings.cpp
Log:
Couleur OSD configurable, ajout de commandes et d'affichages OSD pour gérer
les pistes son. Inclusion d'un "ChangeLog".
ini.h, ini.cpp :
* Les variables sauvegardées dans le fichier de configuration sont maintenant
décrites dans une structure, cette structure étant elle-même organisée en
tableau, à la manière de ce qui se faisait déjà avec les raccourcis clavier.
* Ajout de fonctions membres à la classe pour gérer les lectures et écriture
dans la configuration selon ce type de structure.
* Ajout d'une fonction pour permettre de sauvegarder un item de configuration
sous la forme d'une valeur hexadécimale sur 32 bits.
ini.h, ini.cpp, settings.cpp, rendering.cpp, resource.h, res.rc :
* La couleur de l'OSD est maintenant modifiable dans la configuration, et
sauvegardée entre les sessions. Les couleurs personnalisées générées pendant
le choix de couleurs sont également sauvegardées.
* Ajout d'une variable pour configurer la transparence de l'OSD, dans les modes
VMR9 ou EVR seulement. Mais pas d'ajout dans la configuration pour le moment
(ça viendra vraisemblablement plus tard).
ini.h, ini.cpp, settings.cpp, main.cpp :
* La molette de la souris peut aussi être choisie pour sélectionner la piste audio.
main.cpp, channels.h, channels.cpp, rendering.h, resource.h :
* Le changement de piste audio est maintenant accompagné d'un affichage OSD pour
indiquer la nature de la nouvelle piste.
* La génération de l'affichage du nom de la piste audio est produite par un
nouveau membre de la classe "Chaine".
* Ajout d'une fonction et de raccourcis clavier pour produire une rotation dans
la sélection de la piste audio (auparavant, ceci n'existait que dans les
commandes multimédia).
* L'affichage du nom de la chaîne courante après changement n'est pas produit si
une nouvelle sélection a été faite dans le (court) délai qui précède cet
affichage (car conflit avec l'affichage de choix de chaîne).
* Simplification du traitement des commandes multimédia.
record.cpp :
* Correction d'un bug introduit dans la livraison précédente, qui fait que les
enregistrements ne recevaient aucune donnée s'ils étaient démarrés par une
programmation. Ce correctif a cependant déjà été inclus dans la version
0.5.194.1 publiée sur le forum.
console.h, console.cpp :
* Externalisation de la "handle" sur la console de debugging (pour simplifier
la sauvegarde de la position dans "config.ini").
changelog.html, style.css et fichiers de projet :
* Ajout d'un document HTML "changelog.html", récapitulant les changements depuis
la création de Pouchin TV. Ce document est destiné à l'utilisateur final, donc
il ne reprend que les changements qui le concernent et qu'il peut vérifier.
Par ailleurs, ce document est conçu pour pouvoir être également mis en ligne
sur le site web de Pouchin TV Mod, en ne modifiant que la seule feuille de
style "style.css" pour ajuster le formatage général.
Programme_Install.nsi :
* Inclusion du fichier "changelog.html" et de sa feuille de style "style.css"
dans l'installation, et création d'un raccourci vers ce document dans le
"Menu Démarrer".
resource.h :
* Renumérotation de certains items afin de laisser de la place pour insertions
futures.
Modifié: trunk/Pouchin TV_2005.vcproj
===================================================================
--- trunk/Pouchin TV_2005.vcproj 2009-07-03 10:53:11 UTC (rev 194)
+++ trunk/Pouchin TV_2005.vcproj 2009-07-09 16:19:22 UTC (rev 195)
@@ -1411,10 +1411,18 @@
+
+
+
Modifié: trunk/Pouchin TV_2008.vcproj
===================================================================
--- trunk/Pouchin TV_2008.vcproj 2009-07-03 10:53:11 UTC (rev 194)
+++ trunk/Pouchin TV_2008.vcproj 2009-07-09 16:19:22 UTC (rev 195)
@@ -1404,10 +1404,18 @@
+
+
+
Modifié: trunk/Programme_Install.nsi
===================================================================
--- trunk/Programme_Install.nsi 2009-07-03 10:53:11 UTC (rev 194)
+++ trunk/Programme_Install.nsi 2009-07-09 16:19:22 UTC (rev 195)
@@ -203,6 +203,8 @@
File "gpl.txt"
File "canaux.ini"
File "REFERENCES"
+ File "changelog.html"
+ File "style.css"
;Crée les raccourcis internet
WriteINIStr "$INSTDIR\${PRODUCT_BASE_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}"
@@ -229,6 +231,7 @@
;Crée les raccourcis vers Pouchin
CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER"
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${PRODUCT_NAME}.lnk" "$INSTDIR\${EXE_BASENAME_X64}.exe"
+ CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Historique des versions.lnk" "$INSTDIR\changelog.html"
;Raccourci internet
WriteINIStr "$SMPROGRAMS\$STARTMENU_FOLDER\Site internet de ${PRODUCT_BASE_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}"
@@ -257,6 +260,7 @@
;Crée les raccourcis vers Pouchin
CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER"
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${PRODUCT_NAME}.lnk" "$INSTDIR\${EXE_BASENAME_X86}.exe"
+ CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Historique des versions.lnk" "$INSTDIR\changelog.html"
;Raccourcis internet
WriteINIStr "$SMPROGRAMS\$STARTMENU_FOLDER\Site internet de ${PRODUCT_BASE_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}"
Ajouté: trunk/changelog.html
===================================================================
--- trunk/changelog.html (rev 0)
+++ trunk/changelog.html 2009-07-09 16:19:22 UTC (rev 195)
@@ -0,0 +1,800 @@
+
+
+
+
+
+ Changements entre les versions
+
+
+
+
+
+
+
+
+
+Changements entre les versions
+
+
+
+Menu
+
+
+
+
+
+Cette page répertorie l'historique des différentes versions de Pouchin TV Mod
+depuis la création du logiciel Pouchin TV de base.
+
+Les versions dont le numéro apparaît en bleu ont été publiées
+sur le site de Pouchin TV Mod, ou bien
+sur le site du créateur du Mod, ou bien
+sur le site du programme original Pouchin TV.
+
+Les versions dont le numéro apparaît en noir (et en gras)
+ont été publiées à titre expérimental sur le
+forum de Pouchin TV Mod.
+
+Les versions citées en italiques n'ont pas été publiées (ou bien ne sont plus disponibles).
+Certaines d'entre elles (indication SVN
) peuvent cependant être récupérées
+en tant que code source depuis le dépot SVN du projet,
+et compilées en suivant les instructions de la
+page de compilation.
+
+
+
+Changements réalisés pour la version 0.5
+
+
+ - 0.5.194 (expérimentale, publiée dans le forum le 3 juillet 2009) :
+
+ - Réduction à un seul du nombre de filtres
Grabber
pour les enregistrements,
+ et utilisation d'un thread
pour réaliser ceux-ci, améliorant l'immunité
+ des flux enregistrés aux influences d'autres programmes sur le même ordinateur.
+ - Quatre enregistrements simultanés possibles.
+
+
+
+ - SVN rév. 193 :
+
+ - Anticipation temporisée au changement de chaîne et de zoom.
+ - Davantage de choix pour la molette de la souris.
+
+
+
+ - SVN rév. 192 :
+
+ - Il est maintenant possible de passer outre
+ Ã certains messages d'erreurs de conflits d'enregistrements.
+
+
+
+ - SVN rév. 190 :
+
+ - Deux tuners rigoureusement identiques (et donc affichant le même nom dans la configuration)
+ devraient maintenant être accessibles séparément.
+
+
+
+ - SVN rév. 189 :
+
+ - Ajout d'options pour la molette de la souris et les commandes multimédia.
+
+
+
+ - 0.5.188 (expérimentale, publiée dans le forum le 13 juin 2009) :
+
+ - Ajout du support du rendu vidéo EVR (Enhanced Video Renderer),
+ à partir d'un patch proposé par MatMaul.
+
+
+
+ - SVN rév. 187 :
+
+ - Plusieurs instances de l'application peuvent prendre en charge chacune un tuner différent,
+ sur le même ordinateur, grâce à une option qui permet de leur attribuer à chacun des fichiers
+ de configuration différents.
+ - Le titre de la fenêtre peut maintenant être modifié dans la configuration.
+
+
+
+ - 0.5.186 (expérimentale, publiée dans le forum le 28 mai 2009) :
+
+ - Prise en charge des filtres gérant l'audio au format E-AC3.
+ - Implémentation d'une option permettant de revenir au graphe des versions antérieures
+ à la révision 184, car il apparaît que pour certains utilisateurs,
+ le nouveau graphe ne marche pas alors que l'ancien fonctionnait.
+ - La recherche de chaînes peut maintenant essayer deux fréquences voisines pour chaque canal,
+ avec décalage de 5 kHz (à cause de problèmes qu'ont certains tuners à gérer
+ une fréquence trop proche de la fréquence effective).
+ - Ajout d'éléments de configuration supplémentaires à la recherche de chaînes.
+ - Certains messages affichés dans des dialogues d'informations
+ sont assortis d'une option
Ne plus afficher ce message
.
+ - En cas d'échec d'initialisation du rendu vidéo, l'application n'est plus quittée.
+ En lieu et place, l'affichage est désactivé avec un message d'avertissement.
+
+
+
+ - 0.5.184 (expérimentale, publiée dans le forum le 5 avril 2009) :
+
+ - Modification du graphe pour le rendre plus conforme à ce qui était recommandé par Microsoft
+ (utilisation du filtre
Microsoft DVB-T Network Provider
).
+
+
+
+ - SVN rév. 183 :
+
+ - Correction de bogues divers, concernant notamment l'affichage sur clavier
+ LCD Logitech, l'EPG et le masquage de la souris en mode plein écran.
+
+
+
+ - SVN rév. 182 :
+
+ - L'affichage de qualité du signal gère correctement les tuners
+ qui ne donnent pas certaines informations réclamées.
+ - Amélioration de la journalisation de la recherche de canaux et de l'affichage de versions.
+
+
+
+ - SVN rév. 181 :
+
+ - Amélioration du système qui affiche le nom de l'émission en cours.
+
+
+
+ - 0.5.179 (expérimentale, publiée dans le forum le 27 mars 2009) :
+
+ - Refonte complète du système de recherche de chaînes :
+ - La recherche de chaînes devient paramétrable,
+ et se fait maintenant dans un
thread
distinct.
+ - L'attribution des numéros aux chaînes non numérotées,
+ ou bien en cas de doublon, est maintenant configurable.
+ - Le cas de même chaînes reçues de plusieurs émetteurs différents
+ est pris en charge plus proprement.
+ - Prise en charge améliorée des multiplex (vraisemblablement étrangers)
+ qui ne contiennent pas de description des chaînes du réseau.
+ - La recherche peut se faire de manière incrémentale.
+ - Un fichier journal
scan.log
enregistre les résultats
+ des recherches successives.
+ - Les indicateurs de force et de qualité du signal
+ sont répliqués dans le dialogue de recherche de chaînes.
+ - On peut maintenant spécifier une liste de chaînes
+ définie manuellement pour la recherche.
+
+
+
+ - SVN rév. 177 :
+
+ - Indicateurs visuels de niveau de force et de qualité dans le dialogue
+ de qualité du signal.
+ - L'indicateur de force de signal est calibrable dans la configuration.
+
+
+
+ - SVN rév. 176 :
+
+ - En cas de présence de plusieurs tuners, les paramètres spécifiques à chacun
+ d'eux sont sauvegardés séparément dans la configuration.
+ Changer de tuner provoque automatiquement la sélection du récepteur associé au nouveau,
+ s'il a déjà été utilisé auparavant.
+ - Représentation plus stricte des chaînes en interne.
+ - Les raccourcis clavier sont sauvegardés dans une sections distincte du fichier
+ de configuration.
+ - Les tuners et codecs qui sont sélectionnés mais qui ont disparu du système restent
+ néanmoins mémorisés et affichés dans les listes déroulantes.
+ Un message d'alerte avertit alors de leur disparition.
+
+
+
+ - SVN rév. 175 :
+
+ - Le rafraîchissement, dans l'EPG, est limité à une fois par seconde.
+ - Correction d'un bug susceptible de corrompre les enregistrements dans le cas où
+ le pilote du tuner utilisé enverrait des paquets incomplets à reconstituer
+ (merci à virtualblue sur le forum).
+ - Une option de resyntonisation automatique remplace l'ancienne option
+
va-et-vient de fréquences au démarrage
.
+ - Correction d'un problème de relation entre certaines boîtes de dialogue et leurs fenêtres parentes.
+
+
+
+ - 0.5.174 (expérimentale, publiée dans le forum le 27 février 2009) :
+
+ - Le numéro de version devient 0.5.
+ - La mise à jour de la liste des programmes dans l'EPG se fait maintenant en temps réel :
+ plus besoin de presser de bouton
Mettre à jour
, lequel est donc, en conséquence, supprimé,
+ et remplacé par un bouton Réinitialiser
, qui provoque le rechargement intégral de l'EPG.
+ - Ajout de colonnes d'informations dans le dialogue de configuration des chaînes.
+ - La norme de réception est affichée en clair (
MPEG2
ou H264
).
+ - Ajout des icônes de chaînes belges dans l'installation.
+
+
+
+
+
+
+
+
+Changements réalisés pour la version 0.4
+(depuis la reprise du projet)
+
+
+ - 0.4.173 (expérimentale, publiée dans le forum le 22 février 2009,
+ puis supprimée) :
+
+ - Ajout du support des chaînes haute définition.
+ - Les codecs peuvent être être désactivés en spécifiant le choix
Aucun
.
+ - Le va-et-vient de fréquence est remplacé par une détection de gels du graphe,
+ provoquant une resyntonisation automatique.
+ - Nouveau système de numérotation des versions :
+ - numéro majeur
+ - numéro mineur
+ - numéro SVN
+ - indice (0 ou 1) de modification.
+
+
+
+ - SVN rév. 172 :
+
+ - Ajout du numéro
TSID
des chaînes devant leur numéro pour
+ faire ressortir les chaînes appartenant au même multiplex.
+ - Informations supplémentaires dans le dialogue
À propos
+ pour mieux identifier la version compilée.
+ - Correctif visant à éviter qu'un flux TS corrompu
+ puisse provoquer un plantage de l'application.
+ - Correction d'un bug susceptible d'introduire
+ des corruptions du contenu de la liste des chaînes.
+
+
+
+ - SVN rév. 169 :
+
+ - La boîte de dialogue du Guide des Programmes est maintenant redimensionnable.
+ - Ajout d'une commande Ctrl-F pour resyntoniser sur la fréquence courante
+ (permet parfois de débloquer un graphe figé).
+ - Dans les contrôles de dialogue présentant des listes, on peut maintenant
+ réorganiser les colonnes (mais cette réorganisation n'est pas sauvegardée).
+
+
+
+ - SVN rév. 168 :
+
+ - Les changements de codecs ou de rendu vidéo
+ peuvent maintenant se faire sans avoir à relancer l'application.
+
+
+
+ - SVN rév. 166 :
+
+ - Ajout des modes de rendu
VMR7 windowless
et Aucun rendu vidéo
,
+ ce dernier mode permettant d'effectuer des enregistrements sur un ordinateur
+ de performances insuffisantes pour afficher la vidéo.
+ - Ajout d'une option de configuration pour activer ou désactiver
+ le va-et-vient de fréquence au démarrage.
+
+
+
+ - SVN rév. 165 :
+
+ - Ajout d'un raccourci (touche
Suppr.
)
+ pour effacer une programmation de la liste des enregistrements programmés.
+
+
+
+ - SVN rév. 164 :
+
+ - Le réglage de volume a maintenant une variation logarithmique, par pas de 5.
+ - Ajout de l'option de configuration
--prefix
,
+ permettant d'avoir des fichiers de configuration distincts.
+
+
+
+ - SVN rév. 163 :
+
+ - Le projet peut maintenant se compiler ASCII (8 bits) en plus du mode Unicode,
+ Ã l'aide des configuration
Debug_SBCS
et Release_SBCS
ajoutées.
+ - Correction d'un bug qui faisait disparaître les caractères accentués
+ à la fin des noms d'enregistrement programmés.
+
+
+
+ - SVN rév. 160 :
+
+ - Ajout d'options de configuration pour augmenter la durée
+ d'un enregistrement programmé depuis l'EPG, par le début et par la fin,
+ de manière à se prémunir des incertitudes d'horaires.
+ - Suppression des configurations
Vista debug
et Vista release
, qui
+ n'avaient plus de raison d'être.
+
+
+
+ - SVN rév. 159 :
+
+ - Réécriture de la gestion du
Video Mixing Renderer
,
+ ainsi que de la fonction OSD.
+ - Ajout de la gestion du VMR9.
+ - Activation de l'OSD en VMR9 sous Windows Vista.
+ - Ajout d'une commande
Utiliser toute la hauteur
,
+ contrepartie verticale de la commande Utiliser toute la largeur
précédemment existante.
+
+
+
+ - SVN rév. 158 :
+
+ - Le fichier
canaux.ini
est dorénavant placé dans le répertoire Application Data
.
+
+
+
+ - SVN rév. 157 :
+
+ - Mise à jour de la liste des canaux.
+
+
+
+ - SVN rév. 152 :
+
+ - Ajout d'une page de configuration de raccourcis clavier,
+ permettant de modifier les commandes données par le clavier.
+
+
+
+ - SVN rév. 149 :
+
+ - Prise en charge des commandes multimédia
+ (générées par certains périphériques de type clavier ou télécommande).
+
+
+
+ - SVN rév. 146 :
+
+ - Ajout d'une option pour spécifier le format du nom des fichiers enregistrés.
+ - Les options de ligne de commande prennent deux tirets au lieu d'un.
+
+
+
+
+ - SVN rév. 142 :
+
+ - Ajout d'icônes pour les chaînes belges.
+
+
+
+ - SVN rév. 141 :
+
+ - Un changement de chaîne en mode suspendu n'a plus pour effet
+ de
désuspendre
l'audio et la vidéo.
+ - Correction d'un bug dans l'EPG qui faisait que le bouton
Enregistrer
+ ne fonctionnait qu'après modification de la sélection.
+
+
+
+ - SVN rév. 140 :
+
+ - Utilisation de classes ATL pour gérer les filtres,
+ sécurisant ainsi l'application contre certains types de fuites de mémoire.
+
+
+
+ - SVN rév. 136 :
+
+ - Amélioration du système d'affichage des erreurs :
+ les codes d'erreur numériques sont décodés pour affichage en clair,
+ et les erreur successives se cumulent dans une seule fenêtre
+ plutôt que de s'afficher successivement.
+
+
+
+ - SVN rév. 133 :
+
+ - Ajout de diverses options de ligne de commande :
-fs
, -maxi
,
+ -noborders
, -normal
, -recps
, -rects
et -ch##X
.
+
+
+
+ - 0.4~svn-r130 (publiée le 20 octobre 2008) :
+
+ - Correction d'un bug dans la gestion des caractères non latins.
+ - Ajout de diverses icônes pour des chaines locales ou frontalières.
+
+
+
+ - SVN rév. 123 :
+
+ - Affichage intelligible de la valeur des messages d'erreurs DirectX.
+ - Ajout d'icônes de chaines locales.
+ - Diverses réorganisations internes du code.
+
+
+
+ - SVN rév. 117 :
+
+ - Meilleur support de l'enregistrement en mode PS.
+
+
+
+ - 0.4~svn-r112 (publiée le 3 janvier 2008) :
+
+ - Plusieurs bugs corrigés.
+ - Réorganisation interne du code.
+
+
+
+ - SVN rév. 106 :
+
+ - Réactivation de l'enregistrement du multiplex,
+ mais sous condition d'activer une option de configuration.
+ - Refonte de la gestion des enregistrements programmés.
+ - Correction d'un bug avec certains pilotes de cartes TNT.
+
+
+
+ - SVN rév. 102 :
+
+ - Implémentation du dialogue de réorganisation des chaînes :
+ - Les chaines peuvent maintenant être renumérotées facilement en cliquant sur le numéro
+ et en en saisissant un nouveau, ou en déplaçant la chaine dans la liste.
+ - Les chaînes peuvent être déclarées
Actives
,
+ Inactives
ou Préférées
, grâce à un menu contextuel :
+ les chaînes Préférées
peuvent être sélectionnées par flèches haut et bas,
+ molette de souris ou par menu, alors que les chaînes Actives
+ ne peuvent être sélectionnées que par menu.
+ - En maintenant la touche SHIFT pressée au démarrage de l'application,
+ on forcera l'ouverture du dialogue de configuration (utile dans le cas où
+ la configuration courante fait planter l'application avant même d'avoir accès aux menus).
+ - Liste des canaux mis à jour au 5 octobre 2007.
+ - Modification de la gestion de l'offset.
+
+
+
+ - SVN rév. 98 :
+
+ - Plusieurs améliorations au niveau de la recherche de chaînes
+ ainsi que des enregistrements programmés.
+
+
+
+ - SVN rév. 92 :
+
+ - Modification de la configuration, en utilisant des onglets,
+ et rassemblement des options par cathégorie.
+
+
+
+ - 0.4~svn-r87 (publiée le 4 octobre 2007) :
+
+ - Correction pour le plantage qui se produisait à la fin d'un scan des chaînes
+ lors d'une nouvelle installation et de l'utilisation de DScaler.
+ - Suppression de l'option
multiplex
dans le guide des programmes.
+ - Disparition du curseur de la souris en mode plein écran rétablie.
+ - Réactivation de l'arrêt programmé de Pouchin TV Mod à la fin d'un enregistrement.
+ - Réaffiche les icones des chaînes à la suite d'une nouvelle recherche.
+ - Retire la fenêtre du premier plan lorsque l'on supprime l'option.
+ - Correctif pour le démarrage minimisé qui ne marchait plus correctement.
+ - Réorganisation interne du code.
+
+
+
+ - 0.4~svn-r83 (publiée le 28 septembre 2007) :
+
+ - Correction de bogues pour l'enregistrement concurentiel.
+
+
+
+ - SVN rév. 78 :
+
+ - Supporte maintenant un nombre de multiplex variable : de R1 Ã R99 (max).
+ - Corrections pour la gestion des différentes modes de fenêtre de Pouchin TV Mod.
+ - Vérifie si les dossiers de sauvegarde des enregistrements et des captures
+ existent au lancement, et demande quoi faire si non.
+ - Amélioration du support des systèmes Windows 64 bits.
+
+
+
+ - SVN rév. 72 :
+
+ - Support de la répétition des enregistrements
+ (tous les
Lundi
, Mardi
et Vendredi
par exemple).
+ - Le choix de la ville à utiliser se fait maintenant dans la fenêtre de scan.
+ - Réorganisation interne du code.
+
+
+
+ - SVN rév. 68 :
+
+ - Il n'est plus nécessaire d'effacer le fichier
config.ini
.
+ Pouchin TV Mod repropose la configuration plutôt.
+
+
+
+ - SVN rév. 60 :
+
+ - Affichage des chiffres au fur et à mesure de la saisie.
+
+
+
+ - SVN rév. 58 :
+
+ - Ajout des icônes des chaines dans les menus.
+
+
+
+ - 0.4~svn-r57 (publiée le 15 septembre 2007) :
+
+ - Recherche de mise à jour sur internet.
+ - Ajout d'une fonction permettant de ré-actualiser la liste des chaînes depuis Pouchin TV Mod,
+ et ce, en choisissant ou non de conserver les modifications.
+ - Correction d'un bug de longue date (Pouchin TV original)
+ empêchant de récupérer le numéro de la chaîne.
+ - Correction d'un bug conduisant à refaire une recherche des canaux à chaque démarrage,
+ suite à l'ajout de
France Ô
aux chaines (caractères accentués).
+ - Diverses corrections de bugs.
+
+
+
+ - SVN rév. 49 :
+
+ - Les boites de dialogues
Qualité du signal…
, Guide des programmes…
,
+ Enregistrements programmés…
sont non modales.
+ - Ajout d'information sur le programme en cours dans le systray.
+ - Diverses corrections de bugs.
+
+
+
+ - SVN rév. 45 :
+
+ - Remplacement de la fonction permettant d'enregistrer un multiplex
+ par la possibilité d'enregistrer plusieurs chaines (jusqu'à 3) du multiplex.
+ - Le fichier
canaux.ini
est maintenant extrait des ressources.
+ - Changement des répertoires par défaut pour les sauvegardes des images et des vidéos.
+ - Diverses corrections de bugs.
+
+
+
+ - 0.4~svn-r42 (publiée le 29 août 2007) :
+
+ - Correction de plusieurs bugs.
+ - Ajout de la liste des contributeurs à la fenêtre
À propos…
.
+ - les fichiers de configs sont maintenant stockés dans le profil de l'utilisateur,
+
C:\Documents And Settings\Utilisateur\Application Data\Pouchin TV Mod
+ par exemple, ce qui devrait résoudre tous les problèmes pour les
+ télécommandes, de partage d'ordinateur, ou de droits d'accès.
+
+
+
+ - 0.4~svn-r38 (publiée le 28 août 2007) :
+
+ - Correction d'un bug sous Vista empêchant l'affichage correct des fenêtres.
+ - Changement de l'icône de Pouchin TV Mod lorsque l'on enregistre.
+ - Changement de place pour l'indication du volume.
+ - Suppression des dépendances.
+ Maintenant, la seule chose indispensable à installer est Pouchin TV Mod.
+
+
+
+ - 0.4~svn-r25 (publiée le 18 août 2007) :
+
+ - Correction d'un bug lorsque l'on coupait le son.
+ - Fusion des version pour 2000/XP et la version de Vista en une seule.
+
+
+
+ - 0.4~svn-r23 (publiée le 17 août 2007) :
+
+ - Ajout des raccourcis claviers dans les menus.
+ - Ajout d'une fonction demandant confirmation si on quitte
+ Pouchin TV Mod et qu'un enregistrement est en cours.
+
+
+
+ - 0.4~svn-r18 (publiée le 15 août 2007) :
+
+ - Fusion des modifs
+ effectuées
+ par radius pour Vista :
+ - Comme il n'y a plus d'OSD, affiche le volume dans la barre des
+ status (barre du bas).
+ - Correction d'un bug lors de la gestion des bandes noires et commutation 4/3 <-> 16/9.
+
+ - ajout d'une option
Programme / Muet si minimisé
pour
+ activer / désactiver le son de Pouchin TV quand on le minimise.
+ - modification de l'agencement des menus et des boites de
+ dialogues.
+
+
+
+ - 0.4~svn-r16 (publiée le 15 août 2007) :
+
+ - correction d'un bug lors de la sauvegarde de l'enregistrement
+ dans le planificateur des tâches, dont le nom contient des
+ caractères invalide.
+ - ajout de la priorité
Temps réel
au programme.
+ - gestion de l'option
arrêter le PC à la fin de
+ l'enregistrement
.
+
+
+
+
+
+
+
+
+Changements réalisés par le créateur du Mod
+
+
+ - 0.4 RC2 (publiée le 18 juin 2007) :
+
+ - Correction de bugs.
+
+
+
+ - 0.4 RC1 :
+
+ - Correction de bugs.
+ - Si pas de gros bugs, dernière version avant la stable.
+
+
+
+ - 0.4 beta3 :
+
+ - Correction de bugs.
+ - Possibilité de programmer la fin d'un enregistrment après l'avoir lancé
+ (
Stopper l'enregistrement dans …
).
+ - Option pour étirer la vidéo.
+ - Ajout d'une version compatible Vista (sans OSD).
+ - Nouvelle icône, merci à korse2a.
+
+
+ - 0.4 beta2a :
+
+ - Fix d'un bug qui faisait planter le programme dès qu'un enregistrement était programmé.
+
+
+
+ - 0.4 beta2 :
+
+ - Ajout d'une option pour arrêter le logiciel après un enregistrement programmé.
+ - Support des tâches planifiées de Windows.
+
+
+
+ - 0.4 beta1 :
+
+ - Correction de quelques bugs.
+ - Quelques modifications graphiques.
+
+
+
+ - 0.4 alpha2 :
+
+ - Correction du bug qui faisait que seul le premier enregistrement programmé fonctionnait.
+
+
+
+ - 0.4 alpha1 :
+
+ - Première version du Mod. Les nouveautés par rapport à la version 0.3a sont :
+ - Programmation des enregistrements,
+ mon code étant largement inspiré du mod de jmblot, merci à lui.
+ - Minimiser dans le system tray : quand Pouchin est minimisé, il stoppe le son,
+ la vidéo, et ne prend presque plus de processeur
+ → on peut programmer des enregistrements et laisser Pouchin dans le system tray.
+ - Sauvegarde du volume.
+ - Refonte totale de la gestion des pistes :
+ affichage de la langue de la piste, pistes dans un menu à part,
+ gestion d'un nombre de pistes virtuellement illimité.
+ - Quand on enregistre en TS ca enregistre toutes les pistes de la chaîne et non pas que l'audio sélectionné
+ (même les flux de sous-titres sont enregistrés bien qu'ils n'apparaissent pas dans Pouchin).
+ - Fix de ef15c pour le support de la Nova T Stick (merci à lui).
+
+
+
+
+
+
+
+
+
+Changements réalisés par le créateur de la version originale
+(dénommée PouchinTV)
+
+
+ - 0.3a (publiée le 28 mai 2006) :
+
+ - Correction de la vidéo qui ne s'affiche que sur le 1er écran en dual screen.
+
+
+
+ - 0.3 (publiée le 5 mai 2006) :
+
+ - Possibilité d'enregistrer en MPEG2 PS.
+ - OSD simple : nom de la chaîne et du programme, sourdine, volume, zoom.
+ - PouchinTV a maintenant absolument besoin de l'overlay pour fonctionner (conséquence de l'OSD).
+ - Plus besoin de scanner pendant les heures où Canal+, TPS star et Paris Première
+ diffusent en clair pour tout avoir, PouchinTV est capable de récupérer les PID en dynamique.
+ - Option pour switcher directement en AC3 sur les chaînes qui le proposent.
+ - Réglage du volume avec + et -.
+ - Zoom réglable avec Z/Maj-Z.
+ - Correction bug enregistrement sur Nova-t Usb2.
+ - Fenêtre d'EPG : le programme en cours est choisi par défaut,
+ double clic permet de zapper sur une chaîne.
+ - Correction plein écran sur systèmes dual screen.
+ - Version pour XP64 (non testée !).
+ - Option pour que l'image utilise toute la largeur de la fenêtre :
+ utile pour les films 16/9 ou + diffusés sur une chaine en 4/3 avec un écran large.
+ - Sauve/restaure la taille et position de la fenêtre.
+ - Propose l'offset à 166 pour les Hauppauge, et 167 pour les Terratec…
+ - Option dans le .ini pour utliser le désentrelacement hardware du VMR :
+ le codec vidéo doit supporter ce mode.
+
+
+
+ - 0.2b (publiée le 13 mars 2006) :
+
+ - L'offset passe à 167 par défaut, et est réglable dans canaux.ini.
+ Devrait fixer le problème de la Terratec Cynergy T2.
+
+
+
+ - 0.2a (publiée le 12 mars 2006) :
+
+ - Corrige scan complet sans préciser de ville,
+ sauvegarde
Always on top
dans les préférences.
+
+
+
+
+ - 0.2 :
+
+ - Correction des problèmes de compatibilité avec les clés USB, et les cartes qui ont besoin de 166 en offset.
+ - Sélection de la carte TNT pour ceux qui en ont plusieurs installées.
+ - Affiche le nom du programme en cours et de celui qui suit, ainsi que leurs horaires.
+ - Fenêtre d'EPG avec les progammes en cours sur toutes les chaînes.
+ - Peut afficher le nom du programme regardé sur MSN Messenger.
+ - Dialogue affichant la qualité du signal.
+ - Fonction
Always on top
.
+ - Affichage minimum (pas de menu, juste la vidéo), en faisant un clic gauche sur la zone vidéo.
+ - Peut définir la priorité du programme.
+ - Menu contextuel sur la zone vidéo.
+
+
+
+ - 0.1 (publiée le 4 mars 2006) :
+
+ - Première version publiée de Pouchin TV.
+
+
+
+
+
+
+
+
+ Dernière modification de cette page :
+
+
+
Modifié: trunk/channels.cpp
===================================================================
--- trunk/channels.cpp 2009-07-03 10:53:11 UTC (rev 194)
+++ trunk/channels.cpp 2009-07-09 16:19:22 UTC (rev 195)
@@ -200,6 +200,58 @@
}
/**
+ * Génération du nom affichable d'une piste audio pour le menu
+ * \param[in] nTrack Numéro de la piste audio
+ * \param[in] pstr Pointeur sur le tampon qui recevra le résultat
+ * \param[in] bufSize Taille du tampon
+ **/
+int Chaine::toAudioMenuString(int nTrack, LPTSTR pstr, size_t bufSize) const
+{
+ struct Langue {
+ char code[4];
+ LPCSTR szLang;
+ };
+
+ static const Langue Tab_Lang[] =
+ {
+ {"fra", "Français"},
+ {"fre", "Français"},
+ {"eng", "Anglais"},
+ {"ang", "Anglais"},
+ {"deu", "Allemand"},
+ {"spa", "Espagnol"},
+ {"ita", "Italien"},
+ {"por", "Portugais"},
+ {"qaa", "V.O."}
+ };
+
+ static const LPCSTR tblNomsAudio[] =
+ {
+ "MPG",
+ "AC3",
+ "EAC3"
+ };
+
+ char szLangue[32] = "";
+ const une_piste & son_courant = sons.tbl[nTrack];
+
+ for (int j=0; j < _countof(Tab_Lang); j++) {
+ const Langue & tlang = Tab_Lang[j];
+
+ if (strcmp(son_courant.lang, tlang.code)==0) {
+ strcpy_T(szLangue, tlang.szLang);
+ break;
+ }
+ }
+ if (szLangue[0] == 0)
+ strcpy_T(szLangue, son_courant.lang);
+
+ return _stprintf_s(pstr, bufSize,
+ TEXT("Audio %i %") A2t TEXT(" (%") A2t TEXT(")"), nTrack+1, szLangue,
+ son_courant.type > tst_EAC3 ? "???" : tblNomsAudio[son_courant.type]);
+}
+
+/**
* Obtenir la première émission de la liste dont l'heure de fin ne soit pas dépassée
*
* \param[in] localtime Heure de référence (en principe l'heure système)
@@ -629,13 +681,17 @@
**/
void switch_audio(int ixSon)
{
- if (ixSon != ixSonCourant) {
- const une_piste * son_courant = Canaux[ixChaineCourante].sons.tbl;
+ if (ixChaine_ok(ixChaineCourante) && ixSon != ixSonCourant) {
+ const Chaine & canal = Canaux[ixChaineCourante];
- debranche_son();
- branche_son(son_courant[ixSon]);
+ if (ixSon>=0 && ixSonDisplaySoundInfo(canal, ixSon);
+ }
}
}
Modifié: trunk/channels.h
===================================================================
--- trunk/channels.h 2009-07-03 10:53:11 UTC (rev 194)
+++ trunk/channels.h 2009-07-09 16:19:22 UTC (rev 195)
@@ -179,6 +179,14 @@
TEXT("%4i [%u] : %") A2t, nNumeroChaine, TSID, nom); }
/**
+ * Génération du nom affichable d'une piste audio pour le menu
+ * \param[in] nTrack Numéro de la piste audio
+ * \param[in] pstr Pointeur sur le tampon qui recevra le résultat
+ * \param[in] bufSize Taille du tampon
+ **/
+ int toAudioMenuString(int nTrack, LPTSTR pstr, size_t bufSize) const;
+
+ /**
* Obtenir la première émission de la liste dont l'heure de fin ne soit pas dépassée
*
* \param[in] localtime Heure de référence (en principe l'heure système)
Modifié: trunk/console.cpp
===================================================================
--- trunk/console.cpp 2009-07-03 10:53:11 UTC (rev 194)
+++ trunk/console.cpp 2009-07-09 16:19:22 UTC (rev 195)
@@ -39,8 +39,9 @@
#include
#if USE_CONSOLE==1
-HANDLE hStdOut = NULL;
-WindowPos consolePos;
+HWND hConsoleWnd = NULL;
+HANDLE hStdOut = NULL;
+WindowPos consolePos;
void startConsoleWin(bool alloc)
{
@@ -50,7 +51,7 @@
}
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (consolePos.verifie()) {
- HWND hConsoleWnd = GetConsoleWindow();
+ hConsoleWnd = GetConsoleWindow();
MoveWindow(hConsoleWnd, consolePos.X, consolePos.Y, max(consolePos.L, 100), max(consolePos.H, 100), TRUE);
}
}
Modifié: trunk/console.h
===================================================================
--- trunk/console.h 2009-07-03 10:53:11 UTC (rev 194)
+++ trunk/console.h 2009-07-09 16:19:22 UTC (rev 195)
@@ -39,7 +39,8 @@
#include "utils.h"
#if USE_CONSOLE==1
-extern WindowPos consolePos;
+extern HWND hConsoleWnd;
+extern WindowPos consolePos;
#endif
#if USE_CONSOLE
Modifié: trunk/ini.cpp
===================================================================
--- trunk/ini.cpp 2009-07-03 10:53:11 UTC (rev 194)
+++ trunk/ini.cpp 2009-07-09 16:19:22 UTC (rev 195)
@@ -76,6 +76,9 @@
{IDM_MUTE, TEXT("Couper le son"), TEXT("Son couper"), {false, false, false, TEXT('M')}},
{IDM_VOL_AUG, TEXT("Augmenter le volume"), TEXT("Son augmenter"), {false, false, false, VK_ADD}},
{IDM_VOL_DIM, TEXT("Diminuer le volume"), TEXT("Son diminuer"), {false, false, false, VK_SUBTRACT}},
+ {IDM_SON_AUG, TEXT("Piste audio suivante"), TEXT("Son suiv"), {false, false, true, VK_DOWN}},
+ {IDM_SON_DIM, TEXT("Piste audio précédente"), TEXT("Son préc"), {false, false, true, VK_UP}},
+
{IDM_FIRST_AUDIO, TEXT("Utiliser la première piste audio"), TEXT("Son piste 1"), {false, true, false, TEXT('1')}},
{IDM_SECOND_AUDIO, TEXT("Utiliser la seconde piste audio"), TEXT("Son piste 2"), {false, true, false, TEXT('2')}},
{IDM_AC3_AUDIO, TEXT("Utiliser la piste audio AC3"), TEXT("Son piste AC3"), {false, true, false, TEXT('3')}},
@@ -148,13 +151,13 @@
TCHAR video_dir[MAX_PATH];
UINT32 cleChaineConfig = 0;
-int avance_enreg = 8;
-int retard_enreg = 16;
+INT32 avance_enreg = 8;
+INT32 retard_enreg = 16;
extern SearchMethod
methode_recherche = INI_METHODE_RECH_DEFAULT;
OffsetsToUse use_offsets = INI_USE_OFFSETS_DEFAULT;
-int autonum_undef = INI_AUTONUM_UNDEF_DEFAULT;
-int autonum_duplicate = INI_AUTONUM_DUP_DEFAULT;
+INT32 autonum_undef = INI_AUTONUM_UNDEF_DEFAULT;
+INT32 autonum_duplicate = INI_AUTONUM_DUP_DEFAULT;
bool suspend_minimized = false;
bool minimize_system_tray = false;
bool use_vmr_deinterlace = false;
@@ -165,11 +168,15 @@
bool on_top = false;
bool use_ac3 = false;
bool use_osd = true;
+COLORREF osd_color = INI_OSD_COLOR;
+COLORREF aCustomColors[16] = {0};
+
+INT32 osd_transparency = INI_OSD_TRANSPARENCY;
VMRTypes vmr_mode;
PanModes video_pan_mode = pm_Normal;
-int zoom_ratio = 100;
-long volumeCourant = 0;
+INT32 zoom_ratio = 100;
+INT32 volumeCourant = 0;
bool use_multimedia = true;
MouseWheelUsage role_molette = mwu_Channels;
@@ -188,16 +195,16 @@
// Valeurs sauvegardées séparément pour chaque type de tuner :
TCHAR nom_receiver[256];
-int offset_tuner = 0;
+INT32 offset_tuner = 0;
bool try_adding_5khz = INI_TRY_ADDING_5KHZ_DEFAULT;
// bool use_even_frequencies = false;
-int delai_tuner1 = INI_DELAI_TUNER1_DEFAULT;
-int delai_tuner2 = INI_DELAI_TUNER2_DEFAULT;
+INT32 delai_tuner1 = INI_DELAI_TUNER1_DEFAULT;
+INT32 delai_tuner2 = INI_DELAI_TUNER2_DEFAULT;
bool scan_ignore_presence = false;
bool scan_ignore_lock = false;
bool scan_ignore_quality = false;
-int force_signal_zero = 0;
-int force_signal_max = 100;
+INT32 force_signal_zero = 0;
+INT32 force_signal_max = 100;
bool force_signal_aff_pct = false;
bool auto_resyntonisation = true;
@@ -243,74 +250,6 @@
}
// ====================================================================================
-// Sections dans le fichier de config
-// ====================================================================================
-static TCHAR ini_config_section[] = TEXT("Config"); ///< Nom de la section contenant la configuration
-static TCHAR ini_shortcut_section[] = TEXT("Raccourcis"); ///< Nom de la section contenant les raccourcis clavier
-static TCHAR ini_dontshow_section[] = TEXT("Désactiver"); ///< Nom de la section des messages à ne plus afficher
-
-static TCHAR ini_filtre_MPEG2[] = TEXT("Filtre MPEG2");
-static TCHAR ini_filtre_H264[] = TEXT("Filtre H264");
-static TCHAR ini_filtre_audio[] = TEXT("Filtre audio");
-static TCHAR ini_filtre_ac3[] = TEXT("Filtre AC3");
-static TCHAR ini_nom_ville[] = TEXT("Ville");
-static TCHAR ini_liste_canaux[] = TEXT("Liste de canaux");
-static TCHAR ini_strict[] = TEXT("Recherche stricte");
-static TCHAR ini_chaine_courante[] = TEXT("Identifiant chaîne courante");
-static TCHAR ini_avance_enreg[] = TEXT("Avance début enregistrements");
-static TCHAR ini_retard_enreg[] = TEXT("Retard fin enregistrements");
-static TCHAR ini_rep_video[] = TEXT("Répertoire vidéo");
-static TCHAR ini_rep_screen[] = TEXT("Répertoire screenshots");
-static TCHAR ini_priorite[] = TEXT("Priorité");
-static TCHAR ini_methode_recherche[] = TEXT("Méthode de recherche");
-static TCHAR ini_use_offsets[] = TEXT("Offsets");
-static TCHAR ini_autonum_undef[] = TEXT("Base numérotation inconnus");
-static TCHAR ini_autonum_duplicate[] = TEXT("Décalage numérotation duplicatas");
-static TCHAR ini_msn[] = TEXT("Envoie programme regardé à MSN");
-static TCHAR ini_titre_fenetre[] = TEXT("Titre de la fenêtre");
-static TCHAR ini_always_on_top[] = TEXT("Fenêtre toujours devant");
-static TCHAR ini_ac3_defaut[] = TEXT("Utilise AC3 quand dispo");
-static TCHAR ini_use_osd[] = TEXT("Utiliser l'OSD");
-static TCHAR ini_video_rendering[] = TEXT("Rendu vidéo");
-static TCHAR ini_suspend_minimized[] = TEXT("Suspendre si minimisé");
-static TCHAR ini_minimize_system_tray[] = TEXT("Minimiser dans le system tray");
-static TCHAR ini_allow_stream_record[] = TEXT("Enregistrement multiplex autorisé");
-static TCHAR ini_video_pan_mode[] = TEXT("Panoramique");
-static TCHAR ini_zoom_ratio[] = TEXT("Facteur de zoom");
-static TCHAR ini_volume[] = TEXT("Volume");
-static TCHAR ini_use_multimedia[] = TEXT("Gérer les commandes multimédia");
-static TCHAR ini_role_molette[] = TEXT("Molette de la souris");
-static TCHAR ini_inversion_molette[] = TEXT("Inversion du sens de la molette");
-static TCHAR ini_motif_noms_enreg[] = TEXT("Nom du fichier d'enregistrement");
-static TCHAR ini_position_fenetre[] = TEXT("Position fenêtre");
-static TCHAR ini_use_vmr_deinterlace[] = TEXT("Utilise le désentrelacement du VMR");
-static TCHAR ini_etat_fenetre[] = TEXT("État fenêtre");
-static TCHAR ini_epg_typerecvideo[] = TEXT("Type d'enregistrement video");
-static TCHAR ini_epg_typerecaudio[] = TEXT("Type d'enregistrement audio");
-
-#if USE_CONSOLE==1
-static TCHAR ini_position_console[] = TEXT("Position console");
-#endif // #if USE_CONSOLE==1
-
-static TCHAR ini_autre_graphe[] = TEXT("Graphe alternatif");
-static TCHAR ini_tuner[] = TEXT("Tuner TNT");
-
-// Valeurs sauvegardées séparément pour chaque type de tuner :
-static TCHAR ini_receiver[] = TEXT("Récepteur TNT");
-static TCHAR ini_offset_tuner[] = TEXT("Offset tuner");
-// static TCHAR ini_use_even_frequencies[] = TEXT("Aligner aux 2 kHz");
-static TCHAR ini_try_adding_5khz[] = TEXT("Essayer +5 kHz si échec");
-static TCHAR ini_delai_tuner1[] = TEXT("Délai verrouillage tuner");
-static TCHAR ini_delai_tuner2[] = TEXT("Délai recherche tuner");
-static TCHAR ini_scan_ignore_presence[] = TEXT("Ignorer signal présent");
-static TCHAR ini_scan_ignore_lock[] = TEXT("Ignorer signal verrouillé");
-static TCHAR ini_scan_ignore_quality[] = TEXT("Ignorer signal qualité");
-static TCHAR ini_force_signal_zero[] = TEXT("Valeur force signal nulle");
-static TCHAR ini_force_signal_max[] = TEXT("Décalage force signal maximale");
-static TCHAR ini_force_signal_aff_pct[] = TEXT("Force du signal en pourcentage");
-static TCHAR ini_auto_resyntonisation[] = TEXT("Resyntonisation auto");
-
-// ====================================================================================
// Tableaux associatifs
// ====================================================================================
@@ -452,11 +391,143 @@
{TEXT("Aucun"), (DWORD)mwu_None},
{TEXT("Chaînes"), (DWORD)mwu_Channels},
{TEXT("Chaînes multiplex"), (DWORD)mwu_Channels_MX},
+ {TEXT("Piste audio"), (DWORD)mvu_Soundtrack},
{TEXT("Volume"), (DWORD)mwu_Volume},
{TEXT("Zoom"), (DWORD)mvu_Zoom},
{NULL, 0} // -> terminateur
};
+
// ====================================================================================
+// Descripteurs d'items de configuration
+// ====================================================================================
+
+/// Types d'items de configuration
+enum ConfigItemTypes
+{
+ cit_INT, //!< Valeur entière signée (utiliser type \p INT32)
+ cit_HEX, //!< Valeur entière hexa non signée (utiliser type \p UINT32 ou \p DWORD ou équiv.)
+ cit_BOOL, //!< Valeur booléenne
+ cit_STR, //!< Chaîne de caractères
+ cit_DRV, //!< Chaîne de caractères spécialisée (nom de pilote ou de codec)
+ cit_PATH, //!< Chaîne de caractères spécialisée (chemin de répertoire)
+ cit_ASSOC, //!< Association entier <-> chaîne (typiquement énumération)
+ cit_WPOS //!< Position de fenêtre
+};
+
+/// Description d'un item de configuration
+struct ConfigItem
+{
+ LPCTSTR pszName; //!< Nom de l'item de configuration
+ ConfigItemTypes eType; //!< Type de la variable
+ LONG_PTR nDef; //!< Valeur par défaut (utiliser un cast de type au besoin)
+ LPVOID pVar; //!< Adresse de la variable
+ LONG_PTR nExtra; //!< \brief Données complémentaires (utiliser un cast de type au besoin)
+ //!< - \p cit_STR, \p cit_DRV ou \p cit_PATH : taille de la variable
+ //!< - \p cit_ASSOC : adresse de la table
+ //!< - \p cit_WPOS : adresse de la "handle" de la fenêtre)
+};
+
+#define CONFIG_STR(str) &str, _countof(str)
+#define CONFIG_VAL(val) reinterpret_cast(val)
+
+// Sections dans le fichier de config
+static LPCTSTR ini_config_section = TEXT("Config"); ///< Nom de la section contenant la configuration
+static LPCTSTR ini_shortcut_section = TEXT("Raccourcis"); ///< Nom de la section contenant les raccourcis clavier
+static LPCTSTR ini_dontshow_section = TEXT("Désactiver"); ///< Nom de la section des messages à ne plus afficher
+
+static LPCTSTR ini_color_num = TEXT("Couleur Perso %02u"); ///< Nom de sauvegarde des couleurs perso
+
+/// Liste des items sauvegardés globalement
+static ConfigItem ini_general_items[] =
+{ // Nom Type Défaut Variable Extra
+ {TEXT("Filtre MPEG2"), cit_DRV, NULL, CONFIG_STR(filtreMPEG2)},
+ {TEXT("Filtre H264"), cit_DRV, NULL, CONFIG_STR(filtreH264)},
+ {TEXT("Filtre audio"), cit_DRV, NULL, CONFIG_STR(filtreAudio)},
+ {TEXT("Filtre AC3"), cit_DRV, NULL, CONFIG_STR(filtreAc3)},
+
+ {TEXT("Recherche stricte"), cit_BOOL, true, & exact_match},
+ {TEXT("Graphe alternatif"), cit_BOOL, false, & autre_graphe},
+ {TEXT("Utilise AC3 quand dispo"), cit_BOOL, false, & use_ac3},
+
+ {TEXT("Ville"), cit_STR, CONFIG_VAL(NULL_NAME), CONFIG_STR(nomVille)},
+ {TEXT("Liste de canaux"), cit_STR, CONFIG_VAL(TEXT("21-69")), CONFIG_STR(liste_canaux)},
+
+ {TEXT("Méthode de recherche"), cit_ASSOC, INI_METHODE_RECH_DEFAULT, & methode_recherche, CONFIG_VAL(aSMethodTable)},
+ {TEXT("Offsets"), cit_ASSOC, INI_USE_OFFSETS_DEFAULT, & use_offsets, CONFIG_VAL(aOffsetsToUse)},
+ {TEXT("Base numérotation inconnus"), cit_INT, INI_AUTONUM_UNDEF_DEFAULT, & autonum_undef},
+ {TEXT("Décalage numérotation duplicatas"), cit_INT, INI_AUTONUM_DUP_DEFAULT, & autonum_duplicate},
+
+ {TEXT("Identifiant chaîne courante"), cit_HEX, 0, & cleChaineConfig},
+ {TEXT("Avance début enregistrements"), cit_INT, 8, & avance_enreg},
+ {TEXT("Retard fin enregistrements"), cit_INT, 16, & retard_enreg},
+ {TEXT("Enregistrement multiplex autorisé"), cit_BOOL, false, & allow_stream_record},
+
+ // CSIDL_MYVIDEO : Répertoire "Mes vidéos" (utilisé par défaut)
+ {TEXT("Répertoire vidéo"), cit_PATH, CSIDL_MYVIDEO, CONFIG_STR(video_dir)},
+
+ // CSIDL_MYPICTURES : Répertoire "Mes images" (utilisé par défaut)
+ {TEXT("Répertoire screenshots"), cit_PATH, CSIDL_MYPICTURES, CONFIG_STR(screenshots_dir)},
+
+ {TEXT("Nom du fichier d'enregistrement"), cit_STR, CONFIG_VAL(TEXT(MOTIF_NOMS_ENREG_DEFAULT)),
+ CONFIG_STR(motif_noms_enreg)},
+ {TEXT("Type d'enregistrement video"), cit_ASSOC, meth_TS, & epg_typerecvideo, CONFIG_VAL(aEpgRecVideo)},
+ {TEXT("Type d'enregistrement audio"), cit_ASSOC, audio_1, & epg_typerecaudio, CONFIG_VAL(aEpgRecAudio)},
+
+ {TEXT("Titre de la fenêtre"), cit_STR, CONFIG_VAL(szAppName), CONFIG_STR(titre_fenetre)},
+ {TEXT("Fenêtre toujours devant"), cit_BOOL, false, & on_top},
+ {TEXT("Envoie programme regardé à MSN"), cit_BOOL, false, & use_msn},
+
+ {TEXT("Utiliser l'OSD"), cit_BOOL, true, & use_osd},
+ {TEXT("Couleur OSD"), cit_HEX, INI_OSD_COLOR, & osd_color},
+ {TEXT("Transparence OSD"), cit_INT, INI_OSD_TRANSPARENCY, & osd_transparency},
+ {TEXT("Rendu vidéo"), cit_ASSOC, vmt_VMR9_windowless, & vmr_mode, CONFIG_VAL(aVMRModeTable)},
+ {TEXT("Utilise le désentrelacement du VMR"),cit_BOOL, false, & use_vmr_deinterlace},
+
+ {TEXT("Suspendre si minimisé"), cit_BOOL, false, & suspend_minimized},
+ {TEXT("Minimiser dans le system tray"), cit_BOOL, false, & minimize_system_tray},
+ {TEXT("Panoramique"), cit_ASSOC, pm_Normal, & video_pan_mode, CONFIG_VAL(aPanModeTable)},
+ {TEXT("Facteur de zoom"), cit_INT, 100, & zoom_ratio},
+ {TEXT("Volume"), cit_INT, 100, & volumeCourant},
+
+ {TEXT("Gérer les commandes multimédia"), cit_BOOL, true, & use_multimedia},
+ {TEXT("Molette de la souris"), cit_ASSOC, mwu_Channels, & role_molette, CONFIG_VAL(aMWheelTable)},
+ {TEXT("Inversion du sens de la molette"), cit_BOOL, false, & inversion_molette},
+
+ {TEXT("État fenêtre"), cit_ASSOC, etf_normal, & configState, CONFIG_VAL(aWStateTable)},
+ {TEXT("Position fenêtre"), cit_WPOS, MAKELONG(800, 600), & winPos, CONFIG_VAL(&hMainWnd)},
+
+#if USE_CONSOLE==1
+ {TEXT("Position console"), cit_WPOS, MAKELONG(400, 300), & consolePos, CONFIG_VAL(&hConsoleWnd)},
+#endif
+
+ {TEXT("Priorité"), cit_ASSOC, ABOVE_NORMAL_PRIORITY_CLASS, & configPriority, CONFIG_VAL(aPrioTable)}
+};
+
+/// Item de sélection du tuner lui-même
+static ConfigItem ini_tuner = {
+ TEXT("Tuner TNT"), cit_DRV, NULL, CONFIG_STR(nom_tuner)
+};
+
+/// Liste des items sauvegardés séparément pour chaque type de tuner
+static ConfigItem ini_tuner_items[] =
+{ // Nom Type Défaut Variable
+ // Récepteur TNT en première position (à cause d'une fonction qui l'utilise via l'index 0)
+ {TEXT("Récepteur TNT"), cit_DRV, NULL, CONFIG_STR(nom_receiver)},
+ //
+ {TEXT("Offset tuner"), cit_INT, 0, & offset_tuner},
+ {TEXT("Essayer +5 kHz si échec"), cit_BOOL, INI_TRY_ADDING_5KHZ_DEFAULT, & try_adding_5khz},
+ {TEXT("Délai verrouillage tuner"), cit_INT, INI_DELAI_TUNER1_DEFAULT, & delai_tuner1},
+ {TEXT("Délai recherche tuner"), cit_INT, INI_DELAI_TUNER2_DEFAULT, & delai_tuner2},
+ {TEXT("Ignorer signal présent"), cit_BOOL, false, & scan_ignore_presence},
+ {TEXT("Ignorer signal verrouillé"), cit_BOOL, false, & scan_ignore_lock},
+ {TEXT("Ignorer signal qualité"), cit_BOOL, false, & scan_ignore_quality},
+ {TEXT("Valeur force signal nulle"), cit_INT, 0, & force_signal_zero},
+ {TEXT("Décalage force signal maximale"), cit_INT, 100, & force_signal_max},
+ {TEXT("Force du signal en pourcentage"), cit_BOOL, false, & force_signal_aff_pct},
+ {TEXT("Resyntonisation auto"), cit_BOOL, true, & auto_resyntonisation}
+};
+
+// ====================================================================================
// Raccourcis (clavier)
// ====================================================================================
@@ -802,7 +873,7 @@
}
// ====================================================================================
-// Classe d'accès aux fichiers d'initialisation (.ini)
+/// Classe d'accès aux fichiers d'initialisation (.ini)
// ====================================================================================
class CIniFile
@@ -849,9 +920,20 @@
* \retval "une valeur non nulle" en cas de succès
* \retval 0 en cas d'erreur
**/
- BOOL save_int(LPCTSTR lpKeyName, LONG value);
+ BOOL save_int(LPCTSTR lpKeyName, INT32 value);
/**
+ * Écrit une valeur numérique au format hexadécimal 32 bits
+ *
+ * \param[in] lpKeyName nom de la clé devant être utilisée
+ * \param[in] value valeur numérique à enregistrer
+ * \retval "une valeur non nulle" en cas de succès
+ * \retval 0 en cas d'erreur
+ * \note Les valeurs de ce type sont récupérables avec \p load_int
+ **/
+ BOOL save_hex32(LPCTSTR lpKeyName, UINT32 value);
+
+ /**
* Écriture de la chaîne de caractères associée à une valeur fournie
*
* \param[in] lpKeyName nom de la clé devant être utilisée
@@ -899,7 +981,7 @@
* \param[in] nDefault valeur par défaut, si on n'a rien trouvé
* \return valeur recherchée (trouvée, ou par défaut)
**/
- INT load_int(LPCTSTR lpKeyName, INT nDefault);
+ INT32 load_int(LPCTSTR lpKeyName, INT nDefault);
/**
* Cherche une valeur numérique, en convertissant la valeur textuelle contenue dans le fichier de configuration
@@ -976,7 +1058,7 @@
* \retval "une valeur non nulle" en cas de succès
* \retval 0 en cas d'erreur
**/
-BOOL CIniFile::save_int(LPCTSTR lpKeyName, LONG value)
+BOOL CIniFile::save_int(LPCTSTR lpKeyName, INT32 value)
{
TCHAR valeur[64];
@@ -985,6 +1067,22 @@
}
/**
+ * Écrit une valeur numérique au format hexadécimal 32 bits
+ *
+ * \param[in] lpKeyName nom de la clé devant être utilisée
+ * \param[in] value valeur numérique à enregistrer
+ * \retval "une valeur non nulle" en cas de succès
+ * \retval 0 en cas d'erreur
+ **/
+BOOL CIniFile::save_hex32(LPCTSTR lpKeyName, UINT32 value)
+{
+ TCHAR valeur[64];
+
+ _stprintf_s(valeur, TEXT("0x%08x"), value);
+ return save_str(lpKeyName, valeur);
+}
+
+/**
* Écriture de la chaîne de caractères associée à une valeur fournie
*
* \param[in] lpKeyName nom de la clé devant être utilisée
@@ -1032,7 +1130,7 @@
* \param[in] nDefault valeur par défaut, si on n'a rien trouvé
* \return valeur recherchée (trouvée, ou par défaut)
**/
-INT CIniFile::load_int(LPCTSTR lpKeyName, INT nDefault)
+INT32 CIniFile::load_int(LPCTSTR lpKeyName, INT nDefault)
{
return (INT)GetPrivateProfileInt(szSectionName, lpKeyName, nDefault, sIniFilePathName);
}
@@ -1066,7 +1164,7 @@
}
// ====================================================================================
-// Classe d'accès au fichier de configuration générale
+/// Classe d'accès au fichier de configuration générale
// ====================================================================================
class CConfigFile : public CIniFile
@@ -1123,6 +1221,28 @@
BOOL save_shortcut(LPCTSTR lpKeyName, const Raccourci & sShtCut, const Raccourci & sShtDef);
/**
+ * Sauvegarde d'un item décrit par structure
+ *
+ * \param[in] sItem description de l'item à sauvegarder
+ **/
+ void save_item(const ConfigItem & sItem);
+
+ /**
+ * Chargement d'une liste d'items
+ **/
+ template
+ void save_items(const ConfigItem(&aItDescr)[S])
+ {
+ for (int nInx=0; nInx < S; ++nInx)
+ save_item(aItDescr[nInx]);
+ }
+
+ /**
+ * Sauvegarde des couleurs personnalisées
+ **/
+ void save_colors();
+
+ /**
* Sauvegarde tous les raccourcis
**/
void save_raccourcis();
@@ -1188,6 +1308,30 @@
void load_shortcut(LPCTSTR lpKeyName, Raccourci & sShtCut, bool reset);
/**
+ * Chargement d'un item décrit par structure
+ *
+ * \param[in] sItem description de l'item à charger
+ * \return (pour les chaînes seulement) nombre de caractères copiés,
+ * sans tenir compte du caractère '\\0'
+ **/
+ DWORD load_item(const ConfigItem & sItem);
+
+ /**
+ * Chargement d'une liste d'items
+ **/
+ template
+ void load_items(const ConfigItem(&aItDescr)[S])
+ {
+ for (int nInx=0; nInx < S; ++nInx)
+ load_item(aItDescr[nInx]);
+ }
+
+ /**
+ * Chargement des couleurs personnalisées
+ **/
+ void load_colors();
+
+ /**
* Charge les raccourcis
*
* \param[in] reset si \a true , on charge les raccourcis par défaut
@@ -1412,10 +1556,7 @@
// Programmations d'enregistrements
// ====================================================================================
-/**
- * Nom des différents éléments consituant la date/heure.
- * Utile uniquement pour lire/écrire dans les fichiers XML
- **/
+/// Noms des différents éléments consituant la date et l'heure dans \p programmes.xml.
struct XMLSystemTimeNames {
LPCTSTR name_wYear; ///< Année
LPCTSTR name_wMonth; ///< Mois
@@ -1937,6 +2078,23 @@
}
/**
+ * Sauvegarde des couleurs personnalisées
+ **/
+void CConfigFile::save_colors()
+{
+ for (int nInx=0; nInx<_countof(aCustomColors); ++nInx) {
+ COLORREF col = aCustomColors[nInx];
+
+ if (col != RGB(192, 192, 192)) {
+ TCHAR szKey[64];
+
+ _stprintf_s(szKey, ini_color_num, nInx);
+ save_hex32(szKey, col);
+ }
+ }
+}
+
+/**
* Sauvegarde des raccourcis dans leur section
**/
void CConfigFile::save_raccourcis()
@@ -1960,6 +2118,46 @@
}
}
+/**
+ * Sauvegarde d'un item décrit par structure
+ *
+ * \param[in] sItem description de l'item à sauvegarder
+ **/
+void CConfigFile::save_item(const ConfigItem & sItem)
+{
+ switch (sItem.eType) {
+
+ case cit_INT:
+ save_int(sItem.pszName, *reinterpret_cast(sItem.pVar));
+ break;
+
+ case cit_HEX:
+ save_hex32(sItem.pszName, *reinterpret_cast(sItem.pVar));
+ break;
+
+ case cit_BOOL:
+ save_bool(sItem.pszName, *reinterpret_cast(sItem.pVar));
+ break;
+
+ case cit_STR:
+ case cit_PATH:
+ save_str(sItem.pszName, reinterpret_cast(sItem.pVar));
+ break;
+
+ case cit_DRV:
+ save_driver_str(sItem.pszName, reinterpret_cast(sItem.pVar));
+ break;
+
+ case cit_ASSOC:
+ save_assoc(sItem.pszName, reinterpret_cast(sItem.nExtra),
+ *reinterpret_cast(sItem.pVar));
+ break;
+
+ case cit_WPOS:
+ save_winpos(sItem.pszName, *reinterpret_cast(sItem.nExtra));
+ }
+}
+
// ====================================================================================
// Sauvegarde de la configuration générale
// ====================================================================================
@@ -1982,19 +2180,7 @@
NewTunerSection(nom_tuner);
- save_driver_str(ini_receiver, nom_receiver);
- save_int(ini_offset_tuner, offset_tuner);
- save_bool(ini_try_adding_5khz, try_adding_5khz);
- //save_bool(ini_use_even_frequencies, use_even_frequencies);
- save_int(ini_delai_tuner1, delai_tuner1);
- save_int(ini_delai_tuner2, delai_tuner2);
- save_bool(ini_scan_ignore_presence, scan_ignore_presence);
- save_bool(ini_scan_ignore_lock, scan_ignore_lock);
- save_bool(ini_scan_ignore_quality, scan_ignore_quality);
- save_int(ini_force_signal_zero, force_signal_zero);
- save_int(ini_force_signal_max, force_signal_max);
- save_bool(ini_force_signal_aff_pct, force_signal_aff_pct);
- save_bool(ini_auto_resyntonisation, auto_resyntonisation);
+ save_items(ini_tuner_items);
}
/**
@@ -2002,61 +2188,28 @@
**/
void save_config()
{
- CConfigFile cConfig;
+ // Actualiser 'cleChaineConfig' au cas où on relancerait immédiatement l'application
+ cleChaineConfig = indexToCle(ixChaineCourante);
- cConfig.save_driver_str(ini_tuner, nom_tuner);
- cConfig.save_bool(ini_autre_graphe, autre_graphe);
+ // Actualiser la priorité
+ configPriority = get_priority();
- cConfig.save_assoc(ini_methode_recherche, aSMethodTable, // (on ne sauve pas l'état
- min(methode_recherche, sm_prefs)); // "tout réinitialiser")
- cConfig.save_assoc(ini_use_offsets, aOffsetsToUse, use_offsets);
- cConfig.save_int(ini_autonum_undef, autonum_undef);
- cConfig.save_int(ini_autonum_duplicate, autonum_duplicate);
- cConfig.save_driver_str(ini_filtre_MPEG2, filtreMPEG2);
- cConfig.save_driver_str(ini_filtre_H264, filtreH264);
- cConfig.save_driver_str(ini_filtre_audio, filtreAudio);
- cConfig.save_driver_str(ini_filtre_ac3, filtreAc3);
- cConfig.save_str(ini_nom_ville, nomVille);
- cConfig.save_str(ini_liste_canaux, liste_canaux);
- cConfig.save_str(ini_motif_noms_enreg, motif_noms_enreg);
- cConfig.save_bool(ini_strict, exact_match);
+ // État de la fenêtre
+ configState = etat_fenetre(hMainWnd);
- // Actualiser 'sidChaineConfig' au cas où on relancerait immédiatement l'application
- cleChaineConfig = indexToCle(ixChaineCourante);
- cConfig.save_int(ini_chaine_courante, cleChaineConfig);
+#if USE_CONSOLE==1
+ // Handle de la console
+ hConsoleWnd = GetConsoleWindow();
+#endif
- cConfig.save_str(ini_rep_video, video_dir);
- cConfig.save_str(ini_rep_screen, screenshots_dir);
- cConfig.save_int(ini_avance_enreg, avance_enreg);
- cConfig.save_int(ini_retard_enreg, retard_enreg);
- cConfig.save_assoc(ini_priorite, aPrioTable, get_priority());
- cConfig.save_bool(ini_msn, use_msn);
- cConfig.save_bool(ini_always_on_top, on_top);
- cConfig.save_bool(ini_ac3_defaut, use_ac3);
- cConfig.save_bool(ini_use_osd, use_osd);
- cConfig.save_assoc(ini_video_rendering, aVMRModeTable, vmr_mode);
- cConfig.save_bool(ini_suspend_minimized, suspend_minimized);
- cConfig.save_bool(ini_minimize_system_tray, minimize_system_tray);
- cConfig.save_bool(ini_allow_stream_record, allow_stream_record);
- cConfig.save_assoc(ini_video_pan_mode, aPanModeTable, video_pan_mode);
- cConfig.save_bool(ini_use_vmr_deinterlace, use_vmr_deinterlace);
- cConfig.save_assoc(ini_etat_fenetre, aWStateTable, etat_fenetre(hMainWnd));
- cConfig.save_int(ini_zoom_ratio, zoom_ratio);
- cConfig.save_winpos(ini_position_fenetre, hMainWnd);
+ CConfigFile cConfig;
- cConfig.save_str(ini_titre_fenetre, titre_fenetre);
-#if USE_CONSOLE==1
- cConfig.save_winpos(ini_position_console, GetConsoleWindow());
-#endif // #if USE_CONSOLE==1
- cConfig.save_int(ini_volume, volumeCourant);
- cConfig.save_bool(ini_use_multimedia, use_multimedia);
- cConfig.save_assoc(ini_role_molette, aMWheelTable, role_molette);
- cConfig.save_bool(ini_inversion_molette, inversion_molette);
+ cConfig.save_item(ini_tuner);
- if (epg_typerecvideo!=meth_multiplex) // On ne sauve pas le mode "enregistrement du multiplex"
- cConfig.save_assoc(ini_epg_typerecvideo, aEpgRecVideo, epg_typerecvideo);
+ cConfig.save_items(ini_general_items);
- cConfig.save_assoc(ini_epg_typerecaudio, aEpgRecAudio, epg_typerecaudio);
+ // Couleurs perso, s'il y a lieu
+ cConfig.save_colors();
// Section spécifique au tuner
cConfig.save_tuner_config();
@@ -2256,6 +2409,60 @@
hMainAccel = CreateAcceleratorTable(accel, j+1);
}
+/**
+ * Chargement des couleurs personnalisées
+ **/
+void CConfigFile::load_colors()
+{
+ for (int nInx=0; nInx<_countof(aCustomColors); ++nInx) {
+ COLORREF & col = aCustomColors[nInx];
+ TCHAR szKey[64];
+
+ _stprintf_s(szKey, ini_color_num, nInx);
+ col = (COLORREF)load_int(szKey, RGB(192, 192, 192));
+ }
+}
+
+/**
+ * Chargement d'un item décrit par structure
+ *
+ * \param[in] sItem description de l'item à charger
+ **/
+DWORD CConfigFile::load_item(const ConfigItem & sItem)
+{
+ switch (sItem.eType) {
+
+ case cit_INT:
+ case cit_HEX:
+ *reinterpret_cast(sItem.pVar) = load_int(sItem.pszName, (INT)sItem.nDef);
+ break;
+
+ case cit_BOOL:
+ *reinterpret_cast(sItem.pVar) = load_bool(sItem.pszName, sItem.nDef!=0);
+ break;
+
+ case cit_STR:
+ return load_str(sItem.pszName, reinterpret_cast(sItem.pVar),
+ (DWORD)sItem.nExtra, reinterpret_cast(sItem.nDef));
+
+ case cit_DRV:
+ return load_driver_str(sItem.pszName,
+ reinterpret_cast(sItem.pVar), (DWORD)sItem.nExtra);
+
+ case cit_PATH:
+ return load_path(sItem.pszName, reinterpret_cast(sItem.pVar), (DWORD)sItem.nExtra, (int)sItem.nDef);
+
+ case cit_WPOS:
+ load_winpos(sItem.pszName, *reinterpret_cast(sItem.pVar), LOWORD(sItem.nDef), HIWORD(sItem.nDef));
+ break;
+
+ case cit_ASSOC:
+ *reinterpret_cast(sItem.pVar) = load_assoc(sItem.pszName,
+ reinterpret_cast(sItem.nExtra), (DWORD)sItem.nDef);
+ }
+ return 0;
+}
+
// ====================================================================================
// Chargement de la configuration générale
// ====================================================================================
@@ -2284,7 +2491,7 @@
CConfigFile cConfig;
cConfig.NewTunerSection(pszNomTuner);
- cConfig.load_driver_str(ini_receiver, pszReceiver, bufReceiverSize);
+ cConfig.load_driver_str(ini_tuner_items[0].pszName, pszReceiver, bufReceiverSize);
}
/**
@@ -2307,19 +2514,7 @@
NewTunerSection(nom_tuner);
- load_driver_str(ini_receiver, nom_receiver);
- offset_tuner = load_int(ini_offset_tuner, 0);
- try_adding_5khz = load_bool(ini_try_adding_5khz, INI_TRY_ADDING_5KHZ_DEFAULT);
- // use_even_frequencies = load_bool(ini_use_even_frequencies, false);
- delai_tuner1 = load_int(ini_delai_tuner1, INI_DELAI_TUNER1_DEFAULT);
- delai_tuner2 = load_int(ini_delai_tuner2, INI_DELAI_TUNER2_DEFAULT);
- scan_ignore_presence = load_bool(ini_scan_ignore_presence, false);
- scan_ignore_lock = load_bool(ini_scan_ignore_lock, false);
- scan_ignore_quality = load_bool(ini_scan_ignore_quality, false);
- force_signal_zero = load_int(ini_force_signal_zero, 0);
- force_signal_max = load_int(ini_force_signal_max, 100);
- force_signal_aff_pct = load_bool(ini_force_signal_aff_pct, false);
- auto_resyntonisation = load_bool(ini_auto_resyntonisation, true);
+ load_items(ini_tuner_items);
}
/**
@@ -2331,12 +2526,12 @@
CConfigFile cConfig;
// Recherche si on a un fichier de config dans AppData
- if (cConfig.load_driver_str(ini_tuner, nom_tuner) == 0) {
+ if (cConfig.load_item(ini_tuner) == 0) {
// Pas de tuner trouvé. On recherche dans le dossier courant
CConfigFile cConfig2(pouchindir_prog);
// Vérifie si on a une réponse
- if (cConfig2.load_driver_str(ini_tuner, nom_tuner) != 0) {
+ if (cConfig2.load_item(ini_tuner) != 0) {
// la config du tuner a été trouvée dans le répertoire de PTVM
// On change le répertoire de config vers celui du programme
swap(cConfig, cConfig2);
@@ -2347,69 +2542,22 @@
}
}
- autre_graphe = cConfig.load_bool(ini_autre_graphe, false);
+ cConfig.load_items(ini_general_items);
- cConfig.load_driver_str(ini_filtre_MPEG2, filtreMPEG2);
- cConfig.load_driver_str(ini_filtre_H264, filtreH264);
+ cConfig.load_colors();
- methode_recherche = (SearchMethod)cConfig.load_assoc(ini_methode_recherche,
- aSMethodTable, INI_METHODE_RECH_DEFAULT);
- use_offsets = (OffsetsToUse)cConfig.load_assoc(ini_use_offsets,
- aOffsetsToUse, INI_USE_OFFSETS_DEFAULT);
- autonum_undef = cConfig.load_int(ini_autonum_undef, INI_AUTONUM_UNDEF_DEFAULT);
- autonum_duplicate = cConfig.load_int(ini_autonum_duplicate, INI_AUTONUM_DUP_DEFAULT);
-
- cConfig.load_driver_str(ini_filtre_audio, filtreAudio);
- cConfig.load_driver_str(ini_filtre_ac3, filtreAc3);
- cConfig.load_str(ini_nom_ville, nomVille, NULL_NAME);
- cConfig.load_str(ini_liste_canaux, liste_canaux, TEXT("21-69"));
- cConfig.load_str(ini_motif_noms_enreg, motif_noms_enreg, TEXT(MOTIF_NOMS_ENREG_DEFAULT));
-
- exact_match = cConfig.load_bool(ini_strict, true);
- cleChaineConfig = (UINT32)cConfig.load_int(ini_chaine_courante, 0);
-
- // CSIDL_MYVIDEO : Répertoire "Mes vidéos" (utilisé par défaut)
- cConfig.load_path(ini_rep_video, video_dir, _countof(video_dir), CSIDL_MYVIDEO);
-
- // CSIDL_MYPICTURES : Répertoire "Mes images" (utilisé par défaut)
- cConfig.load_path(ini_rep_screen, screenshots_dir, _countof(screenshots_dir), CSIDL_MYPICTURES);
-
- avance_enreg = cConfig.load_int(ini_avance_enreg, 8);
- retard_enreg = cConfig.load_int(ini_retard_enreg, 16);
- configPriority = cConfig.load_assoc(ini_priorite, aPrioTable, ABOVE_NORMAL_PRIORITY_CLASS);
- use_msn = cConfig.load_bool(ini_msn);
- on_top = cConfig.load_bool(ini_always_on_top);
- use_ac3 = cConfig.load_bool(ini_ac3_defaut);
- use_osd = cConfig.load_bool(ini_use_osd, true);
- vmr_mode = (VMRTypes)cConfig.load_assoc(ini_video_rendering, aVMRModeTable, vmt_VMR9_windowless);
- suspend_minimized = cConfig.load_bool(ini_suspend_minimized);
- minimize_system_tray = cConfig.load_bool(ini_minimize_system_tray);
- allow_stream_record = cConfig.load_bool(ini_allow_stream_record);
- use_vmr_deinterlace = cConfig.load_bool(ini_use_vmr_deinterlace);
- configState = (EtatsFenetre)cConfig.load_assoc(ini_etat_fenetre, aWStateTable, etf_normal);
-
- cConfig.load_str(ini_titre_fenetre, titre_fenetre, szAppName);
- cConfig.load_winpos(ini_position_fenetre, winPos, 800, 600);
-#if USE_CONSOLE==1
- cConfig.load_winpos(ini_position_console, consolePos, 400, 300);
-#endif // #if USE_CONSOLE==1
-
- video_pan_mode = (PanModes)cConfig.load_assoc(ini_video_pan_mode, aPanModeTable, pm_Normal);
-
- zoom_ratio = cConfig.load_int(ini_zoom_ratio, 100);
- volumeCourant = cConfig.load_int(ini_volume, 100);
- use_multimedia = cConfig.load_bool(ini_use_multimedia, true);
- role_molette = (MouseWheelUsage)cConfig.load_assoc(ini_role_molette, aMWheelTable, mwu_Channels);
- inversion_molette = cConfig.load_bool(ini_inversion_molette);
-
- epg_typerecvideo = (MethodeEnregistrement)cConfig.load_assoc(ini_epg_typerecvideo, aEpgRecVideo, meth_TS);
- epg_typerecaudio = (AudioMode)cConfig.load_assoc(ini_epg_typerecaudio, aEpgRecAudio, audio_1);
-
// Section spécifique au tuner
cConfig.load_tuner_config();
// Section des raccourcis
cConfig.load_raccourcis();
+
+ // Post-ajustements :
+ if (methode_recherche == sm_full) // On ne restaure pas l'état
+ methode_recherche = sm_prefs; // "tout réinitialiser"
+
+ if (epg_typerecvideo == meth_multiplex) // On ne restaure pas le mode
+ epg_typerecvideo = meth_TS; // "enregistrement du multiplex"
}
// ====================================================================================
@@ -2474,6 +2622,7 @@
}
}
+/// Ajout d'une option "Ne plus afficher ce message" aux dialogues de messages
struct MessageBoxHookData
{
/// Liste simplifiée de types d'items
@@ -2499,8 +2648,7 @@
return ct_other;
}
- /// Structure destinée à récupérer les informations concernant les items présents dans la
- /// boîte de dialogue
+ /// Récupération des informations concernant les items présents dans la boîte de dialogue
struct ParseItemsHelper
{
RECT sAllItemsRect; //!< Union des rectangles de tous les items (sauf statiques vides)
Modifié: trunk/ini.h
===================================================================
--- trunk/ini.h 2009-07-03 10:53:11 UTC (rev 194)
+++ trunk/ini.h 2009-07-09 16:19:22 UTC (rev 195)
@@ -129,6 +129,7 @@
mwu_None, //!< Aucun effet
mwu_Channels, //!< Changer de chaîne
mwu_Channels_MX, //!< Changer de chaîne (même multiplex)
+ mvu_Soundtrack, //!< Changer de piste audio
mwu_Volume, //!< Régler le volume
mvu_Zoom //!< Régler le zoom
};
@@ -141,8 +142,6 @@
* Ces variables contiennent les données qui sont sauvegardées entre les sessions \p PouchinTVMod.
* elles sont chargées au démarrage de l'application, et sont sauvegardées chaque fois qu'une
* modification intervient dans l'une de celles-ci.
- * \todo Autres éléments de configuration à prévoir :
- * - Voir #OSD_COLOR, #OSD_TRANSPARENCY.
* @{
**/
@@ -161,15 +160,15 @@
extern TCHAR video_dir[MAX_PATH]; //!< Répertoire pour les enregistrements vidéo
extern UINT32 cleChaineConfig; //!< Clé chaîne courante
-extern int avance_enreg; //!< Nombre de minutes d'anticipation du début enregistrements EPG
-extern int retard_enreg; //!< Nombre de minutes de retard sur la fin des enregistrements EPG
+extern INT32 avance_enreg; //!< Nombre de minutes d'anticipation du début enregistrements EPG
+extern INT32 retard_enreg; //!< Nombre de minutes de retard sur la fin des enregistrements EPG
extern SearchMethod
methode_recherche; //!< Méthode de recherche des chaînes
extern OffsetsToUse
use_offsets; //!< Offsets à utiliser
-extern int autonum_undef; //!< Numéro de départ pour les chaînes non numérotées
-extern int autonum_duplicate; //!< Décalage de numérotation pour les chaînes dupliquées
+extern INT32 autonum_undef; //!< Numéro de départ pour les chaînes non numérotées
+extern INT32 autonum_duplicate; //!< Décalage de numérotation pour les chaînes dupliquées
extern bool suspend_minimized; //!< Indique que le son doit être coupé en mode minimisé
extern bool minimize_system_tray; //!< Indique que la minimisation doit se faire dans la zone de notification
@@ -179,16 +178,21 @@
extern TCHAR titre_fenetre[128]; //!< Nom affiché dans la barre de titre de la fenêtre
extern bool on_top; //!< Indique que l'affichage doit se faire devant toutes les autres fenêtres
extern bool use_ac3; //!< Indique qu'on veut utiliser le codec AC3 quand il est disponible
-extern bool use_osd; //!< true si l'OSD doit être utilisé
+extern bool use_osd; //!< \p true si l'OSD doit être utilisé
+extern INT32 osd_transparency; //!< Transparence OSD \todo impléménter configuration quand il y aura une place
+
+extern COLORREF osd_color; //!< Couleur de l'OSD
+extern COLORREF aCustomColors[16]; //!< Sauvegarde des couleurs personnalisées
+
extern VMRTypes vmr_mode; //!< Indique le mode VMR à utiliser
extern PanModes video_pan_mode; //!< Mode panoramique de la vidéo
//!< \todo Est-il vraiment opportun que ce mode soit sauvegardé ?
//!< (si oui, attention à la réinitialisation implicite quand on
//!< remet le zoom par défaut, ce qui nuit à la cohérence)
-extern int zoom_ratio; //!< Facteur de zoom à appliquer à la vidéo
+extern INT32 zoom_ratio; //!< Facteur de zoom à appliquer à la vidéo
//!< \todo Est-il vraiment opportun que le zoom soit sauvegardé ?
-extern long volumeCourant; //!< Niveau de volume sonore courant
+extern INT32 volumeCourant; //!< Niveau de volume sonore courant
extern bool use_multimedia; //!< Utiliser les commandes multimédia
extern MouseWheelUsage
@@ -248,6 +252,12 @@
#define INI_METHODE_RECH_DEFAULT sm_prefs //!< Méthode de recherche des chaînes
#define INI_TRY_ADDING_5KHZ_DEFAULT false //!< Essayer d'ajouter 5 kHz si aucun signal trouvé
+/// Couleur utilisée pour l'OSD
+#define INI_OSD_COLOR RGB(0, 255, 0) // vert
+
+/// Transparence de l'OSD (en mode VMR9 seulement), de 0 à 100
+#define INI_OSD_TRANSPARENCY 100 // 100 %
+
/// Motif par défaut pour nommer les enregistrements
#define MOTIF_NOMS_ENREG_DEFAULT "%e - ?%c %a-%m-%j %h-%M-%s"
Modifié: trunk/main.cpp
===================================================================
--- trunk/main.cpp 2009-07-03 10:53:11 UTC (rev 194)
+++ trunk/main.cpp 2009-07-09 16:19:22 UTC (rev 195)
@@ -459,65 +459,21 @@
if (!ixChaine_ok(ixChaineCourante))
return;
- struct Langue {
- char code[4];
- LPCSTR lang;
- };
+ const Chaine & canal_courant = Canaux[ixChaineCourante];
+ TCHAR nom_menu[64];
- static const Langue Tab_Lang[] =
- {
- {"fra", "Français"},
- {"fre", "Français"},
- {"eng", "Anglais"},
- {"ang", "Anglais"},
- {"deu", "Allemand"},
- {"spa", "Espagnol"},
- {"ita", "Italien"},
- {"por", "Portugais"},
- {"qaa", "V.O."}
- };
-
- static const LPCSTR tblNomsAudio[] =
- {
- "MPG",
- "AC3",
- "EAC3"
- };
-
- const Chaine & canal_courant = Canaux[ixChaineCourante];
-
// Récupère le nom du menu avant de l'effacer
- TCHAR nom_menu[64];
GetMenuString(hMenu, MENU_PISTES_POSITION,
nom_menu, _countof(nom_menu), MF_BYPOSITION);
DeleteMenu(hMenu, MENU_PISTES_POSITION, MF_BYPOSITION);
- HMENU pistes = CreatePopupMenu();
+ HMENU pistes = CreatePopupMenu();
for (int i=0; i tst_EAC3 ? "???" : tblNomsAudio[son_courant.type]);
-
- UINT nFlags = i==ixSonCourant ? MF_CHECKED : MF_UNCHECKED;
-
- //if (son_courant.type==tst_EAC3)
- // nFlags|= MF_GRAYED; // E-AC3 non disponible pour le moment
+ canal_courant.toAudioMenuString(i, tab, _countof(tab));
AppendMenu(pistes, nFlags, IDM_PISTES_BASE+i, tab);
}
@@ -1482,6 +1438,24 @@
}
}
+/**
+ * Changement de piste son par rotation
+ * \param[in] pas Sens de la progression
+ **/
+static void son_avance(int pas)
+{
+ if (ixChaine_ok(ixChaineCourante)) {
+ INT son = ixSonCourant+pas;
+ INT max = Canaux[ixChaineCourante].sons.nbr;
+
+ if( son < 0 )
+ son = max-1;
+ else if (son >= max)
+ son = 0;
+ switch_audio(son);
+ }
+}
+
/// Appliquer un changement de chaîne par saisie
static void chaine_saisie()
{
@@ -1922,6 +1896,14 @@
chaine_avance(1, true);
break;
+ case IDM_SON_AUG:
+ son_avance(1);
+ break;
+
+ case IDM_SON_DIM:
+ son_avance(-1);
+ break;
+
case IDM_UPDATE:
do_web_update(hMainWnd);
break;
@@ -2044,8 +2026,11 @@
// Gestion du timer qui affiche le nom et la programmation de la chaîne après un
// certain délai, une fois qu'on a changé de chaîne
KillTimer(hMainWnd, wTimerID);
- PostMessage(hMainWnd, WM_COMMAND, IDM_SHOW_PROGRAMME, wTimerID);
+ // Demander l'affichage effectif du nom
+ if (ixChaineCourante==ixChaineAvance) // Ne pas afficher si on a déjà sélectionné une nouvelle chaîne
+ PostMessage(hMainWnd, WM_COMMAND, IDM_SHOW_PROGRAMME, wTimerID);
+
// Recalcul des coordonnées d'affichage pour être sûrs d'avoir un positionnement correct
update_coords();
break;
@@ -2159,57 +2144,23 @@
break;
case WM_APPCOMMAND:
- if (use_multimedia) { // Évènements standards sous me/2k/xp/vista
+ if (use_multimedia) { // Évènements standards sous ME/2k/XP/Vista
int cmd = GET_APPCOMMAND_LPARAM(lParam);
+ WORD wID = 0;
switch (cmd) {
- case APPCOMMAND_MEDIA_CHANNEL_DOWN: // Met la chaîne suivante
- chaine_avance(-1);
- break;
+ case APPCOMMAND_MEDIA_CHANNEL_DOWN: wID = IDM_CHAN_DIM; break; // Met la chaîne suivante
+ case APPCOMMAND_MEDIA_CHANNEL_UP: wID = IDM_CHAN_AUG; break; // Met la chaîne précédente
+ case APPCOMMAND_MEDIA_RECORD: wID = IDM_RECORD_CHANNEL_PS;break; // Lance l'enregistrement en mode PS (fichier MPG)
+ case APPCOMMAND_VOLUME_DOWN: wID = IDM_VOL_DIM; break; // Diminue le volume
+ case APPCOMMAND_VOLUME_UP: wID = IDM_VOL_AUG; break; // Augmente le volume
+ case APPCOMMAND_VOLUME_MUTE: wID = IDM_MUTE; break; // Coupe le son
+ case APPCOMMAND_MEDIA_STOP: wID = IDM_STOP_RECORD; break; // Arrête l'enregistrement
+ case APPCOMMAND_MEDIA_NEXTTRACK: wID = IDM_SON_AUG; break; // Piste son suivante
+ case APPCOMMAND_MEDIA_PREVIOUSTRACK:wID = IDM_SON_DIM; break; // Piste son précédente
+ case APPCOMMAND_BROWSER_FAVORITES: wID = IDM_EPG; break; // Affiche la liste des programmes EPG
- case APPCOMMAND_MEDIA_CHANNEL_UP: // Met la chaîne précédente
- chaine_avance(1);
- break;
-
- case APPCOMMAND_MEDIA_RECORD: // Lance l'enregistrement en mode PS (fichier MPG)
- PostMessage(hWnd, WM_COMMAND, IDM_RECORD_CHANNEL_PS, 0);
- break;
-
- case APPCOMMAND_VOLUME_DOWN: // Diminue le volume
- PostMessage(hWnd, WM_COMMAND, IDM_VOL_DIM, 0);
- break;
-
- case APPCOMMAND_VOLUME_UP: // Augmente le volume
- PostMessage(hWnd, WM_COMMAND, IDM_VOL_AUG, 0);
- break;
-
- case APPCOMMAND_VOLUME_MUTE: // Coupe le son
- PostMessage(hWnd, WM_COMMAND, IDM_MUTE, 0);
- break;
-
- case APPCOMMAND_MEDIA_STOP: // Arrête l'enregistrement
- if(enregistrements_actuels.recording())
- PostMessage(hWnd, WM_COMMAND, IDM_STOP_RECORD, 0);
- else
- return FALSE;
- break;
-
- case APPCOMMAND_MEDIA_NEXTTRACK: // Piste son suivante
- case APPCOMMAND_MEDIA_PREVIOUSTRACK:{// Piste son précédente
- int son = ixSonCourant+(cmd==APPCOMMAND_MEDIA_NEXTTRACK ? 1 : -1);
- if( son < 0 )
- son = Canaux[ixChaineCourante].sons.nbr-1;
- else if( son > Canaux[ixChaineCourante].sons.nbr-1 )
- son = 0;
- PostMessage(hWnd, WM_COMMAND, IDM_PISTES_BASE+son, 0);
- }
- break;
-
- case APPCOMMAND_BROWSER_FAVORITES: // Affiche la liste des programmes EPG
- PostMessage(hWnd, WM_COMMAND, IDM_EPG, 0);
- break;
-
default: // Non traité, juste pour le connaitre
myprintf(TEXT("WM_APPCOMMAND non traité: %d / Device: %s / Touches: %d\n"),
cmd,
@@ -2221,6 +2172,8 @@
GET_KEYSTATE_LPARAM(lParam));
return FALSE;
}
+ if (wID)
+ PostMessage(hWnd, WM_COMMAND, wID, 0);
}
return TRUE;
@@ -2273,6 +2226,7 @@
switch (role_molette) {
case mwu_Channels: wID = IDM_CHAN_AUG; break;
case mwu_Channels_MX: wID = IDM_CHAN_AUG_MPX; break;
+ case mvu_Soundtrack: wID = IDM_SON_AUG; break;
case mwu_Volume: wID = IDM_VOL_AUG; break;
case mvu_Zoom: wID = IDM_ZOOM;
}
@@ -2280,6 +2234,7 @@
switch (role_molette) {
case mwu_Channels: wID = IDM_CHAN_DIM; break;
case mwu_Channels_MX: wID = IDM_CHAN_DIM_MPX; break;
+ case mvu_Soundtrack: wID = IDM_SON_DIM; break;
case mwu_Volume: wID = IDM_VOL_DIM; break;
case mvu_Zoom: wID = IDM_DEZOOM;
}
Modifié: trunk/record.cpp
===================================================================
--- trunk/record.cpp 2009-07-03 10:53:11 UTC (rev 194)
+++ trunk/record.cpp 2009-07-09 16:19:22 UTC (rev 195)
@@ -57,6 +57,9 @@
stop(epr_interrompu); // précaution
#if USE_SINGLE_GRABBER // USE_SINGLE_GRABBER
if (pGrabber && cleCh!=0 && pGrabberCB) {
+ // Nombre d'enregistrements avant le démarrage de celui-ci :
+ int nPrevRecCount = enregistrements_actuels.count_recording();
+
if (pProg) {
memcpy(this, pProg, sizeof(RecordInfo));
pProg->etat = epr_encours;
@@ -66,9 +69,6 @@
CSampleGrabber & cSg = dynamic_cast(*pGrabberCB);
if (cSg.Lock()) { // On a l'accès au mutex
- // Nombre d'enregistrement avant le démarrage de celui-ci :
- int nPrevRecCount = enregistrements_actuels.count_recording();
-
if (pCapture)
delete pCapture; // Au cas où il y en aurait déjà un (ne devrait pas arriver)
pCapture = pCapt;
Modifié: trunk/rendering.cpp
===================================================================
--- trunk/rendering.cpp 2009-07-03 10:53:11 UTC (rev 194)
+++ trunk/rendering.cpp 2009-07-09 16:19:22 UTC (rev 195)
@@ -41,14 +41,7 @@
/// Intervalle minimal entre deux actualisations de la position de la vidéo
#define DUREE_VIDEO_MOVE 100
-/// Couleur utilisée pour l'OSD
-/// \todo Transformer en paramètre de configuration
-#define OSD_COLOR RGB(0, 255, 0) // vert
-/// Transparence de l'OSD (en mode VMR9 seulement), de 0 à 100
-/// \todo Transformer en paramètre de configuration
-#define OSD_TRANSPARENCY 100
-
// ====================================================================================
// Fonctions locales (non exportées)
// ====================================================================================
@@ -199,7 +192,7 @@
HFONT hOldFont = (HFONT)SelectObject(hDC, sRefs.hFnt);
// Couleur de l'OSD (VERT ici)
- SetTextColor(hDC, OSD_COLOR);
+ SetTextColor(hDC, osd_color);
// Couleur de fond (remplacée par de la transparence)
SetBkColor(hDC, colorKey);
@@ -1562,7 +1555,7 @@
{0.0f, 0.0f, 1.0f, 1.0f}, // rDest
//
// Transparency value 1.0 is opaque, 0.0 is transparent.
- float(OSD_TRANSPARENCY/100), // fAlpha (transparence)
+ float(osd_transparency)/100, // fAlpha (transparence)
//
colorKey, // clrSrcKey
0 // dwFilterMode
@@ -1782,7 +1775,7 @@
colorKey, // params.clrSrcKey
{0, 0, sBmpSize.cx, sBmpSize.cy}, // params.rcSrc
{0.0f, 0.0f, 1.0f, 1.0f}, // params.nrcDest
- float(OSD_TRANSPARENCY/100), // params.fAlpha
+ float(osd_transparency)/100, // params.fAlpha
D3DTEXF_LINEAR // params.dwFilterMode
}
};
Modifié: trunk/rendering.h
===================================================================
--- trunk/rendering.h 2009-07-03 10:53:11 UTC (rev 194)
+++ trunk/rendering.h 2009-07-09 16:19:22 UTC (rev 195)
@@ -452,6 +452,14 @@
void DisplayZoom(int nZoomRatio) {
cBotLeft.SetText(true, TEXT("Zoom %i%%"), nZoomRatio);}
+ /// Affichage du nom d'une piste son
+ /// \param[in] canal Descripteur de la chaîne courante
+ /// \param[in] nTrack Numéro de la piste son
+ void DisplaySoundInfo(const Chaine & canal, int nTrack) {
+ TCHAR tab[64];
+ canal.toAudioMenuString(nTrack, tab, _countof(tab));
+ cBotRight.SetText(true, TEXT("%s"), tab);}
+
/// Affichage de l'état "mute"
/// \param[in] bMuted true si on est en mode silencieux
void DisplayMute(bool bMuted) {
Modifié: trunk/res.rc
===================================================================
--- trunk/res.rc 2009-07-03 10:53:11 UTC (rev 194)
+++ trunk/res.rc 2009-07-09 16:19:22 UTC (rev 195)
@@ -185,9 +185,10 @@
"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_GROUP | WS_TABSTOP,154,57,124,16
GROUPBOX "Vidéo",IDC_STATIC,7,76,275,34
LTEXT "Méthode de rendu :",IDC_STATIC,14,85,128,8
- COMBOBOX IDC_COMBO_RENDERING,14,94,128,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP
- CONTROL "Utiliser l'OSD (On Screen Display\n = texte sur l'écran)",IDC_USE_OSD,
- "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,154,88,124,17
+ COMBOBOX IDC_COMBO_RENDERING,14,94,124,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP
+ CONTROL "Utiliser l'OSD (On Screen Display =",IDC_USE_OSD,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,154,85,124,8
+ LTEXT "texte sur l'écran)",IDC_USE_OSD_S,154,93,59,8
+ PUSHBUTTON "Couleur OSD…",IDC_OSD_COLOR,218,93,60,14
GROUPBOX "Calibration de l'indicateur de force du signal",IDC_STATIC,7,111,276,64
RTEXT "Définition des limites de la force du signal pour le tuner utilisé.",IDC_STATIC,66,120,212,8
EDITTEXT IDC_SIGNAL_ZERO,14,128,45,14,ES_CENTER | ES_AUTOHSCROLL | WS_GROUP
@@ -427,7 +428,8 @@
"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_GROUP | WS_TABSTOP,7,187,119,16
LTEXT "Rôle de la molette de la souris :",IDC_STATIC,146,172,137,8
COMBOBOX IDC_WHEEL_USAGE,146,183,137,54,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
- CONTROL "Défilement de la molette inversé",IDC_WHEEL_INVERT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,146,197,137,10
+ CONTROL "Défilement de la molette inversé",IDC_WHEEL_INVERT,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,146,197,137,10
END
IDD_UPDATE DIALOGEX 0, 0, 251, 155
Modifié: trunk/resource.h
===================================================================
--- trunk/resource.h 2009-07-03 10:53:11 UTC (rev 194)
+++ trunk/resource.h 2009-07-09 16:19:22 UTC (rev 195)
@@ -55,15 +55,9 @@
#define IDC_TIME_START 1030
#define IDC_TIME_END 1031
#define IDC_LIST_PROGRAMMES 1032
-#define IDC_CURRENT_PROGRAM 1034
-#define IDC_SUSPEND 1035
-#define IDC_SYSTEM_TRAY 1036
-#define IDC_AC3_DEF 1037
-#define IDC_USE_OSD 1038
+#define IDC_CURRENT_PROGRAM 1033
#define IDC_WINDOW_TITLE 1039
-#define IDC_COMBO_RENDERING 1040
-#define IDC_MSN 1041
-#define IDC_ALLOW_STREAM_RECORD 1042
+
#define IDC_MPEG2_DIR_VIEW 1043
#define IDC_MPEG2_DIR 1044
#define IDC_SCREENSHOTS_DIR_VIEW 1045
@@ -72,7 +66,6 @@
#define IDC_NAME 1048
#define IDC_RECORD 1049
#define IDC_INACTIVE 1050
-#define IDC_AUTO_RETUNE 1051
#define IDC_METHOD 1052
#define IDC_AUDIO 1053
#define IDC_SIGNAL_ZERO 1054
@@ -160,6 +153,17 @@
#define IDC_UPDATE_CHECK 1161
#define IDC_UPDATE_LIST 1162
+#define IDC_SUSPEND 1170
+#define IDC_SYSTEM_TRAY 1171
+#define IDC_AUTO_RETUNE 1172
+#define IDC_AC3_DEF 1173
+#define IDC_ALLOW_STREAM_RECORD 1174
+#define IDC_COMBO_RENDERING 1180
+#define IDC_USE_OSD 1181
+#define IDC_USE_OSD_S 1182
+#define IDC_OSD_COLOR 1183
+#define IDC_MSN 1184
+
#define MY_TRAY_ICON_ID 20001
#define IDM_CHAINES_BASE 39000 // Offset de base pour changement chaîne
@@ -213,36 +217,38 @@
#define IDM_DEFAULT_ZOOM 40054
#define IDM_ALLWDT 40055
#define IDM_ALLHGT 40056
-#define IDM_CHAN_AUG 40057
-#define IDM_CHAN_DIM 40058
-#define IDM_CHAN_AUG_MPX 40059
-#define IDM_CHAN_DIM_MPX 40060
-#define IDM_PISTES 40061
-#define IDM_CHAINES 40062
-#define IDM_SHORT_DEFAUT 40063
-#define IDM_SHORT_EFFACER 40064
-#define IDM_CHAN_TUNE 40065
-#define IDM_ETIRER 40066
-#define IDM_UPDATE 40067
-#define IDM_SHOW_PROGRAMME 40068
+#define IDM_CHAN_AUG 40060
+#define IDM_CHAN_DIM 40061
+#define IDM_CHAN_AUG_MPX 40062
+#define IDM_CHAN_DIM_MPX 40063
+#define IDM_SON_AUG 40064
+#define IDM_SON_DIM 40065
+#define IDM_PISTES 40068
+#define IDM_CHAINES 40069
+#define IDM_SHORT_DEFAUT 40070
+#define IDM_SHORT_EFFACER 40071
+#define IDM_CHAN_TUNE 40072
+#define IDM_ETIRER 40073
+#define IDM_UPDATE 40074
+#define IDM_SHOW_PROGRAMME 40075
-#define IDM_CHAN_NUMERO 40069
-#define IDM_CHAN_NOM 40070
-#define IDM_CHAN_RESTORNUM 40071
-#define IDM_CHAN_RESTORNOM 40072
+#define IDM_CHAN_NUMERO 40080
+#define IDM_CHAN_NOM 40081
+#define IDM_CHAN_RESTORNUM 40082
+#define IDM_CHAN_RESTORNOM 40083
-#define IDM_GRAPH_STATE 40075 // debug
-#define IDM_RUN_GRAPH 40076 // debug
-#define IDM_PAUSE_GRAPH 40077 // debug
-#define IDM_STOP_GRAPH 40078 // debug
+#define IDM_GRAPH_STATE 40086 // debug
+#define IDM_RUN_GRAPH 40087 // debug
+#define IDM_PAUSE_GRAPH 40088 // debug
+#define IDM_STOP_GRAPH 40089 // debug
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 137
-#define _APS_NEXT_COMMAND_VALUE 40079
-#define _APS_NEXT_CONTROL_VALUE 1163
+#define _APS_NEXT_COMMAND_VALUE 40090
+#define _APS_NEXT_CONTROL_VALUE 1190
#define _APS_NEXT_SYMED_VALUE 121
#endif
#endif
Modifié: trunk/settings.cpp
===================================================================
--- trunk/settings.cpp 2009-07-03 10:53:11 UTC (rev 194)
+++ trunk/settings.cpp 2009-07-09 16:19:22 UTC (rev 195)
@@ -34,6 +34,7 @@
#include "trayicon.h"
#include
+#include
/**
* Classe de base pour gérer un dialog modal en tant qu'objet
@@ -2513,6 +2514,7 @@
TEXT("Aucun"),
TEXT("Changer de chaîne"),
TEXT("Changer de chaîne dans multiplex"),
+ TEXT("Changer de piste son"),
TEXT("Régler le volume"),
TEXT("Ajuster le zoom")
};
@@ -2910,10 +2912,11 @@
**/
void SetOSDState(HWND hDlg)
{
- VMRTypes eSelMode = GetVMRSel(hDlg);
+ VMRTypes eSelMode = GetVMRSel(hDlg);
+ bool bCanUseOSD = !is_vista || eSelMode!=vmt_VMR7_renderless && eSelMode!=vmt_VMR7_windowless;
- EnableWindow(GetDlgItem(hDlg, IDC_USE_OSD),
- !is_vista || eSelMode!=vmt_VMR7_renderless && eSelMode!=vmt_VMR7_windowless);
+ EnableWindow(GetDlgItem(hDlg, IDC_USE_OSD), bCanUseOSD);
+ EnableWindow(GetDlgItem(hDlg, IDC_USE_OSD_S), bCanUseOSD);
}
/**
@@ -2980,6 +2983,24 @@
PropSheet_Changed(GetParent(hDlg), hDlg);
return 0;
+ case _cmd_(IDC_OSD_COLOR, BN_CLICKED): {
+ CHOOSECOLOR sChooseColor = {
+ sizeof(sChooseColor), // lStructSize
+ hDlg, // hwndOwner
+ NULL, // hInstance
+ osd_color, // rgbResult
+ aCustomColors, // lpCustColors
+ CC_ANYCOLOR|CC_RGBINIT|CC_FULLOPEN,
+ // Flags
+ NULL, // lCustData
+ NULL, // lpfnHook
+ NULL // lpTemplateName
+ };
+
+ if (ChooseColor(&sChooseColor))
+ osd_color = sChooseColor.rgbResult;
+ return 0; }
+
case _cmd_(IDC_WINDOW_TITLE, EN_CHANGE): {
TCHAR szTmp[_countof(titre_fenetre)];
Ajouté: trunk/style.css
===================================================================
--- trunk/style.css (rev 0)
+++ trunk/style.css 2009-07-09 16:19:22 UTC (rev 195)
@@ -0,0 +1,97 @@
+/* Feuille de styles pour les fichiers HTML inclus dans le SVN ou bien copiés à l'installation de Pouchin TV Mod */
+
+body { /* Guillemets utilisés dans */
+ background-color:#f3f3f3;
+ quotes: "\00ab\00a0" "\00a0\00bb";
+}
+
+h1, h2 {
+ text-align:center;
+}
+
+h2.with_subtitle {
+ margin-bottom:0;
+}
+
+p.subtitle {
+ margin-top:0;
+ font-style:italic;
+ text-align:center;
+}
+
+code {
+ width: 100%;
+ display: block;
+ text-align:left;
+ color:#088;
+ margin:4px auto 4px 0;
+}
+
+div.ptvm {
+ width:760px;
+ margin:32px auto;
+ background-color:white;
+ padding:1em 2em 1em 1em;
+ border:1px solid black;
+ text-align:justify;
+ font-family:Arial,Helvetica,sans-serif;
+}
+
+.cond_hide { /* masquage conditionnel de certains éléments */
+ display:none;
+}
+
+p.retour {
+ font-weight:bold;
+ text-align:center;
+}
+
+p.modif {
+ background-color:white;
+ border:1px solid black;
+ width:24em;
+ margin:auto;
+ text-align:center;
+ font-style:italic;
+}
+
+dt.release {
+ font-weight:bold;
+ font-size:110%;
+ color:#00c;
+ margin-top:24px;
+}
+
+dt.experi {
+ font-weight:bold;
+ margin-top:24px;
+}
+
+dt.experi i, dt.release i {
+ font-style:italic;
+ font-weight:normal;
+ font-size:10pt;
+ color:black;
+}
+
+dt.svn {
+ font-weight:normal;
+ font-style:italic;
+ color:black;
+ font-size:90%;
+ margin-top:4px;
+ padding-left:1em;
+}
+
+q {
+ font-style:italic;
+}
+
+.with_smiley:after {
+ content:url("data:image/gif;base64, R0lGODlhFgAPALMAAEVFRf/qAAAAAP/////OAP/JAP+0AP6dAP/+k//9E///x///6//lAP7+/gAAAAAAACH5BAEAAA0ALAAAAAAWAA8AQARlsMlJJbi36gZSEEMoDkJhABuHeELgtgGBphxBFDhOHDMNLIqEx7XraQAImGv5OqUAhM+IVJDRKJjMFftTIBAy4wbgHTKLz+BrCSvwxkmBfE53HqOgKfU9tjHoJWhXFwaFBjw9EQAAOw==");
+}
+
+.u {
+ text-decoration:underline;
+}
+
From pouchintv-dev at baysse.fr Fri Jul 17 16:22:20 2009
From: pouchintv-dev at baysse.fr (=?iso-8859-1?q?Liste_utilis=E9e_par_les_d=E9veloppeurs?=)
Date: Fri, 17 Jul 2009 14:22:20 -0000
Subject: [Pouchintv-dev] [PouchinTVMod] gingko | r196 - trunk
Message-ID: <20090717142208.7ADC56EFE7@mail.baysse.fr>
Author: gingko
Date: 2009-07-17 16:22:07 +0200 (ven 17 jui 2009)
New Revision: 196
Added:
trunk/filters.cpp
trunk/filters.h
Modified:
trunk/Pouchin TV_2005.vcproj
trunk/Pouchin TV_2008.vcproj
trunk/changelog.html
trunk/channels.cpp
trunk/channels.h
trunk/epgfilter.cpp
trunk/epgfilter.h
trunk/graph.cpp
trunk/graph.h
trunk/ini.cpp
trunk/main.cpp
trunk/network.cpp
trunk/network.h
trunk/parse.cpp
trunk/pmtfilter.cpp
trunk/pmtfilter.h
trunk/record.cpp
trunk/rendering.cpp
trunk/rendering.h
trunk/settings.cpp
trunk/settings.h
Log:
Début de réorganisation du graphe, et améliorations mineures.
graph.h, graph.cpp, filters.h, filters.cpp, channels.h, channels.cpp,
main.cpp, record.cpp, rendering.h, rendering.cpp, settings.h, settings.cpp :
* Création de structures spécifiques pour décrire les filtres utilisés,
permettant de gérer certains traitements à ne spécifiant plus que ces
structures en paramètres d'entrée.
* Importante factorisation du graphe en utilisant ces structures.
* Ajout de deux fichiers : "filters.h" et "filters.cpp" pour contenir les
structures et fonctions spécifiquement dédiées aux filtres. Plusieurs
fonctions prédédemment réparties dans d'autres fichiers sont maintenant
déplacées dans ces deux fichiers.
* Retrait de certains messages d'erreur, car d'autres messages qui les
précèdent dans la chaîne des messages sont déjà suffisamment explicites.
* À noter le changement de nom de certaines variables internes à la fontion
"Search_IBDA_Topology", afin d'éviter un conflit avec le nom "Interface",
appelé à un avenir d'importance plus globale.
Ce changement constitue la première étape dans un projet général de
migration du graphe entier vers une représentation orientée objet,
susceptible de contenir plusieurs graphes différents, ou bien plusieurs
instances d'un même graphe.
channels.cpp :
* La resyntonisation (manuelle ou automatique) ne fait plus de déconnexion
temporaire des filtres du démultiplexeur, ce qui devrait éviter certains
plantages parfois constatés pendant cette déconnexion.
epgfilter.h, epgfilter.cpp, pmtfilter.h, pmtfilter.cpp, network.h, network.cpp :
* Ajout de macros pour définir les noms des filtres locaux, de telle manière que
la même macro puisse être utilisée aussi bien en mode TCHAR qu'en mode WCHAR.
ini.cpp :
* La vérification de la configuration n'utilise plus les mêmes pointeurs de
filtres que le graphe, rendant celle-ci indépendante de la construction du
graphe, et dispensant de la nécessité, pour le graphe, de devoir s'assurer
que la vérification de la configuration a été appelée avant.
main.cpp :
* Ajout du filtre H264 dans le récapitulatif des filtres présentés au démarrage
dans la console de debugging, en mode debugging.
parse.cpp :
* Une erreur détectée pendant le changement de fréquence n'arrête plus la
recherche des chaînes (car au moins un utilisateur a eu le problème que cet
arrêt ne lui permettait plus de rechercher les chaînes correctement :
apparemment, malgré l'erreur, le changement de fréquence était effectué).
* Ajout de premier délai de stabilisation dans le log de la recherche.
settings.cpp :
* Les listes de pilotes ou de codecs, dans la configuration, sont maintenant
triées insensibles à la casse.
Modifié: trunk/Pouchin TV_2005.vcproj
===================================================================
--- trunk/Pouchin TV_2005.vcproj 2009-07-09 16:19:22 UTC (rev 195)
+++ trunk/Pouchin TV_2005.vcproj 2009-07-17 14:22:07 UTC (rev 196)
@@ -792,6 +792,10 @@
>
+
+
@@ -914,6 +918,10 @@
>
+
+
Modifié: trunk/Pouchin TV_2008.vcproj
===================================================================
--- trunk/Pouchin TV_2008.vcproj 2009-07-09 16:19:22 UTC (rev 195)
+++ trunk/Pouchin TV_2008.vcproj 2009-07-17 14:22:07 UTC (rev 196)
@@ -785,6 +785,10 @@
>
+
+
@@ -907,6 +911,10 @@
>
+
+
Modifié: trunk/changelog.html
===================================================================
--- trunk/changelog.html 2009-07-09 16:19:22 UTC (rev 195)
+++ trunk/changelog.html 2009-07-17 14:22:07 UTC (rev 196)
@@ -15,7 +15,7 @@
-Changements entre les versions
+Changements entre les versions de Pouchin TV Mod
@@ -56,6 +56,26 @@
Changements réalisés pour la version 0.5
+ - SVN rév. 196 :
+
+ - Plus de déconnexion des filtres pendant la resyntonisation, afin d'éviter des plantages.
+ - Les listes de pilotes ou de codecs, dans la configuration, sont maintenant triées insensibles
+ Ã la casse.
+ - Une erreur détectée pendant le changement de fréquence n'arrête plus la recherche
+ des chaînes (cette détection avait été introduite à la révision 189, mais certains tuners semblent
+ retourner une erreur alors qu'ils changent de fréquence correctement).
+ - Première étape d'une importante réorganisation du code dans le graphe.
+
+
+
+ - SVN rév. 195 :
+
+ - La couleur de l'affichage OSD peut maintenant être changée.
+ - Possibilité de sélectionner les pistes audio par défilement, entre autres avec la molette de la souris.
+ - Affichage OSD au changement de piste audio.
+
+
+
- 0.5.194 (expérimentale, publiée dans le forum le 3 juillet 2009) :
- Réduction à un seul du nombre de filtres
Grabber
pour les enregistrements,
Modifié: trunk/channels.cpp
===================================================================
--- trunk/channels.cpp 2009-07-09 16:19:22 UTC (rev 195)
+++ trunk/channels.cpp 2009-07-17 14:22:07 UTC (rev 196)
@@ -147,12 +147,12 @@
switch (son.type) {
case tst_MPEG2:
- hr = branche_pid(pMapSound, pid IF_CONSOLE_CB("Audio MPEG2"));
+ hr = sMp2aCodec.branche_pid(pid);
break;
case tst_AC3:
case tst_EAC3:
- hr = branche_pid(pMapAc3, pid IF_CONSOLE_CB("Audio AC3"));
+ hr = sAc3_Codec.branche_pid(pid);
break;
default:
@@ -161,12 +161,10 @@
}
}
-static HRESULT debranche_tous_pids(CComPtr & pMap IF_CONSOLE_CB(LPCSTR nom_itf)); // forward
-
static void debranche_son()
{
- debranche_tous_pids(pMapSound IF_CONSOLE_CB("Audio MPEG2"));
- debranche_tous_pids(pMapAc3 IF_CONSOLE_CB("Audio AC3"));
+ sMp2aCodec.debranche_pids();
+ sAc3_Codec.debranche_pids();
}
HBITMAP Chaine::ChargeIcone()
@@ -343,20 +341,20 @@
switch (video_type) {
case vst_MPEG2:
if (pVMR && ePrevVideoType!=vst_MPEG2) {
- if (FAILED(hr = switch_codec(pVideoCodec, TEXT("MPEG2"))))
+ if (FAILED(hr = switch_codec(sMp2vCodec.pFilter, TEXT("MPEG2"))))
return hr;
ePrevVideoType = vst_MPEG2;
}
- hr = branche_pid(pMapMPEG2, pid IF_CONSOLE_CB("Vidéo MPEG2"));
+ hr = sMp2vCodec.branche_pid(pid);
break;
case vst_H264:
if (pVMR && ePrevVideoType!=vst_H264) {
- if (FAILED(hr = switch_codec(pVideoH264Codec, TEXT("H264"))))
+ if (FAILED(hr = switch_codec(sH264Codec.pFilter, TEXT("H264"))))
return hr;
ePrevVideoType = vst_H264;
}
- hr = branche_pid(pMapH264, pid IF_CONSOLE_CB("Vidéo H264"));
+ hr = sH264Codec.branche_pid(pid);
break;
default:
@@ -381,7 +379,7 @@
#if USE_PMTFILTER
// pmt
- hr = branche_pid(pMapPmt, pmt_pid IF_CONSOLE_CB("PMT"), MEDIA_MPEG2_PSI);
+ hr = sPMT_Filter.branche_pid(pmt_pid);
#endif
return hr;
}
@@ -569,72 +567,16 @@
}
/**
- * Débranchement de tous les flux élémentaires (identifiés par PID) qui sont couramment
- * présentés sur la connexion pMap (en sortie du démultiplexeur).
- * \param[in] pMap Interface d'une broche de sortie du démultiplexeur
- * \param[in] nom_itf Nom de la connexion pour debugging
- **/
-static HRESULT debranche_tous_pids(CComPtr & pMap IF_CONSOLE_CB(LPCSTR nom_itf))
-{
- HRESULT hr = S_OK;
-
-if (!pMap)
- return E_FAIL;
-
- CComPtr pEnumMap;
-
- if (SUCCEEDED(hr = pMap->EnumPIDMap(&pEnumMap))) {
- PID_MAP maps[8];
- ULONG nbPids = 0;
-
- if (pEnumMap->Next(_countof(maps), maps, &nbPids)==S_OK) {
- for (ULONG i=0; iUnmapPID(1, &pid))) {
- myprintf(TEXT("Échec UnmapPID(%u) (%") A2t TEXT("), hr=0x%08x\n"), pid, nom_itf, hr);
- break;
- }
- }
- }
-
- }
-
- return hr;
-}
-
-/**
- * Branchement d'un flux élémentaire (identifiés par PID) sur la connexion pMap
- * (en sortie du démultiplexeur).
- * \param[in] pMap Interface d'une broche de sortie du démultiplexeur
- * \param[in] pid N° de PID à y connecter
- * \param[in] nom_itf Nom de la connexion pour debugging
- * \param[in] eMsc Type de contenu (MEDIA_ELEMENTARY_STREAM par défaut)
- **/
-HRESULT branche_pid(CComPtr & pMap, ULONG pid IF_CONSOLE_CB(LPCSTR nom_itf),
- MEDIA_SAMPLE_CONTENT eMsc)
-{
- if (!pMap) // Filtre non défini : on ne branche rien et on retourne S_OK
- return S_OK;
-
- myprintf(TEXT("Branche pid=%u sur broche %") A2t TEXT("\n"), pid, nom_itf);
- HRESULT hr = pMap->MapPID(1, &pid, eMsc);
- myprintf(TEXT("%?Échec MapPID(%u) (%") A2t TEXT("), hr=0x%08x\n"), FAILED(hr), pid, nom_itf, hr);
- return hr;
-}
-
-/**
* Déconnexion globale des sorties vidéo et audio
**/
void debranche()
{
if (!suspendu) {
- debranche_tous_pids(pMapMPEG2 IF_CONSOLE_CB("Vidéo MPEG2"));
- debranche_tous_pids(pMapH264 IF_CONSOLE_CB("Vidéo H264"));
+ sMp2vCodec.debranche_pids();
+ sH264Codec.debranche_pids();
debranche_son();
#if USE_PMTFILTER
- debranche_tous_pids(pMapPmt IF_CONSOLE_CB("PMT"));
+ sPMT_Filter.debranche_pids();
#endif
suspendu = true;
}
@@ -711,7 +653,7 @@
}
bool freq_differente = true;
bool sauve_suspend = suspendu;
- bool reset_son = ixChaine!=ixChaineCourante;
+ bool chaine_differente = ixChaine!=ixChaineCourante;
if (!bForceTune) {
if (ixChaine_ok(ixChaineCourante) && ixChaine_ok(ixChaine) &&
@@ -727,7 +669,7 @@
ixChaineCourante = -1; // doit être égal à -1 pendant les transitions (à cause du filtre PMT)
- if (!suspendu) {
+ if (!suspendu && chaine_differente) {
debranche();
}
@@ -745,8 +687,8 @@
ixChaineAvance = ixChaineCourante;
// Ne reconnecter l'interface que si elle l'était avant :
- if (!sauve_suspend)
- rebranche(reset_son);
+ if (!sauve_suspend && chaine_differente)
+ rebranche(true);
} else {
// ixChaine < 0 pour désélection de chaîne
Modifié: trunk/channels.h
===================================================================
--- trunk/channels.h 2009-07-09 16:19:22 UTC (rev 195)
+++ trunk/channels.h 2009-07-17 14:22:07 UTC (rev 196)
@@ -321,17 +321,6 @@
void set_volume(long volume);
/**
- * Branchement d'un flux élémentaire (identifiés par PID) sur la connexion pMap
- * (en sortie du démultiplexeur).
- * \param[in] pMap Interface d'une broche de sortie du démultiplexeur
- * \param[in] pid N° de PID à y connecter
- * \param[in] nom_itf Nom de la connexion pour debugging
- * \param[in] eMsc Type de contenu (MEDIA_ELEMENTARY_STREAM par défaut)
- **/
-HRESULT branche_pid(CComPtr & pMap, ULONG pid IF_CONSOLE_CB(LPCSTR nom_itf),
- MEDIA_SAMPLE_CONTENT eMsc=MEDIA_ELEMENTARY_STREAM);
-
-/**
* Déconnexion globale des sorties vidéo et audio
**/
void debranche();
Modifié: trunk/epgfilter.cpp
===================================================================
--- trunk/epgfilter.cpp 2009-07-09 16:19:22 UTC (rev 195)
+++ trunk/epgfilter.cpp 2009-07-17 14:22:07 UTC (rev 196)
@@ -91,7 +91,9 @@
*dst = 0;
}
-LPCWSTR CEPGFilter::szFilterName = L"Filtre EPG PTvM";
+#define __WTXT(str) L##str
+#define WTXT(str) __WTXT(str)
+LPCWSTR CEPGFilter::szFilterName = WTXT(EPG_FILTER_NAME);
CUnknown * WINAPI CEPGFilter::CreateInstance(IUnknown *pUnk, HRESULT *phr) // static
{
Modifié: trunk/epgfilter.h
===================================================================
--- trunk/epgfilter.h 2009-07-09 16:19:22 UTC (rev 195)
+++ trunk/epgfilter.h 2009-07-17 14:22:07 UTC (rev 196)
@@ -30,6 +30,8 @@
#include
+#define EPG_FILTER_NAME "Filtre EPG PTvM"
+
[uuid("3A81A9CF-606B-458f-8244-9DC73128C79E")]
class CEPGFilter : public CBaseRenderer
{
Ajouté: trunk/filters.cpp
===================================================================
--- trunk/filters.cpp (rev 0)
+++ trunk/filters.cpp 2009-07-17 14:22:07 UTC (rev 196)
@@ -0,0 +1,176 @@
+/*
+ * filters.cpp
+ * Copyright (C) 2009 gingko - http://gingko.homeip.net/
+ *
+ * This file is part of Pouchin TV Mod, a free DVB-T viewer.
+ * See http://pouchintv.baysse.fr/ for updates.
+ *
+ * Pouchin TV Mod is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Pouchin TV Mod is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *
+ * Most files of this project have been changed from the Pouchin TV
+ * project (Copyright (C) 2006 Pouchin ),
+ * to use with a modified version of this software.
+ * See http://pouchinteve.free.fr/ for the original project.
+ */
+
+#include "main.h"
+#include "filters.h"
+
+// ====================================================================================
+// Structures, définitions et méthodes concernant les filtres
+// ====================================================================================
+
+/**
+ * \brief Création du filtre
+ **/
+HRESULT FilterData::Create()
+{
+ HRESULT hr = E_FAIL;
+
+ if (bLocal)
+ pFilter = dynamic_cast(procCrea(NULL, &hr));
+ else if (pclsid)
+ hr = pFilter.CoCreateInstance(*pclsid, NULL, CLSCTX_INPROC_SERVER);
+
+ return hr;
+}
+
+/**
+ * \brief Appel du dialogue de propriétés du filtre
+ **/
+VOID FilterData::create_property_dialog()
+{
+ if (!pFilter) {
+ affiche_erreurs(TEXT("Il faut d'abord configurer un filtre et redémarrer l'application"));
+ return;
+ }
+
+ CComQIPtr pPages(pFilter);
+
+ if (!pPages) {
+ // (avertissement maintenant en principe inutile car dans ce cas, le menu est désactivé)
+ affiche_erreurs(TEXT("Ce filtre n'a pas de page de propriétés"), E_NOINTERFACE);
+ return;
+ }
+
+ CComPtr pUnk(pPages);
+
+ if (pUnk) {
+ CAUUID caGUID;
+
+ HRESULT hr = pPages->GetPages(&caGUID);
+
+#ifdef _UNICODE
+ LPOLESTR pszTmp = LPOLESTR(pszName);
+#else
+ COPY_STR_ON_STACK(OLECHAR, pszTmp, nom, nLen);
+#endif
+ if (SUCCEEDED(hr)) {
+ LCID lcid = GetUserDefaultLCID();
+
+ ShowCursor(TRUE);
+
+ hr = OleCreatePropertyFrame(
+ hMainWnd,
+ 10,
+ 10,
+ pszTmp,
+ 1,
+ &pUnk.p,
+ caGUID.cElems,
+ caGUID.pElems,
+ lcid,
+ 0L,
+ NULL );
+
+ ShowCursor(FALSE);
+ CoTaskMemFree(caGUID.pElems);
+
+ if (FAILED(hr)) {
+ affiche_erreurs(TEXT("Erreur lors de la création de la page de propriétés"), hr);
+ }
+ }
+ }
+}
+
+/**
+ * \brief Vérification de l'existence d'un dialogue de propriétés sur ce filtre
+ *
+ * \return \p true si un dialogue de propriétés existe
+ **/
+bool FilterData::check_property_dialog() const
+{
+ if (IsNullName(pszName) || !pFilter)
+ return false;
+
+ CComQIPtr pPages(pFilter);
+
+ return !!pPages;
+}
+
+/**
+ * Branchement d'un flux élémentaire (identifié par PID) sur la connexion \p pMap
+ * (en sortie du démultiplexeur).
+ * \param[in] pid N° de PID à y connecter
+ * \return Code d'erreur DirectShow
+ **/
+HRESULT DecoderData::branche_pid(ULONG pid)
+{
+ if (!pMap) // Filtre non défini : on ne branche rien et on retourne S_OK
+ return S_OK;
+
+ myprintf(TEXT("Branche pid=%u sur broche %") A2t TEXT("\n"), pid, pszType);
+
+ HRESULT hr = pMap->MapPID(1, &pid, eMsc);
+
+ myprintf(TEXT("%?Échec branchement pid=%u sur broche %") A2t TEXT(", hr=0x%08x\n"), FAILED(hr), pid, pszType, hr);
+ return hr;
+}
+
+/**
+ * Débranchement de tous les flux élémentaires qui sont couramment
+ * présentés sur la connexion \p pMap (en sortie du démultiplexeur).
+ * \return Code d'erreur DirectShow
+ **/
+HRESULT DecoderData::debranche_pids()
+{
+ HRESULT hr = S_OK;
+
+ if (!pMap)
+ return E_FAIL;
+
+ CComPtr pEnumMap;
+
+ if (SUCCEEDED(hr = pMap->EnumPIDMap(&pEnumMap))) {
+ PID_MAP maps[8];
+ ULONG nbPids = 0;
+
+ if (pEnumMap->Next(_countof(maps), maps, &nbPids)==S_OK) {
+ for (ULONG i=0; iUnmapPID(1, &pid))) {
+ myprintf(TEXT("Échec UnmapPID(%u) (%") A2t TEXT("), hr=0x%08x\n"), pid, pszType, hr);
+ break;
+ }
+ }
+ }
+
+ }
+
+ return hr;
+}
Ajouté: trunk/filters.h
===================================================================
--- trunk/filters.h (rev 0)
+++ trunk/filters.h 2009-07-17 14:22:07 UTC (rev 196)
@@ -0,0 +1,178 @@
+/*
+ * filters.h
+ * Copyright (C) 2009 gingko - http://gingko.homeip.net/
+ *
+ * This file is part of Pouchin TV Mod, a free DVB-T viewer.
+ * See http://pouchintv.baysse.fr/ for updates.
+ *
+ * Pouchin TV Mod is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Pouchin TV Mod is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *
+ * Most files of this project have been changed from the Pouchin TV
+ * project (Copyright (C) 2006 Pouchin ),
+ * to use with a modified version of this software.
+ * See http://pouchinteve.free.fr/ for the original project.
+ */
+
+#pragma once
+
+// ====================================================================================
+// Structures, définitions et méthodes concernant les filtres
+// ====================================================================================
+
+/** \defgroup Interfaces Gestion d'interfaces en C++
+ Macros permettant de gérer la notion d'interfaces, en dépit
+ du fait que le langage C++ ne fournit pas (encore) cette possibilité.
+ Voir http://www.codeguru.com/cpp/cpp/cpp_mfc/oop/article.php/c9989
+ * @{ */
+
+#define Interface class
+
+/// Déclaration d'une interface de base
+#define DeclareInterface(name) Interface name { \
+ public: \
+ virtual ~name() {}
+
+/// Déclaration d'une interface basée sur une autre interface
+#define DeclareBasedInterface(name, base) class name : \
+ public base { \
+ public: \
+ virtual ~name() {}
+
+/// Fin de déclaration d'interface
+#define EndInterface };
+
+/// Définition d'un "mot clé" plus spécifique
+#define implements public
+
+/** @} */
+
+// ====================================================================================
+
+typedef CUnknown * (WINAPI * CreateFilterProc)(IUnknown *, HRESULT *);
+
+/// Données relatives aux filtres de sortie
+struct FilterData
+{
+ CComPtr pFilter; //!< Interface du filtre
+ LPCTSTR pszName; //!< Nom du filtre, pour affichage
+ bool bLocal; //!< \p true si filtre local, \p false si filtre externe
+ union {
+ const IID * pclsid; //!< CLSID du filtre si externe
+ LPFNNewCOMObject procCrea; //!< Fonction de création du filtre si interne
+ };
+
+ /// Constructeur pour filtre externe (COM)
+ FilterData(LPCTSTR pszNam, REFCLSID clsid) :
+ pszName(pszNam),
+ bLocal(false),
+ pclsid(&clsid)
+ {}
+
+ /// Constructeur pour filtre interne
+ FilterData(LPCTSTR pszNam, LPFNNewCOMObject proc) :
+ pszName(pszNam),
+ bLocal(proc!=NULL),
+ procCrea(proc)
+ {}
+
+ /**
+ * \brief Création du filtre
+ **/
+ HRESULT Create();
+
+ /**
+ * \brief Appel du dialogue de propriétés du filtre
+ **/
+ VOID create_property_dialog();
+
+ /**
+ * \brief Vérification de l'existence d'un dialogue de propriétés sur ce filtre
+ *
+ * \return \p true si un dialogue de propriétés existe
+ **/
+ bool check_property_dialog() const;
+
+ void Release() {
+ pFilter.Release(); }
+};
+
+/// Données relatives aux filtres connectés à une broche de sortie du démultiplexeur
+struct DecoderData : public FilterData
+{
+ CComPtr pMap; //!< Interface de la broche de sortie du démultiplexeur
+ const AM_MEDIA_TYPE * pAmt; //!< Descripteur du média
+ const LPCSTR pszType; //!< Type de codec, pour affichage
+ const LPCWSTR pszPinName; //!< Nom de la broche
+ MEDIA_SAMPLE_CONTENT eMsc; //!< Type de contenu
+
+ /// Constructeur pour filtre externe (COM)
+ DecoderData(const AM_MEDIA_TYPE * pAm, LPCSTR pszTyp, LPCTSTR pszNam, LPCWSTR pszPinNam,
+ MEDIA_SAMPLE_CONTENT eMs, REFCLSID clsid) :
+ FilterData(pszNam, clsid),
+ pAmt(pAm),
+ pszType(pszTyp),
+ pszPinName(pszPinNam),
+ eMsc(eMs)
+ {}
+
+ /// Constructeur pour filtre interne
+ DecoderData(const AM_MEDIA_TYPE * pAm, LPCSTR pszTyp, LPCTSTR pszNam, LPCWSTR pszPinNam,
+ MEDIA_SAMPLE_CONTENT eMs=MEDIA_ELEMENTARY_STREAM, LPFNNewCOMObject proc=NULL) :
+ FilterData(pszNam, proc),
+ pAmt(pAm),
+ pszType(pszTyp),
+ pszPinName(pszPinNam),
+ eMsc(eMs)
+ {}
+
+ /**
+ * Branchement d'un flux élémentaire (identifié par PID) sur la connexion \p pMap
+ * (en sortie du démultiplexeur).
+ * \param[in] pid N° de PID à y connecter
+ * \return Code d'erreur DirectShow
+ **/
+ HRESULT branche_pid(ULONG pid);
+
+ /**
+ * Débranchement de tous les flux élémentaires qui sont couramment
+ * présentés sur la connexion \p pMap (en sortie du démultiplexeur).
+ * \return Code d'erreur DirectShow
+ **/
+ HRESULT debranche_pids();
+
+ void Release() {
+ pMap.Release();
+ __super::Release(); }
+};
+
+struct GrabberData
+{
+ CComPtr pInterface;
+ CComPtr pCallback;
+
+ void Release() {
+ pCallback.Release();
+ pInterface.Release(); }
+
+ HRESULT SetCallback() {
+ return pInterface->SetCallback(pCallback, 0);
+ }
+
+ HRESULT ResetCallback() {
+ return pInterface->SetCallback(NULL, 0);
+ }
+};
+
Modifié: trunk/graph.cpp
===================================================================
--- trunk/graph.cpp 2009-07-09 16:19:22 UTC (rev 195)
+++ trunk/graph.cpp 2009-07-17 14:22:07 UTC (rev 196)
@@ -47,6 +47,193 @@
#endif
// ====================================================================================
+// Descripteurs de médias
+// ====================================================================================
+
+/// Format, Vidéo MPEG2
+static const MPEG2VIDEOINFO sMp2v_fmt = {
+ { // hdr
+ {0,0,720,576}, // rcSource
+ {0,0,0,0}, // rcTarget
+ 0, // dwBitRate
+ 0, // dwBitErrorRate
+ 0, // AvgTimePerFrame
+ 0, // dwInterlaceFlags
+ 0, // dwCopyProtectFlags
+ 4, // dwPictAspectRatioX
+ 3, // dwPictAspectRatioY
+ {0}, // dwControlFlag & dwReserved1
+ 0, // dwReserved2
+ { // bmiHeader
+ sizeof(BITMAPINFOHEADER),// biSize
+ 720, // biWidth
+ 576 // biHeight
+ }
+ // le reste à zéro (implicite)
+ }
+};
+
+/// Media type, Vidéo MPEG2
+static const AM_MEDIA_TYPE sMp2v_am = {
+ MEDIATYPE_Video, // majortype
+ MEDIASUBTYPE_MPEG2_VIDEO, // subtype
+ FALSE, // bFixedSizeSamples
+ TRUE, // bTemporalCompression
+ 0, // lSampleSize
+ FORMAT_MPEG2Video, // formattype
+ NULL, // pUnk
+ sizeof(sMp2v_fmt), // cbFormat
+ (LPBYTE)&sMp2v_fmt // pbFormat
+};
+
+#define FCC_AVC1 MAKEFOURCC('A', 'V', 'C', '1') // Possible aussi ...
+#define FCC_h264 MAKEFOURCC('h', '2', '6', '4')
+#define DIMH 720
+#define DIMV 576
+
+/// Format, Vidéo H264
+static const VIDEOINFOHEADER2 sH264_fmt = {
+ {0,0,0,0}, // rcSource
+ {0,0,0,0}, // rcTarget
+ 0, // dwBitRate,
+ 0, // dwBitErrorRate
+ 0, // AvgTimePerFrame
+ 0, // dwInterlaceFlags
+ 0, // dwCopyProtectFlags
+ 0, // dwPictAspectRatioX
+ 0, // dwPictAspectRatioY
+ {0}, // dwControlFlag & dwReserved1
+ 0, // dwReserved2
+ { // bmiHeader
+ sizeof(BITMAPINFOHEADER), // biSize
+ DIMH, // biWidth
+ DIMV, // biHeight
+ 0, // biPlanes
+ 0, // biBitCount
+ FCC_h264 // biCompression ( FCC_AVC1 ? )
+ }
+ // le reste à zéro (implicite)
+};
+
+/// Media type, Vidéo H264
+static const AM_MEDIA_TYPE sH264_am = {
+ MEDIATYPE_Video, // majortype
+ MEDIASUBTYPE_H264, // subtype
+ FALSE, // bFixedSizeSamples
+ TRUE, // bTemporalCompression
+ 1, // lSampleSize
+ FORMAT_VideoInfo2, // formattype
+ NULL, // pUnk
+ sizeof(sH264_fmt), // cbFormat
+ (LPBYTE)&sH264_fmt // pbFormat
+};
+
+/// Format, Audio MPEG2
+static const WAVEFORMATEX sMp2a_fmt = {
+ WAVE_FORMAT_PCM, // wFormatTag
+ 2, // nChannels
+ 48000, // nSamplesPerSec
+ 4*48000, // nAvgBytesPerSec
+ 4, // nBlockAlign
+ 16, // wBitsPerSample
+ 0 // cbSize
+};
+
+/// Media type, Audio MPEG2
+static const AM_MEDIA_TYPE sMp2a_am = {
+ MEDIATYPE_Audio, // majortype
+ MEDIASUBTYPE_MPEG2_AUDIO, // subtype
+ TRUE, // bFixedSizeSamples
+ FALSE, // bTemporalCompression
+ 0, // lSampleSize
+ FORMAT_WaveFormatEx, // formattype
+ NULL, // pUnk
+ sizeof(sMp2a_fmt), // cbFormat
+ (LPBYTE)&sMp2a_fmt // pbFormat
+};
+
+/// Format, Audio AC3
+static const WAVEFORMATEX sAc3__fmt = {
+ WAVE_FORMAT_PCM, // wFormatTag
+ 2, // nChannels
+ 48000, // nSamplesPerSec
+ 48000*4, // nAvgBytesPerSec
+ 4, // nBlockAlign
+ 16, // wBitsPerSample
+ 0 // cbSize
+};
+
+/// Media type, Audio AC3
+static const AM_MEDIA_TYPE sAc3__am = {
+ MEDIATYPE_Audio, // majortype
+ MEDIASUBTYPE_DOLBY_AC3, // subtype
+ TRUE, // bFixedSizeSamples
+ FALSE, // bTemporalCompression
+ 0, // lSampleSize
+ FORMAT_WaveFormatEx, // formattype
+ NULL, // pUnk
+ sizeof(sAc3__fmt), // cbFormat
+ (LPBYTE)&sAc3__fmt, // pbFormat
+};
+
+/// Media type, PSI
+static const AM_MEDIA_TYPE sPsi__am = {
+ MEDIATYPE_MPEG2_SECTIONS, // majortype
+ MEDIASUBTYPE_MPEG2DATA, // subtype
+ TRUE, // bFixedSizeSamples
+ FALSE, // bTemporalCompression
+ 0, // lSampleSize
+ FORMAT_None, // formattype
+ NULL, // pUnk
+ 0, // cbFormat
+ NULL // pbFormat
+};
+
+/// CLSID pour TIF
+// FC772AB0-0C7F-11D3-8FF2-00A0C9224CF4
+static CLSID CLSID_BDA_MPEG2_TIF =
+ {0xFC772AB0, 0x0C7F, 0x11D3, {0x8F, 0xF2, 0x00, 0xA0, 0xC9, 0x22, 0x4C, 0xF4}};
+
+/// Media type, TIF
+static const AM_MEDIA_TYPE sTif__am = {
+ MEDIATYPE_MPEG2_SECTIONS, // majortype
+ MEDIASUBTYPE_DVB_SI, // subtype
+ TRUE, // bFixedSizeSamples
+ FALSE, // bTemporalCompression
+ 0, // lSampleSize
+ FORMAT_None, // formattype
+ NULL, // pUnk
+ 0, // cbFormat
+ NULL // pbFormat
+};
+
+/// Media type, EPG
+static const AM_MEDIA_TYPE sEpg__am = {
+ MEDIATYPE_MPEG2_SECTIONS, // majortype
+ MEDIASUBTYPE_DVB_SI, // subtype
+ TRUE, // bFixedSizeSamples
+ FALSE, // bTemporalCompression
+ 0, // lSampleSize
+ FORMAT_None, // formattype
+ NULL, // pUnk
+ 0, // cbFormat
+ NULL, // pbFormat
+};
+
+/// Media type, PMT
+static const AM_MEDIA_TYPE sPmt__am = {
+ MEDIATYPE_MPEG2_SECTIONS, // majortype
+ MEDIASUBTYPE_DVB_SI, // subtype
+ TRUE, // bFixedSizeSamples
+ FALSE, // bTemporalCompression
+ 0, // lSampleSize
+ FORMAT_None, // formattype
+ NULL, // pUnk
+ 0, // cbFormat
+ NULL // pbFormat
+};
+
+// ====================================================================================
// Variables globales
// ====================================================================================
@@ -56,23 +243,20 @@
CComPtr pGraph;
CComPtr pEvents;
-CComPtr pNetworkProvider;
-CComPtr pDemux;
-CComPtr pVideoCodec;
-CComPtr pVideoH264Codec;
-CComPtr pAudioCodec;
-CComPtr pAc3Codec;
+FilterData sNetworkProvider(TEXT("Microsoft DVB-T Network Provider"), CLSID_DVBTNetworkProvider);
+FilterData sDemux(TEXT("MPEG2 Demultiplexer"), CLSID_MPEG2Demultiplexer);
-CComPtr pDSound;
-CComPtr pDSoundAc3;
+DecoderData sMp2vCodec(&sMp2v_am, "vidéo MPEG2", filtreMPEG2, L"mp2v");
+DecoderData sH264Codec(&sH264_am, "vidéo H264", filtreH264, L"h264");
+DecoderData sMp2aCodec(&sMp2a_am, "audio MPEG2", filtreAudio, L"mp2a");
+DecoderData sAc3_Codec(&sAc3__am, "audio AC3", filtreAc3, L"ac3");
-CComPtr pMapMPEG2;
-CComPtr pMapH264;
-CComPtr pMapSound;
-CComPtr pMapAc3;
+FilterData sDSound(TEXT("DirectSound (MPEG2)"), CLSID_DSoundRender);
+FilterData sDSoundAc3(TEXT("DirectSound (AC3)"), CLSID_DSoundRender);
+
#if USE_PMTFILTER
-CComPtr pMapPmt;
+DecoderData sPMT_Filter(&sPmt__am, "PMT", TEXT(PMT_FILTER_NAME), L"pmt", MEDIA_MPEG2_PSI, CPMTFilter::CreateInstance);
#endif
CComPtr pMpeg2Data;
@@ -80,8 +264,7 @@
CComPtr pReceiverComponent;
#if USE_SINGLE_GRABBER
-CComPtr pGrabberCB;
-CComPtr pGrabber;
+GrabberData sGrabber;
#endif
CComPtr pBDAControl;
@@ -186,7 +369,7 @@
pGraph->SetLogFile(NULL);
CloseHandle(logFile);
}
-#endif // #if LOG_DSHOW
+#endif // #if LOG_DSHOW
#if EXPORT_GRAPH
cExport.Remove();
@@ -198,33 +381,28 @@
pEvents.Release();
- pVideoCodec.Release();
- pVideoH264Codec.Release();
- pAudioCodec.Release();
- pAc3Codec.Release();
+ sMp2vCodec.Release();
+ sH264Codec.Release();
+ sMp2aCodec.Release();
+ sAc3_Codec.Release();
- pMapMPEG2.Release();
- pMapH264.Release();
- pMapSound.Release();
- pMapAc3.Release();
#if USE_PMTFILTER
- pMapPmt.Release();
+ sPMT_Filter.Release();
#endif
- pDemux.Release();
+ sDemux.Release();
clean_vmr();
- pDSound.Release();
- pDSoundAc3.Release();
+ sDSound.Release();
+ sDSoundAc3.Release();
#if USE_SINGLE_GRABBER
- pGrabberCB.Release();
- pGrabber.Release();
+ sGrabber.Release();
#endif
pNetworkTuner.Release();
pReceiverComponent.Release();
- pNetworkProvider.Release();
+ sNetworkProvider.Release();
pStats.Release();
pBDAFreq.Release();
pBDAControl.Release();
@@ -245,40 +423,36 @@
/**
* Création et ajout d'une instance de filtre défini par son "clsid" (le paramètre "nom"
* n'est ici qu'informatif, à l'usage des messages d'erreur et de l'exportation du graphe).
- * \param[in] clsid CLSID du filtre à ajouter
- * \param[in] nom Nom à associer à ce filtre
- * \param[out] pFilter Interface renvoyée de ce filtre
+ * \param[in,out] sFData Données d'après lesquelles créer le filtre
**/
-HRESULT create_and_add_filter(REFCLSID clsid, LPCTSTR nom,
- CComPtr & pFilter)
+HRESULT create_and_add_filter(FilterData & sFData)
{
- HRESULT hr = pFilter.CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER);
+ HRESULT hr = sFData.Create();
if (FAILED(hr))
- return erreur(TEXT("Le filtre \"%s\" n'a pas pu être créé"), hr, nom);
+ return erreur(TEXT("Le filtre \"%s\" n'a pas pu être créé"), hr, sFData.pszName);
- hr = AddFilterToGraph(pFilter, nom);
+ hr = AddFilterToGraph(sFData.pFilter, sFData.pszName);
if (FAILED(hr))
- return erreur(TEXT("Le filtre \"%s\" n'a pas pu être ajouté au graphe"), hr, nom);
+ return erreur(TEXT("Le filtre \"%s\" n'a pas pu être ajouté au graphe"), hr, sFData.pszName);
return hr;
}
// Création et ajout d'un filtre de type codec défini par son nom, et devant
// de plus correspondre au type 'type' et au sous-type 'subtype' définis.
-static HRESULT get_and_add_codec(LPCTSTR nom, GUID type, GUID subtype,
- LPCTSTR infotype, CComPtr & pFilter)
+static HRESULT get_and_add_codec(DecoderData & sDData)
{
- HRESULT hr = CSearchByType_Get(type, subtype, exact_match, nom, pFilter).Do();
+ HRESULT hr = CSearchByType_Get(sDData.pAmt->majortype, sDData.pAmt->subtype, exact_match, sDData.pszName, sDData.pFilter).Do();
if (SUCCEEDED(hr)) {
- myprintf(TEXT("Ajout codec %s\n"), infotype);
+ myprintf(TEXT("Ajout codec %") A2t TEXT("\n"), sDData.pszType);
- hr = AddFilterToGraph(pFilter, nom);
+ hr = AddFilterToGraph(sDData.pFilter, sDData.pszName);
if (FAILED(hr))
- return erreur(TEXT("Le codec %s \"%s\" n'a pas pu être inséré dans le graphe"),
- hr, infotype, nom);
+ return erreur(TEXT("Le codec %") A2t TEXT(" \"%s\" n'a pas pu être inséré dans le graphe"),
+ hr, sDData.pszType, sDData.pszName);
}
return hr;
}
@@ -288,8 +462,9 @@
CComPtr pInPin;
HRESULT hr = cherche_pin(pFilter, PINDIR_INPUT, pInPin, NOTCONNECTED);
- if (SUCCEEDED(hr))
+ if (SUCCEEDED(hr)) {
hr = pGraph->ConnectDirect(pOutPin, pInPin, NULL);
+ }
return hr;
}
@@ -336,16 +511,16 @@
return hr;
for (ULONG i = 0; i < NodeTypes; i++) {
- ULONG Interfaces;
- GUID Interface[32];
+ ULONG nInterfaces;
+ GUID aInterface[32];
- hr = pTop->GetNodeInterfaces(NodeType[i], &Interfaces, _countof(Interface), Interface);
+ hr = pTop->GetNodeInterfaces(NodeType[i], &nInterfaces, _countof(aInterface), aInterface);
if (FAILED(hr))
continue;
- for (ULONG j = 0; j < Interfaces; j++) {
- if (Interface[j] == iid)
+ for (ULONG j = 0; j < nInterfaces; j++) {
+ if (aInterface[j] == iid)
return pTop->GetControlNode(0, 1, NodeType[i], &pUnk);
}
}
@@ -379,547 +554,197 @@
* Créer ou obtenir une broche de sortie sur ou depuis le démultiplexeur.
*
* \param[in] pMpeg2Demux Interface du démultiplexeur
- * \param[in] am Type de média géré par la broche
+ * \param[in] sDData Information concernant le média dont la broche doit être obtenue
* \param[in] bFindExisting si \p true, rechercher si une broche déjà existante
* peut satisfaire à la demande
- * \param[in] pszPinName Nom à donner à la broche si elle est créée
* \param[out] pOutPin Interface sur la broche trouvée ou créé
**/
static HRESULT get_output_pin(IMpeg2Demultiplexer * pMpeg2Demux,
- const AM_MEDIA_TYPE & am,
+ DecoderData & sDData,
bool bFindExisting,
- LPCWSTR pszPinName,
CComPtr & pOutPin)
{
HRESULT hr;
if (bFindExisting) {
- hr = cherche_pin(pDemux, PINDIR_OUTPUT, pOutPin, &am);
+ hr = cherche_pin(sDemux.pFilter, PINDIR_OUTPUT, pOutPin, sDData.pAmt);
if (hr != E_FAIL) {
- myprintf(TEXT("%?Broche existante trouvée pour \"%") W2t TEXT("\"\n"), SUCCEEDED(hr), pszPinName);
+ myprintf(TEXT("%?Broche existante trouvée pour \"%") W2t TEXT("\"\n"), SUCCEEDED(hr), sDData.pszPinName);
return hr;
}
}
// Note : utilisation de "const_cast" ici car on ne s'attend pas normalement à ce que
// "CreateOutputPin" modifie les objets pointés.
- hr = pMpeg2Demux->CreateOutputPin(const_cast(&am),
- const_cast(pszPinName), &pOutPin);
- myprintf(TEXT("%?Broche créée pour \"%") W2t TEXT("\"\n"), SUCCEEDED(hr), pszPinName);
- return hr;
-}
-
-static HRESULT render_mp2v(IMpeg2Demultiplexer * pMpeg2Demux)
-{
- if (filtreMPEG2[0] == 0) {
- affiche_erreurs(TEXT("Aucun codec vidéo MPEG2 n'a été sélectionné"));
- return S_OK;
- }
-
- if (IsNullName(filtreMPEG2))
- return S_OK;
-
- static const MPEG2VIDEOINFO mvi = {
- { // hdr
- {0,0,720,576}, // rcSource
- {0,0,0,0}, // rcTarget
- 0, // dwBitRate
- 0, // dwBitErrorRate
- 0, // AvgTimePerFrame
- 0, // dwInterlaceFlags
- 0, // dwCopyProtectFlags
- 4, // dwPictAspectRatioX
- 3, // dwPictAspectRatioY
- {0}, // dwControlFlag & dwReserved1
- 0, // dwReserved2
- { // bmiHeader
- sizeof(BITMAPINFOHEADER), // biSize
- 720, // biWidth
- 576 // biHeight
- }
- // le reste à zéro (implicite)
- }
- };
-
- static const AM_MEDIA_TYPE am = {
- MEDIATYPE_Video, // majortype
- MEDIASUBTYPE_MPEG2_VIDEO, // subtype
- FALSE, // bFixedSizeSamples
- TRUE, // bTemporalCompression
- 0, // lSampleSize
- FORMAT_MPEG2Video, // formattype
- NULL, // pUnk
- sizeof(mvi), // cbFormat
- (LPBYTE)&mvi // pbFormat
- };
-
- CComPtr pVideoPin;
- HRESULT hr = get_output_pin(pMpeg2Demux, am, false, L"video", pVideoPin);
-
+ hr = pMpeg2Demux->CreateOutputPin(const_cast(sDData.pAmt),
+ const_cast(sDData.pszPinName), &pOutPin);
+ myprintf(TEXT("%?Broche \"%") W2t TEXT("\" créée pour %") A2t TEXT("\n"), SUCCEEDED(hr), sDData.pszPinName, sDData.pszType);
if (FAILED(hr))
- return erreur(TEXT("La broche vidéo MPEG2 n'a pas pu être créée"), hr);
-
- // le décodeur vidéo
- hr = get_and_add_codec(filtreMPEG2, MEDIATYPE_Video, MEDIASUBTYPE_MPEG2_VIDEO,
- TEXT("vidéo MPEG2"), pVideoCodec);
-
- if (SUCCEEDED(hr)) {
- hr = connect_pin_to_filter(pVideoPin, pVideoCodec);
- if (FAILED(hr))
- return erreur(
- TEXT("Impossible de connecter le démultiplexeur au codec vidéo MPEG2 \"%s\""),
- hr, filtreMPEG2);
- } else {
-#if AUTO_RENDER
- hr = pGraph->RenderEx(pVideoPin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL);
- if (FAILED(hr))
-#endif
- return erreur(TEXT("Pas de rendu possible depuis la broche vidéo MPEG2"), hr);
- }
-
- if (SUCCEEDED(hr)) {
- hr = pVideoPin.QueryInterface(&pMapMPEG2);
- myprintf(TEXT("%?erreur pMapMPEG2, hr=0x%08x\n"), FAILED(hr), hr);
- }
-
+ return erreur(TEXT("La broche %") A2t TEXT(" n'a pas pu être créée"), hr, sDData.pszType);
return hr;
}
-static HRESULT render_h264(IMpeg2Demultiplexer * pMpeg2Demux)
+static HRESULT render_video(IMpeg2Demultiplexer * pMpeg2Demux, DecoderData & sDData)
{
- if (filtreH264[0] == 0) {
- affiche_erreurs(TEXT("Aucun codec vidéo H264 n'a été sélectionné"));
+ if (sDData.pszName[0] == 0) {
+ affiche_erreurs(tstr_printf(TEXT("Aucun codec %") A2t TEXT(" n'a été sélectionné"), sDData.pszType).c_str());
return S_OK;
}
- if (IsNullName(filtreH264))
+ if (IsNullName(sDData.pszName))
return S_OK;
- #define FCC_AVC1 MAKEFOURCC('A', 'V', 'C', '1') // Possible aussi ...
- #define FCC_h264 MAKEFOURCC('h', '2', '6', '4')
- #define DIMH 720
- #define DIMV 576
+ CComPtr pOutPin;
+ HRESULT hr = get_output_pin(pMpeg2Demux, sDData, false, pOutPin);
- static const VIDEOINFOHEADER2 hdr = {
- {0,0,0,0}, // rcSource
- {0,0,0,0}, // rcTarget
- 0, // dwBitRate,
- 0, // dwBitErrorRate
- 0, // AvgTimePerFrame
- 0, // dwInterlaceFlags
- 0, // dwCopyProtectFlags
- 0, // dwPictAspectRatioX
- 0, // dwPictAspectRatioY
- {0}, // dwControlFlag & dwReserved1
- 0, // dwReserved2
- { // bmiHeader
- sizeof(BITMAPINFOHEADER), // biSize
- DIMH, // biWidth
- DIMV, // biHeight
- 0, // biPlanes
- 0, // biBitCount
- FCC_h264 // biCompression ( FCC_AVC1 ? )
- }
- // le reste à zéro (implicite)
- };
-
- static const AM_MEDIA_TYPE am = {
- MEDIATYPE_Video, // majortype
- MEDIASUBTYPE_H264, // subtype
- FALSE, // bFixedSizeSamples
- TRUE, // bTemporalCompression
- 1, // lSampleSize
- FORMAT_VideoInfo2, // formattype
- NULL, // pUnk
- sizeof(hdr), // cbFormat
- (LPBYTE)&hdr // pbFormat
- };
-
- CComPtr pVideoPin;
- HRESULT hr = get_output_pin(pMpeg2Demux, am, false, L"h264", pVideoPin);
-
if (FAILED(hr))
- return erreur(TEXT("La broche vidéo H264 n'a pas pu être créée"), hr);
-
- // le décodeur vidéo
- hr = get_and_add_codec(filtreH264, MEDIATYPE_Video, MEDIASUBTYPE_H264,
- TEXT("vidéo H264"), pVideoH264Codec);
- if (SUCCEEDED(hr)) {
- hr = connect_pin_to_filter(pVideoPin, pVideoH264Codec);
- if (FAILED(hr))
- return erreur(TEXT("Impossible de connecter le démultiplexeur au codec vidéo H264 \"%s\""), hr, filtreH264);
- } else {
-#if AUTO_RENDER
- hr = pGraph->RenderEx(pVideoPin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL);
- if (FAILED(hr))
-#endif
- affiche_erreurs(TEXT("Pas de rendu possible depuis la broche vidéo H264"), hr);
- }
-
- hr = pVideoPin.QueryInterface(&pMapH264);
- myprintf(TEXT("%?erreur pMapH264, hr=0x%08x\n"), FAILED(hr), hr);
-
- return hr;
-}
-
-static HRESULT render_son(IMpeg2Demultiplexer * pMpeg2Demux)
-{
- if (IsNullName(filtreAudio))
- return S_OK;
-
- static const WAVEFORMATEX wfm = {
- WAVE_FORMAT_PCM, // wFormatTag
- 2, // nChannels
- 48000, // nSamplesPerSec
- 4*48000, // nAvgBytesPerSec
- 4, // nBlockAlign
- 16, // wBitsPerSample
- 0 // cbSize
- };
-
- static const AM_MEDIA_TYPE am = {
- MEDIATYPE_Audio, // majortype
- MEDIASUBTYPE_MPEG2_AUDIO, // subtype
- TRUE, // bFixedSizeSamples
- FALSE, // bTemporalCompression
- 0, // lSampleSize
- FORMAT_WaveFormatEx, // formattype
- NULL, // pUnk
- sizeof(wfm), // cbFormat
- (LPBYTE)&wfm // pbFormat
- };
-
- CComPtr pSoundPin;
- HRESULT hr = get_output_pin(pMpeg2Demux, am, false, L"son", pSoundPin);
-
- if (FAILED(hr))
- return erreur(TEXT("La broche audio MPEG2 n'a pas pu être créée"), hr);
-
- // add direct sound
- hr = create_and_add_filter(CLSID_DSoundRender, TEXT("DirectSound (MPEG2)"), pDSound);
- if (FAILED(hr))
return hr;
- // le décodeur audio
- hr = get_and_add_codec(filtreAudio, MEDIATYPE_Audio, MEDIASUBTYPE_MPEG2_AUDIO,
- TEXT("audio MPEG2"), pAudioCodec);
+ // Ajout du décodeur
+ hr = get_and_add_codec(sDData);
if (SUCCEEDED(hr)) {
- hr = connect_pin_to_filter(pSoundPin, pAudioCodec);
+ hr = connect_pin_to_filter(pOutPin, sDData.pFilter);
if (FAILED(hr))
return erreur(
- TEXT("Impossible de connecter le démultiplexeur au codec audio MPEG2 \"%s\""),
- hr, filtreAudio);
-
- hr = connect_filters(pAudioCodec, pDSound);
- if (FAILED(hr))
- return erreur(
- TEXT("Impossible de connecter le Codec audio MPEG2 \"%s\" au filtre de rendu DirectSound"),
- hr, filtreAudio);
-
+ TEXT("Impossible de connecter le démultiplexeur au codec %") A2t TEXT(" \"%s\""),
+ hr, sDData.pszType, sDData.pszName);
} else {
#if AUTO_RENDER
- hr = pGraph->RenderEx(pSoundPin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL);
+ hr = pGraph->RenderEx(pOutPin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL);
if (FAILED(hr))
#endif
- return erreur(TEXT("Pas de rendu possible depuis la broche audio MPEG2"), hr);
+ return erreur(TEXT("Pas de rendu possible depuis la broche %") A2t,
+ hr, sDData.pszType);
}
- hr = pSoundPin.QueryInterface(&pMapSound);
- myprintf(TEXT("%?erreur pMapSound, hr=0x%08x\n"), FAILED(hr), hr);
-
+ if (FAILED(hr = pOutPin.QueryInterface(&sDData.pMap)))
+ return erreur(TEXT("L'interface de la broche %") A2t TEXT(" n'a pas été trouvée"), hr, sDData.pszType);
return hr;
}
-static HRESULT render_ac3(IMpeg2Demultiplexer * pMpeg2Demux)
+static HRESULT render_audio(IMpeg2Demultiplexer * pMpeg2Demux,
+ DecoderData & sDData, FilterData & sSoundFilter)
{
- if (IsNullName(filtreAc3))
+ if (IsNullName(sDData.pszName))
return S_OK;
- static const WAVEFORMATEX wfm = {
- WAVE_FORMAT_PCM, // wFormatTag
- 2, // nChannels
- 48000, // nSamplesPerSec
- 48000*4, // nAvgBytesPerSec
- 4, // nBlockAlign
- 16, // wBitsPerSample
- 0 // cbSize
- };
+ CComPtr pOutPin;
+ HRESULT hr = get_output_pin(pMpeg2Demux, sDData, false, pOutPin);
- static const AM_MEDIA_TYPE am = {
- MEDIATYPE_Audio, // majortype
- MEDIASUBTYPE_DOLBY_AC3, // subtype
- TRUE, // bFixedSizeSamples
- FALSE, // bTemporalCompression
- 0, // lSampleSize
- FORMAT_WaveFormatEx, // formattype
- NULL, // pUnk
- sizeof(wfm), // cbFormat
- (LPBYTE)&wfm, // pbFormat
- };
-
- CComPtr pAc3Pin;
- HRESULT hr = get_output_pin(pMpeg2Demux, am, false, L"ac3", pAc3Pin);
-
if (FAILED(hr))
- return erreur(TEXT("La broche audio AC3 n'a pas pu être créée"), hr);
+ return hr;
- // add direct sound
- hr = create_and_add_filter(CLSID_DSoundRender, TEXT("DirectSound (AC3)"), pDSoundAc3);
- if (FAILED(hr))
+ // Ajout du rendu audio
+ if (FAILED(hr = create_and_add_filter(sSoundFilter)))
return hr;
- // le décodeur ac3
- hr = get_and_add_codec(filtreAc3, MEDIATYPE_Audio, MEDIASUBTYPE_DOLBY_AC3,
- TEXT("audio AC3"), pAc3Codec);
+ // Ajout du décodeur
+ hr = get_and_add_codec(sDData);
if (SUCCEEDED(hr)) {
- hr = connect_pin_to_filter(pAc3Pin, pAc3Codec);
+ hr = connect_pin_to_filter(pOutPin, sDData.pFilter);
if (FAILED(hr))
return erreur(
- TEXT("Impossible de connecter le démultiplexeur au codec AC3 \"%s\""),
- hr, filtreAc3);
+ TEXT("Impossible de connecter le démultiplexeur au codec %") A2t TEXT(" \"%s\""),
+ hr, sDData.pszType, sDData.pszName);
- hr = connect_filters(pAc3Codec, pDSoundAc3);
+ hr = connect_filters(sDData.pFilter, sSoundFilter.pFilter);
if (FAILED(hr))
return erreur(
- TEXT("Impossible de connecter le Codec audio AC3 \"%s\" au filtre de rendu DirectSound"),
- hr, filtreAc3);
+ TEXT("Impossible de connecter le Codec %") A2t TEXT(" \"%s\" au filtre de rendu DirectSound"),
+ hr, sDData.pszType, sDData.pszName);
} else {
#if AUTO_RENDER
- hr = pGraph->RenderEx(pAc3Pin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL);
+ hr = pGraph->RenderEx(pOutPin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL);
if (FAILED(hr))
#endif
- return erreur(TEXT("Pas de rendu possible depuis la broche audio AC3"), hr);
+ return erreur(TEXT("Pas de rendu possible depuis la broche %") A2t,
+ hr, sDData.pszType);
}
- hr = pAc3Pin.QueryInterface(&pMapAc3);
- myprintf(TEXT("%?erreur pMapAc3, hr=0x%08x\n"), FAILED(hr), hr);
-
+ if (FAILED(hr = pOutPin.QueryInterface(&sDData.pMap)))
+ return erreur(TEXT("L'interface de la broche %") A2t TEXT(" n'a pas été trouvée"), hr, sDData.pszType);
return hr;
}
-
-static HRESULT render_psi(IMpeg2Demultiplexer * pMpeg2Demux)
+static HRESULT render_data(IMpeg2Demultiplexer * pMpeg2Demux, DecoderData & sDData, bool bFindExisting)
{
- static const AM_MEDIA_TYPE am = {
- MEDIATYPE_MPEG2_SECTIONS, // majortype
- MEDIASUBTYPE_MPEG2DATA, // subtype
- TRUE, // bFixedSizeSamples
- FALSE, // bTemporalCompression
- 0, // lSampleSize
- FORMAT_None, // formattype
- NULL, // pUnk
- 0, // cbFormat
- NULL // pbFormat
- };
+ CComPtr pOutPin;
+ HRESULT hr = get_output_pin(pMpeg2Demux, sDData, bFindExisting, pOutPin);
- CComPtr pDataPin;
- HRESULT hr = get_output_pin(pMpeg2Demux, am, true, L"data", pDataPin);
-
- if (FAILED(hr)) {
- erreur(TEXT("La broche PSI n'a pas pu être créée"), hr);
+ if (FAILED(hr))
return hr;
- }
- // add mpeg2
- {
- CComPtr pPSIFilter;
-
- hr = create_and_add_filter(__uuidof(Mpeg2Data), TEXT("MPEG-2 Sections and Tables"), pPSIFilter);
- if (FAILED(hr))
- return hr;
-
- // query MPEG-2 Sections and Tables Filter
-
- hr = pPSIFilter.QueryInterface(&pMpeg2Data);
-
- if (FAILED(hr)) {
- erreur(TEXT("L'interface d'accès aux tables PSI n'a pas été trouvée"), hr);
- return hr;
- }
-
- hr = connect_pin_to_filter(pDataPin, pPSIFilter);
- if (FAILED(hr))
- return erreur(TEXT("Impossible de connecter le démultiplexeur au filtre PSI"), hr);
- }
-
- return hr;
-}
-
-static HRESULT render_tif(IMpeg2Demultiplexer * pMpeg2Demux)
-{
- // FC772AB0-0C7F-11D3-8FF2-00A0C9224CF4
- static CLSID CLSID_BDA_MPEG2_TIF =
- {0xFC772AB0, 0x0C7F, 0x11D3, {0x8F, 0xF2, 0x00, 0xA0, 0xC9, 0x22, 0x4C, 0xF4}};
-
- static const AM_MEDIA_TYPE am = {
- MEDIATYPE_MPEG2_SECTIONS, // majortype
- MEDIASUBTYPE_DVB_SI, // subtype
- TRUE, // bFixedSizeSamples
- FALSE, // bTemporalCompression
- 0, // lSampleSize
- FORMAT_None, // formattype
- NULL, // pUnk
- 0, // cbFormat
- NULL // pbFormat
- };
-
- CComPtr pTifPin;
- HRESULT hr = get_output_pin(pMpeg2Demux, am, true, L"tif", pTifPin);
-
- if (FAILED(hr)) {
- erreur(TEXT("La broche TIF n'a pas pu être créée"), hr);
+ if (FAILED(hr = create_and_add_filter(sDData)))
return hr;
- }
- // add TIF
- {
- CComPtr pTIFFilter;
+ if (FAILED(hr = connect_pin_to_filter(pOutPin, sDData.pFilter)))
+ return erreur(TEXT("Impossible de connecter le démultiplexeur au filtre %") A2t, hr, sDData.pszType);
- hr = create_and_add_filter(CLSID_BDA_MPEG2_TIF,
- TEXT("BDA MPEG2 Transport Information Filter"), pTIFFilter);
- if (FAILED(hr))
- return hr;
-
- hr = connect_pin_to_filter(pTifPin, pTIFFilter);
- if (FAILED(hr))
- return erreur(TEXT("Impossible de connecter le démultiplexeur au filtre TIF"), hr);
- }
-
+ if (FAILED(hr = pOutPin.QueryInterface(&sDData.pMap)))
+ return erreur(TEXT("L'interface de la broche %") A2t TEXT(" n'a pas été trouvée"), hr, sDData.pszType);
return hr;
}
-static HRESULT render_epgfilter(IMpeg2Demultiplexer * pMpeg2Demux)
-{
- static const AM_MEDIA_TYPE am = {
- MEDIATYPE_MPEG2_SECTIONS, // majortype
- MEDIASUBTYPE_DVB_SI, // subtype
- TRUE, // bFixedSizeSamples
- FALSE, // bTemporalCompression
- 0, // lSampleSize
- FORMAT_None, // formattype
- NULL, // pUnk
- 0, // cbFormat
- NULL, // pbFormat
- };
-
- CComPtr pEpgPin;
- HRESULT hr = get_output_pin(pMpeg2Demux, am, false, L"epg", pEpgPin);
-
- if (FAILED(hr)) {
- erreur(TEXT("La broche EPG n'a pas pu être créée"), hr);
- return hr;
- }
-
- // add mpeg2
- {
- CComPtr pEPGFilter =
- dynamic_cast (CEPGFilter::CreateInstance(NULL, &hr));
-
- if (FAILED(hr))
- return erreur(TEXT("Le filtre EPG n'a pas pu être créé"), hr);
- hr = AddFilterToGraph(pEPGFilter, CEPGFilter::szFilterName);
- if (FAILED(hr))
- return erreur(TEXT("Le filtre EPG n'a pas pu être ajouté au graphe"), hr);
-
- hr = connect_pin_to_filter(pEpgPin, pEPGFilter);
- if (FAILED(hr))
- return erreur(TEXT("Impossible de connecter le démultiplexeur au filtre EPG"), hr);
- }
-
- CComQIPtr pMapEpg(pEpgPin);
-
- if (!pMapEpg)
- return E_NOINTERFACE;
-
- return branche_pid(pMapEpg, p_pid_EIT IF_CONSOLE_CB("EPG"), MEDIA_MPEG2_PSI);
-}
-
-#if USE_PMTFILTER
-
-static HRESULT render_pmtfilter(IMpeg2Demultiplexer * pMpeg2Demux)
-{
- static const AM_MEDIA_TYPE am = {
- MEDIATYPE_MPEG2_SECTIONS, // majortype
- MEDIASUBTYPE_DVB_SI, // subtype
- TRUE, // bFixedSizeSamples
- FALSE, // bTemporalCompression
- 0, // lSampleSize
- FORMAT_None, // formattype
- NULL, // pUnk
- 0, // cbFormat
- NULL // pbFormat
- };
-
- CComPtr pPmtPin;
- HRESULT hr = get_output_pin(pMpeg2Demux, am, false, L"pmt", pPmtPin);
-
- if (FAILED(hr))
- return erreur(TEXT("La broche PMT n'a pas pu être créée"), hr);
-
- // add mpeg2
- {
- CComPtr pPMTFilter =
- dynamic_cast(CPMTFilter::CreateInstance(NULL, &hr)); // new CPMTFilter(clsid, &hr);
-
- if (FAILED(hr))
- return erreur(TEXT("Le filtre PMT n'a pas pu être créé"), hr);
-
- hr = AddFilterToGraph(pPMTFilter, CPMTFilter::szFilterName);
- if (FAILED(hr))
- return erreur(TEXT("Le filtre PMT n'a pas pu être ajouté au graphe"), hr);
-
- hr = connect_pin_to_filter(pPmtPin, pPMTFilter);
- if (FAILED(hr))
- return erreur(TEXT("Impossible de connecter le démultiplexeur au filtre PMT"), hr);
- }
-
- hr = pPmtPin.QueryInterface(&pMapPmt);
- myprintf(TEXT("%?erreur pMapPmt, hr=0x%08x\n"), FAILED(hr), hr);
-
- return hr;
-}
-
-#endif // #if USE_PMTFILTER
-
static HRESULT cree_and_render_pins()
{
// crée les ports
- CComQIPtr pMpeg2Demux(pDemux);
+ CComQIPtr pMpeg2Demux(sDemux.pFilter);
if (!pMpeg2Demux)
return erreur(TEXT("L'interface du démultiplexeur n'a pas été trouvée"), E_NOINTERFACE);
HRESULT hr;
+ // ####### TIF :
if (!autre_graphe) {
- if (FAILED(hr = render_tif(pMpeg2Demux)))
- return erreur(TEXT("Erreur lors du rendu de la broche TIF"), hr);
+ DecoderData sTIF_Filter(&sTif__am, "TIF", TEXT("BDA MPEG2 Transport Information Filter"), L"tif", MEDIA_MPEG2_PSI, CLSID_BDA_MPEG2_TIF);
+
+ if (FAILED(hr = render_data(pMpeg2Demux, sTIF_Filter, true)))
+ return hr;
}
- if (FAILED(hr = render_mp2v(pMpeg2Demux)))
- return erreur(TEXT("Erreur lors du rendu de la broche vidéo MPEG2"), hr);
+ // ####### Vidéo MPEG2 :
+ if (FAILED(hr = render_video(pMpeg2Demux, sMp2vCodec)))
+ return hr;
- if (FAILED(hr = render_h264(pMpeg2Demux)))
- return erreur(TEXT("Erreur lors du rendu de la broche vidéo H264"), hr);
+ // ####### Vidéo H264 :
+ if (FAILED(hr = render_video(pMpeg2Demux, sH264Codec)))
+ return hr;
- if (FAILED(hr = render_son(pMpeg2Demux)))
- return erreur(TEXT("Erreur lors du rendu de la broche audio MPEG2"), hr);
+ // ####### Audio MPEG2 :
+ if (FAILED(hr = render_audio(pMpeg2Demux, sMp2aCodec, sDSound)))
+ return hr;
- if (FAILED(hr = render_ac3(pMpeg2Demux)))
- return erreur(TEXT("Erreur lors du rendu de la broche audio AC3"), hr);
+ // ####### Audio AC3 :
+ if (FAILED(hr = render_audio(pMpeg2Demux, sAc3_Codec, sDSoundAc3)))
+ return hr;
- if (FAILED(hr = render_psi(pMpeg2Demux)))
- return erreur(TEXT("Erreur lors du rendu de la broche PSI"), hr);
- if (FAILED(hr = render_epgfilter(pMpeg2Demux)))
- return erreur(TEXT("Erreur lors du rendu de la broche EPG"), hr);
+ // ####### PSI :
+ DecoderData sPSI_Filter(&sPsi__am, "PSI", TEXT("MPEG-2 Sections and Tables"), L"data", MEDIA_MPEG2_PSI, __uuidof(Mpeg2Data));
+ if (SUCCEEDED(hr = render_data(pMpeg2Demux, sPSI_Filter, true))) {
+ // query MPEG-2 Sections and Tables Filter
+ if (FAILED(hr = sPSI_Filter.pFilter.QueryInterface(&pMpeg2Data)))
+ return erreur(TEXT("L'interface d'accès aux tables %") A2t TEXT(" n'a pas été trouvée"), hr, sPSI_Filter.pszType);
+ }
+ if (FAILED(hr))
+ return hr;
+
+ // ####### EPG :
+ DecoderData sEPG_Filter(&sEpg__am, "EPG", TEXT(EPG_FILTER_NAME), L"epg", MEDIA_MPEG2_PSI, CEPGFilter::CreateInstance);
+
+ if (SUCCEEDED(hr = render_data(pMpeg2Demux, sEPG_Filter, false)))
+ hr = sEPG_Filter.branche_pid(p_pid_EIT);
+ if (FAILED(hr))
+ return hr;
+
#if USE_PMTFILTER
- if (FAILED(hr = render_pmtfilter(pMpeg2Demux)))
- return erreur(TEXT("Erreur lors du rendu de la broche PMT"), hr);
+ // ####### PMT :
+ if (FAILED(hr = render_data(pMpeg2Demux, sPMT_Filter, false)))
+ return hr;
#endif
- // fini
return hr;
}
@@ -1010,6 +835,11 @@
// Gestion des événements du graphe
// ====================================================================================
+/**
+ * Traitement d'un événement du graphe
+ * \param[in] hWnd Handle de la fenêtre principale
+ * \return Code d'erreur DirectShow
+ **/
HRESULT HandleGraphEvent(HWND hWnd)
{
// Disregard if we don't have an IMediaEventEx pointer.
@@ -1169,16 +999,14 @@
**/
HRESULT build_graph()
{
- CompatResult eCompat;
- // créer le graphe
-
+ // Créer le graphe
HRESULT hr = pGraph.CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER);
if (FAILED(hr) )
return erreur(TEXT("Pas réussi à créer le graphe DirectShow !"), hr);
- // on logge
#if LOG_DSHOW
+ // On loggue
static TCHAR szLogFileName[MAX_PATH] = {0}; // -> Même système que dans 'console.cpp'
if (!*szLogFileName) {
@@ -1199,27 +1027,27 @@
if (FAILED(hr))
return erreur(TEXT("Échec de l'exportation du graphe"), hr);
#endif // #if EXPORT_GRAPH
+
{
- // Création filtre dvb-t
- if (!autre_graphe) {
- hr = create_and_add_filter(CLSID_DVBTNetworkProvider,
- TEXT("Microsoft DVB-T Network Provider"), pNetworkProvider);
- if (FAILED(hr))
- return hr;
- } else {
+ if (autre_graphe) {
// Ancien graphe
- pNetworkProvider =
- dynamic_cast(CNetworkProvider::CreateInstance(NULL, &hr));
+ sNetworkProvider.bLocal = true;
+ sNetworkProvider.procCrea = CNetworkProvider::CreateInstance;
+ sNetworkProvider.pszName = TEXT(NETWORK_FILTER_NAME);
+ }
- if (SUCCEEDED(hr))
- hr = AddFilterToGraph(pNetworkProvider, CNetworkProvider::szFilterName);
+ // Création filtre DVB-T
+ hr = create_and_add_filter(sNetworkProvider);
if (FAILED(hr))
- return erreur(TEXT("Échec de l'insertion du filtre Network Provider"), hr);
- }
- CComPtr pAvantDemux;
+ return hr;
- eCompat = filtre_compat(pNetworkTuner);
+ CSearchByCategory_Get(KSCATEGORY_BDA_NETWORK_TUNER, nom_tuner, pNetworkTuner).Do();
+ CompatResult eCompat = filtre_compat(pNetworkTuner);
+ CComPtr pLastAddedFilter; //!< Pointeur sur dernier filtre ajouté
+ // (nécessaire lorsque la connexion au filtre suivant requiert
+ // un filtre source qui est susceptible de varier)
+
if (eCompat == compat_Tuner) {
// PCI
@@ -1227,12 +1055,14 @@
if (FAILED(hr))
return erreur(TEXT("Échec de l'insertion du filtre Tuner"), hr);
+ CSearchByCategory_Get(KSCATEGORY_BDA_RECEIVER_COMPONENT, nom_receiver, pReceiverComponent).Do();
+
hr = AddFilterToGraph(pReceiverComponent, nom_receiver);
if (FAILED(hr))
return erreur(TEXT("Échec de l'insertion du filtre Récepteur"), hr);
// connect Tuner
- hr = connect_filters(pNetworkProvider, pNetworkTuner);
+ hr = connect_filters(sNetworkProvider.pFilter, pNetworkTuner);
if (FAILED(hr))
return erreur(TEXT("Tuner TNT non compatible, veuillez effacer \"config.ini\" et redémarrer"), hr);
@@ -1241,7 +1071,7 @@
if (FAILED(hr))
return erreur(TEXT("Récepteur TNT non compatible, veuillez effacer \"config.ini\" et redémarrer"), hr);
- pAvantDemux = pReceiverComponent;
+ pLastAddedFilter = pReceiverComponent; // Mémoriser pour connexion suivante
} else if (eCompat == compat_Receiver) {
// USB
@@ -1250,11 +1080,11 @@
if (FAILED(hr))
return erreur(TEXT("Échec de l'insertion du filtre Tuner USB"), hr);
- hr = connect_filters(pNetworkProvider, pNetworkTuner);
+ hr = connect_filters(sNetworkProvider.pFilter, pNetworkTuner);
if (FAILED(hr))
return erreur(TEXT("Tuner USB non compatible, veuillez effacer \"config.ini\" et redémarrer"), hr);
- pAvantDemux = pNetworkTuner;
+ pLastAddedFilter = pNetworkTuner; // Mémoriser pour connexion suivante
} else
return E_FAIL;
@@ -1262,7 +1092,6 @@
if (FAILED(hr))
return erreur(TEXT("L'interface IBDA_DeviceControl n'a pas été trouvée"), hr);
-
hr = Search_IBDA_Topology(pNetworkTuner, pBDAFreq);
if (FAILED(hr))
return erreur(TEXT("L'interface de changement de fréquence n'a pas été trouvée"), hr);
@@ -1276,58 +1105,56 @@
// connect 3
#if USE_SINGLE_GRABBER
- CComPtr filtrePrec;
+ FilterData sGrabberFilter(TEXT("Grabber"), CLSID_SampleGrabber);
- hr = create_and_add_filter(CLSID_SampleGrabber, TEXT("Grabber"), filtrePrec);
+ hr = create_and_add_filter(sGrabberFilter);
if (FAILED(hr))
return hr;
- hr = connect_filters(pAvantDemux, filtrePrec);
+ hr = connect_filters(pLastAddedFilter, sGrabberFilter.pFilter);
if (FAILED(hr))
return erreur(
TEXT("Le grabber n'a pas pu être connecté à la carte TNT, ")
TEXT("veuillez effacer \"%s%s\" et redémarrer"), hr, prefix_conf, config_file);
- hr = filtrePrec.QueryInterface(&pGrabber);
+ hr = sGrabberFilter.pFilter.QueryInterface(&sGrabber.pInterface);
if (FAILED(hr))
return erreur(TEXT("L'interface du grabber n'a pas été trouvée"), hr);
- pGrabberCB = new CSampleGrabber();
- if (pGrabberCB==NULL)
+ sGrabber.pCallback = new CSampleGrabber();
+ if (sGrabber.pCallback==NULL)
return erreur(TEXT("L'interface de callback du grabber n'a pas pu être créée"), E_FAIL);
+ pLastAddedFilter = sGrabberFilter.pFilter; // Mémoriser pour connexion suivante
-#else
- CComPtr filtrePrec = pAvantDemux;
-
+#else // #if USE_SINGLE_GRABBER
for (int i=0; i < enregistrements_actuels.count(); i++) {
- CComPtr pGrabber;
TCHAR nom[20];
_stprintf_s(nom, _countof(nom), TEXT("Grabber %u"), i);
- hr = create_and_add_filter(CLSID_SampleGrabber, nom, pGrabber);
- if (FAILED(hr))
+
+ FilterData sGrabberFilter(nom, CLSID_SampleGrabber);
+
+ if (FAILED(hr = create_and_add_filter(sGrabberFilter)))
return hr;
- hr = connect_filters(filtrePrec, pGrabber);
+ hr = connect_filters(pLastAddedFilter, sGrabberFilter.pFilter);
if (FAILED(hr))
return erreur(
TEXT("Le grabber n'a pas pu être connecté à la carte TNT, ")
TEXT("veuillez effacer \"%s%s\" et redémarrer"), hr, prefix_conf, config_file);
- filtrePrec.Release();
- enregistrements_actuels[i].query(pGrabber);
- filtrePrec = pGrabber;
+ enregistrements_actuels[i].query(sGrabberFilter.pFilter);
+ pLastAddedFilter = sGrabberFilter.pFilter; // Mémoriser pour connexion suivante
}
-#endif
+#endif // #if USE_SINGLE_GRABBER
-
// connect 4
- hr = create_and_add_filter(CLSID_MPEG2Demultiplexer, TEXT("MPEG2 Demultiplexer"), pDemux);
+ hr = create_and_add_filter(sDemux);
if (FAILED(hr))
return hr;
- hr = connect_filters(filtrePrec, pDemux);
+ hr = connect_filters(pLastAddedFilter, sDemux.pFilter);
if (FAILED(hr))
return erreur(
TEXT("Le grabber n'a pas pu être connecté au démultiplexeur, ")
@@ -1335,10 +1162,8 @@
}
}
- // fin des recherches, ajoute tout dans le graphe
+ // connexions
- // connections
-
hr = cree_and_render_pins();
if (FAILED(hr))
return erreur(TEXT("Erreur lors de la création du graphe"), hr);
Modifié: trunk/graph.h
===================================================================
--- trunk/graph.h 2009-07-09 16:19:22 UTC (rev 195)
+++ trunk/graph.h 2009-07-17 14:22:07 UTC (rev 196)
@@ -29,6 +29,7 @@
#pragma once
#include "base.h"
+#include "filters.h"
#include "rendering.h"
#include
@@ -113,37 +114,26 @@
extern CComPtr pGraph; //!< Interface d'accès global au graphe
-extern CComPtr pNetworkProvider;
-
-extern CComPtr pNetworkTuner;
-extern CComPtr pReceiverComponent;
-
#if USE_SINGLE_GRABBER
-extern CComPtr pGrabberCB;
-extern CComPtr pGrabber;
+extern GrabberData sGrabber;
#endif
extern CComPtr pBDAControl;
extern CComPtr pBDAFreq;
-extern CComPtr pMapMPEG2;
-extern CComPtr pMapH264;
-extern CComPtr pMapSound;
-extern CComPtr pMapAc3;
-
#if USE_PMTFILTER
-extern CComPtr pMapPmt;
+extern DecoderData sPMT_Filter;
#endif
-extern CComPtr pDSound;
-extern CComPtr pDSoundAc3;
+extern FilterData sDSound;
+extern FilterData sDSoundAc3;
-extern CComPtr pVideoCodec;
-extern CComPtr pVideoH264Codec;
-extern CComPtr pAudioCodec;
-extern CComPtr pAc3Codec;
+extern DecoderData sMp2vCodec;
+extern DecoderData sH264Codec;
+extern DecoderData sMp2aCodec;
+extern DecoderData sAc3_Codec;
-extern CComPtr pDemux;
+extern FilterData sDemux;
extern VideoStreamType ePrevVideoType; //!< Type de flux vidéo couramment utilisé (pour pouvoir
//!< détecter quand changer de codec)
@@ -159,13 +149,31 @@
/**
* Création et ajout d'une instance de filtre défini par son "clsid" (le paramètre "nom"
* n'est ici qu'informatif, à l'usage des messages d'erreur et de l'exportation du graphe).
- * \param[in] clsid CLSID du filtre à ajouter
- * \param[in] nom Nom à associer à ce filtre
- * \param[out] pFilter Interface renvoyée de ce filtre
+ * \param[in,out] sFData Données d'après lesquelles créer le filtre
**/
-HRESULT create_and_add_filter(REFCLSID clsid, LPCTSTR nom,
- CComPtr & pFilter);
+HRESULT create_and_add_filter(FilterData & sFData);
+/**
+ * Appel du dialogue de propriétés d'un filtre donné
+ *
+ * \param[in] pFilter Interface du filtre à dont le dialogue doit être ouvert
+ * \param[in] nom Nom du filtre
+ **/
+VOID create_property_dialog(CComPtr & pFilter, LPCTSTR nom);
+
+inline VOID create_property_dialog(FilterData & sFData)
+{
+ create_property_dialog(sFData.pFilter, sFData.pszName);
+}
+
+/**
+ * Vérification de l'existence d'un dialogue de propriétés sur un filtre donné
+ *
+ * \param[in] pFilter Interface du filtre à tester
+ * \return \p true si dialogue disponible, \p false si non
+ **/
+bool check_property_dialog(IBaseFilter * pFilter);
+
/// Intervalle (recommandé) pour l'échantillonnage de la qualité du signal
#define DUREE_SIGNAL_STATS 200
Modifié: trunk/ini.cpp
===================================================================
--- trunk/ini.cpp 2009-07-09 16:19:22 UTC (rev 195)
+++ trunk/ini.cpp 2009-07-17 14:22:07 UTC (rev 196)
@@ -2596,6 +2596,9 @@
**/
bool check_config(void)
{
+ CComPtr pNetworkTuner;
+ CComPtr pReceiverComponent;
+
CSearchByCategory_Get(KSCATEGORY_BDA_NETWORK_TUNER, nom_tuner, pNetworkTuner).Do();
if (pNetworkTuner == NULL) {
@@ -2609,14 +2612,11 @@
if (filtre_compat(pReceiverComponent) != compat_None) {
return true;
} else {
- pNetworkTuner.Release();
- pReceiverComponent.Release();
return false;
}
} else if (eCompat == compat_Receiver) { // USB
return true;
} else {
- pNetworkTuner.Release();
return false;
}
}
Modifié: trunk/main.cpp
===================================================================
--- trunk/main.cpp 2009-07-09 16:19:22 UTC (rev 195)
+++ trunk/main.cpp 2009-07-17 14:22:07 UTC (rev 196)
@@ -649,31 +649,23 @@
static void update_filtres_menus(HMENU hMenu)
{
// Ajustement des menus
- set_menu_enable_state(hMenu, IDM_MPEG2,
- !IsNullName(filtreMPEG2) && check_property_dialog(pVideoCodec));
- set_menu_enable_state(hMenu, IDM_H264,
- !IsNullName(filtreH264) && check_property_dialog(pVideoH264Codec));
- set_menu_enable_state(hMenu, IDM_AUDIO,
- !IsNullName(filtreAudio) && check_property_dialog(pAudioCodec));
- set_menu_enable_state(hMenu, IDM_AC3,
- !IsNullName(filtreAc3) && check_property_dialog(pAc3Codec));
+ set_menu_enable_state(hMenu, IDM_MPEG2, sMp2vCodec.check_property_dialog());
+ set_menu_enable_state(hMenu, IDM_H264, sH264Codec.check_property_dialog());
+ set_menu_enable_state(hMenu, IDM_AUDIO, sMp2aCodec.check_property_dialog());
+ set_menu_enable_state(hMenu, IDM_AC3, sAc3_Codec.check_property_dialog());
bool bHaveVmr = vmr_mode!=vmt_null;
- set_menu_enable_state(hMenu, IDM_VMR,
- bHaveVmr && pVMR && pVMR->check_property_dialog());
- set_menu_enable_state(hMenu, IDM_DSOUND,
- check_property_dialog(pDSound));
- set_menu_enable_state(hMenu, IDM_DSOUNDAC3,
- check_property_dialog(pDSoundAc3));
- set_menu_enable_state(hMenu, IDM_DEMUX,
- check_property_dialog(pDemux));
+ set_menu_enable_state(hMenu, IDM_VMR, bHaveVmr && pVMR && pVMR->check_property_dialog());
+ set_menu_enable_state(hMenu, IDM_DSOUND, sDSound.check_property_dialog());
+ set_menu_enable_state(hMenu, IDM_DSOUNDAC3, sDSoundAc3.check_property_dialog());
+ set_menu_enable_state(hMenu, IDM_DEMUX, sDemux.check_property_dialog());
- set_menu_enable_state(hMenu, IDM_ZOOM, bHaveVmr);
- set_menu_enable_state(hMenu, IDM_DEZOOM, bHaveVmr);
- set_menu_enable_state(hMenu, IDM_ALLWDT, bHaveVmr);
- set_menu_enable_state(hMenu, IDM_ALLHGT, bHaveVmr);
- set_menu_enable_state(hMenu, IDM_ETIRER, bHaveVmr);
+ set_menu_enable_state(hMenu, IDM_ZOOM, bHaveVmr);
+ set_menu_enable_state(hMenu, IDM_DEZOOM, bHaveVmr);
+ set_menu_enable_state(hMenu, IDM_ALLWDT, bHaveVmr);
+ set_menu_enable_state(hMenu, IDM_ALLHGT, bHaveVmr);
+ set_menu_enable_state(hMenu, IDM_ETIRER, bHaveVmr);
set_menu_enable_state(hMenu, IDM_DEFAULT_ZOOM, bHaveVmr);
}
@@ -1662,19 +1654,19 @@
break;
case IDM_MPEG2:
- create_property_dialog(pVideoCodec, filtreMPEG2);
+ sMp2vCodec.create_property_dialog();
break;
case IDM_H264:
- create_property_dialog(pVideoH264Codec, filtreH264);
+ sH264Codec.create_property_dialog();
break;
case IDM_AUDIO:
- create_property_dialog(pAudioCodec, filtreAudio);
+ sMp2aCodec.create_property_dialog();
break;
case IDM_AC3:
- create_property_dialog(pAc3Codec, filtreAc3);
+ sAc3_Codec.create_property_dialog();
break;
case IDM_VMR:
@@ -1683,15 +1675,15 @@
break;
case IDM_DSOUND:
- create_property_dialog(pDSound, TEXT("Direct sound"));
+ sDSound.create_property_dialog();
break;
case IDM_DSOUNDAC3:
- create_property_dialog(pDSoundAc3, TEXT("Direct sound AC3"));
+ sDSoundAc3.create_property_dialog();
break;
case IDM_DEMUX:
- create_property_dialog(pDemux, TEXT("Demux"));
+ sDemux.create_property_dialog();
break;
case IDM_ZOOM:
@@ -3058,12 +3050,14 @@
TEXT("Tuner : %s\n")
TEXT("Récepteur : %s\n")
TEXT("Codec MPEG2 : %s\n")
+ TEXT("Codec H264 : %s\n")
TEXT("Codec Audio : %s\n")
TEXT("Codec AC3 : %s\n")
TEXT("Ville : %s\n"),
nom_tuner,
nom_receiver,
filtreMPEG2,
+ filtreH264,
filtreAudio,
filtreAc3,
nomVille);
Modifié: trunk/network.cpp
===================================================================
--- trunk/network.cpp 2009-07-09 16:19:22 UTC (rev 195)
+++ trunk/network.cpp 2009-07-17 14:22:07 UTC (rev 196)
@@ -122,7 +122,9 @@
delete m_bidon;
}
-LPCWSTR CNetworkProvider::szFilterName = L"Network Provider PTvM";
+#define __WTXT(str) L##str
+#define WTXT(str) __WTXT(str)
+LPCWSTR CNetworkProvider::szFilterName = WTXT(NETWORK_FILTER_NAME);
CUnknown * WINAPI CNetworkProvider::CreateInstance(IUnknown *pUnk, HRESULT *phr) // static
{
Modifié: trunk/network.h
===================================================================
--- trunk/network.h 2009-07-09 16:19:22 UTC (rev 195)
+++ trunk/network.h 2009-07-17 14:22:07 UTC (rev 196)
@@ -34,6 +34,8 @@
#include
+#define NETWORK_FILTER_NAME "Network Provider PTvM"
+
/**
* Pseudo-broche de sortie pour pseudo-filtre.
* Cette broche de sortie n'a en réalité aucun flux à fournir.
Modifié: trunk/parse.cpp
===================================================================
--- trunk/parse.cpp 2009-07-09 16:19:22 UTC (rev 195)
+++ trunk/parse.cpp 2009-07-17 14:22:07 UTC (rev 196)
@@ -407,7 +407,7 @@
if (FAILED(hr)) {
log(TEXT("Erreur au changement de fréquence, code 0x%08x\n"), hr);
- return ss_error;
+ // return ss_error; // (apparemment certains tuners renvoient le code d'erreur alors qu'ils ont quand même changé la fréquence)
}
Sleep(delai_tuner1); // Délai de verrouillage
@@ -425,7 +425,7 @@
if (FAILED(hr)) {
log(TEXT("Erreur au changement de fréquence, code 0x%08x\n"), hr);
- return ss_error;
+ // return ss_error;
}
Sleep(delai_tuner1); // Délai de verrouillage
@@ -727,11 +727,12 @@
boolToYesNo(scan_ignore_presence),
boolToYesNo(scan_ignore_lock),
boolToYesNo(scan_ignore_quality));
- log(TEXT(" -- Temps de stabilisation = %u mS\n")
+ log(TEXT(" -- Temps de stabilisation 1 = %u mS\n")
+ TEXT(" -- Temps de stabilisation 2 = %u mS\n")
TEXT(" -- Correction fréquence tuner = %i kHz (non inclus dans valeurs affichées)\n")
// TEXT(" -- Utiliser fréquences paires = %s\n"),
TEXT(" -- Essayer +5 kHz si échec = %s\n"),
- delai_tuner2, offset_tuner,
+ delai_tuner1, delai_tuner2, offset_tuner,
// boolToYesNo(use_even_frequencies),
boolToYesNo(try_adding_5khz));
Modifié: trunk/pmtfilter.cpp
===================================================================
--- trunk/pmtfilter.cpp 2009-07-09 16:19:22 UTC (rev 195)
+++ trunk/pmtfilter.cpp 2009-07-17 14:22:07 UTC (rev 196)
@@ -47,7 +47,9 @@
myprintf(TEXT("%") W2t TEXT(" detruit\n"), szFilterName);
}
-LPCWSTR CPMTFilter::szFilterName = L"Filtre PMT PTvM";
+#define __WTXT(str) L##str
+#define WTXT(str) __WTXT(str)
+LPCWSTR CPMTFilter::szFilterName = WTXT(PMT_FILTER_NAME);
CUnknown * WINAPI CPMTFilter::CreateInstance(IUnknown *pUnk, HRESULT *phr) // static
{
Modifié: trunk/pmtfilter.h
===================================================================
--- trunk/pmtfilter.h 2009-07-09 16:19:22 UTC (rev 195)
+++ trunk/pmtfilter.h 2009-07-17 14:22:07 UTC (rev 196)
@@ -34,6 +34,8 @@
#include
+#define PMT_FILTER_NAME "Filtre PMT PTvM"
+
[uuid("A72DA4DF-8931-4598-97C5-0AB895EEB356")]
class CPMTFilter : public CBaseRenderer
{
Modifié: trunk/record.cpp
===================================================================
--- trunk/record.cpp 2009-07-09 16:19:22 UTC (rev 195)
+++ trunk/record.cpp 2009-07-17 14:22:07 UTC (rev 196)
@@ -56,7 +56,7 @@
stop(epr_interrompu); // précaution
#if USE_SINGLE_GRABBER // USE_SINGLE_GRABBER
- if (pGrabber && cleCh!=0 && pGrabberCB) {
+ if (sGrabber.pInterface && cleCh!=0 && sGrabber.pCallback) {
// Nombre d'enregistrements avant le démarrage de celui-ci :
int nPrevRecCount = enregistrements_actuels.count_recording();
@@ -66,7 +66,7 @@
programmation_modifiee = true;
}
- CSampleGrabber & cSg = dynamic_cast(*pGrabberCB);
+ CSampleGrabber & cSg = dynamic_cast(*sGrabber.pCallback);
if (cSg.Lock()) { // On a l'accès au mutex
if (pCapture)
@@ -77,7 +77,7 @@
// S'il n'y avait aucun enregitrement en cours auparavant, on démarre le "callback" maintenant :
if (nPrevRecCount==0) {
- pGrabber->SetCallback(pGrabberCB, 0);
+ sGrabber.SetCallback();
#if USE_THREAD_IN_GRABBER
cSg.StartThread(); // Démarrage du "thread"
#endif
@@ -168,9 +168,10 @@
programmation_modifiee = true;
}
}
- if (pCapture && pGrabberCB) {
- CSampleGrabber & cSg = dynamic_cast(*pGrabberCB);
+ if (pCapture && sGrabber.pCallback) {
+ CSampleGrabber & cSg = dynamic_cast(*sGrabber.pCallback);
+
if (cSg.Lock()) {
CCapture * pCapt = pCapture;
@@ -184,7 +185,7 @@
// S'il n'y a plus aucun enregistrement en cours, on arrête le "callback" maintenant :
if (nPrevRecCount==0) {
- pGrabber->SetCallback(NULL, 0);
+ sGrabber.ResetCallback();
#if USE_THREAD_IN_GRABBER
cSg.StopThread();
#endif
Modifié: trunk/rendering.cpp
===================================================================
--- trunk/rendering.cpp 2009-07-09 16:19:22 UTC (rev 195)
+++ trunk/rendering.cpp 2009-07-17 14:22:07 UTC (rev 196)
@@ -469,18 +469,12 @@
// Implémentations des méthodes de la classe CVideoRenderer
// ====================================================================================
-/// Vérification du dialogue de propriétés du VMR
-bool CVideoRenderer::check_property_dialog()
+/// Création et ajout du VMR dans le filtre
+HRESULT CVideoRenderer::CreateAndAdd()
{
- return ::check_property_dialog(*this);
+ return create_and_add_filter(*this);
}
-/// Ouverture du dialogue de propriétés du VMR
-VOID CVideoRenderer::create_property_dialog()
-{
- ::create_property_dialog(*this, TEXT("VMR"));
-}
-
/// Initialisation générale
HRESULT CVideoRenderer::Init()
{
@@ -511,7 +505,7 @@
return hr;
// Récupération de la broche d'entrée (pour le ratio d'aspect)
- return cherche_pin(*this, PINDIR_INPUT, pInputPin);
+ return cherche_pin(pFilter, PINDIR_INPUT, pInputPin);
}
/// Connexion à une sortie de codec
@@ -523,7 +517,7 @@
HRESULT hr = E_FAIL;
if (pVidCodec) {
- hr = connect_filters(pVidCodec, *this);
+ hr = connect_filters(pVidCodec, pFilter);
// Problème récurrent à identifier ici : erreur 0x80040207
// = VFW_E_NO_ACCEPTABLE_TYPES ("There is no common media type between these pins")
if (FAILED(hr)) {
@@ -554,7 +548,7 @@
CComPtr pOutPin;
HRESULT hr;
- if (FAILED(hr = cherche_pin(*this, PINDIR_INPUT, pInPin)))
+ if (FAILED(hr = cherche_pin(pFilter, PINDIR_INPUT, pInPin)))
return hr;
if (FAILED(hr = pInPin->ConnectedTo(&pOutPin)))
return hr;
@@ -688,7 +682,8 @@
void LimitOsdRate();
protected:
- CVideoRendererWithBitmapOSD() :
+ CVideoRendererWithBitmapOSD(LPCTSTR pszNam, REFCLSID clsid) :
+ CVideoRenderer(pszNam, clsid),
hBmp(NULL),
hdcBmp(NULL),
sBmpSize(SIZE()),
@@ -737,9 +732,6 @@
{
HPEN hPen;
- /// Création et ajout du filtre
- virtual HRESULT CreateAndAdd();
-
/// Point d'appel pour redessiner cet objet OSD en réponse à \p WM_PAINT
/// \param[in] hDC "Device context" à utiliser
virtual void Paint(HDC hDC);
@@ -772,7 +764,6 @@
{
CComPtr pVMR7Control;
- virtual HRESULT CreateAndAdd();
virtual HRESULT InitDeinterlace(); //!< \todo Voir \p CVideoRenderer::InitDeinterlace
virtual HRESULT InitControl();
@@ -813,7 +804,7 @@
public:
// Constructeur
CVideoMixingRenderer7() :
- CVideoRenderer()
+ CVideoRenderer(TEXT("Video Mixing Renderer 7"), CLSID_VideoMixingRenderer)
{}
};
@@ -858,7 +849,6 @@
CComPtr pVMR9Control; //!< Interface de contrôle
CComPtr pBMP; //!< Interface de transfert du bitmap
- virtual HRESULT CreateAndAdd();
virtual HRESULT Configure();
virtual HRESULT InitControl();
@@ -898,7 +888,8 @@
virtual void Paint(HDC hDC);
public:
- CVideoMixingRenderer9()
+ CVideoMixingRenderer9() :
+ CVideoRendererWithBitmapOSD(TEXT("Video Mixing Renderer 9"), CLSID_VideoMixingRenderer9)
{
}
};
@@ -913,7 +904,6 @@
CComPtr pEVRControl; //!< Interface de contrôle
CComPtr pBMP; //!< Interface de transfert du bitmap
- virtual HRESULT CreateAndAdd();
virtual HRESULT InitControl();
/// Calcul de la taille à attribuer au bitmap à incruster dans la vidéo
@@ -951,7 +941,8 @@
virtual void Paint(HDC hDC);
public:
- CEnhancedVideoRenderer()
+ CEnhancedVideoRenderer() :
+ CVideoRendererWithBitmapOSD(TEXT("Enhanced Video Renderer"), CLSID_EnhancedVideoRenderer)
{
}
};
@@ -1077,7 +1068,7 @@
/// Constructeur
CNullVideoRenderer::CNullVideoRenderer() :
- CVideoRenderer(),
+ CVideoRenderer(TEXT("Null Renderer"), CLSID_NullRenderer),
hPen(NULL)
{
LOGBRUSH sLbrsh = {
@@ -1089,14 +1080,6 @@
hPen = ExtCreatePen(PS_COSMETIC|PS_SOLID, 1, &sLbrsh, 0, NULL);
}
-/// Création et ajout du filtre
-HRESULT CNullVideoRenderer::CreateAndAdd()
-{
- return
- create_and_add_filter(
- CLSID_NullRenderer, TEXT("Null Renderer"), *this);
-}
-
/// Point d'appel pour redessiner cet objet OSD en réponse à \p WM_PAINT
/// \param[in] hDC "Device context" à utiliser
/// \todo Ajouter éventuellement un texte "Sortie vidéo désactivée" en milieu d'affichage
@@ -1133,7 +1116,7 @@
HRESULT hr;
{
- CComQIPtr pMixControl(*this);
+ CComQIPtr pMixControl(pFilter);
if (!pMixControl)
return erreur(
@@ -1146,7 +1129,7 @@
if (FAILED(hr))
return erreur(TEXT("Échec de SetMixingPrefs"), hr);
- CComQIPtr pDeint(*this);
+ CComQIPtr pDeint(pFilter);
if (!pDeint)
return erreur(
@@ -1186,16 +1169,9 @@
return hr;
}
-HRESULT CVideoMixingRenderer7::CreateAndAdd()
-{
- return
- create_and_add_filter(
- CLSID_VideoMixingRenderer, TEXT("Video Mixing Renderer"), *this);
-}
-
HRESULT CVideoMixingRenderer7::InitControl()
{
- HRESULT hr = QueryInterface(&pVMR7Control);
+ HRESULT hr = pFilter.QueryInterface(&pVMR7Control);
if (FAILED(hr))
return erreur(TEXT("L'interface de contrôle VMR n'est pas disponible"), hr);
@@ -1212,7 +1188,7 @@
/// \param[in] bEtirer Déformer la vidéo si nécessaire pour remplir le rectangle
HRESULT CVideoMixingRenderer7::SetAspectRatioMode(bool bEtirer)
{
- CComQIPtr pARC(*this);
+ CComQIPtr pARC(pFilter);
if (!pARC)
return erreur(
@@ -1287,7 +1263,7 @@
HRESULT CVideoMixingRenderer7_renderless::Configure()
{
- CComQIPtr pVMRConfig(*this);
+ CComQIPtr pVMRConfig(pFilter);
if (!pVMRConfig)
return erreur(
@@ -1303,7 +1279,7 @@
HRESULT CVideoMixingRenderer7_renderless::PrepareSurface()
{
- CComQIPtr pNotify(*this);
+ CComQIPtr pNotify(pFilter);
if (!pNotify)
return erreur(
@@ -1349,7 +1325,7 @@
HRESULT CVideoMixingRenderer7_windowless::Configure()
{
- CComQIPtr pVMRConfig(*this);
+ CComQIPtr pVMRConfig(pFilter);
if (!pVMRConfig)
return erreur(
@@ -1374,16 +1350,9 @@
// Implémentations des méthodes de la classe CVideoMixingRenderer9
// ====================================================================================
-HRESULT CVideoMixingRenderer9::CreateAndAdd()
-{
- return
- create_and_add_filter(
- CLSID_VideoMixingRenderer9, TEXT("Video Mixing Renderer"), *this);
-}
-
HRESULT CVideoMixingRenderer9::Configure()
{
- CComQIPtr pVMRConfig(*this);
+ CComQIPtr pVMRConfig(pFilter);
if (!pVMRConfig)
return erreur(
@@ -1398,7 +1367,7 @@
HRESULT CVideoMixingRenderer9::InitControl()
{
- HRESULT hr = QueryInterface(&pVMR9Control);
+ HRESULT hr = pFilter.QueryInterface(&pVMR9Control);
if (FAILED(hr)) {
erreur(TEXT("L'interface de contrôle VMR n'est pas disponible"), hr);
return hr;
@@ -1436,7 +1405,7 @@
#endif
// Get alpha-blended bitmap interface
- hr = QueryInterface(&pBMP);
+ hr = pFilter.QueryInterface(&pBMP);
return hr;
}
@@ -1445,7 +1414,7 @@
/// \param[in] bEtirer Déformer la vidéo si nécessaire pour remplir le rectangle
HRESULT CVideoMixingRenderer9::SetAspectRatioMode(bool bEtirer)
{
- CComQIPtr pARC(*this);
+ CComQIPtr pARC(pFilter);
if (!pARC)
return erreur(
@@ -1580,16 +1549,9 @@
// Implémentations des méthodes de la classe CEnhancedVideoRenderer
// ====================================================================================
-HRESULT CEnhancedVideoRenderer::CreateAndAdd()
-{
- return
- create_and_add_filter(
- CLSID_EnhancedVideoRenderer, TEXT("Enhanced Video Renderer"), *this);
-}
-
HRESULT CEnhancedVideoRenderer::InitControl()
{
- CComQIPtr pMFGetService(*this);
+ CComQIPtr pMFGetService(pFilter);
if (!pMFGetService)
return erreur(
Modifié: trunk/rendering.h
===================================================================
--- trunk/rendering.h 2009-07-09 16:19:22 UTC (rev 195)
+++ trunk/rendering.h 2009-07-17 14:22:07 UTC (rev 196)
@@ -29,6 +29,7 @@
#pragma once
#include "base.h"
+#include "filters.h"
// ====================================================================================
// Définitions
@@ -77,14 +78,14 @@
* Ceci est la classe de base dont dérivent toutes les différentes implémentations
* de Video Mixing Renderer.
**/
-class CVideoRenderer : public CComPtr
+class CVideoRenderer : public FilterData
{
CComPtr pInputPin; //!< Interface sur la broche d'entrée
DWORD last_tick;
bool bConnected;
protected:
/// Création et ajout du VMR dans le filtre
- virtual HRESULT CreateAndAdd() = 0;
+ HRESULT CreateAndAdd();
/// Configuration du VMR
virtual HRESULT Configure() {
@@ -125,7 +126,8 @@
public:
/// Constructeur
- CVideoRenderer() :
+ CVideoRenderer(LPCTSTR pszNam, REFCLSID clsid) :
+ FilterData(pszNam, clsid),
last_tick(0),
bConnected(false)
{}
@@ -159,12 +161,6 @@
/// Effacement de tout le contenu OSD couramment affiché
virtual void ClearOsd() {}
- /// Vérification du dialogue de propriétés du VMR
- bool check_property_dialog();
-
- /// Ouverture du dialogue de propriétés du VMR
- VOID create_property_dialog();
-
/// Initialisation générale
HRESULT Init();
Modifié: trunk/settings.cpp
===================================================================
--- trunk/settings.cpp 2009-07-09 16:19:22 UTC (rev 195)
+++ trunk/settings.cpp 2009-07-17 14:22:07 UTC (rev 196)
@@ -1320,6 +1320,12 @@
return true;
}
+/// Comparaison insensible à la casse de deux chaînes \p tstring
+bool str_i_comp(tstring & elem1, tstring & elem2)
+{
+ return _tcsicmp(elem1.c_str(), elem2.c_str()) < 0;
+}
+
/**
* Transfert d'une liste de filtres placée dans une table de chaînes de caractères
* vers une liste déroulante. La liste est préalablement triée, et un item "Aucun"
@@ -1336,7 +1342,7 @@
static bool vectorstr_to_combo(vector & vStrFiltres, HWND hItm, LPCTSTR nom)
{
// Tri de la table
- std::sort(vStrFiltres.begin(), vStrFiltres.end());
+ std::sort(vStrFiltres.begin(), vStrFiltres.end(), str_i_comp);
// Ajout de l'item "Aucun" en début de liste
SendMessage(hItm, CB_ADDSTRING, 0, reinterpret_cast(TEXT("Aucun")));
@@ -3170,7 +3176,7 @@
hwndOwner, // hwndParent
hAppInstance, // hInstance
{NULL}, // pszIcon (union)
- TEXT("PouchinTV Mod"), // pszCaption
+ szAppName, // pszCaption
_countof(psp), // nPages
{0}, // nStartPage (union)
{(LPCPROPSHEETPAGE) &psp}, // ppsp (union)
@@ -3183,82 +3189,3 @@
ShowCursor(FALSE);
save_config(); // sauvegarde la configuration
}
-
-/**
- * Vérification de l'existence d'un dialogue de propriétés sur un filtre donné
- *
- * \param[in] pFilter Interface du filtre à tester
- * \return \p true si dialogue disponible, \p false si non
- **/
-bool check_property_dialog(CComPtr & pFilter)
-{
- if (!pFilter)
- return false;
-
- CComQIPtr pPages(pFilter);
-
- if (!pPages)
- return false;
- return true;
-}
-
-/**
- * Appel du dialogue de propriétés d'un filtre donné
- *
- * \param[in] pFilter Interface du filtre à dont le dialogue doit être ouvert
- * \param[in] nom Nom du filtre
- **/
-VOID create_property_dialog(CComPtr & pFilter, LPCTSTR nom)
-{
- if (!pFilter) {
- affiche_erreurs(TEXT("Il faut d'abord configurer un filtre et redémarrer l'application"));
- return;
- }
-
- CComQIPtr pPages(pFilter);
-
- if (!pPages) {
- // (avertissement maintenant en principe inutile car dans ce cas, le menu est désactivé)
- affiche_erreurs(TEXT("Ce filtre n'a pas de page de propriétés"), E_NOINTERFACE);
- return;
- }
-
- CComPtr pUnk(pPages);
-
- if (pUnk) {
- CAUUID caGUID;
-
- HRESULT hr = pPages->GetPages(&caGUID);
-
-#ifdef _UNICODE
- LPOLESTR pszTmp = LPOLESTR(nom);
-#else
- COPY_STR_ON_STACK(OLECHAR, pszTmp, nom, nLen);
-#endif
- if (SUCCEEDED(hr)) {
- LCID lcid = GetUserDefaultLCID();
-
- ShowCursor(TRUE);
-
- hr = OleCreatePropertyFrame(
- hMainWnd,
- 10,
- 10,
- pszTmp,
- 1,
- &pUnk.p,
- caGUID.cElems,
- caGUID.pElems,
- lcid,
- 0L,
- NULL );
-
- ShowCursor(FALSE);
- CoTaskMemFree(caGUID.pElems);
-
- if (FAILED(hr)) {
- affiche_erreurs(TEXT("Erreur lors de la création de la page de propriétés"), hr);
- }
- }
- }
-}
Modifié: trunk/settings.h
===================================================================
--- trunk/settings.h 2009-07-09 16:19:22 UTC (rev 195)
+++ trunk/settings.h 2009-07-17 14:22:07 UTC (rev 196)
@@ -56,19 +56,3 @@
* \param[in] hwndOwner handle de la fenêtre parente
**/
VOID do_config(HWND hwndOwner);
-
-/**
- * Vérification de l'existence d'un dialogue de propriétés sur un filtre donné
- *
- * \param[in] pFilter Interface du filtre à tester
- * \return \p true si dialogue disponible, \p false si non
- **/
-bool check_property_dialog(CComPtr & pFilter);
-
-/**
- * Appel du dialogue de propriétés d'un filtre donné
- *
- * \param[in] pFilter Interface du filtre à dont le dialogue doit être ouvert
- * \param[in] nom Nom du filtre
- **/
-VOID create_property_dialog(CComPtr & pFilter, LPCTSTR nom);
From pouchintv-dev at baysse.fr Thu Jul 23 22:40:45 2009
From: pouchintv-dev at baysse.fr (=?iso-8859-1?q?Liste_utilis=E9e_par_les_d=E9veloppeurs?=)
Date: Thu, 23 Jul 2009 20:40:45 -0000
Subject: [Pouchintv-dev] [PouchinTVMod] gingko | r197 - trunk
Message-ID: <20090723204030.A37D386AEC@mail.baysse.fr>
Author: gingko
Date: 2009-07-23 22:40:30 +0200 (jeu 23 jui 2009)
New Revision: 197
Modified:
trunk/changelog.html
trunk/channels.cpp
trunk/channels.h
trunk/console.cpp
trunk/filters.cpp
trunk/filters.h
trunk/graph.cpp
trunk/graph.h
trunk/main.cpp
trunk/parse.cpp
trunk/rendering.cpp
trunk/rendering.h
trunk/search.cpp
trunk/search.h
Log:
Poursuite de la réorganisation du graphe, et corrections mineures.
channels.h, channels.cpp, filters.h, filters.cpp, parse.cpp, rendering.cpp,
search.h, search.cpp, main.cpp, graph.h, graph.cpp :
* Regroupement de plusieurs fonctions liées au graphe, mais qui étaient
auparavant dispersées ailleurs dans l'application, en vue de faciliter leur
intégration dans le graphe orienté objet à venir.
* Réorganisation des fonctions de construction du graphe, avec réduction du
nombre d'objets exposés globalement, en vue de faciliter l'intégration à un
futur graphe orienté objet.
Ce changement constitue la deuxième étape dans un projet général de
migration du graphe entier vers une représentation orientée objet,
susceptible de contenir plusieurs graphes différents, ou bien plusieurs
instances d'un même graphe.
console.cpp :
* Ajout d'un transcodage ANSI -> OEM en compilation SBCS.
parse.cpp :
* Les erreurs qui se produisent pendant le changement de fréquence sont
rapportées de façon plus détaillées.
filters.cpp :
* Correction d'un oubli dans FilterData::create_property_dialog en mode SBCS.
Modifié: trunk/changelog.html
===================================================================
--- trunk/changelog.html 2009-07-17 14:22:07 UTC (rev 196)
+++ trunk/changelog.html 2009-07-23 20:40:30 UTC (rev 197)
@@ -56,6 +56,13 @@
Changements réalisés pour la version 0.5
+ - SVN rév. 197 :
+
+ - Seconde étape d'une importante réorganisation du code dans le graphe.
+ - Quelques corrections mineures.
+
+
+
- SVN rév. 196 :
- Plus de déconnexion des filtres pendant la resyntonisation, afin d'éviter des plantages.
Modifié: trunk/channels.cpp
===================================================================
--- trunk/channels.cpp 2009-07-17 14:22:07 UTC (rev 196)
+++ trunk/channels.cpp 2009-07-23 20:40:30 UTC (rev 197)
@@ -26,7 +26,6 @@
* See http://pouchinteve.free.fr/ for the original project.
*/
-#include
#include "base.h"
#include "channels.h"
#include "main.h"
@@ -35,15 +34,15 @@
#include "crc32.h"
/// Tableau des chaînes
-Chaines Canaux;
+Chaines Canaux;
-int ixChaineCourante = -1; //!< Index de la chaîne couramment utilisée
-int ixChaineAvance = -1; /*!< Index de la chaîne pendant les transitions de zapping
- (normalement identique à \p ixChaineCourante, sauf entre la
- sélection d'une chaîne et l'application de cette sélection) */
-int ixSonCourant = 0; //!< Index de la piste sonore couramment utilisée
-bool suspendu = true; //!< \p true si vidéo et audio suspendus (à l'initialisation,
- //!< ou si minimisé + \p suspend_minimized)
+int ixChaineCourante = -1; //!< Index de la chaîne couramment utilisée
+int ixChaineAvance = -1; /*!< Index de la chaîne pendant les transitions de zapping
+ (normalement identique à \p ixChaineCourante, sauf entre la
+ sélection d'une chaîne et l'application de cette sélection) */
+int ixSonCourant = 0; //!< Index de la piste sonore couramment utilisée
+static bool suspendu = true; //!< \p true si vidéo et audio suspendus (à l'initialisation,
+ //!< ou si minimisé + \p suspend_minimized)
// Taille des images des chaînes (largeur et longueur)
#define TAILLE_IMAGE_CHAINE 16
@@ -138,35 +137,6 @@
groupe[0] = 0;
}
-static void branche_son(une_piste son)
-{
- ULONG pid = son.pid;
- HRESULT hr;
-
- if (pid!=0) {
- switch (son.type) {
-
- case tst_MPEG2:
- hr = sMp2aCodec.branche_pid(pid);
- break;
-
- case tst_AC3:
- case tst_EAC3:
- hr = sAc3_Codec.branche_pid(pid);
- break;
-
- default:
- myprintf(TEXT("Type de piste audio non identifié\n"));
- }
- }
-}
-
-static void debranche_son()
-{
- sMp2aCodec.debranche_pids();
- sAc3_Codec.debranche_pids();
-}
-
HBITMAP Chaine::ChargeIcone()
{
if (hImage==INVALID_HANDLE_VALUE)
@@ -331,37 +301,8 @@
**/
HRESULT Chaine::branche(bool reset_son) const
{
- ULONG pid = video_pid;
-
myprintf(TEXT("Chaine::branche SID=%i, TSID=%i, ONID=%i, freq=%i\n"), SID, TSID, ONID, khz);
- HRESULT hr = E_FAIL; // valeur par défaut
-
- if (pid) {
- switch (video_type) {
- case vst_MPEG2:
- if (pVMR && ePrevVideoType!=vst_MPEG2) {
- if (FAILED(hr = switch_codec(sMp2vCodec.pFilter, TEXT("MPEG2"))))
- return hr;
- ePrevVideoType = vst_MPEG2;
- }
- hr = sMp2vCodec.branche_pid(pid);
- break;
-
- case vst_H264:
- if (pVMR && ePrevVideoType!=vst_H264) {
- if (FAILED(hr = switch_codec(sH264Codec.pFilter, TEXT("H264"))))
- return hr;
- ePrevVideoType = vst_H264;
- }
- hr = sH264Codec.branche_pid(pid);
- break;
-
- default:
- hr=E_FAIL;
- }
- }
-
if (reset_son) {
ixSonCourant = 0; // par défaut
@@ -375,13 +316,9 @@
}
}
- branche_son(sons.tbl[ixSonCourant]);
+ const une_piste son = sons.tbl[ixSonCourant];
-#if USE_PMTFILTER
- // pmt
- hr = sPMT_Filter.branche_pid(pmt_pid);
-#endif
- return hr;
+ return branche_medias(pmt_pid, video_pid, video_type, son.pid, son.type);
}
/**
@@ -511,47 +448,6 @@
}
/**
- * Syntonisation d'une fréquence dans le tuner.
- * \param[in] freq Fréquence à syntoniser, exprimée en kilohertz
- **/
-HRESULT change_frequence(ULONG freq)
-{
-
- HRESULT hr = E_FAIL;
-
- if (pBDAControl && pBDAFreq) {
- hr = pBDAControl->StartChanges();
- myprintf(TEXT("%?change_frequence pBDAControl->StartChanges(), hr=0x%08x\n"), FAILED(hr), hr);
-
- if (SUCCEEDED(hr)) {
- HRESULT hr2 = pBDAFreq->put_Bandwidth(8);
- myprintf(TEXT("%?change_frequence pBDAFreq->put_Bandwidth(8), hr=0x%08x\n"), FAILED(hr), hr);
- if (FAILED(hr2))
- hr = hr2;
-
- freq += offset_tuner; // Correction de fréquence
-
- hr2 = pBDAFreq->put_Frequency(freq);
- myprintf(TEXT("%?change_frequence pBDAFreq->put_Frequency(%ul), hr=0x%08x\n"), FAILED(hr),
- freq, hr);
- if (SUCCEEDED(hr) && FAILED(hr2))
- hr = hr2;
-
- hr2 = pBDAControl->CheckChanges();
- myprintf(TEXT("%?change_frequence pBDAControl->CheckChanges(), hr=0x%08xn"), FAILED(hr), hr);
- if (SUCCEEDED(hr) && FAILED(hr2))
- hr = hr2;
-
- hr2 = pBDAControl->CommitChanges();
- myprintf(TEXT("%?change_frequence pBDAControl->CommitChanges(), hr=0x%08x\n"), FAILED(hr), hr);
- if (SUCCEEDED(hr) && FAILED(hr2))
- hr = hr2;
- }
- }
- return hr;
-}
-
-/**
* S'assurer que le Video Mixing Renderer a été initialisé
**/
bool do_init_vmr()
@@ -571,15 +467,8 @@
**/
void debranche()
{
- if (!suspendu) {
- sMp2vCodec.debranche_pids();
- sH264Codec.debranche_pids();
- debranche_son();
-#if USE_PMTFILTER
- sPMT_Filter.debranche_pids();
-#endif
- suspendu = true;
- }
+ debranche_medias();
+ suspendu = true;
}
/**
@@ -602,11 +491,11 @@
if (do_init_vmr()) {
if (suspendu) {
- suspendu = false;
HRESULT hr = Canaux[ixChaineCourante].branche(reset_son);
if (FAILED(hr))
affiche_erreurs(TEXT("Erreur lors du rebranchement des sorties"), hr);
+ suspendu = false;
}
bRes = true;
}
@@ -627,8 +516,10 @@
const Chaine & canal = Canaux[ixChaineCourante];
if (ixSon>=0 && ixSon= 0) {
const Chaine & nouveau_canal = Canaux[ixChaine];
@@ -680,39 +569,25 @@
ixChaine, nouveau_canal.nNumeroChaine, nouveau_canal.SID, nouveau_canal.TSID,
nouveau_canal.ONID, nouveau_canal.khz, nouveau_canal.nom);
- if (freq_differente)
- change_frequence(nouveau_canal.khz);
+ if (freq_differente) {
+#if USE_CONSOLE
+ tstring strErr;
+#endif
+ change_frequence(nouveau_canal.khz IF_CONSOLE_CB(&strErr));
+ myprintf(TEXT("%?Erreur(s) change_frequence : %s\n"), !strErr.empty(), strErr.c_str());
+ }
ixChaineCourante = ixChaine_ok(ixChaine) ? ixChaine : -1;
ixChaineAvance = ixChaineCourante;
- // Ne reconnecter l'interface que si elle l'était avant :
- if (!sauve_suspend && chaine_differente)
- rebranche(true);
- } else {
- // ixChaine < 0 pour désélection de chaîne
+ // Ne reconnecter l'interface que si elle n'était pas suspendue :
+ if (!suspendu && chaine_differente) {
+ HRESULT hr = Canaux[ixChaineCourante].branche(true);
- // Restaurer 'suspendu' après désélection de chaîne sinon l'affichage
- // ne redémarre pas à l'issue d'une recherche de chaînes :
- suspendu = sauve_suspend;
+ if (FAILED(hr))
+ affiche_erreurs(TEXT("Erreur lors du rebranchement des sorties"), hr);
+ }
}
return S_OK;
}
-
-/**
- * Changement de volume sonore
- * \param[in] volume Nouveau volume sonore, valeur de 0 à 100
- **/
-void set_volume(long volume)
-{
- CComQIPtr pBas(pGraph);
-
- if (pBas) {
- int nDbVolume = -8000;
-
- if (volume > 0)
- nDbVolume = (int)((log10(1.0*volume)-2)*5000);
- pBas->put_Volume(nDbVolume);
- }
-}
Modifié: trunk/channels.h
===================================================================
--- trunk/channels.h 2009-07-17 14:22:07 UTC (rev 196)
+++ trunk/channels.h 2009-07-23 20:40:30 UTC (rev 197)
@@ -284,13 +284,6 @@
sélection d'une chaîne et l'application de cette sélection) */
extern int ixSonCourant; //!< Index de la piste sonore couramment utilisée
-extern bool suspendu; //!< \p true si vidéo et audio suspendus (à l'initialisation,
- //!< ou si minimisé + \p suspend_minimized)
-/**
- * Syntonisation d'une fréquence dans le tuner.
- * \param[in] freq Fréquence à syntoniser, exprimée en kilohertz
- **/
-HRESULT change_frequence(ULONG freq);
/**
* S'assurer que le Video Mixing Renderer a été initialisé
@@ -315,12 +308,6 @@
void switch_audio(int ixSon);
/**
- * Changement de volume sonore
- * \param[in] volume Nouveau volume sonore, valeur de 0 à 100
- **/
-void set_volume(long volume);
-
-/**
* Déconnexion globale des sorties vidéo et audio
**/
void debranche();
Modifié: trunk/console.cpp
===================================================================
--- trunk/console.cpp 2009-07-17 14:22:07 UTC (rev 196)
+++ trunk/console.cpp 2009-07-23 20:40:30 UTC (rev 197)
@@ -85,10 +85,6 @@
// leur propre système de capture, alors il est moins utile d'avoir
// une copie dans "pouchin.log".
#else // #if USE_CONSOLE==-1
- DWORD cCharsWritten;
-
- WriteConsole(hStdOut, s, cnt, &cCharsWritten, NULL);
-
static TCHAR szLogFileName[MAX_PATH] = {0};
if (!*szLogFileName) {
@@ -105,6 +101,13 @@
_fputts(s, f);
fclose(f);
}
+
+ DWORD cCharsWritten;
+
+#ifndef _UNICODE
+ CharToOem(s, s);
+#endif
+ WriteConsole(hStdOut, s, cnt, &cCharsWritten, NULL);
#endif // #if USE_CONSOLE==-1
}
#endif // #if USE_CONSOLE
Modifié: trunk/filters.cpp
===================================================================
--- trunk/filters.cpp 2009-07-17 14:22:07 UTC (rev 196)
+++ trunk/filters.cpp 2009-07-23 20:40:30 UTC (rev 197)
@@ -69,14 +69,13 @@
CComPtr pUnk(pPages);
if (pUnk) {
- CAUUID caGUID;
-
+ CAUUID caGUID;
HRESULT hr = pPages->GetPages(&caGUID);
#ifdef _UNICODE
- LPOLESTR pszTmp = LPOLESTR(pszName);
+ LPOLESTR pszTmp = LPOLESTR(pszName);
#else
- COPY_STR_ON_STACK(OLECHAR, pszTmp, nom, nLen);
+ COPY_STR_ON_STACK(OLECHAR, pszTmp, pszName, nLen);
#endif
if (SUCCEEDED(hr)) {
LCID lcid = GetUserDefaultLCID();
@@ -174,3 +173,86 @@
return hr;
}
+
+// ====================================================================================
+// Recherche de broche dans un filtre
+// ====================================================================================
+
+/**
+ * Vérification de la compatibilité d'une broche avec un type de média donné.
+ * \param[in] pPin Interface de la broche à tester
+ * \param[in] am Descripteur de type de média
+ * \retval \p true en cas de succès
+ **/
+bool check_pin_for_media(CComPtr & pPin, const AM_MEDIA_TYPE & am)
+{
+ CComPtr pEnumMedia;
+ AM_MEDIA_TYPE * pmt;
+ bool found = false;
+
+ for (
+ pPin->EnumMediaTypes(&pEnumMedia);
+ !found && (pEnumMedia->Next(1, &pmt, NULL))==S_OK;
+ DeleteMediaType(pmt)
+ ) {
+ if (am.majortype == pmt->majortype && am.subtype == pmt->subtype)
+ found = true;
+ }
+ //if (pPin->QueryAccept(&am)==S_OK) {
+ // return true;
+ //}
+ return found;
+}
+
+/**
+ * Recherche de la première broche d'un filtre, pour une direction donnée.
+ * \param[in] pFilter Interface du filtre dans lequel la recherche s'effectue
+ * \param[in] dir Direction de la broche recherchée (entrée ou sortie)
+ * \param[out] result Interface de la broche trouvée
+ * \param[in] pmt Si != \p NULL, alors la broche doit être non connectée, et si la valeur
+ * est différente de NOTCONNECTED, elle doit en plus accepter le média spécifié/
+ * \retval \p S_OK en cas de succès
+ **/
+HRESULT cherche_pin(CComPtr & pFilter, PIN_DIRECTION dir,
+ CComPtr & result, const AM_MEDIA_TYPE * pmt)
+{
+ // myprintf(TEXT("** cherche_pin\n"));
+ CComPtr pEnumPins;
+ HRESULT hr = pFilter->EnumPins(&pEnumPins);
+
+ if (FAILED(hr)) {
+ myprintf(TEXT("cherche_pin, 1, hr=0x%08x\n"), hr);
+ return hr;
+ }
+
+ for (
+ CComPtr pPin;
+ (hr = pEnumPins->Next(1, &pPin, NULL))==S_OK;
+ pPin.Release()
+ ) {
+ PIN_DIRECTION direction;
+
+ pPin->QueryDirection(&direction);
+
+ if (direction == dir) {
+ if (pmt) {
+ // write_pin_info(pPin);
+ CComPtr connected;
+
+ pPin->ConnectedTo(&connected);
+
+ if (!connected) {
+ if (pmt==NOTCONNECTED || check_pin_for_media(pPin, *pmt)) {
+ result = pPin;
+ break;
+ }
+ }
+ } else {
+ result = pPin;
+ break;
+ }
+ }
+ }
+
+ return !result ? E_FAIL : hr;
+}
Modifié: trunk/filters.h
===================================================================
--- trunk/filters.h 2009-07-17 14:22:07 UTC (rev 196)
+++ trunk/filters.h 2009-07-23 20:40:30 UTC (rev 197)
@@ -158,6 +158,7 @@
__super::Release(); }
};
+/// Données d'accès au "grabber"
struct GrabberData
{
CComPtr pInterface;
@@ -176,3 +177,30 @@
}
};
+// ====================================================================================
+// Recherche de broche dans un filtre
+// ====================================================================================
+
+/// Paramètre possible de FilterData::cherche_pin
+#define NOTCONNECTED ((AM_MEDIA_TYPE *)-1)
+
+/**
+ * Vérification de la compatibilité d'une broche avec un type de média donné.
+ * \param[in] pPin Interface de la broche à tester
+ * \param[in] am Descripteur de type de média
+ * \retval \p true en cas de succès
+ **/
+bool check_pin_for_media(CComPtr & pPin, const AM_MEDIA_TYPE & am);
+
+/**
+ * Recherche de la première broche d'un filtre, pour une direction donnée.
+ * \param[in] pFilter Interface du filtre dans lequel la recherche s'effectue
+ * \param[in] dir Direction de la broche recherchée (entrée ou sortie)
+ * \param[out] result Interface de la broche trouvée
+ * \param[in] pmt Si != \p NULL, alors la broche doit être non connectée, et si la valeur
+ * est différente de NOTCONNECTED, elle doit en plus accepter le média spécifié/
+ * \retval \p S_OK en cas de succès
+ **/
+HRESULT cherche_pin(CComPtr & pFilter, PIN_DIRECTION dir,
+ CComPtr & result, const AM_MEDIA_TYPE * pmt=NULL);
+
Modifié: trunk/graph.cpp
===================================================================
--- trunk/graph.cpp 2009-07-17 14:22:07 UTC (rev 196)
+++ trunk/graph.cpp 2009-07-23 20:40:30 UTC (rev 197)
@@ -41,6 +41,7 @@
#include "mpeg2defs.h"
#include
+#include // Pour log10() dans calcul du volume sonore
#if USE_SINGLE_GRABBER
#include "grabber.h"
@@ -238,13 +239,12 @@
// ====================================================================================
#if LOG_DSHOW
-HANDLE logFile = INVALID_HANDLE_VALUE;
+HANDLE logFile = INVALID_HANDLE_VALUE;
#endif // #if LOG_DSHOW
CComPtr pGraph;
CComPtr pEvents;
-FilterData sNetworkProvider(TEXT("Microsoft DVB-T Network Provider"), CLSID_DVBTNetworkProvider);
FilterData sDemux(TEXT("MPEG2 Demultiplexer"), CLSID_MPEG2Demultiplexer);
DecoderData sMp2vCodec(&sMp2v_am, "vidéo MPEG2", filtreMPEG2, L"mp2v");
@@ -258,11 +258,8 @@
#if USE_PMTFILTER
DecoderData sPMT_Filter(&sPmt__am, "PMT", TEXT(PMT_FILTER_NAME), L"pmt", MEDIA_MPEG2_PSI, CPMTFilter::CreateInstance);
#endif
-CComPtr pMpeg2Data;
+DecoderData sPSI_Filter(&sPsi__am, "PSI", TEXT("MPEG-2 Sections and Tables"), L"data", MEDIA_MPEG2_PSI, _uuidof(Mpeg2Data));
-CComPtr pNetworkTuner;
-CComPtr pReceiverComponent;
-
#if USE_SINGLE_GRABBER
GrabberData sGrabber;
#endif
@@ -272,8 +269,10 @@
static CComPtr pStats;
-VideoStreamType ePrevVideoType = vst_Unknown; //!< Type de flux vidéo couramment utilisé (pour pouvoir
- //!< détecter quand changer de codec)
+bool bSuspended; //!< \p true si vidéo et audio suspendus (à l'initialisation,
+ //!< ou si minimisé + \p suspend_minimized)
+VideoStreamType ePrevVideoType = vst_Unknown; //!< Type de flux vidéo couramment utilisé (pour pouvoir
+ //!< détecter quand changer de codec)
// ====================================================================================
// Exportation du graphe
@@ -352,17 +351,16 @@
void clean_dshow(void)
{
- myprintf(TEXT("save ok\n"));
+ myprintf(TEXT("Arrêt des enregistrements\n"));
- // Traite tous les enregistrements en cours
- // Supprime la fonction de Rappel
+ // Arrêt de tous les enregistrements en cours
enregistrements_actuels.stop_all();
- myprintf(TEXT("callback ok\n"));
+ myprintf(TEXT("Arrêt du graphe\n"));
graph_Stop();
- myprintf(TEXT("stop ok\n"));
+ myprintf(TEXT("Destruction du graphe\n"));
#if LOG_DSHOW
if (pGraph && logFile != INVALID_HANDLE_VALUE) {
@@ -377,7 +375,6 @@
if (pEvents)
pEvents->SetNotifyWindow(NULL, 0, 0);
- pMpeg2Data.Release();
pEvents.Release();
@@ -389,6 +386,7 @@
#if USE_PMTFILTER
sPMT_Filter.Release();
#endif
+ sPSI_Filter.Release();
sDemux.Release();
clean_vmr();
@@ -399,10 +397,6 @@
#if USE_SINGLE_GRABBER
sGrabber.Release();
#endif
- pNetworkTuner.Release();
- pReceiverComponent.Release();
-
- sNetworkProvider.Release();
pStats.Release();
pBDAFreq.Release();
pBDAControl.Release();
@@ -473,6 +467,7 @@
* d'entrée d'un autre.
* \param[in] source Filtre présentant la broche de sortie à connecter
* \param[in] dest Filtre présentant la broche d'entrée à connecter
+ * \return Code d'erreur DirectShow
**/
HRESULT connect_filters(CComPtr & source, CComPtr & dest)
{
@@ -484,6 +479,79 @@
return hr;
}
+/**
+ * Déconnexion de la broche d'entrée d'un filtre de la broche de sortie du filtre qui le précède.
+ * \param[in] pFilter Filtre présentant la broche d'entrée à déconnecter
+ * \return Code d'erreur DirectShow
+ **/
+HRESULT disconnect_filter(CComPtr & pFilter)
+{
+ CComPtr pInPin;
+ CComPtr pOutPin;
+ HRESULT hr;
+
+ if (FAILED(hr = cherche_pin(pFilter, PINDIR_INPUT, pInPin)))
+ return hr;
+ if (FAILED(hr = pInPin->ConnectedTo(&pOutPin)))
+ return hr;
+ if (FAILED(hr = pGraph->Disconnect(pOutPin)))
+ return hr;
+ return pGraph->Disconnect(pInPin);
+}
+
+#ifdef _DEBUG
+tstring get_graph_state()
+{
+ OAFilterState state = graph_GetState();
+ CComPtr pEnumfilters;
+ tstring strState;
+
+ pGraph->EnumFilters(&pEnumfilters);
+
+ for (ENUM_ITF(pEnumfilters, IBaseFilter, pFilter)) {
+ HRESULT hr;
+ FILTER_INFO sInfo;
+ CComHeapPtr pszVendorInfo;
+ FILTER_STATE eState;
+ // CComPtr
+ // pRefClock;
+ CLSID clsidFlt;
+ tstring strFlt;
+
+ hr = pFilter->QueryFilterInfo(&sInfo);
+ hr = pFilter->QueryVendorInfo(&pszVendorInfo);
+ hr = pFilter->GetState(2000, &eState);
+ // hr = pFilter->GetSyncSource(&pRefClock);
+ hr = pFilter->GetClassID(&clsidFlt);
+
+ strFlt = tstr_printf(TEXT("\n- %") W2t, sInfo.achName);
+ if (pszVendorInfo)
+ strFlt += tstr_printf(TEXT(" [%") W2t TEXT("]"), pszVendorInfo.m_pData);
+ strFlt += tstr_printf(TEXT(", clsid=") GUIDFMT, GUIDPARM(clsidFlt));
+ /*
+ if (pRefClock) {
+ REFERENCE_TIME nTime;
+
+ hr = pRefClock->GetTime(&nTime);
+ strState += tstr_printf(TEXT(", %I64u"), nTime);
+ } */
+ strFlt += tstr_printf(TEXT(", état=%") A2t,
+ EnumToString(eState, "Arrêt\0Pause\0Marche\0", "État inconnu"));
+ strState.insert(0, strFlt); // Insertion au début (pour inverser l'ordre)
+ }
+
+ strState.insert(0,
+ tstr_printf(
+ TEXT("%") A2t TEXT("\n\n** Liste des filtres utilisés :"),
+ EnumToString(state,
+ "Le graphe est à l'arrêt\0"
+ "Le graphe est en pause\0"
+ "Le graphe est en marche\0",
+ "État du graphe inconnu")));
+ return strState;
+}
+#endif
+
// ====================================================================================
// Topologie du filtre tuner
// ====================================================================================
@@ -493,7 +561,7 @@
* \param[in] pTuner Tuner dans lequel rechercher l'interface
* \param[in] iid IID de l'interface recherchée
* \param[out] pUnk Noeud de contrôle de l'interface trouvée
- * \return Code de succès ou d'erreur
+ * \return Code d'erreur DirectShow
**/
static HRESULT Search_IBDA_Topology(const CComPtr & pTuner, REFIID iid, CComPtr & pUnk)
{
@@ -532,7 +600,7 @@
* Recherche d'une interface spécifique du filtre tuner, via son interface générique \p IBDA_Topology.
* \param[in] pTuner Tuner dans lequel rechercher l'interface
* \param[in] pItf Pointeur du l'interface trouvée (le type du pointeur détermine le type d'interface)
- * \return Code de succès ou d'erreur
+ * \return Code d'erreur DirectShow
**/
template
static HRESULT Search_IBDA_Topology(const CComPtr & pTuner, CComPtr & pItf)
@@ -553,13 +621,13 @@
/**
* Créer ou obtenir une broche de sortie sur ou depuis le démultiplexeur.
*
- * \param[in] pMpeg2Demux Interface du démultiplexeur
+ * \param[in] iMp2Demux Interface du démultiplexeur
* \param[in] sDData Information concernant le média dont la broche doit être obtenue
* \param[in] bFindExisting si \p true, rechercher si une broche déjà existante
* peut satisfaire à la demande
* \param[out] pOutPin Interface sur la broche trouvée ou créé
**/
-static HRESULT get_output_pin(IMpeg2Demultiplexer * pMpeg2Demux,
+static HRESULT get_output_pin(IMpeg2Demultiplexer & iMp2Demux,
DecoderData & sDData,
bool bFindExisting,
CComPtr & pOutPin)
@@ -576,15 +644,15 @@
// Note : utilisation de "const_cast" ici car on ne s'attend pas normalement à ce que
// "CreateOutputPin" modifie les objets pointés.
- hr = pMpeg2Demux->CreateOutputPin(const_cast(sDData.pAmt),
- const_cast(sDData.pszPinName), &pOutPin);
+ hr = iMp2Demux.CreateOutputPin(const_cast(sDData.pAmt),
+ const_cast(sDData.pszPinName), &pOutPin);
myprintf(TEXT("%?Broche \"%") W2t TEXT("\" créée pour %") A2t TEXT("\n"), SUCCEEDED(hr), sDData.pszPinName, sDData.pszType);
if (FAILED(hr))
return erreur(TEXT("La broche %") A2t TEXT(" n'a pas pu être créée"), hr, sDData.pszType);
return hr;
}
-static HRESULT render_video(IMpeg2Demultiplexer * pMpeg2Demux, DecoderData & sDData)
+static HRESULT render_video(IMpeg2Demultiplexer & iMp2Demux, DecoderData & sDData)
{
if (sDData.pszName[0] == 0) {
affiche_erreurs(tstr_printf(TEXT("Aucun codec %") A2t TEXT(" n'a été sélectionné"), sDData.pszType).c_str());
@@ -595,7 +663,7 @@
return S_OK;
CComPtr pOutPin;
- HRESULT hr = get_output_pin(pMpeg2Demux, sDData, false, pOutPin);
+ HRESULT hr = get_output_pin(iMp2Demux, sDData, false, pOutPin);
if (FAILED(hr))
return hr;
@@ -622,14 +690,14 @@
return hr;
}
-static HRESULT render_audio(IMpeg2Demultiplexer * pMpeg2Demux,
+static HRESULT render_audio(IMpeg2Demultiplexer & iMp2Demux,
DecoderData & sDData, FilterData & sSoundFilter)
{
if (IsNullName(sDData.pszName))
return S_OK;
CComPtr pOutPin;
- HRESULT hr = get_output_pin(pMpeg2Demux, sDData, false, pOutPin);
+ HRESULT hr = get_output_pin(iMp2Demux, sDData, false, pOutPin);
if (FAILED(hr))
return hr;
@@ -666,10 +734,10 @@
return hr;
}
-static HRESULT render_data(IMpeg2Demultiplexer * pMpeg2Demux, DecoderData & sDData, bool bFindExisting)
+static HRESULT render_data(IMpeg2Demultiplexer & iMp2Demux, DecoderData & sDData, bool bFindExisting)
{
CComPtr pOutPin;
- HRESULT hr = get_output_pin(pMpeg2Demux, sDData, bFindExisting, pOutPin);
+ HRESULT hr = get_output_pin(iMp2Demux, sDData, bFindExisting, pOutPin);
if (FAILED(hr))
return hr;
@@ -685,70 +753,57 @@
return hr;
}
-static HRESULT cree_and_render_pins()
+static HRESULT AddDataFilters(IMpeg2Demultiplexer & iMp2Demux)
{
- // crée les ports
-
- CComQIPtr pMpeg2Demux(sDemux.pFilter);
-
- if (!pMpeg2Demux)
- return erreur(TEXT("L'interface du démultiplexeur n'a pas été trouvée"), E_NOINTERFACE);
-
HRESULT hr;
// ####### TIF :
if (!autre_graphe) {
DecoderData sTIF_Filter(&sTif__am, "TIF", TEXT("BDA MPEG2 Transport Information Filter"), L"tif", MEDIA_MPEG2_PSI, CLSID_BDA_MPEG2_TIF);
- if (FAILED(hr = render_data(pMpeg2Demux, sTIF_Filter, true)))
+ if (FAILED(hr = render_data(iMp2Demux, sTIF_Filter, true)))
return hr;
}
- // ####### Vidéo MPEG2 :
- if (FAILED(hr = render_video(pMpeg2Demux, sMp2vCodec)))
- return hr;
-
- // ####### Vidéo H264 :
- if (FAILED(hr = render_video(pMpeg2Demux, sH264Codec)))
- return hr;
-
- // ####### Audio MPEG2 :
- if (FAILED(hr = render_audio(pMpeg2Demux, sMp2aCodec, sDSound)))
- return hr;
-
- // ####### Audio AC3 :
- if (FAILED(hr = render_audio(pMpeg2Demux, sAc3_Codec, sDSoundAc3)))
- return hr;
-
-
// ####### PSI :
- DecoderData sPSI_Filter(&sPsi__am, "PSI", TEXT("MPEG-2 Sections and Tables"), L"data", MEDIA_MPEG2_PSI, __uuidof(Mpeg2Data));
-
- if (SUCCEEDED(hr = render_data(pMpeg2Demux, sPSI_Filter, true))) {
- // query MPEG-2 Sections and Tables Filter
- if (FAILED(hr = sPSI_Filter.pFilter.QueryInterface(&pMpeg2Data)))
- return erreur(TEXT("L'interface d'accès aux tables %") A2t TEXT(" n'a pas été trouvée"), hr, sPSI_Filter.pszType);
- }
+ hr = render_data(iMp2Demux, sPSI_Filter, true);
if (FAILED(hr))
return hr;
// ####### EPG :
DecoderData sEPG_Filter(&sEpg__am, "EPG", TEXT(EPG_FILTER_NAME), L"epg", MEDIA_MPEG2_PSI, CEPGFilter::CreateInstance);
- if (SUCCEEDED(hr = render_data(pMpeg2Demux, sEPG_Filter, false)))
+ if (SUCCEEDED(hr = render_data(iMp2Demux, sEPG_Filter, false)))
hr = sEPG_Filter.branche_pid(p_pid_EIT);
- if (FAILED(hr))
- return hr;
#if USE_PMTFILTER
// ####### PMT :
- if (FAILED(hr = render_data(pMpeg2Demux, sPMT_Filter, false)))
- return hr;
+ if (SUCCEEDED(hr))
+ hr = render_data(iMp2Demux, sPMT_Filter, false);
#endif
-
return hr;
}
+static HRESULT AddDecoders(IMpeg2Demultiplexer & iMp2Demux)
+{
+ HRESULT hr;
+
+ // ####### Vidéo MPEG2 :
+ if (FAILED(hr = render_video(iMp2Demux, sMp2vCodec)))
+ return hr;
+
+ // ####### Vidéo H264 :
+ if (FAILED(hr = render_video(iMp2Demux, sH264Codec)))
+ return hr;
+
+ // ####### Audio MPEG2 :
+ if (FAILED(hr = render_audio(iMp2Demux, sMp2aCodec, sDSound)))
+ return hr;
+
+ // ####### Audio AC3 :
+ return render_audio(iMp2Demux, sAc3_Codec, sDSoundAc3);
+}
+
// ====================================================================================
// Mise en route, arrêt, état du graphe
// ====================================================================================
@@ -993,12 +1048,196 @@
// Construction du graphe
// ====================================================================================
+static HRESULT AddEventNotifier(HWND hWnd, UINT uMsg)
+{
+ HRESULT hr = pGraph.QueryInterface(&pEvents);
+
+ if (SUCCEEDED(hr))
+ pEvents->SetNotifyWindow((OAHWND)hWnd, uMsg, 0);
+ return hr;
+}
+
+static HRESULT AddTunerAndReceiver(CComPtr & pLastAddedFilter)
+{
+ CComPtr pNetworkTuner;
+ HRESULT hr = E_FAIL;
+
+ CSearchByCategory_Get(KSCATEGORY_BDA_NETWORK_TUNER, nom_tuner, pNetworkTuner).Do();
+
+ CompatResult eCompat = filtre_compat(pNetworkTuner);
+ if (eCompat == compat_Tuner) {
+ // PCI
+ CComPtr pReceiverComponent;
+
+ hr = AddFilterToGraph(pNetworkTuner, nom_tuner);
+ if (FAILED(hr))
+ return erreur(TEXT("Échec de l'insertion du filtre Tuner"), hr);
+
+ CSearchByCategory_Get(KSCATEGORY_BDA_RECEIVER_COMPONENT, nom_receiver, pReceiverComponent).Do();
+
+ hr = AddFilterToGraph(pReceiverComponent, nom_receiver);
+ if (FAILED(hr))
+ return erreur(TEXT("Échec de l'insertion du filtre Récepteur"), hr);
+
+ // connect Tuner
+ hr = connect_filters(pLastAddedFilter, pNetworkTuner);
+ if (FAILED(hr))
+ return erreur(TEXT("Tuner TNT non compatible, veuillez effacer \"config.ini\" et redémarrer"), hr);
+
+ // connect Receiver
+ hr = connect_filters(pNetworkTuner, pReceiverComponent);
+ if (FAILED(hr))
+ return erreur(TEXT("Récepteur TNT non compatible, veuillez effacer \"config.ini\" et redémarrer"), hr);
+
+ pLastAddedFilter = pReceiverComponent; // Mémoriser pour connexion suivante
+ } else if (eCompat == compat_Receiver) {
+ // USB
+
+ // connect USB
+ hr = AddFilterToGraph(pNetworkTuner, nom_tuner);
+ if (FAILED(hr))
+ return erreur(TEXT("Échec de l'insertion du filtre Tuner USB"), hr);
+
+ hr = connect_filters(pLastAddedFilter, pNetworkTuner);
+ if (FAILED(hr))
+ return erreur(TEXT("Tuner USB non compatible, veuillez effacer \"config.ini\" et redémarrer"), hr);
+
+ pLastAddedFilter = pNetworkTuner; // Mémoriser pour connexion suivante
+ }
+
+ hr = pNetworkTuner.QueryInterface(&pBDAControl);
+
+ if (FAILED(hr))
+ return erreur(TEXT("L'interface IBDA_DeviceControl n'a pas été trouvée"), hr);
+
+ hr = Search_IBDA_Topology(pNetworkTuner, pBDAFreq);
+ if (FAILED(hr))
+ return erreur(TEXT("L'interface de changement de fréquence n'a pas été trouvée"), hr);
+
+ hr = Search_IBDA_Topology(pNetworkTuner, pStats);
+ if (FAILED(hr))
+ return erreur(TEXT("L'interface de qualité du signal n'a pas été trouvée"), hr);
+ return hr;
+}
+
+static HRESULT AddGrabber(CComPtr & pLastAddedFilter)
+{
+ HRESULT hr;
+
+#if USE_SINGLE_GRABBER
+ FilterData sGrabberFilter(TEXT("Grabber"), CLSID_SampleGrabber);
+
+ hr = create_and_add_filter(sGrabberFilter);
+ if (FAILED(hr))
+ return hr;
+
+ hr = connect_filters(pLastAddedFilter, sGrabberFilter.pFilter);
+ if (FAILED(hr))
+ return erreur(
+ TEXT("Le grabber n'a pas pu être connecté à la carte TNT, ")
+ TEXT("veuillez effacer \"%s%s\" et redémarrer"), hr, prefix_conf, config_file);
+
+ hr = sGrabberFilter.pFilter.QueryInterface(&sGrabber.pInterface);
+ if (FAILED(hr))
+ return erreur(TEXT("L'interface du grabber n'a pas été trouvée"), hr);
+
+ sGrabber.pCallback = new CSampleGrabber();
+ if (sGrabber.pCallback==NULL)
+ return erreur(TEXT("L'interface de callback du grabber n'a pas pu être créée"), E_FAIL);
+ pLastAddedFilter = sGrabberFilter.pFilter; // Mémoriser pour connexion suivante
+
+#else
+ for (int i=0; i < enregistrements_actuels.count(); i++) {
+ TCHAR nom[20];
+
+ _stprintf_s(nom, _countof(nom), TEXT("Grabber %u"), i);
+
+ FilterData sGrabberFilter(nom, CLSID_SampleGrabber);
+
+ if (FAILED(hr = create_and_add_filter(sGrabberFilter)))
+ return hr;
+
+ hr = connect_filters(pLastAddedFilter, sGrabberFilter.pFilter);
+ if (FAILED(hr))
+ return erreur(
+ TEXT("Le grabber n'a pas pu être connecté à la carte TNT, ")
+ TEXT("veuillez effacer \"%s%s\" et redémarrer"), hr, prefix_conf, config_file);
+
+ enregistrements_actuels[i].query(sGrabberFilter.pFilter);
+ pLastAddedFilter = sGrabberFilter.pFilter; // Mémoriser pour connexion suivante
+ }
+#endif
+ return hr;
+}
+
+static HRESULT AddDemux(CComPtr & pLastAddedFilter)
+{
+ HRESULT hr = create_and_add_filter(sDemux);
+
+ if (FAILED(hr))
+ return hr;
+
+ hr = connect_filters(pLastAddedFilter, sDemux.pFilter);
+ if (FAILED(hr))
+ return erreur(
+ TEXT("Le grabber n'a pas pu être connecté au démultiplexeur, ")
+ TEXT("veuillez effacer \"%s%s\" et redémarrer"), hr, prefix_conf, config_file);
+ return hr;
+}
+
+/// Construction du graphe
+static HRESULT Build()
+{
+ HRESULT hr;
+
+ CComPtr pLastAddedFilter; //!< Pointeur sur dernier filtre ajouté
+ FilterData sNetworkProvider(TEXT("Microsoft DVB-T Network Provider"), CLSID_DVBTNetworkProvider);
+
+ // Ajout des éléments nécessaires au tuner :
+ if (autre_graphe) {
+ // Ancien graphe
+ sNetworkProvider.bLocal = true;
+ sNetworkProvider.procCrea = CNetworkProvider::CreateInstance;
+ sNetworkProvider.pszName = TEXT(NETWORK_FILTER_NAME);
+ }
+
+ // Création filtre DVB-T
+ hr = create_and_add_filter(sNetworkProvider);
+ if (FAILED(hr))
+ return hr;
+ pLastAddedFilter = sNetworkProvider.pFilter;
+
+ if (FAILED(hr = AddTunerAndReceiver(pLastAddedFilter))) // Tuner et récepteur
+ return hr;
+ if (FAILED(hr = AddGrabber(pLastAddedFilter))) // Grabber
+ return hr;
+ if (FAILED(hr = AddDemux(pLastAddedFilter))) // Démultiplexeur
+ return hr;
+
+ // Interface du démultiplexeur
+ CComQIPtr pMpeg2Demux(sDemux.pFilter);
+
+ if (!pMpeg2Demux)
+ return erreur(TEXT("L'interface du démultiplexeur n'a pas été trouvée"), E_NOINTERFACE);
+
+ // connections
+ if (FAILED(hr = AddDataFilters(*pMpeg2Demux))) // Filtres de contrôle
+ return erreur(TEXT("Erreur lors de l'ajout des filtres de contrôle dans le graphe"), hr);
+ if (FAILED(hr = AddDecoders(*pMpeg2Demux))) // Codecs
+ return erreur(TEXT("Erreur lors de l'ajout des décodeurs dans le graphe"), hr);
+ return hr;
+}
+
/**
* Construction et mise en route du graphe DirectShow
* \return Code d'erreur DirectShow
**/
HRESULT build_graph()
{
+ // Nécessaire pour que le codec vidéo puisse se reconnecter après redémarrage :
+ bSuspended = true;
+ ePrevVideoType = vst_Unknown;
+
// Créer le graphe
HRESULT hr = pGraph.CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER);
@@ -1028,155 +1267,276 @@
return erreur(TEXT("Échec de l'exportation du graphe"), hr);
#endif // #if EXPORT_GRAPH
- {
- if (autre_graphe) {
- // Ancien graphe
- sNetworkProvider.bLocal = true;
- sNetworkProvider.procCrea = CNetworkProvider::CreateInstance;
- sNetworkProvider.pszName = TEXT(NETWORK_FILTER_NAME);
- }
+ hr = Build();
- // Création filtre DVB-T
- hr = create_and_add_filter(sNetworkProvider);
- if (FAILED(hr))
- return hr;
+ if (FAILED(hr))
+ return erreur(TEXT("Erreur lors de la création du graphe"), hr);
- CSearchByCategory_Get(KSCATEGORY_BDA_NETWORK_TUNER, nom_tuner, pNetworkTuner).Do();
+ AddEventNotifier(hMainWnd, WM_APP_GRAPHNOTIFY);
- CompatResult eCompat = filtre_compat(pNetworkTuner);
- CComPtr pLastAddedFilter; //!< Pointeur sur dernier filtre ajouté
- // (nécessaire lorsque la connexion au filtre suivant requiert
- // un filtre source qui est susceptible de varier)
+ // mise en route
+ return graph_Run();
+}
- if (eCompat == compat_Tuner) {
- // PCI
+// ====================================================================================
+// Contrôle de la réception
+// ====================================================================================
- hr = AddFilterToGraph(pNetworkTuner, nom_tuner);
- if (FAILED(hr))
- return erreur(TEXT("Échec de l'insertion du filtre Tuner"), hr);
+/// Ajout informations si \p pstr non \p NULL
+static void addStr(tstring * pstr, LPCTSTR pszFmt, ...)
+{
+ if (!pstr)
+ return;
- CSearchByCategory_Get(KSCATEGORY_BDA_RECEIVER_COMPONENT, nom_receiver, pReceiverComponent).Do();
+ TCHAR szBuffer[96];
- hr = AddFilterToGraph(pReceiverComponent, nom_receiver);
- if (FAILED(hr))
- return erreur(TEXT("Échec de l'insertion du filtre Récepteur"), hr);
+ va_list args;
+ va_start(args, pszFmt);
+ _vstprintf_s(szBuffer, pszFmt, args);
+ va_end(args);
+ if (!pstr->empty())
+ *pstr += TEXT("; ");
+ *pstr += szBuffer;
+}
- // connect Tuner
- hr = connect_filters(sNetworkProvider.pFilter, pNetworkTuner);
- if (FAILED(hr))
- return erreur(TEXT("Tuner TNT non compatible, veuillez effacer \"config.ini\" et redémarrer"), hr);
+/**
+ * Syntonisation d'une fréquence dans le tuner.
+ * \param[in] freq Fréquence à syntoniser, exprimée en kilohertz
+ * \param[in] pstrErr Pointeur sur une variable recevant un détail des erreurs si non NULL
+ **/
+HRESULT change_frequence(ULONG freq, tstring * pstrErr)
+{
+#if USE_STD_NETWP_TUNSPC == 0
- // connect Receiver
- hr = connect_filters(pNetworkTuner, pReceiverComponent);
- if (FAILED(hr))
- return erreur(TEXT("Récepteur TNT non compatible, veuillez effacer \"config.ini\" et redémarrer"), hr);
+ if (!pBDAControl || !pBDAFreq)
+ return E_FAIL;
- pLastAddedFilter = pReceiverComponent; // Mémoriser pour connexion suivante
- } else if (eCompat == compat_Receiver) {
- // USB
+ HRESULT hr = pBDAControl->StartChanges();
- // connect USB
- hr = AddFilterToGraph(pNetworkTuner, nom_tuner);
- if (FAILED(hr))
- return erreur(TEXT("Échec de l'insertion du filtre Tuner USB"), hr);
+ if (hr != S_OK) {
+ addStr(pstrErr, TEXT("StartChanges: hr=0x%08x"), hr);
+ return hr;
+ }
- hr = connect_filters(sNetworkProvider.pFilter, pNetworkTuner);
- if (FAILED(hr))
- return erreur(TEXT("Tuner USB non compatible, veuillez effacer \"config.ini\" et redémarrer"), hr);
+ hr = pBDAFreq->put_Bandwidth(8);
+ if (hr != S_OK)
+ addStr(pstrErr, TEXT("put_Bandwidth(8): hr=0x%08x"), hr);
- pLastAddedFilter = pNetworkTuner; // Mémoriser pour connexion suivante
- } else
- return E_FAIL;
+ freq += offset_tuner; // Correction de fréquence
- hr = pNetworkTuner.QueryInterface(&pBDAControl);
+ HRESULT hr2 = pBDAFreq->put_Frequency(freq);
- if (FAILED(hr))
- return erreur(TEXT("L'interface IBDA_DeviceControl n'a pas été trouvée"), hr);
- hr = Search_IBDA_Topology(pNetworkTuner, pBDAFreq);
- if (FAILED(hr))
- return erreur(TEXT("L'interface de changement de fréquence n'a pas été trouvée"), hr);
+ if (hr2 != S_OK) {
+ addStr(pstrErr, TEXT("put_Frequency(%ul): hr=0x%08x"), freq, hr2);
+ if (hr == S_OK)
+ hr = hr2;
+ }
- hr = Search_IBDA_Topology(pNetworkTuner, pStats);
- if (FAILED(hr))
- return erreur(TEXT("L'interface de qualité du signal n'a pas été trouvée"), hr);
+ hr2 = pBDAControl->CheckChanges();
+ if (hr2 != S_OK) {
+ addStr(pstrErr, TEXT("CheckChanges(): hr=0x%08x"), hr2);
+ if (hr == S_OK)
+ hr = hr2;
+ }
- // ajoute pGrabber filter
- {
- // connect 3
+ hr2 = pBDAControl->CommitChanges();
+ if (hr2 != S_OK) {
+ addStr(pstrErr, TEXT("CommitChanges(): hr=0x%08x"), hr2);
+ if (hr == S_OK)
+ hr = hr2;
+ }
+#endif
+ return hr;
+}
-#if USE_SINGLE_GRABBER
- FilterData sGrabberFilter(TEXT("Grabber"), CLSID_SampleGrabber);
+/**
+ * Branchement d'une piste sonore.
+ * \param[in] pid PID de la piste à brancher
+ * \param[in] type Type de la piste audio
+ **/
+HRESULT branche_son(UINT16 pid, TrackStreamType type)
+{
+ HRESULT hr = E_FAIL;
- hr = create_and_add_filter(sGrabberFilter);
- if (FAILED(hr))
- return hr;
+ if (pid!=0) {
+ switch (type) {
- hr = connect_filters(pLastAddedFilter, sGrabberFilter.pFilter);
- if (FAILED(hr))
- return erreur(
- TEXT("Le grabber n'a pas pu être connecté à la carte TNT, ")
- TEXT("veuillez effacer \"%s%s\" et redémarrer"), hr, prefix_conf, config_file);
+ case tst_MPEG2:
+ hr = sMp2aCodec.branche_pid(pid);
+ break;
- hr = sGrabberFilter.pFilter.QueryInterface(&sGrabber.pInterface);
- if (FAILED(hr))
- return erreur(TEXT("L'interface du grabber n'a pas été trouvée"), hr);
+ case tst_AC3:
+ case tst_EAC3:
+ hr = sAc3_Codec.branche_pid(pid);
+ break;
- sGrabber.pCallback = new CSampleGrabber();
- if (sGrabber.pCallback==NULL)
- return erreur(TEXT("L'interface de callback du grabber n'a pas pu être créée"), E_FAIL);
- pLastAddedFilter = sGrabberFilter.pFilter; // Mémoriser pour connexion suivante
+ default:
+ myprintf(TEXT("Type de piste audio non identifié\n"));
+ }
+ }
+ return hr;
+}
-#else // #if USE_SINGLE_GRABBER
- for (int i=0; i < enregistrements_actuels.count(); i++) {
- TCHAR nom[20];
+/**
+ * Débranchement de toutes les pistes sonores
+ **/
+void debranche_son()
+{
+ sMp2aCodec.debranche_pids();
+ sAc3_Codec.debranche_pids();
+}
- _stprintf_s(nom, _countof(nom), TEXT("Grabber %u"), i);
+/**
+ * Branchement de tous les médias de sortie d'une chaîne.
+ *
+ * \param[in] pmt_pid PID du flux PMT de la chaîne
+ * \param[in] video_pid PID du flux vidéo
+ * \param[in] video_type Type du flux vidéo
+ * \param[in] audio_pid PID du flux audio
+ * \param[in] audio_type Type du flux audio
+ * \return Code d'erreur DirectShow
+ **/
+HRESULT branche_medias(UINT16 pmt_pid, UINT16 video_pid, VideoStreamType video_type, UINT16 audio_pid, TrackStreamType audio_type)
+{
+ HRESULT hr = E_FAIL; // valeur par défaut
- FilterData sGrabberFilter(nom, CLSID_SampleGrabber);
+ if (bSuspended) {
+ if (video_pid) {
+ switch (video_type) {
+ case vst_MPEG2:
+ if (pVMR && ePrevVideoType!=vst_MPEG2) {
+ if (FAILED(hr = switch_codec(sMp2vCodec)))
+ return hr;
+ ePrevVideoType = vst_MPEG2;
+ }
+ hr = sMp2vCodec.branche_pid(video_pid);
+ break;
- if (FAILED(hr = create_and_add_filter(sGrabberFilter)))
- return hr;
+ case vst_H264:
+ if (pVMR && ePrevVideoType!=vst_H264) {
+ if (FAILED(hr = switch_codec(sH264Codec)))
+ return hr;
+ ePrevVideoType = vst_H264;
+ }
+ hr = sH264Codec.branche_pid(video_pid);
+ break;
- hr = connect_filters(pLastAddedFilter, sGrabberFilter.pFilter);
- if (FAILED(hr))
- return erreur(
- TEXT("Le grabber n'a pas pu être connecté à la carte TNT, ")
- TEXT("veuillez effacer \"%s%s\" et redémarrer"), hr, prefix_conf, config_file);
-
- enregistrements_actuels[i].query(sGrabberFilter.pFilter);
- pLastAddedFilter = sGrabberFilter.pFilter; // Mémoriser pour connexion suivante
+ default:
+ hr=E_FAIL;
}
-#endif // #if USE_SINGLE_GRABBER
+ }
- // connect 4
+ branche_son(audio_pid, audio_type);
- hr = create_and_add_filter(sDemux);
- if (FAILED(hr))
- return hr;
+#if USE_PMTFILTER
+ // pmt
+ hr = sPMT_Filter.branche_pid(pmt_pid);
+#endif
+ bSuspended = false;
+ }
+ return hr;
+}
- hr = connect_filters(pLastAddedFilter, sDemux.pFilter);
- if (FAILED(hr))
- return erreur(
- TEXT("Le grabber n'a pas pu être connecté au démultiplexeur, ")
- TEXT("veuillez effacer \"%s%s\" et redémarrer"), hr, prefix_conf, config_file);
- }
+/**
+ * Débranchement de tous les médias
+ **/
+void debranche_medias()
+{
+ if (!bSuspended) {
+ sMp2vCodec.debranche_pids();
+ sH264Codec.debranche_pids();
+ debranche_son();
+#if USE_PMTFILTER
+ sPMT_Filter.debranche_pids();
+#endif
+ bSuspended = true;
}
+}
- // connexions
+/**
+ * Changement de volume sonore
+ * \param[in] volume Nouveau volume sonore, valeur de 0 à 100
+ * \return Code d'erreur DirectShow
+ **/
+HRESULT set_volume(long volume)
+{
+ CComQIPtr