19 typedef struct _ContentTYPE{
25 static CONTENT_TYPE ContentCatList[CAT_COUNT] = {
26 { "ニュース・報道", "news" },
28 { "情報", "information" },
31 { "バラエティ", "variety" },
33 { "アニメ・特撮", "anime" },
34 { "ドキュメンタリー・教養", "documentary" },
45 SVT_CONTROL *svttop = NULL;
46 DSM_CONTROL dsmctl[1024];
48 static unsigned char *base64 = (unsigned char *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
50 static void base64_char(unsigned long bb, int srclen, unsigned char *dest, int j)
55 for ( i = srclen; i < 2; i++ )
59 for ( base = 18, x = 0; x < srclen + 2; x++, base -= 6) {
60 dest[j++] = base64[ (unsigned long)((bb>>base) & 0x3F) ];
64 for ( i = x; i < 4; i++ ) {
65 dest[j++] = (unsigned char)'='; /* 端数 */
70 static void base64_encode(unsigned char *dest, const unsigned char *src, int len)
72 unsigned char *p = src;
73 unsigned long bb = (unsigned long)0;
79 bb |= (unsigned long)*p;
83 base64_char(bb, i, dest, j);
95 if (i) base64_char(bb, i - 1, dest, j);
99 void xmlspecialchars(char *str)
101 strrep(str, "&", "&");
102 strrep(str, "'", "'");
103 strrep(str, "\"", """);
104 strrep(str, "<", "<");
105 strrep(str, ">", ">");
110 void GetSDT(FILE *infile, SVT_CONTROL *svttop, SECcache *secs,
111 int count, STATION **station, int * station_count, char *header, int is_logo)
114 int pmtpids[SECCOUNT];
115 memset(pmtpids, 0, sizeof(pmtpids));
116 int dsmccpids[SECCOUNT];
117 memset(dsmccpids, 0, sizeof(dsmccpids));
118 int i = 0 , downloadDataId = 0;
120 while((bsecs = readTS(infile, secs, count)) != NULL) {
122 if((bsecs->pid & 0xFF) == 0x11) {
123 dumpSDT(bsecs->buf, svttop, station, station_count, header);
126 else if((bsecs->pid & 0xFF) == 0x14) {
130 //else if((bsecs->pid & 0xFF) == 0x23) {
131 // dumpSDTT(bsecs->buf, *station, *station_count);
134 else if((bsecs->pid & 0xFF) == 0x24) {
138 else if((bsecs->pid & 0xFF) == 0x29) {
139 dumpCDT(bsecs->buf, *station, *station_count);
141 else if ( is_logo ) {
143 if((bsecs->pid & 0xFF) == 0x00) {
144 dumpPAT(bsecs->buf, secs, count, pmtpids);
147 for ( i = 1; i < SECCOUNT; i++ ) {
148 if ( pmtpids[i] == 0 ) {
151 /* PMT specified by PAT */
152 if ( bsecs->pid == pmtpids[i] ) {
153 dumpPMT(bsecs->buf, secs, count, dsmccpids);
157 for ( i = 0; i < SECCOUNT; i++ ) {
158 if ( dsmccpids[i] == 0 ) {
161 /* DSM-CC specified by PMT */
162 if ( bsecs->pid == dsmccpids[i] ) {
163 dumpDSMCC(bsecs->buf, &downloadDataId, &dsmctl);
170 void GetEIT(FILE *infile, FILE *outfile, STATION *psta, SECcache *secs)
173 EIT_CONTROL *eitcur ;
174 EIT_CONTROL *eitnext ;
175 EIT_CONTROL *eittop = NULL;
185 char desc[102400] = {0};
187 char VideoType[1024];
188 char AudioType[1024];
190 memset(secs, 0, sizeof(SECcache) * SECCOUNT);
191 secs[0].pid = 0x12; /* EIT */
192 secs[1].pid = 0x26; /* EIT */
193 secs[2].pid = 0x27; /* EIT */
195 eittop = calloc(1, sizeof(EIT_CONTROL));
197 fseek(infile, 0, SEEK_SET);
198 while((bsecs = readTS(infile, secs, SECCOUNT)) != NULL) {
200 if((bsecs->pid & 0xFF) == 0x12) {
201 dumpEIT(bsecs->buf, psta->svId, psta->onId, psta->tsId, eittop);
202 }else if((bsecs->pid & 0xFF) == 0x26) {
203 dumpEIT(bsecs->buf, psta->svId, psta->onId, psta->tsId, eittop);
204 }else if((bsecs->pid & 0xFF) == 0x27) {
205 dumpEIT(bsecs->buf, psta->svId, psta->onId, psta->tsId, eittop);
209 while(eitcur != NULL){
211 eitcur = eitcur->next ;
214 if(eitcur->content_type > CAT_COUNT){
215 eitcur->content_type = CAT_COUNT -1 ;
217 memset(title, '\0', sizeof(title));
218 strcpy(title, eitcur->title);
219 xmlspecialchars(title);
221 memset(subtitle, '\0', sizeof(subtitle));
222 strcpy(subtitle, eitcur->subtitle);
223 xmlspecialchars(subtitle);
225 memset(desc, '\0', sizeof(desc));
226 if ( eitcur->desc ) {
227 strcpy(desc, eitcur->desc);
228 xmlspecialchars(desc);
231 memset(Category, '\0', sizeof(Category));
232 strcpy(Category, ContentCatList[eitcur->content_type].japanese);
233 xmlspecialchars(Category);
235 memset(VideoType, '\0', sizeof(VideoType));
236 strcpy(VideoType, parseComponentDescType(eitcur->video_type));
237 xmlspecialchars(VideoType);
239 memset(AudioType, '\0', sizeof(AudioType));
240 strcpy(AudioType, parseAudioComponentDescType(eitcur->audio_type));
241 xmlspecialchars(AudioType);
243 tl.tm_sec = eitcur->ss ;
244 tl.tm_min = eitcur->hm ;
245 tl.tm_hour = eitcur->hh ;
246 tl.tm_mday = eitcur->dd ;
247 tl.tm_mon = (eitcur->mm - 1);
248 tl.tm_year = (eitcur->yy - 1900);
252 l_time = mktime(&tl);
253 if((eitcur->ehh == 0) && (eitcur->emm == 0) && (eitcur->ess == 0)){
255 end_time = l_time + (60 * 5); // 5分後に設定
256 endtl = localtime(&end_time);
258 end_time = l_time + eitcur->ehh * 3600 + eitcur->emm * 60 + eitcur->ess;
259 endtl = localtime(&end_time);
261 memset(cendtime, '\0', sizeof(cendtime));
262 memset(cstarttime, '\0', sizeof(cstarttime));
263 strftime(cendtime, (sizeof(cendtime) - 1), "%Y%m%d%H%M%S", endtl);
264 strftime(cstarttime, (sizeof(cstarttime) - 1), "%Y%m%d%H%M%S", &tl);
266 fprintf(outfile, " <programme start=\"%s +0900\" stop=\"%s +0900\" channel=\"%s\" event=\"%d\">\n",
267 cstarttime, cendtime, psta->ontv, eitcur->event_id);
268 fprintf(outfile, " <title lang=\"ja_JP\">%s</title>\n", title);
269 fprintf(outfile, " <desc lang=\"ja_JP\">%s</desc>\n", subtitle);
270 fprintf(outfile, " <longdesc lang=\"ja_JP\">%s</longdesc>\n", desc);
271 fprintf(outfile, " <category lang=\"ja_JP\">%s</category>\n", Category);
272 fprintf(outfile, " <video type=\"%d\">%s</video>\n", eitcur->video_type, VideoType);
273 fprintf(outfile, " <audio type=\"%d\" multi=\"%d\">%s</audio>\n", eitcur->audio_type, eitcur->multi_type, AudioType);
274 //fprintf(outfile, " <category lang=\"en\">%s</category>\n", ContentCatList[eitcur->content_type].english);
275 fprintf(outfile, " </programme>\n");
277 fprintf(outfile, "(%x:%x:%x)%s,%s,%s,%s,%s,%s\n",
278 eitcur->servid, eitcur->table_id, eitcur->event_id,
279 cstarttime, cendtime,
282 ContentCatList[eitcur->content_type].english);
284 fprintf(outfile, "(%x:%x)%04d/%02d/%02d,%02d:%02d:%02d,%02d:%02d:%02d,%s,%s,%s,%s\n",
285 eitcur->table_id, eitcur->event_id,
286 eitcur->yy, eitcur->mm, eitcur->dd,
287 eitcur->hh, eitcur->hm, eitcur->ss,
288 eitcur->ehh, eitcur->emm, eitcur->ess,
289 eitcur->title, eitcur->subtitle,
290 ContentCatList[eitcur->content_type].japanese,
291 ContentCatList[eitcur->content_type].english);
293 eitnext = eitcur->next ;
295 free(eitcur->subtitle);
303 void checkSta(STATION **station,int *stalength){
308 STATION * statin = *station;
309 statmp = malloc( sizeof(STATION) * 2 );
310 for (int i = 0 ; i < *stalength ; i++){
312 for (int j = 0 ; j < chlt ; j++){
313 if ( chl[j] == statin[i].svId ) {
317 if ( noidinchl == 1 ) {
318 statmp = realloc(statmp, (stal+1) * sizeof(STATION));
319 statmp[stal] = statin[i];
320 chl[chlt] = statin[i].svId;
326 *stalength = stal;//ここいらが怪しい
327 //memcpy(statin,statmp,chlt*sizeof(STATION));
332 int main(int argc, char *argv[])
335 FILE *infile = stdin;
336 FILE *outfile = stdout;
341 SVT_CONTROL *svtcur ;
342 SVT_CONTROL *svtsave ;
343 SECcache secs[SECCOUNT];
351 SDTTdataService *service;
353 memset(dsmctl, 0, sizeof(dsmctl));
355 if(argc == 5 && strcmp(argv[1], "/LOGO") == 0){
364 if(strcmp(argv[2], "-")) {
365 infile = fopen(argv[2], "r");
367 printf( "tsFile not found (Can't open file: %s)\n", argv[2] );
375 if(strcmp(argv[3], "-")) {
376 outfile = fopen(argv[3], "w+");
378 printf( "xmlFile not found (Can't open file: %s)\n", argv[3] );
387 fprintf(stdout, "Usage : %s (/LOGO) {/BS|/CS|<id>} <tsFile> <outfile>\n", argv[0]);
388 fprintf(stdout, "\n");
389 fprintf(stdout, "/LOGO ロゴ取得モード。独立して指定し、番組表の出力を行ないません。\n");
390 fprintf(stdout, " 必要なTSの長さ 地上波は10分 BS/CSは20分です。\n");
391 fprintf(stdout, "id チャンネル識別子。地上波の物理チャンネルを与えます。\n");
392 fprintf(stdout, "/BS BSモード。一つのTSからBS全局のデータを読み込みます。\n");
393 fprintf(stdout, "/CS CSモード。一つのTSから複数局のデータを読み込みます。\n");
394 fprintf(stdout, "/TIME 時刻合わせモード。TSからTOT(Time Offset Table)を読み込みます。\n");
395 fprintf(stdout, " recpt1 <任意> 10(秒以上) - | epgdump /TIME - <任意>の形で使用してください。\n");
396 fprintf(stdout, " TOTは5秒に1回しか来ないため、recpt1に与える時間をある程度長くしてください。\n");
398 fprintf(stdout, " ontvcode Channel identifier (ex. ****.ontvjapan.com)\n");
399 fprintf(stdout, " /BS BS mode\n");
400 fprintf(stdout, " This mode reads the data of all BS TV stations\n");
401 fprintf(stdout, " from one TS data.\n");
402 fprintf(stdout, " /CS CS mode\n");
403 fprintf(stdout, " This mode reads the data of two or more CS TV stations\n");
404 fprintf(stdout, " from one TS data.\n");
411 svttop = calloc(1, sizeof(SVT_CONTROL));
416 memset(secs, 0, sizeof(SECcache) * SECCOUNT);
417 secs[0].pid = 0x00; /* PAT */
418 secs[1].pid = 0x11; /* SDT */
419 secs[2].pid = 0x29; /* CDT */
422 memset(secs, 0, sizeof(SECcache) * SECCOUNT);
423 secs[0].pid = 0x00; /* PAT */
424 secs[1].pid = 0x11; /* SDT */
425 secs[2].pid = 0x12; /* EIT */
426 secs[3].pid = 0x23; /* SDTT */
427 secs[4].pid = 0x26; /* EIT */
428 secs[5].pid = 0x27; /* EIT */
429 secs[6].pid = 0x29; /* CDT */
432 if(strcmp(arg_onTV, "/TIME") == 0){
433 printf("TSに載っている時刻データは2秒ほど早めてあるのかもしれません。\n");
434 memset(secs, 0, sizeof(SECcache) * SECCOUNT);
435 secs[0].pid = 0x14; /* TOT */
437 GetSDT(infile, NULL, secs, SECCOUNT,NULL, NULL,NULL, 0);
440 }else if(strcmp(arg_onTV, "/BS") == 0){
442 GetSDT(infile, svttop, secs, SECCOUNT, &pStas, &staCount, head, is_logo);
443 }else if(strcmp(arg_onTV, "/CS") == 0){
445 GetSDT(infile, svttop, secs, SECCOUNT, &pStas, &staCount, head, is_logo);
446 }else if(strcmp(arg_onTV, "/TEST") == 0){
447 memset(secs, 0, sizeof(SECcache) * SECCOUNT);
448 secs[0].pid = 0x24; /* BIT */
451 GetSDT(infile, svttop, secs, SECCOUNT, &pStas, &staCount, head, 0);
453 // printf("Station count: %d\n1st ontv=%s,name=%s\n",staCount, pStas[0].ontv, pStas[0].name);
455 GetSDT(infile, svttop, secs, SECCOUNT, &pStas, &staCount, arg_onTV, 0);
457 // 地上波のマルチチャンネル対応のためコメントアウト
460 svttop = calloc(1, sizeof(SVT_CONTROL));
461 GetSDT(infile, svttop, secs, SECCOUNT);
462 svtcur = svttop->next ; //先頭
468 pStas = calloc(1, sizeof(STATION));
469 pStas->tsId = svtcur->transport_stream_id ;
470 pStas->onId = svtcur->original_network_id ;
471 pStas->svId = svtcur->event_id ;
472 pStas->ontv = arg_onTV ;
473 pStas->name = svtcur->servicename ;
477 checkSta(&pStas, &staCount);
479 fprintf(outfile, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
480 fprintf(outfile, "<!DOCTYPE tv SYSTEM \"xmltv.dtd\">\n\n");
481 fprintf(outfile, "<tv generator-info-name=\"tsEPG2xml\" generator-info-url=\"http://localhost/\">\n");
483 char ServiceName[1024];
487 memset(Logo, '\0', sizeof(Logo));
488 for(lp = 0 ; lp < staCount ; lp++){
489 for ( i = 0 ; i < 6 ; i++) {
490 if (pStas[lp].logo_array[i].logo) {
491 base64_encode(Logo, pStas[lp].logo_array[i].logo, pStas[lp].logo_array[i].logo_size);
492 xmlspecialchars(Logo);
493 fprintf(outfile, " <logo ts=\"%d\" on=\"%d\" sv=\"%d\" type=\"%d\">%s</logo>\n",
503 for ( i = 0; i < 1024; i++) {
504 if ( dsmctl[i].isUsed == 0 ) break;
505 parseSDTTdata(dsmctl[i].blockData, &sdtd);
507 for (j = 0; j < sdtd.number_of_loop; j++) {
508 loop = sdtd.loop + sizeof(SDTTdataLoop) * j;
510 for ( k = 0; k < loop->number_of_services; k++) {
511 service = loop->services + sizeof(SDTTdataService) * k;
514 for(lp = 0 ; lp < staCount ; lp++){
516 pStas[lp].tsId == service->transport_stream_id &&
517 pStas[lp].onId == service->original_network_id &&
518 pStas[lp].svId == service->service_id
521 &pStas[lp].logo_array[sdtd.logo_type].logo,
522 &pStas[lp].logo_array[sdtd.logo_type].logo_size);
528 printf( "SDTTdataLoop (%d:%d) %d:%d[%d:%d:%d]%d\n",
532 service->transport_stream_id,
533 service->original_network_id,
543 clt2png(loop->data, &logo, &logo_size);
544 memset(Logo, '\0', sizeof(Logo));
545 base64_encode(Logo, logo, logo_size);
546 xmlspecialchars(Logo);
548 fprintf(outfile, " <logo ts=\"%d\" on=\"%d\" sv=\"%d\" type=\"%d\" dlid=\"%d\">%s</logo>\n",
549 service->transport_stream_id,
550 service->original_network_id,
560 for(lp = 0 ; lp < staCount ; lp++){
561 memset(ServiceName, '\0', sizeof(ServiceName));
562 strcpy(ServiceName, pStas[lp].name);
563 xmlspecialchars(ServiceName);
565 fprintf(outfile, " <channel id=\"%s\">\n", pStas[lp].ontv);
566 fprintf(outfile, " <display-name lang=\"ja_JP\">%s</display-name>\n", ServiceName);
567 fprintf(outfile, " <id ts=\"%d\" on=\"%d\" sv=\"%d\"/>\n", pStas[lp].tsId, pStas[lp].onId, pStas[lp].svId);
569 fprintf(outfile, " </channel>\n");
572 fprintf(outfile, "</tv>\n");
575 for(lp = 0 ; lp < staCount ; lp++){
576 GetEIT(infile, outfile, &pStas[lp], secs);
578 fprintf(outfile, "</tv>\n");
588 svtcur = svttop ; //先頭
589 while(svtcur != NULL){
590 svtsave = svtcur->next ;