OSDN Git Service

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