From pouchintv-svn at baysse.fr Mon Mar 3 00:35:27 2008
From: pouchintv-svn at baysse.fr (pouchintv-svn at baysse.fr)
Date: Mon, 3 Mar 2008 00:35:27 +0100 (CET)
Subject: [Pouchintv-dev] [PouchinTVMod] gingko | r113 - trunk
Message-ID: <20080302233527.8AE075F5EF@mail.baysse.fr>
Author: gingko
Date: 2008-03-03 00:35:26 +0100 (Mon, 03 Mar 2008)
New Revision: 113
Added:
trunk/chanutils.cpp
trunk/chanutils.h
trunk/console.cpp
trunk/console.h
trunk/utils.cpp
trunk/utils.h
Modified:
trunk/Pouchin TV.vcproj
trunk/base.cpp
trunk/base.h
trunk/channels.cpp
trunk/channels.h
trunk/crc32.cpp
trunk/crc32.h
trunk/graph.h
trunk/ini.cpp
trunk/ini.h
trunk/main.cpp
trunk/parse.cpp
trunk/parse.h
trunk/pmtfilter.cpp
trunk/record.h
trunk/recprog.cpp
trunk/recprog.h
Log:
Modifications pr?\195?\169liminaires ?\195?\160 une livraison majeure ?\195?\160 venir :
Ajout de plusieurs fichiers regroupant du code qui se trouvait
auparavant dans d'autres fichiers, afin de rendre ce code plus
ind?\195?\169pendant et r?\195?\169utilisable.
?\195?\128 cette fin sont cr?\195?\169?\195?\169s les fichiers suivants :
- chanutils.h, chanutils.cpp (pour les structures m?\195?\169morisant les
pistes son et autres li?\195?\169s aux canaux);
- console.h, console.cpp (pour la console de debugging);
- utils.h, utils.cpp (pour les fonctions utilitaires simples).
Le code qui y est ajout?\195?\169 est, bien ?\195?\169videmment, retir?\195?\169 des fichiers o?\195?\185
il se trouvait.
Ajout de quelques macros de debugging.
Renommage de quelques variables et structures MPEG2 afin de les faire
pr?\195?\169-correspondre aux futurs noms qu'elles vont recevoir dans le
fichier de d?\195?\169clarations MPEG2 global que je suis en train de finaliser.
Autres changements mineurs.
Modified: trunk/Pouchin TV.vcproj
===================================================================
--- trunk/Pouchin TV.vcproj 2008-01-03 21:31:07 UTC (rev 112)
+++ trunk/Pouchin TV.vcproj 2008-03-02 23:35:26 UTC (rev 113)
@@ -716,6 +716,14 @@
>
+
+
+
+
@@ -788,6 +796,10 @@
>
+
+
@@ -806,6 +818,14 @@
>
+
+
+
+
@@ -882,6 +902,10 @@
>
+
+
Modified: trunk/base.cpp
===================================================================
--- trunk/base.cpp 2008-01-03 21:31:07 UTC (rev 112)
+++ trunk/base.cpp 2008-03-02 23:35:26 UTC (rev 113)
@@ -29,68 +29,10 @@
#include "main.h"
#include "ini.h"
-#if USE_CONSOLE==1
-static HANDLE hStdOut = NULL;
-#endif // #if USE_CONSOLE==1
+HWND hMainWnd = NULL;
-#if USE_CONSOLE
-void myprintf(const wchar_t *fmt, ...)
-{
- wchar_t s[512];
- va_list argptr;
- DWORD cnt;
- va_start(argptr, fmt);
-
- // Affichage conditionnel : si la chaîne de formatage débute par "%?",
- // alors le premier paramètre suivant est un booléen qui conditionne
- // si l'affichage a lieu ou pas. Le "%?" n'est bien sûr pas affiché.
- if (fmt[0]=='%' && fmt[1]=='?') {
- if (!va_arg(argptr, bool))
- return;
- fmt += 2;
- }
-
- cnt = vswprintf_s(s, _countof(s), fmt, argptr);
- va_end(argptr);
-
-#if USE_CONSOLE==-1
- OutputDebugString(s);
- //
- // Les logiciels qui récupèrent les messages de debugging ont généralement
- // 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);
-
- FILE * f;
- f = fopen("pouchin.log", "a");
- if (f) {
- fwprintf_s(f, s);
- fclose(f);
- }
-#endif // #if USE_CONSOLE==-1
-}
-#endif // #if USE_CONSOLE
-
-#if USE_CONSOLE==1
-void startConsoleWin(void)
-{
- AllocConsole();
- SetConsoleTitle(L"Debug Window");
- hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
- if (consolePos.verifie()) {
- HWND hConsoleWnd = GetConsoleWindow();
- MoveWindow(hConsoleWnd, consolePos.X, consolePos.Y, max(consolePos.L, 100), max(consolePos.H, 100), TRUE);
- }
-}
-#endif //#if USE_CONSOLE==1
-
-
void erreur(const wchar_t * str)
{
MessageBox(hMainWnd, str, NULL, MB_ICONERROR);
}
-
Modified: trunk/base.h
===================================================================
--- trunk/base.h 2008-01-03 21:31:07 UTC (rev 112)
+++ trunk/base.h 2008-03-02 23:35:26 UTC (rev 113)
@@ -50,8 +50,6 @@
#include
#include
-#include
-
#if USE_VMR9
# include
# include
@@ -74,33 +72,42 @@
// récupérer avec un debugger ou bien un logiciel tel que DebugView :
// http://www.microsoft.com/TechNet/Sysinternals/Utilities/DebugView.mspx
+#include "console.h"
+
+#ifdef _DEBUG
+# define EXPORT_GRAPH 1
+# define LOG_DSHOW 1 // Enregistrer DShow
+#else
#define EXPORT_GRAPH 0
+# define LOG_DSHOW 0
+#endif
// Activer le LCD Logitech
//#define USE_LOGITECH_LCD
-// Enregistrer DShow
-#define LOG_DSHOW 0
-
// Nombre max de chaînes
#define NB_MAX_CHAINES 500
-// Nombre max de pistes son par chaîne
-#define NB_MAX_PISTES 32
// Nombre max d'enregistrements simultanés sur un même multiplex
#define NB_MAX_ENREG 3
///////////////////////////////////////////////////////////////////
//
-// Fin des variables pouvant être modifiée pour la compilation
+// Fin des variables pouvant être modifiées pour la compilation
//
///////////////////////////////////////////////////////////////////
+
+// Macros d'assistance à l'insertion conditionnelle de courtes séquences de code en mode debugging :
+// (utile en particulier s'il s'agit de paramètres supplémentaires de fonctions)
#if USE_CONSOLE
-void myprintf(const wchar_t *fmt, ...);
-void startConsoleWin(void);
-#else // #if USE_CONSOLE
-#define myprintf(...)
-#endif // #if USE_CONSOLE
+#define IF_DEBUG(code) code
+#define IF_DEBUG_CA(code) code , // virgule après ("comma after")
+#define IF_DEBUG_CB(code) , code // virgule avant ("comma before")
+#else
+#define IF_DEBUG(code)
+#define IF_DEBUG_CA(arg)
+#define IF_DEBUG_CB(arg)
+#endif
#if defined _M_IX86
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
Modified: trunk/channels.cpp
===================================================================
--- trunk/channels.cpp 2008-01-03 21:31:07 UTC (rev 112)
+++ trunk/channels.cpp 2008-03-02 23:35:26 UTC (rev 113)
@@ -61,41 +61,6 @@
}
-bool liste_pistes::operator == (const liste_pistes & lp) const
-{
- if (nbr!=lp.nbr)
- return false;
- for (int i=0; i),
+ * to use with a modified version of this software.
+ * See http://pouchinteve.free.fr/ for the original project.
+ */
+
+/********************************************************************************************
+ * CHANUTILS (chanutils.h, chanutils.cpp) *
+ * *
+ * Définitions de structures pour la sauvegarde des pistes associées à une chaîne. *
+ * *
+ ********************************************************************************************/
+
+// Note : ces structures et ce module pourraient être supprimés ultérieurement
+
+#include "chanutils.h"
+
+bool liste_pistes::operator == (const liste_pistes & lp) const
+{
+ if (nbr!=lp.nbr)
+ return false;
+ for (int i=0; i),
+ * to use with a modified version of this software.
+ * See http://pouchinteve.free.fr/ for the original project.
+ */
+
+/********************************************************************************************
+ * CHANUTILS (chanutils.h, chanutils.cpp) *
+ * *
+ * Définitions de structures pour la sauvegarde des pistes associées à une chaîne. *
+ * *
+ ********************************************************************************************/
+
+// Note : ces structures et ce module pourraient être supprimés ultérieurement
+
+#pragma once
+
+#include
+
+// Nombre max de pistes son par chaîne
+#define NB_MAX_PISTES 32
+
+struct une_piste {
+ UINT16 pid;
+ UINT8 type; // si son : 0 = normal, 1 = AC3; réservé si autres
+ char lang[8];
+
+ bool operator == (const une_piste & up) const
+ {return pid==up.pid && type==up.type/* && strcmp(lang, up.lang)==0*/;}
+ // (strcmp pas nécessaire pour le moment)
+
+ bool operator != (const une_piste & up) const {return ! operator == (up);};
+};
+
+struct liste_pistes {
+ UINT16 nbr;
+ une_piste tbl[NB_MAX_PISTES];
+
+ liste_pistes() : nbr(0) {};
+
+ bool cherche_pid(UINT16 pid) const;
+ int ajoute(UINT16 newpid, UINT8 newtype=0, LPCSTR newlang=NULL);
+ bool operator == (const liste_pistes & lp) const;
+ bool operator != (const liste_pistes & lp) const {return ! operator == (lp);};
+};
Added: trunk/console.cpp
===================================================================
--- trunk/console.cpp (rev 0)
+++ trunk/console.cpp 2008-03-02 23:35:26 UTC (rev 113)
@@ -0,0 +1,98 @@
+/*
+ * console.cpp
+ * Copyright (C) 2008
+ *
+ * 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.
+ */
+
+/********************************************************************************************
+ * CONSOLE (console.h, console.cpp) *
+ * *
+ * Module de gestion de la console de debugging de Pouchin TV Mod. *
+ * *
+ ********************************************************************************************/
+
+#include "console.h"
+#include
+#include
+
+#if USE_CONSOLE==1
+HANDLE hStdOut = NULL;
+WindowPos consolePos;
+
+void startConsoleWin(bool alloc)
+{
+ if (alloc) {
+ AllocConsole();
+ SetConsoleTitle(L"Debug Window");
+ }
+ hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (consolePos.verifie()) {
+ HWND hConsoleWnd = GetConsoleWindow();
+ MoveWindow(hConsoleWnd, consolePos.X, consolePos.Y, max(consolePos.L, 100), max(consolePos.H, 100), TRUE);
+ }
+}
+#endif //#if USE_CONSOLE==1
+
+#if USE_CONSOLE
+void myprintf(const wchar_t *fmt, ...)
+{
+ wchar_t s[512];
+ va_list argptr;
+ DWORD cnt;
+
+ va_start(argptr, fmt);
+
+ // Affichage conditionnel : si la chaîne de formatage débute par "%?",
+ // alors le premier paramètre suivant est un booléen qui conditionne
+ // si l'affichage a lieu ou pas. Le "%?" n'est bien sûr pas affiché.
+ if (fmt[0]=='%' && fmt[1]=='?') {
+ if (!va_arg(argptr, bool))
+ return;
+ fmt += 2;
+ }
+
+ cnt = vswprintf_s(s, _countof(s), fmt, argptr);
+ va_end(argptr);
+
+#if USE_CONSOLE==-1
+ OutputDebugString(s);
+ //
+ // Les logiciels qui récupèrent les messages de debugging ont généralement
+ // 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);
+
+ FILE * f;
+
+ if (fopen_s(&f, "pouchin.log", "a")==0) {
+ fwprintf_s(f, s);
+ fclose(f);
+ }
+#endif // #if USE_CONSOLE==-1
+}
+#endif // #if USE_CONSOLE
Added: trunk/console.h
===================================================================
--- trunk/console.h (rev 0)
+++ trunk/console.h 2008-03-02 23:35:26 UTC (rev 113)
@@ -0,0 +1,57 @@
+/*
+ * console.h
+ * Copyright (C) 2008
+ *
+ * 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.
+ */
+
+/********************************************************************************************
+ * CONSOLE (console.h, console.cpp) *
+ * *
+ * Module de gestion de la console de debugging de Pouchin TV Mod. *
+ * *
+ ********************************************************************************************/
+
+#pragma once
+
+#include "utils.h"
+
+#if USE_CONSOLE==1
+extern WindowPos consolePos;
+#endif
+
+#if USE_CONSOLE
+void myprintf(const wchar_t *fmt, ...);
+#else // #if USE_CONSOLE
+#define myprintf(...)
+#endif // #if USE_CONSOLE
+
+#if USE_CONSOLE==1
+/*
+ * Initialisation de la console de debugging.
+ * Le paramètre "alloc" doit être 'true' si on veut ouvrir une nouvelle console,
+ * ou bien 'false' si on veut s'attacher à la console existante.
+ */
+void startConsoleWin(bool alloc);
+#endif
Modified: trunk/crc32.cpp
===================================================================
--- trunk/crc32.cpp 2008-01-03 21:31:07 UTC (rev 112)
+++ trunk/crc32.cpp 2008-03-02 23:35:26 UTC (rev 113)
@@ -73,7 +73,7 @@
0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
-static unsigned long crc32 (unsigned char * data, int len)
+unsigned long crc32 (const unsigned char * data, int len)
{
unsigned long crc = 0xffffffff;
@@ -85,7 +85,7 @@
return crc;
}
-bool check_crc32(unsigned char * data, long len)
+bool check_crc32(const unsigned char * data, long len)
{
unsigned long crc = crc32(data, len - 4);
Modified: trunk/crc32.h
===================================================================
--- trunk/crc32.h 2008-01-03 21:31:07 UTC (rev 112)
+++ trunk/crc32.h 2008-03-02 23:35:26 UTC (rev 113)
@@ -27,4 +27,6 @@
#pragma once
-bool check_crc32(unsigned char * data, long len);
+unsigned long crc32 (const unsigned char * data, int len);
+
+bool check_crc32(const unsigned char * data, long len);
Modified: trunk/graph.h
===================================================================
--- trunk/graph.h 2008-01-03 21:31:07 UTC (rev 112)
+++ trunk/graph.h 2008-03-02 23:35:26 UTC (rev 113)
@@ -27,6 +27,8 @@
#pragma once
+#include
+
#define free_interface(X) if (X) { X->Release(); X=NULL;}
int build_graph(void); // retourne 0 = pas d'erreur, 1 = erreur
Modified: trunk/ini.cpp
===================================================================
--- trunk/ini.cpp 2008-01-03 21:31:07 UTC (rev 112)
+++ trunk/ini.cpp 2008-03-02 23:35:26 UTC (rev 113)
@@ -43,9 +43,6 @@
static wchar_t general[]=L"Général";
WindowPos winPos;
-#if USE_CONSOLE==1
-WindowPos consolePos;
-#endif // #if USE_CONSOLE==1
// Priorité du processus courant selon la configuration
DWORD configPriority = IDM_ABOVE_NORMAL_PRIORITY;
@@ -96,24 +93,6 @@
static wchar_t ini_use_vmr_deinterlace[]=L"Utilise le désentrelacement du VMR";
static wchar_t ini_etat_fenetre[]=L"État fenêtre";
-bool WindowPos::verifie()
-{
- RECT rect;
- //
- SetRect(&rect, X, Y, X+L, Y+16);
- if (
- X==CW_USEDEFAULT ||
- Y==CW_USEDEFAULT ||
- L==CW_USEDEFAULT ||
- H==CW_USEDEFAULT ||
- MonitorFromRect(&rect, MONITOR_DEFAULTTONULL)==NULL
- ) {
- myprintf(L"Position fenêtre invalide\n");
- return false;
- }
- return true;
-}
-
NomProtege::NomProtege(LPCSTR src, char remplacement)
{
LPSTR pcar;
@@ -159,38 +138,6 @@
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
}
-/**
- * Trouver la valeur binaire associée à une chaîne de caractères fournie,
- * selon la table 'assocTable'. Si la chaîne ne se trouve pas dans la table,
- * alors la valeur 'bydefault' est retournée.
- **/
-DWORD str2dword(const AssocElement * assocTable, LPCWSTR lpStr, DWORD bydefault)
-{
- while (assocTable->str != NULL && wcscmp(lpStr, assocTable->str) != 0)
- assocTable++;
-
- if (assocTable->str==NULL)
- return bydefault;
- return assocTable->bin;
-}
-
-/**
- * Trouver la chaîne de caractères associée à une valeur binaire fournie,
- * selon la table 'assocTable'. Si la valeur binaire ne se trouve pas dans la table,
- * alors un pointeur sur une chaîne vide est retourné.
- **/
-LPCWSTR dword2str(const AssocElement * assocTable, DWORD value)
-{
- while (assocTable->str != NULL && assocTable->bin != value)
- assocTable++;
-
- LPCWSTR str = assocTable->str;
-
- if (str==NULL)
- str = L"??";
- return str;
-}
-
BOOL save_config_int(LPCWSTR lpKeyName, LONG value); // forward
void lit_fichier_scan(wchar_t * ville)
@@ -847,7 +794,7 @@
wcscpy_s(confPathName, _countof(confPathName), chemin_config);
else
// la config du tuner a été trouvée dans le répertoire de PTVM
- // On change le répertoire de config vers celui su programme
+ // On change le répertoire de config vers celui du programme
wcscpy_s(pouchindir_conf, _countof(pouchindir_conf), pouchindir_prog);
}
Modified: trunk/ini.h
===================================================================
--- trunk/ini.h 2008-01-03 21:31:07 UTC (rev 112)
+++ trunk/ini.h 2008-03-02 23:35:26 UTC (rev 113)
@@ -27,6 +27,8 @@
#pragma once
+#include "utils.h"
+
void lit_fichier_scan(wchar_t * ville);
/**
@@ -67,21 +69,7 @@
**/
bool check_config(void);
-// Structure pour la sauvegarde de la position des fenêtres :
-struct WindowPos {
- long X;
- long Y;
- long L;
- long H;
- //
- // Vérifie si cette valeur est visible sur un des moniteurs existants
- bool verifie();
-};
-
extern WindowPos winPos;
-#if USE_CONSOLE==1
-extern WindowPos consolePos;
-#endif // #if USE_CONSOLE==1
// Priorité du processus courant selon la configuration
extern DWORD configPriority;
@@ -120,31 +108,6 @@
};
/**
- * Élement de table d'association chaîne <--> valeur binaire.
- * Cette structure est destinée à faire partie d'une table dont le dernier élément
- * doit avoir ses deux valeurs à NULL et 0 respectivement.
- **/
-struct AssocElement
-{
- LPCWSTR str;
- DWORD bin;
-};
-
-/**
- * Trouver la valeur binaire associée à une chaîne de caractères fournie,
- * selon la table 'assocTable'. Si la chaîne ne se trouve pas dans la table,
- * alors la valeur 'bydefault' est retournée.
- **/
-DWORD str2dword(const AssocElement * assocTable, LPCWSTR lpStr, DWORD bydefault);
-
-/**
- * Trouver la chaîne de caractères associée à une valeur binaire fournie,
- * selon la table 'assocTable'. Si la valeur binaire ne se trouve pas dans la table,
- * alors un pointeur sur une chaîne vide est retourné.
- **/
-LPCWSTR dword2str(const AssocElement * assocTable, DWORD value);
-
-/**
* Table d'associations pour nommer les états possible des chaînes.
**/
extern const AssocElement aChStateTable[];
Modified: trunk/main.cpp
===================================================================
--- trunk/main.cpp 2008-01-03 21:31:07 UTC (rev 112)
+++ trunk/main.cpp 2008-03-02 23:35:26 UTC (rev 113)
@@ -55,7 +55,6 @@
wchar_t szAppName[]=L"Pouchin TV Mod";
HINSTANCE hAppInstance;
-HWND hMainWnd;
HMENU hMainMenu;
HICON hPrgIcon = NULL; // Icône normale du programme
HICON hRecIcon = NULL; // Icône utilisée en mode enregistrement
@@ -1644,7 +1643,7 @@
}
}
-// Obtenir le ration d'aspect :
+// Obtenir le ratio d'aspect :
static POINT GetAspectRatio()
{
POINT ar = {4, 3}; // (valeurs par défaut)
@@ -2633,7 +2632,7 @@
if (!RegisterClass(&wndclass)) return 0;
#if USE_CONSOLE==1
- startConsoleWin();
+ startConsoleWin(true);
#endif // #if USE_CONSOLE==1
#if USE_CONSOLE
myprintf(L"Compile le : %S %S\n", __DATE__, __TIME__);
Modified: trunk/parse.cpp
===================================================================
--- trunk/parse.cpp 2008-01-03 21:31:07 UTC (rev 112)
+++ trunk/parse.cpp 2008-03-02 23:35:26 UTC (rev 113)
@@ -49,7 +49,7 @@
}
// Partie commune à toutes les tables :
-struct TableHead {
+struct SI_hdr {
BYTE table_id;
BYTE section_length_hi;
BYTE section_length_lo;
@@ -114,7 +114,7 @@
CRC_32 32
}
*/
-struct PAT_entry {
+struct SI_PAT_entry {
BYTE program_number_hi;
BYTE program_number_lo;
BYTE program_map_pid_hi;
@@ -123,28 +123,28 @@
// Méthodes d'extraction :
WORD program_number() const
{return (program_number_hi<<8) | program_number_lo;}
- WORD program_map_pid() const
+ WORD pid() const
{return ((program_map_pid_hi & 0x1f)<<8) | program_map_pid_lo;}
};
-struct PAT : public TableHead {
+struct SI_PAT : public SI_hdr {
//
// Méthodes d'extraction :
- const PAT_entry * begin() const
- {return (const PAT_entry *)(this+1);}
+ const SI_PAT_entry * begin() const
+ {return (const SI_PAT_entry *)(this+1);}
};
// PAT = Program Association Table
-static void parse_pat(const PAT * ppat, int max)
+static void parse_pat(const SI_PAT & pat, int max)
{
- WORD tsid = ppat->tsid();
+ WORD tsid = pat.tsid();
- for (const PAT_entry * ppaent = ppat->begin(); LPBYTE(ppaent)end(max); ppaent++) {
+ for (const SI_PAT_entry * ppaent = pat.begin(); LPBYTE(ppaent)program_number();
- WORD pmt = ppaent->program_map_pid();
+ WORD pid = ppaent->pid();
- myprintf(L"Service : 0x%04x, PMT PID : 0x%04x\n", service, pmt);
- sauve_pmt(tsid, service, pmt);
+ myprintf(L"Service : 0x%04x, PMT PID : 0x%04x\n", service, pid);
+ sauve_pmt(tsid, service, pid);
}
}
@@ -229,7 +229,7 @@
};
// PMT = Program Map Table
-struct PMT : public TableHead {
+struct SI_PMT : public SI_hdr {
BYTE pcr_pid_hi;
BYTE pcr_pid_lo;
BYTE program_info_length_hi;
@@ -244,13 +244,13 @@
{return (const PMT_entry *)(LPBYTE(this+1)+length());}
};
-void parse_pmt(const PMT * ppmt, int max, ChainePMT & pmt/*, bool debug*/)
+void parse_pmt(const SI_PMT & pmt, int max, ChainePMT & lpmt_e/*, bool debug*/)
{
- pmt.pcr_pid = ppmt->pcr_pid();
- pmt.sons.nbr=0;
- pmt.autr.nbr=0;
+ lpmt_e.pcr_pid = pmt.pcr_pid();
+ lpmt_e.sons.nbr=0;
+ lpmt_e.autr.nbr=0;
- for (const PMT_entry * ppent = ppmt->begin(); LPBYTE(ppent)end(max); ppent=ppent->next()) {
+ for (const PMT_entry * ppent = pmt.begin(); LPBYTE(ppent)next()) {
WORD pid = ppent->pid();
BYTE stream_type = ppent->stream_type;
bool private_stream = 0;
@@ -262,28 +262,28 @@
switch (stream_type) {
case 0x01: //ISO_IEC_11172_2_VIDEO, MPEG-1 video streams
case 0x02: //ISO_IEC_13818_2_VIDEO, MPEG-2 video streams
- pmt.video_pid=pid;
+ lpmt_e.video_pid=pid;
break;
case 0x03: //ISO_IEC_11172_3_AUDIO, MPEG-1 audio streams
case 0x04: //ISO_IEC_13818_3_AUDIO, MPEG-2 audio streams
- pmt.sons.ajoute(pid, 0);
+ lpmt_e.sons.ajoute(pid, 0);
break;
case 0x06:
private_stream=1;
break;
case 0x1B: //H264
- pmt.mpeg4_pid=pid;
+ lpmt_e.mpeg4_pid=pid;
break;
}
if (private_stream) {
for (; (LPBYTE)ppdescend(); ppdesc=ppdesc->next()) {
if (ppdesc->descriptor_tag == 0x6A)
- pmt.sons.ajoute(pid, 1);
+ lpmt_e.sons.ajoute(pid, 1);
}
- if (pmt.sons.tbl[pmt.sons.nbr-1].pid != pid)
- pmt.autr.ajoute(pid);
+ if (lpmt_e.sons.tbl[lpmt_e.sons.nbr-1].pid != pid)
+ lpmt_e.autr.ajoute(pid);
ppdesc = ppent->begin();
}
@@ -295,7 +295,7 @@
//if (debug)
// myprintf(L"sous_type : %02X, sous_taille : %i\n", tag, length);
if (tag == 0x0A && length > 0) {
- une_piste & pmt_son = pmt.sons.tbl[pmt.sons.nbr-1];
+ une_piste & pmt_son = lpmt_e.sons.tbl[lpmt_e.sons.nbr-1];
if (pmt_son.pid == pid) {
memcpy(pmt_son.lang, ppdesc->begin(), length);
@@ -303,7 +303,7 @@
pmt_son.lang[length-1]='\0';
}
- // une_piste & pmt_autre = pmt.autr.tbl[pmt.autr.nbr-1];
+ // une_piste & pmt_autre = lpmt_e.autr.tbl[lpmt_e.autr.nbr-1];
// if (pmt_autre.pid == pid) {
// memcpy(pmt_autre.lang, ppdesc->begin(), length);
@@ -364,7 +364,7 @@
return p+taille;
}
-struct SDT_entry {
+struct SI_SDT_entry {
BYTE service_id_hi;
BYTE service_id_lo;
BYTE eit_flags;
@@ -378,12 +378,12 @@
{return ((descriptors_loop_length_hi & 0x0f)<<8) | descriptors_loop_length_lo;}
const SDT_descriptor * begin() const
{return (const SDT_descriptor *)LPBYTE(this+1);}
- const SDT_entry * next() const
- {return (const SDT_entry *)(LPBYTE(this+1)+length());}
+ const SI_SDT_entry * next() const
+ {return (const SI_SDT_entry *)(LPBYTE(this+1)+length());}
};
// SDT = Service Description Table
-struct SDT : public TableHead {
+struct SI_SDT : public SI_hdr {
BYTE onid_hi;
BYTE onid_lo;
BYTE reserved;
@@ -391,21 +391,21 @@
// Méthodes d'extraction :
WORD onid() const
{return (onid_hi<<8) | onid_lo;}
- const SDT_entry * begin() const
- {return (const SDT_entry *)LPBYTE(this+1);}
+ const SI_SDT_entry * begin() const
+ {return (const SI_SDT_entry *)LPBYTE(this+1);}
};
-static void parse_sdt(const SDT * psdt, int max, const Frequence & freq)
+static void parse_sdt(const SI_SDT & sdt, int max, const Frequence & freq)
{
- WORD tsid = psdt->tsid(); // transport_stream_id
- WORD onid = psdt->onid(); // original_network_id
+ WORD tsid = sdt.tsid(); // transport_stream_id
+ WORD onid = sdt.onid(); // original_network_id
- //myprintf(L"Taille section : %i\n", psdt->section_length());
+ //myprintf(L"Taille section : %i\n", sdt.section_length());
myprintf(L"Transport stream id : %i\n", tsid);
myprintf(L"Onid : %i\n", onid);
myprintf(L"chaines : \n");
- for (const SDT_entry * psent = psdt->begin(); LPBYTE(psent)end(max); psent=psent->next()) {
+ for (const SI_SDT_entry * psent = sdt.begin(); LPBYTE(psent)next()) {
Chaine canal;
const SDT_descriptor * psdesc = psent->begin();
const BYTE * pdata = psdesc->begin();
@@ -512,7 +512,7 @@
};
// NIT = Network Information Table
-struct NIT2 {
+struct SI_NIT_entries_hdr {
BYTE transport_stream_loop_length_hi;
BYTE transport_stream_loop_length_lo;
//
@@ -525,7 +525,7 @@
{return LPBYTE(this+1)+length();}
};
-struct NIT : public TableHead {
+struct SI_NIT : public SI_hdr {
BYTE network_descriptors_length_hi;
BYTE network_descriptors_length_lo;
//
@@ -536,14 +536,14 @@
{return (const descriptor *)(this+1);}
const LPBYTE end() const
{return LPBYTE(this+1)+length();}
- const NIT2 * part2() const
- {return (const NIT2 *)end();}
+ const SI_NIT_entries_hdr & entries_hdr() const
+ {return *reinterpret_cast(end());}
};
-static void parse_nit(const NIT * pnit, int max)
+static void parse_nit(const SI_NIT & nit, int max)
{
#if USE_CONSOLE
- for (const descriptor * pndesc = pnit->begin(); LPBYTE(pndesc)end(); pndesc=pndesc->next()) {
+ for (const descriptor * pndesc = nit.begin(); LPBYTE(pndesc)next()) {
if (pndesc->descriptor_tag == 0x40) {
char nom[256];
BYTE taille = pndesc->descriptor_length;
@@ -555,10 +555,10 @@
}
#endif // #if USE_CONSOLE
- const NIT2 * pnit2 = pnit->part2();
+ const SI_NIT_entries_hdr & nit_e = nit.entries_hdr();
- for (const NIT_entry * pnent = pnit2->begin();
- LPBYTE(pnent)end(); pnent=pnent->next()
+ for (const NIT_entry * pnent = nit_e.begin();
+ LPBYTE(pnent) < nit_e.end(); pnent=pnent->next()
) {
ChaineIDs chIDs;
@@ -596,9 +596,7 @@
DWORD _dwTimeout;
ISectionList * pSectionList;
MPEG2_FILTER filter;
-#if USE_CONSOLE
- DWORD dwTableName; // Utilisé seulement en debugging
-#endif // #if USE_CONSOLE
+ IF_DEBUG(FOURCC tableName;)
BYTE nextSection;
BYTE lastSection;
public:
@@ -606,15 +604,13 @@
DWORD length;
bool complete; // true si toute la table a été lue avec succès
//
- void Init(PID pid, TID tid, DWORD dwTimeout, DWORD dwTblName);
+ void Init(PID pid, TID tid, DWORD dwTimeout, FOURCC tblName);
bool GetNextSection();
};
-void Mpeg2SectionsHandler::Init(PID pid, TID tid, DWORD dwTimeout, DWORD dwTblName)
+void Mpeg2SectionsHandler::Init(PID pid, TID tid, DWORD dwTimeout, FOURCC tblName)
{
-#if USE_CONSOLE
- dwTableName = dwTblName;
-#endif // #if USE_CONSOLE
+ IF_DEBUG(tableName = tblName;)
pSectionList = NULL;
nextSection = 0;
lastSection = 0;
@@ -648,16 +644,16 @@
filter.SectionNumber = nextSection++;
hr = pMpeg2Data->GetSection(_pid, _tid, &filter, _dwTimeout, &pSectionList);
if (!SUCCEEDED(hr)) {
- myprintf(L"Pas eu la %S\n", (LPCSTR)&dwTableName);
+ myprintf(L"Pas eu la %S\n", (LPCSTR)&tableName);
return false;
}
hr = pSectionList->GetSectionData(0, &length, &data);
if (!SUCCEEDED(hr)) {
- myprintf(L"Pas eu les données de la %S\n", (LPCSTR)&dwTableName);
+ myprintf(L"Pas eu les données de la %S\n", (LPCSTR)&tableName);
return false;
}
- myprintf(L"Taille %S : %u\n", (LPCSTR)&dwTableName, length);
- lastSection = ((const TableHead *)data)->last_section_number;
+ myprintf(L"Taille %S : %u\n", (LPCSTR)&tableName, length);
+ lastSection = ((const SI_hdr *)data)->last_section_number;
return true;
}
@@ -680,9 +676,9 @@
return false;
// Choppe les noms des chaînes
- handler.Init(17, 66, 5000, 'TDS' /* inversé, c'est normal */);
+ handler.Init(17, 66, 5000, MAKEFOURCC('S','D','T',0));
while (handler.GetNextSection()) {
- parse_sdt((const SDT *)handler.data, handler.length, freq);
+ parse_sdt(*reinterpret_cast(handler.data), handler.length, freq);
if (*pStopping)
return false;
}
@@ -690,9 +686,9 @@
return false; // Pas reçu la SDT : inutile de continuer
// Choppe la PAT
- handler.Init(0, 0, 10000, 'TAP' /* inversé ... */);
+ handler.Init(0, 0, 10000, MAKEFOURCC('P','A','T',0));
while (handler.GetNextSection()) {
- parse_pat((const PAT *)handler.data, handler.length);
+ parse_pat(*reinterpret_cast(handler.data), handler.length);
if (*pStopping)
return false;
}
@@ -704,9 +700,9 @@
// Traiter les chaînes ajoutées depuis le début de l'exécution de cette fonction.
Chaine & canal = Canaux[i];
- handler.Init((PID)canal.pmt_pid, 2, 5000, 'TMP' /* inversé */);
+ handler.Init((PID)canal.pmt_pid, 2, 5000, MAKEFOURCC('P','M','T',0));
while (handler.GetNextSection()) {
- parse_pmt((const PMT *)handler.data, handler.length, canal/*, true*/);
+ parse_pmt(*reinterpret_cast(handler.data), handler.length, canal/*, true*/);
if (*pStopping)
return false;
}
@@ -716,9 +712,9 @@
if (!nit_chargee) { // sur un seul flux seulement, puisque tous les flux
// sont supposés avoir la même table
PostMessage(hwndDlg, WM_APP+1, 0, 0); // Pour déclencher affichage info "NIT"
- handler.Init(16, 64, 10000, 'TIN' /* inversé */);
+ handler.Init(16, 64, 10000, MAKEFOURCC('N','I','T',0));
while (handler.GetNextSection()) {
- parse_nit((const NIT *)handler.data, handler.length);
+ parse_nit(*reinterpret_cast(handler.data), handler.length);
if (*pStopping)
return false;
}
Modified: trunk/parse.h
===================================================================
--- trunk/parse.h 2008-01-03 21:31:07 UTC (rev 112)
+++ trunk/parse.h 2008-03-02 23:35:26 UTC (rev 113)
@@ -29,9 +29,9 @@
#include "channels.h"
-struct PMT;
+struct SI_PMT;
-void parse_pmt(const PMT * ppmt, int max, ChainePMT & pmt/*, bool debug*/);
+void parse_pmt(const SI_PMT & pmt, int max, ChainePMT & lpmt_e/*, bool debug*/);
bool tune(HWND hwndDlg, const Frequence & freq, bool * stopping);
Modified: trunk/pmtfilter.cpp
===================================================================
--- trunk/pmtfilter.cpp 2008-01-03 21:31:07 UTC (rev 112)
+++ trunk/pmtfilter.cpp 2008-03-02 23:35:26 UTC (rev 113)
@@ -50,14 +50,14 @@
static void verifie_pmt(unsigned char * p, int max)
{
ChainePMT & chaine = Canaux[ixChaineCourante];
- ChainePMT pmt;
+ ChainePMT lpmt_e;
- parse_pmt((const PMT *)p, max, pmt/*, false*/);
+ parse_pmt(*reinterpret_cast(p), max, lpmt_e/*, false*/);
- if (pmt != chaine) { // "operator !=" maintenant implémenté
+ if (lpmt_e != chaine) { // "operator !=" maintenant implémenté
myprintf(L"Le pmt a changé\n");
- chaine = pmt;
+ chaine = lpmt_e;
sauve_chaines();
Modified: trunk/record.h
===================================================================
--- trunk/record.h 2008-01-03 21:31:07 UTC (rev 112)
+++ trunk/record.h 2008-03-02 23:35:26 UTC (rev 113)
@@ -29,11 +29,6 @@
#include "recprog.h"
-// Constante matérialisant un temps "infini" lors des calculs de différence de temps :
-// (représentant en fait un peu moins de 25 jours, mais dans notre contexte ça ne
-// devrait pas poser de problèmes)
-#define DUREE_INFINIE long((unsigned long)-1 >> 1) // = 0x7fffffff, si 'long' est sur 32 bits
-
// 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,
// le timer est programmé sur cette valeur, et est donc de fait recalculé
Modified: trunk/recprog.cpp
===================================================================
--- trunk/recprog.cpp 2008-01-03 21:31:07 UTC (rev 112)
+++ trunk/recprog.cpp 2008-03-02 23:35:26 UTC (rev 113)
@@ -75,38 +75,6 @@
return -1;
}
-/**
- * Fonction qui retourne la différence time1 - time2, convertie en millisecondes.
- **/
-long DiffTime(SYSTEMTIME time1, SYSTEMTIME time2)
-{
- INT64 Utime1, Utime2;
- SystemTimeToFileTime(&time1, (LPFILETIME)&Utime1);
- SystemTimeToFileTime(&time2, (LPFILETIME)&Utime2);
-
- // Plafonner la différence à DUREE_INFINIE-1
- INT64 diff = (Utime1 - Utime2) / 10000;
-
- if (diff > DUREE_INFINIE-1)
- return DUREE_INFINIE-1;
- if (diff < -(DUREE_INFINIE-1))
- return -(DUREE_INFINIE-1);
-
- return long(diff);
-}
-
-/**
- * Fonction qui ajoute 'add' millisecondes au temps 'time.
- **/
-void AddTime(SYSTEMTIME & time, long add)
-{
- INT64 Utime;
-
- SystemTimeToFileTime(&time, LPFILETIME(&Utime));
- Utime += INT64(add)*10000;
- FileTimeToSystemTime(LPFILETIME(&Utime), &time);
-}
-
static INT_PTR CALLBACK PaswdDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_INITDIALOG:
Modified: trunk/recprog.h
===================================================================
--- trunk/recprog.h 2008-01-03 21:31:07 UTC (rev 112)
+++ trunk/recprog.h 2008-03-02 23:35:26 UTC (rev 113)
@@ -210,16 +210,6 @@
int trouve_prog_par_nom(LPCSTR nom);
/**
- * Fonction qui retourne la différence time1 - time2, convertie en millisecondes.
- **/
-long DiffTime(SYSTEMTIME time1, SYSTEMTIME time2);
-
-/**
- * Fonction qui ajoute 'add' millisecondes au temps 'time.
- **/
-void AddTime(SYSTEMTIME & time, long add);
-
-/**
* Remplissage d'une combo-box de méthodes d'enregistement
**/
void remplit_liste_methodes(HWND hCtl);
Added: trunk/utils.cpp
===================================================================
--- trunk/utils.cpp (rev 0)
+++ trunk/utils.cpp 2008-03-02 23:35:26 UTC (rev 113)
@@ -0,0 +1,120 @@
+/*
+ * utils.cpp
+ * Copyright (C) 2008
+ *
+ * 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.
+ */
+
+/********************************************************************************************
+ * UTILS (utils.h, utils.cpp) *
+ * *
+ * Ce module contient des définitions et structures utilitaires simples, et non *
+ * obligatoirement liées au programme principal. *
+ * *
+ * Les objets définis ici ne doivent faire référence qu'à des bibliothèques externes *
+ * standard du C, du C++ ou de Windows. *
+ * *
+ ********************************************************************************************/
+
+#include "utils.h"
+
+bool WindowPos::verifie()
+{
+ RECT rect;
+ //
+ SetRect(&rect, X, Y, X+L, Y+16);
+ if (
+ X==CW_USEDEFAULT ||
+ Y==CW_USEDEFAULT ||
+ L==CW_USEDEFAULT ||
+ H==CW_USEDEFAULT ||
+ MonitorFromRect(&rect, MONITOR_DEFAULTTONULL)==NULL
+ ) {
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Trouver la valeur binaire associée à une chaîne de caractères fournie,
+ * selon la table 'assocTable'. Si la chaîne ne se trouve pas dans la table,
+ * alors la valeur 'bydefault' est retournée.
+ **/
+DWORD str2dword(const AssocElement * assocTable, LPCWSTR lpStr, DWORD bydefault)
+{
+ while (assocTable->str != NULL && wcscmp(lpStr, assocTable->str) != 0)
+ assocTable++;
+
+ if (assocTable->str==NULL)
+ return bydefault;
+ return assocTable->bin;
+}
+
+/**
+ * Trouver la chaîne de caractères associée à une valeur binaire fournie,
+ * selon la table 'assocTable'. Si la valeur binaire ne se trouve pas dans la table,
+ * alors un pointeur sur une chaîne vide est retourné.
+ **/
+LPCWSTR dword2str(const AssocElement * assocTable, DWORD value)
+{
+ while (assocTable->str != NULL && assocTable->bin != value)
+ assocTable++;
+
+ LPCWSTR str = assocTable->str;
+
+ if (str==NULL)
+ str = L"??";
+ return str;
+}
+/**
+ * Fonction qui retourne la différence time1 - time2, convertie en millisecondes.
+ **/
+long DiffTime(SYSTEMTIME time1, SYSTEMTIME time2)
+{
+ INT64 Utime1, Utime2;
+ SystemTimeToFileTime(&time1, (LPFILETIME)&Utime1);
+ SystemTimeToFileTime(&time2, (LPFILETIME)&Utime2);
+
+ // Plafonner la différence à DUREE_INFINIE-1
+ INT64 diff = (Utime1 - Utime2) / 10000;
+
+ if (diff > DUREE_INFINIE-1)
+ return DUREE_INFINIE-1;
+ if (diff < -(DUREE_INFINIE-1))
+ return -(DUREE_INFINIE-1);
+
+ return long(diff);
+}
+
+/**
+ * Fonction qui ajoute 'add' millisecondes au temps 'time.
+ **/
+void AddTime(SYSTEMTIME & time, long add)
+{
+ INT64 Utime;
+
+ SystemTimeToFileTime(&time, LPFILETIME(&Utime));
+ Utime += INT64(add)*10000;
+ FileTimeToSystemTime(LPFILETIME(&Utime), &time);
+}
Added: trunk/utils.h
===================================================================
--- trunk/utils.h (rev 0)
+++ trunk/utils.h 2008-03-02 23:35:26 UTC (rev 113)
@@ -0,0 +1,111 @@
+/*
+ * utils.h
+ * Copyright (C) 2008
+ *
+ * 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.
+ */
+
+/********************************************************************************************
+ * UTILS (utils.h, utils.cpp) *
+ * *
+ * Ce module contient des définitions et structures utilitaires simples, et non *
+ * obligatoirement liées au programme principal. *
+ * *
+ * Les objets définis ici ne doivent faire référence qu'à des bibliothèques externes *
+ * standard du C, du C++ ou de Windows. *
+ * *
+ ********************************************************************************************/
+
+#pragma once
+
+#include
+
+// Conversions 'printf' entre CHAR ou WCHAR vers TCHAR
+#ifdef _UNICODE
+ #define T2A "S" // TCHAR vers CHAR
+ #define T2W L"s" // TCHAR vers WCHAR
+ #define A2T L"S" // CHAR vers TCHAR
+ #define W2T L"s" // WCHAR vers TCHAR
+#else
+ #define T2A "s" // TCHAR vers CHAR
+ #define T2W L"S" // TCHAR vers WCHAR
+ #define A2T "s" // CHAR vers TCHAR
+ #define W2T "S" // WCHAR vers TCHAR
+#endif
+
+// Structure pour la sauvegarde de la position des fenêtres :
+struct WindowPos {
+ long X;
+ long Y;
+ long L;
+ long H;
+ //
+ // Vérifie si cette valeur est visible sur un des moniteurs existants
+ bool verifie();
+
+ WindowPos() :
+ X(CW_USEDEFAULT),Y(CW_USEDEFAULT),
+ L(CW_USEDEFAULT),H(CW_USEDEFAULT)
+ {}
+};
+
+/**
+ * Élement de table d'association chaîne <--> valeur binaire.
+ * Cette structure est destinée à faire partie d'une table dont le dernier élément
+ * doit avoir ses deux valeurs à NULL et 0 respectivement.
+ **/
+struct AssocElement
+{
+ LPCWSTR str;
+ DWORD bin;
+};
+
+/**
+ * Trouver la valeur binaire associée à une chaîne de caractères fournie,
+ * selon la table 'assocTable'. Si la chaîne ne se trouve pas dans la table,
+ * alors la valeur 'bydefault' est retournée.
+ **/
+DWORD str2dword(const AssocElement * assocTable, LPCWSTR lpStr, DWORD bydefault);
+
+/**
+ * Trouver la chaîne de caractères associée à une valeur binaire fournie,
+ * selon la table 'assocTable'. Si la valeur binaire ne se trouve pas dans la table,
+ * alors un pointeur sur une chaîne vide est retourné.
+ **/
+LPCWSTR dword2str(const AssocElement * assocTable, DWORD value);
+
+// Constante matérialisant un temps "infini" lors des calculs de différence de temps :
+// (représentant en fait un peu moins de 25 jours, mais dans notre contexte ça ne
+// devrait pas poser de problèmes)
+#define DUREE_INFINIE long((unsigned long)-1 >> 1) // = 0x7fffffff, si 'long' est sur 32 bits
+
+/**
+ * Fonction qui retourne la différence time1 - time2, convertie en millisecondes.
+ **/
+long DiffTime(SYSTEMTIME time1, SYSTEMTIME time2);
+
+/**
+ * Fonction qui ajoute 'add' millisecondes au temps 'time.
+ **/
+void AddTime(SYSTEMTIME & time, long add);
From pouchintv-svn at baysse.fr Fri Mar 7 22:43:52 2008
From: pouchintv-svn at baysse.fr (pouchintv-svn at baysse.fr)
Date: Fri, 7 Mar 2008 22:43:52 +0100 (CET)
Subject: [Pouchintv-dev] [PouchinTVMod] gingko | r115 - trunk
Message-ID: <20080307214352.BC8BD5F5E6@mail.baysse.fr>
Author: gingko
Date: 2008-03-07 22:43:52 +0100 (Fri, 07 Mar 2008)
New Revision: 115
Modified:
trunk/mpeg2defs.h
trunk/parse.cpp
trunk/parse.h
trunk/pmtfilter.cpp
Log:
Int?\195?\169gration des nouvelles d?\195?\169finitions MPEG2 de 'mpeg2defs.h' et
'mpeg2defs.cpp' au syst?\195?\168me de recherche de cha?\195?\174nes (parse.cpp), ainsi
qu'au filtre PMT (pmtfilter.cpp).
Modified: trunk/mpeg2defs.h
===================================================================
--- trunk/mpeg2defs.h 2008-03-07 19:34:12 UTC (rev 114)
+++ trunk/mpeg2defs.h 2008-03-07 21:43:52 UTC (rev 115)
@@ -2378,7 +2378,7 @@
struct SI_PAT_entry
{
- UBE16 program_number;
+ UBE16 program_number; // devrait peut-être être renommé en 'service_id' ??
PID13 pid;
//
const SI_PAT_entry * next() const
Modified: trunk/parse.cpp
===================================================================
--- trunk/parse.cpp 2008-03-07 19:34:12 UTC (rev 114)
+++ trunk/parse.cpp 2008-03-07 21:43:52 UTC (rev 115)
@@ -29,6 +29,7 @@
#include "channels.h"
#include "graph.h"
#include "ini.h"
+#include "mpeg2defs.h"
std::vector chaineIDs;
@@ -46,537 +47,149 @@
}
}
-// Partie commune à toutes les tables :
-struct SI_hdr {
- BYTE table_id;
- BYTE section_length_hi;
- BYTE section_length_lo;
- BYTE tsid_lo;
- BYTE tsid_hi; // Ordre inversé ??
- BYTE versnum_and_next_indic;
- BYTE section_number;
- BYTE last_section_number;
- //
- // Méthodes d'extraction :
- WORD section_length() const
- {return ((section_length_hi & 0x0f)<<8) | section_length_lo;}
- WORD tsid() const
- {return (tsid_hi<<8) | tsid_lo;}
- BYTE version_number() const
- {return (versnum_and_next_indic & 0x3e)>>1;}
- bool current_next_indicator() const
- {return (versnum_and_next_indic & 0x01)!=0;}
- const LPBYTE end(int limit) const
- {return ((LPBYTE)this)+limit-sizeof(DWORD);}
-};
-
-struct MDescriptor {
- BYTE tag;
- BYTE length;
- //
- // Méthodes d'extraction :
- const LPBYTE begin() const
- {return LPBYTE(this+1);}
- const MDescriptor * next() const
- {return (const MDescriptor *)(begin()+length);}
- const LPBYTE end() const
- {return LPBYTE(this+1) + length;}
-};
-
-
-/* Program association section (PAT)
-
- Syntax No. of bits Offset
- ------------------------------------------------------
- program_association_section( ) {
- table_id 8 0
- section_syntax_indicator 1 1
- ‘0’ 1 1
- reserved 2 1
- section_length 12 1,2
- transport_stream_id 16 3,4
- reserved 2 5
- version_number 5 5
- current_next_indicator 1 5
- section_number 8 6
- last_section_number 8 7
- for (j=0;j< N;j++) { 8
- program_number 16 +0,+1
- reserved 3 +2
- if (program_number==’0’ ) {
- network_PID 13 +2,+3
- } else {
- program_map_PID 13 +2,+3
- }
- }
- CRC_32 32
- }
-*/
-struct SI_PAT_entry {
- BYTE program_number_hi;
- BYTE program_number_lo;
- BYTE program_map_pid_hi;
- BYTE program_map_pid_lo;
- //
- // Méthodes d'extraction :
- WORD program_number() const
- {return (program_number_hi<<8) | program_number_lo;}
- WORD pid() const
- {return ((program_map_pid_hi & 0x1f)<<8) | program_map_pid_lo;}
-};
-
-struct SI_PAT : public SI_hdr {
- //
- // Méthodes d'extraction :
- const SI_PAT_entry * begin() const
- {return (const SI_PAT_entry *)(this+1);}
-};
-
// PAT = Program Association Table
-static void parse_pat(const SI_PAT & pat, int max)
+static void parse_pat(const SI_PAT & pat)
{
- WORD tsid = pat.tsid();
+ WORD tsid = pat.tsid(true);
- for (const SI_PAT_entry * ppaent = pat.begin(); LPBYTE(ppaent)program_number();
- WORD pid = ppaent->pid();
+ for (streamScanner se(pat.entryRange()); !se; ++se) {
+ UINT16 service = se().program_number();
+ UINT16 pid = se().pid();
myprintf(L"Service : 0x%04x, PMT PID : 0x%04x\n", service, pid);
sauve_pmt(tsid, service, pid);
}
}
-/* Transport Stream program map section (PMT)
-
- Syntax No. of bits Offset
- ------------------------------------------------------
- TS_program_map_section( ) {
- table_id 8 0
- section_syntax_indicator 1 1
- ‘0’ 1 1
- reserved 2 1
- section_length 12 1,2
- program_number 16 3,4
- reserved 2 5
- version_number 5 5
- current_next_indicator 1 5
- section_number 8 6
- last_section number 8 7
- reserved 3 8
- PCR_PID 13 8,9
- reserved 4 10
- program_info_length 12 10,11
- for (i=0;inext()) {
- WORD pid = ppent->pid();
- BYTE stream_type = ppent->stream_type;
- bool private_stream = 0;
- const MDescriptor * ppdesc = ppent->begin();
+ for (streamScanner se(pmt.entryRange(bMicrosoft)); !se; ++se) {
+ UINT16 pid = se().pid();
+ StreamType stream_type = se().type();
+ bool private_stream = 0;
+ descrScanner sd(se().descrRange());
//if (debug)
// myprintf(L"type : %02X, pid : %i\n", stream_type, pid);
switch (stream_type) {
- case 0x01: //ISO_IEC_11172_2_VIDEO, MPEG-1 video streams
- case 0x02: //ISO_IEC_13818_2_VIDEO, MPEG-2 video streams
+ case st_MPEG_1_video: //ISO_IEC_11172_2_VIDEO, MPEG-1 video streams
+ case st_MPEG_2_video: //ISO_IEC_13818_2_VIDEO, MPEG-2 video streams
lpmt_e.video_pid=pid;
break;
- case 0x03: //ISO_IEC_11172_3_AUDIO, MPEG-1 audio streams
- case 0x04: //ISO_IEC_13818_3_AUDIO, MPEG-2 audio streams
+ case st_MPEG_1_audio: //ISO_IEC_11172_3_AUDIO, MPEG-1 audio streams
+ case st_MPEG_2_audio: //ISO_IEC_13818_3_AUDIO, MPEG-2 audio streams
lpmt_e.sons.ajoute(pid, 0);
break;
- case 0x06:
+ case st_PES_private:
private_stream=1;
break;
- case 0x1B: //H264
+ case st_MPEG_4_video: //H264
lpmt_e.mpeg4_pid=pid;
break;
}
if (private_stream) {
- for (; (LPBYTE)ppdescend(); ppdesc=ppdesc->next()) {
- if (ppdesc->tag == 0x6A)
+ for (; !sd; ++sd) {
+ if (sd().tag() == mdt_AC3_Audio)
lpmt_e.sons.ajoute(pid, 1);
}
if (lpmt_e.sons.tbl[lpmt_e.sons.nbr-1].pid != pid)
lpmt_e.autr.ajoute(pid);
- ppdesc = ppent->begin();
+ sd = se().descrRange(); // repartir du début
}
- for (; LPBYTE(ppdesc)end(); ppdesc=ppdesc->next()) {
- BYTE tag = ppdesc->tag;
- BYTE length = ppdesc->length;
+ for (sd = se().descrRange(); !sd; ++sd) {
+ MDescriptorTag tag = sd().tag();
+ UINT8 length = sd().length;
//if (debug)
// myprintf(L"sous_type : %02X, sous_taille : %i\n", tag, length);
- if (tag == 0x0A && length > 0) {
+ if (tag == mdt_ISO_639_Language && length > 0) {
une_piste & pmt_son = lpmt_e.sons.tbl[lpmt_e.sons.nbr-1];
- if (pmt_son.pid == pid) {
- memcpy(pmt_son.lang, ppdesc->begin(), length);
- // On écrit le \0 sur le caractère nul
- pmt_son.lang[length-1]='\0';
- }
+ if (pmt_son.pid == pid)
+ sd().as()().language_code.get(pmt_son.lang);
- // une_piste & pmt_autre = lpmt_e.autr.tbl[lpmt_e.autr.nbr-1];
+ //une_piste & pmt_autre = lpmt_e.autr.tbl[lpmt_e.autr.nbr-1];
- // if (pmt_autre.pid == pid) {
- // memcpy(pmt_autre.lang, ppdesc->begin(), length);
- // pmt_autre.lang[length]='\0';
- // }
+ //if (pmt_autre.pid == pid)
+ // sd().as()().language_code.get(pmt_autre.lang);
}
}
}
}
-/* Service description section (SDT)
-
- Syntax No. of bits Offset
- ------------------------------------------------------
- service_description_section() {
- table_id 8 0
- section_syntax_indicator 1 1
- reserved_future_use 1 1
- reserved 2 1
- section_length 12 1,2
- transport_stream_id 16 3,4
- reserved 2 5
- version_number 5 5
- current_next_indicator 1 5
- section_number 8 6
- last_section_number 8 7
- original_network_id 16 8,9
- reserved_future_use 8 10
- for(i=0;inext()) {
- Chaine canal;
- const SDT_descriptor * psdesc = psent->begin();
- const BYTE * pdata = psdesc->begin();
+ for (streamScanner se(sdt.entryRange(true)); !se; ++se) {
+ Chaine canal;
- pdata = psdesc->get_str(pdata, canal.groupe);
- pdata = psdesc->get_str(pdata, canal.nom);
- canal.canal_no=freq.canal_no;
- canal.frequence=freq.mhz;
- canal.ONID=onid;
- canal.TSID=tsid;
- canal.SID=psent->sid();
+ for (descrScanner sd(se().descrRange()); !sd; sd++) {
+ if (sd().tag()==mdt_Service) {
+ const MDescriptor_48 & d48 = sd().as();
- myprintf(L"Groupe : %S, Chaine : %S, SID : %i\n", canal.groupe, canal.nom, psent->sid());
+ d48.service_provider_name().get(canal.groupe);
+ d48.service_name().get(canal.nom);
+ canal.canal_no = freq.canal_no;
+ canal.frequence = freq.mhz;
+ canal.ONID = onid;
+ canal.TSID = tsid;
+ canal.SID = se().service_id();
- Canaux.push_back(canal);
+ myprintf(L"Groupe : %S, Chaine : %S, SID : %i\n", canal.groupe, canal.nom, se().service_id());
+
+ Canaux.push_back(canal);
+ break;
+ }
+ }
}
}
-/* Network Information section (NIT)
-
- Syntax No. of bits Offset
- ----------------------------------------------------------
- network_information_section() {
- table_id 8 0
- section_syntax_indicator 1 1
- reserved_future_use 1 1
- reserved 2 1
- section_length 12 1,2
- network_id 16 3,4
- reserved 2 5
- version_number 5 5
- current_next_indicator 1 5
- section_number 8 6
- last_section number 8 7
- reserved_future_use 4 8
- network_descriptors_length 12 8,9
- for(i=0;i(end());}
-};
-
-static void parse_nit(const SI_NIT & nit, int max)
+static void parse_nit(const SI_NIT & nit)
{
#if USE_CONSOLE
- for (const MDescriptor * pndesc = nit.begin(); LPBYTE(pndesc)next()) {
- if (pndesc->tag == 0x40) {
+ for (descrScanner sd(nit.descrRange()); !sd; ++sd) {
+ if (sd().tag() == mdt_Network_Name) {
char nom[256];
- BYTE taille = pndesc->length;
//
- memcpy(nom, pndesc->begin(), taille);
- nom[taille] = 0;
+ sd().as().get_network_name(nom);
myprintf(L"parse_nit: Nom réseau : %S\n", nom);
}
}
#endif // #if USE_CONSOLE
- const SI_NIT_entries_hdr & nit_e = nit.entries_hdr();
-
- for (const SI_NIT_entry * pnent = nit_e.begin();
- LPBYTE(pnent) < nit_e.end(); pnent=pnent->next()
- ) {
+ for (streamScanner se = nit.entries_hdr().entryRange(); !se; ++se) {
ChaineIDs chIDs;
- chIDs.TSID = pnent->tsid();
- chIDs.ONID = pnent->onid();
+ chIDs.TSID = se().tsid();
+ chIDs.ONID = se().onid();
- // myprintf(L"parse_nit: TSID=%i, ONID=%i, taille=%i\n", chIDs.TSID, chIDs.ONID, pnent->length());
+ // myprintf(L"parse_nit: TSID=%i, ONID=%i, taille=%i\n", chIDs.TSID, chIDs.ONID, se().length());
- for (const MDescriptor * ptdesc = pnent->begin();
- LPBYTE(ptdesc)end(); ptdesc=ptdesc->next()
- ) {
- // myprintf(L"parse_nit: type : %02X, taille : %i\n", ptdesc->tag, ptdesc->length);
+ for (descrScanner sed(se().descrRange()); !sed; ++sed) {
+ // myprintf(L"parse_nit: type : %02X, taille : %i\n", sed().tag, sed().length);
- if (ptdesc->tag == 0x83) {
- for (
- const MSubDescr_83 * plchent = (const MSubDescr_83 *)ptdesc->begin();
- LPBYTE(plchent)end(); plchent++
- ) {
- chIDs.SID = plchent->sid();
- chIDs.numero_nit = plchent->logical_channel_number();
+ if (sed().tag() == mdt_Logical_Channel) {
+ for (streamScanner seds(sed().as().subDescrRange()); !seds; ++seds) {
+ chIDs.SID = seds().service_id();
+ chIDs.numero_nit = seds().logical_channel_number();
//myprintf(L"parse_nit: ONID=%i, TSID=%i, SID=%i, numero=%i\n",
// chIDs.ONID, chIDs.TSID, chIDs.SID, chIDs.numeroChaine);
chaineIDs.push_back(chIDs);
@@ -676,7 +289,7 @@
// Choppe les noms des chaînes
handler.Init(17, 66, 5000, MAKEFOURCC('S','D','T',0));
while (handler.GetNextSection()) {
- parse_sdt(*reinterpret_cast(handler.data), handler.length, freq);
+ parse_sdt(*reinterpret_cast(handler.data), freq);
if (*pStopping)
return false;
}
@@ -686,7 +299,7 @@
// Choppe la PAT
handler.Init(0, 0, 10000, MAKEFOURCC('P','A','T',0));
while (handler.GetNextSection()) {
- parse_pat(*reinterpret_cast(handler.data), handler.length);
+ parse_pat(*reinterpret_cast(handler.data));
if (*pStopping)
return false;
}
@@ -700,7 +313,7 @@
handler.Init((PID)canal.pmt_pid, 2, 5000, MAKEFOURCC('P','M','T',0));
while (handler.GetNextSection()) {
- parse_pmt(*reinterpret_cast(handler.data), handler.length, canal/*, true*/);
+ parse_pmt(*reinterpret_cast(handler.data), true, canal/*, true*/);
if (*pStopping)
return false;
}
@@ -712,7 +325,7 @@
PostMessage(hwndDlg, WM_APP+1, 0, 0); // Pour déclencher affichage info "NIT"
handler.Init(16, 64, 10000, MAKEFOURCC('N','I','T',0));
while (handler.GetNextSection()) {
- parse_nit(*reinterpret_cast(handler.data), handler.length);
+ parse_nit(*reinterpret_cast(handler.data));
if (*pStopping)
return false;
}
Modified: trunk/parse.h
===================================================================
--- trunk/parse.h 2008-03-07 19:34:12 UTC (rev 114)
+++ trunk/parse.h 2008-03-07 21:43:52 UTC (rev 115)
@@ -29,9 +29,9 @@
#include "channels.h"
-struct SI_PMT;
+#include "mpeg2defs.h"
-void parse_pmt(const SI_PMT & pmt, int max, ChainePMT & lpmt_e/*, bool debug*/);
+void parse_pmt(const SI_PMT & pmt, bool bMicrosoft, ChainePMT & lpmt_e/*, bool debug*/);
bool tune(HWND hwndDlg, const Frequence & freq, bool * stopping);
Modified: trunk/pmtfilter.cpp
===================================================================
--- trunk/pmtfilter.cpp 2008-03-07 19:34:12 UTC (rev 114)
+++ trunk/pmtfilter.cpp 2008-03-07 21:43:52 UTC (rev 115)
@@ -47,42 +47,31 @@
myprintf(L"PMT filter detruit\n");
}
-static void verifie_pmt(unsigned char * p, int max)
+HRESULT CPMTFilter::DoRenderSample(IMediaSample *pMediaSample)
{
- ChainePMT & chaine = Canaux[ixChaineCourante];
- ChainePMT lpmt_e;
+ const SI_PMT * ppmt;
+ size_t taille = pMediaSample->GetActualDataLength();
- parse_pmt(*reinterpret_cast(p), max, lpmt_e/*, false*/);
+// myprintf(L"PMT DoRenderSample %i\n", taille);
+ pMediaSample->GetPointer((LPBYTE *)(&ppmt));
- if (lpmt_e != chaine) { // "operator !=" maintenant implémenté
- myprintf(L"Le pmt a changé\n");
+ if (ppmt->table_id()==si_PMT && taille >= ppmt->size() && ppmt->check_crc32()) {
+ ChainePMT & chaine = Canaux[ixChaineCourante];
+ ChainePMT lpmt_e;
- chaine = lpmt_e;
+ parse_pmt(*ppmt, false, lpmt_e/*, false*/);
- sauve_chaines();
+ if (lpmt_e != chaine) { // "operator !=" maintenant implémenté
+ myprintf(L"Le pmt a changé\n");
+ chaine = lpmt_e;
+ sauve_chaines();
- // dit de rezapper sur cette chaîne
- PostMessage(hMainWnd, WM_USER+1, 0, 0);
+ // dit de rezapper sur cette chaîne
+ PostMessage(hMainWnd, WM_USER+1, 0, 0);
+ }
}
-}
-
-HRESULT CPMTFilter::DoRenderSample(IMediaSample *pMediaSample)
-{
- BYTE * p;
- pMediaSample->GetPointer(&p);
-
- long taille = pMediaSample->GetActualDataLength();
-
-// myprintf(L"PMT DoRenderSample %i\n", taille);
-
- if (p[0] == 2 && check_crc32(p, taille))
- {
- verifie_pmt(p, taille);
- }
-
return S_OK;
-
}
HRESULT CPMTFilter::CheckMediaType(const CMediaType * pmt)
From pouchintv-svn at baysse.fr Sat Mar 8 20:06:31 2008
From: pouchintv-svn at baysse.fr (pouchintv-svn at baysse.fr)
Date: Sat, 8 Mar 2008 20:06:31 +0100 (CET)
Subject: [Pouchintv-dev] [PouchinTVMod] gingko | r116 - trunk
Message-ID: <20080308190631.24A235F4D2@mail.baysse.fr>
Author: gingko
Date: 2008-03-08 20:06:30 +0100 (Sat, 08 Mar 2008)
New Revision: 116
Added:
trunk/sbuffer.cpp
trunk/sbuffer.h
Modified:
trunk/Pouchin TV.vcproj
trunk/mpeg2defs.h
trunk/parse.cpp
trunk/utils.h
Log:
Modified: trunk/Pouchin TV.vcproj
===================================================================
--- trunk/Pouchin TV.vcproj 2008-03-07 21:43:52 UTC (rev 115)
+++ trunk/Pouchin TV.vcproj 2008-03-08 19:06:30 UTC (rev 116)
@@ -788,6 +788,10 @@
>
+
+
@@ -898,6 +902,10 @@
>
+
+
Modified: trunk/mpeg2defs.h
===================================================================
--- trunk/mpeg2defs.h 2008-03-07 21:43:52 UTC (rev 115)
+++ trunk/mpeg2defs.h 2008-03-08 19:06:30 UTC (rev 116)
@@ -1306,12 +1306,15 @@
UINT32 get_start_code() const
{return MAKELONG(MAKEWORD(start_code[2], start_code[1]), start_code[0]);}
- void set_start_code()
- {start_code[1] = start_code[0] = 0x00; start_code[2] = 0x01;}
bool isPS() const
{return get_start_code()==0x000001;}
template const T & as() const // Dérivation vers un type de descripteur spécifique
{return *reinterpret_cast(this);}
+
+ // Constructeur :
+ PS_hdr(UINT8 id) :
+ stream_id(id)
+ {start_code[1] = start_code[0] = 0x00; start_code[2] = 0x01;};
};
struct PS_hdr_wl : public PS_hdr // wl="With Length"
@@ -1326,6 +1329,11 @@
{return sizeof(*this) + hdr_length();}
PUINT8 next() const
{return PUINT8(this) + packet_size();}
+
+ // Constructeur :
+ PS_hdr_wl(UINT8 id) :
+ PS_hdr(id)
+ {hdr_length = 0;}
};
/*
@@ -1373,6 +1381,11 @@
{return PUINT8(this+1);}
PUINT8 end_of_packet() const
{return end_of_header()+stuffing_length();}
+
+ // Constructeur
+ PS_PackHeader() :
+ PS_hdr(sid_Pack_Header)
+ {}
};
#define PES_SB_BUFFERSCALE_FLAG 0x20
@@ -1474,6 +1487,11 @@
{return reinterpret_cast(this+1)[index];}
streamScanner entryRange() const
{return streamScanner(this+1, PUINT8(this+1) + hdr_length());}
+
+ // Constructeur
+ PS_SystemHeader() :
+ PS_hdr_wl(sid_System_Header)
+ {}
};
/*
@@ -1546,6 +1564,11 @@
{return *reinterpret_cast(PUINT8(this+1) + dloop_length());}
CRC_32 & crc32() const
{return *reinterpret_cast(next() - sizeof(CRC_32));}
+
+ // Constructeur :
+ PS_ProgramStreamMap() :
+ PS_hdr_wl(sid_Program_Stream_Map)
+ {}
};
/*
@@ -1796,6 +1819,13 @@
{return PUINT8(this)+header_size();}
PUINT8 beg_of_fields() const
{return PUINT8(this+1);}
+
+ // Constructeur copie :
+ PS_hdr_wd(const PS_hdr_wd & src) :
+ PS_hdr_wl(src.stream_id)
+ {
+ memcpy(this, &src, src.header_size());
+ }
};
// Sous-ensemble de la classe 'PS_data_unwrapper_full' :
Modified: trunk/parse.cpp
===================================================================
--- trunk/parse.cpp 2008-03-07 21:43:52 UTC (rev 115)
+++ trunk/parse.cpp 2008-03-08 19:06:30 UTC (rev 116)
@@ -36,28 +36,24 @@
// true une fois que la NIT a été entièrement récupérée (sur n'importe quel multiplex) :
bool nit_chargee = false;
-static void sauve_pmt(WORD tsid, WORD sid, WORD pid)
-{
- //myprintf(L"sauve_pid : tsid : %i, sid : %i, pid : %i\n", tsid, sid, pid);
-
- for (std::vector::iterator it = Canaux.begin(); it != Canaux.end(); it++) {
- if (it->TSID==tsid && it->SID==sid) {
- it->pmt_pid=(WORD)pid;
- }
- }
-}
-
// PAT = Program Association Table
static void parse_pat(const SI_PAT & pat)
{
WORD tsid = pat.tsid(true);
- for (streamScanner se(pat.entryRange()); !se; ++se) {
- UINT16 service = se().program_number();
- UINT16 pid = se().pid();
+ for (streamScanner se(pat.entryRange(true)); !se; ++se) {
+ UINT16 service_id = se().program_number();
- myprintf(L"Service : 0x%04x, PMT PID : 0x%04x\n", service, pid);
- sauve_pmt(tsid, service, pid);
+ if (service_id != 0) {
+ UINT16 pid = se().pid();
+
+ myprintf(L"Service : 0x%04x, PMT PID : 0x%04x\n", service_id, pid);
+ for (std::vector::iterator it = Canaux.begin(); it != Canaux.end(); it++) {
+ if (it->TSID==tsid && it->SID==service_id) {
+ it->pmt_pid=(WORD)pid;
+ }
+ }
+ }
}
}
@@ -73,7 +69,6 @@
for (streamScanner se(pmt.entryRange(bMicrosoft)); !se; ++se) {
UINT16 pid = se().pid();
StreamType stream_type = se().type();
- bool private_stream = 0;
descrScanner sd(se().descrRange());
//if (debug)
@@ -89,14 +84,6 @@
lpmt_e.sons.ajoute(pid, 0);
break;
case st_PES_private:
- private_stream=1;
- break;
- case st_MPEG_4_video: //H264
- lpmt_e.mpeg4_pid=pid;
- break;
- }
-
- if (private_stream) {
for (; !sd; ++sd) {
if (sd().tag() == mdt_AC3_Audio)
lpmt_e.sons.ajoute(pid, 1);
@@ -105,10 +92,14 @@
if (lpmt_e.sons.tbl[lpmt_e.sons.nbr-1].pid != pid)
lpmt_e.autr.ajoute(pid);
- sd = se().descrRange(); // repartir du début
+ sd = se().descrRange(); // repartir du début au prochain 'for'
+ break;
+ case st_MPEG_4_video: //H264
+ lpmt_e.mpeg4_pid=pid;
+ break;
}
- for (sd = se().descrRange(); !sd; ++sd) {
+ for (; !sd; ++sd) {
MDescriptorTag tag = sd().tag();
UINT8 length = sd().length;
Added: trunk/sbuffer.cpp
===================================================================
--- trunk/sbuffer.cpp (rev 0)
+++ trunk/sbuffer.cpp 2008-03-08 19:06:30 UTC (rev 116)
@@ -0,0 +1,72 @@
+/*
+ * sbuffer.cpp
+ * Copyright (C) 2008
+ *
+ * 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.
+ */
+
+/********************************************************************************************
+ * SBUFFER (sbuffer.h, sbuffer.cpp) *
+ * *
+ * Gestion d'un tampon de données à croissance automatique. *
+ * *
+ ********************************************************************************************/
+
+#include "sbuffer.h"
+
+void StreamBuffer::flush()
+{
+ if (data_size > 0 && size() >= data_size) {
+ if (!sent)
+ send();
+ else
+ extra_send();
+ sent = true;
+ data_size = 0;
+ }
+}
+
+void StreamBuffer::put_data(const UINT8 * ptr, size_t ptr_size, bool start)
+{
+ if (ptr_size > 0) {
+ if (start) {
+ flush();
+ sent = false;
+ }
+ size_t newIndex = data_size+ptr_size;
+
+ if (newIndex > buf_size) {
+ buf_size = ((newIndex/gran)+1)*gran;
+ resize(buf_size);
+ }
+ memcpy(&(*this)[data_size], ptr, ptr_size);
+ data_size = newIndex;
+ if (test())
+ flush();
+ }
+}
+
+StreamBuffer::~StreamBuffer()
+{
+}
Added: trunk/sbuffer.h
===================================================================
--- trunk/sbuffer.h (rev 0)
+++ trunk/sbuffer.h 2008-03-08 19:06:30 UTC (rev 116)
@@ -0,0 +1,86 @@
+/*
+ * sbuffer.h
+ * Copyright (C) 2008
+ *
+ * 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.
+ */
+
+/********************************************************************************************
+ * SBUFFER (sbuffer.h, sbuffer.cpp) *
+ * *
+ * Gestion d'un tampon de données à croissance automatique. *
+ * *
+ ********************************************************************************************/
+
+#pragma once
+
+#include
+#include
+
+/*
+ * Dérivation de la classe "vector" pour recevoir des données fragmentées et réassembler celles-ci,
+ * en utilisant un tampon dont la taille croît automatiquement en cas de dépassement de longueur.
+ * Afin d'éviter des réallocations mémoire continuelles, la taille du tampon ne se réduit jamais
+ * en cours d'utilisation. Il est simplement entièrement détruit avec le destructeur de l'objet.
+ */
+class StreamBuffer : public std::vector
+{
+ size_t gran; // granularité (valeur qui spécifie par multiples
+ // de combien la taille du tampon doit être augmentée)
+ size_t buf_size;
+ bool sent; // 'true' à partir du moment où "send" a été appelé (à cause d'un appel 'test'
+ // retournant 'true'), et jusqu'à la réception d'un appel "put" avec 'start=true'
+public:
+ size_t data_size;
+
+ StreamBuffer(size_t gr=0x200) :
+ gran(gr),
+ buf_size(0),
+ sent(false),
+ data_size(0)
+ {}
+
+ // Ajout de données :
+ void put_data(const UINT8 * ptr, size_t ptr_size, bool start=false);
+
+ // Envoi et vidange du tampon :
+ void flush();
+
+ PUINT8 data_ptr() const
+ {return const_cast(&front());};
+
+ // Envoi des données complétées :
+ virtual void send() = 0;
+
+ // Envoi de données "hors paquet" :
+ virtual void extra_send()
+ {} // données ignorées par défaut
+
+ // Vérification du tampon après ajout de données, pour savoir s'il est complet, en utilisant
+ // les données elles-mêmes :
+ virtual bool test() const
+ {return false;} // pas de vérification, par défaut
+
+ virtual ~StreamBuffer();
+};
Modified: trunk/utils.h
===================================================================
--- trunk/utils.h 2008-03-07 21:43:52 UTC (rev 115)
+++ trunk/utils.h 2008-03-08 19:06:30 UTC (rev 116)
@@ -109,3 +109,40 @@
* Fonction qui ajoute 'add' millisecondes au temps 'time.
**/
void AddTime(SYSTEMTIME & time, long add);
+
+/*
+ * TEMPLATE :
+ * Structure d'assistance à l'évaluation de la moyenne des N plus récentes valeurs de type T données :
+ */
+template struct MeanHelper {
+ unsigned short ix;
+ unsigned short s;
+ T t[N];
+
+ MeanHelper() :
+ ix(0),
+ s(0)
+ {}
+
+ T mean() const {
+ // Récupèration de la moyenne des N plus récentes valeurs :
+ int i;
+ T r = 0;
+
+ if (s==0)
+ return 0;
+ for (i=0; i= N)
+ ix = 0;
+ return s; // Le nombre de valeurs mémorisées est retourné
+ }
+};
From gingko_pouchintv at nospam.homelinux.org Sat Mar 8 20:16:20 2008
From: gingko_pouchintv at nospam.homelinux.org (Gingko)
Date: Sat, 8 Mar 2008 20:16:20 +0100
Subject: [Pouchintv-dev] [PouchinTVMod] gingko | r116 - trunk
References: <20080308190631.24A235F4D2@mail.baysse.fr>
Message-ID: <001301c88150$e44568e0$464da8c0@GILLES>
Désolé, la révision 116 est accidentellement partie sans mes commentaires,
et apparemment, je ne peux pas (ou bien je ne sais pas comment) rectifier
cela.
Voici ce que je voulais y mettre :
----------------------------------------------------------------------
Ajout d'une paire de fichiers "sbuffer.h" et "sbuffer.cpp", gestion
de tampon à croissance dynamique, dont l'utilité apparaîtra
très prochainement.
Quelques ajustements supplémentaires, notamment dans "parse.cpp".
----------------------------------------------------------------------
Gingko
From pouchintv-svn at baysse.fr Fri Mar 7 20:34:12 2008
From: pouchintv-svn at baysse.fr (pouchintv-svn at baysse.fr)
Date: Fri, 7 Mar 2008 20:34:12 +0100 (CET)
Subject: [Pouchintv-dev] [PouchinTVMod] gingko | r114 - trunk
Message-ID: <20080307193413.0B0445F5E6@mail.baysse.fr>
Author: gingko
Date: 2008-03-07 20:34:12 +0100 (Fri, 07 Mar 2008)
New Revision: 114
Added:
trunk/mpeg2defs.cpp
trunk/mpeg2defs.h
Modified:
trunk/Pouchin TV.vcproj
trunk/parse.cpp
Log:
Cr?\195?\169ation d'un fichier global de d?\195?\169clarations 'mpeg2defs.h' pour toutes
les structures MPEG2 utilis?\195?\169es dans le programme.
Un fichier 'mpeg2defs.cpp' lui est associ?\195?\169, contenant quelques fonctions
d'extraction ?\195?\169l?\195?\169mentaires.
Tous les fichiers r?\195?\169f?\195?\169ren?\195?\167ant des structures MPEG2 vont ensuite ?\195?\170tre
ajust?\195?\169s pour faire usage de ces nouvelles d?\195?\169finitions, qui
deviendront donc une r?\195?\169f?\195?\169rence commune.
Par ailleurs, quelques variables et structures sont encore renomm?\195?\169s,
oublis de la livraison pr?\195?\169c?\195?\169dente.
Modified: trunk/Pouchin TV.vcproj
===================================================================
--- trunk/Pouchin TV.vcproj 2008-03-02 23:35:26 UTC (rev 113)
+++ trunk/Pouchin TV.vcproj 2008-03-07 19:34:12 UTC (rev 114)
@@ -764,6 +764,10 @@
>
+
+
@@ -866,6 +870,10 @@
>
+
+
Added: trunk/mpeg2defs.cpp
===================================================================
--- trunk/mpeg2defs.cpp (rev 0)
+++ trunk/mpeg2defs.cpp 2008-03-07 19:34:12 UTC (rev 114)
@@ -0,0 +1,214 @@
+/*
+ * mpeg2defs.cpp
+ * Copyright (C) 2008
+ *
+ * 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.
+ */
+
+/********************************************************************************************
+ * MPEG2DEFS (mpeg2defs.h, mpeg2defs.cpp) *
+ * *
+ * Ensemble de définitions, structures et méthodes pour extraire le contenu des flux *
+ * MPEG2 - PS (Program Stream) et PS (Transport Stream). *
+ * *
+ ********************************************************************************************/
+
+#include
+#include
+#include "mpeg2defs.h"
+
+/*
+ * Récupération d'une chaîne de caractères à partir d'un pointeur sur début et d'une longueur.
+ * La chaîne source n'est PAS (nécessairement) terminée par zéro.
+ * Version pour adresse de destination type LPSTR (caractères 8 bits) :
+ * Si un caractère d'encodage est présent au début de la chaîne (code 0x01 à 0x1f), celui-ci
+ * est éliminé, et il est retourné par la fonction (qui autrement retourne 0).
+ * Aucune conversion n'est cependant effectuée en relation avec ce code.
+ */
+UINT get_raw_str(LPCSTR src, UINT siz, LPSTR dst, UINT bufsize)
+{
+ UINT ixcp = 0;
+
+ if (siz>=bufsize)
+ siz=UINT(bufsize-1);
+ if (siz > 0 && *src < 0x20) {
+ ixcp = *src++;
+ --siz;
+ }
+ memcpy(dst, src, siz);
+ dst[siz] = 0;
+ return ixcp;
+}
+
+/*
+ * Récupération d'une chaîne de caractères à partir d'un pointeur sur début et d'une longueur.
+ * La chaîne source n'est PAS (nécessairement) terminée par zéro.
+ * Version pour adresse de destination type LPWSTR (caractères 16 bits) :
+ * Si un caractère d'encodage est présent au début de la chaîne (code 0x01 à 0x1f), celui-ci
+ * est éliminé, et il est retourné par la fonction (qui autrement retourne 0).
+ * De plus, dans ce dernier cas, il est tenté, dans la mesure du possible, d'utiliser ce code
+ * pour convertir la chaîne de caractères en chaîne Unicode.
+ * Les codes de contrôle éventuels (0x80 à 0x9f) sont convertis en codes de 0xe080 à 0xe09f.
+ * Si au moins un code de ce type est présent, la valeur 0x100 est ajoutée au code de retour.
+ */
+UINT get_raw_str(LPCSTR src, UINT siz, LPWSTR dst, UINT bufsize)
+{
+ static const UINT16 codepages[0x20] = {
+ 28591, // 00 - ISO 8859-1 Latin I
+ 28595, // 01 - ISO 8859-5 Cyrillic
+ 28596, // 02 - ISO 8859-6 Arabic
+ 28597, // 03 - ISO 8859-7 Greek
+ 28598, // 04 - ISO 8859-8 Hebrew
+ 28599, // 05 - ISO 8859-9 Latin 5
+ 28591, // 06 - ??? - ISO/IEC 8859-10 - Latin alphabet No. 6
+ 28591, // 07 - ??? - ISO/IEC 8859-11 - Latin/Thai (draft only)
+ 28591, // 08 - ??? - ISO/IEC 8859-12 - possibly reserved for Indian
+ 28591, // 09 - ??? - ISO/IEC 8859-13 - Latin alphabet No. 7
+ 28591, // 0a - ??? - ISO/IEC 8859-14 - Latin alphabet No. 8 (Celtic)
+ 28605, // 0b - ISO 8859-15 Latin 9
+ 28591, // 0c - réservé
+ 28591, // 0d - réservé
+ 28591, // 0e - réservé
+ 28591, // 0f - réservé
+ // Les valeurs 0x10 à 0x14 encodent pour des choses plus complexes à résoudre plus tard
+ // (si jamais un jour on diffuse notre code dans les pays asiatiques ... :-) )
+ 28591, 28591, 28591, 28591, 28591, 28591, 28591, 28591,
+ 28591, 28591, 28591, 28591, 28591, 28591, 28591, 28591
+ };
+
+ UINT ixcp = 0;
+
+ if (siz>=bufsize)
+ siz=UINT(bufsize-1);
+ if (siz > 0 && *src < 0x20) {
+ ixcp = *src++;
+ --siz;
+ }
+
+ UINT cp = codepages[ixcp];
+ UINT sofs = 0;
+ UINT8 ch;
+
+ for (UINT i=0; i= 0x80 && ch <= 0x9f) {
+ if (i>sofs) {
+ UINT dsiz = MultiByteToWideChar(cp, MB_PRECOMPOSED, src+sofs, int(i-sofs), dst, bufsize);
+
+ dst += dsiz;
+ bufsize -= dsiz;
+ }
+ if (bufsize > 1) {
+ *dst++ = 0xe000 + ch;
+ --bufsize;
+ }
+ sofs = i+1;
+ ixcp |= 0x100;
+ }
+ }
+ if (siz>sofs)
+ dst += MultiByteToWideChar(cp, MB_PRECOMPOSED, src+sofs, int(siz-sofs), dst, bufsize);
+ *dst = 0;
+ return ixcp;
+}
+
+/*
+ * Déballage de tous les champs "data" optionnels du paquet 'hdr':
+ * La structure est chargée avec des pointeurs vers tous les champs
+ * existants, ou des valeurs NULL pour tous les champs inexistants.
+ * Le pointeur 'p_next' pointe l'espace encore libre qui suit, lequel correspond
+ * à des octets de remplissage optionnels suivis des données du paquet.
+ */
+PS_data_unwrapper_full::PS_data_unwrapper_full(const PS_hdr_wd & hdr) :
+ PS_data_unwrapper_base(hdr),
+ p_rate(NULL),
+ p_trick(NULL),
+ p_add_copy_info(NULL),
+ p_prev_crc(NULL),
+ p_ext1(NULL),
+ p_priv_data(NULL),
+ p_pack(NULL),
+ p_seqcount(NULL),
+ p_stdbuf(NULL),
+ p_ext2(NULL)
+{
+ PUINT8 p_nxt = p_next;
+ UINT8 flags = hdr.flags;
+
+ if (flags & PES_ES_RATE_FLAG)
+ get_and_skip(p_nxt, p_rate);
+ if (flags & PES_DSM_TRICK_MODE_FLAG)
+ get_and_skip(p_nxt, p_trick);
+ if (flags & PES_ADDITIONAL_COPY_INFO_FLAG)
+ get_and_skip(p_nxt, p_add_copy_info);
+ if (flags & PES_CRC_FLAG)
+ get_and_skip(p_nxt, p_prev_crc);
+ if (flags & PES_EXTENSION_FLAG) {
+ get_and_skip(p_nxt, p_ext1);
+ flags = p_ext1->flags;
+ if (flags & PES_PRIVATE_DATA_FLAG)
+ get_and_skip(p_nxt, p_priv_data);
+ if (flags & PES_PACK_HEADER_FIELD_FLAG)
+ get_and_skip(p_nxt, p_pack);
+ if (flags & PES_PROG_PACKET_SEQ_COUNT_FLAG)
+ get_and_skip(p_nxt, p_seqcount);
+ if (flags & PES_P_STD_BUFFER_FLAG)
+ get_and_skip(p_nxt, p_stdbuf);
+ if (flags & PES_EXTENSION_FLAG_2)
+ get_and_skip(p_nxt, p_ext2);
+ }
+ p_next = p_nxt;
+}
+
+TS_AF_unwrapper_full::TS_AF_unwrapper_full(const TS_AF_hdr & af) :
+ TS_AF_unwrapper_base(af),
+ p_splicing_point(NULL),
+ p_priv_data(NULL),
+ p_ext(NULL),
+ p_ltw(NULL),
+ p_piecewise_rate(NULL),
+ p_seamless_splice(NULL)
+{
+ PUINT8 p_nxt = p_next;
+ UINT8 flags = af.get_flags();
+
+ //memset(PUINT8(&p_splicing_point), 0,
+ // sizeof(TS_AF_unwrapper_full)-offsetof(TS_AF_unwrapper_full, p_splicing_point));
+
+ if (flags & AF_SPLICEPT_FLAG)
+ get_and_skip(p_nxt, p_splicing_point);
+ if (flags & AF_PRIV_DATA_FLAG)
+ get_and_skip(p_nxt, p_priv_data);
+ if (flags & AF_EXTENSION_FLAG) {
+ get_and_skip(p_nxt, p_ext);
+ flags = p_ext->flags;
+
+ if (flags & AF_LTW_FLAG)
+ get_and_skip(p_nxt, p_ltw);
+ if (flags & AF_PW_RATE_FLAG)
+ get_and_skip(p_nxt, p_piecewise_rate);
+ if (flags & AF_SLSPLICE_FLAG)
+ get_and_skip(p_nxt, p_seamless_splice);
+ }
+ p_next = p_nxt;
+}
Added: trunk/mpeg2defs.h
===================================================================
--- trunk/mpeg2defs.h (rev 0)
+++ trunk/mpeg2defs.h 2008-03-07 19:34:12 UTC (rev 114)
@@ -0,0 +1,2743 @@
+/*
+ * mpeg2defs.h
+ * Copyright (C) 2008
+ *
+ * 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.
+ */
+
+/********************************************************************************************
+ * MPEG2DEFS (mpeg2defs.h, mpeg2defs.cpp) *
+ * *
+ * Ensemble de définitions, structures et méthodes pour extraire le contenu des flux *
+ * MPEG2 - PS (Program Stream) et PS (Transport Stream). *
+ * *
+ ********************************************************************************************/
+
+#pragma once
+
+#include
+#include
+#include
+#include "crc32.h"
+
+#pragma warning(disable:4512) // warning C4512: assignment operator could not be generated
+
+/*#######################################################################################
+ # ################################################################################### #
+ # # # #
+ # # DÉFINITIONS DES STRUCTURES DE DONNÉES CONTENUES # #
+ # # DANS LES FICHIERS ET FLOTS MPEG2 # #
+ # # # #
+ # ################################################################################### #
+ #######################################################################################*/
+
+/*
+ * Classe d'assistance pour parcourir séquentiellement une suite d'enregistrements
+ * se succédant directement, dans un intervalle entre deux adresses mémoire définies,
+ * mais dont les longueurs sont inégales (chaque objet de type T doit implémenter
+ * un membre "next()" qui retourne un pointeur sur l'objet de type T qui le suit immédiatement).
+ * La fin de la liste est atteinte lorsque l'adresse 'pend' est atteinte ; on s'attend normalement
+ * à ce que le dernier objet se termine exactement à l'adresse de fin.
+ */
+template struct streamScanner
+{
+ const T * pbeg;
+ const T * pend;
+
+ streamScanner(const void * pb, const void * pe) :
+ pbeg(reinterpret_cast(pb)),
+ pend(reinterpret_cast(pe))
+ {}
+
+ const T & operator ++ () {pbeg = pbeg->next(); return *pbeg;}
+ const T & operator ++ (int) {const T * res = pbeg; pbeg = pbeg->next(); return *res;}
+ bool operator ! () const {return pbeg < pend;}
+ operator const T & () const {return *pbeg;}
+ operator const T * () const {return pbeg;}
+ const T & operator () () const {return *pbeg;};
+};
+
+template UINT8 unwrap_sequence(streamScanner limits, const T * tbl[])
+{
+ UINT8 count = 0;
+
+ for (;!limits; ++limits)
+ tbl[count++] = limits.pbeg;
+ tbl[count] = limits.pbeg;
+ return count;
+}
+
+template void get_and_skip(PUINT8 & p_next, T * & p_res)
+{
+ p_res = reinterpret_cast(p_next);
+ p_next = p_res->next();
+}
+
+struct UBE16
+{
+ UINT8 hi;
+ UINT8 lo;
+
+ operator UINT16() const
+ {return hi<<8 | lo;}
+ UINT16 operator () () const
+ {return UINT16(*this);}
+ UBE16 & operator = (UINT16 val)
+ {hi = UINT8(val>>8); lo=UINT8(val); return *this;};
+ PUINT8 next() const
+ {return PUINT8(this+1);}
+};
+
+struct UBE32
+{
+ UBE16 hi;
+ UBE16 lo;
+
+ operator UINT32() const
+ {return hi()<<16 | lo();}
+ UINT32 operator () () const
+ {return UINT32(*this);}
+ UBE32 & operator = (UINT32 val)
+ {hi = UINT16(val>>16); lo=UINT16(val); return *this;};
+ PUINT8 next() const
+ {return PUINT8(this+1);}
+};
+
+template struct UBE : public UBE16
+{
+ UINT16 operator () () const
+ {return UBE16::operator ()() & ((1< & operator = (UINT16 val)
+ {hi = UINT8(val>>8) | flags(); lo=UINT8(val); return *this;}
+};
+
+typedef UBE<12> LEN12; // Longueur de champ sur 12 bits
+typedef UBE<13> PID13; // PID sur 13 bits
+typedef UBE16 CRC_16;
+typedef UBE32 CRC_32;
+
+struct UINT8uw {
+ UINT8 b;
+
+ UINT8 operator()() const
+ {return b;}
+ PUINT8 next() const
+ {return PUINT8(this+1);}
+};
+
+/****************************************************************************************
+ * Structures de référence d'horloge *
+ ****************************************************************************************/
+
+/*
+ Les références d'horloge sont constituées d'échantillons d'un compteur piloté à 27 MHz
+ (donc s'incrémentant de 27000000 unités toutes les secondes).
+
+ Les échantillons sont divisés par 300, représentant donc un compteur piloté à 90 kHz,
+ et sauvegardés dans un champ de 33 bits représentant les valeurs de 0 à 8589934591,
+ soit environ 95443 secondes (1 jour, 2 heures, 30 minutes, 43 secondes).
+ Le reste de la division est éventuellement conservé dans un camp de 9 bits dénommé "ext".
+*/
+
+/*
+ Description du SCR (System Reference Clock) utilisé dans le Pack Header
+ en mode PS (Program Stream) :
+
+ Répartition des bits dans les 6 octets du SCR :
+ [référence] [ext]
+ 3 33222222 22221111 11111100 00000000 0 00000000
+ 2 10987654 32109876 54321098 76543210 8 76543210
+ a bbbbbbbb cccccccc dddddddd eeeeeeee x yyyyyyyy
+
+ [0] [1] [2] [3] [4] [5]
+ 44444444 33333333 33222222 22221111 11111100 00000000
+ 76543210 98765432 10987654 32109876 54321098 76543210
+ SCR: 01abb1bb bbbbcccc ccccd1dd dddddeee eeeee1xy yyyyyyy1
+*/
+struct PS_D_SCR
+{
+ UINT8 b[6];
+
+ PS_D_SCR & set(UINT64 val90k, UINT16 ext=0) {
+ UINT32 lo = UINT32(val90k);
+
+ // Note : vérifier que les 2 bits de poids fort de b[0] sont égaux à 01 dans tous
+ // les enregistrements contenant PS_D_SCR
+ b[0] = UINT8(val90k >> 27 & 0x38) | UINT8(lo >> 28 & 0x03) | 0x04 | 0x40;
+ b[1] = UINT8(lo >> 20);
+ b[2] = UINT8(lo >> 12 & 0xf8) | UINT8(lo >> 13 & 0x03) | 0x04;
+ b[3] = UINT8(lo >> 5);
+ b[4] = UINT8(lo << 3) | UINT8(ext >> 7 & 0x03) | 0x04;
+ b[5] = UINT8(ext << 1) | 0x01;
+ return *this;
+ }
+
+ UINT64 get90k() const {
+ UINT32 lo =
+ (b[0] & 0x03) << 28 |
+ b[1] << 20 |
+ (b[2] & 0xf8) << 12 |
+ (b[2] & 0x03) << 13 |
+ b[3] << 5 |
+ (b[4] & 0xf8) >> 3;
+
+ return UINT64(b[0] & 0x38)<<27 | UINT64(lo);
+ }
+
+ UINT16 getExt() const
+ {return (b[4]&0x03)<<7 | b[5]>>1;}
+ PS_D_SCR & operator = (UINT64 val27M)
+ {return set(val27M/300, UINT16(val27M%300));}
+ UINT64 get27M() const
+ {return get90k()*300 + getExt();}
+ operator UINT64() const
+ {return get90k()*300 + getExt();}
+ PUINT8 next() const
+ {return PUINT8(this+1);}
+};
+
+/*
+ Description du Time Stamp utilisé, soit en tant que Presentation Time Stamp (PTS),
+ soit en tant que Decoding Time Stamp (DTS), dans l'extension optionnelle des
+ packets PES en mode PS (Program Stream) :
+
+ Répartition des bits dans les 5 octets du PTS ou du DTS :
+ [time stamp]
+ 3 33222222 22221111 11111100 00000000 xx = 01 (DTS)
+ 2 10987654 32109876 54321098 76543210 10 (PTS sans DTS)
+ a bbbbbbbb cccccccc dddddddd eeeeeeee 11 (PTS avec DTS)
+
+ [0] [1] [2] [3] [4]
+ 33333333 33222222 22221111 11111100 00000000
+ 98765432 10987654 32109876 54321098 76543210
+ SCR: 00xxabb1 bbbbbbcc ccccccd1 ddddddde eeeeeee1
+*/
+struct PS_D_TimeStamp
+{
+ UINT8 b[5];
+
+ PS_D_TimeStamp & set(UINT64 val90k) {
+ UINT32 lo = UINT32(val90k);
+
+ b[0] = UINT8(val90k >> 29 & 0x0e) | b[0] & 0x30 | 0x01;
+ b[1] = UINT8(lo >> 22);
+ b[2] = UINT8(lo >> 14) | 0x01;
+ b[3] = UINT8(lo >> 7);
+ b[4] = UINT8(lo << 1) | 0x01;
+ return *this;
+ }
+
+ UINT64 get90k() const {
+ UINT32 lo =
+ b[1] << 22 |
+ (b[2] & 0xfe) << 14 |
+ b[3] << 7 |
+ b[4] >> 1;
+
+ return UINT64(b[0] & 0x0e) << 29 | UINT64(lo);
+ }
+
+ PS_D_TimeStamp & operator = (UINT64 val27M)
+ {return set(val27M/300);}
+ UINT64 get27M() const
+ {return get90k()*300;}
+ operator UINT64() const
+ {return get90k()*300;}
+ PUINT8 next() const
+ {return PUINT8(this+1);}
+};
+
+typedef PS_D_TimeStamp MPEG_DTS;
+
+/*
+ Description du PCR (Program Reference Clock) utilisé dans le champ
+ d'adaptation (Adaptation Field) en mode TS (Transport Stream) :
+
+ Répartition des bits dans les 6 octets du PCR :
+ [référence] [ext]
+ 3 33222222 22221111 11111100 00000000 0 00000000
+ 2 10987654 32109876 54321098 76543210 8 76543210
+ a bbbbbbbb cccccccc dddddddd eeeeeeee x yyyyyyyy
+
+ [0] [1] [2] [3] [4] [5]
+ 44444444 33333333 33222222 22221111 11111100 00000000
+ 76543210 98765432 10987654 32109876 54321098 76543210
+ SCR: abbbbbbb bccccccc cddddddd deeeeeee e------x yyyyyyyy
+*/
+
+struct TS_PCR
+{
+ UINT8 b[6];
+
+ TS_PCR & set(UINT64 val90k, UINT16 ext=0) {
+ UINT32 lo = UINT32(val90k);
+
+ b[0] = UINT8(val90k >> 25);
+ b[1] = UINT8(lo >> 17);
+ b[2] = UINT8(lo >> 9);
+ b[3] = UINT8(lo >> 1);
+ b[4] = UINT8(lo << 7) | UINT8(ext >> 8);
+ b[5] = UINT8(ext);
+ return *this;
+ }
+
+ UINT64 get90k() const {
+ UINT8 hi =
+ b[0] >> 7;
+ UINT32 lo =
+ b[0] << 25 |
+ b[1] << 17 |
+ b[2] << 9 |
+ b[3] << 1 |
+ b[4] >> 7;
+
+ return UINT64(lo) | UINT64(hi)<<32;
+ }
+
+ UINT16 getExt() const
+ {return MAKEWORD(b[5], b[4]) & 0x1ff;}
+ TS_PCR & operator = (UINT64 val27M)
+ {return set(val27M/300, UINT16(val27M%300));}
+ UINT64 get27M() const
+ {return get90k()*300 + getExt();}
+ operator UINT64() const
+ {return get90k()*300 + getExt();}
+ PUINT8 next() const
+ {return PUINT8(this+1);}
+};
+
+/*
+ Correspondance des bits entre les 6 octets du PCR et les 6 octets du SCR du pack header :
+ [0] [1] [2] [3] [4] [5]
+ 33322222 22222111 11111110 00000000 0 0 00000000
+ 21098765 43210987 65432109 87654321 0 8 76543210
+ PCR: aaaaaaaa bbbbbbbb cccccccc dddddddd e------x yyyyyyyy
+ SCR: 01aaa1aa aaabbbbb bbbcc1cc ccccdddd dddde1xy yyyyyyy1
+*/
+
+/****************************************************************************************/
+
+/*
+ Répartition des bits dans les 3 octets du mux rate :
+ [rate]
+ 221111 11111100 00000000
+ 109876 54321098 76543210
+ aaaaaa bbbbbbbb cccccccc
+
+ [0] [1] [2]
+ 22221111 11111100 00000000
+ 32109876 54321098 76543210
+ mux rate: aaaaaabb bbbbbbcc cccccc11
+*/
+struct PS_PH_mux_rate
+{
+ UINT8 b[3];
+
+ PS_PH_mux_rate & operator = (UINT32 rate) {
+ b[0] = UINT8(rate >> 14);
+ b[1] = UINT8(rate >> 6);
+ b[2] = UINT8(rate << 2) | 0x03;
+ return *this;
+ }
+ operator UINT32() const
+ {return MAKELONG(MAKEWORD(b[2], b[1]), b[0] & 0x3f) >> 2;}
+ PUINT8 next() const
+ {return PUINT8(this+1);}
+};
+
+/****************************************************************************************/
+
+/*
+ Répartition des bits dans les 3 octets du mux rate (PES extension) :
+ [rate]
+ 221111 11111100 00000000
+ 109876 54321098 76543210
+ aaaaaa bbbbbbbb cccccccc
+
+ [0] [1] [2]
+ 22221111 11111100 00000000
+ 32109876 54321098 76543210
+ mux rate: 1aaaaaab bbbbbbbc ccccccc1
+*/
+struct PS_D_mux_rate
+{
+ UINT8 b[3];
+
+ PS_D_mux_rate & operator = (UINT32 rate) {
+ b[0] = UINT8(rate >> 15) | 0x80;
+ b[1] = UINT8(rate >> 7);
+ b[2] = UINT8(rate << 1) | 0x01;
+ return *this;
+ }
+ operator UINT32() const
+ {return MAKELONG(MAKEWORD(b[2], b[1]), b[0] & 0x7f) >> 1;}
+ PUINT8 next() const
+ {return PUINT8(this+1);}
+};
+
+/****************************************************************************************
+ * DESCRIPTOR *
+ ****************************************************************************************/
+/*
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ descriptor(){
+ descriptor_tag 8 +0
+ descriptor_length 8 +1
+ for (i=0;i
+ inline UINT get_raw_str(LPCSTR src, UINT siz, T (&dst)[S])
+{
+ return get_raw_str(src, siz, dst, S);
+}
+
+struct MDescriptor
+{
+ UINT8 _tag; // enum MDescriptorTag
+ UINT8 length;
+
+ MDescriptorTag tag() const
+ {return static_cast(_tag);}
+ MDescriptor * next() const
+ {return reinterpret_cast(PUINT8(this+1) + length);}
+ template const T & as() const // Dérivation vers un type de descripteur spécifique
+ {return *reinterpret_cast(this);}
+};
+
+// Modèle pour les descripteurs contenant des suites répétitives :
+template struct MDescriptor_list : public MDescriptor
+{
+ const T & operator () () const
+ {return *reinterpret_cast(this+1);}
+ streamScanner subDescrRange() const
+ {return streamScanner(this+1, PUINT8(this+1) + length);}
+};
+
+// Sous-descripteur générique pour les chaînes de caractères
+// au format longueur + chaîne (style PASCAL) :
+struct MSubDescr_str
+{
+ UINT8 strlen;
+
+ template UINT get(T dst, UINT bufsize) const
+ {return get_raw_str(LPCSTR(this+1), strlen, dst, bufsize);}
+ template UINT get(T (&dst)[S]) const
+ {return get(dst, S);}
+
+ const MSubDescr_str * next() const
+ {return reinterpret_cast(this+1+strlen);}
+};
+
+// Instantiation qui revient souvent :
+typedef streamScanner descrScanner;
+
+/* ISO 639 Registration descriptor tag 0x05
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ registration_descriptor() {
+ descriptor_tag 8 0
+ descriptor_length 8 1
+ format_identifier 32 2..5
+ for (i=0; i subDescrRange() const
+ {return streamScanner(this+1, PUINT8(this+1) + length);}
+};
+
+/* ISO 639 Language Descriptor (PMT) tag 0x0a
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ ISO_639_language_descriptor() {
+ descriptor_tag 8 0
+ descriptor_length 8 1
+ for (i=0; i MDescriptor_0a; // tag = mdt_ISO_639_Language
+
+/* Network Name (NIT) tag 0x40
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ network_name_descriptor(){
+ descriptor_tag 8 0
+ descriptor_length 8 1
+ for (i=0;i UINT get_network_name(T dst, UINT bufsize) const
+ {return get_raw_str(LPCSTR(this+1), length, dst, bufsize);}
+ template UINT get_network_name(T (&dst)[S]) const
+ {return get_network_name(dst, S);}
+};
+
+/* Service List Descriptor (NIT) tag 0x41
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ service_list_descriptor() {
+ descriptor_tag 8 0
+ descriptor_length 8 1
+ for (i=0; i MDescriptor_41; // tag = mdt_Service_List
+
+/* Service Descriptor (SDT) tag 0x48
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ service_descriptor() {
+ descriptor_tag 8 0
+ descriptor_length 8 1
+ service_type 8 2
+ service_provider_name_length 8 3
+ for (i=0;i(this+1);};
+ const MSubDescr_str & service_name() const
+ {return *service_provider_name().next();};
+};
+
+/* Linkage descriptor (NIT) tag 0x4a
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ linkage_descriptor(){
+ descriptor_tag 8 0
+ descriptor_length 8 1
+ transport_stream_id 16 2,3
+ original_network_id 16 4,5
+ service_id 16 6,7
+ linkage_type 8 8
+ if (linkage_type!=0x08) { 9
+ for (i=0;i=0x01 && hand_over_type<=0x03)
+ get_and_skip(p_nxt, p_network_id);
+ if ((*p_hand_over_and_origin)() & 0x01)
+ get_and_skip(p_nxt, p_initial_service_id);
+ }
+ p_next = p_nxt;
+ }
+};
+
+/* Short event descriptor (EIT) tag 0x4d
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ short_event_descriptor(){
+ descriptor_tag 8 0
+ descriptor_length 8 1
+ ISO_639_language_code 24 2..4
+ event_name_length 8 5
+ for (i=0;i(this+1);};
+ const MSubDescr_str & text() const
+ {return *event_name().next();};
+};
+
+/* Extended event descriptor (EIT) tag 0x4e
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ extended_event_descriptor(){
+ descriptor_tag 8 0
+ descriptor_length 8 1
+ descriptor_number 4 2
+ last_descriptor_number 4 2
+ ISO_639_language_code 24 3..5
+ length_of_items 8 6
+ for ( i=0;i(this);};
+ const MSubDescr_str & item() const
+ {return *item_description().next();};
+
+ const MSubDescr_4e * next() const
+ {return reinterpret_cast(item().next());}
+};
+
+struct MDescriptor_4e : public MDescriptor // tag = mdt_Extended_Event
+{
+ UINT8 descriptor_numbers;
+ ISO639_LANG language_code;
+ UINT8 length_of_items;
+ //
+ UINT8 descriptor_number() const
+ {return UINT8(descriptor_numbers >> 4);}
+ UINT8 last_descriptor_number() const
+ {return UINT8(descriptor_numbers & 0x0f);}
+ streamScanner subDescrRange() const
+ {return streamScanner(this+1, PUINT8(this+1) + length_of_items);}
+ const MSubDescr_str & text() const
+ {return *reinterpret_cast(PUINT8(this+1)+length_of_items);};
+};
+
+/* Component descriptor (EIT) tag 0x50
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ component_descriptor() {
+ descriptor_tag 8 0
+ descriptor_length 8 1
+ reserved_future_use 4 2
+ stream_content 4 2
+ component_type 8 3
+ component_tag 8 4
+ ISO_639_language_code 24 5..7
+ for (i=0;i UINT get_text_char(T dst, UINT bufsize) const
+ {return get_raw_str(LPCSTR(this+1), UINT(PUINT8(next())-PUINT8(this+1)), dst, bufsize);}
+ template UINT get_text_char(T (&dst)[S]) const
+ {return get_text_char(dst, S);}
+};
+
+/* Stream identifier descriptor (PMT) tag 0x52
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ stream_identifier_descriptor(){
+ descriptor_tag 8 0
+ descriptor_length 8 1
+ component_tag 8 2
+ }
+*/
+
+struct MDescriptor_52 : public MDescriptor // tag = mdt_Stream_Identifier
+{
+ UINT8 component_tag;
+};
+
+/* Content descriptor (EIT) tag 0x54
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ content_descriptor(){
+ descriptor_tag 8 uimsbf
+ descriptor_length 8 uimsbf
+ for (i=0;i>4);}
+ UINT8 content_nibble_level_2() const
+ {return UINT8(content_nibbles&0x0f);}
+ UINT8 user_nibble_1() const
+ {return UINT8(user_nibbles>>4);}
+ UINT8 user_nibble_2() const
+ {return UINT8(user_nibbles&0x0f);}
+
+ const MSubDescr_54 * next() const
+ {return this+1;}
+};
+
+typedef MDescriptor_list MDescriptor_54; // tag = mdt_Content
+
+/* Parental rating descriptor (EIT) tag 0x55
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ parental_rating_descriptor() {
+ descriptor_tag 8 0
+ descriptor_length 8 1
+ for (i=0;i MDescriptor_55; // tag = mdt_Parental_Rating
+
+/* Subtitling descriptor (PMT) tag 0x56
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ teletext_descriptor() {
+ descriptor_tag 8 0
+ descriptor_length 8 1
+ for (i=0;i>3);}
+ UINT8 teletext_magazine_number() const
+ {return UINT8(teletext_type_and_mag&0x07);}
+
+ const MSubDescr_56 * next() const
+ {return this+1;}
+};
+
+typedef MDescriptor_list MDescriptor_56; // tag = mdt_Teletext
+
+/* Subtitling descriptor (PMT) tag 0x59
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ subtitling_descriptor() {
+ descriptor_tag 8 0
+ descriptor_length 8 1
+ for (i=0;i MDescriptor_59; // tag = mdt_Subtitling
+
+/* Private Data Specifier tag 0x5a
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ terrestrial_delivery_system_descriptor() {
+ descriptor_tag 8 0
+ descriptor_length 8 1
+ centre_frequency 32 2..5
+ bandwidth 3 6
+ reserved_future_use 5 6
+ constellation 2 7
+ hierarchy_information 3 7
+ code_rate-HP_stream 3 7
+ code_rate-LP_stream 3 8
+ guard_interval 2 8
+ transmission_mode 2 8
+ other_frequency_flag 1 8
+ reserved_future_use 32 9..12
+ } 13
+*/
+
+struct MDescriptor_5a : public MDescriptor // tag = mdt_Terrestrial_Deliv_Sys
+{
+ UBE32 centre_frequency;
+ UINT8 _bandwidth;
+ UINT8 data1; // constellation, hierarchy_information, code_rate-HP_stream
+ UINT8 data2; // code_rate-LP_stream, guard_interval, transmission_mode, other_frequency_flag
+ UBE32 reserved2;
+
+ UINT8 bandwidth() const
+ {return UINT8(_bandwidth>>5);}
+ UINT8 constellation() const
+ {return UINT8(data1>>6);}
+ UINT8 hierarchy_information() const
+ {return UINT8((data1>>3)&0x07);}
+ UINT8 code_rate_HP_stream() const
+ {return UINT8(data1&0x07);}
+ UINT8 code_rate_LP_stream() const
+ {return UINT8(data2>>5);}
+ UINT8 guard_interval() const
+ {return UINT8((data2>>3)&0x03);}
+ UINT8 transmission_mode() const
+ {return UINT8((data2>>1)&0x03);}
+ UINT8 other_frequency_flag() const
+ {return UINT8(data2&0x01);}
+};
+
+/* Private Data Specifier tag 0x5f
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ private_data_specifier_descriptor() {
+ descriptor_tag 8 0
+ descriptor_length 8 1
+ private_data_specifier 32 2
+ }
+*/
+
+struct MDescriptor_5f : public MDescriptor // tag = mdt_Stream_Identifier
+{
+ UBE32 private_data_specifier;
+};
+
+/* Logical Channel Descriptor (PMT) tag 0x6a
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ AC3_descriptor() {
+ descriptor_tag 8 0
+ descriptor_length 8 1
+ component_type_flag 1 2
+ bsid_flag 1 2
+ mainid_flag 1 2
+ asvc_flag 1 2
+ reserved 4 2
+ if (component_type_flag)==1 { 3
+ AC3_type 8 +0
+ }
+ if (bsid_flag)==1 { +0
+ bsid 8 +0
+ }
+ if (mainid_flag)==1 { +0
+ mainid 8 +0
+ }
+ if (asvc_flag)==1 { +0
+ asvc 8 +0
+ }
+ for (i=0;i subDescrRange() const
+ {return streamScanner(this+1, next());}
+};
+
+/* Logical Channel Descriptor (NIT) tag 0x83
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ Logical_channel_descriptor() {
+ descriptor_tag 8 0
+ descriptor_length 8 1
+ for (i=0; i logical_channel_number;
+ //
+ const MSubDescr_83 * next() const
+ {return this+1;}
+};
+
+typedef MDescriptor_list MDescriptor_83; // tag = mdt_Logical_Channel
+
+/****************************************************************************************
+ * PROGRAM STREAM *
+ ****************************************************************************************/
+
+// Identificateurs de flots (streams) :
+enum StreamIDs
+{
+ sid_Program_End = 0xb9, // 0xb9
+ sid_Pack_Header, // 0xba
+ sid_System_Header, // 0xbb
+ sid_Program_Stream_Map, // 0xbc
+ sid_Private_Stream_1, // 0xbd
+ sid_Padding_Stream, // 0xbe
+ sid_Private_Stream_2, // 0xbf
+ //
+ // Audio Streams (0xc0 à 0xdf)
+ sid_Audio_Stream__1, sid_Audio_Stream__2, sid_Audio_Stream__3, sid_Audio_Stream__4,
+ sid_Audio_Stream__5, sid_Audio_Stream__6, sid_Audio_Stream__7, sid_Audio_Stream__8,
+ sid_Audio_Stream__9, sid_Audio_Stream_10, sid_Audio_Stream_11, sid_Audio_Stream_12,
+ sid_Audio_Stream_13, sid_Audio_Stream_14, sid_Audio_Stream_15, sid_Audio_Stream_16,
+ sid_Audio_Stream_17, sid_Audio_Stream_18, sid_Audio_Stream_19, sid_Audio_Stream_20,
+ sid_Audio_Stream_21, sid_Audio_Stream_22, sid_Audio_Stream_23, sid_Audio_Stream_24,
+ sid_Audio_Stream_25, sid_Audio_Stream_26, sid_Audio_Stream_27, sid_Audio_Stream_28,
+ sid_Audio_Stream_29, sid_Audio_Stream_30, sid_Audio_Stream_31, sid_Audio_Stream_32,
+ //
+ // Video Streams (0xe0 à 0xef)
+ sid_Video_Stream__1, sid_Video_Stream__2, sid_Video_Stream__3, sid_Video_Stream__4,
+ sid_Video_Stream__5, sid_Video_Stream__6, sid_Video_Stream__7, sid_Video_Stream__8,
+ sid_Video_Stream__9, sid_Video_Stream_10, sid_Video_Stream_11, sid_Video_Stream_12,
+ sid_Video_Stream_13, sid_Video_Stream_14, sid_Video_Stream_15, sid_Video_Stream_16,
+ //
+ sid_ECM_Stream, // 0xf0
+ sid_EMM_Stream, // 0xf1
+ sid_ISO_IEC_13818, // 0xf2
+ sid_ISO_IEC_13522, // 0xf3
+ sid_H_222_1_type_A, // 0xf4
+ sid_H_222_1_type_B, // 0xf5
+ sid_H_222_1_type_C, // 0xf6
+ sid_H_222_1_type_D, // 0xf7
+ sid_H_222_1_type_E, // 0xf8
+ sid_Ancillary_Stream, // 0xf9
+ //
+ sid_Program_Stream_Directory = 0xff
+};
+
+// Pour insertion dans un switch/case :
+#define sid_Audio_Stream_range sid_Audio_Stream__1: \
+ case sid_Audio_Stream__2: \
+ case sid_Audio_Stream__3: \
+ case sid_Audio_Stream__4: \
+ case sid_Audio_Stream__5: \
+ case sid_Audio_Stream__6: \
+ case sid_Audio_Stream__7: \
+ case sid_Audio_Stream__8: \
+ case sid_Audio_Stream__9: \
+ case sid_Audio_Stream_10: \
+ case sid_Audio_Stream_11: \
+ case sid_Audio_Stream_12: \
+ case sid_Audio_Stream_13: \
+ case sid_Audio_Stream_14: \
+ case sid_Audio_Stream_15: \
+ case sid_Audio_Stream_16: \
+ case sid_Audio_Stream_17: \
+ case sid_Audio_Stream_18: \
+ case sid_Audio_Stream_19: \
+ case sid_Audio_Stream_20: \
+ case sid_Audio_Stream_21: \
+ case sid_Audio_Stream_22: \
+ case sid_Audio_Stream_23: \
+ case sid_Audio_Stream_24: \
+ case sid_Audio_Stream_25: \
+ case sid_Audio_Stream_26: \
+ case sid_Audio_Stream_27: \
+ case sid_Audio_Stream_28: \
+ case sid_Audio_Stream_29: \
+ case sid_Audio_Stream_30: \
+ case sid_Audio_Stream_31: \
+ case sid_Audio_Stream_32
+
+// Pour insertion dans un switch/case :
+#define sid_Video_Stream_range sid_Video_Stream__1: \
+ case sid_Video_Stream__2: \
+ case sid_Video_Stream__3: \
+ case sid_Video_Stream__4: \
+ case sid_Video_Stream__5: \
+ case sid_Video_Stream__6: \
+ case sid_Video_Stream__7: \
+ case sid_Video_Stream__8: \
+ case sid_Video_Stream__9: \
+ case sid_Video_Stream_10: \
+ case sid_Video_Stream_11: \
+ case sid_Video_Stream_12: \
+ case sid_Video_Stream_13: \
+ case sid_Video_Stream_14: \
+ case sid_Video_Stream_15: \
+ case sid_Video_Stream_16
+
+/*
+ Program Stream pack
+
+ Syntax No. of bits Offset
+ --------------------------------------------------------------------------
+ pack() {
+ pack_header() 0
+ while (nextbits()==packet_start_code_prefix) {
+ PES_packet() +0
+ }
+ }
+*/
+
+struct PS_hdr
+{
+ UINT8 start_code[3];
+ UINT8 stream_id;
+
+ UINT32 get_start_code() const
+ {return MAKELONG(MAKEWORD(start_code[2], start_code[1]), start_code[0]);}
+ void set_start_code()
+ {start_code[1] = start_code[0] = 0x00; start_code[2] = 0x01;}
+ bool isPS() const
+ {return get_start_code()==0x000001;}
+ template const T & as() const // Dérivation vers un type de descripteur spécifique
+ {return *reinterpret_cast(this);}
+};
+
+struct PS_hdr_wl : public PS_hdr // wl="With Length"
+{
+ UBE16 hdr_length;
+
+ PUINT8 base_of_data_size() const
+ {return PUINT8(this+1);}
+ void set_data_size(PUINT8 adr)
+ {hdr_length = UINT16(adr-base_of_data_size());}
+ size_t packet_size() const
+ {return sizeof(*this) + hdr_length();}
+ PUINT8 next() const
+ {return PUINT8(this) + packet_size();}
+};
+
+/*
+ Program Stream pack header
+ Voir aussi : http://dvd.sourceforge.net/dvdinfo/packhdr.html
+
+ Syntax No. of bits Offset
+ --------------------------------------------------------------------------
+ pack_header() {
+ start_code (0x00, 0x00, 0x01) 24 0..2
+ stream_id (0xBA) 8 3
+ '01' 2 4
+ system_clock_reference_base [32..30] 3 4
+ marker_bit '1' 1 4
+ system_clock_reference_base [29..15] 15 4..6
+ marker_bit '1' 1 6
+ system_clock_reference_base [14..0] 15 6..8
+ marker_bit '1' 1 8
+ system_clock_reference_extension 9 8, 9
+ marker_bit '1' 1 9
+ program_mux_rate 22 10..12
+ marker_bits '11' 2 12
+ reserved 5 13
+ pack_stuffing_length 3 13
+ for (i=0; i buffer_size;
+
+ UINT16 buffer_scale() const
+ {return buffer_size.flags() & PES_SB_BUFFERSCALE_FLAG ? 0x400 : 0x80;}
+ void set_size(bool scale, UINT16 size)
+ {buffer_size = size; buffer_size.set_flags(PES_SB_BUFFERSCALE_FLAG, scale ? PES_SB_BUFFERSCALE_FLAG : 0);}
+ UINT32 actual_buffer_size() const
+ {return buffer_size()*buffer_scale();}
+ PUINT8 next() const
+ {return PUINT8(this+1);}
+};
+
+/*
+ Program Stream system header
+
+ Syntax No. of bits Offset
+ --------------------------------------------------------------------------
+ system_header () {
+ start_code (0x00, 0x00, 0x01) 24 0..2
+ stream_id (0xBB) 8 3
+ packet_length 16 4, 5
+ marker_bit 1 6
+ rate_bound 22 6..8
+ marker_bit 1 8
+ audio_bound 6 9
+ fixed_flag 1 9
+ CSPS_flag 1 9
+ system_audio_lock_flag 1 10
+ system_video_lock_flag 1 10
+ marker_bit 1 10
+ video_bound 5 10
+ packet_rate_restriction_flag 1 11
+ reserved_bits 7 11
+ while (nextbits()=='1') {
+ stream_id 8 +0
+ '11' 2 +1
+ P-STD_buffer_bound_scale 1 +1
+ P-STD_buffer_size_bound 13 +1, +2
+ }
+ }
+*/
+
+struct PS_SH_entry
+{
+ UINT8 stream_id;
+ PS_D_StdBuff bound_buf;
+
+ bool isEot() const
+ {return (stream_id & 0x80)==0;}
+ const PS_SH_entry * next() const
+ {return this+1;}
+};
+
+// ** Flags dans les champs de PS_SystemHeader :
+// audio_bound_and_flags :
+#define SH_FIXED_FLAG 0x02
+#define SH_CSPS_FLAG 0x01
+// video_bound_and_flags :
+#define SH_SYSTEM_AUDIO_LOCK_FLAG 0x80
+#define SH_SYSTEM_VIDEO_LOCK_FLAG 0x40
+// packet_rate_restriction_flag :
+#define SH_PACKET_RATE_RESTRICTION_FLAG 0x80
+
+struct PS_SystemHeader : public PS_hdr_wl
+{
+ PS_D_mux_rate rate_bound; // MUX rate maximal de l'ensemble du fichier PS
+ UINT8 audio_bound_and_flags; // nombre maximal de flux audio (+ 2 flags)
+ UINT8 video_bound_and_flags; // nombre maximal de flux vidéo (+ 3 flags)
+ UINT8 packet_rate_restriction_flag; // + 7 bits réservés
+
+ UINT8 audio_bound() const
+ {return audio_bound_and_flags >> 2;};
+ UINT8 video_bound() const
+ {return video_bound_and_flags & 0x1f;};
+ bool fixed() const
+ {return (audio_bound_and_flags & SH_FIXED_FLAG)!=0;}
+ bool CSPS() const
+ {return (audio_bound_and_flags & SH_CSPS_FLAG)!=0;}
+ bool system_audio_lock() const
+ {return (video_bound_and_flags & SH_SYSTEM_AUDIO_LOCK_FLAG)!=0;}
+ bool system_video_lock() const
+ {return (video_bound_and_flags & SH_SYSTEM_VIDEO_LOCK_FLAG)!=0;}
+ bool packet_rate_restriction() const
+ {return (packet_rate_restriction_flag & SH_PACKET_RATE_RESTRICTION_FLAG)!=0;}
+ //
+ // Note : si, dans un élément, la fonction PS_SH_entry::isEot() retourne 'false', il se pourrait
+ // qu'on doive comprendre que les éléments suivants ne sont pas valides, même si 'count' n'est pas épuisé.
+ int count() const
+ {return int(INT_PTR(next()-INT_PTR(this+1))/sizeof(PS_SH_entry));}
+ PS_SH_entry & operator [] (int index)
+ {return reinterpret_cast(this+1)[index];}
+ streamScanner entryRange() const
+ {return streamScanner(this+1, PUINT8(this+1) + hdr_length());}
+};
+
+/*
+ Program Stream Map
+
+ Syntax No. of bits Offset
+ --------------------------------------------------------------------------
+ program_stream_map() {
+ packet_start_code_prefix 24 0..2
+ map_stream_id 8 3
+ program_stream_map_length 16 4, 5
+ current_next_indicator 1 6
+ reserved 2 6
+ program_stream_map_version 5 6
+ reserved 7 7
+ marker_bit 1 7
+ program_stream_info_length 16 8, 9
+ for (i = 0; i < N; i++) {
+ descriptor()
+ }
+ elementary_stream_map_length 16 +0, +1
+ for (i = 0; i < N1; i++) {
+ stream_type 8 +0
+ elementary_stream_id 8 +1
+ elementary_stream_info_length 16 +2, +3
+ for (i = 0; i < N2; i++) {
+ descriptor()
+ }
+ }
+ CRC_32 32 +0
+ }
+*/
+
+// Descripteur de flot élémentaire "elementary stream", partie de PS_ProgramStreamMap.
+// Ce type de champ peut être répété pour former une table, donc chaque élément peut être
+// obtenu à partir du précédent en appelant la méthode "next" :
+struct PS_PSM_entry
+{
+ UINT8 type;
+ UINT8 id;
+ UBE16 dloop_length;
+
+ descrScanner descrRange() const
+ {return descrScanner(this+1, PUINT8(this+1) + dloop_length());}
+ PS_PSM_entry * next() const
+ {return reinterpret_cast(PUINT8(this+1) + dloop_length());}
+};
+
+// Seconde partie de PS_ProgramStreamMap, contenant la longueur de la table
+// des flots élémentaires "elementary stream" :
+struct PS_PSM_entries_hdr
+{
+ UBE16 eloop_length;
+
+ streamScanner entryRange() const
+ {return streamScanner(this+1, PUINT8(this+1) + eloop_length());}
+};
+
+struct PS_ProgramStreamMap : public PS_hdr_wl
+{
+ UINT8 version;
+ UINT8 reserved;
+ UBE16 dloop_length;
+
+ // Accès à la table de descripteurs incluse :
+ descrScanner descrRange() const
+ {return descrScanner(this+1, PUINT8(this+1) + dloop_length());}
+ // Accès aux champs suivant :
+ PS_PSM_entries_hdr & entries_hdr() const
+ {return *reinterpret_cast(PUINT8(this+1) + dloop_length());}
+ CRC_32 & crc32() const
+ {return *reinterpret_cast(next() - sizeof(CRC_32));}
+};
+
+/*
+ Program Stream PES packet
+ Voir aussi : http://dvd.sourceforge.net/dvdinfo/pes-hdr.html
+
+ Syntax No. of bits Offset
+ --------------------------------------------------------------------------
+ PES_packet() {
+ start_code (0x00, 0x00, 0x01) 24 0..2
+ stream_id 8 3
+ packet_length 16 4, 5
+ if (stream_id!=program_stream_map
+ && stream_id!=padding_stream
+ && stream_id!=private_stream_2
+ && stream_id!=ECM
+ && stream_id!=EMM
+ && stream_id!=program_stream_directory
+ && stream_id!=DSMCC_stream
+ && stream_id!=ITU-T Rec.H.222.1 type E stream
+ ) {
+ '10' 2 6
+ PES_scrambling_control 2 6
+ PES_priority 1 6
+ data_alignment_indicator 1 6
+ copyright 1 6
+ original_or_copy 1 6
+ PTS_DTS_flags 2 7
+ ESCR_flag 1 7
+ ES_rate_flag 1 7
+ DSM_trick_mode_flag 1 7
+ additional_copy_info_flag 1 7
+ PES_CRC_flag 1 7
+ PES_extension_flag 1 7
+ PES_header_data_length 8 8
+ if (PTS_DTS_flags=='10') {
+ '0010' 4 9
+ PTS [32..30] 3 9
+ marker_bit 1 9
+ PTS [29..15] 15 10, 11
+ marker_bit 1 11
+ PTS [14..0] 15 12, 13
+ marker_bit 1 13
+ }
+ if (PTS_DTS_flags=='11') {
+ '0011' 4 9
+ PTS [32..30] 3 9
+ marker_bit 1 9
+ PTS [29..15] 15 10, 11
+ marker_bit 1 11
+ PTS [14..0] 15 12, 13
+ marker_bit 1 13
+ '0001' 4 14
+ DTS [32..30] 3 14
+ marker_bit 1 14
+ DTS [29..15] 15 15, 16
+ marker_bit 1 16
+ DTS [14..0] 15 17, 18
+ marker_bit 1 18
+ }
+ if (ESCR_flag=='1') {
+ reserved 2 +0
+ ESCR_base[32..30] 3 +0
+ marker_bit 1 +0
+ ESCR_base[29..15] 15 +0..+2
+ marker_bit 1 +2
+ ESCR_base[14..0] 15 +2..+4
+ marker_bit 1 +4
+ ESCR_extension 9 +4, +5
+ marker_bit 1 +5
+ }
+ if (ES_rate_flag=='1') {
+ marker_bit 1 +0
+ ES_rate 22 +0..+2
+ marker_bit 1 +2
+ }
+ if (DSM_trick_mode_flag=='1') {
+ trick_mode_control 3 +0
+ if (trick_mode_control==fast_forward) {
+ field_id 2 +0
+ intra_slice_refresh 1 +0
+ frequency_truncation 2 +0
+ } else if (trick_mode_control==slow_motion) {
+ rep_cntrl 5 +0
+ } else if (trick_mode_control==freeze_frame) {
+ field_id 2 +0
+ reserved 3 +0
+ } else if (trick_mode_control==fast_reverse) {
+ field_id 2 +0
+ intra_slice_refresh 1 +0
+ frequency_truncation 2 +0
+ } else if (trick_mode_control==slow_reverse) {
+ rep_cntrl 5 +0
+ } else
+ reserved 5 +0
+ }
+ if (additional_copy_info_flag=='1') {
+ marker_bit 1 +0
+ additional_copy_info 7 +0
+ }
+ if (PES_CRC_flag=='1') {
+ previous_PES_packet_CRC 16 +0, +1
+ }
+ if (PES_extension_flag=='1') {
+ PES_private_data_flag 1 +0
+ pack_header_field_flag 1 +0
+ program_packet_sequence_counter_flag 1 +0
+ P-STD_buffer_flag 1 +0
+ reserved 3 +0
+ PES_extension_flag_2 1 +0
+ if (PES_private_data_flag=='1') {
+ PES_private_data 128 +0..+15
+ }
+ if (pack_header_field_flag=='1') {
+ pack_field_length 8 +0
+ pack_header() +1
+ }
+ if (program_packet_sequence_counter_flag=='1') {
+ marker_bit 1 +0
+ program_packet_sequence_counter 7 +0
+ marker_bit 1 +1
+ MPEG1_MPEG2_identifier 1 +1
+ original_stuff_length 6 +1
+ }
+ if (P-STD_buffer_flag=='1') {
+ '01' 2 +0
+ P-STD_buffer_scale 1 +0
+ P-STD_buffer_size 13 +0, +1
+ }
+ if (PES_extension_flag_2=='1') {
+ marker_bit 1 +0
+ PES_extension_field_length 7 +1
+ for (i=0; i> 6;}
+ UINT8 original_stuff_length() const
+ {return original_stuff_length_and_id & 0x3f;}
+ PUINT8 next() const
+ {return PUINT8(this+1);}
+};
+
+struct PS_D_extension1
+{
+ UINT8 flags;
+
+ PUINT8 begin() const
+ {return PUINT8(this+1);}
+ PUINT8 next() const
+ {return PUINT8(this+1);}
+};
+
+struct PS_D_extension2
+{
+ UINT8 length;
+
+ PUINT8 next() const
+ {return PUINT8(this+1) + length;}
+};
+
+// Définition des bits de "PS_hdr_wd::info" :
+#define PES_PRIORITY_FLAG 0x08
+#define DATA_ALIGNMENT_INDICATOR 0x04 // 1=video start code or audio syncword follows
+#define COPYRIGHT_FLAG 0x02 // 1=copyrighted material
+#define ORIGINAL_FLAG 0x01 // 1=original; 0=copy
+
+// Définition des bits de "PS_hdr_wd::flags" :
+#define PES_PTS_FLAG 0x80
+#define PES_DTS_FLAG 0x40
+#define PES_ESCR_FLAG 0x20
+#define PES_ES_RATE_FLAG 0x10
+#define PES_DSM_TRICK_MODE_FLAG 0x08
+#define PES_ADDITIONAL_COPY_INFO_FLAG 0x04
+#define PES_CRC_FLAG 0x02
+#define PES_EXTENSION_FLAG 0x01
+
+// Définition des flags de "PS_D_extension1" :
+#define PES_PRIVATE_DATA_FLAG 0x80
+#define PES_PACK_HEADER_FIELD_FLAG 0x40
+#define PES_PROG_PACKET_SEQ_COUNT_FLAG 0x20
+#define PES_P_STD_BUFFER_FLAG 0x10
+// flags 0x08, 0x04, 0x02 réservés
+#define PES_EXTENSION_FLAG_2 0x01
+
+struct PS_hdr_wd : public PS_hdr_wl // wd = "With Data"
+{
+ UINT8 info;
+ UINT8 flags;
+ UINT8 data_length;
+
+ size_t header_size() const
+ {return sizeof(*this)+data_length;}
+ PUINT8 base_of_data() const
+ {return PUINT8(this)+header_size();}
+ PUINT8 end_of_header() const
+ {return PUINT8(this)+header_size();}
+ PUINT8 beg_of_fields() const
+ {return PUINT8(this+1);}
+};
+
+// Sous-ensemble de la classe 'PS_data_unwrapper_full' :
+// (seulement les trois champs contenant des informations de timing)
+struct PS_data_unwrapper_base
+{
+ const PS_hdr_wd & hdr;
+ PUINT8 p_next;
+ PS_D_TimeStamp * p_pts;
+ PS_D_TimeStamp * p_dts;
+ PS_D_SCR * p_escr;
+
+ PS_data_unwrapper_base(const PS_hdr_wd & h) :
+ hdr(h),
+ p_next(h.beg_of_fields()),
+ p_pts(NULL),
+ p_dts(NULL),
+ p_escr(NULL)
+ {
+ PUINT8 p_nxt = p_next;
+ UINT8 flags = h.flags;
+
+ if (flags & PES_PTS_FLAG) {
+ get_and_skip(p_nxt, p_pts);
+ if (flags & PES_DTS_FLAG)
+ get_and_skip(p_nxt, p_dts);
+ }
+ if (flags & PES_ESCR_FLAG)
+ get_and_skip(p_nxt, p_escr);
+ p_next = p_nxt;
+ };
+};
+
+/*
+ * Déballage de tous les champs "data" optionnels du paquet 'hdr':
+ * La structure est chargée avec des pointeurs vers tous les champs
+ * existants, ou des valeurs NULL pour tous les champs inexistants.
+ * Le pointeur 'p_next' pointe l'espace encore libre qui suit, lequel correspond
+ * à des octets de remplissage optionnels suivis des données du paquet.
+ */
+struct PS_data_unwrapper_full : public PS_data_unwrapper_base
+{
+ PS_D_mux_rate * p_rate;
+ UINT8uw * p_trick;
+ UINT8uw * p_add_copy_info;
+ CRC_16 * p_prev_crc;
+ //
+ PS_D_extension1 * p_ext1; // pointeur début premier champ d'extension optionnel
+ PS_D_PrivData * p_priv_data;
+ PS_D_PackHdr * p_pack;
+ PS_D_SeqCount * p_seqcount;
+ PS_D_StdBuff * p_stdbuf;
+ PS_D_extension2 * p_ext2; // pointeur début second champ d'extension optionnel
+
+ PS_data_unwrapper_full(const PS_hdr_wd & hdr);
+};
+
+/****************************************************************************************
+ * TRANSPORT STREAM *
+ ****************************************************************************************/
+
+#define TS_SIZE 188 // Taille (fixée) des paquets TS
+
+// Codes de PID préféfinis :
+enum Predefined_PID {
+ p_pid_PAT = 0x000, // Program Association Table
+ p_pid_CAT = 0x001, // Conditional Access Table
+ p_pid_TSDT = 0x002, // Transport Stream Description Table
+ // (codes 0x003 à 0x00f spécifiés comme "réservés")
+ p_pid_NIT = 0x010, // Network Identification Table
+ p_pid_BAT = 0x011, // Bouquet Association Table ou ...
+ p_pid_SDT = 0x011, // Service Description Table
+ p_pid_EIT = 0x012, // Event Information Table (guide des programmes ...)
+ p_pid_RST = 0x013, // Running Status Tection
+ p_pid_TDT = 0x014, // Time and Date Table ou ...
+ p_pid_TOT = 0x014, // Time Offset Table
+ p_pid_SFN = 0x015, // SFN/MIP synchronisation
+ p_pid_DIT = 0x01e,
+ p_pid_SIT = 0x01f,
+ //
+ p_pid_NULL = 0x1fff // Null packet
+};
+
+
+/* Description Transport stream packet
+
+ Syntax No. of bits Offset
+ --------------------------------------------------------------------------
+ transport_packet() {
+ sync_byte 8 0
+ transport_error_indicator 1 1
+ payload_unit_start_indicator 1 1
+ transport_priority 1 1
+ PID 13 1, 2
+ transport_scrambling_control 2 3
+ adaptation_field_control 2 3
+ continuity_counter 4 3
+ if(adaptation_field_control=='10'||adaptation_field_control=='11') {
+ adaptation_field() 4
+ }
+ if (adaptation_field_control=='01'||adaptation_field_control=='11') {
+ for (i=0;i>6);}
+ AdaptationFieldCtlValues adaptation_field_control() const
+ {return AdaptationFieldCtlValues((control_and_ccounter & 0x30)>>4);}
+ UINT8 continuity_counter() const
+ {return control_and_ccounter & 0x0f;}
+ PUINT8 beg_of_fields() const
+ {return PUINT8(this+1);}
+};
+
+/* Adaptation Field
+
+ Syntax No. of bits Offset
+ --------------------------------------------------------------------------
+ adaptation_field() {
+ adaptation_field_length 8 0
+ if (adaptation_field_length>0) {
+ discontinuity_indicator 1 1
+ random_access_indicator 1 1
+ elementary_stream_priority_indicator 1 1
+ PCR_flag 1 1
+ OPCR_flag 1 1
+ splicing_point_flag 1 1
+ transport_private_data_flag 1 1
+ adaptation_field_extension_flag 1 1
+ if (PCR_flag=='1') {
+ program_clock_reference_base 33 2..6
+ reserved 6 6
+ program_clock_reference_extension 9 6,7
+ }
+ if (OPCR_flag=='1') {
+ original_program_clock_reference_base 33 +0..+4
+ reserved 6 +4
+ original_program_clock_reference_extension 9 +4,+5
+ }
+ if (splicing_point_flag=='1') {
+ splice_countdown 8 +0
+ }
+ if (transport_private_data_flag=='1') {
+ transport_private_data_length 8 +0
+ for (i=0; i0 ? PUINT8(this+1) : PUINT8(&flags);}
+ UINT8 get_flags() const
+ {return adaptation_field_length==0 ? 0 : flags;}
+ PUINT8 next() const
+ {return PUINT8(&flags)+adaptation_field_length;}
+};
+
+struct TS_unwrapper
+{
+ const TS_hdr & hdr;
+ PUINT8 p_next;
+ TS_AF_hdr * p_afield;
+ PUINT8 p_payload;
+ UINT8 payload_size;
+
+ TS_unwrapper(const TS_hdr & h) :
+ hdr(h),
+ p_afield(NULL),
+ p_payload(NULL),
+ payload_size(0)
+ {
+ PUINT8 p_nxt = h.beg_of_fields();
+ AdaptationFieldCtlValues afv = h.adaptation_field_control();
+
+ if (afv>=afcv_afield_only)
+ get_and_skip(p_nxt, p_afield);
+ if (afv==afcv_payload_only || afv==afcv_afield_and_payload) {
+ p_payload = p_nxt;
+ payload_size = UINT8((PUINT8(&h)+TS_SIZE)-p_payload);
+ }
+ p_next = p_nxt;
+ }
+};
+
+struct TS_AF_unwrapper_base
+{
+ PUINT8 p_next;
+ TS_PCR * p_pcr;
+ TS_PCR * p_opcr;
+
+ TS_AF_unwrapper_base(const TS_AF_hdr & af) :
+ p_pcr(NULL),
+ p_opcr(NULL)
+ {
+ PUINT8 p_nxt = af.beg_of_fields();
+ UINT8 flags = af.get_flags();
+
+ if (flags & AF_PCR_FLAG)
+ get_and_skip(p_nxt, p_pcr);
+ if (flags & AF_OPCR_FLAG)
+ get_and_skip(p_nxt, p_opcr);
+ p_next = p_nxt;
+ }
+};
+
+struct TS_AF_PrivData
+{
+ UINT8 length;
+
+ PUINT8 next() const
+ {return PUINT8(this+1) + length;}
+};
+
+struct TS_AF_extension
+{
+ UINT8 length;
+ UINT8 flags;
+
+ PUINT8 next() const
+ {return PUINT8(this+1);}
+};
+
+struct TS_AF_pw_rate
+{
+ UINT8 piecewise_rate[3];
+
+ PUINT8 next() const
+ {return PUINT8(this+1);}
+};
+
+struct TS_AF_SlSplice
+{
+ UINT8 seamless_splice[5];
+
+ PUINT8 next() const
+ {return PUINT8(this+1);}
+};
+
+struct TS_AF_unwrapper_full : public TS_AF_unwrapper_base
+{
+ UINT8uw * p_splicing_point;
+ TS_AF_PrivData * p_priv_data;
+ //
+ TS_AF_extension * p_ext; // pointeur début champ d'extension optionnel
+ UBE<15> * p_ltw;
+ TS_AF_pw_rate * p_piecewise_rate;
+ TS_AF_SlSplice * p_seamless_splice;
+
+ TS_AF_unwrapper_full(const TS_AF_hdr & af);
+};
+
+#define TS_SYNC 0x47 // valeur de l'octet de synchronisation
+
+union TS_packet
+{
+ TS_hdr hdr;
+ UINT8 bytes[TS_SIZE];
+
+ bool isTS(bool single=false) const
+ {return hdr.sync_byte==TS_SYNC && (single || this[1].hdr.sync_byte==TS_SYNC);}
+};
+
+/****************************************************************************************
+ * SERVICE INFORMATION *
+ ****************************************************************************************/
+
+/*
+*** ATTENTION à la remarque suivante, extraite de la documentation DirectShow de Microsoft,
+*** concernant la méthode ISectionList::GetSectionData.
+*** (ceci peut compliquer l'accès aux données de certaines sections via les structures
+*** décrites dans le présent fichier) :
+
+The section header is converted from network byte order to native byte order.
+The number of header bytes that are converted depends on the header type.
+The header types are short header (SECTION structure), long header (LONG_SECTION structure),
+or DSM-CC header (DSMCC_SECTION structure).
+If the section has a short header, the first three bytes are converted;
+for a long header, the first eight bytes are converted;
+and for a DSM-CC header, the first 20 bytes are converted.
+
+The body of the section data, after the header, is left unparsed and unconverted.
+
+http://msdn2.microsoft.com/en-us/library/ms786743(VS.85).aspx
+
+*** Les structures suivantes ont pour but de pallier cette complication.
+*/
+
+struct LEN12M : public LEN12
+{
+ UINT16 operator () (bool microsoft) const {
+ if (microsoft)
+ return PMPEG_HEADER_BITS(this)->SectionLength;
+ return LEN12::operator ()();
+ }
+
+ bool syntax_indicator(bool microsoft=false) const {
+ if (microsoft)
+ return PMPEG_HEADER_BITS(this)->SectionSyntaxIndicator != 0;
+ return (flags() & 0x80)!=0;
+ }
+};
+
+struct UBE16M : public UBE16
+{
+ UINT16 operator () (bool microsoft) const {
+ if (microsoft)
+ return *PUINT16(this);
+ return UBE16::operator ()();
+ }
+};
+
+// ############################################################################
+
+// Codes des identifiants de tables :
+enum SI_TableID {
+ si_undef = -1,
+ si_PAT = 0x00,
+ si_CAT = 0x01,
+ si_PMT = 0x02,
+ si_DSMCC_a = 0x3a, // http://en.wikipedia.org/wiki/DSM-CC
+ si_DSMCC_b = 0x3b,
+ si_DSMCC_c = 0x3c,
+ si_DSMCC_d = 0x3d,
+ si_DSMCC_e = 0x3e,
+ si_DSMCC_f = 0x3f,
+ si_NIT = 0x40,
+ si_SDT = 0x42,
+ si_EIT_act = 0x4e,
+ si_EIT_oth = 0x4f,
+ si_EIT_as0, si_EIT_as1, si_EIT_as2, si_EIT_as3, si_EIT_as4, si_EIT_as5, si_EIT_as6, si_EIT_as7,
+ si_EIT_as8, si_EIT_as9, si_EIT_asa, si_EIT_asb, si_EIT_asc, si_EIT_asd, si_EIT_ase, si_EIT_asf,
+ si_EIT_os0, si_EIT_os1, si_EIT_os2, si_EIT_os3, si_EIT_os4, si_EIT_os5, si_EIT_os6, si_EIT_os7,
+ si_EIT_os8, si_EIT_os9, si_EIT_osa, si_EIT_osb, si_EIT_osc, si_EIT_osd, si_EIT_ose, si_EIT_osf
+};
+
+// Pour insertion dans un switch/case :
+#define si_EIT_act_sched si_EIT_as0: \
+ case si_EIT_as1: \
+ case si_EIT_as2: \
+ case si_EIT_as3: \
+ case si_EIT_as4: \
+ case si_EIT_as5: \
+ case si_EIT_as6: \
+ case si_EIT_as7: \
+ case si_EIT_as8: \
+ case si_EIT_as9: \
+ case si_EIT_asa: \
+ case si_EIT_asb: \
+ case si_EIT_asc: \
+ case si_EIT_asd: \
+ case si_EIT_ase: \
+ case si_EIT_asf
+
+#define si_EIT_oth_sched si_EIT_os0: \
+ case si_EIT_os1: \
+ case si_EIT_os2: \
+ case si_EIT_os3: \
+ case si_EIT_os4: \
+ case si_EIT_os5: \
+ case si_EIT_os6: \
+ case si_EIT_os7: \
+ case si_EIT_os8: \
+ case si_EIT_os9: \
+ case si_EIT_osa: \
+ case si_EIT_osb: \
+ case si_EIT_osc: \
+ case si_EIT_osd: \
+ case si_EIT_ose: \
+ case si_EIT_osf
+
+/* System Information Header (SI)
+
+ Syntax No. of bits Offset
+ ------------------------------------------------------
+ system_information_header() {
+ table_id 8 0
+ section_syntax_indicator 1 1
+ reserved_future_use 1 1
+ reserved 2 1
+ section_length 12 1,2
+ section_id 16 3,4 -> variable selon type de table
+ reserved 2 5
+ version_number 5 5
+ current_next_indicator 1 5
+ section_number 8 6
+ last_section_number 8 7
+ [...]
+ [...]
+ [...]
+ CRC_32 32
+ }
+*/
+
+// Partie commune à toutes les tables PSI :
+struct SI_hdr
+{
+ UINT8 _table_id;
+ LEN12M section_length;
+ UBE16M section_id; // usage variable selon type de section
+ UINT8 versnum_and_next_indic;
+ UINT8 section_number;
+ UINT8 last_section_number;
+ //
+ // Certaines des fonctions suivantes ont un paramètre 'microsoft' qui doit être mis à 'true'
+ // lorsqu'on analyse une table PSI qui a été reçue par le biais de certaines fonctions Microsoft.
+ // En effet, ces fonctions ont pour caractéristique de permuter **certains** octets du champ PSI
+ // avec pour idée de les remettre dans l'ordre natif du système d'exploitation ... ...
+ // Le même paramètre doit aussi être donné à toutes les fonctions qui font indirectement usage
+ // de l'une de ces trois fonctions.
+ //
+ SI_TableID table_id() const
+ {return static_cast(_table_id);}
+ UINT8 version_number() const
+ {return (versnum_and_next_indic & 0x3e)>>1;}
+ bool current_next_indicator() const
+ {return (versnum_and_next_indic & 0x01)!=0;}
+
+ PUINT8 begin() const
+ {return PUINT8(this+1);}
+ PUINT8 next(bool microsoft=false) const
+ {return PUINT8(§ion_id) + section_length(microsoft);}
+ size_t size(bool microsoft=false) const
+ {return next(microsoft)-PUINT8(this);}
+ PUINT8 end(bool microsoft=false) const
+ {return next(microsoft) - sizeof(CRC_32);}
+ const CRC_32 & crc32(bool microsoft=false) const
+ {return *reinterpret_cast(end(microsoft));}
+ template const T & as() const
+ {return *reinterpret_cast(this);}
+ bool check_crc32(bool microsoft=false) const
+ {return ::crc32(PUINT8(this), int(size(microsoft)))==0;}
+};
+
+/* Program specific information pointer
+
+ Syntax No. of bits Offset
+ ------------------------------------------------------
+ program_specific information_pointer() {
+ pointer_field 8 0
+ }
+*/
+
+// Cette structure précède immédiatement toutes les tables SI.
+// Au niveau du "Transport Stream", elle se trouve exactement au début de
+// la zone "payload", lorsque celle-ci contient une table SI.
+// Comme l'octet qu'elle contient indique le décalage de la table dans la
+// zone "payload" et que ce décalage est le plus souvent nul, sa présence
+// se résume le plus souvent à intercaler un octet 0 juste devant la table.
+struct SI_ptr
+{
+ UINT8 pointer_field;
+
+ void * operator new(size_t, void * ptr)
+ {return ptr;}
+ const SI_hdr * getSI() const
+ {return reinterpret_cast(&this[1]+pointer_field);}
+};
+
+// Obtenir une référence sur une table PSI à partir du début de la zone de données PSI :
+template const T & asSI(LPCVOID ptr)
+{
+ return reinterpret_cast(ptr)->getSI()->as();
+}
+
+// ############################################################################
+
+/* Program association section (PAT)
+
+ Syntax No. of bits Offset
+ ------------------------------------------------------
+ program_association_section() { _
+ table_id 8 0 \
+ section_syntax_indicator 1 1 \
+ reserved_future_use 1 1 |
+ reserved 2 1 |
+ section_length 12 1,2 |
+ transport_stream_id 16 3,4 |-- en-tête SI
+ reserved 2 5 |
+ version_number 5 5 |
+ current_next_indicator 1 5 |
+ section_number 8 6 /
+ last_section_number 8 7 _/
+ for (j=0;j< N;j++) { 8
+ program_number 16 +0,+1
+ reserved 3 +2
+ if (program_number==’0’ ) {
+ network_PID 13 +2,+3
+ } else {
+ program_map_PID 13 +2,+3
+ }
+ }
+ CRC_32 32
+ }
+*/
+
+struct SI_PAT_entry
+{
+ UBE16 program_number;
+ PID13 pid;
+ //
+ const SI_PAT_entry * next() const
+ {return this+1;}
+};
+
+struct SI_PAT : public SI_hdr
+{
+ UINT16 tsid(bool microsoft=false) const
+ {return section_id(microsoft);}
+ int count(bool microsoft=false) const
+ {return int((PUINT8(&crc32(microsoft))-begin())/sizeof(SI_PAT_entry));}
+ const SI_PAT_entry & operator [] (int index) const
+ {return reinterpret_cast(begin())[index];}
+ streamScanner entryRange(bool microsoft=false) const
+ {return streamScanner(begin(), end(microsoft));}
+};
+
+// ############################################################################
+
+/* Transport Stream program map section (PMT)
+
+ Syntax No. of bits Offset
+ ------------------------------------------------------
+ TS_program_map_section( ) { _
+ table_id 8 0 \
+ section_syntax_indicator 1 1 \
+ reserved_future_use 1 1 |
+ reserved 2 1 |
+ section_length 12 1,2 |
+ program_number 16 3,4 |-- en-tête SI
+ reserved 2 5 |
+ version_number 5 5 |
+ current_next_indicator 1 5 |
+ section_number 8 6 /
+ last_section number 8 7 _/
+ reserved 3 8
+ PCR_PID 13 8,9
+ reserved 4 10
+ program_info_length 12 10,11
+ for (i=0;i(_type);}
+ descrScanner descrRange() const
+ {return descrScanner(this+1, PUINT8(this+1) + dloop_length());}
+ const SI_PMT_entry * next() const
+ {return reinterpret_cast(PUINT8(this+1) + dloop_length());}
+};
+
+// PMT = Program Map Table
+struct SI_PMT : public SI_hdr
+{
+ PID13 pid;
+ LEN12 dloop_length;
+ //
+ UINT16 program_number(bool microsoft=false) const
+ {return section_id(microsoft);}
+ descrScanner descrRange() const
+ {return descrScanner(this+1, PUINT8(this+1) + dloop_length());}
+ streamScanner entryRange(bool microsoft=false) const
+ {return streamScanner(PUINT8(this+1) + dloop_length(), end(microsoft));}
+};
+
+// ############################################################################
+
+/* Service description section (SDT)
+
+ Syntax No. of bits Offset
+ ------------------------------------------------------
+ service_description_section() { _
+ table_id 8 0 \
+ section_syntax_indicator 1 1 \
+ reserved_future_use 1 1 |
+ reserved 2 1 |
+ section_length 12 1,2 |
+ transport_stream_id 16 3,4 |-- en-tête SI
+ reserved 2 5 |
+ version_number 5 5 |
+ current_next_indicator 1 5 |
+ section_number 8 6 /
+ last_section_number 8 7 _/
+ original_network_id 16 8,9
+ reserved_future_use 8 10
+ for(i=0;i(PUINT8(this+1) + dloop_length());}
+};
+
+// SDT = Service Description Table
+struct SI_SDT : public SI_hdr
+{
+ UBE16 onid;
+ UINT8 reserved;
+ //
+ // Méthodes d'extraction :
+ UINT16 tsid(bool microsoft=false) const
+ {return section_id(microsoft);}
+ streamScanner entryRange(bool microsoft=false) const
+ {return streamScanner(this+1, end(microsoft));}
+};
+
+// ############################################################################
+
+/* Network Information section (NIT)
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ network_information_section() { _
+ table_id 8 0 \
+ section_syntax_indicator 1 1 \
+ reserved_future_use 1 1 |
+ reserved 2 1 |
+ section_length 12 1,2 |
+ network_id 16 3,4 |-- en-tête SI
+ reserved 2 5 |
+ version_number 5 5 |
+ current_next_indicator 1 5 |
+ section_number 8 6 /
+ last_section number 8 7 _/
+ reserved_future_use 4 8
+ network_descriptors_length 12 8,9
+ for(i=0;i(PUINT8(this+1) + dloop_length());}
+};
+
+// NIT = Network Information Table
+struct SI_NIT_entries_hdr
+{
+ LEN12 eloop_length;
+ //
+ streamScanner entryRange() const
+ {return streamScanner(this+1, PUINT8(this+1) + eloop_length());}
+};
+
+struct SI_NIT : public SI_hdr
+{
+ LEN12 dloop_length;
+ //
+ UINT16 network_id(bool microsoft=false) const
+ {return section_id(microsoft);}
+ descrScanner descrRange() const
+ {return descrScanner(this+1, PUINT8(this+1) + dloop_length());}
+ const SI_NIT_entries_hdr & entries_hdr() const
+ {return *reinterpret_cast(PUINT8(this+1) + dloop_length());}
+};
+
+// ############################################################################
+
+/* Event Information Section (EIT)
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ event_information_section( ) { _
+ table_id 8 0 \
+ section_syntax_indicator 1 1 \
+ reserved_future_use 1 1 |
+ reserved 2 1 |
+ section_length 12 1,2 |
+ service_id 16 3,4 |-- en-tête SI
+ reserved 2 5 |
+ version_number 5 5 |
+ current_next_indicator 1 5 |
+ section_number 8 6 /
+ last_section_number 8 7 _/
+ transport_stream_id 16 8,9
+ original_network_id 16 10,11
+ segment_last_section_number 8 12
+ last_table_id 8 13
+ for(i=0;i>4)*10 + (b & 0x0f);}
+};
+
+struct TIM24
+{
+ BCD8 h;
+ BCD8 m;
+ BCD8 s;
+
+ operator UINT32() const
+ {return ((h()*60+m())*60+s())*1000;} // Résultat en millisecondes
+};
+
+struct MJD16 : public UBE16
+{
+ void get(WORD & year, WORD & month, WORD & day) const
+ { // algo: ETSI EN 300 468 - ANNEX C
+ INT32 mjd = (*this)();
+ INT32 y = INT32((mjd - 15078.2) / 365.25);
+ INT32 yd = INT32(y * 365.25);
+ INT32 m = INT32((mjd - 14956.1 - yd) / 30.6001);
+ INT32 k = (m == 14 || m == 15) ? 1 : 0;
+
+ day = WORD(mjd - 14956 - yd - INT32(m * 30.6001));
+ month = WORD(m - 1 - k*12);
+ year = WORD(y + k + 1900);
+ }
+};
+
+struct SI_EIT_time
+{
+ MJD16 day;
+ TIM24 time;
+
+ operator SYSTEMTIME () const
+ {
+ SYSTEMTIME st;
+
+ day.get(st.wYear, st.wMonth, st.wDay);
+ st.wDayOfWeek = 0;
+ st.wHour = time.h();
+ st.wMinute = time.m();
+ st.wSecond = time.s();
+ st.wMilliseconds = 0;
+ return st;
+ }
+};
+
+struct SI_EIT_entry
+{
+ UBE16 event_id;
+ SI_EIT_time start_time;
+ TIM24 duration;
+ LEN12 dloop_length;
+
+ UINT8 running_status() const
+ {return UINT8(dloop_length.flags()>>5);}
+ UINT8 free_CA_mode() const
+ {return UINT8((dloop_length.flags()>>4)&0x01);}
+ descrScanner descrRange() const
+ {return descrScanner(this+1, PUINT8(this+1) + dloop_length());}
+ const SI_EIT_entry * next() const
+ {return reinterpret_cast(PUINT8(this+1) + dloop_length());}
+};
+
+struct SI_EIT : public SI_hdr
+{
+ UBE16 tsid;
+ UBE16 onid;
+ UINT8 segment_last_section_number;
+ UINT8 last_table_id;
+
+ UINT16 service_id(bool microsoft=false) const
+ {return section_id(microsoft);}
+ streamScanner entryRange(bool microsoft=false) const
+ {return streamScanner(this+1, end(microsoft));}
+};
Modified: trunk/parse.cpp
===================================================================
--- trunk/parse.cpp 2008-03-02 23:35:26 UTC (rev 113)
+++ trunk/parse.cpp 2008-03-07 19:34:12 UTC (rev 114)
@@ -43,9 +43,7 @@
if (it->TSID==tsid && it->SID==sid) {
it->pmt_pid=(WORD)pid;
}
-
}
-
}
// Partie commune à toutes les tables :
@@ -72,17 +70,17 @@
{return ((LPBYTE)this)+limit-sizeof(DWORD);}
};
-struct descriptor {
- BYTE descriptor_tag;
- BYTE descriptor_length;
+struct MDescriptor {
+ BYTE tag;
+ BYTE length;
//
// Méthodes d'extraction :
const LPBYTE begin() const
{return LPBYTE(this+1);}
- const descriptor * next() const
- {return (const descriptor *)(begin()+descriptor_length);}
+ const MDescriptor * next() const
+ {return (const MDescriptor *)(begin()+length);}
const LPBYTE end() const
- {return LPBYTE(this+1) + descriptor_length;}
+ {return LPBYTE(this+1) + length;}
};
@@ -208,7 +206,7 @@
0x6A, taille 5 Dolby AC3
*/
-struct PMT_entry {
+struct SI_PMT_entry {
BYTE stream_type;
BYTE elementary_pid_hi;
BYTE elementary_pid_lo;
@@ -220,12 +218,12 @@
{return ((elementary_pid_hi & 0x1f)<<8) | elementary_pid_lo;}
WORD length() const
{return ((es_info_length_hi & 0x0f)<<8) | es_info_length_lo;}
- const descriptor * begin() const
- {return (const descriptor *)LPBYTE(this+1);}
+ const MDescriptor * begin() const
+ {return (const MDescriptor *)LPBYTE(this+1);}
const LPBYTE end() const
{return LPBYTE(this+1) + length();}
- const PMT_entry * next() const
- {return (const PMT_entry *)end();}
+ const SI_PMT_entry * next() const
+ {return (const SI_PMT_entry *)end();}
};
// PMT = Program Map Table
@@ -236,25 +234,25 @@
BYTE program_info_length_lo;
//
// Méthodes d'extraction :
- WORD pcr_pid() const
+ WORD pid() const
{return ((pcr_pid_hi & 0x1f)<<8) | pcr_pid_lo;}
WORD length() const
{return ((program_info_length_hi & 0x0f)<<8) | program_info_length_lo;}
- const PMT_entry * begin() const
- {return (const PMT_entry *)(LPBYTE(this+1)+length());}
+ const SI_PMT_entry * begin() const
+ {return (const SI_PMT_entry *)(LPBYTE(this+1)+length());}
};
void parse_pmt(const SI_PMT & pmt, int max, ChainePMT & lpmt_e/*, bool debug*/)
{
- lpmt_e.pcr_pid = pmt.pcr_pid();
+ lpmt_e.pcr_pid = pmt.pid();
lpmt_e.sons.nbr=0;
lpmt_e.autr.nbr=0;
- for (const PMT_entry * ppent = pmt.begin(); LPBYTE(ppent)next()) {
+ for (const SI_PMT_entry * ppent = pmt.begin(); LPBYTE(ppent)next()) {
WORD pid = ppent->pid();
BYTE stream_type = ppent->stream_type;
bool private_stream = 0;
- const descriptor * ppdesc = ppent->begin();
+ const MDescriptor * ppdesc = ppent->begin();
//if (debug)
// myprintf(L"type : %02X, pid : %i\n", stream_type, pid);
@@ -278,7 +276,7 @@
if (private_stream) {
for (; (LPBYTE)ppdescend(); ppdesc=ppdesc->next()) {
- if (ppdesc->descriptor_tag == 0x6A)
+ if (ppdesc->tag == 0x6A)
lpmt_e.sons.ajoute(pid, 1);
}
@@ -289,8 +287,8 @@
}
for (; LPBYTE(ppdesc)end(); ppdesc=ppdesc->next()) {
- BYTE tag = ppdesc->descriptor_tag;
- BYTE length = ppdesc->descriptor_length;
+ BYTE tag = ppdesc->tag;
+ BYTE length = ppdesc->length;
//if (debug)
// myprintf(L"sous_type : %02X, sous_taille : %i\n", tag, length);
@@ -348,7 +346,7 @@
}
*/
-struct SDT_descriptor : public descriptor {
+struct SDT_descriptor : public MDescriptor {
BYTE service_type;
//
// Méthodes d'extraction :
@@ -475,7 +473,7 @@
}
*/
-struct LogicalChannelEntry { // pour tag 0x83
+struct MSubDescr_83 { // pour tag 0x83
BYTE service_id_hi;
BYTE service_id_lo;
BYTE logical_channel_number_hi;
@@ -488,7 +486,7 @@
{return ((logical_channel_number_hi & 0x03)<<8) | logical_channel_number_lo;}
};
-struct NIT_entry {
+struct SI_NIT_entry {
BYTE tsid_hi;
BYTE tsid_lo;
BYTE onid_hi;
@@ -503,10 +501,10 @@
{return (onid_hi<<8) | onid_lo;}
WORD length() const
{return ((transport_descriptors_length_hi & 0x0f)<<8) | transport_descriptors_length_lo;}
- const NIT_entry * next() const
- {return (const NIT_entry *)(LPBYTE(this+1)+length());}
- const descriptor * begin() const
- {return (const descriptor *)(this+1);}
+ const SI_NIT_entry * next() const
+ {return (const SI_NIT_entry *)(LPBYTE(this+1)+length());}
+ const MDescriptor * begin() const
+ {return (const MDescriptor *)(this+1);}
const LPBYTE end() const
{return LPBYTE(this+1)+length();}
};
@@ -519,8 +517,8 @@
// Méthodes d'extraction :
WORD length() const
{return ((transport_stream_loop_length_hi & 0x0f)<<8) | transport_stream_loop_length_lo;}
- const NIT_entry * begin() const
- {return (const NIT_entry *)(this+1);}
+ const SI_NIT_entry * begin() const
+ {return (const SI_NIT_entry *)(this+1);}
const LPBYTE end() const
{return LPBYTE(this+1)+length();}
};
@@ -532,8 +530,8 @@
// Méthodes d'extraction :
WORD length() const
{return ((network_descriptors_length_hi & 0x0f)<<8) | network_descriptors_length_lo;}
- const descriptor * begin() const
- {return (const descriptor *)(this+1);}
+ const MDescriptor * begin() const
+ {return (const MDescriptor *)(this+1);}
const LPBYTE end() const
{return LPBYTE(this+1)+length();}
const SI_NIT_entries_hdr & entries_hdr() const
@@ -543,10 +541,10 @@
static void parse_nit(const SI_NIT & nit, int max)
{
#if USE_CONSOLE
- for (const descriptor * pndesc = nit.begin(); LPBYTE(pndesc)next()) {
- if (pndesc->descriptor_tag == 0x40) {
+ for (const MDescriptor * pndesc = nit.begin(); LPBYTE(pndesc)next()) {
+ if (pndesc->tag == 0x40) {
char nom[256];
- BYTE taille = pndesc->descriptor_length;
+ BYTE taille = pndesc->length;
//
memcpy(nom, pndesc->begin(), taille);
nom[taille] = 0;
@@ -557,7 +555,7 @@
const SI_NIT_entries_hdr & nit_e = nit.entries_hdr();
- for (const NIT_entry * pnent = nit_e.begin();
+ for (const SI_NIT_entry * pnent = nit_e.begin();
LPBYTE(pnent) < nit_e.end(); pnent=pnent->next()
) {
ChaineIDs chIDs;
@@ -567,14 +565,14 @@
// myprintf(L"parse_nit: TSID=%i, ONID=%i, taille=%i\n", chIDs.TSID, chIDs.ONID, pnent->length());
- for (const descriptor * ptdesc = pnent->begin();
+ for (const MDescriptor * ptdesc = pnent->begin();
LPBYTE(ptdesc)end(); ptdesc=ptdesc->next()
) {
- // myprintf(L"parse_nit: type : %02X, taille : %i\n", ptdesc->descriptor_tag, ptdesc->descriptor_length);
+ // myprintf(L"parse_nit: type : %02X, taille : %i\n", ptdesc->tag, ptdesc->length);
- if (ptdesc->descriptor_tag == 0x83) {
+ if (ptdesc->tag == 0x83) {
for (
- const LogicalChannelEntry * plchent = (const LogicalChannelEntry *)ptdesc->begin();
+ const MSubDescr_83 * plchent = (const MSubDescr_83 *)ptdesc->begin();
LPBYTE(plchent)end(); plchent++
) {
chIDs.SID = plchent->sid();
From pouchintv-svn at baysse.fr Sat Mar 8 22:01:26 2008
From: pouchintv-svn at baysse.fr (pouchintv-svn at baysse.fr)
Date: Sat, 8 Mar 2008 22:01:26 +0100 (CET)
Subject: [Pouchintv-dev] [PouchinTVMod] gingko | r117 - trunk
Message-ID: <20080308210126.C338E5F5EF@mail.baysse.fr>
Author: gingko
Date: 2008-03-08 22:01:26 +0100 (Sat, 08 Mar 2008)
New Revision: 117
Added:
trunk/capture.cpp
trunk/capture.h
Modified:
trunk/
trunk/Pouchin TV.vcproj
trunk/grabber.cpp
trunk/grabber.h
trunk/record.cpp
Log:
R?\195?\169?\195?\169criture de la fonctionnalit?\195?\169 "capture", pour les enregistrements en
mode PS et TS.
Cette fonctionnalit?\195?\169 se trouve maintenant dans la paire de fichiers
"capture.h" et "capture.cpp", afin de g?\195?\169rer cette fonction de fa?\195?\167on
plus autonome (le couple "grabber.h" / "grabber.cpp" ne contient
maintenant plus que l'extension n?\195?\169cessaire ?\195?\160 DirectShow pour
r?\195?\169cup?\195?\169rer les ?\195?\169chantillons ?\195?\160 enregistrer).
Les fichiers PS g?\195?\169n?\195?\169r?\195?\169s devraient maintenant ?\195?\170tre plus fonctionnels
que pr?\195?\169c?\195?\169demment, en tout cas, ils semblent fonctionner correctement
au moins avec MPC, VLC et Windows Media Player.
Property changes on: trunk
___________________________________________________________________
Name: tsvn:logminsize
+ 100
Modified: trunk/Pouchin TV.vcproj
===================================================================
--- trunk/Pouchin TV.vcproj 2008-03-08 19:06:30 UTC (rev 116)
+++ trunk/Pouchin TV.vcproj 2008-03-08 21:01:26 UTC (rev 117)
@@ -712,6 +712,10 @@
>
+
+
@@ -822,6 +826,10 @@
>
+
+
Added: trunk/capture.cpp
===================================================================
--- trunk/capture.cpp (rev 0)
+++ trunk/capture.cpp 2008-03-08 21:01:26 UTC (rev 117)
@@ -0,0 +1,562 @@
+/*
+ * capture.cpp
+ * Copyright (C) 2006 Pouchin
+ *
+ * This file is part of Pouchin TV, a free DVB-T viewer.
+ * See http://pouchinteve.free.fr/ for updates.
+ *
+ * Pouchin TV 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 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
+ *
+ *
+ * This was changed from the Pouchin TV project, to use with
+ * a modified version of this software.
+ * See http://pouchintv.baysse.fr/ for updates.
+ */
+
+#include "base.h"
+#include "grabber.h"
+#include "main.h"
+#include "mpeg2defs.h"
+
+/* Constructeur de base */
+CCapture::CCapture(HANDLE hFil) :
+ hFile(hFil)
+{
+}
+
+//UINT64 CCapture::pos_fichier(void)
+//{
+// LARGE_INTEGER filepos;
+//
+// filepos.QuadPart = 0;
+// if (SetFilePointerEx(hFile, filepos, &filepos, FILE_CURRENT)!=0)
+// return UINT64(filepos.QuadPart);
+// return 0;
+//}
+
+// Sortie d'un bloc de données vers le fichier
+BOOL CCapture::ecrit_fichier(LPCVOID pBuf, DWORD sizBuf) const
+{
+ DWORD written;
+
+ return WriteFile(hFile, pBuf, sizBuf, &written, NULL);
+}
+
+// (peut-être appelé transitoirement pendant la destruction) :
+void CCapture::traite_paquet(const TS_packet & p) // virtual
+{
+}
+
+/* Destructeur général */
+
+CCapture::~CCapture()
+{
+ myprintf(L"Grabber détruit\n");
+ CloseHandle(hFile);
+}
+
+CCapture_TS::CCapture_TS(
+ HANDLE hFil, int pmt, int video,
+ const liste_pistes & lst_sons,
+ const liste_pistes & lst_autr) :
+ CCapture(hFil),
+ video_pid(video),
+ pmt_pid(pmt),
+ sons(lst_sons),
+ autr(lst_autr)
+{
+}
+
+void CCapture_TS::traite_paquet(const TS_packet & p) // virtual
+{
+ // une chaîne en TS
+ UINT16 pid = p.hdr.pid();
+
+ if (
+ pid == p_pid_PAT ||
+ pid == pmt_pid ||
+ pid == video_pid ||
+ sons.cherche_pid(pid) ||
+ autr.cherche_pid(pid)
+ )
+ ecrit_fichier(p.bytes, TS_SIZE);
+}
+
+// ************************************************************
+
+// Limites du champ "program mux rate".
+// Le programme essaie d'estimer la valeur réelle, mais si le résultat sort de ces limites,
+// la limite correspondante sera utilisée en remplacement.
+#define MIN_PROGRAM_MUX_RATE (0x1000*50)
+#define MAX_PROGRAM_MUX_RATE (0x3000*50)
+
+class PS_chunk
+{
+ const PS_hdr_wd & src_hdr; // Référence sur l'en-tête source
+ CCapture_PS & cGrabber;
+public:
+ UINT32 ixBuf;
+ PS_hdr_wd * p_curPES; // Pointeur sur l'en-tête du PES en cours de construction
+ UINT8 buffer[0x800];
+
+ PS_chunk(const PS_hdr_wd & hdr, PS_buffer & cBuff);
+
+ // Ajout d'un bloc "Pack Header" :
+ // (retourne la taille du bloc ajouté, ou bien 0 si échec)
+ size_t addPackHeader();
+
+ // Ajout d'un bloc "System Header" :
+ // (retourne la taille du bloc ajouté, ou bien 0 si échec)
+ size_t addSystemHeader();
+
+ // Ajout d'un bloc PES de base, dérivé du bloc source 'p_src_hdr' :
+ // (retourne la taille du bloc ajouté, ou bien 0 si échec)
+ size_t addPES_Header(IF_DEBUG(LPCSTR nom_debug));
+
+ // Ajout d'un bloc PES d'extension, dérivé du bloc source 'p_src_hdr' :
+ // (retourne la taille du bloc ajouté, ou bien 0 si échec)
+ size_t addPES_extHeader();
+
+ // Compléter le bloc avec un PES de padding, en laissant néanmoins
+ // éventuellement un espace de taille égale = 'guard' à la fin.
+ // Si l'ajustement requis est très faible, alors l'ajustement se fera, à la place,
+ // en ajoutant des octets de "stuffing" dans l'en-tête.
+ // Retourne la quantité de données *ajoutées* au buffer :
+ size_t add_Padding(size_t guard=0);
+
+ // Ajout de données dans le bloc. Retourne 'true' si la totalité des données ont pu être ajoutées,
+ // 'false' sinon ; dans ce dernier cas, rien n'est modifié.
+ bool addData(const UINT8 * ptr, size_t size);
+
+ // Ajout de données dans le bloc. Retourne 'true' si la totalité des données ont pu être ajoutées,
+ // 'false' sinon ; dans ce dernier cas, 'ptr' et 'size' sont ajustés sur les données restantes.
+ bool addPES_data(const UINT8 * & ptr, size_t & size);
+
+ // Ajustement de l'index du buffer pour que les données subséquentes s'inscrivent
+ // à partir de l'adresse 'ptr' :
+ PUINT8 setBufferIndex(PUINT8 ptr)
+ {ixBuf = UINT16(ptr-&buffer[0]); return ptr;}
+
+ // Construction d'un buffer contenant autant de données que possible parmi celles restant disponibles.
+ // S'il ne reste pas assez de données disponibles pour remplir le buffer, des données de remplissage
+ // sont ajoutées.
+ // La fonction retourne le nombre d'octets *ajoutés* (en-têtes, remplissage, etc) par rapport au flot
+ // d'origine.
+ size_t build(bool start, const UINT8 * & ptr, size_t & size IF_DEBUG_CB(LPCSTR nom_debug));
+
+ // Vidange du tampon dans le fichier :
+ void write_to_file();
+};
+
+PS_chunk::PS_chunk(const PS_hdr_wd & hdr, PS_buffer & cBuff) :
+ src_hdr(hdr),
+ cGrabber(*cBuff.pcGrab),
+ ixBuf(0),
+ p_curPES(NULL)
+{
+}
+// Construction d'un buffer contenant autant de données que possible parmi celles restant disponibles.
+// S'il ne reste pas assez de données disponibles pour remplir le buffer, des données de remplissage
+// sont ajoutées.
+// La fonction retourne le nombre d'octets *ajoutés* (en-têtes, remplissage, etc) par rapport au flot
+// d'origine.
+size_t PS_chunk::build(bool start, const UINT8 * & ptr, size_t & size IF_DEBUG_CB(LPCSTR nom_debug))
+{
+ size_t added_bytes = 0;
+
+ if (start) {
+ added_bytes += addPackHeader();
+ if (!cGrabber.sys_header_set) {
+ added_bytes += addSystemHeader();
+ cGrabber.sys_header_set = true;
+ }
+ //
+ size_t hdsize = addPES_Header(IF_DEBUG(nom_debug));
+ // Le premier en-tête existait dans le tampon source, on le saute donc en lecture
+ ptr += hdsize;
+ size -= hdsize;
+ } else
+ // Les en-têtes subséquents sont ajoutés, donc on n'enlève pas de données de la source
+ added_bytes += addPES_extHeader();
+
+ addPES_data(ptr, size);
+ if (size==0)
+ added_bytes += add_Padding();
+ return added_bytes;
+}
+
+void PS_chunk::write_to_file()
+{
+ cGrabber.ecrit_fichier(buffer, sizeof(buffer));
+}
+
+// Ajout de données dans le bloc. Retourne 'true' si la totalité des données ont pu être ajoutées,
+// 'false' sinon ; dans ce dernier cas, rien n'est modifié.
+bool PS_chunk::addData(const UINT8 * ptr, size_t size)
+{
+ if (ixBuf+size <= _countof(buffer)) {
+ memcpy(&buffer[ixBuf], ptr, size);
+ ixBuf = ixBuf + UINT16(size);
+ return true;
+ }
+ return false;
+}
+
+// Ajout de données dans le bloc. Retourne 'true' si la totalité des données ont pu être ajoutées,
+// 'false' sinon ; dans ce dernier cas, 'ptr' et 'size' sont ajustés sur les données restantes.
+bool PS_chunk::addPES_data(const UINT8 * & ptr, size_t & size)
+{
+ UINT32 adjustedSize = UINT32(size);
+ bool fit = ixBuf+size <= _countof(buffer);
+
+ if (!fit)
+ adjustedSize = sizeof(buffer) - ixBuf;
+
+ addData(ptr, adjustedSize);
+ ptr += adjustedSize;
+ size -= adjustedSize;
+ if (p_curPES)
+ p_curPES->set_data_size(&buffer[ixBuf]);
+
+ return fit;
+}
+
+// Ajout d'un bloc "Pack header" :
+size_t PS_chunk::addPackHeader()
+{
+ if (sizeof(PS_chunk)-ixBuf >= sizeof(PS_PackHeader)) {
+ PS_PackHeader & phdr = *new(&buffer[ixBuf])PS_PackHeader(); // "Placement" new
+
+ phdr.scr = cGrabber.getAdjustedPcr(); // transformation par opérateur surchargé
+ phdr.mux_rate = cGrabber.byte_mux_rate/50;
+ phdr.length = 0xf8;
+ setBufferIndex(phdr.end_of_header());
+ return phdr.packet_size();
+ }
+
+ return 0;
+}
+
+// Ajout d'un bloc "System Header" :
+size_t PS_chunk::addSystemHeader()
+{
+ if (sizeof(PS_chunk)-ixBuf >= sizeof(PS_SystemHeader)+2*sizeof(PS_SH_entry)) {
+ PS_SystemHeader & shd = *new (&buffer[ixBuf])PS_SystemHeader(); // "Placement" new
+
+ shd.rate_bound = MAX_PROGRAM_MUX_RATE;
+ shd.audio_bound_and_flags = 1<<2; // SH_FIXED_FLAG=0, SH_CSPS_FLAG=0
+ shd.video_bound_and_flags = 1|0x20; // SH_SYSTEM_AUDIO_LOCK_FLAG=0, SH_SYSTEM_VIDEO_LOCK_FLAG =0, 0x20=marker bit
+ shd.packet_rate_restriction_flag = 0; // SH_PACKET_RATE_RESTRICTION_FLAG=0
+
+ shd[0].stream_id = PES_SB_ALLAUDIO_SID;
+ shd[0].bound_buf.set_size(0, 0x20); // 0x001000
+ shd[1].stream_id = PES_SB_ALLVIDEO_SID;
+ shd[1].bound_buf.set_size(1, 0xe8); // 0x03a000
+ shd.set_data_size(setBufferIndex(PUINT8(shd[1].next())));
+ return shd.packet_size();
+ }
+
+ return 0;
+}
+
+// Ajout d'un bloc PES de base, dérivé du bloc source 'p_src_hdr' :
+// (retourne la taille du bloc ajouté, ou bien 0 si échec)
+size_t PS_chunk::addPES_Header(IF_DEBUG(LPCSTR nom_debug))
+{
+ if (sizeof(PS_chunk)-ixBuf >= sizeof(PS_hdr_wd)) {
+ PS_hdr_wd & dst_hdr = *new (&buffer[ixBuf]) PS_hdr_wd(src_hdr); // "Placement" new
+
+ p_curPES = &dst_hdr;
+
+#ifdef _DEBUG
+ PS_data_unwrapper_full uw_ph(dst_hdr);
+#else
+ PS_data_unwrapper_base uw_ph(dst_hdr);
+#endif
+
+ // Ajustement des champs de timing pour les ramener à une base commençant au début du
+ // fichier :
+ if (uw_ph.p_pts) {
+ *uw_ph.p_pts = cGrabber.adjustTime(*uw_ph.p_pts);
+ // myprintf(L"PS pts = %10.6f (%S)\n", UINT64(*uw_ph.p_pts)/27000000.0, nom_debug);
+ }
+ if (uw_ph.p_dts) {
+ *uw_ph.p_dts = cGrabber.adjustTime(*uw_ph.p_dts);
+ // myprintf(L"PS dts = %10.6f (%S)\n", UINT64(*uw_ph.p_dts)/27000000.0, nom_debug);
+ }
+ if (uw_ph.p_escr) {
+ *uw_ph.p_escr = cGrabber.adjustTime(*uw_ph.p_escr);
+ // myprintf(L"PS escr = %10.6f (%S)\n", UINT64(*uw_ph.p_escr)/27000000.0, nom_debug);
+ }
+
+ setBufferIndex(dst_hdr.end_of_header());
+ return dst_hdr.header_size();
+ }
+
+ return 0;
+}
+
+// Ajout d'un bloc PES d'extension, dérivé du bloc source 'p_src_hdr' :
+size_t PS_chunk::addPES_extHeader()
+{
+ if (sizeof(PS_chunk)-ixBuf >= sizeof(PS_hdr_wd)) {
+ PS_hdr_wd & dst_hdr = *new (&buffer[ixBuf])PS_hdr_wd(src_hdr); // "Placement" new
+
+ p_curPES = &dst_hdr;
+ dst_hdr.info &= ~DATA_ALIGNMENT_INDICATOR; // reset data aligment indicator
+ dst_hdr.flags = 0; // aucun champ ajouté
+ dst_hdr.data_length = 0; // longueur de champs ajoutés nulle
+ setBufferIndex(dst_hdr.end_of_header());
+ return dst_hdr.header_size();
+ }
+
+ return 0;
+}
+
+// Compléter le bloc avec un PES de padding, en laissant néanmoins
+// éventuellement un espace de taille égale = 'guard' à la fin.
+// Retourne la quantité de données *ajoutées* au buffer.
+size_t PS_chunk::add_Padding(size_t guard)
+{
+ UINT16 remain = UINT16(sizeof(buffer)-guard-ixBuf);
+
+ if (remain>0) {
+ if (remain >= 0x10) {
+ PS_hdr_wl & hdr = *new (&buffer[ixBuf])PS_hdr_wl(sid_Padding_Stream); // "Placement" new
+
+ remain -= sizeof(PS_hdr_wl);
+ hdr.hdr_length = remain;
+ memset(hdr.base_of_data_size(), 0xff, remain);
+ cGrabber.byte_count += remain;
+ return hdr.packet_size();
+ } else {
+ if (p_curPES) {
+ PUINT8 base_ptr = p_curPES->base_of_data();
+
+ memmove(base_ptr+remain, base_ptr, &buffer[ixBuf]-base_ptr);
+ memset(base_ptr, 0xff, remain);
+ ixBuf = ixBuf + UINT16(remain);
+ p_curPES->data_length = p_curPES->data_length + UINT8(remain);
+ p_curPES->set_data_size(&buffer[ixBuf]);
+ cGrabber.byte_count += p_curPES->packet_size();
+ return remain;
+ }
+ }
+ }
+
+ return 0;
+}
+
+// ************************************************************
+
+PS_buffer::PS_buffer(int used_pid, UINT8 maxChnk IF_DEBUG_CB(LPCSTR nom_dbg)) :
+ pcGrab(NULL),
+ IF_DEBUG_CA(nom_debug(nom_dbg))
+ pid(used_pid),
+ valid(false),
+ continuity_counter(0)
+{
+ reserve(maxChnk*sizeof(PS_chunk));
+};
+
+void PS_buffer::traite_paquet(const TS_packet & p)
+{
+ const TS_unwrapper uw_th(p.hdr);
+ bool new_PES_starts_here = p.hdr.payload_unit_start_indicator();
+ UINT8 new_ccounter = p.hdr.continuity_counter();
+ UINT8 diff_ccounter = (new_ccounter - continuity_counter) & 0x0f;
+
+ continuity_counter = new_ccounter;
+
+ // Vérification de la continuité :
+ if (diff_ccounter == 0) {
+ myprintf(L"paquet dupliqué dans %S\n", nom_debug);
+ return; // ignorer
+ }
+
+ if (diff_ccounter != 1) {
+ myprintf(L"discontinuité dans %S\n", nom_debug);
+
+ // envoie le paquet (incomplet) qui était en cours de construction
+ flush();
+
+ // Marque la suite comme invalide, sauf si un nouveau paquet commence justement ici :
+ valid = false;
+ }
+
+ if (new_PES_starts_here) {
+ if (pcGrab->capt_state >= cs_stopping) {
+ flush();
+ valid = false;
+ } else
+ valid = true;
+ }
+
+ if (valid && uw_th.p_payload) {
+ // Paquet valide et "Payload" présent
+ size_t ptr_size = &p.bytes[TS_SIZE]-uw_th.p_payload;
+
+ pcGrab->byte_count += ptr_size;
+ put_data(uw_th.p_payload, ptr_size, new_PES_starts_here);
+ }
+}
+
+void PS_buffer::send()
+{
+ const UINT8 * ptr = data_ptr();
+ size_t size = data_size;
+ const PS_hdr_wd & hdr = *reinterpret_cast(ptr);
+ bool start = true;
+ size_t added_bytes = 0;
+
+ while (size>0) {
+ PS_chunk chunk(hdr, *this);
+
+ added_bytes += chunk.build(start, ptr, size IF_DEBUG_CB(nom_debug));
+ chunk.write_to_file();
+ start = false;
+ }
+
+ pcGrab->byte_count += added_bytes;
+}
+
+CCapture_PS::CCapture_PS(HANDLE hFil, int video, int audio) :
+ CCapture(hFil),
+ first_pcr(0),
+ curr_pcr(0),
+ last_pcr(0),
+ curr_pcr_second(UINT32(-1)),
+ pck_pcr_count(0),
+ pcr_rate(7500), // estimation
+ byte_count(0),
+ byte_mux_rate((MIN_PROGRAM_MUX_RATE+MAX_PROGRAM_MUX_RATE)/2),
+ capt_state(cs_idle),
+ sys_header_set(false),
+ video_build(video, 128 IF_DEBUG_CB("la vidéo")),
+ audio_build(audio, 32 IF_DEBUG_CB("le son"))
+{
+ video_build.pcGrab = this;
+ audio_build.pcGrab = this;
+ if (fichier_valide()) {
+ capt_state = cs_started;
+ } else
+ capt_state = cs_error;
+}
+
+void CCapture_PS::traite_paquet(const TS_packet & p) // virtual
+{
+ // une chaîne en PS
+ UINT16 pid = p.hdr.pid();
+
+ if (capt_state==cs_idle || (pid != video_build.pid && pid != audio_build.pid))
+ return;
+
+ const TS_unwrapper uw_th(p.hdr); // Déballage de l'en-tête
+
+ if (uw_th.p_afield) {
+ // L'en-tête contient un champ "adaptation field" : déballage de ce champ :
+ TS_AF_unwrapper_base uw_af(*uw_th.p_afield);
+ if (uw_af.p_pcr) {
+
+ // Ce champ "adaptation field" contient un échantillon
+ // de l'horloge de référence du programme
+ UINT64 new_pcr = *uw_af.p_pcr;
+ UINT32 diff_time = UINT32(new_pcr-last_pcr);
+
+ if (capt_state>=cs_first_pcr_set) {
+ if (diff_time>0 && pck_pcr_count>=32) {
+ // Estimation du temps moyen qui sépare deux paquests TS du même canal :
+ pcr_rate_helper.submit(diff_time/pck_pcr_count);
+ pcr_rate = pcr_rate_helper.mean();
+ // myprintf(L"pcr rate=%u (packet count=%u)\n", pcr_rate, pck_pcr_count);
+ pck_pcr_count = 0;
+ }
+ } else {
+ first_pcr = new_pcr;
+ capt_state = cs_first_pcr_set;
+ byte_count = 0;
+ curr_pcr_second = UINT32(-1);
+ }
+ if (new_pcr > last_pcr)
+ last_pcr = new_pcr;
+ //myprintf(L"TS pcr = %10.6f (ajusté = %10.6f)\n",
+ // new_pcr/27000000.0, (new_pcr-first_pcr)/27000000.0);
+ }
+ }
+
+ if (capt_state>=cs_first_pcr_set) {
+ UINT64 new_pcr = last_pcr+(pcr_rate*(pck_pcr_count++));
+
+ if (new_pcr > curr_pcr)
+ curr_pcr = new_pcr;
+
+ UINT32 second = UINT32(curr_pcr/27000000);
+
+ // Evaluations statistiques :
+ if (second != curr_pcr_second) {
+ myprintf(L"second=%u\n", second);
+ // Section appelée à chaque nouvelle seconde du PCR
+ curr_pcr_second = second;
+ switch (capt_state) {
+
+ case cs_first_pcr_set:
+ if (video_build.valid && audio_build.valid) {
+ capt_state = cs_running;
+ byte_count = 0;
+ }
+ break;
+
+ case cs_running:
+ if (byte_count > 0) {
+ // Évaluation du "multiplex rate" :
+ mux_rate_helper.submit(byte_count);
+
+ UINT32 mux_rate = mux_rate_helper.mean();
+
+ byte_mux_rate = max(MIN_PROGRAM_MUX_RATE, min(MAX_PROGRAM_MUX_RATE, mux_rate));
+ myprintf(L"mux rate=0x%05x, avg=0x%05x\n", byte_count/50, byte_mux_rate/50);
+ byte_count = 0;
+ }
+ }
+ }
+
+ if (pid == video_build.pid)
+ video_build.traite_paquet(p);
+ else
+ audio_build.traite_paquet(p);
+ }
+}
+
+CCapture_PS::~CCapture_PS()
+{
+ capt_state = cs_stopping;
+ Sleep(200); // Laisser les paquets en cours se terminer
+
+ PS_hdr prog_end(sid_Program_End);
+
+ ecrit_fichier(&prog_end, sizeof(prog_end));
+}
+
+CCapture_Stream::CCapture_Stream(HANDLE hFil) :
+ CCapture(hFil)
+{
+}
+
+void CCapture_Stream::traite_paquet(const TS_packet & p) // virtual
+{
+ // full TS
+ if (p.hdr.pid() != p_pid_NULL)
+ ecrit_fichier(p.bytes, TS_SIZE);
+}
Added: trunk/capture.h
===================================================================
--- trunk/capture.h (rev 0)
+++ trunk/capture.h 2008-03-08 21:01:26 UTC (rev 117)
@@ -0,0 +1,147 @@
+/*
+ * capture.h
+ * Copyright (C) 2006 Pouchin
+ *
+ * This file is part of Pouchin TV, a free DVB-T viewer.
+ * See http://pouchinteve.free.fr/ for updates.
+ *
+ * Pouchin TV 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 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
+ *
+ *
+ * This was changed from the Pouchin TV project, to use with
+ * a modified version of this software.
+ * See http://pouchintv.baysse.fr/ for updates.
+ */
+
+#pragma once
+
+#include "base.h"
+#include "chanutils.h"
+#include "sbuffer.h"
+#include "mpeg2defs.h"
+
+class CCapture
+{
+ HANDLE hFile;
+
+protected:
+
+ CCapture(HANDLE hFil);
+
+ // Sortie d'un bloc de données vers le fichier
+ BOOL ecrit_fichier(LPCVOID pBuf, DWORD sizBuf) const;
+
+public:
+
+ virtual void traite_paquet(const TS_packet & p);
+
+ bool fichier_valide() const
+ {return hFile!=INVALID_HANDLE_VALUE;}
+ // UINT64 pos_fichier(void);
+
+ virtual ~CCapture();
+};
+
+class CCapture_TS : public CCapture
+{
+ int video_pid;
+ int pmt_pid;
+ liste_pistes sons;
+ liste_pistes autr;
+
+public:
+
+ CCapture_TS(HANDLE hFil, int pmt, int video,
+ const liste_pistes & lst_sons,
+ const liste_pistes & lst_autr);
+
+ virtual void traite_paquet(const TS_packet & p);
+};
+
+class PS_buffer : public StreamBuffer
+{
+ friend class CCapture_PS;
+ friend class PS_chunk;
+
+ CCapture_PS * pcGrab;
+ IF_DEBUG(LPCSTR nom_debug;)
+ int pid;
+ bool valid;
+ UINT8 continuity_counter;
+
+public:
+ PS_buffer(int used_pid, UINT8 maxChnk IF_DEBUG_CB(LPCSTR nom_dbg));
+
+ void traite_paquet(const TS_packet & p);
+
+ virtual void send();
+
+ ~PS_buffer()
+ {}
+};
+
+typedef MeanHelper RateHelper;
+
+// état de construction d'une capture PS :
+enum CaptureState {
+ cs_idle,
+ cs_error,
+ cs_started,
+ cs_first_pcr_set, // au moins une référence d'horloge a été reçue
+ cs_running, // tous les flux sont en cours de capture
+ cs_stopping, // arrêt en cours
+ cs_finished // capture terminée
+};
+
+class CCapture_PS : public CCapture
+{
+ friend class PS_buffer;
+ friend class PS_chunk;
+
+ UINT64 first_pcr; // Mémorisation du 1er PCR pour recalage à zéro des suivants
+ UINT64 curr_pcr; // PCR courant (interpolation)
+ UINT64 last_pcr; // Dernier PCR reçu
+ UINT32 curr_pcr_second; // Seconde entière du PCR courant (pour tests statistiques)
+ UINT32 pck_pcr_count; // Comptage des paquets "TS" depuis le dernier PCR reçu
+ UINT32 pcr_rate; // Taux d'incrémentation du PCR par paquet
+ size_t byte_count; // Comptage des octets émis en mode PS pour calcul "multiplex rate"
+ UINT32 byte_mux_rate; // "multiplex rate" courant, calculé en octets par seconde
+ RateHelper pcr_rate_helper; // assistance au calcul de l'intervalle de temps moyen entre paquets TS
+ RateHelper mux_rate_helper; // assistance au calcul du "multiplex rate"
+ CaptureState capt_state; // état de progression de la capture
+ bool sys_header_set; // l'enregistrement "System Header" a été émis
+ PS_buffer video_build;
+ PS_buffer audio_build;
+
+public:
+ CCapture_PS(HANDLE hFil, int video, int audio);
+
+ virtual void traite_paquet(const TS_packet & p);
+
+ UINT64 adjustTime(UINT64 t) const
+ {return t-first_pcr;}
+ UINT64 getAdjustedPcr() const
+ {return adjustTime(curr_pcr);}
+
+ virtual ~CCapture_PS();
+};
+
+class CCapture_Stream : public CCapture // -> Multiplex
+{
+public:
+ CCapture_Stream(HANDLE hFil);
+
+ virtual void traite_paquet(const TS_packet & p);
+};
Modified: trunk/grabber.cpp
===================================================================
--- trunk/grabber.cpp 2008-03-08 19:06:30 UTC (rev 116)
+++ trunk/grabber.cpp 2008-03-08 21:01:26 UTC (rev 117)
@@ -29,15 +29,12 @@
#include "grabber.h"
-#include "main.h"
/* Constructeur de base */
-CSampleGrabber::CSampleGrabber(HANDLE hFil, int video, int audio) :
+CSampleGrabber::CSampleGrabber(CCapture * pCapt) :
CUnknown(L"Sample grabber", NULL),
- hFile(hFil),
- taille_paquet_buf(0),
- video_pid(video),
- audio_pid(audio)
+ pCapture(pCapt),
+ taille_paquet_buf(0)
{
}
@@ -47,7 +44,7 @@
BYTE * p;
long l = pSample->GetActualDataLength();
-// myprintf(L"taille %i\n", l);
+ //myprintf(L"taille %i\n", l);
pSample->GetPointer(&p);
@@ -55,22 +52,22 @@
// Récupération du fragment de paquet éventuellement reçu à la fin de l'appel précédent :
if (taille_paquet_buf) {
- i = 188 - taille_paquet_buf;
+ i = TS_SIZE - taille_paquet_buf;
- memcpy(&paquet_buf[taille_paquet_buf], p, i);
- traite_paquet(paquet_buf, ((paquet_buf[1]&0x1F) << 8 ) + paquet_buf[2]);
+ memcpy(paquet_buf.bytes, p, i);
+ traite_paquet(paquet_buf);
taille_paquet_buf = 0;
}
// Traitement de tous les paquets entiers reçus ici :
- while ( i + 188 <= l){
+ while ( i + TS_SIZE <= l){
- if (p[i] == 0x47 && (i+188==l || p[i+188] == 0x47) ) {
- traite_paquet(p+i, ((p[i+1]&0x1F) << 8) + p[i+2]);
- i += 188;
+ if (reinterpret_cast(p+i)->isTS(i+TS_SIZE>=l)) {
+ traite_paquet(*reinterpret_cast(p+i));
+ i += TS_SIZE;
} else {
// cherche prochaine synchro
- BYTE * res = (BYTE *)memchr(&p[i+1], 0x47, l-i-1);
+ BYTE * res = (BYTE *)memchr(&p[i+1], TS_SYNC, l-i-1);
if (res == NULL) {
// rien trouvé, plus rien a faire
@@ -86,7 +83,7 @@
// Report du fragment résiduel à la fin pour l'appel suivant :
if (i != l) {
taille_paquet_buf = BYTE(l - i);
- memcpy(paquet_buf, &p[i], taille_paquet_buf);
+ memcpy(paquet_buf.bytes, p+i, taille_paquet_buf);
}
return S_OK;
@@ -100,302 +97,19 @@
return S_OK;
}
-// Sortie d'un bloc de données vers le fichier
-BOOL CSampleGrabber::ecrit_fichier(LPCVOID pBuf, DWORD sizBuf) const
-{
- DWORD written;
- return WriteFile(hFile, pBuf, sizBuf, &written, NULL);
-}
-
-// (peut-être appelé transitoirement pendant la destruction) :
-void CSampleGrabber::traite_paquet(BYTE * p, WORD pid) // virtual
+void CSampleGrabber::traite_paquet(const TS_packet & p) // virtual
{
+ if (pCapture)
+ pCapture->traite_paquet(p);
}
/* Destructeur général */
+
CSampleGrabber::~CSampleGrabber()
{
- myprintf(L"Grabber détruit\n");
- CloseHandle(hFile);
-}
-
-CSampleGrabber_TS::CSampleGrabber_TS(
- HANDLE hFil, int pmt, int video,
- const liste_pistes & lst_sons,
- const liste_pistes & lst_autr) :
- CSampleGrabber(hFil, video, 0),
- pmt_pid(pmt),
- sons(lst_sons),
- autr(lst_autr)
-{
- myprintf(L"Enregistre TS, video=%i, pmt=%i\n", video, pmt_pid);
-}
-
-void CSampleGrabber_TS::traite_paquet(BYTE * p, WORD pid) // virtual
-{
- // une chaîne en TS
- if (
- pid == 0 ||
- pid == pmt_pid ||
- pid == video_pid ||
- sons.cherche_pid(pid) ||
- autr.cherche_pid(pid)
- )
- ecrit_fichier(p, 188);
-}
-
-CSampleGrabber_PS::CSampleGrabber_PS(HANDLE hFil, int video, int audio) :
- CSampleGrabber(hFil, video, audio),
- taille_vid(0),
- vid_valid(false),
- taille_son(0),
- son_valid(false),
- pcr_ecrit(false)
-{
- myprintf(L"Enregistre PS, video=%i, audio=%i\n", video, audio);
-}
-
-void CSampleGrabber_PS::traite_paquet(BYTE * p, WORD pid) // virtual
-{
- // une chaîne en PS
-
- if (pid == video_pid) {
-
- // si la video est valide, on verifie que pas de discontinuité
- if (vid_valid) {
- int current = p[3]&15;
-
- if ( ( (current - vid_continuity_counter) & 15 ) != 1 ) {
- myprintf(L"discontinuite dans la video\n");
-
- vid_valid = false;
-
- // jette le paquet qu'on a
- if (taille_vid && pcr_ecrit) {
- ecrit_video();
- }
-
- taille_vid = 0;
- }
- }
-
-
- if (p[1] & 0x40) {
- // start indicator
-
- vid_valid = true;
-
- // on sauve ce qu'on a en stock
- if (taille_vid && pcr_ecrit){
- ecrit_video();
- }
-
- taille_vid = 0;
-
- }
-
- if (vid_valid) {
- vid_continuity_counter = p[3]&15;
-
- if (p[3] & 0x10) {
- // il y a du payload
-
- if (p[3] & 0x20) {
- // et adaptation field
- unsigned int taille = p[4]+1;
-
- if (taille < 184) {
- unsigned int taille_copie = 184-taille;
-
- if (taille_vid + taille_copie <= sizeof(vid_buf) ) {
- memcpy(&vid_buf[taille_vid], &p[4+taille], taille_copie);
- taille_vid += taille_copie;
- }
-
- if (p[5] & 0x10) {
- pcr_block(p);
- }
- }
- } else {
- if (taille_vid + 184 <= sizeof(vid_buf) ) {
- memcpy(&vid_buf[taille_vid], &p[4], 184);
- taille_vid += 184;
- }
-
- }
- }
- }
-
- } else if (pid == audio_pid) {
- // si le son est valide, on verifie que pas de discontinuité
- if (son_valid) {
- int current = p[3]&15;
-
- if ( ( (current - son_continuity_counter) & 15 ) != 1 ) {
- myprintf(L"discontinuite dans le son\n");
-
- son_valid = false;
-
- // jette le paquet qu'on a
- if (taille_son && pcr_ecrit) {
- // on sauve ce qu'on a en stock
-
- long taille = taille_son - 6;
-
- son_buf[4] = (BYTE)(taille >> 8);
- son_buf[5] = (BYTE) taille;
-
- ecrit_fichier(son_buf, taille_son);
- }
-
- taille_son = 0;
- }
- }
-
- if (p[1] & 0x40) {
- // start indicator
-
- son_valid = true;
-
- if (taille_son && pcr_ecrit) {
- // on sauve ce qu'on a en stock
-
- long taille = taille_son - 6;
-
- son_buf[4] = (BYTE)(taille >> 8);
- son_buf[5] = (BYTE) taille;
-
- ecrit_fichier(son_buf, taille_son);
- }
-
- taille_son = 0;
-
- }
-
- if (son_valid) {
- son_continuity_counter = p[3]&15;
-
- if (p[3] & 0x10) {
- // il y a du payload
-
- if (p[3] & 0x20) {
- // et adaptation field
- unsigned int taille = p[4]+1;
-
- if (taille < 184) {
- unsigned int taille_copie = 184-taille;
-
- if (taille_son + taille_copie <= sizeof(son_buf) ) {
- memcpy(&son_buf[taille_son], &p[4+taille], taille_copie);
- taille_son += taille_copie;
- }
- }
- } else {
- if (taille_son + 184 <= sizeof(son_buf) ) {
- memcpy(&son_buf[taille_son], &p[4], 184);
- taille_son += 184;
- }
- }
- }
- }
-
+ if (pCapture) {
+ delete pCapture;
+ pCapture = NULL;
}
}
-
-void CSampleGrabber_PS::pcr_block(BYTE * p)
-{
- BYTE pack_header[14];
-
- memset(pack_header, 0, 14);
- pack_header[2]=1;
- pack_header[3]=0xBA;
-
- pack_header[11]=0xA0;
- pack_header[12]=0x03;
- pack_header[13]=0xF8;
-
- // pcr flag
- // 01 SCR 32..30 1 SCR 29..28
- // bouffe 5 bits SCR[0]
- pack_header[4] = 0x44 + ((p[6]>>2)& 0x38) + ((p[6]>>3) & 3);
-
- // SCR 27..20
- // 3 bits SCR[0] et 5 bits SCR[1]
- pack_header[5] = ((p[6]<<5)& 0xE0) + ((p[7]>>3)& 0x1F);
-
- // SCR 19..15 1 SCR 14..13
- // 3 bits SCR[1] et 2*2 bits SCR[2]
- pack_header[6] = 4 + ((p[7]<<5)& 0xE0) + ((p[8]>>3) & 0x1F) + ((p[8]>>4) & 3);
-
- // SCR 12..5
- // 4 bits SCR[2] et 4 bits SCR[3]
- pack_header[7] = ((p[8]<<4)& 0xF0) + ((p[9]>>4)& 0x0F);
-
- // SCR 4..0 1 SCR_EXT 8..7
- // 4 bits SCR[3] et 1+2 bit SCR[4]
- pack_header[8] = ((p[9]<<4)& 0xF0) + ((p[10]>>4)& 0x08) + 4 + ((p[10]<<1)&2) + ((p[11]>>7)&1);
-
- // SCR_EXT 6..0 1
- pack_header[9] = ((p[11]<<1)&0xFE) + 1;
-
- ecrit_fichier(pack_header, 14);
-
- pcr_ecrit = true;
-}
-
-CSampleGrabber_Stream::CSampleGrabber_Stream(HANDLE hFil) :
- CSampleGrabber(hFil, 0, 0)
-{
- myprintf(L"Enregistre multiplex\n");
-}
-
-#define TAILLE_PAQUET_MAX 65535
-
-void CSampleGrabber_PS::ecrit_video(void)
-{
- while (taille_vid - 6 > TAILLE_PAQUET_MAX) {
- // on a besoin de decouper
-
- myprintf(L"Paquet trop gros : %i\n", taille_vid - 6);
-
-
- int index = TAILLE_PAQUET_MAX + 6;
-
- // copie autant qu'on peut
-
- int taille_sous_paquet = index - 6;
-
- vid_buf[4] = (BYTE)(taille_sous_paquet >> 8);
- vid_buf[5] = (BYTE) taille_sous_paquet;
-
- ecrit_fichier(vid_buf, index);
-
- taille_vid -= index;
-
- memcpy(&vid_buf[9], &vid_buf[index], taille_vid);
-
- taille_vid += 9;
-
- vid_buf[6] &= 0xFB;
- vid_buf[7] = 0;
- vid_buf[8] = 0;
-
- }
-
- long taille = taille_vid - 6;
-
- vid_buf[4] = (BYTE)(taille >> 8);
- vid_buf[5] = (BYTE) taille;
-
- ecrit_fichier(vid_buf, taille_vid);
-
-}
-
-void CSampleGrabber_Stream::traite_paquet(BYTE * p, WORD pid) // virtual
-{
- // full TS
- if ( pid != 0x1FFF ) {
- ecrit_fichier(p, 188);
- }
-}
Modified: trunk/grabber.h
===================================================================
--- trunk/grabber.h 2008-03-08 19:06:30 UTC (rev 116)
+++ trunk/grabber.h 2008-03-08 21:01:26 UTC (rev 117)
@@ -27,35 +27,11 @@
#pragma once
-#include "channels.h"
+#include "capture.h"
-/* Description Transport stream packet
-
- Syntax No. of bits Offset
- ------------------------------------------------------
- transport_packet() {
- sync_byte 8 0
- transport_error_indicator 1 1
- payload_unit_start_indicator 1 1
- transport_priority 1 1
- PID 13 1, 2
- transport_scrambling_control 2 3
- adaptation_field_control 2 3
- continuity_counter 4 3
- if(adaptation_field_control=='10'||adaptation_field_control=='11') {
- adaptation_field()
- }
- if (adaptation_field_control=='01'||adaptation_field_control=='11') {
- for (i=0;i Multiplex
-{
- virtual void traite_paquet(BYTE * p, WORD pid);
-
-public:
- CSampleGrabber_Stream(HANDLE hFil);
-};
Modified: trunk/record.cpp
===================================================================
--- trunk/record.cpp 2008-03-08 19:06:30 UTC (rev 116)
+++ trunk/record.cpp 2008-03-08 21:01:26 UTC (rev 117)
@@ -31,6 +31,7 @@
#include "channels.h"
#include "ini.h"
#include "grabber.h"
+#include "capture.h"
Enregistrement enregistrements_actuels[NB_MAX_ENREG];
@@ -242,11 +243,15 @@
HANDLE hFile = nom_fichier.Create();
if (hFile != INVALID_HANDLE_VALUE) {
- pCallback = new CSampleGrabber_TS(hFile,
- canal.pmt_pid, video, canal.sons, canal.autr);
+ pCallback =
+ new CSampleGrabber(
+ new CCapture_TS(hFile,
+ canal.pmt_pid, video, canal.sons, canal.autr));
- if (pCallback!=NULL)
+ if (pCallback!=NULL) {
+ myprintf(L"Enregistre TS, video=%i, pmt=%i\n", video, canal.pmt_pid);
enregistrements_actuels[grab].start(pCallback, ixChaine, pProg);
+ }
} else
myprintf(L"Erreur création '%s' code %u\n", nom_fichier.nom, GetLastError());
@@ -281,10 +286,14 @@
HANDLE hFile = nom_fichier.Create();
if (hFile != INVALID_HANDLE_VALUE) {
- pCallback = new CSampleGrabber_PS(hFile, video, son);
+ pCallback =
+ new CSampleGrabber(
+ new CCapture_PS(hFile, video, son));
- if (pCallback!=NULL)
+ if (pCallback!=NULL) {
+ myprintf(L"Enregistre PS, video=%i, audio=%i\n", video, son);
enregistrements_actuels[grab].start(pCallback, ixChaine, pProg);
+ }
} else
myprintf(L"Erreur création '%s' code %u\n", nom_fichier.nom, GetLastError());
@@ -311,9 +320,14 @@
HANDLE hFile = nom_fichier.Create();
if (hFile != INVALID_HANDLE_VALUE) {
- pCallback = new CSampleGrabber_Stream(hFile);
+ pCallback =
+ new CSampleGrabber(
+ new CCapture_Stream(hFile));
- enregistrements_actuels[grab].start(pCallback, STREAM_PSEUDO_INDEX, pProg);
+ if (pCallback!=NULL) {
+ myprintf(L"Enregistre multiplex\n");
+ enregistrements_actuels[grab].start(pCallback, STREAM_PSEUDO_INDEX, pProg);
+ }
} else
myprintf(L"Erreur création '%s' code %u\n", nom_fichier.nom, GetLastError());
From pouchintv-svn at baysse.fr Sat Mar 8 22:27:08 2008
From: pouchintv-svn at baysse.fr (pouchintv-svn at baysse.fr)
Date: Sat, 8 Mar 2008 22:27:08 +0100 (CET)
Subject: [Pouchintv-dev] [PouchinTVMod] lolo_32 | r118 - trunk/Icones/Locales
Message-ID: <20080308212708.A4CF85F5F3@mail.baysse.fr>
Author: lolo_32
Date: 2008-03-08 22:27:08 +0100 (Sat, 08 Mar 2008)
New Revision: 118
Added:
trunk/Icones/Locales/FR3 Caen.bmp
trunk/Icones/Locales/FR3 Orl?\195?\169ans.bmp
trunk/Icones/Locales/T?\195?\169l?\195?\169Grenoble.bmp
Log:
Ajout de trois icones pour les chaines locales (2 France 3 + T?\195?\169l?\195?\169Grenoble)
Added: trunk/Icones/Locales/FR3 Caen.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/Icones/Locales/FR3 Caen.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/Icones/Locales/FR3 Orl?\195?\169ans.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/Icones/Locales/FR3 Orl?\195?\169ans.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/Icones/Locales/T?\195?\169l?\195?\169Grenoble.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/Icones/Locales/T?\195?\169l?\195?\169Grenoble.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
From pouchintv-svn at baysse.fr Sat Mar 8 23:26:05 2008
From: pouchintv-svn at baysse.fr (pouchintv-svn at baysse.fr)
Date: Sat, 8 Mar 2008 23:26:05 +0100 (CET)
Subject: [Pouchintv-dev] [PouchinTVMod] lolo_32 | r118 - trunk/Icones/Locales
Message-ID: <20080308222605.5FBD55F5F2@mail.baysse.fr>
Author: lolo_32
Date: 2008-03-08 22:27:08 +0100 (sam, 08 mar 2008)
New Revision: 118
Added:
trunk/Icones/Locales/FR3 Caen.bmp
trunk/Icones/Locales/FR3 Orléans.bmp
trunk/Icones/Locales/TéléGrenoble.bmp
Log:
Ajout de trois icones pour les chaines locales (2 France 3 + TéléGrenoble)
Ajouté: trunk/Icones/Locales/FR3 Caen.bmp
===================================================================
(les fichiers binaires diffèrent)
Property changes on: trunk/Icones/Locales/FR3 Caen.bmp
___________________________________________________________________
Nom : svn:mime-type
+ application/octet-stream
Ajouté: trunk/Icones/Locales/FR3 Orléans.bmp
===================================================================
(les fichiers binaires diffèrent)
Property changes on: trunk/Icones/Locales/FR3 Orléans.bmp
___________________________________________________________________
Nom : svn:mime-type
+ application/octet-stream
Ajouté: trunk/Icones/Locales/TéléGrenoble.bmp
===================================================================
(les fichiers binaires diffèrent)
Property changes on: trunk/Icones/Locales/TéléGrenoble.bmp
___________________________________________________________________
Nom : svn:mime-type
+ application/octet-stream
From pouchintv-svn at baysse.fr Sat Mar 8 23:28:31 2008
From: pouchintv-svn at baysse.fr (pouchintv-svn at baysse.fr)
Date: Sat, 8 Mar 2008 23:28:31 +0100 (CET)
Subject: [Pouchintv-dev] [PouchinTVMod] lolo_32 | r117 - trunk
Message-ID: <20080308222832.041FD5F5F5@mail.baysse.fr>
Author: gingko
Date: 2008-03-08 22:01:26 +0100 (sam, 08 mar 2008)
New Revision: 117
Added:
trunk/capture.cpp
trunk/capture.h
Modified:
trunk/
trunk/Pouchin TV.vcproj
trunk/grabber.cpp
trunk/grabber.h
trunk/record.cpp
Log:
Réécriture de la fonctionnalité "capture", pour les enregistrements en
mode PS et TS.
Cette fonctionnalité se trouve maintenant dans la paire de fichiers
"capture.h" et "capture.cpp", afin de gérer cette fonction de façon
plus autonome (le couple "grabber.h" / "grabber.cpp" ne contient
maintenant plus que l'extension nécessaire à DirectShow pour
récupérer les échantillons à enregistrer).
Les fichiers PS générés devraient maintenant être plus fonctionnels
que précédemment, en tout cas, ils semblent fonctionner correctement
au moins avec MPC, VLC et Windows Media Player.
Property changes on: trunk
___________________________________________________________________
Nom : tsvn:logminsize
+ 100
Modifié: trunk/Pouchin TV.vcproj
===================================================================
--- trunk/Pouchin TV.vcproj 2008-03-08 19:06:30 UTC (rev 116)
+++ trunk/Pouchin TV.vcproj 2008-03-08 21:01:26 UTC (rev 117)
@@ -712,6 +712,10 @@
>
+
+
@@ -822,6 +826,10 @@
>
+
+
Ajouté: trunk/capture.cpp
===================================================================
--- trunk/capture.cpp (rev 0)
+++ trunk/capture.cpp 2008-03-08 21:01:26 UTC (rev 117)
@@ -0,0 +1,562 @@
+/*
+ * capture.cpp
+ * Copyright (C) 2006 Pouchin
+ *
+ * This file is part of Pouchin TV, a free DVB-T viewer.
+ * See http://pouchinteve.free.fr/ for updates.
+ *
+ * Pouchin TV 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 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
+ *
+ *
+ * This was changed from the Pouchin TV project, to use with
+ * a modified version of this software.
+ * See http://pouchintv.baysse.fr/ for updates.
+ */
+
+#include "base.h"
+#include "grabber.h"
+#include "main.h"
+#include "mpeg2defs.h"
+
+/* Constructeur de base */
+CCapture::CCapture(HANDLE hFil) :
+ hFile(hFil)
+{
+}
+
+//UINT64 CCapture::pos_fichier(void)
+//{
+// LARGE_INTEGER filepos;
+//
+// filepos.QuadPart = 0;
+// if (SetFilePointerEx(hFile, filepos, &filepos, FILE_CURRENT)!=0)
+// return UINT64(filepos.QuadPart);
+// return 0;
+//}
+
+// Sortie d'un bloc de données vers le fichier
+BOOL CCapture::ecrit_fichier(LPCVOID pBuf, DWORD sizBuf) const
+{
+ DWORD written;
+
+ return WriteFile(hFile, pBuf, sizBuf, &written, NULL);
+}
+
+// (peut-être appelé transitoirement pendant la destruction) :
+void CCapture::traite_paquet(const TS_packet & p) // virtual
+{
+}
+
+/* Destructeur général */
+
+CCapture::~CCapture()
+{
+ myprintf(L"Grabber détruit\n");
+ CloseHandle(hFile);
+}
+
+CCapture_TS::CCapture_TS(
+ HANDLE hFil, int pmt, int video,
+ const liste_pistes & lst_sons,
+ const liste_pistes & lst_autr) :
+ CCapture(hFil),
+ video_pid(video),
+ pmt_pid(pmt),
+ sons(lst_sons),
+ autr(lst_autr)
+{
+}
+
+void CCapture_TS::traite_paquet(const TS_packet & p) // virtual
+{
+ // une chaîne en TS
+ UINT16 pid = p.hdr.pid();
+
+ if (
+ pid == p_pid_PAT ||
+ pid == pmt_pid ||
+ pid == video_pid ||
+ sons.cherche_pid(pid) ||
+ autr.cherche_pid(pid)
+ )
+ ecrit_fichier(p.bytes, TS_SIZE);
+}
+
+// ************************************************************
+
+// Limites du champ "program mux rate".
+// Le programme essaie d'estimer la valeur réelle, mais si le résultat sort de ces limites,
+// la limite correspondante sera utilisée en remplacement.
+#define MIN_PROGRAM_MUX_RATE (0x1000*50)
+#define MAX_PROGRAM_MUX_RATE (0x3000*50)
+
+class PS_chunk
+{
+ const PS_hdr_wd & src_hdr; // Référence sur l'en-tête source
+ CCapture_PS & cGrabber;
+public:
+ UINT32 ixBuf;
+ PS_hdr_wd * p_curPES; // Pointeur sur l'en-tête du PES en cours de construction
+ UINT8 buffer[0x800];
+
+ PS_chunk(const PS_hdr_wd & hdr, PS_buffer & cBuff);
+
+ // Ajout d'un bloc "Pack Header" :
+ // (retourne la taille du bloc ajouté, ou bien 0 si échec)
+ size_t addPackHeader();
+
+ // Ajout d'un bloc "System Header" :
+ // (retourne la taille du bloc ajouté, ou bien 0 si échec)
+ size_t addSystemHeader();
+
+ // Ajout d'un bloc PES de base, dérivé du bloc source 'p_src_hdr' :
+ // (retourne la taille du bloc ajouté, ou bien 0 si échec)
+ size_t addPES_Header(IF_DEBUG(LPCSTR nom_debug));
+
+ // Ajout d'un bloc PES d'extension, dérivé du bloc source 'p_src_hdr' :
+ // (retourne la taille du bloc ajouté, ou bien 0 si échec)
+ size_t addPES_extHeader();
+
+ // Compléter le bloc avec un PES de padding, en laissant néanmoins
+ // éventuellement un espace de taille égale = 'guard' à la fin.
+ // Si l'ajustement requis est très faible, alors l'ajustement se fera, à la place,
+ // en ajoutant des octets de "stuffing" dans l'en-tête.
+ // Retourne la quantité de données *ajoutées* au buffer :
+ size_t add_Padding(size_t guard=0);
+
+ // Ajout de données dans le bloc. Retourne 'true' si la totalité des données ont pu être ajoutées,
+ // 'false' sinon ; dans ce dernier cas, rien n'est modifié.
+ bool addData(const UINT8 * ptr, size_t size);
+
+ // Ajout de données dans le bloc. Retourne 'true' si la totalité des données ont pu être ajoutées,
+ // 'false' sinon ; dans ce dernier cas, 'ptr' et 'size' sont ajustés sur les données restantes.
+ bool addPES_data(const UINT8 * & ptr, size_t & size);
+
+ // Ajustement de l'index du buffer pour que les données subséquentes s'inscrivent
+ // à partir de l'adresse 'ptr' :
+ PUINT8 setBufferIndex(PUINT8 ptr)
+ {ixBuf = UINT16(ptr-&buffer[0]); return ptr;}
+
+ // Construction d'un buffer contenant autant de données que possible parmi celles restant disponibles.
+ // S'il ne reste pas assez de données disponibles pour remplir le buffer, des données de remplissage
+ // sont ajoutées.
+ // La fonction retourne le nombre d'octets *ajoutés* (en-têtes, remplissage, etc) par rapport au flot
+ // d'origine.
+ size_t build(bool start, const UINT8 * & ptr, size_t & size IF_DEBUG_CB(LPCSTR nom_debug));
+
+ // Vidange du tampon dans le fichier :
+ void write_to_file();
+};
+
+PS_chunk::PS_chunk(const PS_hdr_wd & hdr, PS_buffer & cBuff) :
+ src_hdr(hdr),
+ cGrabber(*cBuff.pcGrab),
+ ixBuf(0),
+ p_curPES(NULL)
+{
+}
+// Construction d'un buffer contenant autant de données que possible parmi celles restant disponibles.
+// S'il ne reste pas assez de données disponibles pour remplir le buffer, des données de remplissage
+// sont ajoutées.
+// La fonction retourne le nombre d'octets *ajoutés* (en-têtes, remplissage, etc) par rapport au flot
+// d'origine.
+size_t PS_chunk::build(bool start, const UINT8 * & ptr, size_t & size IF_DEBUG_CB(LPCSTR nom_debug))
+{
+ size_t added_bytes = 0;
+
+ if (start) {
+ added_bytes += addPackHeader();
+ if (!cGrabber.sys_header_set) {
+ added_bytes += addSystemHeader();
+ cGrabber.sys_header_set = true;
+ }
+ //
+ size_t hdsize = addPES_Header(IF_DEBUG(nom_debug));
+ // Le premier en-tête existait dans le tampon source, on le saute donc en lecture
+ ptr += hdsize;
+ size -= hdsize;
+ } else
+ // Les en-têtes subséquents sont ajoutés, donc on n'enlève pas de données de la source
+ added_bytes += addPES_extHeader();
+
+ addPES_data(ptr, size);
+ if (size==0)
+ added_bytes += add_Padding();
+ return added_bytes;
+}
+
+void PS_chunk::write_to_file()
+{
+ cGrabber.ecrit_fichier(buffer, sizeof(buffer));
+}
+
+// Ajout de données dans le bloc. Retourne 'true' si la totalité des données ont pu être ajoutées,
+// 'false' sinon ; dans ce dernier cas, rien n'est modifié.
+bool PS_chunk::addData(const UINT8 * ptr, size_t size)
+{
+ if (ixBuf+size <= _countof(buffer)) {
+ memcpy(&buffer[ixBuf], ptr, size);
+ ixBuf = ixBuf + UINT16(size);
+ return true;
+ }
+ return false;
+}
+
+// Ajout de données dans le bloc. Retourne 'true' si la totalité des données ont pu être ajoutées,
+// 'false' sinon ; dans ce dernier cas, 'ptr' et 'size' sont ajustés sur les données restantes.
+bool PS_chunk::addPES_data(const UINT8 * & ptr, size_t & size)
+{
+ UINT32 adjustedSize = UINT32(size);
+ bool fit = ixBuf+size <= _countof(buffer);
+
+ if (!fit)
+ adjustedSize = sizeof(buffer) - ixBuf;
+
+ addData(ptr, adjustedSize);
+ ptr += adjustedSize;
+ size -= adjustedSize;
+ if (p_curPES)
+ p_curPES->set_data_size(&buffer[ixBuf]);
+
+ return fit;
+}
+
+// Ajout d'un bloc "Pack header" :
+size_t PS_chunk::addPackHeader()
+{
+ if (sizeof(PS_chunk)-ixBuf >= sizeof(PS_PackHeader)) {
+ PS_PackHeader & phdr = *new(&buffer[ixBuf])PS_PackHeader(); // "Placement" new
+
+ phdr.scr = cGrabber.getAdjustedPcr(); // transformation par opérateur surchargé
+ phdr.mux_rate = cGrabber.byte_mux_rate/50;
+ phdr.length = 0xf8;
+ setBufferIndex(phdr.end_of_header());
+ return phdr.packet_size();
+ }
+
+ return 0;
+}
+
+// Ajout d'un bloc "System Header" :
+size_t PS_chunk::addSystemHeader()
+{
+ if (sizeof(PS_chunk)-ixBuf >= sizeof(PS_SystemHeader)+2*sizeof(PS_SH_entry)) {
+ PS_SystemHeader & shd = *new (&buffer[ixBuf])PS_SystemHeader(); // "Placement" new
+
+ shd.rate_bound = MAX_PROGRAM_MUX_RATE;
+ shd.audio_bound_and_flags = 1<<2; // SH_FIXED_FLAG=0, SH_CSPS_FLAG=0
+ shd.video_bound_and_flags = 1|0x20; // SH_SYSTEM_AUDIO_LOCK_FLAG=0, SH_SYSTEM_VIDEO_LOCK_FLAG =0, 0x20=marker bit
+ shd.packet_rate_restriction_flag = 0; // SH_PACKET_RATE_RESTRICTION_FLAG=0
+
+ shd[0].stream_id = PES_SB_ALLAUDIO_SID;
+ shd[0].bound_buf.set_size(0, 0x20); // 0x001000
+ shd[1].stream_id = PES_SB_ALLVIDEO_SID;
+ shd[1].bound_buf.set_size(1, 0xe8); // 0x03a000
+ shd.set_data_size(setBufferIndex(PUINT8(shd[1].next())));
+ return shd.packet_size();
+ }
+
+ return 0;
+}
+
+// Ajout d'un bloc PES de base, dérivé du bloc source 'p_src_hdr' :
+// (retourne la taille du bloc ajouté, ou bien 0 si échec)
+size_t PS_chunk::addPES_Header(IF_DEBUG(LPCSTR nom_debug))
+{
+ if (sizeof(PS_chunk)-ixBuf >= sizeof(PS_hdr_wd)) {
+ PS_hdr_wd & dst_hdr = *new (&buffer[ixBuf]) PS_hdr_wd(src_hdr); // "Placement" new
+
+ p_curPES = &dst_hdr;
+
+#ifdef _DEBUG
+ PS_data_unwrapper_full uw_ph(dst_hdr);
+#else
+ PS_data_unwrapper_base uw_ph(dst_hdr);
+#endif
+
+ // Ajustement des champs de timing pour les ramener à une base commençant au début du
+ // fichier :
+ if (uw_ph.p_pts) {
+ *uw_ph.p_pts = cGrabber.adjustTime(*uw_ph.p_pts);
+ // myprintf(L"PS pts = %10.6f (%S)\n", UINT64(*uw_ph.p_pts)/27000000.0, nom_debug);
+ }
+ if (uw_ph.p_dts) {
+ *uw_ph.p_dts = cGrabber.adjustTime(*uw_ph.p_dts);
+ // myprintf(L"PS dts = %10.6f (%S)\n", UINT64(*uw_ph.p_dts)/27000000.0, nom_debug);
+ }
+ if (uw_ph.p_escr) {
+ *uw_ph.p_escr = cGrabber.adjustTime(*uw_ph.p_escr);
+ // myprintf(L"PS escr = %10.6f (%S)\n", UINT64(*uw_ph.p_escr)/27000000.0, nom_debug);
+ }
+
+ setBufferIndex(dst_hdr.end_of_header());
+ return dst_hdr.header_size();
+ }
+
+ return 0;
+}
+
+// Ajout d'un bloc PES d'extension, dérivé du bloc source 'p_src_hdr' :
+size_t PS_chunk::addPES_extHeader()
+{
+ if (sizeof(PS_chunk)-ixBuf >= sizeof(PS_hdr_wd)) {
+ PS_hdr_wd & dst_hdr = *new (&buffer[ixBuf])PS_hdr_wd(src_hdr); // "Placement" new
+
+ p_curPES = &dst_hdr;
+ dst_hdr.info &= ~DATA_ALIGNMENT_INDICATOR; // reset data aligment indicator
+ dst_hdr.flags = 0; // aucun champ ajouté
+ dst_hdr.data_length = 0; // longueur de champs ajoutés nulle
+ setBufferIndex(dst_hdr.end_of_header());
+ return dst_hdr.header_size();
+ }
+
+ return 0;
+}
+
+// Compléter le bloc avec un PES de padding, en laissant néanmoins
+// éventuellement un espace de taille égale = 'guard' à la fin.
+// Retourne la quantité de données *ajoutées* au buffer.
+size_t PS_chunk::add_Padding(size_t guard)
+{
+ UINT16 remain = UINT16(sizeof(buffer)-guard-ixBuf);
+
+ if (remain>0) {
+ if (remain >= 0x10) {
+ PS_hdr_wl & hdr = *new (&buffer[ixBuf])PS_hdr_wl(sid_Padding_Stream); // "Placement" new
+
+ remain -= sizeof(PS_hdr_wl);
+ hdr.hdr_length = remain;
+ memset(hdr.base_of_data_size(), 0xff, remain);
+ cGrabber.byte_count += remain;
+ return hdr.packet_size();
+ } else {
+ if (p_curPES) {
+ PUINT8 base_ptr = p_curPES->base_of_data();
+
+ memmove(base_ptr+remain, base_ptr, &buffer[ixBuf]-base_ptr);
+ memset(base_ptr, 0xff, remain);
+ ixBuf = ixBuf + UINT16(remain);
+ p_curPES->data_length = p_curPES->data_length + UINT8(remain);
+ p_curPES->set_data_size(&buffer[ixBuf]);
+ cGrabber.byte_count += p_curPES->packet_size();
+ return remain;
+ }
+ }
+ }
+
+ return 0;
+}
+
+// ************************************************************
+
+PS_buffer::PS_buffer(int used_pid, UINT8 maxChnk IF_DEBUG_CB(LPCSTR nom_dbg)) :
+ pcGrab(NULL),
+ IF_DEBUG_CA(nom_debug(nom_dbg))
+ pid(used_pid),
+ valid(false),
+ continuity_counter(0)
+{
+ reserve(maxChnk*sizeof(PS_chunk));
+};
+
+void PS_buffer::traite_paquet(const TS_packet & p)
+{
+ const TS_unwrapper uw_th(p.hdr);
+ bool new_PES_starts_here = p.hdr.payload_unit_start_indicator();
+ UINT8 new_ccounter = p.hdr.continuity_counter();
+ UINT8 diff_ccounter = (new_ccounter - continuity_counter) & 0x0f;
+
+ continuity_counter = new_ccounter;
+
+ // Vérification de la continuité :
+ if (diff_ccounter == 0) {
+ myprintf(L"paquet dupliqué dans %S\n", nom_debug);
+ return; // ignorer
+ }
+
+ if (diff_ccounter != 1) {
+ myprintf(L"discontinuité dans %S\n", nom_debug);
+
+ // envoie le paquet (incomplet) qui était en cours de construction
+ flush();
+
+ // Marque la suite comme invalide, sauf si un nouveau paquet commence justement ici :
+ valid = false;
+ }
+
+ if (new_PES_starts_here) {
+ if (pcGrab->capt_state >= cs_stopping) {
+ flush();
+ valid = false;
+ } else
+ valid = true;
+ }
+
+ if (valid && uw_th.p_payload) {
+ // Paquet valide et "Payload" présent
+ size_t ptr_size = &p.bytes[TS_SIZE]-uw_th.p_payload;
+
+ pcGrab->byte_count += ptr_size;
+ put_data(uw_th.p_payload, ptr_size, new_PES_starts_here);
+ }
+}
+
+void PS_buffer::send()
+{
+ const UINT8 * ptr = data_ptr();
+ size_t size = data_size;
+ const PS_hdr_wd & hdr = *reinterpret_cast(ptr);
+ bool start = true;
+ size_t added_bytes = 0;
+
+ while (size>0) {
+ PS_chunk chunk(hdr, *this);
+
+ added_bytes += chunk.build(start, ptr, size IF_DEBUG_CB(nom_debug));
+ chunk.write_to_file();
+ start = false;
+ }
+
+ pcGrab->byte_count += added_bytes;
+}
+
+CCapture_PS::CCapture_PS(HANDLE hFil, int video, int audio) :
+ CCapture(hFil),
+ first_pcr(0),
+ curr_pcr(0),
+ last_pcr(0),
+ curr_pcr_second(UINT32(-1)),
+ pck_pcr_count(0),
+ pcr_rate(7500), // estimation
+ byte_count(0),
+ byte_mux_rate((MIN_PROGRAM_MUX_RATE+MAX_PROGRAM_MUX_RATE)/2),
+ capt_state(cs_idle),
+ sys_header_set(false),
+ video_build(video, 128 IF_DEBUG_CB("la vidéo")),
+ audio_build(audio, 32 IF_DEBUG_CB("le son"))
+{
+ video_build.pcGrab = this;
+ audio_build.pcGrab = this;
+ if (fichier_valide()) {
+ capt_state = cs_started;
+ } else
+ capt_state = cs_error;
+}
+
+void CCapture_PS::traite_paquet(const TS_packet & p) // virtual
+{
+ // une chaîne en PS
+ UINT16 pid = p.hdr.pid();
+
+ if (capt_state==cs_idle || (pid != video_build.pid && pid != audio_build.pid))
+ return;
+
+ const TS_unwrapper uw_th(p.hdr); // Déballage de l'en-tête
+
+ if (uw_th.p_afield) {
+ // L'en-tête contient un champ "adaptation field" : déballage de ce champ :
+ TS_AF_unwrapper_base uw_af(*uw_th.p_afield);
+ if (uw_af.p_pcr) {
+
+ // Ce champ "adaptation field" contient un échantillon
+ // de l'horloge de référence du programme
+ UINT64 new_pcr = *uw_af.p_pcr;
+ UINT32 diff_time = UINT32(new_pcr-last_pcr);
+
+ if (capt_state>=cs_first_pcr_set) {
+ if (diff_time>0 && pck_pcr_count>=32) {
+ // Estimation du temps moyen qui sépare deux paquests TS du même canal :
+ pcr_rate_helper.submit(diff_time/pck_pcr_count);
+ pcr_rate = pcr_rate_helper.mean();
+ // myprintf(L"pcr rate=%u (packet count=%u)\n", pcr_rate, pck_pcr_count);
+ pck_pcr_count = 0;
+ }
+ } else {
+ first_pcr = new_pcr;
+ capt_state = cs_first_pcr_set;
+ byte_count = 0;
+ curr_pcr_second = UINT32(-1);
+ }
+ if (new_pcr > last_pcr)
+ last_pcr = new_pcr;
+ //myprintf(L"TS pcr = %10.6f (ajusté = %10.6f)\n",
+ // new_pcr/27000000.0, (new_pcr-first_pcr)/27000000.0);
+ }
+ }
+
+ if (capt_state>=cs_first_pcr_set) {
+ UINT64 new_pcr = last_pcr+(pcr_rate*(pck_pcr_count++));
+
+ if (new_pcr > curr_pcr)
+ curr_pcr = new_pcr;
+
+ UINT32 second = UINT32(curr_pcr/27000000);
+
+ // Evaluations statistiques :
+ if (second != curr_pcr_second) {
+ myprintf(L"second=%u\n", second);
+ // Section appelée à chaque nouvelle seconde du PCR
+ curr_pcr_second = second;
+ switch (capt_state) {
+
+ case cs_first_pcr_set:
+ if (video_build.valid && audio_build.valid) {
+ capt_state = cs_running;
+ byte_count = 0;
+ }
+ break;
+
+ case cs_running:
+ if (byte_count > 0) {
+ // Évaluation du "multiplex rate" :
+ mux_rate_helper.submit(byte_count);
+
+ UINT32 mux_rate = mux_rate_helper.mean();
+
+ byte_mux_rate = max(MIN_PROGRAM_MUX_RATE, min(MAX_PROGRAM_MUX_RATE, mux_rate));
+ myprintf(L"mux rate=0x%05x, avg=0x%05x\n", byte_count/50, byte_mux_rate/50);
+ byte_count = 0;
+ }
+ }
+ }
+
+ if (pid == video_build.pid)
+ video_build.traite_paquet(p);
+ else
+ audio_build.traite_paquet(p);
+ }
+}
+
+CCapture_PS::~CCapture_PS()
+{
+ capt_state = cs_stopping;
+ Sleep(200); // Laisser les paquets en cours se terminer
+
+ PS_hdr prog_end(sid_Program_End);
+
+ ecrit_fichier(&prog_end, sizeof(prog_end));
+}
+
+CCapture_Stream::CCapture_Stream(HANDLE hFil) :
+ CCapture(hFil)
+{
+}
+
+void CCapture_Stream::traite_paquet(const TS_packet & p) // virtual
+{
+ // full TS
+ if (p.hdr.pid() != p_pid_NULL)
+ ecrit_fichier(p.bytes, TS_SIZE);
+}
Ajouté: trunk/capture.h
===================================================================
--- trunk/capture.h (rev 0)
+++ trunk/capture.h 2008-03-08 21:01:26 UTC (rev 117)
@@ -0,0 +1,147 @@
+/*
+ * capture.h
+ * Copyright (C) 2006 Pouchin
+ *
+ * This file is part of Pouchin TV, a free DVB-T viewer.
+ * See http://pouchinteve.free.fr/ for updates.
+ *
+ * Pouchin TV 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 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
+ *
+ *
+ * This was changed from the Pouchin TV project, to use with
+ * a modified version of this software.
+ * See http://pouchintv.baysse.fr/ for updates.
+ */
+
+#pragma once
+
+#include "base.h"
+#include "chanutils.h"
+#include "sbuffer.h"
+#include "mpeg2defs.h"
+
+class CCapture
+{
+ HANDLE hFile;
+
+protected:
+
+ CCapture(HANDLE hFil);
+
+ // Sortie d'un bloc de données vers le fichier
+ BOOL ecrit_fichier(LPCVOID pBuf, DWORD sizBuf) const;
+
+public:
+
+ virtual void traite_paquet(const TS_packet & p);
+
+ bool fichier_valide() const
+ {return hFile!=INVALID_HANDLE_VALUE;}
+ // UINT64 pos_fichier(void);
+
+ virtual ~CCapture();
+};
+
+class CCapture_TS : public CCapture
+{
+ int video_pid;
+ int pmt_pid;
+ liste_pistes sons;
+ liste_pistes autr;
+
+public:
+
+ CCapture_TS(HANDLE hFil, int pmt, int video,
+ const liste_pistes & lst_sons,
+ const liste_pistes & lst_autr);
+
+ virtual void traite_paquet(const TS_packet & p);
+};
+
+class PS_buffer : public StreamBuffer
+{
+ friend class CCapture_PS;
+ friend class PS_chunk;
+
+ CCapture_PS * pcGrab;
+ IF_DEBUG(LPCSTR nom_debug;)
+ int pid;
+ bool valid;
+ UINT8 continuity_counter;
+
+public:
+ PS_buffer(int used_pid, UINT8 maxChnk IF_DEBUG_CB(LPCSTR nom_dbg));
+
+ void traite_paquet(const TS_packet & p);
+
+ virtual void send();
+
+ ~PS_buffer()
+ {}
+};
+
+typedef MeanHelper RateHelper;
+
+// état de construction d'une capture PS :
+enum CaptureState {
+ cs_idle,
+ cs_error,
+ cs_started,
+ cs_first_pcr_set, // au moins une référence d'horloge a été reçue
+ cs_running, // tous les flux sont en cours de capture
+ cs_stopping, // arrêt en cours
+ cs_finished // capture terminée
+};
+
+class CCapture_PS : public CCapture
+{
+ friend class PS_buffer;
+ friend class PS_chunk;
+
+ UINT64 first_pcr; // Mémorisation du 1er PCR pour recalage à zéro des suivants
+ UINT64 curr_pcr; // PCR courant (interpolation)
+ UINT64 last_pcr; // Dernier PCR reçu
+ UINT32 curr_pcr_second; // Seconde entière du PCR courant (pour tests statistiques)
+ UINT32 pck_pcr_count; // Comptage des paquets "TS" depuis le dernier PCR reçu
+ UINT32 pcr_rate; // Taux d'incrémentation du PCR par paquet
+ size_t byte_count; // Comptage des octets émis en mode PS pour calcul "multiplex rate"
+ UINT32 byte_mux_rate; // "multiplex rate" courant, calculé en octets par seconde
+ RateHelper pcr_rate_helper; // assistance au calcul de l'intervalle de temps moyen entre paquets TS
+ RateHelper mux_rate_helper; // assistance au calcul du "multiplex rate"
+ CaptureState capt_state; // état de progression de la capture
+ bool sys_header_set; // l'enregistrement "System Header" a été émis
+ PS_buffer video_build;
+ PS_buffer audio_build;
+
+public:
+ CCapture_PS(HANDLE hFil, int video, int audio);
+
+ virtual void traite_paquet(const TS_packet & p);
+
+ UINT64 adjustTime(UINT64 t) const
+ {return t-first_pcr;}
+ UINT64 getAdjustedPcr() const
+ {return adjustTime(curr_pcr);}
+
+ virtual ~CCapture_PS();
+};
+
+class CCapture_Stream : public CCapture // -> Multiplex
+{
+public:
+ CCapture_Stream(HANDLE hFil);
+
+ virtual void traite_paquet(const TS_packet & p);
+};
Modifié: trunk/grabber.cpp
===================================================================
--- trunk/grabber.cpp 2008-03-08 19:06:30 UTC (rev 116)
+++ trunk/grabber.cpp 2008-03-08 21:01:26 UTC (rev 117)
@@ -29,15 +29,12 @@
#include "grabber.h"
-#include "main.h"
/* Constructeur de base */
-CSampleGrabber::CSampleGrabber(HANDLE hFil, int video, int audio) :
+CSampleGrabber::CSampleGrabber(CCapture * pCapt) :
CUnknown(L"Sample grabber", NULL),
- hFile(hFil),
- taille_paquet_buf(0),
- video_pid(video),
- audio_pid(audio)
+ pCapture(pCapt),
+ taille_paquet_buf(0)
{
}
@@ -47,7 +44,7 @@
BYTE * p;
long l = pSample->GetActualDataLength();
-// myprintf(L"taille %i\n", l);
+ //myprintf(L"taille %i\n", l);
pSample->GetPointer(&p);
@@ -55,22 +52,22 @@
// Récupération du fragment de paquet éventuellement reçu à la fin de l'appel précédent :
if (taille_paquet_buf) {
- i = 188 - taille_paquet_buf;
+ i = TS_SIZE - taille_paquet_buf;
- memcpy(&paquet_buf[taille_paquet_buf], p, i);
- traite_paquet(paquet_buf, ((paquet_buf[1]&0x1F) << 8 ) + paquet_buf[2]);
+ memcpy(paquet_buf.bytes, p, i);
+ traite_paquet(paquet_buf);
taille_paquet_buf = 0;
}
// Traitement de tous les paquets entiers reçus ici :
- while ( i + 188 <= l){
+ while ( i + TS_SIZE <= l){
- if (p[i] == 0x47 && (i+188==l || p[i+188] == 0x47) ) {
- traite_paquet(p+i, ((p[i+1]&0x1F) << 8) + p[i+2]);
- i += 188;
+ if (reinterpret_cast(p+i)->isTS(i+TS_SIZE>=l)) {
+ traite_paquet(*reinterpret_cast(p+i));
+ i += TS_SIZE;
} else {
// cherche prochaine synchro
- BYTE * res = (BYTE *)memchr(&p[i+1], 0x47, l-i-1);
+ BYTE * res = (BYTE *)memchr(&p[i+1], TS_SYNC, l-i-1);
if (res == NULL) {
// rien trouvé, plus rien a faire
@@ -86,7 +83,7 @@
// Report du fragment résiduel à la fin pour l'appel suivant :
if (i != l) {
taille_paquet_buf = BYTE(l - i);
- memcpy(paquet_buf, &p[i], taille_paquet_buf);
+ memcpy(paquet_buf.bytes, p+i, taille_paquet_buf);
}
return S_OK;
@@ -100,302 +97,19 @@
return S_OK;
}
-// Sortie d'un bloc de données vers le fichier
-BOOL CSampleGrabber::ecrit_fichier(LPCVOID pBuf, DWORD sizBuf) const
-{
- DWORD written;
- return WriteFile(hFile, pBuf, sizBuf, &written, NULL);
-}
-
-// (peut-être appelé transitoirement pendant la destruction) :
-void CSampleGrabber::traite_paquet(BYTE * p, WORD pid) // virtual
+void CSampleGrabber::traite_paquet(const TS_packet & p) // virtual
{
+ if (pCapture)
+ pCapture->traite_paquet(p);
}
/* Destructeur général */
+
CSampleGrabber::~CSampleGrabber()
{
- myprintf(L"Grabber détruit\n");
- CloseHandle(hFile);
-}
-
-CSampleGrabber_TS::CSampleGrabber_TS(
- HANDLE hFil, int pmt, int video,
- const liste_pistes & lst_sons,
- const liste_pistes & lst_autr) :
- CSampleGrabber(hFil, video, 0),
- pmt_pid(pmt),
- sons(lst_sons),
- autr(lst_autr)
-{
- myprintf(L"Enregistre TS, video=%i, pmt=%i\n", video, pmt_pid);
-}
-
-void CSampleGrabber_TS::traite_paquet(BYTE * p, WORD pid) // virtual
-{
- // une chaîne en TS
- if (
- pid == 0 ||
- pid == pmt_pid ||
- pid == video_pid ||
- sons.cherche_pid(pid) ||
- autr.cherche_pid(pid)
- )
- ecrit_fichier(p, 188);
-}
-
-CSampleGrabber_PS::CSampleGrabber_PS(HANDLE hFil, int video, int audio) :
- CSampleGrabber(hFil, video, audio),
- taille_vid(0),
- vid_valid(false),
- taille_son(0),
- son_valid(false),
- pcr_ecrit(false)
-{
- myprintf(L"Enregistre PS, video=%i, audio=%i\n", video, audio);
-}
-
-void CSampleGrabber_PS::traite_paquet(BYTE * p, WORD pid) // virtual
-{
- // une chaîne en PS
-
- if (pid == video_pid) {
-
- // si la video est valide, on verifie que pas de discontinuité
- if (vid_valid) {
- int current = p[3]&15;
-
- if ( ( (current - vid_continuity_counter) & 15 ) != 1 ) {
- myprintf(L"discontinuite dans la video\n");
-
- vid_valid = false;
-
- // jette le paquet qu'on a
- if (taille_vid && pcr_ecrit) {
- ecrit_video();
- }
-
- taille_vid = 0;
- }
- }
-
-
- if (p[1] & 0x40) {
- // start indicator
-
- vid_valid = true;
-
- // on sauve ce qu'on a en stock
- if (taille_vid && pcr_ecrit){
- ecrit_video();
- }
-
- taille_vid = 0;
-
- }
-
- if (vid_valid) {
- vid_continuity_counter = p[3]&15;
-
- if (p[3] & 0x10) {
- // il y a du payload
-
- if (p[3] & 0x20) {
- // et adaptation field
- unsigned int taille = p[4]+1;
-
- if (taille < 184) {
- unsigned int taille_copie = 184-taille;
-
- if (taille_vid + taille_copie <= sizeof(vid_buf) ) {
- memcpy(&vid_buf[taille_vid], &p[4+taille], taille_copie);
- taille_vid += taille_copie;
- }
-
- if (p[5] & 0x10) {
- pcr_block(p);
- }
- }
- } else {
- if (taille_vid + 184 <= sizeof(vid_buf) ) {
- memcpy(&vid_buf[taille_vid], &p[4], 184);
- taille_vid += 184;
- }
-
- }
- }
- }
-
- } else if (pid == audio_pid) {
- // si le son est valide, on verifie que pas de discontinuité
- if (son_valid) {
- int current = p[3]&15;
-
- if ( ( (current - son_continuity_counter) & 15 ) != 1 ) {
- myprintf(L"discontinuite dans le son\n");
-
- son_valid = false;
-
- // jette le paquet qu'on a
- if (taille_son && pcr_ecrit) {
- // on sauve ce qu'on a en stock
-
- long taille = taille_son - 6;
-
- son_buf[4] = (BYTE)(taille >> 8);
- son_buf[5] = (BYTE) taille;
-
- ecrit_fichier(son_buf, taille_son);
- }
-
- taille_son = 0;
- }
- }
-
- if (p[1] & 0x40) {
- // start indicator
-
- son_valid = true;
-
- if (taille_son && pcr_ecrit) {
- // on sauve ce qu'on a en stock
-
- long taille = taille_son - 6;
-
- son_buf[4] = (BYTE)(taille >> 8);
- son_buf[5] = (BYTE) taille;
-
- ecrit_fichier(son_buf, taille_son);
- }
-
- taille_son = 0;
-
- }
-
- if (son_valid) {
- son_continuity_counter = p[3]&15;
-
- if (p[3] & 0x10) {
- // il y a du payload
-
- if (p[3] & 0x20) {
- // et adaptation field
- unsigned int taille = p[4]+1;
-
- if (taille < 184) {
- unsigned int taille_copie = 184-taille;
-
- if (taille_son + taille_copie <= sizeof(son_buf) ) {
- memcpy(&son_buf[taille_son], &p[4+taille], taille_copie);
- taille_son += taille_copie;
- }
- }
- } else {
- if (taille_son + 184 <= sizeof(son_buf) ) {
- memcpy(&son_buf[taille_son], &p[4], 184);
- taille_son += 184;
- }
- }
- }
- }
-
+ if (pCapture) {
+ delete pCapture;
+ pCapture = NULL;
}
}
-
-void CSampleGrabber_PS::pcr_block(BYTE * p)
-{
- BYTE pack_header[14];
-
- memset(pack_header, 0, 14);
- pack_header[2]=1;
- pack_header[3]=0xBA;
-
- pack_header[11]=0xA0;
- pack_header[12]=0x03;
- pack_header[13]=0xF8;
-
- // pcr flag
- // 01 SCR 32..30 1 SCR 29..28
- // bouffe 5 bits SCR[0]
- pack_header[4] = 0x44 + ((p[6]>>2)& 0x38) + ((p[6]>>3) & 3);
-
- // SCR 27..20
- // 3 bits SCR[0] et 5 bits SCR[1]
- pack_header[5] = ((p[6]<<5)& 0xE0) + ((p[7]>>3)& 0x1F);
-
- // SCR 19..15 1 SCR 14..13
- // 3 bits SCR[1] et 2*2 bits SCR[2]
- pack_header[6] = 4 + ((p[7]<<5)& 0xE0) + ((p[8]>>3) & 0x1F) + ((p[8]>>4) & 3);
-
- // SCR 12..5
- // 4 bits SCR[2] et 4 bits SCR[3]
- pack_header[7] = ((p[8]<<4)& 0xF0) + ((p[9]>>4)& 0x0F);
-
- // SCR 4..0 1 SCR_EXT 8..7
- // 4 bits SCR[3] et 1+2 bit SCR[4]
- pack_header[8] = ((p[9]<<4)& 0xF0) + ((p[10]>>4)& 0x08) + 4 + ((p[10]<<1)&2) + ((p[11]>>7)&1);
-
- // SCR_EXT 6..0 1
- pack_header[9] = ((p[11]<<1)&0xFE) + 1;
-
- ecrit_fichier(pack_header, 14);
-
- pcr_ecrit = true;
-}
-
-CSampleGrabber_Stream::CSampleGrabber_Stream(HANDLE hFil) :
- CSampleGrabber(hFil, 0, 0)
-{
- myprintf(L"Enregistre multiplex\n");
-}
-
-#define TAILLE_PAQUET_MAX 65535
-
-void CSampleGrabber_PS::ecrit_video(void)
-{
- while (taille_vid - 6 > TAILLE_PAQUET_MAX) {
- // on a besoin de decouper
-
- myprintf(L"Paquet trop gros : %i\n", taille_vid - 6);
-
-
- int index = TAILLE_PAQUET_MAX + 6;
-
- // copie autant qu'on peut
-
- int taille_sous_paquet = index - 6;
-
- vid_buf[4] = (BYTE)(taille_sous_paquet >> 8);
- vid_buf[5] = (BYTE) taille_sous_paquet;
-
- ecrit_fichier(vid_buf, index);
-
- taille_vid -= index;
-
- memcpy(&vid_buf[9], &vid_buf[index], taille_vid);
-
- taille_vid += 9;
-
- vid_buf[6] &= 0xFB;
- vid_buf[7] = 0;
- vid_buf[8] = 0;
-
- }
-
- long taille = taille_vid - 6;
-
- vid_buf[4] = (BYTE)(taille >> 8);
- vid_buf[5] = (BYTE) taille;
-
- ecrit_fichier(vid_buf, taille_vid);
-
-}
-
-void CSampleGrabber_Stream::traite_paquet(BYTE * p, WORD pid) // virtual
-{
- // full TS
- if ( pid != 0x1FFF ) {
- ecrit_fichier(p, 188);
- }
-}
Modifié: trunk/grabber.h
===================================================================
--- trunk/grabber.h 2008-03-08 19:06:30 UTC (rev 116)
+++ trunk/grabber.h 2008-03-08 21:01:26 UTC (rev 117)
@@ -27,35 +27,11 @@
#pragma once
-#include "channels.h"
+#include "capture.h"
-/* Description Transport stream packet
-
- Syntax No. of bits Offset
- ------------------------------------------------------
- transport_packet() {
- sync_byte 8 0
- transport_error_indicator 1 1
- payload_unit_start_indicator 1 1
- transport_priority 1 1
- PID 13 1, 2
- transport_scrambling_control 2 3
- adaptation_field_control 2 3
- continuity_counter 4 3
- if(adaptation_field_control=='10'||adaptation_field_control=='11') {
- adaptation_field()
- }
- if (adaptation_field_control=='01'||adaptation_field_control=='11') {
- for (i=0;i Multiplex
-{
- virtual void traite_paquet(BYTE * p, WORD pid);
-
-public:
- CSampleGrabber_Stream(HANDLE hFil);
-};
Modifié: trunk/record.cpp
===================================================================
--- trunk/record.cpp 2008-03-08 19:06:30 UTC (rev 116)
+++ trunk/record.cpp 2008-03-08 21:01:26 UTC (rev 117)
@@ -31,6 +31,7 @@
#include "channels.h"
#include "ini.h"
#include "grabber.h"
+#include "capture.h"
Enregistrement enregistrements_actuels[NB_MAX_ENREG];
@@ -242,11 +243,15 @@
HANDLE hFile = nom_fichier.Create();
if (hFile != INVALID_HANDLE_VALUE) {
- pCallback = new CSampleGrabber_TS(hFile,
- canal.pmt_pid, video, canal.sons, canal.autr);
+ pCallback =
+ new CSampleGrabber(
+ new CCapture_TS(hFile,
+ canal.pmt_pid, video, canal.sons, canal.autr));
- if (pCallback!=NULL)
+ if (pCallback!=NULL) {
+ myprintf(L"Enregistre TS, video=%i, pmt=%i\n", video, canal.pmt_pid);
enregistrements_actuels[grab].start(pCallback, ixChaine, pProg);
+ }
} else
myprintf(L"Erreur création '%s' code %u\n", nom_fichier.nom, GetLastError());
@@ -281,10 +286,14 @@
HANDLE hFile = nom_fichier.Create();
if (hFile != INVALID_HANDLE_VALUE) {
- pCallback = new CSampleGrabber_PS(hFile, video, son);
+ pCallback =
+ new CSampleGrabber(
+ new CCapture_PS(hFile, video, son));
- if (pCallback!=NULL)
+ if (pCallback!=NULL) {
+ myprintf(L"Enregistre PS, video=%i, audio=%i\n", video, son);
enregistrements_actuels[grab].start(pCallback, ixChaine, pProg);
+ }
} else
myprintf(L"Erreur création '%s' code %u\n", nom_fichier.nom, GetLastError());
@@ -311,9 +320,14 @@
HANDLE hFile = nom_fichier.Create();
if (hFile != INVALID_HANDLE_VALUE) {
- pCallback = new CSampleGrabber_Stream(hFile);
+ pCallback =
+ new CSampleGrabber(
+ new CCapture_Stream(hFile));
- enregistrements_actuels[grab].start(pCallback, STREAM_PSEUDO_INDEX, pProg);
+ if (pCallback!=NULL) {
+ myprintf(L"Enregistre multiplex\n");
+ enregistrements_actuels[grab].start(pCallback, STREAM_PSEUDO_INDEX, pProg);
+ }
} else
myprintf(L"Erreur création '%s' code %u\n", nom_fichier.nom, GetLastError());
From pouchintv-svn at baysse.fr Sat Mar 8 23:57:30 2008
From: pouchintv-svn at baysse.fr (pouchintv-svn at baysse.fr)
Date: Sat, 8 Mar 2008 23:57:30 +0100 (CET)
Subject: [Pouchintv-dev] [PouchinTVMod] lolo_32 | r117 - trunk
Message-ID: <20080308225730.E85E55F5F6@mail.baysse.fr>
Author: gingko
Date: 2008-03-08 22:01:26 +0100 (sam, 08 mar 2008)
New Revision: 117
Added:
trunk/capture.cpp
trunk/capture.h
Modified:
trunk/
trunk/Pouchin TV.vcproj
trunk/grabber.cpp
trunk/grabber.h
trunk/record.cpp
Log:
Réécriture de la fonctionnalité "capture", pour les enregistrements en
mode PS et TS.
Cette fonctionnalité se trouve maintenant dans la paire de fichiers
"capture.h" et "capture.cpp", afin de gérer cette fonction de façon
plus autonome (le couple "grabber.h" / "grabber.cpp" ne contient
maintenant plus que l'extension nécessaire à DirectShow pour
récupérer les échantillons à enregistrer).
Les fichiers PS générés devraient maintenant être plus fonctionnels
que précédemment, en tout cas, ils semblent fonctionner correctement
au moins avec MPC, VLC et Windows Media Player.
Property changes on: trunk
___________________________________________________________________
Nom : tsvn:logminsize
+ 100
Modifié: trunk/Pouchin TV.vcproj
===================================================================
--- trunk/Pouchin TV.vcproj 2008-03-08 19:06:30 UTC (rev 116)
+++ trunk/Pouchin TV.vcproj 2008-03-08 21:01:26 UTC (rev 117)
@@ -712,6 +712,10 @@
>
+
+
@@ -822,6 +826,10 @@
>
+
+
Ajouté: trunk/capture.cpp
===================================================================
--- trunk/capture.cpp (rev 0)
+++ trunk/capture.cpp 2008-03-08 21:01:26 UTC (rev 117)
@@ -0,0 +1,562 @@
+/*
+ * capture.cpp
+ * Copyright (C) 2006 Pouchin
+ *
+ * This file is part of Pouchin TV, a free DVB-T viewer.
+ * See http://pouchinteve.free.fr/ for updates.
+ *
+ * Pouchin TV 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 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
+ *
+ *
+ * This was changed from the Pouchin TV project, to use with
+ * a modified version of this software.
+ * See http://pouchintv.baysse.fr/ for updates.
+ */
+
+#include "base.h"
+#include "grabber.h"
+#include "main.h"
+#include "mpeg2defs.h"
+
+/* Constructeur de base */
+CCapture::CCapture(HANDLE hFil) :
+ hFile(hFil)
+{
+}
+
+//UINT64 CCapture::pos_fichier(void)
+//{
+// LARGE_INTEGER filepos;
+//
+// filepos.QuadPart = 0;
+// if (SetFilePointerEx(hFile, filepos, &filepos, FILE_CURRENT)!=0)
+// return UINT64(filepos.QuadPart);
+// return 0;
+//}
+
+// Sortie d'un bloc de données vers le fichier
+BOOL CCapture::ecrit_fichier(LPCVOID pBuf, DWORD sizBuf) const
+{
+ DWORD written;
+
+ return WriteFile(hFile, pBuf, sizBuf, &written, NULL);
+}
+
+// (peut-être appelé transitoirement pendant la destruction) :
+void CCapture::traite_paquet(const TS_packet & p) // virtual
+{
+}
+
+/* Destructeur général */
+
+CCapture::~CCapture()
+{
+ myprintf(L"Grabber détruit\n");
+ CloseHandle(hFile);
+}
+
+CCapture_TS::CCapture_TS(
+ HANDLE hFil, int pmt, int video,
+ const liste_pistes & lst_sons,
+ const liste_pistes & lst_autr) :
+ CCapture(hFil),
+ video_pid(video),
+ pmt_pid(pmt),
+ sons(lst_sons),
+ autr(lst_autr)
+{
+}
+
+void CCapture_TS::traite_paquet(const TS_packet & p) // virtual
+{
+ // une chaîne en TS
+ UINT16 pid = p.hdr.pid();
+
+ if (
+ pid == p_pid_PAT ||
+ pid == pmt_pid ||
+ pid == video_pid ||
+ sons.cherche_pid(pid) ||
+ autr.cherche_pid(pid)
+ )
+ ecrit_fichier(p.bytes, TS_SIZE);
+}
+
+// ************************************************************
+
+// Limites du champ "program mux rate".
+// Le programme essaie d'estimer la valeur réelle, mais si le résultat sort de ces limites,
+// la limite correspondante sera utilisée en remplacement.
+#define MIN_PROGRAM_MUX_RATE (0x1000*50)
+#define MAX_PROGRAM_MUX_RATE (0x3000*50)
+
+class PS_chunk
+{
+ const PS_hdr_wd & src_hdr; // Référence sur l'en-tête source
+ CCapture_PS & cGrabber;
+public:
+ UINT32 ixBuf;
+ PS_hdr_wd * p_curPES; // Pointeur sur l'en-tête du PES en cours de construction
+ UINT8 buffer[0x800];
+
+ PS_chunk(const PS_hdr_wd & hdr, PS_buffer & cBuff);
+
+ // Ajout d'un bloc "Pack Header" :
+ // (retourne la taille du bloc ajouté, ou bien 0 si échec)
+ size_t addPackHeader();
+
+ // Ajout d'un bloc "System Header" :
+ // (retourne la taille du bloc ajouté, ou bien 0 si échec)
+ size_t addSystemHeader();
+
+ // Ajout d'un bloc PES de base, dérivé du bloc source 'p_src_hdr' :
+ // (retourne la taille du bloc ajouté, ou bien 0 si échec)
+ size_t addPES_Header(IF_DEBUG(LPCSTR nom_debug));
+
+ // Ajout d'un bloc PES d'extension, dérivé du bloc source 'p_src_hdr' :
+ // (retourne la taille du bloc ajouté, ou bien 0 si échec)
+ size_t addPES_extHeader();
+
+ // Compléter le bloc avec un PES de padding, en laissant néanmoins
+ // éventuellement un espace de taille égale = 'guard' à la fin.
+ // Si l'ajustement requis est très faible, alors l'ajustement se fera, à la place,
+ // en ajoutant des octets de "stuffing" dans l'en-tête.
+ // Retourne la quantité de données *ajoutées* au buffer :
+ size_t add_Padding(size_t guard=0);
+
+ // Ajout de données dans le bloc. Retourne 'true' si la totalité des données ont pu être ajoutées,
+ // 'false' sinon ; dans ce dernier cas, rien n'est modifié.
+ bool addData(const UINT8 * ptr, size_t size);
+
+ // Ajout de données dans le bloc. Retourne 'true' si la totalité des données ont pu être ajoutées,
+ // 'false' sinon ; dans ce dernier cas, 'ptr' et 'size' sont ajustés sur les données restantes.
+ bool addPES_data(const UINT8 * & ptr, size_t & size);
+
+ // Ajustement de l'index du buffer pour que les données subséquentes s'inscrivent
+ // à partir de l'adresse 'ptr' :
+ PUINT8 setBufferIndex(PUINT8 ptr)
+ {ixBuf = UINT16(ptr-&buffer[0]); return ptr;}
+
+ // Construction d'un buffer contenant autant de données que possible parmi celles restant disponibles.
+ // S'il ne reste pas assez de données disponibles pour remplir le buffer, des données de remplissage
+ // sont ajoutées.
+ // La fonction retourne le nombre d'octets *ajoutés* (en-têtes, remplissage, etc) par rapport au flot
+ // d'origine.
+ size_t build(bool start, const UINT8 * & ptr, size_t & size IF_DEBUG_CB(LPCSTR nom_debug));
+
+ // Vidange du tampon dans le fichier :
+ void write_to_file();
+};
+
+PS_chunk::PS_chunk(const PS_hdr_wd & hdr, PS_buffer & cBuff) :
+ src_hdr(hdr),
+ cGrabber(*cBuff.pcGrab),
+ ixBuf(0),
+ p_curPES(NULL)
+{
+}
+// Construction d'un buffer contenant autant de données que possible parmi celles restant disponibles.
+// S'il ne reste pas assez de données disponibles pour remplir le buffer, des données de remplissage
+// sont ajoutées.
+// La fonction retourne le nombre d'octets *ajoutés* (en-têtes, remplissage, etc) par rapport au flot
+// d'origine.
+size_t PS_chunk::build(bool start, const UINT8 * & ptr, size_t & size IF_DEBUG_CB(LPCSTR nom_debug))
+{
+ size_t added_bytes = 0;
+
+ if (start) {
+ added_bytes += addPackHeader();
+ if (!cGrabber.sys_header_set) {
+ added_bytes += addSystemHeader();
+ cGrabber.sys_header_set = true;
+ }
+ //
+ size_t hdsize = addPES_Header(IF_DEBUG(nom_debug));
+ // Le premier en-tête existait dans le tampon source, on le saute donc en lecture
+ ptr += hdsize;
+ size -= hdsize;
+ } else
+ // Les en-têtes subséquents sont ajoutés, donc on n'enlève pas de données de la source
+ added_bytes += addPES_extHeader();
+
+ addPES_data(ptr, size);
+ if (size==0)
+ added_bytes += add_Padding();
+ return added_bytes;
+}
+
+void PS_chunk::write_to_file()
+{
+ cGrabber.ecrit_fichier(buffer, sizeof(buffer));
+}
+
+// Ajout de données dans le bloc. Retourne 'true' si la totalité des données ont pu être ajoutées,
+// 'false' sinon ; dans ce dernier cas, rien n'est modifié.
+bool PS_chunk::addData(const UINT8 * ptr, size_t size)
+{
+ if (ixBuf+size <= _countof(buffer)) {
+ memcpy(&buffer[ixBuf], ptr, size);
+ ixBuf = ixBuf + UINT16(size);
+ return true;
+ }
+ return false;
+}
+
+// Ajout de données dans le bloc. Retourne 'true' si la totalité des données ont pu être ajoutées,
+// 'false' sinon ; dans ce dernier cas, 'ptr' et 'size' sont ajustés sur les données restantes.
+bool PS_chunk::addPES_data(const UINT8 * & ptr, size_t & size)
+{
+ UINT32 adjustedSize = UINT32(size);
+ bool fit = ixBuf+size <= _countof(buffer);
+
+ if (!fit)
+ adjustedSize = sizeof(buffer) - ixBuf;
+
+ addData(ptr, adjustedSize);
+ ptr += adjustedSize;
+ size -= adjustedSize;
+ if (p_curPES)
+ p_curPES->set_data_size(&buffer[ixBuf]);
+
+ return fit;
+}
+
+// Ajout d'un bloc "Pack header" :
+size_t PS_chunk::addPackHeader()
+{
+ if (sizeof(PS_chunk)-ixBuf >= sizeof(PS_PackHeader)) {
+ PS_PackHeader & phdr = *new(&buffer[ixBuf])PS_PackHeader(); // "Placement" new
+
+ phdr.scr = cGrabber.getAdjustedPcr(); // transformation par opérateur surchargé
+ phdr.mux_rate = cGrabber.byte_mux_rate/50;
+ phdr.length = 0xf8;
+ setBufferIndex(phdr.end_of_header());
+ return phdr.packet_size();
+ }
+
+ return 0;
+}
+
+// Ajout d'un bloc "System Header" :
+size_t PS_chunk::addSystemHeader()
+{
+ if (sizeof(PS_chunk)-ixBuf >= sizeof(PS_SystemHeader)+2*sizeof(PS_SH_entry)) {
+ PS_SystemHeader & shd = *new (&buffer[ixBuf])PS_SystemHeader(); // "Placement" new
+
+ shd.rate_bound = MAX_PROGRAM_MUX_RATE;
+ shd.audio_bound_and_flags = 1<<2; // SH_FIXED_FLAG=0, SH_CSPS_FLAG=0
+ shd.video_bound_and_flags = 1|0x20; // SH_SYSTEM_AUDIO_LOCK_FLAG=0, SH_SYSTEM_VIDEO_LOCK_FLAG =0, 0x20=marker bit
+ shd.packet_rate_restriction_flag = 0; // SH_PACKET_RATE_RESTRICTION_FLAG=0
+
+ shd[0].stream_id = PES_SB_ALLAUDIO_SID;
+ shd[0].bound_buf.set_size(0, 0x20); // 0x001000
+ shd[1].stream_id = PES_SB_ALLVIDEO_SID;
+ shd[1].bound_buf.set_size(1, 0xe8); // 0x03a000
+ shd.set_data_size(setBufferIndex(PUINT8(shd[1].next())));
+ return shd.packet_size();
+ }
+
+ return 0;
+}
+
+// Ajout d'un bloc PES de base, dérivé du bloc source 'p_src_hdr' :
+// (retourne la taille du bloc ajouté, ou bien 0 si échec)
+size_t PS_chunk::addPES_Header(IF_DEBUG(LPCSTR nom_debug))
+{
+ if (sizeof(PS_chunk)-ixBuf >= sizeof(PS_hdr_wd)) {
+ PS_hdr_wd & dst_hdr = *new (&buffer[ixBuf]) PS_hdr_wd(src_hdr); // "Placement" new
+
+ p_curPES = &dst_hdr;
+
+#ifdef _DEBUG
+ PS_data_unwrapper_full uw_ph(dst_hdr);
+#else
+ PS_data_unwrapper_base uw_ph(dst_hdr);
+#endif
+
+ // Ajustement des champs de timing pour les ramener à une base commençant au début du
+ // fichier :
+ if (uw_ph.p_pts) {
+ *uw_ph.p_pts = cGrabber.adjustTime(*uw_ph.p_pts);
+ // myprintf(L"PS pts = %10.6f (%S)\n", UINT64(*uw_ph.p_pts)/27000000.0, nom_debug);
+ }
+ if (uw_ph.p_dts) {
+ *uw_ph.p_dts = cGrabber.adjustTime(*uw_ph.p_dts);
+ // myprintf(L"PS dts = %10.6f (%S)\n", UINT64(*uw_ph.p_dts)/27000000.0, nom_debug);
+ }
+ if (uw_ph.p_escr) {
+ *uw_ph.p_escr = cGrabber.adjustTime(*uw_ph.p_escr);
+ // myprintf(L"PS escr = %10.6f (%S)\n", UINT64(*uw_ph.p_escr)/27000000.0, nom_debug);
+ }
+
+ setBufferIndex(dst_hdr.end_of_header());
+ return dst_hdr.header_size();
+ }
+
+ return 0;
+}
+
+// Ajout d'un bloc PES d'extension, dérivé du bloc source 'p_src_hdr' :
+size_t PS_chunk::addPES_extHeader()
+{
+ if (sizeof(PS_chunk)-ixBuf >= sizeof(PS_hdr_wd)) {
+ PS_hdr_wd & dst_hdr = *new (&buffer[ixBuf])PS_hdr_wd(src_hdr); // "Placement" new
+
+ p_curPES = &dst_hdr;
+ dst_hdr.info &= ~DATA_ALIGNMENT_INDICATOR; // reset data aligment indicator
+ dst_hdr.flags = 0; // aucun champ ajouté
+ dst_hdr.data_length = 0; // longueur de champs ajoutés nulle
+ setBufferIndex(dst_hdr.end_of_header());
+ return dst_hdr.header_size();
+ }
+
+ return 0;
+}
+
+// Compléter le bloc avec un PES de padding, en laissant néanmoins
+// éventuellement un espace de taille égale = 'guard' à la fin.
+// Retourne la quantité de données *ajoutées* au buffer.
+size_t PS_chunk::add_Padding(size_t guard)
+{
+ UINT16 remain = UINT16(sizeof(buffer)-guard-ixBuf);
+
+ if (remain>0) {
+ if (remain >= 0x10) {
+ PS_hdr_wl & hdr = *new (&buffer[ixBuf])PS_hdr_wl(sid_Padding_Stream); // "Placement" new
+
+ remain -= sizeof(PS_hdr_wl);
+ hdr.hdr_length = remain;
+ memset(hdr.base_of_data_size(), 0xff, remain);
+ cGrabber.byte_count += remain;
+ return hdr.packet_size();
+ } else {
+ if (p_curPES) {
+ PUINT8 base_ptr = p_curPES->base_of_data();
+
+ memmove(base_ptr+remain, base_ptr, &buffer[ixBuf]-base_ptr);
+ memset(base_ptr, 0xff, remain);
+ ixBuf = ixBuf + UINT16(remain);
+ p_curPES->data_length = p_curPES->data_length + UINT8(remain);
+ p_curPES->set_data_size(&buffer[ixBuf]);
+ cGrabber.byte_count += p_curPES->packet_size();
+ return remain;
+ }
+ }
+ }
+
+ return 0;
+}
+
+// ************************************************************
+
+PS_buffer::PS_buffer(int used_pid, UINT8 maxChnk IF_DEBUG_CB(LPCSTR nom_dbg)) :
+ pcGrab(NULL),
+ IF_DEBUG_CA(nom_debug(nom_dbg))
+ pid(used_pid),
+ valid(false),
+ continuity_counter(0)
+{
+ reserve(maxChnk*sizeof(PS_chunk));
+};
+
+void PS_buffer::traite_paquet(const TS_packet & p)
+{
+ const TS_unwrapper uw_th(p.hdr);
+ bool new_PES_starts_here = p.hdr.payload_unit_start_indicator();
+ UINT8 new_ccounter = p.hdr.continuity_counter();
+ UINT8 diff_ccounter = (new_ccounter - continuity_counter) & 0x0f;
+
+ continuity_counter = new_ccounter;
+
+ // Vérification de la continuité :
+ if (diff_ccounter == 0) {
+ myprintf(L"paquet dupliqué dans %S\n", nom_debug);
+ return; // ignorer
+ }
+
+ if (diff_ccounter != 1) {
+ myprintf(L"discontinuité dans %S\n", nom_debug);
+
+ // envoie le paquet (incomplet) qui était en cours de construction
+ flush();
+
+ // Marque la suite comme invalide, sauf si un nouveau paquet commence justement ici :
+ valid = false;
+ }
+
+ if (new_PES_starts_here) {
+ if (pcGrab->capt_state >= cs_stopping) {
+ flush();
+ valid = false;
+ } else
+ valid = true;
+ }
+
+ if (valid && uw_th.p_payload) {
+ // Paquet valide et "Payload" présent
+ size_t ptr_size = &p.bytes[TS_SIZE]-uw_th.p_payload;
+
+ pcGrab->byte_count += ptr_size;
+ put_data(uw_th.p_payload, ptr_size, new_PES_starts_here);
+ }
+}
+
+void PS_buffer::send()
+{
+ const UINT8 * ptr = data_ptr();
+ size_t size = data_size;
+ const PS_hdr_wd & hdr = *reinterpret_cast(ptr);
+ bool start = true;
+ size_t added_bytes = 0;
+
+ while (size>0) {
+ PS_chunk chunk(hdr, *this);
+
+ added_bytes += chunk.build(start, ptr, size IF_DEBUG_CB(nom_debug));
+ chunk.write_to_file();
+ start = false;
+ }
+
+ pcGrab->byte_count += added_bytes;
+}
+
+CCapture_PS::CCapture_PS(HANDLE hFil, int video, int audio) :
+ CCapture(hFil),
+ first_pcr(0),
+ curr_pcr(0),
+ last_pcr(0),
+ curr_pcr_second(UINT32(-1)),
+ pck_pcr_count(0),
+ pcr_rate(7500), // estimation
+ byte_count(0),
+ byte_mux_rate((MIN_PROGRAM_MUX_RATE+MAX_PROGRAM_MUX_RATE)/2),
+ capt_state(cs_idle),
+ sys_header_set(false),
+ video_build(video, 128 IF_DEBUG_CB("la vidéo")),
+ audio_build(audio, 32 IF_DEBUG_CB("le son"))
+{
+ video_build.pcGrab = this;
+ audio_build.pcGrab = this;
+ if (fichier_valide()) {
+ capt_state = cs_started;
+ } else
+ capt_state = cs_error;
+}
+
+void CCapture_PS::traite_paquet(const TS_packet & p) // virtual
+{
+ // une chaîne en PS
+ UINT16 pid = p.hdr.pid();
+
+ if (capt_state==cs_idle || (pid != video_build.pid && pid != audio_build.pid))
+ return;
+
+ const TS_unwrapper uw_th(p.hdr); // Déballage de l'en-tête
+
+ if (uw_th.p_afield) {
+ // L'en-tête contient un champ "adaptation field" : déballage de ce champ :
+ TS_AF_unwrapper_base uw_af(*uw_th.p_afield);
+ if (uw_af.p_pcr) {
+
+ // Ce champ "adaptation field" contient un échantillon
+ // de l'horloge de référence du programme
+ UINT64 new_pcr = *uw_af.p_pcr;
+ UINT32 diff_time = UINT32(new_pcr-last_pcr);
+
+ if (capt_state>=cs_first_pcr_set) {
+ if (diff_time>0 && pck_pcr_count>=32) {
+ // Estimation du temps moyen qui sépare deux paquests TS du même canal :
+ pcr_rate_helper.submit(diff_time/pck_pcr_count);
+ pcr_rate = pcr_rate_helper.mean();
+ // myprintf(L"pcr rate=%u (packet count=%u)\n", pcr_rate, pck_pcr_count);
+ pck_pcr_count = 0;
+ }
+ } else {
+ first_pcr = new_pcr;
+ capt_state = cs_first_pcr_set;
+ byte_count = 0;
+ curr_pcr_second = UINT32(-1);
+ }
+ if (new_pcr > last_pcr)
+ last_pcr = new_pcr;
+ //myprintf(L"TS pcr = %10.6f (ajusté = %10.6f)\n",
+ // new_pcr/27000000.0, (new_pcr-first_pcr)/27000000.0);
+ }
+ }
+
+ if (capt_state>=cs_first_pcr_set) {
+ UINT64 new_pcr = last_pcr+(pcr_rate*(pck_pcr_count++));
+
+ if (new_pcr > curr_pcr)
+ curr_pcr = new_pcr;
+
+ UINT32 second = UINT32(curr_pcr/27000000);
+
+ // Evaluations statistiques :
+ if (second != curr_pcr_second) {
+ myprintf(L"second=%u\n", second);
+ // Section appelée à chaque nouvelle seconde du PCR
+ curr_pcr_second = second;
+ switch (capt_state) {
+
+ case cs_first_pcr_set:
+ if (video_build.valid && audio_build.valid) {
+ capt_state = cs_running;
+ byte_count = 0;
+ }
+ break;
+
+ case cs_running:
+ if (byte_count > 0) {
+ // Évaluation du "multiplex rate" :
+ mux_rate_helper.submit(byte_count);
+
+ UINT32 mux_rate = mux_rate_helper.mean();
+
+ byte_mux_rate = max(MIN_PROGRAM_MUX_RATE, min(MAX_PROGRAM_MUX_RATE, mux_rate));
+ myprintf(L"mux rate=0x%05x, avg=0x%05x\n", byte_count/50, byte_mux_rate/50);
+ byte_count = 0;
+ }
+ }
+ }
+
+ if (pid == video_build.pid)
+ video_build.traite_paquet(p);
+ else
+ audio_build.traite_paquet(p);
+ }
+}
+
+CCapture_PS::~CCapture_PS()
+{
+ capt_state = cs_stopping;
+ Sleep(200); // Laisser les paquets en cours se terminer
+
+ PS_hdr prog_end(sid_Program_End);
+
+ ecrit_fichier(&prog_end, sizeof(prog_end));
+}
+
+CCapture_Stream::CCapture_Stream(HANDLE hFil) :
+ CCapture(hFil)
+{
+}
+
+void CCapture_Stream::traite_paquet(const TS_packet & p) // virtual
+{
+ // full TS
+ if (p.hdr.pid() != p_pid_NULL)
+ ecrit_fichier(p.bytes, TS_SIZE);
+}
Ajouté: trunk/capture.h
===================================================================
--- trunk/capture.h (rev 0)
+++ trunk/capture.h 2008-03-08 21:01:26 UTC (rev 117)
@@ -0,0 +1,147 @@
+/*
+ * capture.h
+ * Copyright (C) 2006 Pouchin
+ *
+ * This file is part of Pouchin TV, a free DVB-T viewer.
+ * See http://pouchinteve.free.fr/ for updates.
+ *
+ * Pouchin TV 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 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
+ *
+ *
+ * This was changed from the Pouchin TV project, to use with
+ * a modified version of this software.
+ * See http://pouchintv.baysse.fr/ for updates.
+ */
+
+#pragma once
+
+#include "base.h"
+#include "chanutils.h"
+#include "sbuffer.h"
+#include "mpeg2defs.h"
+
+class CCapture
+{
+ HANDLE hFile;
+
+protected:
+
+ CCapture(HANDLE hFil);
+
+ // Sortie d'un bloc de données vers le fichier
+ BOOL ecrit_fichier(LPCVOID pBuf, DWORD sizBuf) const;
+
+public:
+
+ virtual void traite_paquet(const TS_packet & p);
+
+ bool fichier_valide() const
+ {return hFile!=INVALID_HANDLE_VALUE;}
+ // UINT64 pos_fichier(void);
+
+ virtual ~CCapture();
+};
+
+class CCapture_TS : public CCapture
+{
+ int video_pid;
+ int pmt_pid;
+ liste_pistes sons;
+ liste_pistes autr;
+
+public:
+
+ CCapture_TS(HANDLE hFil, int pmt, int video,
+ const liste_pistes & lst_sons,
+ const liste_pistes & lst_autr);
+
+ virtual void traite_paquet(const TS_packet & p);
+};
+
+class PS_buffer : public StreamBuffer
+{
+ friend class CCapture_PS;
+ friend class PS_chunk;
+
+ CCapture_PS * pcGrab;
+ IF_DEBUG(LPCSTR nom_debug;)
+ int pid;
+ bool valid;
+ UINT8 continuity_counter;
+
+public:
+ PS_buffer(int used_pid, UINT8 maxChnk IF_DEBUG_CB(LPCSTR nom_dbg));
+
+ void traite_paquet(const TS_packet & p);
+
+ virtual void send();
+
+ ~PS_buffer()
+ {}
+};
+
+typedef MeanHelper RateHelper;
+
+// état de construction d'une capture PS :
+enum CaptureState {
+ cs_idle,
+ cs_error,
+ cs_started,
+ cs_first_pcr_set, // au moins une référence d'horloge a été reçue
+ cs_running, // tous les flux sont en cours de capture
+ cs_stopping, // arrêt en cours
+ cs_finished // capture terminée
+};
+
+class CCapture_PS : public CCapture
+{
+ friend class PS_buffer;
+ friend class PS_chunk;
+
+ UINT64 first_pcr; // Mémorisation du 1er PCR pour recalage à zéro des suivants
+ UINT64 curr_pcr; // PCR courant (interpolation)
+ UINT64 last_pcr; // Dernier PCR reçu
+ UINT32 curr_pcr_second; // Seconde entière du PCR courant (pour tests statistiques)
+ UINT32 pck_pcr_count; // Comptage des paquets "TS" depuis le dernier PCR reçu
+ UINT32 pcr_rate; // Taux d'incrémentation du PCR par paquet
+ size_t byte_count; // Comptage des octets émis en mode PS pour calcul "multiplex rate"
+ UINT32 byte_mux_rate; // "multiplex rate" courant, calculé en octets par seconde
+ RateHelper pcr_rate_helper; // assistance au calcul de l'intervalle de temps moyen entre paquets TS
+ RateHelper mux_rate_helper; // assistance au calcul du "multiplex rate"
+ CaptureState capt_state; // état de progression de la capture
+ bool sys_header_set; // l'enregistrement "System Header" a été émis
+ PS_buffer video_build;
+ PS_buffer audio_build;
+
+public:
+ CCapture_PS(HANDLE hFil, int video, int audio);
+
+ virtual void traite_paquet(const TS_packet & p);
+
+ UINT64 adjustTime(UINT64 t) const
+ {return t-first_pcr;}
+ UINT64 getAdjustedPcr() const
+ {return adjustTime(curr_pcr);}
+
+ virtual ~CCapture_PS();
+};
+
+class CCapture_Stream : public CCapture // -> Multiplex
+{
+public:
+ CCapture_Stream(HANDLE hFil);
+
+ virtual void traite_paquet(const TS_packet & p);
+};
Modifié: trunk/grabber.cpp
===================================================================
--- trunk/grabber.cpp 2008-03-08 19:06:30 UTC (rev 116)
+++ trunk/grabber.cpp 2008-03-08 21:01:26 UTC (rev 117)
@@ -29,15 +29,12 @@
#include "grabber.h"
-#include "main.h"
/* Constructeur de base */
-CSampleGrabber::CSampleGrabber(HANDLE hFil, int video, int audio) :
+CSampleGrabber::CSampleGrabber(CCapture * pCapt) :
CUnknown(L"Sample grabber", NULL),
- hFile(hFil),
- taille_paquet_buf(0),
- video_pid(video),
- audio_pid(audio)
+ pCapture(pCapt),
+ taille_paquet_buf(0)
{
}
@@ -47,7 +44,7 @@
BYTE * p;
long l = pSample->GetActualDataLength();
-// myprintf(L"taille %i\n", l);
+ //myprintf(L"taille %i\n", l);
pSample->GetPointer(&p);
@@ -55,22 +52,22 @@
// Récupération du fragment de paquet éventuellement reçu à la fin de l'appel précédent :
if (taille_paquet_buf) {
- i = 188 - taille_paquet_buf;
+ i = TS_SIZE - taille_paquet_buf;
- memcpy(&paquet_buf[taille_paquet_buf], p, i);
- traite_paquet(paquet_buf, ((paquet_buf[1]&0x1F) << 8 ) + paquet_buf[2]);
+ memcpy(paquet_buf.bytes, p, i);
+ traite_paquet(paquet_buf);
taille_paquet_buf = 0;
}
// Traitement de tous les paquets entiers reçus ici :
- while ( i + 188 <= l){
+ while ( i + TS_SIZE <= l){
- if (p[i] == 0x47 && (i+188==l || p[i+188] == 0x47) ) {
- traite_paquet(p+i, ((p[i+1]&0x1F) << 8) + p[i+2]);
- i += 188;
+ if (reinterpret_cast(p+i)->isTS(i+TS_SIZE>=l)) {
+ traite_paquet(*reinterpret_cast(p+i));
+ i += TS_SIZE;
} else {
// cherche prochaine synchro
- BYTE * res = (BYTE *)memchr(&p[i+1], 0x47, l-i-1);
+ BYTE * res = (BYTE *)memchr(&p[i+1], TS_SYNC, l-i-1);
if (res == NULL) {
// rien trouvé, plus rien a faire
@@ -86,7 +83,7 @@
// Report du fragment résiduel à la fin pour l'appel suivant :
if (i != l) {
taille_paquet_buf = BYTE(l - i);
- memcpy(paquet_buf, &p[i], taille_paquet_buf);
+ memcpy(paquet_buf.bytes, p+i, taille_paquet_buf);
}
return S_OK;
@@ -100,302 +97,19 @@
return S_OK;
}
-// Sortie d'un bloc de données vers le fichier
-BOOL CSampleGrabber::ecrit_fichier(LPCVOID pBuf, DWORD sizBuf) const
-{
- DWORD written;
- return WriteFile(hFile, pBuf, sizBuf, &written, NULL);
-}
-
-// (peut-être appelé transitoirement pendant la destruction) :
-void CSampleGrabber::traite_paquet(BYTE * p, WORD pid) // virtual
+void CSampleGrabber::traite_paquet(const TS_packet & p) // virtual
{
+ if (pCapture)
+ pCapture->traite_paquet(p);
}
/* Destructeur général */
+
CSampleGrabber::~CSampleGrabber()
{
- myprintf(L"Grabber détruit\n");
- CloseHandle(hFile);
-}
-
-CSampleGrabber_TS::CSampleGrabber_TS(
- HANDLE hFil, int pmt, int video,
- const liste_pistes & lst_sons,
- const liste_pistes & lst_autr) :
- CSampleGrabber(hFil, video, 0),
- pmt_pid(pmt),
- sons(lst_sons),
- autr(lst_autr)
-{
- myprintf(L"Enregistre TS, video=%i, pmt=%i\n", video, pmt_pid);
-}
-
-void CSampleGrabber_TS::traite_paquet(BYTE * p, WORD pid) // virtual
-{
- // une chaîne en TS
- if (
- pid == 0 ||
- pid == pmt_pid ||
- pid == video_pid ||
- sons.cherche_pid(pid) ||
- autr.cherche_pid(pid)
- )
- ecrit_fichier(p, 188);
-}
-
-CSampleGrabber_PS::CSampleGrabber_PS(HANDLE hFil, int video, int audio) :
- CSampleGrabber(hFil, video, audio),
- taille_vid(0),
- vid_valid(false),
- taille_son(0),
- son_valid(false),
- pcr_ecrit(false)
-{
- myprintf(L"Enregistre PS, video=%i, audio=%i\n", video, audio);
-}
-
-void CSampleGrabber_PS::traite_paquet(BYTE * p, WORD pid) // virtual
-{
- // une chaîne en PS
-
- if (pid == video_pid) {
-
- // si la video est valide, on verifie que pas de discontinuité
- if (vid_valid) {
- int current = p[3]&15;
-
- if ( ( (current - vid_continuity_counter) & 15 ) != 1 ) {
- myprintf(L"discontinuite dans la video\n");
-
- vid_valid = false;
-
- // jette le paquet qu'on a
- if (taille_vid && pcr_ecrit) {
- ecrit_video();
- }
-
- taille_vid = 0;
- }
- }
-
-
- if (p[1] & 0x40) {
- // start indicator
-
- vid_valid = true;
-
- // on sauve ce qu'on a en stock
- if (taille_vid && pcr_ecrit){
- ecrit_video();
- }
-
- taille_vid = 0;
-
- }
-
- if (vid_valid) {
- vid_continuity_counter = p[3]&15;
-
- if (p[3] & 0x10) {
- // il y a du payload
-
- if (p[3] & 0x20) {
- // et adaptation field
- unsigned int taille = p[4]+1;
-
- if (taille < 184) {
- unsigned int taille_copie = 184-taille;
-
- if (taille_vid + taille_copie <= sizeof(vid_buf) ) {
- memcpy(&vid_buf[taille_vid], &p[4+taille], taille_copie);
- taille_vid += taille_copie;
- }
-
- if (p[5] & 0x10) {
- pcr_block(p);
- }
- }
- } else {
- if (taille_vid + 184 <= sizeof(vid_buf) ) {
- memcpy(&vid_buf[taille_vid], &p[4], 184);
- taille_vid += 184;
- }
-
- }
- }
- }
-
- } else if (pid == audio_pid) {
- // si le son est valide, on verifie que pas de discontinuité
- if (son_valid) {
- int current = p[3]&15;
-
- if ( ( (current - son_continuity_counter) & 15 ) != 1 ) {
- myprintf(L"discontinuite dans le son\n");
-
- son_valid = false;
-
- // jette le paquet qu'on a
- if (taille_son && pcr_ecrit) {
- // on sauve ce qu'on a en stock
-
- long taille = taille_son - 6;
-
- son_buf[4] = (BYTE)(taille >> 8);
- son_buf[5] = (BYTE) taille;
-
- ecrit_fichier(son_buf, taille_son);
- }
-
- taille_son = 0;
- }
- }
-
- if (p[1] & 0x40) {
- // start indicator
-
- son_valid = true;
-
- if (taille_son && pcr_ecrit) {
- // on sauve ce qu'on a en stock
-
- long taille = taille_son - 6;
-
- son_buf[4] = (BYTE)(taille >> 8);
- son_buf[5] = (BYTE) taille;
-
- ecrit_fichier(son_buf, taille_son);
- }
-
- taille_son = 0;
-
- }
-
- if (son_valid) {
- son_continuity_counter = p[3]&15;
-
- if (p[3] & 0x10) {
- // il y a du payload
-
- if (p[3] & 0x20) {
- // et adaptation field
- unsigned int taille = p[4]+1;
-
- if (taille < 184) {
- unsigned int taille_copie = 184-taille;
-
- if (taille_son + taille_copie <= sizeof(son_buf) ) {
- memcpy(&son_buf[taille_son], &p[4+taille], taille_copie);
- taille_son += taille_copie;
- }
- }
- } else {
- if (taille_son + 184 <= sizeof(son_buf) ) {
- memcpy(&son_buf[taille_son], &p[4], 184);
- taille_son += 184;
- }
- }
- }
- }
-
+ if (pCapture) {
+ delete pCapture;
+ pCapture = NULL;
}
}
-
-void CSampleGrabber_PS::pcr_block(BYTE * p)
-{
- BYTE pack_header[14];
-
- memset(pack_header, 0, 14);
- pack_header[2]=1;
- pack_header[3]=0xBA;
-
- pack_header[11]=0xA0;
- pack_header[12]=0x03;
- pack_header[13]=0xF8;
-
- // pcr flag
- // 01 SCR 32..30 1 SCR 29..28
- // bouffe 5 bits SCR[0]
- pack_header[4] = 0x44 + ((p[6]>>2)& 0x38) + ((p[6]>>3) & 3);
-
- // SCR 27..20
- // 3 bits SCR[0] et 5 bits SCR[1]
- pack_header[5] = ((p[6]<<5)& 0xE0) + ((p[7]>>3)& 0x1F);
-
- // SCR 19..15 1 SCR 14..13
- // 3 bits SCR[1] et 2*2 bits SCR[2]
- pack_header[6] = 4 + ((p[7]<<5)& 0xE0) + ((p[8]>>3) & 0x1F) + ((p[8]>>4) & 3);
-
- // SCR 12..5
- // 4 bits SCR[2] et 4 bits SCR[3]
- pack_header[7] = ((p[8]<<4)& 0xF0) + ((p[9]>>4)& 0x0F);
-
- // SCR 4..0 1 SCR_EXT 8..7
- // 4 bits SCR[3] et 1+2 bit SCR[4]
- pack_header[8] = ((p[9]<<4)& 0xF0) + ((p[10]>>4)& 0x08) + 4 + ((p[10]<<1)&2) + ((p[11]>>7)&1);
-
- // SCR_EXT 6..0 1
- pack_header[9] = ((p[11]<<1)&0xFE) + 1;
-
- ecrit_fichier(pack_header, 14);
-
- pcr_ecrit = true;
-}
-
-CSampleGrabber_Stream::CSampleGrabber_Stream(HANDLE hFil) :
- CSampleGrabber(hFil, 0, 0)
-{
- myprintf(L"Enregistre multiplex\n");
-}
-
-#define TAILLE_PAQUET_MAX 65535
-
-void CSampleGrabber_PS::ecrit_video(void)
-{
- while (taille_vid - 6 > TAILLE_PAQUET_MAX) {
- // on a besoin de decouper
-
- myprintf(L"Paquet trop gros : %i\n", taille_vid - 6);
-
-
- int index = TAILLE_PAQUET_MAX + 6;
-
- // copie autant qu'on peut
-
- int taille_sous_paquet = index - 6;
-
- vid_buf[4] = (BYTE)(taille_sous_paquet >> 8);
- vid_buf[5] = (BYTE) taille_sous_paquet;
-
- ecrit_fichier(vid_buf, index);
-
- taille_vid -= index;
-
- memcpy(&vid_buf[9], &vid_buf[index], taille_vid);
-
- taille_vid += 9;
-
- vid_buf[6] &= 0xFB;
- vid_buf[7] = 0;
- vid_buf[8] = 0;
-
- }
-
- long taille = taille_vid - 6;
-
- vid_buf[4] = (BYTE)(taille >> 8);
- vid_buf[5] = (BYTE) taille;
-
- ecrit_fichier(vid_buf, taille_vid);
-
-}
-
-void CSampleGrabber_Stream::traite_paquet(BYTE * p, WORD pid) // virtual
-{
- // full TS
- if ( pid != 0x1FFF ) {
- ecrit_fichier(p, 188);
- }
-}
Modifié: trunk/grabber.h
===================================================================
--- trunk/grabber.h 2008-03-08 19:06:30 UTC (rev 116)
+++ trunk/grabber.h 2008-03-08 21:01:26 UTC (rev 117)
@@ -27,35 +27,11 @@
#pragma once
-#include "channels.h"
+#include "capture.h"
-/* Description Transport stream packet
-
- Syntax No. of bits Offset
- ------------------------------------------------------
- transport_packet() {
- sync_byte 8 0
- transport_error_indicator 1 1
- payload_unit_start_indicator 1 1
- transport_priority 1 1
- PID 13 1, 2
- transport_scrambling_control 2 3
- adaptation_field_control 2 3
- continuity_counter 4 3
- if(adaptation_field_control=='10'||adaptation_field_control=='11') {
- adaptation_field()
- }
- if (adaptation_field_control=='01'||adaptation_field_control=='11') {
- for (i=0;i Multiplex
-{
- virtual void traite_paquet(BYTE * p, WORD pid);
-
-public:
- CSampleGrabber_Stream(HANDLE hFil);
-};
Modifié: trunk/record.cpp
===================================================================
--- trunk/record.cpp 2008-03-08 19:06:30 UTC (rev 116)
+++ trunk/record.cpp 2008-03-08 21:01:26 UTC (rev 117)
@@ -31,6 +31,7 @@
#include "channels.h"
#include "ini.h"
#include "grabber.h"
+#include "capture.h"
Enregistrement enregistrements_actuels[NB_MAX_ENREG];
@@ -242,11 +243,15 @@
HANDLE hFile = nom_fichier.Create();
if (hFile != INVALID_HANDLE_VALUE) {
- pCallback = new CSampleGrabber_TS(hFile,
- canal.pmt_pid, video, canal.sons, canal.autr);
+ pCallback =
+ new CSampleGrabber(
+ new CCapture_TS(hFile,
+ canal.pmt_pid, video, canal.sons, canal.autr));
- if (pCallback!=NULL)
+ if (pCallback!=NULL) {
+ myprintf(L"Enregistre TS, video=%i, pmt=%i\n", video, canal.pmt_pid);
enregistrements_actuels[grab].start(pCallback, ixChaine, pProg);
+ }
} else
myprintf(L"Erreur création '%s' code %u\n", nom_fichier.nom, GetLastError());
@@ -281,10 +286,14 @@
HANDLE hFile = nom_fichier.Create();
if (hFile != INVALID_HANDLE_VALUE) {
- pCallback = new CSampleGrabber_PS(hFile, video, son);
+ pCallback =
+ new CSampleGrabber(
+ new CCapture_PS(hFile, video, son));
- if (pCallback!=NULL)
+ if (pCallback!=NULL) {
+ myprintf(L"Enregistre PS, video=%i, audio=%i\n", video, son);
enregistrements_actuels[grab].start(pCallback, ixChaine, pProg);
+ }
} else
myprintf(L"Erreur création '%s' code %u\n", nom_fichier.nom, GetLastError());
@@ -311,9 +320,14 @@
HANDLE hFile = nom_fichier.Create();
if (hFile != INVALID_HANDLE_VALUE) {
- pCallback = new CSampleGrabber_Stream(hFile);
+ pCallback =
+ new CSampleGrabber(
+ new CCapture_Stream(hFile));
- enregistrements_actuels[grab].start(pCallback, STREAM_PSEUDO_INDEX, pProg);
+ if (pCallback!=NULL) {
+ myprintf(L"Enregistre multiplex\n");
+ enregistrements_actuels[grab].start(pCallback, STREAM_PSEUDO_INDEX, pProg);
+ }
} else
myprintf(L"Erreur création '%s' code %u\n", nom_fichier.nom, GetLastError());
From gingko_pouchintv at nospam.homelinux.org Sun Mar 9 16:08:18 2008
From: gingko_pouchintv at nospam.homelinux.org (Gingko)
Date: Sun, 9 Mar 2008 16:08:18 +0100
Subject: [Pouchintv-dev] Si certains se posent des questions ...
References: <20080308190631.24A235F4D2@mail.baysse.fr>
<001301c88150$e44568e0$464da8c0@GILLES>
Message-ID: <001601c881f7$68952850$464da8c0@GILLES>
Bonjour
Si certains se posent des questions à propos de la réception multiple de
certains fichier de "diff" du SVN la nuit dernière :
C'est parce que des essais étaient en cours afin de trouver une solution au
problème des caractères accentués qui s'affichaient incorrectement dans les
"diff" précédents (seule une partie des messages de test sont passés sur
cette liste, heureusement).
Le problème a, en principe, été corrigé (par Laurent), maintenant.
Gingko
From pouchintv-svn at baysse.fr Sun Mar 9 16:14:06 2008
From: pouchintv-svn at baysse.fr (pouchintv-svn at baysse.fr)
Date: Sun, 9 Mar 2008 16:14:06 +0100 (CET)
Subject: [Pouchintv-dev] [PouchinTVMod] gingko | r119 - trunk
Message-ID: <20080309151406.CA97E5F5EB@mail.baysse.fr>
Author: gingko
Date: 2008-03-09 16:14:06 +0100 (dim, 09 mar 2008)
New Revision: 119
Modified:
trunk/channels.cpp
trunk/mpeg2defs.cpp
trunk/mpeg2defs.h
trunk/pmtfilter.cpp
trunk/recprog.cpp
Log:
Changement de chaîne : l'index de chaîne courante est rendu invalide
(-1) pendant les transitions d'une chaîne à l'autre (afin d'éviter que
le filtre de détection de changement de la PMT fasse "rezapper" juste
derrière).
Quelques ajustements et ajouts dans les fichiers de définition MPEG2.
Modifié: trunk/channels.cpp
===================================================================
--- trunk/channels.cpp 2008-03-08 21:27:08 UTC (rev 118)
+++ trunk/channels.cpp 2008-03-09 15:14:06 UTC (rev 119)
@@ -329,14 +329,14 @@
if (freq_differente && recording())
return 1; // On ne change pas de fréquence si enregistrement en cours
+ ixChaineCourante = -1; // doit être égal à -1 pendant les transitions (à cause du filtre PMT)
+
debranche();
- ixChaineCourante = ixChaine_ok(ixChaine) ? ixChaine : -1;
+ if (ixChaine >= 0) {
+ const Chaine & nouveau_canal = Canaux[ixChaine];
- if (ixChaineCourante >= 0) {
- const Chaine & nouveau_canal = Canaux[ixChaineCourante];
-
- myprintf(L"zappe %i\n", ixChaineCourante+1);
+ myprintf(L"zappe %i\n", ixChaine+1);
myprintf(L"SID %i, TSID %i, ONID %i, freq : %i\n", nouveau_canal.SID, nouveau_canal.TSID, nouveau_canal.ONID, nouveau_canal.frequence);
if (freq_differente)
@@ -381,6 +381,9 @@
myprintf(L"%?erreur pid pmt, hr=0x%08x\n", FAILED(hr), hr);
}
+
+ ixChaineCourante = ixChaine_ok(ixChaine) ? ixChaine : -1;
+
return 0;
}
Modifié: trunk/mpeg2defs.cpp
===================================================================
--- trunk/mpeg2defs.cpp 2008-03-08 21:27:08 UTC (rev 118)
+++ trunk/mpeg2defs.cpp 2008-03-09 15:14:06 UTC (rev 119)
@@ -52,7 +52,7 @@
if (siz>=bufsize)
siz=UINT(bufsize-1);
- if (siz > 0 && *src < 0x20) {
+ if (siz > 0 && UINT8(*src) < 0x20) {
ixcp = *src++;
--siz;
}
@@ -101,7 +101,7 @@
if (siz>=bufsize)
siz=UINT(bufsize-1);
- if (siz > 0 && *src < 0x20) {
+ if (siz > 0 && UINT8(*src) < 0x20) {
ixcp = *src++;
--siz;
}
@@ -111,7 +111,7 @@
UINT8 ch;
for (UINT i=0; i= 0x80 && ch <= 0x9f) {
+ if ((ch = src[i]) >= DCTL_MIN_A && ch <= DCTL_MAX_A) {
if (i>sofs) {
UINT dsiz = MultiByteToWideChar(cp, MB_PRECOMPOSED, src+sofs, int(i-sofs), dst, bufsize);
@@ -119,7 +119,7 @@
bufsize -= dsiz;
}
if (bufsize > 1) {
- *dst++ = 0xe000 + ch;
+ *dst++ = DCTL_W_OFFSET | ch;
--bufsize;
}
sofs = i+1;
Modifié: trunk/mpeg2defs.h
===================================================================
--- trunk/mpeg2defs.h 2008-03-08 21:27:08 UTC (rev 118)
+++ trunk/mpeg2defs.h 2008-03-09 15:14:06 UTC (rev 119)
@@ -495,6 +495,22 @@
*/
UINT get_raw_str(LPCSTR src, UINT siz, LPWSTR dst, UINT bufsize);
+// Définitions des codes de contrôle utilisés dans les descripteurs de texte :
+#define DCTL_MIN_A 0x80 // limite inférieure (attention au signe du CHAR lors des comparaisons !)
+#define DCTL_EMPH_ON_A 0x86 // emphasis on
+#define DCTL_EMPH_OFF_A 0x87 // emphasis off
+#define DCTL_CRLF_A 0x8a // CR/LF (saut de ligne)
+#define DCTL_MAX_A 0x9f // limite supérieure
+
+// Version 16 bits :
+#define DCTL_W_OFFSET 0xe000
+
+#define DCTL_MIN_W (DCTL_W_OFFSET|DCTL_MIN_A)
+#define DCTL_EMPH_ON_W (DCTL_W_OFFSET|DCTL_EMPH_ON_A)
+#define DCTL_EMPH_OFF_W (DCTL_W_OFFSET|DCTL_EMPH_OFF_A)
+#define DCTL_CRLF_W (DCTL_W_OFFSET|DCTL_CRLF_A)
+#define DCTL_MAX_W (DCTL_W_OFFSET|DCTL_MAX_A)
+
/*
* Modèle pour éviter d'avoir à prendre la taille du tampon destination :
*/
@@ -2728,6 +2744,8 @@
MJD16 day;
TIM24 time;
+ UINT64 operator () () const
+ {return UINT64(day*24*60*60) + time;} // Conversion en secondes
operator SYSTEMTIME () const
{
SYSTEMTIME st;
Modifié: trunk/pmtfilter.cpp
===================================================================
--- trunk/pmtfilter.cpp 2008-03-08 21:27:08 UTC (rev 118)
+++ trunk/pmtfilter.cpp 2008-03-09 15:14:06 UTC (rev 119)
@@ -55,7 +55,12 @@
// myprintf(L"PMT DoRenderSample %i\n", taille);
pMediaSample->GetPointer((LPBYTE *)(&ppmt));
- if (ppmt->table_id()==si_PMT && taille >= ppmt->size() && ppmt->check_crc32()) {
+ if (
+ ixChaine_ok(ixChaineCourante) &&
+ ppmt->table_id()==si_PMT &&
+ taille >= ppmt->size() &&
+ ppmt->check_crc32()
+ ) {
ChainePMT & chaine = Canaux[ixChaineCourante];
ChainePMT lpmt_e;
Modifié: trunk/recprog.cpp
===================================================================
--- trunk/recprog.cpp 2008-03-08 21:27:08 UTC (rev 118)
+++ trunk/recprog.cpp 2008-03-09 15:14:06 UTC (rev 119)
@@ -1752,6 +1752,7 @@
frequence_courante = canal.frequence;
if (!ixChaine_ok(ixChaineCourante) || frequence_courante != Canaux[ixChaineCourante].frequence) {
// On syntonise maintenant si on n'était pas déjà syntonisé sur ce multiplex
+ ixChaineCourante = -1; // doit être égal à -1 pendant les transitions
change_frequence(frequence_courante);
ixChaineCourante = ixChaine;
ixSonCourant = 0;
From gingko_pouchintv at nospam.homelinux.org Sun Mar 9 16:28:20 2008
From: gingko_pouchintv at nospam.homelinux.org (Gingko)
Date: Sun, 9 Mar 2008 16:28:20 +0100
Subject: [Pouchintv-dev] =?iso-8859-1?q?=C0_propos_des_commentaires_dans_l?=
=?iso-8859-1?q?es_livraisons_SVN?=
References: <20080308190631.24A235F4D2@mail.baysse.fr><001301c88150$e44568e0$464da8c0@GILLES>
<001601c881f7$68952850$464da8c0@GILLES>
Message-ID: <002001c881fa$34815f40$464da8c0@GILLES>
Rebonjour,
Je tiens aussi à vous informer qu'une modification a été introduite par
Laurent dans le SVN, qui fait en sorte que les modifications livrées dans ce
SVN doivent obligatoirement avoir un commentaire d'au moins 100 caractères.
Dans la foulée, j'ai configuré Tortoise SVN pour que l'envoi soit impossible
(pour les utilisateurs de Tortoise SVN) si un commentaire de cette longueur
n'existe pas dans la boîte de dialogue d'envoi (la modification de Laurent
ne s'appliquant que pour rejeter les livraisons après envoi) : le bouton
"OK" de la boîte de dialogue restera désactivé tant que cette condition ne
sera pas satisfaite.
Le fonctionnement de Tortoise SVN est tel que la modification de ce
paramètre devrait, via le SVN, se propager automatiquement à tous les
utilisateurs de Tortoise SVN à partir du moment où ceux-ci auront récupéré
une version de Pouchin TV Mod au moins aussi récente que la version r117.
Dès lors, la modification de Laurent ne devrait réellement concerner que les
utilisateurs d'autres logiciels que Tortoise SVN.
Gingko
From pouchintv-svn at baysse.fr Sun Mar 9 17:34:40 2008
From: pouchintv-svn at baysse.fr (pouchintv-svn at baysse.fr)
Date: Sun, 9 Mar 2008 17:34:40 +0100 (CET)
Subject: [Pouchintv-dev] [PouchinTVMod] gingko | r120 - trunk
Message-ID: <20080309163440.741A95F5F0@mail.baysse.fr>
Author: gingko
Date: 2008-03-09 17:34:39 +0100 (dim, 09 mar 2008)
New Revision: 120
Modified:
trunk/channels.h
trunk/epg.cpp
trunk/epgfilter.cpp
trunk/main.cpp
trunk/recprog.cpp
trunk/utils.cpp
trunk/utils.h
Log:
Intégration des nouvelles définitions MPEG2 'mpeg2defs.h/mpeg2defs.cpp'
au guide électronique de programmation EPG (epgfilter.cpp), avec, en
même temps, optimisation et simplification de celui-ci.
La gestion du tableau des émissions (même si celui-ci ne contient
toujours que deux éléments) est maintenant vectorisée, ce qui fait
qu'il sera très facile de l'agrandir dans le futur, si besoin est.
Ajouts de quelques fonctions utilitaires (liées à l'EPG et utilisées
dans les modifications ci-dessus) dans 'utils.h' et 'utils.cpp'.
Application d'un filtre de nettoyage de texte aux noms et descriptifs
d'émission, afin d'en éliminer les espaces excédentaires ainsi que
les codes de contrôle (ceci évite, en particulier, que les codes de
saut de ligne apparaissent comme des "?" dans les descriptifs).
Modifié: trunk/channels.h
===================================================================
--- trunk/channels.h 2008-03-09 15:14:06 UTC (rev 119)
+++ trunk/channels.h 2008-03-09 16:34:39 UTC (rev 120)
@@ -30,22 +30,20 @@
#include "chanutils.h"
struct Emission {
- ULARGE_INTEGER debut;
- char debut_str[32];
- char fin[32];
- char nom[256];
- char desc[256];
- bool latest;
- SYSTEMTIME debut2;
- SYSTEMTIME fin2;
+ UINT64 cle; // Représentation simplifiée de l'heure de début pour comparaisons (0 si pas défini)
+ UINT16 eid; // "event id"
+ SYSTEMTIME debut;
+ SYSTEMTIME fin;
+ char nom[86];
+ char desc[256];
};
struct ChainePMT {
- WORD video_pid;
- WORD mpeg4_pid;
- WORD pcr_pid;
- liste_pistes sons;
- liste_pistes autr;
+ UINT16 video_pid;
+ UINT16 mpeg4_pid;
+ UINT16 pcr_pid;
+ liste_pistes sons;
+ liste_pistes autr;
ChainePMT();
char norme(void) const;
@@ -55,10 +53,10 @@
// Définition de l'ensemble des identifiants d'une chaîne :
struct ChaineIDs {
- WORD ONID;
- WORD TSID;
- WORD SID;
- WORD numero_nit;// Numéro de chaîne original
+ UINT16 ONID;
+ UINT16 TSID;
+ UINT16 SID;
+ UINT16 numero_nit;// Numéro de chaîne original
};
enum EtatChaine {
@@ -68,14 +66,15 @@
};
struct Chaine : public ChainePMT, public ChaineIDs {
- char nom[64];
- char groupe[64];
- WORD canal_no;
- long frequence;
- WORD pmt_pid;
- EtatChaine etat;
- WORD numeroChaine;// Numéro de chaîne éventuellement modifié par l'utilisateur
- Emission emis[2];
+ char nom[64];
+ char groupe[64];
+ UINT16 canal_no;
+ UINT16 pmt_pid;
+ long frequence;
+ EtatChaine etat;
+ UINT16 numeroChaine; // Numéro de chaîne éventuellement modifié par l'utilisateur
+ UINT8 emi_count; // Comptage des émissions mémorisées
+ Emission emis[2];
private:
HBITMAP hImage;
public:
Modifié: trunk/epg.cpp
===================================================================
--- trunk/epg.cpp 2008-03-09 15:14:06 UTC (rev 119)
+++ trunk/epg.cpp 2008-03-09 16:34:39 UTC (rev 120)
@@ -35,43 +35,47 @@
static void ajout_emission(HWND hListItem, const Chaine & canal, BYTE noEmis, int & iItem)
{
- if (noEmis >=_countof(canal.emis))
+ if (noEmis >= canal.emi_count)
return;
const Emission & emis = canal.emis[noEmis];
- if (emis.debut.QuadPart != 0) {
- LVITEMA item = {
- LVIF_TEXT | LVIF_PARAM, // mask
- iItem, // iItem
- 0, // iSubItem
- 0, 0, // state, stateMask
- const_cast(canal.nom), // pszText
- 0, // cchTextMax
- 0, // iImage
- MAKELPARAM(canal.SID, noEmis) // lParam
- };
+ if (emis.cle == 0)
+ return;
- SendMessage(hListItem, LVM_INSERTITEMA, 0, (LPARAM)&item);
+ LVITEMA item = {
+ LVIF_TEXT | LVIF_PARAM, // mask
+ iItem, // iItem
+ 0, // iSubItem
+ 0, 0, // state, stateMask
+ const_cast(canal.nom), // pszText
+ 0, // cchTextMax
+ 0, // iImage
+ MAKELPARAM(canal.SID, noEmis) // lParam
+ };
+ CHAR str[16];
- item.pszText = const_cast(emis.debut_str);
- item.iSubItem = 1;
- SendMessage(hListItem, LVM_SETITEMTEXTA, iItem, (LPARAM)&item);
+ SendMessage(hListItem, LVM_INSERTITEMA, 0, (LPARAM)&item);
- item.pszText = const_cast(emis.fin);
- item.iSubItem = 2;
- SendMessage(hListItem, LVM_SETITEMTEXTA, iItem, (LPARAM)&item);
+ item.pszText = const_cast(str);
- item.pszText = const_cast(emis.nom);
- item.iSubItem = 3;
- SendMessage(hListItem, LVM_SETITEMTEXTA, iItem, (LPARAM)&item);
+ TimeToStr(emis.debut, str, _countof(str));
+ item.iSubItem = 1;
+ SendMessage(hListItem, LVM_SETITEMTEXTA, iItem, (LPARAM)&item);
- item.pszText = const_cast(emis.desc);
- item.iSubItem = 4;
- SendMessage(hListItem, LVM_SETITEMTEXTA, iItem, (LPARAM)&item);
+ TimeToStr(emis.fin, str, _countof(str));
+ item.iSubItem = 2;
+ SendMessage(hListItem, LVM_SETITEMTEXTA, iItem, (LPARAM)&item);
- iItem++;
- }
+ item.pszText = const_cast(emis.nom);
+ item.iSubItem = 3;
+ SendMessage(hListItem, LVM_SETITEMTEXTA, iItem, (LPARAM)&item);
+
+ item.pszText = const_cast(emis.desc);
+ item.iSubItem = 4;
+ SendMessage(hListItem, LVM_SETITEMTEXTA, iItem, (LPARAM)&item);
+
+ iItem++;
}
static void remplit_table_epg(HWND hListItem)
Modifié: trunk/epgfilter.cpp
===================================================================
--- trunk/epgfilter.cpp 2008-03-09 15:14:06 UTC (rev 119)
+++ trunk/epgfilter.cpp 2008-03-09 16:34:39 UTC (rev 120)
@@ -31,6 +31,7 @@
#include "main.h"
#include "channels.h"
#include "crc32.h"
+#include "mpeg2defs.h"
CEPGFilter::CEPGFilter(REFCLSID clsid, HRESULT *phr) : CBaseRenderer(clsid, L"filtre EPG", NULL, phr)
{
@@ -43,254 +44,123 @@
myprintf(L"EPG filter detruit\n");
}
-
-static void print_time_mjd (int mjd, SYSTEMTIME * st)
+// Nettoyage des codes spéciaux (codes 0x80 à 0x9f) dans la chaîne,
+// ainsi que des espaces de début, de fin et multiples :
+void clean_epg_string(LPSTR str)
{
- long y, m, d, k;
+ LPSTR src = str;
+ LPSTR dst = str;
+ UINT8 ch; // non signé !
- // algo: ETSI EN 300 468 - ANNEX C
+ while ((ch=*src++) != 0) {
+ if (ch==DCTL_CRLF_A || ch=='\t')
+ ch = ' '; // remplacer code saut de ligne ou tabulation par espace
+ if (
+ (ch==' ' && (dst==str || dst[-1]==' ')) || // sauter les espaces doublés et de début
+ (ch>=DCTL_MIN_A && ch<=DCTL_MAX_A) // sauter les autres codes de contrôle
+ )
+ continue;
- y = (long) ((mjd - 15078.2) / 365.25);
- m = (long) ((mjd - 14956.1 - (long)(y * 365.25) ) / 30.6001);
- d = (long) (mjd - 14956 - (long)(y * 365.25) - (long)(m * 30.6001));
- k = (m == 14 || m == 15) ? 1 : 0;
- y = y + k + 1900;
- m = m - 1 - k*12;
+ *dst++ = ch;
+ }
- st->wYear = (WORD)y;
- st->wMonth = (WORD)m;
- st->wDay = (WORD)d;
-
-// myprintf(L"%02i-%02i-%i\n", d, m, y);
+ // Enlever les espaces de fin :
+ while (dst==str || dst[-1]==' ')
+ --dst;
+ *dst = 0;
}
-static void print(BYTE * p, int taille, char * dest) {
- if (taille > 0 && p[0] == 5)
- {
- p++;
- taille--;
- }
- for (int i=0; i>4)*10 ) + (x&0xF) )
+ for (streamScanner se(eit.entryRange()); !se; ++se) {
+ UINT8 i;
+ UINT16 eid = se().event_id();
-static void parse_eit(BYTE * p, DWORD size) {
+ // Chercher si l'émission n'est pas déjà mémorisée, et trouver le point d'insertion, s'il y a lieu :
+ for (i=0; i= _countof(chaine.emis)) {
+ // Nombre maximal d'émissions mémorisées atteint :
+ // chasser la plus ancienne, et décaler vers le bas selon le point d'insertion.
+ if (cle < chaine.emis[0].cle /*insert == 0*/)
+ continue; // ça ne devrait pas arriver, mais si jamais l'émission juste reçue est la plus ancienne ...
+ for (i=0; i <= _countof(chaine.emis) && cle > chaine.emis[i+1].cle; ++i)
+ chaine.emis[i] = chaine.emis[i+1];
+ } else {
+ // Nombre maximal d'émissions mémorisées non atteint :
+ // juste décaler vers le haut selon le point d'insertion.
+ for (i = chaine.emi_count; i>0 && cle < chaine.emis[i-1].cle; --i);
+ chaine.emis[i] = chaine.emis[i-1];
}
- }
- if (chaineEit < 0) return;
+ Emission & emis = chaine.emis[i];
-// myprintf(L"sid %i, tid %i, onid %i, taille %i\n", sid, tid, onid, size);
+ emis.debut = se().start_time; // (format SYSTEMTIME)
- DWORD offset = 14;
-
- while (offset < size - 4) {
- // int ev = (p[offset]<<8) + p[offset+1];
-
- int jour = (p[offset+2]<<8) + p[offset+3];
-
- SYSTEMTIME st;
- st.wDayOfWeek = 0;
- st.wMilliseconds = 0;
-
- print_time_mjd(jour, &st);
-
- st.wHour = hex_to_dec(p[offset+4]);
- st.wMinute = hex_to_dec(p[offset+5]);
- st.wSecond = hex_to_dec(p[offset+6]);
-
- // myprintf(L"heure %i:%i:%i\n", st.wHour, st.wMinute, st.wSecond);
-
- FILETIME ft;
- SystemTimeToFileTime(&st, &ft);
-
- ULARGE_INTEGER debut;
- debut.LowPart = ft.dwLowDateTime;
- debut.HighPart = ft.dwHighDateTime;
-
- int len = ((p[offset+10]&0xF)<<8) + p[offset+11];
-
- Chaine & chaine = Canaux[chaineEit];
-
- if (debut.QuadPart == chaine.emis[0].debut.QuadPart)
- {
- // we already know that emission
- chaine.emis[0].latest = true;
- chaine.emis[1].latest = false;
- offset += 12 + len;
- continue;
- }
-
- if (debut.QuadPart == chaine.emis[1].debut.QuadPart)
- {
- // we already know that emission
- chaine.emis[0].latest = false;
- chaine.emis[1].latest = true;
- offset += 12 + len;
- continue;
- }
-
- Emission emi;
- memset(&emi, 0, sizeof(Emission));
-
- emi.latest = true;
- emi.debut = debut;
-
// transforme l'heure GMT du programme en local
- FILETIME lft;
- FileTimeToLocalFileTime(&ft, &lft);
- FileTimeToSystemTime(&lft, &st);
- emi.debut2 = st;
+ SystemTimeToLocalSystemTime(emis.debut);
- sprintf_s(emi.debut_str, 32, "%02i:%02i:%02i", st.wHour, st.wMinute, st.wSecond);
+ // on ajoute la durée pour trouver l'heure de fin
+ emis.fin = emis.debut;
+ AddTime(emis.fin, se().duration);
- int heure = hex_to_dec(p[offset+7]);
- int min = hex_to_dec(p[offset+8]);
- int sec = hex_to_dec(p[offset+9]);
+ // Ajouter le nom et le descriptif
+ for (descrScanner sed(se().descrRange()); !sed; ++sed) {
+ if (sed().tag() == mdt_Short_Event) {
+ const MDescriptor_4d & d4d = sed().as();
- ULARGE_INTEGER fin = debut;
+ d4d.event_name().get(emis.nom);
+ d4d.text().get(emis.desc);
- fin.QuadPart += (heure*3600+min*60+sec)*10000000ULL;
-
- ft.dwHighDateTime = fin.HighPart;
- ft.dwLowDateTime = fin.LowPart;
-
- FileTimeToLocalFileTime(&ft, &lft);
- FileTimeToSystemTime(&lft, &st);
- emi.fin2 = st;
-
- sprintf_s(emi.fin, 32, "%02i:%02i:%02i", st.wHour, st.wMinute, st.wSecond);
-
- offset+=12;
-
- int i = 0;
- while (i < len) {
- int tag = p[offset+i];
- int taille = p[offset+i+1];
-
- // myprintf(L"tag %i\n", tag);
- // 77 short_event_descriptor
- // 78 extended_event_descriptor
- // 80 component_descriptor
- // 84 content_descriptor
- // 85 parental rating ?
-
- i += 2;
-
- if (tag == 77) {
- int t1 = p[offset+i+3];
-
- // event name
- print(&p[offset+i+4], t1, emi.nom);
-
- int t2 = p[offset+i+4+t1];
-
- // text
- print(&p[offset+i+5+t1], t2, emi.desc);
-
+ // Nettoyage des chaînes :
+ clean_epg_string(emis.nom);
+ clean_epg_string(emis.desc);
+ break; // en principe, y'aura pas deux descripteurs de ce type ...
}
-
- i += taille;
}
- // myprintf(L"%S : %S : %S\n", chaine.nom, emi.debut_str, emi.nom);
-
- // faut placer l'émission maintenant
- if (chaine.emis[0].debut.QuadPart == 0) {
- // c'est la 1ère recensée
- chaine.emis[0] = emi;
- } else if (chaine.emis[1].debut.QuadPart == 0) {
-
- // c'est la 2ème recensée
- if( debut.QuadPart > chaine.emis[0].debut.QuadPart)
- {
- chaine.emis[1] = emi;
- chaine.emis[0].latest = false;
- } else {
- chaine.emis[1] = chaine.emis[0];
- chaine.emis[0] = emi;
-
- chaine.emis[1].latest = false;
- }
-
- } else {
-
- // on vire l'emission qui est pas la latest
-
- if (chaine.emis[0].latest)
- {
- // on vire la 2
-
- chaine.emis[1] = emi;
- chaine.emis[0].latest = false;
-
- } else {
-
- // on vire la 1
-
- chaine.emis[0] = emi;
- chaine.emis[1].latest = false;
-
- }
-
- // on remet dans l'ordre si nécessaire
-
- if ( chaine.emis[0].debut.QuadPart > chaine.emis[1].debut.QuadPart)
- {
- Emission tmp = chaine.emis[0];
- chaine.emis[0] = chaine.emis[1];
- chaine.emis[1] = tmp;
- }
-
- }
-
- // passe par le thread graphique pour updater, sinon ça plante
- if (chaineEit == ixChaineCourante)
- PostMessage(hMainWnd, WM_USER, 0, 0);
-
- offset += len;
+ emis.cle = cle;
+ emis.eid = eid;
+ if (chaine.emi_count < _countof(chaine.emis)) // en dernier (pour éviter de risquer l'accès à des
+ ++chaine.emi_count; // données mal initialisées depuis un autre thread)
+ modif = true;
}
+
+ // passe par le thread graphique pour updater, sinon ça plante
+ if (modif && ixChaine == ixChaineCourante)
+ PostMessage(hMainWnd, WM_USER, 0, 0);
}
-
HRESULT CEPGFilter::DoRenderSample(IMediaSample *pMediaSample)
{
- BYTE * p;
- pMediaSample->GetPointer(&p);
+ const SI_EIT * peit;
+ size_t taille = pMediaSample->GetActualDataLength();
- long taille = pMediaSample->GetActualDataLength();
-
// myprintf(L"DoRenderSample %i %i\n", taille, p[0]);
+ pMediaSample->GetPointer((LPBYTE *)(&peit));
- if (p[0] == 78 || p[0] == 79)
- {
- if (check_crc32(p, taille))
- {
- parse_eit(p, taille);
- }
+ if (
+ (peit->table_id()==si_EIT_act || peit->table_id()==si_EIT_oth) &&
+ taille >= peit->size()
+ && peit->check_crc32()
+ ) {
+ parse_eit(*peit, taille);
}
return S_OK;
-
}
HRESULT CEPGFilter::CheckMediaType(const CMediaType * pmt)
Modifié: trunk/main.cpp
===================================================================
--- trunk/main.cpp 2008-03-09 15:14:06 UTC (rev 119)
+++ trunk/main.cpp 2008-03-09 16:34:39 UTC (rev 120)
@@ -839,10 +839,22 @@
}
if (hStatus != NULL) {
+ CHAR str[16];
+
SendMessageA(hStatus, SB_SETTEXTA, 0, (LPARAM)canal_courant.nom);
- SendMessageA(hStatus, SB_SETTEXTA, 1, (LPARAM)canal_courant.emis[0].debut_str);
+
+ str[0] = 0;
+ if (canal_courant.emis[0].cle != 0)
+ TimeToStr(canal_courant.emis[0].debut, str, _countof(str));
+ SendMessageA(hStatus, SB_SETTEXTA, 1, (LPARAM)str);
+
SendMessageA(hStatus, SB_SETTEXTA, 2, (LPARAM)canal_courant.emis[0].nom);
- SendMessageA(hStatus, SB_SETTEXTA, 3, (LPARAM)canal_courant.emis[1].debut_str);
+
+ str[0] = 0;
+ if (canal_courant.emis[1].cle != 0)
+ TimeToStr(canal_courant.emis[1].debut, str, _countof(str));
+ SendMessageA(hStatus, SB_SETTEXTA, 3, (LPARAM)str);
+
SendMessageA(hStatus, SB_SETTEXTA, 4, (LPARAM)canal_courant.emis[1].nom);
if (is_vista) {
@@ -865,7 +877,7 @@
}
#endif // #ifdef USE_LOGITECH_LCD
- if (use_msn && canal_courant.emis[0].debut.QuadPart != 0) {
+ if (use_msn && canal_courant.emi_count > 0) {
HWND msnui = FindWindow(L"MsnMsgrUIManager", NULL);
if (msnui != NULL)
@@ -873,7 +885,9 @@
COPYDATASTRUCT msndata;
WCHAR buffer[1024];
- swprintf_s(buffer, _countof(buffer), L"\\0Music\\01\\0{0} - {1}\\0%S\\0%S\\0\\0\\0", canal_courant.nom, canal_courant.emis[0].nom);
+ swprintf_s(buffer, _countof(buffer),
+ L"\\0Music\\01\\0{0} - {1}\\0%S\\0%S\\0\\0\\0",
+ canal_courant.nom, canal_courant.emis[0].nom);
msndata.dwData = 0x547;
msndata.lpData = &buffer;
@@ -1765,7 +1779,7 @@
Chaine & canal = Canaux[ixChaineCourante];
text_osd(hdc, rect.right, rect.top, TA_RIGHT, "%s", canal.nom);
- if (canal.emis[0].debut.QuadPart)
+ if (canal.emi_count > 0)
text_osd(hdc, rect.right, rect.top+hauteur, TA_RIGHT,
"%s", canal.emis[0].nom);
}
Modifié: trunk/recprog.cpp
===================================================================
--- trunk/recprog.cpp 2008-03-09 15:14:06 UTC (rev 119)
+++ trunk/recprog.cpp 2008-03-09 16:34:39 UTC (rev 120)
@@ -912,8 +912,8 @@
prog.apres = apr_rien;
prog.methode = meth_TS;
prog.audio = audio_1;
- prog.fin = emis.fin2;
- prog.debut = emis.debut2;
+ prog.fin = emis.fin;
+ prog.debut = emis.debut;
prog.repetition = 0;
prog.tache = planif_sans;
prog.etat = epr_actif;
Modifié: trunk/utils.cpp
===================================================================
--- trunk/utils.cpp 2008-03-09 15:14:06 UTC (rev 119)
+++ trunk/utils.cpp 2008-03-09 16:34:39 UTC (rev 120)
@@ -37,6 +37,7 @@
* *
********************************************************************************************/
+#include
#include "utils.h"
bool WindowPos::verifie()
@@ -118,3 +119,24 @@
Utime += INT64(add)*10000;
FileTimeToSystemTime(LPFILETIME(&Utime), &time);
}
+
+/**
+ * Conversion heure (sans date) en chaîne de caractères :
+ **/
+void TimeToStr(SYSTEMTIME st, char *str, size_t str_size)
+{
+ sprintf_s(str, str_size, "%02i:%02i:%02i", st.wHour, st.wMinute, st.wSecond);
+}
+
+/**
+ * Conversion temps GMT en temps local :
+ **/
+void SystemTimeToLocalSystemTime(SYSTEMTIME & st)
+{
+ FILETIME ft;
+ FILETIME lft;
+
+ SystemTimeToFileTime(&st, &ft);
+ FileTimeToLocalFileTime(&ft, &lft);
+ FileTimeToSystemTime(&lft, &st);
+}
Modifié: trunk/utils.h
===================================================================
--- trunk/utils.h 2008-03-09 15:14:06 UTC (rev 119)
+++ trunk/utils.h 2008-03-09 16:34:39 UTC (rev 120)
@@ -71,7 +71,7 @@
};
/**
- * Élement de table d'association chaîne <--> valeur binaire.
+ * Élément de table d'association chaîne <--> valeur binaire.
* Cette structure est destinée à faire partie d'une table dont le dernier élément
* doit avoir ses deux valeurs à NULL et 0 respectivement.
**/
@@ -110,6 +110,24 @@
**/
void AddTime(SYSTEMTIME & time, long add);
+/**
+ * Conversion FILETIME vers UINT64 ...
+ **/
+inline UINT64 FILETIME_to_UINT64(const FILETIME & ft)
+{
+ return (UINT64(ft.dwHighDateTime)<<32) | ft.dwLowDateTime;
+}
+
+/**
+ * Conversion heure (sans date) en chaîne de caractères :
+ **/
+void TimeToStr(SYSTEMTIME st, char *str, size_t str_size);
+
+/**
+ * Conversion temps GMT en temps local :
+ **/
+void SystemTimeToLocalSystemTime(SYSTEMTIME & st);
+
/*
* TEMPLATE :
* Structure d'assistance à l'évaluation de la moyenne des N plus récentes valeurs de type T données :
From gingko_pouchintv at nospam.homelinux.org Wed Mar 12 10:21:34 2008
From: gingko_pouchintv at nospam.homelinux.org (Gingko)
Date: Wed, 12 Mar 2008 10:21:34 +0100
Subject: [Pouchintv-dev] =?iso-8859-1?q?Pr=E9-requis_pour_compiler?=
References: <20080308190631.24A235F4D2@mail.baysse.fr><001301c88150$e44568e0$464da8c0@GILLES><001601c881f7$68952850$464da8c0@GILLES>
<002001c881fa$34815f40$464da8c0@GILLES>
Message-ID: <004001c88422$77d150a0$464da8c0@GILLES>
Bonjour,
Sur la page de compilation, dans les pré-requis pour compiler, je pense
qu'il faudrait revoir les liens :
Pour ce qui est du "Tout dernier Platform SDK", le lien n'est plus valide.
Maintenant, Microsoft nous renvoie sur la page suivante :
- Windows SDK for Windows Server 2008 and .NET Framework 3.5
-
http://www.microsoft.com/downloads/details.aspx?FamilyId=F26B1AA4-741A-433A-9BE5-FA919850BDBF&displaylang=en
Pour ce qui est du "Tout dernier SDK DirectX", le lien est apparemment
encore bon, mais néanmoins, on en est à :
- DirectX SDK de Mars 2008
-
http://www.microsoft.com/downloads/details.aspx?FamilyId=572BE8A6-263A-4424-A7FE-69CFF1A5B180&displaylang=en
(et on aura ainsi sauté les versions de juin, août, octobre et décembre
2006, ainsi que d'avril, août et novembre 2007) :-)
... et le lien concernant Visual C++ 2005 Express renvoie d'ores et déjà sur
le téléchargement de Visual C++ 2008 Express ... :-)
Ceci étant dit, je n'ai pas encore testé le bon fonctionnement de la
compilation avec ces versions.
Gingko
From pouchintv-svn at baysse.fr Wed Mar 12 14:16:55 2008
From: pouchintv-svn at baysse.fr (pouchintv-svn at baysse.fr)
Date: Wed, 12 Mar 2008 14:16:55 +0100 (CET)
Subject: [Pouchintv-dev] [PouchinTVMod] gingko | r121 - trunk
Message-ID: <20080312131655.B75B25F6B1@mail.baysse.fr>
Author: gingko
Date: 2008-03-12 14:16:55 +0100 (mer, 12 mar 2008)
New Revision: 121
Modified:
trunk/base.h
trunk/epgfilter.cpp
trunk/graph.cpp
trunk/main.cpp
trunk/main.h
trunk/parse.cpp
trunk/pmtfilter.cpp
trunk/recprog.cpp
trunk/resource.h
trunk/settings.cpp
trunk/trayicon.cpp
trunk/xml.cpp
Log:
Réorganisation des messages "WM_" internes à l'application (anciennement WM_USER, WM_USER+1,
WM_APP, WM_APP+1 et MY_TRAY_ICON_MESSAGE) : ces messages reçoivent des noms cohérents
et correspondant à leur fonction. Les valeurs qui leur sont affectées sont organisées en séquence.
Changements de noms dans 'graph.cpp' : il y avait des noms de variable ('pPinEntrée', plusieurs fois)
avec accent aigu dans le nom. Curieux que le compilateur ait accepté ça ...
(aussi, dans ce même fichier, le numéro du PID EIT reçoit le nom qui lui correspond dans mpeg2defs.h).
Petite modification dans 'xml.cpp'
(à cause de messages d'erreur que j'ai eus après une corruption de données).
Modifié: trunk/base.h
===================================================================
--- trunk/base.h 2008-03-09 16:34:39 UTC (rev 120)
+++ trunk/base.h 2008-03-12 13:16:55 UTC (rev 121)
@@ -78,7 +78,7 @@
# define EXPORT_GRAPH 1
# define LOG_DSHOW 1 // Enregistrer DShow
#else
-#define EXPORT_GRAPH 0
+# define EXPORT_GRAPH 0
# define LOG_DSHOW 0
#endif
Modifié: trunk/epgfilter.cpp
===================================================================
--- trunk/epgfilter.cpp 2008-03-09 16:34:39 UTC (rev 120)
+++ trunk/epgfilter.cpp 2008-03-12 13:16:55 UTC (rev 121)
@@ -141,7 +141,7 @@
// passe par le thread graphique pour updater, sinon ça plante
if (modif && ixChaine == ixChaineCourante)
- PostMessage(hMainWnd, WM_USER, 0, 0);
+ PostMessage(hMainWnd, WM_APP_EPG_UPDATED, 0, 0);
}
HRESULT CEPGFilter::DoRenderSample(IMediaSample *pMediaSample)
Modifié: trunk/graph.cpp
===================================================================
--- trunk/graph.cpp 2008-03-09 16:34:39 UTC (rev 120)
+++ trunk/graph.cpp 2008-03-12 13:16:55 UTC (rev 121)
@@ -42,6 +42,8 @@
#include "record.h"
+#include "mpeg2defs.h"
+
IFilterGraph2 * pGraph = NULL;
IMediaControl * pControl = NULL;
@@ -359,9 +361,9 @@
return 1;
}
- IPin * pPinEntrée = cherche_pin(pVideoCodec, PINDIR_INPUT);
- hr = pGraph->ConnectDirect(pVideoPin, pPinEntrée, NULL);
- pPinEntrée->Release();
+ IPin * pPinEntree = cherche_pin(pVideoCodec, PINDIR_INPUT);
+ hr = pGraph->ConnectDirect(pVideoPin, pPinEntree, NULL);
+ pPinEntree->Release();
if (FAILED(hr)) {
erreur(L"Impossible de connecter le demux au codec vidéo");
@@ -413,7 +415,8 @@
#else
pVMRConfig->SetRenderingMode(MyVMRMode_Renderless);
- if (use_vmr_deinterlace) pVMRConfig->SetNumberOfStreams(1);
+ if (use_vmr_deinterlace)
+ pVMRConfig->SetNumberOfStreams(1);
#endif
pVMRConfig->Release();
@@ -627,9 +630,9 @@
return 1;
}
- IPin * pPinEntrée = cherche_pin(pAudioCodec, PINDIR_INPUT);
- hr = pGraph->ConnectDirect(pSoundPin, pPinEntrée, NULL);
- pPinEntrée->Release();
+ IPin * pPinEntree = cherche_pin(pAudioCodec, PINDIR_INPUT);
+ hr = pGraph->ConnectDirect(pSoundPin, pPinEntree, NULL);
+ pPinEntree->Release();
if (FAILED(hr)) {
erreur(L"Impossible de connecter le demux au codec audio");
@@ -711,9 +714,9 @@
return 1;
}
- IPin * pPinEntrée = cherche_pin(pAc3Codec, PINDIR_INPUT);
- hr = pGraph->ConnectDirect(pAc3Pin, pPinEntrée, NULL);
- pPinEntrée->Release();
+ IPin * pPinEntree = cherche_pin(pAc3Codec, PINDIR_INPUT);
+ hr = pGraph->ConnectDirect(pAc3Pin, pPinEntree, NULL);
+ pPinEntree->Release();
if (FAILED(hr)) {
erreur(L"Impossible de connecter le demux au codec AC3");
@@ -781,9 +784,9 @@
return 1;
}
- IPin * pPinEntrée = cherche_pin(pMpeg2Filter, PINDIR_INPUT);
- hr = pGraph->ConnectDirect(pDataPin, pPinEntrée, NULL);
- pPinEntrée->Release();
+ IPin * pPinEntree = cherche_pin(pMpeg2Filter, PINDIR_INPUT);
+ hr = pGraph->ConnectDirect(pDataPin, pPinEntree, NULL);
+ pPinEntree->Release();
if (FAILED(hr)) {
erreur(L"Impossible de connecter le demux au mpeg2data");
@@ -831,14 +834,14 @@
return 1;
}
- IPin * pPinEntrée = cherche_pin(pEPGFilter, PINDIR_INPUT);
+ IPin * pPinEntree = cherche_pin(pEPGFilter, PINDIR_INPUT);
if (pEPGFilter == NULL) {
erreur(L"pas trouvé pin entrée");
return 1;
}
- hr = pGraph->ConnectDirect(pEpgPin, pPinEntrée, NULL);
- pPinEntrée->Release();
+ hr = pGraph->ConnectDirect(pEpgPin, pPinEntree, NULL);
+ pPinEntree->Release();
if (FAILED(hr)) {
erreur(L"pas connecté pin entrée");
@@ -849,7 +852,7 @@
IMPEG2PIDMap * pMapEpg;
hr = pEpgPin->QueryInterface(&pMapEpg);
if (SUCCEEDED(hr)) {
- ULONG pid = 18;
+ ULONG pid = p_pid_EIT;
pMapEpg->MapPID(1, &pid, MEDIA_MPEG2_PSI);
pMapEpg->Release();
@@ -892,15 +895,15 @@
return 1;
}
- IPin * pPinEntrée = cherche_pin(pPMTFilter, PINDIR_INPUT);
+ IPin * pPinEntree = cherche_pin(pPMTFilter, PINDIR_INPUT);
if (pPMTFilter == NULL)
{
erreur(L"pas trouvé pin entrée");
return 1;
}
- hr = pGraph->ConnectDirect(pPmtPin, pPinEntrée, NULL);
- pPinEntrée->Release();
+ hr = pGraph->ConnectDirect(pPmtPin, pPinEntree, NULL);
+ pPinEntree->Release();
if (FAILED(hr)) {
erreur(L"pas connecté pin entrée");
@@ -977,6 +980,7 @@
int build_graph(void)
{
+ int res;
// créer le graph
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
@@ -1010,7 +1014,7 @@
IBaseFilter * pAvantDemux;
- int res = filtre_compat(pNetworkTuner);
+ res = filtre_compat(pNetworkTuner);
if (res == 1) {
@@ -1147,7 +1151,7 @@
// connections
- int res = cree_and_render_pins();
+ res = cree_and_render_pins();
if (res)
{
erreur(L"Erreur lors de la création du graph");
Modifié: trunk/main.cpp
===================================================================
--- trunk/main.cpp 2008-03-09 16:34:39 UTC (rev 120)
+++ trunk/main.cpp 2008-03-12 13:16:55 UTC (rev 121)
@@ -2297,36 +2297,6 @@
lRet = DefWindowProc(hWnd, uMsg, wParam, lParam);
break;
- case MY_TRAY_ICON_MESSAGE:
- if (wParam==MY_TRAY_ICON_ID) {
- switch(lParam) {
- case WM_LBUTTONDBLCLK:
- if (IsMinimized(hWnd)) {
- if (!do_init_vmr())
- return -1;
- if (suspend_minimized) {
- rebranche();
- change_frequence(Canaux[ixChaineCourante].frequence); // Vérifier si nécessaire
- zappe_index(ixChaineCourante);
- }
- ShowWindow(hWnd, SW_SHOW);
- ShowWindow(hWnd, SW_RESTORE);
- } else {
- SetForegroundWindow(hWnd);
- }
-
- break;
- case WM_LBUTTONDOWN:
- if (!IsMinimized(hWnd))
- SetForegroundWindow(hWnd);
- break;
- case WM_CONTEXTMENU:
- case WM_RBUTTONUP:
- popup_menu(true);
- }
- }
- break;
-
case WM_COMMAND:
do_command(LOWORD(wParam));
break;
@@ -2475,11 +2445,41 @@
time_context_quit = GetTickCount();
break;
- case WM_USER:
+ case WM_APP_TRAYICON_MSG:
+ if (wParam==MY_TRAY_ICON_ID) {
+ switch(lParam) {
+ case WM_LBUTTONDBLCLK:
+ if (IsMinimized(hWnd)) {
+ if (!do_init_vmr())
+ return -1;
+ if (suspend_minimized) {
+ rebranche();
+ change_frequence(Canaux[ixChaineCourante].frequence); // Vérifier si nécessaire
+ zappe_index(ixChaineCourante);
+ }
+ ShowWindow(hWnd, SW_SHOW);
+ ShowWindow(hWnd, SW_RESTORE);
+ } else {
+ SetForegroundWindow(hWnd);
+ }
+
+ break;
+ case WM_LBUTTONDOWN:
+ if (!IsMinimized(hWnd))
+ SetForegroundWindow(hWnd);
+ break;
+ case WM_CONTEXTMENU:
+ case WM_RBUTTONUP:
+ popup_menu(true);
+ }
+ }
+ break;
+
+ case WM_APP_EPG_UPDATED:
update_status_bar();
break;
- case WM_USER+1:
+ case WM_APP_PMT_UPDATED:
zappe_index(ixChaineCourante);
break;
Modifié: trunk/main.h
===================================================================
--- trunk/main.h 2008-03-09 16:34:39 UTC (rev 120)
+++ trunk/main.h 2008-03-12 13:16:55 UTC (rev 121)
@@ -88,6 +88,14 @@
#define TIMER_DELAYED_STOP 128
#define TIMER_UPDATE 129
+// Liste des messages locaux à l'application :
+#define WM_APP_TRAYICON_MSG (WM_APP+0)
+#define WM_APP_EPG_UPDATED (WM_APP+1)
+#define WM_APP_PMT_UPDATED (WM_APP+2)
+#define WM_APP_PROG_CHANGED (WM_APP+3)
+#define WM_APP_SCAN_NEXT (WM_APP+4)
+#define WM_APP_SCAN_NOTIFY (WM_APP+5)
+
DWORD get_priority();
void zappe_index(int ixChaine);
Modifié: trunk/parse.cpp
===================================================================
--- trunk/parse.cpp 2008-03-09 16:34:39 UTC (rev 120)
+++ trunk/parse.cpp 2008-03-12 13:16:55 UTC (rev 121)
@@ -313,7 +313,7 @@
// NIT, pour l'ordre des chaînes.
if (!nit_chargee) { // sur un seul flux seulement, puisque tous les flux
// sont supposés avoir la même table
- PostMessage(hwndDlg, WM_APP+1, 0, 0); // Pour déclencher affichage info "NIT"
+ PostMessage(hwndDlg, WM_APP_SCAN_NOTIFY, 0, 0); // Pour déclencher affichage info "NIT"
handler.Init(16, 64, 10000, MAKEFOURCC('N','I','T',0));
while (handler.GetNextSection()) {
parse_nit(*reinterpret_cast(handler.data));
Modifié: trunk/pmtfilter.cpp
===================================================================
--- trunk/pmtfilter.cpp 2008-03-09 16:34:39 UTC (rev 120)
+++ trunk/pmtfilter.cpp 2008-03-12 13:16:55 UTC (rev 121)
@@ -72,7 +72,7 @@
sauve_chaines();
// dit de rezapper sur cette chaîne
- PostMessage(hMainWnd, WM_USER+1, 0, 0);
+ PostMessage(hMainWnd, WM_APP_PMT_UPDATED, 0, 0);
}
}
Modifié: trunk/recprog.cpp
===================================================================
--- trunk/recprog.cpp 2008-03-09 16:34:39 UTC (rev 120)
+++ trunk/recprog.cpp 2008-03-12 13:16:55 UTC (rev 121)
@@ -1241,7 +1241,7 @@
ShowCursor(FALSE); // Rétablit la disparition temporisée du curseur
return TRUE;
- case WM_APP:
+ case WM_APP_PROG_CHANGED:
// Reconstruction de la liste des enregistrements programmés après changement :
ListView_DeleteAllItems(hListItem);
remplit_liste_programmes(hListItem);
@@ -1645,7 +1645,7 @@
std::sort(Programmes.begin(), Programmes.end());
if (hRecordDlg)
- PostMessage(hRecordDlg, WM_APP, 0, 0); // Reconstruction de la liste si couramment affichée
+ PostMessage(hRecordDlg, WM_APP_PROG_CHANGED, 0, 0); // Reconstruction de la liste si couramment affichée
// Sauvegarde de la liste des programmes
sauve_programmes();
Modifié: trunk/resource.h
===================================================================
--- trunk/resource.h 2008-03-09 16:34:39 UTC (rev 120)
+++ trunk/resource.h 2008-03-12 13:16:55 UTC (rev 121)
@@ -104,7 +104,6 @@
#define IDC_AFTER_NOTE 1115
#define IDC_DELAY_LABEL 1116
#define MY_TRAY_ICON_ID 20001
-#define MY_TRAY_ICON_MESSAGE 20002
#define IDM_CHAINES_BASE 39000 // Offset de base pour changement chaîne
#define IDM_PISTES_BASE 39500 // Offset de base pour choix bande sonore
Modifié: trunk/settings.cpp
===================================================================
--- trunk/settings.cpp 2008-03-09 16:34:39 UTC (rev 120)
+++ trunk/settings.cpp 2008-03-12 13:16:55 UTC (rev 121)
@@ -268,7 +268,7 @@
SendMessage(hListItem, LB_RESETCONTENT, 0, 0); // Vider la liste
EnableWindow(hOkBut, FALSE); // Désactiver le bouton "Accepter"
EnableWindow(hComboItem, FALSE); // Désactiver la liste des villes
- PostMessage(hDlg, WM_APP, 0, 0);
+ PostMessage(hDlg, WM_APP_SCAN_NEXT, 0, 0);
SetWindowText(hStartBut, L"Arrêter");
scanState = ss_running;
stopping = false;
@@ -316,7 +316,7 @@
}
return FALSE;
- case WM_APP: // Recherche pour une fréquence (index dans wParam)
+ case WM_APP_SCAN_NEXT: // Recherche pour une fréquence (index dans wParam)
// (on n'utilise pas WM_USER, parce que apparemment,
// certains objets du dialogue s'en servent !!)
if (!tuning) { // (prévention réentrance)
@@ -413,7 +413,7 @@
return TRUE;
}
break;
- case WM_APP+1:
+ case WM_APP_SCAN_NOTIFY:
// Traitement du message d'information envoyé par la fonction "tune"
// au début de l'analyse de la NIT :
SendMessage(hProgBar, PBM_SETPOS, index+(nit_chargee ? 4 : 2), 0);
Modifié: trunk/trayicon.cpp
===================================================================
--- trunk/trayicon.cpp 2008-03-09 16:34:39 UTC (rev 120)
+++ trunk/trayicon.cpp 2008-03-12 13:16:55 UTC (rev 121)
@@ -77,7 +77,7 @@
{
if (!alreadyset) {
uFlags = NIF_MESSAGE;
- uCallbackMessage = MY_TRAY_ICON_MESSAGE;
+ uCallbackMessage = WM_APP_TRAYICON_MSG;
set_icon();
set_tip();
if (notify(NIM_ADD))
Modifié: trunk/xml.cpp
===================================================================
--- trunk/xml.cpp 2008-03-09 16:34:39 UTC (rev 120)
+++ trunk/xml.cpp 2008-03-12 13:16:55 UTC (rev 121)
@@ -142,7 +142,7 @@
found = true;
BSTR txt;
pNode->get_text(&txt);
- wcscpy_s(str, size, txt);
+ wcsncpy_s(str, size, txt, size-1);
SysFreeString(txt);
}
SysFreeString(bstr);
From laurent at baysse.fr Wed Mar 12 14:47:24 2008
From: laurent at baysse.fr (Laurent Baysse)
Date: Wed, 12 Mar 2008 14:47:24 +0100
Subject: [Pouchintv-dev] =?iso-8859-1?q?Pr=E9-requis_pour_compiler?=
In-Reply-To: <004001c88422$77d150a0$464da8c0@GILLES>
References: <20080308190631.24A235F4D2@mail.baysse.fr><001301c88150$e44568e0$464da8c0@GILLES><001601c881f7$68952850$464da8c0@GILLES> <002001c881fa$34815f40$464da8c0@GILLES>
<004001c88422$77d150a0$464da8c0@GILLES>
Message-ID: <47D7DEEC.9090006@baysse.fr>
Gingko a écrit :
> Bonjour,
>
> Sur la page de compilation, dans les pré-requis pour compiler, je pense
> qu'il faudrait revoir les liens :
>
>
> Pour ce qui est du "Tout dernier Platform SDK", le lien n'est plus valide.
> Maintenant, Microsoft nous renvoie sur la page suivante :
> - Windows SDK for Windows Server 2008 and .NET Framework 3.5
> -
> http://www.microsoft.com/downloads/details.aspx?FamilyId=F26B1AA4-741A-433A-9BE5-FA919850BDBF&displaylang=en
>
>
> Pour ce qui est du "Tout dernier SDK DirectX", le lien est apparemment
> encore bon, mais néanmoins, on en est à :
> - DirectX SDK de Mars 2008
> -
> http://www.microsoft.com/downloads/details.aspx?FamilyId=572BE8A6-263A-4424-A7FE-69CFF1A5B180&displaylang=en
> (et on aura ainsi sauté les versions de juin, août, octobre et décembre
> 2006, ainsi que d'avril, août et novembre 2007) :-)
>
> ... et le lien concernant Visual C++ 2005 Express renvoie d'ores et déjà sur
> le téléchargement de Visual C++ 2008 Express ... :-)
>
>
> Ceci étant dit, je n'ai pas encore testé le bon fonctionnement de la
> compilation avec ces versions.
>
> Gingko
>
Voila, je viens de remettre les liens fonctionnels avec les versions
actuellement utilisées pour le développement
From pouchintv-svn at baysse.fr Wed Mar 12 19:43:16 2008
From: pouchintv-svn at baysse.fr (pouchintv-svn at baysse.fr)
Date: Wed, 12 Mar 2008 19:43:16 +0100 (CET)
Subject: [Pouchintv-dev] [PouchinTVMod] gingko | r122 - trunk
Message-ID: <20080312184316.4000E5F6B1@mail.baysse.fr>
Author: gingko
Date: 2008-03-12 19:43:15 +0100 (mer, 12 mar 2008)
New Revision: 122
Modified:
trunk/epgfilter.cpp
trunk/settings.cpp
Log:
Correction de deux erreurs de programmation que j'ai introduites au cours de mes dernières modifications.
(erreurs minimes en nombre de caractères, mais lourdes de conséquences en terme de fonctionnement)
L'une concerne un message "WM_" oublié à la r121, causant un blocage lors de la recherche de chaînes.
L'autre (un simple point-virgule en trop) concerne le guide EPG modifié à la r120, et produit une
corruption de données dans la table des chaînes à la réception de certaines descriptions d'émissions.
Modifié: trunk/epgfilter.cpp
===================================================================
--- trunk/epgfilter.cpp 2008-03-12 13:16:55 UTC (rev 121)
+++ trunk/epgfilter.cpp 2008-03-12 18:43:15 UTC (rev 122)
@@ -102,7 +102,7 @@
} else {
// Nombre maximal d'émissions mémorisées non atteint :
// juste décaler vers le haut selon le point d'insertion.
- for (i = chaine.emi_count; i>0 && cle < chaine.emis[i-1].cle; --i);
+ for (i = chaine.emi_count; i>0 && cle < chaine.emis[i-1].cle; --i)
chaine.emis[i] = chaine.emis[i-1];
}
Modifié: trunk/settings.cpp
===================================================================
--- trunk/settings.cpp 2008-03-12 13:16:55 UTC (rev 121)
+++ trunk/settings.cpp 2008-03-12 18:43:15 UTC (rev 122)
@@ -382,7 +382,7 @@
case ss_running:
if (wParam+1 < freq_scan.size()) {
// Demander la recherche pour la fréquence suivante :
- PostMessage(hDlg, WM_APP, wParam+1, 0);
+ PostMessage(hDlg, WM_APP_SCAN_NEXT, wParam+1, 0);
} else {
// Recherche terminée :
chaineIDs.clear(); // Vide la table des numéros de chaînes, dont on n'aura plus besoin
From pouchintv-svn at baysse.fr Mon Mar 17 20:45:26 2008
From: pouchintv-svn at baysse.fr (pouchintv-svn at baysse.fr)
Date: Mon, 17 Mar 2008 20:45:26 +0100 (CET)
Subject: [Pouchintv-dev] [PouchinTVMod] gingko | r123 - trunk
Message-ID: <20080317194526.B690D5F5E8@mail.baysse.fr>
Author: gingko
Date: 2008-03-17 20:45:26 +0100 (lun, 17 mar 2008)
New Revision: 123
Modified:
trunk/base.cpp
trunk/base.h
trunk/channels.cpp
trunk/graph.cpp
trunk/graph.h
trunk/main.cpp
trunk/parse.cpp
trunk/search.cpp
trunk/search.h
Log:
Amélioration de la remontée des codes d'erreur : la plupart des codes d'erreur
Microsoft produits pendant la gestion du graphe DirectShow sont maintenant inclus
dans le message d'erreur affiché, lorsque cela est possible et lorsque cela a un sens.
Cette modification a impliqué la modification de certaines fonctions,
afin qu'elles puissent retourner ce code d'erreur en tant que code de retour.
Modifié: trunk/base.cpp
===================================================================
--- trunk/base.cpp 2008-03-12 18:43:15 UTC (rev 122)
+++ trunk/base.cpp 2008-03-17 19:45:26 UTC (rev 123)
@@ -32,7 +32,14 @@
HWND hMainWnd = NULL;
-void erreur(const wchar_t * str)
+void erreur(const wchar_t * str, HRESULT hr)
{
- MessageBox(hMainWnd, str, NULL, MB_ICONERROR);
+ wchar_t buffer[0x200];
+
+ if (hr!=S_OK)
+ swprintf_s(buffer, L"%s\nCode d'erreur = 0x%08x", str, hr);
+ else
+ wcscpy_s(buffer, str);
+
+ MessageBox(hMainWnd, buffer, NULL, MB_ICONERROR);
}
Modifié: trunk/base.h
===================================================================
--- trunk/base.h 2008-03-12 18:43:15 UTC (rev 122)
+++ trunk/base.h 2008-03-17 19:45:26 UTC (rev 123)
@@ -203,4 +203,4 @@
etf_minimized // minimisée (en icône ou pas)
};
-void erreur(const wchar_t * str);
+void erreur(const wchar_t * str, HRESULT hr=S_OK);
Modifié: trunk/channels.cpp
===================================================================
--- trunk/channels.cpp 2008-03-12 18:43:15 UTC (rev 122)
+++ trunk/channels.cpp 2008-03-17 19:45:26 UTC (rev 123)
@@ -255,10 +255,10 @@
bool do_init_vmr()
{
if (pVMRControl == NULL) {
- int res = init_vmr();
+ HRESULT hr = init_vmr();
- if (res) {
- erreur(L"Erreur lors de la création du VMR");
+ if (FAILED(hr)) {
+ erreur(L"Erreur lors de la création du VMR", hr);
return false;
}
}
Modifié: trunk/graph.cpp
===================================================================
--- trunk/graph.cpp 2008-03-12 18:43:15 UTC (rev 122)
+++ trunk/graph.cpp 2008-03-17 19:45:26 UTC (rev 123)
@@ -172,56 +172,55 @@
free_interface(pControl);
}
-static IBaseFilter * create_and_add_filter(REFCLSID clsid, wchar_t * nom)
+static HRESULT create_and_add_filter(REFCLSID clsid, wchar_t * nom, IBaseFilter * & pFilter)
{
- IBaseFilter * pFilter;
HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void**)&pFilter);
if (FAILED(hr)) {
- return NULL;
+ return hr;
}
hr = pGraph->AddFilter(pFilter, nom);
if (FAILED(hr)) {
- pFilter->Release();
- return NULL;
+ pFilter->Release(); // nécessaire ??
+ return hr;
}
- return pFilter;
+ return hr;
}
static HRESULT connect_filters(IBaseFilter * source, IBaseFilter * dest)
{
- IPin * pPin1 = cherche_pin(source, PINDIR_OUTPUT);
- IPin * pPin2 = cherche_pin(dest, PINDIR_INPUT);
+ IPin * pPin1 = NULL;
+ IPin * pPin2 = NULL;
+ HRESULT hr = cherche_pin(source, PINDIR_OUTPUT, pPin1);
- HRESULT hr = pGraph->ConnectDirect(pPin1, pPin2, NULL);
-
- if (pPin1) {
+ if (SUCCEEDED(hr) && pPin1!=NULL) {
+ hr = cherche_pin(dest, PINDIR_INPUT, pPin2);
+ if (SUCCEEDED(hr) && pPin2!=NULL) {
+ hr = pGraph->ConnectDirect(pPin1, pPin2, NULL);
+ pPin2->Release();
+ }
pPin1->Release();
}
- if (pPin2) {
- pPin2->Release();
- }
-
return hr;
}
-static void getFrequencyFilter(IBaseFilter * pNetworkTuner)
+static HRESULT getFrequencyFilter(IBaseFilter * pNetworkTuner)
{
HRESULT hr = pNetworkTuner->QueryInterface(&pBDAControl);
if (FAILED(hr)) {
- erreur(L"IBDA_DeviceControl");
- return;
+ erreur(L"IBDA_DeviceControl", hr);
+ return hr;
}
IBDA_Topology * pTop;
hr = pNetworkTuner->QueryInterface(&pTop);
if (FAILED(hr)) {
myprintf(L"IBDA_Topology : %08X\n", hr);
- return;
+ return hr;
}
ULONG NodeTypes;
@@ -259,16 +258,17 @@
}
pTop->Release();
+ return hr;
}
-static void getSignalStatistics(IBaseFilter * pNetworkTuner)
+static HRESULT getSignalStatistics(IBaseFilter * pNetworkTuner)
{
IBDA_Topology * pTop;
HRESULT hr = pNetworkTuner->QueryInterface(&pTop);
if (FAILED(hr)) {
myprintf(L"IBDA_Topology : %08X\n", hr);
- return;
+ return hr;
}
ULONG NodeTypes;
@@ -305,9 +305,10 @@
}
pTop->Release();
+ return hr;
}
-static int render_mp2v(IMpeg2Demultiplexer * pMpeg2Demux)
+static HRESULT render_mp2v(IMpeg2Demultiplexer * pMpeg2Demux)
{
IPin * pVideoPin;
@@ -344,8 +345,8 @@
HRESULT hr = pMpeg2Demux->CreateOutputPin(&am, L"video", &pVideoPin);
if (FAILED(hr)) {
- erreur(L"pas créé pin video");
- return 1;
+ erreur(L"pas créé pin video", hr);
+ return hr;
}
// le décodeur vidéo
@@ -357,35 +358,39 @@
hr = pGraph->AddFilter(pVideoCodec, L"Codec vidéo");
if (FAILED(hr)) {
- erreur(L"Codec vidéo non inséré dans le graph");
- return 1;
+ erreur(L"Codec vidéo non inséré dans le graph", hr);
+ return hr;
}
- IPin * pPinEntree = cherche_pin(pVideoCodec, PINDIR_INPUT);
+ IPin * pPinEntree = NULL;
+
+ hr = cherche_pin(pVideoCodec, PINDIR_INPUT, pPinEntree);
+ if (SUCCEEDED(hr) && pPinEntree!=NULL) {
hr = pGraph->ConnectDirect(pVideoPin, pPinEntree, NULL);
pPinEntree->Release();
+ }
if (FAILED(hr)) {
- erreur(L"Impossible de connecter le demux au codec vidéo");
- return 1;
+ erreur(L"Impossible de connecter le demux au codec vidéo", hr);
+ return hr;
}
} else {
hr = pGraph->RenderEx(pVideoPin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL);
if (FAILED(hr)) {
- erreur(L"pas trouvé de codec vidéo");
- return 1;
+ erreur(L"pas trouvé de codec vidéo", hr);
+ return hr;
}
}
pVideoPin->QueryInterface(&pMapMPEG2);
pVideoPin->Release();
- return 0;
+ return hr;
}
-int init_vmr(void)
+HRESULT init_vmr()
{
pControl->Stop();
@@ -394,11 +399,11 @@
// crée le VMR
- pVMR = create_and_add_filter(MyCLSID_VideoMixingRenderer, L"Mon VMR");
+ hr = create_and_add_filter(MyCLSID_VideoMixingRenderer, L"Mon VMR", pVMR);
- if (pVMR == NULL) {
- erreur(L"VMR non inséré");
- return 1;
+ if (FAILED(hr) || pVMR == NULL) {
+ erreur(L"VMR non inséré", hr);
+ return hr;
}
@@ -406,8 +411,8 @@
MyIVMRFilterConfig * pVMRConfig;
hr = pVMR->QueryInterface(&pVMRConfig);
if (FAILED(hr)) {
- erreur(L"VMR config non dispo");
- return 1;
+ erreur(L"VMR config non dispo", hr);
+ return hr;
}
#if USE_VMR9
@@ -427,8 +432,8 @@
IVMRSurfaceAllocatorNotify * pNotify;
hr = pVMR->QueryInterface(&pNotify);
if (FAILED(hr)) {
- erreur(L"VMR notify non dispo");
- return 1;
+ erreur(L"VMR notify non dispo", hr);
+ return hr;
}
IVMRSurfaceAllocator * pSurfAlloc;
@@ -447,8 +452,8 @@
hr = pPresConf->SetRenderingPrefs(RenderPrefs_ForceOverlays | RenderPrefs_DoNotRenderColorKeyAndBorder);
}
if (FAILED(hr)) {
- erreur(L"VMR ImagePresenterConfig non dispo");
- return 1;
+ erreur(L"VMR ImagePresenterConfig non dispo", hr);
+ return hr;
}
pPresConf->Release();
@@ -466,7 +471,7 @@
hr = pVMR->QueryInterface(&pMixControl);
if (FAILED(hr)) {
- erreur(L"Pas eu le VMRMixerControl :/");
+ erreur(L"Pas eu le VMRMixerControl :/", hr);
} else {
pMixControl->SetMixingPrefs(MyMixingPrefs);
@@ -477,7 +482,7 @@
hr = pVMR->QueryInterface(&pDeint);
if (FAILED(hr)) {
- erreur(L"Pas eu le DeinterlaceControl :/");
+ erreur(L"Pas eu le DeinterlaceControl :/", hr);
} else {
DWORD num;
@@ -502,8 +507,8 @@
hr = pDeint->GetNumberOfDeinterlaceModes(&desc, &num, NULL);
if (FAILED(hr)) {
- erreur(L"Nombre de modes de désentrelacement non trouvé");
- return 1;
+ erreur(L"Nombre de modes de désentrelacement non trouvé", hr);
+ return hr;
}
myprintf(L"num : %i\n", num);
@@ -514,15 +519,15 @@
hr = pDeint->GetNumberOfDeinterlaceModes(&desc, &num, guid);
if (FAILED(hr)) {
- erreur(L"Impossible d'avoir le GUID du désentrelacement");
- return 1;
+ erreur(L"Impossible d'avoir le GUID du désentrelacement", hr);
+ return hr;
}
hr = pDeint->SetDeinterlaceMode(0xFFFFFFFF, &guid[0]);
if (FAILED(hr)) {
- erreur(L"Impossible de mettre le mode de désentrelacement");
- return 1;
+ erreur(L"Impossible de mettre le mode de désentrelacement", hr);
+ return hr;
}
pDeint->Release();
@@ -534,8 +539,8 @@
hr = pVMR->QueryInterface(&pVMRControl);
if (FAILED(hr)) {
- erreur(L"Pas de VMR control !");
- return 1;
+ erreur(L"Pas de VMR control !", hr);
+ return hr;
}
pVMRControl->SetVideoClippingWindow(hMainWnd);
@@ -549,8 +554,8 @@
hr = pVMR->QueryInterface(&pARC);
if (FAILED(hr)) {
- erreur(L"Pas de AspectRatioControl !");
- return 1;
+ erreur(L"Pas de AspectRatioControl !", hr);
+ return hr;
}
pARC->SetAspectRatioMode(VMR_ARMODE_LETTER_BOX);
@@ -563,21 +568,21 @@
hr = connect_filters(pVideoCodec, pVMR);
if (FAILED(hr)) {
- erreur(L"Impossible de connecter le codec vidéo au VMR.\nC'est probablement l'overlay qui n'est pas disponible.\n\nVeuillez le libérer et relancer l'application");
- return 1;
+ erreur(L"Impossible de connecter le codec vidéo au VMR.\nC'est probablement l'overlay qui n'est pas disponible.\n\nVeuillez le libérer et relancer l'application", hr);
+ return hr;
}
} else {
erreur(L"pas trouvé de codec vidéo");
- return 1;
+ return hr;
}
- pControl->Run();
+ hr = pControl->Run();
- return 0;
+ return hr;
}
-static int render_son(IMpeg2Demultiplexer * pMpeg2Demux)
+static HRESULT render_son(IMpeg2Demultiplexer * pMpeg2Demux)
{
IPin * pSoundPin;
@@ -605,15 +610,15 @@
HRESULT hr = pMpeg2Demux->CreateOutputPin(&am, L"son", &pSoundPin);
if (FAILED(hr)) {
- erreur(L"pas créé pin son");
- return 1;
+ erreur(L"pas créé pin son", hr);
+ return hr;
}
// add direct sound
- pDSound = create_and_add_filter(CLSID_DSoundRender, L"Direct sound");
- if (pDSound == NULL) {
- erreur(L"Direct sound pas ajouté");
- return 1;
+ hr = create_and_add_filter(CLSID_DSoundRender, L"Direct sound", pDSound);
+ if (FAILED(hr) || pDSound == NULL) {
+ erreur(L"Direct sound pas ajouté", hr);
+ return hr;
}
// le décodeur audio
@@ -626,30 +631,34 @@
hr = pGraph->AddFilter(pAudioCodec, L"Codec audio");
if (FAILED(hr)) {
- erreur(L"Codec audio non inséré dans le graph");
+ erreur(L"Codec audio non inséré dans le graph", hr);
return 1;
}
- IPin * pPinEntree = cherche_pin(pAudioCodec, PINDIR_INPUT);
+ IPin * pPinEntree = NULL;
+
+ hr = cherche_pin(pAudioCodec, PINDIR_INPUT, pPinEntree);
+ if (SUCCEEDED(hr) && pPinEntree != NULL) {
hr = pGraph->ConnectDirect(pSoundPin, pPinEntree, NULL);
pPinEntree->Release();
+ }
if (FAILED(hr)) {
- erreur(L"Impossible de connecter le demux au codec audio");
- return 1;
+ erreur(L"Impossible de connecter le demux au codec audio", hr);
+ return hr;
}
hr = connect_filters(pAudioCodec, pDSound);
if (FAILED(hr)) {
- erreur(L"connec Codec audio");
- return 1;
+ erreur(L"connec Codec audio", hr);
+ return hr;
}
} else {
hr = pGraph->RenderEx(pSoundPin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL);
if (FAILED(hr)) {
- erreur(L"pas render son");
- return 1;
+ erreur(L"pas render son", hr);
+ return hr;
}
}
@@ -657,10 +666,10 @@
myprintf(L"%?erreur pMapSound, hr=0x%08x\n", FAILED(hr), hr);
pSoundPin->Release();
- return 0;
+ return hr;
}
-static int render_ac3(IMpeg2Demultiplexer * pMpeg2Demux)
+static HRESULT render_ac3(IMpeg2Demultiplexer * pMpeg2Demux)
{
IPin * pAc3Pin;
@@ -689,15 +698,15 @@
HRESULT hr = pMpeg2Demux->CreateOutputPin(&am, L"ac3", &pAc3Pin);
if (FAILED(hr)) {
- erreur(L"pas créé pin ac3");
- return 1;
+ erreur(L"pas créé pin ac3", hr);
+ return hr;
}
// add direct sound
- pDSoundAc3 = create_and_add_filter(CLSID_DSoundRender, L"Direct sound le retour");
- if (pDSoundAc3 == NULL) {
- erreur(L"Direct sound le retour not added");
- return 1;
+ hr = create_and_add_filter(CLSID_DSoundRender, L"Direct sound le retour", pDSoundAc3);
+ if (FAILED(hr) || pDSoundAc3 == NULL) {
+ erreur(L"Direct sound le retour not added", hr);
+ return hr;
}
// le décodeur ac3
@@ -710,30 +719,34 @@
hr = pGraph->AddFilter(pAc3Codec, L"Codec ac3");
if (FAILED(hr)) {
- erreur(L"Codec AC3 non inséré dans le graph");
- return 1;
+ erreur(L"Codec AC3 non inséré dans le graph", hr);
+ return hr;
}
- IPin * pPinEntree = cherche_pin(pAc3Codec, PINDIR_INPUT);
+ IPin * pPinEntree = NULL;
+
+ hr = cherche_pin(pAc3Codec, PINDIR_INPUT, pPinEntree);
+ if (SUCCEEDED(hr) && pPinEntree!=NULL) {
hr = pGraph->ConnectDirect(pAc3Pin, pPinEntree, NULL);
pPinEntree->Release();
+ }
if (FAILED(hr)) {
- erreur(L"Impossible de connecter le demux au codec AC3");
- return 1;
+ erreur(L"Impossible de connecter le demux au codec AC3", hr);
+ return hr;
}
hr = connect_filters(pAc3Codec, pDSoundAc3);
if (FAILED(hr)) {
- erreur(L"connec Codec audio");
- return 1;
+ erreur(L"connec Codec audio", hr);
+ return hr;
}
} else {
hr = pGraph->RenderEx(pAc3Pin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL);
if (FAILED(hr)) {
- erreur(L"pas render son");
- return 1;
+ erreur(L"pas render son", hr);
+ return hr;
}
}
@@ -741,11 +754,11 @@
myprintf(L"%?erreur pMapAc3, hr=0x%08x\n", FAILED(hr), hr);
pAc3Pin->Release();
- return 0;
+ return hr;
}
-static int render_mpeg2(IMpeg2Demultiplexer * pMpeg2Demux)
+static HRESULT render_mpeg2(IMpeg2Demultiplexer * pMpeg2Demux)
{
IPin * pDataPin;
@@ -763,16 +776,18 @@
HRESULT hr = pMpeg2Demux->CreateOutputPin(&am, L"data", &pDataPin);
if (FAILED(hr)) {
- erreur(L"pas créé pin data");
- return 1;
+ erreur(L"pas créé pin data", hr);
+ return hr;
}
// add mpeg2
{
- IBaseFilter * pMpeg2Filter = create_and_add_filter(__uuidof(Mpeg2Data), L"MPEG2 data");
- if (pMpeg2Filter == NULL) {
- erreur(L"MPEG2 data pas inséré");
- return 1;
+ IBaseFilter * pMpeg2Filter = NULL;
+
+ hr = create_and_add_filter(__uuidof(Mpeg2Data), L"MPEG2 data", pMpeg2Filter);
+ if (FAILED(hr) || pMpeg2Filter == NULL) {
+ erreur(L"MPEG2 data pas inséré", hr);
+ return hr;
}
// query MPEG-2 Sections and Tables Filter
@@ -780,17 +795,21 @@
hr = pMpeg2Filter->QueryInterface(&pMpeg2Data);
if (FAILED(hr)) {
- erreur(L"pas eu le mpeg2data");
- return 1;
+ erreur(L"pas eu le mpeg2data", hr);
+ return hr;
}
- IPin * pPinEntree = cherche_pin(pMpeg2Filter, PINDIR_INPUT);
+ IPin * pPinEntree = NULL;
+
+ hr = cherche_pin(pMpeg2Filter, PINDIR_INPUT, pPinEntree);
+ if (SUCCEEDED(hr) && pPinEntree!=NULL) {
hr = pGraph->ConnectDirect(pDataPin, pPinEntree, NULL);
pPinEntree->Release();
+ }
if (FAILED(hr)) {
- erreur(L"Impossible de connecter le demux au mpeg2data");
- return 1;
+ erreur(L"Impossible de connecter le demux au mpeg2data", hr);
+ return hr;
}
pMpeg2Filter->Release();
@@ -798,10 +817,10 @@
pDataPin->Release();
- return 0;
+ return hr;
}
-static int render_epgfilter(IMpeg2Demultiplexer * pMpeg2Demux)
+static HRESULT render_epgfilter(IMpeg2Demultiplexer * pMpeg2Demux)
{
IPin * pEpgPin;
@@ -819,8 +838,8 @@
HRESULT hr = pMpeg2Demux->CreateOutputPin(&am, L"epg", &pEpgPin);
if (FAILED(hr)) {
- erreur(L"pas créé pin epg");
- return 1;
+ erreur(L"pas créé pin epg", hr);
+ return hr;
}
// add mpeg2
@@ -830,22 +849,24 @@
hr = pGraph->AddFilter(pEPGFilter, L"Mon filtre EPG");
if (FAILED(hr)) {
- erreur(L"pas ajouté filtre EPG au graph");
- return 1;
+ erreur(L"pas ajouté filtre EPG au graph", hr);
+ return hr;
}
- IPin * pPinEntree = cherche_pin(pEPGFilter, PINDIR_INPUT);
- if (pEPGFilter == NULL) {
- erreur(L"pas trouvé pin entrée");
- return 1;
+ IPin * pPinEntree = NULL;
+
+ hr = cherche_pin(pEPGFilter, PINDIR_INPUT, pPinEntree);
+ if (FAILED(hr) || pEPGFilter == NULL) {
+ erreur(L"pas trouvé pin entrée", hr);
+ return hr;
}
hr = pGraph->ConnectDirect(pEpgPin, pPinEntree, NULL);
pPinEntree->Release();
if (FAILED(hr)) {
- erreur(L"pas connecté pin entrée");
- return 1;
+ erreur(L"pas connecté pin entrée", hr);
+ return hr;
}
}
@@ -859,10 +880,10 @@
}
pEpgPin->Release();
- return 0;
+ return hr;
}
-static int render_pmtfilter(IMpeg2Demultiplexer * pMpeg2Demux)
+static HRESULT render_pmtfilter(IMpeg2Demultiplexer * pMpeg2Demux)
{
IPin * pPmtPin;
@@ -880,8 +901,8 @@
HRESULT hr = pMpeg2Demux->CreateOutputPin(&am, L"pmt", &pPmtPin);
if (FAILED(hr)) {
- erreur(L"pas créé pin pmt");
- return 1;
+ erreur(L"pas créé pin pmt", hr);
+ return hr;
}
// add mpeg2
@@ -889,25 +910,32 @@
CLSID clsid = {6, 7, 8, 9, 10, 11, 12, 13, 14};
CPMTFilter * pPMTFilter = new CPMTFilter(clsid, &hr);
+ if (FAILED(hr) || pPMTFilter == NULL) {
+ erreur(L"pas pu créer filtre PMT", hr);
+ return hr;
+ }
+
hr = pGraph->AddFilter(pPMTFilter, L"Mon filtre PMT");
if (FAILED(hr)) {
- erreur(L"pas ajouté PMT filtre au graph");
- return 1;
+ erreur(L"pas ajouté PMT filtre au graph", hr);
+ return hr;
}
- IPin * pPinEntree = cherche_pin(pPMTFilter, PINDIR_INPUT);
- if (pPMTFilter == NULL)
+ IPin * pPinEntree = NULL;
+
+ hr = cherche_pin(pPMTFilter, PINDIR_INPUT, pPinEntree);
+ if (FAILED(hr) || pPMTFilter == NULL)
{
- erreur(L"pas trouvé pin entrée");
- return 1;
+ erreur(L"pas trouvé pin entrée", hr);
+ return hr;
}
hr = pGraph->ConnectDirect(pPmtPin, pPinEntree, NULL);
pPinEntree->Release();
if (FAILED(hr)) {
- erreur(L"pas connecté pin entrée");
- return 1;
+ erreur(L"pas connecté pin entrée", hr);
+ return hr;
}
}
@@ -917,10 +945,10 @@
pPmtPin->Release();
- return 0;
+ return hr;
}
-static int cree_and_render_pins()
+static HRESULT cree_and_render_pins()
{
// cree les ports
@@ -931,54 +959,48 @@
hr = pDemux->QueryInterface(&pMpeg2Demux);
if (FAILED(hr)) {
- erreur(L"Demux MPEG2 non valide !");
- return 1;
+ erreur(L"Demux MPEG2 non valide !", hr);
+ return hr;
}
- if (render_mp2v(pMpeg2Demux))
- {
- erreur(L"Erreur lors du rendu du pin mp2v");
- return 1;
+ if (FAILED(hr = render_mp2v(pMpeg2Demux))) {
+ erreur(L"Erreur lors du rendu du pin mp2v", hr);
+ return hr;
}
- if (render_son(pMpeg2Demux))
- {
- erreur(L"Erreur lors du rendu du pin son");
- return 1;
+ if (FAILED(hr = render_son(pMpeg2Demux))) {
+ erreur(L"Erreur lors du rendu du pin son", hr);
+ return hr;
}
- if (render_ac3(pMpeg2Demux))
- {
- erreur(L"Erreur lors du rendu du pin ac3");
- return 1;
+ if (FAILED(hr = render_ac3(pMpeg2Demux))) {
+ erreur(L"Erreur lors du rendu du pin ac3", hr);
+ return hr;
}
- if (render_mpeg2(pMpeg2Demux))
- {
- erreur(L"Erreur lors du rendu du pin mpeg2");
- return 1;
+ if (FAILED(hr = render_mpeg2(pMpeg2Demux))) {
+ erreur(L"Erreur lors du rendu du pin mpeg2", hr);
+ return hr;
}
- if (render_epgfilter(pMpeg2Demux))
- {
- erreur(L"Erreur lors du rendu du pin epg");
- return 1;
+ if (FAILED(hr = render_epgfilter(pMpeg2Demux))) {
+ erreur(L"Erreur lors du rendu du pin epg", hr);
+ return hr;
}
- if (render_pmtfilter(pMpeg2Demux))
- {
- erreur(L"Erreur lors du rendu du pin pmt");
- return 1;
+ if (FAILED(hr = render_pmtfilter(pMpeg2Demux))) {
+ erreur(L"Erreur lors du rendu du pin pmt", hr);
+ return hr;
}
// fini
pMpeg2Demux->Release();
- return 0;
+ return hr;
}
-int build_graph(void)
+HRESULT build_graph(void)
{
int res;
// créer le graph
@@ -986,8 +1008,8 @@
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IFilterGraph2, (void **)&pGraph);
if (FAILED(hr) ) {
- erreur(L"Pas réussi à créer le graph DirectShow !");
- return 1;
+ erreur(L"Pas réussi à créer le graph DirectShow !", hr);
+ return hr;
}
// on logge
@@ -999,7 +1021,11 @@
#endif // #if LOG_DSHOW
#if EXPORT_GRAPH
- AddToRot();
+ hr = AddToRot();
+ if (FAILED(hr)) {
+ erreur(L"échec de l'exportation du graphe", hr);
+ return hr;
+ }
#endif // #if EXPORT_GRAPH
{
// filtre dvb-t
@@ -1008,8 +1034,8 @@
IBaseFilter * pNetworkProvider = new CNetworkProvider(clsid);
hr = pGraph->AddFilter(pNetworkProvider, L"Fake");
if (FAILED(hr)) {
- erreur(L"ajout du network provider ratée !!!");
- return 1;
+ erreur(L"ajout du network provider ratée !!!", hr);
+ return hr;
}
IBaseFilter * pAvantDemux;
@@ -1021,33 +1047,31 @@
// PCI
hr = pGraph->AddFilter(pNetworkTuner, L"Network Tuner");
- if (FAILED(hr))
- {
- erreur(L"Tuner pas inséré");
- return 1;
+ if (FAILED(hr)) {
+ erreur(L"Tuner pas inséré", hr);
+ return hr;
}
hr = pGraph->AddFilter(pReceiverComponent, L"Receiver Component");
- if (FAILED(hr))
- {
- erreur(L"Récepteur pas inséré");
- return 1;
+ if (FAILED(hr)) {
+ erreur(L"Récepteur pas inséré", hr);
+ return hr;
}
// connect Tuner
hr = connect_filters(pNetworkProvider, pNetworkTuner);
if (FAILED(hr)) {
- erreur(L"Tuner TNT non compatible, veuillez effacer config.ini et redémarrer");
- return 1;
+ erreur(L"Tuner TNT non compatible, veuillez effacer config.ini et redémarrer", hr);
+ return hr;
}
// connect Receiver
hr = connect_filters(pNetworkTuner, pReceiverComponent);
if (FAILED(hr)) {
- erreur(L"Récepteur TNT non compatible, veuillez effacer config.ini et redémarrer");
- return 1;
+ erreur(L"Récepteur TNT non compatible, veuillez effacer config.ini et redémarrer", hr);
+ return hr;
}
pAvantDemux = pReceiverComponent;
@@ -1060,16 +1084,15 @@
// connect USB
hr = pGraph->AddFilter(pNetworkTuner, L"Tuner USB");
- if (FAILED(hr))
- {
- erreur(L"Tuner USB pas inséré");
- return 1;
+ if (FAILED(hr)) {
+ erreur(L"Tuner USB pas inséré", hr);
+ return hr;
}
hr = connect_filters(pNetworkProvider, pNetworkTuner);
if (FAILED(hr)) {
- erreur(L"Tuner USB non compatible, veuillez effacer config.ini et redémarrer");
- return 1;
+ erreur(L"Tuner USB non compatible, veuillez effacer config.ini et redémarrer", hr);
+ return hr;
}
pAvantDemux = pNetworkTuner;
@@ -1077,20 +1100,20 @@
} else {
- return 1;
+ return E_FAIL;
}
- getFrequencyFilter(pNetworkTuner);
- if (pBDAFreq == NULL) {
- erreur(L"Pas trouvé l'interface pour changer de fréquence");
- return 1;
+ hr = getFrequencyFilter(pNetworkTuner);
+ if (FAILED(hr) || pBDAFreq == NULL) {
+ erreur(L"Pas trouvé l'interface pour changer de fréquence", hr);
+ return hr;
}
- getSignalStatistics(pNetworkTuner);
- if (pStats == NULL) {
- erreur(L"Pas trouvé l'interface pour avoir la qualité du signal");
- return 1;
+ hr = getSignalStatistics(pNetworkTuner);
+ if (FAILED(hr) || pStats == NULL) {
+ erreur(L"Pas trouvé l'interface pour avoir la qualité du signal", hr);
+ return hr;
}
@@ -1106,17 +1129,17 @@
for (int i=0; iRelease();
@@ -1126,17 +1149,17 @@
// connect 4
- pDemux = create_and_add_filter(CLSID_MPEG2Demultiplexer, L"Demux");
+ hr = create_and_add_filter(CLSID_MPEG2Demultiplexer, L"Demux", pDemux);
- if (pDemux == NULL) {
+ if (FAILED(hr) || pDemux == NULL) {
myprintf(L"Pas trouvé demux !\n");
- return 1;
+ return hr;
}
hr = connect_filters(pGrabber, pDemux);
if (FAILED(hr)) {
- erreur(L"Pas connecté le grabber au demux, veuillez effacer config.ini et redémarrer");
- return 1;
+ erreur(L"Pas connecté le grabber au demux, veuillez effacer config.ini et redémarrer", hr);
+ return hr;
}
pGrabber->Release();
@@ -1151,22 +1174,21 @@
// connections
- res = cree_and_render_pins();
- if (res)
- {
- erreur(L"Erreur lors de la création du graph");
- return 1;
+ hr = cree_and_render_pins();
+ if (FAILED(hr)) {
+ erreur(L"Erreur lors de la création du graph", hr);
+ return hr;
}
// derniers trucs
hr = pGraph->QueryInterface(&pControl);
if (FAILED(hr)) {
- return 1;
+ return hr;
}
- pControl->Run();
+ hr = pControl->Run();
- return 0;
+ return hr;
}
Modifié: trunk/graph.h
===================================================================
--- trunk/graph.h 2008-03-12 18:43:15 UTC (rev 122)
+++ trunk/graph.h 2008-03-17 19:45:26 UTC (rev 123)
@@ -31,9 +31,9 @@
#define free_interface(X) if (X) { X->Release(); X=NULL;}
-int build_graph(void); // retourne 0 = pas d'erreur, 1 = erreur
+HRESULT build_graph(void); // retourne S_OK = pas d'erreur, != S_OK = erreur
void clean_dshow(void);
-int init_vmr(void);
+HRESULT init_vmr(void);
extern IMpeg2Data * pMpeg2Data;
Modifié: trunk/main.cpp
===================================================================
--- trunk/main.cpp 2008-03-12 18:43:15 UTC (rev 122)
+++ trunk/main.cpp 2008-03-17 19:45:26 UTC (rev 123)
@@ -952,13 +952,13 @@
static int InitDshow(void) // retourne 0 = pas d'erreur, 1 = erreur
{
- int result = build_graph();
- if (result != 0)
- return result;
+ HRESULT hr = build_graph();
+ if (FAILED(hr))
+ return hr;
if (Canaux.size()==0) {
if (scan_dialog()!=IDOK)
- return 1;
+ return S_FALSE;
}
if (Canaux.size() > 0) {
@@ -970,7 +970,7 @@
set_volume(volumeCourant);
- return 0;
+ return S_OK;
}
static INT_PTR CALLBACK AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
@@ -1212,7 +1212,7 @@
HRESULT hr = pFilter->QueryInterface(&pPages);
if (FAILED(hr)) {
- erreur(L"Ce filtre n'a pas de page de propriétés");
+ erreur(L"Ce filtre n'a pas de page de propriétés", hr);
return;
}
@@ -1246,7 +1246,7 @@
CoTaskMemFree(caGUID.pElems);
if (FAILED(hr)) {
- erreur(L"Erreur lors de la création de la page de propriétés");
+ erreur(L"Erreur lors de la création de la page de propriétés", hr);
}
}
@@ -1663,11 +1663,12 @@
POINT ar = {4, 3}; // (valeurs par défaut)
if (pVMR != NULL) { // pVMR pas toujours défini à cet endroit
- IPin * pPin = cherche_pin(pVMR, PINDIR_INPUT);
+ IPin * pPin = NULL;
+ HRESULT hr = cherche_pin(pVMR, PINDIR_INPUT, pPin);
- if (pPin != NULL) {
+ if (SUCCEEDED(hr) && pPin != NULL) {
AM_MEDIA_TYPE am;
- HRESULT hr = pPin->ConnectionMediaType(&am);
+ hr = pPin->ConnectionMediaType(&am);
pPin->Release();
@@ -2750,6 +2751,8 @@
bool config_ok = check_config() && GetKeyState(VK_SHIFT)>=0;
do {
+ HRESULT hr;
+
if (!config_ok) {
if (drivers_dialog()!=IDOK) {
erreur(L"Configuration annulée.\nLe logiciel ne peut pas être exécuté.");
@@ -2760,9 +2763,9 @@
if (!config_ok) {
erreur(L"Configuration incorrecte.\nVeuillez renseigner correctement tous les champs.");
continue;
- } else if (InitDshow() != 0) {
+ } else if (FAILED(hr = InitDshow())) {
clean_dshow();
- erreur(L"Erreur lors de l'initialisation.\nVeuillez corriger la configuration.");
+ erreur(L"Erreur lors de l'initialisation.\nVeuillez corriger la configuration.", hr);
config_ok = false;
}
} while (!config_ok);
Modifié: trunk/parse.cpp
===================================================================
--- trunk/parse.cpp 2008-03-12 18:43:15 UTC (rev 122)
+++ trunk/parse.cpp 2008-03-17 19:45:26 UTC (rev 123)
@@ -172,17 +172,17 @@
chIDs.TSID = se().tsid();
chIDs.ONID = se().onid();
- // myprintf(L"parse_nit: TSID=%i, ONID=%i, taille=%i\n", chIDs.TSID, chIDs.ONID, se().length());
+ // myprintf(L"parse_nit: TSID=%i, ONID=%i, taille=%i\n", chIDs.TSID, chIDs.ONID, se().dloop_length());
for (descrScanner sed(se().descrRange()); !sed; ++sed) {
- // myprintf(L"parse_nit: type : %02X, taille : %i\n", sed().tag, sed().length);
+ // myprintf(L"parse_nit: type : %02X, taille : %i\n", sed().tag(), sed().length);
if (sed().tag() == mdt_Logical_Channel) {
for (streamScanner seds(sed().as().subDescrRange()); !seds; ++seds) {
chIDs.SID = seds().service_id();
chIDs.numero_nit = seds().logical_channel_number();
//myprintf(L"parse_nit: ONID=%i, TSID=%i, SID=%i, numero=%i\n",
- // chIDs.ONID, chIDs.TSID, chIDs.SID, chIDs.numeroChaine);
+ // chIDs.ONID, chIDs.TSID, chIDs.SID, chIDs.numero_nit);
chaineIDs.push_back(chIDs);
}
}
Modifié: trunk/search.cpp
===================================================================
--- trunk/search.cpp 2008-03-12 18:43:15 UTC (rev 122)
+++ trunk/search.cpp 2008-03-17 19:45:26 UTC (rev 123)
@@ -209,40 +209,44 @@
}
// 1er pin non connecté
-IPin * cherche_pin(IBaseFilter * pFilter, PIN_DIRECTION dir)
+HRESULT cherche_pin(IBaseFilter * pFilter, PIN_DIRECTION dir, IPin * & result)
{
IEnumPins * pEnumPins;
- IPin * result = NULL;
+ HRESULT hr;
+ IPin * curpin = NULL;
- HRESULT hr = pFilter->EnumPins(&pEnumPins);
- if (FAILED(hr)) {
- return NULL;
- }
+ hr = pFilter->EnumPins(&pEnumPins);
+ if (FAILED(hr))
+ return hr;
- while (result == NULL && S_OK == pEnumPins->Next(1, &result, NULL) ) {
+ while (pEnumPins->Next(1, &curpin, NULL)==S_OK ) {
PIN_DIRECTION direction;
- result->QueryDirection(&direction);
+ curpin->QueryDirection(&direction);
- if (direction != dir) {
- result->Release();
- result = NULL;
- } /*else {
+ if (direction == dir) {
+#ifdef _DEBUG
IPin * connected = NULL;
- result->ConnectedTo(&connected);
+ curpin->ConnectedTo(&connected);
- if (connected != NULL) {
- connected->Release();
- result->Release();
- result = NULL;
+ if (connected == NULL) {
+ result = curpin;
+ break;
}
- }*/
+ connected->Release();
+#else
+ result = curpin;
+ break;
+#endif
+ }
+ curpin->Release();
+ curpin = NULL;
}
pEnumPins->Release();
- return result;
+ return S_OK;
}
// 0 pas compat, 1 tuner, 2 receiver
@@ -294,7 +298,7 @@
return res;
}
-int remplit_tuners(GUID guid, HWND hItm)
+HRESULT remplit_tuners(GUID guid, HWND hItm)
{
// Create the System Device Enumerator.
ICreateDevEnum * pDevEnum;
@@ -302,7 +306,7 @@
IID_ICreateDevEnum, (void **)&pDevEnum);
if (FAILED(hr)) {
myprintf(L"ICreateDevEnum\n");
- return 1;
+ return hr;
}
IEnumMoniker *pEnumMoniker = NULL;
@@ -311,27 +315,23 @@
if (FAILED(hr) || pEnumMoniker == NULL) {
myprintf(L"erreur création Enum Moniker\n");
pDevEnum->Release();
- return 1;
+ return hr;
}
IMoniker *pMoniker;
while (pEnumMoniker->Next(1, &pMoniker, NULL) == S_OK)
{
IBaseFilter *pFilter;
- HRESULT hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pFilter);
- if (SUCCEEDED(hr))
- {
- if (filtre_compat(pFilter))
- {
+
+ if (SUCCEEDED(pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pFilter))) {
+ if (filtre_compat(pFilter)) {
IPropertyBag * pPropBag;
- if (SUCCEEDED(pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag)))
- {
+ if (SUCCEEDED(pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag))) {
// To retrieve the friendly name of the filter, do the following:
VARIANT varName;
VariantInit(&varName);
- if (SUCCEEDED(pPropBag->Read(L"FriendlyName", &varName, 0)))
- {
+ if (SUCCEEDED(pPropBag->Read(L"FriendlyName", &varName, 0))) {
SendMessage(hItm, CB_ADDSTRING, 0, (LPARAM)varName.bstrVal);
}
VariantClear(&varName);
@@ -348,7 +348,7 @@
pEnumMoniker->Release();
pDevEnum->Release();
- return 0;
+ return hr;
}
// renvoie le filtre à partir du nom
Modifié: trunk/search.h
===================================================================
--- trunk/search.h 2008-03-12 18:43:15 UTC (rev 122)
+++ trunk/search.h 2008-03-17 19:45:26 UTC (rev 123)
@@ -29,11 +29,11 @@
//IBaseFilter * search_mpeg2(IEnumMoniker *pEnumMoniker, GUID subtype, GUID format);
-IPin * cherche_pin(IBaseFilter * pFilter, PIN_DIRECTION dir);
+HRESULT cherche_pin(IBaseFilter * pFilter, PIN_DIRECTION dir, IPin * & result);
void search_filters(GUID type, GUID subtype, HWND hItm);
IBaseFilter * get_filter(GUID type, GUID subtype, wchar_t * nom);
-int remplit_tuners(GUID guid, HWND hItm);
+HRESULT remplit_tuners(GUID guid, HWND hItm);
IBaseFilter * get_tuner(GUID guid, wchar_t * nom);
int filtre_compat(IBaseFilter * pFilter);
From pouchintv-svn at baysse.fr Tue Mar 18 00:20:45 2008
From: pouchintv-svn at baysse.fr (pouchintv-svn at baysse.fr)
Date: Tue, 18 Mar 2008 00:20:45 +0100 (CET)
Subject: [Pouchintv-dev] [PouchinTVMod] gingko | r124 - trunk
Message-ID: <20080317232045.1E04E5F5EF@mail.baysse.fr>
Author: gingko
Date: 2008-03-18 00:20:44 +0100 (mar, 18 mar 2008)
New Revision: 124
Modified:
trunk/ini.cpp
trunk/mpeg2defs.h
trunk/recprog.cpp
trunk/xml.cpp
trunk/xml.h
Log:
* Définition d'une classe dans 'xml.h/xml.cpp' pour prendre en charge la génération des fichiers
XML en remplacement des 'fprintf' sauvages précédemment utilisés.
Utilisation de cette classe pour la génération des fichiers "chaines.xml" et "programmes.xml"
dans "ini.cpp".
Cette classe a surtout l'avantage de prendre en charge la génération des entités SGML pour les
caractères "<", ">" et "&" : dans les versions précédentes, en particulier, le fait d'inclure
un caractère "&" dans le nom d'un programme avait pour effet d'empêcher le rechargement du
fichier "programmes.xml" à l'ouverture, et donc de perdre toute la programmation effectuée
(qui plus est, ceci se produit qu'il soit rapporté de code d'erreur, ce qui me laisse
dubitatif quant à l'opportunité de continuer à utiliser ce format XML pour sauvegarder des
informations dans Pouchin TV Mod).
* Ajout d'un test pour que le fichier "programmes.xml" ne soit sauvegardé, à l'initialisation,
que s'il a été effectivement modifié (par purge d'anciennes programmations).
* Ajout de définitions supplémentaires dans 'mpeg2defs.h'.
Modifié: trunk/ini.cpp
===================================================================
--- trunk/ini.cpp 2008-03-17 19:45:26 UTC (rev 123)
+++ trunk/ini.cpp 2008-03-17 23:20:44 UTC (rev 124)
@@ -366,22 +366,17 @@
return 0;
}
-void xmlSaveSystemTime(FILE * fop, LPCSTR section, const SYSTEMTIME & stim)
+void xmlSaveSystemTime(CXMLOutput & oxml, LPCSTR section, const SYSTEMTIME & stim)
{
- fprintf(fop,
- "\t\t<%s>\n"
- "\t\t\t%i\n"
- "\t\t\t%i\n"
- "\t\t\t%i\n"
- "\t\t\t%i\n"
- "\t\t\t%i\n"
- "\t\t\t%i\n"
- "\t\t\t%i\n"
- "\t\t%s>\n",
- section,
- stim.wYear, stim.wMonth, stim.wDayOfWeek, stim.wDay,
- stim.wHour, stim.wMinute, stim.wSecond,
- section);
+ CXMLOpenChild oxmlc(oxml, section);
+
+ oxml.put("Annee", stim.wYear);
+ oxml.put("Mois", stim.wMonth);
+ oxml.put("Jour_Semaine", stim.wDayOfWeek);
+ oxml.put("Jour", stim.wDay);
+ oxml.put("Heure", stim.wHour);
+ oxml.put("Minute", stim.wMinute);
+ oxml.put("Seconde", stim.wSecond);
}
/**
@@ -395,12 +390,12 @@
wcscpy_s(fileName, _countof(fileName), pouchindir_conf);
wcscat_s(fileName, _countof(fileName), L"programmes.xml");
- FILE * fop;
- if (_wfopen_s(&fop, fileName, L"w")) {
+ CXMLOutput oxml(fileName);
+
+ if (!oxml.opened())
return;
- }
- fprintf(fop, "\n\n");
+ CXMLOpenChild oxmlc1(oxml, "Programmes");
for (int i=0; i\n"
- "\t\t%s\n"
- "\t\t%i\n"
- "\t\t%i\n"
- "\t\t%i\n",
- programme.nom, programme.nomAuto, programme.numeroChaine, programme.sidChaine);
+ CXMLOpenChild oxmlc2(oxml, "Programme");
- xmlSaveSystemTime(fop, "Début", programme.debut);
- xmlSaveSystemTime(fop, "Fin", programme.fin);
+ oxml.put("Nom", programme.nom);
+ oxml.put("NomAuto", programme.nomAuto);
+ oxml.put("Chaine", programme.numeroChaine);
+ oxml.put("ServiceID", programme.sidChaine);
- fprintf(fop,
- "\t\t%i\n"
- "\t\t\n"
- "\t\t%i\n"
- "\t\t%i\n"
- "\t\t%i\n"
- "\t\t\n",
- programme.methode, programme.audio, programme.apres, programme.tache, etat);
+ xmlSaveSystemTime(oxml, "Début", programme.debut);
+ xmlSaveSystemTime(oxml, "Fin", programme.fin);
- for (int j=0; j<7; j++) {
- LPCWSTR dow = Tbl_DoW[j];
+ oxml.put("Methode", programme.methode);
+ oxml.put("Audio", programme.audio);
+ oxml.put("After", programme.apres);
+ oxml.put("Tache", programme.tache);
+ oxml.put("Etat", etat);
- fprintf(fop, "\t\t\t<%S>%i%S>\n", dow, (programme.repetition & (1<\n"
- "\t\n");
+ for (int j=0; j<7; j++)
+ oxml.put(oxml.fmt("%S", Tbl_DoW[j]), (programme.repetition & (1<\n");
-
- fclose(fop);
-
programmation_modifiee = false;
}
@@ -557,67 +539,59 @@
wcscpy_s(fileName, _countof(fileName), pouchindir_conf);
wcscat_s(fileName, _countof(fileName), L"chaines.xml");
- FILE * fop;
- if (_wfopen_s(&fop, fileName, L"w")) {
+ CXMLOutput oxml(fileName);
+
+ if (!oxml.opened())
return;
- }
- fprintf(fop, "\n\n");
+ CXMLOpenChild oxmlc1(oxml, "Chaines");
for (int i=0; i\n");
+ CXMLOpenChild oxmlc2(oxml, "Chaine");
- fprintf(fop, "\t\t%s\n", canal.nom);
- fprintf(fop, "\t\t%i\n", canal.canal_no);
- fprintf(fop, "\t\t%s\n", canal.groupe);
+ oxml.put("Nom", canal.nom);
+ oxml.put("Canal", canal.canal_no);
+ oxml.put("Groupe", canal.groupe);
- fprintf(fop, "\t\t%i\n", canal.frequence);
+ oxml.put("Frequence", canal.frequence);
- fprintf(fop, "\t\t%i\n", canal.ONID);
- fprintf(fop, "\t\t%i\n", canal.TSID);
- fprintf(fop, "\t\t%i\n", canal.SID);
+ oxml.put("ONID", canal.ONID);
+ oxml.put("TSID", canal.TSID);
+ oxml.put("SID", canal.SID);
- fprintf(fop, "\t\t%i\n", canal.numero_nit);
- fprintf(fop, "\t\t%i\n", canal.numeroChaine);
- fprintf(fop, "\t\t%S\n", dword2str(aChStateTable, canal.etat));
- fprintf(fop, "\t\t%i\n", canal.pmt_pid);
- fprintf(fop, "\t\t%i\n", canal.pcr_pid);
+ oxml.put("Numero_initial", canal.numero_nit);
+ oxml.put("Numero", canal.numeroChaine);
+ oxml.put("Etat", oxml.fmt("%S", dword2str(aChStateTable, canal.etat)));
+ oxml.put("PMT", canal.pmt_pid);
+ oxml.put("PCR", canal.pcr_pid);
- if (canal.video_pid > 0) {
- fprintf(fop, "\t\t\n", canal.video_pid);
- }
+ if (canal.video_pid > 0)
+ oxml.put("Video", canal.video_pid);
- if (canal.mpeg4_pid > 0) {
- fprintf(fop, "\t\t%i\n", canal.mpeg4_pid);
- }
+ if (canal.mpeg4_pid > 0)
+ oxml.put("Video_mpeg4", canal.mpeg4_pid);
- fprintf(fop, "\t\t%i\n", canal.sons.nbr);
+ oxml.put("Nb_Son", canal.sons.nbr);
for (int j=0; j%i\n", j, canal_son.pid, j);
- fprintf(fop, "\t\t%i\n", j, canal_son.type, j);
- fprintf(fop, "\t\t%s\n", j, canal_son.lang, j);
+ oxml.put(oxml.fmt("Son%i", j), canal_son.pid);
+ oxml.put(oxml.fmt("Son%i_Type", j), canal_son.type);
+ oxml.put(oxml.fmt("Son%i_Lang", j), canal_son.lang);
}
- fprintf(fop, "\t\t%i\n", canal.autr.nbr);
+ oxml.put("Nb_Autre", canal.autr.nbr);
for (int j=0; j%i\n", j, canal_autre.pid, j);
- fprintf(fop, "\t\t%s\n", j, canal_autre.lang, j);
+ oxml.put(oxml.fmt("Autre%i", j), canal_autre.pid);
+ oxml.put(oxml.fmt("Autre%i_Lang", j), canal_autre.lang);
}
-
- fprintf(fop, "\t\n");
}
-
- fprintf(fop, "\n");
-
- fclose(fop);
}
AssocElement aBoolTable[] =
Modifié: trunk/mpeg2defs.h
===================================================================
--- trunk/mpeg2defs.h 2008-03-17 19:45:26 UTC (rev 123)
+++ trunk/mpeg2defs.h 2008-03-17 23:20:44 UTC (rev 124)
@@ -443,9 +443,23 @@
typedef C3CHAR ISO3166_CTRY; // Code de pays
enum MDescriptorTag {
+ mdt_Video_Stream = 0x02,
+ mdt_Audio_Stream = 0x03,
+ mdt_Hierarchy = 0x04,
mdt_Registration = 0x05,
+ mdt_Data_Stream_Alignment = 0x06,
+ mdt_Target_Background_Grid = 0x07,
+ mdt_Video_Window = 0x08,
+ mdt_Conditional_Access = 0x09,
mdt_ISO_639_Language = 0x0a,
+ mdt_System_Clock = 0x0b,
+ mdt_Multiplex_Buffer_Util = 0x0c,
+ mdt_Copyright_Descriptor = 0x0d,
+ mdt_Maximum_Bitrate = 0x0e,
+ mdt_Private_Data_Indicator = 0x0f,
+ mdt_Smoothing_Buffer = 0x10,
mdt_STD = 0x11, // System Target Decoder ?
+ mdt_IBP = 0x12,
//
// http://www.coolstf.com/tsreader/descriptors.html
mdt_Network_Name = 0x40,
@@ -588,6 +602,37 @@
{return streamScanner(this+1, PUINT8(this+1) + length);}
};
+/* Conditional access descriptor tag 0x09
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ CA_descriptor() {
+ descriptor_tag 8 0
+ descriptor_length 8 1
+ CA_system_ID 16 2,3
+ reserved 3 4
+ CA_PID 13 4,5
+ for (i = 0; i < N; i++) { 6
+ private_data_byte 8 +0
+ }
+ }
+*/
+
+struct MSubDescr_09 : public UINT8uw
+{
+ const MSubDescr_09 * next() const
+ {return this+1;}
+};
+
+struct MDescriptor_09 : public MDescriptor // tag = mdt_Conditional_Access
+{
+ UBE16 ca_system_id;
+ PID13 ca_pid;
+
+ streamScanner subDescrRange() const
+ {return streamScanner(this+1, PUINT8(this+1) + length);}
+};
+
/* ISO 639 Language Descriptor (PMT) tag 0x0a
Syntax No. of bits Offset
@@ -613,6 +658,26 @@
typedef MDescriptor_list MDescriptor_0a; // tag = mdt_ISO_639_Language
+/* Maximum bitrate (PMT) tag 0x0e
+
+ Syntax No. of bits Offset
+ ----------------------------------------------------------
+ maximum_bitrate_descriptor() {
+ descriptor_tag 8 0
+ descriptor_length 8 1
+ reserved 2 2
+ maximum_bitrate 22 2..4
+ }
+*/
+
+struct MDescriptor_0e : public MDescriptor // tag = mdt_Maximum_Bitrate
+{
+ UINT8 _mb[3];
+
+ UINT32 maximum_bitrate() const
+ {return ((_mb[0] & 0x3f)<<16)|(_mb[1]<<8)|(_mb[2]);}
+};
+
/* Network Name (NIT) tag 0x40
Syntax No. of bits Offset
@@ -939,7 +1004,7 @@
country_code 24 +0..+2
rating 8 +3
}
- }
+ }
*/
struct MSubDescr_55
@@ -1212,6 +1277,8 @@
// Identificateurs de flots (streams) :
enum StreamIDs
{
+ sid_undef = 0,
+ //
sid_Program_End = 0xb9, // 0xb9
sid_Pack_Header, // 0xba
sid_System_Header, // 0xbb
@@ -1327,8 +1394,9 @@
template const T & as() const // Dérivation vers un type de descripteur spécifique
{return *reinterpret_cast(this);}
- // Constructeur :
- PS_hdr(UINT8 id) :
+ // Constructeurs :
+ PS_hdr() {} // neutre
+ PS_hdr(UINT8 id) : // avec initialisation
stream_id(id)
{start_code[1] = start_code[0] = 0x00; start_code[2] = 0x01;};
};
@@ -1347,6 +1415,7 @@
{return PUINT8(this) + packet_size();}
// Constructeur :
+ PS_hdr_wl() {} // neutre
PS_hdr_wl(UINT8 id) :
PS_hdr(id)
{hdr_length = 0;}
@@ -1827,17 +1896,29 @@
UINT8 flags;
UINT8 data_length;
- size_t header_size() const
+ size_t header_size() const
{return sizeof(*this)+data_length;}
- PUINT8 base_of_data() const
+ PUINT8 base_of_data() const
{return PUINT8(this)+header_size();}
- PUINT8 end_of_header() const
+ PUINT8 end_of_header() const
{return PUINT8(this)+header_size();}
- PUINT8 beg_of_fields() const
+ PUINT8 beg_of_fields() const
{return PUINT8(this+1);}
- // Constructeur copie :
- PS_hdr_wd(const PS_hdr_wd & src) :
+ UINT8 scrambling_control() const
+ {return UINT8((info >> 4) & 0x03);}
+ bool priority_flag() const
+ {return (info & PES_PRIORITY_FLAG) != 0;}
+ bool data_alignment() const
+ {return (info & DATA_ALIGNMENT_INDICATOR) != 0;}
+ bool copyrighted() const
+ {return (info & COPYRIGHT_FLAG) != 0;}
+ bool original() const
+ {return (info & ORIGINAL_FLAG) != 0;}
+
+ // Constructeurs :
+ PS_hdr_wd() {} // neutre
+ PS_hdr_wd(const PS_hdr_wd & src) : // copie
PS_hdr_wl(src.stream_id)
{
memcpy(this, &src, src.header_size());
@@ -2186,7 +2267,7 @@
UINT8 bytes[TS_SIZE];
bool isTS(bool single=false) const
- {return hdr.sync_byte==TS_SYNC && (single || this[1].hdr.sync_byte==TS_SYNC);}
+ {return hdr.sync_byte==TS_SYNC && (single || this[1].hdr.sync_byte==TS_SYNC);}
};
/****************************************************************************************
@@ -2445,10 +2526,42 @@
// ############################################################################
-/* Transport Stream program map section (PMT)
+/* Transport Stream Conditional Access section (CAT)
Syntax No. of bits Offset
------------------------------------------------------
+ CA_section() { _
+ table_id 8 0 \
+ section_syntax_indicator 1 1 \
+ '0' 1 1 |
+ reserved 2 1 |
+ section_length 12 1,2 |
+ reserved1 16 3,4 |-- en-tête SI
+ reserved2 2 5 |
+ version_number 5 5 |
+ current_next_indicator 1 5 |
+ section_number 8 6 /
+ last_section_number 8 6 _/
+ for (i = 0; i < N; i++) {
+ descriptor()
+ }
+ CRC_32 32 rpchof
+ }
+*/
+
+// CAT = Conditional Access Table
+struct SI_CAT : public SI_hdr
+{
+ descrScanner descrRange(bool microsoft=false) const
+ {return descrScanner(this+1, end(microsoft));}
+};
+
+// ############################################################################
+
+/* Transport Stream Program Map section (PMT)
+
+ Syntax No. of bits Offset
+ ------------------------------------------------------
TS_program_map_section( ) { _
table_id 8 0 \
section_syntax_indicator 1 1 \
Modifié: trunk/recprog.cpp
===================================================================
--- trunk/recprog.cpp 2008-03-17 19:45:26 UTC (rev 123)
+++ trunk/recprog.cpp 2008-03-17 23:20:44 UTC (rev 124)
@@ -487,7 +487,8 @@
}
// Sauvegarde à nouveau la liste des programmes
- sauve_programmes();
+ if (programmation_modifiee)
+ sauve_programmes();
}
/**
Modifié: trunk/xml.cpp
===================================================================
--- trunk/xml.cpp 2008-03-17 19:45:26 UTC (rev 123)
+++ trunk/xml.cpp 2008-03-17 23:20:44 UTC (rev 124)
@@ -252,25 +252,142 @@
/**
* Sauvegarde le contenu du XML dans un fichier
**/
-HRESULT CXMLWrapper::sauvegarde(const wchar_t *nom) {
- VARIANT var;
- VariantInit(&var);
+//HRESULT CXMLWrapper::sauvegarde(const wchar_t *nom) {
+// VARIANT var;
+// VariantInit(&var);
+//
+// var.vt = VT_BSTR;
+// var.bstrVal = SysAllocString(nom);
+//
+// HRESULT hr = m_doc->save(var);
+//
+// VariantClear(&var);
+//
+// return hr;
+//}
- var.vt = VT_BSTR;
- var.bstrVal = SysAllocString(nom);
+CXMLElement CXMLWrapper::getDocElement()
+{
+ IXMLDOMElement * pDOMElement;
- HRESULT hr = m_doc->save(var);
+ m_doc->get_documentElement(&pDOMElement);
- VariantClear(&var);
+ return CXMLElement(pDOMElement);
+}
- return hr;
+// ----------------------------------------------------------------------------
+
+CXMLOpenChild::CXMLOpenChild(CXMLOutput & rf, LPCSTR name) :
+ ref(rf)
+{
+ sprintf_s(str, name);
+ ref.add_open(str);
+ ref.send();
+ ++ref.indent;
}
-CXMLElement CXMLWrapper::getDocElement()
+CXMLOpenChild::~CXMLOpenChild()
{
- IXMLDOMElement * pDOMElement;
+ --ref.indent;
+ ref.add_indent();
+ ref.add_close(str);
+ ref.send();
+}
- m_doc->get_documentElement(&pDOMElement);
+CXMLOutput::CXMLOutput(LPCWSTR filename) :
+ fop(NULL),
+ indent(0),
+ ix(0)
+{
+ if (_wfopen_s(&fop, filename, L"w")!=0) {
+ fop = NULL;
+ return;
+ }
- return CXMLElement(pDOMElement);
+ add_open("?xml version=\"1.0\" encoding=\"iso-8859-1\"?");
+ send();
}
+
+LPCSTR CXMLOutput::fmt(LPCSTR fmt, ...)
+{
+ static CHAR tmp_str[32];
+ va_list argptr;
+
+ va_start(argptr, fmt);
+ vsprintf_s(tmp_str, fmt, argptr);
+ va_end(argptr);
+ return tmp_str;
+}
+
+void CXMLOutput::add(LPCSTR str)
+{
+ strcpy_s(&buffer[ix], _countof(buffer)-ix, str);
+ ix += strlen(str);
+}
+
+void CXMLOutput::add(CHAR ch)
+{
+ if (ix<_countof(buffer)-1)
+ buffer[ix++] = ch;
+}
+
+void CXMLOutput::add_indent()
+{
+ ix = 0;
+ for (int i=0; i');
+}
+
+void CXMLOutput::add_close(LPCSTR str)
+{
+ add("");
+ add(str);
+ add('>');
+}
+
+int CXMLOutput::send()
+{
+ add("\n"); // ajoute aussi le zéro terminateur
+ ix=0;
+ return fop ? fputs(buffer, fop) : -1;
+}
+
+int CXMLOutput::put(LPCSTR name, LPCSTR str)
+{
+ CHAR ch;
+
+ add_indent();
+ add_open(name);
+ while ((ch = *str++)!=0) {
+ switch (ch) {
+ case '&': add("&"); break;
+ case '<': add("<"); break;
+ case '>': add(">"); break;
+ default: add(ch);
+ }
+ }
+ add_close(name);
+ return send();
+}
+
+int CXMLOutput::put(LPCSTR name, int val)
+{
+ CHAR str[16];
+
+ sprintf_s(str, "%i", val);
+ return put(name, str);
+}
+
+CXMLOutput::~CXMLOutput()
+{
+ if (fop)
+ fclose(fop);
+}
Modifié: trunk/xml.h
===================================================================
--- trunk/xml.h 2008-03-17 19:45:26 UTC (rev 123)
+++ trunk/xml.h 2008-03-17 23:20:44 UTC (rev 124)
@@ -77,5 +77,46 @@
HRESULT charge_xml(const wchar_t * xml);
// Sauvegarde le fichier XML
- HRESULT sauvegarde(const wchar_t * nom);
+ //HRESULT sauvegarde(const wchar_t * nom);
};
+
+// ----------------------------------------------------------------------------
+
+// Génération d'un fichier de sortie XML :
+class CXMLOutput
+{
+ friend class CXMLOpenChild;
+ FILE * fop;
+ CHAR buffer[512];
+ int indent;
+ int ix;
+
+ // (méthodes à usage interne)
+ void add(LPCSTR str);
+ void add(CHAR ch);
+ void add_indent();
+ void add_open(LPCSTR str);
+ void add_close(LPCSTR str);
+ int send();
+
+public:
+ CXMLOutput(LPCWSTR filename); // (constructeur ouvrant le fichier)
+
+ bool opened() const // 'true' si le fichier est ouvert
+ {return fop!=NULL;}
+ int put(LPCSTR name, int val); // Ajout d'un entier
+ int put(LPCSTR name, LPCSTR str); // Ajout d'une chaîne
+ static LPCSTR fmt(LPCSTR fmt, ...); // Utilitaire de reformatage
+ ~CXMLOutput(); // (le destructeur ferme le fichier)
+};
+
+// Ouverture d'un enfant XML (par constructeur);
+// la fermeture est assurée par le destructeur.
+class CXMLOpenChild
+{
+ CXMLOutput & ref;
+ CHAR str[32]; // sauvegarde du nom de la catégorie
+public:
+ CXMLOpenChild(CXMLOutput & rf, LPCSTR name);
+ ~CXMLOpenChild(); // (le destructeur ferme l'enfant)
+};
From pouchintv-svn at baysse.fr Thu Mar 20 15:31:13 2008
From: pouchintv-svn at baysse.fr (pouchintv-svn at baysse.fr)
Date: Thu, 20 Mar 2008 15:31:13 +0100 (CET)
Subject: [Pouchintv-dev] [PouchinTVMod] lolo_32 | r125 - in trunk: .
BaseClasses Icones Icones/Locales LCD_Logitech
LCD_Logitech/Win32 LCD_Logitech/x64 docs docs/LCD_Logitech
docs/MPEG-2_Transport_Stream
Message-ID: <20080320143113.8FB565F5ED@mail.baysse.fr>
Author: lolo_32
Date: 2008-03-20 15:31:13 +0100 (jeu, 20 mar 2008)
New Revision: 125
Modified:
trunk/
trunk/BaseClasses/
trunk/Icones/
trunk/Icones/Locales/
trunk/LCD_Logitech/
trunk/LCD_Logitech/Win32/
trunk/LCD_Logitech/x64/
trunk/canaux.ini
trunk/docs/
trunk/docs/LCD_Logitech/
trunk/docs/MPEG-2_Transport_Stream/
Log:
* Ajout du canal 23 pour les 6 nouvelles chaines de "Paris - Tour Eiffel"
* Diminution du nombre de caractères à 25 pour un descriptif
Property changes on: trunk
___________________________________________________________________
Nom : tsvn:logminsize
- 100
+ 25
Property changes on: trunk/BaseClasses
___________________________________________________________________
Nom : tsvn:logminsize
+ 25
Property changes on: trunk/Icones
___________________________________________________________________
Nom : tsvn:logminsize
+ 25
Property changes on: trunk/Icones/Locales
___________________________________________________________________
Nom : tsvn:logminsize
+ 25
Property changes on: trunk/LCD_Logitech
___________________________________________________________________
Nom : tsvn:logminsize
+ 25
Property changes on: trunk/LCD_Logitech/Win32
___________________________________________________________________
Nom : tsvn:logminsize
+ 25
Property changes on: trunk/LCD_Logitech/x64
___________________________________________________________________
Nom : tsvn:logminsize
+ 25
Modifié: trunk/canaux.ini
===================================================================
--- trunk/canaux.ini 2008-03-17 23:20:44 UTC (rev 124)
+++ trunk/canaux.ini 2008-03-20 14:31:13 UTC (rev 125)
@@ -890,6 +890,7 @@
R4=24
R5=29
R6=32
+R7=23
Offset=167
[Paris Est - Chennevières]
@@ -1208,4 +1209,4 @@
Offset=167
;
-; Mise à jour depuis les données du CSA du 2007-10-05
+; Mise à jour depuis les données du CSA du 2008-03-20
Property changes on: trunk/docs
___________________________________________________________________
Nom : tsvn:logminsize
+ 25
Property changes on: trunk/docs/LCD_Logitech
___________________________________________________________________
Nom : tsvn:logminsize
+ 25
Property changes on: trunk/docs/MPEG-2_Transport_Stream
___________________________________________________________________
Nom : tsvn:logminsize
+ 25
From pouchintv-svn at baysse.fr Sat Mar 22 02:49:10 2008
From: pouchintv-svn at baysse.fr (pouchintv-svn at baysse.fr)
Date: Sat, 22 Mar 2008 02:49:10 +0100 (CET)
Subject: [Pouchintv-dev] [PouchinTVMod] gingko | r126 - trunk/Icones/Locales
Message-ID: <20080322014911.10B7C5F6B1@mail.baysse.fr>
Author: gingko
Date: 2008-03-22 02:49:10 +0100 (sam, 22 mar 2008)
New Revision: 126
Added:
trunk/Icones/Locales/CAP 24.bmp
trunk/Icones/Locales/Canal 21.bmp
trunk/Icones/Locales/IDF1.bmp
trunk/Icones/Locales/NRJ Paris.bmp
Log:
Ajout d'icônes pour les nouvelles chaînes locales de la TNT parisienne.
Pour ce qui concerne la chaîne "Canal 21", qui regroupe sous cette appellation commune
4 "petites" chaînes qui émettent en alternance sur ce canal, j'ai créé un logo utilisant
le graphisme de la TNT elle-même, avec les chiffres "21" à la place des lettres "TNT".
Les trois autres chaînes sont "IDF1", "NRJ Paris" et "CAP 24".
Ajouté: trunk/Icones/Locales/CAP 24.bmp
===================================================================
(les fichiers binaires diffèrent)
Property changes on: trunk/Icones/Locales/CAP 24.bmp
___________________________________________________________________
Nom : svn:mime-type
+ application/octet-stream
Ajouté: trunk/Icones/Locales/Canal 21.bmp
===================================================================
(les fichiers binaires diffèrent)
Property changes on: trunk/Icones/Locales/Canal 21.bmp
___________________________________________________________________
Nom : svn:mime-type
+ application/octet-stream
Ajouté: trunk/Icones/Locales/IDF1.bmp
===================================================================
(les fichiers binaires diffèrent)
Property changes on: trunk/Icones/Locales/IDF1.bmp
___________________________________________________________________
Nom : svn:mime-type
+ application/octet-stream
Ajouté: trunk/Icones/Locales/NRJ Paris.bmp
===================================================================
(les fichiers binaires diffèrent)
Property changes on: trunk/Icones/Locales/NRJ Paris.bmp
___________________________________________________________________
Nom : svn:mime-type
+ application/octet-stream
From pouchintv-svn at baysse.fr Sat Mar 22 03:18:46 2008
From: pouchintv-svn at baysse.fr (pouchintv-svn at baysse.fr)
Date: Sat, 22 Mar 2008 03:18:46 +0100 (CET)
Subject: [Pouchintv-dev] [PouchinTVMod] gingko | r127 - trunk/Icones/Locales
Message-ID: <20080322021846.9B4085F6B1@mail.baysse.fr>
Author: gingko
Date: 2008-03-22 03:18:45 +0100 (sam, 22 mar 2008)
New Revision: 127
Modified:
trunk/Icones/Locales/CAP 24.bmp
Log:
Rectification d'une icône (décidément, je n'ai toujours rien compris à pourquoi des fois
la transparence de fond fonctionne, et pourquoi d'autres fois elle ne fonctionne pas).
Modifié: trunk/Icones/Locales/CAP 24.bmp
===================================================================
(les fichiers binaires diffèrent)
From guerin45 at free.fr Sat Mar 22 11:59:37 2008
From: guerin45 at free.fr (SuperPat)
Date: Sat, 22 Mar 2008 11:59:37 +0100
Subject: [Pouchintv-dev] =?iso-8859-1?q?Ic=F4ne_FR3_Berry_et_FR3_Dijon?=
Message-ID: <47E4E699.5080401@free.fr>
Bonjour,
Je vous envoi les deux icônes des décrochages de FR3 que je reçoit
depuis l'émetteur de Bourge.
Cordialement,
SuperPat
-------------- section suivante --------------
Une pièce jointe non texte a été nettoyée...
Nom: FR3 Berry.bmp
Type: image/bmp
Taille: 456 octets
Desc: non disponible
Url: http://listes.baysse.fr/pipermail/pouchintv-dev/attachments/20080322/ce1605e0/attachment.bin
-------------- section suivante --------------
Une pièce jointe non texte a été nettoyée...
Nom: FR3 Dijon.bmp
Type: image/bmp
Taille: 456 octets
Desc: non disponible
Url: http://listes.baysse.fr/pipermail/pouchintv-dev/attachments/20080322/ce1605e0/attachment-0001.bin
From gingko_pouchintv at nospam.homelinux.org Tue Mar 25 07:41:51 2008
From: gingko_pouchintv at nospam.homelinux.org (Gingko)
Date: Tue, 25 Mar 2008 07:41:51 +0100
Subject: [Pouchintv-dev] =?iso-8859-1?q?Ic=F4ne_FR3_Berry_et_FR3_Dijon?=
References: <47E4E699.5080401@free.fr>
Message-ID: <001501c88e43$4f09e260$464da8c0@GILLES>
Bonjour,
Merci, mais je ne comprends pas bien, en fait :
Ces deux icônes sont identiques entre elles, et identiques aux autres icônes
FR3 dont nous disposons déjà.
Dois-je comprendre que c'est à cause du nom de la chaîne trouvé par PTV lors
des recherches de chaînes, et que celui-ci est différent dans ces régions,
ou bien encore qu'il correspond à des chaînes supplémentaires "locales"
diffusées parallèlement à la chaîne FR3 nationale ?
Gingko
----- Original Message -----
From: "SuperPat"
To:
Sent: Saturday, March 22, 2008 11:59 AM
Subject: [Pouchintv-dev] Icône FR3 Berry et FR3 Dijon
> Bonjour,
>
> Je vous envoi les deux icônes des décrochages de FR3 que je reçoit
> depuis l'émetteur de Bourge.
>
> Cordialement,
>
> SuperPat
From pouchintv-svn at baysse.fr Wed Mar 26 00:14:26 2008
From: pouchintv-svn at baysse.fr (pouchintv-svn at baysse.fr)
Date: Wed, 26 Mar 2008 00:14:26 +0100 (CET)
Subject: [Pouchintv-dev] [PouchinTVMod] gingko | r128 - trunk/Icones/Locales
Message-ID: <20080325231427.05F705F3F7@mail.baysse.fr>
Author: gingko
Date: 2008-03-26 00:14:26 +0100 (mer, 26 mar 2008)
New Revision: 128
Added:
trunk/Icones/Locales/TV7.bmp
Log:
Ajout de l'icône de TV7 Bordeaux, envoyée par un utilisateur local de Pouchin TV Mod
(pseudo "nick ham").
Ajouté: trunk/Icones/Locales/TV7.bmp
===================================================================
(les fichiers binaires diffèrent)
Property changes on: trunk/Icones/Locales/TV7.bmp
___________________________________________________________________
Nom : svn:mime-type
+ application/octet-stream
From guerin45 at free.fr Tue Mar 25 16:50:25 2008
From: guerin45 at free.fr (SuperPat)
Date: Tue, 25 Mar 2008 16:50:25 +0100
Subject: [Pouchintv-dev] =?iso-8859-1?q?_Ic=F4ne_FR3_Berry_et_FR3_Dijon?=
Message-ID: <47E91F41.3020204@free.fr>
C'est deux icônes correspondent effectivement aux noms des chaînes
trouvées par Pouchin TV:
"FR3 Dijon" est bien une chaîne supplémentaire locale (chaîne N° 22)
et la chaîne FR3 nationale à été renommé en "FR3 Berry" (chaîne N°3) (Je
ne reçoit plus de chaînes nommé "France 3" sur l'émetteur de Bourge).
From gingko_pouchintv at nospam.homelinux.org Thu Mar 27 20:37:35 2008
From: gingko_pouchintv at nospam.homelinux.org (Gingko)
Date: Thu, 27 Mar 2008 20:37:35 +0100
Subject: [Pouchintv-dev] =?iso-8859-1?q?Ic=F4ne_FR3_Berry_et_FR3_Dijon?=
References: <47E91F41.3020204@free.fr>
Message-ID: <003101c89042$0212d8d0$464da8c0@GILLES>
----- Original Message -----
From: "SuperPat"
To:
Sent: Tuesday, March 25, 2008 4:50 PM
Subject: [Pouchintv-dev] Icône FR3 Berry et FR3 Dijon
> C'est deux icônes correspondent effectivement aux noms des chaînes
> trouvées par Pouchin TV:
> "FR3 Dijon" est bien une chaîne supplémentaire locale (chaîne N° 22)
> et la chaîne FR3 nationale à été renommé en "FR3 Berry" (chaîne N°3) (Je
> ne reçoit plus de chaînes nommé "France 3" sur l'émetteur de Bourge).
J'ose espérer qu'ils ne vont pas faire ça dans toutes les villes de France
...
... on n'aurait pas fini de recopier l'icône FR3 à l'identique ! :-(
Gingko