OSDN Git Service

305b838b4ba3ffa585d0e2ebd938977a9fbbb5ee
[rec10/rec10-git.git] / epgdump / epgdump.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <string.h>
5 #include <getopt.h>
6 #include <iconv.h>
7 #include <time.h>
8
9 #include "ts.h"
10 #include "psi.h"
11 #include "sdt.h"
12 #include "sdtt.h"
13 #include "eit.h"
14 #include "dsmcc.h"
15 #include "ts_ctl.h"
16
17 typedef         struct  _ContentTYPE{
18         char    *japanese ;
19         char    *english ;
20 }CONTENT_TYPE;
21
22 #define         CAT_COUNT               16
23 static  CONTENT_TYPE    ContentCatList[CAT_COUNT] = {
24         { "ニュース・報道", "news" },
25         { "スポーツ", "sports" },
26         { "情報", "information" },
27         { "ドラマ", "drama" },
28         { "音楽", "music" },
29         { "バラエティ", "variety" },
30         { "映画", "cinema" },
31         { "アニメ・特撮", "anime" },
32         { "ドキュメンタリー・教養", "documentary" },
33         { "演劇", "stage" },
34         { "趣味・実用", "hobby" },
35         { "福祉", "etc" },                    //福祉
36         { "予備", "etc" }, //予備
37         { "予備", "etc" }, //予備
38         { "予備", "etc" }, //予備
39         { "その他", "etc" } //その他
40 };
41
42
43 SVT_CONTROL     *svttop = NULL;
44 #define         SECCOUNT        64
45 char    title[1024];
46 char    subtitle[1024];
47 char    desc[102400] = {0};
48 char    Category[1024];
49 char    ServiceName[1024];
50 char    Logo[8192];
51 static unsigned char *base64 = (unsigned char *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
52
53 static void base64_char(unsigned long bb, int srclen, unsigned char *dest, int j)
54 {
55         int x, i, base;
56
57         /* 最終位置の計算 */
58         for ( i = srclen; i < 2; i++ ) 
59                 bb <<= 8;
60
61         /* BASE64変換 */
62         for ( base = 18, x = 0; x < srclen + 2; x++, base -= 6) {
63                 dest[j++] = base64[ (unsigned long)((bb>>base) & 0x3F) ];
64         }
65
66         /* 端数の判断 */
67         for ( i = x; i < 4; i++ ) {
68                 dest[j++] = (unsigned char)'=';         /* 端数 */
69         }
70         
71 }
72
73 static void base64_encode(unsigned char *dest, const unsigned char *src, int len)
74 {
75         unsigned char *p = src;
76         unsigned long bb = (unsigned long)0;
77         int i = 0, j = 0;
78
79         while (len--)
80         {
81                 bb <<= 8;
82                 bb |= (unsigned long)*p;
83
84                 /* 24bit単位に編集 */
85                 if (i == 2) {
86                         base64_char(bb, i, dest, j);
87
88                         j = j + 4;
89                         i = 0;
90                         bb = 0;
91                 } else
92                         i++;
93
94                 p++;
95         }
96
97         /* 24bitに満たない場合 */
98         if (i) base64_char(bb, i - 1, dest, j);
99
100 }
101
102 void    xmlspecialchars(char *str)
103 {
104         strrep(str, "&", "&amp;");
105         strrep(str, "'", "&apos;");
106         strrep(str, "\"", "&quot;");
107         strrep(str, "<", "&lt;");
108         strrep(str, ">", "&gt;");
109 }
110
111
112
113 void    GetSDT(FILE *infile, SVT_CONTROL *svttop, SECcache *secs, 
114         int count, STATION **station, int * station_count, char *header, int is_bs_cs)
115 {
116         SECcache  *bsecs;
117         int pmtpids[SECCOUNT];
118         memset(pmtpids, 0, sizeof(pmtpids));
119         int dsmccpids[SECCOUNT];
120         memset(dsmccpids, 0, sizeof(dsmccpids));
121         int i = 0;
122
123         while((bsecs = readTS(infile, secs, count)) != NULL) {
124                 /* PAT */
125                 if(is_bs_cs && (bsecs->pid & 0xFF) == 0x00) {
126                         dumpPAT(bsecs->buf, secs, count, pmtpids);
127                 }
128                 /* SDT */
129                 else if((bsecs->pid & 0xFF) == 0x11) {
130                         dumpSDT(bsecs->buf, svttop, station, station_count, header);
131                 }
132                 /* TOT */
133                 else if((bsecs->pid & 0xFF) == 0x14) {
134                         dumpTOT(bsecs->buf);
135                 }
136                 /* SDTT */
137                 else if((bsecs->pid & 0xFF) == 0x23) {
138                         dumpSDTT(bsecs->buf, *station, *station_count);
139                 }
140                 /* CDT */
141                 else if((bsecs->pid & 0xFF) == 0x29) {
142                         dumpCDT(bsecs->buf, *station, *station_count);
143                 }
144                 else if ( is_bs_cs ) {
145                         for ( i = 1; i < SECCOUNT; i++ ) {
146                                 if ( pmtpids[i] == 0 ) {
147                                         break;
148                                 }
149                                 /* PMT specified by PAT */
150                                 if ( bsecs->pid == pmtpids[i] ) {
151                                         dumpPMT(bsecs->buf, secs, count, dsmccpids);
152                                 }
153                         }
154
155                         for ( i = 0; i < SECCOUNT; i++ ) {
156                                 if ( dsmccpids[i] == 0 ) {
157                                         break;
158                                 }
159                                 /* DSM-CC specified by PMT */
160                                 if ( bsecs->pid == dsmccpids[i] ) {
161                                         dumpDSMCC(bsecs->buf, *station, *station_count);
162                                 }
163                         }
164                 }
165         }
166 }
167
168 void    GetEIT(FILE *infile, FILE *outfile, STATION *psta, SECcache *secs)
169 {
170         SECcache  *bsecs;
171         EIT_CONTROL     *eitcur ;
172         EIT_CONTROL     *eitnext ;
173         EIT_CONTROL     *eittop = NULL;
174         time_t  l_time ;
175         time_t  end_time ;
176         struct  tm      tl ;
177         struct  tm      *endtl ;
178         char    cendtime[32];
179         char    cstarttime[32];
180
181         memset(secs, 0,  sizeof(SECcache) * SECCOUNT);
182         secs[0].pid = 0x12; /* EIT  */
183         secs[1].pid = 0x26; /* EIT  */
184         secs[2].pid = 0x27; /* EIT  */
185
186         eittop = calloc(1, sizeof(EIT_CONTROL));
187         eitcur = eittop ;
188         fseek(infile, 0, SEEK_SET);
189         while((bsecs = readTS(infile, secs, SECCOUNT)) != NULL) {
190                 /* EIT */
191                 if((bsecs->pid & 0xFF) == 0x12) {
192                         dumpEIT(bsecs->buf, psta->svId, psta->onId, psta->tsId, eittop);
193                 }else if((bsecs->pid & 0xFF) == 0x26) {
194                         dumpEIT(bsecs->buf, psta->svId, psta->onId, psta->tsId, eittop);
195                 }else if((bsecs->pid & 0xFF) == 0x27) {
196                         dumpEIT(bsecs->buf, psta->svId, psta->onId, psta->tsId, eittop);
197                 }
198         }
199         eitcur = eittop ;
200         while(eitcur != NULL){
201                 if(!eitcur->servid){
202                         eitcur = eitcur->next ;
203                         continue ;
204                 }
205                 if(eitcur->content_type > CAT_COUNT){
206                         eitcur->content_type = CAT_COUNT -1 ;
207                 }
208                 memset(title, '\0', sizeof(title));
209                 strcpy(title, eitcur->title);
210                 xmlspecialchars(title);
211
212                 memset(subtitle, '\0', sizeof(subtitle));
213                 strcpy(subtitle, eitcur->subtitle);
214                 xmlspecialchars(subtitle);
215
216                 memset(desc, '\0', sizeof(desc));
217                 if ( eitcur->desc ) {
218                         strcpy(desc, eitcur->desc);
219                         xmlspecialchars(desc);
220                 }
221
222                 memset(Category, '\0', sizeof(Category));
223                 strcpy(Category, ContentCatList[eitcur->content_type].japanese);
224                 xmlspecialchars(Category);
225
226                 tl.tm_sec = eitcur->ss ;
227                 tl.tm_min = eitcur->hm ;
228                 tl.tm_hour = eitcur->hh ;
229                 tl.tm_mday = eitcur->dd ;
230                 tl.tm_mon = (eitcur->mm - 1);
231                 tl.tm_year = (eitcur->yy - 1900);
232                 tl.tm_wday = 0;
233                 tl.tm_isdst = 0;
234                 tl.tm_yday = 0;
235                 l_time = mktime(&tl);
236                 if((eitcur->ehh == 0) && (eitcur->emm == 0) && (eitcur->ess == 0)){
237                         (void)time(&l_time);
238                         end_time = l_time + (60 * 5);           // 5分後に設定
239                 endtl = localtime(&end_time);
240                 }else{
241                         end_time = l_time + eitcur->ehh * 3600 + eitcur->emm * 60 + eitcur->ess;
242                         endtl = localtime(&end_time);
243                 }
244                 memset(cendtime, '\0', sizeof(cendtime));
245                 memset(cstarttime, '\0', sizeof(cstarttime));
246                 strftime(cendtime, (sizeof(cendtime) - 1), "%Y%m%d%H%M%S", endtl);
247                 strftime(cstarttime, (sizeof(cstarttime) - 1), "%Y%m%d%H%M%S", &tl);
248                 fprintf(outfile, "  <programme start=\"%s +0900\" stop=\"%s +0900\" channel=\"%s\" event=\"%d\">\n",    
249                                 cstarttime, cendtime, psta->ontv, eitcur->event_id);
250                 fprintf(outfile, "    <title lang=\"ja_JP\">%s</title>\n", title);
251                 fprintf(outfile, "    <desc lang=\"ja_JP\">%s</desc>\n", subtitle);
252                 fprintf(outfile, "    <longdesc lang=\"ja_JP\">%s</longdesc>\n", desc);
253                 fprintf(outfile, "    <category lang=\"ja_JP\">%s</category>\n", Category);
254                 //fprintf(outfile, "    <category lang=\"en\">%s</category>\n", ContentCatList[eitcur->content_type].english);
255                 fprintf(outfile, "  </programme>\n");
256 #if 0
257                 fprintf(outfile, "(%x:%x:%x)%s,%s,%s,%s,%s,%s\n",
258                                         eitcur->servid, eitcur->table_id, eitcur->event_id,
259                                         cstarttime, cendtime,
260                                         title, subtitle,
261                                         Category,
262                                         ContentCatList[eitcur->content_type].english);
263
264                 fprintf(outfile, "(%x:%x)%04d/%02d/%02d,%02d:%02d:%02d,%02d:%02d:%02d,%s,%s,%s,%s\n",
265                                         eitcur->table_id, eitcur->event_id,
266                                         eitcur->yy, eitcur->mm, eitcur->dd,
267                                         eitcur->hh, eitcur->hm, eitcur->ss,
268                                         eitcur->ehh, eitcur->emm, eitcur->ess,
269                                         eitcur->title, eitcur->subtitle,
270                                         ContentCatList[eitcur->content_type].japanese,
271                                         ContentCatList[eitcur->content_type].english);
272 #endif
273                 eitnext = eitcur->next ;
274                 free(eitcur->title);
275                 free(eitcur->subtitle);
276                 free(eitcur);
277                 eitcur = eitnext ;
278         }
279         free(eittop);
280         eittop = NULL;
281 }
282 void checkSta_BS(STATION **station,int *stalength){
283         STATION *statmp;
284         int chl[30];
285         int chlt=0;
286         int stal=0;
287         STATION * statin= *station;
288         statmp=malloc(sizeof(STATION)*2);
289         for (int i=0;i<*stalength;i++){
290                 int noidinchl=1;
291                 for (int j=0;j<chlt;j++){
292                         if (chl[j]==statin[i].svId || statin[i].svId >= 290){
293                                 noidinchl=0;
294                         }
295                 }
296                 if (noidinchl==1){
297                         statmp=realloc(statmp,(stal+1)*sizeof(STATION));
298                         statmp[stal]=statin[i];
299                         //memcpy(statmp[stal-1],station[i],sizeof(STATION));
300                         chl[chlt]=statin[i].svId;
301                         chlt++;
302                         stal++;
303                 }
304         }
305         //*station=realloc(station,(stal+1)*sizeof(STATION));
306         //memcpy(*station,statmp,(stal+1)*sizeof(STATION));
307         *station=statmp;
308         *stalength=stal;
309         //memcpy(statin,statmp,chlt*sizeof(STATION));
310         //free(statmp);
311 }
312
313 void checkSta(STATION **station,int *stalength){
314         STATION *statmp;
315         int chl[90];
316         int chlt=0;
317         int stal=0;
318         STATION * statin= *station;
319         statmp=malloc(sizeof(STATION)*2);
320         for (int i=0;i<*stalength;i++){
321                 int noidinchl=1;
322                 for (int j=0;j<chlt;j++){
323                         if (chl[j]==statin[i].svId){
324                                 noidinchl=0;
325                         }
326                 }
327                 if (noidinchl==1){
328                         statmp=realloc(statmp,(stal+1)*sizeof(STATION));
329                         statmp[stal]=statin[i];
330                         //memcpy(statmp[stal-1],station[i],sizeof(STATION));
331                         chl[chlt]=statin[i].svId;
332                         chlt++;
333                         stal++;
334                 }
335         }
336         *station=statmp;
337         *stalength=stal;//ここいらが怪しい
338         //memcpy(statin,statmp,chlt*sizeof(STATION));
339         //free(statmp);
340         return;
341 }
342 int main(int argc, char *argv[])
343 {
344
345         FILE *infile = stdin;
346         FILE *outfile = stdout;
347         char    *arg_onTV ;
348         int             staCount ;
349         int   inclose = 0;
350         int   outclose = 0;
351         SVT_CONTROL     *svtcur ;
352         SVT_CONTROL     *svtsave ;
353         SECcache   secs[SECCOUNT];
354         int             lp ;
355         STATION *pStas ;
356         int             act = 0;
357         int             i ;
358
359         /* 興味のあるpidを指定 */
360         memset(secs, 0,  sizeof(SECcache) * SECCOUNT);
361         secs[0].pid = 0x00; /* PAT  */
362         secs[1].pid = 0x11; /* SDT  */
363         secs[2].pid = 0x12; /* EIT  */
364         secs[3].pid = 0x23; /* SDTT */
365         secs[4].pid = 0x26; /* EIT  */
366         secs[5].pid = 0x27; /* EIT  */
367         secs[6].pid = 0x29; /* CDT  */
368
369         if(argc == 4){
370                 arg_onTV = argv[1];
371                 if(strcmp(argv[2], "-")) {
372                         infile = fopen(argv[2], "r");
373                         if ( !infile) {
374                           printf( "tsFile not found.\n" );
375                           exit( -1 );
376                         }
377                         inclose = 1;
378                 }
379                 else {
380                         infile = stdin;
381                 }
382                 if(strcmp(argv[3], "-")) {
383                         outfile = fopen(argv[3], "w+");
384                         if ( !outfile) {
385                           printf( "xmlfile not found.\n" );
386                           exit( -1 );
387                         }
388                         outclose = 1;
389                 }
390                 else {
391                         outfile = stdout;
392                 }
393         }else{
394                 fprintf(stdout, "Usage : %s {/BS|/CS} <tsFile> <outfile>\n", argv[0]);
395                 fprintf(stdout, "Usage : %s <id> <tsFile> <outfile>\n", argv[0]);
396                 fprintf(stdout, "\n");
397                 fprintf(stdout, "id       チャンネル識別子。地上波の物理チャンネルを与えます。\n");
398                 fprintf(stdout, "/BS      BSモード。一つのTSからBS全局のデータを読み込みます。\n");
399                 fprintf(stdout, "/CS      CSモード。一つのTSから複数局のデータを読み込みます。\n");
400                 fprintf(stdout, "/TIME    時刻合わせモード。TSからTOT(Time Offset Table)を読み込みます。\n");
401                 fprintf(stdout, "         recpt1 <任意> 10(秒以上) - | epgdump /TIME - <任意>の形で使用してください。\n");
402                 fprintf(stdout, "         TOTは5秒に1回しか来ないため、recpt1に与える時間をある程度長くしてください。\n");
403 /*
404                 fprintf(stdout, "  ontvcode   Channel identifier (ex. ****.ontvjapan.com)\n");
405                 fprintf(stdout, "  /BS        BS mode\n");
406                 fprintf(stdout, "               This mode reads the data of all BS TV stations\n");
407                 fprintf(stdout, "               from one TS data.\n");
408                 fprintf(stdout, "  /CS        CS mode\n");
409                 fprintf(stdout, "               This mode reads the data of two or more CS TV stations\n");
410                 fprintf(stdout, "               from one TS data.\n");
411 */
412                 return 0;
413         }
414
415         if(strcmp(arg_onTV, "/BS") == 0){
416                 STATION *sta = NULL;
417                 int sta_count = 0;
418                 svttop = calloc(1, sizeof(SVT_CONTROL));
419                 char *head="BS";
420                 GetSDT(infile, svttop, secs, SECCOUNT,&sta, &sta_count, head, 1);
421                 checkSta_BS(&sta,&sta_count);
422                 pStas = sta;
423                 staCount = sta_count;
424                 //staCount = sizeof(pStas) / sizeof (STATION);
425                 act = 0 ;
426         }else if(strcmp(arg_onTV, "/CS") == 0){
427                 STATION *sta=NULL;
428                 int sta_count = 0;
429                 svttop = calloc(1, sizeof(SVT_CONTROL));
430                 char *head="CS";
431                 GetSDT(infile, svttop, secs, SECCOUNT,&sta, &sta_count, head, 1);
432                 checkSta(&sta,&sta_count);
433                 pStas = sta;
434                 staCount = sta_count;
435                 //staCount=sizeof(pStas) / sizeof (STATION);
436                 act = 0 ;
437         }else if(strcmp(arg_onTV, "/TEST") == 0){
438                 STATION *sta=NULL;
439                 int sta_count = 0;
440                 svttop = calloc(1, sizeof(SVT_CONTROL));
441                 char *head="TEST";
442                 GetSDT(infile, svttop, secs, SECCOUNT,&sta, &sta_count, head, 0);
443                 checkSta(&sta,&sta_count);
444                 //if (sta_count) 
445                 printf("Station count: %d\n1st ontv=%s,name=%s\n",sta_count, sta[0].ontv, sta[0].name);
446                 pStas = sta;
447                 staCount = sta_count;// sizeof(pStas) / sizeof (STATION);
448                 act = 0 ;
449         }else if(strcmp(arg_onTV, "/TIME") == 0){
450                 printf("TSに載っている時刻データは2秒ほど早めてあるのかもしれません。\n");
451                 memset(secs, 0,  sizeof(SECcache) * SECCOUNT);
452                 secs[0].pid = 0x14; /* TOT  */
453
454                 GetSDT(infile, NULL, secs, SECCOUNT,NULL, NULL,NULL, 0);
455                 act = 0 ;
456
457                 goto cleanup;
458         }else{
459                 if(infile == NULL){
460                         fprintf(stderr, "Can't open file: %s\n", argv[2]);
461                         return 1;
462                 }
463                 /*
464                 act = 1 ;
465                 svttop = calloc(1, sizeof(SVT_CONTROL));
466                 GetSDT(infile, svttop, secs, SECCOUNT);
467                 svtcur = svttop->next ; //先頭
468                 if(svtcur == NULL){
469                         free(svttop);
470                         return 1;
471                 }
472
473                 pStas = calloc(1, sizeof(STATION));
474                 pStas->tsId = svtcur->transport_stream_id ;
475                 pStas->onId = svtcur->original_network_id ;
476                 pStas->svId = svtcur->event_id ;
477                 pStas->ontv = arg_onTV ;
478                 pStas->name = svtcur->servicename ;
479                 staCount = 1;
480                 */
481
482                 // 地上波のマルチチャンネル対応のため
483                 STATION *sta = NULL;
484                 int sta_count = 0;
485                 svttop = calloc(1, sizeof(SVT_CONTROL));
486                 //char *head=arg_onTV;
487                 GetSDT(infile, svttop, secs, SECCOUNT, &sta, &sta_count, arg_onTV, 0);
488                 checkSta(&sta, &sta_count);
489                 //if (sta_count) printf("Station count: %d\n1st ontv=%s,name=%s\n",sta_count, sta[0].ontv, sta[0].name);
490                 pStas = sta;
491                 staCount = sta_count;// sizeof(pStas) / sizeof (STATION);
492                 act = 0 ;
493         }
494
495         fprintf(outfile, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
496         fprintf(outfile, "<!DOCTYPE tv SYSTEM \"xmltv.dtd\">\n\n");
497         fprintf(outfile, "<tv generator-info-name=\"tsEPG2xml\" generator-info-url=\"http://localhost/\">\n");
498
499         for(lp = 0 ; lp < staCount ; lp++){
500                 memset(ServiceName, '\0', sizeof(ServiceName));
501                 strcpy(ServiceName, pStas[lp].name);
502                 xmlspecialchars(ServiceName);
503
504                 fprintf(outfile, "  <channel id=\"%s\">\n", pStas[lp].ontv);
505                 fprintf(outfile, "    <display-name lang=\"ja_JP\">%s</display-name>\n", ServiceName);
506
507                 memset(Logo, '\0', sizeof(Logo));
508                 for ( i = 0 ; i < 6 ; i++) {
509                         if (pStas[lp].logo_array[i].logo) {
510                                 base64_encode(Logo, pStas[lp].logo_array[i].logo, pStas[lp].logo_array[i].logo_size);
511                                 xmlspecialchars(Logo);
512                                 fprintf(outfile, "    <logo id=\"%02d\">%s</logo>\n", i, Logo);
513                         }
514                 }
515
516                 fprintf(outfile, "  </channel>\n");
517         }
518         for(lp = 0 ; lp < staCount ; lp++){
519                 GetEIT(infile, outfile, &pStas[lp], secs);
520         }
521         fprintf(outfile, "</tv>\n");
522 cleanup: 
523         if(inclose) {
524                 fclose(infile);
525         }
526         if(outclose) {
527                 fclose(outfile);
528         }
529         if(act){
530                 free(pStas);
531                 svtcur = svttop ;       //先頭
532                 while(svtcur != NULL){
533                         svtsave = svtcur->next ;
534                         free(svtcur);
535                         svtcur = svtsave ;
536                 }
537         }
538
539         return 0;
540 }