/** @brief, tell if the eit have a newer version than the one recorded actually * In the EIT pid there is a field to say if the EIT was updated * This function check if it has changed (in order to rewrite the eit only once) * Note this function can give false positive since it doesn't check the CRC32 * *@param rewrite_vars the parameters for eit rewriting *@param buf : the received buffer */ int eit_need_update(rewrite_parameters_t *rewrite_vars, unsigned char *buf, int raw) { //Get the SID of the new EIT //loop over the stored EIT //if found and version > : need update //if not found need update eit_t *eit; //if it's a raw TS packet we search for the beginning if(raw) eit=(eit_t*)(get_ts_begin(buf)); else eit=(eit_t*)(buf); eit_packet_t *eit_packet; if(eit) //It's the beginning of a new packet { eit_packet=eit_find_by_tsid(rewrite_vars,HILO(eit->service_id)); if(eit_packet==NULL) { log_message( log_module, MSG_DETAIL,"EIT sid %d not stored, need update.", HILO(eit->service_id)); return 1; } // if((eit->table_id==0x4E)||((eit->table_id&0xF0)==0x50)) //if((eit->table_id&0xF0)==0x50) // log_message( log_module, MSG_DETAIL,"EIT table id 0x%x schedule not supported yet.",eit->table_id); if(eit->table_id==0x4E) // 0x4E event_information_section - actual_transport_stream, present/following // 0x50 to 0x5F event_information_section - actual_transport_stream, schedule //TODO : deal with all these table id_ which could have different version number for the same service { /*current_next_indicator – A 1-bit indicator, which when set to '1' indicates that the table sent is currently applicable.*/ if(eit->current_next_indicator == 0) return 0; if(eit->version_number!=eit_packet->version) { log_message( log_module, MSG_DETAIL,"EIT sid %d need update. stored version : %d, new: %d", HILO(eit->service_id), eit_packet->version, eit->version_number); return 1; } if(!eit_packet->sections_stored[eit->section_number] ) { log_message( log_module, MSG_DETAIL,"EIT sid %d new section %d version : %d", HILO(eit->service_id), eit->section_number, eit_packet->version, eit->version_number); return 1; } } } return 0; }
/** @brief This function is called when a new EIT packet for a channel is there and we asked for rewrite * This function copy the rewritten EIT to the buffer. And checks if the EIT was changed so the rewritten version have to be updated */ void eit_rewrite_new_channel_packet(unsigned char *ts_packet, rewrite_parameters_t *rewrite_vars, mumudvb_channel_t *channel, multicast_parameters_t *multicast_vars, unicast_parameters_t *unicast_vars, mumudvb_chan_and_pids_t *chan_and_pids,fds_t *fds) { int i=0; //If payload unit start indicator , we will send all the present EIT for this service, otherwise nothing //We generate the TS packets on by one, and for each one, we check if we have to send //Otherwise we skip the packet //If payload unit start indicator, we will send all the present EIT for this service, otherwise nothing //just a matter to send an EIT per service only if an EIT is starting in the stream, //the better way would be an EIT starting and corresponding to this SID but, it's more difficult to get this information ts_header_t *ts_header=(ts_header_t *)ts_packet; if(!(ts_header->payload_unit_start_indicator)) return; //If there is an EIT PID sorted for this channel eit_packet_t *eit_pkt; eit_pkt=eit_find_by_tsid(rewrite_vars,channel->service_id); if((eit_pkt==NULL)||(!eit_pkt->full_eit_ok)) return; //search for the next section we can send //just in case we have a new version with less sections channel->eit_section_to_send=channel->eit_section_to_send % (eit_pkt->last_section_number+1); //the real search while((i<=eit_pkt->last_section_number)&&(!eit_pkt->sections_stored[channel->eit_section_to_send])) { channel->eit_section_to_send++; channel->eit_section_to_send=channel->eit_section_to_send % (eit_pkt->last_section_number+1); i++; } //if nothing found if(!eit_pkt->sections_stored[channel->eit_section_to_send]) return; //bye //ok we send this! mumudvb_ts_packet_t *pkt_to_send; int data_left_to_send,sent; unsigned char send_buf[TS_PACKET_SIZE]; ts_header=(ts_header_t *)send_buf; pkt_to_send=eit_pkt->full_eit_sections[channel->eit_section_to_send]; data_left_to_send=pkt_to_send->full_buffer_len; sent=0; //log_message(log_module,MSG_FLOOD,"Sending EIT to channel %s (sid %d) section %d data_len %d", // channel->name, // channel->service_id, // channel->eit_section_to_send, // data_left_to_send); while(data_left_to_send>0) { int header_len; memset(send_buf,0,TS_PACKET_SIZE*sizeof(unsigned char)); //we fill the TS header ts_header->sync_byte=0x47; if(sent==0) { ts_header->payload_unit_start_indicator=1; header_len=TS_HEADER_LEN; //includes the pointer field } else header_len=TS_HEADER_LEN-1; //the packet has started, we don't count the pointer field ts_header->pid_lo=18; //specify the PID ts_header->adaptation_field_control=1; //always one ts_header->continuity_counter=channel->eit_cc; //continuity counter channel->eit_cc++; channel->eit_cc= channel->eit_cc % 16; //We send the data //plus one because of pointer field if(data_left_to_send>(TS_PACKET_SIZE-header_len)) { memcpy(send_buf+header_len,pkt_to_send->data_full+sent,(TS_PACKET_SIZE-header_len)*sizeof(unsigned char)); sent+=(TS_PACKET_SIZE-header_len); data_left_to_send-=(TS_PACKET_SIZE-header_len); } else { memcpy(send_buf+header_len,pkt_to_send->data_full+sent,data_left_to_send*sizeof(unsigned char)); sent+=data_left_to_send; //Padding with OxFF memset(send_buf+header_len+data_left_to_send, 0xFF, (TS_PACKET_SIZE-(header_len+data_left_to_send))*sizeof(unsigned char)); data_left_to_send=0; } //NOW we really send the data over the network // we fill the channel buffer memcpy(channel->buf + channel->nb_bytes, send_buf, TS_PACKET_SIZE*sizeof(unsigned char)); channel->nb_bytes += TS_PACKET_SIZE; //The buffer is full, we send it if ((!multicast_vars->rtp_header && ((channel->nb_bytes + TS_PACKET_SIZE) > MAX_UDP_SIZE)) ||(multicast_vars->rtp_header && ((channel->nb_bytes + RTP_HEADER_LEN + TS_PACKET_SIZE) > MAX_UDP_SIZE))) { uint64_t now_time; now_time=get_time(); send_func(channel, &now_time, unicast_vars, multicast_vars, chan_and_pids, fds); } } //We update which section we want to send channel->eit_section_to_send++; channel->eit_section_to_send=channel->eit_section_to_send % (eit_pkt->last_section_number+1); //TODO increase table id if we reached the end }
/** @brief This function is called when a new EIT packet for a channel is there and we asked for rewrite * This function copy the rewritten EIT to the buffer. And checks if the EIT was changed so the rewritten version have to be updated */ void eit_rewrite_new_channel_packet(unsigned char *ts_packet, rewrite_parameters_t *rewrite_vars, mumudvb_channel_t *channel, multi_p_t *multi_p, unicast_parameters_t *unicast_vars, void *scam_vars_v,fds_t *fds) { int i=0; //If payload unit start indicator , we will send all the present EIT for this service, otherwise nothing //We generate the TS packets on by one, and for each one, we check if we have to send //Otherwise we skip the packet //If payload unit start indicator, we will send all the present EIT for this service, otherwise nothing //just a matter to send an EIT per service only if an EIT is starting in the stream, //the better way would be an EIT starting and corresponding to this SID but, it's more difficult to get this information ts_header_t *ts_header=(ts_header_t *)ts_packet; if(!(ts_header->payload_unit_start_indicator)) return; //If there is an EIT PID sorted for this channel eit_packet_t *eit_pkt; uint8_t section_start; //we check we start with a valid section if((channel->eit_table_id_to_send!=0x4E)&&((channel->eit_table_id_to_send&0xF0)!=0x50)) channel->eit_table_id_to_send=0x4E; //We search for the EIT packet to send, if not found we loop on the sections section_start=channel->eit_table_id_to_send; do { eit_pkt=eit_find_by_tsid(rewrite_vars,channel->service_id,channel->eit_table_id_to_send); //loop over the table id if((eit_pkt==NULL)||(!eit_pkt->full_eit_ok)) { channel->eit_table_id_to_send=eit_next_table_id(channel->eit_table_id_to_send); eit_pkt=NULL; } } while((eit_pkt==NULL)&&(channel->eit_table_id_to_send!=section_start)); //we go away if there is no EIT packet to send if(eit_pkt==NULL) return; //search for the next section we can send //just in case we have a new version with less sections channel->eit_section_to_send=channel->eit_section_to_send % (eit_pkt->last_section_number+1); //the real search while((i<=eit_pkt->last_section_number)&&(!eit_pkt->sections_stored[channel->eit_section_to_send])) { channel->eit_section_to_send++; channel->eit_section_to_send=channel->eit_section_to_send % (eit_pkt->last_section_number+1); i++; } //if nothing found if(!eit_pkt->sections_stored[channel->eit_section_to_send]) { //bye (we should be here BTW) but we avoid to stay on invalid packet by going to next section channel->eit_table_id_to_send=eit_next_table_id(channel->eit_table_id_to_send); return; } //ok we send this! mumudvb_ts_packet_t *pkt_to_send; int data_left_to_send,sent; unsigned char send_buf[TS_PACKET_SIZE]; ts_header=(ts_header_t *)send_buf; pkt_to_send=eit_pkt->full_eit_sections[channel->eit_section_to_send]; data_left_to_send=pkt_to_send->len_full; sent=0; //log_message(log_module,MSG_FLOOD,"Sending EIT to channel %s (sid %d) section %d table_id 0x%02x data_len %d", // channel->name, // channel->service_id, // channel->eit_section_to_send, // channel->eit_table_id_to_send, // data_left_to_send); while(data_left_to_send>0) { int header_len; memset(send_buf,0,TS_PACKET_SIZE*sizeof(unsigned char)); //we fill the TS header ts_header->sync_byte=0x47; if(sent==0) { ts_header->payload_unit_start_indicator=1; header_len=TS_HEADER_LEN; //includes the pointer field } else header_len=TS_HEADER_LEN-1; //the packet has started, we don't count the pointer field ts_header->pid_lo=18; //specify the PID ts_header->adaptation_field_control=1; //always one ts_header->continuity_counter=channel->eit_cc; //continuity counter channel->eit_cc++; channel->eit_cc= channel->eit_cc % 16; //We send the data //plus one because of pointer field if(data_left_to_send>=(TS_PACKET_SIZE-header_len)) { memcpy(send_buf+header_len,pkt_to_send->data_full+sent,(TS_PACKET_SIZE-header_len)*sizeof(unsigned char)); sent+=(TS_PACKET_SIZE-header_len); data_left_to_send-=(TS_PACKET_SIZE-header_len); } else { memcpy(send_buf+header_len,pkt_to_send->data_full+sent,data_left_to_send*sizeof(unsigned char)); sent+=data_left_to_send; //Padding with OxFF memset(send_buf+header_len+data_left_to_send, 0xFF, (TS_PACKET_SIZE-(header_len+data_left_to_send))*sizeof(unsigned char)); data_left_to_send=0; } //NOW we fill the channel buffer for sending buffer_func(channel, send_buf, unicast_vars, multi_p, scam_vars_v, fds); } //We update which section we want to send channel->eit_section_to_send++; channel->eit_section_to_send=channel->eit_section_to_send % (eit_pkt->last_section_number+1); //if we reached the end, we go to the next table_id if(channel->eit_section_to_send==0) channel->eit_table_id_to_send=eit_next_table_id(channel->eit_table_id_to_send); }