dvbpsi_t *dvbpsi_new(dvbpsi_message_cb callback, enum dvbpsi_msg_level level) { dvbpsi_t *p_dvbpsi = calloc(1, sizeof(dvbpsi_t)); if (p_dvbpsi == NULL) return NULL; p_dvbpsi->p_decoder = NULL; //赋值为NULL,pat decoder还未初始化 p_dvbpsi->pf_message = callback; p_dvbpsi->i_msg_level = level; return p_dvbpsi; }b、初始化PAT decoder 并且绑定pat表的解析handle动作。其中dvbpsi_pat_attach中dvbpsi_decoder_new创建了 真正的pat decoder实例,并通过p_dvbpsi->p_decoder = DVBPSI_DECODER(p_pat_decoder)将其赋值给了抽象的decoder。
bool dvbpsi_pat_attach(dvbpsi_t *p_dvbpsi, dvbpsi_pat_callback pf_callback, void* p_cb_data) { assert(p_dvbpsi); assert(p_dvbpsi->p_decoder == NULL); /* PSI decoder configuration and initial state */ dvbpsi_pat_decoder_t *p_pat_decoder; /*创建真正的pat decoder*/ p_pat_decoder = (dvbpsi_pat_decoder_t*) dvbpsi_decoder_new(&dvbpsi_pat_sections_gather, 1024, true, sizeof(dvbpsi_pat_decoder_t)); if (p_pat_decoder == NULL) return false; /* PAT decoder information */ p_pat_decoder->pf_pat_callback = pf_callback; p_pat_decoder->p_cb_data = p_cb_data; p_pat_decoder->p_building_pat = NULL; /*将pat decoder赋值给p_decoder(类型的强转dvbpsi_pat_decoder_t* 转成dvbpsi_decoder_t*)*/ p_dvbpsi->p_decoder = DVBPSI_DECODER(p_pat_decoder); return true; }【总结a,b】
{ dvbpsi_pat_attach,(tables/pat.c) dvbpsi_bat_attach,(tables/bat.c) ... }c、PAT表中section的聚集
void dvbpsi_pat_sections_gather(dvbpsi_t* p_dvbpsi, dvbpsi_psi_section_t* p_section) { dvbpsi_pat_decoder_t* p_pat_decoder; assert(p_dvbpsi); assert(p_dvbpsi->p_decoder); if (!dvbpsi_CheckPSISection(p_dvbpsi, p_section, 0x00, "PAT decoder")) { dvbpsi_DeletePSISections(p_section); return; } /* Now we have a valid PAT section */ p_pat_decoder = (dvbpsi_pat_decoder_t *)p_dvbpsi->p_decoder; /* TS discontinuity check */ if (p_pat_decoder->b_discontinuity) { dvbpsi_ReInitPAT(p_pat_decoder, true); p_pat_decoder->b_discontinuity = false; } else { if (p_pat_decoder->p_building_pat) { if (dvbpsi_CheckPAT(p_dvbpsi, p_section)) dvbpsi_ReInitPAT(p_pat_decoder, true); } else { if( (p_pat_decoder->b_current_valid) && (p_pat_decoder->current_pat.i_version == p_section->i_version) && (p_pat_decoder->current_pat.b_current_next == p_section->b_current_next)) { /* Don't decode since this version is already decoded */ dvbpsi_debug(p_dvbpsi, "PAT decoder", "ignoring already decoded section %d", p_section->i_number); dvbpsi_DeletePSISections(p_section); return; } } } /* Add section to PAT */ if (!dvbpsi_AddSectionPAT(p_dvbpsi, p_pat_decoder, p_section)) { dvbpsi_error(p_dvbpsi, "PAT decoder", "failed decoding section %d", p_section->i_number); dvbpsi_DeletePSISections(p_section); return; } /* Check if we have all the sections */ if (dvbpsi_decoder_psi_sections_completed(DVBPSI_DECODER(p_pat_decoder))) { assert(p_pat_decoder->pf_pat_callback); /* Save the current information */ p_pat_decoder->current_pat = *p_pat_decoder->p_building_pat; p_pat_decoder->b_current_valid = true; /* Decode the sections */ dvbpsi_pat_sections_decode(p_pat_decoder->p_building_pat, p_pat_decoder->p_sections); /* Delete the sections */ dvbpsi_DeletePSISections(p_pat_decoder->p_sections); p_pat_decoder->p_sections = NULL; /* signal the new PAT */ p_pat_decoder->pf_pat_callback(p_pat_decoder->p_cb_data, p_pat_decoder->p_building_pat); /* Reinitialize the structures */ dvbpsi_ReInitPAT(p_pat_decoder, false); } }d、PAT表及PMT表的解析
源码解析如下:
/***************************************************************************** * handle_PAT *****************************************************************************/ static void handle_PAT(void* p_data, dvbpsi_pat_t* p_pat) { dvbpsi_pat_program_t* p_program = p_pat->p_first_program; ts_stream_t* p_stream = (ts_stream_t*) p_data; p_stream->pat.i_pat_version = p_pat->i_version; p_stream->pat.i_ts_id = p_pat->i_ts_id; printf("\n"); printf(" PAT: Program Association Table\n"); printf("\tTransport stream id : %d\n", p_pat->i_ts_id); printf("\tVersion number : %d\n", p_pat->i_version); printf("\tCurrent next : %s\n", p_pat->b_current_next ? "yes" : "no"); if (p_stream->pat.pid->i_prev_received > 0) printf("\tLast received : %"PRId64" ms ago\n", (mtime_t)(p_stream->pat.pid->i_received - p_stream->pat.pid->i_prev_received)); printf("\t\t| program_number @ [NIT|PMT]_PID\n"); while (p_program) { /* Attach new PMT decoder */ ts_pmt_t *p_pmt = calloc(1, sizeof(ts_pmt_t)); if (p_pmt) { /* PMT */ p_pmt->handle = dvbpsi_new(&dvbpsi_message, p_stream->level); if (p_pmt->handle == NULL) { fprintf(stderr, "dvbinfo: Failed attach new PMT decoder\n"); free(p_pmt); break; } p_pmt->i_number = p_program->i_number; p_pmt->pid_pmt = &p_stream->pid[p_program->i_pid]; p_pmt->pid_pmt->i_pid = p_program->i_pid; p_pmt->p_next = NULL; /*创建PMT Decoder*/ if (!dvbpsi_pmt_attach(p_pmt->handle, p_program->i_number, handle_PMT, p_stream)) { fprintf(stderr, "dvbinfo: Failed to attach new pmt decoder\n"); break; } /* insert at start of list */ p_pmt->p_next = p_stream->pmt; p_stream->pmt = p_pmt; p_stream->i_pmt++; assert(p_stream->pmt); } else fprintf(stderr, "dvbinfo: Failed create new PMT decoder\n"); printf("\t\t| %14d @ pid: 0x%x (%d)\n", p_program->i_number, p_program->i_pid, p_program->i_pid); p_program = p_program->p_next; } printf("\tActive : %s\n", p_pat->b_current_next ? "yes" : "no"); dvbpsi_pat_delete(p_pat); }
PAT表中含有PMT表的节目号,所以需要解析PMT表。
PMT表的协议根据标准ISO/IEC 13818-1 section 2.4.4.8如下表所示:
源码解析如下:
/***************************************************************************** * handle_PMT *****************************************************************************/ static void handle_PMT(void* p_data, dvbpsi_pmt_t* p_pmt) { dvbpsi_pmt_es_t* p_es = p_pmt->p_first_es; ts_stream_t* p_stream = (ts_stream_t*) p_data; /* Find signalled PMT */ ts_pmt_t *p = p_stream->pmt; while (p) { if (p->i_number == p_pmt->i_program_number) break; p = p->p_next; } assert(p); p->i_pmt_version = p_pmt->i_version; p->pid_pcr = &p_stream->pid[p_pmt->i_pcr_pid]; p_stream->pid[p_pmt->i_pcr_pid].b_pcr = true; printf("\n"); printf(" PMT: Program Map Table\n"); printf("\tProgram number : %d\n", p_pmt->i_program_number); printf("\tVersion number : %d\n", p_pmt->i_version); printf("\tPCR_PID : 0x%x (%d)\n", p_pmt->i_pcr_pid, p_pmt->i_pcr_pid); printf("\tCurrent next : %s\n", p_pmt->b_current_next ? "yes" : "no"); DumpDescriptors("\t ]", p_pmt->p_first_descriptor); printf("\t| type @ elementary_PID : Description\n"); while(p_es) { printf("\t| 0x%02x @ pid 0x%x (%d): %s\n", p_es->i_type, p_es->i_pid, p_es->i_pid, GetTypeName(p_es->i_type) ); DumpDescriptors("\t| ]", p_es->p_first_descriptor); p_es = p_es->p_next; } dvbpsi_pmt_delete(p_pmt); }【小结】至此,PAT表的解析分析完成了。具体在代码调试过程中,可借助pes码流分析工具,详细的查看各个表的信息,并结合dvb规范,详细查询每个descriptor的描述,完成解码工作。