Refactor parsing buffer handling + better constification
This commit is contained in:
parent
3f68bb68aa
commit
6f85b14767
12 changed files with 206 additions and 150 deletions
|
@ -22,9 +22,20 @@
|
|||
|
||||
|
||||
void
|
||||
init_bits(bitstream_t *bs, uint8_t *data, int bits)
|
||||
init_rbits(bitstream_t *bs, const uint8_t *data, int bits)
|
||||
{
|
||||
bs->data = data;
|
||||
bs->wdata = NULL;
|
||||
bs->rdata = data;
|
||||
bs->offset = 0;
|
||||
bs->len = bits;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
init_wbits(bitstream_t *bs, uint8_t *data, int bits)
|
||||
{
|
||||
bs->wdata = data;
|
||||
bs->rdata = NULL;
|
||||
bs->offset = 0;
|
||||
bs->len = bits;
|
||||
}
|
||||
|
@ -46,7 +57,7 @@ read_bits(bitstream_t *bs, int num)
|
|||
|
||||
num--;
|
||||
|
||||
if(bs->data[bs->offset / 8] & (1 << (7 - (bs->offset & 7))))
|
||||
if(bs->rdata[bs->offset / 8] & (1 << (7 - (bs->offset & 7))))
|
||||
r |= 1 << num;
|
||||
|
||||
bs->offset++;
|
||||
|
@ -103,9 +114,9 @@ put_bits(bitstream_t *bs, int val, int num)
|
|||
num--;
|
||||
|
||||
if(val & (1 << num))
|
||||
bs->data[bs->offset / 8] |= 1 << (7 - (bs->offset & 7));
|
||||
bs->wdata[bs->offset / 8] |= 1 << (7 - (bs->offset & 7));
|
||||
else
|
||||
bs->data[bs->offset / 8] &= ~(1 << (7 - (bs->offset & 7)));
|
||||
bs->wdata[bs->offset / 8] &= ~(1 << (7 - (bs->offset & 7)));
|
||||
|
||||
bs->offset++;
|
||||
}
|
||||
|
|
|
@ -20,14 +20,17 @@
|
|||
#define BITSTREAM_H_
|
||||
|
||||
typedef struct bitstream {
|
||||
uint8_t *data;
|
||||
const uint8_t *rdata;
|
||||
uint8_t *wdata;
|
||||
int offset;
|
||||
int len;
|
||||
} bitstream_t;
|
||||
|
||||
void skip_bits(bitstream_t *bs, int num);
|
||||
|
||||
void init_bits(bitstream_t *bs, uint8_t *data, int bits);
|
||||
void init_rbits(bitstream_t *bs, const uint8_t *data, int bits);
|
||||
|
||||
void init_wbits(bitstream_t *bs, uint8_t *data, int bits);
|
||||
|
||||
unsigned int read_bits(bitstream_t *gb, int num);
|
||||
|
||||
|
|
|
@ -145,6 +145,7 @@ mk_build_segment_info(mk_mux_t *mkm)
|
|||
ebml_append_string(q, 0x4d80, "HTS Tvheadend Matroska muxer");
|
||||
ebml_append_string(q, 0x5741, app);
|
||||
ebml_append_uint(q, 0x2ad7b1, MATROSKA_TIMESCALE);
|
||||
printf("Writing total duration %f\n", (float)mkm->totduration);
|
||||
if(mkm->totduration)
|
||||
ebml_append_float(q, 0x4489, (float)mkm->totduration);
|
||||
else
|
||||
|
|
|
@ -36,29 +36,29 @@
|
|||
/**
|
||||
* H.264 parser, nal escaper
|
||||
*/
|
||||
int
|
||||
h264_nal_deescape(bitstream_t *bs, uint8_t *data, int size)
|
||||
void *
|
||||
h264_nal_deescape(bitstream_t *bs, const uint8_t *data, int size)
|
||||
{
|
||||
int rbsp_size, i;
|
||||
|
||||
bs->data = malloc(size);
|
||||
uint8_t *d = malloc(size);
|
||||
bs->rdata = d;
|
||||
|
||||
/* Escape 0x000003 into 0x0000 */
|
||||
|
||||
rbsp_size = 0;
|
||||
for(i = 1; i < size; i++) {
|
||||
if(i + 2 < size && data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 3) {
|
||||
bs->data[rbsp_size++] = 0;
|
||||
bs->data[rbsp_size++] = 0;
|
||||
d[rbsp_size++] = 0;
|
||||
d[rbsp_size++] = 0;
|
||||
i += 2;
|
||||
} else {
|
||||
bs->data[rbsp_size++] = data[i];
|
||||
d[rbsp_size++] = data[i];
|
||||
}
|
||||
}
|
||||
|
||||
bs->offset = 0;
|
||||
bs->len = rbsp_size * 8;
|
||||
return 0;
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
|
@ -353,7 +353,7 @@ h264_decode_slice_header(th_stream_t *st, bitstream_t *bs, int *pkttype,
|
|||
|
||||
st->st_vbv_delay = -1;
|
||||
|
||||
if(p->sps[sps_id].width && p->sps[sps_id].height && !st->st_buffer_errors)
|
||||
if(p->sps[sps_id].width && p->sps[sps_id].height && !st->st_buf.sb_err)
|
||||
parser_set_stream_vsize(st, p->sps[sps_id].width, p->sps[sps_id].height);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "bitstream.h"
|
||||
|
||||
int h264_nal_deescape(bitstream_t *bs, uint8_t *data, int size);
|
||||
void *h264_nal_deescape(bitstream_t *bs, const uint8_t *data, int size);
|
||||
|
||||
int h264_decode_seq_parameter_set(th_stream_t *st, bitstream_t *bs);
|
||||
|
||||
|
|
|
@ -159,15 +159,15 @@ read_stream_mux_config(th_stream_t *st, latm_private_t *latm, bitstream_t *bs)
|
|||
* Parse AAC LATM
|
||||
*/
|
||||
th_pkt_t *
|
||||
parse_latm_audio_mux_element(th_transport_t *t, th_stream_t *st, uint8_t *data,
|
||||
int len)
|
||||
parse_latm_audio_mux_element(th_transport_t *t, th_stream_t *st,
|
||||
const uint8_t *data, int len)
|
||||
{
|
||||
latm_private_t *latm;
|
||||
bitstream_t bs, out;
|
||||
int slot_len, tmp, i;
|
||||
uint8_t *buf;
|
||||
|
||||
init_bits(&bs, data, len * 8);
|
||||
init_rbits(&bs, data, len * 8);
|
||||
|
||||
if((latm = st->st_priv) == NULL)
|
||||
latm = st->st_priv = calloc(1, sizeof(latm_private_t));
|
||||
|
@ -202,7 +202,7 @@ parse_latm_audio_mux_element(th_transport_t *t, th_stream_t *st, uint8_t *data,
|
|||
pkt->pkt_channels = latm->channel_config;
|
||||
|
||||
/* 7 bytes of ADTS header */
|
||||
init_bits(&out, pktbuf_ptr(pkt->pkt_payload), 56);
|
||||
init_wbits(&out, pktbuf_ptr(pkt->pkt_payload), 56);
|
||||
|
||||
put_bits(&out, 0xfff, 12); // Sync marker
|
||||
put_bits(&out, 0, 1); // ID 0 = MPEG 4
|
||||
|
|
|
@ -20,6 +20,6 @@
|
|||
#define PARSER_LATM_H_
|
||||
|
||||
th_pkt_t *parse_latm_audio_mux_element(th_transport_t *t, th_stream_t *st,
|
||||
uint8_t *data, int len);
|
||||
const uint8_t *data, int len);
|
||||
|
||||
#endif /* PARSER_LATM_H_ */
|
||||
|
|
165
src/parsers.c
165
src/parsers.c
|
@ -120,11 +120,9 @@ void
|
|||
parse_mpeg_ts(th_transport_t *t, th_stream_t *st, const uint8_t *data,
|
||||
int len, int start, int err)
|
||||
{
|
||||
if(start)
|
||||
st->st_buffer_errors = 0;
|
||||
|
||||
|
||||
if(err)
|
||||
st->st_buffer_errors++;
|
||||
sbuf_err(&st->st_buf);
|
||||
|
||||
switch(st->st_type) {
|
||||
case SCT_MPEG2VIDEO:
|
||||
|
@ -194,7 +192,7 @@ parse_mpeg_ps(th_transport_t *t, th_stream_t *st, uint8_t *data, int len)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -266,7 +264,7 @@ buffer3_cut(th_stream_t *st, int p)
|
|||
memmove(st->st_buffer3, st->st_buffer3 + p, st->st_buffer3_ptr);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Parse AAC LATM
|
||||
|
@ -281,34 +279,24 @@ parse_aac(th_transport_t *t, th_stream_t *st, const uint8_t *data,
|
|||
if(start) {
|
||||
/* Payload unit start */
|
||||
st->st_parser_state = 1;
|
||||
st->st_buffer_ptr = 0;
|
||||
st->st_parser_ptr = 0;
|
||||
sbuf_reset(&st->st_buf);
|
||||
}
|
||||
|
||||
if(st->st_parser_state == 0)
|
||||
return;
|
||||
|
||||
if(st->st_buffer == NULL) {
|
||||
st->st_buffer_size = 4000;
|
||||
st->st_buffer = malloc(st->st_buffer_size);
|
||||
}
|
||||
|
||||
if(st->st_buffer_ptr + len >= st->st_buffer_size) {
|
||||
st->st_buffer_size += len * 4;
|
||||
st->st_buffer = realloc(st->st_buffer, st->st_buffer_size);
|
||||
}
|
||||
|
||||
memcpy(st->st_buffer + st->st_buffer_ptr, data, len);
|
||||
st->st_buffer_ptr += len;
|
||||
sbuf_append(&st->st_buf, data, len);
|
||||
|
||||
|
||||
if(st->st_parser_ptr == 0) {
|
||||
int hlen;
|
||||
|
||||
if(st->st_buffer_ptr < 9)
|
||||
if(st->st_buf.sb_ptr < 9)
|
||||
return;
|
||||
|
||||
hlen = parse_pes_header(t, st, st->st_buffer + 6, st->st_buffer_ptr - 6);
|
||||
hlen = parse_pes_header(t, st,
|
||||
st->st_buf.sb_data + 6, st->st_buf.sb_ptr - 6);
|
||||
if(hlen < 0)
|
||||
return;
|
||||
st->st_parser_ptr += 6 + hlen;
|
||||
|
@ -317,15 +305,15 @@ parse_aac(th_transport_t *t, th_stream_t *st, const uint8_t *data,
|
|||
|
||||
p = st->st_parser_ptr;
|
||||
|
||||
while((l = st->st_buffer_ptr - p) > 3) {
|
||||
if(st->st_buffer[p] == 0x56 && (st->st_buffer[p + 1] & 0xe0) == 0xe0) {
|
||||
muxlen = (st->st_buffer[p + 1] & 0x1f) << 8 |
|
||||
st->st_buffer[p + 2];
|
||||
while((l = st->st_buf.sb_ptr - p) > 3) {
|
||||
const uint8_t *d = st->st_buf.sb_data + p;
|
||||
if(d[0] == 0x56 && (d[1] & 0xe0) == 0xe0) {
|
||||
muxlen = (d[1] & 0x1f) << 8 | d[2];
|
||||
|
||||
if(l < muxlen + 3)
|
||||
break;
|
||||
|
||||
pkt = parse_latm_audio_mux_element(t, st, st->st_buffer + p + 3, muxlen);
|
||||
pkt = parse_latm_audio_mux_element(t, st, d + 3, muxlen);
|
||||
|
||||
if(pkt != NULL)
|
||||
parser_deliver(t, st, pkt);
|
||||
|
@ -354,8 +342,7 @@ parse_sc(th_transport_t *t, th_stream_t *st, const uint8_t *data, int len,
|
|||
{
|
||||
uint32_t sc = st->st_startcond;
|
||||
int i, r;
|
||||
|
||||
buffer_alloc(st, len);
|
||||
sbuf_alloc(&st->st_buf, len);
|
||||
|
||||
for(i = 0; i < len; i++) {
|
||||
|
||||
|
@ -378,20 +365,20 @@ parse_sc(th_transport_t *t, th_stream_t *st, const uint8_t *data, int len,
|
|||
continue;
|
||||
}
|
||||
|
||||
st->st_buffer[st->st_buffer_ptr++] = data[i];
|
||||
st->st_buf.sb_data[st->st_buf.sb_ptr++] = data[i];
|
||||
sc = sc << 8 | data[i];
|
||||
|
||||
if((sc & 0xffffff00) != 0x00000100)
|
||||
continue;
|
||||
|
||||
r = st->st_buffer_ptr - st->st_startcode_offset - 4;
|
||||
r = st->st_buf.sb_ptr - st->st_startcode_offset - 4;
|
||||
|
||||
if(r > 0 && st->st_startcode != 0) {
|
||||
r = vp(t, st, r, sc, st->st_startcode_offset);
|
||||
if(r == 3)
|
||||
continue;
|
||||
if(r == 4) {
|
||||
st->st_buffer_ptr -= 4;
|
||||
st->st_buf.sb_ptr -= 4;
|
||||
st->st_ssc_intercept = 1;
|
||||
st->st_ssc_ptr = 0;
|
||||
sc = -1;
|
||||
|
@ -403,27 +390,26 @@ parse_sc(th_transport_t *t, th_stream_t *st, const uint8_t *data, int len,
|
|||
|
||||
if(r == 2) {
|
||||
// Drop packet
|
||||
st->st_buffer_ptr = st->st_startcode_offset;
|
||||
st->st_buf.sb_ptr = st->st_startcode_offset;
|
||||
|
||||
st->st_buffer[st->st_buffer_ptr++] = sc >> 24;
|
||||
st->st_buffer[st->st_buffer_ptr++] = sc >> 16;
|
||||
st->st_buffer[st->st_buffer_ptr++] = sc >> 8;
|
||||
st->st_buffer[st->st_buffer_ptr++] = sc;
|
||||
st->st_buf.sb_data[st->st_buf.sb_ptr++] = sc >> 24;
|
||||
st->st_buf.sb_data[st->st_buf.sb_ptr++] = sc >> 16;
|
||||
st->st_buf.sb_data[st->st_buf.sb_ptr++] = sc >> 8;
|
||||
st->st_buf.sb_data[st->st_buf.sb_ptr++] = sc;
|
||||
st->st_startcode = sc;
|
||||
|
||||
} else {
|
||||
if(r == 1) {
|
||||
/* Reset packet parser upon length error or if parser
|
||||
tells us so */
|
||||
st->st_buffer_ptr = 0;
|
||||
st->st_buffer_errors = 0;
|
||||
st->st_buffer[st->st_buffer_ptr++] = sc >> 24;
|
||||
st->st_buffer[st->st_buffer_ptr++] = sc >> 16;
|
||||
st->st_buffer[st->st_buffer_ptr++] = sc >> 8;
|
||||
st->st_buffer[st->st_buffer_ptr++] = sc;
|
||||
sbuf_reset(&st->st_buf);
|
||||
st->st_buf.sb_data[st->st_buf.sb_ptr++] = sc >> 24;
|
||||
st->st_buf.sb_data[st->st_buf.sb_ptr++] = sc >> 16;
|
||||
st->st_buf.sb_data[st->st_buf.sb_ptr++] = sc >> 8;
|
||||
st->st_buf.sb_data[st->st_buf.sb_ptr++] = sc;
|
||||
}
|
||||
st->st_startcode = sc;
|
||||
st->st_startcode_offset = st->st_buffer_ptr - 4;
|
||||
st->st_startcode_offset = st->st_buf.sb_ptr - 4;
|
||||
}
|
||||
}
|
||||
st->st_startcond = sc;
|
||||
|
@ -437,7 +423,7 @@ static int
|
|||
depacketize(th_transport_t *t, th_stream_t *st, size_t len,
|
||||
uint32_t next_startcode, int sc_offset)
|
||||
{
|
||||
const uint8_t *buf = st->st_buffer + sc_offset;
|
||||
const uint8_t *buf = st->st_buf.sb_data + sc_offset;
|
||||
uint32_t sc = st->st_startcode;
|
||||
int hlen, plen;
|
||||
|
||||
|
@ -463,7 +449,7 @@ depacketize(th_transport_t *t, th_stream_t *st, size_t len,
|
|||
buf += hlen;
|
||||
len -= hlen;
|
||||
|
||||
buffer3_append(st, buf, len);
|
||||
sbuf_append(&st->st_buf_a, buf, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -521,8 +507,8 @@ parse_mpa(th_transport_t *t, th_stream_t *st, size_t ilen,
|
|||
return i;
|
||||
|
||||
again:
|
||||
buf = st->st_buffer3;
|
||||
len = st->st_buffer3_ptr;
|
||||
buf = st->st_buf_a.sb_data;
|
||||
len = st->st_buf_a.sb_ptr;
|
||||
|
||||
for(i = 0; i < len - 4; i++) {
|
||||
if(mpa_valid_frame(buf + i)) {
|
||||
|
@ -544,7 +530,7 @@ parse_mpa(th_transport_t *t, th_stream_t *st, size_t ilen,
|
|||
|
||||
makeapkt(t, st, buf + i, fsize, dts, duration,
|
||||
channels, mpa_sri[(buf[i+2] >> 2) & 3]);
|
||||
buffer3_cut(st, i + fsize);
|
||||
sbuf_cut(&st->st_buf_a, i + fsize);
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
@ -634,8 +620,8 @@ parse_ac3(th_transport_t *t, th_stream_t *st, size_t ilen,
|
|||
return i;
|
||||
|
||||
again:
|
||||
buf = st->st_buffer3;
|
||||
len = st->st_buffer3_ptr;
|
||||
buf = st->st_buf_a.sb_data;
|
||||
len = st->st_buf_a.sb_ptr;
|
||||
|
||||
for(i = 0; i < len - 6; i++) {
|
||||
const uint8_t *p = buf + i;
|
||||
|
@ -677,7 +663,7 @@ parse_ac3(th_transport_t *t, th_stream_t *st, size_t ilen,
|
|||
ac3_valid_frame(p + fsize)) {
|
||||
|
||||
bitstream_t bs;
|
||||
init_bits(&bs, (uint8_t *)p + 5, (fsize - 5) * 8);
|
||||
init_rbits(&bs, p + 5, (fsize - 5) * 8);
|
||||
|
||||
read_bits(&bs, 5); // bsid
|
||||
read_bits(&bs, 3); // bsmod
|
||||
|
@ -694,7 +680,7 @@ parse_ac3(th_transport_t *t, th_stream_t *st, size_t ilen,
|
|||
int channels = acmodtab[acmod] + lfeon;
|
||||
|
||||
makeapkt(t, st, p, fsize, dts, duration, channels, sri);
|
||||
buffer3_cut(st, i + fsize);
|
||||
sbuf_cut(&st->st_buf_a, i + fsize);
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
@ -744,7 +730,7 @@ parse_pes_header(th_transport_t *t, th_stream_t *st,
|
|||
} else
|
||||
return hlen + 3;
|
||||
|
||||
if(st->st_buffer_errors) {
|
||||
if(st->st_buf.sb_err) {
|
||||
st->st_curdts = PTS_UNSET;
|
||||
st->st_curpts = PTS_UNSET;
|
||||
} else {
|
||||
|
@ -889,7 +875,7 @@ parser_global_data_move(th_stream_t *st, const uint8_t *data, size_t len)
|
|||
memcpy(st->st_global_data + st->st_global_data_len, data, len2);
|
||||
st->st_global_data_len += len2;
|
||||
|
||||
st->st_buffer_ptr -= len;
|
||||
st->st_buf.sb_ptr -= len;
|
||||
}
|
||||
|
||||
|
||||
|
@ -907,14 +893,14 @@ static int
|
|||
parse_mpeg2video(th_transport_t *t, th_stream_t *st, size_t len,
|
||||
uint32_t next_startcode, int sc_offset)
|
||||
{
|
||||
uint8_t *buf = st->st_buffer + sc_offset;
|
||||
const uint8_t *buf = st->st_buf.sb_data + sc_offset;
|
||||
bitstream_t bs;
|
||||
int frametype;
|
||||
|
||||
if(next_startcode == 0x1e0)
|
||||
return 4;
|
||||
|
||||
init_bits(&bs, buf + 4, (len - 4) * 8);
|
||||
init_rbits(&bs, buf + 4, (len - 4) * 8);
|
||||
|
||||
switch(st->st_startcode) {
|
||||
case 0x000001e0 ... 0x000001ef:
|
||||
|
@ -944,7 +930,7 @@ parse_mpeg2video(th_transport_t *t, th_stream_t *st, size_t len,
|
|||
|
||||
case 0x000001b3:
|
||||
/* Sequence start code */
|
||||
if(!st->st_buffer_errors) {
|
||||
if(!st->st_buf.sb_err) {
|
||||
if(parse_mpeg2video_seq_start(t, st, &bs))
|
||||
return 1;
|
||||
parser_global_data_move(st, buf, len);
|
||||
|
@ -957,12 +943,12 @@ parse_mpeg2video(th_transport_t *t, th_stream_t *st, size_t len,
|
|||
switch(buf[4] >> 4) {
|
||||
case 0x1:
|
||||
// Sequence Extension
|
||||
if(!st->st_buffer_errors)
|
||||
if(!st->st_buf.sb_err)
|
||||
parser_global_data_move(st, buf, len);
|
||||
return 2;
|
||||
case 0x2:
|
||||
// Sequence Display Extension
|
||||
if(!st->st_buffer_errors)
|
||||
if(!st->st_buf.sb_err)
|
||||
parser_global_data_move(st, buf, len);
|
||||
return 2;
|
||||
}
|
||||
|
@ -986,13 +972,14 @@ parse_mpeg2video(th_transport_t *t, th_stream_t *st, size_t len,
|
|||
st->st_global_data_len = 0;
|
||||
}
|
||||
|
||||
pkt->pkt_payload = pktbuf_make(st->st_buffer, st->st_buffer_ptr - 4);
|
||||
pkt->pkt_payload = pktbuf_make(st->st_buf.sb_data,
|
||||
st->st_buf.sb_ptr - 4);
|
||||
pkt->pkt_duration = st->st_frame_duration;
|
||||
|
||||
parser_deliver(t, st, pkt);
|
||||
st->st_curpkt = NULL;
|
||||
|
||||
st->st_buffer = malloc(st->st_buffer_size);
|
||||
st->st_buf.sb_data = malloc(st->st_buf.sb_size);
|
||||
|
||||
/* If we know the frame duration, increase DTS accordingly */
|
||||
if(st->st_curdts != PTS_UNSET)
|
||||
|
@ -1006,7 +993,7 @@ parse_mpeg2video(th_transport_t *t, th_stream_t *st, size_t len,
|
|||
|
||||
case 0x000001b8:
|
||||
// GOP header
|
||||
if(!st->st_buffer_errors)
|
||||
if(!st->st_buf.sb_err)
|
||||
parser_global_data_move(st, buf, len);
|
||||
return 2;
|
||||
|
||||
|
@ -1029,7 +1016,7 @@ static int
|
|||
parse_h264(th_transport_t *t, th_stream_t *st, size_t len,
|
||||
uint32_t next_startcode, int sc_offset)
|
||||
{
|
||||
uint8_t *buf = st->st_buffer + sc_offset;
|
||||
const uint8_t *buf = st->st_buf.sb_data + sc_offset;
|
||||
uint32_t sc = st->st_startcode;
|
||||
int64_t d;
|
||||
int l2, pkttype, duration, isfield;
|
||||
|
@ -1051,12 +1038,10 @@ parse_h264(th_transport_t *t, th_stream_t *st, size_t len,
|
|||
return 1;
|
||||
}
|
||||
|
||||
bs.data = NULL;
|
||||
|
||||
if(sc == 0x10c) {
|
||||
// Padding
|
||||
|
||||
st->st_buffer_ptr -= len;
|
||||
st->st_buf.sb_ptr -= len;
|
||||
ret = 2;
|
||||
|
||||
} else {
|
||||
|
@ -1064,18 +1049,20 @@ parse_h264(th_transport_t *t, th_stream_t *st, size_t len,
|
|||
switch(sc & 0x1f) {
|
||||
|
||||
case 7:
|
||||
if(!st->st_buffer_errors) {
|
||||
h264_nal_deescape(&bs, buf + 3, len - 3);
|
||||
if(!st->st_buf.sb_err) {
|
||||
void *f = h264_nal_deescape(&bs, buf + 3, len - 3);
|
||||
h264_decode_seq_parameter_set(st, &bs);
|
||||
free(f);
|
||||
parser_global_data_move(st, buf, len);
|
||||
}
|
||||
ret = 2;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
if(!st->st_buffer_errors) {
|
||||
h264_nal_deescape(&bs, buf + 3, len - 3);
|
||||
if(!st->st_buf.sb_err) {
|
||||
void *f = h264_nal_deescape(&bs, buf + 3, len - 3);
|
||||
h264_decode_pic_parameter_set(st, &bs);
|
||||
free(f);
|
||||
parser_global_data_move(st, buf, len);
|
||||
}
|
||||
ret = 2;
|
||||
|
@ -1087,12 +1074,14 @@ parse_h264(th_transport_t *t, th_stream_t *st, size_t len,
|
|||
break;
|
||||
|
||||
l2 = len - 3 > 64 ? 64 : len - 3;
|
||||
h264_nal_deescape(&bs, buf + 3, l2); /* we just want the first stuff */
|
||||
void *f = h264_nal_deescape(&bs, buf + 3, l2);
|
||||
/* we just want the first stuff */
|
||||
|
||||
if(h264_decode_slice_header(st, &bs, &pkttype, &duration, &isfield)) {
|
||||
free(bs.data);
|
||||
free(f);
|
||||
return 1;
|
||||
}
|
||||
free(f);
|
||||
|
||||
st->st_curpkt = pkt_alloc(NULL, 0, st->st_curpts, st->st_curdts);
|
||||
st->st_curpkt->pkt_frametype = pkttype;
|
||||
|
@ -1105,7 +1094,6 @@ parse_h264(th_transport_t *t, th_stream_t *st, size_t len,
|
|||
break;
|
||||
}
|
||||
}
|
||||
free(bs.data);
|
||||
|
||||
if(next_startcode >= 0x000001e0 && next_startcode <= 0x000001ef) {
|
||||
/* Complete frame */
|
||||
|
@ -1121,11 +1109,12 @@ parse_h264(th_transport_t *t, th_stream_t *st, size_t len,
|
|||
st->st_global_data_len = 0;
|
||||
}
|
||||
|
||||
pkt->pkt_payload = pktbuf_make(st->st_buffer, st->st_buffer_ptr - 4);
|
||||
pkt->pkt_payload = pktbuf_make(st->st_buf.sb_data,
|
||||
st->st_buf.sb_ptr - 4);
|
||||
parser_deliver(t, st, pkt);
|
||||
|
||||
st->st_curpkt = NULL;
|
||||
st->st_buffer = malloc(st->st_buffer_size);
|
||||
st->st_buf.sb_data = malloc(st->st_buf.sb_size);
|
||||
|
||||
st->st_curdts = PTS_UNSET;
|
||||
st->st_curpts = PTS_UNSET;
|
||||
|
@ -1145,46 +1134,42 @@ parse_subtitles(th_transport_t *t, th_stream_t *st, const uint8_t *data,
|
|||
{
|
||||
th_pkt_t *pkt;
|
||||
int psize, hlen;
|
||||
uint8_t *buf;
|
||||
|
||||
const uint8_t *buf;
|
||||
const uint8_t *d;
|
||||
if(start) {
|
||||
/* Payload unit start */
|
||||
st->st_parser_state = 1;
|
||||
st->st_buffer_errors = 0;
|
||||
st->st_buf.sb_err = 0;
|
||||
}
|
||||
|
||||
if(st->st_parser_state == 0)
|
||||
return;
|
||||
|
||||
buffer_append(st, data, len);
|
||||
sbuf_append(&st->st_buf, data, len);
|
||||
|
||||
if(st->st_buffer_ptr < 6)
|
||||
if(st->st_buf.sb_ptr < 6)
|
||||
return;
|
||||
|
||||
uint32_t startcode =
|
||||
(st->st_buffer[0] << 24) |
|
||||
(st->st_buffer[1] << 16) |
|
||||
(st->st_buffer[2] << 8) |
|
||||
(st->st_buffer[3]);
|
||||
d = st->st_buf.sb_data;
|
||||
uint32_t startcode = (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3];
|
||||
|
||||
if(startcode == 0x1be) {
|
||||
st->st_parser_state = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
psize = st->st_buffer[4] << 8 | st->st_buffer[5];
|
||||
psize = d[4] << 8 | d[5];
|
||||
|
||||
if(st->st_buffer_ptr != psize + 6)
|
||||
if(st->st_buf.sb_ptr != psize + 6)
|
||||
return;
|
||||
|
||||
st->st_parser_state = 0;
|
||||
|
||||
hlen = parse_pes_header(t, st, st->st_buffer + 6, st->st_buffer_ptr - 6);
|
||||
hlen = parse_pes_header(t, st, d + 6, st->st_buf.sb_ptr - 6);
|
||||
if(hlen < 0)
|
||||
return;
|
||||
|
||||
psize -= hlen;
|
||||
buf = st->st_buffer + 6 + hlen;
|
||||
buf = d + 6 + hlen;
|
||||
|
||||
if(psize < 2 || buf[0] != 0x20 || buf[1] != 0x00)
|
||||
return;
|
||||
|
|
|
@ -92,22 +92,10 @@ stream_clean(th_stream_t *st)
|
|||
/* Clear reassembly buffers */
|
||||
|
||||
st->st_startcode = 0;
|
||||
|
||||
free(st->st_buffer);
|
||||
st->st_buffer = NULL;
|
||||
st->st_buffer_size = 0;
|
||||
st->st_buffer_ptr = 0;
|
||||
|
||||
free(st->st_buffer2);
|
||||
st->st_buffer2 = NULL;
|
||||
st->st_buffer2_size = 0;
|
||||
st->st_buffer2_ptr = 0;
|
||||
|
||||
free(st->st_buffer3);
|
||||
st->st_buffer3 = NULL;
|
||||
st->st_buffer3_size = 0;
|
||||
st->st_buffer3_ptr = 0;
|
||||
|
||||
|
||||
sbuf_free(&st->st_buf);
|
||||
sbuf_free(&st->st_buf_ps);
|
||||
sbuf_free(&st->st_buf_a);
|
||||
|
||||
if(st->st_curpkt != NULL) {
|
||||
pkt_ref_dec(st->st_curpkt);
|
||||
|
|
37
src/tvhead.h
37
src/tvhead.h
|
@ -313,6 +313,17 @@ typedef struct streaming_queue {
|
|||
} streaming_queue_t;
|
||||
|
||||
|
||||
/**
|
||||
* Simple dynamically growing buffer
|
||||
*/
|
||||
typedef struct sbuf {
|
||||
uint8_t *sb_data;
|
||||
int sb_ptr;
|
||||
int sb_size;
|
||||
int sb_err;
|
||||
} sbuf_t;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Descrambler superclass
|
||||
|
@ -401,10 +412,7 @@ typedef struct th_stream {
|
|||
|
||||
/* For transport stream packet reassembly */
|
||||
|
||||
uint8_t *st_buffer;
|
||||
int st_buffer_ptr;
|
||||
int st_buffer_size;
|
||||
int st_buffer_errors; /* Errors accumulated for this packet */
|
||||
sbuf_t st_buf;
|
||||
|
||||
uint32_t st_startcond;
|
||||
uint32_t st_startcode;
|
||||
|
@ -413,13 +421,8 @@ typedef struct th_stream {
|
|||
int st_parser_ptr;
|
||||
void *st_priv; /* Parser private data */
|
||||
|
||||
uint8_t *st_buffer2;
|
||||
int st_buffer2_ptr;
|
||||
int st_buffer2_size;
|
||||
|
||||
uint8_t *st_buffer3;
|
||||
int st_buffer3_ptr;
|
||||
int st_buffer3_size;
|
||||
sbuf_t st_buf_ps; // program stream reassembly (analogue adapters)
|
||||
sbuf_t st_buf_a; // Audio packet reassembly
|
||||
|
||||
uint8_t *st_global_data;
|
||||
int st_global_data_len;
|
||||
|
@ -853,4 +856,16 @@ static inline int64_t ts_rescale(int64_t ts, int tb)
|
|||
return (ts * tb ) / 90000LL;
|
||||
}
|
||||
|
||||
void sbuf_free(sbuf_t *sb);
|
||||
|
||||
void sbuf_reset(sbuf_t *sb);
|
||||
|
||||
void sbuf_err(sbuf_t *sb);
|
||||
|
||||
void sbuf_alloc(sbuf_t *sb, int len);
|
||||
|
||||
void sbuf_append(sbuf_t *sb, const uint8_t *data, int len);
|
||||
|
||||
void sbuf_cut(sbuf_t *sb, int off);
|
||||
|
||||
#endif /* TV_HEAD_H */
|
||||
|
|
53
src/utils.c
53
src/utils.c
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "tvhead.h"
|
||||
|
||||
|
@ -224,3 +225,55 @@ put_utf8(char *out, int c)
|
|||
*out++ = 0x80 | (0x3f & c);
|
||||
return 6;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
sbuf_free(sbuf_t *sb)
|
||||
{
|
||||
free(sb->sb_data);
|
||||
sb->sb_size = sb->sb_ptr = sb->sb_err = 0;
|
||||
}
|
||||
|
||||
void
|
||||
sbuf_reset(sbuf_t *sb)
|
||||
{
|
||||
sb->sb_ptr = 0;
|
||||
sb->sb_err = 0;
|
||||
}
|
||||
|
||||
void
|
||||
sbuf_err(sbuf_t *sb)
|
||||
{
|
||||
sb->sb_err = 1;
|
||||
}
|
||||
|
||||
void
|
||||
sbuf_alloc(sbuf_t *sb, int len)
|
||||
{
|
||||
if(sb->sb_data == NULL) {
|
||||
sb->sb_size = 4000;
|
||||
sb->sb_data = malloc(sb->sb_size);
|
||||
}
|
||||
|
||||
if(sb->sb_ptr + len >= sb->sb_size) {
|
||||
sb->sb_size += len * 4;
|
||||
sb->sb_data = realloc(sb->sb_data, sb->sb_size);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sbuf_append(sbuf_t *sb, const uint8_t *data, int len)
|
||||
{
|
||||
sbuf_alloc(sb, len);
|
||||
memcpy(sb->sb_data + sb->sb_ptr, data, len);
|
||||
sb->sb_ptr += len;
|
||||
}
|
||||
|
||||
void
|
||||
sbuf_cut(sbuf_t *sb, int off)
|
||||
{
|
||||
assert(off <= sb->sb_ptr);
|
||||
sb->sb_ptr = sb->sb_ptr - off;
|
||||
memmove(sb->sb_data, sb->sb_data + off, sb->sb_ptr);
|
||||
}
|
||||
|
|
22
src/v4l.c
22
src/v4l.c
|
@ -87,36 +87,36 @@ v4l_input(v4l_adapter_t *va)
|
|||
}
|
||||
|
||||
if(va->va_lenlock == 2) {
|
||||
l = st->st_buffer2_size;
|
||||
st->st_buffer2 = pkt = realloc(st->st_buffer2, l);
|
||||
l = st->st_buf_ps.sb_size;
|
||||
st->st_buf_ps.sb_data = pkt = realloc(st->st_buf_ps.sb_data, l);
|
||||
|
||||
r = l - st->st_buffer2_ptr;
|
||||
r = l - st->st_buf_ps.sb_ptr;
|
||||
if(r > len)
|
||||
r = len;
|
||||
memcpy(pkt + st->st_buffer2_ptr, ptr, r);
|
||||
memcpy(pkt + st->st_buf_ps.sb_ptr, ptr, r);
|
||||
|
||||
ptr += r;
|
||||
len -= r;
|
||||
|
||||
st->st_buffer2_ptr += r;
|
||||
if(st->st_buffer2_ptr == l) {
|
||||
st->st_buf_ps.sb_ptr += r;
|
||||
if(st->st_buf_ps.sb_ptr == l) {
|
||||
|
||||
transport_set_streaming_status_flags(t, TSS_MUX_PACKETS);
|
||||
|
||||
parse_mpeg_ps(t, st, pkt + 6, l - 6);
|
||||
|
||||
st->st_buffer2_size = 0;
|
||||
st->st_buf_ps.sb_size = 0;
|
||||
va->va_startcode = 0;
|
||||
} else {
|
||||
assert(st->st_buffer2_ptr < l);
|
||||
assert(st->st_buf_ps.sb_ptr < l);
|
||||
}
|
||||
|
||||
} else {
|
||||
st->st_buffer2_size = st->st_buffer2_size << 8 | *ptr;
|
||||
st->st_buf_ps.sb_size = st->st_buf_ps.sb_size << 8 | *ptr;
|
||||
va->va_lenlock++;
|
||||
if(va->va_lenlock == 2) {
|
||||
st->st_buffer2_size += 6;
|
||||
st->st_buffer2_ptr = 6;
|
||||
st->st_buf_ps.sb_size += 6;
|
||||
st->st_buf_ps.sb_ptr = 6;
|
||||
}
|
||||
ptr++; len--;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue