// input parser: Parse a TS packet Documentation at iso13818-1.pdf SSIZE_T TSDemuxer::parse( Buffer *buf, SSIZE_T parsed ) { BYTE *ptr = (BYTE *)buf->buffer(); SIZE_T size = buf->length(); //printf( "[TSDemuxer] Begin parse: offset=%ld, bufLen=%ld, local=%d\n", parsed, size, (_local == buf) ); while (parsed < size) { { // Find TS SYNC byte SSIZE_T begin=parsed; while (ptr[parsed] != TS_SYNC && parsed < size) { parsed++; } if (parsed - begin) { Buffer show( buf->buffer()+begin, parsed+10, false ); printf( "[TSDemuxer] Warning: Sync lost offset=%ld, size=%ld, count=%ld, isLocal=%d, data=%s\n", begin, size, parsed-begin, (_local == buf), show.asHexa().c_str() ); } } // is the begin of TS packet! if (parsed < size) { int len = size - parsed; BYTE *ts = ptr + parsed; // is ths TS complete? if (len >= TS_PACKET_SIZE) { ID pid = TS_PID(ts); // Check for Transport Error Indicator (TES), payload exist, and null packets!! if (!TS_HAS_ERROR(ts) && TS_HAS_PAYLOAD(ts) && pid != TS_PID_NULL) { int payloadOffset = TS_HEAD_SIZE; // Adaptation field exists? if (TS_HAS_ADAPTATION(ts)) { // Only calculate payload offset if adaptation field exist payloadOffset += TSA_LEN(ts); } // Check payload offset if (payloadOffset < TS_PACKET_SIZE) { bool startFlag = TS_START(ts); // Find filter (and check continuity bit) _mutex.lock(); PSIFilter *filter = checkContinuity( pid, startFlag, TS_CONTINUITY(ts) ); if (filter) { BYTE *tsPayload = ts+payloadOffset; int tsPayloadLen = TS_PACKET_SIZE-payloadOffset; // Begin of a section? if (startFlag) { // Get pointer field, skip them in payload and len BYTE pointerField = tsPayload[0]; tsPayload++; tsPayloadLen--; // Check pointer field if (!pointerField || pointerField < tsPayloadLen) { if (pointerField) { // Append last block of a section filter->pushData( tsPayload, pointerField ); // Skip data marked via pointer field tsPayload += pointerField; tsPayloadLen -= pointerField; } // TODO: Can start more than one section/pes packet // Start a new section filter->startData( tsPayload, tsPayloadLen ); } else { printf( "[TSDemuxer] Warning: Pointer field invalid pointer=%d, tsPayloadLen=%d\n", pointerField, tsPayloadLen ); } } else { // Add payload to current section filter->pushData( tsPayload, tsPayloadLen ); } if (TS_PRIORITY(ts)) { // TODO: Priority not processed printf( "[TSDemuxer] Warning: Priority not processed\n" ); } } _mutex.unlock(); } else { printf( "[TSDemuxer] Warning: Transport stream payload not valid\n" ); } } parsed += TS_PACKET_SIZE; } else { // break loop break; } } } //printf( "[TSDemuxer] End parse: parsed=%ld\n", parsed ); return parsed; }
/* sms1xxx_demux_write_section(): write a section to demux filter Return 0 if section handled (written or no buffer space left) Return 1 if section data is corrupt */ static int sms1xxx_demux_write_section(struct sms1xxx_softc *sc, u8 *p, struct filter *f) { u8 hlen, len, total, count; u8 *payload; if(!TS_HAS_PAYLOAD(p)) return (1); hlen = TS_GET_HDR_LEN(p); if(hlen >= PACKET_SIZE) { sms1xxx_demux_sectbuf_reset(sc, f, 1, "corrupt packet"); return (1); } payload = p + hlen; len = PACKET_SIZE - hlen; if(TS_HAS_PUSI(p)) { u8 off = TS_GET_SECT_OFF(payload); if((hlen + off + 3) > PACKET_SIZE) { sms1xxx_demux_sectbuf_reset(sc, f, 1, "corrupt packet"); return (1); } #ifdef SMS1XXX_DIAGNOSTIC /* XXX Check if the old section is finished */ if(f->wtodo != 0) { WARN("pid: %hu section not finished but new pusi " "hlen %d off %d todo %d\n", f->pid, hlen, off, f->wtodo); } #endif /* Section start */ payload += off; len -= off; if((TS_GET_SECT_TBLID(payload) & f->mask) != f->value) { f->wtodo = 0; return (0); } f->wtodo = TS_GET_SECT_LEN(payload); TRACE(TRACE_SECT,"pid: %hu writing new section len: %d\n", f->pid, f->wtodo); } if(f->wtodo == 0) return (0); total = MIN(f->wtodo,len); if(total > f->wavail) { #ifdef SMS1XXX_DIAGNOSTIC WARN("pid: %hu no section buffer space available\n",f->pid); #endif sms1xxx_demux_sectbuf_reset(sc, f, 1, "no buffer space"); return (0); } if(total > f->size) { ERR("total > f->size, this shouldn't happen! %d > %d\n", total,f->size); return (1); } TRACE(TRACE_SECT,"pid: %hu writing %d bytes to section\n", f->pid,total); count = MIN(total,f->size - f->woff); memcpy(f->buf + f->woff,payload,count); if(count < total) { f->woff = total - count; memcpy(f->buf,payload+count,f->woff); } else { f->woff += total; } if(f->woff == f->size) f->woff = 0; f->wtodo -= total; if(f->wtodo == 0) { mtx_lock(&sc->filterlock); f->wavail -= total; f->ravail += total; f->cnt++; f->state &= ~FILTER_OVERFLOW; mtx_unlock(&sc->filterlock); TRACE(TRACE_SECT,"pid: %hu writing section done cnt: %d\n" ,f->pid, f->cnt); /* Wake up readers ! */ if(f->state & FILTER_SLEEP) wakeup(f); if(f->state & FILTER_POLL) { f->state &= ~FILTER_POLL; selwakeuppri(&f->rsel, PZERO); } } else { mtx_lock(&sc->filterlock); f->wavail -= total; f->ravail += total; mtx_unlock(&sc->filterlock); } #ifdef SMS1XXX_DIAGNOSTIC if(total < len && TS_GET_SECT_TBLID(payload+total) != 0xFF) WARN("possible section(s) discarded\n"); #endif return (0); }