// ITU-T H.222.0(06/2012) // Information technology – Generic coding of moving pictures and associated audio information: Systems // 2.4.3.1 Transport stream(p34) #include "mpeg-ts-proto.h" #include "mpeg-ps-proto.h" #include "mpeg-pes-proto.h" #include "mpeg-util.h" #include "mpeg-ts.h" #include #include #include struct ts_demuxer_t { struct pat_t pat; ts_demuxer_onpacket onpacket; void *param; }; static uint32_t adaptation_filed_read(struct ts_adaptation_field_t *adp, const uint8_t *data, size_t bytes) { // 2.4.3.4 Adaptation field // Table 2-6 uint32_t i = 0; uint32_t j = 0; assert(bytes <= TS_PACKET_SIZE); adp->adaptation_field_length = data[i++]; if (adp->adaptation_field_length > 0) { adp->discontinuity_indicator = (data[i] >> 7) & 0x01; adp->random_access_indicator = (data[i] >> 6) & 0x01; adp->elementary_stream_priority_indicator = (data[i] >> 5) & 0x01; adp->PCR_flag = (data[i] >> 4) & 0x01; adp->OPCR_flag = (data[i] >> 3) & 0x01; adp->splicing_point_flag = (data[i] >> 2) & 0x01; adp->transport_private_data_flag = (data[i] >> 1) & 0x01; adp->adaptation_field_extension_flag = (data[i] >> 0) & 0x01; i++; if (adp->PCR_flag) { adp->program_clock_reference_base = ((uint64_t)data[i] << 25) | ((uint64_t)data[i + 1] << 17) | ((uint64_t)data[i + 2] << 9) | ((uint64_t)data[i + 3] << 1) | ((data[i + 4] >> 7) & 0x01); adp->program_clock_reference_extension = ((data[i + 4] & 0x01) << 8) | data[i + 5]; i += 6; } if (adp->OPCR_flag) { adp->original_program_clock_reference_base = (((uint64_t)data[i]) << 25) | ((uint64_t)data[i + 1] << 17) | ((uint64_t)data[i + 2] << 9) | ((uint64_t)data[i + 3] << 1) | ((data[i + 4] >> 7) & 0x01); adp->original_program_clock_reference_extension = ((data[i + 4] & 0x01) << 1) | data[i + 5]; i += 6; } if (adp->splicing_point_flag) { adp->splice_countdown = data[i++]; } if (adp->transport_private_data_flag) { adp->transport_private_data_length = data[i++]; for (j = 0; j < adp->transport_private_data_length; j++) { // uint8_t transport_private_data = data[i+j]; } i += adp->transport_private_data_length; } if (adp->adaptation_field_extension_flag) { uint8_t reserved; adp->adaptation_field_extension_length = data[i++]; adp->ltw_flag = (data[i] >> 7) & 0x01; adp->piecewise_rate_flag = (data[i] >> 6) & 0x01; adp->seamless_splice_flag = (data[i] >> 5) & 0x01; reserved = data[i] & 0x1F; i++; if (adp->ltw_flag) { // uint8_t ltw_valid_flag = (data[i] >> 7) & 0x01; // uint16_t ltw_offset = ((data[i] & 0x7F) << 8) | data[i+1]; i += 2; } if (adp->piecewise_rate_flag) { // uint32_t piecewise_rate = ((data[i] & 0x3F) << 16) | (data[i+1] << 8) | data[i+2]; i += 3; } if (adp->seamless_splice_flag) { // uint8_t Splice_type = (data[i] >> 4) & 0x0F; // uint32_t DTS_next_AU = (((data[i] >> 1) & 0x07) << 30) | (data[i+1] << 22) | (((data[i+2] >> 1) & 0x7F) << 15) | (data[i+3] << 7) | ((data[i+4] >> 1) & 0x7F); i += 5; } // reserved byte } // stuffing byte } return adp->adaptation_field_length + 1; } #define TS_IS_SYNC_BYTE(data) (data[0] == TS_SYNC_BYTE) #define TS_TRANSPORT_ERROR_INDICATOR(data) (data[1] & 0x80) #define TS_PAYLOAD_UNIT_START_INDICATOR(data) (data[1] & 0x40) #define TS_TRANSPORT_PRIORITY(data) (data[1] & 0x20) size_t ts_demuxer_flush(struct ts_demuxer_t *ts) { uint32_t i, j; for (i = 0; i < ts->pat.pmt_count; i++) { for (j = 0; j < ts->pat.pmts[i].stream_count; j++) { struct pes_t *pes = &ts->pat.pmts[i].streams[j]; if (pes->pkt.size < 5) { continue; } if (PSI_STREAM_H264 == pes->codecid) { const uint8_t aud[] = {0, 0, 0, 1, 0x09, 0xf0}; pes_packet(&pes->pkt, pes, aud, sizeof(aud), ts->onpacket, ts->param); } else if (PSI_STREAM_H265 == pes->codecid) { const uint8_t aud[] = {0, 0, 0, 1, 0x46, 0x01, 0x50}; pes_packet(&pes->pkt, pes, aud, sizeof(aud), ts->onpacket, ts->param); } else { //assert(0); pes_packet(&pes->pkt, pes, NULL, 0, ts->onpacket, ts->param); } } } return 0; } size_t ts_demuxer_input(struct ts_demuxer_t *ts, const uint8_t *data, size_t bytes) { int r = 0; uint32_t i, j, k; uint32_t PID; struct ts_packet_header_t pkhd; // 2.4.3 Specification of the transport stream syntax and semantics // Transport stream packets shall be 188 bytes long. assert(188 == bytes); // 2.4.3.2 Transport stream packet layer // Table 2-2 memset(&pkhd, 0, sizeof(pkhd)); /* assert(0x47 == data[0]); // sync_byte */ if (0x47 != data[0]) { return (size_t) - 1; } PID = ((data[1] << 8) | data[2]) & 0x1FFF; pkhd.transport_error_indicator = (data[1] >> 7) & 0x01; pkhd.payload_unit_start_indicator = (data[1] >> 6) & 0x01; pkhd.transport_priority = (data[1] >> 5) & 0x01; pkhd.transport_scrambling_control = (data[3] >> 6) & 0x03; pkhd.adaptation_field_control = (data[3] >> 4) & 0x03; pkhd.continuity_counter = data[3] & 0x0F; // printf("-----------------------------------------------\n"); // printf("PID[%u]: Error: %u, Start:%u, Priority:%u, Scrambler:%u, AF: %u, CC: %u\n", PID, pkhd.transport_error_indicator, pkhd.payload_unit_start_indicator, pkhd.transport_priority, pkhd.transport_scrambling_control, pkhd.adaptation_field_control, pkhd.continuity_counter); i = 4; if (0x02 & pkhd.adaptation_field_control) { i += adaptation_filed_read(&pkhd.adaptation, data + 4, bytes - 4); if (pkhd.adaptation.adaptation_field_length > 0 && pkhd.adaptation.PCR_flag) { int64_t t; t = pkhd.adaptation.program_clock_reference_base / 90L; // ms; /* printf("pcr: %02d:%02d:%02d.%03d - %" PRId64 "/%u\n", (int)(t / 3600000), (int)(t % 3600000)/60000, (int)((t/1000) % 60), (int)(t % 1000), pkhd.adaptation.program_clock_reference_base, pkhd.adaptation.program_clock_reference_extension); */ } } if (0x01 & pkhd.adaptation_field_control) { if (TS_PID_PAT == PID) { if (TS_PAYLOAD_UNIT_START_INDICATOR(data)) { i += 1; // pointer 0x00 } pat_read(&ts->pat, data + i, bytes - i); } else if (TS_PID_SDT == PID) { if (TS_PAYLOAD_UNIT_START_INDICATOR(data)) { i += 1; // pointer 0x00 } sdt_read(&ts->pat, data + i, bytes - i); } else { for (j = 0; j < ts->pat.pmt_count; j++) { if (PID == ts->pat.pmts[j].pid) { if (TS_PAYLOAD_UNIT_START_INDICATOR(data)) { i += 1; // pointer 0x00 } pmt_read(&ts->pat.pmts[j], data + i, bytes - i); break; } else { for (k = 0; k < ts->pat.pmts[j].stream_count; k++) { struct pes_t *pes = &ts->pat.pmts[j].streams[k]; if (PID != pes->pid) { continue; } if (TS_PAYLOAD_UNIT_START_INDICATOR(data)) { size_t n; n = pes_read_header(pes, data + i, bytes - i); assert(n > 0); i += n; } r = pes_packet(&pes->pkt, pes, data + i, bytes - i, ts->onpacket, ts->param); break; // find stream } } // PMT handler } } // PAT handler } return r; } static inline int mpeg_ts_is_idr_first_packet(const void *packet, int bytes) { const unsigned char *data; struct ts_packet_header_t pkhd; int payload_unit_start_indicator; memset(&pkhd, 0, sizeof(pkhd)); data = (const unsigned char *)packet; payload_unit_start_indicator = data[1] & 0x40; pkhd.adaptation_field_control = (data[3] >> 4) & 0x03; pkhd.continuity_counter = data[3] & 0x0F; if (0x02 == pkhd.adaptation_field_control || 0x03 == pkhd.adaptation_field_control) { adaptation_filed_read(&pkhd.adaptation, data + 4, bytes - 4); } return (payload_unit_start_indicator && pkhd.adaptation.random_access_indicator) ? 1 : 0; } struct ts_demuxer_t *ts_demuxer_create(ts_demuxer_onpacket onpacket, void *param) { struct ts_demuxer_t *ts; ts = calloc(1, sizeof(struct ts_demuxer_t)); if (!ts) { return NULL; } ts->onpacket = onpacket; ts->param = param; return ts; } int ts_demuxer_destroy(struct ts_demuxer_t *ts) { size_t i, j; struct pes_t *pes; for (i = 0; i < ts->pat.pmt_count; i++) { for (j = 0; j < ts->pat.pmts[i].stream_count; j++) { pes = &ts->pat.pmts[i].streams[j]; if (pes->pkt.data) { free(pes->pkt.data); } pes->pkt.data = NULL; } } free(ts); return 0; } int ts_demuxer_getservice(struct ts_demuxer_t *ts, int program, char *provider, int nprovider, char *name, int nname) { struct pmt_t *pmt; pmt = pat_find(&ts->pat, program); if (NULL == pmt) { return -1; } extern int snprintf(char *buf, unsigned long size, const char *fmt, ...); snprintf(provider, nprovider, "%s", pmt->provider); snprintf(name, nname, "%s", pmt->name); return 0; }