📄 mpegts.c
字号:
u8 table_id; u16 extended_table_id; u32 status, section_start; GF_M2TS_Table *t, *prev_t; unsigned char *data; Bool section_valid = 0; /*parse header*/ data = sec->section; /*look for proper table*/ prev_t = NULL; table_id = data[0]; t = sec->table; while (t) { if (t->table_id==table_id) break; prev_t = t; t = t->next; } /*create table*/ if (!t) { GF_SAFEALLOC(t, GF_M2TS_Table); t->table_id = table_id; if (prev_t) prev_t->next = t; else sec->table = t; } extended_table_id = 0; section_start = 3;// sec->table_id = data[0]; has_syntax_indicator = (data[1] & 0x80) ? 1 : 0; if (has_syntax_indicator) { /*remove crc32*/ sec->length -= 4; if (gf_m2ts_crc32_check(data, sec->length)) { s32 cur_sec_num; extended_table_id = (data[3]<<8) | data[4]; t->version_number = (data[5] >> 1) & 0x1f; t->current_next_indicator = (data[5] & 0x1) ? 1 : 0; cur_sec_num = data[6]; t->last_section_number = data[7]; section_start = 8; section_valid = 1; /*we missed something*/ if (cur_sec_num && (t->section_number + 1 != cur_sec_num)) { section_valid = 0; GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] corrupted table (lost section %d)\n", cur_sec_num ? cur_sec_num-1 : 31) ); } t->section_number = cur_sec_num; } else { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] corrupted section (CRC32 failed)\n")); } } else if (!sec->had_error) { section_valid = 1; } /*process section*/ if (section_valid) { /*table is spread across several sections, gather*/ if (t->last_section_number) { u32 pay_size = t->data_size + sec->length - section_start; t->data = (char*)realloc(t->data, sizeof(char)*pay_size); memcpy(t->data + t->data_size, sec->section + section_start, sizeof(char)*(sec->length - section_start) ); t->data_size = pay_size; if (sec->section) free(sec->section); sec->section = NULL; sec->length = sec->received = 0; } /*not done yet*/ if (t->last_section_number > t->section_number) return; if (!t->is_init) status = GF_M2TS_TABLE_FOUND; else status = (t->last_version_number==t->version_number) ? GF_M2TS_TABLE_REPEAT : GF_M2TS_TABLE_UPDATE; t->last_version_number = t->version_number; t->is_init = 1; if (t->current_next_indicator) { if (t->data) { sec->process_section(ts, ses, t->data, t->data_size, t->table_id, extended_table_id, status); free(t->data); t->data = NULL; t->data_size = 0; } else { sec->process_section(ts, ses, sec->section + section_start, sec->length - section_start, t->table_id, extended_table_id, status); } } } else { sec->cc = -1; } /*clean-up (including broken sections)*/ if (sec->section) free(sec->section); sec->section = NULL; sec->length = sec->received = 0;}static Bool gf_m2ts_is_long_section(u8 table_id){ switch (table_id) { case GF_M2TS_TABLE_ID_MPEG4_BIFS: case GF_M2TS_TABLE_ID_MPEG4_OD: case GF_M2TS_TABLE_ID_EIT_ACTUAL_PF: case GF_M2TS_TABLE_ID_ST: case GF_M2TS_TABLE_ID_SIT: return 1; default: return 0; }}static void gf_m2ts_gather_section(GF_M2TS_Demuxer *ts, GF_M2TS_SectionFilter *sec, GF_M2TS_SECTION_ES *ses, GF_M2TS_Header *hdr, unsigned char *data, u32 data_size){ u8 expect_cc = (sec->cc<0) ? hdr->continuity_counter : (sec->cc + 1) & 0xf; Bool disc = (expect_cc == hdr->continuity_counter) ? 0 : 1; sec->cc = expect_cc; if (hdr->error || (hdr->adaptation_field==2)) /* 2 = no payload in TS packet */ return; if (hdr->payload_start) { u32 ptr_field; ptr_field = data[0]; if (ptr_field+1>data_size) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] Invalid section start (@ptr_field=%d, @data_size=%d)\n", ptr_field, data_size) ); return; } /*end of previous section*/ if (sec->length && sec->received + ptr_field >= sec->length) { memcpy(sec->section + sec->received, data, sizeof(char)*ptr_field); sec->received += ptr_field; gf_m2ts_section_complete(ts, sec, ses); } data += ptr_field+1; data_size -= ptr_field+1; if (sec->section) free(sec->section); sec->length = sec->received = 0; sec->section = (char*)malloc(sizeof(char)*data_size); memcpy(sec->section, data, sizeof(char)*data_size); sec->received = data_size; sec->had_error = 0; } else if (disc || hdr->error) { if (sec->section) free(sec->section); sec->section = NULL; sec->received = sec->length = 0; return; } else if (!sec->section) { return; } else { if (sec->received+data_size > sec->length) {#if 0 GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] skipping %d bytes of garbage in section\n", data_size - (sec->length - sec->received) ));#endif data_size = sec->length - sec->received; } if (sec->length) { memcpy(sec->section + sec->received, data, sizeof(char)*data_size); } else { sec->section = (char*)realloc(sec->section, sizeof(char)*(sec->received+data_size)); memcpy(sec->section + sec->received, data, sizeof(char)*data_size); } sec->received += data_size; } if (hdr->error) sec->had_error = 1; /*alloc final buffer*/ if (!sec->length && (sec->received >= 3)) { if (gf_m2ts_is_long_section(sec->section[0])) { sec->length = 3 + ( ((sec->section[1]<<8) | sec->section[2]) & 0xfff ); } else { sec->length = 3 + ( ((sec->section[1]<<8) | sec->section[2]) & 0x3ff ); } sec->section = (char*)realloc(sec->section, sizeof(char)*sec->length); } if (sec->received < sec->length) return; /*OK done*/ gf_m2ts_section_complete(ts, sec, ses);}static void gf_m2ts_process_sdt(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *ses, unsigned char *data, u32 data_size, u8 table_id, u16 ex_table_id, u32 status){ u32 orig_net_id, pos, evt_type; /*skip if already received*/ if (status==GF_M2TS_TABLE_REPEAT) { if (ts->on_event) ts->on_event(ts, GF_M2TS_EVT_SDT_REPEAT, NULL); return; } if (table_id != GF_M2TS_TABLE_ID_SDT_ACTUAL) { gf_m2ts_reset_sdt(ts); return; } /*reset service desc*/ free(ses->sec->section); ses->sec->section = NULL; ses->sec->length = ses->sec->received = 0;// GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] SDT for actual ts\n")); gf_m2ts_reset_sdt(ts); orig_net_id = (data[0] << 8) | data[1]; pos = 3; while (pos < data_size) { GF_M2TS_SDT *sdt; u32 descs_size, d_pos, ulen; GF_SAFEALLOC(sdt, GF_M2TS_SDT); gf_list_add(ts->SDTs, sdt); sdt->service_id = (data[pos]<<8) + data[pos+1]; sdt->EIT_schedule = (data[pos+2] & 0x2) ? 1 : 0; sdt->EIT_present_following = (data[pos+2] & 0x1); sdt->running_status = (data[pos+3]>>5) & 0x7; sdt->free_CA_mode = (data[pos+3]>>4) & 0x1; descs_size = ((data[pos+3]&0xf)<<8) | data[pos+4]; pos += 5; d_pos = 0; while (d_pos < descs_size) { u8 d_tag = data[pos+d_pos]; u8 d_len = data[pos+d_pos+1]; switch (d_tag) { case GF_M2TS_DVB_SERVICE_DESCRIPTOR: if (sdt->provider) free(sdt->provider); sdt->provider = NULL; if (sdt->service) free(sdt->service); sdt->service = NULL; d_pos+=2; sdt->service_type = data[pos+d_pos]; ulen = data[pos+d_pos+1]; d_pos += 2; sdt->provider = (char*)malloc(sizeof(char)*(ulen+1)); memcpy(sdt->provider, data+pos+d_pos, sizeof(char)*ulen); sdt->provider[ulen] = 0; d_pos += ulen; ulen = data[pos+d_pos]; d_pos += 1; sdt->service = (char*)malloc(sizeof(char)*(ulen+1)); memcpy(sdt->service, data+pos+d_pos, sizeof(char)*ulen); sdt->service[ulen] = 0; d_pos += ulen; break; default: GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] Skipping descriptor (0x%x) not supported\n", d_tag)); d_pos += d_len; if (d_len == 0) d_pos = descs_size; break; } } pos += descs_size; } evt_type = GF_M2TS_EVT_SDT_FOUND; if (ts->on_event) ts->on_event(ts, evt_type, NULL);}static void gf_m2ts_process_mpeg4section(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *es, unsigned char *data, u32 data_size, u8 table_id, u16 ex_table_id, u32 status){ GF_M2TS_SL_PCK sl_pck; /*skip if already received*/ if (status==GF_M2TS_TABLE_REPEAT) return; GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MPEG-2 TS] Section for PID %d\n", es->pid) ); sl_pck.data = data; sl_pck.data_len = data_size; sl_pck.stream = (GF_M2TS_ES *)es; if (ts->on_event) ts->on_event(ts, GF_M2TS_EVT_SL_PCK, &sl_pck);}static void gf_m2ts_process_int(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *ip_not_table, unsigned char *data, u32 data_size, u8 table_id, u16 ex_table_id, u32 status){ fprintf(stdout, "Processing IP/MAC Notification table (PID %d) %s\n", ip_not_table->pid, (status==GF_M2TS_TABLE_REPEAT)?"repeated":"");}#if 0static void gf_m2ts_process_mpe(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *mpe, unsigned char *data, u32 data_size, u8 table_id, u16 ex_table_id, u32 status){ fprintf(stdout, "Processing MPE Datagram (PID %d)\n", mpe->pid);}#endifstatic void gf_m2ts_process_nit(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *mpe, unsigned char *data, u32 data_size, u8 table_id, u16 ex_table_id, u32 status){}static void gf_m2ts_process_pmt(GF_M2TS_Demuxer *ts, GF_M2TS_SECTION_ES *pmt, unsigned char *data, u32 data_size, u8 table_id, u16 ex_table_id, u32 status){ u32 info_length, pos, desc_len, evt_type; /*skip if already received*/ if (status==GF_M2TS_TABLE_REPEAT) { if (ts->on_event) ts->on_event(ts, GF_M2TS_EVT_PMT_REPEAT, pmt->program); return; } pmt->program->pcr_pid = ((data[0] & 0x1f) << 8) | data[1]; info_length = ((data[2]&0xf)<<8) | data[3]; if (info_length != 0) { /* ...Read Descriptors ... */ u8 tag, len; u32 first_loop_len = 0; tag = data[4]; len = data[5]; while (info_length > first_loop_len) { if (tag == GF_M2TS_MPEG4_IOD_DESCRIPTOR) { u8 scope, label; u32 size; GF_BitStream *iod_bs; scope = data[6]; label = data[7]; iod_bs = gf_bs_new(data+8, data_size-8, GF_BITSTREAM_READ);#if 0 printf("Parsing IOD descriptor ... "); if (gf_odf_parse_descriptor(iod_bs , (GF_Descriptor **) &pmt->program->pmt_iod, &size) == GF_OK) printf("done.\n"); else printf("error.\n");#else if (pmt->program->pmt_iod) gf_odf_desc_del((GF_Descriptor *)pmt->program->pmt_iod); gf_odf_parse_descriptor(iod_bs , (GF_Descriptor **) &pmt->program->pmt_iod, &size);#endif gf_bs_del(iod_bs ); } else { GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] Skipping descriptor (0x%x) and others not supported\n", tag)); } first_loop_len += 2 + len; } } if (data_size <= 4 + info_length) return; data += 4 + info_length; data_size -= 4 + info_length; pos = 0; while (pos<data_size) { GF_M2TS_PES *pes = NULL; GF_M2TS_SECTION_ES *ses = NULL; GF_M2TS_ES *es; u32 pid, stream_type; stream_type = data[0]; pid = ((data[1] & 0x1f) << 8) | data[2]; desc_len = ((data[3] & 0xf) << 8) | data[4]; switch (stream_type) { /* PES */ case GF_M2TS_VIDEO_MPEG1: case GF_M2TS_VIDEO_MPEG2: case GF_M2TS_AUDIO_MPEG1: case GF_M2TS_AUDIO_MPEG2: case GF_M2TS_AUDIO_AAC: case GF_M2TS_VIDEO_MPEG4: case GF_M2TS_SYSTEMS_MPEG4_PES: case GF_M2TS_VIDEO_H264: case GF_M2TS_AUDIO_AC3: case GF_M2TS_AUDIO_DTS: case GF_M2TS_SUBTITLE_DVB: case GF_M2TS_PRIVATE_DATA: GF_SAFEALLOC(pes, GF_M2TS_PES); es = (GF_M2TS_ES *)pes; break; /* Sections */ case GF_M2TS_PRIVATE_SECTION: case GF_M2TS_SYSTEMS_MPEG4_SECTIONS: GF_SAFEALLOC(ses, GF_M2TS_SECTION_ES); es = (GF_M2TS_ES *)ses; es->flags |= GF_M2TS_ES_IS_SECTION; /* carriage of ISO_IEC_14496 data in sections */ if (stream_type == GF_M2TS_SYSTEMS_MPEG4_SECTIONS) { ses->sec = gf_m2ts_section_filter_new(gf_m2ts_process_mpeg4section); } break; default: GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] Stream type (0x%x) for PID %d not supported\n", stream_type, pid ) ); return; } es->stream_type = stream_type; es->program = pmt->program; es->pid = pid; ts->ess[es->pid] = es; gf_list_add(pmt->program->streams, es); pos += 5; data += 5; while (desc_len) { u8 tag = data[0]; u32 len = data[1]; switch (tag) { case GF_M2TS_ISO_639_LANGUAGE_DESCRIPTOR: pes->lang = GF_4CC(' ', data[2], data[3], data[4]); break; case GF_M2TS_MPEG4_SL_DESCRIPTOR: { //u32 esd_index = 0; pes->mpeg4_es_id = ((data[7] & 0x1f) << 8) | data[8]; pes->flags |= GF_M2TS_ES_IS_SL;/* while ( (GF_ESD *esd = (GF_ESD*)gf_list_enum(pmt->program->pmt_iod->ESDescriptors, &esd_index)) ) { if (esd->ESID == pes->ES_ID) pes->esd = esd; }*/ } break; case GF_M2TS_DVB_DATA_BROADCAST_ID_DESCRIPTOR: { u32 id = data[2]<<8 | data[3]; if (id == 0xB) { ses->sec = gf_m2ts_section_filter_new(gf_m2ts_process_int); gf_list_add(ts->ip_mac_not_tables, es); } } break; default: GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MPEG-2 TS] skipping descriptor (0x%x) not supported\n", tag)); break; } data += len+2; pos += len+2; if (desc_len < len+2) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MPEG-2 TS] Invalid PMT es descriptor size for PID %d\n", pes->pid ) ); break; } desc_len-=len+2; } if (!(es->flags & GF_M2TS_ES_IS_SECTION) ) gf_m2ts_set_pes_framing(pes, GF_M2TS_PES_FRAMING_DEFAULT); } evt_type = (status==GF_M2TS_TABLE_FOUND) ? GF_M2TS_EVT_PMT_FOUND : GF_M2TS_EVT_PMT_UPDATE; if (ts->on_event) ts->on_event(ts, evt_type, pmt->program);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -