Created
February 20, 2012 09:40
-
-
Save kimson/1868591 to your computer and use it in GitHub Desktop.
mpeg2-ts : display a SDT(Service Description Table)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <errno.h> | |
#define PID_SDT 0x0011 | |
typedef struct ServiceDescriptorStructure { | |
unsigned char descriptor_tag; | |
unsigned char descriptor_length; | |
unsigned char service_type; | |
unsigned char service_provider_name_length; | |
unsigned char *service_provider_name; | |
unsigned char service_name_length; | |
unsigned char *service_name; | |
struct ServiceDescriptorStructure *next; | |
}ServiceDescriptor; | |
typedef struct LoopSectionStructure { | |
unsigned short int service_id; | |
char reserved_future_use; | |
char eit_user_defined_flags; | |
char eit_schedule_flag; | |
char eit_present_following_flag; | |
unsigned char running_status; | |
char free_ca_mode; | |
unsigned short int descriptors_loop_length; | |
ServiceDescriptor *descriptor; | |
struct LoopSectionStructure *next; | |
}LoopSection; | |
typedef struct { | |
char table_id; | |
char section_syntax_indicator; | |
char reserved_future_use; | |
char reserved; | |
unsigned short int section_length; | |
unsigned short int transport_stream_id; | |
char reserved2; | |
unsigned char version_number; | |
char current_next_indicator; | |
unsigned char section_number; | |
unsigned char last_section_number; | |
unsigned short int original_network_id; | |
char reserved_future_use2; | |
LoopSection *loop; | |
char crc[4]; | |
}ServiceDescriptionTable; | |
unsigned short int getSectionLength(unsigned char*); | |
unsigned short int getPid(unsigned char*); | |
void printPacket(unsigned char*); | |
unsigned short int getTransportStreamId(unsigned char*); | |
unsigned short int getOriginalNetworkId(unsigned char*); | |
unsigned short int getServiceId(unsigned char*); | |
unsigned short int getDescriptorsLoopLength(unsigned char*); | |
void printSdtStruct(); | |
void printSdt(ServiceDescriptionTable*); | |
char* toB(unsigned char, int, char*); | |
void *MyMalloc(size_t); | |
LoopSection *loop_tail = NULL; | |
ServiceDescriptor *sd_tail = NULL; | |
int main(int argc, char* argv[]) | |
{ | |
int byte_count, adaptation_field_byte, payload_start_index, section_length, service_id, descriptor_length; | |
int loop_start_index, service_p_length, service_n_length, chname_length; | |
int i,j,k; | |
unsigned short int pid; | |
unsigned char *buf, tmp; | |
char *inputfile; | |
FILE *fp; | |
ServiceDescriptionTable *sdt; | |
LoopSection *loop; | |
ServiceDescriptor *sd; | |
if(argc > 3){ | |
printf("Usage: ./tsinfo -v <input filename>\n"); | |
exit(0); | |
} | |
if(argc == 3 && strcmp("-v", argv[1])==0){ | |
printSdtStruct(); | |
inputfile = argv[2]; | |
}else{ | |
inputfile = argv[1]; | |
} | |
if((fp = fopen(inputfile, "r")) == NULL){ | |
perror("Input file : "); | |
return 1; | |
} | |
buf = (unsigned char*)MyMalloc(sizeof(char)*188); | |
sdt = (ServiceDescriptionTable*)MyMalloc(sizeof(ServiceDescriptionTable)); | |
sdt->loop = NULL; | |
byte_count = 0; | |
j = 0; | |
while(fread(buf, sizeof(char), 188, fp) != 0){ | |
pid = getPid(buf); | |
//PID == 0x0011 | |
if(pid == PID_SDT){ | |
//adaptation fieldのチェック | |
if((buf[3] | 0xcf) == 0xff){ //adaptation field ctl = '11'. both. | |
adaptation_field_byte = (int)buf[5]; | |
//adaptation field ctl = '01'. only payload. | |
}else if((buf[3] | 0xcf) == 0xdf){ | |
adaptation_field_byte = 0; | |
//adaptation field ctl = '10' only adaptation field. | |
}else if((buf[3] | 0xcf) == 0xef){ | |
adaptation_field_byte = -1; | |
//adaptation field ctl = '00'. undefined. | |
}else{ | |
adaptation_field_byte = -2; | |
} | |
//adaptation fieldは無視 | |
if(adaptation_field_byte < 0) continue; | |
payload_start_index = 5 + adaptation_field_byte; | |
sdt->table_id = buf[payload_start_index]; | |
sdt->section_syntax_indicator = buf[payload_start_index + 1] >> 7; | |
sdt->reserved_future_use = (buf[payload_start_index + 1] >> 6) & 0x01; | |
sdt->reserved = (buf[payload_start_index + 1] >> 4) & 0x03; | |
sdt->section_length = getSectionLength(buf + payload_start_index); | |
sdt->transport_stream_id = getTransportStreamId(buf + payload_start_index); | |
sdt->reserved2 = buf[payload_start_index + 5] >> 6; | |
sdt->version_number = (buf[payload_start_index + 5] >> 1) & 0x1f; | |
sdt->current_next_indicator = buf[payload_start_index + 5] & 0x01; | |
sdt->section_number = buf[payload_start_index + 6]; | |
sdt->last_section_number = buf[payload_start_index + 7]; | |
sdt->original_network_id = getOriginalNetworkId(buf + payload_start_index); | |
sdt->reserved_future_use2 = buf[payload_start_index + 10]; | |
i = 0; | |
while(i < sdt->section_length - 12){ | |
loop_start_index = payload_start_index + 11 + i; | |
loop = (LoopSection*)MyMalloc(sizeof(LoopSection)); | |
loop->next = NULL; | |
if(loop_tail == NULL){ | |
sdt->loop = loop; | |
}else{ | |
loop_tail->next = loop; | |
} | |
loop_tail = loop; | |
loop->service_id = getServiceId(buf + loop_start_index); | |
loop->reserved_future_use = buf[loop_start_index + 2] >> 5; | |
loop->eit_user_defined_flags = (buf[loop_start_index + 2] >> 2) & 0x07; | |
loop->eit_schedule_flag = (buf[loop_start_index + 2] >> 1) & 0x01; | |
loop->eit_present_following_flag = buf[loop_start_index + 2] & 0x01; | |
loop->running_status = buf[loop_start_index + 3] >> 5; | |
loop->free_ca_mode = (buf[loop_start_index + 3] >> 4) & 0x01; | |
loop->descriptors_loop_length = getDescriptorsLoopLength(buf + loop_start_index); | |
j = 0; | |
while(j < loop->descriptors_loop_length){ | |
sd = (ServiceDescriptor*)MyMalloc(sizeof(ServiceDescriptor)); | |
sd->next = NULL; | |
if(sd_tail == NULL){ | |
loop->descriptor = sd; | |
}else{ | |
sd_tail->next = sd; | |
} | |
sd_tail = sd; | |
sd->descriptor_tag = buf[loop_start_index + 5 + j]; | |
switch(sd->descriptor_tag) | |
{ | |
case 0x48 : | |
sd->descriptor_length = buf[loop_start_index + 5 + j + 1]; | |
sd->service_type = buf[loop_start_index + 5 + j + 2]; | |
sd->service_provider_name_length = buf[loop_start_index + 5 + j + 3]; | |
if(sd->service_provider_name_length > 0){ | |
sd->service_provider_name = (char*)MyMalloc(sizeof(char)*(size_t)sd->service_provider_name_length); | |
for(k=0;k<sd->service_provider_name_length;k++){ | |
sd->service_provider_name[k] = buf[loop_start_index + 5 + j + 4 + k]; | |
} | |
}else{ | |
sd->service_provider_name = NULL; | |
} | |
sd->service_name_length = buf[loop_start_index + 5 + j + 4 + sd->service_provider_name_length]; | |
if(sd->service_name_length > 0){ | |
sd->service_name = (char*)MyMalloc(sizeof(char)*(size_t)sd->service_name_length); | |
for(k=0;k<sd->service_name_length;k++){ | |
sd->service_name[k] = buf[loop_start_index + 5 + j + 4 + sd->service_provider_name_length + k]; | |
} | |
}else{ | |
sd->service_name = NULL; | |
} | |
j += 5 + sd->service_provider_name_length + sd->service_name_length; | |
break; | |
//case 0xCF : | |
// break; | |
default : | |
j += loop->descriptors_loop_length; | |
break; | |
} | |
} | |
i += (5 + loop->descriptors_loop_length); | |
sd_tail = NULL; | |
} | |
printSdt(sdt); | |
printPacket(buf); | |
freeSdtLoop(sdt->loop); | |
loop_tail = NULL; | |
} | |
if(k==1){ | |
printf("\n\n"); | |
} | |
byte_count += 188; | |
} | |
free(buf); | |
fclose(fp); | |
return 0; | |
} | |
unsigned short int getPid(unsigned char* buf) | |
{ | |
int pid = 0x0000; | |
pid = pid | (buf[1] & 0x1f); | |
pid = pid << 8; | |
pid = pid | buf[2]; | |
return pid; | |
} | |
//payloadの先頭アドレス | |
unsigned short int getSectionLength(unsigned char* buf) | |
{ | |
unsigned short int section_length = 0x00; | |
section_length |= buf[1] & 0x0f; | |
section_length = section_length << 8; | |
section_length |= buf[2]; | |
return section_length; | |
} | |
//payloadの先頭アドレス | |
unsigned short int getTransportStreamId(unsigned char* buf) | |
{ | |
unsigned short int transport_stream_id = 0x00; | |
transport_stream_id |= buf[3]; | |
transport_stream_id = transport_stream_id << 8; | |
transport_stream_id |= buf[4]; | |
return transport_stream_id; | |
} | |
//payloadの先頭アドレス | |
unsigned short int getOriginalNetworkId(unsigned char* buf) | |
{ | |
unsigned short int original_network_id = 0x0000; | |
original_network_id |= buf[8]; | |
original_network_id = original_network_id << 8; | |
original_network_id |= buf[9]; | |
return original_network_id; | |
} | |
//payload内のloopの先頭アドレス | |
unsigned short int getServiceId(unsigned char* buf) | |
{ | |
unsigned short int service_id = 0x0000; | |
service_id |= buf[0]; | |
service_id = service_id << 8; | |
service_id |= buf[1]; | |
return service_id; | |
} | |
//payload内のloopの先頭アドレス | |
unsigned short int getDescriptorsLoopLength(unsigned char* buf) | |
{ | |
unsigned short int descriptor_length = 0x0000; | |
descriptor_length |= buf[3] & 0x0f; | |
descriptor_length = descriptor_length << 8; | |
descriptor_length |= buf[4]; | |
return descriptor_length; | |
} | |
void printSdtStruct() | |
{ | |
printf("SDT table structure \n \ | |
===================================================== \n \ | |
service_description_section(){ \n \ | |
table_id(8) \n \ | |
section_syntax_indicator(1) \n \ | |
reserved_future_use(1) \n \ | |
reserved(2) \n \ | |
section_length(12) \n \ | |
transport_stream_id(16) \n \ | |
reserved(2) \n \ | |
version_number(5) \n \ | |
current_next_indicator(1) \n \ | |
section_number(8) \n \ | |
last_section_number(8) \n \ | |
original_network_id(16) \n \ | |
reserved_future_use(8) \n \ | |
for (i=0;i<N;i++){ \n \ | |
service_id(16) \n \ | |
reserved_future_use(3) \n \ | |
EIT_user_defined_flags(3) \n \ | |
EIT_schedule_flag(1) \n \ | |
EIT_present_following_flag(1) \n \ | |
running_status(3) \n \ | |
free_CA_mode(1) \n \ | |
descriptors_loop_length(12) \n \ | |
for (j=0;j<N;j++){ \n \ | |
descriptor() \n \ | |
} \n \ | |
} \n \ | |
CRC_32(32) \n \ | |
} \n \ | |
===================================================== \n\ | |
"); | |
} | |
void printSdt(ServiceDescriptionTable *sdt) | |
{ | |
char tmp1[9],tmp2[9],tmp3[9],tmp4[9],tmp5[9],tmp6[9]; | |
printf("==================SDT================== \n\ | |
table_id = 0x%02X \n\ | |
section_syntax_indicator = 0b%s \n\ | |
reserved_future_use = 0b%s \n\ | |
reserved = 0b%s \n\ | |
section_length = %d, 0x%04X \n\ | |
transport_stream_id = %d, 0x%04X \n\ | |
reserved2 = 0b%s \n\ | |
version_number = %d, 0x%02X \n\ | |
current_next_indicator = 0b%s \n\ | |
section_number = %d, 0x%02X \n\ | |
last_section_number = %d, 0x%02X \n\ | |
original_network_id = %d, 0x%04X \n\ | |
reserved_future_use2 = 0b%s \n", | |
sdt->table_id, toB(sdt->section_syntax_indicator, 1, tmp1), toB(sdt->reserved_future_use, 1, tmp2), | |
toB(sdt->reserved, 2, tmp3), sdt->section_length, sdt->section_length, | |
sdt->transport_stream_id, sdt->transport_stream_id, toB(sdt->reserved2, 2, tmp4), | |
sdt->version_number, sdt->version_number, toB(sdt->current_next_indicator, 1, tmp5), | |
sdt->section_number, sdt->section_number, sdt->last_section_number, sdt->last_section_number, | |
sdt->original_network_id, sdt->original_network_id, toB(sdt->reserved_future_use2, 8, tmp6)); | |
LoopSection *loop = sdt->loop; | |
int i,j; | |
i = 0; | |
while(loop != NULL){ | |
printf("\t--------------loop%d-------------- \n\ | |
service_id = %d = 0x%04X \n\ | |
reserved_future_use = 0b%s \n\ | |
EIT_user_defined_flags = 0b%s \n\ | |
EIT_schedule_flag = 0b%s \n\ | |
EIT_present_following_flag = 0b%s \n\ | |
running_status = %d = 0x%02X \n\ | |
free_CA_mode = 0b%s \n\ | |
descriptors_loop_length = %d = 0x%02X \n", | |
i, | |
loop->service_id, loop->service_id, toB(loop->reserved_future_use, 3, tmp1), | |
toB(loop->eit_user_defined_flags, 3, tmp2), toB(loop->eit_schedule_flag, 1, tmp3), | |
toB(loop->eit_present_following_flag, 1, tmp4), loop->running_status, loop->running_status, | |
toB(loop->free_ca_mode, 1 ,tmp5), loop->descriptors_loop_length, loop->descriptors_loop_length); | |
ServiceDescriptor *sd = loop->descriptor; | |
while(sd != NULL){ | |
if(sd->descriptor_tag != 0x48){ | |
sd = sd->next; | |
continue; | |
} | |
printf("\t\t*********descriptor********* \n\ | |
descriptor_tag = 0x%02X \n\ | |
descriptor_length = %d = 0x%02X \n\ | |
service_type = 0x%02X \n\ | |
service_provider_name_length = %d = 0x%02X \n", | |
sd->descriptor_tag, sd->descriptor_length, sd->descriptor_length, | |
sd->service_type, sd->service_provider_name_length, sd->service_provider_name_length); | |
printf("\t\tservice_provider_name = "); | |
for(j=0;j<sd->service_provider_name_length;j++){ | |
printf("%02X ", sd->service_provider_name[j]); | |
} | |
printf("\n"); | |
printf("\t\tservice_name_length = %d = 0x%02X\n", sd->service_name_length, sd->service_name_length); | |
printf("\t\tservice_name = "); | |
for(j=0;j<sd->service_name_length;j++){ | |
printf("%02X ", sd->service_name[j]); | |
} | |
printf("\n"); | |
sd = sd->next; | |
} | |
i++; | |
loop = loop->next; | |
} | |
printf("======================================= \n"); | |
} | |
char *toB(unsigned char buf, int n, char *str) | |
{ | |
int i; | |
str[n] = '\0'; | |
for(i=n-1;i>=0;i--){ | |
if(buf & 0x1){ | |
str[i] = '1'; | |
}else{ | |
str[i] = '0'; | |
} | |
buf = buf >> 1; | |
} | |
return str; | |
} | |
void printPacket(unsigned char* buf) | |
{ | |
int i; | |
for(i=0;i<188;i++){ | |
printf("%02X ", buf[i]); | |
if((i+1) % 12 == 0){ | |
printf("\n"); | |
} | |
} | |
printf("\n-----------------------\n\n"); | |
} | |
void* MyMalloc(size_t size) | |
{ | |
void *buf; | |
if((buf = malloc(size)) == NULL){ | |
perror("malloc error"); | |
exit(1); | |
} | |
return buf; | |
} | |
void freeSdtLoop(LoopSection *loop) | |
{ | |
LoopSection *tmp_loop; | |
ServiceDescriptor *sd, *tmp_sd; | |
while(loop != NULL){ | |
if(loop->descriptor != NULL){ | |
sd = loop->descriptor; | |
while(sd != NULL){ | |
tmp_sd = sd->next; | |
free(sd); | |
sd = tmp_sd; | |
} | |
} | |
tmp_loop = loop->next; | |
free(loop); | |
loop = tmp_loop; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment