Skip to content

Instantly share code, notes, and snippets.

@kimson
Created February 20, 2012 09:40
Show Gist options
  • Save kimson/1868591 to your computer and use it in GitHub Desktop.
Save kimson/1868591 to your computer and use it in GitHub Desktop.
mpeg2-ts : display a SDT(Service Description Table)
#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