328 SetupStore("OptionPattern",SetupPE.OptPat); |
333 SetupStore("OptionPattern",SetupPE.OptPat); |
329 SetupStore("OrderInfo",SetupPE.OrderInfo); |
334 SetupStore("OrderInfo",SetupPE.OrderInfo); |
330 SetupStore("RatingInfo",SetupPE.RatingInfo); |
335 SetupStore("RatingInfo",SetupPE.RatingInfo); |
331 } |
336 } |
332 |
337 |
333 // --- CIT --------------------------------------------------------------------- |
338 // --- CRC16 ------------------------------------------------------------------- |
334 |
339 |
335 namespace SI { |
340 #define POLY 0xA001 // CRC16 |
336 |
341 |
337 #define CIT_LEN 17 |
342 unsigned int crc16(unsigned int crc, unsigned char const *p, int len) |
338 |
343 { |
339 struct cit { |
344 while(len--) { |
340 u_char table_id :8; |
345 crc^=*p++; |
341 #if BYTE_ORDER == BIG_ENDIAN |
346 for(int i=0; i<8; i++) |
342 u_char section_syntax_indicator :1; |
347 crc=(crc&1) ? (crc>>1)^POLY : (crc>>1); |
343 u_char :3; |
|
344 u_char section_length_hi :4; |
|
345 #else |
|
346 u_char section_length_hi :4; |
|
347 u_char :3; |
|
348 u_char section_syntax_indicator :1; |
|
349 #endif |
|
350 u_char section_length_lo :8; |
|
351 u_char service_id_hi :8; |
|
352 u_char service_id_lo :8; |
|
353 #if BYTE_ORDER == BIG_ENDIAN |
|
354 u_char :2; |
|
355 u_char version_number :5; |
|
356 u_char current_next_indicator :1; |
|
357 #else |
|
358 u_char current_next_indicator :1; |
|
359 u_char version_number :5; |
|
360 u_char :2; |
|
361 #endif |
|
362 u_char section_number :8; |
|
363 u_char last_section_number :8; |
|
364 u_char content_id_hi_hi :8; |
|
365 u_char content_id_hi_lo :8; |
|
366 u_char content_id_lo_hi :8; |
|
367 u_char content_id_lo_lo :8; |
|
368 u_char duration_h :8; |
|
369 u_char duration_m :8; |
|
370 u_char duration_s :8; |
|
371 #if BYTE_ORDER == BIG_ENDIAN |
|
372 u_char :4; |
|
373 u_char descriptors_loop_length_hi :4; |
|
374 #else |
|
375 u_char descriptors_loop_length_hi :4; |
|
376 u_char :4; |
|
377 #endif |
|
378 u_char descriptors_loop_length_lo :8; |
|
379 }; |
|
380 |
|
381 class CIT : public NumberedSection { |
|
382 public: |
|
383 CIT(const unsigned char *data, bool doCopy=true) : NumberedSection(data, doCopy) {} |
|
384 CIT() {} |
|
385 int getContentId(void) const; |
|
386 time_t getDuration(void) const; |
|
387 DescriptorLoop eventDescriptors; |
|
388 protected: |
|
389 virtual void Parse(void); |
|
390 private: |
|
391 const cit *s; |
|
392 }; |
|
393 |
|
394 int CIT::getContentId(void) const { |
|
395 return (HILO(s->content_id_hi)<<16) | (HILO(s->content_id_lo)); |
|
396 } |
|
397 |
|
398 time_t CIT::getDuration(void) const { |
|
399 return DVBTime::getDuration(s->duration_h,s->duration_m,s->duration_s); |
|
400 } |
|
401 |
|
402 void CIT::Parse(void) { |
|
403 #if VDRVERSNUM >= 10343 |
|
404 int offset=0; |
|
405 #else |
|
406 unsigned int offset=0; |
|
407 #endif |
|
408 data.setPointerAndOffset<const cit>(s, offset); |
|
409 eventDescriptors.setData(data+offset,HILO(s->descriptors_loop_length)); |
|
410 } |
|
411 |
|
412 } // end of namespace |
|
413 |
|
414 // --- cDescrF2 ---------------------------------------------------------------- |
|
415 |
|
416 class cDescrF2 { |
|
417 private: |
|
418 SI::Descriptor *d; |
|
419 SI::CharArray data; |
|
420 int idx, loop, nloop, index; |
|
421 public: |
|
422 cDescrF2(SI::Descriptor *D); |
|
423 int TransportStreamId(void) { return data.TwoBytes(2); } |
|
424 int OrgNetworkId(void) { return data.TwoBytes(4); } |
|
425 int ServiceId(void) { return data.TwoBytes(6); } |
|
426 void Start(void); |
|
427 bool Next(void); |
|
428 time_t StartTime(void); |
|
429 int Index(void) { return index; } |
|
430 }; |
|
431 |
|
432 cDescrF2::cDescrF2(SI::Descriptor *D) |
|
433 { |
|
434 d=D; |
|
435 data=d->getData(); |
|
436 Start(); |
|
437 } |
|
438 |
|
439 void cDescrF2::Start(void) |
|
440 { |
|
441 idx=8; loop=0; nloop=-3; index=-1; |
|
442 } |
|
443 |
|
444 bool cDescrF2::Next(void) |
|
445 { |
|
446 loop+=3; |
|
447 if(loop>=nloop) { |
|
448 idx+=nloop+3; |
|
449 if(idx>=d->getLength()) return false; |
|
450 loop=0; nloop=data[idx+2]; |
|
451 } |
348 } |
452 index++; |
349 return crc&0xFFFF; |
453 return true; |
|
454 } |
|
455 |
|
456 time_t cDescrF2::StartTime(void) |
|
457 { |
|
458 int off=idx+3+loop; |
|
459 return SI::DVBTime::getTime(data[idx+0],data[idx+1],data[off+0],data[off+1],data[off+2]); |
|
460 } |
350 } |
461 |
351 |
462 // --- cFilterPremiereEpg ------------------------------------------------------ |
352 // --- cFilterPremiereEpg ------------------------------------------------------ |
|
353 |
|
354 #define STARTTIME_BIAS (20*60) |
463 |
355 |
464 class cFilterPremiereEpg : public cFilter { |
356 class cFilterPremiereEpg : public cFilter { |
465 private: |
357 private: |
466 int pmtpid, pmtidx, pmtnext; |
358 int pmtpid, pmtsid, pmtidx, pmtnext; |
467 // |
359 // |
468 void NextPmt(void); |
360 void NextPmt(void); |
469 protected: |
361 protected: |
470 virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length); |
362 virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length); |
471 public: |
363 public: |
532 } |
425 } |
533 } |
426 } |
534 } |
427 } |
535 else if(pmtpid>0 && Pid==pmtpid && Tid==SI::TableIdPMT && Source() && Transponder()) { |
428 else if(pmtpid>0 && Pid==pmtpid && Tid==SI::TableIdPMT && Source() && Transponder()) { |
536 SI::PMT pmt(Data,false); |
429 SI::PMT pmt(Data,false); |
537 if(pmt.CheckCRCAndParse()) { |
430 if(pmt.CheckCRCAndParse() && pmt.getServiceId()==pmtsid) { |
538 SI::PMT::Stream stream; |
431 SI::PMT::Stream stream; |
539 for(SI::Loop::Iterator it; pmt.streamLoop.getNext(stream,it); ) { |
432 for(SI::Loop::Iterator it; pmt.streamLoop.getNext(stream,it); ) { |
540 if(stream.getStreamType()==0x05) { |
433 if(stream.getStreamType()==0x05) { |
541 SI::CharArray data=stream.getData(); |
434 SI::CharArray data=stream.getData(); |
542 if((data[1]&0xE0)==0xE0 && (data[3]&0xF0)==0xF0) { |
435 if((data[1]&0xE0)==0xE0 && (data[3]&0xF0)==0xF0) { |
573 } |
466 } |
574 NextPmt(); pmtnext=0; |
467 NextPmt(); pmtnext=0; |
575 } |
468 } |
576 } |
469 } |
577 else if(Tid==0xA0 && Source()) { |
470 else if(Tid==0xA0 && Source()) { |
578 SI::CIT cit(Data,false); |
471 SI::PremiereCIT cit(Data,false); |
579 if(cit.CheckCRCAndParse()) { |
472 if(cit.CheckCRCAndParse()) { |
580 cSchedulesLock SchedulesLock(true,10); |
473 cSchedulesLock SchedulesLock(true,10); |
581 cSchedules *Schedules=(cSchedules *)cSchedules::Schedules(SchedulesLock); |
474 cSchedules *Schedules=(cSchedules *)cSchedules::Schedules(SchedulesLock); |
582 if(Schedules) { |
475 if(Schedules) { |
583 int nCount=0; |
476 int nCount=0; |
584 time_t firstTime=0; |
|
585 SI::Descriptor *d; |
|
586 int LanguagePreferenceShort=-1; |
|
587 int LanguagePreferenceExt=-1; |
|
588 bool UseExtendedEventDescriptor=false; |
|
589 SI::ExtendedEventDescriptors *ExtendedEventDescriptors=0; |
477 SI::ExtendedEventDescriptors *ExtendedEventDescriptors=0; |
590 SI::ShortEventDescriptor *ShortEventDescriptor=0; |
478 SI::ShortEventDescriptor *ShortEventDescriptor=0; |
591 char *order=0, *rating=0; |
479 char *order=0, *rating=0; |
|
480 { |
|
481 time_t firstTime=0; |
|
482 SI::Descriptor *d; |
|
483 bool UseExtendedEventDescriptor=false; |
|
484 int LanguagePreferenceShort=-1; |
|
485 int LanguagePreferenceExt=-1; |
592 for(SI::Loop::Iterator it; (d=cit.eventDescriptors.getNext(it)); ) { |
486 for(SI::Loop::Iterator it; (d=cit.eventDescriptors.getNext(it)); ) { |
593 switch(d->getDescriptorTag()) { |
487 switch(d->getDescriptorTag()) { |
594 case 0xF0: // order information |
488 case 0xF0: // order information |
595 if(SetupPE.OrderInfo) { |
489 if(SetupPE.OrderInfo) { |
596 static const char *text[] = { |
490 static const char *text[] = { |
621 int l=data[0]; |
515 int l=data[0]; |
622 if(l>0) p+=snprintf(&buff[p],sizeof(buff)-p," (%.*s)",l,&data[1]); |
516 if(l>0) p+=snprintf(&buff[p],sizeof(buff)-p," (%.*s)",l,&data[1]); |
623 if(p>0) rating=strdup(buff); |
517 if(p>0) rating=strdup(buff); |
624 } |
518 } |
625 break; |
519 break; |
626 case 0xF2: // transmisions |
520 case SI::PremiereContentTransmissionDescriptorTag: |
627 if(nCount>=0) { |
521 if(nCount>=0) { |
|
522 SI::PremiereContentTransmissionDescriptor *pct=(SI::PremiereContentTransmissionDescriptor *)d; |
628 nCount++; |
523 nCount++; |
629 cDescrF2 f2(d); |
524 SI::PremiereContentTransmissionDescriptor::StartDayEntry sd; |
630 if(f2.Next()) { |
525 SI::Loop::Iterator it; |
631 if(nCount==1) firstTime=f2.StartTime(); |
526 if(pct->startDayLoop.getNext(sd,it)) { |
632 else { |
527 SI::PremiereContentTransmissionDescriptor::StartDayEntry::StartTimeEntry st; |
633 time_t time=f2.StartTime(); |
528 SI::Loop::Iterator it2; |
634 if(firstTime<time-5*50 || firstTime>time+5*60) |
529 if(sd.startTimeLoop.getNext(st,it2)) { |
|
530 time_t StartTime=st.getStartTime(sd.getMJD()); |
|
531 if(nCount==1) firstTime=StartTime; |
|
532 else if(firstTime<StartTime-5*50 || firstTime>StartTime+5*60) |
635 nCount=-1; |
533 nCount=-1; |
636 } |
534 } |
637 } |
535 } |
638 } |
536 } |
639 break; |
537 break; |
640 case SI::ExtendedEventDescriptorTag: |
538 case SI::ExtendedEventDescriptorTag: |
641 { |
539 { |
642 SI::ExtendedEventDescriptor *eed=(SI::ExtendedEventDescriptor *)d; |
540 SI::ExtendedEventDescriptor *eed=(SI::ExtendedEventDescriptor *)d; |
643 #if VDRVERSNUM < 10332 |
|
644 if(I18nIsPreferredLanguage(Setup.EPGLanguages,I18nLanguageIndex(eed->languageCode), LanguagePreferenceExt) || !ExtendedEventDescriptors) { |
|
645 #else |
|
646 if(I18nIsPreferredLanguage(Setup.EPGLanguages,eed->languageCode, LanguagePreferenceExt) || !ExtendedEventDescriptors) { |
541 if(I18nIsPreferredLanguage(Setup.EPGLanguages,eed->languageCode, LanguagePreferenceExt) || !ExtendedEventDescriptors) { |
647 #endif |
|
648 delete ExtendedEventDescriptors; |
542 delete ExtendedEventDescriptors; |
649 ExtendedEventDescriptors=new SI::ExtendedEventDescriptors; |
543 ExtendedEventDescriptors=new SI::ExtendedEventDescriptors; |
650 UseExtendedEventDescriptor=true; |
544 UseExtendedEventDescriptor=true; |
651 } |
545 } |
652 if(UseExtendedEventDescriptor) { |
546 if(UseExtendedEventDescriptor) { |
674 default: |
564 default: |
675 break; |
565 break; |
676 } |
566 } |
677 delete d; |
567 delete d; |
678 } |
568 } |
679 |
569 } |
|
570 |
|
571 { |
680 bool Modified=false; |
572 bool Modified=false; |
681 int optCount=0; |
573 int optCount=0; |
682 for(SI::Loop::Iterator it; (d=cit.eventDescriptors.getNext(it)); ) { |
574 unsigned int crc[3]; |
683 if(d->getDescriptorTag()==0xF2) { |
575 crc[0]=cit.getContentId(); |
684 optCount++; |
576 SI::PremiereContentTransmissionDescriptor *pct; |
685 |
577 for(SI::Loop::Iterator it; (pct=(SI::PremiereContentTransmissionDescriptor *)cit.eventDescriptors.getNext(it,SI::PremiereContentTransmissionDescriptorTag)); ) { |
686 cDescrF2 f2(d); |
578 tChannelID channelID(Source(),pct->getOriginalNetworkId(),pct->getTransportStreamId(),pct->getServiceId()); |
687 tChannelID channelID(Source(),f2.OrgNetworkId(),f2.TransportStreamId(),f2.ServiceId()); |
579 cChannel *channel=Channels.GetByChannelID(channelID,true); |
688 cChannel *channel=Channels.GetByChannelID(channelID,true); |
580 if(!channel) continue; |
689 if(!channel) continue; |
581 |
690 |
582 cSchedule *pSchedule=(cSchedule *)Schedules->GetSchedule(channelID); |
691 cSchedule *pSchedule=(cSchedule *)Schedules->GetSchedule(channelID); |
583 if(!pSchedule) { |
692 if(!pSchedule) { |
584 pSchedule=new cSchedule(channelID); |
693 pSchedule=new cSchedule(channelID); |
585 Schedules->Add(pSchedule); |
694 Schedules->Add(pSchedule); |
586 } |
695 } |
587 |
696 |
588 optCount++; |
697 for(f2.Start(); f2.Next();) { |
589 SI::PremiereContentTransmissionDescriptor::StartDayEntry sd; |
698 u_int16_t EventId=(cit.getContentId()<<4) | f2.Index(); |
590 int index=0; |
699 time_t StartTime=f2.StartTime(); |
591 for(SI::Loop::Iterator it; pct->startDayLoop.getNext(sd,it); ) { |
700 |
592 int mjd=sd.getMJD(); |
|
593 SI::PremiereContentTransmissionDescriptor::StartDayEntry::StartTimeEntry st; |
|
594 for(SI::Loop::Iterator it2; sd.startTimeLoop.getNext(st,it2); ) { |
|
595 time_t StartTime=st.getStartTime(mjd); |
|
596 time_t EndTime=StartTime+cit.getDuration(); |
|
597 int runningStatus=(StartTime<now && now<EndTime) ? SI::RunningStatusRunning : ((StartTime-30<now && now<StartTime) ? SI::RunningStatusStartsInAFewSeconds : SI::RunningStatusNotRunning); |
701 bool isOpt=false; |
598 bool isOpt=false; |
702 if(f2.Index()==0 && nCount>1) isOpt=true; |
599 if(index++==0 && nCount>1) isOpt=true; |
703 |
600 crc[1]=isOpt ? optCount : 0; |
704 d2(printf("ch=%s id=%04x/%08x %d opt=%d/%d st=%s ",*channelID.ToString(),EventId,cit.getContentId(),f2.Index(),isOpt,optCount,stripspace(ctime(&StartTime)))) |
601 crc[2]=StartTime / STARTTIME_BIAS; |
705 if(StartTime+cit.getDuration()+Setup.EPGLinger*60<time(0)) { |
602 tEventID EventId=((('P'<<8)|'W')<<16) | crc16(0,(unsigned char *)crc,sizeof(crc)); |
|
603 |
|
604 d2(printf("%s R%d %04x/%.4x %d %d/%d %s +%d ",*channelID.ToString(),runningStatus,EventId&0xFFFF,cit.getContentId(),index,isOpt,optCount,stripspace(ctime(&StartTime)),(int)cit.getDuration()/60)) |
|
605 if(EndTime+Setup.EPGLinger*60<now) { |
706 d2(printf("(old)\n")) |
606 d2(printf("(old)\n")) |
707 continue; |
607 continue; |
708 } |
608 } |
709 |
609 |
710 bool newEvent=false; |
610 bool newEvent=false; |
711 cEvent *pEvent=(cEvent *)pSchedule->GetEvent(EventId,StartTime); |
611 cEvent *pEvent=(cEvent *)pSchedule->GetEvent(EventId,-1); |
712 if(!pEvent) { |
612 if(!pEvent) { |
713 d2(printf("(new)\n")) |
613 d2(printf("(new)\n")) |
714 #if VDRVERSNUM >= 10325 |
614 pEvent=new cEvent(EventId); |
715 pEvent=new cEvent(EventId); |
615 if(!pEvent) continue; |
716 #else |
616 newEvent=true; |
717 pEvent=new cEvent(channelID,EventId); |
617 } |
718 #endif |
|
719 if(!pEvent) continue; |
|
720 newEvent=true; |
|
721 } |
|
722 else { |
618 else { |
723 d2(printf("(upd)\n")) |
619 d2(printf("(upd)\n")) |
724 pEvent->SetSeen(); |
620 pEvent->SetSeen(); |
725 if(pEvent->TableID()==0x00) continue; |
621 if(pEvent->TableID()==0x00 || pEvent->Version()==cit.getVersionNumber()) { |
726 if(Tid==pEvent->TableID() && pEvent->Version()==cit.getVersionNumber()) continue; |
622 if(pEvent->RunningStatus()!=runningStatus) |
727 } |
623 pSchedule->SetRunningStatus(pEvent,runningStatus,channel); |
|
624 continue; |
|
625 } |
|
626 } |
728 pEvent->SetEventID(EventId); |
627 pEvent->SetEventID(EventId); |
729 pEvent->SetTableID(Tid); |
628 pEvent->SetTableID(Tid); |
730 pEvent->SetVersion(cit.getVersionNumber()); |
629 pEvent->SetVersion(cit.getVersionNumber()); |
731 pEvent->SetStartTime(StartTime); |
630 pEvent->SetStartTime(StartTime); |
732 pEvent->SetDuration(cit.getDuration()); |
631 pEvent->SetDuration(cit.getDuration()); |
739 snprintf(buffer2,sizeof(buffer2),optPats[SetupPE.OptPat],buffer,optCount); |
638 snprintf(buffer2,sizeof(buffer2),optPats[SetupPE.OptPat],buffer,optCount); |
740 pEvent->SetTitle(buffer2); |
639 pEvent->SetTitle(buffer2); |
741 } |
640 } |
742 else |
641 else |
743 pEvent->SetTitle(buffer); |
642 pEvent->SetTitle(buffer); |
|
643 d2(printf("title: %s\n",pEvent->Title())) |
744 pEvent->SetShortText(ShortEventDescriptor->text.getText(buffer,sizeof(buffer))); |
644 pEvent->SetShortText(ShortEventDescriptor->text.getText(buffer,sizeof(buffer))); |
745 } |
645 } |
746 if(ExtendedEventDescriptors) { |
646 if(ExtendedEventDescriptors) { |
747 char buffer[ExtendedEventDescriptors->getMaximumTextLength(": ")+1]; |
647 char buffer[ExtendedEventDescriptors->getMaximumTextLength(": ")+1]; |
748 pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer,sizeof(buffer),": ")); |
648 pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer,sizeof(buffer),": ")); |
758 if(order) strcat(buffer,order); |
658 if(order) strcat(buffer,order); |
759 pEvent->SetDescription(buffer); |
659 pEvent->SetDescription(buffer); |
760 } |
660 } |
761 |
661 |
762 if(newEvent) pSchedule->AddEvent(pEvent); |
662 if(newEvent) pSchedule->AddEvent(pEvent); |
763 #if VDRVERSNUM >= 10318 |
|
764 pEvent->SetComponents(NULL); |
663 pEvent->SetComponents(NULL); |
765 #endif |
|
766 pEvent->FixEpgBugs(); |
664 pEvent->FixEpgBugs(); |
|
665 if(pEvent->RunningStatus()!=runningStatus) |
|
666 pSchedule->SetRunningStatus(pEvent,runningStatus,channel); |
|
667 pSchedule->DropOutdated(StartTime,EndTime,Tid,cit.getVersionNumber()); |
767 Modified=true; |
668 Modified=true; |
768 } |
669 } |
769 if(Modified) { |
|
770 pSchedule->Sort(); |
|
771 Schedules->SetModified(pSchedule); |
|
772 } |
|
773 } |
670 } |
774 delete d; |
671 if(Modified) { |
|
672 pSchedule->Sort(); |
|
673 Schedules->SetModified(pSchedule); |
|
674 } |
|
675 delete pct; |
775 } |
676 } |
|
677 } |
776 delete ExtendedEventDescriptors; |
678 delete ExtendedEventDescriptors; |
777 delete ShortEventDescriptor; |
679 delete ShortEventDescriptor; |
778 free(order); |
680 free(order); |
779 free(rating); |
681 free(rating); |
780 } |
682 } |